drm/amd/powerplay: drop unneeded newline
[linux-2.6-block.git] / drivers / gpu / drm / amd / powerplay / smumgr / fiji_smumgr.c
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
24 #include "pp_debug.h"
25 #include "smumgr.h"
26 #include "smu7_dyn_defaults.h"
27 #include "smu73.h"
28 #include "smu_ucode_xfer_vi.h"
29 #include "fiji_smumgr.h"
30 #include "fiji_ppsmc.h"
31 #include "smu73_discrete.h"
32 #include "ppatomctrl.h"
33 #include "smu/smu_7_1_3_d.h"
34 #include "smu/smu_7_1_3_sh_mask.h"
35 #include "gmc/gmc_8_1_d.h"
36 #include "gmc/gmc_8_1_sh_mask.h"
37 #include "oss/oss_3_0_d.h"
38 #include "gca/gfx_8_0_d.h"
39 #include "bif/bif_5_0_d.h"
40 #include "bif/bif_5_0_sh_mask.h"
41 #include "dce/dce_10_0_d.h"
42 #include "dce/dce_10_0_sh_mask.h"
43 #include "hardwaremanager.h"
44 #include "cgs_common.h"
45 #include "atombios.h"
46 #include "pppcielanes.h"
47 #include "hwmgr.h"
48 #include "smu7_hwmgr.h"
49
50
51 #define AVFS_EN_MSB                                        1568
52 #define AVFS_EN_LSB                                        1568
53
54 #define FIJI_SMC_SIZE 0x20000
55
56 #define VOLTAGE_SCALE 4
57 #define POWERTUNE_DEFAULT_SET_MAX    1
58 #define VOLTAGE_VID_OFFSET_SCALE1   625
59 #define VOLTAGE_VID_OFFSET_SCALE2   100
60 #define VDDC_VDDCI_DELTA            300
61 #define MC_CG_ARB_FREQ_F1           0x0b
62
63 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
64  * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
65  */
66 static const uint16_t fiji_clock_stretcher_lookup_table[2][4] = {
67                                 {600, 1050, 3, 0}, {600, 1050, 6, 1} };
68
69 /* [FF, SS] type, [] 4 voltage ranges, and
70  * [Floor Freq, Boundary Freq, VID min , VID max]
71  */
72 static const uint32_t fiji_clock_stretcher_ddt_table[2][4][4] = {
73         { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
74         { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
75
76 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
77  * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
78  */
79 static const uint8_t fiji_clock_stretch_amount_conversion[2][6] = {
80                                 {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
81
82 static const struct fiji_pt_defaults fiji_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
83                 /*sviLoadLIneEn,  SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
84                 {1,               0xF,             0xFD,
85                 /* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
86                 0x19,        5,               45}
87 };
88
89 static const struct SMU73_Discrete_GraphicsLevel avfs_graphics_level[8] = {
90                 /*  Min        Sclk       pcie     DeepSleep Activity  CgSpll      CgSpll    spllSpread  SpllSpread   CcPwr  CcPwr  Sclk   Display     Enabled     Enabled                       Voltage    Power */
91                 /* Voltage,  Frequency,  DpmLevel,  DivId,    Level,  FuncCntl3,  FuncCntl4,  Spectrum,   Spectrum2,  DynRm, DynRm1  Did, Watermark, ForActivity, ForThrottle, UpHyst, DownHyst, DownHyst, Throttle */
92                 { 0x3c0fd047, 0x30750000,   0x00,     0x03,   0x1e00, 0x00200410, 0x87020000, 0x21680000, 0x0c000000,   0,      0,   0x16,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
93                 { 0xa00fd047, 0x409c0000,   0x01,     0x04,   0x1e00, 0x00800510, 0x87020000, 0x21680000, 0x11000000,   0,      0,   0x16,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
94                 { 0x0410d047, 0x50c30000,   0x01,     0x00,   0x1e00, 0x00600410, 0x87020000, 0x21680000, 0x0d000000,   0,      0,   0x0e,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
95                 { 0x6810d047, 0x60ea0000,   0x01,     0x00,   0x1e00, 0x00800410, 0x87020000, 0x21680000, 0x0e000000,   0,      0,   0x0c,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
96                 { 0xcc10d047, 0xe8fd0000,   0x01,     0x00,   0x1e00, 0x00e00410, 0x87020000, 0x21680000, 0x0f000000,   0,      0,   0x0c,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
97                 { 0x3011d047, 0x70110100,   0x01,     0x00,   0x1e00, 0x00400510, 0x87020000, 0x21680000, 0x10000000,   0,      0,   0x0c,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
98                 { 0x9411d047, 0xf8240100,   0x01,     0x00,   0x1e00, 0x00a00510, 0x87020000, 0x21680000, 0x11000000,   0,      0,   0x0c,   0x00,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 },
99                 { 0xf811d047, 0x80380100,   0x01,     0x00,   0x1e00, 0x00000610, 0x87020000, 0x21680000, 0x12000000,   0,      0,   0x0c,   0x01,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 }
100 };
101
102 static int fiji_start_smu_in_protection_mode(struct pp_hwmgr *hwmgr)
103 {
104         int result = 0;
105
106         /* Wait for smc boot up */
107         /* PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
108                 RCU_UC_EVENTS, boot_seq_done, 0); */
109
110         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
111                         SMC_SYSCON_RESET_CNTL, rst_reg, 1);
112
113         result = smu7_upload_smu_firmware_image(hwmgr);
114         if (result)
115                 return result;
116
117         /* Clear status */
118         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
119                         ixSMU_STATUS, 0);
120
121         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
122                         SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
123
124         /* De-assert reset */
125         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
126                         SMC_SYSCON_RESET_CNTL, rst_reg, 0);
127
128         /* Wait for ROM firmware to initialize interrupt hendler */
129         /*SMUM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, SMC_IND,
130                         SMC_INTR_CNTL_MASK_0, 0x10040, 0xFFFFFFFF); */
131
132         /* Set SMU Auto Start */
133         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
134                         SMU_INPUT_DATA, AUTO_START, 1);
135
136         /* Clear firmware interrupt enable flag */
137         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
138                         ixFIRMWARE_FLAGS, 0);
139
140         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND, RCU_UC_EVENTS,
141                         INTERRUPTS_ENABLED, 1);
142
143         cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, 0x20000);
144         cgs_write_register(hwmgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
145         PHM_WAIT_FIELD_UNEQUAL(hwmgr, SMC_RESP_0, SMC_RESP, 0);
146
147         /* Wait for done bit to be set */
148         PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
149                         SMU_STATUS, SMU_DONE, 0);
150
151         /* Check pass/failed indicator */
152         if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
153                         SMU_STATUS, SMU_PASS) != 1) {
154                 PP_ASSERT_WITH_CODE(false,
155                                 "SMU Firmware start failed!", return -1);
156         }
157
158         /* Wait for firmware to initialize */
159         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND,
160                         FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
161
162         return result;
163 }
164
165 static int fiji_start_smu_in_non_protection_mode(struct pp_hwmgr *hwmgr)
166 {
167         int result = 0;
168
169         /* wait for smc boot up */
170         PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
171                         RCU_UC_EVENTS, boot_seq_done, 0);
172
173         /* Clear firmware interrupt enable flag */
174         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
175                         ixFIRMWARE_FLAGS, 0);
176
177         /* Assert reset */
178         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
179                         SMC_SYSCON_RESET_CNTL, rst_reg, 1);
180
181         result = smu7_upload_smu_firmware_image(hwmgr);
182         if (result)
183                 return result;
184
185         /* Set smc instruct start point at 0x0 */
186         smu7_program_jump_on_start(hwmgr);
187
188         /* Enable clock */
189         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
190                         SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
191
192         /* De-assert reset */
193         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
194                         SMC_SYSCON_RESET_CNTL, rst_reg, 0);
195
196         /* Wait for firmware to initialize */
197         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND,
198                         FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
199
200         return result;
201 }
202
203 static int fiji_start_avfs_btc(struct pp_hwmgr *hwmgr)
204 {
205         int result = 0;
206         struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend);
207
208         if (0 != smu_data->avfs.avfs_btc_param) {
209                 if (0 != smu7_send_msg_to_smc_with_parameter(hwmgr,
210                                 PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) {
211                         pr_info("[AVFS][Fiji_PerformBtc] PerformBTC SMU msg failed");
212                         result = -EINVAL;
213                 }
214         }
215         /* Soft-Reset to reset the engine before loading uCode */
216          /* halt */
217         cgs_write_register(hwmgr->device, mmCP_MEC_CNTL, 0x50000000);
218         /* reset everything */
219         cgs_write_register(hwmgr->device, mmGRBM_SOFT_RESET, 0xffffffff);
220         /* clear reset */
221         cgs_write_register(hwmgr->device, mmGRBM_SOFT_RESET, 0);
222
223         return result;
224 }
225
226 static int fiji_setup_graphics_level_structure(struct pp_hwmgr *hwmgr)
227 {
228         int32_t vr_config;
229         uint32_t table_start;
230         uint32_t level_addr, vr_config_addr;
231         uint32_t level_size = sizeof(avfs_graphics_level);
232
233         PP_ASSERT_WITH_CODE(0 == smu7_read_smc_sram_dword(hwmgr,
234                         SMU7_FIRMWARE_HEADER_LOCATION +
235                         offsetof(SMU73_Firmware_Header, DpmTable),
236                         &table_start, 0x40000),
237                         "[AVFS][Fiji_SetupGfxLvlStruct] SMU could not "
238                         "communicate starting address of DPM table",
239                         return -1;);
240
241         /* Default value for vr_config =
242          * VR_MERGED_WITH_VDDC + VR_STATIC_VOLTAGE(VDDCI) */
243         vr_config = 0x01000500;   /* Real value:0x50001 */
244
245         vr_config_addr = table_start +
246                         offsetof(SMU73_Discrete_DpmTable, VRConfig);
247
248         PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(hwmgr, vr_config_addr,
249                         (uint8_t *)&vr_config, sizeof(int32_t), 0x40000),
250                         "[AVFS][Fiji_SetupGfxLvlStruct] Problems copying "
251                         "vr_config value over to SMC",
252                         return -1;);
253
254         level_addr = table_start + offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
255
256         PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(hwmgr, level_addr,
257                         (uint8_t *)(&avfs_graphics_level), level_size, 0x40000),
258                         "[AVFS][Fiji_SetupGfxLvlStruct] Copying of DPM table failed!",
259                         return -1;);
260
261         return 0;
262 }
263
264 static int fiji_avfs_event_mgr(struct pp_hwmgr *hwmgr, bool smu_started)
265 {
266         struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend);
267
268         switch (smu_data->avfs.avfs_btc_status) {
269         case AVFS_BTC_COMPLETED_PREVIOUSLY:
270                 break;
271
272         case AVFS_BTC_BOOT: /*Cold Boot State - Post SMU Start*/
273                 if (!smu_started)
274                         break;
275                 smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED;
276                 PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(hwmgr),
277                                 "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level"
278                                 " table over to SMU",
279                                 return -EINVAL;);
280                 smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL;
281                 PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr),
282                                 "[AVFS][fiji_avfs_event_mgr] Could not setup "
283                                 "Pwr Virus for AVFS ",
284                                 return -EINVAL;);
285                 smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED;
286                 PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(hwmgr),
287                                 "[AVFS][fiji_avfs_event_mgr] Failure at "
288                                 "fiji_start_avfs_btc. AVFS Disabled",
289                                 return -EINVAL;);
290
291                 smu_data->avfs.avfs_btc_status = AVFS_BTC_ENABLEAVFS;
292                 break;
293         case AVFS_BTC_DISABLED: /* Do nothing */
294         case AVFS_BTC_NOTSUPPORTED: /* Do nothing */
295         case AVFS_BTC_ENABLEAVFS:
296                 break;
297         default:
298                 pr_err("AVFS failed status is %x !\n", smu_data->avfs.avfs_btc_status);
299                 break;
300         }
301         return 0;
302 }
303
304 static int fiji_start_smu(struct pp_hwmgr *hwmgr)
305 {
306         int result = 0;
307         struct fiji_smumgr *priv = (struct fiji_smumgr *)(hwmgr->smu_backend);
308
309         /* Only start SMC if SMC RAM is not running */
310         if (!(smu7_is_smc_ram_running(hwmgr)
311                 || cgs_is_virtualization_enabled(hwmgr->device))) {
312                 fiji_avfs_event_mgr(hwmgr, false);
313
314                 /* Check if SMU is running in protected mode */
315                 if (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
316                                 CGS_IND_REG__SMC,
317                                 SMU_FIRMWARE, SMU_MODE)) {
318                         result = fiji_start_smu_in_non_protection_mode(hwmgr);
319                         if (result)
320                                 return result;
321                 } else {
322                         result = fiji_start_smu_in_protection_mode(hwmgr);
323                         if (result)
324                                 return result;
325                 }
326                 fiji_avfs_event_mgr(hwmgr, true);
327         }
328
329         /* To initialize all clock gating before RLC loaded and running.*/
330         cgs_set_clockgating_state(hwmgr->device,
331                         AMD_IP_BLOCK_TYPE_GFX, AMD_CG_STATE_GATE);
332         cgs_set_clockgating_state(hwmgr->device,
333                         AMD_IP_BLOCK_TYPE_GMC, AMD_CG_STATE_GATE);
334         cgs_set_clockgating_state(hwmgr->device,
335                         AMD_IP_BLOCK_TYPE_SDMA, AMD_CG_STATE_GATE);
336         cgs_set_clockgating_state(hwmgr->device,
337                         AMD_IP_BLOCK_TYPE_COMMON, AMD_CG_STATE_GATE);
338
339         /* Setup SoftRegsStart here for register lookup in case
340          * DummyBackEnd is used and ProcessFirmwareHeader is not executed
341          */
342         smu7_read_smc_sram_dword(hwmgr,
343                         SMU7_FIRMWARE_HEADER_LOCATION +
344                         offsetof(SMU73_Firmware_Header, SoftRegisters),
345                         &(priv->smu7_data.soft_regs_start), 0x40000);
346
347         result = smu7_request_smu_load_fw(hwmgr);
348
349         return result;
350 }
351
352 static bool fiji_is_hw_avfs_present(struct pp_hwmgr *hwmgr)
353 {
354
355         uint32_t efuse = 0;
356         uint32_t mask = (1 << ((AVFS_EN_MSB - AVFS_EN_LSB) + 1)) - 1;
357
358         if (cgs_is_virtualization_enabled(hwmgr->device))
359                 return 0;
360
361         if (!atomctrl_read_efuse(hwmgr->device, AVFS_EN_LSB, AVFS_EN_MSB,
362                         mask, &efuse)) {
363                 if (efuse)
364                         return true;
365         }
366         return false;
367 }
368
369 static int fiji_smu_init(struct pp_hwmgr *hwmgr)
370 {
371         int i;
372         struct fiji_smumgr *fiji_priv = NULL;
373
374         fiji_priv = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL);
375
376         if (fiji_priv == NULL)
377                 return -ENOMEM;
378
379         hwmgr->smu_backend = fiji_priv;
380
381         if (smu7_init(hwmgr))
382                 return -EINVAL;
383
384         for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
385                 fiji_priv->activity_target[i] = 30;
386
387         return 0;
388 }
389
390 static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
391                 struct phm_ppt_v1_clock_voltage_dependency_table *dep_table,
392                 uint32_t clock, uint32_t *voltage, uint32_t *mvdd)
393 {
394         uint32_t i;
395         uint16_t vddci;
396         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
397         *voltage = *mvdd = 0;
398
399
400         /* clock - voltage dependency table is empty table */
401         if (dep_table->count == 0)
402                 return -EINVAL;
403
404         for (i = 0; i < dep_table->count; i++) {
405                 /* find first sclk bigger than request */
406                 if (dep_table->entries[i].clk >= clock) {
407                         *voltage |= (dep_table->entries[i].vddc *
408                                         VOLTAGE_SCALE) << VDDC_SHIFT;
409                         if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
410                                 *voltage |= (data->vbios_boot_state.vddci_bootup_value *
411                                                 VOLTAGE_SCALE) << VDDCI_SHIFT;
412                         else if (dep_table->entries[i].vddci)
413                                 *voltage |= (dep_table->entries[i].vddci *
414                                                 VOLTAGE_SCALE) << VDDCI_SHIFT;
415                         else {
416                                 vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
417                                                 (dep_table->entries[i].vddc -
418                                                                 VDDC_VDDCI_DELTA));
419                                 *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
420                         }
421
422                         if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control)
423                                 *mvdd = data->vbios_boot_state.mvdd_bootup_value *
424                                         VOLTAGE_SCALE;
425                         else if (dep_table->entries[i].mvdd)
426                                 *mvdd = (uint32_t) dep_table->entries[i].mvdd *
427                                         VOLTAGE_SCALE;
428
429                         *voltage |= 1 << PHASES_SHIFT;
430                         return 0;
431                 }
432         }
433
434         /* sclk is bigger than max sclk in the dependence table */
435         *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
436
437         if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
438                 *voltage |= (data->vbios_boot_state.vddci_bootup_value *
439                                 VOLTAGE_SCALE) << VDDCI_SHIFT;
440         else if (dep_table->entries[i-1].vddci) {
441                 vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
442                                 (dep_table->entries[i].vddc -
443                                                 VDDC_VDDCI_DELTA));
444                 *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
445         }
446
447         if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control)
448                 *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
449         else if (dep_table->entries[i].mvdd)
450                 *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
451
452         return 0;
453 }
454
455
456 static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
457 {
458         uint32_t tmp;
459         tmp = raw_setting * 4096 / 100;
460         return (uint16_t)tmp;
461 }
462
463 static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t *sda)
464 {
465         switch (line) {
466         case SMU7_I2CLineID_DDC1:
467                 *scl = SMU7_I2C_DDC1CLK;
468                 *sda = SMU7_I2C_DDC1DATA;
469                 break;
470         case SMU7_I2CLineID_DDC2:
471                 *scl = SMU7_I2C_DDC2CLK;
472                 *sda = SMU7_I2C_DDC2DATA;
473                 break;
474         case SMU7_I2CLineID_DDC3:
475                 *scl = SMU7_I2C_DDC3CLK;
476                 *sda = SMU7_I2C_DDC3DATA;
477                 break;
478         case SMU7_I2CLineID_DDC4:
479                 *scl = SMU7_I2C_DDC4CLK;
480                 *sda = SMU7_I2C_DDC4DATA;
481                 break;
482         case SMU7_I2CLineID_DDC5:
483                 *scl = SMU7_I2C_DDC5CLK;
484                 *sda = SMU7_I2C_DDC5DATA;
485                 break;
486         case SMU7_I2CLineID_DDC6:
487                 *scl = SMU7_I2C_DDC6CLK;
488                 *sda = SMU7_I2C_DDC6DATA;
489                 break;
490         case SMU7_I2CLineID_SCLSDA:
491                 *scl = SMU7_I2C_SCL;
492                 *sda = SMU7_I2C_SDA;
493                 break;
494         case SMU7_I2CLineID_DDCVGA:
495                 *scl = SMU7_I2C_DDCVGACLK;
496                 *sda = SMU7_I2C_DDCVGADATA;
497                 break;
498         default:
499                 *scl = 0;
500                 *sda = 0;
501                 break;
502         }
503 }
504
505 static void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
506 {
507         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
508         struct phm_ppt_v1_information *table_info =
509                         (struct  phm_ppt_v1_information *)(hwmgr->pptable);
510
511         if (table_info &&
512                         table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
513                         table_info->cac_dtp_table->usPowerTuneDataSetID)
514                 smu_data->power_tune_defaults =
515                                 &fiji_power_tune_data_set_array
516                                 [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
517         else
518                 smu_data->power_tune_defaults = &fiji_power_tune_data_set_array[0];
519
520 }
521
522 static int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
523 {
524
525         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
526         const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults;
527
528         SMU73_Discrete_DpmTable  *dpm_table = &(smu_data->smc_state_table);
529
530         struct phm_ppt_v1_information *table_info =
531                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
532         struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
533         struct pp_advance_fan_control_parameters *fan_table =
534                         &hwmgr->thermal_controller.advanceFanControlParameters;
535         uint8_t uc_scl, uc_sda;
536
537         /* TDP number of fraction bits are changed from 8 to 7 for Fiji
538          * as requested by SMC team
539          */
540         dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
541                         (uint16_t)(cac_dtp_table->usTDP * 128));
542         dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
543                         (uint16_t)(cac_dtp_table->usTDP * 128));
544
545         PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
546                         "Target Operating Temp is out of Range!",
547                         );
548
549         dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
550         dpm_table->GpuTjHyst = 8;
551
552         dpm_table->DTEAmbientTempBase = defaults->DTEAmbientTempBase;
553
554         /* The following are for new Fiji Multi-input fan/thermal control */
555         dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
556                         cac_dtp_table->usTargetOperatingTemp * 256);
557         dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
558                         cac_dtp_table->usTemperatureLimitHotspot * 256);
559         dpm_table->TemperatureLimitLiquid1 = PP_HOST_TO_SMC_US(
560                         cac_dtp_table->usTemperatureLimitLiquid1 * 256);
561         dpm_table->TemperatureLimitLiquid2 = PP_HOST_TO_SMC_US(
562                         cac_dtp_table->usTemperatureLimitLiquid2 * 256);
563         dpm_table->TemperatureLimitVrVddc = PP_HOST_TO_SMC_US(
564                         cac_dtp_table->usTemperatureLimitVrVddc * 256);
565         dpm_table->TemperatureLimitVrMvdd = PP_HOST_TO_SMC_US(
566                         cac_dtp_table->usTemperatureLimitVrMvdd * 256);
567         dpm_table->TemperatureLimitPlx = PP_HOST_TO_SMC_US(
568                         cac_dtp_table->usTemperatureLimitPlx * 256);
569
570         dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
571                         scale_fan_gain_settings(fan_table->usFanGainEdge));
572         dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
573                         scale_fan_gain_settings(fan_table->usFanGainHotspot));
574         dpm_table->FanGainLiquid = PP_HOST_TO_SMC_US(
575                         scale_fan_gain_settings(fan_table->usFanGainLiquid));
576         dpm_table->FanGainVrVddc = PP_HOST_TO_SMC_US(
577                         scale_fan_gain_settings(fan_table->usFanGainVrVddc));
578         dpm_table->FanGainVrMvdd = PP_HOST_TO_SMC_US(
579                         scale_fan_gain_settings(fan_table->usFanGainVrMvdd));
580         dpm_table->FanGainPlx = PP_HOST_TO_SMC_US(
581                         scale_fan_gain_settings(fan_table->usFanGainPlx));
582         dpm_table->FanGainHbm = PP_HOST_TO_SMC_US(
583                         scale_fan_gain_settings(fan_table->usFanGainHbm));
584
585         dpm_table->Liquid1_I2C_address = cac_dtp_table->ucLiquid1_I2C_address;
586         dpm_table->Liquid2_I2C_address = cac_dtp_table->ucLiquid2_I2C_address;
587         dpm_table->Vr_I2C_address = cac_dtp_table->ucVr_I2C_address;
588         dpm_table->Plx_I2C_address = cac_dtp_table->ucPlx_I2C_address;
589
590         get_scl_sda_value(cac_dtp_table->ucLiquid_I2C_Line, &uc_scl, &uc_sda);
591         dpm_table->Liquid_I2C_LineSCL = uc_scl;
592         dpm_table->Liquid_I2C_LineSDA = uc_sda;
593
594         get_scl_sda_value(cac_dtp_table->ucVr_I2C_Line, &uc_scl, &uc_sda);
595         dpm_table->Vr_I2C_LineSCL = uc_scl;
596         dpm_table->Vr_I2C_LineSDA = uc_sda;
597
598         get_scl_sda_value(cac_dtp_table->ucPlx_I2C_Line, &uc_scl, &uc_sda);
599         dpm_table->Plx_I2C_LineSCL = uc_scl;
600         dpm_table->Plx_I2C_LineSDA = uc_sda;
601
602         return 0;
603 }
604
605
606 static int fiji_populate_svi_load_line(struct pp_hwmgr *hwmgr)
607 {
608         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
609         const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults;
610
611         smu_data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
612         smu_data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
613         smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
614         smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
615
616         return 0;
617 }
618
619
620 static int fiji_populate_tdc_limit(struct pp_hwmgr *hwmgr)
621 {
622         uint16_t tdc_limit;
623         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
624         struct phm_ppt_v1_information *table_info =
625                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
626         const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults;
627
628         /* TDC number of fraction bits are changed from 8 to 7
629          * for Fiji as requested by SMC team
630          */
631         tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
632         smu_data->power_tune_table.TDC_VDDC_PkgLimit =
633                         CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
634         smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
635                         defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
636         smu_data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
637
638         return 0;
639 }
640
641 static int fiji_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
642 {
643         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
644         const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults;
645         uint32_t temp;
646
647         if (smu7_read_smc_sram_dword(hwmgr,
648                         fuse_table_offset +
649                         offsetof(SMU73_Discrete_PmFuses, TdcWaterfallCtl),
650                         (uint32_t *)&temp, SMC_RAM_END))
651                 PP_ASSERT_WITH_CODE(false,
652                                 "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
653                                 return -EINVAL);
654         else {
655                 smu_data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
656                 smu_data->power_tune_table.LPMLTemperatureMin =
657                                 (uint8_t)((temp >> 16) & 0xff);
658                 smu_data->power_tune_table.LPMLTemperatureMax =
659                                 (uint8_t)((temp >> 8) & 0xff);
660                 smu_data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
661         }
662         return 0;
663 }
664
665 static int fiji_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
666 {
667         int i;
668         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
669
670         /* Currently not used. Set all to zero. */
671         for (i = 0; i < 16; i++)
672                 smu_data->power_tune_table.LPMLTemperatureScaler[i] = 0;
673
674         return 0;
675 }
676
677 static int fiji_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
678 {
679         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
680
681         if ((hwmgr->thermal_controller.advanceFanControlParameters.
682                         usFanOutputSensitivity & (1 << 15)) ||
683                         0 == hwmgr->thermal_controller.advanceFanControlParameters.
684                         usFanOutputSensitivity)
685                 hwmgr->thermal_controller.advanceFanControlParameters.
686                 usFanOutputSensitivity = hwmgr->thermal_controller.
687                         advanceFanControlParameters.usDefaultFanOutputSensitivity;
688
689         smu_data->power_tune_table.FuzzyFan_PwmSetDelta =
690                         PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
691                                         advanceFanControlParameters.usFanOutputSensitivity);
692         return 0;
693 }
694
695 static int fiji_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
696 {
697         int i;
698         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
699
700         /* Currently not used. Set all to zero. */
701         for (i = 0; i < 16; i++)
702                 smu_data->power_tune_table.GnbLPML[i] = 0;
703
704         return 0;
705 }
706
707 static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
708 {
709         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
710         struct phm_ppt_v1_information *table_info =
711                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
712         uint16_t HiSidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
713         uint16_t LoSidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
714         struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
715
716         HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
717         LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
718
719         smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
720                         CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
721         smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
722                         CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
723
724         return 0;
725 }
726
727 static int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr)
728 {
729         uint32_t pm_fuse_table_offset;
730         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
731
732         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
733                         PHM_PlatformCaps_PowerContainment)) {
734                 if (smu7_read_smc_sram_dword(hwmgr,
735                                 SMU7_FIRMWARE_HEADER_LOCATION +
736                                 offsetof(SMU73_Firmware_Header, PmFuseTable),
737                                 &pm_fuse_table_offset, SMC_RAM_END))
738                         PP_ASSERT_WITH_CODE(false,
739                                         "Attempt to get pm_fuse_table_offset Failed!",
740                                         return -EINVAL);
741
742                 /* DW6 */
743                 if (fiji_populate_svi_load_line(hwmgr))
744                         PP_ASSERT_WITH_CODE(false,
745                                         "Attempt to populate SviLoadLine Failed!",
746                                         return -EINVAL);
747                 /* DW7 */
748                 if (fiji_populate_tdc_limit(hwmgr))
749                         PP_ASSERT_WITH_CODE(false,
750                                         "Attempt to populate TDCLimit Failed!", return -EINVAL);
751                 /* DW8 */
752                 if (fiji_populate_dw8(hwmgr, pm_fuse_table_offset))
753                         PP_ASSERT_WITH_CODE(false,
754                                         "Attempt to populate TdcWaterfallCtl, "
755                                         "LPMLTemperature Min and Max Failed!",
756                                         return -EINVAL);
757
758                 /* DW9-DW12 */
759                 if (0 != fiji_populate_temperature_scaler(hwmgr))
760                         PP_ASSERT_WITH_CODE(false,
761                                         "Attempt to populate LPMLTemperatureScaler Failed!",
762                                         return -EINVAL);
763
764                 /* DW13-DW14 */
765                 if (fiji_populate_fuzzy_fan(hwmgr))
766                         PP_ASSERT_WITH_CODE(false,
767                                         "Attempt to populate Fuzzy Fan Control parameters Failed!",
768                                         return -EINVAL);
769
770                 /* DW15-DW18 */
771                 if (fiji_populate_gnb_lpml(hwmgr))
772                         PP_ASSERT_WITH_CODE(false,
773                                         "Attempt to populate GnbLPML Failed!",
774                                         return -EINVAL);
775
776                 /* DW20 */
777                 if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr))
778                         PP_ASSERT_WITH_CODE(false,
779                                         "Attempt to populate BapmVddCBaseLeakage Hi and Lo "
780                                         "Sidd Failed!", return -EINVAL);
781
782                 if (smu7_copy_bytes_to_smc(hwmgr, pm_fuse_table_offset,
783                                 (uint8_t *)&smu_data->power_tune_table,
784                                 sizeof(struct SMU73_Discrete_PmFuses), SMC_RAM_END))
785                         PP_ASSERT_WITH_CODE(false,
786                                         "Attempt to download PmFuseTable Failed!",
787                                         return -EINVAL);
788         }
789         return 0;
790 }
791
792 static int fiji_populate_cac_table(struct pp_hwmgr *hwmgr,
793                 struct SMU73_Discrete_DpmTable *table)
794 {
795         uint32_t count;
796         uint8_t index;
797         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
798         struct phm_ppt_v1_information *table_info =
799                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
800         struct phm_ppt_v1_voltage_lookup_table *lookup_table =
801                         table_info->vddc_lookup_table;
802         /* tables is already swapped, so in order to use the value from it,
803          * we need to swap it back.
804          * We are populating vddc CAC data to BapmVddc table
805          * in split and merged mode
806          */
807
808         for (count = 0; count < lookup_table->count; count++) {
809                 index = phm_get_voltage_index(lookup_table,
810                                 data->vddc_voltage_table.entries[count].value);
811                 table->BapmVddcVidLoSidd[count] =
812                         convert_to_vid(lookup_table->entries[index].us_cac_low);
813                 table->BapmVddcVidHiSidd[count] =
814                         convert_to_vid(lookup_table->entries[index].us_cac_high);
815         }
816
817         return 0;
818 }
819
820 static int fiji_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
821                 struct SMU73_Discrete_DpmTable *table)
822 {
823         int result;
824
825         result = fiji_populate_cac_table(hwmgr, table);
826         PP_ASSERT_WITH_CODE(0 == result,
827                         "can not populate CAC voltage tables to SMC",
828                         return -EINVAL);
829
830         return 0;
831 }
832
833 static int fiji_populate_ulv_level(struct pp_hwmgr *hwmgr,
834                 struct SMU73_Discrete_Ulv *state)
835 {
836         int result = 0;
837
838         struct phm_ppt_v1_information *table_info =
839                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
840
841         state->CcPwrDynRm = 0;
842         state->CcPwrDynRm1 = 0;
843
844         state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
845         state->VddcOffsetVid = (uint8_t)(table_info->us_ulv_voltage_offset *
846                         VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
847
848         state->VddcPhase = 1;
849
850         if (!result) {
851                 CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
852                 CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
853                 CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
854         }
855         return result;
856 }
857
858 static int fiji_populate_ulv_state(struct pp_hwmgr *hwmgr,
859                 struct SMU73_Discrete_DpmTable *table)
860 {
861         return fiji_populate_ulv_level(hwmgr, &table->Ulv);
862 }
863
864 static int fiji_populate_smc_link_level(struct pp_hwmgr *hwmgr,
865                 struct SMU73_Discrete_DpmTable *table)
866 {
867         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
868         struct smu7_dpm_table *dpm_table = &data->dpm_table;
869         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
870         int i;
871
872         /* Index (dpm_table->pcie_speed_table.count)
873          * is reserved for PCIE boot level. */
874         for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
875                 table->LinkLevel[i].PcieGenSpeed  =
876                                 (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
877                 table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
878                                 dpm_table->pcie_speed_table.dpm_levels[i].param1);
879                 table->LinkLevel[i].EnabledForActivity = 1;
880                 table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
881                 table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
882                 table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
883         }
884
885         smu_data->smc_state_table.LinkLevelCount =
886                         (uint8_t)dpm_table->pcie_speed_table.count;
887         data->dpm_level_enable_mask.pcie_dpm_enable_mask =
888                         phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
889
890         return 0;
891 }
892
893 static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr,
894                 uint32_t clock, struct SMU73_Discrete_GraphicsLevel *sclk)
895 {
896         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
897         struct pp_atomctrl_clock_dividers_vi dividers;
898         uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
899         uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
900         uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
901         uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
902         uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
903         uint32_t ref_clock;
904         uint32_t ref_divider;
905         uint32_t fbdiv;
906         int result;
907
908         /* get the engine clock dividers for this clock value */
909         result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock,  &dividers);
910
911         PP_ASSERT_WITH_CODE(result == 0,
912                         "Error retrieving Engine Clock dividers from VBIOS.",
913                         return result);
914
915         /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
916         ref_clock = atomctrl_get_reference_clock(hwmgr);
917         ref_divider = 1 + dividers.uc_pll_ref_div;
918
919         /* low 14 bits is fraction and high 12 bits is divider */
920         fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
921
922         /* SPLL_FUNC_CNTL setup */
923         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
924                         SPLL_REF_DIV, dividers.uc_pll_ref_div);
925         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
926                         SPLL_PDIV_A,  dividers.uc_pll_post_div);
927
928         /* SPLL_FUNC_CNTL_3 setup*/
929         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
930                         SPLL_FB_DIV, fbdiv);
931
932         /* set to use fractional accumulation*/
933         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
934                         SPLL_DITHEN, 1);
935
936         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
937                                 PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
938                 struct pp_atomctrl_internal_ss_info ssInfo;
939
940                 uint32_t vco_freq = clock * dividers.uc_pll_post_div;
941                 if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
942                                 vco_freq, &ssInfo)) {
943                         /*
944                          * ss_info.speed_spectrum_percentage -- in unit of 0.01%
945                          * ss_info.speed_spectrum_rate -- in unit of khz
946                          *
947                          * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
948                          */
949                         uint32_t clk_s = ref_clock * 5 /
950                                         (ref_divider * ssInfo.speed_spectrum_rate);
951                         /* clkv = 2 * D * fbdiv / NS */
952                         uint32_t clk_v = 4 * ssInfo.speed_spectrum_percentage *
953                                         fbdiv / (clk_s * 10000);
954
955                         cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
956                                         CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
957                         cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
958                                         CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
959                         cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
960                                         CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
961                 }
962         }
963
964         sclk->SclkFrequency        = clock;
965         sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
966         sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
967         sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
968         sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
969         sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
970
971         return 0;
972 }
973
974 static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
975                 uint32_t clock, uint16_t sclk_al_threshold,
976                 struct SMU73_Discrete_GraphicsLevel *level)
977 {
978         int result;
979         /* PP_Clocks minClocks; */
980         uint32_t threshold, mvdd;
981         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
982         struct phm_ppt_v1_information *table_info =
983                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
984
985         result = fiji_calculate_sclk_params(hwmgr, clock, level);
986
987         /* populate graphics levels */
988         result = fiji_get_dependency_volt_by_clk(hwmgr,
989                         table_info->vdd_dep_on_sclk, clock,
990                         (uint32_t *)(&level->MinVoltage), &mvdd);
991         PP_ASSERT_WITH_CODE((0 == result),
992                         "can not find VDDC voltage value for "
993                         "VDDC engine clock dependency table",
994                         return result);
995
996         level->SclkFrequency = clock;
997         level->ActivityLevel = sclk_al_threshold;
998         level->CcPwrDynRm = 0;
999         level->CcPwrDynRm1 = 0;
1000         level->EnabledForActivity = 0;
1001         level->EnabledForThrottle = 1;
1002         level->UpHyst = 10;
1003         level->DownHyst = 0;
1004         level->VoltageDownHyst = 0;
1005         level->PowerThrottle = 0;
1006
1007         threshold = clock * data->fast_watermark_threshold / 100;
1008
1009         data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr;
1010
1011         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
1012                 level->DeepSleepDivId = smu7_get_sleep_divider_id_from_clock(clock,
1013                                                                 hwmgr->display_config.min_core_set_clock_in_sr);
1014
1015
1016         /* Default to slow, highest DPM level will be
1017          * set to PPSMC_DISPLAY_WATERMARK_LOW later.
1018          */
1019         level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1020
1021         CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
1022         CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
1023         CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
1024         CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
1025         CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
1026         CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
1027         CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
1028         CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
1029         CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
1030
1031         return 0;
1032 }
1033
1034 static int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
1035 {
1036         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1037         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
1038
1039         struct smu7_dpm_table *dpm_table = &data->dpm_table;
1040         struct phm_ppt_v1_information *table_info =
1041                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1042         struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
1043         uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count;
1044         int result = 0;
1045         uint32_t array = smu_data->smu7_data.dpm_table_start +
1046                         offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
1047         uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) *
1048                         SMU73_MAX_LEVELS_GRAPHICS;
1049         struct SMU73_Discrete_GraphicsLevel *levels =
1050                         smu_data->smc_state_table.GraphicsLevel;
1051         uint32_t i, max_entry;
1052         uint8_t hightest_pcie_level_enabled = 0,
1053                         lowest_pcie_level_enabled = 0,
1054                         mid_pcie_level_enabled = 0,
1055                         count = 0;
1056
1057         for (i = 0; i < dpm_table->sclk_table.count; i++) {
1058                 result = fiji_populate_single_graphic_level(hwmgr,
1059                                 dpm_table->sclk_table.dpm_levels[i].value,
1060                                 (uint16_t)smu_data->activity_target[i],
1061                                 &levels[i]);
1062                 if (result)
1063                         return result;
1064
1065                 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
1066                 if (i > 1)
1067                         levels[i].DeepSleepDivId = 0;
1068         }
1069
1070         /* Only enable level 0 for now.*/
1071         levels[0].EnabledForActivity = 1;
1072
1073         /* set highest level watermark to high */
1074         levels[dpm_table->sclk_table.count - 1].DisplayWatermark =
1075                         PPSMC_DISPLAY_WATERMARK_HIGH;
1076
1077         smu_data->smc_state_table.GraphicsDpmLevelCount =
1078                         (uint8_t)dpm_table->sclk_table.count;
1079         data->dpm_level_enable_mask.sclk_dpm_enable_mask =
1080                         phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
1081
1082         if (pcie_table != NULL) {
1083                 PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
1084                                 "There must be 1 or more PCIE levels defined in PPTable.",
1085                                 return -EINVAL);
1086                 max_entry = pcie_entry_cnt - 1;
1087                 for (i = 0; i < dpm_table->sclk_table.count; i++)
1088                         levels[i].pcieDpmLevel =
1089                                         (uint8_t) ((i < max_entry) ? i : max_entry);
1090         } else {
1091                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
1092                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
1093                                                 (1 << (hightest_pcie_level_enabled + 1))) != 0))
1094                         hightest_pcie_level_enabled++;
1095
1096                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
1097                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
1098                                                 (1 << lowest_pcie_level_enabled)) == 0))
1099                         lowest_pcie_level_enabled++;
1100
1101                 while ((count < hightest_pcie_level_enabled) &&
1102                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
1103                                                 (1 << (lowest_pcie_level_enabled + 1 + count))) == 0))
1104                         count++;
1105
1106                 mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1 + count) <
1107                                 hightest_pcie_level_enabled ?
1108                                                 (lowest_pcie_level_enabled + 1 + count) :
1109                                                 hightest_pcie_level_enabled;
1110
1111                 /* set pcieDpmLevel to hightest_pcie_level_enabled */
1112                 for (i = 2; i < dpm_table->sclk_table.count; i++)
1113                         levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
1114
1115                 /* set pcieDpmLevel to lowest_pcie_level_enabled */
1116                 levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
1117
1118                 /* set pcieDpmLevel to mid_pcie_level_enabled */
1119                 levels[1].pcieDpmLevel = mid_pcie_level_enabled;
1120         }
1121         /* level count will send to smc once at init smc table and never change */
1122         result = smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels,
1123                         (uint32_t)array_size, SMC_RAM_END);
1124
1125         return result;
1126 }
1127
1128
1129 /**
1130  * MCLK Frequency Ratio
1131  * SEQ_CG_RESP  Bit[31:24] - 0x0
1132  * Bit[27:24] \96 DDR3 Frequency ratio
1133  * 0x0 <= 100MHz,       450 < 0x8 <= 500MHz
1134  * 100 < 0x1 <= 150MHz,       500 < 0x9 <= 550MHz
1135  * 150 < 0x2 <= 200MHz,       550 < 0xA <= 600MHz
1136  * 200 < 0x3 <= 250MHz,       600 < 0xB <= 650MHz
1137  * 250 < 0x4 <= 300MHz,       650 < 0xC <= 700MHz
1138  * 300 < 0x5 <= 350MHz,       700 < 0xD <= 750MHz
1139  * 350 < 0x6 <= 400MHz,       750 < 0xE <= 800MHz
1140  * 400 < 0x7 <= 450MHz,       800 < 0xF
1141  */
1142 static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock)
1143 {
1144         if (mem_clock <= 10000)
1145                 return 0x0;
1146         if (mem_clock <= 15000)
1147                 return 0x1;
1148         if (mem_clock <= 20000)
1149                 return 0x2;
1150         if (mem_clock <= 25000)
1151                 return 0x3;
1152         if (mem_clock <= 30000)
1153                 return 0x4;
1154         if (mem_clock <= 35000)
1155                 return 0x5;
1156         if (mem_clock <= 40000)
1157                 return 0x6;
1158         if (mem_clock <= 45000)
1159                 return 0x7;
1160         if (mem_clock <= 50000)
1161                 return 0x8;
1162         if (mem_clock <= 55000)
1163                 return 0x9;
1164         if (mem_clock <= 60000)
1165                 return 0xa;
1166         if (mem_clock <= 65000)
1167                 return 0xb;
1168         if (mem_clock <= 70000)
1169                 return 0xc;
1170         if (mem_clock <= 75000)
1171                 return 0xd;
1172         if (mem_clock <= 80000)
1173                 return 0xe;
1174         /* mem_clock > 800MHz */
1175         return 0xf;
1176 }
1177
1178 static int fiji_calculate_mclk_params(struct pp_hwmgr *hwmgr,
1179     uint32_t clock, struct SMU73_Discrete_MemoryLevel *mclk)
1180 {
1181         struct pp_atomctrl_memory_clock_param mem_param;
1182         int result;
1183
1184         result = atomctrl_get_memory_pll_dividers_vi(hwmgr, clock, &mem_param);
1185         PP_ASSERT_WITH_CODE((0 == result),
1186                         "Failed to get Memory PLL Dividers.",
1187                         );
1188
1189         /* Save the result data to outpupt memory level structure */
1190         mclk->MclkFrequency   = clock;
1191         mclk->MclkDivider     = (uint8_t)mem_param.mpll_post_divider;
1192         mclk->FreqRange       = fiji_get_mclk_frequency_ratio(clock);
1193
1194         return result;
1195 }
1196
1197 static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr,
1198                 uint32_t clock, struct SMU73_Discrete_MemoryLevel *mem_level)
1199 {
1200         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1201         struct phm_ppt_v1_information *table_info =
1202                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1203         int result = 0;
1204         uint32_t mclk_stutter_mode_threshold = 60000;
1205
1206         if (table_info->vdd_dep_on_mclk) {
1207                 result = fiji_get_dependency_volt_by_clk(hwmgr,
1208                                 table_info->vdd_dep_on_mclk, clock,
1209                                 (uint32_t *)(&mem_level->MinVoltage), &mem_level->MinMvdd);
1210                 PP_ASSERT_WITH_CODE((0 == result),
1211                                 "can not find MinVddc voltage value from memory "
1212                                 "VDDC voltage dependency table", return result);
1213         }
1214
1215         mem_level->EnabledForThrottle = 1;
1216         mem_level->EnabledForActivity = 0;
1217         mem_level->UpHyst = 0;
1218         mem_level->DownHyst = 100;
1219         mem_level->VoltageDownHyst = 0;
1220         mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
1221         mem_level->StutterEnable = false;
1222
1223         mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1224
1225         /* enable stutter mode if all the follow condition applied
1226          * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
1227          * &(data->DisplayTiming.numExistingDisplays));
1228          */
1229         data->display_timing.num_existing_displays = 1;
1230
1231         if (mclk_stutter_mode_threshold &&
1232                 (clock <= mclk_stutter_mode_threshold) &&
1233                 (!data->is_uvd_enabled) &&
1234                 (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
1235                                 STUTTER_ENABLE) & 0x1))
1236                 mem_level->StutterEnable = true;
1237
1238         result = fiji_calculate_mclk_params(hwmgr, clock, mem_level);
1239         if (!result) {
1240                 CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
1241                 CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
1242                 CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
1243                 CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
1244         }
1245         return result;
1246 }
1247
1248 static int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
1249 {
1250         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1251         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
1252         struct smu7_dpm_table *dpm_table = &data->dpm_table;
1253         int result;
1254         /* populate MCLK dpm table to SMU7 */
1255         uint32_t array = smu_data->smu7_data.dpm_table_start +
1256                         offsetof(SMU73_Discrete_DpmTable, MemoryLevel);
1257         uint32_t array_size = sizeof(SMU73_Discrete_MemoryLevel) *
1258                         SMU73_MAX_LEVELS_MEMORY;
1259         struct SMU73_Discrete_MemoryLevel *levels =
1260                         smu_data->smc_state_table.MemoryLevel;
1261         uint32_t i;
1262
1263         for (i = 0; i < dpm_table->mclk_table.count; i++) {
1264                 PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
1265                                 "can not populate memory level as memory clock is zero",
1266                                 return -EINVAL);
1267                 result = fiji_populate_single_memory_level(hwmgr,
1268                                 dpm_table->mclk_table.dpm_levels[i].value,
1269                                 &levels[i]);
1270                 if (result)
1271                         return result;
1272         }
1273
1274         /* Only enable level 0 for now. */
1275         levels[0].EnabledForActivity = 1;
1276
1277         /* in order to prevent MC activity from stutter mode to push DPM up.
1278          * the UVD change complements this by putting the MCLK in
1279          * a higher state by default such that we are not effected by
1280          * up threshold or and MCLK DPM latency.
1281          */
1282         levels[0].ActivityLevel = (uint16_t)data->mclk_dpm0_activity_target;
1283         CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
1284
1285         smu_data->smc_state_table.MemoryDpmLevelCount =
1286                         (uint8_t)dpm_table->mclk_table.count;
1287         data->dpm_level_enable_mask.mclk_dpm_enable_mask =
1288                         phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
1289         /* set highest level watermark to high */
1290         levels[dpm_table->mclk_table.count - 1].DisplayWatermark =
1291                         PPSMC_DISPLAY_WATERMARK_HIGH;
1292
1293         /* level count will send to smc once at init smc table and never change */
1294         result = smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels,
1295                         (uint32_t)array_size, SMC_RAM_END);
1296
1297         return result;
1298 }
1299
1300 static int fiji_populate_mvdd_value(struct pp_hwmgr *hwmgr,
1301                 uint32_t mclk, SMIO_Pattern *smio_pat)
1302 {
1303         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1304         struct phm_ppt_v1_information *table_info =
1305                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1306         uint32_t i = 0;
1307
1308         if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
1309                 /* find mvdd value which clock is more than request */
1310                 for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
1311                         if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
1312                                 smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
1313                                 break;
1314                         }
1315                 }
1316                 PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
1317                                 "MVDD Voltage is outside the supported range.",
1318                                 return -EINVAL);
1319         } else
1320                 return -EINVAL;
1321
1322         return 0;
1323 }
1324
1325 static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
1326                 SMU73_Discrete_DpmTable *table)
1327 {
1328         int result = 0;
1329         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1330         struct phm_ppt_v1_information *table_info =
1331                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1332         struct pp_atomctrl_clock_dividers_vi dividers;
1333         SMIO_Pattern vol_level;
1334         uint32_t mvdd;
1335         uint16_t us_mvdd;
1336         uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
1337         uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
1338
1339         table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
1340
1341         if (!data->sclk_dpm_key_disabled) {
1342                 /* Get MinVoltage and Frequency from DPM0,
1343                  * already converted to SMC_UL */
1344                 table->ACPILevel.SclkFrequency =
1345                                 data->dpm_table.sclk_table.dpm_levels[0].value;
1346                 result = fiji_get_dependency_volt_by_clk(hwmgr,
1347                                 table_info->vdd_dep_on_sclk,
1348                                 table->ACPILevel.SclkFrequency,
1349                                 (uint32_t *)(&table->ACPILevel.MinVoltage), &mvdd);
1350                 PP_ASSERT_WITH_CODE((0 == result),
1351                                 "Cannot find ACPI VDDC voltage value " \
1352                                 "in Clock Dependency Table",
1353                                 );
1354         } else {
1355                 table->ACPILevel.SclkFrequency =
1356                                 data->vbios_boot_state.sclk_bootup_value;
1357                 table->ACPILevel.MinVoltage =
1358                                 data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE;
1359         }
1360
1361         /* get the engine clock dividers for this clock value */
1362         result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
1363                         table->ACPILevel.SclkFrequency,  &dividers);
1364         PP_ASSERT_WITH_CODE(result == 0,
1365                         "Error retrieving Engine Clock dividers from VBIOS.",
1366                         return result);
1367
1368         table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
1369         table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1370         table->ACPILevel.DeepSleepDivId = 0;
1371
1372         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
1373                         SPLL_PWRON, 0);
1374         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
1375                         SPLL_RESET, 1);
1376         spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
1377                         SCLK_MUX_SEL, 4);
1378
1379         table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
1380         table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
1381         table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
1382         table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
1383         table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
1384         table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
1385         table->ACPILevel.CcPwrDynRm = 0;
1386         table->ACPILevel.CcPwrDynRm1 = 0;
1387
1388         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
1389         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
1390         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
1391         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
1392         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
1393         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
1394         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
1395         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
1396         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
1397         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
1398         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
1399
1400         if (!data->mclk_dpm_key_disabled) {
1401                 /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
1402                 table->MemoryACPILevel.MclkFrequency =
1403                                 data->dpm_table.mclk_table.dpm_levels[0].value;
1404                 result = fiji_get_dependency_volt_by_clk(hwmgr,
1405                                 table_info->vdd_dep_on_mclk,
1406                                 table->MemoryACPILevel.MclkFrequency,
1407                         (uint32_t *)(&table->MemoryACPILevel.MinVoltage), &mvdd);
1408                 PP_ASSERT_WITH_CODE((0 == result),
1409                                 "Cannot find ACPI VDDCI voltage value in Clock Dependency Table",
1410                                 );
1411         } else {
1412                 table->MemoryACPILevel.MclkFrequency =
1413                                 data->vbios_boot_state.mclk_bootup_value;
1414                 table->MemoryACPILevel.MinVoltage =
1415                                 data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE;
1416         }
1417
1418         us_mvdd = 0;
1419         if ((SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
1420                         (data->mclk_dpm_key_disabled))
1421                 us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
1422         else {
1423                 if (!fiji_populate_mvdd_value(hwmgr,
1424                                 data->dpm_table.mclk_table.dpm_levels[0].value,
1425                                 &vol_level))
1426                         us_mvdd = vol_level.Voltage;
1427         }
1428
1429         table->MemoryACPILevel.MinMvdd =
1430                         PP_HOST_TO_SMC_UL(us_mvdd * VOLTAGE_SCALE);
1431
1432         table->MemoryACPILevel.EnabledForThrottle = 0;
1433         table->MemoryACPILevel.EnabledForActivity = 0;
1434         table->MemoryACPILevel.UpHyst = 0;
1435         table->MemoryACPILevel.DownHyst = 100;
1436         table->MemoryACPILevel.VoltageDownHyst = 0;
1437         table->MemoryACPILevel.ActivityLevel =
1438                         PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
1439
1440         table->MemoryACPILevel.StutterEnable = false;
1441         CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
1442         CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
1443
1444         return result;
1445 }
1446
1447 static int fiji_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
1448                 SMU73_Discrete_DpmTable *table)
1449 {
1450         int result = -EINVAL;
1451         uint8_t count;
1452         struct pp_atomctrl_clock_dividers_vi dividers;
1453         struct phm_ppt_v1_information *table_info =
1454                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1455         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1456                         table_info->mm_dep_table;
1457
1458         table->VceLevelCount = (uint8_t)(mm_table->count);
1459         table->VceBootLevel = 0;
1460
1461         for (count = 0; count < table->VceLevelCount; count++) {
1462                 table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
1463                 table->VceLevel[count].MinVoltage = 0;
1464                 table->VceLevel[count].MinVoltage |=
1465                                 (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
1466                 table->VceLevel[count].MinVoltage |=
1467                                 ((mm_table->entries[count].vddc - VDDC_VDDCI_DELTA) *
1468                                                 VOLTAGE_SCALE) << VDDCI_SHIFT;
1469                 table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
1470
1471                 /*retrieve divider value for VBIOS */
1472                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1473                                 table->VceLevel[count].Frequency, &dividers);
1474                 PP_ASSERT_WITH_CODE((0 == result),
1475                                 "can not find divide id for VCE engine clock",
1476                                 return result);
1477
1478                 table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1479
1480                 CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
1481                 CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
1482         }
1483         return result;
1484 }
1485
1486 static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
1487                 SMU73_Discrete_DpmTable *table)
1488 {
1489         int result = -EINVAL;
1490         uint8_t count;
1491         struct pp_atomctrl_clock_dividers_vi dividers;
1492         struct phm_ppt_v1_information *table_info =
1493                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1494         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1495                         table_info->mm_dep_table;
1496
1497         table->AcpLevelCount = (uint8_t)(mm_table->count);
1498         table->AcpBootLevel = 0;
1499
1500         for (count = 0; count < table->AcpLevelCount; count++) {
1501                 table->AcpLevel[count].Frequency = mm_table->entries[count].aclk;
1502                 table->AcpLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
1503                                 VOLTAGE_SCALE) << VDDC_SHIFT;
1504                 table->AcpLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
1505                                 VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT;
1506                 table->AcpLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
1507
1508                 /* retrieve divider value for VBIOS */
1509                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1510                                 table->AcpLevel[count].Frequency, &dividers);
1511                 PP_ASSERT_WITH_CODE((0 == result),
1512                                 "can not find divide id for engine clock", return result);
1513
1514                 table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1515
1516                 CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
1517                 CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].MinVoltage);
1518         }
1519         return result;
1520 }
1521
1522 static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
1523                 SMU73_Discrete_DpmTable *table)
1524 {
1525         int result = -EINVAL;
1526         uint8_t count;
1527         struct pp_atomctrl_clock_dividers_vi dividers;
1528         struct phm_ppt_v1_information *table_info =
1529                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1530         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1531                         table_info->mm_dep_table;
1532
1533         table->SamuBootLevel = 0;
1534         table->SamuLevelCount = (uint8_t)(mm_table->count);
1535
1536         for (count = 0; count < table->SamuLevelCount; count++) {
1537                 /* not sure whether we need evclk or not */
1538                 table->SamuLevel[count].MinVoltage = 0;
1539                 table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
1540                 table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
1541                                 VOLTAGE_SCALE) << VDDC_SHIFT;
1542                 table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
1543                                 VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT;
1544                 table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
1545
1546                 /* retrieve divider value for VBIOS */
1547                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1548                                 table->SamuLevel[count].Frequency, &dividers);
1549                 PP_ASSERT_WITH_CODE((0 == result),
1550                                 "can not find divide id for samu clock", return result);
1551
1552                 table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1553
1554                 CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
1555                 CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
1556         }
1557         return result;
1558 }
1559
1560 static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
1561                 int32_t eng_clock, int32_t mem_clock,
1562                 struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs)
1563 {
1564         uint32_t dram_timing;
1565         uint32_t dram_timing2;
1566         uint32_t burstTime;
1567         ULONG state, trrds, trrdl;
1568         int result;
1569
1570         result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
1571                         eng_clock, mem_clock);
1572         PP_ASSERT_WITH_CODE(result == 0,
1573                         "Error calling VBIOS to set DRAM_TIMING.", return result);
1574
1575         dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
1576         dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
1577         burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME);
1578
1579         state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0);
1580         trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0);
1581         trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0);
1582
1583         arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dram_timing);
1584         arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
1585         arb_regs->McArbBurstTime   = (uint8_t)burstTime;
1586         arb_regs->TRRDS            = (uint8_t)trrds;
1587         arb_regs->TRRDL            = (uint8_t)trrdl;
1588
1589         return 0;
1590 }
1591
1592 static int fiji_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
1593 {
1594         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1595         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
1596         struct SMU73_Discrete_MCArbDramTimingTable arb_regs;
1597         uint32_t i, j;
1598         int result = 0;
1599
1600         for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
1601                 for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
1602                         result = fiji_populate_memory_timing_parameters(hwmgr,
1603                                         data->dpm_table.sclk_table.dpm_levels[i].value,
1604                                         data->dpm_table.mclk_table.dpm_levels[j].value,
1605                                         &arb_regs.entries[i][j]);
1606                         if (result)
1607                                 break;
1608                 }
1609         }
1610
1611         if (!result)
1612                 result = smu7_copy_bytes_to_smc(
1613                                 hwmgr,
1614                                 smu_data->smu7_data.arb_table_start,
1615                                 (uint8_t *)&arb_regs,
1616                                 sizeof(SMU73_Discrete_MCArbDramTimingTable),
1617                                 SMC_RAM_END);
1618         return result;
1619 }
1620
1621 static int fiji_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
1622                 struct SMU73_Discrete_DpmTable *table)
1623 {
1624         int result = -EINVAL;
1625         uint8_t count;
1626         struct pp_atomctrl_clock_dividers_vi dividers;
1627         struct phm_ppt_v1_information *table_info =
1628                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1629         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1630                         table_info->mm_dep_table;
1631
1632         table->UvdLevelCount = (uint8_t)(mm_table->count);
1633         table->UvdBootLevel = 0;
1634
1635         for (count = 0; count < table->UvdLevelCount; count++) {
1636                 table->UvdLevel[count].MinVoltage = 0;
1637                 table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
1638                 table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
1639                 table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
1640                                 VOLTAGE_SCALE) << VDDC_SHIFT;
1641                 table->UvdLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
1642                                 VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT;
1643                 table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
1644
1645                 /* retrieve divider value for VBIOS */
1646                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1647                                 table->UvdLevel[count].VclkFrequency, &dividers);
1648                 PP_ASSERT_WITH_CODE((0 == result),
1649                                 "can not find divide id for Vclk clock", return result);
1650
1651                 table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
1652
1653                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1654                                 table->UvdLevel[count].DclkFrequency, &dividers);
1655                 PP_ASSERT_WITH_CODE((0 == result),
1656                                 "can not find divide id for Dclk clock", return result);
1657
1658                 table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
1659
1660                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
1661                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
1662                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
1663
1664         }
1665         return result;
1666 }
1667
1668 static int fiji_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
1669                 struct SMU73_Discrete_DpmTable *table)
1670 {
1671         int result = 0;
1672         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1673
1674         table->GraphicsBootLevel = 0;
1675         table->MemoryBootLevel = 0;
1676
1677         /* find boot level from dpm table */
1678         result = phm_find_boot_level(&(data->dpm_table.sclk_table),
1679                         data->vbios_boot_state.sclk_bootup_value,
1680                         (uint32_t *)&(table->GraphicsBootLevel));
1681
1682         result = phm_find_boot_level(&(data->dpm_table.mclk_table),
1683                         data->vbios_boot_state.mclk_bootup_value,
1684                         (uint32_t *)&(table->MemoryBootLevel));
1685
1686         table->BootVddc  = data->vbios_boot_state.vddc_bootup_value *
1687                         VOLTAGE_SCALE;
1688         table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
1689                         VOLTAGE_SCALE;
1690         table->BootMVdd  = data->vbios_boot_state.mvdd_bootup_value *
1691                         VOLTAGE_SCALE;
1692
1693         CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
1694         CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
1695         CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
1696
1697         return 0;
1698 }
1699
1700 static int fiji_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
1701 {
1702         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1703         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
1704         struct phm_ppt_v1_information *table_info =
1705                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1706         uint8_t count, level;
1707
1708         count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
1709         for (level = 0; level < count; level++) {
1710                 if (table_info->vdd_dep_on_sclk->entries[level].clk >=
1711                                 data->vbios_boot_state.sclk_bootup_value) {
1712                         smu_data->smc_state_table.GraphicsBootLevel = level;
1713                         break;
1714                 }
1715         }
1716
1717         count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
1718         for (level = 0; level < count; level++) {
1719                 if (table_info->vdd_dep_on_mclk->entries[level].clk >=
1720                                 data->vbios_boot_state.mclk_bootup_value) {
1721                         smu_data->smc_state_table.MemoryBootLevel = level;
1722                         break;
1723                 }
1724         }
1725
1726         return 0;
1727 }
1728
1729 static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
1730 {
1731         uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
1732                         volt_with_cks, value;
1733         uint16_t clock_freq_u16;
1734         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
1735         uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
1736                         volt_offset = 0;
1737         struct phm_ppt_v1_information *table_info =
1738                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1739         struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
1740                         table_info->vdd_dep_on_sclk;
1741
1742         stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
1743
1744         /* Read SMU_Eefuse to read and calculate RO and determine
1745          * if the part is SS or FF. if RO >= 1660MHz, part is FF.
1746          */
1747         efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1748                         ixSMU_EFUSE_0 + (146 * 4));
1749         efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1750                         ixSMU_EFUSE_0 + (148 * 4));
1751         efuse &= 0xFF000000;
1752         efuse = efuse >> 24;
1753         efuse2 &= 0xF;
1754
1755         if (efuse2 == 1)
1756                 ro = (2300 - 1350) * efuse / 255 + 1350;
1757         else
1758                 ro = (2500 - 1000) * efuse / 255 + 1000;
1759
1760         if (ro >= 1660)
1761                 type = 0;
1762         else
1763                 type = 1;
1764
1765         /* Populate Stretch amount */
1766         smu_data->smc_state_table.ClockStretcherAmount = stretch_amount;
1767
1768         /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
1769         for (i = 0; i < sclk_table->count; i++) {
1770                 smu_data->smc_state_table.Sclk_CKS_masterEn0_7 |=
1771                                 sclk_table->entries[i].cks_enable << i;
1772                 volt_without_cks = (uint32_t)((14041 *
1773                         (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
1774                         (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
1775                 volt_with_cks = (uint32_t)((13946 *
1776                         (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
1777                         (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
1778                 if (volt_without_cks >= volt_with_cks)
1779                         volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
1780                                         sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
1781                 smu_data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
1782         }
1783
1784         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
1785                         STRETCH_ENABLE, 0x0);
1786         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
1787                         masterReset, 0x1);
1788         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
1789                         staticEnable, 0x1);
1790         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
1791                         masterReset, 0x0);
1792
1793         /* Populate CKS Lookup Table */
1794         if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
1795                 stretch_amount2 = 0;
1796         else if (stretch_amount == 3 || stretch_amount == 4)
1797                 stretch_amount2 = 1;
1798         else {
1799                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
1800                                 PHM_PlatformCaps_ClockStretcher);
1801                 PP_ASSERT_WITH_CODE(false,
1802                                 "Stretch Amount in PPTable not supported",
1803                                 return -EINVAL);
1804         }
1805
1806         value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1807                         ixPWR_CKS_CNTL);
1808         value &= 0xFFC2FF87;
1809         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
1810                         fiji_clock_stretcher_lookup_table[stretch_amount2][0];
1811         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
1812                         fiji_clock_stretcher_lookup_table[stretch_amount2][1];
1813         clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(smu_data->smc_state_table.
1814                         GraphicsLevel[smu_data->smc_state_table.GraphicsDpmLevelCount - 1].
1815                         SclkFrequency) / 100);
1816         if (fiji_clock_stretcher_lookup_table[stretch_amount2][0] <
1817                         clock_freq_u16 &&
1818             fiji_clock_stretcher_lookup_table[stretch_amount2][1] >
1819                         clock_freq_u16) {
1820                 /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
1821                 value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
1822                 /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
1823                 value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
1824                 /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
1825                 value |= (fiji_clock_stretch_amount_conversion
1826                                 [fiji_clock_stretcher_lookup_table[stretch_amount2][3]]
1827                                  [stretch_amount]) << 3;
1828         }
1829         CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
1830                         CKS_LOOKUPTableEntry[0].minFreq);
1831         CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
1832                         CKS_LOOKUPTableEntry[0].maxFreq);
1833         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
1834                         fiji_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
1835         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
1836                         (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
1837
1838         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1839                         ixPWR_CKS_CNTL, value);
1840
1841         /* Populate DDT Lookup Table */
1842         for (i = 0; i < 4; i++) {
1843                 /* Assign the minimum and maximum VID stored
1844                  * in the last row of Clock Stretcher Voltage Table.
1845                  */
1846                 smu_data->smc_state_table.ClockStretcherDataTable.
1847                 ClockStretcherDataTableEntry[i].minVID =
1848                                 (uint8_t) fiji_clock_stretcher_ddt_table[type][i][2];
1849                 smu_data->smc_state_table.ClockStretcherDataTable.
1850                 ClockStretcherDataTableEntry[i].maxVID =
1851                                 (uint8_t) fiji_clock_stretcher_ddt_table[type][i][3];
1852                 /* Loop through each SCLK and check the frequency
1853                  * to see if it lies within the frequency for clock stretcher.
1854                  */
1855                 for (j = 0; j < smu_data->smc_state_table.GraphicsDpmLevelCount; j++) {
1856                         cks_setting = 0;
1857                         clock_freq = PP_SMC_TO_HOST_UL(
1858                                         smu_data->smc_state_table.GraphicsLevel[j].SclkFrequency);
1859                         /* Check the allowed frequency against the sclk level[j].
1860                          *  Sclk's endianness has already been converted,
1861                          *  and it's in 10Khz unit,
1862                          *  as opposed to Data table, which is in Mhz unit.
1863                          */
1864                         if (clock_freq >=
1865                                         (fiji_clock_stretcher_ddt_table[type][i][0]) * 100) {
1866                                 cks_setting |= 0x2;
1867                                 if (clock_freq <
1868                                                 (fiji_clock_stretcher_ddt_table[type][i][1]) * 100)
1869                                         cks_setting |= 0x1;
1870                         }
1871                         smu_data->smc_state_table.ClockStretcherDataTable.
1872                         ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
1873                 }
1874                 CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.
1875                                 ClockStretcherDataTable.
1876                                 ClockStretcherDataTableEntry[i].setting);
1877         }
1878
1879         value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
1880         value &= 0xFFFFFFFE;
1881         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
1882
1883         return 0;
1884 }
1885
1886 static int fiji_populate_vr_config(struct pp_hwmgr *hwmgr,
1887                 struct SMU73_Discrete_DpmTable *table)
1888 {
1889         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1890         uint16_t config;
1891
1892         config = VR_MERGED_WITH_VDDC;
1893         table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
1894
1895         /* Set Vddc Voltage Controller */
1896         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1897                 config = VR_SVI2_PLANE_1;
1898                 table->VRConfig |= config;
1899         } else {
1900                 PP_ASSERT_WITH_CODE(false,
1901                                 "VDDC should be on SVI2 control in merged mode!",
1902                                 );
1903         }
1904         /* Set Vddci Voltage Controller */
1905         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
1906                 config = VR_SVI2_PLANE_2;  /* only in merged mode */
1907                 table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
1908         } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
1909                 config = VR_SMIO_PATTERN_1;
1910                 table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
1911         } else {
1912                 config = VR_STATIC_VOLTAGE;
1913                 table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
1914         }
1915         /* Set Mvdd Voltage Controller */
1916         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
1917                 config = VR_SVI2_PLANE_2;
1918                 table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
1919         } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
1920                 config = VR_SMIO_PATTERN_2;
1921                 table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
1922         } else {
1923                 config = VR_STATIC_VOLTAGE;
1924                 table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
1925         }
1926
1927         return 0;
1928 }
1929
1930 static int fiji_init_arb_table_index(struct pp_hwmgr *hwmgr)
1931 {
1932         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
1933         uint32_t tmp;
1934         int result;
1935
1936         /* This is a read-modify-write on the first byte of the ARB table.
1937          * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
1938          * is the field 'current'.
1939          * This solution is ugly, but we never write the whole table only
1940          * individual fields in it.
1941          * In reality this field should not be in that structure
1942          * but in a soft register.
1943          */
1944         result = smu7_read_smc_sram_dword(hwmgr,
1945                         smu_data->smu7_data.arb_table_start, &tmp, SMC_RAM_END);
1946
1947         if (result)
1948                 return result;
1949
1950         tmp &= 0x00FFFFFF;
1951         tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
1952
1953         return smu7_write_smc_sram_dword(hwmgr,
1954                         smu_data->smu7_data.arb_table_start,  tmp, SMC_RAM_END);
1955 }
1956
1957 static int fiji_save_default_power_profile(struct pp_hwmgr *hwmgr)
1958 {
1959         struct fiji_smumgr *data = (struct fiji_smumgr *)(hwmgr->smu_backend);
1960         struct SMU73_Discrete_GraphicsLevel *levels =
1961                                 data->smc_state_table.GraphicsLevel;
1962         unsigned min_level = 1;
1963
1964         hwmgr->default_gfx_power_profile.activity_threshold =
1965                         be16_to_cpu(levels[0].ActivityLevel);
1966         hwmgr->default_gfx_power_profile.up_hyst = levels[0].UpHyst;
1967         hwmgr->default_gfx_power_profile.down_hyst = levels[0].DownHyst;
1968         hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE;
1969
1970         hwmgr->default_compute_power_profile = hwmgr->default_gfx_power_profile;
1971         hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE;
1972
1973         /* Workaround compute SDMA instability: disable lowest SCLK
1974          * DPM level. Optimize compute power profile: Use only highest
1975          * 2 power levels (if more than 2 are available), Hysteresis:
1976          * 0ms up, 5ms down
1977          */
1978         if (data->smc_state_table.GraphicsDpmLevelCount > 2)
1979                 min_level = data->smc_state_table.GraphicsDpmLevelCount - 2;
1980         else if (data->smc_state_table.GraphicsDpmLevelCount == 2)
1981                 min_level = 1;
1982         else
1983                 min_level = 0;
1984         hwmgr->default_compute_power_profile.min_sclk =
1985                         be32_to_cpu(levels[min_level].SclkFrequency);
1986         hwmgr->default_compute_power_profile.up_hyst = 0;
1987         hwmgr->default_compute_power_profile.down_hyst = 5;
1988
1989         hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile;
1990         hwmgr->compute_power_profile = hwmgr->default_compute_power_profile;
1991
1992         return 0;
1993 }
1994
1995 static int fiji_setup_dpm_led_config(struct pp_hwmgr *hwmgr)
1996 {
1997         pp_atomctrl_voltage_table param_led_dpm;
1998         int result = 0;
1999         u32 mask = 0;
2000
2001         result = atomctrl_get_voltage_table_v3(hwmgr,
2002                                                VOLTAGE_TYPE_LEDDPM, VOLTAGE_OBJ_GPIO_LUT,
2003                                                &param_led_dpm);
2004         if (result == 0) {
2005                 int i, j;
2006                 u32 tmp = param_led_dpm.mask_low;
2007
2008                 for (i = 0, j = 0; i < 32; i++) {
2009                         if (tmp & 1) {
2010                                 mask |= (i << (8 * j));
2011                                 if (++j >= 3)
2012                                         break;
2013                         }
2014                         tmp >>= 1;
2015                 }
2016         }
2017         if (mask)
2018                 smum_send_msg_to_smc_with_parameter(hwmgr,
2019                                                     PPSMC_MSG_LedConfig,
2020                                                     mask);
2021         return 0;
2022 }
2023
2024 static int fiji_init_smc_table(struct pp_hwmgr *hwmgr)
2025 {
2026         int result;
2027         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2028         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
2029         struct phm_ppt_v1_information *table_info =
2030                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2031         struct SMU73_Discrete_DpmTable *table = &(smu_data->smc_state_table);
2032         uint8_t i;
2033         struct pp_atomctrl_gpio_pin_assignment gpio_pin;
2034
2035         fiji_initialize_power_tune_defaults(hwmgr);
2036
2037         if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control)
2038                 fiji_populate_smc_voltage_tables(hwmgr, table);
2039
2040         table->SystemFlags = 0;
2041
2042         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2043                         PHM_PlatformCaps_AutomaticDCTransition))
2044                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
2045
2046         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2047                         PHM_PlatformCaps_StepVddc))
2048                 table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
2049
2050         if (data->is_memory_gddr5)
2051                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
2052
2053         if (data->ulv_supported && table_info->us_ulv_voltage_offset) {
2054                 result = fiji_populate_ulv_state(hwmgr, table);
2055                 PP_ASSERT_WITH_CODE(0 == result,
2056                                 "Failed to initialize ULV state!", return result);
2057                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2058                                 ixCG_ULV_PARAMETER, 0x40035);
2059         }
2060
2061         result = fiji_populate_smc_link_level(hwmgr, table);
2062         PP_ASSERT_WITH_CODE(0 == result,
2063                         "Failed to initialize Link Level!", return result);
2064
2065         result = fiji_populate_all_graphic_levels(hwmgr);
2066         PP_ASSERT_WITH_CODE(0 == result,
2067                         "Failed to initialize Graphics Level!", return result);
2068
2069         result = fiji_populate_all_memory_levels(hwmgr);
2070         PP_ASSERT_WITH_CODE(0 == result,
2071                         "Failed to initialize Memory Level!", return result);
2072
2073         result = fiji_populate_smc_acpi_level(hwmgr, table);
2074         PP_ASSERT_WITH_CODE(0 == result,
2075                         "Failed to initialize ACPI Level!", return result);
2076
2077         result = fiji_populate_smc_vce_level(hwmgr, table);
2078         PP_ASSERT_WITH_CODE(0 == result,
2079                         "Failed to initialize VCE Level!", return result);
2080
2081         result = fiji_populate_smc_acp_level(hwmgr, table);
2082         PP_ASSERT_WITH_CODE(0 == result,
2083                         "Failed to initialize ACP Level!", return result);
2084
2085         result = fiji_populate_smc_samu_level(hwmgr, table);
2086         PP_ASSERT_WITH_CODE(0 == result,
2087                         "Failed to initialize SAMU Level!", return result);
2088
2089         /* Since only the initial state is completely set up at this point
2090          * (the other states are just copies of the boot state) we only
2091          * need to populate the  ARB settings for the initial state.
2092          */
2093         result = fiji_program_memory_timing_parameters(hwmgr);
2094         PP_ASSERT_WITH_CODE(0 == result,
2095                         "Failed to Write ARB settings for the initial state.", return result);
2096
2097         result = fiji_populate_smc_uvd_level(hwmgr, table);
2098         PP_ASSERT_WITH_CODE(0 == result,
2099                         "Failed to initialize UVD Level!", return result);
2100
2101         result = fiji_populate_smc_boot_level(hwmgr, table);
2102         PP_ASSERT_WITH_CODE(0 == result,
2103                         "Failed to initialize Boot Level!", return result);
2104
2105         result = fiji_populate_smc_initailial_state(hwmgr);
2106         PP_ASSERT_WITH_CODE(0 == result,
2107                         "Failed to initialize Boot State!", return result);
2108
2109         result = fiji_populate_bapm_parameters_in_dpm_table(hwmgr);
2110         PP_ASSERT_WITH_CODE(0 == result,
2111                         "Failed to populate BAPM Parameters!", return result);
2112
2113         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2114                         PHM_PlatformCaps_ClockStretcher)) {
2115                 result = fiji_populate_clock_stretcher_data_table(hwmgr);
2116                 PP_ASSERT_WITH_CODE(0 == result,
2117                                 "Failed to populate Clock Stretcher Data Table!",
2118                                 return result);
2119         }
2120
2121         table->GraphicsVoltageChangeEnable  = 1;
2122         table->GraphicsThermThrottleEnable  = 1;
2123         table->GraphicsInterval = 1;
2124         table->VoltageInterval  = 1;
2125         table->ThermalInterval  = 1;
2126         table->TemperatureLimitHigh =
2127                         table_info->cac_dtp_table->usTargetOperatingTemp *
2128                         SMU7_Q88_FORMAT_CONVERSION_UNIT;
2129         table->TemperatureLimitLow  =
2130                         (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
2131                         SMU7_Q88_FORMAT_CONVERSION_UNIT;
2132         table->MemoryVoltageChangeEnable = 1;
2133         table->MemoryInterval = 1;
2134         table->VoltageResponseTime = 0;
2135         table->PhaseResponseTime = 0;
2136         table->MemoryThermThrottleEnable = 1;
2137         table->PCIeBootLinkLevel = 0;      /* 0:Gen1 1:Gen2 2:Gen3*/
2138         table->PCIeGenInterval = 1;
2139         table->VRConfig = 0;
2140
2141         result = fiji_populate_vr_config(hwmgr, table);
2142         PP_ASSERT_WITH_CODE(0 == result,
2143                         "Failed to populate VRConfig setting!", return result);
2144
2145         table->ThermGpio = 17;
2146         table->SclkStepSize = 0x4000;
2147
2148         if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
2149                 table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
2150                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2151                                 PHM_PlatformCaps_RegulatorHot);
2152         } else {
2153                 table->VRHotGpio = SMU7_UNUSED_GPIO_PIN;
2154                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2155                                 PHM_PlatformCaps_RegulatorHot);
2156         }
2157
2158         if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
2159                         &gpio_pin)) {
2160                 table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
2161                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2162                                 PHM_PlatformCaps_AutomaticDCTransition);
2163         } else {
2164                 table->AcDcGpio = SMU7_UNUSED_GPIO_PIN;
2165                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2166                                 PHM_PlatformCaps_AutomaticDCTransition);
2167         }
2168
2169         /* Thermal Output GPIO */
2170         if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
2171                         &gpio_pin)) {
2172                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2173                                 PHM_PlatformCaps_ThermalOutGPIO);
2174
2175                 table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
2176
2177                 /* For porlarity read GPIOPAD_A with assigned Gpio pin
2178                  * since VBIOS will program this register to set 'inactive state',
2179                  * driver can then determine 'active state' from this and
2180                  * program SMU with correct polarity
2181                  */
2182                 table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
2183                                 (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
2184                 table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
2185
2186                 /* if required, combine VRHot/PCC with thermal out GPIO */
2187                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2188                                 PHM_PlatformCaps_RegulatorHot) &&
2189                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2190                                         PHM_PlatformCaps_CombinePCCWithThermalSignal))
2191                         table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
2192         } else {
2193                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2194                                 PHM_PlatformCaps_ThermalOutGPIO);
2195                 table->ThermOutGpio = 17;
2196                 table->ThermOutPolarity = 1;
2197                 table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
2198         }
2199
2200         for (i = 0; i < SMU73_MAX_ENTRIES_SMIO; i++)
2201                 table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
2202
2203         CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
2204         CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
2205         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
2206         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
2207         CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
2208         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
2209         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
2210         CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
2211         CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
2212
2213         /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
2214         result = smu7_copy_bytes_to_smc(hwmgr,
2215                         smu_data->smu7_data.dpm_table_start +
2216                         offsetof(SMU73_Discrete_DpmTable, SystemFlags),
2217                         (uint8_t *)&(table->SystemFlags),
2218                         sizeof(SMU73_Discrete_DpmTable) - 3 * sizeof(SMU73_PIDController),
2219                         SMC_RAM_END);
2220         PP_ASSERT_WITH_CODE(0 == result,
2221                         "Failed to upload dpm data to SMC memory!", return result);
2222
2223         result = fiji_init_arb_table_index(hwmgr);
2224         PP_ASSERT_WITH_CODE(0 == result,
2225                         "Failed to upload arb data to SMC memory!", return result);
2226
2227         result = fiji_populate_pm_fuses(hwmgr);
2228         PP_ASSERT_WITH_CODE(0 == result,
2229                         "Failed to  populate PM fuses to SMC memory!", return result);
2230
2231         result = fiji_setup_dpm_led_config(hwmgr);
2232         PP_ASSERT_WITH_CODE(0 == result,
2233                             "Failed to setup dpm led config", return result);
2234
2235         fiji_save_default_power_profile(hwmgr);
2236
2237         return 0;
2238 }
2239
2240 static int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
2241 {
2242         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
2243
2244         SMU73_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
2245         uint32_t duty100;
2246         uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
2247         uint16_t fdo_min, slope1, slope2;
2248         uint32_t reference_clock;
2249         int res;
2250         uint64_t tmp64;
2251
2252         if (hwmgr->thermal_controller.fanInfo.bNoFan) {
2253                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2254                         PHM_PlatformCaps_MicrocodeFanControl);
2255                 return 0;
2256         }
2257
2258         if (smu_data->smu7_data.fan_table_start == 0) {
2259                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2260                                 PHM_PlatformCaps_MicrocodeFanControl);
2261                 return 0;
2262         }
2263
2264         duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
2265                         CG_FDO_CTRL1, FMAX_DUTY100);
2266
2267         if (duty100 == 0) {
2268                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2269                                 PHM_PlatformCaps_MicrocodeFanControl);
2270                 return 0;
2271         }
2272
2273         tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
2274                         usPWMMin * duty100;
2275         do_div(tmp64, 10000);
2276         fdo_min = (uint16_t)tmp64;
2277
2278         t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
2279                         hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
2280         t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
2281                         hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
2282
2283         pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
2284                         hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
2285         pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
2286                         hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
2287
2288         slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
2289         slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
2290
2291         fan_table.TempMin = cpu_to_be16((50 + hwmgr->
2292                         thermal_controller.advanceFanControlParameters.usTMin) / 100);
2293         fan_table.TempMed = cpu_to_be16((50 + hwmgr->
2294                         thermal_controller.advanceFanControlParameters.usTMed) / 100);
2295         fan_table.TempMax = cpu_to_be16((50 + hwmgr->
2296                         thermal_controller.advanceFanControlParameters.usTMax) / 100);
2297
2298         fan_table.Slope1 = cpu_to_be16(slope1);
2299         fan_table.Slope2 = cpu_to_be16(slope2);
2300
2301         fan_table.FdoMin = cpu_to_be16(fdo_min);
2302
2303         fan_table.HystDown = cpu_to_be16(hwmgr->
2304                         thermal_controller.advanceFanControlParameters.ucTHyst);
2305
2306         fan_table.HystUp = cpu_to_be16(1);
2307
2308         fan_table.HystSlope = cpu_to_be16(1);
2309
2310         fan_table.TempRespLim = cpu_to_be16(5);
2311
2312         reference_clock = smu7_get_xclk(hwmgr);
2313
2314         fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
2315                         thermal_controller.advanceFanControlParameters.ulCycleDelay *
2316                         reference_clock) / 1600);
2317
2318         fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
2319
2320         fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
2321                         hwmgr->device, CGS_IND_REG__SMC,
2322                         CG_MULT_THERMAL_CTRL, TEMP_SEL);
2323
2324         res = smu7_copy_bytes_to_smc(hwmgr, smu_data->smu7_data.fan_table_start,
2325                         (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
2326                         SMC_RAM_END);
2327
2328         if (!res && hwmgr->thermal_controller.
2329                         advanceFanControlParameters.ucMinimumPWMLimit)
2330                 res = smum_send_msg_to_smc_with_parameter(hwmgr,
2331                                 PPSMC_MSG_SetFanMinPwm,
2332                                 hwmgr->thermal_controller.
2333                                 advanceFanControlParameters.ucMinimumPWMLimit);
2334
2335         if (!res && hwmgr->thermal_controller.
2336                         advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
2337                 res = smum_send_msg_to_smc_with_parameter(hwmgr,
2338                                 PPSMC_MSG_SetFanSclkTarget,
2339                                 hwmgr->thermal_controller.
2340                                 advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
2341
2342         if (res)
2343                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2344                                 PHM_PlatformCaps_MicrocodeFanControl);
2345
2346         return 0;
2347 }
2348
2349
2350 static int fiji_thermal_avfs_enable(struct pp_hwmgr *hwmgr)
2351 {
2352         int ret;
2353         struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend);
2354
2355         if (smu_data->avfs.avfs_btc_status != AVFS_BTC_ENABLEAVFS)
2356                 return 0;
2357
2358         ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs);
2359
2360         if (!ret)
2361                 /* If this param is not changed, this function could fire unnecessarily */
2362                 smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY;
2363
2364         return ret;
2365 }
2366
2367 static int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
2368 {
2369         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2370
2371         if (data->need_update_smu7_dpm_table &
2372                 (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
2373                 return fiji_program_memory_timing_parameters(hwmgr);
2374
2375         return 0;
2376 }
2377
2378 static int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr)
2379 {
2380         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2381         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
2382
2383         int result = 0;
2384         uint32_t low_sclk_interrupt_threshold = 0;
2385
2386         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2387                         PHM_PlatformCaps_SclkThrottleLowNotification)
2388                 && (data->low_sclk_interrupt_threshold != 0)) {
2389                 low_sclk_interrupt_threshold =
2390                                 data->low_sclk_interrupt_threshold;
2391
2392                 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
2393
2394                 result = smu7_copy_bytes_to_smc(
2395                                 hwmgr,
2396                                 smu_data->smu7_data.dpm_table_start +
2397                                 offsetof(SMU73_Discrete_DpmTable,
2398                                         LowSclkInterruptThreshold),
2399                                 (uint8_t *)&low_sclk_interrupt_threshold,
2400                                 sizeof(uint32_t),
2401                                 SMC_RAM_END);
2402         }
2403         result = fiji_program_mem_timing_parameters(hwmgr);
2404         PP_ASSERT_WITH_CODE((result == 0),
2405                         "Failed to program memory timing parameters!",
2406                         );
2407         return result;
2408 }
2409
2410 static uint32_t fiji_get_offsetof(uint32_t type, uint32_t member)
2411 {
2412         switch (type) {
2413         case SMU_SoftRegisters:
2414                 switch (member) {
2415                 case HandshakeDisables:
2416                         return offsetof(SMU73_SoftRegisters, HandshakeDisables);
2417                 case VoltageChangeTimeout:
2418                         return offsetof(SMU73_SoftRegisters, VoltageChangeTimeout);
2419                 case AverageGraphicsActivity:
2420                         return offsetof(SMU73_SoftRegisters, AverageGraphicsActivity);
2421                 case PreVBlankGap:
2422                         return offsetof(SMU73_SoftRegisters, PreVBlankGap);
2423                 case VBlankTimeout:
2424                         return offsetof(SMU73_SoftRegisters, VBlankTimeout);
2425                 case UcodeLoadStatus:
2426                         return offsetof(SMU73_SoftRegisters, UcodeLoadStatus);
2427                 case DRAM_LOG_ADDR_H:
2428                         return offsetof(SMU73_SoftRegisters, DRAM_LOG_ADDR_H);
2429                 case DRAM_LOG_ADDR_L:
2430                         return offsetof(SMU73_SoftRegisters, DRAM_LOG_ADDR_L);
2431                 case DRAM_LOG_PHY_ADDR_H:
2432                         return offsetof(SMU73_SoftRegisters, DRAM_LOG_PHY_ADDR_H);
2433                 case DRAM_LOG_PHY_ADDR_L:
2434                         return offsetof(SMU73_SoftRegisters, DRAM_LOG_PHY_ADDR_L);
2435                 case DRAM_LOG_BUFF_SIZE:
2436                         return offsetof(SMU73_SoftRegisters, DRAM_LOG_BUFF_SIZE);
2437                 }
2438         case SMU_Discrete_DpmTable:
2439                 switch (member) {
2440                 case UvdBootLevel:
2441                         return offsetof(SMU73_Discrete_DpmTable, UvdBootLevel);
2442                 case VceBootLevel:
2443                         return offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
2444                 case SamuBootLevel:
2445                         return offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
2446                 case LowSclkInterruptThreshold:
2447                         return offsetof(SMU73_Discrete_DpmTable, LowSclkInterruptThreshold);
2448                 }
2449         }
2450         pr_warn("can't get the offset of type %x member %x\n", type, member);
2451         return 0;
2452 }
2453
2454 static uint32_t fiji_get_mac_definition(uint32_t value)
2455 {
2456         switch (value) {
2457         case SMU_MAX_LEVELS_GRAPHICS:
2458                 return SMU73_MAX_LEVELS_GRAPHICS;
2459         case SMU_MAX_LEVELS_MEMORY:
2460                 return SMU73_MAX_LEVELS_MEMORY;
2461         case SMU_MAX_LEVELS_LINK:
2462                 return SMU73_MAX_LEVELS_LINK;
2463         case SMU_MAX_ENTRIES_SMIO:
2464                 return SMU73_MAX_ENTRIES_SMIO;
2465         case SMU_MAX_LEVELS_VDDC:
2466                 return SMU73_MAX_LEVELS_VDDC;
2467         case SMU_MAX_LEVELS_VDDGFX:
2468                 return SMU73_MAX_LEVELS_VDDGFX;
2469         case SMU_MAX_LEVELS_VDDCI:
2470                 return SMU73_MAX_LEVELS_VDDCI;
2471         case SMU_MAX_LEVELS_MVDD:
2472                 return SMU73_MAX_LEVELS_MVDD;
2473         }
2474
2475         pr_warn("can't get the mac of %x\n", value);
2476         return 0;
2477 }
2478
2479
2480 static int fiji_update_uvd_smc_table(struct pp_hwmgr *hwmgr)
2481 {
2482         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
2483         uint32_t mm_boot_level_offset, mm_boot_level_value;
2484         struct phm_ppt_v1_information *table_info =
2485                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2486
2487         smu_data->smc_state_table.UvdBootLevel = 0;
2488         if (table_info->mm_dep_table->count > 0)
2489                 smu_data->smc_state_table.UvdBootLevel =
2490                                 (uint8_t) (table_info->mm_dep_table->count - 1);
2491         mm_boot_level_offset = smu_data->smu7_data.dpm_table_start + offsetof(SMU73_Discrete_DpmTable,
2492                                                 UvdBootLevel);
2493         mm_boot_level_offset /= 4;
2494         mm_boot_level_offset *= 4;
2495         mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
2496                         CGS_IND_REG__SMC, mm_boot_level_offset);
2497         mm_boot_level_value &= 0x00FFFFFF;
2498         mm_boot_level_value |= smu_data->smc_state_table.UvdBootLevel << 24;
2499         cgs_write_ind_register(hwmgr->device,
2500                         CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
2501
2502         if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2503                         PHM_PlatformCaps_UVDDPM) ||
2504                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2505                         PHM_PlatformCaps_StablePState))
2506                 smum_send_msg_to_smc_with_parameter(hwmgr,
2507                                 PPSMC_MSG_UVDDPM_SetEnabledMask,
2508                                 (uint32_t)(1 << smu_data->smc_state_table.UvdBootLevel));
2509         return 0;
2510 }
2511
2512 static int fiji_update_vce_smc_table(struct pp_hwmgr *hwmgr)
2513 {
2514         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
2515         uint32_t mm_boot_level_offset, mm_boot_level_value;
2516         struct phm_ppt_v1_information *table_info =
2517                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2518
2519         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2520                                         PHM_PlatformCaps_StablePState))
2521                 smu_data->smc_state_table.VceBootLevel =
2522                         (uint8_t) (table_info->mm_dep_table->count - 1);
2523         else
2524                 smu_data->smc_state_table.VceBootLevel = 0;
2525
2526         mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
2527                                         offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
2528         mm_boot_level_offset /= 4;
2529         mm_boot_level_offset *= 4;
2530         mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
2531                         CGS_IND_REG__SMC, mm_boot_level_offset);
2532         mm_boot_level_value &= 0xFF00FFFF;
2533         mm_boot_level_value |= smu_data->smc_state_table.VceBootLevel << 16;
2534         cgs_write_ind_register(hwmgr->device,
2535                         CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
2536
2537         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
2538                 smum_send_msg_to_smc_with_parameter(hwmgr,
2539                                 PPSMC_MSG_VCEDPM_SetEnabledMask,
2540                                 (uint32_t)1 << smu_data->smc_state_table.VceBootLevel);
2541         return 0;
2542 }
2543
2544 static int fiji_update_samu_smc_table(struct pp_hwmgr *hwmgr)
2545 {
2546         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
2547         uint32_t mm_boot_level_offset, mm_boot_level_value;
2548
2549
2550         smu_data->smc_state_table.SamuBootLevel = 0;
2551         mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
2552                                 offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
2553
2554         mm_boot_level_offset /= 4;
2555         mm_boot_level_offset *= 4;
2556         mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
2557                         CGS_IND_REG__SMC, mm_boot_level_offset);
2558         mm_boot_level_value &= 0xFFFFFF00;
2559         mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0;
2560         cgs_write_ind_register(hwmgr->device,
2561                         CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
2562
2563         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2564                         PHM_PlatformCaps_StablePState))
2565                 smum_send_msg_to_smc_with_parameter(hwmgr,
2566                                 PPSMC_MSG_SAMUDPM_SetEnabledMask,
2567                                 (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel));
2568         return 0;
2569 }
2570
2571 static int fiji_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
2572 {
2573         switch (type) {
2574         case SMU_UVD_TABLE:
2575                 fiji_update_uvd_smc_table(hwmgr);
2576                 break;
2577         case SMU_VCE_TABLE:
2578                 fiji_update_vce_smc_table(hwmgr);
2579                 break;
2580         case SMU_SAMU_TABLE:
2581                 fiji_update_samu_smc_table(hwmgr);
2582                 break;
2583         default:
2584                 break;
2585         }
2586         return 0;
2587 }
2588
2589 static int fiji_process_firmware_header(struct pp_hwmgr *hwmgr)
2590 {
2591         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2592         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend);
2593         uint32_t tmp;
2594         int result;
2595         bool error = false;
2596
2597         result = smu7_read_smc_sram_dword(hwmgr,
2598                         SMU7_FIRMWARE_HEADER_LOCATION +
2599                         offsetof(SMU73_Firmware_Header, DpmTable),
2600                         &tmp, SMC_RAM_END);
2601
2602         if (0 == result)
2603                 smu_data->smu7_data.dpm_table_start = tmp;
2604
2605         error |= (0 != result);
2606
2607         result = smu7_read_smc_sram_dword(hwmgr,
2608                         SMU7_FIRMWARE_HEADER_LOCATION +
2609                         offsetof(SMU73_Firmware_Header, SoftRegisters),
2610                         &tmp, SMC_RAM_END);
2611
2612         if (!result) {
2613                 data->soft_regs_start = tmp;
2614                 smu_data->smu7_data.soft_regs_start = tmp;
2615         }
2616
2617         error |= (0 != result);
2618
2619         result = smu7_read_smc_sram_dword(hwmgr,
2620                         SMU7_FIRMWARE_HEADER_LOCATION +
2621                         offsetof(SMU73_Firmware_Header, mcRegisterTable),
2622                         &tmp, SMC_RAM_END);
2623
2624         if (!result)
2625                 smu_data->smu7_data.mc_reg_table_start = tmp;
2626
2627         result = smu7_read_smc_sram_dword(hwmgr,
2628                         SMU7_FIRMWARE_HEADER_LOCATION +
2629                         offsetof(SMU73_Firmware_Header, FanTable),
2630                         &tmp, SMC_RAM_END);
2631
2632         if (!result)
2633                 smu_data->smu7_data.fan_table_start = tmp;
2634
2635         error |= (0 != result);
2636
2637         result = smu7_read_smc_sram_dword(hwmgr,
2638                         SMU7_FIRMWARE_HEADER_LOCATION +
2639                         offsetof(SMU73_Firmware_Header, mcArbDramTimingTable),
2640                         &tmp, SMC_RAM_END);
2641
2642         if (!result)
2643                 smu_data->smu7_data.arb_table_start = tmp;
2644
2645         error |= (0 != result);
2646
2647         result = smu7_read_smc_sram_dword(hwmgr,
2648                         SMU7_FIRMWARE_HEADER_LOCATION +
2649                         offsetof(SMU73_Firmware_Header, Version),
2650                         &tmp, SMC_RAM_END);
2651
2652         if (!result)
2653                 hwmgr->microcode_version_info.SMC = tmp;
2654
2655         error |= (0 != result);
2656
2657         return error ? -1 : 0;
2658 }
2659
2660 static int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
2661 {
2662
2663         /* Program additional LP registers
2664          * that are no longer programmed by VBIOS
2665          */
2666         cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
2667                         cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
2668         cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
2669                         cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
2670         cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
2671                         cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
2672         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
2673                         cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
2674         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
2675                         cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
2676         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
2677                         cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
2678         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
2679                         cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
2680
2681         return 0;
2682 }
2683
2684 static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr)
2685 {
2686         return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
2687                         CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
2688                         ? true : false;
2689 }
2690
2691 static int fiji_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr,
2692                 struct amd_pp_profile *request)
2693 {
2694         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)
2695                         (hwmgr->smu_backend);
2696         struct SMU73_Discrete_GraphicsLevel *levels =
2697                         smu_data->smc_state_table.GraphicsLevel;
2698         uint32_t array = smu_data->smu7_data.dpm_table_start +
2699                         offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
2700         uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) *
2701                         SMU73_MAX_LEVELS_GRAPHICS;
2702         uint32_t i;
2703
2704         for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) {
2705                 levels[i].ActivityLevel =
2706                                 cpu_to_be16(request->activity_threshold);
2707                 levels[i].EnabledForActivity = 1;
2708                 levels[i].UpHyst = request->up_hyst;
2709                 levels[i].DownHyst = request->down_hyst;
2710         }
2711
2712         return smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels,
2713                                 array_size, SMC_RAM_END);
2714 }
2715
2716 const struct pp_smumgr_func fiji_smu_funcs = {
2717         .smu_init = &fiji_smu_init,
2718         .smu_fini = &smu7_smu_fini,
2719         .start_smu = &fiji_start_smu,
2720         .check_fw_load_finish = &smu7_check_fw_load_finish,
2721         .request_smu_load_fw = &smu7_reload_firmware,
2722         .request_smu_load_specific_fw = NULL,
2723         .send_msg_to_smc = &smu7_send_msg_to_smc,
2724         .send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
2725         .download_pptable_settings = NULL,
2726         .upload_pptable_settings = NULL,
2727         .update_smc_table = fiji_update_smc_table,
2728         .get_offsetof = fiji_get_offsetof,
2729         .process_firmware_header = fiji_process_firmware_header,
2730         .init_smc_table = fiji_init_smc_table,
2731         .update_sclk_threshold = fiji_update_sclk_threshold,
2732         .thermal_setup_fan_table = fiji_thermal_setup_fan_table,
2733         .thermal_avfs_enable = fiji_thermal_avfs_enable,
2734         .populate_all_graphic_levels = fiji_populate_all_graphic_levels,
2735         .populate_all_memory_levels = fiji_populate_all_memory_levels,
2736         .get_mac_definition = fiji_get_mac_definition,
2737         .initialize_mc_reg_table = fiji_initialize_mc_reg_table,
2738         .is_dpm_running = fiji_is_dpm_running,
2739         .populate_requested_graphic_levels = fiji_populate_requested_graphic_levels,
2740         .is_hw_avfs_present = fiji_is_hw_avfs_present,
2741 };