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