linux/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
<<
>>
Prefs
   1/*
   2 * Copyright 2015 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 */
  23#include <linux/types.h>
  24#include <linux/kernel.h>
  25#include <linux/slab.h>
  26#include <linux/gfp.h>
  27#include "linux/delay.h"
  28#include "cgs_common.h"
  29#include "smu/smu_8_0_d.h"
  30#include "smu/smu_8_0_sh_mask.h"
  31#include "smu8.h"
  32#include "smu8_fusion.h"
  33#include "cz_smumgr.h"
  34#include "cz_ppsmc.h"
  35#include "smu_ucode_xfer_cz.h"
  36#include "gca/gfx_8_0_d.h"
  37#include "gca/gfx_8_0_sh_mask.h"
  38#include "smumgr.h"
  39
  40#define SIZE_ALIGN_32(x)    (((x) + 31) / 32 * 32)
  41
  42static const enum cz_scratch_entry firmware_list[] = {
  43        CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0,
  44        CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1,
  45        CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE,
  46        CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
  47        CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME,
  48        CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
  49        CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
  50        CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G,
  51};
  52
  53static int cz_smum_get_argument(struct pp_smumgr *smumgr)
  54{
  55        if (smumgr == NULL || smumgr->device == NULL)
  56                return -EINVAL;
  57
  58        return cgs_read_register(smumgr->device,
  59                                        mmSMU_MP1_SRBM2P_ARG_0);
  60}
  61
  62static int cz_send_msg_to_smc_async(struct pp_smumgr *smumgr,
  63                                                                uint16_t msg)
  64{
  65        int result = 0;
  66
  67        if (smumgr == NULL || smumgr->device == NULL)
  68                return -EINVAL;
  69
  70        result = SMUM_WAIT_FIELD_UNEQUAL(smumgr,
  71                                        SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
  72        if (result != 0) {
  73                printk(KERN_ERR "[ powerplay ] cz_send_msg_to_smc_async failed\n");
  74                return result;
  75        }
  76
  77        cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0);
  78        cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg);
  79
  80        return 0;
  81}
  82
  83/* Send a message to the SMC, and wait for its response.*/
  84static int cz_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
  85{
  86        int result = 0;
  87
  88        result = cz_send_msg_to_smc_async(smumgr, msg);
  89        if (result != 0)
  90                return result;
  91
  92        result = SMUM_WAIT_FIELD_UNEQUAL(smumgr,
  93                                        SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
  94
  95        if (result != 0)
  96                return result;
  97
  98        return 0;
  99}
 100
 101static int cz_set_smc_sram_address(struct pp_smumgr *smumgr,
 102                                     uint32_t smc_address, uint32_t limit)
 103{
 104        if (smumgr == NULL || smumgr->device == NULL)
 105                return -EINVAL;
 106
 107        if (0 != (3 & smc_address)) {
 108                printk(KERN_ERR "[ powerplay ] SMC address must be 4 byte aligned\n");
 109                return -1;
 110        }
 111
 112        if (limit <= (smc_address + 3)) {
 113                printk(KERN_ERR "[ powerplay ] SMC address beyond the SMC RAM area\n");
 114                return -1;
 115        }
 116
 117        cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX_0,
 118                                SMN_MP1_SRAM_START_ADDR + smc_address);
 119
 120        return 0;
 121}
 122
 123static int cz_write_smc_sram_dword(struct pp_smumgr *smumgr,
 124                uint32_t smc_address, uint32_t value, uint32_t limit)
 125{
 126        int result;
 127
 128        if (smumgr == NULL || smumgr->device == NULL)
 129                return -EINVAL;
 130
 131        result = cz_set_smc_sram_address(smumgr, smc_address, limit);
 132        cgs_write_register(smumgr->device, mmMP0PUB_IND_DATA_0, value);
 133
 134        return 0;
 135}
 136
 137static int cz_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
 138                                          uint16_t msg, uint32_t parameter)
 139{
 140        if (smumgr == NULL || smumgr->device == NULL)
 141                return -EINVAL;
 142
 143        cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter);
 144
 145        return cz_send_msg_to_smc(smumgr, msg);
 146}
 147
 148static int cz_request_smu_load_fw(struct pp_smumgr *smumgr)
 149{
 150        struct cz_smumgr *cz_smu = (struct cz_smumgr *)(smumgr->backend);
 151        int result = 0;
 152        uint32_t smc_address;
 153
 154        if (!smumgr->reload_fw) {
 155                printk(KERN_INFO "[ powerplay ] skip reloading...\n");
 156                return 0;
 157        }
 158
 159        smc_address = SMU8_FIRMWARE_HEADER_LOCATION +
 160                offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
 161
 162        cz_write_smc_sram_dword(smumgr, smc_address, 0, smc_address+4);
 163
 164        cz_send_msg_to_smc_with_parameter(smumgr,
 165                                        PPSMC_MSG_DriverDramAddrHi,
 166                                        cz_smu->toc_buffer.mc_addr_high);
 167
 168        cz_send_msg_to_smc_with_parameter(smumgr,
 169                                        PPSMC_MSG_DriverDramAddrLo,
 170                                        cz_smu->toc_buffer.mc_addr_low);
 171
 172        cz_send_msg_to_smc(smumgr, PPSMC_MSG_InitJobs);
 173
 174        cz_send_msg_to_smc_with_parameter(smumgr,
 175                                        PPSMC_MSG_ExecuteJob,
 176                                        cz_smu->toc_entry_aram);
 177        cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
 178                                cz_smu->toc_entry_power_profiling_index);
 179
 180        result = cz_send_msg_to_smc_with_parameter(smumgr,
 181                                        PPSMC_MSG_ExecuteJob,
 182                                        cz_smu->toc_entry_initialize_index);
 183
 184        return result;
 185}
 186
 187static int cz_check_fw_load_finish(struct pp_smumgr *smumgr,
 188                                   uint32_t firmware)
 189{
 190        int i;
 191        uint32_t index = SMN_MP1_SRAM_START_ADDR +
 192                         SMU8_FIRMWARE_HEADER_LOCATION +
 193                         offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
 194
 195        if (smumgr == NULL || smumgr->device == NULL)
 196                return -EINVAL;
 197
 198        return cgs_read_register(smumgr->device,
 199                                        mmSMU_MP1_SRBM2P_ARG_0);
 200
 201        cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX, index);
 202
 203        for (i = 0; i < smumgr->usec_timeout; i++) {
 204                if (firmware ==
 205                        (cgs_read_register(smumgr->device, mmMP0PUB_IND_DATA) & firmware))
 206                        break;
 207                udelay(1);
 208        }
 209
 210        if (i >= smumgr->usec_timeout) {
 211                printk(KERN_ERR "[ powerplay ] SMU check loaded firmware failed.\n");
 212                return -EINVAL;
 213        }
 214
 215        return 0;
 216}
 217
 218static int cz_load_mec_firmware(struct pp_smumgr *smumgr)
 219{
 220        uint32_t reg_data;
 221        uint32_t tmp;
 222        int ret = 0;
 223        struct cgs_firmware_info info = {0};
 224        struct cz_smumgr *cz_smu;
 225
 226        if (smumgr == NULL || smumgr->device == NULL)
 227                return -EINVAL;
 228
 229        cz_smu = (struct cz_smumgr *)smumgr->backend;
 230        ret = cgs_get_firmware_info(smumgr->device,
 231                                                CGS_UCODE_ID_CP_MEC, &info);
 232
 233        if (ret)
 234                return -EINVAL;
 235
 236        /* Disable MEC parsing/prefetching */
 237        tmp = cgs_read_register(smumgr->device,
 238                                        mmCP_MEC_CNTL);
 239        tmp = SMUM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1);
 240        tmp = SMUM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1);
 241        cgs_write_register(smumgr->device, mmCP_MEC_CNTL, tmp);
 242
 243        tmp = cgs_read_register(smumgr->device,
 244                                        mmCP_CPC_IC_BASE_CNTL);
 245
 246        tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0);
 247        tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0);
 248        tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0);
 249        tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1);
 250        cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_CNTL, tmp);
 251
 252        reg_data = smu_lower_32_bits(info.mc_addr) &
 253                        SMUM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO);
 254        cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_LO, reg_data);
 255
 256        reg_data = smu_upper_32_bits(info.mc_addr) &
 257                        SMUM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI);
 258        cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_HI, reg_data);
 259
 260        return 0;
 261}
 262
 263static int cz_start_smu(struct pp_smumgr *smumgr)
 264{
 265        int ret = 0;
 266        uint32_t fw_to_check = UCODE_ID_RLC_G_MASK |
 267                                UCODE_ID_SDMA0_MASK |
 268                                UCODE_ID_SDMA1_MASK |
 269                                UCODE_ID_CP_CE_MASK |
 270                                UCODE_ID_CP_ME_MASK |
 271                                UCODE_ID_CP_PFP_MASK |
 272                                UCODE_ID_CP_MEC_JT1_MASK |
 273                                UCODE_ID_CP_MEC_JT2_MASK;
 274
 275        if (smumgr->chip_id == CHIP_STONEY)
 276                fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK);
 277
 278        cz_request_smu_load_fw(smumgr);
 279        cz_check_fw_load_finish(smumgr, fw_to_check);
 280
 281        ret = cz_load_mec_firmware(smumgr);
 282        if (ret)
 283                printk(KERN_ERR "[ powerplay ] Mec Firmware load failed\n");
 284
 285        return ret;
 286}
 287
 288static uint8_t cz_translate_firmware_enum_to_arg(struct pp_smumgr *smumgr,
 289                        enum cz_scratch_entry firmware_enum)
 290{
 291        uint8_t ret = 0;
 292
 293        switch (firmware_enum) {
 294        case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0:
 295                ret = UCODE_ID_SDMA0;
 296                break;
 297        case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1:
 298                if (smumgr->chip_id == CHIP_STONEY)
 299                        ret = UCODE_ID_SDMA0;
 300                else
 301                        ret = UCODE_ID_SDMA1;
 302                break;
 303        case CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE:
 304                ret = UCODE_ID_CP_CE;
 305                break;
 306        case CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP:
 307                ret = UCODE_ID_CP_PFP;
 308                break;
 309        case CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME:
 310                ret = UCODE_ID_CP_ME;
 311                break;
 312        case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1:
 313                ret = UCODE_ID_CP_MEC_JT1;
 314                break;
 315        case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2:
 316                if (smumgr->chip_id == CHIP_STONEY)
 317                        ret = UCODE_ID_CP_MEC_JT1;
 318                else
 319                        ret = UCODE_ID_CP_MEC_JT2;
 320                break;
 321        case CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG:
 322                ret = UCODE_ID_GMCON_RENG;
 323                break;
 324        case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G:
 325                ret = UCODE_ID_RLC_G;
 326                break;
 327        case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH:
 328                ret = UCODE_ID_RLC_SCRATCH;
 329                break;
 330        case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM:
 331                ret = UCODE_ID_RLC_SRM_ARAM;
 332                break;
 333        case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM:
 334                ret = UCODE_ID_RLC_SRM_DRAM;
 335                break;
 336        case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM:
 337                ret = UCODE_ID_DMCU_ERAM;
 338                break;
 339        case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM:
 340                ret = UCODE_ID_DMCU_IRAM;
 341                break;
 342        case CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING:
 343                ret = TASK_ARG_INIT_MM_PWR_LOG;
 344                break;
 345        case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT:
 346        case CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING:
 347        case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS:
 348        case CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT:
 349        case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START:
 350        case CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS:
 351                ret = TASK_ARG_REG_MMIO;
 352                break;
 353        case CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE:
 354                ret = TASK_ARG_INIT_CLK_TABLE;
 355                break;
 356        }
 357
 358        return ret;
 359}
 360
 361static enum cgs_ucode_id cz_convert_fw_type_to_cgs(uint32_t fw_type)
 362{
 363        enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
 364
 365        switch (fw_type) {
 366        case UCODE_ID_SDMA0:
 367                result = CGS_UCODE_ID_SDMA0;
 368                break;
 369        case UCODE_ID_SDMA1:
 370                result = CGS_UCODE_ID_SDMA1;
 371                break;
 372        case UCODE_ID_CP_CE:
 373                result = CGS_UCODE_ID_CP_CE;
 374                break;
 375        case UCODE_ID_CP_PFP:
 376                result = CGS_UCODE_ID_CP_PFP;
 377                break;
 378        case UCODE_ID_CP_ME:
 379                result = CGS_UCODE_ID_CP_ME;
 380                break;
 381        case UCODE_ID_CP_MEC_JT1:
 382                result = CGS_UCODE_ID_CP_MEC_JT1;
 383                break;
 384        case UCODE_ID_CP_MEC_JT2:
 385                result = CGS_UCODE_ID_CP_MEC_JT2;
 386                break;
 387        case UCODE_ID_RLC_G:
 388                result = CGS_UCODE_ID_RLC_G;
 389                break;
 390        default:
 391                break;
 392        }
 393
 394        return result;
 395}
 396
 397static int cz_smu_populate_single_scratch_task(
 398                        struct pp_smumgr *smumgr,
 399                        enum cz_scratch_entry fw_enum,
 400                        uint8_t type, bool is_last)
 401{
 402        uint8_t i;
 403        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 404        struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
 405        struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++];
 406
 407        task->type = type;
 408        task->arg = cz_translate_firmware_enum_to_arg(smumgr, fw_enum);
 409        task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count;
 410
 411        for (i = 0; i < cz_smu->scratch_buffer_length; i++)
 412                if (cz_smu->scratch_buffer[i].firmware_ID == fw_enum)
 413                        break;
 414
 415        if (i >= cz_smu->scratch_buffer_length) {
 416                printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n");
 417                return -EINVAL;
 418        }
 419
 420        task->addr.low = cz_smu->scratch_buffer[i].mc_addr_low;
 421        task->addr.high = cz_smu->scratch_buffer[i].mc_addr_high;
 422        task->size_bytes = cz_smu->scratch_buffer[i].data_size;
 423
 424        if (CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) {
 425                struct cz_ih_meta_data *pIHReg_restore =
 426                     (struct cz_ih_meta_data *)cz_smu->scratch_buffer[i].kaddr;
 427                pIHReg_restore->command =
 428                        METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD;
 429        }
 430
 431        return 0;
 432}
 433
 434static int cz_smu_populate_single_ucode_load_task(
 435                                        struct pp_smumgr *smumgr,
 436                                        enum cz_scratch_entry fw_enum,
 437                                        bool is_last)
 438{
 439        uint8_t i;
 440        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 441        struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
 442        struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++];
 443
 444        task->type = TASK_TYPE_UCODE_LOAD;
 445        task->arg = cz_translate_firmware_enum_to_arg(smumgr, fw_enum);
 446        task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count;
 447
 448        for (i = 0; i < cz_smu->driver_buffer_length; i++)
 449                if (cz_smu->driver_buffer[i].firmware_ID == fw_enum)
 450                        break;
 451
 452        if (i >= cz_smu->driver_buffer_length) {
 453                printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n");
 454                return -EINVAL;
 455        }
 456
 457        task->addr.low = cz_smu->driver_buffer[i].mc_addr_low;
 458        task->addr.high = cz_smu->driver_buffer[i].mc_addr_high;
 459        task->size_bytes = cz_smu->driver_buffer[i].data_size;
 460
 461        return 0;
 462}
 463
 464static int cz_smu_construct_toc_for_rlc_aram_save(struct pp_smumgr *smumgr)
 465{
 466        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 467
 468        cz_smu->toc_entry_aram = cz_smu->toc_entry_used_count;
 469        cz_smu_populate_single_scratch_task(smumgr,
 470                                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
 471                                TASK_TYPE_UCODE_SAVE, true);
 472
 473        return 0;
 474}
 475
 476static int cz_smu_initialize_toc_empty_job_list(struct pp_smumgr *smumgr)
 477{
 478        int i;
 479        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 480        struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
 481
 482        for (i = 0; i < NUM_JOBLIST_ENTRIES; i++)
 483                toc->JobList[i] = (uint8_t)IGNORE_JOB;
 484
 485        return 0;
 486}
 487
 488static int cz_smu_construct_toc_for_vddgfx_enter(struct pp_smumgr *smumgr)
 489{
 490        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 491        struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
 492
 493        toc->JobList[JOB_GFX_SAVE] = (uint8_t)cz_smu->toc_entry_used_count;
 494        cz_smu_populate_single_scratch_task(smumgr,
 495                                    CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
 496                                    TASK_TYPE_UCODE_SAVE, false);
 497
 498        cz_smu_populate_single_scratch_task(smumgr,
 499                                    CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
 500                                    TASK_TYPE_UCODE_SAVE, true);
 501
 502        return 0;
 503}
 504
 505
 506static int cz_smu_construct_toc_for_vddgfx_exit(struct pp_smumgr *smumgr)
 507{
 508        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 509        struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
 510
 511        toc->JobList[JOB_GFX_RESTORE] = (uint8_t)cz_smu->toc_entry_used_count;
 512
 513        cz_smu_populate_single_ucode_load_task(smumgr,
 514                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
 515        cz_smu_populate_single_ucode_load_task(smumgr,
 516                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
 517        cz_smu_populate_single_ucode_load_task(smumgr,
 518                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
 519        cz_smu_populate_single_ucode_load_task(smumgr,
 520                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
 521
 522        if (smumgr->chip_id == CHIP_STONEY)
 523                cz_smu_populate_single_ucode_load_task(smumgr,
 524                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
 525        else
 526                cz_smu_populate_single_ucode_load_task(smumgr,
 527                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
 528
 529        cz_smu_populate_single_ucode_load_task(smumgr,
 530                                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, false);
 531
 532        /* populate scratch */
 533        cz_smu_populate_single_scratch_task(smumgr,
 534                                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
 535                                TASK_TYPE_UCODE_LOAD, false);
 536
 537        cz_smu_populate_single_scratch_task(smumgr,
 538                                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
 539                                TASK_TYPE_UCODE_LOAD, false);
 540
 541        cz_smu_populate_single_scratch_task(smumgr,
 542                                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
 543                                TASK_TYPE_UCODE_LOAD, true);
 544
 545        return 0;
 546}
 547
 548static int cz_smu_construct_toc_for_power_profiling(
 549                                                 struct pp_smumgr *smumgr)
 550{
 551        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 552
 553        cz_smu->toc_entry_power_profiling_index = cz_smu->toc_entry_used_count;
 554
 555        cz_smu_populate_single_scratch_task(smumgr,
 556                                CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
 557                                TASK_TYPE_INITIALIZE, true);
 558        return 0;
 559}
 560
 561static int cz_smu_construct_toc_for_bootup(struct pp_smumgr *smumgr)
 562{
 563        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 564
 565        cz_smu->toc_entry_initialize_index = cz_smu->toc_entry_used_count;
 566
 567        cz_smu_populate_single_ucode_load_task(smumgr,
 568                                CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
 569        if (smumgr->chip_id == CHIP_STONEY)
 570                cz_smu_populate_single_ucode_load_task(smumgr,
 571                                CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
 572        else
 573                cz_smu_populate_single_ucode_load_task(smumgr,
 574                                CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false);
 575        cz_smu_populate_single_ucode_load_task(smumgr,
 576                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
 577        cz_smu_populate_single_ucode_load_task(smumgr,
 578                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
 579        cz_smu_populate_single_ucode_load_task(smumgr,
 580                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
 581        cz_smu_populate_single_ucode_load_task(smumgr,
 582                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
 583        if (smumgr->chip_id == CHIP_STONEY)
 584                cz_smu_populate_single_ucode_load_task(smumgr,
 585                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
 586        else
 587                cz_smu_populate_single_ucode_load_task(smumgr,
 588                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
 589        cz_smu_populate_single_ucode_load_task(smumgr,
 590                                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, true);
 591
 592        return 0;
 593}
 594
 595static int cz_smu_construct_toc_for_clock_table(struct pp_smumgr *smumgr)
 596{
 597        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 598
 599        cz_smu->toc_entry_clock_table = cz_smu->toc_entry_used_count;
 600
 601        cz_smu_populate_single_scratch_task(smumgr,
 602                                CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
 603                                TASK_TYPE_INITIALIZE, true);
 604
 605        return 0;
 606}
 607
 608static int cz_smu_construct_toc(struct pp_smumgr *smumgr)
 609{
 610        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 611
 612        cz_smu->toc_entry_used_count = 0;
 613
 614        cz_smu_initialize_toc_empty_job_list(smumgr);
 615
 616        cz_smu_construct_toc_for_rlc_aram_save(smumgr);
 617
 618        cz_smu_construct_toc_for_vddgfx_enter(smumgr);
 619
 620        cz_smu_construct_toc_for_vddgfx_exit(smumgr);
 621
 622        cz_smu_construct_toc_for_power_profiling(smumgr);
 623
 624        cz_smu_construct_toc_for_bootup(smumgr);
 625
 626        cz_smu_construct_toc_for_clock_table(smumgr);
 627
 628        return 0;
 629}
 630
 631static int cz_smu_populate_firmware_entries(struct pp_smumgr *smumgr)
 632{
 633        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 634        uint32_t firmware_type;
 635        uint32_t i;
 636        int ret;
 637        enum cgs_ucode_id ucode_id;
 638        struct cgs_firmware_info info = {0};
 639
 640        cz_smu->driver_buffer_length = 0;
 641
 642        for (i = 0; i < ARRAY_SIZE(firmware_list); i++) {
 643
 644                firmware_type = cz_translate_firmware_enum_to_arg(smumgr,
 645                                        firmware_list[i]);
 646
 647                ucode_id = cz_convert_fw_type_to_cgs(firmware_type);
 648
 649                ret = cgs_get_firmware_info(smumgr->device,
 650                                                        ucode_id, &info);
 651
 652                if (ret == 0) {
 653                        cz_smu->driver_buffer[i].mc_addr_high =
 654                                        smu_upper_32_bits(info.mc_addr);
 655
 656                        cz_smu->driver_buffer[i].mc_addr_low =
 657                                        smu_lower_32_bits(info.mc_addr);
 658
 659                        cz_smu->driver_buffer[i].data_size = info.image_size;
 660
 661                        cz_smu->driver_buffer[i].firmware_ID = firmware_list[i];
 662                        cz_smu->driver_buffer_length++;
 663                }
 664        }
 665
 666        return 0;
 667}
 668
 669static int cz_smu_populate_single_scratch_entry(
 670                                struct pp_smumgr *smumgr,
 671                                enum cz_scratch_entry scratch_type,
 672                                uint32_t ulsize_byte,
 673                                struct cz_buffer_entry *entry)
 674{
 675        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 676        long long mc_addr =
 677                        ((long long)(cz_smu->smu_buffer.mc_addr_high) << 32)
 678                        | cz_smu->smu_buffer.mc_addr_low;
 679
 680        uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte);
 681
 682        mc_addr += cz_smu->smu_buffer_used_bytes;
 683
 684        entry->data_size = ulsize_byte;
 685        entry->kaddr = (char *) cz_smu->smu_buffer.kaddr +
 686                                cz_smu->smu_buffer_used_bytes;
 687        entry->mc_addr_low = smu_lower_32_bits(mc_addr);
 688        entry->mc_addr_high = smu_upper_32_bits(mc_addr);
 689        entry->firmware_ID = scratch_type;
 690
 691        cz_smu->smu_buffer_used_bytes += ulsize_aligned;
 692
 693        return 0;
 694}
 695
 696static int cz_download_pptable_settings(struct pp_smumgr *smumgr, void **table)
 697{
 698        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 699        unsigned long i;
 700
 701        for (i = 0; i < cz_smu->scratch_buffer_length; i++) {
 702                if (cz_smu->scratch_buffer[i].firmware_ID
 703                        == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
 704                        break;
 705        }
 706
 707        *table = (struct SMU8_Fusion_ClkTable *)cz_smu->scratch_buffer[i].kaddr;
 708
 709        cz_send_msg_to_smc_with_parameter(smumgr,
 710                                PPSMC_MSG_SetClkTableAddrHi,
 711                                cz_smu->scratch_buffer[i].mc_addr_high);
 712
 713        cz_send_msg_to_smc_with_parameter(smumgr,
 714                                PPSMC_MSG_SetClkTableAddrLo,
 715                                cz_smu->scratch_buffer[i].mc_addr_low);
 716
 717        cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
 718                                cz_smu->toc_entry_clock_table);
 719
 720        cz_send_msg_to_smc(smumgr, PPSMC_MSG_ClkTableXferToDram);
 721
 722        return 0;
 723}
 724
 725static int cz_upload_pptable_settings(struct pp_smumgr *smumgr)
 726{
 727        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 728        unsigned long i;
 729
 730        for (i = 0; i < cz_smu->scratch_buffer_length; i++) {
 731                if (cz_smu->scratch_buffer[i].firmware_ID
 732                                == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
 733                        break;
 734        }
 735
 736        cz_send_msg_to_smc_with_parameter(smumgr,
 737                                PPSMC_MSG_SetClkTableAddrHi,
 738                                cz_smu->scratch_buffer[i].mc_addr_high);
 739
 740        cz_send_msg_to_smc_with_parameter(smumgr,
 741                                PPSMC_MSG_SetClkTableAddrLo,
 742                                cz_smu->scratch_buffer[i].mc_addr_low);
 743
 744        cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
 745                                cz_smu->toc_entry_clock_table);
 746
 747        cz_send_msg_to_smc(smumgr, PPSMC_MSG_ClkTableXferToSmu);
 748
 749        return 0;
 750}
 751
 752static int cz_smu_init(struct pp_smumgr *smumgr)
 753{
 754        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 755        uint64_t mc_addr = 0;
 756        int ret = 0;
 757
 758        cz_smu->toc_buffer.data_size = 4096;
 759        cz_smu->smu_buffer.data_size =
 760                ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) +
 761                ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) +
 762                ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) +
 763                ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) +
 764                ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32);
 765
 766        ret = smu_allocate_memory(smumgr->device,
 767                                cz_smu->toc_buffer.data_size,
 768                                CGS_GPU_MEM_TYPE__GART_CACHEABLE,
 769                                PAGE_SIZE,
 770                                &mc_addr,
 771                                &cz_smu->toc_buffer.kaddr,
 772                                &cz_smu->toc_buffer.handle);
 773        if (ret != 0)
 774                return -1;
 775
 776        cz_smu->toc_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
 777        cz_smu->toc_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
 778
 779        ret = smu_allocate_memory(smumgr->device,
 780                                cz_smu->smu_buffer.data_size,
 781                                CGS_GPU_MEM_TYPE__GART_CACHEABLE,
 782                                PAGE_SIZE,
 783                                &mc_addr,
 784                                &cz_smu->smu_buffer.kaddr,
 785                                &cz_smu->smu_buffer.handle);
 786        if (ret != 0)
 787                return -1;
 788
 789        cz_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
 790        cz_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
 791
 792        cz_smu_populate_firmware_entries(smumgr);
 793        if (0 != cz_smu_populate_single_scratch_entry(smumgr,
 794                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
 795                UCODE_ID_RLC_SCRATCH_SIZE_BYTE,
 796                &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
 797                printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
 798                return -1;
 799        }
 800
 801        if (0 != cz_smu_populate_single_scratch_entry(smumgr,
 802                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
 803                UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE,
 804                &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
 805                printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
 806                return -1;
 807        }
 808        if (0 != cz_smu_populate_single_scratch_entry(smumgr,
 809                CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
 810                UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE,
 811                &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
 812                printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
 813                return -1;
 814        }
 815
 816        if (0 != cz_smu_populate_single_scratch_entry(smumgr,
 817                CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
 818                sizeof(struct SMU8_MultimediaPowerLogData),
 819                &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
 820                printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
 821                return -1;
 822        }
 823
 824        if (0 != cz_smu_populate_single_scratch_entry(smumgr,
 825                CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
 826                sizeof(struct SMU8_Fusion_ClkTable),
 827                &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
 828                printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
 829                return -1;
 830        }
 831        cz_smu_construct_toc(smumgr);
 832
 833        return 0;
 834}
 835
 836static int cz_smu_fini(struct pp_smumgr *smumgr)
 837{
 838        struct cz_smumgr *cz_smu;
 839
 840        if (smumgr == NULL || smumgr->device == NULL)
 841                return -EINVAL;
 842
 843        cz_smu = (struct cz_smumgr *)smumgr->backend;
 844        if (cz_smu) {
 845                cgs_free_gpu_mem(smumgr->device,
 846                                cz_smu->toc_buffer.handle);
 847                cgs_free_gpu_mem(smumgr->device,
 848                                cz_smu->smu_buffer.handle);
 849                kfree(cz_smu);
 850                kfree(smumgr);
 851        }
 852
 853        return 0;
 854}
 855
 856static const struct pp_smumgr_func cz_smu_funcs = {
 857        .smu_init = cz_smu_init,
 858        .smu_fini = cz_smu_fini,
 859        .start_smu = cz_start_smu,
 860        .check_fw_load_finish = cz_check_fw_load_finish,
 861        .request_smu_load_fw = NULL,
 862        .request_smu_load_specific_fw = NULL,
 863        .get_argument = cz_smum_get_argument,
 864        .send_msg_to_smc = cz_send_msg_to_smc,
 865        .send_msg_to_smc_with_parameter = cz_send_msg_to_smc_with_parameter,
 866        .download_pptable_settings = cz_download_pptable_settings,
 867        .upload_pptable_settings = cz_upload_pptable_settings,
 868};
 869
 870int cz_smum_init(struct pp_smumgr *smumgr)
 871{
 872        struct cz_smumgr *cz_smu;
 873
 874        cz_smu = kzalloc(sizeof(struct cz_smumgr), GFP_KERNEL);
 875        if (cz_smu == NULL)
 876                return -ENOMEM;
 877
 878        smumgr->backend = cz_smu;
 879        smumgr->smumgr_funcs = &cz_smu_funcs;
 880        return 0;
 881}
 882