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