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