Commit | Line | Data |
---|---|---|
f83a9991 EH |
1 | /* |
2 | * Copyright 2016 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 "smumgr.h" | |
25 | #include "vega10_inc.h" | |
26 | #include "pp_soc15.h" | |
27 | #include "vega10_smumgr.h" | |
28 | #include "vega10_ppsmc.h" | |
29 | #include "smu9_driver_if.h" | |
30 | ||
31 | #include "ppatomctrl.h" | |
32 | #include "pp_debug.h" | |
33 | #include "smu_ucode_xfer_vi.h" | |
34 | #include "smu7_smumgr.h" | |
35 | ||
36 | #define AVFS_EN_MSB 1568 | |
37 | #define AVFS_EN_LSB 1568 | |
38 | ||
39 | #define VOLTAGE_SCALE 4 | |
40 | ||
41 | /* Microcode file is stored in this buffer */ | |
42 | #define BUFFER_SIZE 80000 | |
43 | #define MAX_STRING_SIZE 15 | |
44 | #define BUFFER_SIZETWO 131072 /* 128 *1024 */ | |
45 | ||
46 | /* MP Apertures */ | |
47 | #define MP0_Public 0x03800000 | |
48 | #define MP0_SRAM 0x03900000 | |
49 | #define MP1_Public 0x03b00000 | |
50 | #define MP1_SRAM 0x03c00004 | |
51 | ||
52 | #define smnMP1_FIRMWARE_FLAGS 0x3010028 | |
53 | #define smnMP0_FW_INTF 0x3010104 | |
54 | #define smnMP1_PUB_CTRL 0x3010b14 | |
55 | ||
d3f8c0ab | 56 | static bool vega10_is_smc_ram_running(struct pp_hwmgr *hwmgr) |
f83a9991 EH |
57 | { |
58 | uint32_t mp1_fw_flags, reg; | |
59 | ||
60 | reg = soc15_get_register_offset(NBIF_HWID, 0, | |
61 | mmPCIE_INDEX2_BASE_IDX, mmPCIE_INDEX2); | |
62 | ||
d3f8c0ab | 63 | cgs_write_register(hwmgr->device, reg, |
f83a9991 EH |
64 | (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); |
65 | ||
66 | reg = soc15_get_register_offset(NBIF_HWID, 0, | |
67 | mmPCIE_DATA2_BASE_IDX, mmPCIE_DATA2); | |
68 | ||
d3f8c0ab | 69 | mp1_fw_flags = cgs_read_register(hwmgr->device, reg); |
f83a9991 EH |
70 | |
71 | if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) | |
72 | return true; | |
73 | ||
74 | return false; | |
75 | } | |
76 | ||
b4a33e32 RZ |
77 | /* |
78 | * Check if SMC has responded to previous message. | |
79 | * | |
80 | * @param smumgr the address of the powerplay hardware manager. | |
81 | * @return TRUE SMC has responded, FALSE otherwise. | |
82 | */ | |
d3f8c0ab | 83 | static uint32_t vega10_wait_for_response(struct pp_hwmgr *hwmgr) |
f83a9991 EH |
84 | { |
85 | uint32_t reg; | |
86 | ||
d3f8c0ab | 87 | if (!vega10_is_smc_ram_running(hwmgr)) |
ef181f26 | 88 | return -EINVAL; |
f83a9991 EH |
89 | |
90 | reg = soc15_get_register_offset(MP1_HWID, 0, | |
91 | mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); | |
92 | ||
d92cb162 | 93 | phm_wait_for_register_unequal(hwmgr, reg, |
f83a9991 EH |
94 | 0, MP1_C2PMSG_90__CONTENT_MASK); |
95 | ||
d3f8c0ab | 96 | return cgs_read_register(hwmgr->device, reg); |
f83a9991 EH |
97 | } |
98 | ||
b4a33e32 RZ |
99 | /* |
100 | * Send a message to the SMC, and do not wait for its response. | |
101 | * @param smumgr the address of the powerplay hardware manager. | |
102 | * @param msg the message to send. | |
103 | * @return Always return 0. | |
104 | */ | |
d3f8c0ab | 105 | int vega10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, |
f83a9991 EH |
106 | uint16_t msg) |
107 | { | |
108 | uint32_t reg; | |
109 | ||
d3f8c0ab | 110 | if (!vega10_is_smc_ram_running(hwmgr)) |
ef181f26 | 111 | return -EINVAL; |
f83a9991 EH |
112 | |
113 | reg = soc15_get_register_offset(MP1_HWID, 0, | |
114 | mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); | |
d3f8c0ab | 115 | cgs_write_register(hwmgr->device, reg, msg); |
f83a9991 EH |
116 | |
117 | return 0; | |
118 | } | |
119 | ||
b4a33e32 RZ |
120 | /* |
121 | * Send a message to the SMC, and wait for its response. | |
d3f8c0ab | 122 | * @param hwmgr the address of the powerplay hardware manager. |
b4a33e32 RZ |
123 | * @param msg the message to send. |
124 | * @return Always return 0. | |
125 | */ | |
d3f8c0ab | 126 | int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) |
f83a9991 EH |
127 | { |
128 | uint32_t reg; | |
129 | ||
d3f8c0ab | 130 | if (!vega10_is_smc_ram_running(hwmgr)) |
ef181f26 | 131 | return -EINVAL; |
f83a9991 | 132 | |
d3f8c0ab | 133 | vega10_wait_for_response(hwmgr); |
f83a9991 EH |
134 | |
135 | reg = soc15_get_register_offset(MP1_HWID, 0, | |
136 | mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); | |
d3f8c0ab | 137 | cgs_write_register(hwmgr->device, reg, 0); |
f83a9991 | 138 | |
d3f8c0ab | 139 | vega10_send_msg_to_smc_without_waiting(hwmgr, msg); |
f83a9991 | 140 | |
d3f8c0ab | 141 | if (vega10_wait_for_response(hwmgr) != 1) |
b4a33e32 | 142 | pr_err("Failed to send message: 0x%x\n", msg); |
f83a9991 EH |
143 | |
144 | return 0; | |
145 | } | |
146 | ||
b4a33e32 | 147 | /* |
f83a9991 | 148 | * Send a message to the SMC with parameter |
d3f8c0ab | 149 | * @param hwmgr: the address of the powerplay hardware manager. |
f83a9991 EH |
150 | * @param msg: the message to send. |
151 | * @param parameter: the parameter to send | |
b4a33e32 | 152 | * @return Always return 0. |
f83a9991 | 153 | */ |
d3f8c0ab | 154 | int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, |
f83a9991 EH |
155 | uint16_t msg, uint32_t parameter) |
156 | { | |
157 | uint32_t reg; | |
158 | ||
d3f8c0ab | 159 | if (!vega10_is_smc_ram_running(hwmgr)) |
ef181f26 | 160 | return -EINVAL; |
f83a9991 | 161 | |
d3f8c0ab | 162 | vega10_wait_for_response(hwmgr); |
f83a9991 EH |
163 | |
164 | reg = soc15_get_register_offset(MP1_HWID, 0, | |
165 | mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); | |
d3f8c0ab | 166 | cgs_write_register(hwmgr->device, reg, 0); |
f83a9991 EH |
167 | |
168 | reg = soc15_get_register_offset(MP1_HWID, 0, | |
169 | mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); | |
d3f8c0ab | 170 | cgs_write_register(hwmgr->device, reg, parameter); |
f83a9991 | 171 | |
d3f8c0ab | 172 | vega10_send_msg_to_smc_without_waiting(hwmgr, msg); |
f83a9991 | 173 | |
d3f8c0ab | 174 | if (vega10_wait_for_response(hwmgr) != 1) |
b4a33e32 | 175 | pr_err("Failed to send message: 0x%x\n", msg); |
f83a9991 EH |
176 | |
177 | return 0; | |
178 | } | |
179 | ||
180 | ||
b4a33e32 RZ |
181 | /* |
182 | * Send a message to the SMC with parameter, do not wait for response | |
d3f8c0ab | 183 | * @param hwmgr: the address of the powerplay hardware manager. |
b4a33e32 RZ |
184 | * @param msg: the message to send. |
185 | * @param parameter: the parameter to send | |
186 | * @return The response that came from the SMC. | |
187 | */ | |
f83a9991 | 188 | int vega10_send_msg_to_smc_with_parameter_without_waiting( |
d3f8c0ab | 189 | struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter) |
f83a9991 EH |
190 | { |
191 | uint32_t reg; | |
192 | ||
193 | reg = soc15_get_register_offset(MP1_HWID, 0, | |
194 | mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); | |
d3f8c0ab | 195 | cgs_write_register(hwmgr->device, reg, parameter); |
f83a9991 | 196 | |
d3f8c0ab | 197 | return vega10_send_msg_to_smc_without_waiting(hwmgr, msg); |
f83a9991 EH |
198 | } |
199 | ||
b4a33e32 RZ |
200 | /* |
201 | * Retrieve an argument from SMC. | |
d3f8c0ab | 202 | * @param hwmgr the address of the powerplay hardware manager. |
b4a33e32 RZ |
203 | * @param arg pointer to store the argument from SMC. |
204 | * @return Always return 0. | |
205 | */ | |
d3f8c0ab | 206 | int vega10_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg) |
f83a9991 EH |
207 | { |
208 | uint32_t reg; | |
209 | ||
210 | reg = soc15_get_register_offset(MP1_HWID, 0, | |
211 | mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); | |
212 | ||
d3f8c0ab | 213 | *arg = cgs_read_register(hwmgr->device, reg); |
f83a9991 EH |
214 | |
215 | return 0; | |
216 | } | |
217 | ||
b4a33e32 RZ |
218 | /* |
219 | * Copy table from SMC into driver FB | |
d3f8c0ab | 220 | * @param hwmgr the address of the HW manager |
b4a33e32 RZ |
221 | * @param table_id the driver's table ID to copy from |
222 | */ | |
d3f8c0ab | 223 | int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, |
f83a9991 EH |
224 | uint8_t *table, int16_t table_id) |
225 | { | |
226 | struct vega10_smumgr *priv = | |
b3b03052 | 227 | (struct vega10_smumgr *)(hwmgr->smu_backend); |
f83a9991 EH |
228 | |
229 | PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, | |
ef181f26 | 230 | "Invalid SMU Table ID!", return -EINVAL); |
f83a9991 | 231 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, |
ef181f26 | 232 | "Invalid SMU Table version!", return -EINVAL); |
f83a9991 | 233 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, |
ef181f26 | 234 | "Invalid SMU Table Length!", return -EINVAL); |
d3f8c0ab | 235 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
236 | PPSMC_MSG_SetDriverDramAddrHigh, |
237 | priv->smu_tables.entry[table_id].table_addr_high) == 0, | |
ef181f26 | 238 | "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL); |
d3f8c0ab | 239 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
240 | PPSMC_MSG_SetDriverDramAddrLow, |
241 | priv->smu_tables.entry[table_id].table_addr_low) == 0, | |
242 | "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!", | |
ef181f26 | 243 | return -EINVAL); |
d3f8c0ab | 244 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
245 | PPSMC_MSG_TransferTableSmu2Dram, |
246 | priv->smu_tables.entry[table_id].table_id) == 0, | |
247 | "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", | |
ef181f26 | 248 | return -EINVAL); |
f83a9991 EH |
249 | |
250 | memcpy(table, priv->smu_tables.entry[table_id].table, | |
251 | priv->smu_tables.entry[table_id].size); | |
252 | ||
253 | return 0; | |
254 | } | |
255 | ||
b4a33e32 RZ |
256 | /* |
257 | * Copy table from Driver FB into SMC | |
d3f8c0ab | 258 | * @param hwmgr the address of the HW manager |
b4a33e32 RZ |
259 | * @param table_id the table to copy from |
260 | */ | |
d3f8c0ab | 261 | int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, |
f83a9991 EH |
262 | uint8_t *table, int16_t table_id) |
263 | { | |
264 | struct vega10_smumgr *priv = | |
b3b03052 | 265 | (struct vega10_smumgr *)(hwmgr->smu_backend); |
f83a9991 EH |
266 | |
267 | PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, | |
ef181f26 | 268 | "Invalid SMU Table ID!", return -EINVAL); |
f83a9991 | 269 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, |
ef181f26 | 270 | "Invalid SMU Table version!", return -EINVAL); |
f83a9991 | 271 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, |
ef181f26 | 272 | "Invalid SMU Table Length!", return -EINVAL); |
f83a9991 EH |
273 | |
274 | memcpy(priv->smu_tables.entry[table_id].table, table, | |
275 | priv->smu_tables.entry[table_id].size); | |
276 | ||
d3f8c0ab | 277 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
278 | PPSMC_MSG_SetDriverDramAddrHigh, |
279 | priv->smu_tables.entry[table_id].table_addr_high) == 0, | |
280 | "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!", | |
ef181f26 | 281 | return -EINVAL;); |
d3f8c0ab | 282 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
283 | PPSMC_MSG_SetDriverDramAddrLow, |
284 | priv->smu_tables.entry[table_id].table_addr_low) == 0, | |
285 | "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!", | |
ef181f26 | 286 | return -EINVAL); |
d3f8c0ab | 287 | PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
288 | PPSMC_MSG_TransferTableDram2Smu, |
289 | priv->smu_tables.entry[table_id].table_id) == 0, | |
290 | "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!", | |
ef181f26 | 291 | return -EINVAL); |
f83a9991 EH |
292 | |
293 | return 0; | |
294 | } | |
295 | ||
d3f8c0ab | 296 | int vega10_save_vft_table(struct pp_hwmgr *hwmgr, uint8_t *avfs_table) |
f83a9991 EH |
297 | { |
298 | PP_ASSERT_WITH_CODE(avfs_table, | |
299 | "No access to SMC AVFS Table", | |
ef181f26 | 300 | return -EINVAL); |
f83a9991 | 301 | |
d3f8c0ab | 302 | return vega10_copy_table_from_smc(hwmgr, avfs_table, AVFSTABLE); |
f83a9991 EH |
303 | } |
304 | ||
d3f8c0ab | 305 | int vega10_restore_vft_table(struct pp_hwmgr *hwmgr, uint8_t *avfs_table) |
f83a9991 EH |
306 | { |
307 | PP_ASSERT_WITH_CODE(avfs_table, | |
308 | "No access to SMC AVFS Table", | |
ef181f26 | 309 | return -EINVAL); |
f83a9991 | 310 | |
d3f8c0ab | 311 | return vega10_copy_table_to_smc(hwmgr, avfs_table, AVFSTABLE); |
f83a9991 EH |
312 | } |
313 | ||
d3f8c0ab | 314 | int vega10_enable_smc_features(struct pp_hwmgr *hwmgr, |
f83a9991 EH |
315 | bool enable, uint32_t feature_mask) |
316 | { | |
317 | int msg = enable ? PPSMC_MSG_EnableSmuFeatures : | |
318 | PPSMC_MSG_DisableSmuFeatures; | |
319 | ||
d3f8c0ab | 320 | return vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
321 | msg, feature_mask); |
322 | } | |
323 | ||
d3f8c0ab | 324 | int vega10_get_smc_features(struct pp_hwmgr *hwmgr, |
f83a9991 EH |
325 | uint32_t *features_enabled) |
326 | { | |
ef181f26 RZ |
327 | if (features_enabled == NULL) |
328 | return -EINVAL; | |
329 | ||
d3f8c0ab | 330 | if (!vega10_send_msg_to_smc(hwmgr, |
f83a9991 | 331 | PPSMC_MSG_GetEnabledSmuFeatures)) { |
d3f8c0ab | 332 | vega10_read_arg_from_smc(hwmgr, features_enabled); |
ef181f26 | 333 | return 0; |
f83a9991 EH |
334 | } |
335 | ||
ef181f26 | 336 | return -EINVAL; |
f83a9991 EH |
337 | } |
338 | ||
d3f8c0ab | 339 | int vega10_set_tools_address(struct pp_hwmgr *hwmgr) |
f83a9991 EH |
340 | { |
341 | struct vega10_smumgr *priv = | |
b3b03052 | 342 | (struct vega10_smumgr *)(hwmgr->smu_backend); |
f83a9991 EH |
343 | |
344 | if (priv->smu_tables.entry[TOOLSTABLE].table_addr_high || | |
345 | priv->smu_tables.entry[TOOLSTABLE].table_addr_low) { | |
d3f8c0ab | 346 | if (!vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
347 | PPSMC_MSG_SetToolsDramAddrHigh, |
348 | priv->smu_tables.entry[TOOLSTABLE].table_addr_high)) | |
d3f8c0ab | 349 | vega10_send_msg_to_smc_with_parameter(hwmgr, |
f83a9991 EH |
350 | PPSMC_MSG_SetToolsDramAddrLow, |
351 | priv->smu_tables.entry[TOOLSTABLE].table_addr_low); | |
352 | } | |
353 | return 0; | |
354 | } | |
355 | ||
d3f8c0ab | 356 | static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) |
f83a9991 EH |
357 | { |
358 | uint32_t smc_driver_if_version; | |
a80c9294 EQ |
359 | struct cgs_system_info sys_info = {0}; |
360 | uint32_t dev_id; | |
361 | uint32_t rev_id; | |
f83a9991 | 362 | |
d3f8c0ab | 363 | PP_ASSERT_WITH_CODE(!vega10_send_msg_to_smc(hwmgr, |
f83a9991 EH |
364 | PPSMC_MSG_GetDriverIfVersion), |
365 | "Attempt to get SMC IF Version Number Failed!", | |
ef181f26 | 366 | return -EINVAL); |
d3f8c0ab | 367 | vega10_read_arg_from_smc(hwmgr, &smc_driver_if_version); |
f83a9991 | 368 | |
a80c9294 EQ |
369 | sys_info.size = sizeof(struct cgs_system_info); |
370 | sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; | |
d3f8c0ab | 371 | cgs_query_system_info(hwmgr->device, &sys_info); |
a80c9294 EQ |
372 | dev_id = (uint32_t)sys_info.value; |
373 | ||
374 | sys_info.size = sizeof(struct cgs_system_info); | |
375 | sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV; | |
d3f8c0ab | 376 | cgs_query_system_info(hwmgr->device, &sys_info); |
a80c9294 EQ |
377 | rev_id = (uint32_t)sys_info.value; |
378 | ||
379 | if (!((dev_id == 0x687f) && | |
380 | ((rev_id == 0xc0) || | |
381 | (rev_id == 0xc1) || | |
382 | (rev_id == 0xc3)))) { | |
383 | if (smc_driver_if_version != SMU9_DRIVER_IF_VERSION) { | |
384 | pr_err("Your firmware(0x%x) doesn't match \ | |
385 | SMU9_DRIVER_IF_VERSION(0x%x). \ | |
386 | Please update your firmware!\n", | |
387 | smc_driver_if_version, SMU9_DRIVER_IF_VERSION); | |
388 | return -EINVAL; | |
389 | } | |
42f72d0b | 390 | } |
f83a9991 EH |
391 | |
392 | return 0; | |
393 | } | |
394 | ||
d3f8c0ab | 395 | static int vega10_smu_init(struct pp_hwmgr *hwmgr) |
f83a9991 EH |
396 | { |
397 | struct vega10_smumgr *priv; | |
398 | uint64_t mc_addr; | |
399 | void *kaddr = NULL; | |
400 | unsigned long handle, tools_size; | |
401 | int ret; | |
402 | struct cgs_firmware_info info = {0}; | |
403 | ||
d3f8c0ab | 404 | ret = cgs_get_firmware_info(hwmgr->device, |
f83a9991 EH |
405 | smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), |
406 | &info); | |
407 | if (ret || !info.kptr) | |
408 | return -EINVAL; | |
409 | ||
410 | priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL); | |
411 | ||
412 | if (!priv) | |
413 | return -ENOMEM; | |
414 | ||
b3b03052 | 415 | hwmgr->smu_backend = priv; |
f83a9991 EH |
416 | |
417 | /* allocate space for pptable */ | |
d3f8c0ab | 418 | smu_allocate_memory(hwmgr->device, |
f83a9991 EH |
419 | sizeof(PPTable_t), |
420 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
421 | PAGE_SIZE, | |
422 | &mc_addr, | |
423 | &kaddr, | |
424 | &handle); | |
425 | ||
426 | PP_ASSERT_WITH_CODE(kaddr, | |
427 | "[vega10_smu_init] Out of memory for pptable.", | |
b3b03052 | 428 | kfree(hwmgr->smu_backend); |
d3f8c0ab | 429 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 430 | (cgs_handle_t)handle); |
ef181f26 | 431 | return -EINVAL); |
f83a9991 EH |
432 | |
433 | priv->smu_tables.entry[PPTABLE].version = 0x01; | |
434 | priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t); | |
435 | priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE; | |
436 | priv->smu_tables.entry[PPTABLE].table_addr_high = | |
437 | smu_upper_32_bits(mc_addr); | |
438 | priv->smu_tables.entry[PPTABLE].table_addr_low = | |
439 | smu_lower_32_bits(mc_addr); | |
440 | priv->smu_tables.entry[PPTABLE].table = kaddr; | |
441 | priv->smu_tables.entry[PPTABLE].handle = handle; | |
442 | ||
443 | /* allocate space for watermarks table */ | |
d3f8c0ab | 444 | smu_allocate_memory(hwmgr->device, |
f83a9991 EH |
445 | sizeof(Watermarks_t), |
446 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
447 | PAGE_SIZE, | |
448 | &mc_addr, | |
449 | &kaddr, | |
450 | &handle); | |
451 | ||
452 | PP_ASSERT_WITH_CODE(kaddr, | |
453 | "[vega10_smu_init] Out of memory for wmtable.", | |
b3b03052 | 454 | kfree(hwmgr->smu_backend); |
d3f8c0ab | 455 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 456 | (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); |
d3f8c0ab | 457 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 458 | (cgs_handle_t)handle); |
ef181f26 | 459 | return -EINVAL); |
f83a9991 EH |
460 | |
461 | priv->smu_tables.entry[WMTABLE].version = 0x01; | |
462 | priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); | |
463 | priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; | |
464 | priv->smu_tables.entry[WMTABLE].table_addr_high = | |
465 | smu_upper_32_bits(mc_addr); | |
466 | priv->smu_tables.entry[WMTABLE].table_addr_low = | |
467 | smu_lower_32_bits(mc_addr); | |
468 | priv->smu_tables.entry[WMTABLE].table = kaddr; | |
469 | priv->smu_tables.entry[WMTABLE].handle = handle; | |
470 | ||
471 | /* allocate space for AVFS table */ | |
d3f8c0ab | 472 | smu_allocate_memory(hwmgr->device, |
f83a9991 EH |
473 | sizeof(AvfsTable_t), |
474 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
475 | PAGE_SIZE, | |
476 | &mc_addr, | |
477 | &kaddr, | |
478 | &handle); | |
479 | ||
480 | PP_ASSERT_WITH_CODE(kaddr, | |
481 | "[vega10_smu_init] Out of memory for avfs table.", | |
b3b03052 | 482 | kfree(hwmgr->smu_backend); |
d3f8c0ab | 483 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 484 | (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); |
d3f8c0ab | 485 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 486 | (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); |
d3f8c0ab | 487 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 488 | (cgs_handle_t)handle); |
ef181f26 | 489 | return -EINVAL); |
f83a9991 EH |
490 | |
491 | priv->smu_tables.entry[AVFSTABLE].version = 0x01; | |
492 | priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t); | |
493 | priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS; | |
494 | priv->smu_tables.entry[AVFSTABLE].table_addr_high = | |
495 | smu_upper_32_bits(mc_addr); | |
496 | priv->smu_tables.entry[AVFSTABLE].table_addr_low = | |
497 | smu_lower_32_bits(mc_addr); | |
498 | priv->smu_tables.entry[AVFSTABLE].table = kaddr; | |
499 | priv->smu_tables.entry[AVFSTABLE].handle = handle; | |
500 | ||
67131aa5 | 501 | tools_size = 0x19000; |
f83a9991 | 502 | if (tools_size) { |
d3f8c0ab | 503 | smu_allocate_memory(hwmgr->device, |
f83a9991 EH |
504 | tools_size, |
505 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
506 | PAGE_SIZE, | |
507 | &mc_addr, | |
508 | &kaddr, | |
509 | &handle); | |
510 | ||
511 | if (kaddr) { | |
512 | priv->smu_tables.entry[TOOLSTABLE].version = 0x01; | |
513 | priv->smu_tables.entry[TOOLSTABLE].size = tools_size; | |
514 | priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; | |
515 | priv->smu_tables.entry[TOOLSTABLE].table_addr_high = | |
516 | smu_upper_32_bits(mc_addr); | |
517 | priv->smu_tables.entry[TOOLSTABLE].table_addr_low = | |
518 | smu_lower_32_bits(mc_addr); | |
519 | priv->smu_tables.entry[TOOLSTABLE].table = kaddr; | |
520 | priv->smu_tables.entry[TOOLSTABLE].handle = handle; | |
521 | } | |
522 | } | |
523 | ||
d475ce62 | 524 | /* allocate space for AVFS Fuse table */ |
d3f8c0ab | 525 | smu_allocate_memory(hwmgr->device, |
d475ce62 RZ |
526 | sizeof(AvfsFuseOverride_t), |
527 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
528 | PAGE_SIZE, | |
529 | &mc_addr, | |
530 | &kaddr, | |
531 | &handle); | |
532 | ||
533 | PP_ASSERT_WITH_CODE(kaddr, | |
534 | "[vega10_smu_init] Out of memory for avfs fuse table.", | |
b3b03052 | 535 | kfree(hwmgr->smu_backend); |
d3f8c0ab | 536 | cgs_free_gpu_mem(hwmgr->device, |
d475ce62 | 537 | (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); |
d3f8c0ab | 538 | cgs_free_gpu_mem(hwmgr->device, |
d475ce62 | 539 | (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); |
d3f8c0ab | 540 | cgs_free_gpu_mem(hwmgr->device, |
d475ce62 | 541 | (cgs_handle_t)priv->smu_tables.entry[AVFSTABLE].handle); |
d3f8c0ab | 542 | cgs_free_gpu_mem(hwmgr->device, |
d475ce62 | 543 | (cgs_handle_t)priv->smu_tables.entry[TOOLSTABLE].handle); |
d3f8c0ab | 544 | cgs_free_gpu_mem(hwmgr->device, |
d475ce62 | 545 | (cgs_handle_t)handle); |
ef181f26 | 546 | return -EINVAL); |
d475ce62 RZ |
547 | |
548 | priv->smu_tables.entry[AVFSFUSETABLE].version = 0x01; | |
549 | priv->smu_tables.entry[AVFSFUSETABLE].size = sizeof(AvfsFuseOverride_t); | |
550 | priv->smu_tables.entry[AVFSFUSETABLE].table_id = TABLE_AVFS_FUSE_OVERRIDE; | |
551 | priv->smu_tables.entry[AVFSFUSETABLE].table_addr_high = | |
552 | smu_upper_32_bits(mc_addr); | |
553 | priv->smu_tables.entry[AVFSFUSETABLE].table_addr_low = | |
554 | smu_lower_32_bits(mc_addr); | |
555 | priv->smu_tables.entry[AVFSFUSETABLE].table = kaddr; | |
556 | priv->smu_tables.entry[AVFSFUSETABLE].handle = handle; | |
557 | ||
f83a9991 EH |
558 | return 0; |
559 | } | |
560 | ||
d3f8c0ab | 561 | static int vega10_smu_fini(struct pp_hwmgr *hwmgr) |
f83a9991 EH |
562 | { |
563 | struct vega10_smumgr *priv = | |
b3b03052 | 564 | (struct vega10_smumgr *)(hwmgr->smu_backend); |
f83a9991 EH |
565 | |
566 | if (priv) { | |
d3f8c0ab | 567 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 568 | (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); |
d3f8c0ab | 569 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 570 | (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); |
d3f8c0ab | 571 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 EH |
572 | (cgs_handle_t)priv->smu_tables.entry[AVFSTABLE].handle); |
573 | if (priv->smu_tables.entry[TOOLSTABLE].table) | |
d3f8c0ab | 574 | cgs_free_gpu_mem(hwmgr->device, |
f83a9991 | 575 | (cgs_handle_t)priv->smu_tables.entry[TOOLSTABLE].handle); |
d3f8c0ab | 576 | cgs_free_gpu_mem(hwmgr->device, |
d475ce62 | 577 | (cgs_handle_t)priv->smu_tables.entry[AVFSFUSETABLE].handle); |
b3b03052 RZ |
578 | kfree(hwmgr->smu_backend); |
579 | hwmgr->smu_backend = NULL; | |
f83a9991 EH |
580 | } |
581 | return 0; | |
582 | } | |
583 | ||
d3f8c0ab | 584 | static int vega10_start_smu(struct pp_hwmgr *hwmgr) |
f83a9991 | 585 | { |
d3f8c0ab | 586 | PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr), |
f83a9991 | 587 | "Failed to verify SMC interface!", |
ef181f26 | 588 | return -EINVAL); |
88eadc31 | 589 | |
d3f8c0ab | 590 | vega10_set_tools_address(hwmgr); |
88eadc31 | 591 | |
f83a9991 EH |
592 | return 0; |
593 | } | |
594 | ||
595 | const struct pp_smumgr_func vega10_smu_funcs = { | |
596 | .smu_init = &vega10_smu_init, | |
597 | .smu_fini = &vega10_smu_fini, | |
598 | .start_smu = &vega10_start_smu, | |
599 | .request_smu_load_specific_fw = NULL, | |
600 | .send_msg_to_smc = &vega10_send_msg_to_smc, | |
601 | .send_msg_to_smc_with_parameter = &vega10_send_msg_to_smc_with_parameter, | |
602 | .download_pptable_settings = NULL, | |
603 | .upload_pptable_settings = NULL, | |
604 | }; |