Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / powerplay / smumgr / tonga_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 #include "pp_debug.h"
24 #include <linux/types.h>
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
27 #include <linux/gfp.h>
28
29 #include "smumgr.h"
30 #include "tonga_smumgr.h"
31 #include "smu_ucode_xfer_vi.h"
32 #include "tonga_ppsmc.h"
33 #include "smu/smu_7_1_2_d.h"
34 #include "smu/smu_7_1_2_sh_mask.h"
35 #include "cgs_common.h"
36 #include "smu7_smumgr.h"
37
38 #include "smu7_dyn_defaults.h"
39
40 #include "smu7_hwmgr.h"
41 #include "hardwaremanager.h"
42 #include "ppatomctrl.h"
43
44 #include "atombios.h"
45
46 #include "pppcielanes.h"
47 #include "pp_endian.h"
48
49 #include "gmc/gmc_8_1_d.h"
50 #include "gmc/gmc_8_1_sh_mask.h"
51
52 #include "bif/bif_5_0_d.h"
53 #include "bif/bif_5_0_sh_mask.h"
54
55 #include "dce/dce_10_0_d.h"
56 #include "dce/dce_10_0_sh_mask.h"
57
58
59 #define VOLTAGE_SCALE 4
60 #define POWERTUNE_DEFAULT_SET_MAX    1
61 #define VOLTAGE_VID_OFFSET_SCALE1   625
62 #define VOLTAGE_VID_OFFSET_SCALE2   100
63 #define MC_CG_ARB_FREQ_F1           0x0b
64 #define VDDC_VDDCI_DELTA            200
65
66
67 static const struct tonga_pt_defaults tonga_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
68 /* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc,  TDC_MAWt,
69  * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,        BAPM_TEMP_GRADIENT
70  */
71         {1,               0xF,             0xFD,                0x19,
72          5,               45,                 0,              0xB0000,
73          {0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8,
74                 0xC9, 0xC9, 0x2F, 0x4D, 0x61},
75          {0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203,
76                 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4}
77         },
78 };
79
80 /* [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
81 static const uint16_t tonga_clock_stretcher_lookup_table[2][4] = {
82         {600, 1050, 3, 0},
83         {600, 1050, 6, 1}
84 };
85
86 /* [FF, SS] type, [] 4 voltage ranges,
87  * and [Floor Freq, Boundary Freq, VID min , VID max]
88  */
89 static const uint32_t tonga_clock_stretcher_ddt_table[2][4][4] = {
90         { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
91         { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} }
92 };
93
94 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] */
95 static const uint8_t tonga_clock_stretch_amount_conversion[2][6] = {
96         {0, 1, 3, 2, 4, 5},
97         {0, 2, 4, 5, 6, 5}
98 };
99
100 static int tonga_start_in_protection_mode(struct pp_hwmgr *hwmgr)
101 {
102         int result;
103
104         /* Assert reset */
105         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
106                 SMC_SYSCON_RESET_CNTL, rst_reg, 1);
107
108         result = smu7_upload_smu_firmware_image(hwmgr);
109         if (result)
110                 return result;
111
112         /* Clear status */
113         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
114                 ixSMU_STATUS, 0);
115
116         /* Enable clock */
117         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
118                 SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
119
120         /* De-assert reset */
121         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
122                 SMC_SYSCON_RESET_CNTL, rst_reg, 0);
123
124         /* Set SMU Auto Start */
125         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
126                 SMU_INPUT_DATA, AUTO_START, 1);
127
128         /* Clear firmware interrupt enable flag */
129         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
130                 ixFIRMWARE_FLAGS, 0);
131
132         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND,
133                 RCU_UC_EVENTS, INTERRUPTS_ENABLED, 1);
134
135         /**
136          * Call Test SMU message with 0x20000 offset to trigger SMU start
137          */
138         smu7_send_msg_to_smc_offset(hwmgr);
139
140         /* Wait for done bit to be set */
141         PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
142                 SMU_STATUS, SMU_DONE, 0);
143
144         /* Check pass/failed indicator */
145         if (1 != PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
146                                 CGS_IND_REG__SMC, SMU_STATUS, SMU_PASS)) {
147                 pr_err("SMU Firmware start failed\n");
148                 return -EINVAL;
149         }
150
151         /* Wait for firmware to initialize */
152         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND,
153                 FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
154
155         return 0;
156 }
157
158 static int tonga_start_in_non_protection_mode(struct pp_hwmgr *hwmgr)
159 {
160         int result = 0;
161
162         /* wait for smc boot up */
163         PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
164                 RCU_UC_EVENTS, boot_seq_done, 0);
165
166         /*Clear firmware interrupt enable flag*/
167         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
168                 ixFIRMWARE_FLAGS, 0);
169
170
171         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
172                 SMC_SYSCON_RESET_CNTL, rst_reg, 1);
173
174         result = smu7_upload_smu_firmware_image(hwmgr);
175
176         if (result != 0)
177                 return result;
178
179         /* Set smc instruct start point at 0x0 */
180         smu7_program_jump_on_start(hwmgr);
181
182
183         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
184                 SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
185
186         /*De-assert reset*/
187         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
188                 SMC_SYSCON_RESET_CNTL, rst_reg, 0);
189
190         /* Wait for firmware to initialize */
191         PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, SMC_IND,
192                 FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
193
194         return result;
195 }
196
197 static int tonga_start_smu(struct pp_hwmgr *hwmgr)
198 {
199         int result;
200
201         /* Only start SMC if SMC RAM is not running */
202         if (!(smu7_is_smc_ram_running(hwmgr) ||
203                 cgs_is_virtualization_enabled(hwmgr->device))) {
204                 /*Check if SMU is running in protected mode*/
205                 if (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
206                                         SMU_FIRMWARE, SMU_MODE)) {
207                         result = tonga_start_in_non_protection_mode(hwmgr);
208                         if (result)
209                                 return result;
210                 } else {
211                         result = tonga_start_in_protection_mode(hwmgr);
212                         if (result)
213                                 return result;
214                 }
215         }
216
217         result = smu7_request_smu_load_fw(hwmgr);
218
219         return result;
220 }
221
222 static int tonga_smu_init(struct pp_hwmgr *hwmgr)
223 {
224         struct tonga_smumgr *tonga_priv = NULL;
225
226         tonga_priv = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL);
227         if (tonga_priv == NULL)
228                 return -ENOMEM;
229
230         hwmgr->smu_backend = tonga_priv;
231
232         if (smu7_init(hwmgr)) {
233                 kfree(tonga_priv);
234                 return -EINVAL;
235         }
236
237         return 0;
238 }
239
240
241 static int tonga_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
242         phm_ppt_v1_clock_voltage_dependency_table *allowed_clock_voltage_table,
243         uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
244 {
245         uint32_t i = 0;
246         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
247         struct phm_ppt_v1_information *pptable_info =
248                            (struct phm_ppt_v1_information *)(hwmgr->pptable);
249
250         /* clock - voltage dependency table is empty table */
251         if (allowed_clock_voltage_table->count == 0)
252                 return -EINVAL;
253
254         for (i = 0; i < allowed_clock_voltage_table->count; i++) {
255                 /* find first sclk bigger than request */
256                 if (allowed_clock_voltage_table->entries[i].clk >= clock) {
257                         voltage->VddGfx = phm_get_voltage_index(
258                                         pptable_info->vddgfx_lookup_table,
259                                 allowed_clock_voltage_table->entries[i].vddgfx);
260                         voltage->Vddc = phm_get_voltage_index(
261                                                 pptable_info->vddc_lookup_table,
262                                   allowed_clock_voltage_table->entries[i].vddc);
263
264                         if (allowed_clock_voltage_table->entries[i].vddci)
265                                 voltage->Vddci =
266                                         phm_get_voltage_id(&data->vddci_voltage_table, allowed_clock_voltage_table->entries[i].vddci);
267                         else
268                                 voltage->Vddci =
269                                         phm_get_voltage_id(&data->vddci_voltage_table,
270                                                 allowed_clock_voltage_table->entries[i].vddc - VDDC_VDDCI_DELTA);
271
272
273                         if (allowed_clock_voltage_table->entries[i].mvdd)
274                                 *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i].mvdd;
275
276                         voltage->Phases = 1;
277                         return 0;
278                 }
279         }
280
281         /* sclk is bigger than max sclk in the dependence table */
282         voltage->VddGfx = phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
283                 allowed_clock_voltage_table->entries[i-1].vddgfx);
284         voltage->Vddc = phm_get_voltage_index(pptable_info->vddc_lookup_table,
285                 allowed_clock_voltage_table->entries[i-1].vddc);
286
287         if (allowed_clock_voltage_table->entries[i-1].vddci)
288                 voltage->Vddci = phm_get_voltage_id(&data->vddci_voltage_table,
289                         allowed_clock_voltage_table->entries[i-1].vddci);
290
291         if (allowed_clock_voltage_table->entries[i-1].mvdd)
292                 *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i-1].mvdd;
293
294         return 0;
295 }
296
297 static int tonga_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
298                         SMU72_Discrete_DpmTable *table)
299 {
300         unsigned int count;
301         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
302
303         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
304                 table->VddcLevelCount = data->vddc_voltage_table.count;
305                 for (count = 0; count < table->VddcLevelCount; count++) {
306                         table->VddcTable[count] =
307                                 PP_HOST_TO_SMC_US(data->vddc_voltage_table.entries[count].value * VOLTAGE_SCALE);
308                 }
309                 CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
310         }
311         return 0;
312 }
313
314 static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr *hwmgr,
315                         SMU72_Discrete_DpmTable *table)
316 {
317         unsigned int count;
318         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
319
320         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
321                 table->VddGfxLevelCount = data->vddgfx_voltage_table.count;
322                 for (count = 0; count < data->vddgfx_voltage_table.count; count++) {
323                         table->VddGfxTable[count] =
324                                 PP_HOST_TO_SMC_US(data->vddgfx_voltage_table.entries[count].value * VOLTAGE_SCALE);
325                 }
326                 CONVERT_FROM_HOST_TO_SMC_UL(table->VddGfxLevelCount);
327         }
328         return 0;
329 }
330
331 static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
332                         SMU72_Discrete_DpmTable *table)
333 {
334         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
335         uint32_t count;
336
337         table->VddciLevelCount = data->vddci_voltage_table.count;
338         for (count = 0; count < table->VddciLevelCount; count++) {
339                 if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
340                         table->VddciTable[count] =
341                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
342                 } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
343                         table->SmioTable1.Pattern[count].Voltage =
344                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
345                         /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
346                         table->SmioTable1.Pattern[count].Smio =
347                                 (uint8_t) count;
348                         table->Smio[count] |=
349                                 data->vddci_voltage_table.entries[count].smio_low;
350                         table->VddciTable[count] =
351                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
352                 }
353         }
354
355         table->SmioMask1 = data->vddci_voltage_table.mask_low;
356         CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
357
358         return 0;
359 }
360
361 static int tonga_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
362                         SMU72_Discrete_DpmTable *table)
363 {
364         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
365         uint32_t count;
366
367         if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
368                 table->MvddLevelCount = data->mvdd_voltage_table.count;
369                 for (count = 0; count < table->MvddLevelCount; count++) {
370                         table->SmioTable2.Pattern[count].Voltage =
371                                 PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
372                         /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
373                         table->SmioTable2.Pattern[count].Smio =
374                                 (uint8_t) count;
375                         table->Smio[count] |=
376                                 data->mvdd_voltage_table.entries[count].smio_low;
377                 }
378                 table->SmioMask2 = data->mvdd_voltage_table.mask_low;
379
380                 CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
381         }
382
383         return 0;
384 }
385
386 static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr,
387                         SMU72_Discrete_DpmTable *table)
388 {
389         uint32_t count;
390         uint8_t index = 0;
391         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
392         struct phm_ppt_v1_information *pptable_info =
393                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
394         struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table =
395                                            pptable_info->vddgfx_lookup_table;
396         struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table =
397                                                 pptable_info->vddc_lookup_table;
398
399         /* table is already swapped, so in order to use the value from it
400          * we need to swap it back.
401          */
402         uint32_t vddc_level_count = PP_SMC_TO_HOST_UL(table->VddcLevelCount);
403         uint32_t vddgfx_level_count = PP_SMC_TO_HOST_UL(table->VddGfxLevelCount);
404
405         for (count = 0; count < vddc_level_count; count++) {
406                 /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
407                 index = phm_get_voltage_index(vddc_lookup_table,
408                         data->vddc_voltage_table.entries[count].value);
409                 table->BapmVddcVidLoSidd[count] =
410                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
411                 table->BapmVddcVidHiSidd[count] =
412                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
413                 table->BapmVddcVidHiSidd2[count] =
414                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
415         }
416
417         if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
418                 /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
419                 for (count = 0; count < vddgfx_level_count; count++) {
420                         index = phm_get_voltage_index(vddgfx_lookup_table,
421                                 convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_mid));
422                         table->BapmVddGfxVidHiSidd2[count] =
423                                 convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_high);
424                 }
425         } else {
426                 for (count = 0; count < vddc_level_count; count++) {
427                         index = phm_get_voltage_index(vddc_lookup_table,
428                                 data->vddc_voltage_table.entries[count].value);
429                         table->BapmVddGfxVidLoSidd[count] =
430                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
431                         table->BapmVddGfxVidHiSidd[count] =
432                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
433                         table->BapmVddGfxVidHiSidd2[count] =
434                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
435                 }
436         }
437
438         return 0;
439 }
440
441 static int tonga_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
442         SMU72_Discrete_DpmTable *table)
443 {
444         int result;
445
446         result = tonga_populate_smc_vddc_table(hwmgr, table);
447         PP_ASSERT_WITH_CODE(!result,
448                         "can not populate VDDC voltage table to SMC",
449                         return -EINVAL);
450
451         result = tonga_populate_smc_vdd_ci_table(hwmgr, table);
452         PP_ASSERT_WITH_CODE(!result,
453                         "can not populate VDDCI voltage table to SMC",
454                         return -EINVAL);
455
456         result = tonga_populate_smc_vdd_gfx_table(hwmgr, table);
457         PP_ASSERT_WITH_CODE(!result,
458                         "can not populate VDDGFX voltage table to SMC",
459                         return -EINVAL);
460
461         result = tonga_populate_smc_mvdd_table(hwmgr, table);
462         PP_ASSERT_WITH_CODE(!result,
463                         "can not populate MVDD voltage table to SMC",
464                         return -EINVAL);
465
466         result = tonga_populate_cac_tables(hwmgr, table);
467         PP_ASSERT_WITH_CODE(!result,
468                         "can not populate CAC voltage tables to SMC",
469                         return -EINVAL);
470
471         return 0;
472 }
473
474 static int tonga_populate_ulv_level(struct pp_hwmgr *hwmgr,
475                 struct SMU72_Discrete_Ulv *state)
476 {
477         struct phm_ppt_v1_information *table_info =
478                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
479
480         state->CcPwrDynRm = 0;
481         state->CcPwrDynRm1 = 0;
482
483         state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
484         state->VddcOffsetVid = (uint8_t)(table_info->us_ulv_voltage_offset *
485                         VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
486
487         state->VddcPhase = 1;
488
489         CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
490         CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
491         CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
492
493         return 0;
494 }
495
496 static int tonga_populate_ulv_state(struct pp_hwmgr *hwmgr,
497                 struct SMU72_Discrete_DpmTable *table)
498 {
499         return tonga_populate_ulv_level(hwmgr, &table->Ulv);
500 }
501
502 static int tonga_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU72_Discrete_DpmTable *table)
503 {
504         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
505         struct smu7_dpm_table *dpm_table = &data->dpm_table;
506         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
507         uint32_t i;
508
509         /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
510         for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
511                 table->LinkLevel[i].PcieGenSpeed  =
512                         (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
513                 table->LinkLevel[i].PcieLaneCount =
514                         (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
515                 table->LinkLevel[i].EnabledForActivity =
516                         1;
517                 table->LinkLevel[i].SPC =
518                         (uint8_t)(data->pcie_spc_cap & 0xff);
519                 table->LinkLevel[i].DownThreshold =
520                         PP_HOST_TO_SMC_UL(5);
521                 table->LinkLevel[i].UpThreshold =
522                         PP_HOST_TO_SMC_UL(30);
523         }
524
525         smu_data->smc_state_table.LinkLevelCount =
526                 (uint8_t)dpm_table->pcie_speed_table.count;
527         data->dpm_level_enable_mask.pcie_dpm_enable_mask =
528                 phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
529
530         return 0;
531 }
532
533 static int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr,
534                 uint32_t engine_clock, SMU72_Discrete_GraphicsLevel *sclk)
535 {
536         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
537         pp_atomctrl_clock_dividers_vi dividers;
538         uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
539         uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
540         uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
541         uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
542         uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
543         uint32_t    reference_clock;
544         uint32_t reference_divider;
545         uint32_t fbdiv;
546         int result;
547
548         /* get the engine clock dividers for this clock value*/
549         result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock,  &dividers);
550
551         PP_ASSERT_WITH_CODE(result == 0,
552                 "Error retrieving Engine Clock dividers from VBIOS.", return result);
553
554         /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
555         reference_clock = atomctrl_get_reference_clock(hwmgr);
556
557         reference_divider = 1 + dividers.uc_pll_ref_div;
558
559         /* low 14 bits is fraction and high 12 bits is divider*/
560         fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
561
562         /* SPLL_FUNC_CNTL setup*/
563         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
564                 CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
565         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
566                 CG_SPLL_FUNC_CNTL, SPLL_PDIV_A,  dividers.uc_pll_post_div);
567
568         /* SPLL_FUNC_CNTL_3 setup*/
569         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
570                 CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
571
572         /* set to use fractional accumulation*/
573         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
574                 CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
575
576         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
577                         PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
578                 pp_atomctrl_internal_ss_info ss_info;
579
580                 uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
581                 if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
582                         /*
583                         * ss_info.speed_spectrum_percentage -- in unit of 0.01%
584                         * ss_info.speed_spectrum_rate -- in unit of khz
585                         */
586                         /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
587                         uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
588
589                         /* clkv = 2 * D * fbdiv / NS */
590                         uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
591
592                         cg_spll_spread_spectrum =
593                                 PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
594                         cg_spll_spread_spectrum =
595                                 PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
596                         cg_spll_spread_spectrum_2 =
597                                 PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
598                 }
599         }
600
601         sclk->SclkFrequency        = engine_clock;
602         sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
603         sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
604         sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
605         sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
606         sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
607
608         return 0;
609 }
610
611 static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
612                                                 uint32_t engine_clock,
613                                 SMU72_Discrete_GraphicsLevel *graphic_level)
614 {
615         int result;
616         uint32_t mvdd;
617         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
618         struct phm_ppt_v1_information *pptable_info =
619                             (struct phm_ppt_v1_information *)(hwmgr->pptable);
620         phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL;
621
622         result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
623
624         if (hwmgr->od_enabled)
625                 vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk;
626         else
627                 vdd_dep_table = pptable_info->vdd_dep_on_sclk;
628
629         /* populate graphics levels*/
630         result = tonga_get_dependency_volt_by_clk(hwmgr,
631                 vdd_dep_table, engine_clock,
632                 &graphic_level->MinVoltage, &mvdd);
633         PP_ASSERT_WITH_CODE((!result),
634                 "can not find VDDC voltage value for VDDC "
635                 "engine clock dependency table", return result);
636
637         /* SCLK frequency in units of 10KHz*/
638         graphic_level->SclkFrequency = engine_clock;
639         /* Indicates maximum activity level for this performance level. 50% for now*/
640         graphic_level->ActivityLevel = data->current_profile_setting.sclk_activity;
641
642         graphic_level->CcPwrDynRm = 0;
643         graphic_level->CcPwrDynRm1 = 0;
644         /* this level can be used if activity is high enough.*/
645         graphic_level->EnabledForActivity = 0;
646         /* this level can be used for throttling.*/
647         graphic_level->EnabledForThrottle = 1;
648         graphic_level->UpHyst = data->current_profile_setting.sclk_up_hyst;
649         graphic_level->DownHyst = data->current_profile_setting.sclk_down_hyst;
650         graphic_level->VoltageDownHyst = 0;
651         graphic_level->PowerThrottle = 0;
652
653         data->display_timing.min_clock_in_sr =
654                         hwmgr->display_config.min_core_set_clock_in_sr;
655
656         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
657                         PHM_PlatformCaps_SclkDeepSleep))
658                 graphic_level->DeepSleepDivId =
659                                 smu7_get_sleep_divider_id_from_clock(engine_clock,
660                                                 data->display_timing.min_clock_in_sr);
661
662         /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
663         graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
664
665         if (!result) {
666                 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
667                 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
668                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
669                 CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
670                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
671                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
672                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
673                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
674                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
675                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
676         }
677
678         return result;
679 }
680
681 static int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
682 {
683         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
684         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
685         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
686         struct smu7_dpm_table *dpm_table = &data->dpm_table;
687         struct phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
688         uint8_t pcie_entry_count = (uint8_t) data->dpm_table.pcie_speed_table.count;
689         uint32_t level_array_address = smu_data->smu7_data.dpm_table_start +
690                                 offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
691
692         uint32_t level_array_size = sizeof(SMU72_Discrete_GraphicsLevel) *
693                                                 SMU72_MAX_LEVELS_GRAPHICS;
694
695         SMU72_Discrete_GraphicsLevel *levels = smu_data->smc_state_table.GraphicsLevel;
696
697         uint32_t i, max_entry;
698         uint8_t highest_pcie_level_enabled = 0;
699         uint8_t lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0;
700         uint8_t count = 0;
701         int result = 0;
702
703         memset(levels, 0x00, level_array_size);
704
705         for (i = 0; i < dpm_table->sclk_table.count; i++) {
706                 result = tonga_populate_single_graphic_level(hwmgr,
707                                         dpm_table->sclk_table.dpm_levels[i].value,
708                                         &(smu_data->smc_state_table.GraphicsLevel[i]));
709                 if (result != 0)
710                         return result;
711
712                 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
713                 if (i > 1)
714                         smu_data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
715         }
716
717         /* Only enable level 0 for now. */
718         smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
719
720         /* set highest level watermark to high */
721         if (dpm_table->sclk_table.count > 1)
722                 smu_data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
723                         PPSMC_DISPLAY_WATERMARK_HIGH;
724
725         smu_data->smc_state_table.GraphicsDpmLevelCount =
726                 (uint8_t)dpm_table->sclk_table.count;
727         data->dpm_level_enable_mask.sclk_dpm_enable_mask =
728                 phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
729
730         if (pcie_table != NULL) {
731                 PP_ASSERT_WITH_CODE((pcie_entry_count >= 1),
732                         "There must be 1 or more PCIE levels defined in PPTable.",
733                         return -EINVAL);
734                 max_entry = pcie_entry_count - 1; /* for indexing, we need to decrement by 1.*/
735                 for (i = 0; i < dpm_table->sclk_table.count; i++) {
736                         smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel =
737                                 (uint8_t) ((i < max_entry) ? i : max_entry);
738                 }
739         } else {
740                 if (0 == data->dpm_level_enable_mask.pcie_dpm_enable_mask)
741                         pr_err("Pcie Dpm Enablemask is 0 !");
742
743                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
744                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
745                                         (1<<(highest_pcie_level_enabled+1))) != 0)) {
746                         highest_pcie_level_enabled++;
747                 }
748
749                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
750                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
751                                         (1<<lowest_pcie_level_enabled)) == 0)) {
752                         lowest_pcie_level_enabled++;
753                 }
754
755                 while ((count < highest_pcie_level_enabled) &&
756                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
757                                         (1<<(lowest_pcie_level_enabled+1+count))) == 0)) {
758                         count++;
759                 }
760                 mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
761                         (lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
762
763
764                 /* set pcieDpmLevel to highest_pcie_level_enabled*/
765                 for (i = 2; i < dpm_table->sclk_table.count; i++)
766                         smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
767
768                 /* set pcieDpmLevel to lowest_pcie_level_enabled*/
769                 smu_data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
770
771                 /* set pcieDpmLevel to mid_pcie_level_enabled*/
772                 smu_data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
773         }
774         /* level count will send to smc once at init smc table and never change*/
775         result = smu7_copy_bytes_to_smc(hwmgr, level_array_address,
776                                 (uint8_t *)levels, (uint32_t)level_array_size,
777                                                                 SMC_RAM_END);
778
779         return result;
780 }
781
782 static int tonga_calculate_mclk_params(
783                 struct pp_hwmgr *hwmgr,
784                 uint32_t memory_clock,
785                 SMU72_Discrete_MemoryLevel *mclk,
786                 bool strobe_mode,
787                 bool dllStateOn
788                 )
789 {
790         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
791
792         uint32_t dll_cntl = data->clock_registers.vDLL_CNTL;
793         uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
794         uint32_t mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
795         uint32_t mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
796         uint32_t mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
797         uint32_t mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
798         uint32_t mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
799         uint32_t mpll_ss1 = data->clock_registers.vMPLL_SS1;
800         uint32_t mpll_ss2 = data->clock_registers.vMPLL_SS2;
801
802         pp_atomctrl_memory_clock_param mpll_param;
803         int result;
804
805         result = atomctrl_get_memory_pll_dividers_si(hwmgr,
806                                 memory_clock, &mpll_param, strobe_mode);
807         PP_ASSERT_WITH_CODE(
808                         !result,
809                         "Error retrieving Memory Clock Parameters from VBIOS.",
810                         return result);
811
812         /* MPLL_FUNC_CNTL setup*/
813         mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL,
814                                         mpll_param.bw_ctrl);
815
816         /* MPLL_FUNC_CNTL_1 setup*/
817         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
818                                         MPLL_FUNC_CNTL_1, CLKF,
819                                         mpll_param.mpll_fb_divider.cl_kf);
820         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
821                                         MPLL_FUNC_CNTL_1, CLKFRAC,
822                                         mpll_param.mpll_fb_divider.clk_frac);
823         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
824                                                 MPLL_FUNC_CNTL_1, VCO_MODE,
825                                                 mpll_param.vco_mode);
826
827         /* MPLL_AD_FUNC_CNTL setup*/
828         mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
829                                         MPLL_AD_FUNC_CNTL, YCLK_POST_DIV,
830                                         mpll_param.mpll_post_divider);
831
832         if (data->is_memory_gddr5) {
833                 /* MPLL_DQ_FUNC_CNTL setup*/
834                 mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
835                                                 MPLL_DQ_FUNC_CNTL, YCLK_SEL,
836                                                 mpll_param.yclk_sel);
837                 mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
838                                                 MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV,
839                                                 mpll_param.mpll_post_divider);
840         }
841
842         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
843                         PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
844                 /*
845                  ************************************
846                  Fref = Reference Frequency
847                  NF = Feedback divider ratio
848                  NR = Reference divider ratio
849                  Fnom = Nominal VCO output frequency = Fref * NF / NR
850                  Fs = Spreading Rate
851                  D = Percentage down-spread / 2
852                  Fint = Reference input frequency to PFD = Fref / NR
853                  NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
854                  CLKS = NS - 1 = ISS_STEP_NUM[11:0]
855                  NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
856                  CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
857                  *************************************
858                  */
859                 pp_atomctrl_internal_ss_info ss_info;
860                 uint32_t freq_nom;
861                 uint32_t tmp;
862                 uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
863
864                 /* for GDDR5 for all modes and DDR3 */
865                 if (1 == mpll_param.qdr)
866                         freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
867                 else
868                         freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
869
870                 /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
871                 tmp = (freq_nom / reference_clock);
872                 tmp = tmp * tmp;
873
874                 if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
875                         /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
876                         /* ss.Info.speed_spectrum_rate -- in unit of khz */
877                         /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
878                         /*     = reference_clock * 5 / speed_spectrum_rate */
879                         uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
880
881                         /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
882                         /*     = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
883                         uint32_t clkv =
884                                 (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
885                                                         ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
886
887                         mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
888                         mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
889                 }
890         }
891
892         /* MCLK_PWRMGT_CNTL setup */
893         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
894                 MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
895         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
896                 MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
897         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
898                 MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
899
900         /* Save the result data to outpupt memory level structure */
901         mclk->MclkFrequency   = memory_clock;
902         mclk->MpllFuncCntl    = mpll_func_cntl;
903         mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
904         mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
905         mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
906         mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
907         mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
908         mclk->DllCntl         = dll_cntl;
909         mclk->MpllSs1         = mpll_ss1;
910         mclk->MpllSs2         = mpll_ss2;
911
912         return 0;
913 }
914
915 static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock,
916                 bool strobe_mode)
917 {
918         uint8_t mc_para_index;
919
920         if (strobe_mode) {
921                 if (memory_clock < 12500)
922                         mc_para_index = 0x00;
923                 else if (memory_clock > 47500)
924                         mc_para_index = 0x0f;
925                 else
926                         mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
927         } else {
928                 if (memory_clock < 65000)
929                         mc_para_index = 0x00;
930                 else if (memory_clock > 135000)
931                         mc_para_index = 0x0f;
932                 else
933                         mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
934         }
935
936         return mc_para_index;
937 }
938
939 static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
940 {
941         uint8_t mc_para_index;
942
943         if (memory_clock < 10000)
944                 mc_para_index = 0;
945         else if (memory_clock >= 80000)
946                 mc_para_index = 0x0f;
947         else
948                 mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
949
950         return mc_para_index;
951 }
952
953
954 static int tonga_populate_single_memory_level(
955                 struct pp_hwmgr *hwmgr,
956                 uint32_t memory_clock,
957                 SMU72_Discrete_MemoryLevel *memory_level
958                 )
959 {
960         uint32_t mvdd = 0;
961         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
962         struct phm_ppt_v1_information *pptable_info =
963                           (struct phm_ppt_v1_information *)(hwmgr->pptable);
964         int result = 0;
965         bool dll_state_on;
966         struct cgs_display_info info = {0};
967         uint32_t mclk_edc_wr_enable_threshold = 40000;
968         uint32_t mclk_stutter_mode_threshold = 30000;
969         uint32_t mclk_edc_enable_threshold = 40000;
970         uint32_t mclk_strobe_mode_threshold = 40000;
971         phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL;
972
973         if (hwmgr->od_enabled)
974                 vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_mclk;
975         else
976                 vdd_dep_table = pptable_info->vdd_dep_on_mclk;
977
978         if (NULL != vdd_dep_table) {
979                 result = tonga_get_dependency_volt_by_clk(hwmgr,
980                                 vdd_dep_table,
981                                 memory_clock,
982                                 &memory_level->MinVoltage, &mvdd);
983                 PP_ASSERT_WITH_CODE(
984                         !result,
985                         "can not find MinVddc voltage value from memory VDDC "
986                         "voltage dependency table",
987                         return result);
988         }
989
990         if (data->mvdd_control == SMU7_VOLTAGE_CONTROL_NONE)
991                 memory_level->MinMvdd = data->vbios_boot_state.mvdd_bootup_value;
992         else
993                 memory_level->MinMvdd = mvdd;
994
995         memory_level->EnabledForThrottle = 1;
996         memory_level->EnabledForActivity = 0;
997         memory_level->UpHyst = data->current_profile_setting.mclk_up_hyst;
998         memory_level->DownHyst = data->current_profile_setting.mclk_down_hyst;
999         memory_level->VoltageDownHyst = 0;
1000
1001         /* Indicates maximum activity level for this performance level.*/
1002         memory_level->ActivityLevel = data->current_profile_setting.mclk_activity;
1003         memory_level->StutterEnable = 0;
1004         memory_level->StrobeEnable = 0;
1005         memory_level->EdcReadEnable = 0;
1006         memory_level->EdcWriteEnable = 0;
1007         memory_level->RttEnable = 0;
1008
1009         /* default set to low watermark. Highest level will be set to high later.*/
1010         memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1011
1012         cgs_get_active_displays_info(hwmgr->device, &info);
1013         data->display_timing.num_existing_displays = info.display_count;
1014
1015         if ((mclk_stutter_mode_threshold != 0) &&
1016             (memory_clock <= mclk_stutter_mode_threshold) &&
1017             (!data->is_uvd_enabled)
1018             && (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE) & 0x1)
1019             && (data->display_timing.num_existing_displays <= 2)
1020             && (data->display_timing.num_existing_displays != 0))
1021                 memory_level->StutterEnable = 1;
1022
1023         /* decide strobe mode*/
1024         memory_level->StrobeEnable = (mclk_strobe_mode_threshold != 0) &&
1025                 (memory_clock <= mclk_strobe_mode_threshold);
1026
1027         /* decide EDC mode and memory clock ratio*/
1028         if (data->is_memory_gddr5) {
1029                 memory_level->StrobeRatio = tonga_get_mclk_frequency_ratio(memory_clock,
1030                                         memory_level->StrobeEnable);
1031
1032                 if ((mclk_edc_enable_threshold != 0) &&
1033                                 (memory_clock > mclk_edc_enable_threshold)) {
1034                         memory_level->EdcReadEnable = 1;
1035                 }
1036
1037                 if ((mclk_edc_wr_enable_threshold != 0) &&
1038                                 (memory_clock > mclk_edc_wr_enable_threshold)) {
1039                         memory_level->EdcWriteEnable = 1;
1040                 }
1041
1042                 if (memory_level->StrobeEnable) {
1043                         if (tonga_get_mclk_frequency_ratio(memory_clock, 1) >=
1044                                         ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf)) {
1045                                 dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
1046                         } else {
1047                                 dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
1048                         }
1049
1050                 } else {
1051                         dll_state_on = data->dll_default_on;
1052                 }
1053         } else {
1054                 memory_level->StrobeRatio =
1055                         tonga_get_ddr3_mclk_frequency_ratio(memory_clock);
1056                 dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
1057         }
1058
1059         result = tonga_calculate_mclk_params(hwmgr,
1060                 memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
1061
1062         if (!result) {
1063                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinMvdd);
1064                 /* MCLK frequency in units of 10KHz*/
1065                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
1066                 /* Indicates maximum activity level for this performance level.*/
1067                 CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
1068                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
1069                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
1070                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
1071                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
1072                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
1073                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
1074                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
1075                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
1076                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
1077         }
1078
1079         return result;
1080 }
1081
1082 int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
1083 {
1084         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1085         struct tonga_smumgr *smu_data =
1086                         (struct tonga_smumgr *)(hwmgr->smu_backend);
1087         struct smu7_dpm_table *dpm_table = &data->dpm_table;
1088         int result;
1089
1090         /* populate MCLK dpm table to SMU7 */
1091         uint32_t level_array_address =
1092                                 smu_data->smu7_data.dpm_table_start +
1093                                 offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
1094         uint32_t level_array_size =
1095                                 sizeof(SMU72_Discrete_MemoryLevel) *
1096                                 SMU72_MAX_LEVELS_MEMORY;
1097         SMU72_Discrete_MemoryLevel *levels =
1098                                 smu_data->smc_state_table.MemoryLevel;
1099         uint32_t i;
1100
1101         memset(levels, 0x00, level_array_size);
1102
1103         for (i = 0; i < dpm_table->mclk_table.count; i++) {
1104                 PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
1105                         "can not populate memory level as memory clock is zero",
1106                         return -EINVAL);
1107                 result = tonga_populate_single_memory_level(
1108                                 hwmgr,
1109                                 dpm_table->mclk_table.dpm_levels[i].value,
1110                                 &(smu_data->smc_state_table.MemoryLevel[i]));
1111                 if (result)
1112                         return result;
1113         }
1114
1115         /* Only enable level 0 for now.*/
1116         smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
1117
1118         /*
1119         * in order to prevent MC activity from stutter mode to push DPM up.
1120         * the UVD change complements this by putting the MCLK in a higher state
1121         * by default such that we are not effected by up threshold or and MCLK DPM latency.
1122         */
1123         smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
1124         CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
1125
1126         smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
1127         data->dpm_level_enable_mask.mclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
1128         /* set highest level watermark to high*/
1129         smu_data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
1130
1131         /* level count will send to smc once at init smc table and never change*/
1132         result = smu7_copy_bytes_to_smc(hwmgr,
1133                 level_array_address, (uint8_t *)levels, (uint32_t)level_array_size,
1134                 SMC_RAM_END);
1135
1136         return result;
1137 }
1138
1139 static int tonga_populate_mvdd_value(struct pp_hwmgr *hwmgr,
1140                                 uint32_t mclk, SMIO_Pattern *smio_pattern)
1141 {
1142         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1143         struct phm_ppt_v1_information *table_info =
1144                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1145         uint32_t i = 0;
1146
1147         if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
1148                 /* find mvdd value which clock is more than request */
1149                 for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
1150                         if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
1151                                 /* Always round to higher voltage. */
1152                                 smio_pattern->Voltage =
1153                                       data->mvdd_voltage_table.entries[i].value;
1154                                 break;
1155                         }
1156                 }
1157
1158                 PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
1159                         "MVDD Voltage is outside the supported range.",
1160                         return -EINVAL);
1161         } else {
1162                 return -EINVAL;
1163         }
1164
1165         return 0;
1166 }
1167
1168
1169 static int tonga_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
1170         SMU72_Discrete_DpmTable *table)
1171 {
1172         int result = 0;
1173         struct tonga_smumgr *smu_data =
1174                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
1175         const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1176         struct pp_atomctrl_clock_dividers_vi dividers;
1177
1178         SMIO_Pattern voltage_level;
1179         uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
1180         uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
1181         uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
1182         uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
1183
1184         /* The ACPI state should not do DPM on DC (or ever).*/
1185         table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
1186
1187         table->ACPILevel.MinVoltage =
1188                         smu_data->smc_state_table.GraphicsLevel[0].MinVoltage;
1189
1190         /* assign zero for now*/
1191         table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
1192
1193         /* get the engine clock dividers for this clock value*/
1194         result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
1195                 table->ACPILevel.SclkFrequency,  &dividers);
1196
1197         PP_ASSERT_WITH_CODE(result == 0,
1198                 "Error retrieving Engine Clock dividers from VBIOS.",
1199                 return result);
1200
1201         /* divider ID for required SCLK*/
1202         table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
1203         table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
1204         table->ACPILevel.DeepSleepDivId = 0;
1205
1206         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
1207                                         SPLL_PWRON, 0);
1208         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
1209                                                 SPLL_RESET, 1);
1210         spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
1211                                                 SCLK_MUX_SEL, 4);
1212
1213         table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
1214         table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
1215         table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
1216         table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
1217         table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
1218         table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
1219         table->ACPILevel.CcPwrDynRm = 0;
1220         table->ACPILevel.CcPwrDynRm1 = 0;
1221
1222
1223         /* For various features to be enabled/disabled while this level is active.*/
1224         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
1225         /* SCLK frequency in units of 10KHz*/
1226         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
1227         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
1228         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
1229         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
1230         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
1231         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
1232         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
1233         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
1234         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
1235
1236         /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
1237         table->MemoryACPILevel.MinVoltage =
1238                             smu_data->smc_state_table.MemoryLevel[0].MinVoltage;
1239
1240         /*  CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
1241
1242         if (0 == tonga_populate_mvdd_value(hwmgr, 0, &voltage_level))
1243                 table->MemoryACPILevel.MinMvdd =
1244                         PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
1245         else
1246                 table->MemoryACPILevel.MinMvdd = 0;
1247
1248         /* Force reset on DLL*/
1249         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1250                 MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
1251         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1252                 MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
1253
1254         /* Disable DLL in ACPIState*/
1255         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1256                 MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
1257         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1258                 MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
1259
1260         /* Enable DLL bypass signal*/
1261         dll_cntl            = PHM_SET_FIELD(dll_cntl,
1262                 DLL_CNTL, MRDCK0_BYPASS, 0);
1263         dll_cntl            = PHM_SET_FIELD(dll_cntl,
1264                 DLL_CNTL, MRDCK1_BYPASS, 0);
1265
1266         table->MemoryACPILevel.DllCntl            =
1267                 PP_HOST_TO_SMC_UL(dll_cntl);
1268         table->MemoryACPILevel.MclkPwrmgtCntl     =
1269                 PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
1270         table->MemoryACPILevel.MpllAdFuncCntl     =
1271                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
1272         table->MemoryACPILevel.MpllDqFuncCntl     =
1273                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
1274         table->MemoryACPILevel.MpllFuncCntl       =
1275                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
1276         table->MemoryACPILevel.MpllFuncCntl_1     =
1277                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
1278         table->MemoryACPILevel.MpllFuncCntl_2     =
1279                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
1280         table->MemoryACPILevel.MpllSs1            =
1281                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
1282         table->MemoryACPILevel.MpllSs2            =
1283                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
1284
1285         table->MemoryACPILevel.EnabledForThrottle = 0;
1286         table->MemoryACPILevel.EnabledForActivity = 0;
1287         table->MemoryACPILevel.UpHyst = 0;
1288         table->MemoryACPILevel.DownHyst = 100;
1289         table->MemoryACPILevel.VoltageDownHyst = 0;
1290         /* Indicates maximum activity level for this performance level.*/
1291         table->MemoryACPILevel.ActivityLevel =
1292                         PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity);
1293
1294         table->MemoryACPILevel.StutterEnable = 0;
1295         table->MemoryACPILevel.StrobeEnable = 0;
1296         table->MemoryACPILevel.EdcReadEnable = 0;
1297         table->MemoryACPILevel.EdcWriteEnable = 0;
1298         table->MemoryACPILevel.RttEnable = 0;
1299
1300         return result;
1301 }
1302
1303 static int tonga_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
1304                                         SMU72_Discrete_DpmTable *table)
1305 {
1306         int result = 0;
1307
1308         uint8_t count;
1309         pp_atomctrl_clock_dividers_vi dividers;
1310         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1311         struct phm_ppt_v1_information *pptable_info =
1312                                 (struct phm_ppt_v1_information *)(hwmgr->pptable);
1313         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1314                                                 pptable_info->mm_dep_table;
1315
1316         table->UvdLevelCount = (uint8_t) (mm_table->count);
1317         table->UvdBootLevel = 0;
1318
1319         for (count = 0; count < table->UvdLevelCount; count++) {
1320                 table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
1321                 table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
1322                 table->UvdLevel[count].MinVoltage.Vddc =
1323                         phm_get_voltage_index(pptable_info->vddc_lookup_table,
1324                                                 mm_table->entries[count].vddc);
1325                 table->UvdLevel[count].MinVoltage.VddGfx =
1326                         (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
1327                         phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
1328                                                 mm_table->entries[count].vddgfx) : 0;
1329                 table->UvdLevel[count].MinVoltage.Vddci =
1330                         phm_get_voltage_id(&data->vddci_voltage_table,
1331                                              mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
1332                 table->UvdLevel[count].MinVoltage.Phases = 1;
1333
1334                 /* retrieve divider value for VBIOS */
1335                 result = atomctrl_get_dfs_pll_dividers_vi(
1336                                         hwmgr,
1337                                         table->UvdLevel[count].VclkFrequency,
1338                                         &dividers);
1339
1340                 PP_ASSERT_WITH_CODE((!result),
1341                                     "can not find divide id for Vclk clock",
1342                                         return result);
1343
1344                 table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
1345
1346                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1347                                                           table->UvdLevel[count].DclkFrequency, &dividers);
1348                 PP_ASSERT_WITH_CODE((!result),
1349                                     "can not find divide id for Dclk clock",
1350                                         return result);
1351
1352                 table->UvdLevel[count].DclkDivider =
1353                                         (uint8_t)dividers.pll_post_divider;
1354
1355                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
1356                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
1357         }
1358
1359         return result;
1360
1361 }
1362
1363 static int tonga_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
1364                 SMU72_Discrete_DpmTable *table)
1365 {
1366         int result = 0;
1367
1368         uint8_t count;
1369         pp_atomctrl_clock_dividers_vi dividers;
1370         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1371         struct phm_ppt_v1_information *pptable_info =
1372                               (struct phm_ppt_v1_information *)(hwmgr->pptable);
1373         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1374                                                      pptable_info->mm_dep_table;
1375
1376         table->VceLevelCount = (uint8_t) (mm_table->count);
1377         table->VceBootLevel = 0;
1378
1379         for (count = 0; count < table->VceLevelCount; count++) {
1380                 table->VceLevel[count].Frequency =
1381                         mm_table->entries[count].eclk;
1382                 table->VceLevel[count].MinVoltage.Vddc =
1383                         phm_get_voltage_index(pptable_info->vddc_lookup_table,
1384                                 mm_table->entries[count].vddc);
1385                 table->VceLevel[count].MinVoltage.VddGfx =
1386                         (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
1387                         phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
1388                                 mm_table->entries[count].vddgfx) : 0;
1389                 table->VceLevel[count].MinVoltage.Vddci =
1390                         phm_get_voltage_id(&data->vddci_voltage_table,
1391                                 mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
1392                 table->VceLevel[count].MinVoltage.Phases = 1;
1393
1394                 /* retrieve divider value for VBIOS */
1395                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1396                                         table->VceLevel[count].Frequency, &dividers);
1397                 PP_ASSERT_WITH_CODE((!result),
1398                                 "can not find divide id for VCE engine clock",
1399                                 return result);
1400
1401                 table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1402
1403                 CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
1404         }
1405
1406         return result;
1407 }
1408
1409 static int tonga_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
1410                 SMU72_Discrete_DpmTable *table)
1411 {
1412         int result = 0;
1413         uint8_t count;
1414         pp_atomctrl_clock_dividers_vi dividers;
1415         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1416         struct phm_ppt_v1_information *pptable_info =
1417                              (struct phm_ppt_v1_information *)(hwmgr->pptable);
1418         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1419                                                     pptable_info->mm_dep_table;
1420
1421         table->AcpLevelCount = (uint8_t) (mm_table->count);
1422         table->AcpBootLevel = 0;
1423
1424         for (count = 0; count < table->AcpLevelCount; count++) {
1425                 table->AcpLevel[count].Frequency =
1426                         pptable_info->mm_dep_table->entries[count].aclk;
1427                 table->AcpLevel[count].MinVoltage.Vddc =
1428                         phm_get_voltage_index(pptable_info->vddc_lookup_table,
1429                         mm_table->entries[count].vddc);
1430                 table->AcpLevel[count].MinVoltage.VddGfx =
1431                         (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
1432                         phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
1433                                 mm_table->entries[count].vddgfx) : 0;
1434                 table->AcpLevel[count].MinVoltage.Vddci =
1435                         phm_get_voltage_id(&data->vddci_voltage_table,
1436                                 mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
1437                 table->AcpLevel[count].MinVoltage.Phases = 1;
1438
1439                 /* retrieve divider value for VBIOS */
1440                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1441                         table->AcpLevel[count].Frequency, &dividers);
1442                 PP_ASSERT_WITH_CODE((!result),
1443                         "can not find divide id for engine clock", return result);
1444
1445                 table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1446
1447                 CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
1448         }
1449
1450         return result;
1451 }
1452
1453 static int tonga_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
1454                 SMU72_Discrete_DpmTable *table)
1455 {
1456         int result = 0;
1457         uint8_t count;
1458         pp_atomctrl_clock_dividers_vi dividers;
1459         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1460         struct phm_ppt_v1_information *pptable_info =
1461                              (struct phm_ppt_v1_information *)(hwmgr->pptable);
1462         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
1463                                                     pptable_info->mm_dep_table;
1464
1465         table->SamuBootLevel = 0;
1466         table->SamuLevelCount = (uint8_t) (mm_table->count);
1467
1468         for (count = 0; count < table->SamuLevelCount; count++) {
1469                 /* not sure whether we need evclk or not */
1470                 table->SamuLevel[count].Frequency =
1471                         pptable_info->mm_dep_table->entries[count].samclock;
1472                 table->SamuLevel[count].MinVoltage.Vddc =
1473                         phm_get_voltage_index(pptable_info->vddc_lookup_table,
1474                                 mm_table->entries[count].vddc);
1475                 table->SamuLevel[count].MinVoltage.VddGfx =
1476                         (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
1477                         phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
1478                                 mm_table->entries[count].vddgfx) : 0;
1479                 table->SamuLevel[count].MinVoltage.Vddci =
1480                         phm_get_voltage_id(&data->vddci_voltage_table,
1481                                 mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
1482                 table->SamuLevel[count].MinVoltage.Phases = 1;
1483
1484                 /* retrieve divider value for VBIOS */
1485                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1486                                         table->SamuLevel[count].Frequency, &dividers);
1487                 PP_ASSERT_WITH_CODE((!result),
1488                         "can not find divide id for samu clock", return result);
1489
1490                 table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1491
1492                 CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
1493         }
1494
1495         return result;
1496 }
1497
1498 static int tonga_populate_memory_timing_parameters(
1499                 struct pp_hwmgr *hwmgr,
1500                 uint32_t engine_clock,
1501                 uint32_t memory_clock,
1502                 struct SMU72_Discrete_MCArbDramTimingTableEntry *arb_regs
1503                 )
1504 {
1505         uint32_t dramTiming;
1506         uint32_t dramTiming2;
1507         uint32_t burstTime;
1508         int result;
1509
1510         result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
1511                                 engine_clock, memory_clock);
1512
1513         PP_ASSERT_WITH_CODE(result == 0,
1514                 "Error calling VBIOS to set DRAM_TIMING.", return result);
1515
1516         dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
1517         dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
1518         burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
1519
1520         arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
1521         arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
1522         arb_regs->McArbBurstTime = (uint8_t)burstTime;
1523
1524         return 0;
1525 }
1526
1527 static int tonga_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
1528 {
1529         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1530         struct tonga_smumgr *smu_data =
1531                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
1532         int result = 0;
1533         SMU72_Discrete_MCArbDramTimingTable  arb_regs;
1534         uint32_t i, j;
1535
1536         memset(&arb_regs, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable));
1537
1538         for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
1539                 for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
1540                         result = tonga_populate_memory_timing_parameters
1541                                 (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
1542                                  data->dpm_table.mclk_table.dpm_levels[j].value,
1543                                  &arb_regs.entries[i][j]);
1544
1545                         if (result)
1546                                 break;
1547                 }
1548         }
1549
1550         if (!result) {
1551                 result = smu7_copy_bytes_to_smc(
1552                                 hwmgr,
1553                                 smu_data->smu7_data.arb_table_start,
1554                                 (uint8_t *)&arb_regs,
1555                                 sizeof(SMU72_Discrete_MCArbDramTimingTable),
1556                                 SMC_RAM_END
1557                                 );
1558         }
1559
1560         return result;
1561 }
1562
1563 static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
1564                         SMU72_Discrete_DpmTable *table)
1565 {
1566         int result = 0;
1567         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1568         struct tonga_smumgr *smu_data =
1569                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
1570         table->GraphicsBootLevel = 0;
1571         table->MemoryBootLevel = 0;
1572
1573         /* find boot level from dpm table*/
1574         result = phm_find_boot_level(&(data->dpm_table.sclk_table),
1575         data->vbios_boot_state.sclk_bootup_value,
1576         (uint32_t *)&(smu_data->smc_state_table.GraphicsBootLevel));
1577
1578         if (result != 0) {
1579                 smu_data->smc_state_table.GraphicsBootLevel = 0;
1580                 pr_err("[powerplay] VBIOS did not find boot engine "
1581                                 "clock value in dependency table. "
1582                                 "Using Graphics DPM level 0 !");
1583                 result = 0;
1584         }
1585
1586         result = phm_find_boot_level(&(data->dpm_table.mclk_table),
1587                 data->vbios_boot_state.mclk_bootup_value,
1588                 (uint32_t *)&(smu_data->smc_state_table.MemoryBootLevel));
1589
1590         if (result != 0) {
1591                 smu_data->smc_state_table.MemoryBootLevel = 0;
1592                 pr_err("[powerplay] VBIOS did not find boot "
1593                                 "engine clock value in dependency table."
1594                                 "Using Memory DPM level 0 !");
1595                 result = 0;
1596         }
1597
1598         table->BootVoltage.Vddc =
1599                 phm_get_voltage_id(&(data->vddc_voltage_table),
1600                         data->vbios_boot_state.vddc_bootup_value);
1601         table->BootVoltage.VddGfx =
1602                 phm_get_voltage_id(&(data->vddgfx_voltage_table),
1603                         data->vbios_boot_state.vddgfx_bootup_value);
1604         table->BootVoltage.Vddci =
1605                 phm_get_voltage_id(&(data->vddci_voltage_table),
1606                         data->vbios_boot_state.vddci_bootup_value);
1607         table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
1608
1609         CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
1610
1611         return result;
1612 }
1613
1614 static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
1615 {
1616         uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
1617                         volt_with_cks, value;
1618         uint16_t clock_freq_u16;
1619         struct tonga_smumgr *smu_data =
1620                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
1621         uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
1622                         volt_offset = 0;
1623         struct phm_ppt_v1_information *table_info =
1624                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1625         struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
1626                         table_info->vdd_dep_on_sclk;
1627         uint32_t hw_revision, dev_id;
1628         struct amdgpu_device *adev = hwmgr->adev;
1629
1630         stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
1631
1632         hw_revision = adev->pdev->revision;
1633         dev_id = adev->pdev->device;
1634
1635         /* Read SMU_Eefuse to read and calculate RO and determine
1636          * if the part is SS or FF. if RO >= 1660MHz, part is FF.
1637          */
1638         efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1639                         ixSMU_EFUSE_0 + (146 * 4));
1640         efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1641                         ixSMU_EFUSE_0 + (148 * 4));
1642         efuse &= 0xFF000000;
1643         efuse = efuse >> 24;
1644         efuse2 &= 0xF;
1645
1646         if (efuse2 == 1)
1647                 ro = (2300 - 1350) * efuse / 255 + 1350;
1648         else
1649                 ro = (2500 - 1000) * efuse / 255 + 1000;
1650
1651         if (ro >= 1660)
1652                 type = 0;
1653         else
1654                 type = 1;
1655
1656         /* Populate Stretch amount */
1657         smu_data->smc_state_table.ClockStretcherAmount = stretch_amount;
1658
1659
1660         /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
1661         for (i = 0; i < sclk_table->count; i++) {
1662                 smu_data->smc_state_table.Sclk_CKS_masterEn0_7 |=
1663                                 sclk_table->entries[i].cks_enable << i;
1664                 if (ASICID_IS_TONGA_P(dev_id, hw_revision)) {
1665                         volt_without_cks = (uint32_t)((7732 + 60 - ro - 20838 *
1666                                 (sclk_table->entries[i].clk/100) / 10000) * 1000 /
1667                                 (8730 - (5301 * (sclk_table->entries[i].clk/100) / 1000)));
1668                         volt_with_cks = (uint32_t)((5250 + 51 - ro - 2404 *
1669                                 (sclk_table->entries[i].clk/100) / 100000) * 1000 /
1670                                 (6146 - (3193 * (sclk_table->entries[i].clk/100) / 1000)));
1671                 } else {
1672                         volt_without_cks = (uint32_t)((14041 *
1673                                 (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
1674                                 (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
1675                         volt_with_cks = (uint32_t)((13946 *
1676                                 (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
1677                                 (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
1678                 }
1679                 if (volt_without_cks >= volt_with_cks)
1680                         volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
1681                                         sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
1682                 smu_data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
1683         }
1684
1685         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
1686                         STRETCH_ENABLE, 0x0);
1687         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
1688                         masterReset, 0x1);
1689         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
1690                         staticEnable, 0x1);
1691         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
1692                         masterReset, 0x0);
1693
1694         /* Populate CKS Lookup Table */
1695         if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
1696                 stretch_amount2 = 0;
1697         else if (stretch_amount == 3 || stretch_amount == 4)
1698                 stretch_amount2 = 1;
1699         else {
1700                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
1701                                 PHM_PlatformCaps_ClockStretcher);
1702                 PP_ASSERT_WITH_CODE(false,
1703                                 "Stretch Amount in PPTable not supported",
1704                                 return -EINVAL);
1705         }
1706
1707         value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1708                         ixPWR_CKS_CNTL);
1709         value &= 0xFFC2FF87;
1710         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
1711                         tonga_clock_stretcher_lookup_table[stretch_amount2][0];
1712         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
1713                         tonga_clock_stretcher_lookup_table[stretch_amount2][1];
1714         clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(smu_data->smc_state_table.
1715                         GraphicsLevel[smu_data->smc_state_table.GraphicsDpmLevelCount - 1].
1716                         SclkFrequency) / 100);
1717         if (tonga_clock_stretcher_lookup_table[stretch_amount2][0] <
1718                         clock_freq_u16 &&
1719             tonga_clock_stretcher_lookup_table[stretch_amount2][1] >
1720                         clock_freq_u16) {
1721                 /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
1722                 value |= (tonga_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
1723                 /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
1724                 value |= (tonga_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
1725                 /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
1726                 value |= (tonga_clock_stretch_amount_conversion
1727                                 [tonga_clock_stretcher_lookup_table[stretch_amount2][3]]
1728                                  [stretch_amount]) << 3;
1729         }
1730         CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
1731                         CKS_LOOKUPTableEntry[0].minFreq);
1732         CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
1733                         CKS_LOOKUPTableEntry[0].maxFreq);
1734         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
1735                         tonga_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
1736         smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
1737                         (tonga_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
1738
1739         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1740                         ixPWR_CKS_CNTL, value);
1741
1742         /* Populate DDT Lookup Table */
1743         for (i = 0; i < 4; i++) {
1744                 /* Assign the minimum and maximum VID stored
1745                  * in the last row of Clock Stretcher Voltage Table.
1746                  */
1747                 smu_data->smc_state_table.ClockStretcherDataTable.
1748                 ClockStretcherDataTableEntry[i].minVID =
1749                                 (uint8_t) tonga_clock_stretcher_ddt_table[type][i][2];
1750                 smu_data->smc_state_table.ClockStretcherDataTable.
1751                 ClockStretcherDataTableEntry[i].maxVID =
1752                                 (uint8_t) tonga_clock_stretcher_ddt_table[type][i][3];
1753                 /* Loop through each SCLK and check the frequency
1754                  * to see if it lies within the frequency for clock stretcher.
1755                  */
1756                 for (j = 0; j < smu_data->smc_state_table.GraphicsDpmLevelCount; j++) {
1757                         cks_setting = 0;
1758                         clock_freq = PP_SMC_TO_HOST_UL(
1759                                         smu_data->smc_state_table.GraphicsLevel[j].SclkFrequency);
1760                         /* Check the allowed frequency against the sclk level[j].
1761                          *  Sclk's endianness has already been converted,
1762                          *  and it's in 10Khz unit,
1763                          *  as opposed to Data table, which is in Mhz unit.
1764                          */
1765                         if (clock_freq >= tonga_clock_stretcher_ddt_table[type][i][0] * 100) {
1766                                 cks_setting |= 0x2;
1767                                 if (clock_freq < tonga_clock_stretcher_ddt_table[type][i][1] * 100)
1768                                         cks_setting |= 0x1;
1769                         }
1770                         smu_data->smc_state_table.ClockStretcherDataTable.
1771                         ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
1772                 }
1773                 CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.
1774                                 ClockStretcherDataTable.
1775                                 ClockStretcherDataTableEntry[i].setting);
1776         }
1777
1778         value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1779                                         ixPWR_CKS_CNTL);
1780         value &= 0xFFFFFFFE;
1781         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1782                                         ixPWR_CKS_CNTL, value);
1783
1784         return 0;
1785 }
1786
1787 static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
1788                         SMU72_Discrete_DpmTable *table)
1789 {
1790         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
1791         uint16_t config;
1792
1793         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
1794                 /*  Splitted mode */
1795                 config = VR_SVI2_PLANE_1;
1796                 table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
1797
1798                 if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1799                         config = VR_SVI2_PLANE_2;
1800                         table->VRConfig |= config;
1801                 } else {
1802                         pr_err("VDDC and VDDGFX should "
1803                                 "be both on SVI2 control in splitted mode !\n");
1804                 }
1805         } else {
1806                 /* Merged mode  */
1807                 config = VR_MERGED_WITH_VDDC;
1808                 table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
1809
1810                 /* Set Vddc Voltage Controller  */
1811                 if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1812                         config = VR_SVI2_PLANE_1;
1813                         table->VRConfig |= config;
1814                 } else {
1815                         pr_err("VDDC should be on "
1816                                         "SVI2 control in merged mode !\n");
1817                 }
1818         }
1819
1820         /* Set Vddci Voltage Controller  */
1821         if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
1822                 config = VR_SVI2_PLANE_2;  /* only in merged mode */
1823                 table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
1824         } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
1825                 config = VR_SMIO_PATTERN_1;
1826                 table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
1827         }
1828
1829         /* Set Mvdd Voltage Controller */
1830         if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
1831                 config = VR_SMIO_PATTERN_2;
1832                 table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
1833         }
1834
1835         return 0;
1836 }
1837
1838 static int tonga_init_arb_table_index(struct pp_hwmgr *hwmgr)
1839 {
1840         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
1841         uint32_t tmp;
1842         int result;
1843
1844         /*
1845         * This is a read-modify-write on the first byte of the ARB table.
1846         * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure
1847         * is the field 'current'.
1848         * This solution is ugly, but we never write the whole table only
1849         * individual fields in it.
1850         * In reality this field should not be in that structure
1851         * but in a soft register.
1852         */
1853         result = smu7_read_smc_sram_dword(hwmgr,
1854                                 smu_data->smu7_data.arb_table_start, &tmp, SMC_RAM_END);
1855
1856         if (result != 0)
1857                 return result;
1858
1859         tmp &= 0x00FFFFFF;
1860         tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
1861
1862         return smu7_write_smc_sram_dword(hwmgr,
1863                         smu_data->smu7_data.arb_table_start, tmp, SMC_RAM_END);
1864 }
1865
1866
1867 static int tonga_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
1868 {
1869         struct tonga_smumgr *smu_data =
1870                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
1871         const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
1872         SMU72_Discrete_DpmTable  *dpm_table = &(smu_data->smc_state_table);
1873         struct phm_ppt_v1_information *table_info =
1874                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1875         struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
1876         int  i, j, k;
1877         const uint16_t *pdef1, *pdef2;
1878
1879         dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
1880                         (uint16_t)(cac_dtp_table->usTDP * 256));
1881         dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
1882                         (uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
1883
1884         PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
1885                         "Target Operating Temp is out of Range !",
1886                         );
1887
1888         dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
1889         dpm_table->GpuTjHyst = 8;
1890
1891         dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
1892
1893         dpm_table->BAPM_TEMP_GRADIENT =
1894                                 PP_HOST_TO_SMC_UL(defaults->bapm_temp_gradient);
1895         pdef1 = defaults->bapmti_r;
1896         pdef2 = defaults->bapmti_rc;
1897
1898         for (i = 0; i < SMU72_DTE_ITERATIONS; i++) {
1899                 for (j = 0; j < SMU72_DTE_SOURCES; j++) {
1900                         for (k = 0; k < SMU72_DTE_SINKS; k++) {
1901                                 dpm_table->BAPMTI_R[i][j][k] =
1902                                                 PP_HOST_TO_SMC_US(*pdef1);
1903                                 dpm_table->BAPMTI_RC[i][j][k] =
1904                                                 PP_HOST_TO_SMC_US(*pdef2);
1905                                 pdef1++;
1906                                 pdef2++;
1907                         }
1908                 }
1909         }
1910
1911         return 0;
1912 }
1913
1914 static int tonga_populate_svi_load_line(struct pp_hwmgr *hwmgr)
1915 {
1916         struct tonga_smumgr *smu_data =
1917                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
1918         const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
1919
1920         smu_data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
1921         smu_data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddC;
1922         smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
1923         smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
1924
1925         return 0;
1926 }
1927
1928 static int tonga_populate_tdc_limit(struct pp_hwmgr *hwmgr)
1929 {
1930         uint16_t tdc_limit;
1931         struct tonga_smumgr *smu_data =
1932                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
1933         const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
1934         struct phm_ppt_v1_information *table_info =
1935                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1936
1937         /* TDC number of fraction bits are changed from 8 to 7
1938          * for Fiji as requested by SMC team
1939          */
1940         tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 256);
1941         smu_data->power_tune_table.TDC_VDDC_PkgLimit =
1942                         CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
1943         smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
1944                         defaults->tdc_vddc_throttle_release_limit_perc;
1945         smu_data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
1946
1947         return 0;
1948 }
1949
1950 static int tonga_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
1951 {
1952         struct tonga_smumgr *smu_data =
1953                         (struct tonga_smumgr *)(hwmgr->smu_backend);
1954         const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
1955         uint32_t temp;
1956
1957         if (smu7_read_smc_sram_dword(hwmgr,
1958                         fuse_table_offset +
1959                         offsetof(SMU72_Discrete_PmFuses, TdcWaterfallCtl),
1960                         (uint32_t *)&temp, SMC_RAM_END))
1961                 PP_ASSERT_WITH_CODE(false,
1962                                 "Attempt to read PmFuses.DW6 "
1963                                 "(SviLoadLineEn) from SMC Failed !",
1964                                 return -EINVAL);
1965         else
1966                 smu_data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
1967
1968         return 0;
1969 }
1970
1971 static int tonga_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
1972 {
1973         int i;
1974         struct tonga_smumgr *smu_data =
1975                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
1976
1977         /* Currently not used. Set all to zero. */
1978         for (i = 0; i < 16; i++)
1979                 smu_data->power_tune_table.LPMLTemperatureScaler[i] = 0;
1980
1981         return 0;
1982 }
1983
1984 static int tonga_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
1985 {
1986         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
1987
1988         if ((hwmgr->thermal_controller.advanceFanControlParameters.
1989                         usFanOutputSensitivity & (1 << 15)) ||
1990                 (hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity == 0))
1991                 hwmgr->thermal_controller.advanceFanControlParameters.
1992                 usFanOutputSensitivity = hwmgr->thermal_controller.
1993                         advanceFanControlParameters.usDefaultFanOutputSensitivity;
1994
1995         smu_data->power_tune_table.FuzzyFan_PwmSetDelta =
1996                         PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
1997                                         advanceFanControlParameters.usFanOutputSensitivity);
1998         return 0;
1999 }
2000
2001 static int tonga_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
2002 {
2003         int i;
2004         struct tonga_smumgr *smu_data =
2005                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
2006
2007         /* Currently not used. Set all to zero. */
2008         for (i = 0; i < 16; i++)
2009                 smu_data->power_tune_table.GnbLPML[i] = 0;
2010
2011         return 0;
2012 }
2013
2014 static int tonga_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
2015 {
2016         struct tonga_smumgr *smu_data =
2017                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
2018         struct phm_ppt_v1_information *table_info =
2019                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2020         uint16_t hi_sidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
2021         uint16_t lo_sidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
2022         struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
2023
2024         hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
2025         lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
2026
2027         smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
2028                         CONVERT_FROM_HOST_TO_SMC_US(hi_sidd);
2029         smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
2030                         CONVERT_FROM_HOST_TO_SMC_US(lo_sidd);
2031
2032         return 0;
2033 }
2034
2035 static int tonga_populate_pm_fuses(struct pp_hwmgr *hwmgr)
2036 {
2037         struct tonga_smumgr *smu_data =
2038                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
2039         uint32_t pm_fuse_table_offset;
2040
2041         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2042                         PHM_PlatformCaps_PowerContainment)) {
2043                 if (smu7_read_smc_sram_dword(hwmgr,
2044                                 SMU72_FIRMWARE_HEADER_LOCATION +
2045                                 offsetof(SMU72_Firmware_Header, PmFuseTable),
2046                                 &pm_fuse_table_offset, SMC_RAM_END))
2047                         PP_ASSERT_WITH_CODE(false,
2048                                 "Attempt to get pm_fuse_table_offset Failed !",
2049                                 return -EINVAL);
2050
2051                 /* DW6 */
2052                 if (tonga_populate_svi_load_line(hwmgr))
2053                         PP_ASSERT_WITH_CODE(false,
2054                                 "Attempt to populate SviLoadLine Failed !",
2055                                 return -EINVAL);
2056                 /* DW7 */
2057                 if (tonga_populate_tdc_limit(hwmgr))
2058                         PP_ASSERT_WITH_CODE(false,
2059                                         "Attempt to populate TDCLimit Failed !",
2060                                         return -EINVAL);
2061                 /* DW8 */
2062                 if (tonga_populate_dw8(hwmgr, pm_fuse_table_offset))
2063                         PP_ASSERT_WITH_CODE(false,
2064                                 "Attempt to populate TdcWaterfallCtl Failed !",
2065                                 return -EINVAL);
2066
2067                 /* DW9-DW12 */
2068                 if (tonga_populate_temperature_scaler(hwmgr) != 0)
2069                         PP_ASSERT_WITH_CODE(false,
2070                                 "Attempt to populate LPMLTemperatureScaler Failed !",
2071                                 return -EINVAL);
2072
2073                 /* DW13-DW14 */
2074                 if (tonga_populate_fuzzy_fan(hwmgr))
2075                         PP_ASSERT_WITH_CODE(false,
2076                                 "Attempt to populate Fuzzy Fan "
2077                                 "Control parameters Failed !",
2078                                 return -EINVAL);
2079
2080                 /* DW15-DW18 */
2081                 if (tonga_populate_gnb_lpml(hwmgr))
2082                         PP_ASSERT_WITH_CODE(false,
2083                                 "Attempt to populate GnbLPML Failed !",
2084                                 return -EINVAL);
2085
2086                 /* DW20 */
2087                 if (tonga_populate_bapm_vddc_base_leakage_sidd(hwmgr))
2088                         PP_ASSERT_WITH_CODE(
2089                                 false,
2090                                 "Attempt to populate BapmVddCBaseLeakage "
2091                                 "Hi and Lo Sidd Failed !",
2092                                 return -EINVAL);
2093
2094                 if (smu7_copy_bytes_to_smc(hwmgr, pm_fuse_table_offset,
2095                                 (uint8_t *)&smu_data->power_tune_table,
2096                                 sizeof(struct SMU72_Discrete_PmFuses), SMC_RAM_END))
2097                         PP_ASSERT_WITH_CODE(false,
2098                                         "Attempt to download PmFuseTable Failed !",
2099                                         return -EINVAL);
2100         }
2101         return 0;
2102 }
2103
2104 static int tonga_populate_mc_reg_address(struct pp_hwmgr *hwmgr,
2105                                  SMU72_Discrete_MCRegisters *mc_reg_table)
2106 {
2107         const struct tonga_smumgr *smu_data = (struct tonga_smumgr *)hwmgr->smu_backend;
2108
2109         uint32_t i, j;
2110
2111         for (i = 0, j = 0; j < smu_data->mc_reg_table.last; j++) {
2112                 if (smu_data->mc_reg_table.validflag & 1<<j) {
2113                         PP_ASSERT_WITH_CODE(
2114                                 i < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE,
2115                                 "Index of mc_reg_table->address[] array "
2116                                 "out of boundary",
2117                                 return -EINVAL);
2118                         mc_reg_table->address[i].s0 =
2119                                 PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s0);
2120                         mc_reg_table->address[i].s1 =
2121                                 PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s1);
2122                         i++;
2123                 }
2124         }
2125
2126         mc_reg_table->last = (uint8_t)i;
2127
2128         return 0;
2129 }
2130
2131 /*convert register values from driver to SMC format */
2132 static void tonga_convert_mc_registers(
2133         const struct tonga_mc_reg_entry *entry,
2134         SMU72_Discrete_MCRegisterSet *data,
2135         uint32_t num_entries, uint32_t valid_flag)
2136 {
2137         uint32_t i, j;
2138
2139         for (i = 0, j = 0; j < num_entries; j++) {
2140                 if (valid_flag & 1<<j) {
2141                         data->value[i] = PP_HOST_TO_SMC_UL(entry->mc_data[j]);
2142                         i++;
2143                 }
2144         }
2145 }
2146
2147 static int tonga_convert_mc_reg_table_entry_to_smc(
2148                 struct pp_hwmgr *hwmgr,
2149                 const uint32_t memory_clock,
2150                 SMU72_Discrete_MCRegisterSet *mc_reg_table_data
2151                 )
2152 {
2153         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
2154         uint32_t i = 0;
2155
2156         for (i = 0; i < smu_data->mc_reg_table.num_entries; i++) {
2157                 if (memory_clock <=
2158                         smu_data->mc_reg_table.mc_reg_table_entry[i].mclk_max) {
2159                         break;
2160                 }
2161         }
2162
2163         if ((i == smu_data->mc_reg_table.num_entries) && (i > 0))
2164                 --i;
2165
2166         tonga_convert_mc_registers(&smu_data->mc_reg_table.mc_reg_table_entry[i],
2167                                 mc_reg_table_data, smu_data->mc_reg_table.last,
2168                                 smu_data->mc_reg_table.validflag);
2169
2170         return 0;
2171 }
2172
2173 static int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
2174                 SMU72_Discrete_MCRegisters *mc_regs)
2175 {
2176         int result = 0;
2177         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2178         int res;
2179         uint32_t i;
2180
2181         for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
2182                 res = tonga_convert_mc_reg_table_entry_to_smc(
2183                                 hwmgr,
2184                                 data->dpm_table.mclk_table.dpm_levels[i].value,
2185                                 &mc_regs->data[i]
2186                                 );
2187
2188                 if (0 != res)
2189                         result = res;
2190         }
2191
2192         return result;
2193 }
2194
2195 static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
2196 {
2197         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
2198         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2199         uint32_t address;
2200         int32_t result;
2201
2202         if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
2203                 return 0;
2204
2205
2206         memset(&smu_data->mc_regs, 0, sizeof(SMU72_Discrete_MCRegisters));
2207
2208         result = tonga_convert_mc_reg_table_to_smc(hwmgr, &(smu_data->mc_regs));
2209
2210         if (result != 0)
2211                 return result;
2212
2213
2214         address = smu_data->smu7_data.mc_reg_table_start +
2215                         (uint32_t)offsetof(SMU72_Discrete_MCRegisters, data[0]);
2216
2217         return  smu7_copy_bytes_to_smc(
2218                         hwmgr, address,
2219                         (uint8_t *)&smu_data->mc_regs.data[0],
2220                         sizeof(SMU72_Discrete_MCRegisterSet) *
2221                         data->dpm_table.mclk_table.count,
2222                         SMC_RAM_END);
2223 }
2224
2225 static int tonga_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
2226 {
2227         int result;
2228         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
2229
2230         memset(&smu_data->mc_regs, 0x00, sizeof(SMU72_Discrete_MCRegisters));
2231         result = tonga_populate_mc_reg_address(hwmgr, &(smu_data->mc_regs));
2232         PP_ASSERT_WITH_CODE(!result,
2233                 "Failed to initialize MCRegTable for the MC register addresses !",
2234                 return result;);
2235
2236         result = tonga_convert_mc_reg_table_to_smc(hwmgr, &smu_data->mc_regs);
2237         PP_ASSERT_WITH_CODE(!result,
2238                 "Failed to initialize MCRegTable for driver state !",
2239                 return result;);
2240
2241         return smu7_copy_bytes_to_smc(hwmgr, smu_data->smu7_data.mc_reg_table_start,
2242                         (uint8_t *)&smu_data->mc_regs, sizeof(SMU72_Discrete_MCRegisters), SMC_RAM_END);
2243 }
2244
2245 static void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
2246 {
2247         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
2248         struct  phm_ppt_v1_information *table_info =
2249                         (struct  phm_ppt_v1_information *)(hwmgr->pptable);
2250
2251         if (table_info &&
2252                         table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
2253                         table_info->cac_dtp_table->usPowerTuneDataSetID)
2254                 smu_data->power_tune_defaults =
2255                                 &tonga_power_tune_data_set_array
2256                                 [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
2257         else
2258                 smu_data->power_tune_defaults = &tonga_power_tune_data_set_array[0];
2259 }
2260
2261 static int tonga_init_smc_table(struct pp_hwmgr *hwmgr)
2262 {
2263         int result;
2264         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2265         struct tonga_smumgr *smu_data =
2266                         (struct tonga_smumgr *)(hwmgr->smu_backend);
2267         SMU72_Discrete_DpmTable *table = &(smu_data->smc_state_table);
2268         struct phm_ppt_v1_information *table_info =
2269                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2270
2271         uint8_t i;
2272         pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
2273
2274
2275         memset(&(smu_data->smc_state_table), 0x00, sizeof(smu_data->smc_state_table));
2276
2277         tonga_initialize_power_tune_defaults(hwmgr);
2278
2279         if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control)
2280                 tonga_populate_smc_voltage_tables(hwmgr, table);
2281
2282         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2283                         PHM_PlatformCaps_AutomaticDCTransition))
2284                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
2285
2286
2287         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2288                         PHM_PlatformCaps_StepVddc))
2289                 table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
2290
2291         if (data->is_memory_gddr5)
2292                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
2293
2294         i = PHM_READ_FIELD(hwmgr->device, CC_MC_MAX_CHANNEL, NOOFCHAN);
2295
2296         if (i == 1 || i == 0)
2297                 table->SystemFlags |= 0x40;
2298
2299         if (data->ulv_supported && table_info->us_ulv_voltage_offset) {
2300                 result = tonga_populate_ulv_state(hwmgr, table);
2301                 PP_ASSERT_WITH_CODE(!result,
2302                         "Failed to initialize ULV state !",
2303                         return result;);
2304
2305                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2306                         ixCG_ULV_PARAMETER, 0x40035);
2307         }
2308
2309         result = tonga_populate_smc_link_level(hwmgr, table);
2310         PP_ASSERT_WITH_CODE(!result,
2311                 "Failed to initialize Link Level !", return result);
2312
2313         result = tonga_populate_all_graphic_levels(hwmgr);
2314         PP_ASSERT_WITH_CODE(!result,
2315                 "Failed to initialize Graphics Level !", return result);
2316
2317         result = tonga_populate_all_memory_levels(hwmgr);
2318         PP_ASSERT_WITH_CODE(!result,
2319                 "Failed to initialize Memory Level !", return result);
2320
2321         result = tonga_populate_smc_acpi_level(hwmgr, table);
2322         PP_ASSERT_WITH_CODE(!result,
2323                 "Failed to initialize ACPI Level !", return result);
2324
2325         result = tonga_populate_smc_vce_level(hwmgr, table);
2326         PP_ASSERT_WITH_CODE(!result,
2327                 "Failed to initialize VCE Level !", return result);
2328
2329         result = tonga_populate_smc_acp_level(hwmgr, table);
2330         PP_ASSERT_WITH_CODE(!result,
2331                 "Failed to initialize ACP Level !", return result);
2332
2333         result = tonga_populate_smc_samu_level(hwmgr, table);
2334         PP_ASSERT_WITH_CODE(!result,
2335                 "Failed to initialize SAMU Level !", return result);
2336
2337         /* Since only the initial state is completely set up at this
2338         * point (the other states are just copies of the boot state) we only
2339         * need to populate the  ARB settings for the initial state.
2340         */
2341         result = tonga_program_memory_timing_parameters(hwmgr);
2342         PP_ASSERT_WITH_CODE(!result,
2343                 "Failed to Write ARB settings for the initial state.",
2344                 return result;);
2345
2346         result = tonga_populate_smc_uvd_level(hwmgr, table);
2347         PP_ASSERT_WITH_CODE(!result,
2348                 "Failed to initialize UVD Level !", return result);
2349
2350         result = tonga_populate_smc_boot_level(hwmgr, table);
2351         PP_ASSERT_WITH_CODE(!result,
2352                 "Failed to initialize Boot Level !", return result);
2353
2354         tonga_populate_bapm_parameters_in_dpm_table(hwmgr);
2355         PP_ASSERT_WITH_CODE(!result,
2356                 "Failed to populate BAPM Parameters !", return result);
2357
2358         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2359                         PHM_PlatformCaps_ClockStretcher)) {
2360                 result = tonga_populate_clock_stretcher_data_table(hwmgr);
2361                 PP_ASSERT_WITH_CODE(!result,
2362                         "Failed to populate Clock Stretcher Data Table !",
2363                         return result;);
2364         }
2365         table->GraphicsVoltageChangeEnable  = 1;
2366         table->GraphicsThermThrottleEnable  = 1;
2367         table->GraphicsInterval = 1;
2368         table->VoltageInterval  = 1;
2369         table->ThermalInterval  = 1;
2370         table->TemperatureLimitHigh =
2371                 table_info->cac_dtp_table->usTargetOperatingTemp *
2372                 SMU7_Q88_FORMAT_CONVERSION_UNIT;
2373         table->TemperatureLimitLow =
2374                 (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
2375                 SMU7_Q88_FORMAT_CONVERSION_UNIT;
2376         table->MemoryVoltageChangeEnable  = 1;
2377         table->MemoryInterval  = 1;
2378         table->VoltageResponseTime  = 0;
2379         table->PhaseResponseTime  = 0;
2380         table->MemoryThermThrottleEnable  = 1;
2381
2382         /*
2383         * Cail reads current link status and reports it as cap (we cannot
2384         * change this due to some previous issues we had)
2385         * SMC drops the link status to lowest level after enabling
2386         * DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
2387         * but this time Cail reads current link status which was set to low by
2388         * SMC and reports it as cap to powerplay
2389         * To avoid it, we set PCIeBootLinkLevel to highest dpm level
2390         */
2391         PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
2392                         "There must be 1 or more PCIE levels defined in PPTable.",
2393                         return -EINVAL);
2394
2395         table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
2396
2397         table->PCIeGenInterval  = 1;
2398
2399         result = tonga_populate_vr_config(hwmgr, table);
2400         PP_ASSERT_WITH_CODE(!result,
2401                 "Failed to populate VRConfig setting !", return result);
2402         data->vr_config = table->VRConfig;
2403         table->ThermGpio  = 17;
2404         table->SclkStepSize = 0x4000;
2405
2406         if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID,
2407                                                 &gpio_pin_assignment)) {
2408                 table->VRHotGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
2409                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2410                         PHM_PlatformCaps_RegulatorHot);
2411         } else {
2412                 table->VRHotGpio = SMU7_UNUSED_GPIO_PIN;
2413                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2414                         PHM_PlatformCaps_RegulatorHot);
2415         }
2416
2417         if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
2418                                                 &gpio_pin_assignment)) {
2419                 table->AcDcGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
2420                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2421                         PHM_PlatformCaps_AutomaticDCTransition);
2422         } else {
2423                 table->AcDcGpio = SMU7_UNUSED_GPIO_PIN;
2424                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2425                         PHM_PlatformCaps_AutomaticDCTransition);
2426         }
2427
2428         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2429                 PHM_PlatformCaps_Falcon_QuickTransition);
2430
2431         if (0) {
2432                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2433                         PHM_PlatformCaps_AutomaticDCTransition);
2434                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2435                         PHM_PlatformCaps_Falcon_QuickTransition);
2436         }
2437
2438         if (atomctrl_get_pp_assign_pin(hwmgr,
2439                         THERMAL_INT_OUTPUT_GPIO_PINID, &gpio_pin_assignment)) {
2440                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
2441                         PHM_PlatformCaps_ThermalOutGPIO);
2442
2443                 table->ThermOutGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
2444
2445                 table->ThermOutPolarity =
2446                         (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
2447                         (1 << gpio_pin_assignment.uc_gpio_pin_bit_shift))) ? 1 : 0;
2448
2449                 table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
2450
2451                 /* if required, combine VRHot/PCC with thermal out GPIO*/
2452                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2453                         PHM_PlatformCaps_RegulatorHot) &&
2454                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2455                         PHM_PlatformCaps_CombinePCCWithThermalSignal)){
2456                         table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
2457                 }
2458         } else {
2459                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2460                         PHM_PlatformCaps_ThermalOutGPIO);
2461
2462                 table->ThermOutGpio = 17;
2463                 table->ThermOutPolarity = 1;
2464                 table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
2465         }
2466
2467         for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++)
2468                 table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
2469         CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
2470         CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
2471         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
2472         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
2473         CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
2474         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
2475         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
2476         CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
2477         CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
2478
2479         /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
2480         result = smu7_copy_bytes_to_smc(
2481                         hwmgr,
2482                         smu_data->smu7_data.dpm_table_start + offsetof(SMU72_Discrete_DpmTable, SystemFlags),
2483                         (uint8_t *)&(table->SystemFlags),
2484                         sizeof(SMU72_Discrete_DpmTable) - 3 * sizeof(SMU72_PIDController),
2485                         SMC_RAM_END);
2486
2487         PP_ASSERT_WITH_CODE(!result,
2488                 "Failed to upload dpm data to SMC memory !", return result;);
2489
2490         result = tonga_init_arb_table_index(hwmgr);
2491         PP_ASSERT_WITH_CODE(!result,
2492                         "Failed to upload arb data to SMC memory !", return result);
2493
2494         tonga_populate_pm_fuses(hwmgr);
2495         PP_ASSERT_WITH_CODE((!result),
2496                 "Failed to populate initialize pm fuses !", return result);
2497
2498         result = tonga_populate_initial_mc_reg_table(hwmgr);
2499         PP_ASSERT_WITH_CODE((!result),
2500                 "Failed to populate initialize MC Reg table !", return result);
2501
2502         return 0;
2503 }
2504
2505 static int tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
2506 {
2507         struct tonga_smumgr *smu_data =
2508                         (struct tonga_smumgr *)(hwmgr->smu_backend);
2509         SMU72_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
2510         uint32_t duty100;
2511         uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
2512         uint16_t fdo_min, slope1, slope2;
2513         uint32_t reference_clock;
2514         int res;
2515         uint64_t tmp64;
2516
2517         if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2518                                         PHM_PlatformCaps_MicrocodeFanControl))
2519                 return 0;
2520
2521         if (hwmgr->thermal_controller.fanInfo.bNoFan) {
2522                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2523                         PHM_PlatformCaps_MicrocodeFanControl);
2524                 return 0;
2525         }
2526
2527         if (0 == smu_data->smu7_data.fan_table_start) {
2528                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2529                                         PHM_PlatformCaps_MicrocodeFanControl);
2530                 return 0;
2531         }
2532
2533         duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
2534                                                 CGS_IND_REG__SMC,
2535                                                 CG_FDO_CTRL1, FMAX_DUTY100);
2536
2537         if (0 == duty100) {
2538                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2539                                 PHM_PlatformCaps_MicrocodeFanControl);
2540                 return 0;
2541         }
2542
2543         tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
2544         do_div(tmp64, 10000);
2545         fdo_min = (uint16_t)tmp64;
2546
2547         t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
2548                    hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
2549         t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
2550                   hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
2551
2552         pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
2553                     hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
2554         pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
2555                     hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
2556
2557         slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
2558         slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
2559
2560         fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
2561         fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
2562         fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
2563
2564         fan_table.Slope1 = cpu_to_be16(slope1);
2565         fan_table.Slope2 = cpu_to_be16(slope2);
2566
2567         fan_table.FdoMin = cpu_to_be16(fdo_min);
2568
2569         fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
2570
2571         fan_table.HystUp = cpu_to_be16(1);
2572
2573         fan_table.HystSlope = cpu_to_be16(1);
2574
2575         fan_table.TempRespLim = cpu_to_be16(5);
2576
2577         reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
2578
2579         fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
2580
2581         fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
2582
2583         fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
2584
2585         fan_table.FanControl_GL_Flag = 1;
2586
2587         res = smu7_copy_bytes_to_smc(hwmgr,
2588                                         smu_data->smu7_data.fan_table_start,
2589                                         (uint8_t *)&fan_table,
2590                                         (uint32_t)sizeof(fan_table),
2591                                         SMC_RAM_END);
2592
2593         return 0;
2594 }
2595
2596
2597 static int tonga_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
2598 {
2599         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2600
2601         if (data->need_update_smu7_dpm_table &
2602                 (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
2603                 return tonga_program_memory_timing_parameters(hwmgr);
2604
2605         return 0;
2606 }
2607
2608 static int tonga_update_sclk_threshold(struct pp_hwmgr *hwmgr)
2609 {
2610         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2611         struct tonga_smumgr *smu_data =
2612                         (struct tonga_smumgr *)(hwmgr->smu_backend);
2613
2614         int result = 0;
2615         uint32_t low_sclk_interrupt_threshold = 0;
2616
2617         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2618                         PHM_PlatformCaps_SclkThrottleLowNotification)
2619                 && (data->low_sclk_interrupt_threshold != 0)) {
2620                 low_sclk_interrupt_threshold =
2621                                 data->low_sclk_interrupt_threshold;
2622
2623                 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
2624
2625                 result = smu7_copy_bytes_to_smc(
2626                                 hwmgr,
2627                                 smu_data->smu7_data.dpm_table_start +
2628                                 offsetof(SMU72_Discrete_DpmTable,
2629                                         LowSclkInterruptThreshold),
2630                                 (uint8_t *)&low_sclk_interrupt_threshold,
2631                                 sizeof(uint32_t),
2632                                 SMC_RAM_END);
2633         }
2634
2635         result = tonga_update_and_upload_mc_reg_table(hwmgr);
2636
2637         PP_ASSERT_WITH_CODE((!result),
2638                                 "Failed to upload MC reg table !",
2639                                 return result);
2640
2641         result = tonga_program_mem_timing_parameters(hwmgr);
2642         PP_ASSERT_WITH_CODE((result == 0),
2643                         "Failed to program memory timing parameters !",
2644                         );
2645
2646         return result;
2647 }
2648
2649 static uint32_t tonga_get_offsetof(uint32_t type, uint32_t member)
2650 {
2651         switch (type) {
2652         case SMU_SoftRegisters:
2653                 switch (member) {
2654                 case HandshakeDisables:
2655                         return offsetof(SMU72_SoftRegisters, HandshakeDisables);
2656                 case VoltageChangeTimeout:
2657                         return offsetof(SMU72_SoftRegisters, VoltageChangeTimeout);
2658                 case AverageGraphicsActivity:
2659                         return offsetof(SMU72_SoftRegisters, AverageGraphicsActivity);
2660                 case PreVBlankGap:
2661                         return offsetof(SMU72_SoftRegisters, PreVBlankGap);
2662                 case VBlankTimeout:
2663                         return offsetof(SMU72_SoftRegisters, VBlankTimeout);
2664                 case UcodeLoadStatus:
2665                         return offsetof(SMU72_SoftRegisters, UcodeLoadStatus);
2666                 case DRAM_LOG_ADDR_H:
2667                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_ADDR_H);
2668                 case DRAM_LOG_ADDR_L:
2669                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_ADDR_L);
2670                 case DRAM_LOG_PHY_ADDR_H:
2671                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_PHY_ADDR_H);
2672                 case DRAM_LOG_PHY_ADDR_L:
2673                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_PHY_ADDR_L);
2674                 case DRAM_LOG_BUFF_SIZE:
2675                         return offsetof(SMU72_SoftRegisters, DRAM_LOG_BUFF_SIZE);
2676                 }
2677         case SMU_Discrete_DpmTable:
2678                 switch (member) {
2679                 case UvdBootLevel:
2680                         return offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
2681                 case VceBootLevel:
2682                         return offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
2683                 case SamuBootLevel:
2684                         return offsetof(SMU72_Discrete_DpmTable, SamuBootLevel);
2685                 case LowSclkInterruptThreshold:
2686                         return offsetof(SMU72_Discrete_DpmTable, LowSclkInterruptThreshold);
2687                 }
2688         }
2689         pr_warn("can't get the offset of type %x member %x\n", type, member);
2690         return 0;
2691 }
2692
2693 static uint32_t tonga_get_mac_definition(uint32_t value)
2694 {
2695         switch (value) {
2696         case SMU_MAX_LEVELS_GRAPHICS:
2697                 return SMU72_MAX_LEVELS_GRAPHICS;
2698         case SMU_MAX_LEVELS_MEMORY:
2699                 return SMU72_MAX_LEVELS_MEMORY;
2700         case SMU_MAX_LEVELS_LINK:
2701                 return SMU72_MAX_LEVELS_LINK;
2702         case SMU_MAX_ENTRIES_SMIO:
2703                 return SMU72_MAX_ENTRIES_SMIO;
2704         case SMU_MAX_LEVELS_VDDC:
2705                 return SMU72_MAX_LEVELS_VDDC;
2706         case SMU_MAX_LEVELS_VDDGFX:
2707                 return SMU72_MAX_LEVELS_VDDGFX;
2708         case SMU_MAX_LEVELS_VDDCI:
2709                 return SMU72_MAX_LEVELS_VDDCI;
2710         case SMU_MAX_LEVELS_MVDD:
2711                 return SMU72_MAX_LEVELS_MVDD;
2712         }
2713         pr_warn("can't get the mac value %x\n", value);
2714
2715         return 0;
2716 }
2717
2718 static int tonga_update_uvd_smc_table(struct pp_hwmgr *hwmgr)
2719 {
2720         struct tonga_smumgr *smu_data =
2721                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
2722         uint32_t mm_boot_level_offset, mm_boot_level_value;
2723         struct phm_ppt_v1_information *table_info =
2724                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2725
2726         smu_data->smc_state_table.UvdBootLevel = 0;
2727         if (table_info->mm_dep_table->count > 0)
2728                 smu_data->smc_state_table.UvdBootLevel =
2729                                 (uint8_t) (table_info->mm_dep_table->count - 1);
2730         mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
2731                                 offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
2732         mm_boot_level_offset /= 4;
2733         mm_boot_level_offset *= 4;
2734         mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
2735                         CGS_IND_REG__SMC, mm_boot_level_offset);
2736         mm_boot_level_value &= 0x00FFFFFF;
2737         mm_boot_level_value |= smu_data->smc_state_table.UvdBootLevel << 24;
2738         cgs_write_ind_register(hwmgr->device,
2739                                 CGS_IND_REG__SMC,
2740                                 mm_boot_level_offset, mm_boot_level_value);
2741
2742         if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2743                         PHM_PlatformCaps_UVDDPM) ||
2744                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2745                         PHM_PlatformCaps_StablePState))
2746                 smum_send_msg_to_smc_with_parameter(hwmgr,
2747                                 PPSMC_MSG_UVDDPM_SetEnabledMask,
2748                                 (uint32_t)(1 << smu_data->smc_state_table.UvdBootLevel));
2749         return 0;
2750 }
2751
2752 static int tonga_update_vce_smc_table(struct pp_hwmgr *hwmgr)
2753 {
2754         struct tonga_smumgr *smu_data =
2755                                 (struct tonga_smumgr *)(hwmgr->smu_backend);
2756         uint32_t mm_boot_level_offset, mm_boot_level_value;
2757         struct phm_ppt_v1_information *table_info =
2758                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2759
2760
2761         smu_data->smc_state_table.VceBootLevel =
2762                 (uint8_t) (table_info->mm_dep_table->count - 1);
2763
2764         mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
2765                                         offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
2766         mm_boot_level_offset /= 4;
2767         mm_boot_level_offset *= 4;
2768         mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
2769                         CGS_IND_REG__SMC, mm_boot_level_offset);
2770         mm_boot_level_value &= 0xFF00FFFF;
2771         mm_boot_level_value |= smu_data->smc_state_table.VceBootLevel << 16;
2772         cgs_write_ind_register(hwmgr->device,
2773                         CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
2774
2775         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2776                                         PHM_PlatformCaps_StablePState))
2777                 smum_send_msg_to_smc_with_parameter(hwmgr,
2778                                 PPSMC_MSG_VCEDPM_SetEnabledMask,
2779                                 (uint32_t)1 << smu_data->smc_state_table.VceBootLevel);
2780         return 0;
2781 }
2782
2783 static int tonga_update_samu_smc_table(struct pp_hwmgr *hwmgr)
2784 {
2785         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
2786         uint32_t mm_boot_level_offset, mm_boot_level_value;
2787
2788         smu_data->smc_state_table.SamuBootLevel = 0;
2789         mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
2790                                 offsetof(SMU72_Discrete_DpmTable, SamuBootLevel);
2791
2792         mm_boot_level_offset /= 4;
2793         mm_boot_level_offset *= 4;
2794         mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
2795                         CGS_IND_REG__SMC, mm_boot_level_offset);
2796         mm_boot_level_value &= 0xFFFFFF00;
2797         mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0;
2798         cgs_write_ind_register(hwmgr->device,
2799                         CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
2800
2801         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2802                         PHM_PlatformCaps_StablePState))
2803                 smum_send_msg_to_smc_with_parameter(hwmgr,
2804                                 PPSMC_MSG_SAMUDPM_SetEnabledMask,
2805                                 (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel));
2806         return 0;
2807 }
2808
2809 static int tonga_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
2810 {
2811         switch (type) {
2812         case SMU_UVD_TABLE:
2813                 tonga_update_uvd_smc_table(hwmgr);
2814                 break;
2815         case SMU_VCE_TABLE:
2816                 tonga_update_vce_smc_table(hwmgr);
2817                 break;
2818         case SMU_SAMU_TABLE:
2819                 tonga_update_samu_smc_table(hwmgr);
2820                 break;
2821         default:
2822                 break;
2823         }
2824         return 0;
2825 }
2826
2827 static int tonga_process_firmware_header(struct pp_hwmgr *hwmgr)
2828 {
2829         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
2830         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
2831
2832         uint32_t tmp;
2833         int result;
2834         bool error = false;
2835
2836         result = smu7_read_smc_sram_dword(hwmgr,
2837                                 SMU72_FIRMWARE_HEADER_LOCATION +
2838                                 offsetof(SMU72_Firmware_Header, DpmTable),
2839                                 &tmp, SMC_RAM_END);
2840
2841         if (!result)
2842                 smu_data->smu7_data.dpm_table_start = tmp;
2843
2844         error |= (result != 0);
2845
2846         result = smu7_read_smc_sram_dword(hwmgr,
2847                                 SMU72_FIRMWARE_HEADER_LOCATION +
2848                                 offsetof(SMU72_Firmware_Header, SoftRegisters),
2849                                 &tmp, SMC_RAM_END);
2850
2851         if (!result) {
2852                 data->soft_regs_start = tmp;
2853                 smu_data->smu7_data.soft_regs_start = tmp;
2854         }
2855
2856         error |= (result != 0);
2857
2858
2859         result = smu7_read_smc_sram_dword(hwmgr,
2860                                 SMU72_FIRMWARE_HEADER_LOCATION +
2861                                 offsetof(SMU72_Firmware_Header, mcRegisterTable),
2862                                 &tmp, SMC_RAM_END);
2863
2864         if (!result)
2865                 smu_data->smu7_data.mc_reg_table_start = tmp;
2866
2867         result = smu7_read_smc_sram_dword(hwmgr,
2868                                 SMU72_FIRMWARE_HEADER_LOCATION +
2869                                 offsetof(SMU72_Firmware_Header, FanTable),
2870                                 &tmp, SMC_RAM_END);
2871
2872         if (!result)
2873                 smu_data->smu7_data.fan_table_start = tmp;
2874
2875         error |= (result != 0);
2876
2877         result = smu7_read_smc_sram_dword(hwmgr,
2878                                 SMU72_FIRMWARE_HEADER_LOCATION +
2879                                 offsetof(SMU72_Firmware_Header, mcArbDramTimingTable),
2880                                 &tmp, SMC_RAM_END);
2881
2882         if (!result)
2883                 smu_data->smu7_data.arb_table_start = tmp;
2884
2885         error |= (result != 0);
2886
2887         result = smu7_read_smc_sram_dword(hwmgr,
2888                                 SMU72_FIRMWARE_HEADER_LOCATION +
2889                                 offsetof(SMU72_Firmware_Header, Version),
2890                                 &tmp, SMC_RAM_END);
2891
2892         if (!result)
2893                 hwmgr->microcode_version_info.SMC = tmp;
2894
2895         error |= (result != 0);
2896
2897         return error ? 1 : 0;
2898 }
2899
2900 /*---------------------------MC----------------------------*/
2901
2902 static uint8_t tonga_get_memory_modile_index(struct pp_hwmgr *hwmgr)
2903 {
2904         return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
2905 }
2906
2907 static bool tonga_check_s0_mc_reg_index(uint16_t in_reg, uint16_t *out_reg)
2908 {
2909         bool result = true;
2910
2911         switch (in_reg) {
2912         case  mmMC_SEQ_RAS_TIMING:
2913                 *out_reg = mmMC_SEQ_RAS_TIMING_LP;
2914                 break;
2915
2916         case  mmMC_SEQ_DLL_STBY:
2917                 *out_reg = mmMC_SEQ_DLL_STBY_LP;
2918                 break;
2919
2920         case  mmMC_SEQ_G5PDX_CMD0:
2921                 *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
2922                 break;
2923
2924         case  mmMC_SEQ_G5PDX_CMD1:
2925                 *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
2926                 break;
2927
2928         case  mmMC_SEQ_G5PDX_CTRL:
2929                 *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
2930                 break;
2931
2932         case mmMC_SEQ_CAS_TIMING:
2933                 *out_reg = mmMC_SEQ_CAS_TIMING_LP;
2934                 break;
2935
2936         case mmMC_SEQ_MISC_TIMING:
2937                 *out_reg = mmMC_SEQ_MISC_TIMING_LP;
2938                 break;
2939
2940         case mmMC_SEQ_MISC_TIMING2:
2941                 *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
2942                 break;
2943
2944         case mmMC_SEQ_PMG_DVS_CMD:
2945                 *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
2946                 break;
2947
2948         case mmMC_SEQ_PMG_DVS_CTL:
2949                 *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
2950                 break;
2951
2952         case mmMC_SEQ_RD_CTL_D0:
2953                 *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
2954                 break;
2955
2956         case mmMC_SEQ_RD_CTL_D1:
2957                 *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
2958                 break;
2959
2960         case mmMC_SEQ_WR_CTL_D0:
2961                 *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
2962                 break;
2963
2964         case mmMC_SEQ_WR_CTL_D1:
2965                 *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
2966                 break;
2967
2968         case mmMC_PMG_CMD_EMRS:
2969                 *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
2970                 break;
2971
2972         case mmMC_PMG_CMD_MRS:
2973                 *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
2974                 break;
2975
2976         case mmMC_PMG_CMD_MRS1:
2977                 *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
2978                 break;
2979
2980         case mmMC_SEQ_PMG_TIMING:
2981                 *out_reg = mmMC_SEQ_PMG_TIMING_LP;
2982                 break;
2983
2984         case mmMC_PMG_CMD_MRS2:
2985                 *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
2986                 break;
2987
2988         case mmMC_SEQ_WR_CTL_2:
2989                 *out_reg = mmMC_SEQ_WR_CTL_2_LP;
2990                 break;
2991
2992         default:
2993                 result = false;
2994                 break;
2995         }
2996
2997         return result;
2998 }
2999
3000 static int tonga_set_s0_mc_reg_index(struct tonga_mc_reg_table *table)
3001 {
3002         uint32_t i;
3003         uint16_t address;
3004
3005         for (i = 0; i < table->last; i++) {
3006                 table->mc_reg_address[i].s0 =
3007                         tonga_check_s0_mc_reg_index(table->mc_reg_address[i].s1,
3008                                                         &address) ?
3009                                                         address :
3010                                                  table->mc_reg_address[i].s1;
3011         }
3012         return 0;
3013 }
3014
3015 static int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table,
3016                                         struct tonga_mc_reg_table *ni_table)
3017 {
3018         uint8_t i, j;
3019
3020         PP_ASSERT_WITH_CODE((table->last <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3021                 "Invalid VramInfo table.", return -EINVAL);
3022         PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
3023                 "Invalid VramInfo table.", return -EINVAL);
3024
3025         for (i = 0; i < table->last; i++)
3026                 ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
3027
3028         ni_table->last = table->last;
3029
3030         for (i = 0; i < table->num_entries; i++) {
3031                 ni_table->mc_reg_table_entry[i].mclk_max =
3032                         table->mc_reg_table_entry[i].mclk_max;
3033                 for (j = 0; j < table->last; j++) {
3034                         ni_table->mc_reg_table_entry[i].mc_data[j] =
3035                                 table->mc_reg_table_entry[i].mc_data[j];
3036                 }
3037         }
3038
3039         ni_table->num_entries = table->num_entries;
3040
3041         return 0;
3042 }
3043
3044 static int tonga_set_mc_special_registers(struct pp_hwmgr *hwmgr,
3045                                         struct tonga_mc_reg_table *table)
3046 {
3047         uint8_t i, j, k;
3048         uint32_t temp_reg;
3049         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3050
3051         for (i = 0, j = table->last; i < table->last; i++) {
3052                 PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3053                         "Invalid VramInfo table.", return -EINVAL);
3054
3055                 switch (table->mc_reg_address[i].s1) {
3056
3057                 case mmMC_SEQ_MISC1:
3058                         temp_reg = cgs_read_register(hwmgr->device,
3059                                                         mmMC_PMG_CMD_EMRS);
3060                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
3061                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
3062                         for (k = 0; k < table->num_entries; k++) {
3063                                 table->mc_reg_table_entry[k].mc_data[j] =
3064                                         ((temp_reg & 0xffff0000)) |
3065                                         ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
3066                         }
3067                         j++;
3068
3069                         PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3070                                 "Invalid VramInfo table.", return -EINVAL);
3071                         temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
3072                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
3073                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
3074                         for (k = 0; k < table->num_entries; k++) {
3075                                 table->mc_reg_table_entry[k].mc_data[j] =
3076                                         (temp_reg & 0xffff0000) |
3077                                         (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
3078
3079                                 if (!data->is_memory_gddr5)
3080                                         table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
3081                         }
3082                         j++;
3083
3084                         if (!data->is_memory_gddr5) {
3085                                 PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3086                                         "Invalid VramInfo table.", return -EINVAL);
3087                                 table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
3088                                 table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
3089                                 for (k = 0; k < table->num_entries; k++)
3090                                         table->mc_reg_table_entry[k].mc_data[j] =
3091                                                 (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
3092                                 j++;
3093                         }
3094
3095                         break;
3096
3097                 case mmMC_SEQ_RESERVE_M:
3098                         temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
3099                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
3100                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
3101                         for (k = 0; k < table->num_entries; k++) {
3102                                 table->mc_reg_table_entry[k].mc_data[j] =
3103                                         (temp_reg & 0xffff0000) |
3104                                         (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
3105                         }
3106                         j++;
3107                         break;
3108
3109                 default:
3110                         break;
3111                 }
3112
3113         }
3114
3115         table->last = j;
3116
3117         return 0;
3118 }
3119
3120 static int tonga_set_valid_flag(struct tonga_mc_reg_table *table)
3121 {
3122         uint8_t i, j;
3123
3124         for (i = 0; i < table->last; i++) {
3125                 for (j = 1; j < table->num_entries; j++) {
3126                         if (table->mc_reg_table_entry[j-1].mc_data[i] !=
3127                                 table->mc_reg_table_entry[j].mc_data[i]) {
3128                                 table->validflag |= (1<<i);
3129                                 break;
3130                         }
3131                 }
3132         }
3133
3134         return 0;
3135 }
3136
3137 static int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
3138 {
3139         int result;
3140         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend);
3141         pp_atomctrl_mc_reg_table *table;
3142         struct tonga_mc_reg_table *ni_table = &smu_data->mc_reg_table;
3143         uint8_t module_index = tonga_get_memory_modile_index(hwmgr);
3144
3145         table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
3146
3147         if (table == NULL)
3148                 return -ENOMEM;
3149
3150         /* Program additional LP registers that are no longer programmed by VBIOS */
3151         cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
3152                         cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
3153         cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
3154                         cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
3155         cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP,
3156                         cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
3157         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP,
3158                         cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
3159         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP,
3160                         cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
3161         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP,
3162                         cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
3163         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP,
3164                         cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
3165         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP,
3166                         cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
3167         cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP,
3168                         cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
3169         cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
3170                         cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
3171         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP,
3172                         cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
3173         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP,
3174                         cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
3175         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP,
3176                         cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
3177         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP,
3178                         cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
3179         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
3180                         cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
3181         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
3182                         cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
3183         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
3184                         cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
3185         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
3186                         cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
3187         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP,
3188                         cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
3189         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP,
3190                         cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
3191
3192         memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
3193
3194         result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
3195
3196         if (!result)
3197                 result = tonga_copy_vbios_smc_reg_table(table, ni_table);
3198
3199         if (!result) {
3200                 tonga_set_s0_mc_reg_index(ni_table);
3201                 result = tonga_set_mc_special_registers(hwmgr, ni_table);
3202         }
3203
3204         if (!result)
3205                 tonga_set_valid_flag(ni_table);
3206
3207         kfree(table);
3208
3209         return result;
3210 }
3211
3212 static bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr)
3213 {
3214         return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
3215                         CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
3216                         ? true : false;
3217 }
3218
3219 static int tonga_update_dpm_settings(struct pp_hwmgr *hwmgr,
3220                                 void *profile_setting)
3221 {
3222         struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
3223         struct tonga_smumgr *smu_data = (struct tonga_smumgr *)
3224                         (hwmgr->smu_backend);
3225         struct profile_mode_setting *setting;
3226         struct SMU72_Discrete_GraphicsLevel *levels =
3227                         smu_data->smc_state_table.GraphicsLevel;
3228         uint32_t array = smu_data->smu7_data.dpm_table_start +
3229                         offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
3230
3231         uint32_t mclk_array = smu_data->smu7_data.dpm_table_start +
3232                         offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
3233         struct SMU72_Discrete_MemoryLevel *mclk_levels =
3234                         smu_data->smc_state_table.MemoryLevel;
3235         uint32_t i;
3236         uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp;
3237
3238         if (profile_setting == NULL)
3239                 return -EINVAL;
3240
3241         setting = (struct profile_mode_setting *)profile_setting;
3242
3243         if (setting->bupdate_sclk) {
3244                 if (!data->sclk_dpm_key_disabled)
3245                         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel);
3246                 for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) {
3247                         if (levels[i].ActivityLevel !=
3248                                 cpu_to_be16(setting->sclk_activity)) {
3249                                 levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity);
3250
3251                                 clk_activity_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i)
3252                                                 + offsetof(SMU72_Discrete_GraphicsLevel, ActivityLevel);
3253                                 offset = clk_activity_offset & ~0x3;
3254                                 tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
3255                                 tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t));
3256                                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
3257
3258                         }
3259                         if (levels[i].UpHyst != setting->sclk_up_hyst ||
3260                                 levels[i].DownHyst != setting->sclk_down_hyst) {
3261                                 levels[i].UpHyst = setting->sclk_up_hyst;
3262                                 levels[i].DownHyst = setting->sclk_down_hyst;
3263                                 up_hyst_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i)
3264                                                 + offsetof(SMU72_Discrete_GraphicsLevel, UpHyst);
3265                                 down_hyst_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i)
3266                                                 + offsetof(SMU72_Discrete_GraphicsLevel, DownHyst);
3267                                 offset = up_hyst_offset & ~0x3;
3268                                 tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
3269                                 tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpHyst, sizeof(uint8_t));
3270                                 tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownHyst, sizeof(uint8_t));
3271                                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
3272                         }
3273                 }
3274                 if (!data->sclk_dpm_key_disabled)
3275                         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel);
3276         }
3277
3278         if (setting->bupdate_mclk) {
3279                 if (!data->mclk_dpm_key_disabled)
3280                         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel);
3281                 for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) {
3282                         if (mclk_levels[i].ActivityLevel !=
3283                                 cpu_to_be16(setting->mclk_activity)) {
3284                                 mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity);
3285
3286                                 clk_activity_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i)
3287                                                 + offsetof(SMU72_Discrete_MemoryLevel, ActivityLevel);
3288                                 offset = clk_activity_offset & ~0x3;
3289                                 tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
3290                                 tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t));
3291                                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
3292
3293                         }
3294                         if (mclk_levels[i].UpHyst != setting->mclk_up_hyst ||
3295                                 mclk_levels[i].DownHyst != setting->mclk_down_hyst) {
3296                                 mclk_levels[i].UpHyst = setting->mclk_up_hyst;
3297                                 mclk_levels[i].DownHyst = setting->mclk_down_hyst;
3298                                 up_hyst_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i)
3299                                                 + offsetof(SMU72_Discrete_MemoryLevel, UpHyst);
3300                                 down_hyst_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i)
3301                                                 + offsetof(SMU72_Discrete_MemoryLevel, DownHyst);
3302                                 offset = up_hyst_offset & ~0x3;
3303                                 tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset));
3304                                 tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpHyst, sizeof(uint8_t));
3305                                 tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownHyst, sizeof(uint8_t));
3306                                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp));
3307                         }
3308                 }
3309                 if (!data->mclk_dpm_key_disabled)
3310                         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel);
3311         }
3312         return 0;
3313 }
3314
3315 const struct pp_smumgr_func tonga_smu_funcs = {
3316         .smu_init = &tonga_smu_init,
3317         .smu_fini = &smu7_smu_fini,
3318         .start_smu = &tonga_start_smu,
3319         .check_fw_load_finish = &smu7_check_fw_load_finish,
3320         .request_smu_load_fw = &smu7_request_smu_load_fw,
3321         .request_smu_load_specific_fw = NULL,
3322         .send_msg_to_smc = &smu7_send_msg_to_smc,
3323         .send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
3324         .download_pptable_settings = NULL,
3325         .upload_pptable_settings = NULL,
3326         .update_smc_table = tonga_update_smc_table,
3327         .get_offsetof = tonga_get_offsetof,
3328         .process_firmware_header = tonga_process_firmware_header,
3329         .init_smc_table = tonga_init_smc_table,
3330         .update_sclk_threshold = tonga_update_sclk_threshold,
3331         .thermal_setup_fan_table = tonga_thermal_setup_fan_table,
3332         .populate_all_graphic_levels = tonga_populate_all_graphic_levels,
3333         .populate_all_memory_levels = tonga_populate_all_memory_levels,
3334         .get_mac_definition = tonga_get_mac_definition,
3335         .initialize_mc_reg_table = tonga_initialize_mc_reg_table,
3336         .is_dpm_running = tonga_is_dpm_running,
3337         .update_dpm_settings = tonga_update_dpm_settings,
3338 };