49f8af515d733d54e8ac679430901af670680afc
[linux-2.6-block.git] / drivers / gpu / drm / amd / powerplay / hwmgr / tonga_hwmgr.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 <linux/module.h>
24 #include <linux/slab.h>
25 #include <linux/fb.h>
26 #include "linux/delay.h"
27 #include "pp_acpi.h"
28 #include "hwmgr.h"
29 #include <atombios.h>
30 #include "tonga_hwmgr.h"
31 #include "pptable.h"
32 #include "processpptables.h"
33 #include "tonga_processpptables.h"
34 #include "tonga_pptable.h"
35 #include "pp_debug.h"
36 #include "tonga_ppsmc.h"
37 #include "cgs_common.h"
38 #include "pppcielanes.h"
39 #include "tonga_dyn_defaults.h"
40 #include "smumgr.h"
41 #include "tonga_smumgr.h"
42 #include "tonga_clockpowergating.h"
43 #include "tonga_thermal.h"
44
45 #include "smu/smu_7_1_2_d.h"
46 #include "smu/smu_7_1_2_sh_mask.h"
47
48 #include "gmc/gmc_8_1_d.h"
49 #include "gmc/gmc_8_1_sh_mask.h"
50
51 #include "bif/bif_5_0_d.h"
52 #include "bif/bif_5_0_sh_mask.h"
53
54 #include "cgs_linux.h"
55 #include "eventmgr.h"
56 #include "amd_pcie_helpers.h"
57
58 #define MC_CG_ARB_FREQ_F0           0x0a
59 #define MC_CG_ARB_FREQ_F1           0x0b
60 #define MC_CG_ARB_FREQ_F2           0x0c
61 #define MC_CG_ARB_FREQ_F3           0x0d
62
63 #define MC_CG_SEQ_DRAMCONF_S0       0x05
64 #define MC_CG_SEQ_DRAMCONF_S1       0x06
65 #define MC_CG_SEQ_YCLK_SUSPEND      0x04
66 #define MC_CG_SEQ_YCLK_RESUME       0x0a
67
68 #define PCIE_BUS_CLK                10000
69 #define TCLK                        (PCIE_BUS_CLK / 10)
70
71 #define SMC_RAM_END 0x40000
72 #define SMC_CG_IND_START            0xc0030000
73 #define SMC_CG_IND_END              0xc0040000  /* First byte after SMC_CG_IND*/
74
75 #define VOLTAGE_SCALE               4
76 #define VOLTAGE_VID_OFFSET_SCALE1   625
77 #define VOLTAGE_VID_OFFSET_SCALE2   100
78
79 #define VDDC_VDDCI_DELTA            200
80 #define VDDC_VDDGFX_DELTA           300
81
82 #define MC_SEQ_MISC0_GDDR5_SHIFT 28
83 #define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
84 #define MC_SEQ_MISC0_GDDR5_VALUE 5
85
86 typedef uint32_t PECI_RegistryValue;
87
88 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
89 uint16_t PP_ClockStretcherLookupTable[2][4] = {
90         {600, 1050, 3, 0},
91         {600, 1050, 6, 1} };
92
93 /* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
94 uint32_t PP_ClockStretcherDDTTable[2][4][4] = {
95         { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
96         { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
97
98 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
99 uint8_t PP_ClockStretchAmountConversion[2][6] = {
100         {0, 1, 3, 2, 4, 5},
101         {0, 2, 4, 5, 6, 5} };
102
103 /* Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
104 enum DPM_EVENT_SRC {
105         DPM_EVENT_SRC_ANALOG = 0,               /* Internal analog trip point */
106         DPM_EVENT_SRC_EXTERNAL = 1,             /* External (GPIO 17) signal */
107         DPM_EVENT_SRC_DIGITAL = 2,              /* Internal digital trip point (DIG_THERM_DPM) */
108         DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,   /* Internal analog or external */
109         DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4   /* Internal digital or external */
110 };
111 typedef enum DPM_EVENT_SRC DPM_EVENT_SRC;
112
113 const unsigned long PhwTonga_Magic = (unsigned long)(PHM_VIslands_Magic);
114
115 struct tonga_power_state *cast_phw_tonga_power_state(
116                                   struct pp_hw_power_state *hw_ps)
117 {
118         PP_ASSERT_WITH_CODE((PhwTonga_Magic == hw_ps->magic),
119                                 "Invalid Powerstate Type!",
120                                  return NULL;);
121
122         return (struct tonga_power_state *)hw_ps;
123 }
124
125 const struct tonga_power_state *cast_const_phw_tonga_power_state(
126                                  const struct pp_hw_power_state *hw_ps)
127 {
128         PP_ASSERT_WITH_CODE((PhwTonga_Magic == hw_ps->magic),
129                                 "Invalid Powerstate Type!",
130                                  return NULL;);
131
132         return (const struct tonga_power_state *)hw_ps;
133 }
134
135 int tonga_add_voltage(struct pp_hwmgr *hwmgr,
136         phm_ppt_v1_voltage_lookup_table *look_up_table,
137         phm_ppt_v1_voltage_lookup_record *record)
138 {
139         uint32_t i;
140         PP_ASSERT_WITH_CODE((NULL != look_up_table),
141                 "Lookup Table empty.", return -1;);
142         PP_ASSERT_WITH_CODE((0 != look_up_table->count),
143                 "Lookup Table empty.", return -1;);
144         PP_ASSERT_WITH_CODE((SMU72_MAX_LEVELS_VDDGFX >= look_up_table->count),
145                 "Lookup Table is full.", return -1;);
146
147         /* This is to avoid entering duplicate calculated records. */
148         for (i = 0; i < look_up_table->count; i++) {
149                 if (look_up_table->entries[i].us_vdd == record->us_vdd) {
150                         if (look_up_table->entries[i].us_calculated == 1)
151                                 return 0;
152                         else
153                                 break;
154                 }
155         }
156
157         look_up_table->entries[i].us_calculated = 1;
158         look_up_table->entries[i].us_vdd = record->us_vdd;
159         look_up_table->entries[i].us_cac_low = record->us_cac_low;
160         look_up_table->entries[i].us_cac_mid = record->us_cac_mid;
161         look_up_table->entries[i].us_cac_high = record->us_cac_high;
162         /* Only increment the count when we're appending, not replacing duplicate entry. */
163         if (i == look_up_table->count)
164                 look_up_table->count++;
165
166         return 0;
167 }
168
169 int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
170 {
171         PPSMC_Msg msg = has_display? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
172
173         return (smum_send_msg_to_smc(hwmgr->smumgr, msg) == 0) ?  0 : -1;
174 }
175
176 uint8_t tonga_get_voltage_id(pp_atomctrl_voltage_table *voltage_table,
177                 uint32_t voltage)
178 {
179         uint8_t count = (uint8_t) (voltage_table->count);
180         uint8_t i = 0;
181
182         PP_ASSERT_WITH_CODE((NULL != voltage_table),
183                 "Voltage Table empty.", return 0;);
184         PP_ASSERT_WITH_CODE((0 != count),
185                 "Voltage Table empty.", return 0;);
186
187         for (i = 0; i < count; i++) {
188                 /* find first voltage bigger than requested */
189                 if (voltage_table->entries[i].value >= voltage)
190                         return i;
191         }
192
193         /* voltage is bigger than max voltage in the table */
194         return i - 1;
195 }
196
197 /**
198  * @brief PhwTonga_GetVoltageOrder
199  *  Returns index of requested voltage record in lookup(table)
200  * @param hwmgr - pointer to hardware manager
201  * @param lookupTable - lookup list to search in
202  * @param voltage - voltage to look for
203  * @return 0 on success
204  */
205 uint8_t tonga_get_voltage_index(phm_ppt_v1_voltage_lookup_table *look_up_table,
206                 uint16_t voltage)
207 {
208         uint8_t count = (uint8_t) (look_up_table->count);
209         uint8_t i;
210
211         PP_ASSERT_WITH_CODE((NULL != look_up_table), "Lookup Table empty.", return 0;);
212         PP_ASSERT_WITH_CODE((0 != count), "Lookup Table empty.", return 0;);
213
214         for (i = 0; i < count; i++) {
215                 /* find first voltage equal or bigger than requested */
216                 if (look_up_table->entries[i].us_vdd >= voltage)
217                         return i;
218         }
219
220         /* voltage is bigger than max voltage in the table */
221         return i-1;
222 }
223
224 bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr)
225 {
226         /*
227          * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
228          * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
229          * whereas voltage control is a fundemental change that will not be disabled
230          */
231
232         return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
233                                         FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) ? 1 : 0);
234 }
235
236 /**
237  * Re-generate the DPM level mask value
238  * @param    hwmgr      the address of the hardware manager
239  */
240 static uint32_t tonga_get_dpm_level_enable_mask_value(
241                         struct tonga_single_dpm_table * dpm_table)
242 {
243         uint32_t i;
244         uint32_t mask_value = 0;
245
246         for (i = dpm_table->count; i > 0; i--) {
247                 mask_value = mask_value << 1;
248
249                 if (dpm_table->dpm_levels[i-1].enabled)
250                         mask_value |= 0x1;
251                 else
252                         mask_value &= 0xFFFFFFFE;
253         }
254         return mask_value;
255 }
256
257 /**
258  * Retrieve DPM default values from registry (if available)
259  *
260  * @param    hwmgr  the address of the powerplay hardware manager.
261  */
262 void tonga_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
263 {
264         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
265         phw_tonga_ulv_parm *ulv = &(data->ulv);
266         uint32_t tmp;
267
268         ulv->ch_ulv_parameter = PPTONGA_CGULVPARAMETER_DFLT;
269         data->voting_rights_clients0 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0;
270         data->voting_rights_clients1 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1;
271         data->voting_rights_clients2 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2;
272         data->voting_rights_clients3 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3;
273         data->voting_rights_clients4 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4;
274         data->voting_rights_clients5 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5;
275         data->voting_rights_clients6 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6;
276         data->voting_rights_clients7 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7;
277
278         data->static_screen_threshold_unit = PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT;
279         data->static_screen_threshold = PPTONGA_STATICSCREENTHRESHOLD_DFLT;
280
281         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
282                 PHM_PlatformCaps_ABM);
283         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
284                 PHM_PlatformCaps_NonABMSupportInPPLib);
285
286         tmp = 0;
287         if (tmp == 0)
288                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
289                         PHM_PlatformCaps_DynamicACTiming);
290
291         tmp = 0;
292         if (0 != tmp)
293                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
294                         PHM_PlatformCaps_DisableMemoryTransition);
295
296         data->mclk_strobe_mode_threshold = 40000;
297         data->mclk_stutter_mode_threshold = 30000;
298         data->mclk_edc_enable_threshold = 40000;
299         data->mclk_edc_wr_enable_threshold = 40000;
300
301         tmp = 0;
302         if (tmp != 0)
303                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
304                         PHM_PlatformCaps_DisableMCLS);
305
306         data->pcie_gen_performance.max = PP_PCIEGen1;
307         data->pcie_gen_performance.min = PP_PCIEGen3;
308         data->pcie_gen_power_saving.max = PP_PCIEGen1;
309         data->pcie_gen_power_saving.min = PP_PCIEGen3;
310
311         data->pcie_lane_performance.max = 0;
312         data->pcie_lane_performance.min = 16;
313         data->pcie_lane_power_saving.max = 0;
314         data->pcie_lane_power_saving.min = 16;
315
316         tmp = 0;
317
318         if (tmp)
319                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
320                         PHM_PlatformCaps_SclkThrottleLowNotification);
321
322         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
323                 PHM_PlatformCaps_DynamicUVDState);
324
325 }
326
327 int tonga_update_sclk_threshold(struct pp_hwmgr *hwmgr)
328 {
329         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
330
331         int result = 0;
332         uint32_t low_sclk_interrupt_threshold = 0;
333
334         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
335                         PHM_PlatformCaps_SclkThrottleLowNotification)
336                 && (hwmgr->gfx_arbiter.sclk_threshold != data->low_sclk_interrupt_threshold)) {
337                 data->low_sclk_interrupt_threshold = hwmgr->gfx_arbiter.sclk_threshold;
338                 low_sclk_interrupt_threshold = data->low_sclk_interrupt_threshold;
339
340                 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
341
342                 result = tonga_copy_bytes_to_smc(
343                                 hwmgr->smumgr,
344                                 data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable,
345                                 LowSclkInterruptThreshold),
346                                 (uint8_t *)&low_sclk_interrupt_threshold,
347                                 sizeof(uint32_t),
348                                 data->sram_end
349                                 );
350         }
351
352         return result;
353 }
354
355 /**
356  * Find SCLK value that is associated with specified virtual_voltage_Id.
357  *
358  * @param    hwmgr  the address of the powerplay hardware manager.
359  * @param    virtual_voltage_Id  voltageId to look for.
360  * @param    sclk output value .
361  * @return   always 0 if success and 2 if association not found
362  */
363 static int tonga_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
364         phm_ppt_v1_voltage_lookup_table *lookup_table,
365         uint16_t virtual_voltage_id, uint32_t *sclk)
366 {
367         uint8_t entryId;
368         uint8_t voltageId;
369         struct phm_ppt_v1_information *pptable_info =
370                                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
371
372         PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -1);
373
374         /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
375         for (entryId = 0; entryId < pptable_info->vdd_dep_on_sclk->count; entryId++) {
376                 voltageId = pptable_info->vdd_dep_on_sclk->entries[entryId].vddInd;
377                 if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
378                         break;
379         }
380
381         PP_ASSERT_WITH_CODE(entryId < pptable_info->vdd_dep_on_sclk->count,
382                         "Can't find requested voltage id in vdd_dep_on_sclk table!",
383                         return -1;
384                         );
385
386         *sclk = pptable_info->vdd_dep_on_sclk->entries[entryId].clk;
387
388         return 0;
389 }
390
391 /**
392  * Get Leakage VDDC based on leakage ID.
393  *
394  * @param    hwmgr  the address of the powerplay hardware manager.
395  * @return   2 if vddgfx returned is greater than 2V or if BIOS
396  */
397 int tonga_get_evv_voltage(struct pp_hwmgr *hwmgr)
398 {
399         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
400         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
401         phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
402         uint16_t    virtual_voltage_id;
403         uint16_t    vddc = 0;
404         uint16_t    vddgfx = 0;
405         uint16_t    i, j;
406         uint32_t  sclk = 0;
407
408         /* retrieve voltage for leakage ID (0xff01 + i) */
409         for (i = 0; i < TONGA_MAX_LEAKAGE_COUNT; i++) {
410                 virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
411
412                 /* in split mode we should have only vddgfx EVV leakages */
413                 if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
414                         if (0 == tonga_get_sclk_for_voltage_evv(hwmgr,
415                                                 pptable_info->vddgfx_lookup_table, virtual_voltage_id, &sclk)) {
416                                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
417                                                         PHM_PlatformCaps_ClockStretcher)) {
418                                         for (j = 1; j < sclk_table->count; j++) {
419                                                 if (sclk_table->entries[j].clk == sclk &&
420                                                                 sclk_table->entries[j].cks_enable == 0) {
421                                                         sclk += 5000;
422                                                         break;
423                                                 }
424                                         }
425                                 }
426                                 PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
427                                                 (hwmgr, VOLTAGE_TYPE_VDDGFX, sclk,
428                                                  virtual_voltage_id, &vddgfx),
429                                                 "Error retrieving EVV voltage value!", continue);
430
431                                 /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
432                                 PP_ASSERT_WITH_CODE((vddgfx < 2000 && vddgfx != 0), "Invalid VDDGFX value!", return -1);
433
434                                 /* the voltage should not be zero nor equal to leakage ID */
435                                 if (vddgfx != 0 && vddgfx != virtual_voltage_id) {
436                                         data->vddcgfx_leakage.actual_voltage[data->vddcgfx_leakage.count] = vddgfx;
437                                         data->vddcgfx_leakage.leakage_id[data->vddcgfx_leakage.count] = virtual_voltage_id;
438                                         data->vddcgfx_leakage.count++;
439                                 }
440                         }
441                 } else {
442                         /*  in merged mode we have only vddc EVV leakages */
443                         if (0 == tonga_get_sclk_for_voltage_evv(hwmgr,
444                                                 pptable_info->vddc_lookup_table,
445                                                 virtual_voltage_id, &sclk)) {
446                                 PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
447                                                 (hwmgr, VOLTAGE_TYPE_VDDC, sclk,
448                                                  virtual_voltage_id, &vddc),
449                                                 "Error retrieving EVV voltage value!", continue);
450
451                                 /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
452                                 if (vddc > 2000)
453                                         printk(KERN_ERR "[ powerplay ] Invalid VDDC value! \n");
454
455                                 /* the voltage should not be zero nor equal to leakage ID */
456                                 if (vddc != 0 && vddc != virtual_voltage_id) {
457                                         data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = vddc;
458                                         data->vddc_leakage.leakage_id[data->vddc_leakage.count] = virtual_voltage_id;
459                                         data->vddc_leakage.count++;
460                                 }
461                         }
462                 }
463         }
464
465         return 0;
466 }
467
468 int tonga_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
469 {
470         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
471
472         /* enable SCLK dpm */
473         if (0 == data->sclk_dpm_key_disabled) {
474                 PP_ASSERT_WITH_CODE(
475                                 (0 == smum_send_msg_to_smc(hwmgr->smumgr,
476                                                    PPSMC_MSG_DPM_Enable)),
477                                 "Failed to enable SCLK DPM during DPM Start Function!",
478                                 return -1);
479         }
480
481         /* enable MCLK dpm */
482         if (0 == data->mclk_dpm_key_disabled) {
483                 PP_ASSERT_WITH_CODE(
484                                 (0 == smum_send_msg_to_smc(hwmgr->smumgr,
485                                              PPSMC_MSG_MCLKDPM_Enable)),
486                                 "Failed to enable MCLK DPM during DPM Start Function!",
487                                 return -1);
488
489                 PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1);
490
491                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
492                         ixLCAC_MC0_CNTL, 0x05);/* CH0,1 read */
493                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
494                         ixLCAC_MC1_CNTL, 0x05);/* CH2,3 read */
495                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
496                         ixLCAC_CPL_CNTL, 0x100005);/*Read */
497
498                 udelay(10);
499
500                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
501                         ixLCAC_MC0_CNTL, 0x400005);/* CH0,1 write */
502                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
503                         ixLCAC_MC1_CNTL, 0x400005);/* CH2,3 write */
504                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
505                         ixLCAC_CPL_CNTL, 0x500005);/* write */
506
507         }
508
509         return 0;
510 }
511
512 int tonga_start_dpm(struct pp_hwmgr *hwmgr)
513 {
514         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
515
516         /* enable general power management */
517         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 1);
518         /* enable sclk deep sleep */
519         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 1);
520
521         /* prepare for PCIE DPM */
522         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start +
523                         offsetof(SMU72_SoftRegisters, VoltageChangeTimeout), 0x1000);
524
525         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE, SWRST_COMMAND_1, RESETLC, 0x0);
526
527         PP_ASSERT_WITH_CODE(
528                         (0 == smum_send_msg_to_smc(hwmgr->smumgr,
529                                         PPSMC_MSG_Voltage_Cntl_Enable)),
530                         "Failed to enable voltage DPM during DPM Start Function!",
531                         return -1);
532
533         if (0 != tonga_enable_sclk_mclk_dpm(hwmgr)) {
534                 PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1);
535         }
536
537         /* enable PCIE dpm */
538         if (0 == data->pcie_dpm_key_disabled) {
539                 PP_ASSERT_WITH_CODE(
540                                 (0 == smum_send_msg_to_smc(hwmgr->smumgr,
541                                                 PPSMC_MSG_PCIeDPM_Enable)),
542                                 "Failed to enable pcie DPM during DPM Start Function!",
543                                 return -1
544                                 );
545         }
546
547         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
548                                 PHM_PlatformCaps_Falcon_QuickTransition)) {
549                                    smum_send_msg_to_smc(hwmgr->smumgr,
550                                     PPSMC_MSG_EnableACDCGPIOInterrupt);
551         }
552
553         return 0;
554 }
555
556 int tonga_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
557 {
558         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
559
560         /* disable SCLK dpm */
561         if (0 == data->sclk_dpm_key_disabled) {
562                 /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
563                 PP_ASSERT_WITH_CODE(
564                                 (0 == tonga_is_dpm_running(hwmgr)),
565                                 "Trying to Disable SCLK DPM when DPM is disabled",
566                                 return -1
567                                 );
568
569                 PP_ASSERT_WITH_CODE(
570                                 (0 == smum_send_msg_to_smc(hwmgr->smumgr,
571                                                   PPSMC_MSG_DPM_Disable)),
572                                 "Failed to disable SCLK DPM during DPM stop Function!",
573                                 return -1);
574         }
575
576         /* disable MCLK dpm */
577         if (0 == data->mclk_dpm_key_disabled) {
578                 /* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
579                 PP_ASSERT_WITH_CODE(
580                                 (0 == tonga_is_dpm_running(hwmgr)),
581                                 "Trying to Disable MCLK DPM when DPM is disabled",
582                                 return -1
583                                 );
584
585                 PP_ASSERT_WITH_CODE(
586                                 (0 == smum_send_msg_to_smc(hwmgr->smumgr,
587                                             PPSMC_MSG_MCLKDPM_Disable)),
588                                 "Failed to Disable MCLK DPM during DPM stop Function!",
589                                 return -1);
590         }
591
592         return 0;
593 }
594
595 int tonga_stop_dpm(struct pp_hwmgr *hwmgr)
596 {
597         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
598
599         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 0);
600         /* disable sclk deep sleep*/
601         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 0);
602
603         /* disable PCIE dpm */
604         if (0 == data->pcie_dpm_key_disabled) {
605                 /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
606                 PP_ASSERT_WITH_CODE(
607                                 (0 == tonga_is_dpm_running(hwmgr)),
608                                 "Trying to Disable PCIE DPM when DPM is disabled",
609                                 return -1
610                                 );
611                 PP_ASSERT_WITH_CODE(
612                                 (0 == smum_send_msg_to_smc(hwmgr->smumgr,
613                                                 PPSMC_MSG_PCIeDPM_Disable)),
614                                 "Failed to disable pcie DPM during DPM stop Function!",
615                                 return -1);
616         }
617
618         if (0 != tonga_disable_sclk_mclk_dpm(hwmgr))
619                 PP_ASSERT_WITH_CODE(0, "Failed to disable Sclk DPM and Mclk DPM!", return -1);
620
621         /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
622         PP_ASSERT_WITH_CODE(
623                         (0 == tonga_is_dpm_running(hwmgr)),
624                         "Trying to Disable Voltage CNTL when DPM is disabled",
625                         return -1
626                         );
627
628         PP_ASSERT_WITH_CODE(
629                         (0 == smum_send_msg_to_smc(hwmgr->smumgr,
630                                         PPSMC_MSG_Voltage_Cntl_Disable)),
631                         "Failed to disable voltage DPM during DPM stop Function!",
632                         return -1);
633
634         return 0;
635 }
636
637 int tonga_enable_sclk_control(struct pp_hwmgr *hwmgr)
638 {
639         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, 0);
640
641         return 0;
642 }
643
644 /**
645  * Send a message to the SMC and return a parameter
646  *
647  * @param    hwmgr:  the address of the powerplay hardware manager.
648  * @param    msg: the message to send.
649  * @param    parameter: pointer to the received parameter
650  * @return   The response that came from the SMC.
651  */
652 PPSMC_Result tonga_send_msg_to_smc_return_parameter(
653                 struct pp_hwmgr *hwmgr,
654                 PPSMC_Msg msg,
655                 uint32_t *parameter)
656 {
657         int result;
658
659         result = smum_send_msg_to_smc(hwmgr->smumgr, msg);
660
661         if ((0 == result) && parameter) {
662                 *parameter = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
663         }
664
665         return result;
666 }
667
668 /**
669  * force DPM power State
670  *
671  * @param    hwmgr:  the address of the powerplay hardware manager.
672  * @param    n     :  DPM level
673  * @return   The response that came from the SMC.
674  */
675 int tonga_dpm_force_state(struct pp_hwmgr *hwmgr, uint32_t n)
676 {
677         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
678         uint32_t level_mask = 1 << n;
679
680         /* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
681         PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
682                         "Trying to force SCLK when DPM is disabled", return -1;);
683         if (0 == data->sclk_dpm_key_disabled)
684                 return (0 == smum_send_msg_to_smc_with_parameter(
685                                                              hwmgr->smumgr,
686                      (PPSMC_Msg)(PPSMC_MSG_SCLKDPM_SetEnabledMask),
687                                                     level_mask) ? 0 : 1);
688
689         return 0;
690 }
691
692 /**
693  * force DPM power State
694  *
695  * @param    hwmgr:  the address of the powerplay hardware manager.
696  * @param    n     :  DPM level
697  * @return   The response that came from the SMC.
698  */
699 int tonga_dpm_force_state_mclk(struct pp_hwmgr *hwmgr, uint32_t n)
700 {
701         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
702         uint32_t level_mask = 1 << n;
703
704         /* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
705         PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
706                         "Trying to Force MCLK when DPM is disabled", return -1;);
707         if (0 == data->mclk_dpm_key_disabled)
708                 return (0 == smum_send_msg_to_smc_with_parameter(
709                                                                 hwmgr->smumgr,
710                                                                 (PPSMC_Msg)(PPSMC_MSG_MCLKDPM_SetEnabledMask),
711                                                                 level_mask) ? 0 : 1);
712
713         return 0;
714 }
715
716 /**
717  * force DPM power State
718  *
719  * @param    hwmgr:  the address of the powerplay hardware manager.
720  * @param    n     :  DPM level
721  * @return   The response that came from the SMC.
722  */
723 int tonga_dpm_force_state_pcie(struct pp_hwmgr *hwmgr, uint32_t n)
724 {
725         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
726
727         /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
728         PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
729                         "Trying to Force PCIE level when DPM is disabled", return -1;);
730         if (0 == data->pcie_dpm_key_disabled)
731                 return (0 == smum_send_msg_to_smc_with_parameter(
732                                                              hwmgr->smumgr,
733                            (PPSMC_Msg)(PPSMC_MSG_PCIeDPM_ForceLevel),
734                                                                 n) ? 0 : 1);
735
736         return 0;
737 }
738
739 /**
740  * Set the initial state by calling SMC to switch to this state directly
741  *
742  * @param    hwmgr  the address of the powerplay hardware manager.
743  * @return   always 0
744  */
745 int tonga_set_boot_state(struct pp_hwmgr *hwmgr)
746 {
747         /*
748         * SMC only stores one state that SW will ask to switch too,
749         * so we switch the the just uploaded one
750         */
751         return (0 == tonga_disable_sclk_mclk_dpm(hwmgr)) ? 0 : 1;
752 }
753
754 /**
755  * Get the location of various tables inside the FW image.
756  *
757  * @param    hwmgr  the address of the powerplay hardware manager.
758  * @return   always 0
759  */
760 int tonga_process_firmware_header(struct pp_hwmgr *hwmgr)
761 {
762         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
763         struct tonga_smumgr *tonga_smu = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
764
765         uint32_t tmp;
766         int result;
767         bool error = 0;
768
769         result = tonga_read_smc_sram_dword(hwmgr->smumgr,
770                                 SMU72_FIRMWARE_HEADER_LOCATION +
771                                 offsetof(SMU72_Firmware_Header, DpmTable),
772                                 &tmp, data->sram_end);
773
774         if (0 == result) {
775                 data->dpm_table_start = tmp;
776         }
777
778         error |= (0 != result);
779
780         result = tonga_read_smc_sram_dword(hwmgr->smumgr,
781                                 SMU72_FIRMWARE_HEADER_LOCATION +
782                                 offsetof(SMU72_Firmware_Header, SoftRegisters),
783                                 &tmp, data->sram_end);
784
785         if (0 == result) {
786                 data->soft_regs_start = tmp;
787                 tonga_smu->ulSoftRegsStart = tmp;
788         }
789
790         error |= (0 != result);
791
792
793         result = tonga_read_smc_sram_dword(hwmgr->smumgr,
794                                 SMU72_FIRMWARE_HEADER_LOCATION +
795                                 offsetof(SMU72_Firmware_Header, mcRegisterTable),
796                                 &tmp, data->sram_end);
797
798         if (0 == result) {
799                 data->mc_reg_table_start = tmp;
800         }
801
802         result = tonga_read_smc_sram_dword(hwmgr->smumgr,
803                                 SMU72_FIRMWARE_HEADER_LOCATION +
804                                 offsetof(SMU72_Firmware_Header, FanTable),
805                                 &tmp, data->sram_end);
806
807         if (0 == result) {
808                 data->fan_table_start = tmp;
809         }
810
811         error |= (0 != result);
812
813         result = tonga_read_smc_sram_dword(hwmgr->smumgr,
814                                 SMU72_FIRMWARE_HEADER_LOCATION +
815                                 offsetof(SMU72_Firmware_Header, mcArbDramTimingTable),
816                                 &tmp, data->sram_end);
817
818         if (0 == result) {
819                 data->arb_table_start = tmp;
820         }
821
822         error |= (0 != result);
823
824
825         result = tonga_read_smc_sram_dword(hwmgr->smumgr,
826                                 SMU72_FIRMWARE_HEADER_LOCATION +
827                                 offsetof(SMU72_Firmware_Header, Version),
828                                 &tmp, data->sram_end);
829
830         if (0 == result) {
831                 hwmgr->microcode_version_info.SMC = tmp;
832         }
833
834         error |= (0 != result);
835
836         return error ? 1 : 0;
837 }
838
839 /**
840  * Read clock related registers.
841  *
842  * @param    hwmgr  the address of the powerplay hardware manager.
843  * @return   always 0
844  */
845 int tonga_read_clock_registers(struct pp_hwmgr *hwmgr)
846 {
847         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
848
849         data->clock_registers.vCG_SPLL_FUNC_CNTL         =
850                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL);
851         data->clock_registers.vCG_SPLL_FUNC_CNTL_2       =
852                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_2);
853         data->clock_registers.vCG_SPLL_FUNC_CNTL_3       =
854                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_3);
855         data->clock_registers.vCG_SPLL_FUNC_CNTL_4       =
856                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_4);
857         data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM   =
858                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM);
859         data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
860                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM_2);
861         data->clock_registers.vDLL_CNTL                  =
862                 cgs_read_register(hwmgr->device, mmDLL_CNTL);
863         data->clock_registers.vMCLK_PWRMGT_CNTL          =
864                 cgs_read_register(hwmgr->device, mmMCLK_PWRMGT_CNTL);
865         data->clock_registers.vMPLL_AD_FUNC_CNTL         =
866                 cgs_read_register(hwmgr->device, mmMPLL_AD_FUNC_CNTL);
867         data->clock_registers.vMPLL_DQ_FUNC_CNTL         =
868                 cgs_read_register(hwmgr->device, mmMPLL_DQ_FUNC_CNTL);
869         data->clock_registers.vMPLL_FUNC_CNTL            =
870                 cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL);
871         data->clock_registers.vMPLL_FUNC_CNTL_1          =
872                 cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_1);
873         data->clock_registers.vMPLL_FUNC_CNTL_2          =
874                 cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_2);
875         data->clock_registers.vMPLL_SS1                  =
876                 cgs_read_register(hwmgr->device, mmMPLL_SS1);
877         data->clock_registers.vMPLL_SS2                  =
878                 cgs_read_register(hwmgr->device, mmMPLL_SS2);
879
880         return 0;
881 }
882
883 /**
884  * Find out if memory is GDDR5.
885  *
886  * @param    hwmgr  the address of the powerplay hardware manager.
887  * @return   always 0
888  */
889 int tonga_get_memory_type(struct pp_hwmgr *hwmgr)
890 {
891         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
892         uint32_t temp;
893
894         temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
895
896         data->is_memory_GDDR5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
897                         ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
898                          MC_SEQ_MISC0_GDDR5_SHIFT));
899
900         return 0;
901 }
902
903 /**
904  * Enables Dynamic Power Management by SMC
905  *
906  * @param    hwmgr  the address of the powerplay hardware manager.
907  * @return   always 0
908  */
909 int tonga_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
910 {
911         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, STATIC_PM_EN, 1);
912
913         return 0;
914 }
915
916 /**
917  * Initialize PowerGating States for different engines
918  *
919  * @param    hwmgr  the address of the powerplay hardware manager.
920  * @return   always 0
921  */
922 int tonga_init_power_gate_state(struct pp_hwmgr *hwmgr)
923 {
924         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
925
926         data->uvd_power_gated = 0;
927         data->vce_power_gated = 0;
928         data->samu_power_gated = 0;
929         data->acp_power_gated = 0;
930         data->pg_acp_init = 1;
931
932         return 0;
933 }
934
935 /**
936  * Checks if DPM is enabled
937  *
938  * @param    hwmgr  the address of the powerplay hardware manager.
939  * @return   always 0
940  */
941 int tonga_check_for_dpm_running(struct pp_hwmgr *hwmgr)
942 {
943         /*
944          * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
945          * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
946          * whereas voltage control is a fundemental change that will not be disabled
947          */
948         return (0 == tonga_is_dpm_running(hwmgr) ? 0 : 1);
949 }
950
951 /**
952  * Checks if DPM is stopped
953  *
954  * @param    hwmgr  the address of the powerplay hardware manager.
955  * @return   always 0
956  */
957 int tonga_check_for_dpm_stopped(struct pp_hwmgr *hwmgr)
958 {
959         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
960
961         if (0 != tonga_is_dpm_running(hwmgr)) {
962                 /* If HW Virtualization is enabled, dpm_table_start will not have a valid value */
963                 if (!data->dpm_table_start) {
964                         return 1;
965                 }
966         }
967
968         return 0;
969 }
970
971 /**
972  * Remove repeated voltage values and create table with unique values.
973  *
974  * @param    hwmgr  the address of the powerplay hardware manager.
975  * @param    voltage_table  the pointer to changing voltage table
976  * @return    1 in success
977  */
978
979 static int tonga_trim_voltage_table(struct pp_hwmgr *hwmgr,
980                         pp_atomctrl_voltage_table *voltage_table)
981 {
982         uint32_t table_size, i, j;
983         uint16_t vvalue;
984         bool bVoltageFound = 0;
985         pp_atomctrl_voltage_table *table;
986
987         PP_ASSERT_WITH_CODE((NULL != voltage_table), "Voltage Table empty.", return -1;);
988         table_size = sizeof(pp_atomctrl_voltage_table);
989         table = kzalloc(table_size, GFP_KERNEL);
990
991         if (NULL == table)
992                 return -ENOMEM;
993
994         memset(table, 0x00, table_size);
995         table->mask_low = voltage_table->mask_low;
996         table->phase_delay = voltage_table->phase_delay;
997
998         for (i = 0; i < voltage_table->count; i++) {
999                 vvalue = voltage_table->entries[i].value;
1000                 bVoltageFound = 0;
1001
1002                 for (j = 0; j < table->count; j++) {
1003                         if (vvalue == table->entries[j].value) {
1004                                 bVoltageFound = 1;
1005                                 break;
1006                         }
1007                 }
1008
1009                 if (!bVoltageFound) {
1010                         table->entries[table->count].value = vvalue;
1011                         table->entries[table->count].smio_low =
1012                                 voltage_table->entries[i].smio_low;
1013                         table->count++;
1014                 }
1015         }
1016
1017         memcpy(table, voltage_table, sizeof(pp_atomctrl_voltage_table));
1018
1019         kfree(table);
1020
1021         return 0;
1022 }
1023
1024 static int tonga_get_svi2_vdd_ci_voltage_table(
1025                 struct pp_hwmgr *hwmgr,
1026                 phm_ppt_v1_clock_voltage_dependency_table *voltage_dependency_table)
1027 {
1028         uint32_t i;
1029         int result;
1030         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1031         pp_atomctrl_voltage_table *vddci_voltage_table = &(data->vddci_voltage_table);
1032
1033         PP_ASSERT_WITH_CODE((0 != voltage_dependency_table->count),
1034                         "Voltage Dependency Table empty.", return -1;);
1035
1036         vddci_voltage_table->mask_low = 0;
1037         vddci_voltage_table->phase_delay = 0;
1038         vddci_voltage_table->count = voltage_dependency_table->count;
1039
1040         for (i = 0; i < voltage_dependency_table->count; i++) {
1041                 vddci_voltage_table->entries[i].value =
1042                         voltage_dependency_table->entries[i].vddci;
1043                 vddci_voltage_table->entries[i].smio_low = 0;
1044         }
1045
1046         result = tonga_trim_voltage_table(hwmgr, vddci_voltage_table);
1047         PP_ASSERT_WITH_CODE((0 == result),
1048                         "Failed to trim VDDCI table.", return result;);
1049
1050         return 0;
1051 }
1052
1053
1054
1055 static int tonga_get_svi2_vdd_voltage_table(
1056                 struct pp_hwmgr *hwmgr,
1057                 phm_ppt_v1_voltage_lookup_table *look_up_table,
1058                 pp_atomctrl_voltage_table *voltage_table)
1059 {
1060         uint8_t i = 0;
1061
1062         PP_ASSERT_WITH_CODE((0 != look_up_table->count),
1063                         "Voltage Lookup Table empty.", return -1;);
1064
1065         voltage_table->mask_low = 0;
1066         voltage_table->phase_delay = 0;
1067
1068         voltage_table->count = look_up_table->count;
1069
1070         for (i = 0; i < voltage_table->count; i++) {
1071                 voltage_table->entries[i].value = look_up_table->entries[i].us_vdd;
1072                 voltage_table->entries[i].smio_low = 0;
1073         }
1074
1075         return 0;
1076 }
1077
1078 /*
1079  * -------------------------------------------------------- Voltage Tables --------------------------------------------------------------------------
1080  * If the voltage table would be bigger than what will fit into the state table on the SMC keep only the higher entries.
1081  */
1082
1083 static void tonga_trim_voltage_table_to_fit_state_table(
1084                 struct pp_hwmgr *hwmgr,
1085                 uint32_t max_voltage_steps,
1086                 pp_atomctrl_voltage_table *voltage_table)
1087 {
1088         unsigned int i, diff;
1089
1090         if (voltage_table->count <= max_voltage_steps) {
1091                 return;
1092         }
1093
1094         diff = voltage_table->count - max_voltage_steps;
1095
1096         for (i = 0; i < max_voltage_steps; i++) {
1097                 voltage_table->entries[i] = voltage_table->entries[i + diff];
1098         }
1099
1100         voltage_table->count = max_voltage_steps;
1101
1102         return;
1103 }
1104
1105 /**
1106  * Create Voltage Tables.
1107  *
1108  * @param    hwmgr  the address of the powerplay hardware manager.
1109  * @return   always 0
1110  */
1111 int tonga_construct_voltage_tables(struct pp_hwmgr *hwmgr)
1112 {
1113         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1114         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1115         int result;
1116
1117         /* MVDD has only GPIO voltage control */
1118         if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
1119                 result = atomctrl_get_voltage_table_v3(hwmgr,
1120                                         VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT, &(data->mvdd_voltage_table));
1121                 PP_ASSERT_WITH_CODE((0 == result),
1122                         "Failed to retrieve MVDD table.", return result;);
1123         }
1124
1125         if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
1126                 /* GPIO voltage */
1127                 result = atomctrl_get_voltage_table_v3(hwmgr,
1128                                         VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT, &(data->vddci_voltage_table));
1129                 PP_ASSERT_WITH_CODE((0 == result),
1130                         "Failed to retrieve VDDCI table.", return result;);
1131         } else if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
1132                 /* SVI2 voltage */
1133                 result = tonga_get_svi2_vdd_ci_voltage_table(hwmgr,
1134                                         pptable_info->vdd_dep_on_mclk);
1135                 PP_ASSERT_WITH_CODE((0 == result),
1136                         "Failed to retrieve SVI2 VDDCI table from dependancy table.", return result;);
1137         }
1138
1139         if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
1140                 /* VDDGFX has only SVI2 voltage control */
1141                 result = tonga_get_svi2_vdd_voltage_table(hwmgr,
1142                                         pptable_info->vddgfx_lookup_table, &(data->vddgfx_voltage_table));
1143                 PP_ASSERT_WITH_CODE((0 == result),
1144                         "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result;);
1145         }
1146
1147         if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1148                 /* VDDC has only SVI2 voltage control */
1149                 result = tonga_get_svi2_vdd_voltage_table(hwmgr,
1150                                         pptable_info->vddc_lookup_table, &(data->vddc_voltage_table));
1151                 PP_ASSERT_WITH_CODE((0 == result),
1152                         "Failed to retrieve SVI2 VDDC table from lookup table.", return result;);
1153         }
1154
1155         PP_ASSERT_WITH_CODE(
1156                         (data->vddc_voltage_table.count <= (SMU72_MAX_LEVELS_VDDC)),
1157                         "Too many voltage values for VDDC. Trimming to fit state table.",
1158                         tonga_trim_voltage_table_to_fit_state_table(hwmgr,
1159                         SMU72_MAX_LEVELS_VDDC, &(data->vddc_voltage_table));
1160                         );
1161
1162         PP_ASSERT_WITH_CODE(
1163                         (data->vddgfx_voltage_table.count <= (SMU72_MAX_LEVELS_VDDGFX)),
1164                         "Too many voltage values for VDDGFX. Trimming to fit state table.",
1165                         tonga_trim_voltage_table_to_fit_state_table(hwmgr,
1166                         SMU72_MAX_LEVELS_VDDGFX, &(data->vddgfx_voltage_table));
1167                         );
1168
1169         PP_ASSERT_WITH_CODE(
1170                         (data->vddci_voltage_table.count <= (SMU72_MAX_LEVELS_VDDCI)),
1171                         "Too many voltage values for VDDCI. Trimming to fit state table.",
1172                         tonga_trim_voltage_table_to_fit_state_table(hwmgr,
1173                         SMU72_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table));
1174                         );
1175
1176         PP_ASSERT_WITH_CODE(
1177                         (data->mvdd_voltage_table.count <= (SMU72_MAX_LEVELS_MVDD)),
1178                         "Too many voltage values for MVDD. Trimming to fit state table.",
1179                         tonga_trim_voltage_table_to_fit_state_table(hwmgr,
1180                         SMU72_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table));
1181                         );
1182
1183         return 0;
1184 }
1185
1186 /**
1187  * Vddc table preparation for SMC.
1188  *
1189  * @param    hwmgr      the address of the hardware manager
1190  * @param    table     the SMC DPM table structure to be populated
1191  * @return   always 0
1192  */
1193 static int tonga_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
1194                         SMU72_Discrete_DpmTable *table)
1195 {
1196         unsigned int count;
1197         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1198
1199         if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1200                 table->VddcLevelCount = data->vddc_voltage_table.count;
1201                 for (count = 0; count < table->VddcLevelCount; count++) {
1202                         table->VddcTable[count] =
1203                                 PP_HOST_TO_SMC_US(data->vddc_voltage_table.entries[count].value * VOLTAGE_SCALE);
1204                 }
1205                 CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
1206         }
1207         return 0;
1208 }
1209
1210 /**
1211  * VddGfx table preparation for SMC.
1212  *
1213  * @param    hwmgr      the address of the hardware manager
1214  * @param    table     the SMC DPM table structure to be populated
1215  * @return   always 0
1216  */
1217 static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr *hwmgr,
1218                         SMU72_Discrete_DpmTable *table)
1219 {
1220         unsigned int count;
1221         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1222
1223         if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
1224                 table->VddGfxLevelCount = data->vddgfx_voltage_table.count;
1225                 for (count = 0; count < data->vddgfx_voltage_table.count; count++) {
1226                         table->VddGfxTable[count] =
1227                                 PP_HOST_TO_SMC_US(data->vddgfx_voltage_table.entries[count].value * VOLTAGE_SCALE);
1228                 }
1229                 CONVERT_FROM_HOST_TO_SMC_UL(table->VddGfxLevelCount);
1230         }
1231         return 0;
1232 }
1233
1234 /**
1235  * Vddci table preparation for SMC.
1236  *
1237  * @param    *hwmgr The address of the hardware manager.
1238  * @param    *table The SMC DPM table structure to be populated.
1239  * @return   0
1240  */
1241 static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
1242                         SMU72_Discrete_DpmTable *table)
1243 {
1244         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1245         uint32_t count;
1246
1247         table->VddciLevelCount = data->vddci_voltage_table.count;
1248         for (count = 0; count < table->VddciLevelCount; count++) {
1249                 if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
1250                         table->VddciTable[count] =
1251                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
1252                 } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
1253                         table->SmioTable1.Pattern[count].Voltage =
1254                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
1255                         /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
1256                         table->SmioTable1.Pattern[count].Smio =
1257                                 (uint8_t) count;
1258                         table->Smio[count] |=
1259                                 data->vddci_voltage_table.entries[count].smio_low;
1260                         table->VddciTable[count] =
1261                                 PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
1262                 }
1263         }
1264
1265         table->SmioMask1 = data->vddci_voltage_table.mask_low;
1266         CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
1267
1268         return 0;
1269 }
1270
1271 /**
1272  * Mvdd table preparation for SMC.
1273  *
1274  * @param    *hwmgr The address of the hardware manager.
1275  * @param    *table The SMC DPM table structure to be populated.
1276  * @return   0
1277  */
1278 static int tonga_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
1279                         SMU72_Discrete_DpmTable *table)
1280 {
1281         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1282         uint32_t count;
1283
1284         if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
1285                 table->MvddLevelCount = data->mvdd_voltage_table.count;
1286                 for (count = 0; count < table->MvddLevelCount; count++) {
1287                         table->SmioTable2.Pattern[count].Voltage =
1288                                 PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
1289                         /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
1290                         table->SmioTable2.Pattern[count].Smio =
1291                                 (uint8_t) count;
1292                         table->Smio[count] |=
1293                                 data->mvdd_voltage_table.entries[count].smio_low;
1294                 }
1295                 table->SmioMask2 = data->vddci_voltage_table.mask_low;
1296
1297                 CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
1298         }
1299
1300         return 0;
1301 }
1302
1303 /**
1304  * Convert a voltage value in mv unit to VID number required by SMU firmware
1305  */
1306 static uint8_t convert_to_vid(uint16_t vddc)
1307 {
1308         return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
1309 }
1310
1311
1312 /**
1313  * Preparation of vddc and vddgfx CAC tables for SMC.
1314  *
1315  * @param    hwmgr      the address of the hardware manager
1316  * @param    table     the SMC DPM table structure to be populated
1317  * @return   always 0
1318  */
1319 static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr,
1320                         SMU72_Discrete_DpmTable *table)
1321 {
1322         uint32_t count;
1323         uint8_t index;
1324         int result = 0;
1325         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1326         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1327         struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table = pptable_info->vddgfx_lookup_table;
1328         struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table = pptable_info->vddc_lookup_table;
1329
1330         /* pTables is already swapped, so in order to use the value from it, we need to swap it back. */
1331         uint32_t vddcLevelCount = PP_SMC_TO_HOST_UL(table->VddcLevelCount);
1332         uint32_t vddgfxLevelCount = PP_SMC_TO_HOST_UL(table->VddGfxLevelCount);
1333
1334         for (count = 0; count < vddcLevelCount; count++) {
1335                 /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
1336                 index = tonga_get_voltage_index(vddc_lookup_table,
1337                         data->vddc_voltage_table.entries[count].value);
1338                 table->BapmVddcVidLoSidd[count] =
1339                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
1340                 table->BapmVddcVidHiSidd[count] =
1341                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
1342                 table->BapmVddcVidHiSidd2[count] =
1343                         convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
1344         }
1345
1346         if ((data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2)) {
1347                 /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
1348                 for (count = 0; count < vddgfxLevelCount; count++) {
1349                         index = tonga_get_voltage_index(vddgfx_lookup_table,
1350                                 data->vddgfx_voltage_table.entries[count].value);
1351                         table->BapmVddGfxVidLoSidd[count] =
1352                                 convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_low);
1353                         table->BapmVddGfxVidHiSidd[count] =
1354                                 convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_mid);
1355                         table->BapmVddGfxVidHiSidd2[count] =
1356                                 convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_high);
1357                 }
1358         } else {
1359                 for (count = 0; count < vddcLevelCount; count++) {
1360                         index = tonga_get_voltage_index(vddc_lookup_table,
1361                                 data->vddc_voltage_table.entries[count].value);
1362                         table->BapmVddGfxVidLoSidd[count] =
1363                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
1364                         table->BapmVddGfxVidHiSidd[count] =
1365                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
1366                         table->BapmVddGfxVidHiSidd2[count] =
1367                                 convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
1368                 }
1369         }
1370
1371         return result;
1372 }
1373
1374
1375 /**
1376  * Preparation of voltage tables for SMC.
1377  *
1378  * @param    hwmgr      the address of the hardware manager
1379  * @param    table     the SMC DPM table structure to be populated
1380  * @return   always 0
1381  */
1382
1383 int tonga_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
1384         SMU72_Discrete_DpmTable *table)
1385 {
1386         int result;
1387
1388         result = tonga_populate_smc_vddc_table(hwmgr, table);
1389         PP_ASSERT_WITH_CODE(0 == result,
1390                         "can not populate VDDC voltage table to SMC", return -1);
1391
1392         result = tonga_populate_smc_vdd_ci_table(hwmgr, table);
1393         PP_ASSERT_WITH_CODE(0 == result,
1394                         "can not populate VDDCI voltage table to SMC", return -1);
1395
1396         result = tonga_populate_smc_vdd_gfx_table(hwmgr, table);
1397         PP_ASSERT_WITH_CODE(0 == result,
1398                         "can not populate VDDGFX voltage table to SMC", return -1);
1399
1400         result = tonga_populate_smc_mvdd_table(hwmgr, table);
1401         PP_ASSERT_WITH_CODE(0 == result,
1402                         "can not populate MVDD voltage table to SMC", return -1);
1403
1404         result = tonga_populate_cac_tables(hwmgr, table);
1405         PP_ASSERT_WITH_CODE(0 == result,
1406                         "can not populate CAC voltage tables to SMC", return -1);
1407
1408         return 0;
1409 }
1410
1411 /**
1412  * Populates the SMC VRConfig field in DPM table.
1413  *
1414  * @param    hwmgr      the address of the hardware manager
1415  * @param    table     the SMC DPM table structure to be populated
1416  * @return   always 0
1417  */
1418 static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
1419                         SMU72_Discrete_DpmTable *table)
1420 {
1421         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1422         uint16_t config;
1423
1424         if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
1425                 /*  Splitted mode */
1426                 config = VR_SVI2_PLANE_1;
1427                 table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
1428
1429                 if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1430                         config = VR_SVI2_PLANE_2;
1431                         table->VRConfig |= config;
1432                 } else {
1433                         printk(KERN_ERR "[ powerplay ] VDDC and VDDGFX should be both on SVI2 control in splitted mode! \n");
1434                 }
1435         } else {
1436                 /* Merged mode  */
1437                 config = VR_MERGED_WITH_VDDC;
1438                 table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
1439
1440                 /* Set Vddc Voltage Controller  */
1441                 if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1442                         config = VR_SVI2_PLANE_1;
1443                         table->VRConfig |= config;
1444                 } else {
1445                         printk(KERN_ERR "[ powerplay ] VDDC should be on SVI2 control in merged mode! \n");
1446                 }
1447         }
1448
1449         /* Set Vddci Voltage Controller  */
1450         if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
1451                 config = VR_SVI2_PLANE_2;  /* only in merged mode */
1452                 table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
1453         } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
1454                 config = VR_SMIO_PATTERN_1;
1455                 table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
1456         }
1457
1458         /* Set Mvdd Voltage Controller */
1459         if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
1460                 config = VR_SMIO_PATTERN_2;
1461                 table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
1462         }
1463
1464         return 0;
1465 }
1466
1467 static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr *hwmgr,
1468         phm_ppt_v1_clock_voltage_dependency_table *allowed_clock_voltage_table,
1469         uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
1470 {
1471         uint32_t i = 0;
1472         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1473         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1474
1475         /* clock - voltage dependency table is empty table */
1476         if (allowed_clock_voltage_table->count == 0)
1477                 return -1;
1478
1479         for (i = 0; i < allowed_clock_voltage_table->count; i++) {
1480                 /* find first sclk bigger than request */
1481                 if (allowed_clock_voltage_table->entries[i].clk >= clock) {
1482                         voltage->VddGfx = tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
1483                                                                 allowed_clock_voltage_table->entries[i].vddgfx);
1484
1485                         voltage->Vddc = tonga_get_voltage_index(pptable_info->vddc_lookup_table,
1486                                                                 allowed_clock_voltage_table->entries[i].vddc);
1487
1488                         if (allowed_clock_voltage_table->entries[i].vddci) {
1489                                 voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
1490                                                                         allowed_clock_voltage_table->entries[i].vddci);
1491                         } else {
1492                                 voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
1493                                                                         allowed_clock_voltage_table->entries[i].vddc - data->vddc_vddci_delta);
1494                         }
1495
1496                         if (allowed_clock_voltage_table->entries[i].mvdd) {
1497                                 *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i].mvdd;
1498                         }
1499
1500                         voltage->Phases = 1;
1501                         return 0;
1502                 }
1503         }
1504
1505         /* sclk is bigger than max sclk in the dependence table */
1506         voltage->VddGfx = tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
1507                 allowed_clock_voltage_table->entries[i-1].vddgfx);
1508         voltage->Vddc = tonga_get_voltage_index(pptable_info->vddc_lookup_table,
1509                 allowed_clock_voltage_table->entries[i-1].vddc);
1510
1511         if (allowed_clock_voltage_table->entries[i-1].vddci) {
1512                 voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
1513                         allowed_clock_voltage_table->entries[i-1].vddci);
1514         }
1515         if (allowed_clock_voltage_table->entries[i-1].mvdd) {
1516                 *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i-1].mvdd;
1517         }
1518
1519         return 0;
1520 }
1521
1522 /**
1523  * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1524  *
1525  * @param    hwmgr  the address of the powerplay hardware manager.
1526  * @return   always 0
1527  */
1528 int tonga_reset_to_default(struct pp_hwmgr *hwmgr)
1529 {
1530         return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults) == 0) ? 0 : 1;
1531 }
1532
1533 int tonga_populate_memory_timing_parameters(
1534                 struct pp_hwmgr *hwmgr,
1535                 uint32_t engine_clock,
1536                 uint32_t memory_clock,
1537                 struct SMU72_Discrete_MCArbDramTimingTableEntry *arb_regs
1538                 )
1539 {
1540         uint32_t dramTiming;
1541         uint32_t dramTiming2;
1542         uint32_t burstTime;
1543         int result;
1544
1545         result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
1546                                 engine_clock, memory_clock);
1547
1548         PP_ASSERT_WITH_CODE(result == 0,
1549                 "Error calling VBIOS to set DRAM_TIMING.", return result);
1550
1551         dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
1552         dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
1553         burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
1554
1555         arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
1556         arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
1557         arb_regs->McArbBurstTime = (uint8_t)burstTime;
1558
1559         return 0;
1560 }
1561
1562 /**
1563  * Setup parameters for the MC ARB.
1564  *
1565  * @param    hwmgr  the address of the powerplay hardware manager.
1566  * @return   always 0
1567  * This function is to be called from the SetPowerState table.
1568  */
1569 int tonga_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
1570 {
1571         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1572         int result = 0;
1573         SMU72_Discrete_MCArbDramTimingTable  arb_regs;
1574         uint32_t i, j;
1575
1576         memset(&arb_regs, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable));
1577
1578         for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
1579                 for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
1580                         result = tonga_populate_memory_timing_parameters
1581                                 (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
1582                                  data->dpm_table.mclk_table.dpm_levels[j].value,
1583                                  &arb_regs.entries[i][j]);
1584
1585                         if (0 != result) {
1586                                 break;
1587                         }
1588                 }
1589         }
1590
1591         if (0 == result) {
1592                 result = tonga_copy_bytes_to_smc(
1593                                 hwmgr->smumgr,
1594                                 data->arb_table_start,
1595                                 (uint8_t *)&arb_regs,
1596                                 sizeof(SMU72_Discrete_MCArbDramTimingTable),
1597                                 data->sram_end
1598                                 );
1599         }
1600
1601         return result;
1602 }
1603
1604 static int tonga_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU72_Discrete_DpmTable *table)
1605 {
1606         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1607         struct tonga_dpm_table *dpm_table = &data->dpm_table;
1608         uint32_t i;
1609
1610         /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
1611         for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
1612                 table->LinkLevel[i].PcieGenSpeed  =
1613                         (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
1614                 table->LinkLevel[i].PcieLaneCount =
1615                         (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
1616                 table->LinkLevel[i].EnabledForActivity =
1617                         1;
1618                 table->LinkLevel[i].SPC =
1619                         (uint8_t)(data->pcie_spc_cap & 0xff);
1620                 table->LinkLevel[i].DownThreshold =
1621                         PP_HOST_TO_SMC_UL(5);
1622                 table->LinkLevel[i].UpThreshold =
1623                         PP_HOST_TO_SMC_UL(30);
1624         }
1625
1626         data->smc_state_table.LinkLevelCount =
1627                 (uint8_t)dpm_table->pcie_speed_table.count;
1628         data->dpm_level_enable_mask.pcie_dpm_enable_mask =
1629                 tonga_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
1630
1631         return 0;
1632 }
1633
1634 static int tonga_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
1635                                         SMU72_Discrete_DpmTable *table)
1636 {
1637         int result = 0;
1638
1639         uint8_t count;
1640         pp_atomctrl_clock_dividers_vi dividers;
1641         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1642         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1643         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
1644
1645         table->UvdLevelCount = (uint8_t) (mm_table->count);
1646         table->UvdBootLevel = 0;
1647
1648         for (count = 0; count < table->UvdLevelCount; count++) {
1649                 table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
1650                 table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
1651                 table->UvdLevel[count].MinVoltage.Vddc =
1652                         tonga_get_voltage_index(pptable_info->vddc_lookup_table,
1653                                                 mm_table->entries[count].vddc);
1654                 table->UvdLevel[count].MinVoltage.VddGfx =
1655                         (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
1656                         tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
1657                                                 mm_table->entries[count].vddgfx) : 0;
1658                 table->UvdLevel[count].MinVoltage.Vddci =
1659                         tonga_get_voltage_id(&data->vddci_voltage_table,
1660                                              mm_table->entries[count].vddc - data->vddc_vddci_delta);
1661                 table->UvdLevel[count].MinVoltage.Phases = 1;
1662
1663                 /* retrieve divider value for VBIOS */
1664                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1665                                                           table->UvdLevel[count].VclkFrequency, &dividers);
1666                 PP_ASSERT_WITH_CODE((0 == result),
1667                                     "can not find divide id for Vclk clock", return result);
1668
1669                 table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
1670
1671                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1672                                                           table->UvdLevel[count].DclkFrequency, &dividers);
1673                 PP_ASSERT_WITH_CODE((0 == result),
1674                                     "can not find divide id for Dclk clock", return result);
1675
1676                 table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
1677
1678                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
1679                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
1680                 //CONVERT_FROM_HOST_TO_SMC_UL((uint32_t)table->UvdLevel[count].MinVoltage);
1681     }
1682
1683     return result;
1684
1685 }
1686
1687 static int tonga_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
1688                 SMU72_Discrete_DpmTable *table)
1689 {
1690         int result = 0;
1691
1692         uint8_t count;
1693         pp_atomctrl_clock_dividers_vi dividers;
1694         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1695         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1696         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
1697
1698         table->VceLevelCount = (uint8_t) (mm_table->count);
1699         table->VceBootLevel = 0;
1700
1701         for (count = 0; count < table->VceLevelCount; count++) {
1702                 table->VceLevel[count].Frequency =
1703                         mm_table->entries[count].eclk;
1704                 table->VceLevel[count].MinVoltage.Vddc =
1705                         tonga_get_voltage_index(pptable_info->vddc_lookup_table,
1706                                 mm_table->entries[count].vddc);
1707                 table->VceLevel[count].MinVoltage.VddGfx =
1708                         (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
1709                         tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
1710                                 mm_table->entries[count].vddgfx) : 0;
1711                 table->VceLevel[count].MinVoltage.Vddci =
1712                         tonga_get_voltage_id(&data->vddci_voltage_table,
1713                                 mm_table->entries[count].vddc - data->vddc_vddci_delta);
1714                 table->VceLevel[count].MinVoltage.Phases = 1;
1715
1716                 /* retrieve divider value for VBIOS */
1717                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1718                                         table->VceLevel[count].Frequency, &dividers);
1719                 PP_ASSERT_WITH_CODE((0 == result),
1720                                 "can not find divide id for VCE engine clock", return result);
1721
1722                 table->VceLevel[count].Divider    = (uint8_t)dividers.pll_post_divider;
1723
1724                 CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
1725         }
1726
1727         return result;
1728 }
1729
1730 static int tonga_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
1731                 SMU72_Discrete_DpmTable *table)
1732 {
1733         int result = 0;
1734         uint8_t count;
1735         pp_atomctrl_clock_dividers_vi dividers;
1736         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1737         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1738         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
1739
1740         table->AcpLevelCount = (uint8_t) (mm_table->count);
1741         table->AcpBootLevel = 0;
1742
1743         for (count = 0; count < table->AcpLevelCount; count++) {
1744                 table->AcpLevel[count].Frequency =
1745                         pptable_info->mm_dep_table->entries[count].aclk;
1746                 table->AcpLevel[count].MinVoltage.Vddc =
1747                         tonga_get_voltage_index(pptable_info->vddc_lookup_table,
1748                         mm_table->entries[count].vddc);
1749                 table->AcpLevel[count].MinVoltage.VddGfx =
1750                         (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
1751                         tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
1752                                 mm_table->entries[count].vddgfx) : 0;
1753                 table->AcpLevel[count].MinVoltage.Vddci =
1754                         tonga_get_voltage_id(&data->vddci_voltage_table,
1755                                 mm_table->entries[count].vddc - data->vddc_vddci_delta);
1756                 table->AcpLevel[count].MinVoltage.Phases = 1;
1757
1758                 /* retrieve divider value for VBIOS */
1759                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1760                         table->AcpLevel[count].Frequency, &dividers);
1761                 PP_ASSERT_WITH_CODE((0 == result),
1762                         "can not find divide id for engine clock", return result);
1763
1764                 table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
1765
1766                 CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
1767         }
1768
1769         return result;
1770 }
1771
1772 static int tonga_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
1773         SMU72_Discrete_DpmTable *table)
1774 {
1775         int result = 0;
1776         uint8_t count;
1777         pp_atomctrl_clock_dividers_vi dividers;
1778         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1779         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1780         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
1781
1782         table->SamuBootLevel = 0;
1783         table->SamuLevelCount = (uint8_t) (mm_table->count);
1784
1785         for (count = 0; count < table->SamuLevelCount; count++) {
1786                 /* not sure whether we need evclk or not */
1787                 table->SamuLevel[count].Frequency =
1788                         pptable_info->mm_dep_table->entries[count].samclock;
1789                 table->SamuLevel[count].MinVoltage.Vddc =
1790                         tonga_get_voltage_index(pptable_info->vddc_lookup_table,
1791                                 mm_table->entries[count].vddc);
1792                 table->SamuLevel[count].MinVoltage.VddGfx =
1793                         (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
1794                         tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
1795                                 mm_table->entries[count].vddgfx) : 0;
1796                 table->SamuLevel[count].MinVoltage.Vddci =
1797                         tonga_get_voltage_id(&data->vddci_voltage_table,
1798                                 mm_table->entries[count].vddc - data->vddc_vddci_delta);
1799                 table->SamuLevel[count].MinVoltage.Phases = 1;
1800
1801                 /* retrieve divider value for VBIOS */
1802                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
1803                                         table->SamuLevel[count].Frequency, &dividers);
1804                 PP_ASSERT_WITH_CODE((0 == result),
1805                         "can not find divide id for samu clock", return result);
1806
1807                 table->SamuLevel[count].Divider     = (uint8_t)dividers.pll_post_divider;
1808
1809                 CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
1810         }
1811
1812         return result;
1813 }
1814
1815 /**
1816  * Populates the SMC MCLK structure using the provided memory clock
1817  *
1818  * @param    hwmgr      the address of the hardware manager
1819  * @param    memory_clock the memory clock to use to populate the structure
1820  * @param    sclk        the SMC SCLK structure to be populated
1821  */
1822 static int tonga_calculate_mclk_params(
1823                 struct pp_hwmgr *hwmgr,
1824                 uint32_t memory_clock,
1825                 SMU72_Discrete_MemoryLevel *mclk,
1826                 bool strobe_mode,
1827                 bool dllStateOn
1828                 )
1829 {
1830         const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1831         uint32_t  dll_cntl = data->clock_registers.vDLL_CNTL;
1832         uint32_t  mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
1833         uint32_t  mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
1834         uint32_t  mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
1835         uint32_t  mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
1836         uint32_t  mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
1837         uint32_t  mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
1838         uint32_t  mpll_ss1 = data->clock_registers.vMPLL_SS1;
1839         uint32_t  mpll_ss2 = data->clock_registers.vMPLL_SS2;
1840
1841         pp_atomctrl_memory_clock_param mpll_param;
1842         int result;
1843
1844         result = atomctrl_get_memory_pll_dividers_si(hwmgr,
1845                                 memory_clock, &mpll_param, strobe_mode);
1846         PP_ASSERT_WITH_CODE(0 == result,
1847                 "Error retrieving Memory Clock Parameters from VBIOS.", return result);
1848
1849         /* MPLL_FUNC_CNTL setup*/
1850         mpll_func_cntl    = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl);
1851
1852         /* MPLL_FUNC_CNTL_1 setup*/
1853         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
1854                                                         MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf);
1855         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
1856                                                         MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac);
1857         mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
1858                                                         MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode);
1859
1860         /* MPLL_AD_FUNC_CNTL setup*/
1861         mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
1862                                                         MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
1863
1864         if (data->is_memory_GDDR5) {
1865                 /* MPLL_DQ_FUNC_CNTL setup*/
1866                 mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
1867                                                                 MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel);
1868                 mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
1869                                                                 MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
1870         }
1871
1872         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1873                         PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
1874                 /*
1875                  ************************************
1876                  Fref = Reference Frequency
1877                  NF = Feedback divider ratio
1878                  NR = Reference divider ratio
1879                  Fnom = Nominal VCO output frequency = Fref * NF / NR
1880                  Fs = Spreading Rate
1881                  D = Percentage down-spread / 2
1882                  Fint = Reference input frequency to PFD = Fref / NR
1883                  NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
1884                  CLKS = NS - 1 = ISS_STEP_NUM[11:0]
1885                  NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
1886                  CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
1887                  *************************************
1888                  */
1889                 pp_atomctrl_internal_ss_info ss_info;
1890                 uint32_t freq_nom;
1891                 uint32_t tmp;
1892                 uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
1893
1894                 /* for GDDR5 for all modes and DDR3 */
1895                 if (1 == mpll_param.qdr)
1896                         freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
1897                 else
1898                         freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
1899
1900                 /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
1901                 tmp = (freq_nom / reference_clock);
1902                 tmp = tmp * tmp;
1903
1904                 if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
1905                         /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
1906                         /* ss.Info.speed_spectrum_rate -- in unit of khz */
1907                         /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
1908                         /*     = reference_clock * 5 / speed_spectrum_rate */
1909                         uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
1910
1911                         /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
1912                         /*     = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
1913                         uint32_t clkv =
1914                                 (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
1915                                                         ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
1916
1917                         mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
1918                         mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
1919                 }
1920         }
1921
1922         /* MCLK_PWRMGT_CNTL setup */
1923         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1924                 MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
1925         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1926                 MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
1927         mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
1928                 MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
1929
1930
1931         /* Save the result data to outpupt memory level structure */
1932         mclk->MclkFrequency   = memory_clock;
1933         mclk->MpllFuncCntl    = mpll_func_cntl;
1934         mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
1935         mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
1936         mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
1937         mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
1938         mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
1939         mclk->DllCntl         = dll_cntl;
1940         mclk->MpllSs1         = mpll_ss1;
1941         mclk->MpllSs2         = mpll_ss2;
1942
1943         return 0;
1944 }
1945
1946 static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock,
1947                 bool strobe_mode)
1948 {
1949         uint8_t mc_para_index;
1950
1951         if (strobe_mode) {
1952                 if (memory_clock < 12500) {
1953                         mc_para_index = 0x00;
1954                 } else if (memory_clock > 47500) {
1955                         mc_para_index = 0x0f;
1956                 } else {
1957                         mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
1958                 }
1959         } else {
1960                 if (memory_clock < 65000) {
1961                         mc_para_index = 0x00;
1962                 } else if (memory_clock > 135000) {
1963                         mc_para_index = 0x0f;
1964                 } else {
1965                         mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
1966                 }
1967         }
1968
1969         return mc_para_index;
1970 }
1971
1972 static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
1973 {
1974         uint8_t mc_para_index;
1975
1976         if (memory_clock < 10000) {
1977                 mc_para_index = 0;
1978         } else if (memory_clock >= 80000) {
1979                 mc_para_index = 0x0f;
1980         } else {
1981                 mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
1982         }
1983
1984         return mc_para_index;
1985 }
1986
1987 static int tonga_populate_single_memory_level(
1988                 struct pp_hwmgr *hwmgr,
1989                 uint32_t memory_clock,
1990                 SMU72_Discrete_MemoryLevel *memory_level
1991                 )
1992 {
1993         uint32_t minMvdd = 0;
1994         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
1995         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
1996         int result = 0;
1997         bool dllStateOn;
1998         struct cgs_display_info info = {0};
1999
2000
2001         if (NULL != pptable_info->vdd_dep_on_mclk) {
2002                 result = tonga_get_dependecy_volt_by_clk(hwmgr,
2003                         pptable_info->vdd_dep_on_mclk, memory_clock, &memory_level->MinVoltage, &minMvdd);
2004                 PP_ASSERT_WITH_CODE((0 == result),
2005                         "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result);
2006         }
2007
2008         if (data->mvdd_control == TONGA_VOLTAGE_CONTROL_NONE) {
2009                 memory_level->MinMvdd = data->vbios_boot_state.mvdd_bootup_value;
2010         } else {
2011                 memory_level->MinMvdd = minMvdd;
2012         }
2013         memory_level->EnabledForThrottle = 1;
2014         memory_level->EnabledForActivity = 0;
2015         memory_level->UpHyst = 0;
2016         memory_level->DownHyst = 100;
2017         memory_level->VoltageDownHyst = 0;
2018
2019         /* Indicates maximum activity level for this performance level.*/
2020         memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
2021         memory_level->StutterEnable = 0;
2022         memory_level->StrobeEnable = 0;
2023         memory_level->EdcReadEnable = 0;
2024         memory_level->EdcWriteEnable = 0;
2025         memory_level->RttEnable = 0;
2026
2027         /* default set to low watermark. Highest level will be set to high later.*/
2028         memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2029
2030         cgs_get_active_displays_info(hwmgr->device, &info);
2031         data->display_timing.num_existing_displays = info.display_count;
2032
2033         if ((data->mclk_stutter_mode_threshold != 0) &&
2034                         (memory_clock <= data->mclk_stutter_mode_threshold) &&
2035                         (data->is_uvd_enabled == 0)
2036 #if defined(LINUX)
2037                         && (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE) & 0x1)
2038                         && (data->display_timing.num_existing_displays <= 2)
2039                         && (data->display_timing.num_existing_displays != 0)
2040 #endif
2041         )
2042                 memory_level->StutterEnable = 1;
2043
2044         /* decide strobe mode*/
2045         memory_level->StrobeEnable = (data->mclk_strobe_mode_threshold != 0) &&
2046                 (memory_clock <= data->mclk_strobe_mode_threshold);
2047
2048         /* decide EDC mode and memory clock ratio*/
2049         if (data->is_memory_GDDR5) {
2050                 memory_level->StrobeRatio = tonga_get_mclk_frequency_ratio(memory_clock,
2051                                         memory_level->StrobeEnable);
2052
2053                 if ((data->mclk_edc_enable_threshold != 0) &&
2054                                 (memory_clock > data->mclk_edc_enable_threshold)) {
2055                         memory_level->EdcReadEnable = 1;
2056                 }
2057
2058                 if ((data->mclk_edc_wr_enable_threshold != 0) &&
2059                                 (memory_clock > data->mclk_edc_wr_enable_threshold)) {
2060                         memory_level->EdcWriteEnable = 1;
2061                 }
2062
2063                 if (memory_level->StrobeEnable) {
2064                         if (tonga_get_mclk_frequency_ratio(memory_clock, 1) >=
2065                                         ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf)) {
2066                                 dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
2067                         } else {
2068                                 dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
2069                         }
2070
2071                 } else {
2072                         dllStateOn = data->dll_defaule_on;
2073                 }
2074         } else {
2075                 memory_level->StrobeRatio =
2076                         tonga_get_ddr3_mclk_frequency_ratio(memory_clock);
2077                 dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
2078         }
2079
2080         result = tonga_calculate_mclk_params(hwmgr,
2081                 memory_clock, memory_level, memory_level->StrobeEnable, dllStateOn);
2082
2083         if (0 == result) {
2084                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinMvdd);
2085                 /* MCLK frequency in units of 10KHz*/
2086                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
2087                 /* Indicates maximum activity level for this performance level.*/
2088                 CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
2089                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
2090                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
2091                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
2092                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
2093                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
2094                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
2095                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
2096                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
2097                 CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
2098         }
2099
2100         return result;
2101 }
2102
2103 /**
2104  * Populates the SMC MVDD structure using the provided memory clock.
2105  *
2106  * @param    hwmgr      the address of the hardware manager
2107  * @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
2108  * @param    voltage     the SMC VOLTAGE structure to be populated
2109  */
2110 int tonga_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk, SMIO_Pattern *smio_pattern)
2111 {
2112         const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2113         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
2114         uint32_t i = 0;
2115
2116         if (TONGA_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
2117                 /* find mvdd value which clock is more than request */
2118                 for (i = 0; i < pptable_info->vdd_dep_on_mclk->count; i++) {
2119                         if (mclk <= pptable_info->vdd_dep_on_mclk->entries[i].clk) {
2120                                 /* Always round to higher voltage. */
2121                                 smio_pattern->Voltage = data->mvdd_voltage_table.entries[i].value;
2122                                 break;
2123                         }
2124                 }
2125
2126                 PP_ASSERT_WITH_CODE(i < pptable_info->vdd_dep_on_mclk->count,
2127                         "MVDD Voltage is outside the supported range.", return -1);
2128
2129         } else {
2130                 return -1;
2131         }
2132
2133         return 0;
2134 }
2135
2136
2137 static int tonga_populate_smv_acpi_level(struct pp_hwmgr *hwmgr,
2138         SMU72_Discrete_DpmTable *table)
2139 {
2140         int result = 0;
2141         const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2142         pp_atomctrl_clock_dividers_vi dividers;
2143         SMIO_Pattern voltage_level;
2144         uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
2145         uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
2146         uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
2147         uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
2148
2149         /* The ACPI state should not do DPM on DC (or ever).*/
2150         table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
2151
2152         table->ACPILevel.MinVoltage = data->smc_state_table.GraphicsLevel[0].MinVoltage;
2153
2154         /* assign zero for now*/
2155         table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
2156
2157         /* get the engine clock dividers for this clock value*/
2158         result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
2159                 table->ACPILevel.SclkFrequency,  &dividers);
2160
2161         PP_ASSERT_WITH_CODE(result == 0,
2162                 "Error retrieving Engine Clock dividers from VBIOS.", return result);
2163
2164         /* divider ID for required SCLK*/
2165         table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
2166         table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2167         table->ACPILevel.DeepSleepDivId = 0;
2168
2169         spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
2170                                                         CG_SPLL_FUNC_CNTL,   SPLL_PWRON,     0);
2171         spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
2172                                                         CG_SPLL_FUNC_CNTL,   SPLL_RESET,     1);
2173         spll_func_cntl_2    = PHM_SET_FIELD(spll_func_cntl_2,
2174                                                         CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL,   4);
2175
2176         table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
2177         table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
2178         table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
2179         table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
2180         table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
2181         table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
2182         table->ACPILevel.CcPwrDynRm = 0;
2183         table->ACPILevel.CcPwrDynRm1 = 0;
2184
2185
2186         /* For various features to be enabled/disabled while this level is active.*/
2187         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
2188         /* SCLK frequency in units of 10KHz*/
2189         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
2190         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
2191         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
2192         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
2193         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
2194         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
2195         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
2196         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
2197         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
2198
2199         /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
2200         table->MemoryACPILevel.MinVoltage = data->smc_state_table.MemoryLevel[0].MinVoltage;
2201
2202         /*  CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
2203
2204         if (0 == tonga_populate_mvdd_value(hwmgr, 0, &voltage_level))
2205                 table->MemoryACPILevel.MinMvdd =
2206                         PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
2207         else
2208                 table->MemoryACPILevel.MinMvdd = 0;
2209
2210         /* Force reset on DLL*/
2211         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
2212                 MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
2213         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
2214                 MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
2215
2216         /* Disable DLL in ACPIState*/
2217         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
2218                 MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
2219         mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
2220                 MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
2221
2222         /* Enable DLL bypass signal*/
2223         dll_cntl            = PHM_SET_FIELD(dll_cntl,
2224                 DLL_CNTL, MRDCK0_BYPASS, 0);
2225         dll_cntl            = PHM_SET_FIELD(dll_cntl,
2226                 DLL_CNTL, MRDCK1_BYPASS, 0);
2227
2228         table->MemoryACPILevel.DllCntl            =
2229                 PP_HOST_TO_SMC_UL(dll_cntl);
2230         table->MemoryACPILevel.MclkPwrmgtCntl     =
2231                 PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
2232         table->MemoryACPILevel.MpllAdFuncCntl     =
2233                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
2234         table->MemoryACPILevel.MpllDqFuncCntl     =
2235                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
2236         table->MemoryACPILevel.MpllFuncCntl       =
2237                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
2238         table->MemoryACPILevel.MpllFuncCntl_1     =
2239                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
2240         table->MemoryACPILevel.MpllFuncCntl_2     =
2241                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
2242         table->MemoryACPILevel.MpllSs1            =
2243                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
2244         table->MemoryACPILevel.MpllSs2            =
2245                 PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
2246
2247         table->MemoryACPILevel.EnabledForThrottle = 0;
2248         table->MemoryACPILevel.EnabledForActivity = 0;
2249         table->MemoryACPILevel.UpHyst = 0;
2250         table->MemoryACPILevel.DownHyst = 100;
2251         table->MemoryACPILevel.VoltageDownHyst = 0;
2252         /* Indicates maximum activity level for this performance level.*/
2253         table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
2254
2255         table->MemoryACPILevel.StutterEnable = 0;
2256         table->MemoryACPILevel.StrobeEnable = 0;
2257         table->MemoryACPILevel.EdcReadEnable = 0;
2258         table->MemoryACPILevel.EdcWriteEnable = 0;
2259         table->MemoryACPILevel.RttEnable = 0;
2260
2261         return result;
2262 }
2263
2264 static int tonga_find_boot_level(struct tonga_single_dpm_table *table, uint32_t value, uint32_t *boot_level)
2265 {
2266         int result = 0;
2267         uint32_t i;
2268
2269         for (i = 0; i < table->count; i++) {
2270                 if (value == table->dpm_levels[i].value) {
2271                         *boot_level = i;
2272                         result = 0;
2273                 }
2274         }
2275         return result;
2276 }
2277
2278 static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
2279                         SMU72_Discrete_DpmTable *table)
2280 {
2281         int result = 0;
2282         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2283
2284         table->GraphicsBootLevel  = 0;        /* 0 == DPM[0] (low), etc. */
2285         table->MemoryBootLevel    = 0;        /* 0 == DPM[0] (low), etc. */
2286
2287         /* find boot level from dpm table*/
2288         result = tonga_find_boot_level(&(data->dpm_table.sclk_table),
2289         data->vbios_boot_state.sclk_bootup_value,
2290         (uint32_t *)&(data->smc_state_table.GraphicsBootLevel));
2291
2292         if (0 != result) {
2293                 data->smc_state_table.GraphicsBootLevel = 0;
2294                 printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
2295                         in dependency table. Using Graphics DPM level 0!");
2296                 result = 0;
2297         }
2298
2299         result = tonga_find_boot_level(&(data->dpm_table.mclk_table),
2300                 data->vbios_boot_state.mclk_bootup_value,
2301                 (uint32_t *)&(data->smc_state_table.MemoryBootLevel));
2302
2303         if (0 != result) {
2304                 data->smc_state_table.MemoryBootLevel = 0;
2305                 printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
2306                         in dependency table. Using Memory DPM level 0!");
2307                 result = 0;
2308         }
2309
2310         table->BootVoltage.Vddc =
2311                 tonga_get_voltage_id(&(data->vddc_voltage_table),
2312                         data->vbios_boot_state.vddc_bootup_value);
2313         table->BootVoltage.VddGfx =
2314                 tonga_get_voltage_id(&(data->vddgfx_voltage_table),
2315                         data->vbios_boot_state.vddgfx_bootup_value);
2316         table->BootVoltage.Vddci =
2317                 tonga_get_voltage_id(&(data->vddci_voltage_table),
2318                         data->vbios_boot_state.vddci_bootup_value);
2319         table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
2320
2321         CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
2322
2323         return result;
2324 }
2325
2326
2327 /**
2328  * Calculates the SCLK dividers using the provided engine clock
2329  *
2330  * @param    hwmgr      the address of the hardware manager
2331  * @param    engine_clock the engine clock to use to populate the structure
2332  * @param    sclk        the SMC SCLK structure to be populated
2333  */
2334 int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr,
2335                 uint32_t engine_clock, SMU72_Discrete_GraphicsLevel *sclk)
2336 {
2337         const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2338         pp_atomctrl_clock_dividers_vi dividers;
2339         uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
2340         uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
2341         uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
2342         uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
2343         uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
2344         uint32_t    reference_clock;
2345         uint32_t reference_divider;
2346         uint32_t fbdiv;
2347         int result;
2348
2349         /* get the engine clock dividers for this clock value*/
2350         result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock,  &dividers);
2351
2352         PP_ASSERT_WITH_CODE(result == 0,
2353                 "Error retrieving Engine Clock dividers from VBIOS.", return result);
2354
2355         /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
2356         reference_clock = atomctrl_get_reference_clock(hwmgr);
2357
2358         reference_divider = 1 + dividers.uc_pll_ref_div;
2359
2360         /* low 14 bits is fraction and high 12 bits is divider*/
2361         fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
2362
2363         /* SPLL_FUNC_CNTL setup*/
2364         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
2365                 CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
2366         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
2367                 CG_SPLL_FUNC_CNTL, SPLL_PDIV_A,  dividers.uc_pll_post_div);
2368
2369         /* SPLL_FUNC_CNTL_3 setup*/
2370         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
2371                 CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
2372
2373         /* set to use fractional accumulation*/
2374         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
2375                 CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
2376
2377         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2378                         PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
2379                 pp_atomctrl_internal_ss_info ss_info;
2380
2381                 uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
2382                 if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
2383                         /*
2384                         * ss_info.speed_spectrum_percentage -- in unit of 0.01%
2385                         * ss_info.speed_spectrum_rate -- in unit of khz
2386                         */
2387                         /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
2388                         uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
2389
2390                         /* clkv = 2 * D * fbdiv / NS */
2391                         uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
2392
2393                         cg_spll_spread_spectrum =
2394                                 PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
2395                         cg_spll_spread_spectrum =
2396                                 PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
2397                         cg_spll_spread_spectrum_2 =
2398                                 PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
2399                 }
2400         }
2401
2402         sclk->SclkFrequency        = engine_clock;
2403         sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
2404         sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
2405         sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
2406         sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
2407         sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
2408
2409         return 0;
2410 }
2411
2412 /**
2413  * Populates single SMC SCLK structure using the provided engine clock
2414  *
2415  * @param    hwmgr      the address of the hardware manager
2416  * @param    engine_clock the engine clock to use to populate the structure
2417  * @param    sclk        the SMC SCLK structure to be populated
2418  */
2419 static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t engine_clock, uint16_t sclk_activity_level_threshold, SMU72_Discrete_GraphicsLevel *graphic_level)
2420 {
2421         int result;
2422         uint32_t threshold;
2423         uint32_t mvdd;
2424         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2425         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
2426
2427         result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
2428
2429
2430         /* populate graphics levels*/
2431         result = tonga_get_dependecy_volt_by_clk(hwmgr,
2432                 pptable_info->vdd_dep_on_sclk, engine_clock,
2433                 &graphic_level->MinVoltage, &mvdd);
2434         PP_ASSERT_WITH_CODE((0 == result),
2435                 "can not find VDDC voltage value for VDDC       \
2436                 engine clock dependency table", return result);
2437
2438         /* SCLK frequency in units of 10KHz*/
2439         graphic_level->SclkFrequency = engine_clock;
2440
2441         /* Indicates maximum activity level for this performance level. 50% for now*/
2442         graphic_level->ActivityLevel = sclk_activity_level_threshold;
2443
2444         graphic_level->CcPwrDynRm = 0;
2445         graphic_level->CcPwrDynRm1 = 0;
2446         /* this level can be used if activity is high enough.*/
2447         graphic_level->EnabledForActivity = 0;
2448         /* this level can be used for throttling.*/
2449         graphic_level->EnabledForThrottle = 1;
2450         graphic_level->UpHyst = 0;
2451         graphic_level->DownHyst = 0;
2452         graphic_level->VoltageDownHyst = 0;
2453         graphic_level->PowerThrottle = 0;
2454
2455         threshold = engine_clock * data->fast_watemark_threshold / 100;
2456 /*
2457         *get the DAL clock. do it in funture.
2458         PECI_GetMinClockSettings(hwmgr->peci, &minClocks);
2459         data->display_timing.min_clock_insr = minClocks.engineClockInSR;
2460
2461         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
2462         {
2463                 graphic_level->DeepSleepDivId = PhwTonga_GetSleepDividerIdFromClock(hwmgr, engine_clock, minClocks.engineClockInSR);
2464         }
2465 */
2466
2467         /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
2468         graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2469
2470         if (0 == result) {
2471                 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
2472                 /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
2473                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
2474                 CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
2475                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
2476                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
2477                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
2478                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
2479                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
2480                 CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
2481         }
2482
2483         return result;
2484 }
2485
2486 /**
2487  * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2488  *
2489  * @param    hwmgr      the address of the hardware manager
2490  */
2491 static int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
2492 {
2493         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2494         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
2495         struct tonga_dpm_table *dpm_table = &data->dpm_table;
2496         phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
2497         uint8_t pcie_entry_count = (uint8_t) data->dpm_table.pcie_speed_table.count;
2498         int result = 0;
2499         uint32_t level_array_adress = data->dpm_table_start +
2500                 offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
2501         uint32_t level_array_size = sizeof(SMU72_Discrete_GraphicsLevel) *
2502                 SMU72_MAX_LEVELS_GRAPHICS;   /* 64 -> long; 32 -> int*/
2503         SMU72_Discrete_GraphicsLevel *levels = data->smc_state_table.GraphicsLevel;
2504         uint32_t i, maxEntry;
2505         uint8_t highest_pcie_level_enabled = 0, lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0, count = 0;
2506         PECI_RegistryValue reg_value;
2507         memset(levels, 0x00, level_array_size);
2508
2509         for (i = 0; i < dpm_table->sclk_table.count; i++) {
2510                 result = tonga_populate_single_graphic_level(hwmgr,
2511                                         dpm_table->sclk_table.dpm_levels[i].value,
2512                                         (uint16_t)data->activity_target[i],
2513                                         &(data->smc_state_table.GraphicsLevel[i]));
2514
2515                 if (0 != result)
2516                         return result;
2517
2518                 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2519                 if (i > 1)
2520                         data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
2521
2522                 if (0 == i) {
2523                         reg_value = 0;
2524                         if (reg_value != 0)
2525                                 data->smc_state_table.GraphicsLevel[0].UpHyst = (uint8_t)reg_value;
2526                 }
2527
2528                 if (1 == i) {
2529                         reg_value = 0;
2530                         if (reg_value != 0)
2531                                 data->smc_state_table.GraphicsLevel[1].UpHyst = (uint8_t)reg_value;
2532                 }
2533         }
2534
2535         /* Only enable level 0 for now. */
2536         data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
2537
2538         /* set highest level watermark to high */
2539         if (dpm_table->sclk_table.count > 1)
2540                 data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
2541                         PPSMC_DISPLAY_WATERMARK_HIGH;
2542
2543         data->smc_state_table.GraphicsDpmLevelCount =
2544                 (uint8_t)dpm_table->sclk_table.count;
2545         data->dpm_level_enable_mask.sclk_dpm_enable_mask =
2546                 tonga_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
2547
2548         if (pcie_table != NULL) {
2549                 PP_ASSERT_WITH_CODE((pcie_entry_count >= 1),
2550                         "There must be 1 or more PCIE levels defined in PPTable.", return -1);
2551                 maxEntry = pcie_entry_count - 1; /* for indexing, we need to decrement by 1.*/
2552                 for (i = 0; i < dpm_table->sclk_table.count; i++) {
2553                         data->smc_state_table.GraphicsLevel[i].pcieDpmLevel =
2554                                 (uint8_t) ((i < maxEntry) ? i : maxEntry);
2555                 }
2556         } else {
2557                 if (0 == data->dpm_level_enable_mask.pcie_dpm_enable_mask)
2558                         printk(KERN_ERR "[ powerplay ] Pcie Dpm Enablemask is 0!");
2559
2560                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
2561                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2562                                         (1<<(highest_pcie_level_enabled+1))) != 0)) {
2563                         highest_pcie_level_enabled++;
2564                 }
2565
2566                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
2567                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2568                                         (1<<lowest_pcie_level_enabled)) == 0)) {
2569                         lowest_pcie_level_enabled++;
2570                 }
2571
2572                 while ((count < highest_pcie_level_enabled) &&
2573                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2574                                         (1<<(lowest_pcie_level_enabled+1+count))) == 0)) {
2575                         count++;
2576                 }
2577                 mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
2578                         (lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
2579
2580
2581                 /* set pcieDpmLevel to highest_pcie_level_enabled*/
2582                 for (i = 2; i < dpm_table->sclk_table.count; i++) {
2583                         data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
2584                 }
2585
2586                 /* set pcieDpmLevel to lowest_pcie_level_enabled*/
2587                 data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
2588
2589                 /* set pcieDpmLevel to mid_pcie_level_enabled*/
2590                 data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
2591         }
2592         /* level count will send to smc once at init smc table and never change*/
2593         result = tonga_copy_bytes_to_smc(hwmgr->smumgr, level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end);
2594
2595         if (0 != result)
2596                 return result;
2597
2598         return 0;
2599 }
2600
2601 /**
2602  * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2603  *
2604  * @param    hwmgr      the address of the hardware manager
2605  */
2606
2607 static int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
2608 {
2609         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2610         struct tonga_dpm_table *dpm_table = &data->dpm_table;
2611         int result;
2612         /* populate MCLK dpm table to SMU7 */
2613         uint32_t level_array_adress = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
2614         uint32_t level_array_size = sizeof(SMU72_Discrete_MemoryLevel) * SMU72_MAX_LEVELS_MEMORY;
2615         SMU72_Discrete_MemoryLevel *levels = data->smc_state_table.MemoryLevel;
2616         uint32_t i;
2617
2618         memset(levels, 0x00, level_array_size);
2619
2620         for (i = 0; i < dpm_table->mclk_table.count; i++) {
2621                 PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
2622                         "can not populate memory level as memory clock is zero", return -1);
2623                 result = tonga_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
2624                         &(data->smc_state_table.MemoryLevel[i]));
2625                 if (0 != result) {
2626                         return result;
2627                 }
2628         }
2629
2630         /* Only enable level 0 for now.*/
2631         data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
2632
2633         /*
2634         * in order to prevent MC activity from stutter mode to push DPM up.
2635         * the UVD change complements this by putting the MCLK in a higher state
2636         * by default such that we are not effected by up threshold or and MCLK DPM latency.
2637         */
2638         data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
2639         CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.MemoryLevel[0].ActivityLevel);
2640
2641         data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
2642         data->dpm_level_enable_mask.mclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
2643         /* set highest level watermark to high*/
2644         data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
2645
2646         /* level count will send to smc once at init smc table and never change*/
2647         result = tonga_copy_bytes_to_smc(hwmgr->smumgr,
2648                 level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end);
2649
2650         if (0 != result) {
2651                 return result;
2652         }
2653
2654         return 0;
2655 }
2656
2657 struct TONGA_DLL_SPEED_SETTING {
2658         uint16_t            Min;                          /* Minimum Data Rate*/
2659         uint16_t            Max;                          /* Maximum Data Rate*/
2660         uint32_t                        dll_speed;                     /* The desired DLL_SPEED setting*/
2661 };
2662
2663 static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
2664 {
2665         return 0;
2666 }
2667
2668 /* ---------------------------------------- ULV related functions ----------------------------------------------------*/
2669
2670
2671 static int tonga_reset_single_dpm_table(
2672         struct pp_hwmgr *hwmgr,
2673         struct tonga_single_dpm_table *dpm_table,
2674         uint32_t count)
2675 {
2676         uint32_t i;
2677         if (!(count <= MAX_REGULAR_DPM_NUMBER))
2678                 printk(KERN_ERR "[ powerplay ] Fatal error, can not set up single DPM \
2679                         table entries to exceed max number! \n");
2680
2681         dpm_table->count = count;
2682         for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++) {
2683                 dpm_table->dpm_levels[i].enabled = 0;
2684         }
2685
2686         return 0;
2687 }
2688
2689 static void tonga_setup_pcie_table_entry(
2690         struct tonga_single_dpm_table *dpm_table,
2691         uint32_t index, uint32_t pcie_gen,
2692         uint32_t pcie_lanes)
2693 {
2694         dpm_table->dpm_levels[index].value = pcie_gen;
2695         dpm_table->dpm_levels[index].param1 = pcie_lanes;
2696         dpm_table->dpm_levels[index].enabled = 1;
2697 }
2698
2699 static int tonga_setup_default_pcie_tables(struct pp_hwmgr *hwmgr)
2700 {
2701         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2702         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
2703         phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
2704         uint32_t i, maxEntry;
2705
2706         if (data->use_pcie_performance_levels && !data->use_pcie_power_saving_levels) {
2707                 data->pcie_gen_power_saving = data->pcie_gen_performance;
2708                 data->pcie_lane_power_saving = data->pcie_lane_performance;
2709         } else if (!data->use_pcie_performance_levels && data->use_pcie_power_saving_levels) {
2710                 data->pcie_gen_performance = data->pcie_gen_power_saving;
2711                 data->pcie_lane_performance = data->pcie_lane_power_saving;
2712         }
2713
2714         tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.pcie_speed_table, SMU72_MAX_LEVELS_LINK);
2715
2716         if (pcie_table != NULL) {
2717                 /*
2718                 * maxEntry is used to make sure we reserve one PCIE level for boot level (fix for A+A PSPP issue).
2719                 * If PCIE table from PPTable have ULV entry + 8 entries, then ignore the last entry.
2720                 */
2721                 maxEntry = (SMU72_MAX_LEVELS_LINK < pcie_table->count) ?
2722                                                 SMU72_MAX_LEVELS_LINK : pcie_table->count;
2723                 for (i = 1; i < maxEntry; i++) {
2724                         tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i-1,
2725                                 get_pcie_gen_support(data->pcie_gen_cap, pcie_table->entries[i].gen_speed),
2726                                 get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
2727                 }
2728                 data->dpm_table.pcie_speed_table.count = maxEntry - 1;
2729         } else {
2730                 /* Hardcode Pcie Table */
2731                 tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
2732                         get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
2733                         get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
2734                 tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
2735                         get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
2736                         get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
2737                 tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
2738                         get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
2739                         get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
2740                 tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
2741                         get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
2742                         get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
2743                 tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
2744                         get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
2745                         get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
2746                 tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
2747                         get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
2748                         get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
2749                 data->dpm_table.pcie_speed_table.count = 6;
2750         }
2751         /* Populate last level for boot PCIE level, but do not increment count. */
2752         tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
2753                 data->dpm_table.pcie_speed_table.count,
2754                 get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
2755                 get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
2756
2757         return 0;
2758
2759 }
2760
2761 /*
2762  * This function is to initalize all DPM state tables for SMU7 based on the dependency table.
2763  * Dynamic state patching function will then trim these state tables to the allowed range based
2764  * on the power policy or external client requests, such as UVD request, etc.
2765  */
2766 static int tonga_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
2767 {
2768         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2769         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
2770         uint32_t i;
2771
2772         phm_ppt_v1_clock_voltage_dependency_table *allowed_vdd_sclk_table =
2773                 pptable_info->vdd_dep_on_sclk;
2774         phm_ppt_v1_clock_voltage_dependency_table *allowed_vdd_mclk_table =
2775                 pptable_info->vdd_dep_on_mclk;
2776
2777         PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
2778                 "SCLK dependency table is missing. This table is mandatory", return -1);
2779         PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table->count >= 1,
2780                 "SCLK dependency table has to have is missing. This table is mandatory", return -1);
2781
2782         PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
2783                 "MCLK dependency table is missing. This table is mandatory", return -1);
2784         PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table->count >= 1,
2785                 "VMCLK dependency table has to have is missing. This table is mandatory", return -1);
2786
2787         /* clear the state table to reset everything to default */
2788         memset(&(data->dpm_table), 0x00, sizeof(data->dpm_table));
2789         tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.sclk_table, SMU72_MAX_LEVELS_GRAPHICS);
2790         tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.mclk_table, SMU72_MAX_LEVELS_MEMORY);
2791         /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.VddcTable, SMU72_MAX_LEVELS_VDDC); */
2792         /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_gfx_table, SMU72_MAX_LEVELS_VDDGFX);*/
2793         /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_ci_table, SMU72_MAX_LEVELS_VDDCI);*/
2794         /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.mvdd_table, SMU72_MAX_LEVELS_MVDD);*/
2795
2796         PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
2797                 "SCLK dependency table is missing. This table is mandatory", return -1);
2798         /* Initialize Sclk DPM table based on allow Sclk values*/
2799         data->dpm_table.sclk_table.count = 0;
2800
2801         for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
2802                 if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
2803                                 allowed_vdd_sclk_table->entries[i].clk) {
2804                         data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
2805                                 allowed_vdd_sclk_table->entries[i].clk;
2806                         data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; to do */
2807                         data->dpm_table.sclk_table.count++;
2808                 }
2809         }
2810
2811         PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
2812                 "MCLK dependency table is missing. This table is mandatory", return -1);
2813         /* Initialize Mclk DPM table based on allow Mclk values */
2814         data->dpm_table.mclk_table.count = 0;
2815         for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
2816                 if (i == 0 || data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count-1].value !=
2817                         allowed_vdd_mclk_table->entries[i].clk) {
2818                         data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
2819                                 allowed_vdd_mclk_table->entries[i].clk;
2820                         data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; */
2821                         data->dpm_table.mclk_table.count++;
2822                 }
2823         }
2824
2825         /* Initialize Vddc DPM table based on allow Vddc values.  And populate corresponding std values. */
2826         for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
2827                 data->dpm_table.vddc_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].vddc;
2828                 /* tonga_hwmgr->dpm_table.VddcTable.dpm_levels[i].param1 = stdVoltageTable->entries[i].Leakage; */
2829                 /* param1 is for corresponding std voltage */
2830                 data->dpm_table.vddc_table.dpm_levels[i].enabled = 1;
2831         }
2832         data->dpm_table.vddc_table.count = allowed_vdd_sclk_table->count;
2833
2834         if (NULL != allowed_vdd_mclk_table) {
2835                 /* Initialize Vddci DPM table based on allow Mclk values */
2836                 for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
2837                         data->dpm_table.vdd_ci_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].vddci;
2838                         data->dpm_table.vdd_ci_table.dpm_levels[i].enabled = 1;
2839                         data->dpm_table.mvdd_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].mvdd;
2840                         data->dpm_table.mvdd_table.dpm_levels[i].enabled = 1;
2841                 }
2842                 data->dpm_table.vdd_ci_table.count = allowed_vdd_mclk_table->count;
2843                 data->dpm_table.mvdd_table.count = allowed_vdd_mclk_table->count;
2844         }
2845
2846         /* setup PCIE gen speed levels*/
2847         tonga_setup_default_pcie_tables(hwmgr);
2848
2849         /* save a copy of the default DPM table*/
2850         memcpy(&(data->golden_dpm_table), &(data->dpm_table), sizeof(struct tonga_dpm_table));
2851
2852         return 0;
2853 }
2854
2855 int tonga_populate_smc_initial_state(struct pp_hwmgr *hwmgr,
2856                 const struct tonga_power_state *bootState)
2857 {
2858         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2859         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
2860         uint8_t count, level;
2861
2862         count = (uint8_t) (pptable_info->vdd_dep_on_sclk->count);
2863         for (level = 0; level < count; level++) {
2864                 if (pptable_info->vdd_dep_on_sclk->entries[level].clk >=
2865                         bootState->performance_levels[0].engine_clock) {
2866                         data->smc_state_table.GraphicsBootLevel = level;
2867                         break;
2868                 }
2869         }
2870
2871         count = (uint8_t) (pptable_info->vdd_dep_on_mclk->count);
2872         for (level = 0; level < count; level++) {
2873                 if (pptable_info->vdd_dep_on_mclk->entries[level].clk >=
2874                         bootState->performance_levels[0].memory_clock) {
2875                         data->smc_state_table.MemoryBootLevel = level;
2876                         break;
2877                 }
2878         }
2879
2880         return 0;
2881 }
2882
2883 /**
2884  * Initializes the SMC table and uploads it
2885  *
2886  * @param    hwmgr  the address of the powerplay hardware manager.
2887  * @param    pInput  the pointer to input data (PowerState)
2888  * @return   always 0
2889  */
2890 int tonga_init_smc_table(struct pp_hwmgr *hwmgr)
2891 {
2892         int result;
2893         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
2894         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
2895         SMU72_Discrete_DpmTable  *table = &(data->smc_state_table);
2896         const phw_tonga_ulv_parm *ulv = &(data->ulv);
2897         uint8_t i;
2898         PECI_RegistryValue reg_value;
2899         pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
2900
2901         result = tonga_setup_default_dpm_tables(hwmgr);
2902         PP_ASSERT_WITH_CODE(0 == result,
2903                 "Failed to setup default DPM tables!", return result;);
2904         memset(&(data->smc_state_table), 0x00, sizeof(data->smc_state_table));
2905         if (TONGA_VOLTAGE_CONTROL_NONE != data->voltage_control) {
2906                 tonga_populate_smc_voltage_tables(hwmgr, table);
2907         }
2908
2909         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2910                         PHM_PlatformCaps_AutomaticDCTransition)) {
2911                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
2912         }
2913
2914         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2915                         PHM_PlatformCaps_StepVddc)) {
2916                 table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
2917         }
2918
2919         if (data->is_memory_GDDR5) {
2920                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
2921         }
2922
2923         i = PHM_READ_FIELD(hwmgr->device, CC_MC_MAX_CHANNEL, NOOFCHAN);
2924
2925         if (i == 1 || i == 0) {
2926                 table->SystemFlags |= PPSMC_SYSTEMFLAG_12CHANNEL;
2927         }
2928
2929         if (ulv->ulv_supported && pptable_info->us_ulv_voltage_offset) {
2930                 PP_ASSERT_WITH_CODE(0 == result,
2931                         "Failed to initialize ULV state!", return result;);
2932
2933                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2934                         ixCG_ULV_PARAMETER, ulv->ch_ulv_parameter);
2935         }
2936
2937         result = tonga_populate_smc_link_level(hwmgr, table);
2938         PP_ASSERT_WITH_CODE(0 == result,
2939                 "Failed to initialize Link Level!", return result;);
2940
2941         result = tonga_populate_all_graphic_levels(hwmgr);
2942         PP_ASSERT_WITH_CODE(0 == result,
2943                 "Failed to initialize Graphics Level!", return result;);
2944
2945         result = tonga_populate_all_memory_levels(hwmgr);
2946         PP_ASSERT_WITH_CODE(0 == result,
2947                 "Failed to initialize Memory Level!", return result;);
2948
2949         result = tonga_populate_smv_acpi_level(hwmgr, table);
2950         PP_ASSERT_WITH_CODE(0 == result,
2951                 "Failed to initialize ACPI Level!", return result;);
2952
2953         result = tonga_populate_smc_vce_level(hwmgr, table);
2954         PP_ASSERT_WITH_CODE(0 == result,
2955                 "Failed to initialize VCE Level!", return result;);
2956
2957         result = tonga_populate_smc_acp_level(hwmgr, table);
2958         PP_ASSERT_WITH_CODE(0 == result,
2959                 "Failed to initialize ACP Level!", return result;);
2960
2961         result = tonga_populate_smc_samu_level(hwmgr, table);
2962         PP_ASSERT_WITH_CODE(0 == result,
2963                 "Failed to initialize SAMU Level!", return result;);
2964
2965         /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
2966         /* need to populate the  ARB settings for the initial state. */
2967         result = tonga_program_memory_timing_parameters(hwmgr);
2968         PP_ASSERT_WITH_CODE(0 == result,
2969                 "Failed to Write ARB settings for the initial state.", return result;);
2970
2971         result = tonga_populate_smc_uvd_level(hwmgr, table);
2972         PP_ASSERT_WITH_CODE(0 == result,
2973                 "Failed to initialize UVD Level!", return result;);
2974
2975         result = tonga_populate_smc_boot_level(hwmgr, table);
2976         PP_ASSERT_WITH_CODE(0 == result,
2977                 "Failed to initialize Boot Level!", return result;);
2978
2979         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2980                         PHM_PlatformCaps_ClockStretcher)) {
2981                 result = tonga_populate_clock_stretcher_data_table(hwmgr);
2982                 PP_ASSERT_WITH_CODE(0 == result,
2983                         "Failed to populate Clock Stretcher Data Table!", return result;);
2984         }
2985         table->GraphicsVoltageChangeEnable  = 1;
2986         table->GraphicsThermThrottleEnable  = 1;
2987         table->GraphicsInterval = 1;
2988         table->VoltageInterval  = 1;
2989         table->ThermalInterval  = 1;
2990         table->TemperatureLimitHigh =
2991                 pptable_info->cac_dtp_table->usTargetOperatingTemp *
2992                 TONGA_Q88_FORMAT_CONVERSION_UNIT;
2993         table->TemperatureLimitLow =
2994                 (pptable_info->cac_dtp_table->usTargetOperatingTemp - 1) *
2995                 TONGA_Q88_FORMAT_CONVERSION_UNIT;
2996         table->MemoryVoltageChangeEnable  = 1;
2997         table->MemoryInterval  = 1;
2998         table->VoltageResponseTime  = 0;
2999         table->PhaseResponseTime  = 0;
3000         table->MemoryThermThrottleEnable  = 1;
3001
3002         /*
3003         * Cail reads current link status and reports it as cap (we cannot change this due to some previous issues we had)
3004         * SMC drops the link status to lowest level after enabling DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
3005         * but this time Cail reads current link status which was set to low by SMC and reports it as cap to powerplay
3006         * To avoid it, we set PCIeBootLinkLevel to highest dpm level
3007         */
3008         PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
3009                         "There must be 1 or more PCIE levels defined in PPTable.",
3010                         return -1);
3011
3012         table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
3013
3014         table->PCIeGenInterval  = 1;
3015
3016         result = tonga_populate_vr_config(hwmgr, table);
3017         PP_ASSERT_WITH_CODE(0 == result,
3018                 "Failed to populate VRConfig setting!", return result);
3019
3020         table->ThermGpio  = 17;
3021         table->SclkStepSize = 0x4000;
3022
3023         reg_value = 0;
3024         if ((0 == reg_value) &&
3025                 (0 == atomctrl_get_pp_assign_pin(hwmgr,
3026                         VDDC_VRHOT_GPIO_PINID, &gpio_pin_assignment))) {
3027                 table->VRHotGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
3028                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3029                         PHM_PlatformCaps_RegulatorHot);
3030         } else {
3031                 table->VRHotGpio = TONGA_UNUSED_GPIO_PIN;
3032                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3033                         PHM_PlatformCaps_RegulatorHot);
3034         }
3035
3036         /* ACDC Switch GPIO */
3037         reg_value = 0;
3038         if ((0 == reg_value) &&
3039                 (0 == atomctrl_get_pp_assign_pin(hwmgr,
3040                         PP_AC_DC_SWITCH_GPIO_PINID, &gpio_pin_assignment))) {
3041                 table->AcDcGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
3042                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3043                         PHM_PlatformCaps_AutomaticDCTransition);
3044         } else {
3045                 table->AcDcGpio = TONGA_UNUSED_GPIO_PIN;
3046                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3047                         PHM_PlatformCaps_AutomaticDCTransition);
3048         }
3049
3050         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3051                 PHM_PlatformCaps_Falcon_QuickTransition);
3052
3053         reg_value = 0;
3054         if (1 == reg_value) {
3055                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3056                         PHM_PlatformCaps_AutomaticDCTransition);
3057                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3058                         PHM_PlatformCaps_Falcon_QuickTransition);
3059         }
3060
3061         reg_value = 0;
3062         if ((0 == reg_value) &&
3063                 (0 == atomctrl_get_pp_assign_pin(hwmgr,
3064                         THERMAL_INT_OUTPUT_GPIO_PINID, &gpio_pin_assignment))) {
3065                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3066                         PHM_PlatformCaps_ThermalOutGPIO);
3067
3068                 table->ThermOutGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
3069
3070                 table->ThermOutPolarity =
3071                         (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
3072                         (1 << gpio_pin_assignment.uc_gpio_pin_bit_shift))) ? 1:0;
3073
3074                 table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
3075
3076                 /* if required, combine VRHot/PCC with thermal out GPIO*/
3077                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3078                         PHM_PlatformCaps_RegulatorHot) &&
3079                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3080                         PHM_PlatformCaps_CombinePCCWithThermalSignal)){
3081                         table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
3082                 }
3083         } else {
3084                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3085                         PHM_PlatformCaps_ThermalOutGPIO);
3086
3087                 table->ThermOutGpio = 17;
3088                 table->ThermOutPolarity = 1;
3089                 table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
3090         }
3091
3092         for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++) {
3093                 table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
3094         }
3095         CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
3096         CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
3097         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
3098         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
3099         CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
3100         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
3101         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
3102         CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
3103         CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
3104
3105         /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3106         result = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->dpm_table_start +
3107                                                                                 offsetof(SMU72_Discrete_DpmTable, SystemFlags),
3108                                                                                 (uint8_t *)&(table->SystemFlags),
3109                                                                                 sizeof(SMU72_Discrete_DpmTable)-3 * sizeof(SMU72_PIDController),
3110                                                                                 data->sram_end);
3111
3112         PP_ASSERT_WITH_CODE(0 == result,
3113                 "Failed to upload dpm data to SMC memory!", return result;);
3114
3115         return result;
3116 }
3117
3118 /* Look up the voltaged based on DAL's requested level. and then send the requested VDDC voltage to SMC*/
3119 static void tonga_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
3120 {
3121         return;
3122 }
3123
3124 int tonga_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
3125 {
3126         PPSMC_Result result;
3127         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3128
3129         /* Apply minimum voltage based on DAL's request level */
3130         tonga_apply_dal_minimum_voltage_request(hwmgr);
3131
3132         if (0 == data->sclk_dpm_key_disabled) {
3133                 /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
3134                 if (0 != tonga_is_dpm_running(hwmgr))
3135                         printk(KERN_ERR "[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3136
3137                 if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
3138                         result = smum_send_msg_to_smc_with_parameter(
3139                                                                 hwmgr->smumgr,
3140                                 (PPSMC_Msg)PPSMC_MSG_SCLKDPM_SetEnabledMask,
3141                                 data->dpm_level_enable_mask.sclk_dpm_enable_mask);
3142                         PP_ASSERT_WITH_CODE((0 == result),
3143                                 "Set Sclk Dpm enable Mask failed", return -1);
3144                 }
3145         }
3146
3147         if (0 == data->mclk_dpm_key_disabled) {
3148                 /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
3149                 if (0 != tonga_is_dpm_running(hwmgr))
3150                         printk(KERN_ERR "[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
3151
3152                 if (0 != data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
3153                         result = smum_send_msg_to_smc_with_parameter(
3154                                                                 hwmgr->smumgr,
3155                                 (PPSMC_Msg)PPSMC_MSG_MCLKDPM_SetEnabledMask,
3156                                 data->dpm_level_enable_mask.mclk_dpm_enable_mask);
3157                         PP_ASSERT_WITH_CODE((0 == result),
3158                                 "Set Mclk Dpm enable Mask failed", return -1);
3159                 }
3160         }
3161
3162         return 0;
3163 }
3164
3165
3166 int tonga_force_dpm_highest(struct pp_hwmgr *hwmgr)
3167 {
3168         uint32_t level, tmp;
3169         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3170
3171         if (0 == data->pcie_dpm_key_disabled) {
3172                 /* PCIE */
3173                 if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) {
3174                         level = 0;
3175                         tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
3176                         while (tmp >>= 1)
3177                                 level++ ;
3178
3179                         if (0 != level) {
3180                                 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr, level)),
3181                                         "force highest pcie dpm state failed!", return -1);
3182                         }
3183                 }
3184         }
3185
3186         if (0 == data->sclk_dpm_key_disabled) {
3187                 /* SCLK */
3188                 if (data->dpm_level_enable_mask.sclk_dpm_enable_mask != 0) {
3189                         level = 0;
3190                         tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
3191                         while (tmp >>= 1)
3192                                 level++ ;
3193
3194                         if (0 != level) {
3195                                 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr, level)),
3196                                         "force highest sclk dpm state failed!", return -1);
3197                                 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
3198                                         CGS_IND_REG__SMC, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX) != level)
3199                                         printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
3200                                                 Curr_Sclk_Index does not match the level \n");
3201
3202                         }
3203                 }
3204         }
3205
3206         if (0 == data->mclk_dpm_key_disabled) {
3207                 /* MCLK */
3208                 if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) {
3209                         level = 0;
3210                         tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
3211                         while (tmp >>= 1)
3212                                 level++ ;
3213
3214                         if (0 != level) {
3215                                 PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr, level)),
3216                                         "force highest mclk dpm state failed!", return -1);
3217                                 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3218                                         TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX) != level)
3219                                         printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
3220                                                 Curr_Mclk_Index does not match the level \n");
3221                         }
3222                 }
3223         }
3224
3225         return 0;
3226 }
3227
3228 /**
3229  * Find the MC microcode version and store it in the HwMgr struct
3230  *
3231  * @param    hwmgr  the address of the powerplay hardware manager.
3232  * @return   always 0
3233  */
3234 int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr)
3235 {
3236         cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F);
3237
3238         hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
3239
3240         return 0;
3241 }
3242
3243 /**
3244  * Initialize Dynamic State Adjustment Rule Settings
3245  *
3246  * @param    hwmgr  the address of the powerplay hardware manager.
3247  */
3248 int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
3249 {
3250         uint32_t table_size;
3251         struct phm_clock_voltage_dependency_table *table_clk_vlt;
3252         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
3253
3254         hwmgr->dyn_state.mclk_sclk_ratio = 4;
3255         hwmgr->dyn_state.sclk_mclk_delta = 15000;      /* 150 MHz */
3256         hwmgr->dyn_state.vddc_vddci_delta = 200;       /* 200mV */
3257
3258         /* initialize vddc_dep_on_dal_pwrl table */
3259         table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
3260         table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL);
3261
3262         if (NULL == table_clk_vlt) {
3263                 printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
3264                 return -ENOMEM;
3265         } else {
3266                 table_clk_vlt->count = 4;
3267                 table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
3268                 table_clk_vlt->entries[0].v = 0;
3269                 table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
3270                 table_clk_vlt->entries[1].v = 720;
3271                 table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
3272                 table_clk_vlt->entries[2].v = 810;
3273                 table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
3274                 table_clk_vlt->entries[3].v = 900;
3275                 pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
3276                 hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
3277         }
3278
3279         return 0;
3280 }
3281
3282 static int tonga_set_private_var_based_on_pptale(struct pp_hwmgr *hwmgr)
3283 {
3284         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3285         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
3286
3287         phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
3288                 pptable_info->vdd_dep_on_sclk;
3289         phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
3290                 pptable_info->vdd_dep_on_mclk;
3291
3292         PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
3293                 "VDD dependency on SCLK table is missing.       \
3294                 This table is mandatory", return -1);
3295         PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
3296                 "VDD dependency on SCLK table has to have is missing.   \
3297                 This table is mandatory", return -1);
3298
3299         PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
3300                 "VDD dependency on MCLK table is missing.       \
3301                 This table is mandatory", return -1);
3302         PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
3303                 "VDD dependency on MCLK table has to have is missing.    \
3304                 This table is mandatory", return -1);
3305
3306         data->min_vddc_in_pp_table = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
3307         data->max_vddc_in_pp_table = (uint16_t)allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
3308
3309         pptable_info->max_clock_voltage_on_ac.sclk =
3310                 allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
3311         pptable_info->max_clock_voltage_on_ac.mclk =
3312                 allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
3313         pptable_info->max_clock_voltage_on_ac.vddc =
3314                 allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
3315         pptable_info->max_clock_voltage_on_ac.vddci =
3316                 allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
3317
3318         hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
3319                 pptable_info->max_clock_voltage_on_ac.sclk;
3320         hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
3321                 pptable_info->max_clock_voltage_on_ac.mclk;
3322         hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
3323                 pptable_info->max_clock_voltage_on_ac.vddc;
3324         hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
3325                 pptable_info->max_clock_voltage_on_ac.vddci;
3326
3327         return 0;
3328 }
3329
3330 int tonga_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
3331 {
3332         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3333         int result = 1;
3334
3335         PP_ASSERT_WITH_CODE (0 == tonga_is_dpm_running(hwmgr),
3336                 "Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.",
3337                                                         return result);
3338
3339         if (0 == data->pcie_dpm_key_disabled) {
3340                 PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(
3341                                                              hwmgr->smumgr,
3342                                         PPSMC_MSG_PCIeDPM_UnForceLevel)),
3343                                            "unforce pcie level failed!",
3344                                                                 return -1);
3345         }
3346
3347         result = tonga_upload_dpm_level_enable_mask(hwmgr);
3348
3349         return result;
3350 }
3351
3352 static uint32_t tonga_get_lowest_enable_level(
3353                                 struct pp_hwmgr *hwmgr, uint32_t level_mask)
3354 {
3355         uint32_t level = 0;
3356
3357         while (0 == (level_mask & (1 << level)))
3358                 level++;
3359
3360         return level;
3361 }
3362
3363 static int tonga_force_dpm_lowest(struct pp_hwmgr *hwmgr)
3364 {
3365         uint32_t level;
3366         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3367
3368         if (0 == data->pcie_dpm_key_disabled) {
3369                 /* PCIE */
3370                 if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) {
3371                         level = tonga_get_lowest_enable_level(hwmgr,
3372                                                               data->dpm_level_enable_mask.pcie_dpm_enable_mask);
3373                         PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr, level)),
3374                                             "force lowest pcie dpm state failed!", return -1);
3375                 }
3376         }
3377
3378         if (0 == data->sclk_dpm_key_disabled) {
3379                 /* SCLK */
3380                 if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
3381                         level = tonga_get_lowest_enable_level(hwmgr,
3382                                                               data->dpm_level_enable_mask.sclk_dpm_enable_mask);
3383
3384                         PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr, level)),
3385                                             "force sclk dpm state failed!", return -1);
3386
3387                         if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
3388                                                          CGS_IND_REG__SMC, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX) != level)
3389                                 printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index.        \
3390                                 Curr_Sclk_Index does not match the level \n");
3391                 }
3392         }
3393
3394         if (0 == data->mclk_dpm_key_disabled) {
3395                 /* MCLK */
3396                 if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) {
3397                         level = tonga_get_lowest_enable_level(hwmgr,
3398                                                               data->dpm_level_enable_mask.mclk_dpm_enable_mask);
3399                         PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr, level)),
3400                                             "force lowest mclk dpm state failed!", return -1);
3401                         if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3402                                                          TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX) != level)
3403                                 printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
3404                                                 Curr_Mclk_Index does not match the level \n");
3405                 }
3406         }
3407
3408         return 0;
3409 }
3410
3411 static int tonga_patch_voltage_dependency_tables_with_lookup_table(struct pp_hwmgr *hwmgr)
3412 {
3413         uint8_t entryId;
3414         uint8_t voltageId;
3415         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3416         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
3417
3418         phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
3419         phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
3420         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
3421
3422         if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
3423                 for (entryId = 0; entryId < sclk_table->count; ++entryId) {
3424                         voltageId = sclk_table->entries[entryId].vddInd;
3425                         sclk_table->entries[entryId].vddgfx =
3426                                 pptable_info->vddgfx_lookup_table->entries[voltageId].us_vdd;
3427                 }
3428         } else {
3429                 for (entryId = 0; entryId < sclk_table->count; ++entryId) {
3430                         voltageId = sclk_table->entries[entryId].vddInd;
3431                         sclk_table->entries[entryId].vddc =
3432                                 pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
3433                 }
3434         }
3435
3436         for (entryId = 0; entryId < mclk_table->count; ++entryId) {
3437                 voltageId = mclk_table->entries[entryId].vddInd;
3438                 mclk_table->entries[entryId].vddc =
3439                         pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
3440         }
3441
3442         for (entryId = 0; entryId < mm_table->count; ++entryId) {
3443                 voltageId = mm_table->entries[entryId].vddcInd;
3444                 mm_table->entries[entryId].vddc =
3445                         pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
3446         }
3447
3448         return 0;
3449
3450 }
3451
3452 static int tonga_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
3453 {
3454         uint8_t entryId;
3455         phm_ppt_v1_voltage_lookup_record v_record;
3456         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3457         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
3458
3459         phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
3460         phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
3461
3462         if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
3463                 for (entryId = 0; entryId < sclk_table->count; ++entryId) {
3464                         if (sclk_table->entries[entryId].vdd_offset & (1 << 15))
3465                                 v_record.us_vdd = sclk_table->entries[entryId].vddgfx +
3466                                         sclk_table->entries[entryId].vdd_offset - 0xFFFF;
3467                         else
3468                                 v_record.us_vdd = sclk_table->entries[entryId].vddgfx +
3469                                         sclk_table->entries[entryId].vdd_offset;
3470
3471                         sclk_table->entries[entryId].vddc =
3472                                 v_record.us_cac_low = v_record.us_cac_mid =
3473                                 v_record.us_cac_high = v_record.us_vdd;
3474
3475                         tonga_add_voltage(hwmgr, pptable_info->vddc_lookup_table, &v_record);
3476                 }
3477
3478                 for (entryId = 0; entryId < mclk_table->count; ++entryId) {
3479                         if (mclk_table->entries[entryId].vdd_offset & (1 << 15))
3480                                 v_record.us_vdd = mclk_table->entries[entryId].vddc +
3481                                         mclk_table->entries[entryId].vdd_offset - 0xFFFF;
3482                         else
3483                                 v_record.us_vdd = mclk_table->entries[entryId].vddc +
3484                                         mclk_table->entries[entryId].vdd_offset;
3485
3486                         mclk_table->entries[entryId].vddgfx = v_record.us_cac_low =
3487                                 v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
3488                         tonga_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
3489                 }
3490         }
3491
3492         return 0;
3493
3494 }
3495
3496 static int tonga_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
3497 {
3498         uint32_t entryId;
3499         phm_ppt_v1_voltage_lookup_record v_record;
3500         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3501         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
3502         phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
3503
3504         if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
3505                 for (entryId = 0; entryId < mm_table->count; entryId++) {
3506                         if (mm_table->entries[entryId].vddgfx_offset & (1 << 15))
3507                                 v_record.us_vdd = mm_table->entries[entryId].vddc +
3508                                         mm_table->entries[entryId].vddgfx_offset - 0xFFFF;
3509                         else
3510                                 v_record.us_vdd = mm_table->entries[entryId].vddc +
3511                                         mm_table->entries[entryId].vddgfx_offset;
3512
3513                         /* Add the calculated VDDGFX to the VDDGFX lookup table */
3514                         mm_table->entries[entryId].vddgfx = v_record.us_cac_low =
3515                                 v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
3516                         tonga_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
3517                 }
3518         }
3519         return 0;
3520 }
3521
3522
3523 /**
3524  * Change virtual leakage voltage to actual value.
3525  *
3526  * @param     hwmgr  the address of the powerplay hardware manager.
3527  * @param     pointer to changing voltage
3528  * @param     pointer to leakage table
3529  */
3530 static void tonga_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
3531                 uint16_t *voltage, phw_tonga_leakage_voltage *pLeakageTable)
3532 {
3533         uint32_t leakage_index;
3534
3535         /* search for leakage voltage ID 0xff01 ~ 0xff08 */
3536         for (leakage_index = 0; leakage_index < pLeakageTable->count; leakage_index++) {
3537                 /* if this voltage matches a leakage voltage ID */
3538                 /* patch with actual leakage voltage */
3539                 if (pLeakageTable->leakage_id[leakage_index] == *voltage) {
3540                         *voltage = pLeakageTable->actual_voltage[leakage_index];
3541                         break;
3542                 }
3543         }
3544
3545         if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
3546                 printk(KERN_ERR "[ powerplay ] Voltage value looks like a Leakage ID but it's not patched \n");
3547 }
3548
3549 /**
3550  * Patch voltage lookup table by EVV leakages.
3551  *
3552  * @param     hwmgr  the address of the powerplay hardware manager.
3553  * @param     pointer to voltage lookup table
3554  * @param     pointer to leakage table
3555  * @return     always 0
3556  */
3557 static int tonga_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
3558                 phm_ppt_v1_voltage_lookup_table *lookup_table,
3559                 phw_tonga_leakage_voltage *pLeakageTable)
3560 {
3561         uint32_t i;
3562
3563         for (i = 0; i < lookup_table->count; i++) {
3564                 tonga_patch_with_vdd_leakage(hwmgr,
3565                         &lookup_table->entries[i].us_vdd, pLeakageTable);
3566         }
3567
3568         return 0;
3569 }
3570
3571 static int tonga_patch_clock_voltage_lomits_with_vddc_leakage(struct pp_hwmgr *hwmgr,
3572                 phw_tonga_leakage_voltage *pLeakageTable, uint16_t *Vddc)
3573 {
3574         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
3575
3576         tonga_patch_with_vdd_leakage(hwmgr, (uint16_t *)Vddc, pLeakageTable);
3577         hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
3578                 pptable_info->max_clock_voltage_on_dc.vddc;
3579
3580         return 0;
3581 }
3582
3583 static int tonga_patch_clock_voltage_limits_with_vddgfx_leakage(
3584                 struct pp_hwmgr *hwmgr, phw_tonga_leakage_voltage *pLeakageTable,
3585                 uint16_t *Vddgfx)
3586 {
3587         tonga_patch_with_vdd_leakage(hwmgr, (uint16_t *)Vddgfx, pLeakageTable);
3588         return 0;
3589 }
3590
3591 int tonga_sort_lookup_table(struct pp_hwmgr *hwmgr,
3592                 phm_ppt_v1_voltage_lookup_table *lookup_table)
3593 {
3594         uint32_t table_size, i, j;
3595         phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
3596         table_size = lookup_table->count;
3597
3598         PP_ASSERT_WITH_CODE(0 != lookup_table->count,
3599                 "Lookup table is empty", return -1);
3600
3601         /* Sorting voltages */
3602         for (i = 0; i < table_size - 1; i++) {
3603                 for (j = i + 1; j > 0; j--) {
3604                         if (lookup_table->entries[j].us_vdd < lookup_table->entries[j-1].us_vdd) {
3605                                 tmp_voltage_lookup_record = lookup_table->entries[j-1];
3606                                 lookup_table->entries[j-1] = lookup_table->entries[j];
3607                                 lookup_table->entries[j] = tmp_voltage_lookup_record;
3608                         }
3609                 }
3610         }
3611
3612         return 0;
3613 }
3614
3615 static int tonga_complete_dependency_tables(struct pp_hwmgr *hwmgr)
3616 {
3617         int result = 0;
3618         int tmp_result;
3619         tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
3620         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
3621
3622         if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
3623                 tmp_result = tonga_patch_lookup_table_with_leakage(hwmgr,
3624                         pptable_info->vddgfx_lookup_table, &(data->vddcgfx_leakage));
3625                 if (tmp_result != 0)
3626                         result = tmp_result;
3627
3628                 tmp_result = tonga_patch_clock_voltage_limits_with_vddgfx_leakage(hwmgr,
3629                         &(data->vddcgfx_leakage), &pptable_info->max_clock_voltage_on_dc.vddgfx);
3630                 if (tmp_result != 0)
3631                         result = tmp_result;
3632         } else {
3633                 tmp_result = tonga_patch_lookup_table_with_leakage(hwmgr,
3634                         pptable_info->vddc_lookup_table, &(data->vddc_leakage));
3635                 if (tmp_result != 0)
3636                         result = tmp_result;
3637
3638                 tmp_result = tonga_patch_clock_voltage_lomits_with_vddc_leakage(hwmgr,
3639                         &(data->vddc_leakage), &pptable_info->max_clock_voltage_on_dc.vddc);
3640                 if (tmp_result != 0)
3641                         result = tmp_result;
3642         }
3643
3644         tmp_result = tonga_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
3645         if (tmp_result != 0)
3646                 result = tmp_result;
3647
3648         tmp_result = tonga_calc_voltage_dependency_tables(hwmgr);
3649         if (tmp_result != 0)
3650                 result = tmp_result;
3651
3652         tmp_result = tonga_calc_mm_voltage_dependency_table(hwmgr);
3653         if (tmp_result != 0)
3654                 result = tmp_result;
3655
3656         tmp_result = tonga_sort_lookup_table(hwmgr, pptable_info->vddgfx_lookup_table);
3657         if (tmp_result != 0)
3658                 result = tmp_result;
3659
3660         tmp_result = tonga_sort_lookup_table(hwmgr, pptable_info->vddc_lookup_table);
3661         if (tmp_result != 0)
3662                 result = tmp_result;
3663
3664         return result;
3665 }
3666
3667 int tonga_init_sclk_threshold(struct pp_hwmgr *hwmgr)
3668 {
3669         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3670         data->low_sclk_interrupt_threshold = 0;
3671
3672         return 0;
3673 }
3674
3675 int tonga_setup_asic_task(struct pp_hwmgr *hwmgr)
3676 {
3677         int tmp_result, result = 0;
3678
3679         tmp_result = tonga_read_clock_registers(hwmgr);
3680         PP_ASSERT_WITH_CODE((0 == tmp_result),
3681                 "Failed to read clock registers!", result = tmp_result);
3682
3683         tmp_result = tonga_get_memory_type(hwmgr);
3684         PP_ASSERT_WITH_CODE((0 == tmp_result),
3685                 "Failed to get memory type!", result = tmp_result);
3686
3687         tmp_result = tonga_enable_acpi_power_management(hwmgr);
3688         PP_ASSERT_WITH_CODE((0 == tmp_result),
3689                 "Failed to enable ACPI power management!", result = tmp_result);
3690
3691         tmp_result = tonga_init_power_gate_state(hwmgr);
3692         PP_ASSERT_WITH_CODE((0 == tmp_result),
3693                 "Failed to init power gate state!", result = tmp_result);
3694
3695         tmp_result = tonga_get_mc_microcode_version(hwmgr);
3696         PP_ASSERT_WITH_CODE((0 == tmp_result),
3697                 "Failed to get MC microcode version!", result = tmp_result);
3698
3699         tmp_result = tonga_init_sclk_threshold(hwmgr);
3700         PP_ASSERT_WITH_CODE((0 == tmp_result),
3701                 "Failed to init sclk threshold!", result = tmp_result);
3702
3703         return result;
3704 }
3705
3706 /**
3707  * Enable voltage control
3708  *
3709  * @param    hwmgr  the address of the powerplay hardware manager.
3710  * @return   always 0
3711  */
3712 int tonga_enable_voltage_control(struct pp_hwmgr *hwmgr)
3713 {
3714         /* enable voltage control */
3715         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
3716
3717         return 0;
3718 }
3719
3720 /**
3721  * Checks if we want to support voltage control
3722  *
3723  * @param    hwmgr  the address of the powerplay hardware manager.
3724  */
3725 bool cf_tonga_voltage_control(const struct pp_hwmgr *hwmgr)
3726 {
3727         const struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
3728
3729         return(TONGA_VOLTAGE_CONTROL_NONE != data->voltage_control);
3730 }
3731
3732 /*---------------------------MC----------------------------*/
3733
3734 uint8_t tonga_get_memory_modile_index(struct pp_hwmgr *hwmgr)
3735 {
3736         return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
3737 }
3738
3739 bool tonga_check_s0_mc_reg_index(uint16_t inReg, uint16_t *outReg)
3740 {
3741         bool result = 1;
3742
3743         switch (inReg) {
3744         case  mmMC_SEQ_RAS_TIMING:
3745                 *outReg = mmMC_SEQ_RAS_TIMING_LP;
3746                 break;
3747
3748         case  mmMC_SEQ_DLL_STBY:
3749                 *outReg = mmMC_SEQ_DLL_STBY_LP;
3750                 break;
3751
3752         case  mmMC_SEQ_G5PDX_CMD0:
3753                 *outReg = mmMC_SEQ_G5PDX_CMD0_LP;
3754                 break;
3755
3756         case  mmMC_SEQ_G5PDX_CMD1:
3757                 *outReg = mmMC_SEQ_G5PDX_CMD1_LP;
3758                 break;
3759
3760         case  mmMC_SEQ_G5PDX_CTRL:
3761                 *outReg = mmMC_SEQ_G5PDX_CTRL_LP;
3762                 break;
3763
3764         case mmMC_SEQ_CAS_TIMING:
3765                 *outReg = mmMC_SEQ_CAS_TIMING_LP;
3766                 break;
3767
3768         case mmMC_SEQ_MISC_TIMING:
3769                 *outReg = mmMC_SEQ_MISC_TIMING_LP;
3770                 break;
3771
3772         case mmMC_SEQ_MISC_TIMING2:
3773                 *outReg = mmMC_SEQ_MISC_TIMING2_LP;
3774                 break;
3775
3776         case mmMC_SEQ_PMG_DVS_CMD:
3777                 *outReg = mmMC_SEQ_PMG_DVS_CMD_LP;
3778                 break;
3779
3780         case mmMC_SEQ_PMG_DVS_CTL:
3781                 *outReg = mmMC_SEQ_PMG_DVS_CTL_LP;
3782                 break;
3783
3784         case mmMC_SEQ_RD_CTL_D0:
3785                 *outReg = mmMC_SEQ_RD_CTL_D0_LP;
3786                 break;
3787
3788         case mmMC_SEQ_RD_CTL_D1:
3789                 *outReg = mmMC_SEQ_RD_CTL_D1_LP;
3790                 break;
3791
3792         case mmMC_SEQ_WR_CTL_D0:
3793                 *outReg = mmMC_SEQ_WR_CTL_D0_LP;
3794                 break;
3795
3796         case mmMC_SEQ_WR_CTL_D1:
3797                 *outReg = mmMC_SEQ_WR_CTL_D1_LP;
3798                 break;
3799
3800         case mmMC_PMG_CMD_EMRS:
3801                 *outReg = mmMC_SEQ_PMG_CMD_EMRS_LP;
3802                 break;
3803
3804         case mmMC_PMG_CMD_MRS:
3805                 *outReg = mmMC_SEQ_PMG_CMD_MRS_LP;
3806                 break;
3807
3808         case mmMC_PMG_CMD_MRS1:
3809                 *outReg = mmMC_SEQ_PMG_CMD_MRS1_LP;
3810                 break;
3811
3812         case mmMC_SEQ_PMG_TIMING:
3813                 *outReg = mmMC_SEQ_PMG_TIMING_LP;
3814                 break;
3815
3816         case mmMC_PMG_CMD_MRS2:
3817                 *outReg = mmMC_SEQ_PMG_CMD_MRS2_LP;
3818                 break;
3819
3820         case mmMC_SEQ_WR_CTL_2:
3821                 *outReg = mmMC_SEQ_WR_CTL_2_LP;
3822                 break;
3823
3824         default:
3825                 result = 0;
3826                 break;
3827         }
3828
3829         return result;
3830 }
3831
3832 int tonga_set_s0_mc_reg_index(phw_tonga_mc_reg_table *table)
3833 {
3834         uint32_t i;
3835         uint16_t address;
3836
3837         for (i = 0; i < table->last; i++) {
3838                 table->mc_reg_address[i].s0 =
3839                         tonga_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address)
3840                         ? address : table->mc_reg_address[i].s1;
3841         }
3842         return 0;
3843 }
3844
3845 int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table, phw_tonga_mc_reg_table *ni_table)
3846 {
3847         uint8_t i, j;
3848
3849         PP_ASSERT_WITH_CODE((table->last <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3850                 "Invalid VramInfo table.", return -1);
3851         PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
3852                 "Invalid VramInfo table.", return -1);
3853
3854         for (i = 0; i < table->last; i++) {
3855                 ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
3856         }
3857         ni_table->last = table->last;
3858
3859         for (i = 0; i < table->num_entries; i++) {
3860                 ni_table->mc_reg_table_entry[i].mclk_max =
3861                         table->mc_reg_table_entry[i].mclk_max;
3862                 for (j = 0; j < table->last; j++) {
3863                         ni_table->mc_reg_table_entry[i].mc_data[j] =
3864                                 table->mc_reg_table_entry[i].mc_data[j];
3865                 }
3866         }
3867         ni_table->num_entries = table->num_entries;
3868
3869         return 0;
3870 }
3871
3872 /**
3873  * VBIOS omits some information to reduce size, we need to recover them here.
3874  * 1.   when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to  mmMC_PMG_CMD_EMRS /_LP[15:0].
3875  *      Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3876  * 2.   when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
3877  * 3.   need to set these data for each clock range
3878  *
3879  * @param    hwmgr the address of the powerplay hardware manager.
3880  * @param    table the address of MCRegTable
3881  * @return   always 0
3882  */
3883 int tonga_set_mc_special_registers(struct pp_hwmgr *hwmgr, phw_tonga_mc_reg_table *table)
3884 {
3885         uint8_t i, j, k;
3886         uint32_t temp_reg;
3887         const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
3888
3889         for (i = 0, j = table->last; i < table->last; i++) {
3890                 PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3891                         "Invalid VramInfo table.", return -1);
3892                 switch (table->mc_reg_address[i].s1) {
3893                 /*
3894                 * mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to  mmMC_PMG_CMD_EMRS /_LP[15:0].
3895                 * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
3896                 */
3897                 case mmMC_SEQ_MISC1:
3898                         temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS);
3899                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
3900                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
3901                         for (k = 0; k < table->num_entries; k++) {
3902                                 table->mc_reg_table_entry[k].mc_data[j] =
3903                                         ((temp_reg & 0xffff0000)) |
3904                                         ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
3905                         }
3906                         j++;
3907                         PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3908                                 "Invalid VramInfo table.", return -1);
3909
3910                         temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
3911                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
3912                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
3913                         for (k = 0; k < table->num_entries; k++) {
3914                                 table->mc_reg_table_entry[k].mc_data[j] =
3915                                         (temp_reg & 0xffff0000) |
3916                                         (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
3917
3918                                 if (!data->is_memory_GDDR5) {
3919                                         table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
3920                                 }
3921                         }
3922                         j++;
3923                         PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3924                                 "Invalid VramInfo table.", return -1);
3925
3926                         if (!data->is_memory_GDDR5) {
3927                                 table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
3928                                 table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
3929                                 for (k = 0; k < table->num_entries; k++) {
3930                                         table->mc_reg_table_entry[k].mc_data[j] =
3931                                                 (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
3932                                 }
3933                                 j++;
3934                                 PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3935                                         "Invalid VramInfo table.", return -1);
3936                         }
3937
3938                         break;
3939
3940                 case mmMC_SEQ_RESERVE_M:
3941                         temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
3942                         table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
3943                         table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
3944                         for (k = 0; k < table->num_entries; k++) {
3945                                 table->mc_reg_table_entry[k].mc_data[j] =
3946                                         (temp_reg & 0xffff0000) |
3947                                         (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
3948                         }
3949                         j++;
3950                         PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
3951                                 "Invalid VramInfo table.", return -1);
3952                         break;
3953
3954                 default:
3955                         break;
3956                 }
3957
3958         }
3959
3960         table->last = j;
3961
3962         return 0;
3963 }
3964
3965 int tonga_set_valid_flag(phw_tonga_mc_reg_table *table)
3966 {
3967         uint8_t i, j;
3968         for (i = 0; i < table->last; i++) {
3969                 for (j = 1; j < table->num_entries; j++) {
3970                         if (table->mc_reg_table_entry[j-1].mc_data[i] !=
3971                                 table->mc_reg_table_entry[j].mc_data[i]) {
3972                                 table->validflag |= (1<<i);
3973                                 break;
3974                         }
3975                 }
3976         }
3977
3978         return 0;
3979 }
3980
3981 int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
3982 {
3983         int result;
3984         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
3985         pp_atomctrl_mc_reg_table *table;
3986         phw_tonga_mc_reg_table *ni_table = &data->tonga_mc_reg_table;
3987         uint8_t module_index = tonga_get_memory_modile_index(hwmgr);
3988
3989         table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
3990
3991         if (NULL == table)
3992                 return -1;
3993
3994         /* Program additional LP registers that are no longer programmed by VBIOS */
3995         cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
3996         cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
3997         cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
3998         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
3999         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
4000         cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
4001         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
4002         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
4003         cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
4004         cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
4005         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
4006         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
4007         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
4008         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
4009         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
4010         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
4011         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
4012         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
4013         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
4014         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
4015
4016         memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
4017
4018         result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
4019
4020         if (0 == result)
4021                 result = tonga_copy_vbios_smc_reg_table(table, ni_table);
4022
4023         if (0 == result) {
4024                 tonga_set_s0_mc_reg_index(ni_table);
4025                 result = tonga_set_mc_special_registers(hwmgr, ni_table);
4026         }
4027
4028         if (0 == result)
4029                 tonga_set_valid_flag(ni_table);
4030
4031         kfree(table);
4032         return result;
4033 }
4034
4035 /*
4036 * Copy one arb setting to another and then switch the active set.
4037 * arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants.
4038 */
4039 int tonga_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
4040                 uint32_t arbFreqSrc, uint32_t arbFreqDest)
4041 {
4042         uint32_t mc_arb_dram_timing;
4043         uint32_t mc_arb_dram_timing2;
4044         uint32_t burst_time;
4045         uint32_t mc_cg_config;
4046
4047         switch (arbFreqSrc) {
4048         case MC_CG_ARB_FREQ_F0:
4049                 mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
4050                 mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
4051                 burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
4052                 break;
4053
4054         case MC_CG_ARB_FREQ_F1:
4055                 mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
4056                 mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
4057                 burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
4058                 break;
4059
4060         default:
4061                 return -1;
4062         }
4063
4064         switch (arbFreqDest) {
4065         case MC_CG_ARB_FREQ_F0:
4066                 cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
4067                 cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
4068                 PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
4069                 break;
4070
4071         case MC_CG_ARB_FREQ_F1:
4072                 cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
4073                 cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
4074                 PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
4075                 break;
4076
4077         default:
4078                 return -1;
4079         }
4080
4081         mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
4082         mc_cg_config |= 0x0000000F;
4083         cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
4084         PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arbFreqDest);
4085
4086         return 0;
4087 }
4088
4089 /**
4090  * Initial switch from ARB F0->F1
4091  *
4092  * @param    hwmgr  the address of the powerplay hardware manager.
4093  * @return   always 0
4094  * This function is to be called from the SetPowerState table.
4095  */
4096 int tonga_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr *hwmgr)
4097 {
4098         return tonga_copy_and_switch_arb_sets(hwmgr, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
4099 }
4100
4101 /**
4102  * Initialize the ARB DRAM timing table's index field.
4103  *
4104  * @param    hwmgr  the address of the powerplay hardware manager.
4105  * @return   always 0
4106  */
4107 int tonga_init_arb_table_index(struct pp_hwmgr *hwmgr)
4108 {
4109         const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4110         uint32_t tmp;
4111         int result;
4112
4113         /*
4114         * This is a read-modify-write on the first byte of the ARB table.
4115         * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure is the field 'current'.
4116         * This solution is ugly, but we never write the whole table only individual fields in it.
4117         * In reality this field should not be in that structure but in a soft register.
4118         */
4119         result = tonga_read_smc_sram_dword(hwmgr->smumgr,
4120                                 data->arb_table_start, &tmp, data->sram_end);
4121
4122         if (0 != result)
4123                 return result;
4124
4125         tmp &= 0x00FFFFFF;
4126         tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
4127
4128         return tonga_write_smc_sram_dword(hwmgr->smumgr,
4129                         data->arb_table_start,  tmp, data->sram_end);
4130 }
4131
4132 int tonga_populate_mc_reg_address(struct pp_hwmgr *hwmgr, SMU72_Discrete_MCRegisters *mc_reg_table)
4133 {
4134         const struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4135
4136         uint32_t i, j;
4137
4138         for (i = 0, j = 0; j < data->tonga_mc_reg_table.last; j++) {
4139                 if (data->tonga_mc_reg_table.validflag & 1<<j) {
4140                         PP_ASSERT_WITH_CODE(i < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE,
4141                                 "Index of mc_reg_table->address[] array out of boundary", return -1);
4142                         mc_reg_table->address[i].s0 =
4143                                 PP_HOST_TO_SMC_US(data->tonga_mc_reg_table.mc_reg_address[j].s0);
4144                         mc_reg_table->address[i].s1 =
4145                                 PP_HOST_TO_SMC_US(data->tonga_mc_reg_table.mc_reg_address[j].s1);
4146                         i++;
4147                 }
4148         }
4149
4150         mc_reg_table->last = (uint8_t)i;
4151
4152         return 0;
4153 }
4154
4155 /*convert register values from driver to SMC format */
4156 void tonga_convert_mc_registers(
4157         const phw_tonga_mc_reg_entry * pEntry,
4158         SMU72_Discrete_MCRegisterSet *pData,
4159         uint32_t numEntries, uint32_t validflag)
4160 {
4161         uint32_t i, j;
4162
4163         for (i = 0, j = 0; j < numEntries; j++) {
4164                 if (validflag & 1<<j) {
4165                         pData->value[i] = PP_HOST_TO_SMC_UL(pEntry->mc_data[j]);
4166                         i++;
4167                 }
4168         }
4169 }
4170
4171 /* find the entry in the memory range table, then populate the value to SMC's tonga_mc_reg_table */
4172 int tonga_convert_mc_reg_table_entry_to_smc(
4173                 struct pp_hwmgr *hwmgr,
4174                 const uint32_t memory_clock,
4175                 SMU72_Discrete_MCRegisterSet *mc_reg_table_data
4176                 )
4177 {
4178         const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4179         uint32_t i = 0;
4180
4181         for (i = 0; i < data->tonga_mc_reg_table.num_entries; i++) {
4182                 if (memory_clock <=
4183                         data->tonga_mc_reg_table.mc_reg_table_entry[i].mclk_max) {
4184                         break;
4185                 }
4186         }
4187
4188         if ((i == data->tonga_mc_reg_table.num_entries) && (i > 0))
4189                 --i;
4190
4191         tonga_convert_mc_registers(&data->tonga_mc_reg_table.mc_reg_table_entry[i],
4192                 mc_reg_table_data, data->tonga_mc_reg_table.last, data->tonga_mc_reg_table.validflag);
4193
4194         return 0;
4195 }
4196
4197 int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
4198                 SMU72_Discrete_MCRegisters *mc_reg_table)
4199 {
4200         int result = 0;
4201         tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4202         int res;
4203         uint32_t i;
4204
4205         for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
4206                 res = tonga_convert_mc_reg_table_entry_to_smc(
4207                                 hwmgr,
4208                                 data->dpm_table.mclk_table.dpm_levels[i].value,
4209                                 &mc_reg_table->data[i]
4210                                 );
4211
4212                 if (0 != res)
4213                         result = res;
4214         }
4215
4216         return result;
4217 }
4218
4219 int tonga_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
4220 {
4221         int result;
4222         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4223
4224         memset(&data->mc_reg_table, 0x00, sizeof(SMU72_Discrete_MCRegisters));
4225         result = tonga_populate_mc_reg_address(hwmgr, &(data->mc_reg_table));
4226         PP_ASSERT_WITH_CODE(0 == result,
4227                 "Failed to initialize MCRegTable for the MC register addresses!", return result;);
4228
4229         result = tonga_convert_mc_reg_table_to_smc(hwmgr, &data->mc_reg_table);
4230         PP_ASSERT_WITH_CODE(0 == result,
4231                 "Failed to initialize MCRegTable for driver state!", return result;);
4232
4233         return tonga_copy_bytes_to_smc(hwmgr->smumgr, data->mc_reg_table_start,
4234                         (uint8_t *)&data->mc_reg_table, sizeof(SMU72_Discrete_MCRegisters), data->sram_end);
4235 }
4236
4237 /**
4238  * Programs static screed detection parameters
4239  *
4240  * @param   hwmgr  the address of the powerplay hardware manager.
4241  * @return   always 0
4242  */
4243 int tonga_program_static_screen_threshold_parameters(struct pp_hwmgr *hwmgr)
4244 {
4245         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
4246
4247         /* Set static screen threshold unit*/
4248         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
4249                 CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
4250                 data->static_screen_threshold_unit);
4251         /* Set static screen threshold*/
4252         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
4253                 CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
4254                 data->static_screen_threshold);
4255
4256         return 0;
4257 }
4258
4259 /**
4260  * Setup display gap for glitch free memory clock switching.
4261  *
4262  * @param    hwmgr  the address of the powerplay hardware manager.
4263  * @return   always 0
4264  */
4265 int tonga_enable_display_gap(struct pp_hwmgr *hwmgr)
4266 {
4267         uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
4268                                                         CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
4269
4270         display_gap = PHM_SET_FIELD(display_gap,
4271                                         CG_DISPLAY_GAP_CNTL, DISP_GAP, DISPLAY_GAP_IGNORE);
4272
4273         display_gap = PHM_SET_FIELD(display_gap,
4274                                         CG_DISPLAY_GAP_CNTL, DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
4275
4276         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4277                 ixCG_DISPLAY_GAP_CNTL, display_gap);
4278
4279         return 0;
4280 }
4281
4282 /**
4283  * Programs activity state transition voting clients
4284  *
4285  * @param    hwmgr  the address of the powerplay hardware manager.
4286  * @return   always 0
4287  */
4288 int tonga_program_voting_clients(struct pp_hwmgr *hwmgr)
4289 {
4290         tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
4291
4292         /* Clear reset for voting clients before enabling DPM */
4293         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
4294                 SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
4295         PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
4296                 SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
4297
4298         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4299                 ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
4300         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4301                 ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
4302         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4303                 ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
4304         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4305                 ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
4306         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4307                 ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
4308         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4309                 ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
4310         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4311                 ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
4312         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4313                 ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
4314
4315         return 0;
4316 }
4317
4318
4319 int tonga_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
4320 {
4321         int tmp_result, result = 0;
4322
4323         tmp_result = tonga_check_for_dpm_stopped(hwmgr);
4324
4325         if (cf_tonga_voltage_control(hwmgr)) {
4326                 tmp_result = tonga_enable_voltage_control(hwmgr);
4327                 PP_ASSERT_WITH_CODE((0 == tmp_result),
4328                         "Failed to enable voltage control!", result = tmp_result);
4329
4330                 tmp_result = tonga_construct_voltage_tables(hwmgr);
4331                 PP_ASSERT_WITH_CODE((0 == tmp_result),
4332                         "Failed to contruct voltage tables!", result = tmp_result);
4333         }
4334
4335         tmp_result = tonga_initialize_mc_reg_table(hwmgr);
4336         PP_ASSERT_WITH_CODE((0 == tmp_result),
4337                 "Failed to initialize MC reg table!", result = tmp_result);
4338
4339         tmp_result = tonga_program_static_screen_threshold_parameters(hwmgr);
4340         PP_ASSERT_WITH_CODE((0 == tmp_result),
4341                 "Failed to program static screen threshold parameters!", result = tmp_result);
4342
4343         tmp_result = tonga_enable_display_gap(hwmgr);
4344         PP_ASSERT_WITH_CODE((0 == tmp_result),
4345                 "Failed to enable display gap!", result = tmp_result);
4346
4347         tmp_result = tonga_program_voting_clients(hwmgr);
4348         PP_ASSERT_WITH_CODE((0 == tmp_result),
4349                 "Failed to program voting clients!", result = tmp_result);
4350
4351         tmp_result = tonga_process_firmware_header(hwmgr);
4352         PP_ASSERT_WITH_CODE((0 == tmp_result),
4353                 "Failed to process firmware header!", result = tmp_result);
4354
4355         tmp_result = tonga_initial_switch_from_arb_f0_to_f1(hwmgr);
4356         PP_ASSERT_WITH_CODE((0 == tmp_result),
4357                 "Failed to initialize switch from ArbF0 to F1!", result = tmp_result);
4358
4359         tmp_result = tonga_init_smc_table(hwmgr);
4360         PP_ASSERT_WITH_CODE((0 == tmp_result),
4361                 "Failed to initialize SMC table!", result = tmp_result);
4362
4363         tmp_result = tonga_init_arb_table_index(hwmgr);
4364         PP_ASSERT_WITH_CODE((0 == tmp_result),
4365                 "Failed to initialize ARB table index!", result = tmp_result);
4366
4367         tmp_result = tonga_populate_initial_mc_reg_table(hwmgr);
4368         PP_ASSERT_WITH_CODE((0 == tmp_result),
4369                 "Failed to populate initialize MC Reg table!", result = tmp_result);
4370
4371         tmp_result = tonga_notify_smc_display_change(hwmgr, false);
4372         PP_ASSERT_WITH_CODE((0 == tmp_result),
4373                 "Failed to notify no display!", result = tmp_result);
4374
4375         /* enable SCLK control */
4376         tmp_result = tonga_enable_sclk_control(hwmgr);
4377         PP_ASSERT_WITH_CODE((0 == tmp_result),
4378                 "Failed to enable SCLK control!", result = tmp_result);
4379
4380         /* enable DPM */
4381         tmp_result = tonga_start_dpm(hwmgr);
4382         PP_ASSERT_WITH_CODE((0 == tmp_result),
4383                 "Failed to start DPM!", result = tmp_result);
4384
4385         return result;
4386 }
4387
4388 int tonga_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
4389 {
4390         int tmp_result, result = 0;
4391
4392         tmp_result = tonga_check_for_dpm_running(hwmgr);
4393         PP_ASSERT_WITH_CODE((0 == tmp_result),
4394                 "SMC is still running!", return 0);
4395
4396         tmp_result = tonga_stop_dpm(hwmgr);
4397         PP_ASSERT_WITH_CODE((0 == tmp_result),
4398                 "Failed to stop DPM!", result = tmp_result);
4399
4400         tmp_result = tonga_reset_to_default(hwmgr);
4401         PP_ASSERT_WITH_CODE((0 == tmp_result),
4402                 "Failed to reset to default!", result = tmp_result);
4403
4404         return result;
4405 }
4406
4407 int tonga_reset_asic_tasks(struct pp_hwmgr *hwmgr)
4408 {
4409         int result;
4410
4411         result = tonga_set_boot_state(hwmgr);
4412         if (0 != result)
4413                 printk(KERN_ERR "[ powerplay ] Failed to reset asic via set boot state! \n");
4414
4415         return result;
4416 }
4417
4418 int tonga_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
4419 {
4420         if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
4421                 kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
4422                 hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
4423         }
4424
4425         if (NULL != hwmgr->backend) {
4426                 kfree(hwmgr->backend);
4427                 hwmgr->backend = NULL;
4428         }
4429
4430         return 0;
4431 }
4432
4433 /**
4434  * Initializes the Volcanic Islands Hardware Manager
4435  *
4436  * @param   hwmgr the address of the powerplay hardware manager.
4437  * @return   1 if success; otherwise appropriate error code.
4438  */
4439 int tonga_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
4440 {
4441         int result = 0;
4442         SMU72_Discrete_DpmTable  *table = NULL;
4443         tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4444         pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
4445         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
4446         phw_tonga_ulv_parm *ulv;
4447
4448         PP_ASSERT_WITH_CODE((NULL != hwmgr),
4449                 "Invalid Parameter!", return -1;);
4450
4451         data->dll_defaule_on = 0;
4452         data->sram_end = SMC_RAM_END;
4453
4454         data->activity_target[0] = PPTONGA_TARGETACTIVITY_DFLT;
4455         data->activity_target[1] = PPTONGA_TARGETACTIVITY_DFLT;
4456         data->activity_target[2] = PPTONGA_TARGETACTIVITY_DFLT;
4457         data->activity_target[3] = PPTONGA_TARGETACTIVITY_DFLT;
4458         data->activity_target[4] = PPTONGA_TARGETACTIVITY_DFLT;
4459         data->activity_target[5] = PPTONGA_TARGETACTIVITY_DFLT;
4460         data->activity_target[6] = PPTONGA_TARGETACTIVITY_DFLT;
4461         data->activity_target[7] = PPTONGA_TARGETACTIVITY_DFLT;
4462
4463         data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
4464         data->vddc_vddgfx_delta = VDDC_VDDGFX_DELTA;
4465         data->mclk_activity_target = PPTONGA_MCLK_TARGETACTIVITY_DFLT;
4466
4467         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
4468                 PHM_PlatformCaps_DisableVoltageIsland);
4469
4470         data->sclk_dpm_key_disabled = 0;
4471         data->mclk_dpm_key_disabled = 0;
4472         data->pcie_dpm_key_disabled = 0;
4473         data->pcc_monitor_enabled = 0;
4474
4475         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
4476                 PHM_PlatformCaps_UnTabledHardwareInterface);
4477
4478         data->gpio_debug = 0;
4479         data->engine_clock_data = 0;
4480         data->memory_clock_data = 0;
4481         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
4482                 PHM_PlatformCaps_DynamicPatchPowerState);
4483
4484         /* need to set voltage control types before EVV patching*/
4485         data->voltage_control = TONGA_VOLTAGE_CONTROL_NONE;
4486         data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_NONE;
4487         data->vdd_gfx_control = TONGA_VOLTAGE_CONTROL_NONE;
4488         data->mvdd_control = TONGA_VOLTAGE_CONTROL_NONE;
4489
4490         if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
4491                                 VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2)) {
4492                 data->voltage_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
4493         }
4494
4495         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4496                         PHM_PlatformCaps_ControlVDDGFX)) {
4497                 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
4498                         VOLTAGE_TYPE_VDDGFX, VOLTAGE_OBJ_SVID2)) {
4499                         data->vdd_gfx_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
4500                 }
4501         }
4502
4503         if (TONGA_VOLTAGE_CONTROL_NONE == data->vdd_gfx_control) {
4504                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
4505                         PHM_PlatformCaps_ControlVDDGFX);
4506         }
4507
4508         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4509                         PHM_PlatformCaps_EnableMVDDControl)) {
4510                 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
4511                                         VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT)) {
4512                         data->mvdd_control = TONGA_VOLTAGE_CONTROL_BY_GPIO;
4513                 }
4514         }
4515
4516         if (TONGA_VOLTAGE_CONTROL_NONE == data->mvdd_control) {
4517                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
4518                         PHM_PlatformCaps_EnableMVDDControl);
4519         }
4520
4521         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4522                         PHM_PlatformCaps_ControlVDDCI)) {
4523                 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
4524                                         VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
4525                         data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_BY_GPIO;
4526                 else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
4527                                                 VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
4528                         data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
4529         }
4530
4531         if (TONGA_VOLTAGE_CONTROL_NONE == data->vdd_ci_control)
4532                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
4533                 PHM_PlatformCaps_ControlVDDCI);
4534
4535         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
4536                 PHM_PlatformCaps_TablelessHardwareInterface);
4537
4538         if (pptable_info->cac_dtp_table->usClockStretchAmount != 0)
4539                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
4540                         PHM_PlatformCaps_ClockStretcher);
4541
4542         /* Initializes DPM default values*/
4543         tonga_initialize_dpm_defaults(hwmgr);
4544
4545         /* Get leakage voltage based on leakage ID.*/
4546         PP_ASSERT_WITH_CODE((0 == tonga_get_evv_voltage(hwmgr)),
4547                 "Get EVV Voltage Failed.  Abort Driver loading!", return -1);
4548
4549         tonga_complete_dependency_tables(hwmgr);
4550
4551         /* Parse pptable data read from VBIOS*/
4552         tonga_set_private_var_based_on_pptale(hwmgr);
4553
4554         /* ULV Support*/
4555         ulv = &(data->ulv);
4556         ulv->ulv_supported = 0;
4557
4558         /* Initalize Dynamic State Adjustment Rule Settings*/
4559         result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
4560         data->uvd_enabled = 0;
4561
4562         table = &(data->smc_state_table);
4563
4564         /*
4565         * if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable,
4566         * Peak Current Control feature is enabled and we should program PCC HW register
4567         */
4568         if (0 == atomctrl_get_pp_assign_pin(hwmgr, VDDC_PCC_GPIO_PINID, &gpio_pin_assignment)) {
4569                 uint32_t temp_reg = cgs_read_ind_register(hwmgr->device,
4570                                                                                 CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL);
4571
4572                 switch (gpio_pin_assignment.uc_gpio_pin_bit_shift) {
4573                 case 0:
4574                         temp_reg = PHM_SET_FIELD(temp_reg,
4575                                 CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x1);
4576                         break;
4577                 case 1:
4578                         temp_reg = PHM_SET_FIELD(temp_reg,
4579                                 CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x2);
4580                         break;
4581                 case 2:
4582                         temp_reg = PHM_SET_FIELD(temp_reg,
4583                                 CNB_PWRMGT_CNTL, GNB_SLOW, 0x1);
4584                         break;
4585                 case 3:
4586                         temp_reg = PHM_SET_FIELD(temp_reg,
4587                                 CNB_PWRMGT_CNTL, FORCE_NB_PS1, 0x1);
4588                         break;
4589                 case 4:
4590                         temp_reg = PHM_SET_FIELD(temp_reg,
4591                                 CNB_PWRMGT_CNTL, DPM_ENABLED, 0x1);
4592                         break;
4593                 default:
4594                         printk(KERN_ERR "[ powerplay ] Failed to setup PCC HW register! \
4595                                 Wrong GPIO assigned for VDDC_PCC_GPIO_PINID! \n");
4596                         break;
4597                 }
4598                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
4599                         ixCNB_PWRMGT_CNTL, temp_reg);
4600         }
4601
4602         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
4603                 PHM_PlatformCaps_EnableSMU7ThermalManagement);
4604         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
4605                 PHM_PlatformCaps_SMU7);
4606
4607         data->vddc_phase_shed_control = 0;
4608
4609         if (0 == result) {
4610                 struct cgs_system_info sys_info = {0};
4611
4612                 data->is_tlu_enabled = 0;
4613                 hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
4614                         TONGA_MAX_HARDWARE_POWERLEVELS;
4615                 hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
4616                 hwmgr->platform_descriptor.minimumClocksReductionPercentage  = 50;
4617
4618                 sys_info.size = sizeof(struct cgs_system_info);
4619                 sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
4620                 result = cgs_query_system_info(hwmgr->device, &sys_info);
4621                 if (result)
4622                         data->pcie_gen_cap = 0x30007;
4623                 else
4624                         data->pcie_gen_cap = (uint32_t)sys_info.value;
4625                 if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
4626                         data->pcie_spc_cap = 20;
4627                 sys_info.size = sizeof(struct cgs_system_info);
4628                 sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
4629                 result = cgs_query_system_info(hwmgr->device, &sys_info);
4630                 if (result)
4631                         data->pcie_lane_cap = 0x2f0000;
4632                 else
4633                         data->pcie_lane_cap = (uint32_t)sys_info.value;
4634         } else {
4635                 /* Ignore return value in here, we are cleaning up a mess. */
4636                 tonga_hwmgr_backend_fini(hwmgr);
4637         }
4638
4639         return result;
4640 }
4641
4642 static int tonga_force_dpm_level(struct pp_hwmgr *hwmgr,
4643                 enum amd_dpm_forced_level level)
4644 {
4645         int ret = 0;
4646
4647         switch (level) {
4648         case AMD_DPM_FORCED_LEVEL_HIGH:
4649                 ret = tonga_force_dpm_highest(hwmgr);
4650                 if (ret)
4651                         return ret;
4652                 break;
4653         case AMD_DPM_FORCED_LEVEL_LOW:
4654                 ret = tonga_force_dpm_lowest(hwmgr);
4655                 if (ret)
4656                         return ret;
4657                 break;
4658         case AMD_DPM_FORCED_LEVEL_AUTO:
4659                 ret = tonga_unforce_dpm_levels(hwmgr);
4660                 if (ret)
4661                         return ret;
4662                 break;
4663         default:
4664                 break;
4665         }
4666
4667         hwmgr->dpm_level = level;
4668         return ret;
4669 }
4670
4671 static int tonga_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
4672                                 struct pp_power_state  *prequest_ps,
4673                         const struct pp_power_state *pcurrent_ps)
4674 {
4675         struct tonga_power_state *tonga_ps =
4676                                 cast_phw_tonga_power_state(&prequest_ps->hardware);
4677
4678         uint32_t sclk;
4679         uint32_t mclk;
4680         struct PP_Clocks minimum_clocks = {0};
4681         bool disable_mclk_switching;
4682         bool disable_mclk_switching_for_frame_lock;
4683         struct cgs_display_info info = {0};
4684         const struct phm_clock_and_voltage_limits *max_limits;
4685         uint32_t i;
4686         tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4687         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
4688
4689         int32_t count;
4690         int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
4691
4692         data->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
4693
4694         PP_ASSERT_WITH_CODE(tonga_ps->performance_level_count == 2,
4695                                  "VI should always have 2 performance levels",
4696                                  );
4697
4698         max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
4699                         &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
4700                         &(hwmgr->dyn_state.max_clock_voltage_on_dc);
4701
4702         if (PP_PowerSource_DC == hwmgr->power_source) {
4703                 for (i = 0; i < tonga_ps->performance_level_count; i++) {
4704                         if (tonga_ps->performance_levels[i].memory_clock > max_limits->mclk)
4705                                 tonga_ps->performance_levels[i].memory_clock = max_limits->mclk;
4706                         if (tonga_ps->performance_levels[i].engine_clock > max_limits->sclk)
4707                                 tonga_ps->performance_levels[i].engine_clock = max_limits->sclk;
4708                 }
4709         }
4710
4711         tonga_ps->vce_clocks.EVCLK = hwmgr->vce_arbiter.evclk;
4712         tonga_ps->vce_clocks.ECCLK = hwmgr->vce_arbiter.ecclk;
4713
4714         tonga_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
4715
4716         cgs_get_active_displays_info(hwmgr->device, &info);
4717
4718         /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4719
4720         /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4721
4722         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) {
4723
4724                 max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
4725                 stable_pstate_sclk = (max_limits->sclk * 75) / 100;
4726
4727                 for (count = pptable_info->vdd_dep_on_sclk->count-1; count >= 0; count--) {
4728                         if (stable_pstate_sclk >= pptable_info->vdd_dep_on_sclk->entries[count].clk) {
4729                                 stable_pstate_sclk = pptable_info->vdd_dep_on_sclk->entries[count].clk;
4730                                 break;
4731                         }
4732                 }
4733
4734                 if (count < 0)
4735                         stable_pstate_sclk = pptable_info->vdd_dep_on_sclk->entries[0].clk;
4736
4737                 stable_pstate_mclk = max_limits->mclk;
4738
4739                 minimum_clocks.engineClock = stable_pstate_sclk;
4740                 minimum_clocks.memoryClock = stable_pstate_mclk;
4741         }
4742
4743         if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
4744                 minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
4745
4746         if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
4747                 minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
4748
4749         tonga_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
4750
4751         if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
4752                 PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.engineClock),
4753                                         "Overdrive sclk exceeds limit",
4754                                         hwmgr->gfx_arbiter.sclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.engineClock);
4755
4756                 if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
4757                         tonga_ps->performance_levels[1].engine_clock = hwmgr->gfx_arbiter.sclk_over_drive;
4758         }
4759
4760         if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
4761                 PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.memoryClock),
4762                         "Overdrive mclk exceeds limit",
4763                         hwmgr->gfx_arbiter.mclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.memoryClock);
4764
4765                 if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
4766                         tonga_ps->performance_levels[1].memory_clock = hwmgr->gfx_arbiter.mclk_over_drive;
4767         }
4768
4769         disable_mclk_switching_for_frame_lock = phm_cap_enabled(
4770                                     hwmgr->platform_descriptor.platformCaps,
4771                                     PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
4772
4773         disable_mclk_switching = (1 < info.display_count) ||
4774                                     disable_mclk_switching_for_frame_lock;
4775
4776         sclk  = tonga_ps->performance_levels[0].engine_clock;
4777         mclk  = tonga_ps->performance_levels[0].memory_clock;
4778
4779         if (disable_mclk_switching)
4780                 mclk  = tonga_ps->performance_levels[tonga_ps->performance_level_count - 1].memory_clock;
4781
4782         if (sclk < minimum_clocks.engineClock)
4783                 sclk = (minimum_clocks.engineClock > max_limits->sclk) ? max_limits->sclk : minimum_clocks.engineClock;
4784
4785         if (mclk < minimum_clocks.memoryClock)
4786                 mclk = (minimum_clocks.memoryClock > max_limits->mclk) ? max_limits->mclk : minimum_clocks.memoryClock;
4787
4788         tonga_ps->performance_levels[0].engine_clock = sclk;
4789         tonga_ps->performance_levels[0].memory_clock = mclk;
4790
4791         tonga_ps->performance_levels[1].engine_clock =
4792                 (tonga_ps->performance_levels[1].engine_clock >= tonga_ps->performance_levels[0].engine_clock) ?
4793                               tonga_ps->performance_levels[1].engine_clock :
4794                               tonga_ps->performance_levels[0].engine_clock;
4795
4796         if (disable_mclk_switching) {
4797                 if (mclk < tonga_ps->performance_levels[1].memory_clock)
4798                         mclk = tonga_ps->performance_levels[1].memory_clock;
4799
4800                 tonga_ps->performance_levels[0].memory_clock = mclk;
4801                 tonga_ps->performance_levels[1].memory_clock = mclk;
4802         } else {
4803                 if (tonga_ps->performance_levels[1].memory_clock < tonga_ps->performance_levels[0].memory_clock)
4804                         tonga_ps->performance_levels[1].memory_clock = tonga_ps->performance_levels[0].memory_clock;
4805         }
4806
4807         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) {
4808                 for (i=0; i < tonga_ps->performance_level_count; i++) {
4809                         tonga_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
4810                         tonga_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
4811                         tonga_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
4812                         tonga_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
4813                 }
4814         }
4815
4816         return 0;
4817 }
4818
4819 int tonga_get_power_state_size(struct pp_hwmgr *hwmgr)
4820 {
4821         return sizeof(struct tonga_power_state);
4822 }
4823
4824 static int tonga_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
4825 {
4826         struct pp_power_state  *ps;
4827         struct tonga_power_state  *tonga_ps;
4828
4829         if (hwmgr == NULL)
4830                 return -EINVAL;
4831
4832         ps = hwmgr->request_ps;
4833
4834         if (ps == NULL)
4835                 return -EINVAL;
4836
4837         tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
4838
4839         if (low)
4840                 return tonga_ps->performance_levels[0].memory_clock;
4841         else
4842                 return tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
4843 }
4844
4845 static int tonga_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
4846 {
4847         struct pp_power_state  *ps;
4848         struct tonga_power_state  *tonga_ps;
4849
4850         if (hwmgr == NULL)
4851                 return -EINVAL;
4852
4853         ps = hwmgr->request_ps;
4854
4855         if (ps == NULL)
4856                 return -EINVAL;
4857
4858         tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
4859
4860         if (low)
4861                 return tonga_ps->performance_levels[0].engine_clock;
4862         else
4863                 return tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
4864 }
4865
4866 static uint16_t tonga_get_current_pcie_speed(
4867                                                    struct pp_hwmgr *hwmgr)
4868 {
4869         uint32_t speed_cntl = 0;
4870
4871         speed_cntl = cgs_read_ind_register(hwmgr->device,
4872                                                    CGS_IND_REG__PCIE,
4873                                                    ixPCIE_LC_SPEED_CNTL);
4874         return((uint16_t)PHM_GET_FIELD(speed_cntl,
4875                         PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
4876 }
4877
4878 static int tonga_get_current_pcie_lane_number(
4879                                                    struct pp_hwmgr *hwmgr)
4880 {
4881         uint32_t link_width;
4882
4883         link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device,
4884                                                         CGS_IND_REG__PCIE,
4885                                                   PCIE_LC_LINK_WIDTH_CNTL,
4886                                                         LC_LINK_WIDTH_RD);
4887
4888         PP_ASSERT_WITH_CODE((7 >= link_width),
4889                         "Invalid PCIe lane width!", return 0);
4890
4891         return decode_pcie_lane_width(link_width);
4892 }
4893
4894 static int tonga_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
4895                                         struct pp_hw_power_state *hw_ps)
4896 {
4897         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4898         struct tonga_power_state *ps = (struct tonga_power_state *)hw_ps;
4899         ATOM_FIRMWARE_INFO_V2_2 *fw_info;
4900         uint16_t size;
4901         uint8_t frev, crev;
4902         int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
4903
4904         /* First retrieve the Boot clocks and VDDC from the firmware info table.
4905          * We assume here that fw_info is unchanged if this call fails.
4906          */
4907         fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
4908                         hwmgr->device, index,
4909                         &size, &frev, &crev);
4910         if (!fw_info)
4911                 /* During a test, there is no firmware info table. */
4912                 return 0;
4913
4914         /* Patch the state. */
4915         data->vbios_boot_state.sclk_bootup_value  = le32_to_cpu(fw_info->ulDefaultEngineClock);
4916         data->vbios_boot_state.mclk_bootup_value  = le32_to_cpu(fw_info->ulDefaultMemoryClock);
4917         data->vbios_boot_state.mvdd_bootup_value  = le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
4918         data->vbios_boot_state.vddc_bootup_value  = le16_to_cpu(fw_info->usBootUpVDDCVoltage);
4919         data->vbios_boot_state.vddci_bootup_value = le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
4920         data->vbios_boot_state.pcie_gen_bootup_value = tonga_get_current_pcie_speed(hwmgr);
4921         data->vbios_boot_state.pcie_lane_bootup_value =
4922                         (uint16_t)tonga_get_current_pcie_lane_number(hwmgr);
4923
4924         /* set boot power state */
4925         ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
4926         ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
4927         ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
4928         ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
4929
4930         return 0;
4931 }
4932
4933 static int tonga_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
4934                 void *state, struct pp_power_state *power_state,
4935                 void *pp_table, uint32_t classification_flag)
4936 {
4937         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
4938
4939         struct tonga_power_state  *tonga_ps =
4940                         (struct tonga_power_state *)(&(power_state->hardware));
4941
4942         struct tonga_performance_level *performance_level;
4943
4944         ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
4945
4946         ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
4947                         (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
4948
4949         ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
4950                         (ATOM_Tonga_SCLK_Dependency_Table *)
4951                         (((unsigned long)powerplay_table) +
4952                         le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
4953
4954         ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
4955                         (ATOM_Tonga_MCLK_Dependency_Table *)
4956                         (((unsigned long)powerplay_table) +
4957                         le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
4958
4959         /* The following fields are not initialized here: id orderedList allStatesList */
4960         power_state->classification.ui_label =
4961                         (le16_to_cpu(state_entry->usClassification) &
4962                         ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
4963                         ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
4964         power_state->classification.flags = classification_flag;
4965         /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
4966
4967         power_state->classification.temporary_state = false;
4968         power_state->classification.to_be_deleted = false;
4969
4970         power_state->validation.disallowOnDC =
4971                         (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) & ATOM_Tonga_DISALLOW_ON_DC));
4972
4973         power_state->pcie.lanes = 0;
4974
4975         power_state->display.disableFrameModulation = false;
4976         power_state->display.limitRefreshrate = false;
4977         power_state->display.enableVariBright =
4978                         (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) & ATOM_Tonga_ENABLE_VARIBRIGHT));
4979
4980         power_state->validation.supportedPowerLevels = 0;
4981         power_state->uvd_clocks.VCLK = 0;
4982         power_state->uvd_clocks.DCLK = 0;
4983         power_state->temperatures.min = 0;
4984         power_state->temperatures.max = 0;
4985
4986         performance_level = &(tonga_ps->performance_levels
4987                         [tonga_ps->performance_level_count++]);
4988
4989         PP_ASSERT_WITH_CODE(
4990                         (tonga_ps->performance_level_count < SMU72_MAX_LEVELS_GRAPHICS),
4991                         "Performance levels exceeds SMC limit!",
4992                         return -1);
4993
4994         PP_ASSERT_WITH_CODE(
4995                         (tonga_ps->performance_level_count <=
4996                                         hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
4997                         "Performance levels exceeds Driver limit!",
4998                         return -1);
4999
5000         /* Performance levels are arranged from low to high. */
5001         performance_level->memory_clock =
5002                                 le32_to_cpu(mclk_dep_table->entries[state_entry->ucMemoryClockIndexLow].ulMclk);
5003
5004         performance_level->engine_clock =
5005                                 le32_to_cpu(sclk_dep_table->entries[state_entry->ucEngineClockIndexLow].ulSclk);
5006
5007         performance_level->pcie_gen = get_pcie_gen_support(
5008                                                         data->pcie_gen_cap,
5009                                              state_entry->ucPCIEGenLow);
5010
5011         performance_level->pcie_lane = get_pcie_lane_support(
5012                                                     data->pcie_lane_cap,
5013                                            state_entry->ucPCIELaneHigh);
5014
5015         performance_level =
5016                         &(tonga_ps->performance_levels[tonga_ps->performance_level_count++]);
5017
5018         performance_level->memory_clock =
5019                                 le32_to_cpu(mclk_dep_table->entries[state_entry->ucMemoryClockIndexHigh].ulMclk);
5020
5021         performance_level->engine_clock =
5022                                 le32_to_cpu(sclk_dep_table->entries[state_entry->ucEngineClockIndexHigh].ulSclk);
5023
5024         performance_level->pcie_gen = get_pcie_gen_support(
5025                                                         data->pcie_gen_cap,
5026                                             state_entry->ucPCIEGenHigh);
5027
5028         performance_level->pcie_lane = get_pcie_lane_support(
5029                                                     data->pcie_lane_cap,
5030                                            state_entry->ucPCIELaneHigh);
5031
5032         return 0;
5033 }
5034
5035 static int tonga_get_pp_table_entry(struct pp_hwmgr *hwmgr,
5036                     unsigned long entry_index, struct pp_power_state *ps)
5037 {
5038         int result;
5039         struct tonga_power_state *tonga_ps;
5040         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5041
5042         struct phm_ppt_v1_information *table_info =
5043                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
5044
5045         struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
5046                                            table_info->vdd_dep_on_mclk;
5047
5048         ps->hardware.magic = PhwTonga_Magic;
5049
5050         tonga_ps = cast_phw_tonga_power_state(&(ps->hardware));
5051
5052         result = tonga_get_powerplay_table_entry(hwmgr, entry_index, ps,
5053                         tonga_get_pp_table_entry_callback_func);
5054
5055         /* This is the earliest time we have all the dependency table and the VBIOS boot state
5056          * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
5057          * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
5058          */
5059         if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
5060                 if (dep_mclk_table->entries[0].clk !=
5061                                 data->vbios_boot_state.mclk_bootup_value)
5062                         printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
5063                                         "does not match VBIOS boot MCLK level");
5064                 if (dep_mclk_table->entries[0].vddci !=
5065                                 data->vbios_boot_state.vddci_bootup_value)
5066                         printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
5067                                         "does not match VBIOS boot VDDCI level");
5068         }
5069
5070         /* set DC compatible flag if this state supports DC */
5071         if (!ps->validation.disallowOnDC)
5072                 tonga_ps->dc_compatible = true;
5073
5074         if (ps->classification.flags & PP_StateClassificationFlag_ACPI)
5075                 data->acpi_pcie_gen = tonga_ps->performance_levels[0].pcie_gen;
5076         else if (ps->classification.flags & PP_StateClassificationFlag_Boot) {
5077                 if (data->bacos.best_match == 0xffff) {
5078                         /* For V.I. use boot state as base BACO state */
5079                         data->bacos.best_match = PP_StateClassificationFlag_Boot;
5080                         data->bacos.performance_level = tonga_ps->performance_levels[0];
5081                 }
5082         }
5083
5084         tonga_ps->uvd_clocks.VCLK = ps->uvd_clocks.VCLK;
5085         tonga_ps->uvd_clocks.DCLK = ps->uvd_clocks.DCLK;
5086
5087         if (!result) {
5088                 uint32_t i;
5089
5090                 switch (ps->classification.ui_label) {
5091                 case PP_StateUILabel_Performance:
5092                         data->use_pcie_performance_levels = true;
5093
5094                         for (i = 0; i < tonga_ps->performance_level_count; i++) {
5095                                 if (data->pcie_gen_performance.max <
5096                                                 tonga_ps->performance_levels[i].pcie_gen)
5097                                         data->pcie_gen_performance.max =
5098                                                         tonga_ps->performance_levels[i].pcie_gen;
5099
5100                                 if (data->pcie_gen_performance.min >
5101                                                 tonga_ps->performance_levels[i].pcie_gen)
5102                                         data->pcie_gen_performance.min =
5103                                                         tonga_ps->performance_levels[i].pcie_gen;
5104
5105                                 if (data->pcie_lane_performance.max <
5106                                                 tonga_ps->performance_levels[i].pcie_lane)
5107                                         data->pcie_lane_performance.max =
5108                                                         tonga_ps->performance_levels[i].pcie_lane;
5109
5110                                 if (data->pcie_lane_performance.min >
5111                                                 tonga_ps->performance_levels[i].pcie_lane)
5112                                         data->pcie_lane_performance.min =
5113                                                         tonga_ps->performance_levels[i].pcie_lane;
5114                         }
5115                         break;
5116                 case PP_StateUILabel_Battery:
5117                         data->use_pcie_power_saving_levels = true;
5118
5119                         for (i = 0; i < tonga_ps->performance_level_count; i++) {
5120                                 if (data->pcie_gen_power_saving.max <
5121                                                 tonga_ps->performance_levels[i].pcie_gen)
5122                                         data->pcie_gen_power_saving.max =
5123                                                         tonga_ps->performance_levels[i].pcie_gen;
5124
5125                                 if (data->pcie_gen_power_saving.min >
5126                                                 tonga_ps->performance_levels[i].pcie_gen)
5127                                         data->pcie_gen_power_saving.min =
5128                                                         tonga_ps->performance_levels[i].pcie_gen;
5129
5130                                 if (data->pcie_lane_power_saving.max <
5131                                                 tonga_ps->performance_levels[i].pcie_lane)
5132                                         data->pcie_lane_power_saving.max =
5133                                                         tonga_ps->performance_levels[i].pcie_lane;
5134
5135                                 if (data->pcie_lane_power_saving.min >
5136                                                 tonga_ps->performance_levels[i].pcie_lane)
5137                                         data->pcie_lane_power_saving.min =
5138                                                         tonga_ps->performance_levels[i].pcie_lane;
5139                         }
5140                         break;
5141                 default:
5142                         break;
5143                 }
5144         }
5145         return 0;
5146 }
5147
5148 static void
5149 tonga_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
5150 {
5151         uint32_t sclk, mclk, active_percent;
5152         uint32_t offset;
5153         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5154
5155         smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetSclkFrequency));
5156
5157         sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5158
5159         smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetMclkFrequency));
5160
5161         mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5162         seq_printf(m, "\n [  mclk  ]: %u MHz\n\n [  sclk  ]: %u MHz\n", mclk/100, sclk/100);
5163
5164
5165         offset = data->soft_regs_start + offsetof(SMU72_SoftRegisters, AverageGraphicsActivity);
5166         active_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
5167         active_percent += 80;
5168         active_percent >>= 8;
5169
5170         seq_printf(m, "\n [GPU load]: %u%%\n\n", active_percent > 100 ? 100 : active_percent);
5171
5172 }
5173
5174 static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
5175 {
5176         const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
5177         const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
5178         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5179         struct tonga_single_dpm_table *psclk_table = &(data->dpm_table.sclk_table);
5180         uint32_t sclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
5181         struct tonga_single_dpm_table *pmclk_table = &(data->dpm_table.mclk_table);
5182         uint32_t mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
5183         struct PP_Clocks min_clocks = {0};
5184         uint32_t i;
5185         struct cgs_display_info info = {0};
5186
5187         data->need_update_smu7_dpm_table = 0;
5188
5189         for (i = 0; i < psclk_table->count; i++) {
5190                 if (sclk == psclk_table->dpm_levels[i].value)
5191                         break;
5192         }
5193
5194         if (i >= psclk_table->count)
5195                 data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
5196         else {
5197         /* TODO: Check SCLK in DAL's minimum clocks in case DeepSleep divider update is required.*/
5198                 if(data->display_timing.min_clock_insr != min_clocks.engineClockInSR)
5199                         data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
5200         }
5201
5202         for (i=0; i < pmclk_table->count; i++) {
5203                 if (mclk == pmclk_table->dpm_levels[i].value)
5204                         break;
5205         }
5206
5207         if (i >= pmclk_table->count)
5208                 data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
5209
5210         cgs_get_active_displays_info(hwmgr->device, &info);
5211
5212         if (data->display_timing.num_existing_displays != info.display_count)
5213                 data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
5214
5215         return 0;
5216 }
5217
5218 static uint16_t tonga_get_maximum_link_speed(struct pp_hwmgr *hwmgr, const struct tonga_power_state *hw_ps)
5219 {
5220         uint32_t i;
5221         uint32_t sclk, max_sclk = 0;
5222         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5223         struct tonga_dpm_table *pdpm_table = &data->dpm_table;
5224
5225         for (i = 0; i < hw_ps->performance_level_count; i++) {
5226                 sclk = hw_ps->performance_levels[i].engine_clock;
5227                 if (max_sclk < sclk)
5228                         max_sclk = sclk;
5229         }
5230
5231         for (i = 0; i < pdpm_table->sclk_table.count; i++) {
5232                 if (pdpm_table->sclk_table.dpm_levels[i].value == max_sclk)
5233                         return (uint16_t) ((i >= pdpm_table->pcie_speed_table.count) ?
5234                                         pdpm_table->pcie_speed_table.dpm_levels[pdpm_table->pcie_speed_table.count-1].value :
5235                                         pdpm_table->pcie_speed_table.dpm_levels[i].value);
5236         }
5237
5238         return 0;
5239 }
5240
5241 static int tonga_request_link_speed_change_before_state_change(struct pp_hwmgr *hwmgr, const void *input)
5242 {
5243         const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
5244         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5245         const struct tonga_power_state *tonga_nps = cast_const_phw_tonga_power_state(states->pnew_state);
5246         const struct tonga_power_state *tonga_cps = cast_const_phw_tonga_power_state(states->pcurrent_state);
5247
5248         uint16_t target_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_nps);
5249         uint16_t current_link_speed;
5250
5251         if (data->force_pcie_gen == PP_PCIEGenInvalid)
5252                 current_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_cps);
5253         else
5254                 current_link_speed = data->force_pcie_gen;
5255
5256         data->force_pcie_gen = PP_PCIEGenInvalid;
5257         data->pspp_notify_required = false;
5258         if (target_link_speed > current_link_speed) {
5259                 switch(target_link_speed) {
5260                 case PP_PCIEGen3:
5261                         if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
5262                                 break;
5263                         data->force_pcie_gen = PP_PCIEGen2;
5264                         if (current_link_speed == PP_PCIEGen2)
5265                                 break;
5266                 case PP_PCIEGen2:
5267                         if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
5268                                 break;
5269                 default:
5270                         data->force_pcie_gen = tonga_get_current_pcie_speed(hwmgr);
5271                         break;
5272                 }
5273         } else {
5274                 if (target_link_speed < current_link_speed)
5275                         data->pspp_notify_required = true;
5276         }
5277
5278         return 0;
5279 }
5280
5281 static int tonga_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
5282 {
5283         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5284
5285         if (0 == data->need_update_smu7_dpm_table)
5286                 return 0;
5287
5288         if ((0 == data->sclk_dpm_key_disabled) &&
5289                 (data->need_update_smu7_dpm_table &
5290                 (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
5291                 PP_ASSERT_WITH_CODE(
5292                         true == tonga_is_dpm_running(hwmgr),
5293                         "Trying to freeze SCLK DPM when DPM is disabled",
5294                         );
5295                 PP_ASSERT_WITH_CODE(
5296                         0 == smum_send_msg_to_smc(hwmgr->smumgr,
5297                                           PPSMC_MSG_SCLKDPM_FreezeLevel),
5298                         "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
5299                         return -1);
5300         }
5301
5302         if ((0 == data->mclk_dpm_key_disabled) &&
5303                 (data->need_update_smu7_dpm_table &
5304                  DPMTABLE_OD_UPDATE_MCLK)) {
5305                 PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr),
5306                         "Trying to freeze MCLK DPM when DPM is disabled",
5307                         );
5308                 PP_ASSERT_WITH_CODE(
5309                         0 == smum_send_msg_to_smc(hwmgr->smumgr,
5310                                                         PPSMC_MSG_MCLKDPM_FreezeLevel),
5311                         "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
5312                         return -1);
5313         }
5314
5315         return 0;
5316 }
5317
5318 static int tonga_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr *hwmgr, const void *input)
5319 {
5320         int result = 0;
5321
5322         const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
5323         const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
5324         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5325         uint32_t sclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
5326         uint32_t mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
5327         struct tonga_dpm_table *pdpm_table = &data->dpm_table;
5328
5329         struct tonga_dpm_table *pgolden_dpm_table = &data->golden_dpm_table;
5330         uint32_t dpm_count, clock_percent;
5331         uint32_t i;
5332
5333         if (0 == data->need_update_smu7_dpm_table)
5334                 return 0;
5335
5336         if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
5337                 pdpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value = sclk;
5338
5339                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
5340                     phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
5341                 /* Need to do calculation based on the golden DPM table
5342                  * as the Heatmap GPU Clock axis is also based on the default values
5343                  */
5344                         PP_ASSERT_WITH_CODE(
5345                                 (pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value != 0),
5346                                 "Divide by 0!",
5347                                 return -1);
5348                         dpm_count = pdpm_table->sclk_table.count < 2 ? 0 : pdpm_table->sclk_table.count-2;
5349                         for (i = dpm_count; i > 1; i--) {
5350                                 if (sclk > pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value) {
5351                                         clock_percent = ((sclk - pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value)*100) /
5352                                                         pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value;
5353
5354                                         pdpm_table->sclk_table.dpm_levels[i].value =
5355                                                         pgolden_dpm_table->sclk_table.dpm_levels[i].value +
5356                                                         (pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100;
5357
5358                                 } else if (pgolden_dpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value > sclk) {
5359                                         clock_percent = ((pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value - sclk)*100) /
5360                                                                 pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value;
5361
5362                                         pdpm_table->sclk_table.dpm_levels[i].value =
5363                                                         pgolden_dpm_table->sclk_table.dpm_levels[i].value -
5364                                                         (pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100;
5365                                 } else
5366                                         pdpm_table->sclk_table.dpm_levels[i].value =
5367                                                         pgolden_dpm_table->sclk_table.dpm_levels[i].value;
5368                         }
5369                 }
5370         }
5371
5372         if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
5373                 pdpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value = mclk;
5374
5375                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
5376                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
5377
5378                         PP_ASSERT_WITH_CODE(
5379                                         (pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value != 0),
5380                                         "Divide by 0!",
5381                                         return -1);
5382                         dpm_count = pdpm_table->mclk_table.count < 2? 0 : pdpm_table->mclk_table.count-2;
5383                         for (i = dpm_count; i > 1; i--) {
5384                                 if (mclk > pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value) {
5385                                                 clock_percent = ((mclk - pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value)*100) /
5386                                                                     pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value;
5387
5388                                                 pdpm_table->mclk_table.dpm_levels[i].value =
5389                                                                                 pgolden_dpm_table->mclk_table.dpm_levels[i].value +
5390                                                                                 (pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100;
5391
5392                                 } else if (pgolden_dpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value > mclk) {
5393                                                 clock_percent = ((pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value - mclk)*100) /
5394                                                                     pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value;
5395
5396                                                 pdpm_table->mclk_table.dpm_levels[i].value =
5397                                                                         pgolden_dpm_table->mclk_table.dpm_levels[i].value -
5398                                                                         (pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100;
5399                                 } else
5400                                         pdpm_table->mclk_table.dpm_levels[i].value = pgolden_dpm_table->mclk_table.dpm_levels[i].value;
5401                         }
5402                 }
5403         }
5404
5405         if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
5406                 result = tonga_populate_all_memory_levels(hwmgr);
5407                 PP_ASSERT_WITH_CODE((0 == result),
5408                         "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
5409                         return result);
5410         }
5411
5412         if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
5413                 /*populate MCLK dpm table to SMU7 */
5414                 result = tonga_populate_all_memory_levels(hwmgr);
5415                 PP_ASSERT_WITH_CODE((0 == result),
5416                                 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
5417                                 return result);
5418         }
5419
5420         return result;
5421 }
5422
5423 static  int tonga_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
5424                           struct tonga_single_dpm_table * pdpm_table,
5425                              uint32_t low_limit, uint32_t high_limit)
5426 {
5427         uint32_t i;
5428
5429         for (i = 0; i < pdpm_table->count; i++) {
5430                 if ((pdpm_table->dpm_levels[i].value < low_limit) ||
5431                     (pdpm_table->dpm_levels[i].value > high_limit))
5432                         pdpm_table->dpm_levels[i].enabled = false;
5433                 else
5434                         pdpm_table->dpm_levels[i].enabled = true;
5435         }
5436         return 0;
5437 }
5438
5439 static int tonga_trim_dpm_states(struct pp_hwmgr *hwmgr, const struct tonga_power_state *hw_state)
5440 {
5441         int result = 0;
5442         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5443         uint32_t high_limit_count;
5444
5445         PP_ASSERT_WITH_CODE((hw_state->performance_level_count >= 1),
5446                                 "power state did not have any performance level",
5447                                  return -1);
5448
5449         high_limit_count = (1 == hw_state->performance_level_count) ? 0: 1;
5450
5451         tonga_trim_single_dpm_states(hwmgr,
5452                                         &(data->dpm_table.sclk_table),
5453                                         hw_state->performance_levels[0].engine_clock,
5454                                         hw_state->performance_levels[high_limit_count].engine_clock);
5455
5456         tonga_trim_single_dpm_states(hwmgr,
5457                                                 &(data->dpm_table.mclk_table),
5458                                                 hw_state->performance_levels[0].memory_clock,
5459                                                 hw_state->performance_levels[high_limit_count].memory_clock);
5460
5461         return result;
5462 }
5463
5464 static int tonga_generate_dpm_level_enable_mask(struct pp_hwmgr *hwmgr, const void *input)
5465 {
5466         int result;
5467         const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
5468         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5469         const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
5470
5471
5472         result = tonga_trim_dpm_states(hwmgr, tonga_ps);
5473         if (0 != result)
5474                 return result;
5475
5476         data->dpm_level_enable_mask.sclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
5477         data->dpm_level_enable_mask.mclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
5478         data->last_mclk_dpm_enable_mask = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
5479         if (data->uvd_enabled)
5480                 data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
5481
5482         data->dpm_level_enable_mask.pcie_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
5483
5484         return 0;
5485 }
5486
5487 int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
5488 {
5489         return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
5490                                   (PPSMC_Msg)PPSMC_MSG_VCEDPM_Enable :
5491                                   (PPSMC_Msg)PPSMC_MSG_VCEDPM_Disable);
5492 }
5493
5494 int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
5495 {
5496         return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
5497                                   (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
5498                                   (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
5499 }
5500
5501 int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
5502 {
5503         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5504         uint32_t mm_boot_level_offset, mm_boot_level_value;
5505         struct phm_ppt_v1_information *ptable_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
5506
5507         if (!bgate) {
5508                 data->smc_state_table.UvdBootLevel = (uint8_t) (ptable_information->mm_dep_table->count - 1);
5509                 mm_boot_level_offset = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
5510                 mm_boot_level_offset /= 4;
5511                 mm_boot_level_offset *= 4;
5512                 mm_boot_level_value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset);
5513                 mm_boot_level_value &= 0x00FFFFFF;
5514                 mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
5515                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
5516
5517                 if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDDPM) ||
5518                     phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
5519                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5520                                                 PPSMC_MSG_UVDDPM_SetEnabledMask,
5521                                                 (uint32_t)(1 << data->smc_state_table.UvdBootLevel));
5522         }
5523
5524         return tonga_enable_disable_uvd_dpm(hwmgr, !bgate);
5525 }
5526
5527 int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
5528 {
5529         const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
5530         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5531         const struct tonga_power_state *tonga_nps = cast_const_phw_tonga_power_state(states->pnew_state);
5532         const struct tonga_power_state *tonga_cps = cast_const_phw_tonga_power_state(states->pcurrent_state);
5533
5534         uint32_t mm_boot_level_offset, mm_boot_level_value;
5535         struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
5536
5537         if (tonga_nps->vce_clocks.EVCLK > 0 && (tonga_cps == NULL || tonga_cps->vce_clocks.EVCLK == 0)) {
5538                 data->smc_state_table.VceBootLevel = (uint8_t) (pptable_info->mm_dep_table->count - 1);
5539
5540                 mm_boot_level_offset = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
5541                 mm_boot_level_offset /= 4;
5542                 mm_boot_level_offset *= 4;
5543                 mm_boot_level_value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset);
5544                 mm_boot_level_value &= 0xFF00FFFF;
5545                 mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
5546                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
5547
5548                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
5549                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5550                                         PPSMC_MSG_VCEDPM_SetEnabledMask,
5551                                 (uint32_t)(1 << data->smc_state_table.VceBootLevel));
5552
5553                 tonga_enable_disable_vce_dpm(hwmgr, true);
5554         } else if (tonga_nps->vce_clocks.EVCLK == 0 && tonga_cps != NULL && tonga_cps->vce_clocks.EVCLK > 0)
5555                 tonga_enable_disable_vce_dpm(hwmgr, false);
5556
5557         return 0;
5558 }
5559
5560 static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
5561 {
5562         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5563
5564         uint32_t address;
5565         int32_t result;
5566
5567         if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
5568                 return 0;
5569
5570
5571         memset(&data->mc_reg_table, 0, sizeof(SMU72_Discrete_MCRegisters));
5572
5573         result = tonga_convert_mc_reg_table_to_smc(hwmgr, &(data->mc_reg_table));
5574
5575         if(result != 0)
5576                 return result;
5577
5578
5579         address = data->mc_reg_table_start + (uint32_t)offsetof(SMU72_Discrete_MCRegisters, data[0]);
5580
5581         return  tonga_copy_bytes_to_smc(hwmgr->smumgr, address,
5582                                  (uint8_t *)&data->mc_reg_table.data[0],
5583                                 sizeof(SMU72_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
5584                                 data->sram_end);
5585 }
5586
5587 static int tonga_program_memory_timing_parameters_conditionally(struct pp_hwmgr *hwmgr)
5588 {
5589         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5590
5591         if (data->need_update_smu7_dpm_table &
5592                 (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
5593                 return tonga_program_memory_timing_parameters(hwmgr);
5594
5595         return 0;
5596 }
5597
5598 static int tonga_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
5599 {
5600         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5601
5602         if (0 == data->need_update_smu7_dpm_table)
5603                 return 0;
5604
5605         if ((0 == data->sclk_dpm_key_disabled) &&
5606                 (data->need_update_smu7_dpm_table &
5607                 (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
5608
5609                 PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr),
5610                         "Trying to Unfreeze SCLK DPM when DPM is disabled",
5611                         );
5612                 PP_ASSERT_WITH_CODE(
5613                          0 == smum_send_msg_to_smc(hwmgr->smumgr,
5614                                          PPSMC_MSG_SCLKDPM_UnfreezeLevel),
5615                         "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
5616                         return -1);
5617         }
5618
5619         if ((0 == data->mclk_dpm_key_disabled) &&
5620                 (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
5621
5622                 PP_ASSERT_WITH_CODE(
5623                                 true == tonga_is_dpm_running(hwmgr),
5624                                 "Trying to Unfreeze MCLK DPM when DPM is disabled",
5625                                 );
5626                 PP_ASSERT_WITH_CODE(
5627                          0 == smum_send_msg_to_smc(hwmgr->smumgr,
5628                                          PPSMC_MSG_SCLKDPM_UnfreezeLevel),
5629                     "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
5630                     return -1);
5631         }
5632
5633         data->need_update_smu7_dpm_table = 0;
5634
5635         return 0;
5636 }
5637
5638 static int tonga_notify_link_speed_change_after_state_change(struct pp_hwmgr *hwmgr, const void *input)
5639 {
5640         const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
5641         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5642         const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
5643         uint16_t target_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_ps);
5644         uint8_t  request;
5645
5646         if (data->pspp_notify_required  ||
5647             data->pcie_performance_request) {
5648                 if (target_link_speed == PP_PCIEGen3)
5649                         request = PCIE_PERF_REQ_GEN3;
5650                 else if (target_link_speed == PP_PCIEGen2)
5651                         request = PCIE_PERF_REQ_GEN2;
5652                 else
5653                         request = PCIE_PERF_REQ_GEN1;
5654
5655                 if(request == PCIE_PERF_REQ_GEN1 && tonga_get_current_pcie_speed(hwmgr) > 0) {
5656                         data->pcie_performance_request = false;
5657                         return 0;
5658                 }
5659
5660                 if (0 != acpi_pcie_perf_request(hwmgr->device, request, false)) {
5661                         if (PP_PCIEGen2 == target_link_speed)
5662                                 printk("PSPP request to switch to Gen2 from Gen3 Failed!");
5663                         else
5664                                 printk("PSPP request to switch to Gen1 from Gen2 Failed!");
5665                 }
5666         }
5667
5668         data->pcie_performance_request = false;
5669         return 0;
5670 }
5671
5672 static int tonga_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
5673 {
5674         int tmp_result, result = 0;
5675
5676         tmp_result = tonga_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
5677         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to find DPM states clocks in DPM table!", result = tmp_result);
5678
5679         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) {
5680                 tmp_result = tonga_request_link_speed_change_before_state_change(hwmgr, input);
5681                 PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to request link speed change before state change!", result = tmp_result);
5682         }
5683
5684         tmp_result = tonga_freeze_sclk_mclk_dpm(hwmgr);
5685         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
5686
5687         tmp_result = tonga_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
5688         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to populate and upload SCLK MCLK DPM levels!", result = tmp_result);
5689
5690         tmp_result = tonga_generate_dpm_level_enable_mask(hwmgr, input);
5691         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to generate DPM level enabled mask!", result = tmp_result);
5692
5693         tmp_result = tonga_update_vce_dpm(hwmgr, input);
5694         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update VCE DPM!", result = tmp_result);
5695
5696         tmp_result = tonga_update_sclk_threshold(hwmgr);
5697         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update SCLK threshold!", result = tmp_result);
5698
5699         tmp_result = tonga_update_and_upload_mc_reg_table(hwmgr);
5700         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload MC reg table!", result = tmp_result);
5701
5702         tmp_result = tonga_program_memory_timing_parameters_conditionally(hwmgr);
5703         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to program memory timing parameters!", result = tmp_result);
5704
5705         tmp_result = tonga_unfreeze_sclk_mclk_dpm(hwmgr);
5706         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to unfreeze SCLK MCLK DPM!", result = tmp_result);
5707
5708         tmp_result = tonga_upload_dpm_level_enable_mask(hwmgr);
5709         PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload DPM level enabled mask!", result = tmp_result);
5710
5711         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) {
5712                 tmp_result = tonga_notify_link_speed_change_after_state_change(hwmgr, input);
5713                 PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to notify link speed change after state change!", result = tmp_result);
5714         }
5715
5716         return result;
5717 }
5718
5719 /**
5720 *  Set maximum target operating fan output PWM
5721 *
5722 * @param    pHwMgr:  the address of the powerplay hardware manager.
5723 * @param    usMaxFanPwm:  max operating fan PWM in percents
5724 * @return   The response that came from the SMC.
5725 */
5726 static int tonga_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
5727 {
5728         hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
5729
5730         if (phm_is_hw_access_blocked(hwmgr))
5731                 return 0;
5732
5733     return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm) ? 0 : -EINVAL);
5734 }
5735
5736 int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
5737 {
5738         uint32_t num_active_displays = 0;
5739         struct cgs_display_info info = {0};
5740         info.mode_info = NULL;
5741
5742         cgs_get_active_displays_info(hwmgr->device, &info);
5743
5744         num_active_displays = info.display_count;
5745
5746         if (num_active_displays > 1)  /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
5747                 tonga_notify_smc_display_change(hwmgr, false);
5748         else
5749                 tonga_notify_smc_display_change(hwmgr, true);
5750
5751         return 0;
5752 }
5753
5754 /**
5755 * Programs the display gap
5756 *
5757 * @param    hwmgr  the address of the powerplay hardware manager.
5758 * @return   always OK
5759 */
5760 int tonga_program_display_gap(struct pp_hwmgr *hwmgr)
5761 {
5762         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5763         uint32_t num_active_displays = 0;
5764         uint32_t display_gap = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
5765         uint32_t display_gap2;
5766         uint32_t pre_vbi_time_in_us;
5767         uint32_t frame_time_in_us;
5768         uint32_t ref_clock;
5769         uint32_t refresh_rate = 0;
5770         struct cgs_display_info info = {0};
5771         struct cgs_mode_info mode_info;
5772
5773         info.mode_info = &mode_info;
5774
5775         cgs_get_active_displays_info(hwmgr->device, &info);
5776         num_active_displays = info.display_count;
5777
5778         display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, DISP_GAP, (num_active_displays > 0)? DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
5779         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL, display_gap);
5780
5781         ref_clock = mode_info.ref_clock;
5782         refresh_rate = mode_info.refresh_rate;
5783
5784         if(0 == refresh_rate)
5785                 refresh_rate = 60;
5786
5787         frame_time_in_us = 1000000 / refresh_rate;
5788
5789         pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
5790         display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
5791
5792         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2);
5793
5794         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU72_SoftRegisters, PreVBlankGap), 0x64);
5795
5796         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU72_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
5797
5798         if (num_active_displays == 1)
5799                 tonga_notify_smc_display_change(hwmgr, true);
5800
5801         return 0;
5802 }
5803
5804 int tonga_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
5805 {
5806
5807         tonga_program_display_gap(hwmgr);
5808
5809         /* to do PhwTonga_CacUpdateDisplayConfiguration(pHwMgr); */
5810         return 0;
5811 }
5812
5813 /**
5814 *  Set maximum target operating fan output RPM
5815 *
5816 * @param    pHwMgr:  the address of the powerplay hardware manager.
5817 * @param    usMaxFanRpm:  max operating fan RPM value.
5818 * @return   The response that came from the SMC.
5819 */
5820 static int tonga_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
5821 {
5822         hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM = us_max_fan_pwm;
5823
5824         if (phm_is_hw_access_blocked(hwmgr))
5825                 return 0;
5826
5827         return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanRpmMax, us_max_fan_pwm) ? 0 : -EINVAL);
5828 }
5829
5830 uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr)
5831 {
5832         uint32_t reference_clock;
5833         uint32_t tc;
5834         uint32_t divide;
5835
5836         ATOM_FIRMWARE_INFO *fw_info;
5837         uint16_t size;
5838         uint8_t frev, crev;
5839         int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
5840
5841         tc = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK);
5842
5843         if (tc)
5844                 return TCLK;
5845
5846         fw_info = (ATOM_FIRMWARE_INFO *)cgs_atom_get_data_table(hwmgr->device, index,
5847                                                   &size, &frev, &crev);
5848
5849         if (!fw_info)
5850                 return 0;
5851
5852         reference_clock = le16_to_cpu(fw_info->usMinPixelClockPLL_Output);
5853
5854         divide = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL, XTALIN_DIVIDE);
5855
5856         if (0 != divide)
5857                 return reference_clock / 4;
5858
5859         return reference_clock;
5860 }
5861
5862 int tonga_dpm_set_interrupt_state(void *private_data,
5863                                          unsigned src_id, unsigned type,
5864                                          int enabled)
5865 {
5866         uint32_t cg_thermal_int;
5867         struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
5868
5869         if (hwmgr == NULL)
5870                 return -EINVAL;
5871
5872         switch (type) {
5873         case AMD_THERMAL_IRQ_LOW_TO_HIGH:
5874                 if (enabled) {
5875                         cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5876                         cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
5877                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5878                 } else {
5879                         cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5880                         cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
5881                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5882                 }
5883                 break;
5884
5885         case AMD_THERMAL_IRQ_HIGH_TO_LOW:
5886                 if (enabled) {
5887                         cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5888                         cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
5889                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5890                 } else {
5891                         cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5892                         cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
5893                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5894                 }
5895                 break;
5896         default:
5897                 break;
5898         }
5899         return 0;
5900 }
5901
5902 int tonga_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
5903                                         const void *thermal_interrupt_info)
5904 {
5905         int result;
5906         const struct pp_interrupt_registration_info *info =
5907                         (const struct pp_interrupt_registration_info *)thermal_interrupt_info;
5908
5909         if (info == NULL)
5910                 return -EINVAL;
5911
5912         result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
5913                                 tonga_dpm_set_interrupt_state,
5914                                 info->call_back, info->context);
5915
5916         if (result)
5917                 return -EINVAL;
5918
5919         result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
5920                                 tonga_dpm_set_interrupt_state,
5921                                 info->call_back, info->context);
5922
5923         if (result)
5924                 return -EINVAL;
5925
5926         return 0;
5927 }
5928
5929 bool tonga_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
5930 {
5931         struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
5932         bool is_update_required = false;
5933         struct cgs_display_info info = {0,0,NULL};
5934
5935         cgs_get_active_displays_info(hwmgr->device, &info);
5936
5937         if (data->display_timing.num_existing_displays != info.display_count)
5938                 is_update_required = true;
5939 /* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL
5940         if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
5941                 cgs_get_min_clock_settings(hwmgr->device, &min_clocks);
5942                 if(min_clocks.engineClockInSR != data->display_timing.minClockInSR)
5943                         is_update_required = true;
5944 */
5945         return is_update_required;
5946 }
5947
5948 static inline bool tonga_are_power_levels_equal(const struct tonga_performance_level *pl1,
5949                                                            const struct tonga_performance_level *pl2)
5950 {
5951         return ((pl1->memory_clock == pl2->memory_clock) &&
5952                   (pl1->engine_clock == pl2->engine_clock) &&
5953                   (pl1->pcie_gen == pl2->pcie_gen) &&
5954                   (pl1->pcie_lane == pl2->pcie_lane));
5955 }
5956
5957 int tonga_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
5958 {
5959         const struct tonga_power_state *psa = cast_const_phw_tonga_power_state(pstate1);
5960         const struct tonga_power_state *psb = cast_const_phw_tonga_power_state(pstate2);
5961         int i;
5962
5963         if (pstate1 == NULL || pstate2 == NULL || equal == NULL)
5964                 return -EINVAL;
5965
5966         /* If the two states don't even have the same number of performance levels they cannot be the same state. */
5967         if (psa->performance_level_count != psb->performance_level_count) {
5968                 *equal = false;
5969                 return 0;
5970         }
5971
5972         for (i = 0; i < psa->performance_level_count; i++) {
5973                 if (!tonga_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
5974                         /* If we have found even one performance level pair that is different the states are different. */
5975                         *equal = false;
5976                         return 0;
5977                 }
5978         }
5979
5980         /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
5981         *equal = ((psa->uvd_clocks.VCLK == psb->uvd_clocks.VCLK) && (psa->uvd_clocks.DCLK == psb->uvd_clocks.DCLK));
5982         *equal &= ((psa->vce_clocks.EVCLK == psb->vce_clocks.EVCLK) && (psa->vce_clocks.ECCLK == psb->vce_clocks.ECCLK));
5983         *equal &= (psa->sclk_threshold == psb->sclk_threshold);
5984         *equal &= (psa->acp_clk == psb->acp_clk);
5985
5986         return 0;
5987 }
5988
5989 static int tonga_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
5990 {
5991         if (mode) {
5992                 /* stop auto-manage */
5993                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
5994                                 PHM_PlatformCaps_MicrocodeFanControl))
5995                         tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
5996                 tonga_fan_ctrl_set_static_mode(hwmgr, mode);
5997         } else
5998                 /* restart auto-manage */
5999                 tonga_fan_ctrl_reset_fan_speed_to_default(hwmgr);
6000
6001         return 0;
6002 }
6003
6004 static int tonga_get_fan_control_mode(struct pp_hwmgr *hwmgr)
6005 {
6006         if (hwmgr->fan_ctrl_is_in_default_mode)
6007                 return hwmgr->fan_ctrl_default_mode;
6008         else
6009                 return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
6010                                 CG_FDO_CTRL2, FDO_PWM_MODE);
6011 }
6012
6013 static const struct pp_hwmgr_func tonga_hwmgr_funcs = {
6014         .backend_init = &tonga_hwmgr_backend_init,
6015         .backend_fini = &tonga_hwmgr_backend_fini,
6016         .asic_setup = &tonga_setup_asic_task,
6017         .dynamic_state_management_enable = &tonga_enable_dpm_tasks,
6018         .apply_state_adjust_rules = tonga_apply_state_adjust_rules,
6019         .force_dpm_level = &tonga_force_dpm_level,
6020         .power_state_set = tonga_set_power_state_tasks,
6021         .get_power_state_size = tonga_get_power_state_size,
6022         .get_mclk = tonga_dpm_get_mclk,
6023         .get_sclk = tonga_dpm_get_sclk,
6024         .patch_boot_state = tonga_dpm_patch_boot_state,
6025         .get_pp_table_entry = tonga_get_pp_table_entry,
6026         .get_num_of_pp_table_entries = tonga_get_number_of_powerplay_table_entries,
6027         .print_current_perforce_level = tonga_print_current_perforce_level,
6028         .powerdown_uvd = tonga_phm_powerdown_uvd,
6029         .powergate_uvd = tonga_phm_powergate_uvd,
6030         .powergate_vce = tonga_phm_powergate_vce,
6031         .disable_clock_power_gating = tonga_phm_disable_clock_power_gating,
6032         .notify_smc_display_config_after_ps_adjustment = tonga_notify_smc_display_config_after_ps_adjustment,
6033         .display_config_changed = tonga_display_configuration_changed_task,
6034         .set_max_fan_pwm_output = tonga_set_max_fan_pwm_output,
6035         .set_max_fan_rpm_output = tonga_set_max_fan_rpm_output,
6036         .get_temperature = tonga_thermal_get_temperature,
6037         .stop_thermal_controller = tonga_thermal_stop_thermal_controller,
6038         .get_fan_speed_info = tonga_fan_ctrl_get_fan_speed_info,
6039         .get_fan_speed_percent = tonga_fan_ctrl_get_fan_speed_percent,
6040         .set_fan_speed_percent = tonga_fan_ctrl_set_fan_speed_percent,
6041         .reset_fan_speed_to_default = tonga_fan_ctrl_reset_fan_speed_to_default,
6042         .get_fan_speed_rpm = tonga_fan_ctrl_get_fan_speed_rpm,
6043         .set_fan_speed_rpm = tonga_fan_ctrl_set_fan_speed_rpm,
6044         .uninitialize_thermal_controller = tonga_thermal_ctrl_uninitialize_thermal_controller,
6045         .register_internal_thermal_interrupt = tonga_register_internal_thermal_interrupt,
6046         .check_smc_update_required_for_display_configuration = tonga_check_smc_update_required_for_display_configuration,
6047         .check_states_equal = tonga_check_states_equal,
6048         .set_fan_control_mode = tonga_set_fan_control_mode,
6049         .get_fan_control_mode = tonga_get_fan_control_mode,
6050 };
6051
6052 int tonga_hwmgr_init(struct pp_hwmgr *hwmgr)
6053 {
6054         tonga_hwmgr  *data;
6055
6056         data = kzalloc (sizeof(tonga_hwmgr), GFP_KERNEL);
6057         if (data == NULL)
6058                 return -ENOMEM;
6059         memset(data, 0x00, sizeof(tonga_hwmgr));
6060
6061         hwmgr->backend = data;
6062         hwmgr->hwmgr_func = &tonga_hwmgr_funcs;
6063         hwmgr->pptable_func = &tonga_pptable_funcs;
6064         pp_tonga_thermal_initialize(hwmgr);
6065         return 0;
6066 }
6067