diff options
author | Rex Zhu <Rex.Zhu@amd.com> | 2016-09-09 01:29:37 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2016-09-19 13:22:11 -0400 |
commit | 18edef19ea44f4379e635bd32b553e58e23bba95 (patch) | |
tree | 7319a18e30eee207cb59580f334f7b203fa41742 /drivers/gpu | |
parent | 4be051aeb3964146d3922238fff0ed1e4a9656d1 (diff) |
drm/amd/powerplay: implement fw image related smu interface for Fiji.
Signed-off-by: Rex Zhu <Rex.Zhu@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/smumgr/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c | 2371 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.h | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c | 37 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h | 19 |
5 files changed, 2472 insertions, 8 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile index 872a2f030989..7561239eb874 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for the 'smu manager' sub-component of powerplay. | 2 | # Makefile for the 'smu manager' sub-component of powerplay. |
3 | # It provides the smu management services for the driver. | 3 | # It provides the smu management services for the driver. |
4 | 4 | ||
5 | SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o \ | 5 | SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o fiji_smc.o\ |
6 | polaris10_smumgr.o iceland_smumgr.o polaris10_smc.o | 6 | polaris10_smumgr.o iceland_smumgr.o polaris10_smc.o |
7 | 7 | ||
8 | AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) | 8 | AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) |
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c new file mode 100644 index 000000000000..fd0c00173cce --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c | |||
@@ -0,0 +1,2371 @@ | |||
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 | |||
24 | #include "fiji_smc.h" | ||
25 | #include "smu7_dyn_defaults.h" | ||
26 | |||
27 | #include "smu7_hwmgr.h" | ||
28 | #include "hardwaremanager.h" | ||
29 | #include "ppatomctrl.h" | ||
30 | #include "pp_debug.h" | ||
31 | #include "cgs_common.h" | ||
32 | #include "atombios.h" | ||
33 | #include "fiji_smumgr.h" | ||
34 | #include "pppcielanes.h" | ||
35 | #include "smu7_ppsmc.h" | ||
36 | #include "smu73.h" | ||
37 | #include "smu/smu_7_1_3_d.h" | ||
38 | #include "smu/smu_7_1_3_sh_mask.h" | ||
39 | #include "gmc/gmc_8_1_d.h" | ||
40 | #include "gmc/gmc_8_1_sh_mask.h" | ||
41 | #include "bif/bif_5_0_d.h" | ||
42 | #include "bif/bif_5_0_sh_mask.h" | ||
43 | #include "dce/dce_10_0_d.h" | ||
44 | #include "dce/dce_10_0_sh_mask.h" | ||
45 | |||
46 | #define VOLTAGE_SCALE 4 | ||
47 | #define POWERTUNE_DEFAULT_SET_MAX 1 | ||
48 | #define VOLTAGE_VID_OFFSET_SCALE1 625 | ||
49 | #define VOLTAGE_VID_OFFSET_SCALE2 100 | ||
50 | #define VDDC_VDDCI_DELTA 300 | ||
51 | #define MC_CG_ARB_FREQ_F1 0x0b | ||
52 | |||
53 | /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs | ||
54 | * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] | ||
55 | */ | ||
56 | static const uint16_t fiji_clock_stretcher_lookup_table[2][4] = { | ||
57 | {600, 1050, 3, 0}, {600, 1050, 6, 1} }; | ||
58 | |||
59 | /* [FF, SS] type, [] 4 voltage ranges, and | ||
60 | * [Floor Freq, Boundary Freq, VID min , VID max] | ||
61 | */ | ||
62 | static const uint32_t fiji_clock_stretcher_ddt_table[2][4][4] = { | ||
63 | { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} }, | ||
64 | { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } }; | ||
65 | |||
66 | /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] | ||
67 | * (coming from PWR_CKS_CNTL.stretch_amount reg spec) | ||
68 | */ | ||
69 | static const uint8_t fiji_clock_stretch_amount_conversion[2][6] = { | ||
70 | {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} }; | ||
71 | |||
72 | static const struct fiji_pt_defaults fiji_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = { | ||
73 | /*sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */ | ||
74 | {1, 0xF, 0xFD, | ||
75 | /* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */ | ||
76 | 0x19, 5, 45} | ||
77 | }; | ||
78 | |||
79 | /* PPGen has the gain setting generated in x * 100 unit | ||
80 | * This function is to convert the unit to x * 4096(0x1000) unit. | ||
81 | * This is the unit expected by SMC firmware | ||
82 | */ | ||
83 | static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr, | ||
84 | struct phm_ppt_v1_clock_voltage_dependency_table *dep_table, | ||
85 | uint32_t clock, uint32_t *voltage, uint32_t *mvdd) | ||
86 | { | ||
87 | uint32_t i; | ||
88 | uint16_t vddci; | ||
89 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
90 | *voltage = *mvdd = 0; | ||
91 | |||
92 | |||
93 | /* clock - voltage dependency table is empty table */ | ||
94 | if (dep_table->count == 0) | ||
95 | return -EINVAL; | ||
96 | |||
97 | for (i = 0; i < dep_table->count; i++) { | ||
98 | /* find first sclk bigger than request */ | ||
99 | if (dep_table->entries[i].clk >= clock) { | ||
100 | *voltage |= (dep_table->entries[i].vddc * | ||
101 | VOLTAGE_SCALE) << VDDC_SHIFT; | ||
102 | if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control) | ||
103 | *voltage |= (data->vbios_boot_state.vddci_bootup_value * | ||
104 | VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
105 | else if (dep_table->entries[i].vddci) | ||
106 | *voltage |= (dep_table->entries[i].vddci * | ||
107 | VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
108 | else { | ||
109 | vddci = phm_find_closest_vddci(&(data->vddci_voltage_table), | ||
110 | (dep_table->entries[i].vddc - | ||
111 | VDDC_VDDCI_DELTA)); | ||
112 | *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
113 | } | ||
114 | |||
115 | if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) | ||
116 | *mvdd = data->vbios_boot_state.mvdd_bootup_value * | ||
117 | VOLTAGE_SCALE; | ||
118 | else if (dep_table->entries[i].mvdd) | ||
119 | *mvdd = (uint32_t) dep_table->entries[i].mvdd * | ||
120 | VOLTAGE_SCALE; | ||
121 | |||
122 | *voltage |= 1 << PHASES_SHIFT; | ||
123 | return 0; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /* sclk is bigger than max sclk in the dependence table */ | ||
128 | *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT; | ||
129 | |||
130 | if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control) | ||
131 | *voltage |= (data->vbios_boot_state.vddci_bootup_value * | ||
132 | VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
133 | else if (dep_table->entries[i-1].vddci) { | ||
134 | vddci = phm_find_closest_vddci(&(data->vddci_voltage_table), | ||
135 | (dep_table->entries[i].vddc - | ||
136 | VDDC_VDDCI_DELTA)); | ||
137 | *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
138 | } | ||
139 | |||
140 | if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) | ||
141 | *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE; | ||
142 | else if (dep_table->entries[i].mvdd) | ||
143 | *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE; | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | |||
149 | static uint16_t scale_fan_gain_settings(uint16_t raw_setting) | ||
150 | { | ||
151 | uint32_t tmp; | ||
152 | tmp = raw_setting * 4096 / 100; | ||
153 | return (uint16_t)tmp; | ||
154 | } | ||
155 | |||
156 | static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t *sda) | ||
157 | { | ||
158 | switch (line) { | ||
159 | case SMU7_I2CLineID_DDC1: | ||
160 | *scl = SMU7_I2C_DDC1CLK; | ||
161 | *sda = SMU7_I2C_DDC1DATA; | ||
162 | break; | ||
163 | case SMU7_I2CLineID_DDC2: | ||
164 | *scl = SMU7_I2C_DDC2CLK; | ||
165 | *sda = SMU7_I2C_DDC2DATA; | ||
166 | break; | ||
167 | case SMU7_I2CLineID_DDC3: | ||
168 | *scl = SMU7_I2C_DDC3CLK; | ||
169 | *sda = SMU7_I2C_DDC3DATA; | ||
170 | break; | ||
171 | case SMU7_I2CLineID_DDC4: | ||
172 | *scl = SMU7_I2C_DDC4CLK; | ||
173 | *sda = SMU7_I2C_DDC4DATA; | ||
174 | break; | ||
175 | case SMU7_I2CLineID_DDC5: | ||
176 | *scl = SMU7_I2C_DDC5CLK; | ||
177 | *sda = SMU7_I2C_DDC5DATA; | ||
178 | break; | ||
179 | case SMU7_I2CLineID_DDC6: | ||
180 | *scl = SMU7_I2C_DDC6CLK; | ||
181 | *sda = SMU7_I2C_DDC6DATA; | ||
182 | break; | ||
183 | case SMU7_I2CLineID_SCLSDA: | ||
184 | *scl = SMU7_I2C_SCL; | ||
185 | *sda = SMU7_I2C_SDA; | ||
186 | break; | ||
187 | case SMU7_I2CLineID_DDCVGA: | ||
188 | *scl = SMU7_I2C_DDCVGACLK; | ||
189 | *sda = SMU7_I2C_DDCVGADATA; | ||
190 | break; | ||
191 | default: | ||
192 | *scl = 0; | ||
193 | *sda = 0; | ||
194 | break; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | static void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) | ||
199 | { | ||
200 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
201 | struct phm_ppt_v1_information *table_info = | ||
202 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
203 | |||
204 | if (table_info && | ||
205 | table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX && | ||
206 | table_info->cac_dtp_table->usPowerTuneDataSetID) | ||
207 | smu_data->power_tune_defaults = | ||
208 | &fiji_power_tune_data_set_array | ||
209 | [table_info->cac_dtp_table->usPowerTuneDataSetID - 1]; | ||
210 | else | ||
211 | smu_data->power_tune_defaults = &fiji_power_tune_data_set_array[0]; | ||
212 | |||
213 | } | ||
214 | |||
215 | static int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr) | ||
216 | { | ||
217 | |||
218 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
219 | const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults; | ||
220 | |||
221 | SMU73_Discrete_DpmTable *dpm_table = &(smu_data->smc_state_table); | ||
222 | |||
223 | struct phm_ppt_v1_information *table_info = | ||
224 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
225 | struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table; | ||
226 | struct pp_advance_fan_control_parameters *fan_table = | ||
227 | &hwmgr->thermal_controller.advanceFanControlParameters; | ||
228 | uint8_t uc_scl, uc_sda; | ||
229 | |||
230 | /* TDP number of fraction bits are changed from 8 to 7 for Fiji | ||
231 | * as requested by SMC team | ||
232 | */ | ||
233 | dpm_table->DefaultTdp = PP_HOST_TO_SMC_US( | ||
234 | (uint16_t)(cac_dtp_table->usTDP * 128)); | ||
235 | dpm_table->TargetTdp = PP_HOST_TO_SMC_US( | ||
236 | (uint16_t)(cac_dtp_table->usTDP * 128)); | ||
237 | |||
238 | PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255, | ||
239 | "Target Operating Temp is out of Range!", | ||
240 | ); | ||
241 | |||
242 | dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp); | ||
243 | dpm_table->GpuTjHyst = 8; | ||
244 | |||
245 | dpm_table->DTEAmbientTempBase = defaults->DTEAmbientTempBase; | ||
246 | |||
247 | /* The following are for new Fiji Multi-input fan/thermal control */ | ||
248 | dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US( | ||
249 | cac_dtp_table->usTargetOperatingTemp * 256); | ||
250 | dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US( | ||
251 | cac_dtp_table->usTemperatureLimitHotspot * 256); | ||
252 | dpm_table->TemperatureLimitLiquid1 = PP_HOST_TO_SMC_US( | ||
253 | cac_dtp_table->usTemperatureLimitLiquid1 * 256); | ||
254 | dpm_table->TemperatureLimitLiquid2 = PP_HOST_TO_SMC_US( | ||
255 | cac_dtp_table->usTemperatureLimitLiquid2 * 256); | ||
256 | dpm_table->TemperatureLimitVrVddc = PP_HOST_TO_SMC_US( | ||
257 | cac_dtp_table->usTemperatureLimitVrVddc * 256); | ||
258 | dpm_table->TemperatureLimitVrMvdd = PP_HOST_TO_SMC_US( | ||
259 | cac_dtp_table->usTemperatureLimitVrMvdd * 256); | ||
260 | dpm_table->TemperatureLimitPlx = PP_HOST_TO_SMC_US( | ||
261 | cac_dtp_table->usTemperatureLimitPlx * 256); | ||
262 | |||
263 | dpm_table->FanGainEdge = PP_HOST_TO_SMC_US( | ||
264 | scale_fan_gain_settings(fan_table->usFanGainEdge)); | ||
265 | dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US( | ||
266 | scale_fan_gain_settings(fan_table->usFanGainHotspot)); | ||
267 | dpm_table->FanGainLiquid = PP_HOST_TO_SMC_US( | ||
268 | scale_fan_gain_settings(fan_table->usFanGainLiquid)); | ||
269 | dpm_table->FanGainVrVddc = PP_HOST_TO_SMC_US( | ||
270 | scale_fan_gain_settings(fan_table->usFanGainVrVddc)); | ||
271 | dpm_table->FanGainVrMvdd = PP_HOST_TO_SMC_US( | ||
272 | scale_fan_gain_settings(fan_table->usFanGainVrMvdd)); | ||
273 | dpm_table->FanGainPlx = PP_HOST_TO_SMC_US( | ||
274 | scale_fan_gain_settings(fan_table->usFanGainPlx)); | ||
275 | dpm_table->FanGainHbm = PP_HOST_TO_SMC_US( | ||
276 | scale_fan_gain_settings(fan_table->usFanGainHbm)); | ||
277 | |||
278 | dpm_table->Liquid1_I2C_address = cac_dtp_table->ucLiquid1_I2C_address; | ||
279 | dpm_table->Liquid2_I2C_address = cac_dtp_table->ucLiquid2_I2C_address; | ||
280 | dpm_table->Vr_I2C_address = cac_dtp_table->ucVr_I2C_address; | ||
281 | dpm_table->Plx_I2C_address = cac_dtp_table->ucPlx_I2C_address; | ||
282 | |||
283 | get_scl_sda_value(cac_dtp_table->ucLiquid_I2C_Line, &uc_scl, &uc_sda); | ||
284 | dpm_table->Liquid_I2C_LineSCL = uc_scl; | ||
285 | dpm_table->Liquid_I2C_LineSDA = uc_sda; | ||
286 | |||
287 | get_scl_sda_value(cac_dtp_table->ucVr_I2C_Line, &uc_scl, &uc_sda); | ||
288 | dpm_table->Vr_I2C_LineSCL = uc_scl; | ||
289 | dpm_table->Vr_I2C_LineSDA = uc_sda; | ||
290 | |||
291 | get_scl_sda_value(cac_dtp_table->ucPlx_I2C_Line, &uc_scl, &uc_sda); | ||
292 | dpm_table->Plx_I2C_LineSCL = uc_scl; | ||
293 | dpm_table->Plx_I2C_LineSDA = uc_sda; | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | |||
299 | static int fiji_populate_svi_load_line(struct pp_hwmgr *hwmgr) | ||
300 | { | ||
301 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
302 | const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults; | ||
303 | |||
304 | smu_data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn; | ||
305 | smu_data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC; | ||
306 | smu_data->power_tune_table.SviLoadLineTrimVddC = 3; | ||
307 | smu_data->power_tune_table.SviLoadLineOffsetVddC = 0; | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | |||
313 | static int fiji_populate_tdc_limit(struct pp_hwmgr *hwmgr) | ||
314 | { | ||
315 | uint16_t tdc_limit; | ||
316 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
317 | struct phm_ppt_v1_information *table_info = | ||
318 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
319 | const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults; | ||
320 | |||
321 | /* TDC number of fraction bits are changed from 8 to 7 | ||
322 | * for Fiji as requested by SMC team | ||
323 | */ | ||
324 | tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128); | ||
325 | smu_data->power_tune_table.TDC_VDDC_PkgLimit = | ||
326 | CONVERT_FROM_HOST_TO_SMC_US(tdc_limit); | ||
327 | smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc = | ||
328 | defaults->TDC_VDDC_ThrottleReleaseLimitPerc; | ||
329 | smu_data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt; | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int fiji_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) | ||
335 | { | ||
336 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
337 | const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults; | ||
338 | uint32_t temp; | ||
339 | |||
340 | if (fiji_read_smc_sram_dword(hwmgr->smumgr, | ||
341 | fuse_table_offset + | ||
342 | offsetof(SMU73_Discrete_PmFuses, TdcWaterfallCtl), | ||
343 | (uint32_t *)&temp, SMC_RAM_END)) | ||
344 | PP_ASSERT_WITH_CODE(false, | ||
345 | "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", | ||
346 | return -EINVAL); | ||
347 | else { | ||
348 | smu_data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl; | ||
349 | smu_data->power_tune_table.LPMLTemperatureMin = | ||
350 | (uint8_t)((temp >> 16) & 0xff); | ||
351 | smu_data->power_tune_table.LPMLTemperatureMax = | ||
352 | (uint8_t)((temp >> 8) & 0xff); | ||
353 | smu_data->power_tune_table.Reserved = (uint8_t)(temp & 0xff); | ||
354 | } | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static int fiji_populate_temperature_scaler(struct pp_hwmgr *hwmgr) | ||
359 | { | ||
360 | int i; | ||
361 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
362 | |||
363 | /* Currently not used. Set all to zero. */ | ||
364 | for (i = 0; i < 16; i++) | ||
365 | smu_data->power_tune_table.LPMLTemperatureScaler[i] = 0; | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int fiji_populate_fuzzy_fan(struct pp_hwmgr *hwmgr) | ||
371 | { | ||
372 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
373 | |||
374 | if ((hwmgr->thermal_controller.advanceFanControlParameters. | ||
375 | usFanOutputSensitivity & (1 << 15)) || | ||
376 | 0 == hwmgr->thermal_controller.advanceFanControlParameters. | ||
377 | usFanOutputSensitivity) | ||
378 | hwmgr->thermal_controller.advanceFanControlParameters. | ||
379 | usFanOutputSensitivity = hwmgr->thermal_controller. | ||
380 | advanceFanControlParameters.usDefaultFanOutputSensitivity; | ||
381 | |||
382 | smu_data->power_tune_table.FuzzyFan_PwmSetDelta = | ||
383 | PP_HOST_TO_SMC_US(hwmgr->thermal_controller. | ||
384 | advanceFanControlParameters.usFanOutputSensitivity); | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int fiji_populate_gnb_lpml(struct pp_hwmgr *hwmgr) | ||
389 | { | ||
390 | int i; | ||
391 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
392 | |||
393 | /* Currently not used. Set all to zero. */ | ||
394 | for (i = 0; i < 16; i++) | ||
395 | smu_data->power_tune_table.GnbLPML[i] = 0; | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int fiji_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr) | ||
401 | { | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr) | ||
406 | { | ||
407 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
408 | struct phm_ppt_v1_information *table_info = | ||
409 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
410 | uint16_t HiSidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd; | ||
411 | uint16_t LoSidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd; | ||
412 | struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table; | ||
413 | |||
414 | HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256); | ||
415 | LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256); | ||
416 | |||
417 | smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd = | ||
418 | CONVERT_FROM_HOST_TO_SMC_US(HiSidd); | ||
419 | smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd = | ||
420 | CONVERT_FROM_HOST_TO_SMC_US(LoSidd); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr) | ||
426 | { | ||
427 | uint32_t pm_fuse_table_offset; | ||
428 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
429 | |||
430 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
431 | PHM_PlatformCaps_PowerContainment)) { | ||
432 | if (fiji_read_smc_sram_dword(hwmgr->smumgr, | ||
433 | SMU7_FIRMWARE_HEADER_LOCATION + | ||
434 | offsetof(SMU73_Firmware_Header, PmFuseTable), | ||
435 | &pm_fuse_table_offset, SMC_RAM_END)) | ||
436 | PP_ASSERT_WITH_CODE(false, | ||
437 | "Attempt to get pm_fuse_table_offset Failed!", | ||
438 | return -EINVAL); | ||
439 | |||
440 | /* DW6 */ | ||
441 | if (fiji_populate_svi_load_line(hwmgr)) | ||
442 | PP_ASSERT_WITH_CODE(false, | ||
443 | "Attempt to populate SviLoadLine Failed!", | ||
444 | return -EINVAL); | ||
445 | /* DW7 */ | ||
446 | if (fiji_populate_tdc_limit(hwmgr)) | ||
447 | PP_ASSERT_WITH_CODE(false, | ||
448 | "Attempt to populate TDCLimit Failed!", return -EINVAL); | ||
449 | /* DW8 */ | ||
450 | if (fiji_populate_dw8(hwmgr, pm_fuse_table_offset)) | ||
451 | PP_ASSERT_WITH_CODE(false, | ||
452 | "Attempt to populate TdcWaterfallCtl, " | ||
453 | "LPMLTemperature Min and Max Failed!", | ||
454 | return -EINVAL); | ||
455 | |||
456 | /* DW9-DW12 */ | ||
457 | if (0 != fiji_populate_temperature_scaler(hwmgr)) | ||
458 | PP_ASSERT_WITH_CODE(false, | ||
459 | "Attempt to populate LPMLTemperatureScaler Failed!", | ||
460 | return -EINVAL); | ||
461 | |||
462 | /* DW13-DW14 */ | ||
463 | if (fiji_populate_fuzzy_fan(hwmgr)) | ||
464 | PP_ASSERT_WITH_CODE(false, | ||
465 | "Attempt to populate Fuzzy Fan Control parameters Failed!", | ||
466 | return -EINVAL); | ||
467 | |||
468 | /* DW15-DW18 */ | ||
469 | if (fiji_populate_gnb_lpml(hwmgr)) | ||
470 | PP_ASSERT_WITH_CODE(false, | ||
471 | "Attempt to populate GnbLPML Failed!", | ||
472 | return -EINVAL); | ||
473 | |||
474 | /* DW19 */ | ||
475 | if (fiji_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr)) | ||
476 | PP_ASSERT_WITH_CODE(false, | ||
477 | "Attempt to populate GnbLPML Min and Max Vid Failed!", | ||
478 | return -EINVAL); | ||
479 | |||
480 | /* DW20 */ | ||
481 | if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr)) | ||
482 | PP_ASSERT_WITH_CODE(false, | ||
483 | "Attempt to populate BapmVddCBaseLeakage Hi and Lo " | ||
484 | "Sidd Failed!", return -EINVAL); | ||
485 | |||
486 | if (fiji_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset, | ||
487 | (uint8_t *)&smu_data->power_tune_table, | ||
488 | sizeof(struct SMU73_Discrete_PmFuses), SMC_RAM_END)) | ||
489 | PP_ASSERT_WITH_CODE(false, | ||
490 | "Attempt to download PmFuseTable Failed!", | ||
491 | return -EINVAL); | ||
492 | } | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * Preparation of vddc and vddgfx CAC tables for SMC. | ||
498 | * | ||
499 | * @param hwmgr the address of the hardware manager | ||
500 | * @param table the SMC DPM table structure to be populated | ||
501 | * @return always 0 | ||
502 | */ | ||
503 | static int fiji_populate_cac_table(struct pp_hwmgr *hwmgr, | ||
504 | struct SMU73_Discrete_DpmTable *table) | ||
505 | { | ||
506 | uint32_t count; | ||
507 | uint8_t index; | ||
508 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
509 | struct phm_ppt_v1_information *table_info = | ||
510 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
511 | struct phm_ppt_v1_voltage_lookup_table *lookup_table = | ||
512 | table_info->vddc_lookup_table; | ||
513 | /* tables is already swapped, so in order to use the value from it, | ||
514 | * we need to swap it back. | ||
515 | * We are populating vddc CAC data to BapmVddc table | ||
516 | * in split and merged mode | ||
517 | */ | ||
518 | |||
519 | for (count = 0; count < lookup_table->count; count++) { | ||
520 | index = phm_get_voltage_index(lookup_table, | ||
521 | data->vddc_voltage_table.entries[count].value); | ||
522 | table->BapmVddcVidLoSidd[count] = | ||
523 | convert_to_vid(lookup_table->entries[index].us_cac_low); | ||
524 | table->BapmVddcVidHiSidd[count] = | ||
525 | convert_to_vid(lookup_table->entries[index].us_cac_high); | ||
526 | } | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | /** | ||
532 | * Preparation of voltage tables for SMC. | ||
533 | * | ||
534 | * @param hwmgr the address of the hardware manager | ||
535 | * @param table the SMC DPM table structure to be populated | ||
536 | * @return always 0 | ||
537 | */ | ||
538 | |||
539 | static int fiji_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr, | ||
540 | struct SMU73_Discrete_DpmTable *table) | ||
541 | { | ||
542 | int result; | ||
543 | |||
544 | result = fiji_populate_cac_table(hwmgr, table); | ||
545 | PP_ASSERT_WITH_CODE(0 == result, | ||
546 | "can not populate CAC voltage tables to SMC", | ||
547 | return -EINVAL); | ||
548 | |||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | static int fiji_populate_ulv_level(struct pp_hwmgr *hwmgr, | ||
553 | struct SMU73_Discrete_Ulv *state) | ||
554 | { | ||
555 | int result = 0; | ||
556 | |||
557 | struct phm_ppt_v1_information *table_info = | ||
558 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
559 | |||
560 | state->CcPwrDynRm = 0; | ||
561 | state->CcPwrDynRm1 = 0; | ||
562 | |||
563 | state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset; | ||
564 | state->VddcOffsetVid = (uint8_t)(table_info->us_ulv_voltage_offset * | ||
565 | VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1); | ||
566 | |||
567 | state->VddcPhase = 1; | ||
568 | |||
569 | if (!result) { | ||
570 | CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm); | ||
571 | CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1); | ||
572 | CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset); | ||
573 | } | ||
574 | return result; | ||
575 | } | ||
576 | |||
577 | static int fiji_populate_ulv_state(struct pp_hwmgr *hwmgr, | ||
578 | struct SMU73_Discrete_DpmTable *table) | ||
579 | { | ||
580 | return fiji_populate_ulv_level(hwmgr, &table->Ulv); | ||
581 | } | ||
582 | |||
583 | static int fiji_populate_smc_link_level(struct pp_hwmgr *hwmgr, | ||
584 | struct SMU73_Discrete_DpmTable *table) | ||
585 | { | ||
586 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
587 | struct smu7_dpm_table *dpm_table = &data->dpm_table; | ||
588 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
589 | int i; | ||
590 | |||
591 | /* Index (dpm_table->pcie_speed_table.count) | ||
592 | * is reserved for PCIE boot level. */ | ||
593 | for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) { | ||
594 | table->LinkLevel[i].PcieGenSpeed = | ||
595 | (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value; | ||
596 | table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width( | ||
597 | dpm_table->pcie_speed_table.dpm_levels[i].param1); | ||
598 | table->LinkLevel[i].EnabledForActivity = 1; | ||
599 | table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff); | ||
600 | table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5); | ||
601 | table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30); | ||
602 | } | ||
603 | |||
604 | smu_data->smc_state_table.LinkLevelCount = | ||
605 | (uint8_t)dpm_table->pcie_speed_table.count; | ||
606 | data->dpm_level_enable_mask.pcie_dpm_enable_mask = | ||
607 | phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table); | ||
608 | |||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | |||
613 | /** | ||
614 | * Calculates the SCLK dividers using the provided engine clock | ||
615 | * | ||
616 | * @param hwmgr the address of the hardware manager | ||
617 | * @param clock the engine clock to use to populate the structure | ||
618 | * @param sclk the SMC SCLK structure to be populated | ||
619 | */ | ||
620 | static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr, | ||
621 | uint32_t clock, struct SMU73_Discrete_GraphicsLevel *sclk) | ||
622 | { | ||
623 | const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
624 | struct pp_atomctrl_clock_dividers_vi dividers; | ||
625 | uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL; | ||
626 | uint32_t spll_func_cntl_3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3; | ||
627 | uint32_t spll_func_cntl_4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4; | ||
628 | uint32_t cg_spll_spread_spectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM; | ||
629 | uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2; | ||
630 | uint32_t ref_clock; | ||
631 | uint32_t ref_divider; | ||
632 | uint32_t fbdiv; | ||
633 | int result; | ||
634 | |||
635 | /* get the engine clock dividers for this clock value */ | ||
636 | result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock, ÷rs); | ||
637 | |||
638 | PP_ASSERT_WITH_CODE(result == 0, | ||
639 | "Error retrieving Engine Clock dividers from VBIOS.", | ||
640 | return result); | ||
641 | |||
642 | /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */ | ||
643 | ref_clock = atomctrl_get_reference_clock(hwmgr); | ||
644 | ref_divider = 1 + dividers.uc_pll_ref_div; | ||
645 | |||
646 | /* low 14 bits is fraction and high 12 bits is divider */ | ||
647 | fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF; | ||
648 | |||
649 | /* SPLL_FUNC_CNTL setup */ | ||
650 | spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL, | ||
651 | SPLL_REF_DIV, dividers.uc_pll_ref_div); | ||
652 | spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL, | ||
653 | SPLL_PDIV_A, dividers.uc_pll_post_div); | ||
654 | |||
655 | /* SPLL_FUNC_CNTL_3 setup*/ | ||
656 | spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3, | ||
657 | SPLL_FB_DIV, fbdiv); | ||
658 | |||
659 | /* set to use fractional accumulation*/ | ||
660 | spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3, | ||
661 | SPLL_DITHEN, 1); | ||
662 | |||
663 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
664 | PHM_PlatformCaps_EngineSpreadSpectrumSupport)) { | ||
665 | struct pp_atomctrl_internal_ss_info ssInfo; | ||
666 | |||
667 | uint32_t vco_freq = clock * dividers.uc_pll_post_div; | ||
668 | if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr, | ||
669 | vco_freq, &ssInfo)) { | ||
670 | /* | ||
671 | * ss_info.speed_spectrum_percentage -- in unit of 0.01% | ||
672 | * ss_info.speed_spectrum_rate -- in unit of khz | ||
673 | * | ||
674 | * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 | ||
675 | */ | ||
676 | uint32_t clk_s = ref_clock * 5 / | ||
677 | (ref_divider * ssInfo.speed_spectrum_rate); | ||
678 | /* clkv = 2 * D * fbdiv / NS */ | ||
679 | uint32_t clk_v = 4 * ssInfo.speed_spectrum_percentage * | ||
680 | fbdiv / (clk_s * 10000); | ||
681 | |||
682 | cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum, | ||
683 | CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s); | ||
684 | cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum, | ||
685 | CG_SPLL_SPREAD_SPECTRUM, SSEN, 1); | ||
686 | cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2, | ||
687 | CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v); | ||
688 | } | ||
689 | } | ||
690 | |||
691 | sclk->SclkFrequency = clock; | ||
692 | sclk->CgSpllFuncCntl3 = spll_func_cntl_3; | ||
693 | sclk->CgSpllFuncCntl4 = spll_func_cntl_4; | ||
694 | sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum; | ||
695 | sclk->SpllSpreadSpectrum2 = cg_spll_spread_spectrum_2; | ||
696 | sclk->SclkDid = (uint8_t)dividers.pll_post_divider; | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | /** | ||
702 | * Populates single SMC SCLK structure using the provided engine clock | ||
703 | * | ||
704 | * @param hwmgr the address of the hardware manager | ||
705 | * @param clock the engine clock to use to populate the structure | ||
706 | * @param sclk the SMC SCLK structure to be populated | ||
707 | */ | ||
708 | |||
709 | static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, | ||
710 | uint32_t clock, uint16_t sclk_al_threshold, | ||
711 | struct SMU73_Discrete_GraphicsLevel *level) | ||
712 | { | ||
713 | int result; | ||
714 | /* PP_Clocks minClocks; */ | ||
715 | uint32_t threshold, mvdd; | ||
716 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
717 | struct phm_ppt_v1_information *table_info = | ||
718 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
719 | |||
720 | result = fiji_calculate_sclk_params(hwmgr, clock, level); | ||
721 | |||
722 | /* populate graphics levels */ | ||
723 | result = fiji_get_dependency_volt_by_clk(hwmgr, | ||
724 | table_info->vdd_dep_on_sclk, clock, | ||
725 | (uint32_t *)(&level->MinVoltage), &mvdd); | ||
726 | PP_ASSERT_WITH_CODE((0 == result), | ||
727 | "can not find VDDC voltage value for " | ||
728 | "VDDC engine clock dependency table", | ||
729 | return result); | ||
730 | |||
731 | level->SclkFrequency = clock; | ||
732 | level->ActivityLevel = sclk_al_threshold; | ||
733 | level->CcPwrDynRm = 0; | ||
734 | level->CcPwrDynRm1 = 0; | ||
735 | level->EnabledForActivity = 0; | ||
736 | level->EnabledForThrottle = 1; | ||
737 | level->UpHyst = 10; | ||
738 | level->DownHyst = 0; | ||
739 | level->VoltageDownHyst = 0; | ||
740 | level->PowerThrottle = 0; | ||
741 | |||
742 | threshold = clock * data->fast_watermark_threshold / 100; | ||
743 | |||
744 | data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr; | ||
745 | |||
746 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) | ||
747 | level->DeepSleepDivId = smu7_get_sleep_divider_id_from_clock(clock, | ||
748 | hwmgr->display_config.min_core_set_clock_in_sr); | ||
749 | |||
750 | |||
751 | /* Default to slow, highest DPM level will be | ||
752 | * set to PPSMC_DISPLAY_WATERMARK_LOW later. | ||
753 | */ | ||
754 | level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; | ||
755 | |||
756 | CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage); | ||
757 | CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency); | ||
758 | CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel); | ||
759 | CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3); | ||
760 | CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4); | ||
761 | CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum); | ||
762 | CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2); | ||
763 | CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm); | ||
764 | CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1); | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | /** | ||
769 | * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states | ||
770 | * | ||
771 | * @param hwmgr the address of the hardware manager | ||
772 | */ | ||
773 | int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) | ||
774 | { | ||
775 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
776 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
777 | |||
778 | struct smu7_dpm_table *dpm_table = &data->dpm_table; | ||
779 | struct phm_ppt_v1_information *table_info = | ||
780 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
781 | struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table; | ||
782 | uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count; | ||
783 | int result = 0; | ||
784 | uint32_t array = smu_data->dpm_table_start + | ||
785 | offsetof(SMU73_Discrete_DpmTable, GraphicsLevel); | ||
786 | uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) * | ||
787 | SMU73_MAX_LEVELS_GRAPHICS; | ||
788 | struct SMU73_Discrete_GraphicsLevel *levels = | ||
789 | smu_data->smc_state_table.GraphicsLevel; | ||
790 | uint32_t i, max_entry; | ||
791 | uint8_t hightest_pcie_level_enabled = 0, | ||
792 | lowest_pcie_level_enabled = 0, | ||
793 | mid_pcie_level_enabled = 0, | ||
794 | count = 0; | ||
795 | |||
796 | for (i = 0; i < dpm_table->sclk_table.count; i++) { | ||
797 | result = fiji_populate_single_graphic_level(hwmgr, | ||
798 | dpm_table->sclk_table.dpm_levels[i].value, | ||
799 | (uint16_t)smu_data->activity_target[i], | ||
800 | &levels[i]); | ||
801 | if (result) | ||
802 | return result; | ||
803 | |||
804 | /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */ | ||
805 | if (i > 1) | ||
806 | levels[i].DeepSleepDivId = 0; | ||
807 | } | ||
808 | |||
809 | /* Only enable level 0 for now.*/ | ||
810 | levels[0].EnabledForActivity = 1; | ||
811 | |||
812 | /* set highest level watermark to high */ | ||
813 | levels[dpm_table->sclk_table.count - 1].DisplayWatermark = | ||
814 | PPSMC_DISPLAY_WATERMARK_HIGH; | ||
815 | |||
816 | smu_data->smc_state_table.GraphicsDpmLevelCount = | ||
817 | (uint8_t)dpm_table->sclk_table.count; | ||
818 | data->dpm_level_enable_mask.sclk_dpm_enable_mask = | ||
819 | phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table); | ||
820 | |||
821 | if (pcie_table != NULL) { | ||
822 | PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt), | ||
823 | "There must be 1 or more PCIE levels defined in PPTable.", | ||
824 | return -EINVAL); | ||
825 | max_entry = pcie_entry_cnt - 1; | ||
826 | for (i = 0; i < dpm_table->sclk_table.count; i++) | ||
827 | levels[i].pcieDpmLevel = | ||
828 | (uint8_t) ((i < max_entry) ? i : max_entry); | ||
829 | } else { | ||
830 | while (data->dpm_level_enable_mask.pcie_dpm_enable_mask && | ||
831 | ((data->dpm_level_enable_mask.pcie_dpm_enable_mask & | ||
832 | (1 << (hightest_pcie_level_enabled + 1))) != 0)) | ||
833 | hightest_pcie_level_enabled++; | ||
834 | |||
835 | while (data->dpm_level_enable_mask.pcie_dpm_enable_mask && | ||
836 | ((data->dpm_level_enable_mask.pcie_dpm_enable_mask & | ||
837 | (1 << lowest_pcie_level_enabled)) == 0)) | ||
838 | lowest_pcie_level_enabled++; | ||
839 | |||
840 | while ((count < hightest_pcie_level_enabled) && | ||
841 | ((data->dpm_level_enable_mask.pcie_dpm_enable_mask & | ||
842 | (1 << (lowest_pcie_level_enabled + 1 + count))) == 0)) | ||
843 | count++; | ||
844 | |||
845 | mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1 + count) < | ||
846 | hightest_pcie_level_enabled ? | ||
847 | (lowest_pcie_level_enabled + 1 + count) : | ||
848 | hightest_pcie_level_enabled; | ||
849 | |||
850 | /* set pcieDpmLevel to hightest_pcie_level_enabled */ | ||
851 | for (i = 2; i < dpm_table->sclk_table.count; i++) | ||
852 | levels[i].pcieDpmLevel = hightest_pcie_level_enabled; | ||
853 | |||
854 | /* set pcieDpmLevel to lowest_pcie_level_enabled */ | ||
855 | levels[0].pcieDpmLevel = lowest_pcie_level_enabled; | ||
856 | |||
857 | /* set pcieDpmLevel to mid_pcie_level_enabled */ | ||
858 | levels[1].pcieDpmLevel = mid_pcie_level_enabled; | ||
859 | } | ||
860 | /* level count will send to smc once at init smc table and never change */ | ||
861 | result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels, | ||
862 | (uint32_t)array_size, SMC_RAM_END); | ||
863 | |||
864 | return result; | ||
865 | } | ||
866 | |||
867 | |||
868 | /** | ||
869 | * MCLK Frequency Ratio | ||
870 | * SEQ_CG_RESP Bit[31:24] - 0x0 | ||
871 | * Bit[27:24] \96 DDR3 Frequency ratio | ||
872 | * 0x0 <= 100MHz, 450 < 0x8 <= 500MHz | ||
873 | * 100 < 0x1 <= 150MHz, 500 < 0x9 <= 550MHz | ||
874 | * 150 < 0x2 <= 200MHz, 550 < 0xA <= 600MHz | ||
875 | * 200 < 0x3 <= 250MHz, 600 < 0xB <= 650MHz | ||
876 | * 250 < 0x4 <= 300MHz, 650 < 0xC <= 700MHz | ||
877 | * 300 < 0x5 <= 350MHz, 700 < 0xD <= 750MHz | ||
878 | * 350 < 0x6 <= 400MHz, 750 < 0xE <= 800MHz | ||
879 | * 400 < 0x7 <= 450MHz, 800 < 0xF | ||
880 | */ | ||
881 | static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock) | ||
882 | { | ||
883 | if (mem_clock <= 10000) | ||
884 | return 0x0; | ||
885 | if (mem_clock <= 15000) | ||
886 | return 0x1; | ||
887 | if (mem_clock <= 20000) | ||
888 | return 0x2; | ||
889 | if (mem_clock <= 25000) | ||
890 | return 0x3; | ||
891 | if (mem_clock <= 30000) | ||
892 | return 0x4; | ||
893 | if (mem_clock <= 35000) | ||
894 | return 0x5; | ||
895 | if (mem_clock <= 40000) | ||
896 | return 0x6; | ||
897 | if (mem_clock <= 45000) | ||
898 | return 0x7; | ||
899 | if (mem_clock <= 50000) | ||
900 | return 0x8; | ||
901 | if (mem_clock <= 55000) | ||
902 | return 0x9; | ||
903 | if (mem_clock <= 60000) | ||
904 | return 0xa; | ||
905 | if (mem_clock <= 65000) | ||
906 | return 0xb; | ||
907 | if (mem_clock <= 70000) | ||
908 | return 0xc; | ||
909 | if (mem_clock <= 75000) | ||
910 | return 0xd; | ||
911 | if (mem_clock <= 80000) | ||
912 | return 0xe; | ||
913 | /* mem_clock > 800MHz */ | ||
914 | return 0xf; | ||
915 | } | ||
916 | |||
917 | /** | ||
918 | * Populates the SMC MCLK structure using the provided memory clock | ||
919 | * | ||
920 | * @param hwmgr the address of the hardware manager | ||
921 | * @param clock the memory clock to use to populate the structure | ||
922 | * @param sclk the SMC SCLK structure to be populated | ||
923 | */ | ||
924 | static int fiji_calculate_mclk_params(struct pp_hwmgr *hwmgr, | ||
925 | uint32_t clock, struct SMU73_Discrete_MemoryLevel *mclk) | ||
926 | { | ||
927 | struct pp_atomctrl_memory_clock_param mem_param; | ||
928 | int result; | ||
929 | |||
930 | result = atomctrl_get_memory_pll_dividers_vi(hwmgr, clock, &mem_param); | ||
931 | PP_ASSERT_WITH_CODE((0 == result), | ||
932 | "Failed to get Memory PLL Dividers.", | ||
933 | ); | ||
934 | |||
935 | /* Save the result data to outpupt memory level structure */ | ||
936 | mclk->MclkFrequency = clock; | ||
937 | mclk->MclkDivider = (uint8_t)mem_param.mpll_post_divider; | ||
938 | mclk->FreqRange = fiji_get_mclk_frequency_ratio(clock); | ||
939 | |||
940 | return result; | ||
941 | } | ||
942 | |||
943 | static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr, | ||
944 | uint32_t clock, struct SMU73_Discrete_MemoryLevel *mem_level) | ||
945 | { | ||
946 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
947 | struct phm_ppt_v1_information *table_info = | ||
948 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
949 | int result = 0; | ||
950 | uint32_t mclk_stutter_mode_threshold = 60000; | ||
951 | |||
952 | if (table_info->vdd_dep_on_mclk) { | ||
953 | result = fiji_get_dependency_volt_by_clk(hwmgr, | ||
954 | table_info->vdd_dep_on_mclk, clock, | ||
955 | (uint32_t *)(&mem_level->MinVoltage), &mem_level->MinMvdd); | ||
956 | PP_ASSERT_WITH_CODE((0 == result), | ||
957 | "can not find MinVddc voltage value from memory " | ||
958 | "VDDC voltage dependency table", return result); | ||
959 | } | ||
960 | |||
961 | mem_level->EnabledForThrottle = 1; | ||
962 | mem_level->EnabledForActivity = 0; | ||
963 | mem_level->UpHyst = 0; | ||
964 | mem_level->DownHyst = 100; | ||
965 | mem_level->VoltageDownHyst = 0; | ||
966 | mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target; | ||
967 | mem_level->StutterEnable = false; | ||
968 | |||
969 | mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; | ||
970 | |||
971 | /* enable stutter mode if all the follow condition applied | ||
972 | * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI, | ||
973 | * &(data->DisplayTiming.numExistingDisplays)); | ||
974 | */ | ||
975 | data->display_timing.num_existing_displays = 1; | ||
976 | |||
977 | if (mclk_stutter_mode_threshold && | ||
978 | (clock <= mclk_stutter_mode_threshold) && | ||
979 | (!data->is_uvd_enabled) && | ||
980 | (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, | ||
981 | STUTTER_ENABLE) & 0x1)) | ||
982 | mem_level->StutterEnable = true; | ||
983 | |||
984 | result = fiji_calculate_mclk_params(hwmgr, clock, mem_level); | ||
985 | if (!result) { | ||
986 | CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd); | ||
987 | CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency); | ||
988 | CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel); | ||
989 | CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage); | ||
990 | } | ||
991 | return result; | ||
992 | } | ||
993 | |||
994 | /** | ||
995 | * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states | ||
996 | * | ||
997 | * @param hwmgr the address of the hardware manager | ||
998 | */ | ||
999 | int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr) | ||
1000 | { | ||
1001 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
1002 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
1003 | struct smu7_dpm_table *dpm_table = &data->dpm_table; | ||
1004 | int result; | ||
1005 | /* populate MCLK dpm table to SMU7 */ | ||
1006 | uint32_t array = smu_data->dpm_table_start + | ||
1007 | offsetof(SMU73_Discrete_DpmTable, MemoryLevel); | ||
1008 | uint32_t array_size = sizeof(SMU73_Discrete_MemoryLevel) * | ||
1009 | SMU73_MAX_LEVELS_MEMORY; | ||
1010 | struct SMU73_Discrete_MemoryLevel *levels = | ||
1011 | smu_data->smc_state_table.MemoryLevel; | ||
1012 | uint32_t i; | ||
1013 | |||
1014 | for (i = 0; i < dpm_table->mclk_table.count; i++) { | ||
1015 | PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value), | ||
1016 | "can not populate memory level as memory clock is zero", | ||
1017 | return -EINVAL); | ||
1018 | result = fiji_populate_single_memory_level(hwmgr, | ||
1019 | dpm_table->mclk_table.dpm_levels[i].value, | ||
1020 | &levels[i]); | ||
1021 | if (result) | ||
1022 | return result; | ||
1023 | } | ||
1024 | |||
1025 | /* Only enable level 0 for now. */ | ||
1026 | levels[0].EnabledForActivity = 1; | ||
1027 | |||
1028 | /* in order to prevent MC activity from stutter mode to push DPM up. | ||
1029 | * the UVD change complements this by putting the MCLK in | ||
1030 | * a higher state by default such that we are not effected by | ||
1031 | * up threshold or and MCLK DPM latency. | ||
1032 | */ | ||
1033 | levels[0].ActivityLevel = (uint16_t)data->mclk_dpm0_activity_target; | ||
1034 | CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel); | ||
1035 | |||
1036 | smu_data->smc_state_table.MemoryDpmLevelCount = | ||
1037 | (uint8_t)dpm_table->mclk_table.count; | ||
1038 | data->dpm_level_enable_mask.mclk_dpm_enable_mask = | ||
1039 | phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table); | ||
1040 | /* set highest level watermark to high */ | ||
1041 | levels[dpm_table->mclk_table.count - 1].DisplayWatermark = | ||
1042 | PPSMC_DISPLAY_WATERMARK_HIGH; | ||
1043 | |||
1044 | /* level count will send to smc once at init smc table and never change */ | ||
1045 | result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels, | ||
1046 | (uint32_t)array_size, SMC_RAM_END); | ||
1047 | |||
1048 | return result; | ||
1049 | } | ||
1050 | |||
1051 | |||
1052 | /** | ||
1053 | * Populates the SMC MVDD structure using the provided memory clock. | ||
1054 | * | ||
1055 | * @param hwmgr the address of the hardware manager | ||
1056 | * @param mclk the MCLK value to be used in the decision if MVDD should be high or low. | ||
1057 | * @param voltage the SMC VOLTAGE structure to be populated | ||
1058 | */ | ||
1059 | static int fiji_populate_mvdd_value(struct pp_hwmgr *hwmgr, | ||
1060 | uint32_t mclk, SMIO_Pattern *smio_pat) | ||
1061 | { | ||
1062 | const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
1063 | struct phm_ppt_v1_information *table_info = | ||
1064 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1065 | uint32_t i = 0; | ||
1066 | |||
1067 | if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) { | ||
1068 | /* find mvdd value which clock is more than request */ | ||
1069 | for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) { | ||
1070 | if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) { | ||
1071 | smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value; | ||
1072 | break; | ||
1073 | } | ||
1074 | } | ||
1075 | PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count, | ||
1076 | "MVDD Voltage is outside the supported range.", | ||
1077 | return -EINVAL); | ||
1078 | } else | ||
1079 | return -EINVAL; | ||
1080 | |||
1081 | return 0; | ||
1082 | } | ||
1083 | |||
1084 | static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, | ||
1085 | SMU73_Discrete_DpmTable *table) | ||
1086 | { | ||
1087 | int result = 0; | ||
1088 | const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
1089 | struct phm_ppt_v1_information *table_info = | ||
1090 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1091 | struct pp_atomctrl_clock_dividers_vi dividers; | ||
1092 | SMIO_Pattern vol_level; | ||
1093 | uint32_t mvdd; | ||
1094 | uint16_t us_mvdd; | ||
1095 | uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL; | ||
1096 | uint32_t spll_func_cntl_2 = data->clock_registers.vCG_SPLL_FUNC_CNTL_2; | ||
1097 | |||
1098 | table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC; | ||
1099 | |||
1100 | if (!data->sclk_dpm_key_disabled) { | ||
1101 | /* Get MinVoltage and Frequency from DPM0, | ||
1102 | * already converted to SMC_UL */ | ||
1103 | table->ACPILevel.SclkFrequency = | ||
1104 | data->dpm_table.sclk_table.dpm_levels[0].value; | ||
1105 | result = fiji_get_dependency_volt_by_clk(hwmgr, | ||
1106 | table_info->vdd_dep_on_sclk, | ||
1107 | table->ACPILevel.SclkFrequency, | ||
1108 | (uint32_t *)(&table->ACPILevel.MinVoltage), &mvdd); | ||
1109 | PP_ASSERT_WITH_CODE((0 == result), | ||
1110 | "Cannot find ACPI VDDC voltage value " \ | ||
1111 | "in Clock Dependency Table", | ||
1112 | ); | ||
1113 | } else { | ||
1114 | table->ACPILevel.SclkFrequency = | ||
1115 | data->vbios_boot_state.sclk_bootup_value; | ||
1116 | table->ACPILevel.MinVoltage = | ||
1117 | data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE; | ||
1118 | } | ||
1119 | |||
1120 | /* get the engine clock dividers for this clock value */ | ||
1121 | result = atomctrl_get_engine_pll_dividers_vi(hwmgr, | ||
1122 | table->ACPILevel.SclkFrequency, ÷rs); | ||
1123 | PP_ASSERT_WITH_CODE(result == 0, | ||
1124 | "Error retrieving Engine Clock dividers from VBIOS.", | ||
1125 | return result); | ||
1126 | |||
1127 | table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider; | ||
1128 | table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; | ||
1129 | table->ACPILevel.DeepSleepDivId = 0; | ||
1130 | |||
1131 | spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL, | ||
1132 | SPLL_PWRON, 0); | ||
1133 | spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL, | ||
1134 | SPLL_RESET, 1); | ||
1135 | spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2, | ||
1136 | SCLK_MUX_SEL, 4); | ||
1137 | |||
1138 | table->ACPILevel.CgSpllFuncCntl = spll_func_cntl; | ||
1139 | table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2; | ||
1140 | table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3; | ||
1141 | table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4; | ||
1142 | table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM; | ||
1143 | table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2; | ||
1144 | table->ACPILevel.CcPwrDynRm = 0; | ||
1145 | table->ACPILevel.CcPwrDynRm1 = 0; | ||
1146 | |||
1147 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags); | ||
1148 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency); | ||
1149 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage); | ||
1150 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl); | ||
1151 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2); | ||
1152 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3); | ||
1153 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4); | ||
1154 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum); | ||
1155 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2); | ||
1156 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm); | ||
1157 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1); | ||
1158 | |||
1159 | if (!data->mclk_dpm_key_disabled) { | ||
1160 | /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */ | ||
1161 | table->MemoryACPILevel.MclkFrequency = | ||
1162 | data->dpm_table.mclk_table.dpm_levels[0].value; | ||
1163 | result = fiji_get_dependency_volt_by_clk(hwmgr, | ||
1164 | table_info->vdd_dep_on_mclk, | ||
1165 | table->MemoryACPILevel.MclkFrequency, | ||
1166 | (uint32_t *)(&table->MemoryACPILevel.MinVoltage), &mvdd); | ||
1167 | PP_ASSERT_WITH_CODE((0 == result), | ||
1168 | "Cannot find ACPI VDDCI voltage value in Clock Dependency Table", | ||
1169 | ); | ||
1170 | } else { | ||
1171 | table->MemoryACPILevel.MclkFrequency = | ||
1172 | data->vbios_boot_state.mclk_bootup_value; | ||
1173 | table->MemoryACPILevel.MinVoltage = | ||
1174 | data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE; | ||
1175 | } | ||
1176 | |||
1177 | us_mvdd = 0; | ||
1178 | if ((SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) || | ||
1179 | (data->mclk_dpm_key_disabled)) | ||
1180 | us_mvdd = data->vbios_boot_state.mvdd_bootup_value; | ||
1181 | else { | ||
1182 | if (!fiji_populate_mvdd_value(hwmgr, | ||
1183 | data->dpm_table.mclk_table.dpm_levels[0].value, | ||
1184 | &vol_level)) | ||
1185 | us_mvdd = vol_level.Voltage; | ||
1186 | } | ||
1187 | |||
1188 | table->MemoryACPILevel.MinMvdd = | ||
1189 | PP_HOST_TO_SMC_UL(us_mvdd * VOLTAGE_SCALE); | ||
1190 | |||
1191 | table->MemoryACPILevel.EnabledForThrottle = 0; | ||
1192 | table->MemoryACPILevel.EnabledForActivity = 0; | ||
1193 | table->MemoryACPILevel.UpHyst = 0; | ||
1194 | table->MemoryACPILevel.DownHyst = 100; | ||
1195 | table->MemoryACPILevel.VoltageDownHyst = 0; | ||
1196 | table->MemoryACPILevel.ActivityLevel = | ||
1197 | PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); | ||
1198 | |||
1199 | table->MemoryACPILevel.StutterEnable = false; | ||
1200 | CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency); | ||
1201 | CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage); | ||
1202 | |||
1203 | return result; | ||
1204 | } | ||
1205 | |||
1206 | static int fiji_populate_smc_vce_level(struct pp_hwmgr *hwmgr, | ||
1207 | SMU73_Discrete_DpmTable *table) | ||
1208 | { | ||
1209 | int result = -EINVAL; | ||
1210 | uint8_t count; | ||
1211 | struct pp_atomctrl_clock_dividers_vi dividers; | ||
1212 | struct phm_ppt_v1_information *table_info = | ||
1213 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1214 | struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = | ||
1215 | table_info->mm_dep_table; | ||
1216 | |||
1217 | table->VceLevelCount = (uint8_t)(mm_table->count); | ||
1218 | table->VceBootLevel = 0; | ||
1219 | |||
1220 | for (count = 0; count < table->VceLevelCount; count++) { | ||
1221 | table->VceLevel[count].Frequency = mm_table->entries[count].eclk; | ||
1222 | table->VceLevel[count].MinVoltage = 0; | ||
1223 | table->VceLevel[count].MinVoltage |= | ||
1224 | (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT; | ||
1225 | table->VceLevel[count].MinVoltage |= | ||
1226 | ((mm_table->entries[count].vddc - VDDC_VDDCI_DELTA) * | ||
1227 | VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
1228 | table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT; | ||
1229 | |||
1230 | /*retrieve divider value for VBIOS */ | ||
1231 | result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, | ||
1232 | table->VceLevel[count].Frequency, ÷rs); | ||
1233 | PP_ASSERT_WITH_CODE((0 == result), | ||
1234 | "can not find divide id for VCE engine clock", | ||
1235 | return result); | ||
1236 | |||
1237 | table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider; | ||
1238 | |||
1239 | CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency); | ||
1240 | CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage); | ||
1241 | } | ||
1242 | return result; | ||
1243 | } | ||
1244 | |||
1245 | static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr, | ||
1246 | SMU73_Discrete_DpmTable *table) | ||
1247 | { | ||
1248 | int result = -EINVAL; | ||
1249 | uint8_t count; | ||
1250 | struct pp_atomctrl_clock_dividers_vi dividers; | ||
1251 | struct phm_ppt_v1_information *table_info = | ||
1252 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1253 | struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = | ||
1254 | table_info->mm_dep_table; | ||
1255 | |||
1256 | table->AcpLevelCount = (uint8_t)(mm_table->count); | ||
1257 | table->AcpBootLevel = 0; | ||
1258 | |||
1259 | for (count = 0; count < table->AcpLevelCount; count++) { | ||
1260 | table->AcpLevel[count].Frequency = mm_table->entries[count].aclk; | ||
1261 | table->AcpLevel[count].MinVoltage |= (mm_table->entries[count].vddc * | ||
1262 | VOLTAGE_SCALE) << VDDC_SHIFT; | ||
1263 | table->AcpLevel[count].MinVoltage |= ((mm_table->entries[count].vddc - | ||
1264 | VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
1265 | table->AcpLevel[count].MinVoltage |= 1 << PHASES_SHIFT; | ||
1266 | |||
1267 | /* retrieve divider value for VBIOS */ | ||
1268 | result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, | ||
1269 | table->AcpLevel[count].Frequency, ÷rs); | ||
1270 | PP_ASSERT_WITH_CODE((0 == result), | ||
1271 | "can not find divide id for engine clock", return result); | ||
1272 | |||
1273 | table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider; | ||
1274 | |||
1275 | CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency); | ||
1276 | CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].MinVoltage); | ||
1277 | } | ||
1278 | return result; | ||
1279 | } | ||
1280 | |||
1281 | static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr, | ||
1282 | SMU73_Discrete_DpmTable *table) | ||
1283 | { | ||
1284 | int result = -EINVAL; | ||
1285 | uint8_t count; | ||
1286 | struct pp_atomctrl_clock_dividers_vi dividers; | ||
1287 | struct phm_ppt_v1_information *table_info = | ||
1288 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1289 | struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = | ||
1290 | table_info->mm_dep_table; | ||
1291 | |||
1292 | table->SamuBootLevel = 0; | ||
1293 | table->SamuLevelCount = (uint8_t)(mm_table->count); | ||
1294 | |||
1295 | for (count = 0; count < table->SamuLevelCount; count++) { | ||
1296 | /* not sure whether we need evclk or not */ | ||
1297 | table->SamuLevel[count].MinVoltage = 0; | ||
1298 | table->SamuLevel[count].Frequency = mm_table->entries[count].samclock; | ||
1299 | table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc * | ||
1300 | VOLTAGE_SCALE) << VDDC_SHIFT; | ||
1301 | table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc - | ||
1302 | VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
1303 | table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT; | ||
1304 | |||
1305 | /* retrieve divider value for VBIOS */ | ||
1306 | result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, | ||
1307 | table->SamuLevel[count].Frequency, ÷rs); | ||
1308 | PP_ASSERT_WITH_CODE((0 == result), | ||
1309 | "can not find divide id for samu clock", return result); | ||
1310 | |||
1311 | table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider; | ||
1312 | |||
1313 | CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency); | ||
1314 | CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage); | ||
1315 | } | ||
1316 | return result; | ||
1317 | } | ||
1318 | |||
1319 | static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr, | ||
1320 | int32_t eng_clock, int32_t mem_clock, | ||
1321 | struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs) | ||
1322 | { | ||
1323 | uint32_t dram_timing; | ||
1324 | uint32_t dram_timing2; | ||
1325 | uint32_t burstTime; | ||
1326 | ULONG state, trrds, trrdl; | ||
1327 | int result; | ||
1328 | |||
1329 | result = atomctrl_set_engine_dram_timings_rv770(hwmgr, | ||
1330 | eng_clock, mem_clock); | ||
1331 | PP_ASSERT_WITH_CODE(result == 0, | ||
1332 | "Error calling VBIOS to set DRAM_TIMING.", return result); | ||
1333 | |||
1334 | dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING); | ||
1335 | dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2); | ||
1336 | burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME); | ||
1337 | |||
1338 | state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0); | ||
1339 | trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0); | ||
1340 | trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0); | ||
1341 | |||
1342 | arb_regs->McArbDramTiming = PP_HOST_TO_SMC_UL(dram_timing); | ||
1343 | arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2); | ||
1344 | arb_regs->McArbBurstTime = (uint8_t)burstTime; | ||
1345 | arb_regs->TRRDS = (uint8_t)trrds; | ||
1346 | arb_regs->TRRDL = (uint8_t)trrdl; | ||
1347 | |||
1348 | return 0; | ||
1349 | } | ||
1350 | |||
1351 | static int fiji_program_memory_timing_parameters(struct pp_hwmgr *hwmgr) | ||
1352 | { | ||
1353 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
1354 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
1355 | struct SMU73_Discrete_MCArbDramTimingTable arb_regs; | ||
1356 | uint32_t i, j; | ||
1357 | int result = 0; | ||
1358 | |||
1359 | for (i = 0; i < data->dpm_table.sclk_table.count; i++) { | ||
1360 | for (j = 0; j < data->dpm_table.mclk_table.count; j++) { | ||
1361 | result = fiji_populate_memory_timing_parameters(hwmgr, | ||
1362 | data->dpm_table.sclk_table.dpm_levels[i].value, | ||
1363 | data->dpm_table.mclk_table.dpm_levels[j].value, | ||
1364 | &arb_regs.entries[i][j]); | ||
1365 | if (result) | ||
1366 | break; | ||
1367 | } | ||
1368 | } | ||
1369 | |||
1370 | if (!result) | ||
1371 | result = fiji_copy_bytes_to_smc( | ||
1372 | hwmgr->smumgr, | ||
1373 | smu_data->arb_table_start, | ||
1374 | (uint8_t *)&arb_regs, | ||
1375 | sizeof(SMU73_Discrete_MCArbDramTimingTable), | ||
1376 | SMC_RAM_END); | ||
1377 | return result; | ||
1378 | } | ||
1379 | |||
1380 | static int fiji_populate_smc_uvd_level(struct pp_hwmgr *hwmgr, | ||
1381 | struct SMU73_Discrete_DpmTable *table) | ||
1382 | { | ||
1383 | int result = -EINVAL; | ||
1384 | uint8_t count; | ||
1385 | struct pp_atomctrl_clock_dividers_vi dividers; | ||
1386 | struct phm_ppt_v1_information *table_info = | ||
1387 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1388 | struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = | ||
1389 | table_info->mm_dep_table; | ||
1390 | |||
1391 | table->UvdLevelCount = (uint8_t)(mm_table->count); | ||
1392 | table->UvdBootLevel = 0; | ||
1393 | |||
1394 | for (count = 0; count < table->UvdLevelCount; count++) { | ||
1395 | table->UvdLevel[count].MinVoltage = 0; | ||
1396 | table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk; | ||
1397 | table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk; | ||
1398 | table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc * | ||
1399 | VOLTAGE_SCALE) << VDDC_SHIFT; | ||
1400 | table->UvdLevel[count].MinVoltage |= ((mm_table->entries[count].vddc - | ||
1401 | VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT; | ||
1402 | table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT; | ||
1403 | |||
1404 | /* retrieve divider value for VBIOS */ | ||
1405 | result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, | ||
1406 | table->UvdLevel[count].VclkFrequency, ÷rs); | ||
1407 | PP_ASSERT_WITH_CODE((0 == result), | ||
1408 | "can not find divide id for Vclk clock", return result); | ||
1409 | |||
1410 | table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider; | ||
1411 | |||
1412 | result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, | ||
1413 | table->UvdLevel[count].DclkFrequency, ÷rs); | ||
1414 | PP_ASSERT_WITH_CODE((0 == result), | ||
1415 | "can not find divide id for Dclk clock", return result); | ||
1416 | |||
1417 | table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider; | ||
1418 | |||
1419 | CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency); | ||
1420 | CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency); | ||
1421 | CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage); | ||
1422 | |||
1423 | } | ||
1424 | return result; | ||
1425 | } | ||
1426 | |||
1427 | static int fiji_populate_smc_boot_level(struct pp_hwmgr *hwmgr, | ||
1428 | struct SMU73_Discrete_DpmTable *table) | ||
1429 | { | ||
1430 | int result = 0; | ||
1431 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
1432 | |||
1433 | table->GraphicsBootLevel = 0; | ||
1434 | table->MemoryBootLevel = 0; | ||
1435 | |||
1436 | /* find boot level from dpm table */ | ||
1437 | result = phm_find_boot_level(&(data->dpm_table.sclk_table), | ||
1438 | data->vbios_boot_state.sclk_bootup_value, | ||
1439 | (uint32_t *)&(table->GraphicsBootLevel)); | ||
1440 | |||
1441 | result = phm_find_boot_level(&(data->dpm_table.mclk_table), | ||
1442 | data->vbios_boot_state.mclk_bootup_value, | ||
1443 | (uint32_t *)&(table->MemoryBootLevel)); | ||
1444 | |||
1445 | table->BootVddc = data->vbios_boot_state.vddc_bootup_value * | ||
1446 | VOLTAGE_SCALE; | ||
1447 | table->BootVddci = data->vbios_boot_state.vddci_bootup_value * | ||
1448 | VOLTAGE_SCALE; | ||
1449 | table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value * | ||
1450 | VOLTAGE_SCALE; | ||
1451 | |||
1452 | CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc); | ||
1453 | CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci); | ||
1454 | CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd); | ||
1455 | |||
1456 | return 0; | ||
1457 | } | ||
1458 | |||
1459 | static int fiji_populate_smc_initailial_state(struct pp_hwmgr *hwmgr) | ||
1460 | { | ||
1461 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
1462 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
1463 | struct phm_ppt_v1_information *table_info = | ||
1464 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1465 | uint8_t count, level; | ||
1466 | |||
1467 | count = (uint8_t)(table_info->vdd_dep_on_sclk->count); | ||
1468 | for (level = 0; level < count; level++) { | ||
1469 | if (table_info->vdd_dep_on_sclk->entries[level].clk >= | ||
1470 | data->vbios_boot_state.sclk_bootup_value) { | ||
1471 | smu_data->smc_state_table.GraphicsBootLevel = level; | ||
1472 | break; | ||
1473 | } | ||
1474 | } | ||
1475 | |||
1476 | count = (uint8_t)(table_info->vdd_dep_on_mclk->count); | ||
1477 | for (level = 0; level < count; level++) { | ||
1478 | if (table_info->vdd_dep_on_mclk->entries[level].clk >= | ||
1479 | data->vbios_boot_state.mclk_bootup_value) { | ||
1480 | smu_data->smc_state_table.MemoryBootLevel = level; | ||
1481 | break; | ||
1482 | } | ||
1483 | } | ||
1484 | |||
1485 | return 0; | ||
1486 | } | ||
1487 | |||
1488 | static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) | ||
1489 | { | ||
1490 | uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks, | ||
1491 | volt_with_cks, value; | ||
1492 | uint16_t clock_freq_u16; | ||
1493 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
1494 | uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2, | ||
1495 | volt_offset = 0; | ||
1496 | struct phm_ppt_v1_information *table_info = | ||
1497 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1498 | struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = | ||
1499 | table_info->vdd_dep_on_sclk; | ||
1500 | |||
1501 | stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount; | ||
1502 | |||
1503 | /* Read SMU_Eefuse to read and calculate RO and determine | ||
1504 | * if the part is SS or FF. if RO >= 1660MHz, part is FF. | ||
1505 | */ | ||
1506 | efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
1507 | ixSMU_EFUSE_0 + (146 * 4)); | ||
1508 | efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
1509 | ixSMU_EFUSE_0 + (148 * 4)); | ||
1510 | efuse &= 0xFF000000; | ||
1511 | efuse = efuse >> 24; | ||
1512 | efuse2 &= 0xF; | ||
1513 | |||
1514 | if (efuse2 == 1) | ||
1515 | ro = (2300 - 1350) * efuse / 255 + 1350; | ||
1516 | else | ||
1517 | ro = (2500 - 1000) * efuse / 255 + 1000; | ||
1518 | |||
1519 | if (ro >= 1660) | ||
1520 | type = 0; | ||
1521 | else | ||
1522 | type = 1; | ||
1523 | |||
1524 | /* Populate Stretch amount */ | ||
1525 | smu_data->smc_state_table.ClockStretcherAmount = stretch_amount; | ||
1526 | |||
1527 | /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */ | ||
1528 | for (i = 0; i < sclk_table->count; i++) { | ||
1529 | smu_data->smc_state_table.Sclk_CKS_masterEn0_7 |= | ||
1530 | sclk_table->entries[i].cks_enable << i; | ||
1531 | volt_without_cks = (uint32_t)((14041 * | ||
1532 | (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 / | ||
1533 | (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000))); | ||
1534 | volt_with_cks = (uint32_t)((13946 * | ||
1535 | (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 / | ||
1536 | (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000))); | ||
1537 | if (volt_without_cks >= volt_with_cks) | ||
1538 | volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks + | ||
1539 | sclk_table->entries[i].cks_voffset) * 100 / 625) + 1); | ||
1540 | smu_data->smc_state_table.Sclk_voltageOffset[i] = volt_offset; | ||
1541 | } | ||
1542 | |||
1543 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE, | ||
1544 | STRETCH_ENABLE, 0x0); | ||
1545 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE, | ||
1546 | masterReset, 0x1); | ||
1547 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE, | ||
1548 | staticEnable, 0x1); | ||
1549 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE, | ||
1550 | masterReset, 0x0); | ||
1551 | |||
1552 | /* Populate CKS Lookup Table */ | ||
1553 | if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5) | ||
1554 | stretch_amount2 = 0; | ||
1555 | else if (stretch_amount == 3 || stretch_amount == 4) | ||
1556 | stretch_amount2 = 1; | ||
1557 | else { | ||
1558 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
1559 | PHM_PlatformCaps_ClockStretcher); | ||
1560 | PP_ASSERT_WITH_CODE(false, | ||
1561 | "Stretch Amount in PPTable not supported\n", | ||
1562 | return -EINVAL); | ||
1563 | } | ||
1564 | |||
1565 | value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
1566 | ixPWR_CKS_CNTL); | ||
1567 | value &= 0xFFC2FF87; | ||
1568 | smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq = | ||
1569 | fiji_clock_stretcher_lookup_table[stretch_amount2][0]; | ||
1570 | smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq = | ||
1571 | fiji_clock_stretcher_lookup_table[stretch_amount2][1]; | ||
1572 | clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(smu_data->smc_state_table. | ||
1573 | GraphicsLevel[smu_data->smc_state_table.GraphicsDpmLevelCount - 1]. | ||
1574 | SclkFrequency) / 100); | ||
1575 | if (fiji_clock_stretcher_lookup_table[stretch_amount2][0] < | ||
1576 | clock_freq_u16 && | ||
1577 | fiji_clock_stretcher_lookup_table[stretch_amount2][1] > | ||
1578 | clock_freq_u16) { | ||
1579 | /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */ | ||
1580 | value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 16; | ||
1581 | /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */ | ||
1582 | value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][2]) << 18; | ||
1583 | /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */ | ||
1584 | value |= (fiji_clock_stretch_amount_conversion | ||
1585 | [fiji_clock_stretcher_lookup_table[stretch_amount2][3]] | ||
1586 | [stretch_amount]) << 3; | ||
1587 | } | ||
1588 | CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable. | ||
1589 | CKS_LOOKUPTableEntry[0].minFreq); | ||
1590 | CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable. | ||
1591 | CKS_LOOKUPTableEntry[0].maxFreq); | ||
1592 | smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting = | ||
1593 | fiji_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F; | ||
1594 | smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |= | ||
1595 | (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 7; | ||
1596 | |||
1597 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
1598 | ixPWR_CKS_CNTL, value); | ||
1599 | |||
1600 | /* Populate DDT Lookup Table */ | ||
1601 | for (i = 0; i < 4; i++) { | ||
1602 | /* Assign the minimum and maximum VID stored | ||
1603 | * in the last row of Clock Stretcher Voltage Table. | ||
1604 | */ | ||
1605 | smu_data->smc_state_table.ClockStretcherDataTable. | ||
1606 | ClockStretcherDataTableEntry[i].minVID = | ||
1607 | (uint8_t) fiji_clock_stretcher_ddt_table[type][i][2]; | ||
1608 | smu_data->smc_state_table.ClockStretcherDataTable. | ||
1609 | ClockStretcherDataTableEntry[i].maxVID = | ||
1610 | (uint8_t) fiji_clock_stretcher_ddt_table[type][i][3]; | ||
1611 | /* Loop through each SCLK and check the frequency | ||
1612 | * to see if it lies within the frequency for clock stretcher. | ||
1613 | */ | ||
1614 | for (j = 0; j < smu_data->smc_state_table.GraphicsDpmLevelCount; j++) { | ||
1615 | cks_setting = 0; | ||
1616 | clock_freq = PP_SMC_TO_HOST_UL( | ||
1617 | smu_data->smc_state_table.GraphicsLevel[j].SclkFrequency); | ||
1618 | /* Check the allowed frequency against the sclk level[j]. | ||
1619 | * Sclk's endianness has already been converted, | ||
1620 | * and it's in 10Khz unit, | ||
1621 | * as opposed to Data table, which is in Mhz unit. | ||
1622 | */ | ||
1623 | if (clock_freq >= | ||
1624 | (fiji_clock_stretcher_ddt_table[type][i][0]) * 100) { | ||
1625 | cks_setting |= 0x2; | ||
1626 | if (clock_freq < | ||
1627 | (fiji_clock_stretcher_ddt_table[type][i][1]) * 100) | ||
1628 | cks_setting |= 0x1; | ||
1629 | } | ||
1630 | smu_data->smc_state_table.ClockStretcherDataTable. | ||
1631 | ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2); | ||
1632 | } | ||
1633 | CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table. | ||
1634 | ClockStretcherDataTable. | ||
1635 | ClockStretcherDataTableEntry[i].setting); | ||
1636 | } | ||
1637 | |||
1638 | value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL); | ||
1639 | value &= 0xFFFFFFFE; | ||
1640 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value); | ||
1641 | |||
1642 | return 0; | ||
1643 | } | ||
1644 | |||
1645 | /** | ||
1646 | * Populates the SMC VRConfig field in DPM table. | ||
1647 | * | ||
1648 | * @param hwmgr the address of the hardware manager | ||
1649 | * @param table the SMC DPM table structure to be populated | ||
1650 | * @return always 0 | ||
1651 | */ | ||
1652 | static int fiji_populate_vr_config(struct pp_hwmgr *hwmgr, | ||
1653 | struct SMU73_Discrete_DpmTable *table) | ||
1654 | { | ||
1655 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
1656 | uint16_t config; | ||
1657 | |||
1658 | config = VR_MERGED_WITH_VDDC; | ||
1659 | table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT); | ||
1660 | |||
1661 | /* Set Vddc Voltage Controller */ | ||
1662 | if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) { | ||
1663 | config = VR_SVI2_PLANE_1; | ||
1664 | table->VRConfig |= config; | ||
1665 | } else { | ||
1666 | PP_ASSERT_WITH_CODE(false, | ||
1667 | "VDDC should be on SVI2 control in merged mode!", | ||
1668 | ); | ||
1669 | } | ||
1670 | /* Set Vddci Voltage Controller */ | ||
1671 | if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) { | ||
1672 | config = VR_SVI2_PLANE_2; /* only in merged mode */ | ||
1673 | table->VRConfig |= (config << VRCONF_VDDCI_SHIFT); | ||
1674 | } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) { | ||
1675 | config = VR_SMIO_PATTERN_1; | ||
1676 | table->VRConfig |= (config << VRCONF_VDDCI_SHIFT); | ||
1677 | } else { | ||
1678 | config = VR_STATIC_VOLTAGE; | ||
1679 | table->VRConfig |= (config << VRCONF_VDDCI_SHIFT); | ||
1680 | } | ||
1681 | /* Set Mvdd Voltage Controller */ | ||
1682 | if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) { | ||
1683 | config = VR_SVI2_PLANE_2; | ||
1684 | table->VRConfig |= (config << VRCONF_MVDD_SHIFT); | ||
1685 | } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) { | ||
1686 | config = VR_SMIO_PATTERN_2; | ||
1687 | table->VRConfig |= (config << VRCONF_MVDD_SHIFT); | ||
1688 | } else { | ||
1689 | config = VR_STATIC_VOLTAGE; | ||
1690 | table->VRConfig |= (config << VRCONF_MVDD_SHIFT); | ||
1691 | } | ||
1692 | |||
1693 | return 0; | ||
1694 | } | ||
1695 | |||
1696 | static int fiji_init_arb_table_index(struct pp_smumgr *smumgr) | ||
1697 | { | ||
1698 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(smumgr->backend); | ||
1699 | uint32_t tmp; | ||
1700 | int result; | ||
1701 | |||
1702 | /* This is a read-modify-write on the first byte of the ARB table. | ||
1703 | * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure | ||
1704 | * is the field 'current'. | ||
1705 | * This solution is ugly, but we never write the whole table only | ||
1706 | * individual fields in it. | ||
1707 | * In reality this field should not be in that structure | ||
1708 | * but in a soft register. | ||
1709 | */ | ||
1710 | result = fiji_read_smc_sram_dword(smumgr, | ||
1711 | smu_data->arb_table_start, &tmp, SMC_RAM_END); | ||
1712 | |||
1713 | if (result) | ||
1714 | return result; | ||
1715 | |||
1716 | tmp &= 0x00FFFFFF; | ||
1717 | tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24; | ||
1718 | |||
1719 | return fiji_write_smc_sram_dword(smumgr, | ||
1720 | smu_data->arb_table_start, tmp, SMC_RAM_END); | ||
1721 | } | ||
1722 | |||
1723 | /** | ||
1724 | * Initializes the SMC table and uploads it | ||
1725 | * | ||
1726 | * @param hwmgr the address of the powerplay hardware manager. | ||
1727 | * @param pInput the pointer to input data (PowerState) | ||
1728 | * @return always 0 | ||
1729 | */ | ||
1730 | int fiji_init_smc_table(struct pp_hwmgr *hwmgr) | ||
1731 | { | ||
1732 | int result; | ||
1733 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
1734 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
1735 | struct phm_ppt_v1_information *table_info = | ||
1736 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
1737 | struct SMU73_Discrete_DpmTable *table = &(smu_data->smc_state_table); | ||
1738 | uint8_t i; | ||
1739 | struct pp_atomctrl_gpio_pin_assignment gpio_pin; | ||
1740 | |||
1741 | fiji_initialize_power_tune_defaults(hwmgr); | ||
1742 | |||
1743 | if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control) | ||
1744 | fiji_populate_smc_voltage_tables(hwmgr, table); | ||
1745 | |||
1746 | table->SystemFlags = 0; | ||
1747 | |||
1748 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
1749 | PHM_PlatformCaps_AutomaticDCTransition)) | ||
1750 | table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; | ||
1751 | |||
1752 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
1753 | PHM_PlatformCaps_StepVddc)) | ||
1754 | table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; | ||
1755 | |||
1756 | if (data->is_memory_gddr5) | ||
1757 | table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5; | ||
1758 | |||
1759 | if (data->ulv_supported && table_info->us_ulv_voltage_offset) { | ||
1760 | result = fiji_populate_ulv_state(hwmgr, table); | ||
1761 | PP_ASSERT_WITH_CODE(0 == result, | ||
1762 | "Failed to initialize ULV state!", return result); | ||
1763 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
1764 | ixCG_ULV_PARAMETER, 0x40035); | ||
1765 | } | ||
1766 | |||
1767 | result = fiji_populate_smc_link_level(hwmgr, table); | ||
1768 | PP_ASSERT_WITH_CODE(0 == result, | ||
1769 | "Failed to initialize Link Level!", return result); | ||
1770 | |||
1771 | result = fiji_populate_all_graphic_levels(hwmgr); | ||
1772 | PP_ASSERT_WITH_CODE(0 == result, | ||
1773 | "Failed to initialize Graphics Level!", return result); | ||
1774 | |||
1775 | result = fiji_populate_all_memory_levels(hwmgr); | ||
1776 | PP_ASSERT_WITH_CODE(0 == result, | ||
1777 | "Failed to initialize Memory Level!", return result); | ||
1778 | |||
1779 | result = fiji_populate_smc_acpi_level(hwmgr, table); | ||
1780 | PP_ASSERT_WITH_CODE(0 == result, | ||
1781 | "Failed to initialize ACPI Level!", return result); | ||
1782 | |||
1783 | result = fiji_populate_smc_vce_level(hwmgr, table); | ||
1784 | PP_ASSERT_WITH_CODE(0 == result, | ||
1785 | "Failed to initialize VCE Level!", return result); | ||
1786 | |||
1787 | result = fiji_populate_smc_acp_level(hwmgr, table); | ||
1788 | PP_ASSERT_WITH_CODE(0 == result, | ||
1789 | "Failed to initialize ACP Level!", return result); | ||
1790 | |||
1791 | result = fiji_populate_smc_samu_level(hwmgr, table); | ||
1792 | PP_ASSERT_WITH_CODE(0 == result, | ||
1793 | "Failed to initialize SAMU Level!", return result); | ||
1794 | |||
1795 | /* Since only the initial state is completely set up at this point | ||
1796 | * (the other states are just copies of the boot state) we only | ||
1797 | * need to populate the ARB settings for the initial state. | ||
1798 | */ | ||
1799 | result = fiji_program_memory_timing_parameters(hwmgr); | ||
1800 | PP_ASSERT_WITH_CODE(0 == result, | ||
1801 | "Failed to Write ARB settings for the initial state.", return result); | ||
1802 | |||
1803 | result = fiji_populate_smc_uvd_level(hwmgr, table); | ||
1804 | PP_ASSERT_WITH_CODE(0 == result, | ||
1805 | "Failed to initialize UVD Level!", return result); | ||
1806 | |||
1807 | result = fiji_populate_smc_boot_level(hwmgr, table); | ||
1808 | PP_ASSERT_WITH_CODE(0 == result, | ||
1809 | "Failed to initialize Boot Level!", return result); | ||
1810 | |||
1811 | result = fiji_populate_smc_initailial_state(hwmgr); | ||
1812 | PP_ASSERT_WITH_CODE(0 == result, | ||
1813 | "Failed to initialize Boot State!", return result); | ||
1814 | |||
1815 | result = fiji_populate_bapm_parameters_in_dpm_table(hwmgr); | ||
1816 | PP_ASSERT_WITH_CODE(0 == result, | ||
1817 | "Failed to populate BAPM Parameters!", return result); | ||
1818 | |||
1819 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
1820 | PHM_PlatformCaps_ClockStretcher)) { | ||
1821 | result = fiji_populate_clock_stretcher_data_table(hwmgr); | ||
1822 | PP_ASSERT_WITH_CODE(0 == result, | ||
1823 | "Failed to populate Clock Stretcher Data Table!", | ||
1824 | return result); | ||
1825 | } | ||
1826 | |||
1827 | table->GraphicsVoltageChangeEnable = 1; | ||
1828 | table->GraphicsThermThrottleEnable = 1; | ||
1829 | table->GraphicsInterval = 1; | ||
1830 | table->VoltageInterval = 1; | ||
1831 | table->ThermalInterval = 1; | ||
1832 | table->TemperatureLimitHigh = | ||
1833 | table_info->cac_dtp_table->usTargetOperatingTemp * | ||
1834 | SMU7_Q88_FORMAT_CONVERSION_UNIT; | ||
1835 | table->TemperatureLimitLow = | ||
1836 | (table_info->cac_dtp_table->usTargetOperatingTemp - 1) * | ||
1837 | SMU7_Q88_FORMAT_CONVERSION_UNIT; | ||
1838 | table->MemoryVoltageChangeEnable = 1; | ||
1839 | table->MemoryInterval = 1; | ||
1840 | table->VoltageResponseTime = 0; | ||
1841 | table->PhaseResponseTime = 0; | ||
1842 | table->MemoryThermThrottleEnable = 1; | ||
1843 | table->PCIeBootLinkLevel = 0; /* 0:Gen1 1:Gen2 2:Gen3*/ | ||
1844 | table->PCIeGenInterval = 1; | ||
1845 | table->VRConfig = 0; | ||
1846 | |||
1847 | result = fiji_populate_vr_config(hwmgr, table); | ||
1848 | PP_ASSERT_WITH_CODE(0 == result, | ||
1849 | "Failed to populate VRConfig setting!", return result); | ||
1850 | |||
1851 | table->ThermGpio = 17; | ||
1852 | table->SclkStepSize = 0x4000; | ||
1853 | |||
1854 | if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) { | ||
1855 | table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift; | ||
1856 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
1857 | PHM_PlatformCaps_RegulatorHot); | ||
1858 | } else { | ||
1859 | table->VRHotGpio = SMU7_UNUSED_GPIO_PIN; | ||
1860 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
1861 | PHM_PlatformCaps_RegulatorHot); | ||
1862 | } | ||
1863 | |||
1864 | if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID, | ||
1865 | &gpio_pin)) { | ||
1866 | table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift; | ||
1867 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
1868 | PHM_PlatformCaps_AutomaticDCTransition); | ||
1869 | } else { | ||
1870 | table->AcDcGpio = SMU7_UNUSED_GPIO_PIN; | ||
1871 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
1872 | PHM_PlatformCaps_AutomaticDCTransition); | ||
1873 | } | ||
1874 | |||
1875 | /* Thermal Output GPIO */ | ||
1876 | if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID, | ||
1877 | &gpio_pin)) { | ||
1878 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
1879 | PHM_PlatformCaps_ThermalOutGPIO); | ||
1880 | |||
1881 | table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift; | ||
1882 | |||
1883 | /* For porlarity read GPIOPAD_A with assigned Gpio pin | ||
1884 | * since VBIOS will program this register to set 'inactive state', | ||
1885 | * driver can then determine 'active state' from this and | ||
1886 | * program SMU with correct polarity | ||
1887 | */ | ||
1888 | table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) & | ||
1889 | (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0; | ||
1890 | table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY; | ||
1891 | |||
1892 | /* if required, combine VRHot/PCC with thermal out GPIO */ | ||
1893 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
1894 | PHM_PlatformCaps_RegulatorHot) && | ||
1895 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
1896 | PHM_PlatformCaps_CombinePCCWithThermalSignal)) | ||
1897 | table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT; | ||
1898 | } else { | ||
1899 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
1900 | PHM_PlatformCaps_ThermalOutGPIO); | ||
1901 | table->ThermOutGpio = 17; | ||
1902 | table->ThermOutPolarity = 1; | ||
1903 | table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE; | ||
1904 | } | ||
1905 | |||
1906 | for (i = 0; i < SMU73_MAX_ENTRIES_SMIO; i++) | ||
1907 | table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]); | ||
1908 | |||
1909 | CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags); | ||
1910 | CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig); | ||
1911 | CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1); | ||
1912 | CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2); | ||
1913 | CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize); | ||
1914 | CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh); | ||
1915 | CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow); | ||
1916 | CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime); | ||
1917 | CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime); | ||
1918 | |||
1919 | /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */ | ||
1920 | result = fiji_copy_bytes_to_smc(hwmgr->smumgr, | ||
1921 | smu_data->dpm_table_start + | ||
1922 | offsetof(SMU73_Discrete_DpmTable, SystemFlags), | ||
1923 | (uint8_t *)&(table->SystemFlags), | ||
1924 | sizeof(SMU73_Discrete_DpmTable) - 3 * sizeof(SMU73_PIDController), | ||
1925 | SMC_RAM_END); | ||
1926 | PP_ASSERT_WITH_CODE(0 == result, | ||
1927 | "Failed to upload dpm data to SMC memory!", return result); | ||
1928 | |||
1929 | result = fiji_init_arb_table_index(hwmgr->smumgr); | ||
1930 | PP_ASSERT_WITH_CODE(0 == result, | ||
1931 | "Failed to upload arb data to SMC memory!", return result); | ||
1932 | |||
1933 | result = fiji_populate_pm_fuses(hwmgr); | ||
1934 | PP_ASSERT_WITH_CODE(0 == result, | ||
1935 | "Failed to populate PM fuses to SMC memory!", return result); | ||
1936 | return 0; | ||
1937 | } | ||
1938 | |||
1939 | /** | ||
1940 | * Set up the fan table to control the fan using the SMC. | ||
1941 | * @param hwmgr the address of the powerplay hardware manager. | ||
1942 | * @param pInput the pointer to input data | ||
1943 | * @param pOutput the pointer to output data | ||
1944 | * @param pStorage the pointer to temporary storage | ||
1945 | * @param Result the last failure code | ||
1946 | * @return result from set temperature range routine | ||
1947 | */ | ||
1948 | int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) | ||
1949 | { | ||
1950 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
1951 | |||
1952 | SMU73_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE }; | ||
1953 | uint32_t duty100; | ||
1954 | uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2; | ||
1955 | uint16_t fdo_min, slope1, slope2; | ||
1956 | uint32_t reference_clock; | ||
1957 | int res; | ||
1958 | uint64_t tmp64; | ||
1959 | |||
1960 | if (smu_data->fan_table_start == 0) { | ||
1961 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
1962 | PHM_PlatformCaps_MicrocodeFanControl); | ||
1963 | return 0; | ||
1964 | } | ||
1965 | |||
1966 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, | ||
1967 | CG_FDO_CTRL1, FMAX_DUTY100); | ||
1968 | |||
1969 | if (duty100 == 0) { | ||
1970 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
1971 | PHM_PlatformCaps_MicrocodeFanControl); | ||
1972 | return 0; | ||
1973 | } | ||
1974 | |||
1975 | tmp64 = hwmgr->thermal_controller.advanceFanControlParameters. | ||
1976 | usPWMMin * duty100; | ||
1977 | do_div(tmp64, 10000); | ||
1978 | fdo_min = (uint16_t)tmp64; | ||
1979 | |||
1980 | t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - | ||
1981 | hwmgr->thermal_controller.advanceFanControlParameters.usTMin; | ||
1982 | t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - | ||
1983 | hwmgr->thermal_controller.advanceFanControlParameters.usTMed; | ||
1984 | |||
1985 | pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - | ||
1986 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin; | ||
1987 | pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - | ||
1988 | hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed; | ||
1989 | |||
1990 | slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); | ||
1991 | slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); | ||
1992 | |||
1993 | fan_table.TempMin = cpu_to_be16((50 + hwmgr-> | ||
1994 | thermal_controller.advanceFanControlParameters.usTMin) / 100); | ||
1995 | fan_table.TempMed = cpu_to_be16((50 + hwmgr-> | ||
1996 | thermal_controller.advanceFanControlParameters.usTMed) / 100); | ||
1997 | fan_table.TempMax = cpu_to_be16((50 + hwmgr-> | ||
1998 | thermal_controller.advanceFanControlParameters.usTMax) / 100); | ||
1999 | |||
2000 | fan_table.Slope1 = cpu_to_be16(slope1); | ||
2001 | fan_table.Slope2 = cpu_to_be16(slope2); | ||
2002 | |||
2003 | fan_table.FdoMin = cpu_to_be16(fdo_min); | ||
2004 | |||
2005 | fan_table.HystDown = cpu_to_be16(hwmgr-> | ||
2006 | thermal_controller.advanceFanControlParameters.ucTHyst); | ||
2007 | |||
2008 | fan_table.HystUp = cpu_to_be16(1); | ||
2009 | |||
2010 | fan_table.HystSlope = cpu_to_be16(1); | ||
2011 | |||
2012 | fan_table.TempRespLim = cpu_to_be16(5); | ||
2013 | |||
2014 | reference_clock = smu7_get_xclk(hwmgr); | ||
2015 | |||
2016 | fan_table.RefreshPeriod = cpu_to_be32((hwmgr-> | ||
2017 | thermal_controller.advanceFanControlParameters.ulCycleDelay * | ||
2018 | reference_clock) / 1600); | ||
2019 | |||
2020 | fan_table.FdoMax = cpu_to_be16((uint16_t)duty100); | ||
2021 | |||
2022 | fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD( | ||
2023 | hwmgr->device, CGS_IND_REG__SMC, | ||
2024 | CG_MULT_THERMAL_CTRL, TEMP_SEL); | ||
2025 | |||
2026 | res = fiji_copy_bytes_to_smc(hwmgr->smumgr, smu_data->fan_table_start, | ||
2027 | (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), | ||
2028 | SMC_RAM_END); | ||
2029 | |||
2030 | if (!res && hwmgr->thermal_controller. | ||
2031 | advanceFanControlParameters.ucMinimumPWMLimit) | ||
2032 | res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
2033 | PPSMC_MSG_SetFanMinPwm, | ||
2034 | hwmgr->thermal_controller. | ||
2035 | advanceFanControlParameters.ucMinimumPWMLimit); | ||
2036 | |||
2037 | if (!res && hwmgr->thermal_controller. | ||
2038 | advanceFanControlParameters.ulMinFanSCLKAcousticLimit) | ||
2039 | res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
2040 | PPSMC_MSG_SetFanSclkTarget, | ||
2041 | hwmgr->thermal_controller. | ||
2042 | advanceFanControlParameters.ulMinFanSCLKAcousticLimit); | ||
2043 | |||
2044 | if (res) | ||
2045 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
2046 | PHM_PlatformCaps_MicrocodeFanControl); | ||
2047 | |||
2048 | return 0; | ||
2049 | } | ||
2050 | |||
2051 | int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr) | ||
2052 | { | ||
2053 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
2054 | |||
2055 | if (data->need_update_smu7_dpm_table & | ||
2056 | (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK)) | ||
2057 | return fiji_program_memory_timing_parameters(hwmgr); | ||
2058 | |||
2059 | return 0; | ||
2060 | } | ||
2061 | |||
2062 | int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr) | ||
2063 | { | ||
2064 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
2065 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
2066 | |||
2067 | int result = 0; | ||
2068 | uint32_t low_sclk_interrupt_threshold = 0; | ||
2069 | |||
2070 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2071 | PHM_PlatformCaps_SclkThrottleLowNotification) | ||
2072 | && (hwmgr->gfx_arbiter.sclk_threshold != | ||
2073 | data->low_sclk_interrupt_threshold)) { | ||
2074 | data->low_sclk_interrupt_threshold = | ||
2075 | hwmgr->gfx_arbiter.sclk_threshold; | ||
2076 | low_sclk_interrupt_threshold = | ||
2077 | data->low_sclk_interrupt_threshold; | ||
2078 | |||
2079 | CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold); | ||
2080 | |||
2081 | result = fiji_copy_bytes_to_smc( | ||
2082 | hwmgr->smumgr, | ||
2083 | smu_data->dpm_table_start + | ||
2084 | offsetof(SMU73_Discrete_DpmTable, | ||
2085 | LowSclkInterruptThreshold), | ||
2086 | (uint8_t *)&low_sclk_interrupt_threshold, | ||
2087 | sizeof(uint32_t), | ||
2088 | SMC_RAM_END); | ||
2089 | } | ||
2090 | result = fiji_program_mem_timing_parameters(hwmgr); | ||
2091 | PP_ASSERT_WITH_CODE((result == 0), | ||
2092 | "Failed to program memory timing parameters!", | ||
2093 | ); | ||
2094 | return result; | ||
2095 | } | ||
2096 | |||
2097 | uint32_t fiji_get_offsetof(uint32_t type, uint32_t member) | ||
2098 | { | ||
2099 | switch (type) { | ||
2100 | case SMU_SoftRegisters: | ||
2101 | switch (member) { | ||
2102 | case HandshakeDisables: | ||
2103 | return offsetof(SMU73_SoftRegisters, HandshakeDisables); | ||
2104 | case VoltageChangeTimeout: | ||
2105 | return offsetof(SMU73_SoftRegisters, VoltageChangeTimeout); | ||
2106 | case AverageGraphicsActivity: | ||
2107 | return offsetof(SMU73_SoftRegisters, AverageGraphicsActivity); | ||
2108 | case PreVBlankGap: | ||
2109 | return offsetof(SMU73_SoftRegisters, PreVBlankGap); | ||
2110 | case VBlankTimeout: | ||
2111 | return offsetof(SMU73_SoftRegisters, VBlankTimeout); | ||
2112 | } | ||
2113 | case SMU_Discrete_DpmTable: | ||
2114 | switch (member) { | ||
2115 | case UvdBootLevel: | ||
2116 | return offsetof(SMU73_Discrete_DpmTable, UvdBootLevel); | ||
2117 | case VceBootLevel: | ||
2118 | return offsetof(SMU73_Discrete_DpmTable, VceBootLevel); | ||
2119 | case SamuBootLevel: | ||
2120 | return offsetof(SMU73_Discrete_DpmTable, SamuBootLevel); | ||
2121 | case LowSclkInterruptThreshold: | ||
2122 | return offsetof(SMU73_Discrete_DpmTable, LowSclkInterruptThreshold); | ||
2123 | } | ||
2124 | } | ||
2125 | printk("cant't get the offset of type %x member %x \n", type, member); | ||
2126 | return 0; | ||
2127 | } | ||
2128 | |||
2129 | uint32_t fiji_get_mac_definition(uint32_t value) | ||
2130 | { | ||
2131 | switch (value) { | ||
2132 | case SMU_MAX_LEVELS_GRAPHICS: | ||
2133 | return SMU73_MAX_LEVELS_GRAPHICS; | ||
2134 | case SMU_MAX_LEVELS_MEMORY: | ||
2135 | return SMU73_MAX_LEVELS_MEMORY; | ||
2136 | case SMU_MAX_LEVELS_LINK: | ||
2137 | return SMU73_MAX_LEVELS_LINK; | ||
2138 | case SMU_MAX_ENTRIES_SMIO: | ||
2139 | return SMU73_MAX_ENTRIES_SMIO; | ||
2140 | case SMU_MAX_LEVELS_VDDC: | ||
2141 | return SMU73_MAX_LEVELS_VDDC; | ||
2142 | case SMU_MAX_LEVELS_VDDGFX: | ||
2143 | return SMU73_MAX_LEVELS_VDDGFX; | ||
2144 | case SMU_MAX_LEVELS_VDDCI: | ||
2145 | return SMU73_MAX_LEVELS_VDDCI; | ||
2146 | case SMU_MAX_LEVELS_MVDD: | ||
2147 | return SMU73_MAX_LEVELS_MVDD; | ||
2148 | } | ||
2149 | |||
2150 | printk("cant't get the mac of %x \n", value); | ||
2151 | return 0; | ||
2152 | } | ||
2153 | |||
2154 | |||
2155 | static int fiji_update_uvd_smc_table(struct pp_hwmgr *hwmgr) | ||
2156 | { | ||
2157 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
2158 | uint32_t mm_boot_level_offset, mm_boot_level_value; | ||
2159 | struct phm_ppt_v1_information *table_info = | ||
2160 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
2161 | |||
2162 | smu_data->smc_state_table.UvdBootLevel = 0; | ||
2163 | if (table_info->mm_dep_table->count > 0) | ||
2164 | smu_data->smc_state_table.UvdBootLevel = | ||
2165 | (uint8_t) (table_info->mm_dep_table->count - 1); | ||
2166 | mm_boot_level_offset = smu_data->dpm_table_start + offsetof(SMU73_Discrete_DpmTable, | ||
2167 | UvdBootLevel); | ||
2168 | mm_boot_level_offset /= 4; | ||
2169 | mm_boot_level_offset *= 4; | ||
2170 | mm_boot_level_value = cgs_read_ind_register(hwmgr->device, | ||
2171 | CGS_IND_REG__SMC, mm_boot_level_offset); | ||
2172 | mm_boot_level_value &= 0x00FFFFFF; | ||
2173 | mm_boot_level_value |= smu_data->smc_state_table.UvdBootLevel << 24; | ||
2174 | cgs_write_ind_register(hwmgr->device, | ||
2175 | CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value); | ||
2176 | |||
2177 | if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2178 | PHM_PlatformCaps_UVDDPM) || | ||
2179 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2180 | PHM_PlatformCaps_StablePState)) | ||
2181 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
2182 | PPSMC_MSG_UVDDPM_SetEnabledMask, | ||
2183 | (uint32_t)(1 << smu_data->smc_state_table.UvdBootLevel)); | ||
2184 | return 0; | ||
2185 | } | ||
2186 | |||
2187 | static int fiji_update_vce_smc_table(struct pp_hwmgr *hwmgr) | ||
2188 | { | ||
2189 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
2190 | uint32_t mm_boot_level_offset, mm_boot_level_value; | ||
2191 | struct phm_ppt_v1_information *table_info = | ||
2192 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
2193 | |||
2194 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2195 | PHM_PlatformCaps_StablePState)) | ||
2196 | smu_data->smc_state_table.VceBootLevel = | ||
2197 | (uint8_t) (table_info->mm_dep_table->count - 1); | ||
2198 | else | ||
2199 | smu_data->smc_state_table.VceBootLevel = 0; | ||
2200 | |||
2201 | mm_boot_level_offset = smu_data->dpm_table_start + | ||
2202 | offsetof(SMU73_Discrete_DpmTable, VceBootLevel); | ||
2203 | mm_boot_level_offset /= 4; | ||
2204 | mm_boot_level_offset *= 4; | ||
2205 | mm_boot_level_value = cgs_read_ind_register(hwmgr->device, | ||
2206 | CGS_IND_REG__SMC, mm_boot_level_offset); | ||
2207 | mm_boot_level_value &= 0xFF00FFFF; | ||
2208 | mm_boot_level_value |= smu_data->smc_state_table.VceBootLevel << 16; | ||
2209 | cgs_write_ind_register(hwmgr->device, | ||
2210 | CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value); | ||
2211 | |||
2212 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) | ||
2213 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
2214 | PPSMC_MSG_VCEDPM_SetEnabledMask, | ||
2215 | (uint32_t)1 << smu_data->smc_state_table.VceBootLevel); | ||
2216 | return 0; | ||
2217 | } | ||
2218 | |||
2219 | static int fiji_update_samu_smc_table(struct pp_hwmgr *hwmgr) | ||
2220 | { | ||
2221 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
2222 | uint32_t mm_boot_level_offset, mm_boot_level_value; | ||
2223 | |||
2224 | |||
2225 | smu_data->smc_state_table.SamuBootLevel = 0; | ||
2226 | mm_boot_level_offset = smu_data->dpm_table_start + | ||
2227 | offsetof(SMU73_Discrete_DpmTable, SamuBootLevel); | ||
2228 | |||
2229 | mm_boot_level_offset /= 4; | ||
2230 | mm_boot_level_offset *= 4; | ||
2231 | mm_boot_level_value = cgs_read_ind_register(hwmgr->device, | ||
2232 | CGS_IND_REG__SMC, mm_boot_level_offset); | ||
2233 | mm_boot_level_value &= 0xFFFFFF00; | ||
2234 | mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0; | ||
2235 | cgs_write_ind_register(hwmgr->device, | ||
2236 | CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value); | ||
2237 | |||
2238 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2239 | PHM_PlatformCaps_StablePState)) | ||
2240 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
2241 | PPSMC_MSG_SAMUDPM_SetEnabledMask, | ||
2242 | (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel)); | ||
2243 | return 0; | ||
2244 | } | ||
2245 | |||
2246 | int fiji_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type) | ||
2247 | { | ||
2248 | switch (type) { | ||
2249 | case SMU_UVD_TABLE: | ||
2250 | fiji_update_uvd_smc_table(hwmgr); | ||
2251 | break; | ||
2252 | case SMU_VCE_TABLE: | ||
2253 | fiji_update_vce_smc_table(hwmgr); | ||
2254 | break; | ||
2255 | case SMU_SAMU_TABLE: | ||
2256 | fiji_update_samu_smc_table(hwmgr); | ||
2257 | break; | ||
2258 | default: | ||
2259 | break; | ||
2260 | } | ||
2261 | return 0; | ||
2262 | } | ||
2263 | |||
2264 | |||
2265 | /** | ||
2266 | * Get the location of various tables inside the FW image. | ||
2267 | * | ||
2268 | * @param hwmgr the address of the powerplay hardware manager. | ||
2269 | * @return always 0 | ||
2270 | */ | ||
2271 | int fiji_process_firmware_header(struct pp_hwmgr *hwmgr) | ||
2272 | { | ||
2273 | struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); | ||
2274 | struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend); | ||
2275 | uint32_t tmp; | ||
2276 | int result; | ||
2277 | bool error = false; | ||
2278 | |||
2279 | result = fiji_read_smc_sram_dword(hwmgr->smumgr, | ||
2280 | SMU7_FIRMWARE_HEADER_LOCATION + | ||
2281 | offsetof(SMU73_Firmware_Header, DpmTable), | ||
2282 | &tmp, SMC_RAM_END); | ||
2283 | |||
2284 | if (0 == result) | ||
2285 | smu_data->dpm_table_start = tmp; | ||
2286 | |||
2287 | error |= (0 != result); | ||
2288 | |||
2289 | result = fiji_read_smc_sram_dword(hwmgr->smumgr, | ||
2290 | SMU7_FIRMWARE_HEADER_LOCATION + | ||
2291 | offsetof(SMU73_Firmware_Header, SoftRegisters), | ||
2292 | &tmp, SMC_RAM_END); | ||
2293 | |||
2294 | if (!result) { | ||
2295 | data->soft_regs_start = tmp; | ||
2296 | smu_data->soft_regs_start = tmp; | ||
2297 | } | ||
2298 | |||
2299 | error |= (0 != result); | ||
2300 | |||
2301 | result = fiji_read_smc_sram_dword(hwmgr->smumgr, | ||
2302 | SMU7_FIRMWARE_HEADER_LOCATION + | ||
2303 | offsetof(SMU73_Firmware_Header, mcRegisterTable), | ||
2304 | &tmp, SMC_RAM_END); | ||
2305 | |||
2306 | if (!result) | ||
2307 | smu_data->mc_reg_table_start = tmp; | ||
2308 | |||
2309 | result = fiji_read_smc_sram_dword(hwmgr->smumgr, | ||
2310 | SMU7_FIRMWARE_HEADER_LOCATION + | ||
2311 | offsetof(SMU73_Firmware_Header, FanTable), | ||
2312 | &tmp, SMC_RAM_END); | ||
2313 | |||
2314 | if (!result) | ||
2315 | smu_data->fan_table_start = tmp; | ||
2316 | |||
2317 | error |= (0 != result); | ||
2318 | |||
2319 | result = fiji_read_smc_sram_dword(hwmgr->smumgr, | ||
2320 | SMU7_FIRMWARE_HEADER_LOCATION + | ||
2321 | offsetof(SMU73_Firmware_Header, mcArbDramTimingTable), | ||
2322 | &tmp, SMC_RAM_END); | ||
2323 | |||
2324 | if (!result) | ||
2325 | smu_data->arb_table_start = tmp; | ||
2326 | |||
2327 | error |= (0 != result); | ||
2328 | |||
2329 | result = fiji_read_smc_sram_dword(hwmgr->smumgr, | ||
2330 | SMU7_FIRMWARE_HEADER_LOCATION + | ||
2331 | offsetof(SMU73_Firmware_Header, Version), | ||
2332 | &tmp, SMC_RAM_END); | ||
2333 | |||
2334 | if (!result) | ||
2335 | hwmgr->microcode_version_info.SMC = tmp; | ||
2336 | |||
2337 | error |= (0 != result); | ||
2338 | |||
2339 | return error ? -1 : 0; | ||
2340 | } | ||
2341 | |||
2342 | int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) | ||
2343 | { | ||
2344 | |||
2345 | /* Program additional LP registers | ||
2346 | * that are no longer programmed by VBIOS | ||
2347 | */ | ||
2348 | cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, | ||
2349 | cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING)); | ||
2350 | cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, | ||
2351 | cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING)); | ||
2352 | cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, | ||
2353 | cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2)); | ||
2354 | cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, | ||
2355 | cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1)); | ||
2356 | cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, | ||
2357 | cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0)); | ||
2358 | cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, | ||
2359 | cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1)); | ||
2360 | cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, | ||
2361 | cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING)); | ||
2362 | |||
2363 | return 0; | ||
2364 | } | ||
2365 | |||
2366 | bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr) | ||
2367 | { | ||
2368 | return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device, | ||
2369 | CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON)) | ||
2370 | ? true : false; | ||
2371 | } | ||
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.h b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.h new file mode 100644 index 000000000000..d30d150f9ca6 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.h | |||
@@ -0,0 +1,51 @@ | |||
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 | #ifndef FIJI_SMC_H | ||
24 | #define FIJI_SMC_H | ||
25 | |||
26 | #include "smumgr.h" | ||
27 | #include "smu73.h" | ||
28 | |||
29 | struct fiji_pt_defaults { | ||
30 | uint8_t SviLoadLineEn; | ||
31 | uint8_t SviLoadLineVddC; | ||
32 | uint8_t TDC_VDDC_ThrottleReleaseLimitPerc; | ||
33 | uint8_t TDC_MAWt; | ||
34 | uint8_t TdcWaterfallCtl; | ||
35 | uint8_t DTEAmbientTempBase; | ||
36 | }; | ||
37 | |||
38 | int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr); | ||
39 | int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr); | ||
40 | int fiji_init_smc_table(struct pp_hwmgr *hwmgr); | ||
41 | int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr); | ||
42 | int fiji_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type); | ||
43 | int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr); | ||
44 | uint32_t fiji_get_offsetof(uint32_t type, uint32_t member); | ||
45 | uint32_t fiji_get_mac_definition(uint32_t value); | ||
46 | int fiji_process_firmware_header(struct pp_hwmgr *hwmgr); | ||
47 | int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr); | ||
48 | bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr); | ||
49 | |||
50 | #endif | ||
51 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index 8e52a2e82db5..82a8be4af63b 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include "bif/bif_5_0_sh_mask.h" | 38 | #include "bif/bif_5_0_sh_mask.h" |
39 | #include "pp_debug.h" | 39 | #include "pp_debug.h" |
40 | #include "fiji_pwrvirus.h" | 40 | #include "fiji_pwrvirus.h" |
41 | #include "fiji_smc.h" | ||
41 | 42 | ||
42 | #define AVFS_EN_MSB 1568 | 43 | #define AVFS_EN_MSB 1568 |
43 | #define AVFS_EN_LSB 1568 | 44 | #define AVFS_EN_LSB 1568 |
@@ -219,17 +220,28 @@ bool fiji_is_smc_ram_running(struct pp_smumgr *smumgr) | |||
219 | */ | 220 | */ |
220 | int fiji_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg) | 221 | int fiji_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg) |
221 | { | 222 | { |
223 | int ret; | ||
224 | |||
222 | if (!fiji_is_smc_ram_running(smumgr)) | 225 | if (!fiji_is_smc_ram_running(smumgr)) |
223 | return -1; | 226 | return -1; |
224 | 227 | ||
225 | if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) { | 228 | |
226 | printk(KERN_ERR "Failed to send Previous Message."); | 229 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); |
227 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | 230 | |
228 | } | 231 | ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP); |
232 | |||
233 | if (ret != 1) | ||
234 | printk("\n failed to send pre message %x ret is %d \n", msg, ret); | ||
229 | 235 | ||
230 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); | 236 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); |
237 | |||
231 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | 238 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); |
232 | 239 | ||
240 | ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP); | ||
241 | |||
242 | if (ret != 1) | ||
243 | printk("\n failed to send message %x ret is %d \n", msg, ret); | ||
244 | |||
233 | return 0; | 245 | return 0; |
234 | } | 246 | } |
235 | 247 | ||
@@ -840,7 +852,7 @@ int fiji_avfs_event_mgr(struct pp_smumgr *smumgr, bool smu_started) | |||
840 | case AVFS_BTC_COMPLETED_RESTORED: /*S3 State - Post SMU Start*/ | 852 | case AVFS_BTC_COMPLETED_RESTORED: /*S3 State - Post SMU Start*/ |
841 | priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR; | 853 | priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR; |
842 | PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr, | 854 | PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr, |
843 | PPSMC_MSG_VftTableIsValid), | 855 | 0x666), |
844 | "[AVFS][fiji_avfs_event_mgr] SMU did not respond " | 856 | "[AVFS][fiji_avfs_event_mgr] SMU did not respond " |
845 | "correctly to VftTableIsValid Msg", | 857 | "correctly to VftTableIsValid Msg", |
846 | return -1;); | 858 | return -1;); |
@@ -964,6 +976,7 @@ static int fiji_smu_init(struct pp_smumgr *smumgr) | |||
964 | { | 976 | { |
965 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | 977 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); |
966 | uint64_t mc_addr; | 978 | uint64_t mc_addr; |
979 | int i; | ||
967 | 980 | ||
968 | priv->header_buffer.data_size = | 981 | priv->header_buffer.data_size = |
969 | ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | 982 | ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; |
@@ -1001,6 +1014,9 @@ static int fiji_smu_init(struct pp_smumgr *smumgr) | |||
1001 | 1014 | ||
1002 | priv->acpi_optimization = 1; | 1015 | priv->acpi_optimization = 1; |
1003 | 1016 | ||
1017 | for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++) | ||
1018 | priv->activity_target[i] = 30; | ||
1019 | |||
1004 | return 0; | 1020 | return 0; |
1005 | } | 1021 | } |
1006 | 1022 | ||
@@ -1030,6 +1046,17 @@ static const struct pp_smumgr_func fiji_smu_funcs = { | |||
1030 | .send_msg_to_smc_with_parameter = &fiji_send_msg_to_smc_with_parameter, | 1046 | .send_msg_to_smc_with_parameter = &fiji_send_msg_to_smc_with_parameter, |
1031 | .download_pptable_settings = NULL, | 1047 | .download_pptable_settings = NULL, |
1032 | .upload_pptable_settings = NULL, | 1048 | .upload_pptable_settings = NULL, |
1049 | .update_smc_table = fiji_update_smc_table, | ||
1050 | .get_offsetof = fiji_get_offsetof, | ||
1051 | .process_firmware_header = fiji_process_firmware_header, | ||
1052 | .init_smc_table = fiji_init_smc_table, | ||
1053 | .update_sclk_threshold = fiji_update_sclk_threshold, | ||
1054 | .thermal_setup_fan_table = fiji_thermal_setup_fan_table, | ||
1055 | .populate_all_graphic_levels = fiji_populate_all_graphic_levels, | ||
1056 | .populate_all_memory_levels = fiji_populate_all_memory_levels, | ||
1057 | .get_mac_definition = fiji_get_mac_definition, | ||
1058 | .initialize_mc_reg_table = fiji_initialize_mc_reg_table, | ||
1059 | .is_dpm_running = fiji_is_dpm_running, | ||
1033 | }; | 1060 | }; |
1034 | 1061 | ||
1035 | int fiji_smum_init(struct pp_smumgr *smumgr) | 1062 | int fiji_smum_init(struct pp_smumgr *smumgr) |
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h index b4eb483215b1..291f7042a585 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h | |||
@@ -23,6 +23,10 @@ | |||
23 | #ifndef _FIJI_SMUMANAGER_H_ | 23 | #ifndef _FIJI_SMUMANAGER_H_ |
24 | #define _FIJI_SMUMANAGER_H_ | 24 | #define _FIJI_SMUMANAGER_H_ |
25 | 25 | ||
26 | #include "smu73_discrete.h" | ||
27 | #include <pp_endian.h> | ||
28 | |||
29 | #define SMC_RAM_END 0x40000 | ||
26 | 30 | ||
27 | struct fiji_smu_avfs { | 31 | struct fiji_smu_avfs { |
28 | enum AVFS_BTC_STATUS AvfsBtcStatus; | 32 | enum AVFS_BTC_STATUS AvfsBtcStatus; |
@@ -40,11 +44,22 @@ struct fiji_buffer_entry { | |||
40 | struct fiji_smumgr { | 44 | struct fiji_smumgr { |
41 | uint8_t *header; | 45 | uint8_t *header; |
42 | uint8_t *mec_image; | 46 | uint8_t *mec_image; |
43 | uint32_t soft_regs_start; | 47 | |
48 | uint32_t soft_regs_start; | ||
49 | uint32_t dpm_table_start; | ||
50 | uint32_t mc_reg_table_start; | ||
51 | uint32_t fan_table_start; | ||
52 | uint32_t arb_table_start; | ||
44 | struct fiji_smu_avfs avfs; | 53 | struct fiji_smu_avfs avfs; |
45 | uint32_t acpi_optimization; | 54 | uint32_t acpi_optimization; |
46 | |||
47 | struct fiji_buffer_entry header_buffer; | 55 | struct fiji_buffer_entry header_buffer; |
56 | |||
57 | struct SMU73_Discrete_DpmTable smc_state_table; | ||
58 | struct SMU73_Discrete_Ulv ulv_setting; | ||
59 | struct SMU73_Discrete_PmFuses power_tune_table; | ||
60 | const struct fiji_pt_defaults *power_tune_defaults; | ||
61 | uint32_t activity_target[SMU73_MAX_LEVELS_GRAPHICS]; | ||
62 | |||
48 | }; | 63 | }; |
49 | 64 | ||
50 | int fiji_smum_init(struct pp_smumgr *smumgr); | 65 | int fiji_smum_init(struct pp_smumgr *smumgr); |