Commit | Line | Data |
---|---|---|
74785623 EH |
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 "smumgr.h" | |
25 | #include "smu73.h" | |
26 | #include "smu_ucode_xfer_vi.h" | |
27 | #include "fiji_smumgr.h" | |
28 | #include "fiji_ppsmc.h" | |
29 | #include "smu73_discrete.h" | |
30 | #include "ppatomctrl.h" | |
31 | #include "smu/smu_7_1_3_d.h" | |
32 | #include "smu/smu_7_1_3_sh_mask.h" | |
33 | #include "gmc/gmc_8_1_d.h" | |
34 | #include "gmc/gmc_8_1_sh_mask.h" | |
35 | #include "oss/oss_3_0_d.h" | |
36 | #include "gca/gfx_8_0_d.h" | |
37 | #include "bif/bif_5_0_d.h" | |
38 | #include "bif/bif_5_0_sh_mask.h" | |
39 | #include "pp_debug.h" | |
40 | #include "fiji_pwrvirus.h" | |
41 | ||
42 | #define AVFS_EN_MSB 1568 | |
43 | #define AVFS_EN_LSB 1568 | |
44 | ||
45 | #define FIJI_SMC_SIZE 0x20000 | |
46 | ||
f498d9ed | 47 | static const struct SMU73_Discrete_GraphicsLevel avfs_graphics_level[8] = { |
74785623 EH |
48 | /* Min Sclk pcie DeepSleep Activity CgSpll CgSpll spllSpread SpllSpread CcPwr CcPwr Sclk Display Enabled Enabled Voltage Power */ |
49 | /* Voltage, Frequency, DpmLevel, DivId, Level, FuncCntl3, FuncCntl4, Spectrum, Spectrum2, DynRm, DynRm1 Did, Watermark, ForActivity, ForThrottle, UpHyst, DownHyst, DownHyst, Throttle */ | |
50 | { 0x3c0fd047, 0x30750000, 0x00, 0x03, 0x1e00, 0x00200410, 0x87020000, 0x21680000, 0x0c000000, 0, 0, 0x16, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, | |
51 | { 0xa00fd047, 0x409c0000, 0x01, 0x04, 0x1e00, 0x00800510, 0x87020000, 0x21680000, 0x11000000, 0, 0, 0x16, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, | |
52 | { 0x0410d047, 0x50c30000, 0x01, 0x00, 0x1e00, 0x00600410, 0x87020000, 0x21680000, 0x0d000000, 0, 0, 0x0e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, | |
53 | { 0x6810d047, 0x60ea0000, 0x01, 0x00, 0x1e00, 0x00800410, 0x87020000, 0x21680000, 0x0e000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, | |
54 | { 0xcc10d047, 0xe8fd0000, 0x01, 0x00, 0x1e00, 0x00e00410, 0x87020000, 0x21680000, 0x0f000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, | |
55 | { 0x3011d047, 0x70110100, 0x01, 0x00, 0x1e00, 0x00400510, 0x87020000, 0x21680000, 0x10000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, | |
56 | { 0x9411d047, 0xf8240100, 0x01, 0x00, 0x1e00, 0x00a00510, 0x87020000, 0x21680000, 0x11000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, | |
57 | { 0xf811d047, 0x80380100, 0x01, 0x00, 0x1e00, 0x00000610, 0x87020000, 0x21680000, 0x12000000, 0, 0, 0x0c, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 } | |
58 | }; | |
59 | ||
60 | static enum cgs_ucode_id fiji_convert_fw_type_to_cgs(uint32_t fw_type) | |
61 | { | |
62 | enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; | |
63 | ||
64 | switch (fw_type) { | |
65 | case UCODE_ID_SMU: | |
66 | result = CGS_UCODE_ID_SMU; | |
67 | break; | |
68 | case UCODE_ID_SDMA0: | |
69 | result = CGS_UCODE_ID_SDMA0; | |
70 | break; | |
71 | case UCODE_ID_SDMA1: | |
72 | result = CGS_UCODE_ID_SDMA1; | |
73 | break; | |
74 | case UCODE_ID_CP_CE: | |
75 | result = CGS_UCODE_ID_CP_CE; | |
76 | break; | |
77 | case UCODE_ID_CP_PFP: | |
78 | result = CGS_UCODE_ID_CP_PFP; | |
79 | break; | |
80 | case UCODE_ID_CP_ME: | |
81 | result = CGS_UCODE_ID_CP_ME; | |
82 | break; | |
83 | case UCODE_ID_CP_MEC: | |
84 | result = CGS_UCODE_ID_CP_MEC; | |
85 | break; | |
86 | case UCODE_ID_CP_MEC_JT1: | |
87 | result = CGS_UCODE_ID_CP_MEC_JT1; | |
88 | break; | |
89 | case UCODE_ID_CP_MEC_JT2: | |
90 | result = CGS_UCODE_ID_CP_MEC_JT2; | |
91 | break; | |
92 | case UCODE_ID_RLC_G: | |
93 | result = CGS_UCODE_ID_RLC_G; | |
94 | break; | |
95 | default: | |
96 | break; | |
97 | } | |
98 | ||
99 | return result; | |
100 | } | |
101 | /** | |
102 | * Set the address for reading/writing the SMC SRAM space. | |
103 | * @param smumgr the address of the powerplay hardware manager. | |
104 | * @param smc_addr the address in the SMC RAM to access. | |
105 | */ | |
106 | static int fiji_set_smc_sram_address(struct pp_smumgr *smumgr, | |
107 | uint32_t smc_addr, uint32_t limit) | |
108 | { | |
109 | PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)), | |
110 | "SMC address must be 4 byte aligned.", return -EINVAL;); | |
111 | PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)), | |
112 | "SMC address is beyond the SMC RAM area.", return -EINVAL;); | |
113 | ||
114 | cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smc_addr); | |
115 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | |
116 | ||
117 | return 0; | |
118 | } | |
119 | ||
120 | /** | |
121 | * Copy bytes from an array into the SMC RAM space. | |
122 | * | |
123 | * @param smumgr the address of the powerplay SMU manager. | |
124 | * @param smcStartAddress the start address in the SMC RAM to copy bytes to. | |
125 | * @param src the byte array to copy the bytes from. | |
126 | * @param byteCount the number of bytes to copy. | |
127 | */ | |
128 | int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr, | |
129 | uint32_t smcStartAddress, const uint8_t *src, | |
130 | uint32_t byteCount, uint32_t limit) | |
131 | { | |
132 | int result; | |
133 | uint32_t data, originalData; | |
134 | uint32_t addr, extraShift; | |
135 | ||
136 | PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)), | |
137 | "SMC address must be 4 byte aligned.", return -EINVAL;); | |
138 | PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)), | |
139 | "SMC address is beyond the SMC RAM area.", return -EINVAL;); | |
140 | ||
141 | addr = smcStartAddress; | |
142 | ||
143 | while (byteCount >= 4) { | |
144 | /* Bytes are written into the SMC addres space with the MSB first. */ | |
145 | data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3]; | |
146 | ||
147 | result = fiji_set_smc_sram_address(smumgr, addr, limit); | |
148 | if (result) | |
149 | return result; | |
150 | ||
151 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data); | |
152 | ||
153 | src += 4; | |
154 | byteCount -= 4; | |
155 | addr += 4; | |
156 | } | |
157 | ||
158 | if (byteCount) { | |
159 | /* Now write the odd bytes left. | |
160 | * Do a read modify write cycle. | |
161 | */ | |
162 | data = 0; | |
163 | ||
164 | result = fiji_set_smc_sram_address(smumgr, addr, limit); | |
165 | if (result) | |
166 | return result; | |
167 | ||
168 | originalData = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0); | |
169 | extraShift = 8 * (4 - byteCount); | |
170 | ||
171 | while (byteCount > 0) { | |
172 | /* Bytes are written into the SMC addres | |
173 | * space with the MSB first. | |
174 | */ | |
175 | data = (0x100 * data) + *src++; | |
176 | byteCount--; | |
177 | } | |
178 | data <<= extraShift; | |
179 | data |= (originalData & ~((~0UL) << extraShift)); | |
180 | ||
181 | result = fiji_set_smc_sram_address(smumgr, addr, limit); | |
182 | if (!result) | |
183 | return result; | |
184 | ||
185 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data); | |
186 | } | |
187 | return 0; | |
188 | } | |
189 | ||
190 | int fiji_program_jump_on_start(struct pp_smumgr *smumgr) | |
191 | { | |
f498d9ed | 192 | static const unsigned char data[] = { 0xE0, 0x00, 0x80, 0x40 }; |
74785623 EH |
193 | |
194 | fiji_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data) + 1); | |
195 | ||
196 | return 0; | |
197 | } | |
198 | ||
199 | /** | |
200 | * Return if the SMC is currently running. | |
201 | * | |
202 | * @param smumgr the address of the powerplay hardware manager. | |
203 | */ | |
204 | bool fiji_is_smc_ram_running(struct pp_smumgr *smumgr) | |
205 | { | |
206 | return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, | |
207 | CGS_IND_REG__SMC, | |
208 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable)) | |
209 | && (0x20100 <= cgs_read_ind_register(smumgr->device, | |
210 | CGS_IND_REG__SMC, ixSMC_PC_C))); | |
211 | } | |
212 | ||
213 | /** | |
214 | * Send a message to the SMC, and wait for its response. | |
215 | * | |
216 | * @param smumgr the address of the powerplay hardware manager. | |
217 | * @param msg the message to send. | |
218 | * @return The response that came from the SMC. | |
219 | */ | |
220 | int fiji_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg) | |
221 | { | |
222 | if (!fiji_is_smc_ram_running(smumgr)) | |
223 | return -1; | |
224 | ||
225 | if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) { | |
226 | printk(KERN_ERR "Failed to send Previous Message."); | |
227 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
228 | } | |
229 | ||
230 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); | |
75ac63db | 231 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); |
74785623 | 232 | |
75ac63db | 233 | return 0; |
74785623 EH |
234 | } |
235 | ||
236 | /** | |
237 | * Send a message to the SMC with parameter | |
238 | * @param smumgr: the address of the powerplay hardware manager. | |
239 | * @param msg: the message to send. | |
240 | * @param parameter: the parameter to send | |
241 | * @return The response that came from the SMC. | |
242 | */ | |
243 | int fiji_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, | |
244 | uint16_t msg, uint32_t parameter) | |
245 | { | |
246 | if (!fiji_is_smc_ram_running(smumgr)) | |
247 | return -1; | |
248 | ||
249 | if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) { | |
250 | printk(KERN_ERR "Failed to send Previous Message."); | |
251 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
252 | } | |
253 | ||
254 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter); | |
255 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); | |
256 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
257 | ||
258 | return 0; | |
259 | } | |
260 | ||
261 | ||
262 | /** | |
263 | * Send a message to the SMC with parameter, do not wait for response | |
264 | * | |
265 | * @param smumgr: the address of the powerplay hardware manager. | |
266 | * @param msg: the message to send. | |
267 | * @param parameter: the parameter to send | |
268 | * @return The response that came from the SMC. | |
269 | */ | |
270 | int fiji_send_msg_to_smc_with_parameter_without_waiting( | |
271 | struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter) | |
272 | { | |
273 | if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) { | |
274 | printk(KERN_ERR "Failed to send Previous Message."); | |
275 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
276 | } | |
277 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter); | |
278 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); | |
279 | ||
280 | return 0; | |
281 | } | |
282 | ||
283 | /** | |
284 | * Uploads the SMU firmware from .hex file | |
285 | * | |
286 | * @param smumgr the address of the powerplay SMU manager. | |
287 | * @return 0 or -1. | |
288 | */ | |
289 | ||
290 | static int fiji_upload_smu_firmware_image(struct pp_smumgr *smumgr) | |
291 | { | |
292 | const uint8_t *src; | |
293 | uint32_t byte_count; | |
294 | uint32_t *data; | |
295 | struct cgs_firmware_info info = {0}; | |
296 | ||
297 | cgs_get_firmware_info(smumgr->device, | |
298 | fiji_convert_fw_type_to_cgs(UCODE_ID_SMU), &info); | |
299 | ||
300 | if (info.image_size & 3) { | |
301 | printk(KERN_ERR "SMC ucode is not 4 bytes aligned\n"); | |
302 | return -EINVAL; | |
303 | } | |
304 | ||
305 | if (info.image_size > FIJI_SMC_SIZE) { | |
306 | printk(KERN_ERR "SMC address is beyond the SMC RAM area\n"); | |
307 | return -EINVAL; | |
308 | } | |
309 | ||
310 | cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000); | |
311 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1); | |
312 | ||
313 | byte_count = info.image_size; | |
314 | src = (const uint8_t *)info.kptr; | |
315 | ||
316 | data = (uint32_t *)src; | |
317 | for (; byte_count >= 4; data++, byte_count -= 4) | |
318 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]); | |
319 | ||
320 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | |
321 | return 0; | |
322 | } | |
323 | ||
324 | /** | |
325 | * Read a 32bit value from the SMC SRAM space. | |
326 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | |
327 | * @param smumgr the address of the powerplay hardware manager. | |
328 | * @param smc_addr the address in the SMC RAM to access. | |
329 | * @param value and output parameter for the data read from the SMC SRAM. | |
330 | */ | |
331 | int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, | |
332 | uint32_t *value, uint32_t limit) | |
333 | { | |
334 | int result = fiji_set_smc_sram_address(smumgr, smc_addr, limit); | |
335 | ||
336 | if (result) | |
337 | return result; | |
338 | ||
339 | *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0); | |
340 | return 0; | |
341 | } | |
342 | ||
343 | /** | |
344 | * Write a 32bit value to the SMC SRAM space. | |
345 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | |
346 | * @param smumgr the address of the powerplay hardware manager. | |
347 | * @param smc_addr the address in the SMC RAM to access. | |
348 | * @param value to write to the SMC SRAM. | |
349 | */ | |
350 | int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, | |
351 | uint32_t value, uint32_t limit) | |
352 | { | |
353 | int result; | |
354 | ||
355 | result = fiji_set_smc_sram_address(smumgr, smc_addr, limit); | |
356 | ||
357 | if (result) | |
358 | return result; | |
359 | ||
360 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value); | |
361 | return 0; | |
362 | } | |
363 | ||
364 | static uint32_t fiji_get_mask_for_firmware_type(uint32_t fw_type) | |
365 | { | |
366 | uint32_t result = 0; | |
367 | ||
368 | switch (fw_type) { | |
369 | case UCODE_ID_SDMA0: | |
370 | result = UCODE_ID_SDMA0_MASK; | |
371 | break; | |
372 | case UCODE_ID_SDMA1: | |
373 | result = UCODE_ID_SDMA1_MASK; | |
374 | break; | |
375 | case UCODE_ID_CP_CE: | |
376 | result = UCODE_ID_CP_CE_MASK; | |
377 | break; | |
378 | case UCODE_ID_CP_PFP: | |
379 | result = UCODE_ID_CP_PFP_MASK; | |
380 | break; | |
381 | case UCODE_ID_CP_ME: | |
382 | result = UCODE_ID_CP_ME_MASK; | |
383 | break; | |
384 | case UCODE_ID_CP_MEC_JT1: | |
385 | result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK; | |
386 | break; | |
387 | case UCODE_ID_CP_MEC_JT2: | |
388 | result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT2_MASK; | |
389 | break; | |
390 | case UCODE_ID_RLC_G: | |
391 | result = UCODE_ID_RLC_G_MASK; | |
392 | break; | |
393 | default: | |
394 | printk(KERN_ERR "UCode type is out of range!"); | |
395 | result = 0; | |
396 | } | |
397 | ||
398 | return result; | |
399 | } | |
400 | ||
401 | /* Populate one firmware image to the data structure */ | |
402 | static int fiji_populate_single_firmware_entry(struct pp_smumgr *smumgr, | |
403 | uint32_t fw_type, struct SMU_Entry *entry) | |
404 | { | |
405 | int result; | |
406 | struct cgs_firmware_info info = {0}; | |
407 | ||
408 | result = cgs_get_firmware_info( | |
409 | smumgr->device, | |
410 | fiji_convert_fw_type_to_cgs(fw_type), | |
411 | &info); | |
412 | ||
413 | if (!result) { | |
414 | entry->version = 0; | |
415 | entry->id = (uint16_t)fw_type; | |
416 | entry->image_addr_high = smu_upper_32_bits(info.mc_addr); | |
417 | entry->image_addr_low = smu_lower_32_bits(info.mc_addr); | |
418 | entry->meta_data_addr_high = 0; | |
419 | entry->meta_data_addr_low = 0; | |
420 | entry->data_size_byte = info.image_size; | |
421 | entry->num_register_entries = 0; | |
422 | ||
423 | if (fw_type == UCODE_ID_RLC_G) | |
424 | entry->flags = 1; | |
425 | else | |
426 | entry->flags = 0; | |
427 | } | |
428 | ||
429 | return result; | |
430 | } | |
431 | ||
432 | static int fiji_request_smu_load_fw(struct pp_smumgr *smumgr) | |
433 | { | |
434 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | |
435 | uint32_t fw_to_load; | |
436 | struct SMU_DRAMData_TOC *toc; | |
437 | ||
438 | if (priv->soft_regs_start) | |
439 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
440 | priv->soft_regs_start + | |
441 | offsetof(SMU73_SoftRegisters, UcodeLoadStatus), | |
442 | 0x0); | |
443 | ||
444 | toc = (struct SMU_DRAMData_TOC *)priv->header; | |
445 | toc->num_entries = 0; | |
446 | toc->structure_version = 1; | |
447 | ||
448 | PP_ASSERT_WITH_CODE( | |
449 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
450 | UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]), | |
451 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
452 | PP_ASSERT_WITH_CODE( | |
453 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
454 | UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]), | |
455 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
456 | PP_ASSERT_WITH_CODE( | |
457 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
458 | UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), | |
459 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
460 | PP_ASSERT_WITH_CODE( | |
461 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
462 | UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), | |
463 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
464 | PP_ASSERT_WITH_CODE( | |
465 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
466 | UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), | |
467 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
468 | PP_ASSERT_WITH_CODE( | |
469 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
470 | UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), | |
471 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
472 | PP_ASSERT_WITH_CODE( | |
473 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
474 | UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), | |
475 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
476 | PP_ASSERT_WITH_CODE( | |
477 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
478 | UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), | |
479 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
480 | PP_ASSERT_WITH_CODE( | |
481 | 0 == fiji_populate_single_firmware_entry(smumgr, | |
482 | UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), | |
483 | "Failed to Get Firmware Entry.\n" , return -1 ); | |
484 | ||
485 | fiji_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, | |
486 | priv->header_buffer.mc_addr_high); | |
487 | fiji_send_msg_to_smc_with_parameter(smumgr,PPSMC_MSG_DRV_DRAM_ADDR_LO, | |
488 | priv->header_buffer.mc_addr_low); | |
489 | ||
490 | fw_to_load = UCODE_ID_RLC_G_MASK | |
491 | + UCODE_ID_SDMA0_MASK | |
492 | + UCODE_ID_SDMA1_MASK | |
493 | + UCODE_ID_CP_CE_MASK | |
494 | + UCODE_ID_CP_ME_MASK | |
495 | + UCODE_ID_CP_PFP_MASK | |
496 | + UCODE_ID_CP_MEC_MASK | |
497 | + UCODE_ID_CP_MEC_JT1_MASK | |
498 | + UCODE_ID_CP_MEC_JT2_MASK; | |
499 | ||
500 | if (fiji_send_msg_to_smc_with_parameter(smumgr, | |
501 | PPSMC_MSG_LoadUcodes, fw_to_load)) | |
502 | printk(KERN_ERR "Fail to Request SMU Load uCode"); | |
503 | ||
504 | return 0; | |
505 | } | |
506 | ||
507 | ||
508 | /* Check if the FW has been loaded, SMU will not return | |
509 | * if loading has not finished. | |
510 | */ | |
511 | static int fiji_check_fw_load_finish(struct pp_smumgr *smumgr, | |
512 | uint32_t fw_type) | |
513 | { | |
514 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | |
515 | uint32_t mask = fiji_get_mask_for_firmware_type(fw_type); | |
516 | ||
517 | /* Check SOFT_REGISTERS_TABLE_28.UcodeLoadStatus */ | |
518 | if (smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX, | |
519 | priv->soft_regs_start + | |
520 | offsetof(SMU73_SoftRegisters, UcodeLoadStatus), | |
521 | mask, mask)) { | |
522 | printk(KERN_ERR "check firmware loading failed\n"); | |
523 | return -EINVAL; | |
524 | } | |
525 | return 0; | |
526 | } | |
527 | ||
528 | ||
529 | static int fiji_reload_firmware(struct pp_smumgr *smumgr) | |
530 | { | |
531 | return smumgr->smumgr_funcs->start_smu(smumgr); | |
532 | } | |
533 | ||
534 | static bool fiji_is_hw_virtualization_enabled(struct pp_smumgr *smumgr) | |
535 | { | |
536 | uint32_t value; | |
537 | ||
538 | value = cgs_read_register(smumgr->device, mmBIF_IOV_FUNC_IDENTIFIER); | |
539 | if (value & BIF_IOV_FUNC_IDENTIFIER__IOV_ENABLE_MASK) { | |
540 | /* driver reads on SR-IOV enabled PF: 0x80000000 | |
541 | * driver reads on SR-IOV enabled VF: 0x80000001 | |
542 | * driver reads on SR-IOV disabled: 0x00000000 | |
543 | */ | |
544 | return true; | |
545 | } | |
546 | return false; | |
547 | } | |
548 | ||
549 | static int fiji_request_smu_specific_fw_load(struct pp_smumgr *smumgr, uint32_t fw_type) | |
550 | { | |
551 | if (fiji_is_hw_virtualization_enabled(smumgr)) { | |
552 | uint32_t masks = fiji_get_mask_for_firmware_type(fw_type); | |
553 | if (fiji_send_msg_to_smc_with_parameter_without_waiting(smumgr, | |
554 | PPSMC_MSG_LoadUcodes, masks)) | |
555 | printk(KERN_ERR "Fail to Request SMU Load uCode"); | |
556 | } | |
557 | /* For non-virtualization cases, | |
558 | * SMU loads all FWs at once in fiji_request_smu_load_fw. | |
559 | */ | |
75ac63db | 560 | return 0; |
74785623 EH |
561 | } |
562 | ||
563 | static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr) | |
564 | { | |
565 | int result = 0; | |
566 | ||
567 | /* Wait for smc boot up */ | |
568 | /* SMUM_WAIT_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, | |
569 | RCU_UC_EVENTS, boot_seq_done, 0); */ | |
570 | ||
571 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
572 | SMC_SYSCON_RESET_CNTL, rst_reg, 1); | |
573 | ||
574 | result = fiji_upload_smu_firmware_image(smumgr); | |
575 | if (result) | |
576 | return result; | |
577 | ||
578 | /* Clear status */ | |
579 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
580 | ixSMU_STATUS, 0); | |
581 | ||
582 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
583 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | |
584 | ||
585 | /* De-assert reset */ | |
586 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
587 | SMC_SYSCON_RESET_CNTL, rst_reg, 0); | |
588 | ||
589 | /* Wait for ROM firmware to initialize interrupt hendler */ | |
590 | /*SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND, | |
591 | SMC_INTR_CNTL_MASK_0, 0x10040, 0xFFFFFFFF); */ | |
592 | ||
593 | /* Set SMU Auto Start */ | |
594 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
595 | SMU_INPUT_DATA, AUTO_START, 1); | |
596 | ||
597 | /* Clear firmware interrupt enable flag */ | |
598 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
599 | ixFIRMWARE_FLAGS, 0); | |
600 | ||
601 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, RCU_UC_EVENTS, | |
602 | INTERRUPTS_ENABLED, 1); | |
603 | ||
604 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000); | |
605 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test); | |
606 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
607 | ||
608 | /* Wait for done bit to be set */ | |
609 | SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, | |
610 | SMU_STATUS, SMU_DONE, 0); | |
611 | ||
612 | /* Check pass/failed indicator */ | |
613 | if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
614 | SMU_STATUS, SMU_PASS)) { | |
615 | PP_ASSERT_WITH_CODE(false, | |
616 | "SMU Firmware start failed!", return -1); | |
617 | } | |
618 | ||
619 | /* Wait for firmware to initialize */ | |
620 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, | |
621 | FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1); | |
622 | ||
623 | return result; | |
624 | } | |
625 | ||
626 | static int fiji_start_smu_in_non_protection_mode(struct pp_smumgr *smumgr) | |
627 | { | |
628 | int result = 0; | |
629 | ||
630 | /* wait for smc boot up */ | |
631 | SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, | |
632 | RCU_UC_EVENTS, boot_seq_done, 0); | |
633 | ||
634 | /* Clear firmware interrupt enable flag */ | |
635 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
636 | ixFIRMWARE_FLAGS, 0); | |
637 | ||
638 | /* Assert reset */ | |
639 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
640 | SMC_SYSCON_RESET_CNTL, rst_reg, 1); | |
641 | ||
642 | result = fiji_upload_smu_firmware_image(smumgr); | |
643 | if (result) | |
644 | return result; | |
645 | ||
646 | /* Set smc instruct start point at 0x0 */ | |
647 | fiji_program_jump_on_start(smumgr); | |
648 | ||
649 | /* Enable clock */ | |
650 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
651 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | |
652 | ||
653 | /* De-assert reset */ | |
654 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
655 | SMC_SYSCON_RESET_CNTL, rst_reg, 0); | |
656 | ||
657 | /* Wait for firmware to initialize */ | |
658 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, | |
659 | FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1); | |
660 | ||
661 | return result; | |
662 | } | |
663 | ||
664 | int fiji_setup_pwr_virus(struct pp_smumgr *smumgr) | |
665 | { | |
666 | int i, result = -1; | |
667 | uint32_t reg, data; | |
f498d9ed | 668 | const PWR_Command_Table *virus = PwrVirusTable; |
74785623 EH |
669 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); |
670 | ||
671 | priv->avfs.AvfsBtcStatus = AVFS_LOAD_VIRUS; | |
672 | for (i = 0; (i < PWR_VIRUS_TABLE_SIZE); i++) { | |
673 | switch (virus->command) { | |
674 | case PwrCmdWrite: | |
675 | reg = virus->reg; | |
676 | data = virus->data; | |
677 | cgs_write_register(smumgr->device, reg, data); | |
678 | break; | |
679 | case PwrCmdEnd: | |
680 | priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_LOADED; | |
681 | result = 0; | |
682 | break; | |
683 | default: | |
684 | printk(KERN_ERR "Table Exit with Invalid Command!"); | |
685 | priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_FAIL; | |
686 | result = -1; | |
687 | break; | |
688 | } | |
689 | virus++; | |
690 | } | |
691 | return result; | |
692 | } | |
693 | ||
694 | static int fiji_start_avfs_btc(struct pp_smumgr *smumgr) | |
695 | { | |
696 | int result = 0; | |
697 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | |
698 | ||
699 | priv->avfs.AvfsBtcStatus = AVFS_BTC_STARTED; | |
700 | if (priv->avfs.AvfsBtcParam) { | |
701 | if (!fiji_send_msg_to_smc_with_parameter(smumgr, | |
702 | PPSMC_MSG_PerformBtc, priv->avfs.AvfsBtcParam)) { | |
703 | if (!fiji_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs)) { | |
704 | priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_UNSAVED; | |
705 | result = 0; | |
706 | } else { | |
707 | printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] Attempt" | |
708 | " to Enable AVFS Failed!"); | |
709 | fiji_send_msg_to_smc(smumgr, PPSMC_MSG_DisableAvfs); | |
710 | result = -1; | |
711 | } | |
712 | } else { | |
713 | printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] " | |
714 | "PerformBTC SMU msg failed"); | |
715 | result = -1; | |
716 | } | |
717 | } | |
718 | /* Soft-Reset to reset the engine before loading uCode */ | |
719 | /* halt */ | |
720 | cgs_write_register(smumgr->device, mmCP_MEC_CNTL, 0x50000000); | |
721 | /* reset everything */ | |
722 | cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0xffffffff); | |
723 | /* clear reset */ | |
724 | cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0); | |
725 | ||
75ac63db | 726 | return result; |
74785623 EH |
727 | } |
728 | ||
729 | int fiji_setup_pm_fuse_for_avfs(struct pp_smumgr *smumgr) | |
730 | { | |
731 | int result = 0; | |
732 | uint32_t table_start; | |
733 | uint32_t charz_freq_addr, inversion_voltage_addr, charz_freq; | |
734 | uint16_t inversion_voltage; | |
735 | ||
736 | charz_freq = 0x30750000; /* In 10KHz units 0x00007530 Actual value */ | |
737 | inversion_voltage = 0x1A04; /* mV Q14.2 0x41A Actual value */ | |
738 | ||
739 | PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr, | |
740 | SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU73_Firmware_Header, | |
741 | PmFuseTable), &table_start, 0x40000), | |
742 | "[AVFS][Fiji_SetupGfxLvlStruct] SMU could not communicate " | |
743 | "starting address of PmFuse structure", | |
744 | return -1;); | |
745 | ||
746 | charz_freq_addr = table_start + | |
747 | offsetof(struct SMU73_Discrete_PmFuses, PsmCharzFreq); | |
748 | inversion_voltage_addr = table_start + | |
749 | offsetof(struct SMU73_Discrete_PmFuses, InversionVoltage); | |
750 | ||
751 | result = fiji_copy_bytes_to_smc(smumgr, charz_freq_addr, | |
752 | (uint8_t *)(&charz_freq), sizeof(charz_freq), 0x40000); | |
753 | PP_ASSERT_WITH_CODE(0 == result, | |
754 | "[AVFS][fiji_setup_pm_fuse_for_avfs] charz_freq could not " | |
755 | "be populated.", return -1;); | |
756 | ||
757 | result = fiji_copy_bytes_to_smc(smumgr, inversion_voltage_addr, | |
758 | (uint8_t *)(&inversion_voltage), sizeof(inversion_voltage), 0x40000); | |
759 | PP_ASSERT_WITH_CODE(0 == result, "[AVFS][fiji_setup_pm_fuse_for_avfs] " | |
760 | "charz_freq could not be populated.", return -1;); | |
761 | ||
762 | return result; | |
763 | } | |
764 | ||
765 | int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr) | |
766 | { | |
767 | int32_t vr_config; | |
768 | uint32_t table_start; | |
769 | uint32_t level_addr, vr_config_addr; | |
770 | uint32_t level_size = sizeof(avfs_graphics_level); | |
771 | ||
772 | PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr, | |
773 | SMU7_FIRMWARE_HEADER_LOCATION + | |
774 | offsetof(SMU73_Firmware_Header, DpmTable), | |
775 | &table_start, 0x40000), | |
776 | "[AVFS][Fiji_SetupGfxLvlStruct] SMU could not " | |
777 | "communicate starting address of DPM table", | |
778 | return -1;); | |
779 | ||
780 | /* Default value for vr_config = | |
781 | * VR_MERGED_WITH_VDDC + VR_STATIC_VOLTAGE(VDDCI) */ | |
782 | vr_config = 0x01000500; /* Real value:0x50001 */ | |
783 | ||
784 | vr_config_addr = table_start + | |
785 | offsetof(SMU73_Discrete_DpmTable, VRConfig); | |
786 | ||
787 | PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, vr_config_addr, | |
788 | (uint8_t *)&vr_config, sizeof(int32_t), 0x40000), | |
789 | "[AVFS][Fiji_SetupGfxLvlStruct] Problems copying " | |
790 | "vr_config value over to SMC", | |
791 | return -1;); | |
792 | ||
793 | level_addr = table_start + offsetof(SMU73_Discrete_DpmTable, GraphicsLevel); | |
794 | ||
795 | PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, level_addr, | |
796 | (uint8_t *)(&avfs_graphics_level), level_size, 0x40000), | |
797 | "[AVFS][Fiji_SetupGfxLvlStruct] Copying of DPM table failed!", | |
798 | return -1;); | |
799 | ||
800 | return 0; | |
801 | } | |
802 | ||
803 | /* Work in Progress */ | |
804 | int fiji_restore_vft_table(struct pp_smumgr *smumgr) | |
805 | { | |
806 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | |
807 | ||
808 | if (AVFS_BTC_COMPLETED_SAVED == priv->avfs.AvfsBtcStatus) { | |
809 | priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED; | |
810 | return 0; | |
811 | } else | |
812 | return -EINVAL; | |
813 | } | |
814 | ||
815 | /* Work in Progress */ | |
816 | int fiji_save_vft_table(struct pp_smumgr *smumgr) | |
817 | { | |
818 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | |
819 | ||
820 | if (AVFS_BTC_COMPLETED_SAVED == priv->avfs.AvfsBtcStatus) { | |
821 | priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED; | |
822 | return 0; | |
823 | } else | |
824 | return -EINVAL; | |
825 | } | |
826 | ||
827 | int fiji_avfs_event_mgr(struct pp_smumgr *smumgr, bool smu_started) | |
828 | { | |
829 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | |
830 | ||
831 | switch (priv->avfs.AvfsBtcStatus) { | |
832 | case AVFS_BTC_COMPLETED_SAVED: /*S3 State - Pre SMU Start */ | |
833 | priv->avfs.AvfsBtcStatus = AVFS_BTC_RESTOREVFT_FAILED; | |
834 | PP_ASSERT_WITH_CODE(0 == fiji_restore_vft_table(smumgr), | |
835 | "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics " | |
836 | "Level table over to SMU", | |
837 | return -1;); | |
838 | priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED; | |
839 | break; | |
840 | case AVFS_BTC_COMPLETED_RESTORED: /*S3 State - Post SMU Start*/ | |
841 | priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR; | |
842 | PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr, | |
843 | PPSMC_MSG_VftTableIsValid), | |
844 | "[AVFS][fiji_avfs_event_mgr] SMU did not respond " | |
845 | "correctly to VftTableIsValid Msg", | |
846 | return -1;); | |
847 | priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR; | |
848 | PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr, | |
849 | PPSMC_MSG_EnableAvfs), | |
850 | "[AVFS][fiji_avfs_event_mgr] SMU did not respond " | |
851 | "correctly to EnableAvfs Message Msg", | |
852 | return -1;); | |
853 | priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_SAVED; | |
854 | break; | |
855 | case AVFS_BTC_BOOT: /*Cold Boot State - Post SMU Start*/ | |
856 | if (!smu_started) | |
857 | break; | |
858 | priv->avfs.AvfsBtcStatus = AVFS_BTC_FAILED; | |
859 | PP_ASSERT_WITH_CODE(0 == fiji_setup_pm_fuse_for_avfs(smumgr), | |
860 | "[AVFS][fiji_avfs_event_mgr] Failure at " | |
861 | "fiji_setup_pm_fuse_for_avfs", | |
862 | return -1;); | |
863 | priv->avfs.AvfsBtcStatus = AVFS_BTC_DPMTABLESETUP_FAILED; | |
864 | PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(smumgr), | |
865 | "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level" | |
866 | " table over to SMU", | |
867 | return -1;); | |
868 | priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_FAIL; | |
869 | PP_ASSERT_WITH_CODE(0 == fiji_setup_pwr_virus(smumgr), | |
870 | "[AVFS][fiji_avfs_event_mgr] Could not setup " | |
871 | "Pwr Virus for AVFS ", | |
872 | return -1;); | |
873 | priv->avfs.AvfsBtcStatus = AVFS_BTC_FAILED; | |
874 | PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(smumgr), | |
875 | "[AVFS][fiji_avfs_event_mgr] Failure at " | |
876 | "fiji_start_avfs_btc. AVFS Disabled", | |
877 | return -1;); | |
878 | priv->avfs.AvfsBtcStatus = AVFS_BTC_SAVEVFT_FAILED; | |
879 | PP_ASSERT_WITH_CODE(0 == fiji_save_vft_table(smumgr), | |
880 | "[AVFS][fiji_avfs_event_mgr] Could not save VFT Table", | |
881 | return -1;); | |
882 | priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_SAVED; | |
883 | break; | |
884 | case AVFS_BTC_DISABLED: /* Do nothing */ | |
885 | break; | |
886 | case AVFS_BTC_NOTSUPPORTED: /* Do nothing */ | |
887 | break; | |
888 | default: | |
889 | printk(KERN_ERR "[AVFS] Something is broken. See log!"); | |
890 | break; | |
891 | } | |
892 | return 0; | |
893 | } | |
894 | ||
895 | static int fiji_start_smu(struct pp_smumgr *smumgr) | |
896 | { | |
897 | int result = 0; | |
898 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | |
899 | ||
900 | /* Only start SMC if SMC RAM is not running */ | |
901 | if (!fiji_is_smc_ram_running(smumgr)) { | |
902 | fiji_avfs_event_mgr(smumgr, false); | |
903 | ||
904 | /* Check if SMU is running in protected mode */ | |
905 | if (0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, | |
906 | CGS_IND_REG__SMC, | |
907 | SMU_FIRMWARE, SMU_MODE)) { | |
908 | result = fiji_start_smu_in_non_protection_mode(smumgr); | |
909 | if (result) | |
910 | return result; | |
911 | } else { | |
912 | result = fiji_start_smu_in_protection_mode(smumgr); | |
913 | if (result) | |
914 | return result; | |
915 | } | |
916 | fiji_avfs_event_mgr(smumgr, true); | |
917 | } | |
918 | ||
919 | /* To initialize all clock gating before RLC loaded and running.*/ | |
92b05d82 EH |
920 | cgs_set_clockgating_state(smumgr->device, |
921 | AMD_IP_BLOCK_TYPE_GFX, AMD_CG_STATE_GATE); | |
922 | cgs_set_clockgating_state(smumgr->device, | |
923 | AMD_IP_BLOCK_TYPE_GMC, AMD_CG_STATE_GATE); | |
924 | cgs_set_clockgating_state(smumgr->device, | |
925 | AMD_IP_BLOCK_TYPE_SDMA, AMD_CG_STATE_GATE); | |
926 | cgs_set_clockgating_state(smumgr->device, | |
927 | AMD_IP_BLOCK_TYPE_COMMON, AMD_CG_STATE_GATE); | |
74785623 EH |
928 | |
929 | /* Setup SoftRegsStart here for register lookup in case | |
930 | * DummyBackEnd is used and ProcessFirmwareHeader is not executed | |
931 | */ | |
932 | fiji_read_smc_sram_dword(smumgr, | |
933 | SMU7_FIRMWARE_HEADER_LOCATION + | |
934 | offsetof(SMU73_Firmware_Header, SoftRegisters), | |
935 | &(priv->soft_regs_start), 0x40000); | |
936 | ||
937 | result = fiji_request_smu_load_fw(smumgr); | |
938 | ||
939 | return result; | |
940 | } | |
941 | ||
942 | static bool fiji_is_hw_avfs_present(struct pp_smumgr *smumgr) | |
943 | { | |
944 | ||
945 | uint32_t efuse = 0; | |
946 | uint32_t mask = (1 << ((AVFS_EN_MSB - AVFS_EN_LSB) + 1)) - 1; | |
947 | ||
948 | if (!atomctrl_read_efuse(smumgr->device, AVFS_EN_LSB, AVFS_EN_MSB, | |
949 | mask, &efuse)) { | |
950 | if (efuse) | |
951 | return true; | |
952 | } | |
953 | return false; | |
954 | } | |
955 | ||
956 | /** | |
957 | * Write a 32bit value to the SMC SRAM space. | |
958 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | |
959 | * @param smumgr the address of the powerplay hardware manager. | |
960 | * @param smc_addr the address in the SMC RAM to access. | |
961 | * @param value to write to the SMC SRAM. | |
962 | */ | |
963 | static int fiji_smu_init(struct pp_smumgr *smumgr) | |
964 | { | |
965 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); | |
966 | uint64_t mc_addr; | |
967 | ||
968 | priv->header_buffer.data_size = | |
969 | ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | |
970 | smu_allocate_memory(smumgr->device, | |
971 | priv->header_buffer.data_size, | |
972 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
973 | PAGE_SIZE, | |
974 | &mc_addr, | |
975 | &priv->header_buffer.kaddr, | |
976 | &priv->header_buffer.handle); | |
977 | ||
978 | priv->header = priv->header_buffer.kaddr; | |
979 | priv->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); | |
980 | priv->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); | |
981 | ||
982 | PP_ASSERT_WITH_CODE((NULL != priv->header), | |
983 | "Out of memory.", | |
984 | kfree(smumgr->backend); | |
985 | cgs_free_gpu_mem(smumgr->device, | |
986 | (cgs_handle_t)priv->header_buffer.handle); | |
987 | return -1); | |
988 | ||
989 | priv->avfs.AvfsBtcStatus = AVFS_BTC_BOOT; | |
990 | if (fiji_is_hw_avfs_present(smumgr)) | |
991 | /* AVFS Parameter | |
992 | * 0 - BTC DC disabled, BTC AC disabled | |
993 | * 1 - BTC DC enabled, BTC AC disabled | |
994 | * 2 - BTC DC disabled, BTC AC enabled | |
995 | * 3 - BTC DC enabled, BTC AC enabled | |
996 | * Default is 0 - BTC DC disabled, BTC AC disabled | |
997 | */ | |
998 | priv->avfs.AvfsBtcParam = 0; | |
999 | else | |
1000 | priv->avfs.AvfsBtcStatus = AVFS_BTC_NOTSUPPORTED; | |
1001 | ||
1002 | priv->acpi_optimization = 1; | |
1003 | ||
1004 | return 0; | |
1005 | } | |
1006 | ||
1007 | static int fiji_smu_fini(struct pp_smumgr *smumgr) | |
1008 | { | |
e6232eff ML |
1009 | struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend); |
1010 | ||
1011 | smu_free_memory(smumgr->device, (void *)priv->header_buffer.handle); | |
1012 | ||
74785623 EH |
1013 | if (smumgr->backend) { |
1014 | kfree(smumgr->backend); | |
1015 | smumgr->backend = NULL; | |
1016 | } | |
5bbc16cc ML |
1017 | |
1018 | cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU); | |
74785623 EH |
1019 | return 0; |
1020 | } | |
1021 | ||
1022 | static const struct pp_smumgr_func fiji_smu_funcs = { | |
1023 | .smu_init = &fiji_smu_init, | |
1024 | .smu_fini = &fiji_smu_fini, | |
1025 | .start_smu = &fiji_start_smu, | |
1026 | .check_fw_load_finish = &fiji_check_fw_load_finish, | |
1027 | .request_smu_load_fw = &fiji_reload_firmware, | |
1028 | .request_smu_load_specific_fw = &fiji_request_smu_specific_fw_load, | |
1029 | .send_msg_to_smc = &fiji_send_msg_to_smc, | |
1030 | .send_msg_to_smc_with_parameter = &fiji_send_msg_to_smc_with_parameter, | |
1031 | .download_pptable_settings = NULL, | |
1032 | .upload_pptable_settings = NULL, | |
1033 | }; | |
1034 | ||
1035 | int fiji_smum_init(struct pp_smumgr *smumgr) | |
1036 | { | |
1037 | struct fiji_smumgr *fiji_smu = NULL; | |
1038 | ||
1039 | fiji_smu = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL); | |
1040 | ||
1041 | if (fiji_smu == NULL) | |
c15c8d70 | 1042 | return -ENOMEM; |
74785623 EH |
1043 | |
1044 | smumgr->backend = fiji_smu; | |
1045 | smumgr->smumgr_funcs = &fiji_smu_funcs; | |
1046 | ||
1047 | return 0; | |
1048 | } |