drm/amd/powerplay/fiji: mark symbols static where possible
[cascardo/linux.git] / drivers / gpu / drm / amd / powerplay / hwmgr / fiji_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
28 #include "hwmgr.h"
29 #include "fiji_smumgr.h"
30 #include "atombios.h"
31 #include "hardwaremanager.h"
32 #include "ppatomctrl.h"
33 #include "atombios.h"
34 #include "cgs_common.h"
35 #include "fiji_dyn_defaults.h"
36 #include "fiji_powertune.h"
37 #include "smu73.h"
38 #include "smu/smu_7_1_3_d.h"
39 #include "smu/smu_7_1_3_sh_mask.h"
40 #include "gmc/gmc_8_1_d.h"
41 #include "gmc/gmc_8_1_sh_mask.h"
42 #include "bif/bif_5_0_d.h"
43 #include "bif/bif_5_0_sh_mask.h"
44 #include "dce/dce_10_0_d.h"
45 #include "dce/dce_10_0_sh_mask.h"
46 #include "pppcielanes.h"
47 #include "fiji_hwmgr.h"
48 #include "tonga_processpptables.h"
49 #include "tonga_pptable.h"
50 #include "pp_debug.h"
51 #include "pp_acpi.h"
52 #include "amd_pcie_helpers.h"
53 #include "cgs_linux.h"
54 #include "ppinterrupt.h"
55
56 #include "fiji_clockpowergating.h"
57 #include "fiji_thermal.h"
58
59 #define VOLTAGE_SCALE   4
60 #define SMC_RAM_END             0x40000
61 #define VDDC_VDDCI_DELTA        300
62
63 #define MC_SEQ_MISC0_GDDR5_SHIFT 28
64 #define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
65 #define MC_SEQ_MISC0_GDDR5_VALUE 5
66
67 #define MC_CG_ARB_FREQ_F0           0x0a /* boot-up default */
68 #define MC_CG_ARB_FREQ_F1           0x0b
69 #define MC_CG_ARB_FREQ_F2           0x0c
70 #define MC_CG_ARB_FREQ_F3           0x0d
71
72 /* From smc_reg.h */
73 #define SMC_CG_IND_START            0xc0030000
74 #define SMC_CG_IND_END              0xc0040000  /* First byte after SMC_CG_IND */
75
76 #define VOLTAGE_SCALE               4
77 #define VOLTAGE_VID_OFFSET_SCALE1   625
78 #define VOLTAGE_VID_OFFSET_SCALE2   100
79
80 #define VDDC_VDDCI_DELTA            300
81
82 #define ixSWRST_COMMAND_1           0x1400103
83 #define MC_SEQ_CNTL__CAC_EN_MASK    0x40000000
84
85 /** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
86 enum DPM_EVENT_SRC {
87     DPM_EVENT_SRC_ANALOG = 0,               /* Internal analog trip point */
88     DPM_EVENT_SRC_EXTERNAL = 1,             /* External (GPIO 17) signal */
89     DPM_EVENT_SRC_DIGITAL = 2,              /* Internal digital trip point (DIG_THERM_DPM) */
90     DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,   /* Internal analog or external */
91     DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4   /* Internal digital or external */
92 };
93
94
95 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
96  * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
97  */
98 static const uint16_t fiji_clock_stretcher_lookup_table[2][4] =
99 { {600, 1050, 3, 0}, {600, 1050, 6, 1} };
100
101 /* [FF, SS] type, [] 4 voltage ranges, and
102  * [Floor Freq, Boundary Freq, VID min , VID max]
103  */
104 static const uint32_t fiji_clock_stretcher_ddt_table[2][4][4] =
105 { { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
106   { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
107
108 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
109  * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
110  */
111 static const uint8_t fiji_clock_stretch_amount_conversion[2][6] =
112 { {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
113
114 static const unsigned long PhwFiji_Magic = (unsigned long)(PHM_VIslands_Magic);
115
116 static struct fiji_power_state *cast_phw_fiji_power_state(
117                                   struct pp_hw_power_state *hw_ps)
118 {
119         PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
120                                 "Invalid Powerstate Type!",
121                                  return NULL;);
122
123         return (struct fiji_power_state *)hw_ps;
124 }
125
126 static const struct
127 fiji_power_state *cast_const_phw_fiji_power_state(
128                                  const struct pp_hw_power_state *hw_ps)
129 {
130         PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
131                                 "Invalid Powerstate Type!",
132                                  return NULL;);
133
134         return (const struct fiji_power_state *)hw_ps;
135 }
136
137 static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr)
138 {
139         return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
140                         CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
141                         ? true : false;
142 }
143
144 static void fiji_init_dpm_defaults(struct pp_hwmgr *hwmgr)
145 {
146         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
147         struct fiji_ulv_parm *ulv = &data->ulv;
148
149         ulv->cg_ulv_parameter = PPFIJI_CGULVPARAMETER_DFLT;
150         data->voting_rights_clients0 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0;
151         data->voting_rights_clients1 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1;
152         data->voting_rights_clients2 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2;
153         data->voting_rights_clients3 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3;
154         data->voting_rights_clients4 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4;
155         data->voting_rights_clients5 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5;
156         data->voting_rights_clients6 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6;
157         data->voting_rights_clients7 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7;
158
159         data->static_screen_threshold_unit =
160                         PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT;
161         data->static_screen_threshold =
162                         PPFIJI_STATICSCREENTHRESHOLD_DFLT;
163
164         /* Unset ABM cap as it moved to DAL.
165          * Add PHM_PlatformCaps_NonABMSupportInPPLib
166          * for re-direct ABM related request to DAL
167          */
168         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
169                         PHM_PlatformCaps_ABM);
170         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
171                         PHM_PlatformCaps_NonABMSupportInPPLib);
172
173         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
174                         PHM_PlatformCaps_DynamicACTiming);
175
176         fiji_initialize_power_tune_defaults(hwmgr);
177
178         data->mclk_stutter_mode_threshold = 60000;
179         data->pcie_gen_performance.max = PP_PCIEGen1;
180         data->pcie_gen_performance.min = PP_PCIEGen3;
181         data->pcie_gen_power_saving.max = PP_PCIEGen1;
182         data->pcie_gen_power_saving.min = PP_PCIEGen3;
183         data->pcie_lane_performance.max = 0;
184         data->pcie_lane_performance.min = 16;
185         data->pcie_lane_power_saving.max = 0;
186         data->pcie_lane_power_saving.min = 16;
187
188         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
189                         PHM_PlatformCaps_DynamicUVDState);
190 }
191
192 static int fiji_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
193         phm_ppt_v1_voltage_lookup_table *lookup_table,
194         uint16_t virtual_voltage_id, int32_t *sclk)
195 {
196         uint8_t entryId;
197         uint8_t voltageId;
198         struct phm_ppt_v1_information *table_info =
199                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
200
201         PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
202
203         /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
204         for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
205                 voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
206                 if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
207                         break;
208         }
209
210         PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
211                         "Can't find requested voltage id in vdd_dep_on_sclk table!",
212                         return -EINVAL;
213                         );
214
215         *sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
216
217         return 0;
218 }
219
220 /**
221 * Get Leakage VDDC based on leakage ID.
222 *
223 * @param    hwmgr  the address of the powerplay hardware manager.
224 * @return   always 0
225 */
226 static int fiji_get_evv_voltages(struct pp_hwmgr *hwmgr)
227 {
228         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
229         uint16_t    vv_id;
230         uint16_t    vddc = 0;
231         uint16_t    evv_default = 1150;
232         uint16_t    i, j;
233         uint32_t  sclk = 0;
234         struct phm_ppt_v1_information *table_info =
235                         (struct phm_ppt_v1_information *)hwmgr->pptable;
236         struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
237                         table_info->vdd_dep_on_sclk;
238         int result;
239
240         for (i = 0; i < FIJI_MAX_LEAKAGE_COUNT; i++) {
241                 vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
242                 if (!fiji_get_sclk_for_voltage_evv(hwmgr,
243                                 table_info->vddc_lookup_table, vv_id, &sclk)) {
244                         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
245                                         PHM_PlatformCaps_ClockStretcher)) {
246                                 for (j = 1; j < sclk_table->count; j++) {
247                                         if (sclk_table->entries[j].clk == sclk &&
248                                                         sclk_table->entries[j].cks_enable == 0) {
249                                                 sclk += 5000;
250                                                 break;
251                                         }
252                                 }
253                         }
254
255                         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
256                                         PHM_PlatformCaps_EnableDriverEVV))
257                                 result = atomctrl_calculate_voltage_evv_on_sclk(hwmgr,
258                                                 VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc, i, true);
259                         else
260                                 result = -EINVAL;
261
262                         if (result)
263                                 result = atomctrl_get_voltage_evv_on_sclk(hwmgr,
264                                                 VOLTAGE_TYPE_VDDC, sclk,vv_id, &vddc);
265
266                         /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
267                         PP_ASSERT_WITH_CODE((vddc < 2000),
268                                         "Invalid VDDC value, greater than 2v!", result = -EINVAL;);
269
270                         if (result)
271                                 /* 1.15V is the default safe value for Fiji */
272                                 vddc = evv_default;
273
274                         /* the voltage should not be zero nor equal to leakage ID */
275                         if (vddc != 0 && vddc != vv_id) {
276                                 data->vddc_leakage.actual_voltage
277                                 [data->vddc_leakage.count] = vddc;
278                                 data->vddc_leakage.leakage_id
279                                 [data->vddc_leakage.count] = vv_id;
280                                 data->vddc_leakage.count++;
281                         }
282                 }
283         }
284         return 0;
285 }
286
287 /**
288  * Change virtual leakage voltage to actual value.
289  *
290  * @param     hwmgr  the address of the powerplay hardware manager.
291  * @param     pointer to changing voltage
292  * @param     pointer to leakage table
293  */
294 static void fiji_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
295                 uint16_t *voltage, struct fiji_leakage_voltage *leakage_table)
296 {
297         uint32_t index;
298
299         /* search for leakage voltage ID 0xff01 ~ 0xff08 */
300         for (index = 0; index < leakage_table->count; index++) {
301                 /* if this voltage matches a leakage voltage ID */
302                 /* patch with actual leakage voltage */
303                 if (leakage_table->leakage_id[index] == *voltage) {
304                         *voltage = leakage_table->actual_voltage[index];
305                         break;
306                 }
307         }
308
309         if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
310                 printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
311 }
312
313 /**
314 * Patch voltage lookup table by EVV leakages.
315 *
316 * @param     hwmgr  the address of the powerplay hardware manager.
317 * @param     pointer to voltage lookup table
318 * @param     pointer to leakage table
319 * @return     always 0
320 */
321 static int fiji_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
322                 phm_ppt_v1_voltage_lookup_table *lookup_table,
323                 struct fiji_leakage_voltage *leakage_table)
324 {
325         uint32_t i;
326
327         for (i = 0; i < lookup_table->count; i++)
328                 fiji_patch_with_vdd_leakage(hwmgr,
329                                 &lookup_table->entries[i].us_vdd, leakage_table);
330
331         return 0;
332 }
333
334 static int fiji_patch_clock_voltage_limits_with_vddc_leakage(
335                 struct pp_hwmgr *hwmgr, struct fiji_leakage_voltage *leakage_table,
336                 uint16_t *vddc)
337 {
338         struct phm_ppt_v1_information *table_info =
339                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
340         fiji_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
341         hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
342                         table_info->max_clock_voltage_on_dc.vddc;
343         return 0;
344 }
345
346 static int fiji_patch_voltage_dependency_tables_with_lookup_table(
347                 struct pp_hwmgr *hwmgr)
348 {
349         uint8_t entryId;
350         uint8_t voltageId;
351         struct phm_ppt_v1_information *table_info =
352                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
353
354         struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
355                         table_info->vdd_dep_on_sclk;
356         struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
357                         table_info->vdd_dep_on_mclk;
358         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
359                         table_info->mm_dep_table;
360
361         for (entryId = 0; entryId < sclk_table->count; ++entryId) {
362                 voltageId = sclk_table->entries[entryId].vddInd;
363                 sclk_table->entries[entryId].vddc =
364                                 table_info->vddc_lookup_table->entries[voltageId].us_vdd;
365         }
366
367         for (entryId = 0; entryId < mclk_table->count; ++entryId) {
368                 voltageId = mclk_table->entries[entryId].vddInd;
369                 mclk_table->entries[entryId].vddc =
370                         table_info->vddc_lookup_table->entries[voltageId].us_vdd;
371         }
372
373         for (entryId = 0; entryId < mm_table->count; ++entryId) {
374                 voltageId = mm_table->entries[entryId].vddcInd;
375                 mm_table->entries[entryId].vddc =
376                         table_info->vddc_lookup_table->entries[voltageId].us_vdd;
377         }
378
379         return 0;
380
381 }
382
383 static int fiji_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
384 {
385         /* Need to determine if we need calculated voltage. */
386         return 0;
387 }
388
389 static int fiji_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
390 {
391         /* Need to determine if we need calculated voltage from mm table. */
392         return 0;
393 }
394
395 static int fiji_sort_lookup_table(struct pp_hwmgr *hwmgr,
396                 struct phm_ppt_v1_voltage_lookup_table *lookup_table)
397 {
398         uint32_t table_size, i, j;
399         struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
400         table_size = lookup_table->count;
401
402         PP_ASSERT_WITH_CODE(0 != lookup_table->count,
403                 "Lookup table is empty", return -EINVAL);
404
405         /* Sorting voltages */
406         for (i = 0; i < table_size - 1; i++) {
407                 for (j = i + 1; j > 0; j--) {
408                         if (lookup_table->entries[j].us_vdd <
409                                         lookup_table->entries[j - 1].us_vdd) {
410                                 tmp_voltage_lookup_record = lookup_table->entries[j - 1];
411                                 lookup_table->entries[j - 1] = lookup_table->entries[j];
412                                 lookup_table->entries[j] = tmp_voltage_lookup_record;
413                         }
414                 }
415         }
416
417         return 0;
418 }
419
420 static int fiji_complete_dependency_tables(struct pp_hwmgr *hwmgr)
421 {
422         int result = 0;
423         int tmp_result;
424         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
425         struct phm_ppt_v1_information *table_info =
426                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
427
428         tmp_result = fiji_patch_lookup_table_with_leakage(hwmgr,
429                         table_info->vddc_lookup_table, &(data->vddc_leakage));
430         if (tmp_result)
431                 result = tmp_result;
432
433         tmp_result = fiji_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
434                         &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
435         if (tmp_result)
436                 result = tmp_result;
437
438         tmp_result = fiji_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
439         if (tmp_result)
440                 result = tmp_result;
441
442         tmp_result = fiji_calc_voltage_dependency_tables(hwmgr);
443         if (tmp_result)
444                 result = tmp_result;
445
446         tmp_result = fiji_calc_mm_voltage_dependency_table(hwmgr);
447         if (tmp_result)
448                 result = tmp_result;
449
450         tmp_result = fiji_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
451         if(tmp_result)
452                 result = tmp_result;
453
454         return result;
455 }
456
457 static int fiji_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
458 {
459         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
460         struct phm_ppt_v1_information *table_info =
461                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
462
463         struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
464                         table_info->vdd_dep_on_sclk;
465         struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
466                         table_info->vdd_dep_on_mclk;
467
468         PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
469                 "VDD dependency on SCLK table is missing.       \
470                 This table is mandatory", return -EINVAL);
471         PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
472                 "VDD dependency on SCLK table has to have is missing.   \
473                 This table is mandatory", return -EINVAL);
474
475         PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
476                 "VDD dependency on MCLK table is missing.       \
477                 This table is mandatory", return -EINVAL);
478         PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
479                 "VDD dependency on MCLK table has to have is missing.    \
480                 This table is mandatory", return -EINVAL);
481
482         data->min_vddc_in_pptable = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
483         data->max_vddc_in_pptable =     (uint16_t)allowed_sclk_vdd_table->
484                         entries[allowed_sclk_vdd_table->count - 1].vddc;
485
486         table_info->max_clock_voltage_on_ac.sclk =
487                 allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
488         table_info->max_clock_voltage_on_ac.mclk =
489                 allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
490         table_info->max_clock_voltage_on_ac.vddc =
491                 allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
492         table_info->max_clock_voltage_on_ac.vddci =
493                 allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
494
495         hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
496                 table_info->max_clock_voltage_on_ac.sclk;
497         hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
498                 table_info->max_clock_voltage_on_ac.mclk;
499         hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
500                 table_info->max_clock_voltage_on_ac.vddc;
501         hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
502                 table_info->max_clock_voltage_on_ac.vddci;
503
504         return 0;
505 }
506
507 static uint16_t fiji_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
508 {
509         uint32_t speedCntl = 0;
510
511         /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
512         speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
513                         ixPCIE_LC_SPEED_CNTL);
514         return((uint16_t)PHM_GET_FIELD(speedCntl,
515                         PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
516 }
517
518 static int fiji_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr)
519 {
520         uint32_t link_width;
521
522         /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
523         link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
524                         PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD);
525
526         PP_ASSERT_WITH_CODE((7 >= link_width),
527                         "Invalid PCIe lane width!", return 0);
528
529         return decode_pcie_lane_width(link_width);
530 }
531
532 /** Patch the Boot State to match VBIOS boot clocks and voltage.
533 *
534 * @param hwmgr Pointer to the hardware manager.
535 * @param pPowerState The address of the PowerState instance being created.
536 *
537 */
538 static int fiji_patch_boot_state(struct pp_hwmgr *hwmgr,
539                 struct pp_hw_power_state *hw_ps)
540 {
541         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
542         struct fiji_power_state *ps = (struct fiji_power_state *)hw_ps;
543         ATOM_FIRMWARE_INFO_V2_2 *fw_info;
544         uint16_t size;
545         uint8_t frev, crev;
546         int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
547
548         /* First retrieve the Boot clocks and VDDC from the firmware info table.
549          * We assume here that fw_info is unchanged if this call fails.
550          */
551         fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
552                         hwmgr->device, index,
553                         &size, &frev, &crev);
554         if (!fw_info)
555                 /* During a test, there is no firmware info table. */
556                 return 0;
557
558         /* Patch the state. */
559         data->vbios_boot_state.sclk_bootup_value =
560                         le32_to_cpu(fw_info->ulDefaultEngineClock);
561         data->vbios_boot_state.mclk_bootup_value =
562                         le32_to_cpu(fw_info->ulDefaultMemoryClock);
563         data->vbios_boot_state.mvdd_bootup_value =
564                         le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
565         data->vbios_boot_state.vddc_bootup_value =
566                         le16_to_cpu(fw_info->usBootUpVDDCVoltage);
567         data->vbios_boot_state.vddci_bootup_value =
568                         le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
569         data->vbios_boot_state.pcie_gen_bootup_value =
570                         fiji_get_current_pcie_speed(hwmgr);
571         data->vbios_boot_state.pcie_lane_bootup_value =
572                         (uint16_t)fiji_get_current_pcie_lane_number(hwmgr);
573
574         /* set boot power state */
575         ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
576         ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
577         ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
578         ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
579
580         return 0;
581 }
582
583 static int fiji_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
584 {
585         return phm_hwmgr_backend_fini(hwmgr);
586 }
587
588 static int fiji_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
589 {
590         struct fiji_hwmgr *data;
591         uint32_t i;
592         struct phm_ppt_v1_information *table_info =
593                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
594         bool stay_in_boot;
595         int result;
596
597         data = kzalloc(sizeof(struct fiji_hwmgr), GFP_KERNEL);
598         if (data == NULL)
599                 return -ENOMEM;
600
601         hwmgr->backend = data;
602
603         data->dll_default_on = false;
604         data->sram_end = SMC_RAM_END;
605
606         for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
607                 data->activity_target[i] = FIJI_AT_DFLT;
608
609         data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
610
611         data->mclk_activity_target = PPFIJI_MCLK_TARGETACTIVITY_DFLT;
612         data->mclk_dpm0_activity_target = 0xa;
613
614         data->sclk_dpm_key_disabled = 0;
615         data->mclk_dpm_key_disabled = 0;
616         data->pcie_dpm_key_disabled = 0;
617
618         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
619                         PHM_PlatformCaps_UnTabledHardwareInterface);
620         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
621                         PHM_PlatformCaps_TablelessHardwareInterface);
622
623         data->gpio_debug = 0;
624
625         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
626                         PHM_PlatformCaps_DynamicPatchPowerState);
627
628         /* need to set voltage control types before EVV patching */
629         data->voltage_control = FIJI_VOLTAGE_CONTROL_NONE;
630         data->vddci_control = FIJI_VOLTAGE_CONTROL_NONE;
631         data->mvdd_control = FIJI_VOLTAGE_CONTROL_NONE;
632
633         data->force_pcie_gen = PP_PCIEGenInvalid;
634
635         if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
636                         VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
637                 data->voltage_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
638
639         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
640                         PHM_PlatformCaps_EnableMVDDControl))
641                 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
642                                 VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
643                         data->mvdd_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
644
645         if (data->mvdd_control == FIJI_VOLTAGE_CONTROL_NONE)
646                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
647                         PHM_PlatformCaps_EnableMVDDControl);
648
649         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
650                         PHM_PlatformCaps_ControlVDDCI)) {
651                 if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
652                                 VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
653                         data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
654                 else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
655                                 VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
656                         data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
657         }
658
659         if (data->vddci_control == FIJI_VOLTAGE_CONTROL_NONE)
660                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
661                                 PHM_PlatformCaps_ControlVDDCI);
662
663         if (table_info && table_info->cac_dtp_table->usClockStretchAmount)
664                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
665                                 PHM_PlatformCaps_ClockStretcher);
666
667         fiji_init_dpm_defaults(hwmgr);
668
669         /* Get leakage voltage based on leakage ID. */
670         fiji_get_evv_voltages(hwmgr);
671
672         /* Patch our voltage dependency table with actual leakage voltage
673          * We need to perform leakage translation before it's used by other functions
674          */
675         fiji_complete_dependency_tables(hwmgr);
676
677         /* Parse pptable data read from VBIOS */
678         fiji_set_private_data_based_on_pptable(hwmgr);
679
680         /* ULV Support */
681         data->ulv.ulv_supported = true; /* ULV feature is enabled by default */
682
683         /* Initalize Dynamic State Adjustment Rule Settings */
684         result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
685
686         if (!result) {
687                 data->uvd_enabled = false;
688                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
689                                 PHM_PlatformCaps_EnableSMU7ThermalManagement);
690                 data->vddc_phase_shed_control = false;
691         }
692
693         stay_in_boot = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
694                         PHM_PlatformCaps_StayInBootState);
695
696         if (0 == result) {
697                 struct cgs_system_info sys_info = {0};
698
699                 data->is_tlu_enabled = false;
700                 hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
701                                 FIJI_MAX_HARDWARE_POWERLEVELS;
702                 hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
703                 hwmgr->platform_descriptor.minimumClocksReductionPercentage  = 50;
704
705                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
706                                 PHM_PlatformCaps_FanSpeedInTableIsRPM);
707
708                 if (table_info->cac_dtp_table->usDefaultTargetOperatingTemp &&
709                                 hwmgr->thermal_controller.
710                                 advanceFanControlParameters.ucFanControlMode) {
711                         hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM =
712                                         hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
713                         hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
714                                         hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM;
715                         hwmgr->dyn_state.cac_dtp_table->usOperatingTempMinLimit =
716                                         table_info->cac_dtp_table->usOperatingTempMinLimit;
717                         hwmgr->dyn_state.cac_dtp_table->usOperatingTempMaxLimit =
718                                         table_info->cac_dtp_table->usOperatingTempMaxLimit;
719                         hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
720                                         table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
721                         hwmgr->dyn_state.cac_dtp_table->usOperatingTempStep =
722                                         table_info->cac_dtp_table->usOperatingTempStep;
723                         hwmgr->dyn_state.cac_dtp_table->usTargetOperatingTemp =
724                                         table_info->cac_dtp_table->usTargetOperatingTemp;
725
726                         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
727                                         PHM_PlatformCaps_ODFuzzyFanControlSupport);
728                 }
729
730                 sys_info.size = sizeof(struct cgs_system_info);
731                 sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
732                 result = cgs_query_system_info(hwmgr->device, &sys_info);
733                 if (result)
734                         data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK;
735                 else
736                         data->pcie_gen_cap = (uint32_t)sys_info.value;
737                 if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
738                         data->pcie_spc_cap = 20;
739                 sys_info.size = sizeof(struct cgs_system_info);
740                 sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
741                 result = cgs_query_system_info(hwmgr->device, &sys_info);
742                 if (result)
743                         data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK;
744                 else
745                         data->pcie_lane_cap = (uint32_t)sys_info.value;
746         } else {
747                 /* Ignore return value in here, we are cleaning up a mess. */
748                 fiji_hwmgr_backend_fini(hwmgr);
749         }
750
751         return 0;
752 }
753
754 /**
755  * Read clock related registers.
756  *
757  * @param    hwmgr  the address of the powerplay hardware manager.
758  * @return   always 0
759  */
760 static int fiji_read_clock_registers(struct pp_hwmgr *hwmgr)
761 {
762         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
763
764         data->clock_registers.vCG_SPLL_FUNC_CNTL =
765                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
766                                 ixCG_SPLL_FUNC_CNTL);
767         data->clock_registers.vCG_SPLL_FUNC_CNTL_2 =
768                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
769                                 ixCG_SPLL_FUNC_CNTL_2);
770         data->clock_registers.vCG_SPLL_FUNC_CNTL_3 =
771                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
772                                 ixCG_SPLL_FUNC_CNTL_3);
773         data->clock_registers.vCG_SPLL_FUNC_CNTL_4 =
774                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
775                                 ixCG_SPLL_FUNC_CNTL_4);
776         data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM =
777                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
778                                 ixCG_SPLL_SPREAD_SPECTRUM);
779         data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
780                 cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
781                                 ixCG_SPLL_SPREAD_SPECTRUM_2);
782
783         return 0;
784 }
785
786 /**
787  * Find out if memory is GDDR5.
788  *
789  * @param    hwmgr  the address of the powerplay hardware manager.
790  * @return   always 0
791  */
792 static int fiji_get_memory_type(struct pp_hwmgr *hwmgr)
793 {
794         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
795         uint32_t temp;
796
797         temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
798
799         data->is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
800                         ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
801                          MC_SEQ_MISC0_GDDR5_SHIFT));
802
803         return 0;
804 }
805
806 /**
807  * Enables Dynamic Power Management by SMC
808  *
809  * @param    hwmgr  the address of the powerplay hardware manager.
810  * @return   always 0
811  */
812 static int fiji_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
813 {
814         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
815                         GENERAL_PWRMGT, STATIC_PM_EN, 1);
816
817         return 0;
818 }
819
820 /**
821  * Initialize PowerGating States for different engines
822  *
823  * @param    hwmgr  the address of the powerplay hardware manager.
824  * @return   always 0
825  */
826 static int fiji_init_power_gate_state(struct pp_hwmgr *hwmgr)
827 {
828         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
829
830         data->uvd_power_gated = false;
831         data->vce_power_gated = false;
832         data->samu_power_gated = false;
833         data->acp_power_gated = false;
834         data->pg_acp_init = true;
835
836         return 0;
837 }
838
839 static int fiji_init_sclk_threshold(struct pp_hwmgr *hwmgr)
840 {
841         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
842         data->low_sclk_interrupt_threshold = 0;
843
844         return 0;
845 }
846
847 static int fiji_setup_asic_task(struct pp_hwmgr *hwmgr)
848 {
849         int tmp_result, result = 0;
850
851         tmp_result = fiji_read_clock_registers(hwmgr);
852         PP_ASSERT_WITH_CODE((0 == tmp_result),
853                         "Failed to read clock registers!", result = tmp_result);
854
855         tmp_result = fiji_get_memory_type(hwmgr);
856         PP_ASSERT_WITH_CODE((0 == tmp_result),
857                         "Failed to get memory type!", result = tmp_result);
858
859         tmp_result = fiji_enable_acpi_power_management(hwmgr);
860         PP_ASSERT_WITH_CODE((0 == tmp_result),
861                         "Failed to enable ACPI power management!", result = tmp_result);
862
863         tmp_result = fiji_init_power_gate_state(hwmgr);
864         PP_ASSERT_WITH_CODE((0 == tmp_result),
865                         "Failed to init power gate state!", result = tmp_result);
866
867         tmp_result = tonga_get_mc_microcode_version(hwmgr);
868         PP_ASSERT_WITH_CODE((0 == tmp_result),
869                         "Failed to get MC microcode version!", result = tmp_result);
870
871         tmp_result = fiji_init_sclk_threshold(hwmgr);
872         PP_ASSERT_WITH_CODE((0 == tmp_result),
873                         "Failed to init sclk threshold!", result = tmp_result);
874
875         return result;
876 }
877
878 /**
879 * Checks if we want to support voltage control
880 *
881 * @param    hwmgr  the address of the powerplay hardware manager.
882 */
883 static bool fiji_voltage_control(const struct pp_hwmgr *hwmgr)
884 {
885         const struct fiji_hwmgr *data =
886                         (const struct fiji_hwmgr *)(hwmgr->backend);
887
888         return (FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control);
889 }
890
891 /**
892 * Enable voltage control
893 *
894 * @param    hwmgr  the address of the powerplay hardware manager.
895 * @return   always 0
896 */
897 static int fiji_enable_voltage_control(struct pp_hwmgr *hwmgr)
898 {
899         /* enable voltage control */
900         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
901                         GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
902
903         return 0;
904 }
905
906 /**
907 * Remove repeated voltage values and create table with unique values.
908 *
909 * @param    hwmgr  the address of the powerplay hardware manager.
910 * @param    vol_table  the pointer to changing voltage table
911 * @return    0 in success
912 */
913
914 static int fiji_trim_voltage_table(struct pp_hwmgr *hwmgr,
915                 struct pp_atomctrl_voltage_table *vol_table)
916 {
917         uint32_t i, j;
918         uint16_t vvalue;
919         bool found = false;
920         struct pp_atomctrl_voltage_table *table;
921
922         PP_ASSERT_WITH_CODE((NULL != vol_table),
923                         "Voltage Table empty.", return -EINVAL);
924         table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
925                         GFP_KERNEL);
926
927         if (NULL == table)
928                 return -ENOMEM;
929
930         table->mask_low = vol_table->mask_low;
931         table->phase_delay = vol_table->phase_delay;
932
933         for (i = 0; i < vol_table->count; i++) {
934                 vvalue = vol_table->entries[i].value;
935                 found = false;
936
937                 for (j = 0; j < table->count; j++) {
938                         if (vvalue == table->entries[j].value) {
939                                 found = true;
940                                 break;
941                         }
942                 }
943
944                 if (!found) {
945                         table->entries[table->count].value = vvalue;
946                         table->entries[table->count].smio_low =
947                                         vol_table->entries[i].smio_low;
948                         table->count++;
949                 }
950         }
951
952         memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
953         kfree(table);
954
955         return 0;
956 }
957
958 static int fiji_get_svi2_mvdd_voltage_table(struct pp_hwmgr *hwmgr,
959                 phm_ppt_v1_clock_voltage_dependency_table *dep_table)
960 {
961         uint32_t i;
962         int result;
963         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
964         struct pp_atomctrl_voltage_table *vol_table = &(data->mvdd_voltage_table);
965
966         PP_ASSERT_WITH_CODE((0 != dep_table->count),
967                         "Voltage Dependency Table empty.", return -EINVAL);
968
969         vol_table->mask_low = 0;
970         vol_table->phase_delay = 0;
971         vol_table->count = dep_table->count;
972
973         for (i = 0; i < dep_table->count; i++) {
974                 vol_table->entries[i].value = dep_table->entries[i].mvdd;
975                 vol_table->entries[i].smio_low = 0;
976         }
977
978         result = fiji_trim_voltage_table(hwmgr, vol_table);
979         PP_ASSERT_WITH_CODE((0 == result),
980                         "Failed to trim MVDD table.", return result);
981
982         return 0;
983 }
984
985 static int fiji_get_svi2_vddci_voltage_table(struct pp_hwmgr *hwmgr,
986                 phm_ppt_v1_clock_voltage_dependency_table *dep_table)
987 {
988         uint32_t i;
989         int result;
990         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
991         struct pp_atomctrl_voltage_table *vol_table = &(data->vddci_voltage_table);
992
993         PP_ASSERT_WITH_CODE((0 != dep_table->count),
994                         "Voltage Dependency Table empty.", return -EINVAL);
995
996         vol_table->mask_low = 0;
997         vol_table->phase_delay = 0;
998         vol_table->count = dep_table->count;
999
1000         for (i = 0; i < dep_table->count; i++) {
1001                 vol_table->entries[i].value = dep_table->entries[i].vddci;
1002                 vol_table->entries[i].smio_low = 0;
1003         }
1004
1005         result = fiji_trim_voltage_table(hwmgr, vol_table);
1006         PP_ASSERT_WITH_CODE((0 == result),
1007                         "Failed to trim VDDCI table.", return result);
1008
1009         return 0;
1010 }
1011
1012 static int fiji_get_svi2_vdd_voltage_table(struct pp_hwmgr *hwmgr,
1013                 phm_ppt_v1_voltage_lookup_table *lookup_table)
1014 {
1015         int i = 0;
1016         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1017         struct pp_atomctrl_voltage_table *vol_table = &(data->vddc_voltage_table);
1018
1019         PP_ASSERT_WITH_CODE((0 != lookup_table->count),
1020                         "Voltage Lookup Table empty.", return -EINVAL);
1021
1022         vol_table->mask_low = 0;
1023         vol_table->phase_delay = 0;
1024
1025         vol_table->count = lookup_table->count;
1026
1027         for (i = 0; i < vol_table->count; i++) {
1028                 vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
1029                 vol_table->entries[i].smio_low = 0;
1030         }
1031
1032         return 0;
1033 }
1034
1035 /* ---- Voltage Tables ----
1036  * If the voltage table would be bigger than
1037  * what will fit into the state table on
1038  * the SMC keep only the higher entries.
1039  */
1040 static void fiji_trim_voltage_table_to_fit_state_table(struct pp_hwmgr *hwmgr,
1041                 uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table)
1042 {
1043         unsigned int i, diff;
1044
1045         if (vol_table->count <= max_vol_steps)
1046                 return;
1047
1048         diff = vol_table->count - max_vol_steps;
1049
1050         for (i = 0; i < max_vol_steps; i++)
1051                 vol_table->entries[i] = vol_table->entries[i + diff];
1052
1053         vol_table->count = max_vol_steps;
1054
1055         return;
1056 }
1057
1058 /**
1059 * Create Voltage Tables.
1060 *
1061 * @param    hwmgr  the address of the powerplay hardware manager.
1062 * @return   always 0
1063 */
1064 static int fiji_construct_voltage_tables(struct pp_hwmgr *hwmgr)
1065 {
1066         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1067         struct phm_ppt_v1_information *table_info =
1068                         (struct phm_ppt_v1_information *)hwmgr->pptable;
1069         int result;
1070
1071         if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
1072                 result = atomctrl_get_voltage_table_v3(hwmgr,
1073                                 VOLTAGE_TYPE_MVDDC,     VOLTAGE_OBJ_GPIO_LUT,
1074                                 &(data->mvdd_voltage_table));
1075                 PP_ASSERT_WITH_CODE((0 == result),
1076                                 "Failed to retrieve MVDD table.",
1077                                 return result);
1078         } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
1079                 result = fiji_get_svi2_mvdd_voltage_table(hwmgr,
1080                                 table_info->vdd_dep_on_mclk);
1081                 PP_ASSERT_WITH_CODE((0 == result),
1082                                 "Failed to retrieve SVI2 MVDD table from dependancy table.",
1083                                 return result;);
1084         }
1085
1086         if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
1087                 result = atomctrl_get_voltage_table_v3(hwmgr,
1088                                 VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT,
1089                                 &(data->vddci_voltage_table));
1090                 PP_ASSERT_WITH_CODE((0 == result),
1091                                 "Failed to retrieve VDDCI table.",
1092                                 return result);
1093         } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
1094                 result = fiji_get_svi2_vddci_voltage_table(hwmgr,
1095                                 table_info->vdd_dep_on_mclk);
1096                 PP_ASSERT_WITH_CODE((0 == result),
1097                                 "Failed to retrieve SVI2 VDDCI table from dependancy table.",
1098                                 return result);
1099         }
1100
1101         if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
1102                 result = fiji_get_svi2_vdd_voltage_table(hwmgr,
1103                                 table_info->vddc_lookup_table);
1104                 PP_ASSERT_WITH_CODE((0 == result),
1105                                 "Failed to retrieve SVI2 VDDC table from lookup table.",
1106                                 return result);
1107         }
1108
1109         PP_ASSERT_WITH_CODE(
1110                         (data->vddc_voltage_table.count <= (SMU73_MAX_LEVELS_VDDC)),
1111                         "Too many voltage values for VDDC. Trimming to fit state table.",
1112                         fiji_trim_voltage_table_to_fit_state_table(hwmgr,
1113                                         SMU73_MAX_LEVELS_VDDC, &(data->vddc_voltage_table)));
1114
1115         PP_ASSERT_WITH_CODE(
1116                         (data->vddci_voltage_table.count <= (SMU73_MAX_LEVELS_VDDCI)),
1117                         "Too many voltage values for VDDCI. Trimming to fit state table.",
1118                         fiji_trim_voltage_table_to_fit_state_table(hwmgr,
1119                                         SMU73_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table)));
1120
1121         PP_ASSERT_WITH_CODE(
1122                         (data->mvdd_voltage_table.count <= (SMU73_MAX_LEVELS_MVDD)),
1123                         "Too many voltage values for MVDD. Trimming to fit state table.",
1124                         fiji_trim_voltage_table_to_fit_state_table(hwmgr,
1125                                         SMU73_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table)));
1126
1127         return 0;
1128 }
1129
1130 static int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
1131 {
1132         /* Program additional LP registers
1133          * that are no longer programmed by VBIOS
1134          */
1135         cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
1136                         cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
1137         cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
1138                         cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
1139         cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
1140                         cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
1141         cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
1142                         cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
1143         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
1144                         cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
1145         cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
1146                         cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
1147         cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
1148                         cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
1149
1150         return 0;
1151 }
1152
1153 /**
1154 * Programs static screed detection parameters
1155 *
1156 * @param    hwmgr  the address of the powerplay hardware manager.
1157 * @return   always 0
1158 */
1159 static int fiji_program_static_screen_threshold_parameters(
1160                 struct pp_hwmgr *hwmgr)
1161 {
1162         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1163
1164         /* Set static screen threshold unit */
1165         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1166                         CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
1167                         data->static_screen_threshold_unit);
1168         /* Set static screen threshold */
1169         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1170                         CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
1171                         data->static_screen_threshold);
1172
1173         return 0;
1174 }
1175
1176 /**
1177 * Setup display gap for glitch free memory clock switching.
1178 *
1179 * @param    hwmgr  the address of the powerplay hardware manager.
1180 * @return   always  0
1181 */
1182 static int fiji_enable_display_gap(struct pp_hwmgr *hwmgr)
1183 {
1184         uint32_t displayGap =
1185                         cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1186                                         ixCG_DISPLAY_GAP_CNTL);
1187
1188         displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
1189                         DISP_GAP, DISPLAY_GAP_IGNORE);
1190
1191         displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
1192                         DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
1193
1194         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1195                         ixCG_DISPLAY_GAP_CNTL, displayGap);
1196
1197         return 0;
1198 }
1199
1200 /**
1201 * Programs activity state transition voting clients
1202 *
1203 * @param    hwmgr  the address of the powerplay hardware manager.
1204 * @return   always  0
1205 */
1206 static int fiji_program_voting_clients(struct pp_hwmgr *hwmgr)
1207 {
1208         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1209
1210         /* Clear reset for voting clients before enabling DPM */
1211         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1212                         SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
1213         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1214                         SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
1215
1216         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1217                         ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
1218         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1219                         ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
1220         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1221                         ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
1222         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1223                         ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
1224         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1225                         ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
1226         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1227                         ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
1228         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1229                         ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
1230         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1231                         ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
1232
1233         return 0;
1234 }
1235
1236 static int fiji_clear_voting_clients(struct pp_hwmgr *hwmgr)
1237 {
1238         /* Reset voting clients before disabling DPM */
1239         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1240                         SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1);
1241         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
1242                         SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1);
1243
1244         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1245                         ixCG_FREQ_TRAN_VOTING_0, 0);
1246         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1247                         ixCG_FREQ_TRAN_VOTING_1, 0);
1248         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1249                         ixCG_FREQ_TRAN_VOTING_2, 0);
1250         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1251                         ixCG_FREQ_TRAN_VOTING_3, 0);
1252         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1253                         ixCG_FREQ_TRAN_VOTING_4, 0);
1254         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1255                         ixCG_FREQ_TRAN_VOTING_5, 0);
1256         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1257                         ixCG_FREQ_TRAN_VOTING_6, 0);
1258         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
1259                         ixCG_FREQ_TRAN_VOTING_7, 0);
1260
1261         return 0;
1262 }
1263
1264 /**
1265 * Get the location of various tables inside the FW image.
1266 *
1267 * @param    hwmgr  the address of the powerplay hardware manager.
1268 * @return   always  0
1269 */
1270 static int fiji_process_firmware_header(struct pp_hwmgr *hwmgr)
1271 {
1272         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1273         struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
1274         uint32_t tmp;
1275         int result;
1276         bool error = false;
1277
1278         result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1279                         SMU7_FIRMWARE_HEADER_LOCATION +
1280                         offsetof(SMU73_Firmware_Header, DpmTable),
1281                         &tmp, data->sram_end);
1282
1283         if (0 == result)
1284                 data->dpm_table_start = tmp;
1285
1286         error |= (0 != result);
1287
1288         result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1289                         SMU7_FIRMWARE_HEADER_LOCATION +
1290                         offsetof(SMU73_Firmware_Header, SoftRegisters),
1291                         &tmp, data->sram_end);
1292
1293         if (!result) {
1294                 data->soft_regs_start = tmp;
1295                 smu_data->soft_regs_start = tmp;
1296         }
1297
1298         error |= (0 != result);
1299
1300         result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1301                         SMU7_FIRMWARE_HEADER_LOCATION +
1302                         offsetof(SMU73_Firmware_Header, mcRegisterTable),
1303                         &tmp, data->sram_end);
1304
1305         if (!result)
1306                 data->mc_reg_table_start = tmp;
1307
1308         result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1309                         SMU7_FIRMWARE_HEADER_LOCATION +
1310                         offsetof(SMU73_Firmware_Header, FanTable),
1311                         &tmp, data->sram_end);
1312
1313         if (!result)
1314                 data->fan_table_start = tmp;
1315
1316         error |= (0 != result);
1317
1318         result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1319                         SMU7_FIRMWARE_HEADER_LOCATION +
1320                         offsetof(SMU73_Firmware_Header, mcArbDramTimingTable),
1321                         &tmp, data->sram_end);
1322
1323         if (!result)
1324                 data->arb_table_start = tmp;
1325
1326         error |= (0 != result);
1327
1328         result = fiji_read_smc_sram_dword(hwmgr->smumgr,
1329                         SMU7_FIRMWARE_HEADER_LOCATION +
1330                         offsetof(SMU73_Firmware_Header, Version),
1331                         &tmp, data->sram_end);
1332
1333         if (!result)
1334                 hwmgr->microcode_version_info.SMC = tmp;
1335
1336         error |= (0 != result);
1337
1338         return error ? -1 : 0;
1339 }
1340
1341 /* Copy one arb setting to another and then switch the active set.
1342  * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
1343  */
1344 static int fiji_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
1345                 uint32_t arb_src, uint32_t arb_dest)
1346 {
1347         uint32_t mc_arb_dram_timing;
1348         uint32_t mc_arb_dram_timing2;
1349         uint32_t burst_time;
1350         uint32_t mc_cg_config;
1351
1352         switch (arb_src) {
1353         case MC_CG_ARB_FREQ_F0:
1354                 mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
1355                 mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
1356                 burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
1357                 break;
1358         case MC_CG_ARB_FREQ_F1:
1359                 mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
1360                 mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
1361                 burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
1362                 break;
1363         default:
1364                 return -EINVAL;
1365         }
1366
1367         switch (arb_dest) {
1368         case MC_CG_ARB_FREQ_F0:
1369                 cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
1370                 cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
1371                 PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
1372                 break;
1373         case MC_CG_ARB_FREQ_F1:
1374                 cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
1375                 cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
1376                 PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
1377                 break;
1378         default:
1379                 return -EINVAL;
1380         }
1381
1382         mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
1383         mc_cg_config |= 0x0000000F;
1384         cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
1385         PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest);
1386
1387         return 0;
1388 }
1389
1390 /**
1391 * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
1392 *
1393 * @param    hwmgr  the address of the powerplay hardware manager.
1394 * @return   if success then 0;
1395 */
1396 static int fiji_reset_to_default(struct pp_hwmgr *hwmgr)
1397 {
1398         return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults);
1399 }
1400
1401 /**
1402 * Initial switch from ARB F0->F1
1403 *
1404 * @param    hwmgr  the address of the powerplay hardware manager.
1405 * @return   always 0
1406 * This function is to be called from the SetPowerState table.
1407 */
1408 static int fiji_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
1409 {
1410         return fiji_copy_and_switch_arb_sets(hwmgr,
1411                         MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
1412 }
1413
1414 static int fiji_force_switch_to_arbf0(struct pp_hwmgr *hwmgr)
1415 {
1416         uint32_t tmp;
1417
1418         tmp = (cgs_read_ind_register(hwmgr->device,
1419                         CGS_IND_REG__SMC, ixSMC_SCRATCH9) &
1420                         0x0000ff00) >> 8;
1421
1422         if (tmp == MC_CG_ARB_FREQ_F0)
1423                 return 0;
1424
1425         return fiji_copy_and_switch_arb_sets(hwmgr,
1426                         tmp, MC_CG_ARB_FREQ_F0);
1427 }
1428
1429 static int fiji_reset_single_dpm_table(struct pp_hwmgr *hwmgr,
1430                 struct fiji_single_dpm_table *dpm_table, uint32_t count)
1431 {
1432         int i;
1433         PP_ASSERT_WITH_CODE(count <= MAX_REGULAR_DPM_NUMBER,
1434                         "Fatal error, can not set up single DPM table entries "
1435                         "to exceed max number!",);
1436
1437         dpm_table->count = count;
1438         for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
1439                 dpm_table->dpm_levels[i].enabled = false;
1440
1441         return 0;
1442 }
1443
1444 static void fiji_setup_pcie_table_entry(
1445         struct fiji_single_dpm_table *dpm_table,
1446         uint32_t index, uint32_t pcie_gen,
1447         uint32_t pcie_lanes)
1448 {
1449         dpm_table->dpm_levels[index].value = pcie_gen;
1450         dpm_table->dpm_levels[index].param1 = pcie_lanes;
1451         dpm_table->dpm_levels[index].enabled = true;
1452 }
1453
1454 static int fiji_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
1455 {
1456         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1457         struct phm_ppt_v1_information *table_info =
1458                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1459         struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
1460         uint32_t i, max_entry;
1461
1462         PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels ||
1463                         data->use_pcie_power_saving_levels), "No pcie performance levels!",
1464                         return -EINVAL);
1465
1466         if (data->use_pcie_performance_levels &&
1467                         !data->use_pcie_power_saving_levels) {
1468                 data->pcie_gen_power_saving = data->pcie_gen_performance;
1469                 data->pcie_lane_power_saving = data->pcie_lane_performance;
1470         } else if (!data->use_pcie_performance_levels &&
1471                         data->use_pcie_power_saving_levels) {
1472                 data->pcie_gen_performance = data->pcie_gen_power_saving;
1473                 data->pcie_lane_performance = data->pcie_lane_power_saving;
1474         }
1475
1476         fiji_reset_single_dpm_table(hwmgr,
1477                         &data->dpm_table.pcie_speed_table, SMU73_MAX_LEVELS_LINK);
1478
1479         if (pcie_table != NULL) {
1480                 /* max_entry is used to make sure we reserve one PCIE level
1481                  * for boot level (fix for A+A PSPP issue).
1482                  * If PCIE table from PPTable have ULV entry + 8 entries,
1483                  * then ignore the last entry.*/
1484                 max_entry = (SMU73_MAX_LEVELS_LINK < pcie_table->count) ?
1485                                 SMU73_MAX_LEVELS_LINK : pcie_table->count;
1486                 for (i = 1; i < max_entry; i++) {
1487                         fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1,
1488                                         get_pcie_gen_support(data->pcie_gen_cap,
1489                                                         pcie_table->entries[i].gen_speed),
1490                                         get_pcie_lane_support(data->pcie_lane_cap,
1491                                                         pcie_table->entries[i].lane_width));
1492                 }
1493                 data->dpm_table.pcie_speed_table.count = max_entry - 1;
1494         } else {
1495                 /* Hardcode Pcie Table */
1496                 fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
1497                                 get_pcie_gen_support(data->pcie_gen_cap,
1498                                                 PP_Min_PCIEGen),
1499                                 get_pcie_lane_support(data->pcie_lane_cap,
1500                                                 PP_Max_PCIELane));
1501                 fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
1502                                 get_pcie_gen_support(data->pcie_gen_cap,
1503                                                 PP_Min_PCIEGen),
1504                                 get_pcie_lane_support(data->pcie_lane_cap,
1505                                                 PP_Max_PCIELane));
1506                 fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
1507                                 get_pcie_gen_support(data->pcie_gen_cap,
1508                                                 PP_Max_PCIEGen),
1509                                 get_pcie_lane_support(data->pcie_lane_cap,
1510                                                 PP_Max_PCIELane));
1511                 fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
1512                                 get_pcie_gen_support(data->pcie_gen_cap,
1513                                                 PP_Max_PCIEGen),
1514                                 get_pcie_lane_support(data->pcie_lane_cap,
1515                                                 PP_Max_PCIELane));
1516                 fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
1517                                 get_pcie_gen_support(data->pcie_gen_cap,
1518                                                 PP_Max_PCIEGen),
1519                                 get_pcie_lane_support(data->pcie_lane_cap,
1520                                                 PP_Max_PCIELane));
1521                 fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
1522                                 get_pcie_gen_support(data->pcie_gen_cap,
1523                                                 PP_Max_PCIEGen),
1524                                 get_pcie_lane_support(data->pcie_lane_cap,
1525                                                 PP_Max_PCIELane));
1526
1527                 data->dpm_table.pcie_speed_table.count = 6;
1528         }
1529         /* Populate last level for boot PCIE level, but do not increment count. */
1530         fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
1531                         data->dpm_table.pcie_speed_table.count,
1532                         get_pcie_gen_support(data->pcie_gen_cap,
1533                                         PP_Min_PCIEGen),
1534                         get_pcie_lane_support(data->pcie_lane_cap,
1535                                         PP_Max_PCIELane));
1536
1537         return 0;
1538 }
1539
1540 /*
1541  * This function is to initalize all DPM state tables
1542  * for SMU7 based on the dependency table.
1543  * Dynamic state patching function will then trim these
1544  * state tables to the allowed range based
1545  * on the power policy or external client requests,
1546  * such as UVD request, etc.
1547  */
1548 static int fiji_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
1549 {
1550         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1551         struct phm_ppt_v1_information *table_info =
1552                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1553         uint32_t i;
1554
1555         struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table =
1556                         table_info->vdd_dep_on_sclk;
1557         struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
1558                         table_info->vdd_dep_on_mclk;
1559
1560         PP_ASSERT_WITH_CODE(dep_sclk_table != NULL,
1561                         "SCLK dependency table is missing. This table is mandatory",
1562                         return -EINVAL);
1563         PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1,
1564                         "SCLK dependency table has to have is missing. "
1565                         "This table is mandatory",
1566                         return -EINVAL);
1567
1568         PP_ASSERT_WITH_CODE(dep_mclk_table != NULL,
1569                         "MCLK dependency table is missing. This table is mandatory",
1570                         return -EINVAL);
1571         PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
1572                         "MCLK dependency table has to have is missing. "
1573                         "This table is mandatory",
1574                         return -EINVAL);
1575
1576         /* clear the state table to reset everything to default */
1577         fiji_reset_single_dpm_table(hwmgr,
1578                         &data->dpm_table.sclk_table, SMU73_MAX_LEVELS_GRAPHICS);
1579         fiji_reset_single_dpm_table(hwmgr,
1580                         &data->dpm_table.mclk_table, SMU73_MAX_LEVELS_MEMORY);
1581
1582         /* Initialize Sclk DPM table based on allow Sclk values */
1583         data->dpm_table.sclk_table.count = 0;
1584         for (i = 0; i < dep_sclk_table->count; i++) {
1585                 if (i == 0 || data->dpm_table.sclk_table.dpm_levels
1586                                 [data->dpm_table.sclk_table.count - 1].value !=
1587                                                 dep_sclk_table->entries[i].clk) {
1588                         data->dpm_table.sclk_table.dpm_levels
1589                         [data->dpm_table.sclk_table.count].value =
1590                                         dep_sclk_table->entries[i].clk;
1591                         data->dpm_table.sclk_table.dpm_levels
1592                         [data->dpm_table.sclk_table.count].enabled =
1593                                         (i == 0) ? true : false;
1594                         data->dpm_table.sclk_table.count++;
1595                 }
1596         }
1597
1598         /* Initialize Mclk DPM table based on allow Mclk values */
1599         data->dpm_table.mclk_table.count = 0;
1600         for (i=0; i<dep_mclk_table->count; i++) {
1601                 if ( i==0 || data->dpm_table.mclk_table.dpm_levels
1602                                 [data->dpm_table.mclk_table.count - 1].value !=
1603                                                 dep_mclk_table->entries[i].clk) {
1604                         data->dpm_table.mclk_table.dpm_levels
1605                         [data->dpm_table.mclk_table.count].value =
1606                                         dep_mclk_table->entries[i].clk;
1607                         data->dpm_table.mclk_table.dpm_levels
1608                         [data->dpm_table.mclk_table.count].enabled =
1609                                         (i == 0) ? true : false;
1610                         data->dpm_table.mclk_table.count++;
1611                 }
1612         }
1613
1614         /* setup PCIE gen speed levels */
1615         fiji_setup_default_pcie_table(hwmgr);
1616
1617         /* save a copy of the default DPM table */
1618         memcpy(&(data->golden_dpm_table), &(data->dpm_table),
1619                         sizeof(struct fiji_dpm_table));
1620
1621         return 0;
1622 }
1623
1624 /**
1625  * @brief PhwFiji_GetVoltageOrder
1626  *  Returns index of requested voltage record in lookup(table)
1627  * @param lookup_table - lookup list to search in
1628  * @param voltage - voltage to look for
1629  * @return 0 on success
1630  */
1631 static uint8_t fiji_get_voltage_index(
1632                 struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
1633 {
1634         uint8_t count = (uint8_t) (lookup_table->count);
1635         uint8_t i;
1636
1637         PP_ASSERT_WITH_CODE((NULL != lookup_table),
1638                         "Lookup Table empty.", return 0);
1639         PP_ASSERT_WITH_CODE((0 != count),
1640                         "Lookup Table empty.", return 0);
1641
1642         for (i = 0; i < lookup_table->count; i++) {
1643                 /* find first voltage equal or bigger than requested */
1644                 if (lookup_table->entries[i].us_vdd >= voltage)
1645                         return i;
1646         }
1647         /* voltage is bigger than max voltage in the table */
1648         return i - 1;
1649 }
1650
1651 /**
1652 * Preparation of vddc and vddgfx CAC tables for SMC.
1653 *
1654 * @param    hwmgr  the address of the hardware manager
1655 * @param    table  the SMC DPM table structure to be populated
1656 * @return   always 0
1657 */
1658 static int fiji_populate_cac_table(struct pp_hwmgr *hwmgr,
1659                 struct SMU73_Discrete_DpmTable *table)
1660 {
1661         uint32_t count;
1662         uint8_t index;
1663         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1664         struct phm_ppt_v1_information *table_info =
1665                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1666         struct phm_ppt_v1_voltage_lookup_table *lookup_table =
1667                         table_info->vddc_lookup_table;
1668         /* tables is already swapped, so in order to use the value from it,
1669          * we need to swap it back.
1670          * We are populating vddc CAC data to BapmVddc table
1671          * in split and merged mode
1672          */
1673         for( count = 0; count<lookup_table->count; count++) {
1674                 index = fiji_get_voltage_index(lookup_table,
1675                                 data->vddc_voltage_table.entries[count].value);
1676                 table->BapmVddcVidLoSidd[count] = (uint8_t) ((6200 -
1677                                 (lookup_table->entries[index].us_cac_low *
1678                                                 VOLTAGE_SCALE)) / 25);
1679                 table->BapmVddcVidHiSidd[count] = (uint8_t) ((6200 -
1680                                 (lookup_table->entries[index].us_cac_high *
1681                                                 VOLTAGE_SCALE)) / 25);
1682         }
1683
1684         return 0;
1685 }
1686
1687 /**
1688 * Preparation of voltage tables for SMC.
1689 *
1690 * @param    hwmgr   the address of the hardware manager
1691 * @param    table   the SMC DPM table structure to be populated
1692 * @return   always  0
1693 */
1694
1695 static int fiji_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
1696                 struct SMU73_Discrete_DpmTable *table)
1697 {
1698         int result;
1699
1700         result = fiji_populate_cac_table(hwmgr, table);
1701         PP_ASSERT_WITH_CODE(0 == result,
1702                         "can not populate CAC voltage tables to SMC",
1703                         return -EINVAL);
1704
1705         return 0;
1706 }
1707
1708 static int fiji_populate_ulv_level(struct pp_hwmgr *hwmgr,
1709                 struct SMU73_Discrete_Ulv *state)
1710 {
1711         int result = 0;
1712         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1713         struct phm_ppt_v1_information *table_info =
1714                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1715
1716         state->CcPwrDynRm = 0;
1717         state->CcPwrDynRm1 = 0;
1718
1719         state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
1720         state->VddcOffsetVid = (uint8_t)( table_info->us_ulv_voltage_offset *
1721                         VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1 );
1722
1723         state->VddcPhase = (data->vddc_phase_shed_control) ? 0 : 1;
1724
1725         if (!result) {
1726                 CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
1727                 CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
1728                 CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
1729         }
1730         return result;
1731 }
1732
1733 static int fiji_populate_ulv_state(struct pp_hwmgr *hwmgr,
1734                 struct SMU73_Discrete_DpmTable *table)
1735 {
1736         return fiji_populate_ulv_level(hwmgr, &table->Ulv);
1737 }
1738
1739 static int32_t fiji_get_dpm_level_enable_mask_value(
1740                 struct fiji_single_dpm_table* dpm_table)
1741 {
1742         int32_t i;
1743         int32_t mask = 0;
1744
1745         for (i = dpm_table->count; i > 0; i--) {
1746                 mask = mask << 1;
1747                 if (dpm_table->dpm_levels[i - 1].enabled)
1748                         mask |= 0x1;
1749                 else
1750                         mask &= 0xFFFFFFFE;
1751         }
1752         return mask;
1753 }
1754
1755 static int fiji_populate_smc_link_level(struct pp_hwmgr *hwmgr,
1756                 struct SMU73_Discrete_DpmTable *table)
1757 {
1758         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1759         struct fiji_dpm_table *dpm_table = &data->dpm_table;
1760         int i;
1761
1762         /* Index (dpm_table->pcie_speed_table.count)
1763          * is reserved for PCIE boot level. */
1764         for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
1765                 table->LinkLevel[i].PcieGenSpeed  =
1766                                 (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
1767                 table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
1768                                 dpm_table->pcie_speed_table.dpm_levels[i].param1);
1769                 table->LinkLevel[i].EnabledForActivity = 1;
1770                 table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
1771                 table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
1772                 table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
1773         }
1774
1775         data->smc_state_table.LinkLevelCount =
1776                         (uint8_t)dpm_table->pcie_speed_table.count;
1777         data->dpm_level_enable_mask.pcie_dpm_enable_mask =
1778                         fiji_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
1779
1780         return 0;
1781 }
1782
1783 /**
1784 * Calculates the SCLK dividers using the provided engine clock
1785 *
1786 * @param    hwmgr  the address of the hardware manager
1787 * @param    clock  the engine clock to use to populate the structure
1788 * @param    sclk   the SMC SCLK structure to be populated
1789 */
1790 static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr,
1791                 uint32_t clock, struct SMU73_Discrete_GraphicsLevel *sclk)
1792 {
1793         const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1794         struct pp_atomctrl_clock_dividers_vi dividers;
1795         uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
1796         uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
1797         uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
1798         uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
1799         uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
1800         uint32_t ref_clock;
1801         uint32_t ref_divider;
1802         uint32_t fbdiv;
1803         int result;
1804
1805         /* get the engine clock dividers for this clock value */
1806         result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock,  &dividers);
1807
1808         PP_ASSERT_WITH_CODE(result == 0,
1809                         "Error retrieving Engine Clock dividers from VBIOS.",
1810                         return result);
1811
1812         /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
1813         ref_clock = atomctrl_get_reference_clock(hwmgr);
1814         ref_divider = 1 + dividers.uc_pll_ref_div;
1815
1816         /* low 14 bits is fraction and high 12 bits is divider */
1817         fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
1818
1819         /* SPLL_FUNC_CNTL setup */
1820         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
1821                         SPLL_REF_DIV, dividers.uc_pll_ref_div);
1822         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
1823                         SPLL_PDIV_A,  dividers.uc_pll_post_div);
1824
1825         /* SPLL_FUNC_CNTL_3 setup*/
1826         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
1827                         SPLL_FB_DIV, fbdiv);
1828
1829         /* set to use fractional accumulation*/
1830         spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
1831                         SPLL_DITHEN, 1);
1832
1833         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1834                                 PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
1835                 struct pp_atomctrl_internal_ss_info ssInfo;
1836
1837                 uint32_t vco_freq = clock * dividers.uc_pll_post_div;
1838                 if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
1839                                 vco_freq, &ssInfo)) {
1840                         /*
1841                          * ss_info.speed_spectrum_percentage -- in unit of 0.01%
1842                          * ss_info.speed_spectrum_rate -- in unit of khz
1843                          *
1844                          * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
1845                          */
1846                         uint32_t clk_s = ref_clock * 5 /
1847                                         (ref_divider * ssInfo.speed_spectrum_rate);
1848                         /* clkv = 2 * D * fbdiv / NS */
1849                         uint32_t clk_v = 4 * ssInfo.speed_spectrum_percentage *
1850                                         fbdiv / (clk_s * 10000);
1851
1852                         cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
1853                                         CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
1854                         cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
1855                                         CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
1856                         cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
1857                                         CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
1858                 }
1859         }
1860
1861         sclk->SclkFrequency        = clock;
1862         sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
1863         sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
1864         sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
1865         sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
1866         sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
1867
1868         return 0;
1869 }
1870
1871 static uint16_t fiji_find_closest_vddci(struct pp_hwmgr *hwmgr, uint16_t vddci)
1872 {
1873         uint32_t  i;
1874         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1875         struct pp_atomctrl_voltage_table *vddci_table =
1876                         &(data->vddci_voltage_table);
1877
1878         for (i = 0; i < vddci_table->count; i++) {
1879                 if (vddci_table->entries[i].value >= vddci)
1880                         return vddci_table->entries[i].value;
1881         }
1882
1883         PP_ASSERT_WITH_CODE(false,
1884                         "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
1885                         return vddci_table->entries[i-1].value);
1886 }
1887
1888 static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
1889                 struct phm_ppt_v1_clock_voltage_dependency_table* dep_table,
1890                 uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
1891 {
1892         uint32_t i;
1893         uint16_t vddci;
1894         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1895
1896         *voltage = *mvdd = 0;
1897
1898         /* clock - voltage dependency table is empty table */
1899         if (dep_table->count == 0)
1900                 return -EINVAL;
1901
1902         for (i = 0; i < dep_table->count; i++) {
1903                 /* find first sclk bigger than request */
1904                 if (dep_table->entries[i].clk >= clock) {
1905                         *voltage |= (dep_table->entries[i].vddc *
1906                                         VOLTAGE_SCALE) << VDDC_SHIFT;
1907                         if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
1908                                 *voltage |= (data->vbios_boot_state.vddci_bootup_value *
1909                                                 VOLTAGE_SCALE) << VDDCI_SHIFT;
1910                         else if (dep_table->entries[i].vddci)
1911                                 *voltage |= (dep_table->entries[i].vddci *
1912                                                 VOLTAGE_SCALE) << VDDCI_SHIFT;
1913                         else {
1914                                 vddci = fiji_find_closest_vddci(hwmgr,
1915                                                 (dep_table->entries[i].vddc -
1916                                                                 (uint16_t)data->vddc_vddci_delta));
1917                                 *voltage |= (vddci * VOLTAGE_SCALE) <<  VDDCI_SHIFT;
1918                         }
1919
1920                         if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
1921                                 *mvdd = data->vbios_boot_state.mvdd_bootup_value *
1922                                         VOLTAGE_SCALE;
1923                         else if (dep_table->entries[i].mvdd)
1924                                 *mvdd = (uint32_t) dep_table->entries[i].mvdd *
1925                                         VOLTAGE_SCALE;
1926
1927                         *voltage |= 1 << PHASES_SHIFT;
1928                         return 0;
1929                 }
1930         }
1931
1932         /* sclk is bigger than max sclk in the dependence table */
1933         *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
1934
1935         if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
1936                 *voltage |= (data->vbios_boot_state.vddci_bootup_value *
1937                                 VOLTAGE_SCALE) << VDDCI_SHIFT;
1938         else if (dep_table->entries[i-1].vddci) {
1939                 vddci = fiji_find_closest_vddci(hwmgr,
1940                                 (dep_table->entries[i].vddc -
1941                                                 (uint16_t)data->vddc_vddci_delta));
1942                 *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
1943         }
1944
1945         if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
1946                 *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
1947         else if (dep_table->entries[i].mvdd)
1948                 *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
1949
1950         return 0;
1951 }
1952
1953 static uint8_t fiji_get_sleep_divider_id_from_clock(uint32_t clock,
1954                 uint32_t clock_insr)
1955 {
1956         uint8_t i;
1957         uint32_t temp;
1958         uint32_t min = max(clock_insr, (uint32_t)FIJI_MINIMUM_ENGINE_CLOCK);
1959
1960         PP_ASSERT_WITH_CODE((clock >= min), "Engine clock can't satisfy stutter requirement!", return 0);
1961         for (i = FIJI_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
1962                 temp = clock >> i;
1963
1964                 if (temp >= min || i == 0)
1965                         break;
1966         }
1967         return i;
1968 }
1969 /**
1970 * Populates single SMC SCLK structure using the provided engine clock
1971 *
1972 * @param    hwmgr      the address of the hardware manager
1973 * @param    clock the engine clock to use to populate the structure
1974 * @param    sclk        the SMC SCLK structure to be populated
1975 */
1976
1977 static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
1978                 uint32_t clock, uint16_t sclk_al_threshold,
1979                 struct SMU73_Discrete_GraphicsLevel *level)
1980 {
1981         int result;
1982         /* PP_Clocks minClocks; */
1983         uint32_t threshold, mvdd;
1984         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
1985         struct phm_ppt_v1_information *table_info =
1986                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
1987
1988         result = fiji_calculate_sclk_params(hwmgr, clock, level);
1989
1990         /* populate graphics levels */
1991         result = fiji_get_dependency_volt_by_clk(hwmgr,
1992                         table_info->vdd_dep_on_sclk, clock,
1993                         &level->MinVoltage, &mvdd);
1994         PP_ASSERT_WITH_CODE((0 == result),
1995                         "can not find VDDC voltage value for "
1996                         "VDDC engine clock dependency table",
1997                         return result);
1998
1999         level->SclkFrequency = clock;
2000         level->ActivityLevel = sclk_al_threshold;
2001         level->CcPwrDynRm = 0;
2002         level->CcPwrDynRm1 = 0;
2003         level->EnabledForActivity = 0;
2004         level->EnabledForThrottle = 1;
2005         level->UpHyst = 10;
2006         level->DownHyst = 0;
2007         level->VoltageDownHyst = 0;
2008         level->PowerThrottle = 0;
2009
2010         threshold = clock * data->fast_watermark_threshold / 100;
2011
2012
2013         data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr;
2014
2015         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
2016                 level->DeepSleepDivId = fiji_get_sleep_divider_id_from_clock(clock,
2017                                                                 hwmgr->display_config.min_core_set_clock_in_sr);
2018
2019
2020         /* Default to slow, highest DPM level will be
2021          * set to PPSMC_DISPLAY_WATERMARK_LOW later.
2022          */
2023         level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2024
2025         CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
2026         CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
2027         CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
2028         CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
2029         CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
2030         CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
2031         CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
2032         CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
2033         CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
2034
2035         return 0;
2036 }
2037 /**
2038 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
2039 *
2040 * @param    hwmgr      the address of the hardware manager
2041 */
2042 static int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
2043 {
2044         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2045         struct fiji_dpm_table *dpm_table = &data->dpm_table;
2046         struct phm_ppt_v1_information *table_info =
2047                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2048         struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
2049         uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count;
2050         int result = 0;
2051         uint32_t array = data->dpm_table_start +
2052                         offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
2053         uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) *
2054                         SMU73_MAX_LEVELS_GRAPHICS;
2055         struct SMU73_Discrete_GraphicsLevel *levels =
2056                         data->smc_state_table.GraphicsLevel;
2057         uint32_t i, max_entry;
2058         uint8_t hightest_pcie_level_enabled = 0,
2059                         lowest_pcie_level_enabled = 0,
2060                         mid_pcie_level_enabled = 0,
2061                         count = 0;
2062
2063         for (i = 0; i < dpm_table->sclk_table.count; i++) {
2064                 result = fiji_populate_single_graphic_level(hwmgr,
2065                                 dpm_table->sclk_table.dpm_levels[i].value,
2066                                 (uint16_t)data->activity_target[i],
2067                                 &levels[i]);
2068                 if (result)
2069                         return result;
2070
2071                 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
2072                 if (i > 1)
2073                         levels[i].DeepSleepDivId = 0;
2074         }
2075
2076         /* Only enable level 0 for now.*/
2077         levels[0].EnabledForActivity = 1;
2078
2079         /* set highest level watermark to high */
2080         levels[dpm_table->sclk_table.count - 1].DisplayWatermark =
2081                         PPSMC_DISPLAY_WATERMARK_HIGH;
2082
2083         data->smc_state_table.GraphicsDpmLevelCount =
2084                         (uint8_t)dpm_table->sclk_table.count;
2085         data->dpm_level_enable_mask.sclk_dpm_enable_mask =
2086                         fiji_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
2087
2088         if (pcie_table != NULL) {
2089                 PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
2090                                 "There must be 1 or more PCIE levels defined in PPTable.",
2091                                 return -EINVAL);
2092                 max_entry = pcie_entry_cnt - 1;
2093                 for (i = 0; i < dpm_table->sclk_table.count; i++)
2094                         levels[i].pcieDpmLevel =
2095                                         (uint8_t) ((i < max_entry)? i : max_entry);
2096         } else {
2097                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
2098                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2099                                                 (1 << (hightest_pcie_level_enabled + 1))) != 0 ))
2100                         hightest_pcie_level_enabled++;
2101
2102                 while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
2103                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2104                                                 (1 << lowest_pcie_level_enabled)) == 0 ))
2105                         lowest_pcie_level_enabled++;
2106
2107                 while ((count < hightest_pcie_level_enabled) &&
2108                                 ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
2109                                                 (1 << (lowest_pcie_level_enabled + 1 + count))) == 0 ))
2110                         count++;
2111
2112                 mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1+ count) <
2113                                 hightest_pcie_level_enabled?
2114                                                 (lowest_pcie_level_enabled + 1 + count) :
2115                                                 hightest_pcie_level_enabled;
2116
2117                 /* set pcieDpmLevel to hightest_pcie_level_enabled */
2118                 for(i = 2; i < dpm_table->sclk_table.count; i++)
2119                         levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
2120
2121                 /* set pcieDpmLevel to lowest_pcie_level_enabled */
2122                 levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
2123
2124                 /* set pcieDpmLevel to mid_pcie_level_enabled */
2125                 levels[1].pcieDpmLevel = mid_pcie_level_enabled;
2126         }
2127         /* level count will send to smc once at init smc table and never change */
2128         result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
2129                         (uint32_t)array_size, data->sram_end);
2130
2131         return result;
2132 }
2133
2134 /**
2135  * MCLK Frequency Ratio
2136  * SEQ_CG_RESP  Bit[31:24] - 0x0
2137  * Bit[27:24] \96 DDR3 Frequency ratio
2138  * 0x0 <= 100MHz,       450 < 0x8 <= 500MHz
2139  * 100 < 0x1 <= 150MHz,       500 < 0x9 <= 550MHz
2140  * 150 < 0x2 <= 200MHz,       550 < 0xA <= 600MHz
2141  * 200 < 0x3 <= 250MHz,       600 < 0xB <= 650MHz
2142  * 250 < 0x4 <= 300MHz,       650 < 0xC <= 700MHz
2143  * 300 < 0x5 <= 350MHz,       700 < 0xD <= 750MHz
2144  * 350 < 0x6 <= 400MHz,       750 < 0xE <= 800MHz
2145  * 400 < 0x7 <= 450MHz,       800 < 0xF
2146  */
2147 static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock)
2148 {
2149         if (mem_clock <= 10000) return 0x0;
2150         if (mem_clock <= 15000) return 0x1;
2151         if (mem_clock <= 20000) return 0x2;
2152         if (mem_clock <= 25000) return 0x3;
2153         if (mem_clock <= 30000) return 0x4;
2154         if (mem_clock <= 35000) return 0x5;
2155         if (mem_clock <= 40000) return 0x6;
2156         if (mem_clock <= 45000) return 0x7;
2157         if (mem_clock <= 50000) return 0x8;
2158         if (mem_clock <= 55000) return 0x9;
2159         if (mem_clock <= 60000) return 0xa;
2160         if (mem_clock <= 65000) return 0xb;
2161         if (mem_clock <= 70000) return 0xc;
2162         if (mem_clock <= 75000) return 0xd;
2163         if (mem_clock <= 80000) return 0xe;
2164         /* mem_clock > 800MHz */
2165         return 0xf;
2166 }
2167
2168 /**
2169 * Populates the SMC MCLK structure using the provided memory clock
2170 *
2171 * @param    hwmgr   the address of the hardware manager
2172 * @param    clock   the memory clock to use to populate the structure
2173 * @param    sclk    the SMC SCLK structure to be populated
2174 */
2175 static int fiji_calculate_mclk_params(struct pp_hwmgr *hwmgr,
2176     uint32_t clock, struct SMU73_Discrete_MemoryLevel *mclk)
2177 {
2178         struct pp_atomctrl_memory_clock_param mem_param;
2179         int result;
2180
2181         result = atomctrl_get_memory_pll_dividers_vi(hwmgr, clock, &mem_param);
2182         PP_ASSERT_WITH_CODE((0 == result),
2183                         "Failed to get Memory PLL Dividers.",);
2184
2185         /* Save the result data to outpupt memory level structure */
2186         mclk->MclkFrequency   = clock;
2187         mclk->MclkDivider     = (uint8_t)mem_param.mpll_post_divider;
2188         mclk->FreqRange       = fiji_get_mclk_frequency_ratio(clock);
2189
2190         return result;
2191 }
2192
2193 static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr,
2194                 uint32_t clock, struct SMU73_Discrete_MemoryLevel *mem_level)
2195 {
2196         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2197         struct phm_ppt_v1_information *table_info =
2198                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2199         int result = 0;
2200
2201         if (table_info->vdd_dep_on_mclk) {
2202                 result = fiji_get_dependency_volt_by_clk(hwmgr,
2203                                 table_info->vdd_dep_on_mclk, clock,
2204                                 &mem_level->MinVoltage, &mem_level->MinMvdd);
2205                 PP_ASSERT_WITH_CODE((0 == result),
2206                                 "can not find MinVddc voltage value from memory "
2207                                 "VDDC voltage dependency table", return result);
2208         }
2209
2210         mem_level->EnabledForThrottle = 1;
2211         mem_level->EnabledForActivity = 0;
2212         mem_level->UpHyst = 0;
2213         mem_level->DownHyst = 100;
2214         mem_level->VoltageDownHyst = 0;
2215         mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
2216         mem_level->StutterEnable = false;
2217
2218         mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2219
2220         /* enable stutter mode if all the follow condition applied
2221          * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
2222          * &(data->DisplayTiming.numExistingDisplays));
2223          */
2224         data->display_timing.num_existing_displays = 1;
2225
2226         if ((data->mclk_stutter_mode_threshold) &&
2227                 (clock <= data->mclk_stutter_mode_threshold) &&
2228                 (!data->is_uvd_enabled) &&
2229                 (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
2230                                 STUTTER_ENABLE) & 0x1))
2231                 mem_level->StutterEnable = true;
2232
2233         result = fiji_calculate_mclk_params(hwmgr, clock, mem_level);
2234         if (!result) {
2235                 CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
2236                 CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
2237                 CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
2238                 CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
2239         }
2240         return result;
2241 }
2242
2243 /**
2244 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
2245 *
2246 * @param    hwmgr      the address of the hardware manager
2247 */
2248 static int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
2249 {
2250         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2251         struct fiji_dpm_table *dpm_table = &data->dpm_table;
2252         int result;
2253         /* populate MCLK dpm table to SMU7 */
2254         uint32_t array = data->dpm_table_start +
2255                         offsetof(SMU73_Discrete_DpmTable, MemoryLevel);
2256         uint32_t array_size = sizeof(SMU73_Discrete_MemoryLevel) *
2257                         SMU73_MAX_LEVELS_MEMORY;
2258         struct SMU73_Discrete_MemoryLevel *levels =
2259                         data->smc_state_table.MemoryLevel;
2260         uint32_t i;
2261
2262         for (i = 0; i < dpm_table->mclk_table.count; i++) {
2263                 PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
2264                                 "can not populate memory level as memory clock is zero",
2265                                 return -EINVAL);
2266                 result = fiji_populate_single_memory_level(hwmgr,
2267                                 dpm_table->mclk_table.dpm_levels[i].value,
2268                                 &levels[i]);
2269                 if (result)
2270                         return result;
2271         }
2272
2273         /* Only enable level 0 for now. */
2274         levels[0].EnabledForActivity = 1;
2275
2276         /* in order to prevent MC activity from stutter mode to push DPM up.
2277          * the UVD change complements this by putting the MCLK in
2278          * a higher state by default such that we are not effected by
2279          * up threshold or and MCLK DPM latency.
2280          */
2281         levels[0].ActivityLevel = (uint16_t)data->mclk_dpm0_activity_target;
2282         CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
2283
2284         data->smc_state_table.MemoryDpmLevelCount =
2285                         (uint8_t)dpm_table->mclk_table.count;
2286         data->dpm_level_enable_mask.mclk_dpm_enable_mask =
2287                         fiji_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
2288         /* set highest level watermark to high */
2289         levels[dpm_table->mclk_table.count - 1].DisplayWatermark =
2290                         PPSMC_DISPLAY_WATERMARK_HIGH;
2291
2292         /* level count will send to smc once at init smc table and never change */
2293         result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
2294                         (uint32_t)array_size, data->sram_end);
2295
2296         return result;
2297 }
2298
2299 /**
2300 * Populates the SMC MVDD structure using the provided memory clock.
2301 *
2302 * @param    hwmgr      the address of the hardware manager
2303 * @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
2304 * @param    voltage     the SMC VOLTAGE structure to be populated
2305 */
2306 static int fiji_populate_mvdd_value(struct pp_hwmgr *hwmgr,
2307                 uint32_t mclk, SMIO_Pattern *smio_pat)
2308 {
2309         const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2310         struct phm_ppt_v1_information *table_info =
2311                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2312         uint32_t i = 0;
2313
2314         if (FIJI_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
2315                 /* find mvdd value which clock is more than request */
2316                 for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
2317                         if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
2318                                 smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
2319                                 break;
2320                         }
2321                 }
2322                 PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
2323                                 "MVDD Voltage is outside the supported range.",
2324                                 return -EINVAL);
2325         } else
2326                 return -EINVAL;
2327
2328         return 0;
2329 }
2330
2331 static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
2332                 SMU73_Discrete_DpmTable *table)
2333 {
2334         int result = 0;
2335         const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2336         struct phm_ppt_v1_information *table_info =
2337                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2338         struct pp_atomctrl_clock_dividers_vi dividers;
2339         SMIO_Pattern vol_level;
2340         uint32_t mvdd;
2341         uint16_t us_mvdd;
2342         uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
2343         uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
2344
2345         table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
2346
2347         if (!data->sclk_dpm_key_disabled) {
2348                 /* Get MinVoltage and Frequency from DPM0,
2349                  * already converted to SMC_UL */
2350                 table->ACPILevel.SclkFrequency =
2351                                 data->dpm_table.sclk_table.dpm_levels[0].value;
2352                 result = fiji_get_dependency_volt_by_clk(hwmgr,
2353                                 table_info->vdd_dep_on_sclk,
2354                                 table->ACPILevel.SclkFrequency,
2355                                 &table->ACPILevel.MinVoltage, &mvdd);
2356                 PP_ASSERT_WITH_CODE((0 == result),
2357                                 "Cannot find ACPI VDDC voltage value "
2358                                 "in Clock Dependency Table",);
2359         } else {
2360                 table->ACPILevel.SclkFrequency =
2361                                 data->vbios_boot_state.sclk_bootup_value;
2362                 table->ACPILevel.MinVoltage =
2363                                 data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE;
2364         }
2365
2366         /* get the engine clock dividers for this clock value */
2367         result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
2368                         table->ACPILevel.SclkFrequency,  &dividers);
2369         PP_ASSERT_WITH_CODE(result == 0,
2370                         "Error retrieving Engine Clock dividers from VBIOS.",
2371                         return result);
2372
2373         table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
2374         table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
2375         table->ACPILevel.DeepSleepDivId = 0;
2376
2377         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
2378                         SPLL_PWRON, 0);
2379         spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
2380                         SPLL_RESET, 1);
2381         spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
2382                         SCLK_MUX_SEL, 4);
2383
2384         table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
2385         table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
2386         table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
2387         table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
2388         table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
2389         table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
2390         table->ACPILevel.CcPwrDynRm = 0;
2391         table->ACPILevel.CcPwrDynRm1 = 0;
2392
2393         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
2394         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
2395         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
2396         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
2397         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
2398         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
2399         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
2400         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
2401         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
2402         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
2403         CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
2404
2405         if (!data->mclk_dpm_key_disabled) {
2406                 /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
2407                 table->MemoryACPILevel.MclkFrequency =
2408                                 data->dpm_table.mclk_table.dpm_levels[0].value;
2409                 result = fiji_get_dependency_volt_by_clk(hwmgr,
2410                                 table_info->vdd_dep_on_mclk,
2411                                 table->MemoryACPILevel.MclkFrequency,
2412                                 &table->MemoryACPILevel.MinVoltage, &mvdd);
2413                 PP_ASSERT_WITH_CODE((0 == result),
2414                                 "Cannot find ACPI VDDCI voltage value "
2415                                 "in Clock Dependency Table",);
2416         } else {
2417                 table->MemoryACPILevel.MclkFrequency =
2418                                 data->vbios_boot_state.mclk_bootup_value;
2419                 table->MemoryACPILevel.MinVoltage =
2420                                 data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE;
2421         }
2422
2423         us_mvdd = 0;
2424         if ((FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
2425                         (data->mclk_dpm_key_disabled))
2426                 us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
2427         else {
2428                 if (!fiji_populate_mvdd_value(hwmgr,
2429                                 data->dpm_table.mclk_table.dpm_levels[0].value,
2430                                 &vol_level))
2431                         us_mvdd = vol_level.Voltage;
2432         }
2433
2434         table->MemoryACPILevel.MinMvdd =
2435                         PP_HOST_TO_SMC_UL(us_mvdd * VOLTAGE_SCALE);
2436
2437         table->MemoryACPILevel.EnabledForThrottle = 0;
2438         table->MemoryACPILevel.EnabledForActivity = 0;
2439         table->MemoryACPILevel.UpHyst = 0;
2440         table->MemoryACPILevel.DownHyst = 100;
2441         table->MemoryACPILevel.VoltageDownHyst = 0;
2442         table->MemoryACPILevel.ActivityLevel =
2443                         PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
2444
2445         table->MemoryACPILevel.StutterEnable = false;
2446         CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
2447         CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
2448
2449         return result;
2450 }
2451
2452 static int fiji_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
2453                 SMU73_Discrete_DpmTable *table)
2454 {
2455         int result = -EINVAL;
2456         uint8_t count;
2457         struct pp_atomctrl_clock_dividers_vi dividers;
2458         struct phm_ppt_v1_information *table_info =
2459                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2460         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
2461                         table_info->mm_dep_table;
2462         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2463
2464         table->VceLevelCount = (uint8_t)(mm_table->count);
2465         table->VceBootLevel = 0;
2466
2467         for(count = 0; count < table->VceLevelCount; count++) {
2468                 table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
2469                 table->VceLevel[count].MinVoltage = 0;
2470                 table->VceLevel[count].MinVoltage |=
2471                                 (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
2472                 table->VceLevel[count].MinVoltage |=
2473                                 ((mm_table->entries[count].vddc - data->vddc_vddci_delta) *
2474                                                 VOLTAGE_SCALE) << VDDCI_SHIFT;
2475                 table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
2476
2477                 /*retrieve divider value for VBIOS */
2478                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2479                                 table->VceLevel[count].Frequency, &dividers);
2480                 PP_ASSERT_WITH_CODE((0 == result),
2481                                 "can not find divide id for VCE engine clock",
2482                                 return result);
2483
2484                 table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
2485
2486                 CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
2487                 CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
2488         }
2489         return result;
2490 }
2491
2492 static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
2493                 SMU73_Discrete_DpmTable *table)
2494 {
2495         int result = -EINVAL;
2496         uint8_t count;
2497         struct pp_atomctrl_clock_dividers_vi dividers;
2498         struct phm_ppt_v1_information *table_info =
2499                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2500         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
2501                         table_info->mm_dep_table;
2502         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2503
2504         table->AcpLevelCount = (uint8_t)(mm_table->count);
2505         table->AcpBootLevel = 0;
2506
2507         for (count = 0; count < table->AcpLevelCount; count++) {
2508                 table->AcpLevel[count].Frequency = mm_table->entries[count].aclk;
2509                 table->AcpLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
2510                                 VOLTAGE_SCALE) << VDDC_SHIFT;
2511                 table->AcpLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
2512                                 data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
2513                 table->AcpLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
2514
2515                 /* retrieve divider value for VBIOS */
2516                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2517                                 table->AcpLevel[count].Frequency, &dividers);
2518                 PP_ASSERT_WITH_CODE((0 == result),
2519                                 "can not find divide id for engine clock", return result);
2520
2521                 table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
2522
2523                 CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
2524                 CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].MinVoltage);
2525         }
2526         return result;
2527 }
2528
2529 static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
2530                 SMU73_Discrete_DpmTable *table)
2531 {
2532         int result = -EINVAL;
2533         uint8_t count;
2534         struct pp_atomctrl_clock_dividers_vi dividers;
2535         struct phm_ppt_v1_information *table_info =
2536                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2537         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
2538                         table_info->mm_dep_table;
2539         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2540
2541         table->SamuBootLevel = 0;
2542         table->SamuLevelCount = (uint8_t)(mm_table->count);
2543
2544         for (count = 0; count < table->SamuLevelCount; count++) {
2545                 /* not sure whether we need evclk or not */
2546                 table->SamuLevel[count].MinVoltage = 0;
2547                 table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
2548                 table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
2549                                 VOLTAGE_SCALE) << VDDC_SHIFT;
2550                 table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
2551                                 data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
2552                 table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
2553
2554                 /* retrieve divider value for VBIOS */
2555                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2556                                 table->SamuLevel[count].Frequency, &dividers);
2557                 PP_ASSERT_WITH_CODE((0 == result),
2558                                 "can not find divide id for samu clock", return result);
2559
2560                 table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
2561
2562                 CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
2563                 CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
2564         }
2565         return result;
2566 }
2567
2568 static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
2569                 int32_t eng_clock, int32_t mem_clock,
2570                 struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs)
2571 {
2572         uint32_t dram_timing;
2573         uint32_t dram_timing2;
2574         uint32_t burstTime;
2575         ULONG state, trrds, trrdl;
2576         int result;
2577
2578         result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
2579                         eng_clock, mem_clock);
2580         PP_ASSERT_WITH_CODE(result == 0,
2581                         "Error calling VBIOS to set DRAM_TIMING.", return result);
2582
2583         dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
2584         dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
2585         burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME);
2586
2587         state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0);
2588         trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0);
2589         trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0);
2590
2591         arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dram_timing);
2592         arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
2593         arb_regs->McArbBurstTime   = (uint8_t)burstTime;
2594         arb_regs->TRRDS            = (uint8_t)trrds;
2595         arb_regs->TRRDL            = (uint8_t)trrdl;
2596
2597         return 0;
2598 }
2599
2600 static int fiji_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
2601 {
2602         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2603         struct SMU73_Discrete_MCArbDramTimingTable arb_regs;
2604         uint32_t i, j;
2605         int result = 0;
2606
2607         for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
2608                 for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
2609                         result = fiji_populate_memory_timing_parameters(hwmgr,
2610                                         data->dpm_table.sclk_table.dpm_levels[i].value,
2611                                         data->dpm_table.mclk_table.dpm_levels[j].value,
2612                                         &arb_regs.entries[i][j]);
2613                         if (result)
2614                                 break;
2615                 }
2616         }
2617
2618         if (!result)
2619                 result = fiji_copy_bytes_to_smc(
2620                                 hwmgr->smumgr,
2621                                 data->arb_table_start,
2622                                 (uint8_t *)&arb_regs,
2623                                 sizeof(SMU73_Discrete_MCArbDramTimingTable),
2624                                 data->sram_end);
2625         return result;
2626 }
2627
2628 static int fiji_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
2629                 struct SMU73_Discrete_DpmTable *table)
2630 {
2631         int result = -EINVAL;
2632         uint8_t count;
2633         struct pp_atomctrl_clock_dividers_vi dividers;
2634         struct phm_ppt_v1_information *table_info =
2635                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2636         struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
2637                         table_info->mm_dep_table;
2638         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2639
2640         table->UvdLevelCount = (uint8_t)(mm_table->count);
2641         table->UvdBootLevel = 0;
2642
2643         for (count = 0; count < table->UvdLevelCount; count++) {
2644                 table->UvdLevel[count].MinVoltage = 0;
2645                 table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
2646                 table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
2647                 table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
2648                                 VOLTAGE_SCALE) << VDDC_SHIFT;
2649                 table->UvdLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
2650                                 data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
2651                 table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
2652
2653                 /* retrieve divider value for VBIOS */
2654                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2655                                 table->UvdLevel[count].VclkFrequency, &dividers);
2656                 PP_ASSERT_WITH_CODE((0 == result),
2657                                 "can not find divide id for Vclk clock", return result);
2658
2659                 table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
2660
2661                 result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
2662                                 table->UvdLevel[count].DclkFrequency, &dividers);
2663                 PP_ASSERT_WITH_CODE((0 == result),
2664                                 "can not find divide id for Dclk clock", return result);
2665
2666                 table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
2667
2668                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
2669                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
2670                 CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
2671
2672         }
2673         return result;
2674 }
2675
2676 static int fiji_find_boot_level(struct fiji_single_dpm_table *table,
2677                 uint32_t value, uint32_t *boot_level)
2678 {
2679         int result = -EINVAL;
2680         uint32_t i;
2681
2682         for (i = 0; i < table->count; i++) {
2683                 if (value == table->dpm_levels[i].value) {
2684                         *boot_level = i;
2685                         result = 0;
2686                 }
2687         }
2688         return result;
2689 }
2690
2691 static int fiji_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
2692                 struct SMU73_Discrete_DpmTable *table)
2693 {
2694         int result = 0;
2695         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2696
2697         table->GraphicsBootLevel = 0;
2698         table->MemoryBootLevel = 0;
2699
2700         /* find boot level from dpm table */
2701         result = fiji_find_boot_level(&(data->dpm_table.sclk_table),
2702                         data->vbios_boot_state.sclk_bootup_value,
2703                         (uint32_t *)&(table->GraphicsBootLevel));
2704
2705         result = fiji_find_boot_level(&(data->dpm_table.mclk_table),
2706                         data->vbios_boot_state.mclk_bootup_value,
2707                         (uint32_t *)&(table->MemoryBootLevel));
2708
2709         table->BootVddc  = data->vbios_boot_state.vddc_bootup_value *
2710                         VOLTAGE_SCALE;
2711         table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
2712                         VOLTAGE_SCALE;
2713         table->BootMVdd  = data->vbios_boot_state.mvdd_bootup_value *
2714                         VOLTAGE_SCALE;
2715
2716         CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
2717         CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
2718         CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
2719
2720         return 0;
2721 }
2722
2723 static int fiji_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
2724 {
2725         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2726         struct phm_ppt_v1_information *table_info =
2727                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2728         uint8_t count, level;
2729
2730         count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
2731         for (level = 0; level < count; level++) {
2732                 if(table_info->vdd_dep_on_sclk->entries[level].clk >=
2733                                 data->vbios_boot_state.sclk_bootup_value) {
2734                         data->smc_state_table.GraphicsBootLevel = level;
2735                         break;
2736                 }
2737         }
2738
2739         count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
2740         for (level = 0; level < count; level++) {
2741                 if(table_info->vdd_dep_on_mclk->entries[level].clk >=
2742                                 data->vbios_boot_state.mclk_bootup_value) {
2743                         data->smc_state_table.MemoryBootLevel = level;
2744                         break;
2745                 }
2746         }
2747
2748         return 0;
2749 }
2750
2751 static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
2752 {
2753         uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
2754                         volt_with_cks, value;
2755         uint16_t clock_freq_u16;
2756         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2757         uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
2758                         volt_offset = 0;
2759         struct phm_ppt_v1_information *table_info =
2760                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2761         struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
2762                         table_info->vdd_dep_on_sclk;
2763
2764         stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
2765
2766         /* Read SMU_Eefuse to read and calculate RO and determine
2767          * if the part is SS or FF. if RO >= 1660MHz, part is FF.
2768          */
2769         efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2770                         ixSMU_EFUSE_0 + (146 * 4));
2771         efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2772                         ixSMU_EFUSE_0 + (148 * 4));
2773         efuse &= 0xFF000000;
2774         efuse = efuse >> 24;
2775         efuse2 &= 0xF;
2776
2777         if (efuse2 == 1)
2778                 ro = (2300 - 1350) * efuse / 255 + 1350;
2779         else
2780                 ro = (2500 - 1000) * efuse / 255 + 1000;
2781
2782         if (ro >= 1660)
2783                 type = 0;
2784         else
2785                 type = 1;
2786
2787         /* Populate Stretch amount */
2788         data->smc_state_table.ClockStretcherAmount = stretch_amount;
2789
2790         /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
2791         for (i = 0; i < sclk_table->count; i++) {
2792                 data->smc_state_table.Sclk_CKS_masterEn0_7 |=
2793                                 sclk_table->entries[i].cks_enable << i;
2794                 volt_without_cks = (uint32_t)((14041 *
2795                         (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
2796                         (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
2797                 volt_with_cks = (uint32_t)((13946 *
2798                         (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
2799                         (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
2800                 if (volt_without_cks >= volt_with_cks)
2801                         volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
2802                                         sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
2803                 data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
2804         }
2805
2806         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
2807                         STRETCH_ENABLE, 0x0);
2808         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
2809                         masterReset, 0x1);
2810         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
2811                         staticEnable, 0x1);
2812         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
2813                         masterReset, 0x0);
2814
2815         /* Populate CKS Lookup Table */
2816         if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
2817                 stretch_amount2 = 0;
2818         else if (stretch_amount == 3 || stretch_amount == 4)
2819                 stretch_amount2 = 1;
2820         else {
2821                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
2822                                 PHM_PlatformCaps_ClockStretcher);
2823                 PP_ASSERT_WITH_CODE(false,
2824                                 "Stretch Amount in PPTable not supported\n",
2825                                 return -EINVAL);
2826         }
2827
2828         value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2829                         ixPWR_CKS_CNTL);
2830         value &= 0xFFC2FF87;
2831         data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
2832                         fiji_clock_stretcher_lookup_table[stretch_amount2][0];
2833         data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
2834                         fiji_clock_stretcher_lookup_table[stretch_amount2][1];
2835         clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(data->smc_state_table.
2836                         GraphicsLevel[data->smc_state_table.GraphicsDpmLevelCount - 1].
2837                         SclkFrequency) / 100);
2838         if (fiji_clock_stretcher_lookup_table[stretch_amount2][0] <
2839                         clock_freq_u16 &&
2840             fiji_clock_stretcher_lookup_table[stretch_amount2][1] >
2841                         clock_freq_u16) {
2842                 /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
2843                 value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
2844                 /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
2845                 value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
2846                 /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
2847                 value |= (fiji_clock_stretch_amount_conversion
2848                                 [fiji_clock_stretcher_lookup_table[stretch_amount2][3]]
2849                                  [stretch_amount]) << 3;
2850         }
2851         CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
2852                         CKS_LOOKUPTableEntry[0].minFreq);
2853         CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
2854                         CKS_LOOKUPTableEntry[0].maxFreq);
2855         data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
2856                         fiji_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
2857         data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
2858                         (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
2859
2860         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
2861                         ixPWR_CKS_CNTL, value);
2862
2863         /* Populate DDT Lookup Table */
2864         for (i = 0; i < 4; i++) {
2865                 /* Assign the minimum and maximum VID stored
2866                  * in the last row of Clock Stretcher Voltage Table.
2867                  */
2868                 data->smc_state_table.ClockStretcherDataTable.
2869                 ClockStretcherDataTableEntry[i].minVID =
2870                                 (uint8_t) fiji_clock_stretcher_ddt_table[type][i][2];
2871                 data->smc_state_table.ClockStretcherDataTable.
2872                 ClockStretcherDataTableEntry[i].maxVID =
2873                                 (uint8_t) fiji_clock_stretcher_ddt_table[type][i][3];
2874                 /* Loop through each SCLK and check the frequency
2875                  * to see if it lies within the frequency for clock stretcher.
2876                  */
2877                 for (j = 0; j < data->smc_state_table.GraphicsDpmLevelCount; j++) {
2878                         cks_setting = 0;
2879                         clock_freq = PP_SMC_TO_HOST_UL(
2880                                         data->smc_state_table.GraphicsLevel[j].SclkFrequency);
2881                         /* Check the allowed frequency against the sclk level[j].
2882                          *  Sclk's endianness has already been converted,
2883                          *  and it's in 10Khz unit,
2884                          *  as opposed to Data table, which is in Mhz unit.
2885                          */
2886                         if (clock_freq >=
2887                                         (fiji_clock_stretcher_ddt_table[type][i][0]) * 100) {
2888                                 cks_setting |= 0x2;
2889                                 if (clock_freq <
2890                                                 (fiji_clock_stretcher_ddt_table[type][i][1]) * 100)
2891                                         cks_setting |= 0x1;
2892                         }
2893                         data->smc_state_table.ClockStretcherDataTable.
2894                         ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
2895                 }
2896                 CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.
2897                                 ClockStretcherDataTable.
2898                                 ClockStretcherDataTableEntry[i].setting);
2899         }
2900
2901         value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
2902         value &= 0xFFFFFFFE;
2903         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
2904
2905         return 0;
2906 }
2907
2908 /**
2909 * Populates the SMC VRConfig field in DPM table.
2910 *
2911 * @param    hwmgr   the address of the hardware manager
2912 * @param    table   the SMC DPM table structure to be populated
2913 * @return   always 0
2914 */
2915 static int fiji_populate_vr_config(struct pp_hwmgr *hwmgr,
2916                 struct SMU73_Discrete_DpmTable *table)
2917 {
2918         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2919         uint16_t config;
2920
2921         config = VR_MERGED_WITH_VDDC;
2922         table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
2923
2924         /* Set Vddc Voltage Controller */
2925         if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
2926                 config = VR_SVI2_PLANE_1;
2927                 table->VRConfig |= config;
2928         } else {
2929                 PP_ASSERT_WITH_CODE(false,
2930                                 "VDDC should be on SVI2 control in merged mode!",);
2931         }
2932         /* Set Vddci Voltage Controller */
2933         if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
2934                 config = VR_SVI2_PLANE_2;  /* only in merged mode */
2935                 table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
2936         } else if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
2937                 config = VR_SMIO_PATTERN_1;
2938                 table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
2939         } else {
2940                 config = VR_STATIC_VOLTAGE;
2941                 table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
2942         }
2943         /* Set Mvdd Voltage Controller */
2944         if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
2945                 config = VR_SVI2_PLANE_2;
2946                 table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
2947         } else if(FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
2948                 config = VR_SMIO_PATTERN_2;
2949                 table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
2950         } else {
2951                 config = VR_STATIC_VOLTAGE;
2952                 table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
2953         }
2954
2955         return 0;
2956 }
2957
2958 /**
2959 * Initializes the SMC table and uploads it
2960 *
2961 * @param    hwmgr  the address of the powerplay hardware manager.
2962 * @param    pInput  the pointer to input data (PowerState)
2963 * @return   always 0
2964 */
2965 static int fiji_init_smc_table(struct pp_hwmgr *hwmgr)
2966 {
2967         int result;
2968         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
2969         struct phm_ppt_v1_information *table_info =
2970                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
2971         struct SMU73_Discrete_DpmTable *table = &(data->smc_state_table);
2972         const struct fiji_ulv_parm *ulv = &(data->ulv);
2973         uint8_t i;
2974         struct pp_atomctrl_gpio_pin_assignment gpio_pin;
2975
2976         result = fiji_setup_default_dpm_tables(hwmgr);
2977         PP_ASSERT_WITH_CODE(0 == result,
2978                         "Failed to setup default DPM tables!", return result);
2979
2980         if(FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control)
2981                 fiji_populate_smc_voltage_tables(hwmgr, table);
2982
2983         table->SystemFlags = 0;
2984
2985         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2986                         PHM_PlatformCaps_AutomaticDCTransition))
2987                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
2988
2989         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
2990                         PHM_PlatformCaps_StepVddc))
2991                 table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
2992
2993         if (data->is_memory_gddr5)
2994                 table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
2995
2996         if (ulv->ulv_supported && table_info->us_ulv_voltage_offset) {
2997                 result = fiji_populate_ulv_state(hwmgr, table);
2998                 PP_ASSERT_WITH_CODE(0 == result,
2999                                 "Failed to initialize ULV state!", return result);
3000                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3001                                 ixCG_ULV_PARAMETER, ulv->cg_ulv_parameter);
3002         }
3003
3004         result = fiji_populate_smc_link_level(hwmgr, table);
3005         PP_ASSERT_WITH_CODE(0 == result,
3006                         "Failed to initialize Link Level!", return result);
3007
3008         result = fiji_populate_all_graphic_levels(hwmgr);
3009         PP_ASSERT_WITH_CODE(0 == result,
3010                         "Failed to initialize Graphics Level!", return result);
3011
3012         result = fiji_populate_all_memory_levels(hwmgr);
3013         PP_ASSERT_WITH_CODE(0 == result,
3014                         "Failed to initialize Memory Level!", return result);
3015
3016         result = fiji_populate_smc_acpi_level(hwmgr, table);
3017         PP_ASSERT_WITH_CODE(0 == result,
3018                         "Failed to initialize ACPI Level!", return result);
3019
3020         result = fiji_populate_smc_vce_level(hwmgr, table);
3021         PP_ASSERT_WITH_CODE(0 == result,
3022                         "Failed to initialize VCE Level!", return result);
3023
3024         result = fiji_populate_smc_acp_level(hwmgr, table);
3025         PP_ASSERT_WITH_CODE(0 == result,
3026                         "Failed to initialize ACP Level!", return result);
3027
3028         result = fiji_populate_smc_samu_level(hwmgr, table);
3029         PP_ASSERT_WITH_CODE(0 == result,
3030                         "Failed to initialize SAMU Level!", return result);
3031
3032         /* Since only the initial state is completely set up at this point
3033          * (the other states are just copies of the boot state) we only
3034          * need to populate the  ARB settings for the initial state.
3035          */
3036         result = fiji_program_memory_timing_parameters(hwmgr);
3037         PP_ASSERT_WITH_CODE(0 == result,
3038                         "Failed to Write ARB settings for the initial state.", return result);
3039
3040         result = fiji_populate_smc_uvd_level(hwmgr, table);
3041         PP_ASSERT_WITH_CODE(0 == result,
3042                         "Failed to initialize UVD Level!", return result);
3043
3044         result = fiji_populate_smc_boot_level(hwmgr, table);
3045         PP_ASSERT_WITH_CODE(0 == result,
3046                         "Failed to initialize Boot Level!", return result);
3047
3048         result = fiji_populate_smc_initailial_state(hwmgr);
3049         PP_ASSERT_WITH_CODE(0 == result,
3050                         "Failed to initialize Boot State!", return result);
3051
3052         result = fiji_populate_bapm_parameters_in_dpm_table(hwmgr);
3053         PP_ASSERT_WITH_CODE(0 == result,
3054                         "Failed to populate BAPM Parameters!", return result);
3055
3056         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3057                         PHM_PlatformCaps_ClockStretcher)) {
3058                 result = fiji_populate_clock_stretcher_data_table(hwmgr);
3059                 PP_ASSERT_WITH_CODE(0 == result,
3060                                 "Failed to populate Clock Stretcher Data Table!",
3061                                 return result);
3062         }
3063
3064         table->GraphicsVoltageChangeEnable  = 1;
3065         table->GraphicsThermThrottleEnable  = 1;
3066         table->GraphicsInterval = 1;
3067         table->VoltageInterval  = 1;
3068         table->ThermalInterval  = 1;
3069         table->TemperatureLimitHigh =
3070                         table_info->cac_dtp_table->usTargetOperatingTemp *
3071                         FIJI_Q88_FORMAT_CONVERSION_UNIT;
3072         table->TemperatureLimitLow  =
3073                         (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
3074                         FIJI_Q88_FORMAT_CONVERSION_UNIT;
3075         table->MemoryVoltageChangeEnable = 1;
3076         table->MemoryInterval = 1;
3077         table->VoltageResponseTime = 0;
3078         table->PhaseResponseTime = 0;
3079         table->MemoryThermThrottleEnable = 1;
3080         table->PCIeBootLinkLevel = 0;      /* 0:Gen1 1:Gen2 2:Gen3*/
3081         table->PCIeGenInterval = 1;
3082         table->VRConfig = 0;
3083
3084         result = fiji_populate_vr_config(hwmgr, table);
3085         PP_ASSERT_WITH_CODE(0 == result,
3086                         "Failed to populate VRConfig setting!", return result);
3087
3088         table->ThermGpio = 17;
3089         table->SclkStepSize = 0x4000;
3090
3091         if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
3092                 table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
3093                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3094                                 PHM_PlatformCaps_RegulatorHot);
3095         } else {
3096                 table->VRHotGpio = FIJI_UNUSED_GPIO_PIN;
3097                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3098                                 PHM_PlatformCaps_RegulatorHot);
3099         }
3100
3101         if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
3102                         &gpio_pin)) {
3103                 table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
3104                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3105                                 PHM_PlatformCaps_AutomaticDCTransition);
3106         } else {
3107                 table->AcDcGpio = FIJI_UNUSED_GPIO_PIN;
3108                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3109                                 PHM_PlatformCaps_AutomaticDCTransition);
3110         }
3111
3112         /* Thermal Output GPIO */
3113         if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
3114                         &gpio_pin)) {
3115                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
3116                                 PHM_PlatformCaps_ThermalOutGPIO);
3117
3118                 table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
3119
3120                 /* For porlarity read GPIOPAD_A with assigned Gpio pin
3121                  * since VBIOS will program this register to set 'inactive state',
3122                  * driver can then determine 'active state' from this and
3123                  * program SMU with correct polarity
3124                  */
3125                 table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
3126                                 (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
3127                 table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
3128
3129                 /* if required, combine VRHot/PCC with thermal out GPIO */
3130                 if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3131                                 PHM_PlatformCaps_RegulatorHot) &&
3132                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3133                                         PHM_PlatformCaps_CombinePCCWithThermalSignal))
3134                         table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
3135         } else {
3136                 phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
3137                                 PHM_PlatformCaps_ThermalOutGPIO);
3138                 table->ThermOutGpio = 17;
3139                 table->ThermOutPolarity = 1;
3140                 table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
3141         }
3142
3143         for (i = 0; i < SMU73_MAX_ENTRIES_SMIO; i++)
3144                 table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
3145
3146         CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
3147         CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
3148         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
3149         CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
3150         CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
3151         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
3152         CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
3153         CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
3154         CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
3155
3156         /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
3157         result = fiji_copy_bytes_to_smc(hwmgr->smumgr,
3158                         data->dpm_table_start +
3159                         offsetof(SMU73_Discrete_DpmTable, SystemFlags),
3160                         (uint8_t *)&(table->SystemFlags),
3161                         sizeof(SMU73_Discrete_DpmTable) - 3 * sizeof(SMU73_PIDController),
3162                         data->sram_end);
3163         PP_ASSERT_WITH_CODE(0 == result,
3164                         "Failed to upload dpm data to SMC memory!", return result);
3165
3166         return 0;
3167 }
3168
3169 /**
3170 * Initialize the ARB DRAM timing table's index field.
3171 *
3172 * @param    hwmgr  the address of the powerplay hardware manager.
3173 * @return   always 0
3174 */
3175 static int fiji_init_arb_table_index(struct pp_hwmgr *hwmgr)
3176 {
3177         const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3178         uint32_t tmp;
3179         int result;
3180
3181         /* This is a read-modify-write on the first byte of the ARB table.
3182          * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
3183          * is the field 'current'.
3184          * This solution is ugly, but we never write the whole table only
3185          * individual fields in it.
3186          * In reality this field should not be in that structure
3187          * but in a soft register.
3188          */
3189         result = fiji_read_smc_sram_dword(hwmgr->smumgr,
3190                         data->arb_table_start, &tmp, data->sram_end);
3191
3192         if (result)
3193                 return result;
3194
3195         tmp &= 0x00FFFFFF;
3196         tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
3197
3198         return fiji_write_smc_sram_dword(hwmgr->smumgr,
3199                         data->arb_table_start,  tmp, data->sram_end);
3200 }
3201
3202 static int fiji_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr)
3203 {
3204         if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3205                         PHM_PlatformCaps_RegulatorHot))
3206                 return smum_send_msg_to_smc(hwmgr->smumgr,
3207                                 PPSMC_MSG_EnableVRHotGPIOInterrupt);
3208
3209         return 0;
3210 }
3211
3212 static int fiji_enable_sclk_control(struct pp_hwmgr *hwmgr)
3213 {
3214         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
3215                         SCLK_PWRMGT_OFF, 0);
3216         return 0;
3217 }
3218
3219 static int fiji_enable_ulv(struct pp_hwmgr *hwmgr)
3220 {
3221         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3222         struct fiji_ulv_parm *ulv = &(data->ulv);
3223
3224         if (ulv->ulv_supported)
3225                 return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_EnableULV);
3226
3227         return 0;
3228 }
3229
3230 static int fiji_disable_ulv(struct pp_hwmgr *hwmgr)
3231 {
3232         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3233         struct fiji_ulv_parm *ulv = &(data->ulv);
3234
3235         if (ulv->ulv_supported)
3236                 return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableULV);
3237
3238         return 0;
3239 }
3240
3241 static int fiji_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
3242 {
3243         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3244                         PHM_PlatformCaps_SclkDeepSleep)) {
3245                 if (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MASTER_DeepSleep_ON))
3246                         PP_ASSERT_WITH_CODE(false,
3247                                         "Attempt to enable Master Deep Sleep switch failed!",
3248                                         return -1);
3249         } else {
3250                 if (smum_send_msg_to_smc(hwmgr->smumgr,
3251                                 PPSMC_MSG_MASTER_DeepSleep_OFF)) {
3252                         PP_ASSERT_WITH_CODE(false,
3253                                         "Attempt to disable Master Deep Sleep switch failed!",
3254                                         return -1);
3255                 }
3256         }
3257
3258         return 0;
3259 }
3260
3261 static int fiji_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
3262 {
3263         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3264                         PHM_PlatformCaps_SclkDeepSleep)) {
3265                 if (smum_send_msg_to_smc(hwmgr->smumgr,
3266                                 PPSMC_MSG_MASTER_DeepSleep_OFF)) {
3267                         PP_ASSERT_WITH_CODE(false,
3268                                         "Attempt to disable Master Deep Sleep switch failed!",
3269                                         return -1);
3270                 }
3271         }
3272
3273         return 0;
3274 }
3275
3276 static int fiji_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
3277 {
3278         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3279         uint32_t   val, val0, val2;
3280         uint32_t   i, cpl_cntl, cpl_threshold, mc_threshold;
3281
3282         /* enable SCLK dpm */
3283         if(!data->sclk_dpm_key_disabled)
3284                 PP_ASSERT_WITH_CODE(
3285                 (0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Enable)),
3286                 "Failed to enable SCLK DPM during DPM Start Function!",
3287                 return -1);
3288
3289         /* enable MCLK dpm */
3290         if(0 == data->mclk_dpm_key_disabled) {
3291                 cpl_threshold = 0;
3292                 mc_threshold = 0;
3293
3294                 /* Read per MCD tile (0 - 7) */
3295                 for (i = 0; i < 8; i++) {
3296                         PHM_WRITE_FIELD(hwmgr->device, MC_CONFIG_MCD, MC_RD_ENABLE, i);
3297                         val = cgs_read_register(hwmgr->device, mmMC_SEQ_RESERVE_0_S) & 0xf0000000;
3298                         if (0xf0000000 != val) {
3299                                 /* count number of MCQ that has channel(s) enabled */
3300                                 cpl_threshold++;
3301                                 /* only harvest 3 or full 4 supported */
3302                                 mc_threshold = val ? 3 : 4;
3303                         }
3304                 }
3305                 PP_ASSERT_WITH_CODE(0 != cpl_threshold,
3306                                 "Number of MCQ is zero!", return -EINVAL;);
3307
3308                 mc_threshold = ((mc_threshold & LCAC_MC0_CNTL__MC0_THRESHOLD_MASK) <<
3309                                 LCAC_MC0_CNTL__MC0_THRESHOLD__SHIFT) |
3310                                                 LCAC_MC0_CNTL__MC0_ENABLE_MASK;
3311                 cpl_cntl = ((cpl_threshold & LCAC_CPL_CNTL__CPL_THRESHOLD_MASK) <<
3312                                 LCAC_CPL_CNTL__CPL_THRESHOLD__SHIFT) |
3313                                                 LCAC_CPL_CNTL__CPL_ENABLE_MASK;
3314                 cpl_cntl = (cpl_cntl | (8 << LCAC_CPL_CNTL__CPL_BLOCK_ID__SHIFT));
3315                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3316                                 ixLCAC_MC0_CNTL, mc_threshold);
3317                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3318                                 ixLCAC_MC1_CNTL, mc_threshold);
3319                 if (8 == cpl_threshold) {
3320                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3321                                         ixLCAC_MC2_CNTL, mc_threshold);
3322                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3323                                         ixLCAC_MC3_CNTL, mc_threshold);
3324                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3325                                         ixLCAC_MC4_CNTL, mc_threshold);
3326                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3327                                         ixLCAC_MC5_CNTL, mc_threshold);
3328                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3329                                         ixLCAC_MC6_CNTL, mc_threshold);
3330                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3331                                         ixLCAC_MC7_CNTL, mc_threshold);
3332                 }
3333                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3334                                 ixLCAC_CPL_CNTL, cpl_cntl);
3335
3336                 udelay(5);
3337
3338                 mc_threshold = mc_threshold |
3339                                 (1 << LCAC_MC0_CNTL__MC0_SIGNAL_ID__SHIFT);
3340                 cpl_cntl = cpl_cntl | (1 << LCAC_CPL_CNTL__CPL_SIGNAL_ID__SHIFT);
3341                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3342                                 ixLCAC_MC0_CNTL, mc_threshold);
3343                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3344                                 ixLCAC_MC1_CNTL, mc_threshold);
3345                 if (8 == cpl_threshold) {
3346                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3347                                         ixLCAC_MC2_CNTL, mc_threshold);
3348                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3349                                         ixLCAC_MC3_CNTL, mc_threshold);
3350                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3351                                         ixLCAC_MC4_CNTL, mc_threshold);
3352                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3353                                         ixLCAC_MC5_CNTL, mc_threshold);
3354                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3355                                         ixLCAC_MC6_CNTL, mc_threshold);
3356                         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3357                                         ixLCAC_MC7_CNTL, mc_threshold);
3358                 }
3359                 cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3360                                 ixLCAC_CPL_CNTL, cpl_cntl);
3361
3362                 /* Program CAC_EN per MCD (0-7) Tile */
3363                 val0 = val = cgs_read_register(hwmgr->device, mmMC_CONFIG_MCD);
3364                 val &= ~(MC_CONFIG_MCD__MCD0_WR_ENABLE_MASK |
3365                                 MC_CONFIG_MCD__MCD1_WR_ENABLE_MASK |
3366                                 MC_CONFIG_MCD__MCD2_WR_ENABLE_MASK |
3367                                 MC_CONFIG_MCD__MCD3_WR_ENABLE_MASK |
3368                                 MC_CONFIG_MCD__MCD4_WR_ENABLE_MASK |
3369                                 MC_CONFIG_MCD__MCD5_WR_ENABLE_MASK |
3370                                 MC_CONFIG_MCD__MCD6_WR_ENABLE_MASK |
3371                                 MC_CONFIG_MCD__MCD7_WR_ENABLE_MASK |
3372                                 MC_CONFIG_MCD__MC_RD_ENABLE_MASK);
3373
3374                 for (i = 0; i < 8; i++) {
3375                         /* Enable MCD i Tile read & write */
3376                         val2  = (val | (i << MC_CONFIG_MCD__MC_RD_ENABLE__SHIFT) |
3377                                         (1 << i));
3378                         cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val2);
3379                         /* Enbale CAC_ON MCD i Tile */
3380                         val2 = cgs_read_register(hwmgr->device, mmMC_SEQ_CNTL);
3381                         val2 |= MC_SEQ_CNTL__CAC_EN_MASK;
3382                         cgs_write_register(hwmgr->device, mmMC_SEQ_CNTL, val2);
3383                 }
3384                 /* Set MC_CONFIG_MCD back to its default setting val0 */
3385                 cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val0);
3386
3387                 PP_ASSERT_WITH_CODE(
3388                                 (0 == smum_send_msg_to_smc(hwmgr->smumgr,
3389                                                 PPSMC_MSG_MCLKDPM_Enable)),
3390                                 "Failed to enable MCLK DPM during DPM Start Function!",
3391                                 return -1);
3392         }
3393         return 0;
3394 }
3395
3396 static int fiji_start_dpm(struct pp_hwmgr *hwmgr)
3397 {
3398         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3399
3400         /*enable general power management */
3401         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
3402                         GLOBAL_PWRMGT_EN, 1);
3403         /* enable sclk deep sleep */
3404         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
3405                         DYNAMIC_PM_EN, 1);
3406         /* prepare for PCIE DPM */
3407         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
3408                         data->soft_regs_start + offsetof(SMU73_SoftRegisters,
3409                                         VoltageChangeTimeout), 0x1000);
3410         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
3411                         SWRST_COMMAND_1, RESETLC, 0x0);
3412
3413         PP_ASSERT_WITH_CODE(
3414                         (0 == smum_send_msg_to_smc(hwmgr->smumgr,
3415                                         PPSMC_MSG_Voltage_Cntl_Enable)),
3416                         "Failed to enable voltage DPM during DPM Start Function!",
3417                         return -1);
3418
3419         if (fiji_enable_sclk_mclk_dpm(hwmgr)) {
3420                 printk(KERN_ERR "Failed to enable Sclk DPM and Mclk DPM!");
3421                 return -1;
3422         }
3423
3424         /* enable PCIE dpm */
3425         if(!data->pcie_dpm_key_disabled) {
3426                 PP_ASSERT_WITH_CODE(
3427                                 (0 == smum_send_msg_to_smc(hwmgr->smumgr,
3428                                                 PPSMC_MSG_PCIeDPM_Enable)),
3429                                 "Failed to enable pcie DPM during DPM Start Function!",
3430                                 return -1);
3431         }
3432
3433         return 0;
3434 }
3435
3436 static int fiji_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
3437 {
3438         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3439
3440         /* disable SCLK dpm */
3441         if (!data->sclk_dpm_key_disabled)
3442                 PP_ASSERT_WITH_CODE(
3443                                 (smum_send_msg_to_smc(hwmgr->smumgr,
3444                                                 PPSMC_MSG_DPM_Disable) == 0),
3445                                 "Failed to disable SCLK DPM!",
3446                                 return -1);
3447
3448         /* disable MCLK dpm */
3449         if (!data->mclk_dpm_key_disabled) {
3450                 PP_ASSERT_WITH_CODE(
3451                                 (smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3452                                 PPSMC_MSG_MCLKDPM_SetEnabledMask, 1) == 0),
3453                                 "Failed to force MCLK DPM0!",
3454                                 return -1);
3455
3456                 PP_ASSERT_WITH_CODE(
3457                                 (smum_send_msg_to_smc(hwmgr->smumgr,
3458                                                 PPSMC_MSG_MCLKDPM_Disable) == 0),
3459                                 "Failed to disable MCLK DPM!",
3460                                 return -1);
3461         }
3462
3463         return 0;
3464 }
3465
3466 static int fiji_stop_dpm(struct pp_hwmgr *hwmgr)
3467 {
3468         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3469
3470         /* disable general power management */
3471         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
3472                         GLOBAL_PWRMGT_EN, 0);
3473         /* disable sclk deep sleep */
3474         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
3475                         DYNAMIC_PM_EN, 0);
3476
3477         /* disable PCIE dpm */
3478         if (!data->pcie_dpm_key_disabled) {
3479                 PP_ASSERT_WITH_CODE(
3480                                 (smum_send_msg_to_smc(hwmgr->smumgr,
3481                                                 PPSMC_MSG_PCIeDPM_Disable) == 0),
3482                                 "Failed to disable pcie DPM during DPM Stop Function!",
3483                                 return -1);
3484         }
3485
3486         if (fiji_disable_sclk_mclk_dpm(hwmgr)) {
3487                 printk(KERN_ERR "Failed to disable Sclk DPM and Mclk DPM!");
3488                 return -1;
3489         }
3490
3491         PP_ASSERT_WITH_CODE(
3492                         (smum_send_msg_to_smc(hwmgr->smumgr,
3493                                         PPSMC_MSG_Voltage_Cntl_Disable) == 0),
3494                         "Failed to disable voltage DPM during DPM Stop Function!",
3495                         return -1);
3496
3497         return 0;
3498 }
3499
3500 static void fiji_set_dpm_event_sources(struct pp_hwmgr *hwmgr,
3501                 uint32_t sources)
3502 {
3503         bool protection;
3504         enum DPM_EVENT_SRC src;
3505
3506         switch (sources) {
3507         default:
3508                 printk(KERN_ERR "Unknown throttling event sources.");
3509                 /* fall through */
3510         case 0:
3511                 protection = false;
3512                 /* src is unused */
3513                 break;
3514         case (1 << PHM_AutoThrottleSource_Thermal):
3515                 protection = true;
3516                 src = DPM_EVENT_SRC_DIGITAL;
3517                 break;
3518         case (1 << PHM_AutoThrottleSource_External):
3519                 protection = true;
3520                 src = DPM_EVENT_SRC_EXTERNAL;
3521                 break;
3522         case (1 << PHM_AutoThrottleSource_External) |
3523                         (1 << PHM_AutoThrottleSource_Thermal):
3524                 protection = true;
3525                 src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL;
3526                 break;
3527         }
3528         /* Order matters - don't enable thermal protection for the wrong source. */
3529         if (protection) {
3530                 PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL,
3531                                 DPM_EVENT_SRC, src);
3532                 PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
3533                                 THERMAL_PROTECTION_DIS,
3534                                 !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3535                                                 PHM_PlatformCaps_ThermalController));
3536         } else
3537                 PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
3538                                 THERMAL_PROTECTION_DIS, 1);
3539 }
3540
3541 static int fiji_enable_auto_throttle_source(struct pp_hwmgr *hwmgr,
3542                 PHM_AutoThrottleSource source)
3543 {
3544         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3545
3546         if (!(data->active_auto_throttle_sources & (1 << source))) {
3547                 data->active_auto_throttle_sources |= 1 << source;
3548                 fiji_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
3549         }
3550         return 0;
3551 }
3552
3553 static int fiji_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
3554 {
3555         return fiji_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
3556 }
3557
3558 static int fiji_disable_auto_throttle_source(struct pp_hwmgr *hwmgr,
3559                 PHM_AutoThrottleSource source)
3560 {
3561         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3562
3563         if (data->active_auto_throttle_sources & (1 << source)) {
3564                 data->active_auto_throttle_sources &= ~(1 << source);
3565                 fiji_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
3566         }
3567         return 0;
3568 }
3569
3570 static int fiji_disable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
3571 {
3572         return fiji_disable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
3573 }
3574
3575 static int fiji_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
3576 {
3577         int tmp_result, result = 0;
3578
3579         tmp_result = (!fiji_is_dpm_running(hwmgr))? 0 : -1;
3580         PP_ASSERT_WITH_CODE(result == 0,
3581                         "DPM is already running right now, no need to enable DPM!",
3582                         return 0);
3583
3584         if (fiji_voltage_control(hwmgr)) {
3585                 tmp_result = fiji_enable_voltage_control(hwmgr);
3586                 PP_ASSERT_WITH_CODE(tmp_result == 0,
3587                                 "Failed to enable voltage control!",
3588                                 result = tmp_result);
3589         }
3590
3591         if (fiji_voltage_control(hwmgr)) {
3592                 tmp_result = fiji_construct_voltage_tables(hwmgr);
3593                 PP_ASSERT_WITH_CODE((0 == tmp_result),
3594                                 "Failed to contruct voltage tables!",
3595                                 result = tmp_result);
3596         }
3597
3598         tmp_result = fiji_initialize_mc_reg_table(hwmgr);
3599         PP_ASSERT_WITH_CODE((0 == tmp_result),
3600                         "Failed to initialize MC reg table!", result = tmp_result);
3601
3602         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3603                         PHM_PlatformCaps_EngineSpreadSpectrumSupport))
3604                 PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3605                                 GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 1);
3606
3607         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3608                         PHM_PlatformCaps_ThermalController))
3609                 PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3610                                 GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 0);
3611
3612         tmp_result = fiji_program_static_screen_threshold_parameters(hwmgr);
3613         PP_ASSERT_WITH_CODE((0 == tmp_result),
3614                         "Failed to program static screen threshold parameters!",
3615                         result = tmp_result);
3616
3617         tmp_result = fiji_enable_display_gap(hwmgr);
3618         PP_ASSERT_WITH_CODE((0 == tmp_result),
3619                         "Failed to enable display gap!", result = tmp_result);
3620
3621         tmp_result = fiji_program_voting_clients(hwmgr);
3622         PP_ASSERT_WITH_CODE((0 == tmp_result),
3623                         "Failed to program voting clients!", result = tmp_result);
3624
3625         tmp_result = fiji_process_firmware_header(hwmgr);
3626         PP_ASSERT_WITH_CODE((0 == tmp_result),
3627                         "Failed to process firmware header!", result = tmp_result);
3628
3629         tmp_result = fiji_initial_switch_from_arbf0_to_f1(hwmgr);
3630         PP_ASSERT_WITH_CODE((0 == tmp_result),
3631                         "Failed to initialize switch from ArbF0 to F1!",
3632                         result = tmp_result);
3633
3634         tmp_result = fiji_init_smc_table(hwmgr);
3635         PP_ASSERT_WITH_CODE((0 == tmp_result),
3636                         "Failed to initialize SMC table!", result = tmp_result);
3637
3638         tmp_result = fiji_init_arb_table_index(hwmgr);
3639         PP_ASSERT_WITH_CODE((0 == tmp_result),
3640                         "Failed to initialize ARB table index!", result = tmp_result);
3641
3642         tmp_result = fiji_populate_pm_fuses(hwmgr);
3643         PP_ASSERT_WITH_CODE((0 == tmp_result),
3644                         "Failed to populate PM fuses!", result = tmp_result);
3645
3646         tmp_result = fiji_enable_vrhot_gpio_interrupt(hwmgr);
3647         PP_ASSERT_WITH_CODE((0 == tmp_result),
3648                         "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
3649
3650         tmp_result = tonga_notify_smc_display_change(hwmgr, false);
3651         PP_ASSERT_WITH_CODE((0 == tmp_result),
3652                         "Failed to notify no display!", result = tmp_result);
3653
3654         tmp_result = fiji_enable_sclk_control(hwmgr);
3655         PP_ASSERT_WITH_CODE((0 == tmp_result),
3656                         "Failed to enable SCLK control!", result = tmp_result);
3657
3658         tmp_result = fiji_enable_ulv(hwmgr);
3659         PP_ASSERT_WITH_CODE((0 == tmp_result),
3660                         "Failed to enable ULV!", result = tmp_result);
3661
3662         tmp_result = fiji_enable_deep_sleep_master_switch(hwmgr);
3663         PP_ASSERT_WITH_CODE((0 == tmp_result),
3664                         "Failed to enable deep sleep master switch!", result = tmp_result);
3665
3666         tmp_result = fiji_start_dpm(hwmgr);
3667         PP_ASSERT_WITH_CODE((0 == tmp_result),
3668                         "Failed to start DPM!", result = tmp_result);
3669
3670         tmp_result = fiji_enable_smc_cac(hwmgr);
3671         PP_ASSERT_WITH_CODE((0 == tmp_result),
3672                         "Failed to enable SMC CAC!", result = tmp_result);
3673
3674         tmp_result = fiji_enable_power_containment(hwmgr);
3675         PP_ASSERT_WITH_CODE((0 == tmp_result),
3676                         "Failed to enable power containment!", result = tmp_result);
3677
3678         tmp_result = fiji_power_control_set_level(hwmgr);
3679         PP_ASSERT_WITH_CODE((0 == tmp_result),
3680                         "Failed to power control set level!", result = tmp_result);
3681
3682         tmp_result = fiji_enable_thermal_auto_throttle(hwmgr);
3683         PP_ASSERT_WITH_CODE((0 == tmp_result),
3684                         "Failed to enable thermal auto throttle!", result = tmp_result);
3685
3686         return result;
3687 }
3688
3689 static int fiji_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
3690 {
3691         int tmp_result, result = 0;
3692
3693         tmp_result = (fiji_is_dpm_running(hwmgr)) ? 0 : -1;
3694         PP_ASSERT_WITH_CODE(tmp_result == 0,
3695                         "DPM is not running right now, no need to disable DPM!",
3696                         return 0);
3697
3698         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
3699                         PHM_PlatformCaps_ThermalController))
3700                 PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3701                                 GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 1);
3702
3703         tmp_result = fiji_disable_power_containment(hwmgr);
3704         PP_ASSERT_WITH_CODE((tmp_result == 0),
3705                         "Failed to disable power containment!", result = tmp_result);
3706
3707         tmp_result = fiji_disable_smc_cac(hwmgr);
3708         PP_ASSERT_WITH_CODE((tmp_result == 0),
3709                         "Failed to disable SMC CAC!", result = tmp_result);
3710
3711         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3712                         CG_SPLL_SPREAD_SPECTRUM, SSEN, 0);
3713         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
3714                         GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 0);
3715
3716         tmp_result = fiji_disable_thermal_auto_throttle(hwmgr);
3717         PP_ASSERT_WITH_CODE((tmp_result == 0),
3718                         "Failed to disable thermal auto throttle!", result = tmp_result);
3719
3720         tmp_result = fiji_stop_dpm(hwmgr);
3721         PP_ASSERT_WITH_CODE((tmp_result == 0),
3722                         "Failed to stop DPM!", result = tmp_result);
3723
3724         tmp_result = fiji_disable_deep_sleep_master_switch(hwmgr);
3725         PP_ASSERT_WITH_CODE((tmp_result == 0),
3726                         "Failed to disable deep sleep master switch!", result = tmp_result);
3727
3728         tmp_result = fiji_disable_ulv(hwmgr);
3729         PP_ASSERT_WITH_CODE((tmp_result == 0),
3730                         "Failed to disable ULV!", result = tmp_result);
3731
3732         tmp_result = fiji_clear_voting_clients(hwmgr);
3733         PP_ASSERT_WITH_CODE((tmp_result == 0),
3734                         "Failed to clear voting clients!", result = tmp_result);
3735
3736         tmp_result = fiji_reset_to_default(hwmgr);
3737         PP_ASSERT_WITH_CODE((tmp_result == 0),
3738                         "Failed to reset to default!", result = tmp_result);
3739
3740         tmp_result = fiji_force_switch_to_arbf0(hwmgr);
3741         PP_ASSERT_WITH_CODE((tmp_result == 0),
3742                         "Failed to force to switch arbf0!", result = tmp_result);
3743
3744         return result;
3745 }
3746
3747 static int fiji_force_dpm_highest(struct pp_hwmgr *hwmgr)
3748 {
3749         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3750         uint32_t level, tmp;
3751
3752         if (!data->sclk_dpm_key_disabled) {
3753                 if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
3754                         level = 0;
3755                         tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
3756                         while (tmp >>= 1)
3757                                 level++;
3758                         if (level)
3759                                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3760                                                 PPSMC_MSG_SCLKDPM_SetEnabledMask,
3761                                                 (1 << level));
3762                 }
3763         }
3764
3765         if (!data->mclk_dpm_key_disabled) {
3766                 if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
3767                         level = 0;
3768                         tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
3769                         while (tmp >>= 1)
3770                                 level++;
3771                         if (level)
3772                                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3773                                                 PPSMC_MSG_MCLKDPM_SetEnabledMask,
3774                                                 (1 << level));
3775                 }
3776         }
3777
3778         if (!data->pcie_dpm_key_disabled) {
3779                 if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
3780                         level = 0;
3781                         tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
3782                         while (tmp >>= 1)
3783                                 level++;
3784                         if (level)
3785                                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3786                                                 PPSMC_MSG_PCIeDPM_ForceLevel,
3787                                                 (1 << level));
3788                 }
3789         }
3790         return 0;
3791 }
3792
3793 static int fiji_upload_dpmlevel_enable_mask(struct pp_hwmgr *hwmgr)
3794 {
3795         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3796
3797         phm_apply_dal_min_voltage_request(hwmgr);
3798
3799         if (!data->sclk_dpm_key_disabled) {
3800                 if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
3801                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3802                                         PPSMC_MSG_SCLKDPM_SetEnabledMask,
3803                                         data->dpm_level_enable_mask.sclk_dpm_enable_mask);
3804         }
3805         return 0;
3806 }
3807
3808 static int fiji_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
3809 {
3810         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3811
3812         if (!fiji_is_dpm_running(hwmgr))
3813                 return -EINVAL;
3814
3815         if (!data->pcie_dpm_key_disabled) {
3816                 smum_send_msg_to_smc(hwmgr->smumgr,
3817                                 PPSMC_MSG_PCIeDPM_UnForceLevel);
3818         }
3819
3820         return fiji_upload_dpmlevel_enable_mask(hwmgr);
3821 }
3822
3823 static uint32_t fiji_get_lowest_enabled_level(
3824                 struct pp_hwmgr *hwmgr, uint32_t mask)
3825 {
3826         uint32_t level = 0;
3827
3828         while(0 == (mask & (1 << level)))
3829                 level++;
3830
3831         return level;
3832 }
3833
3834 static int fiji_force_dpm_lowest(struct pp_hwmgr *hwmgr)
3835 {
3836         struct fiji_hwmgr *data =
3837                         (struct fiji_hwmgr *)(hwmgr->backend);
3838         uint32_t level;
3839
3840         if (!data->sclk_dpm_key_disabled)
3841                 if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
3842                         level = fiji_get_lowest_enabled_level(hwmgr,
3843                                                               data->dpm_level_enable_mask.sclk_dpm_enable_mask);
3844                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3845                                                             PPSMC_MSG_SCLKDPM_SetEnabledMask,
3846                                                             (1 << level));
3847
3848         }
3849
3850         if (!data->mclk_dpm_key_disabled) {
3851                 if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
3852                         level = fiji_get_lowest_enabled_level(hwmgr,
3853                                                               data->dpm_level_enable_mask.mclk_dpm_enable_mask);
3854                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3855                                                             PPSMC_MSG_MCLKDPM_SetEnabledMask,
3856                                                             (1 << level));
3857                 }
3858         }
3859
3860         if (!data->pcie_dpm_key_disabled) {
3861                 if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
3862                         level = fiji_get_lowest_enabled_level(hwmgr,
3863                                                               data->dpm_level_enable_mask.pcie_dpm_enable_mask);
3864                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
3865                                                             PPSMC_MSG_PCIeDPM_ForceLevel,
3866                                                             (1 << level));
3867                 }
3868         }
3869
3870         return 0;
3871
3872 }
3873 static int fiji_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
3874                                 enum amd_dpm_forced_level level)
3875 {
3876         int ret = 0;
3877
3878         switch (level) {
3879         case AMD_DPM_FORCED_LEVEL_HIGH:
3880                 ret = fiji_force_dpm_highest(hwmgr);
3881                 if (ret)
3882                         return ret;
3883                 break;
3884         case AMD_DPM_FORCED_LEVEL_LOW:
3885                 ret = fiji_force_dpm_lowest(hwmgr);
3886                 if (ret)
3887                         return ret;
3888                 break;
3889         case AMD_DPM_FORCED_LEVEL_AUTO:
3890                 ret = fiji_unforce_dpm_levels(hwmgr);
3891                 if (ret)
3892                         return ret;
3893                 break;
3894         default:
3895                 break;
3896         }
3897
3898         hwmgr->dpm_level = level;
3899
3900         return ret;
3901 }
3902
3903 static int fiji_get_power_state_size(struct pp_hwmgr *hwmgr)
3904 {
3905         return sizeof(struct fiji_power_state);
3906 }
3907
3908 static int fiji_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
3909                 void *state, struct pp_power_state *power_state,
3910                 void *pp_table, uint32_t classification_flag)
3911 {
3912         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
3913         struct fiji_power_state  *fiji_power_state =
3914                         (struct fiji_power_state *)(&(power_state->hardware));
3915         struct fiji_performance_level *performance_level;
3916         ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
3917         ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
3918                         (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
3919         ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
3920                         (ATOM_Tonga_SCLK_Dependency_Table *)
3921                         (((unsigned long)powerplay_table) +
3922                                 le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
3923         ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
3924                         (ATOM_Tonga_MCLK_Dependency_Table *)
3925                         (((unsigned long)powerplay_table) +
3926                                 le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
3927
3928         /* The following fields are not initialized here: id orderedList allStatesList */
3929         power_state->classification.ui_label =
3930                         (le16_to_cpu(state_entry->usClassification) &
3931                         ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
3932                         ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
3933         power_state->classification.flags = classification_flag;
3934         /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
3935
3936         power_state->classification.temporary_state = false;
3937         power_state->classification.to_be_deleted = false;
3938
3939         power_state->validation.disallowOnDC =
3940                         (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
3941                                         ATOM_Tonga_DISALLOW_ON_DC));
3942
3943         power_state->pcie.lanes = 0;
3944
3945         power_state->display.disableFrameModulation = false;
3946         power_state->display.limitRefreshrate = false;
3947         power_state->display.enableVariBright =
3948                         (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
3949                                         ATOM_Tonga_ENABLE_VARIBRIGHT));
3950
3951         power_state->validation.supportedPowerLevels = 0;
3952         power_state->uvd_clocks.VCLK = 0;
3953         power_state->uvd_clocks.DCLK = 0;
3954         power_state->temperatures.min = 0;
3955         power_state->temperatures.max = 0;
3956
3957         performance_level = &(fiji_power_state->performance_levels
3958                         [fiji_power_state->performance_level_count++]);
3959
3960         PP_ASSERT_WITH_CODE(
3961                         (fiji_power_state->performance_level_count < SMU73_MAX_LEVELS_GRAPHICS),
3962                         "Performance levels exceeds SMC limit!",
3963                         return -1);
3964
3965         PP_ASSERT_WITH_CODE(
3966                         (fiji_power_state->performance_level_count <=
3967                                         hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
3968                         "Performance levels exceeds Driver limit!",
3969                         return -1);
3970
3971         /* Performance levels are arranged from low to high. */
3972         performance_level->memory_clock = mclk_dep_table->entries
3973                         [state_entry->ucMemoryClockIndexLow].ulMclk;
3974         performance_level->engine_clock = sclk_dep_table->entries
3975                         [state_entry->ucEngineClockIndexLow].ulSclk;
3976         performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
3977                         state_entry->ucPCIEGenLow);
3978         performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
3979                         state_entry->ucPCIELaneHigh);
3980
3981         performance_level = &(fiji_power_state->performance_levels
3982                         [fiji_power_state->performance_level_count++]);
3983         performance_level->memory_clock = mclk_dep_table->entries
3984                         [state_entry->ucMemoryClockIndexHigh].ulMclk;
3985         performance_level->engine_clock = sclk_dep_table->entries
3986                         [state_entry->ucEngineClockIndexHigh].ulSclk;
3987         performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
3988                         state_entry->ucPCIEGenHigh);
3989         performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
3990                         state_entry->ucPCIELaneHigh);
3991
3992         return 0;
3993 }
3994
3995 static int fiji_get_pp_table_entry(struct pp_hwmgr *hwmgr,
3996                 unsigned long entry_index, struct pp_power_state *state)
3997 {
3998         int result;
3999         struct fiji_power_state *ps;
4000         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4001         struct phm_ppt_v1_information *table_info =
4002                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
4003         struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
4004                         table_info->vdd_dep_on_mclk;
4005
4006         state->hardware.magic = PHM_VIslands_Magic;
4007
4008         ps = (struct fiji_power_state *)(&state->hardware);
4009
4010         result = tonga_get_powerplay_table_entry(hwmgr, entry_index, state,
4011                         fiji_get_pp_table_entry_callback_func);
4012
4013         /* This is the earliest time we have all the dependency table and the VBIOS boot state
4014          * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
4015          * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
4016          */
4017         if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
4018                 if (dep_mclk_table->entries[0].clk !=
4019                                 data->vbios_boot_state.mclk_bootup_value)
4020                         printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
4021                                         "does not match VBIOS boot MCLK level");
4022                 if (dep_mclk_table->entries[0].vddci !=
4023                                 data->vbios_boot_state.vddci_bootup_value)
4024                         printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
4025                                         "does not match VBIOS boot VDDCI level");
4026         }
4027
4028         /* set DC compatible flag if this state supports DC */
4029         if (!state->validation.disallowOnDC)
4030                 ps->dc_compatible = true;
4031
4032         if (state->classification.flags & PP_StateClassificationFlag_ACPI)
4033                 data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
4034
4035         ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
4036         ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
4037
4038         if (!result) {
4039                 uint32_t i;
4040
4041                 switch (state->classification.ui_label) {
4042                 case PP_StateUILabel_Performance:
4043                         data->use_pcie_performance_levels = true;
4044
4045                         for (i = 0; i < ps->performance_level_count; i++) {
4046                                 if (data->pcie_gen_performance.max <
4047                                                 ps->performance_levels[i].pcie_gen)
4048                                         data->pcie_gen_performance.max =
4049                                                         ps->performance_levels[i].pcie_gen;
4050
4051                                 if (data->pcie_gen_performance.min >
4052                                                 ps->performance_levels[i].pcie_gen)
4053                                         data->pcie_gen_performance.min =
4054                                                         ps->performance_levels[i].pcie_gen;
4055
4056                                 if (data->pcie_lane_performance.max <
4057                                                 ps->performance_levels[i].pcie_lane)
4058                                         data->pcie_lane_performance.max =
4059                                                         ps->performance_levels[i].pcie_lane;
4060
4061                                 if (data->pcie_lane_performance.min >
4062                                                 ps->performance_levels[i].pcie_lane)
4063                                         data->pcie_lane_performance.min =
4064                                                         ps->performance_levels[i].pcie_lane;
4065                         }
4066                         break;
4067                 case PP_StateUILabel_Battery:
4068                         data->use_pcie_power_saving_levels = true;
4069
4070                         for (i = 0; i < ps->performance_level_count; i++) {
4071                                 if (data->pcie_gen_power_saving.max <
4072                                                 ps->performance_levels[i].pcie_gen)
4073                                         data->pcie_gen_power_saving.max =
4074                                                         ps->performance_levels[i].pcie_gen;
4075
4076                                 if (data->pcie_gen_power_saving.min >
4077                                                 ps->performance_levels[i].pcie_gen)
4078                                         data->pcie_gen_power_saving.min =
4079                                                         ps->performance_levels[i].pcie_gen;
4080
4081                                 if (data->pcie_lane_power_saving.max <
4082                                                 ps->performance_levels[i].pcie_lane)
4083                                         data->pcie_lane_power_saving.max =
4084                                                         ps->performance_levels[i].pcie_lane;
4085
4086                                 if (data->pcie_lane_power_saving.min >
4087                                                 ps->performance_levels[i].pcie_lane)
4088                                         data->pcie_lane_power_saving.min =
4089                                                         ps->performance_levels[i].pcie_lane;
4090                         }
4091                         break;
4092                 default:
4093                         break;
4094                 }
4095         }
4096         return 0;
4097 }
4098
4099 static int fiji_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
4100                                 struct pp_power_state  *request_ps,
4101                         const struct pp_power_state *current_ps)
4102 {
4103         struct fiji_power_state *fiji_ps =
4104                                 cast_phw_fiji_power_state(&request_ps->hardware);
4105         uint32_t sclk;
4106         uint32_t mclk;
4107         struct PP_Clocks minimum_clocks = {0};
4108         bool disable_mclk_switching;
4109         bool disable_mclk_switching_for_frame_lock;
4110         struct cgs_display_info info = {0};
4111         const struct phm_clock_and_voltage_limits *max_limits;
4112         uint32_t i;
4113         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4114         struct phm_ppt_v1_information *table_info =
4115                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
4116         int32_t count;
4117         int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
4118
4119         data->battery_state = (PP_StateUILabel_Battery ==
4120                         request_ps->classification.ui_label);
4121
4122         PP_ASSERT_WITH_CODE(fiji_ps->performance_level_count == 2,
4123                                  "VI should always have 2 performance levels",);
4124
4125         max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
4126                         &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
4127                         &(hwmgr->dyn_state.max_clock_voltage_on_dc);
4128
4129         /* Cap clock DPM tables at DC MAX if it is in DC. */
4130         if (PP_PowerSource_DC == hwmgr->power_source) {
4131                 for (i = 0; i < fiji_ps->performance_level_count; i++) {
4132                         if (fiji_ps->performance_levels[i].memory_clock > max_limits->mclk)
4133                                 fiji_ps->performance_levels[i].memory_clock = max_limits->mclk;
4134                         if (fiji_ps->performance_levels[i].engine_clock > max_limits->sclk)
4135                                 fiji_ps->performance_levels[i].engine_clock = max_limits->sclk;
4136                 }
4137         }
4138
4139         fiji_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk;
4140         fiji_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk;
4141
4142         fiji_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
4143
4144         cgs_get_active_displays_info(hwmgr->device, &info);
4145
4146         /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
4147
4148         /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
4149
4150         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4151                         PHM_PlatformCaps_StablePState)) {
4152                 max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
4153                 stable_pstate_sclk = (max_limits->sclk * 75) / 100;
4154
4155                 for (count = table_info->vdd_dep_on_sclk->count - 1;
4156                                 count >= 0; count--) {
4157                         if (stable_pstate_sclk >=
4158                                         table_info->vdd_dep_on_sclk->entries[count].clk) {
4159                                 stable_pstate_sclk =
4160                                                 table_info->vdd_dep_on_sclk->entries[count].clk;
4161                                 break;
4162                         }
4163                 }
4164
4165                 if (count < 0)
4166                         stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
4167
4168                 stable_pstate_mclk = max_limits->mclk;
4169
4170                 minimum_clocks.engineClock = stable_pstate_sclk;
4171                 minimum_clocks.memoryClock = stable_pstate_mclk;
4172         }
4173
4174         if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
4175                 minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
4176
4177         if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
4178                 minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
4179
4180         fiji_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
4181
4182         if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
4183                 PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <=
4184                                 hwmgr->platform_descriptor.overdriveLimit.engineClock),
4185                                 "Overdrive sclk exceeds limit",
4186                                 hwmgr->gfx_arbiter.sclk_over_drive =
4187                                                 hwmgr->platform_descriptor.overdriveLimit.engineClock);
4188
4189                 if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
4190                         fiji_ps->performance_levels[1].engine_clock =
4191                                         hwmgr->gfx_arbiter.sclk_over_drive;
4192         }
4193
4194         if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
4195                 PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <=
4196                                 hwmgr->platform_descriptor.overdriveLimit.memoryClock),
4197                                 "Overdrive mclk exceeds limit",
4198                                 hwmgr->gfx_arbiter.mclk_over_drive =
4199                                                 hwmgr->platform_descriptor.overdriveLimit.memoryClock);
4200
4201                 if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
4202                         fiji_ps->performance_levels[1].memory_clock =
4203                                         hwmgr->gfx_arbiter.mclk_over_drive;
4204         }
4205
4206         disable_mclk_switching_for_frame_lock = phm_cap_enabled(
4207                                     hwmgr->platform_descriptor.platformCaps,
4208                                     PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
4209
4210         disable_mclk_switching = (1 < info.display_count) ||
4211                                     disable_mclk_switching_for_frame_lock;
4212
4213         sclk = fiji_ps->performance_levels[0].engine_clock;
4214         mclk = fiji_ps->performance_levels[0].memory_clock;
4215
4216         if (disable_mclk_switching)
4217                 mclk = fiji_ps->performance_levels
4218                 [fiji_ps->performance_level_count - 1].memory_clock;
4219
4220         if (sclk < minimum_clocks.engineClock)
4221                 sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
4222                                 max_limits->sclk : minimum_clocks.engineClock;
4223
4224         if (mclk < minimum_clocks.memoryClock)
4225                 mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
4226                                 max_limits->mclk : minimum_clocks.memoryClock;
4227
4228         fiji_ps->performance_levels[0].engine_clock = sclk;
4229         fiji_ps->performance_levels[0].memory_clock = mclk;
4230
4231         fiji_ps->performance_levels[1].engine_clock =
4232                 (fiji_ps->performance_levels[1].engine_clock >=
4233                                 fiji_ps->performance_levels[0].engine_clock) ?
4234                                                 fiji_ps->performance_levels[1].engine_clock :
4235                                                 fiji_ps->performance_levels[0].engine_clock;
4236
4237         if (disable_mclk_switching) {
4238                 if (mclk < fiji_ps->performance_levels[1].memory_clock)
4239                         mclk = fiji_ps->performance_levels[1].memory_clock;
4240
4241                 fiji_ps->performance_levels[0].memory_clock = mclk;
4242                 fiji_ps->performance_levels[1].memory_clock = mclk;
4243         } else {
4244                 if (fiji_ps->performance_levels[1].memory_clock <
4245                                 fiji_ps->performance_levels[0].memory_clock)
4246                         fiji_ps->performance_levels[1].memory_clock =
4247                                         fiji_ps->performance_levels[0].memory_clock;
4248         }
4249
4250         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4251                         PHM_PlatformCaps_StablePState)) {
4252                 for (i = 0; i < fiji_ps->performance_level_count; i++) {
4253                         fiji_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
4254                         fiji_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
4255                         fiji_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
4256                         fiji_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
4257                 }
4258         }
4259
4260         return 0;
4261 }
4262
4263 static int fiji_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
4264 {
4265         const struct phm_set_power_state_input *states =
4266                         (const struct phm_set_power_state_input *)input;
4267         const struct fiji_power_state *fiji_ps =
4268                         cast_const_phw_fiji_power_state(states->pnew_state);
4269         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4270         struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
4271         uint32_t sclk = fiji_ps->performance_levels
4272                         [fiji_ps->performance_level_count - 1].engine_clock;
4273         struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
4274         uint32_t mclk = fiji_ps->performance_levels
4275                         [fiji_ps->performance_level_count - 1].memory_clock;
4276         uint32_t i;
4277         struct cgs_display_info info = {0};
4278
4279         data->need_update_smu7_dpm_table = 0;
4280
4281         for (i = 0; i < sclk_table->count; i++) {
4282                 if (sclk == sclk_table->dpm_levels[i].value)
4283                         break;
4284         }
4285
4286         if (i >= sclk_table->count)
4287                 data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
4288         else {
4289                 if(data->display_timing.min_clock_in_sr !=
4290                         hwmgr->display_config.min_core_set_clock_in_sr)
4291                         data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
4292         }
4293
4294         for (i = 0; i < mclk_table->count; i++) {
4295                 if (mclk == mclk_table->dpm_levels[i].value)
4296                         break;
4297         }
4298
4299         if (i >= mclk_table->count)
4300                 data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
4301
4302         cgs_get_active_displays_info(hwmgr->device, &info);
4303
4304         if (data->display_timing.num_existing_displays != info.display_count)
4305                 data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
4306
4307         return 0;
4308 }
4309
4310 static uint16_t fiji_get_maximum_link_speed(struct pp_hwmgr *hwmgr,
4311                 const struct fiji_power_state *fiji_ps)
4312 {
4313         uint32_t i;
4314         uint32_t sclk, max_sclk = 0;
4315         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4316         struct fiji_dpm_table *dpm_table = &data->dpm_table;
4317
4318         for (i = 0; i < fiji_ps->performance_level_count; i++) {
4319                 sclk = fiji_ps->performance_levels[i].engine_clock;
4320                 if (max_sclk < sclk)
4321                         max_sclk = sclk;
4322         }
4323
4324         for (i = 0; i < dpm_table->sclk_table.count; i++) {
4325                 if (dpm_table->sclk_table.dpm_levels[i].value == max_sclk)
4326                         return (uint16_t) ((i >= dpm_table->pcie_speed_table.count) ?
4327                                         dpm_table->pcie_speed_table.dpm_levels
4328                                         [dpm_table->pcie_speed_table.count - 1].value :
4329                                         dpm_table->pcie_speed_table.dpm_levels[i].value);
4330         }
4331
4332         return 0;
4333 }
4334
4335 static int fiji_request_link_speed_change_before_state_change(
4336                 struct pp_hwmgr *hwmgr, const void *input)
4337 {
4338         const struct phm_set_power_state_input *states =
4339                         (const struct phm_set_power_state_input *)input;
4340         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4341         const struct fiji_power_state *fiji_nps =
4342                         cast_const_phw_fiji_power_state(states->pnew_state);
4343         const struct fiji_power_state *fiji_cps =
4344                         cast_const_phw_fiji_power_state(states->pcurrent_state);
4345
4346         uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_nps);
4347         uint16_t current_link_speed;
4348
4349         if (data->force_pcie_gen == PP_PCIEGenInvalid)
4350                 current_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_cps);
4351         else
4352                 current_link_speed = data->force_pcie_gen;
4353
4354         data->force_pcie_gen = PP_PCIEGenInvalid;
4355         data->pspp_notify_required = false;
4356         if (target_link_speed > current_link_speed) {
4357                 switch(target_link_speed) {
4358                 case PP_PCIEGen3:
4359                         if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
4360                                 break;
4361                         data->force_pcie_gen = PP_PCIEGen2;
4362                         if (current_link_speed == PP_PCIEGen2)
4363                                 break;
4364                 case PP_PCIEGen2:
4365                         if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
4366                                 break;
4367                 default:
4368                         data->force_pcie_gen = fiji_get_current_pcie_speed(hwmgr);
4369                         break;
4370                 }
4371         } else {
4372                 if (target_link_speed < current_link_speed)
4373                         data->pspp_notify_required = true;
4374         }
4375
4376         return 0;
4377 }
4378
4379 static int fiji_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
4380 {
4381         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4382
4383         if (0 == data->need_update_smu7_dpm_table)
4384                 return 0;
4385
4386         if ((0 == data->sclk_dpm_key_disabled) &&
4387                 (data->need_update_smu7_dpm_table &
4388                         (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
4389                 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
4390                                     "Trying to freeze SCLK DPM when DPM is disabled",
4391                                     );
4392                 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
4393                                 PPSMC_MSG_SCLKDPM_FreezeLevel),
4394                                 "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
4395                                 return -1);
4396         }
4397
4398         if ((0 == data->mclk_dpm_key_disabled) &&
4399                 (data->need_update_smu7_dpm_table &
4400                  DPMTABLE_OD_UPDATE_MCLK)) {
4401                 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
4402                                     "Trying to freeze MCLK DPM when DPM is disabled",
4403                                     );
4404                 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
4405                                 PPSMC_MSG_MCLKDPM_FreezeLevel),
4406                                 "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
4407                                 return -1);
4408         }
4409
4410         return 0;
4411 }
4412
4413 static int fiji_populate_and_upload_sclk_mclk_dpm_levels(
4414                 struct pp_hwmgr *hwmgr, const void *input)
4415 {
4416         int result = 0;
4417         const struct phm_set_power_state_input *states =
4418                         (const struct phm_set_power_state_input *)input;
4419         const struct fiji_power_state *fiji_ps =
4420                         cast_const_phw_fiji_power_state(states->pnew_state);
4421         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4422         uint32_t sclk = fiji_ps->performance_levels
4423                         [fiji_ps->performance_level_count - 1].engine_clock;
4424         uint32_t mclk = fiji_ps->performance_levels
4425                         [fiji_ps->performance_level_count - 1].memory_clock;
4426         struct fiji_dpm_table *dpm_table = &data->dpm_table;
4427
4428         struct fiji_dpm_table *golden_dpm_table = &data->golden_dpm_table;
4429         uint32_t dpm_count, clock_percent;
4430         uint32_t i;
4431
4432         if (0 == data->need_update_smu7_dpm_table)
4433                 return 0;
4434
4435         if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
4436                 dpm_table->sclk_table.dpm_levels
4437                 [dpm_table->sclk_table.count - 1].value = sclk;
4438
4439                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4440                                 PHM_PlatformCaps_OD6PlusinACSupport) ||
4441                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4442                                         PHM_PlatformCaps_OD6PlusinDCSupport)) {
4443                 /* Need to do calculation based on the golden DPM table
4444                  * as the Heatmap GPU Clock axis is also based on the default values
4445                  */
4446                         PP_ASSERT_WITH_CODE(
4447                                 (golden_dpm_table->sclk_table.dpm_levels
4448                                                 [golden_dpm_table->sclk_table.count - 1].value != 0),
4449                                 "Divide by 0!",
4450                                 return -1);
4451                         dpm_count = dpm_table->sclk_table.count < 2 ?
4452                                         0 : dpm_table->sclk_table.count - 2;
4453                         for (i = dpm_count; i > 1; i--) {
4454                                 if (sclk > golden_dpm_table->sclk_table.dpm_levels
4455                                                 [golden_dpm_table->sclk_table.count-1].value) {
4456                                         clock_percent =
4457                                                 ((sclk - golden_dpm_table->sclk_table.dpm_levels
4458                                                         [golden_dpm_table->sclk_table.count-1].value) * 100) /
4459                                                 golden_dpm_table->sclk_table.dpm_levels
4460                                                         [golden_dpm_table->sclk_table.count-1].value;
4461
4462                                         dpm_table->sclk_table.dpm_levels[i].value =
4463                                                         golden_dpm_table->sclk_table.dpm_levels[i].value +
4464                                                         (golden_dpm_table->sclk_table.dpm_levels[i].value *
4465                                                                 clock_percent)/100;
4466
4467                                 } else if (golden_dpm_table->sclk_table.dpm_levels
4468                                                 [dpm_table->sclk_table.count-1].value > sclk) {
4469                                         clock_percent =
4470                                                 ((golden_dpm_table->sclk_table.dpm_levels
4471                                                 [golden_dpm_table->sclk_table.count - 1].value - sclk) *
4472                                                                 100) /
4473                                                 golden_dpm_table->sclk_table.dpm_levels
4474                                                         [golden_dpm_table->sclk_table.count-1].value;
4475
4476                                         dpm_table->sclk_table.dpm_levels[i].value =
4477                                                         golden_dpm_table->sclk_table.dpm_levels[i].value -
4478                                                         (golden_dpm_table->sclk_table.dpm_levels[i].value *
4479                                                                         clock_percent) / 100;
4480                                 } else
4481                                         dpm_table->sclk_table.dpm_levels[i].value =
4482                                                         golden_dpm_table->sclk_table.dpm_levels[i].value;
4483                         }
4484                 }
4485         }
4486
4487         if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
4488                 dpm_table->mclk_table.dpm_levels
4489                         [dpm_table->mclk_table.count - 1].value = mclk;
4490                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4491                                 PHM_PlatformCaps_OD6PlusinACSupport) ||
4492                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4493                                 PHM_PlatformCaps_OD6PlusinDCSupport)) {
4494
4495                         PP_ASSERT_WITH_CODE(
4496                                         (golden_dpm_table->mclk_table.dpm_levels
4497                                                 [golden_dpm_table->mclk_table.count-1].value != 0),
4498                                         "Divide by 0!",
4499                                         return -1);
4500                         dpm_count = dpm_table->mclk_table.count < 2 ?
4501                                         0 : dpm_table->mclk_table.count - 2;
4502                         for (i = dpm_count; i > 1; i--) {
4503                                 if (mclk > golden_dpm_table->mclk_table.dpm_levels
4504                                                 [golden_dpm_table->mclk_table.count-1].value) {
4505                                         clock_percent = ((mclk -
4506                                                         golden_dpm_table->mclk_table.dpm_levels
4507                                                         [golden_dpm_table->mclk_table.count-1].value) * 100) /
4508                                                         golden_dpm_table->mclk_table.dpm_levels
4509                                                         [golden_dpm_table->mclk_table.count-1].value;
4510
4511                                         dpm_table->mclk_table.dpm_levels[i].value =
4512                                                         golden_dpm_table->mclk_table.dpm_levels[i].value +
4513                                                         (golden_dpm_table->mclk_table.dpm_levels[i].value *
4514                                                                         clock_percent) / 100;
4515
4516                                 } else if (golden_dpm_table->mclk_table.dpm_levels
4517                                                 [dpm_table->mclk_table.count-1].value > mclk) {
4518                                         clock_percent = ((golden_dpm_table->mclk_table.dpm_levels
4519                                                         [golden_dpm_table->mclk_table.count-1].value - mclk) * 100) /
4520                                                                         golden_dpm_table->mclk_table.dpm_levels
4521                                                                         [golden_dpm_table->mclk_table.count-1].value;
4522
4523                                         dpm_table->mclk_table.dpm_levels[i].value =
4524                                                         golden_dpm_table->mclk_table.dpm_levels[i].value -
4525                                                         (golden_dpm_table->mclk_table.dpm_levels[i].value *
4526                                                                         clock_percent) / 100;
4527                                 } else
4528                                         dpm_table->mclk_table.dpm_levels[i].value =
4529                                                         golden_dpm_table->mclk_table.dpm_levels[i].value;
4530                         }
4531                 }
4532         }
4533
4534         if (data->need_update_smu7_dpm_table &
4535                         (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
4536                 result = fiji_populate_all_graphic_levels(hwmgr);
4537                 PP_ASSERT_WITH_CODE((0 == result),
4538                                 "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
4539                                 return result);
4540         }
4541
4542         if (data->need_update_smu7_dpm_table &
4543                         (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
4544                 /*populate MCLK dpm table to SMU7 */
4545                 result = fiji_populate_all_memory_levels(hwmgr);
4546                 PP_ASSERT_WITH_CODE((0 == result),
4547                                 "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
4548                                 return result);
4549         }
4550
4551         return result;
4552 }
4553
4554 static int fiji_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
4555                           struct fiji_single_dpm_table * dpm_table,
4556                              uint32_t low_limit, uint32_t high_limit)
4557 {
4558         uint32_t i;
4559
4560         for (i = 0; i < dpm_table->count; i++) {
4561                 if ((dpm_table->dpm_levels[i].value < low_limit) ||
4562                     (dpm_table->dpm_levels[i].value > high_limit))
4563                         dpm_table->dpm_levels[i].enabled = false;
4564                 else
4565                         dpm_table->dpm_levels[i].enabled = true;
4566         }
4567         return 0;
4568 }
4569
4570 static int fiji_trim_dpm_states(struct pp_hwmgr *hwmgr,
4571                 const struct fiji_power_state *fiji_ps)
4572 {
4573         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4574         uint32_t high_limit_count;
4575
4576         PP_ASSERT_WITH_CODE((fiji_ps->performance_level_count >= 1),
4577                         "power state did not have any performance level",
4578                         return -1);
4579
4580         high_limit_count = (1 == fiji_ps->performance_level_count) ? 0 : 1;
4581
4582         fiji_trim_single_dpm_states(hwmgr,
4583                         &(data->dpm_table.sclk_table),
4584                         fiji_ps->performance_levels[0].engine_clock,
4585                         fiji_ps->performance_levels[high_limit_count].engine_clock);
4586
4587         fiji_trim_single_dpm_states(hwmgr,
4588                         &(data->dpm_table.mclk_table),
4589                         fiji_ps->performance_levels[0].memory_clock,
4590                         fiji_ps->performance_levels[high_limit_count].memory_clock);
4591
4592         return 0;
4593 }
4594
4595 static int fiji_generate_dpm_level_enable_mask(
4596                 struct pp_hwmgr *hwmgr, const void *input)
4597 {
4598         int result;
4599         const struct phm_set_power_state_input *states =
4600                         (const struct phm_set_power_state_input *)input;
4601         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4602         const struct fiji_power_state *fiji_ps =
4603                         cast_const_phw_fiji_power_state(states->pnew_state);
4604
4605         result = fiji_trim_dpm_states(hwmgr, fiji_ps);
4606         if (result)
4607                 return result;
4608
4609         data->dpm_level_enable_mask.sclk_dpm_enable_mask =
4610                         fiji_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
4611         data->dpm_level_enable_mask.mclk_dpm_enable_mask =
4612                         fiji_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
4613         data->last_mclk_dpm_enable_mask =
4614                         data->dpm_level_enable_mask.mclk_dpm_enable_mask;
4615
4616         if (data->uvd_enabled) {
4617                 if (data->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
4618                         data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
4619         }
4620
4621         data->dpm_level_enable_mask.pcie_dpm_enable_mask =
4622                         fiji_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
4623
4624         return 0;
4625 }
4626
4627 static int fiji_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
4628 {
4629         return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
4630                                   (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
4631                                   (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
4632 }
4633
4634 int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
4635 {
4636         return smum_send_msg_to_smc(hwmgr->smumgr, enable?
4637                         PPSMC_MSG_VCEDPM_Enable :
4638                         PPSMC_MSG_VCEDPM_Disable);
4639 }
4640
4641 static int fiji_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable)
4642 {
4643         return smum_send_msg_to_smc(hwmgr->smumgr, enable?
4644                         PPSMC_MSG_SAMUDPM_Enable :
4645                         PPSMC_MSG_SAMUDPM_Disable);
4646 }
4647
4648 static int fiji_enable_disable_acp_dpm(struct pp_hwmgr *hwmgr, bool enable)
4649 {
4650         return smum_send_msg_to_smc(hwmgr->smumgr, enable?
4651                         PPSMC_MSG_ACPDPM_Enable :
4652                         PPSMC_MSG_ACPDPM_Disable);
4653 }
4654
4655 int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
4656 {
4657         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4658         uint32_t mm_boot_level_offset, mm_boot_level_value;
4659         struct phm_ppt_v1_information *table_info =
4660                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
4661
4662         if (!bgate) {
4663                 data->smc_state_table.UvdBootLevel = 0;
4664                 if (table_info->mm_dep_table->count > 0)
4665                         data->smc_state_table.UvdBootLevel =
4666                                         (uint8_t) (table_info->mm_dep_table->count - 1);
4667                 mm_boot_level_offset = data->dpm_table_start +
4668                                 offsetof(SMU73_Discrete_DpmTable, UvdBootLevel);
4669                 mm_boot_level_offset /= 4;
4670                 mm_boot_level_offset *= 4;
4671                 mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
4672                                 CGS_IND_REG__SMC, mm_boot_level_offset);
4673                 mm_boot_level_value &= 0x00FFFFFF;
4674                 mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
4675                 cgs_write_ind_register(hwmgr->device,
4676                                 CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
4677
4678                 if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4679                                 PHM_PlatformCaps_UVDDPM) ||
4680                         phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4681                                 PHM_PlatformCaps_StablePState))
4682                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4683                                         PPSMC_MSG_UVDDPM_SetEnabledMask,
4684                                         (uint32_t)(1 << data->smc_state_table.UvdBootLevel));
4685         }
4686
4687         return fiji_enable_disable_uvd_dpm(hwmgr, !bgate);
4688 }
4689
4690 int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
4691 {
4692         const struct phm_set_power_state_input *states =
4693                         (const struct phm_set_power_state_input *)input;
4694         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4695         const struct fiji_power_state *fiji_nps =
4696                         cast_const_phw_fiji_power_state(states->pnew_state);
4697         const struct fiji_power_state *fiji_cps =
4698                         cast_const_phw_fiji_power_state(states->pcurrent_state);
4699
4700         uint32_t mm_boot_level_offset, mm_boot_level_value;
4701         struct phm_ppt_v1_information *table_info =
4702                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
4703
4704         if (fiji_nps->vce_clks.evclk >0 &&
4705         (fiji_cps == NULL || fiji_cps->vce_clks.evclk == 0)) {
4706                 data->smc_state_table.VceBootLevel =
4707                                 (uint8_t) (table_info->mm_dep_table->count - 1);
4708
4709                 mm_boot_level_offset = data->dpm_table_start +
4710                                 offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
4711                 mm_boot_level_offset /= 4;
4712                 mm_boot_level_offset *= 4;
4713                 mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
4714                                 CGS_IND_REG__SMC, mm_boot_level_offset);
4715                 mm_boot_level_value &= 0xFF00FFFF;
4716                 mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
4717                 cgs_write_ind_register(hwmgr->device,
4718                                 CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
4719
4720                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4721                                 PHM_PlatformCaps_StablePState)) {
4722                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4723                                         PPSMC_MSG_VCEDPM_SetEnabledMask,
4724                                         (uint32_t)1 << data->smc_state_table.VceBootLevel);
4725
4726                         fiji_enable_disable_vce_dpm(hwmgr, true);
4727                 } else if (fiji_nps->vce_clks.evclk == 0 &&
4728                                 fiji_cps != NULL &&
4729                                 fiji_cps->vce_clks.evclk > 0)
4730                         fiji_enable_disable_vce_dpm(hwmgr, false);
4731         }
4732
4733         return 0;
4734 }
4735
4736 int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate)
4737 {
4738         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4739         uint32_t mm_boot_level_offset, mm_boot_level_value;
4740         struct phm_ppt_v1_information *table_info =
4741                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
4742
4743         if (!bgate) {
4744                 data->smc_state_table.SamuBootLevel =
4745                                 (uint8_t) (table_info->mm_dep_table->count - 1);
4746                 mm_boot_level_offset = data->dpm_table_start +
4747                                 offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
4748                 mm_boot_level_offset /= 4;
4749                 mm_boot_level_offset *= 4;
4750                 mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
4751                                 CGS_IND_REG__SMC, mm_boot_level_offset);
4752                 mm_boot_level_value &= 0xFFFFFF00;
4753                 mm_boot_level_value |= data->smc_state_table.SamuBootLevel << 0;
4754                 cgs_write_ind_register(hwmgr->device,
4755                                 CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
4756
4757                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4758                                 PHM_PlatformCaps_StablePState))
4759                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4760                                         PPSMC_MSG_SAMUDPM_SetEnabledMask,
4761                                         (uint32_t)(1 << data->smc_state_table.SamuBootLevel));
4762         }
4763
4764         return fiji_enable_disable_samu_dpm(hwmgr, !bgate);
4765 }
4766
4767 int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate)
4768 {
4769         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4770         uint32_t mm_boot_level_offset, mm_boot_level_value;
4771         struct phm_ppt_v1_information *table_info =
4772                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
4773
4774         if (!bgate) {
4775                 data->smc_state_table.AcpBootLevel =
4776                                 (uint8_t) (table_info->mm_dep_table->count - 1);
4777                 mm_boot_level_offset = data->dpm_table_start +
4778                                 offsetof(SMU73_Discrete_DpmTable, AcpBootLevel);
4779                 mm_boot_level_offset /= 4;
4780                 mm_boot_level_offset *= 4;
4781                 mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
4782                                 CGS_IND_REG__SMC, mm_boot_level_offset);
4783                 mm_boot_level_value &= 0xFFFF00FF;
4784                 mm_boot_level_value |= data->smc_state_table.AcpBootLevel << 8;
4785                 cgs_write_ind_register(hwmgr->device,
4786                                 CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
4787
4788                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4789                                 PHM_PlatformCaps_StablePState))
4790                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4791                                                 PPSMC_MSG_ACPDPM_SetEnabledMask,
4792                                                 (uint32_t)(1 << data->smc_state_table.AcpBootLevel));
4793         }
4794
4795         return fiji_enable_disable_acp_dpm(hwmgr, !bgate);
4796 }
4797
4798 static int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr)
4799 {
4800         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4801
4802         int result = 0;
4803         uint32_t low_sclk_interrupt_threshold = 0;
4804
4805         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4806                         PHM_PlatformCaps_SclkThrottleLowNotification)
4807                 && (hwmgr->gfx_arbiter.sclk_threshold !=
4808                                 data->low_sclk_interrupt_threshold)) {
4809                 data->low_sclk_interrupt_threshold =
4810                                 hwmgr->gfx_arbiter.sclk_threshold;
4811                 low_sclk_interrupt_threshold =
4812                                 data->low_sclk_interrupt_threshold;
4813
4814                 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
4815
4816                 result = fiji_copy_bytes_to_smc(
4817                                 hwmgr->smumgr,
4818                                 data->dpm_table_start +
4819                                 offsetof(SMU73_Discrete_DpmTable,
4820                                         LowSclkInterruptThreshold),
4821                                 (uint8_t *)&low_sclk_interrupt_threshold,
4822                                 sizeof(uint32_t),
4823                                 data->sram_end);
4824         }
4825
4826         return result;
4827 }
4828
4829 static int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
4830 {
4831         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4832
4833         if (data->need_update_smu7_dpm_table &
4834                 (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
4835                 return fiji_program_memory_timing_parameters(hwmgr);
4836
4837         return 0;
4838 }
4839
4840 static int fiji_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
4841 {
4842         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4843
4844         if (0 == data->need_update_smu7_dpm_table)
4845                 return 0;
4846
4847         if ((0 == data->sclk_dpm_key_disabled) &&
4848                 (data->need_update_smu7_dpm_table &
4849                 (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
4850
4851                 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
4852                                     "Trying to Unfreeze SCLK DPM when DPM is disabled",
4853                                     );
4854                 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
4855                                 PPSMC_MSG_SCLKDPM_UnfreezeLevel),
4856                         "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
4857                         return -1);
4858         }
4859
4860         if ((0 == data->mclk_dpm_key_disabled) &&
4861                 (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
4862
4863                 PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
4864                                     "Trying to Unfreeze MCLK DPM when DPM is disabled",
4865                                     );
4866                 PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
4867                                 PPSMC_MSG_SCLKDPM_UnfreezeLevel),
4868                     "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
4869                     return -1);
4870         }
4871
4872         data->need_update_smu7_dpm_table = 0;
4873
4874         return 0;
4875 }
4876
4877 /* Look up the voltaged based on DAL's requested level.
4878  * and then send the requested VDDC voltage to SMC
4879  */
4880 static void fiji_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
4881 {
4882         return;
4883 }
4884
4885 static int fiji_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
4886 {
4887         int result;
4888         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4889
4890         /* Apply minimum voltage based on DAL's request level */
4891         fiji_apply_dal_minimum_voltage_request(hwmgr);
4892
4893         if (0 == data->sclk_dpm_key_disabled) {
4894                 /* Checking if DPM is running.  If we discover hang because of this,
4895                  *  we should skip this message.
4896                  */
4897                 if (!fiji_is_dpm_running(hwmgr))
4898                         printk(KERN_ERR "[ powerplay ] "
4899                                         "Trying to set Enable Mask when DPM is disabled \n");
4900
4901                 if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
4902                         result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4903                                         PPSMC_MSG_SCLKDPM_SetEnabledMask,
4904                                         data->dpm_level_enable_mask.sclk_dpm_enable_mask);
4905                         PP_ASSERT_WITH_CODE((0 == result),
4906                                 "Set Sclk Dpm enable Mask failed", return -1);
4907                 }
4908         }
4909
4910         if (0 == data->mclk_dpm_key_disabled) {
4911                 /* Checking if DPM is running.  If we discover hang because of this,
4912                  *  we should skip this message.
4913                  */
4914                 if (!fiji_is_dpm_running(hwmgr))
4915                         printk(KERN_ERR "[ powerplay ]"
4916                                         " Trying to set Enable Mask when DPM is disabled \n");
4917
4918                 if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
4919                         result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
4920                                         PPSMC_MSG_MCLKDPM_SetEnabledMask,
4921                                         data->dpm_level_enable_mask.mclk_dpm_enable_mask);
4922                         PP_ASSERT_WITH_CODE((0 == result),
4923                                 "Set Mclk Dpm enable Mask failed", return -1);
4924                 }
4925         }
4926
4927         return 0;
4928 }
4929
4930 static int fiji_notify_link_speed_change_after_state_change(
4931                 struct pp_hwmgr *hwmgr, const void *input)
4932 {
4933         const struct phm_set_power_state_input *states =
4934                         (const struct phm_set_power_state_input *)input;
4935         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
4936         const struct fiji_power_state *fiji_ps =
4937                         cast_const_phw_fiji_power_state(states->pnew_state);
4938         uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_ps);
4939         uint8_t  request;
4940
4941         if (data->pspp_notify_required) {
4942                 if (target_link_speed == PP_PCIEGen3)
4943                         request = PCIE_PERF_REQ_GEN3;
4944                 else if (target_link_speed == PP_PCIEGen2)
4945                         request = PCIE_PERF_REQ_GEN2;
4946                 else
4947                         request = PCIE_PERF_REQ_GEN1;
4948
4949                 if(request == PCIE_PERF_REQ_GEN1 &&
4950                                 fiji_get_current_pcie_speed(hwmgr) > 0)
4951                         return 0;
4952
4953                 if (acpi_pcie_perf_request(hwmgr->device, request, false)) {
4954                         if (PP_PCIEGen2 == target_link_speed)
4955                                 printk("PSPP request to switch to Gen2 from Gen3 Failed!");
4956                         else
4957                                 printk("PSPP request to switch to Gen1 from Gen2 Failed!");
4958                 }
4959         }
4960
4961         return 0;
4962 }
4963
4964 static int fiji_set_power_state_tasks(struct pp_hwmgr *hwmgr,
4965                 const void *input)
4966 {
4967         int tmp_result, result = 0;
4968
4969         tmp_result = fiji_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
4970         PP_ASSERT_WITH_CODE((0 == tmp_result),
4971                         "Failed to find DPM states clocks in DPM table!",
4972                         result = tmp_result);
4973
4974         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
4975                         PHM_PlatformCaps_PCIEPerformanceRequest)) {
4976                 tmp_result =
4977                         fiji_request_link_speed_change_before_state_change(hwmgr, input);
4978                 PP_ASSERT_WITH_CODE((0 == tmp_result),
4979                                 "Failed to request link speed change before state change!",
4980                                 result = tmp_result);
4981         }
4982
4983         tmp_result = fiji_freeze_sclk_mclk_dpm(hwmgr);
4984         PP_ASSERT_WITH_CODE((0 == tmp_result),
4985                         "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
4986
4987         tmp_result = fiji_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
4988         PP_ASSERT_WITH_CODE((0 == tmp_result),
4989                         "Failed to populate and upload SCLK MCLK DPM levels!",
4990                         result = tmp_result);
4991
4992         tmp_result = fiji_generate_dpm_level_enable_mask(hwmgr, input);
4993         PP_ASSERT_WITH_CODE((0 == tmp_result),
4994                         "Failed to generate DPM level enabled mask!",
4995                         result = tmp_result);
4996
4997         tmp_result = fiji_update_vce_dpm(hwmgr, input);
4998         PP_ASSERT_WITH_CODE((0 == tmp_result),
4999                         "Failed to update VCE DPM!",
5000                         result = tmp_result);
5001
5002         tmp_result = fiji_update_sclk_threshold(hwmgr);
5003         PP_ASSERT_WITH_CODE((0 == tmp_result),
5004                         "Failed to update SCLK threshold!",
5005                         result = tmp_result);
5006
5007         tmp_result = fiji_program_mem_timing_parameters(hwmgr);
5008         PP_ASSERT_WITH_CODE((0 == tmp_result),
5009                         "Failed to program memory timing parameters!",
5010                         result = tmp_result);
5011
5012         tmp_result = fiji_unfreeze_sclk_mclk_dpm(hwmgr);
5013         PP_ASSERT_WITH_CODE((0 == tmp_result),
5014                         "Failed to unfreeze SCLK MCLK DPM!",
5015                         result = tmp_result);
5016
5017         tmp_result = fiji_upload_dpm_level_enable_mask(hwmgr);
5018         PP_ASSERT_WITH_CODE((0 == tmp_result),
5019                         "Failed to upload DPM level enabled mask!",
5020                         result = tmp_result);
5021
5022         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
5023                         PHM_PlatformCaps_PCIEPerformanceRequest)) {
5024                 tmp_result =
5025                         fiji_notify_link_speed_change_after_state_change(hwmgr, input);
5026                 PP_ASSERT_WITH_CODE((0 == tmp_result),
5027                                 "Failed to notify link speed change after state change!",
5028                                 result = tmp_result);
5029         }
5030
5031         return result;
5032 }
5033
5034 static int fiji_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
5035 {
5036         struct pp_power_state  *ps;
5037         struct fiji_power_state  *fiji_ps;
5038
5039         if (hwmgr == NULL)
5040                 return -EINVAL;
5041
5042         ps = hwmgr->request_ps;
5043
5044         if (ps == NULL)
5045                 return -EINVAL;
5046
5047         fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
5048
5049         if (low)
5050                 return fiji_ps->performance_levels[0].engine_clock;
5051         else
5052                 return fiji_ps->performance_levels
5053                                 [fiji_ps->performance_level_count-1].engine_clock;
5054 }
5055
5056 static int fiji_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
5057 {
5058         struct pp_power_state  *ps;
5059         struct fiji_power_state  *fiji_ps;
5060
5061         if (hwmgr == NULL)
5062                 return -EINVAL;
5063
5064         ps = hwmgr->request_ps;
5065
5066         if (ps == NULL)
5067                 return -EINVAL;
5068
5069         fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
5070
5071         if (low)
5072                 return fiji_ps->performance_levels[0].memory_clock;
5073         else
5074                 return fiji_ps->performance_levels
5075                                 [fiji_ps->performance_level_count-1].memory_clock;
5076 }
5077
5078 static void fiji_print_current_perforce_level(
5079                 struct pp_hwmgr *hwmgr, struct seq_file *m)
5080 {
5081         uint32_t sclk, mclk, activity_percent = 0;
5082         uint32_t offset;
5083         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5084
5085         smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
5086
5087         sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5088
5089         smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
5090
5091         mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5092         seq_printf(m, "\n [  mclk  ]: %u MHz\n\n [  sclk  ]: %u MHz\n",
5093                         mclk / 100, sclk / 100);
5094
5095         offset = data->soft_regs_start + offsetof(SMU73_SoftRegisters, AverageGraphicsActivity);
5096         activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
5097         activity_percent += 0x80;
5098         activity_percent >>= 8;
5099
5100         seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
5101
5102         seq_printf(m, "uvd    %sabled\n", data->uvd_power_gated ? "dis" : "en");
5103
5104         seq_printf(m, "vce    %sabled\n", data->vce_power_gated ? "dis" : "en");
5105 }
5106
5107 static int fiji_program_display_gap(struct pp_hwmgr *hwmgr)
5108 {
5109         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5110         uint32_t num_active_displays = 0;
5111         uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
5112                         CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
5113         uint32_t display_gap2;
5114         uint32_t pre_vbi_time_in_us;
5115         uint32_t frame_time_in_us;
5116         uint32_t ref_clock;
5117         uint32_t refresh_rate = 0;
5118         struct cgs_display_info info = {0};
5119         struct cgs_mode_info mode_info;
5120
5121         info.mode_info = &mode_info;
5122
5123         cgs_get_active_displays_info(hwmgr->device, &info);
5124         num_active_displays = info.display_count;
5125
5126         display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
5127                         DISP_GAP, (num_active_displays > 0)?
5128                         DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
5129         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
5130                         ixCG_DISPLAY_GAP_CNTL, display_gap);
5131
5132         ref_clock = mode_info.ref_clock;
5133         refresh_rate = mode_info.refresh_rate;
5134
5135         if (refresh_rate == 0)
5136                 refresh_rate = 60;
5137
5138         frame_time_in_us = 1000000 / refresh_rate;
5139
5140         pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
5141         display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
5142
5143         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
5144                         ixCG_DISPLAY_GAP_CNTL2, display_gap2);
5145
5146         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
5147                         data->soft_regs_start +
5148                         offsetof(SMU73_SoftRegisters, PreVBlankGap), 0x64);
5149
5150         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
5151                         data->soft_regs_start +
5152                         offsetof(SMU73_SoftRegisters, VBlankTimeout),
5153                         (frame_time_in_us - pre_vbi_time_in_us));
5154
5155         if (num_active_displays == 1)
5156                 tonga_notify_smc_display_change(hwmgr, true);
5157
5158         return 0;
5159 }
5160
5161 static int fiji_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
5162 {
5163         return fiji_program_display_gap(hwmgr);
5164 }
5165
5166 static int fiji_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr,
5167                 uint16_t us_max_fan_pwm)
5168 {
5169         hwmgr->thermal_controller.
5170         advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
5171
5172         if (phm_is_hw_access_blocked(hwmgr))
5173                 return 0;
5174
5175         return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5176                         PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
5177 }
5178
5179 static int fiji_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr,
5180                 uint16_t us_max_fan_rpm)
5181 {
5182         hwmgr->thermal_controller.
5183         advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
5184
5185         if (phm_is_hw_access_blocked(hwmgr))
5186                 return 0;
5187
5188         return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5189                         PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
5190 }
5191
5192 static int fiji_dpm_set_interrupt_state(void *private_data,
5193                                          unsigned src_id, unsigned type,
5194                                          int enabled)
5195 {
5196         uint32_t cg_thermal_int;
5197         struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
5198
5199         if (hwmgr == NULL)
5200                 return -EINVAL;
5201
5202         switch (type) {
5203         case AMD_THERMAL_IRQ_LOW_TO_HIGH:
5204                 if (enabled) {
5205                         cg_thermal_int = cgs_read_ind_register(hwmgr->device,
5206                                         CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5207                         cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
5208                         cgs_write_ind_register(hwmgr->device,
5209                                         CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5210                 } else {
5211                         cg_thermal_int = cgs_read_ind_register(hwmgr->device,
5212                                         CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5213                         cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
5214                         cgs_write_ind_register(hwmgr->device,
5215                                         CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5216                 }
5217                 break;
5218
5219         case AMD_THERMAL_IRQ_HIGH_TO_LOW:
5220                 if (enabled) {
5221                         cg_thermal_int = cgs_read_ind_register(hwmgr->device,
5222                                         CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5223                         cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
5224                         cgs_write_ind_register(hwmgr->device,
5225                                         CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5226                 } else {
5227                         cg_thermal_int = cgs_read_ind_register(hwmgr->device,
5228                                         CGS_IND_REG__SMC, ixCG_THERMAL_INT);
5229                         cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
5230                         cgs_write_ind_register(hwmgr->device,
5231                                         CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
5232                 }
5233                 break;
5234         default:
5235                 break;
5236         }
5237         return 0;
5238 }
5239
5240 static int fiji_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
5241                                         const void *thermal_interrupt_info)
5242 {
5243         int result;
5244         const struct pp_interrupt_registration_info *info =
5245                         (const struct pp_interrupt_registration_info *)
5246                         thermal_interrupt_info;
5247
5248         if (info == NULL)
5249                 return -EINVAL;
5250
5251         result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
5252                                 fiji_dpm_set_interrupt_state,
5253                                 info->call_back, info->context);
5254
5255         if (result)
5256                 return -EINVAL;
5257
5258         result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
5259                                 fiji_dpm_set_interrupt_state,
5260                                 info->call_back, info->context);
5261
5262         if (result)
5263                 return -EINVAL;
5264
5265         return 0;
5266 }
5267
5268 static int fiji_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
5269 {
5270         if (mode) {
5271                 /* stop auto-manage */
5272                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
5273                                 PHM_PlatformCaps_MicrocodeFanControl))
5274                         fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
5275                 fiji_fan_ctrl_set_static_mode(hwmgr, mode);
5276         } else
5277                 /* restart auto-manage */
5278                 fiji_fan_ctrl_reset_fan_speed_to_default(hwmgr);
5279
5280         return 0;
5281 }
5282
5283 static int fiji_get_fan_control_mode(struct pp_hwmgr *hwmgr)
5284 {
5285         if (hwmgr->fan_ctrl_is_in_default_mode)
5286                 return hwmgr->fan_ctrl_default_mode;
5287         else
5288                 return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
5289                                 CG_FDO_CTRL2, FDO_PWM_MODE);
5290 }
5291
5292 static int fiji_force_clock_level(struct pp_hwmgr *hwmgr,
5293                 enum pp_clock_type type, uint32_t mask)
5294 {
5295         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5296
5297         if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
5298                 return -EINVAL;
5299
5300         switch (type) {
5301         case PP_SCLK:
5302                 if (!data->sclk_dpm_key_disabled)
5303                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5304                                         PPSMC_MSG_SCLKDPM_SetEnabledMask,
5305                                         data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
5306                 break;
5307
5308         case PP_MCLK:
5309                 if (!data->mclk_dpm_key_disabled)
5310                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5311                                         PPSMC_MSG_MCLKDPM_SetEnabledMask,
5312                                         data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
5313                 break;
5314
5315         case PP_PCIE:
5316         {
5317                 uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
5318                 uint32_t level = 0;
5319
5320                 while (tmp >>= 1)
5321                         level++;
5322
5323                 if (!data->pcie_dpm_key_disabled)
5324                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
5325                                         PPSMC_MSG_PCIeDPM_ForceLevel,
5326                                         level);
5327                 break;
5328         }
5329         default:
5330                 break;
5331         }
5332
5333         return 0;
5334 }
5335
5336 static int fiji_print_clock_levels(struct pp_hwmgr *hwmgr,
5337                 enum pp_clock_type type, char *buf)
5338 {
5339         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5340         struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
5341         struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
5342         struct fiji_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table);
5343         int i, now, size = 0;
5344         uint32_t clock, pcie_speed;
5345
5346         switch (type) {
5347         case PP_SCLK:
5348                 smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
5349                 clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5350
5351                 for (i = 0; i < sclk_table->count; i++) {
5352                         if (clock > sclk_table->dpm_levels[i].value)
5353                                 continue;
5354                         break;
5355                 }
5356                 now = i;
5357
5358                 for (i = 0; i < sclk_table->count; i++)
5359                         size += sprintf(buf + size, "%d: %uMhz %s\n",
5360                                         i, sclk_table->dpm_levels[i].value / 100,
5361                                         (i == now) ? "*" : "");
5362                 break;
5363         case PP_MCLK:
5364                 smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
5365                 clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
5366
5367                 for (i = 0; i < mclk_table->count; i++) {
5368                         if (clock > mclk_table->dpm_levels[i].value)
5369                                 continue;
5370                         break;
5371                 }
5372                 now = i;
5373
5374                 for (i = 0; i < mclk_table->count; i++)
5375                         size += sprintf(buf + size, "%d: %uMhz %s\n",
5376                                         i, mclk_table->dpm_levels[i].value / 100,
5377                                         (i == now) ? "*" : "");
5378                 break;
5379         case PP_PCIE:
5380                 pcie_speed = fiji_get_current_pcie_speed(hwmgr);
5381                 for (i = 0; i < pcie_table->count; i++) {
5382                         if (pcie_speed != pcie_table->dpm_levels[i].value)
5383                                 continue;
5384                         break;
5385                 }
5386                 now = i;
5387
5388                 for (i = 0; i < pcie_table->count; i++)
5389                         size += sprintf(buf + size, "%d: %s %s\n", i,
5390                                         (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x1" :
5391                                         (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" :
5392                                         (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "",
5393                                         (i == now) ? "*" : "");
5394                 break;
5395         default:
5396                 break;
5397         }
5398         return size;
5399 }
5400
5401 static inline bool fiji_are_power_levels_equal(const struct fiji_performance_level *pl1,
5402                                                            const struct fiji_performance_level *pl2)
5403 {
5404         return ((pl1->memory_clock == pl2->memory_clock) &&
5405                   (pl1->engine_clock == pl2->engine_clock) &&
5406                   (pl1->pcie_gen == pl2->pcie_gen) &&
5407                   (pl1->pcie_lane == pl2->pcie_lane));
5408 }
5409
5410 static int
5411 fiji_check_states_equal(struct pp_hwmgr *hwmgr,
5412                 const struct pp_hw_power_state *pstate1,
5413                 const struct pp_hw_power_state *pstate2, bool *equal)
5414 {
5415         const struct fiji_power_state *psa = cast_const_phw_fiji_power_state(pstate1);
5416         const struct fiji_power_state *psb = cast_const_phw_fiji_power_state(pstate2);
5417         int i;
5418
5419         if (equal == NULL || psa == NULL || psb == NULL)
5420                 return -EINVAL;
5421
5422         /* If the two states don't even have the same number of performance levels they cannot be the same state. */
5423         if (psa->performance_level_count != psb->performance_level_count) {
5424                 *equal = false;
5425                 return 0;
5426         }
5427
5428         for (i = 0; i < psa->performance_level_count; i++) {
5429                 if (!fiji_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
5430                         /* If we have found even one performance level pair that is different the states are different. */
5431                         *equal = false;
5432                         return 0;
5433                 }
5434         }
5435
5436         /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
5437         *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk));
5438         *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk));
5439         *equal &= (psa->sclk_threshold == psb->sclk_threshold);
5440         *equal &= (psa->acp_clk == psb->acp_clk);
5441
5442         return 0;
5443 }
5444
5445 static bool
5446 fiji_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
5447 {
5448         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5449         bool is_update_required = false;
5450         struct cgs_display_info info = {0,0,NULL};
5451
5452         cgs_get_active_displays_info(hwmgr->device, &info);
5453
5454         if (data->display_timing.num_existing_displays != info.display_count)
5455                 is_update_required = true;
5456
5457         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
5458                 if(hwmgr->display_config.min_core_set_clock_in_sr != data->display_timing.min_clock_in_sr)
5459                         is_update_required = true;
5460         }
5461
5462         return is_update_required;
5463 }
5464
5465 static int fiji_get_sclk_od(struct pp_hwmgr *hwmgr)
5466 {
5467         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5468         struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
5469         struct fiji_single_dpm_table *golden_sclk_table =
5470                         &(data->golden_dpm_table.sclk_table);
5471         int value;
5472
5473         value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
5474                         golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
5475                         100 /
5476                         golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
5477
5478         return value;
5479 }
5480
5481 static int fiji_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
5482 {
5483         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5484         struct fiji_single_dpm_table *golden_sclk_table =
5485                         &(data->golden_dpm_table.sclk_table);
5486         struct pp_power_state  *ps;
5487         struct fiji_power_state  *fiji_ps;
5488
5489         if (value > 20)
5490                 value = 20;
5491
5492         ps = hwmgr->request_ps;
5493
5494         if (ps == NULL)
5495                 return -EINVAL;
5496
5497         fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
5498
5499         fiji_ps->performance_levels[fiji_ps->performance_level_count - 1].engine_clock =
5500                         golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
5501                         value / 100 +
5502                         golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
5503
5504         return 0;
5505 }
5506
5507 static int fiji_get_mclk_od(struct pp_hwmgr *hwmgr)
5508 {
5509         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5510         struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
5511         struct fiji_single_dpm_table *golden_mclk_table =
5512                         &(data->golden_dpm_table.mclk_table);
5513         int value;
5514
5515         value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
5516                         golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
5517                         100 /
5518                         golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
5519
5520         return value;
5521 }
5522
5523 static int fiji_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
5524 {
5525         struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
5526         struct fiji_single_dpm_table *golden_mclk_table =
5527                         &(data->golden_dpm_table.mclk_table);
5528         struct pp_power_state  *ps;
5529         struct fiji_power_state  *fiji_ps;
5530
5531         if (value > 20)
5532                 value = 20;
5533
5534         ps = hwmgr->request_ps;
5535
5536         if (ps == NULL)
5537                 return -EINVAL;
5538
5539         fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
5540
5541         fiji_ps->performance_levels[fiji_ps->performance_level_count - 1].memory_clock =
5542                         golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
5543                         value / 100 +
5544                         golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
5545
5546         return 0;
5547 }
5548
5549 static const struct pp_hwmgr_func fiji_hwmgr_funcs = {
5550         .backend_init = &fiji_hwmgr_backend_init,
5551         .backend_fini = &fiji_hwmgr_backend_fini,
5552         .asic_setup = &fiji_setup_asic_task,
5553         .dynamic_state_management_enable = &fiji_enable_dpm_tasks,
5554         .dynamic_state_management_disable = &fiji_disable_dpm_tasks,
5555         .force_dpm_level = &fiji_dpm_force_dpm_level,
5556         .get_num_of_pp_table_entries = &tonga_get_number_of_powerplay_table_entries,
5557         .get_power_state_size = &fiji_get_power_state_size,
5558         .get_pp_table_entry = &fiji_get_pp_table_entry,
5559         .patch_boot_state = &fiji_patch_boot_state,
5560         .apply_state_adjust_rules = &fiji_apply_state_adjust_rules,
5561         .power_state_set = &fiji_set_power_state_tasks,
5562         .get_sclk = &fiji_dpm_get_sclk,
5563         .get_mclk = &fiji_dpm_get_mclk,
5564         .print_current_perforce_level = &fiji_print_current_perforce_level,
5565         .powergate_uvd = &fiji_phm_powergate_uvd,
5566         .powergate_vce = &fiji_phm_powergate_vce,
5567         .disable_clock_power_gating = &fiji_phm_disable_clock_power_gating,
5568         .notify_smc_display_config_after_ps_adjustment =
5569                         &tonga_notify_smc_display_config_after_ps_adjustment,
5570         .display_config_changed = &fiji_display_configuration_changed_task,
5571         .set_max_fan_pwm_output = fiji_set_max_fan_pwm_output,
5572         .set_max_fan_rpm_output = fiji_set_max_fan_rpm_output,
5573         .get_temperature = fiji_thermal_get_temperature,
5574         .stop_thermal_controller = fiji_thermal_stop_thermal_controller,
5575         .get_fan_speed_info = fiji_fan_ctrl_get_fan_speed_info,
5576         .get_fan_speed_percent = fiji_fan_ctrl_get_fan_speed_percent,
5577         .set_fan_speed_percent = fiji_fan_ctrl_set_fan_speed_percent,
5578         .reset_fan_speed_to_default = fiji_fan_ctrl_reset_fan_speed_to_default,
5579         .get_fan_speed_rpm = fiji_fan_ctrl_get_fan_speed_rpm,
5580         .set_fan_speed_rpm = fiji_fan_ctrl_set_fan_speed_rpm,
5581         .uninitialize_thermal_controller = fiji_thermal_ctrl_uninitialize_thermal_controller,
5582         .register_internal_thermal_interrupt = fiji_register_internal_thermal_interrupt,
5583         .set_fan_control_mode = fiji_set_fan_control_mode,
5584         .get_fan_control_mode = fiji_get_fan_control_mode,
5585         .check_states_equal = fiji_check_states_equal,
5586         .check_smc_update_required_for_display_configuration = fiji_check_smc_update_required_for_display_configuration,
5587         .force_clock_level = fiji_force_clock_level,
5588         .print_clock_levels = fiji_print_clock_levels,
5589         .get_sclk_od = fiji_get_sclk_od,
5590         .set_sclk_od = fiji_set_sclk_od,
5591         .get_mclk_od = fiji_get_mclk_od,
5592         .set_mclk_od = fiji_set_mclk_od,
5593 };
5594
5595 int fiji_hwmgr_init(struct pp_hwmgr *hwmgr)
5596 {
5597         hwmgr->hwmgr_func = &fiji_hwmgr_funcs;
5598         hwmgr->pptable_func = &tonga_pptable_funcs;
5599         pp_fiji_thermal_initialize(hwmgr);
5600         return 0;
5601 }