Commit | Line | Data |
---|---|---|
c8172625 | 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 "smu74.h" | |
26 | #include "smu_ucode_xfer_vi.h" | |
2cc0c0b5 | 27 | #include "polaris10_smumgr.h" |
c8172625 | 28 | #include "smu74_discrete.h" |
29 | #include "smu/smu_7_1_3_d.h" | |
30 | #include "smu/smu_7_1_3_sh_mask.h" | |
31 | #include "gmc/gmc_8_1_d.h" | |
32 | #include "gmc/gmc_8_1_sh_mask.h" | |
33 | #include "oss/oss_3_0_d.h" | |
34 | #include "gca/gfx_8_0_d.h" | |
35 | #include "bif/bif_5_0_d.h" | |
36 | #include "bif/bif_5_0_sh_mask.h" | |
2cc0c0b5 | 37 | #include "polaris10_pwrvirus.h" |
c8172625 | 38 | #include "ppatomctrl.h" |
39 | #include "pp_debug.h" | |
40 | #include "cgs_common.h" | |
41 | ||
2cc0c0b5 | 42 | #define POLARIS10_SMC_SIZE 0x20000 |
c8172625 | 43 | #define VOLTAGE_SCALE 4 |
44 | ||
45 | /* Microcode file is stored in this buffer */ | |
46 | #define BUFFER_SIZE 80000 | |
47 | #define MAX_STRING_SIZE 15 | |
48 | #define BUFFER_SIZETWO 131072 /* 128 *1024 */ | |
49 | ||
50 | #define SMC_RAM_END 0x40000 | |
51 | ||
909a0631 | 52 | static const SMU74_Discrete_GraphicsLevel avfs_graphics_level_polaris10[8] = { |
c8172625 | 53 | /* Min pcie DeepSleep Activity CgSpll CgSpll CcPwr CcPwr Sclk Enabled Enabled Voltage Power */ |
54 | /* Voltage, DpmLevel, DivId, Level, FuncCntl3, FuncCntl4, DynRm, DynRm1 Did, Padding,ForActivity, ForThrottle, UpHyst, DownHyst, DownHyst, Throttle */ | |
432c3a3c RZ |
55 | { 0x100ea446, 0x00, 0x03, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0x30750000, 0x3000, 0, 0x2600, 0, 0, 0x0004, 0x8f02, 0xffff, 0x2f00, 0x300e, 0x2700 } }, |
56 | { 0x400ea446, 0x01, 0x04, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0x409c0000, 0x2000, 0, 0x1e00, 1, 1, 0x0004, 0x8300, 0xffff, 0x1f00, 0xcb5e, 0x1a00 } }, | |
57 | { 0x740ea446, 0x01, 0x00, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0x50c30000, 0x2800, 0, 0x2000, 1, 1, 0x0004, 0x0c02, 0xffff, 0x2700, 0x6433, 0x2100 } }, | |
58 | { 0xa40ea446, 0x01, 0x00, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0x60ea0000, 0x3000, 0, 0x2600, 1, 1, 0x0004, 0x8f02, 0xffff, 0x2f00, 0x300e, 0x2700 } }, | |
59 | { 0xd80ea446, 0x01, 0x00, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0x70110100, 0x3800, 0, 0x2c00, 1, 1, 0x0004, 0x1203, 0xffff, 0x3600, 0xc9e2, 0x2e00 } }, | |
60 | { 0x3c0fa446, 0x01, 0x00, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0x80380100, 0x2000, 0, 0x1e00, 2, 1, 0x0004, 0x8300, 0xffff, 0x1f00, 0xcb5e, 0x1a00 } }, | |
61 | { 0x6c0fa446, 0x01, 0x00, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0x905f0100, 0x2400, 0, 0x1e00, 2, 1, 0x0004, 0x8901, 0xffff, 0x2300, 0x314c, 0x1d00 } }, | |
62 | { 0xa00fa446, 0x01, 0x00, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0xa0860100, 0x2800, 0, 0x2000, 2, 1, 0x0004, 0x0c02, 0xffff, 0x2700, 0x6433, 0x2100 } } | |
c8172625 | 63 | }; |
64 | ||
909a0631 | 65 | static const SMU74_Discrete_MemoryLevel avfs_memory_level_polaris10 = |
432c3a3c | 66 | {0x100ea446, 0, 0x30750000, 0x01, 0x01, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x1f00, 0x00, 0x00}; |
c8172625 | 67 | |
68 | /** | |
69 | * Set the address for reading/writing the SMC SRAM space. | |
70 | * @param smumgr the address of the powerplay hardware manager. | |
71 | * @param smcAddress the address in the SMC RAM to access. | |
72 | */ | |
2cc0c0b5 | 73 | static int polaris10_set_smc_sram_address(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t limit) |
c8172625 | 74 | { |
75 | PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)), "SMC address must be 4 byte aligned.", return -EINVAL); | |
76 | PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)), "SMC addr is beyond the SMC RAM area.", return -EINVAL); | |
77 | ||
78 | cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, smc_addr); | |
79 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0); | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | /** | |
85 | * Copy bytes from SMC RAM space into driver memory. | |
86 | * | |
87 | * @param smumgr the address of the powerplay SMU manager. | |
88 | * @param smc_start_address the start address in the SMC RAM to copy bytes from | |
89 | * @param src the byte array to copy the bytes to. | |
90 | * @param byte_count the number of bytes to copy. | |
91 | */ | |
2cc0c0b5 | 92 | int polaris10_copy_bytes_from_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address, uint32_t *dest, uint32_t byte_count, uint32_t limit) |
c8172625 | 93 | { |
94 | uint32_t data; | |
95 | uint32_t addr; | |
96 | uint8_t *dest_byte; | |
97 | uint8_t i, data_byte[4] = {0}; | |
98 | uint32_t *pdata = (uint32_t *)&data_byte; | |
99 | ||
100 | PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -1;); | |
101 | PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -1); | |
102 | ||
103 | addr = smc_start_address; | |
104 | ||
105 | while (byte_count >= 4) { | |
2cc0c0b5 | 106 | polaris10_read_smc_sram_dword(smumgr, addr, &data, limit); |
c8172625 | 107 | |
108 | *dest = PP_SMC_TO_HOST_UL(data); | |
109 | ||
110 | dest += 1; | |
111 | byte_count -= 4; | |
112 | addr += 4; | |
113 | } | |
114 | ||
115 | if (byte_count) { | |
2cc0c0b5 | 116 | polaris10_read_smc_sram_dword(smumgr, addr, &data, limit); |
c8172625 | 117 | *pdata = PP_SMC_TO_HOST_UL(data); |
118 | /* Cast dest into byte type in dest_byte. This way, we don't overflow if the allocated memory is not 4-byte aligned. */ | |
119 | dest_byte = (uint8_t *)dest; | |
120 | for (i = 0; i < byte_count; i++) | |
121 | dest_byte[i] = data_byte[i]; | |
122 | } | |
123 | ||
124 | return 0; | |
125 | } | |
126 | ||
127 | /** | |
128 | * Copy bytes from an array into the SMC RAM space. | |
129 | * | |
130 | * @param pSmuMgr the address of the powerplay SMU manager. | |
131 | * @param smc_start_address the start address in the SMC RAM to copy bytes to. | |
132 | * @param src the byte array to copy the bytes from. | |
133 | * @param byte_count the number of bytes to copy. | |
134 | */ | |
2cc0c0b5 | 135 | int polaris10_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address, |
c8172625 | 136 | const uint8_t *src, uint32_t byte_count, uint32_t limit) |
137 | { | |
138 | int result; | |
139 | uint32_t data = 0; | |
140 | uint32_t original_data; | |
141 | uint32_t addr = 0; | |
142 | uint32_t extra_shift; | |
143 | ||
144 | PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -1); | |
145 | PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -1); | |
146 | ||
147 | addr = smc_start_address; | |
148 | ||
149 | while (byte_count >= 4) { | |
150 | /* Bytes are written into the SMC addres space with the MSB first. */ | |
151 | data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3]; | |
152 | ||
2cc0c0b5 | 153 | result = polaris10_set_smc_sram_address(smumgr, addr, limit); |
c8172625 | 154 | |
155 | if (0 != result) | |
156 | return result; | |
157 | ||
158 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data); | |
159 | ||
160 | src += 4; | |
161 | byte_count -= 4; | |
162 | addr += 4; | |
163 | } | |
164 | ||
165 | if (0 != byte_count) { | |
166 | ||
167 | data = 0; | |
168 | ||
2cc0c0b5 | 169 | result = polaris10_set_smc_sram_address(smumgr, addr, limit); |
c8172625 | 170 | |
171 | if (0 != result) | |
172 | return result; | |
173 | ||
174 | ||
175 | original_data = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11); | |
176 | ||
177 | extra_shift = 8 * (4 - byte_count); | |
178 | ||
179 | while (byte_count > 0) { | |
180 | /* Bytes are written into the SMC addres space with the MSB first. */ | |
181 | data = (0x100 * data) + *src++; | |
182 | byte_count--; | |
183 | } | |
184 | ||
185 | data <<= extra_shift; | |
186 | ||
187 | data |= (original_data & ~((~0UL) << extra_shift)); | |
188 | ||
2cc0c0b5 | 189 | result = polaris10_set_smc_sram_address(smumgr, addr, limit); |
c8172625 | 190 | |
191 | if (0 != result) | |
192 | return result; | |
193 | ||
194 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data); | |
195 | } | |
196 | ||
197 | return 0; | |
198 | } | |
199 | ||
200 | ||
2cc0c0b5 | 201 | static int polaris10_program_jump_on_start(struct pp_smumgr *smumgr) |
c8172625 | 202 | { |
909a0631 | 203 | static const unsigned char data[4] = { 0xE0, 0x00, 0x80, 0x40 }; |
c8172625 | 204 | |
2cc0c0b5 | 205 | polaris10_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data)+1); |
c8172625 | 206 | |
207 | return 0; | |
208 | } | |
209 | ||
210 | /** | |
211 | * Return if the SMC is currently running. | |
212 | * | |
213 | * @param smumgr the address of the powerplay hardware manager. | |
214 | */ | |
2cc0c0b5 | 215 | bool polaris10_is_smc_ram_running(struct pp_smumgr *smumgr) |
c8172625 | 216 | { |
217 | return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable)) | |
218 | && (0x20100 <= cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMC_PC_C))); | |
219 | } | |
220 | ||
432c3a3c RZ |
221 | static bool polaris10_is_hw_avfs_present(struct pp_smumgr *smumgr) |
222 | { | |
223 | uint32_t efuse; | |
224 | ||
225 | efuse = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMU_EFUSE_0 + (49*4)); | |
226 | efuse &= 0x00000001; | |
227 | if (efuse) | |
228 | return true; | |
229 | ||
230 | return false; | |
231 | } | |
232 | ||
c8172625 | 233 | /** |
234 | * Send a message to the SMC, and wait for its response. | |
235 | * | |
236 | * @param smumgr the address of the powerplay hardware manager. | |
237 | * @param msg the message to send. | |
238 | * @return The response that came from the SMC. | |
239 | */ | |
2cc0c0b5 | 240 | int polaris10_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg) |
c8172625 | 241 | { |
432c3a3c RZ |
242 | int ret; |
243 | ||
2cc0c0b5 | 244 | if (!polaris10_is_smc_ram_running(smumgr)) |
c8172625 | 245 | return -1; |
246 | ||
432c3a3c | 247 | |
c8172625 | 248 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); |
249 | ||
432c3a3c | 250 | ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP); |
c8172625 | 251 | |
432c3a3c RZ |
252 | if (ret != 1) |
253 | printk("\n failed to send pre message %x ret is %d \n", msg, ret); | |
c8172625 | 254 | |
255 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); | |
256 | ||
257 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
258 | ||
432c3a3c RZ |
259 | ret = SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP); |
260 | ||
261 | if (ret != 1) | |
262 | printk("\n failed to send message %x ret is %d \n", msg, ret); | |
c8172625 | 263 | |
264 | return 0; | |
265 | } | |
266 | ||
267 | ||
268 | /** | |
269 | * Send a message to the SMC, and do not wait for its response. | |
270 | * | |
271 | * @param smumgr the address of the powerplay hardware manager. | |
272 | * @param msg the message to send. | |
273 | * @return Always return 0. | |
274 | */ | |
2cc0c0b5 | 275 | int polaris10_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, uint16_t msg) |
c8172625 | 276 | { |
277 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); | |
278 | ||
279 | return 0; | |
280 | } | |
281 | ||
282 | /** | |
283 | * Send a message to the SMC with parameter | |
284 | * | |
285 | * @param smumgr: the address of the powerplay hardware manager. | |
286 | * @param msg: the message to send. | |
287 | * @param parameter: the parameter to send | |
288 | * @return The response that came from the SMC. | |
289 | */ | |
2cc0c0b5 | 290 | int polaris10_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter) |
c8172625 | 291 | { |
2cc0c0b5 | 292 | if (!polaris10_is_smc_ram_running(smumgr)) { |
c8172625 | 293 | return -1; |
294 | } | |
295 | ||
296 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
297 | ||
298 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter); | |
299 | ||
2cc0c0b5 | 300 | return polaris10_send_msg_to_smc(smumgr, msg); |
c8172625 | 301 | } |
302 | ||
303 | ||
304 | /** | |
305 | * Send a message to the SMC with parameter, do not wait for response | |
306 | * | |
307 | * @param smumgr: the address of the powerplay hardware manager. | |
308 | * @param msg: the message to send. | |
309 | * @param parameter: the parameter to send | |
310 | * @return The response that came from the SMC. | |
311 | */ | |
2cc0c0b5 | 312 | int polaris10_send_msg_to_smc_with_parameter_without_waiting(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter) |
c8172625 | 313 | { |
314 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter); | |
315 | ||
2cc0c0b5 | 316 | return polaris10_send_msg_to_smc_without_waiting(smumgr, msg); |
c8172625 | 317 | } |
318 | ||
2cc0c0b5 | 319 | int polaris10_send_msg_to_smc_offset(struct pp_smumgr *smumgr) |
c8172625 | 320 | { |
321 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000); | |
322 | ||
323 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test); | |
324 | ||
325 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
326 | ||
327 | if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) | |
328 | printk("Failed to send Message.\n"); | |
329 | ||
330 | return 0; | |
331 | } | |
332 | ||
333 | /** | |
334 | * Wait until the SMC is doing nithing. Doing nothing means that the SMC is either turned off or it is sitting on the STOP instruction. | |
335 | * | |
336 | * @param smumgr the address of the powerplay hardware manager. | |
337 | * @param msg the message to send. | |
338 | * @return The response that came from the SMC. | |
339 | */ | |
2cc0c0b5 | 340 | int polaris10_wait_for_smc_inactive(struct pp_smumgr *smumgr) |
c8172625 | 341 | { |
342 | /* If the SMC is not even on it qualifies as inactive. */ | |
2cc0c0b5 | 343 | if (!polaris10_is_smc_ram_running(smumgr)) |
c8172625 | 344 | return -1; |
345 | ||
346 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, SMC_SYSCON_CLOCK_CNTL_0, cken, 0); | |
347 | return 0; | |
348 | } | |
349 | ||
350 | ||
351 | /** | |
352 | * Upload the SMC firmware to the SMC microcontroller. | |
353 | * | |
354 | * @param smumgr the address of the powerplay hardware manager. | |
355 | * @param pFirmware the data structure containing the various sections of the firmware. | |
356 | */ | |
2cc0c0b5 | 357 | static int polaris10_upload_smc_firmware_data(struct pp_smumgr *smumgr, uint32_t length, uint32_t *src, uint32_t limit) |
c8172625 | 358 | { |
359 | uint32_t byte_count = length; | |
360 | ||
361 | PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -1); | |
362 | ||
363 | cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, 0x20000); | |
364 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 1); | |
365 | ||
c8172625 | 366 | for (; byte_count >= 4; byte_count -= 4) |
367 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, *src++); | |
368 | ||
369 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0); | |
370 | ||
371 | PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be dividable by 4.", return -1); | |
372 | ||
373 | return 0; | |
374 | } | |
375 | ||
2cc0c0b5 | 376 | static enum cgs_ucode_id polaris10_convert_fw_type_to_cgs(uint32_t fw_type) |
c8172625 | 377 | { |
378 | enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; | |
379 | ||
380 | switch (fw_type) { | |
381 | case UCODE_ID_SMU: | |
382 | result = CGS_UCODE_ID_SMU; | |
383 | break; | |
e85c7d66 | 384 | case UCODE_ID_SMU_SK: |
385 | result = CGS_UCODE_ID_SMU_SK; | |
386 | break; | |
c8172625 | 387 | case UCODE_ID_SDMA0: |
388 | result = CGS_UCODE_ID_SDMA0; | |
389 | break; | |
390 | case UCODE_ID_SDMA1: | |
391 | result = CGS_UCODE_ID_SDMA1; | |
392 | break; | |
393 | case UCODE_ID_CP_CE: | |
394 | result = CGS_UCODE_ID_CP_CE; | |
395 | break; | |
396 | case UCODE_ID_CP_PFP: | |
397 | result = CGS_UCODE_ID_CP_PFP; | |
398 | break; | |
399 | case UCODE_ID_CP_ME: | |
400 | result = CGS_UCODE_ID_CP_ME; | |
401 | break; | |
402 | case UCODE_ID_CP_MEC: | |
403 | result = CGS_UCODE_ID_CP_MEC; | |
404 | break; | |
405 | case UCODE_ID_CP_MEC_JT1: | |
406 | result = CGS_UCODE_ID_CP_MEC_JT1; | |
407 | break; | |
408 | case UCODE_ID_CP_MEC_JT2: | |
409 | result = CGS_UCODE_ID_CP_MEC_JT2; | |
410 | break; | |
411 | case UCODE_ID_RLC_G: | |
412 | result = CGS_UCODE_ID_RLC_G; | |
413 | break; | |
414 | default: | |
415 | break; | |
416 | } | |
417 | ||
418 | return result; | |
419 | } | |
420 | ||
2cc0c0b5 | 421 | static int polaris10_upload_smu_firmware_image(struct pp_smumgr *smumgr) |
c8172625 | 422 | { |
423 | int result = 0; | |
2cc0c0b5 | 424 | struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); |
c8172625 | 425 | |
426 | struct cgs_firmware_info info = {0}; | |
427 | ||
e85c7d66 | 428 | if (smu_data->security_hard_key == 1) |
429 | cgs_get_firmware_info(smumgr->device, | |
2cc0c0b5 | 430 | polaris10_convert_fw_type_to_cgs(UCODE_ID_SMU), &info); |
e85c7d66 | 431 | else |
432 | cgs_get_firmware_info(smumgr->device, | |
2cc0c0b5 | 433 | polaris10_convert_fw_type_to_cgs(UCODE_ID_SMU_SK), &info); |
c8172625 | 434 | |
435 | /* TO DO cgs_init_samu_load_smu(smumgr->device, (uint32_t *)info.kptr, info.image_size, smu_data->post_initial_boot);*/ | |
2cc0c0b5 | 436 | result = polaris10_upload_smc_firmware_data(smumgr, info.image_size, (uint32_t *)info.kptr, POLARIS10_SMC_SIZE); |
c8172625 | 437 | |
438 | return result; | |
439 | } | |
440 | ||
441 | /** | |
442 | * Read a 32bit value from the SMC SRAM space. | |
443 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | |
444 | * @param smumgr the address of the powerplay hardware manager. | |
445 | * @param smcAddress the address in the SMC RAM to access. | |
446 | * @param value and output parameter for the data read from the SMC SRAM. | |
447 | */ | |
2cc0c0b5 | 448 | int polaris10_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t *value, uint32_t limit) |
c8172625 | 449 | { |
450 | int result; | |
451 | ||
2cc0c0b5 | 452 | result = polaris10_set_smc_sram_address(smumgr, smc_addr, limit); |
c8172625 | 453 | |
454 | if (result) | |
455 | return result; | |
456 | ||
457 | *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11); | |
458 | return 0; | |
459 | } | |
460 | ||
461 | /** | |
462 | * Write a 32bit value to the SMC SRAM space. | |
463 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | |
464 | * @param smumgr the address of the powerplay hardware manager. | |
465 | * @param smc_addr the address in the SMC RAM to access. | |
466 | * @param value to write to the SMC SRAM. | |
467 | */ | |
2cc0c0b5 | 468 | int polaris10_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t value, uint32_t limit) |
c8172625 | 469 | { |
470 | int result; | |
471 | ||
2cc0c0b5 | 472 | result = polaris10_set_smc_sram_address(smumgr, smc_addr, limit); |
c8172625 | 473 | |
474 | if (result) | |
475 | return result; | |
476 | ||
477 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, value); | |
478 | ||
479 | return 0; | |
480 | } | |
481 | ||
482 | ||
2cc0c0b5 | 483 | int polaris10_smu_fini(struct pp_smumgr *smumgr) |
c8172625 | 484 | { |
485 | if (smumgr->backend) { | |
486 | kfree(smumgr->backend); | |
487 | smumgr->backend = NULL; | |
488 | } | |
5bbc16cc | 489 | cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU); |
c8172625 | 490 | return 0; |
491 | } | |
492 | ||
493 | /* Convert the firmware type to SMU type mask. For MEC, we need to check all MEC related type */ | |
2cc0c0b5 | 494 | static uint32_t polaris10_get_mask_for_firmware_type(uint32_t fw_type) |
c8172625 | 495 | { |
496 | uint32_t result = 0; | |
497 | ||
498 | switch (fw_type) { | |
499 | case UCODE_ID_SDMA0: | |
500 | result = UCODE_ID_SDMA0_MASK; | |
501 | break; | |
502 | case UCODE_ID_SDMA1: | |
503 | result = UCODE_ID_SDMA1_MASK; | |
504 | break; | |
505 | case UCODE_ID_CP_CE: | |
506 | result = UCODE_ID_CP_CE_MASK; | |
507 | break; | |
508 | case UCODE_ID_CP_PFP: | |
509 | result = UCODE_ID_CP_PFP_MASK; | |
510 | break; | |
511 | case UCODE_ID_CP_ME: | |
512 | result = UCODE_ID_CP_ME_MASK; | |
513 | break; | |
514 | case UCODE_ID_CP_MEC_JT1: | |
515 | case UCODE_ID_CP_MEC_JT2: | |
516 | result = UCODE_ID_CP_MEC_MASK; | |
517 | break; | |
518 | case UCODE_ID_RLC_G: | |
519 | result = UCODE_ID_RLC_G_MASK; | |
520 | break; | |
521 | default: | |
522 | printk("UCode type is out of range! \n"); | |
523 | result = 0; | |
524 | } | |
525 | ||
526 | return result; | |
527 | } | |
528 | ||
529 | /* Populate one firmware image to the data structure */ | |
530 | ||
2cc0c0b5 | 531 | static int polaris10_populate_single_firmware_entry(struct pp_smumgr *smumgr, |
c8172625 | 532 | uint32_t fw_type, |
533 | struct SMU_Entry *entry) | |
534 | { | |
535 | int result = 0; | |
536 | struct cgs_firmware_info info = {0}; | |
537 | ||
538 | result = cgs_get_firmware_info(smumgr->device, | |
2cc0c0b5 | 539 | polaris10_convert_fw_type_to_cgs(fw_type), |
c8172625 | 540 | &info); |
541 | ||
542 | if (!result) { | |
543 | entry->version = info.version; | |
544 | entry->id = (uint16_t)fw_type; | |
545 | entry->image_addr_high = smu_upper_32_bits(info.mc_addr); | |
546 | entry->image_addr_low = smu_lower_32_bits(info.mc_addr); | |
547 | entry->meta_data_addr_high = 0; | |
548 | entry->meta_data_addr_low = 0; | |
549 | entry->data_size_byte = info.image_size; | |
550 | entry->num_register_entries = 0; | |
551 | } | |
552 | ||
553 | if (fw_type == UCODE_ID_RLC_G) | |
554 | entry->flags = 1; | |
555 | else | |
556 | entry->flags = 0; | |
557 | ||
558 | return 0; | |
559 | } | |
560 | ||
2cc0c0b5 | 561 | static int polaris10_request_smu_load_fw(struct pp_smumgr *smumgr) |
c8172625 | 562 | { |
2cc0c0b5 | 563 | struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); |
c8172625 | 564 | uint32_t fw_to_load; |
565 | ||
566 | int result = 0; | |
567 | struct SMU_DRAMData_TOC *toc; | |
568 | ||
569 | if (!smumgr->reload_fw) { | |
570 | printk(KERN_INFO "[ powerplay ] skip reloading...\n"); | |
571 | return 0; | |
572 | } | |
573 | ||
574 | if (smu_data->soft_regs_start) | |
575 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
576 | smu_data->soft_regs_start + offsetof(SMU74_SoftRegisters, UcodeLoadStatus), | |
577 | 0x0); | |
578 | ||
2cc0c0b5 FC |
579 | polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_HI, smu_data->smu_buffer.mc_addr_high); |
580 | polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_LO, smu_data->smu_buffer.mc_addr_low); | |
c8172625 | 581 | |
582 | toc = (struct SMU_DRAMData_TOC *)smu_data->header; | |
583 | toc->num_entries = 0; | |
584 | toc->structure_version = 1; | |
585 | ||
2cc0c0b5 FC |
586 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); |
587 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); | |
588 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); | |
589 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); | |
590 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); | |
591 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); | |
592 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); | |
593 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); | |
594 | PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1); | |
c8172625 | 595 | |
2cc0c0b5 FC |
596 | polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, smu_data->header_buffer.mc_addr_high); |
597 | polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, smu_data->header_buffer.mc_addr_low); | |
c8172625 | 598 | |
599 | fw_to_load = UCODE_ID_RLC_G_MASK | |
600 | + UCODE_ID_SDMA0_MASK | |
601 | + UCODE_ID_SDMA1_MASK | |
602 | + UCODE_ID_CP_CE_MASK | |
603 | + UCODE_ID_CP_ME_MASK | |
604 | + UCODE_ID_CP_PFP_MASK | |
605 | + UCODE_ID_CP_MEC_MASK; | |
606 | ||
2cc0c0b5 | 607 | if (polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_LoadUcodes, fw_to_load)) |
c8172625 | 608 | printk(KERN_ERR "Fail to Request SMU Load uCode"); |
609 | ||
610 | return result; | |
611 | } | |
612 | ||
613 | /* Check if the FW has been loaded, SMU will not return if loading has not finished. */ | |
2cc0c0b5 | 614 | static int polaris10_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fw_type) |
c8172625 | 615 | { |
2cc0c0b5 FC |
616 | struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); |
617 | uint32_t fw_mask = polaris10_get_mask_for_firmware_type(fw_type); | |
c8172625 | 618 | uint32_t ret; |
619 | /* Check SOFT_REGISTERS_TABLE_28.UcodeLoadStatus */ | |
620 | ret = smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX_11, | |
621 | smu_data->soft_regs_start + offsetof(SMU74_SoftRegisters, UcodeLoadStatus), | |
622 | fw_mask, fw_mask); | |
623 | ||
624 | return ret; | |
625 | } | |
626 | ||
2cc0c0b5 | 627 | static int polaris10_reload_firmware(struct pp_smumgr *smumgr) |
c8172625 | 628 | { |
629 | return smumgr->smumgr_funcs->start_smu(smumgr); | |
630 | } | |
631 | ||
2cc0c0b5 | 632 | static int polaris10_setup_pwr_virus(struct pp_smumgr *smumgr) |
c8172625 | 633 | { |
634 | int i; | |
635 | int result = -1; | |
636 | uint32_t reg, data; | |
637 | ||
909a0631 | 638 | const PWR_Command_Table *pvirus = pwr_virus_table; |
2cc0c0b5 | 639 | struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); |
c8172625 | 640 | |
641 | ||
642 | for (i = 0; i < PWR_VIRUS_TABLE_SIZE; i++) { | |
643 | switch (pvirus->command) { | |
644 | case PwrCmdWrite: | |
645 | reg = pvirus->reg; | |
646 | data = pvirus->data; | |
647 | cgs_write_register(smumgr->device, reg, data); | |
648 | break; | |
649 | ||
650 | case PwrCmdEnd: | |
651 | result = 0; | |
652 | break; | |
653 | ||
654 | default: | |
655 | printk("Table Exit with Invalid Command!"); | |
656 | smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL; | |
657 | result = -1; | |
658 | break; | |
659 | } | |
660 | pvirus++; | |
661 | } | |
662 | ||
663 | return result; | |
664 | } | |
665 | ||
2cc0c0b5 | 666 | static int polaris10_perform_btc(struct pp_smumgr *smumgr) |
c8172625 | 667 | { |
668 | int result = 0; | |
2cc0c0b5 | 669 | struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); |
c8172625 | 670 | |
671 | if (0 != smu_data->avfs.avfs_btc_param) { | |
2cc0c0b5 FC |
672 | if (0 != polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) { |
673 | printk("[AVFS][SmuPolaris10_PerformBtc] PerformBTC SMU msg failed"); | |
c8172625 | 674 | result = -1; |
675 | } | |
676 | } | |
677 | if (smu_data->avfs.avfs_btc_param > 1) { | |
678 | /* Soft-Reset to reset the engine before loading uCode */ | |
679 | /* halt */ | |
680 | cgs_write_register(smumgr->device, mmCP_MEC_CNTL, 0x50000000); | |
681 | /* reset everything */ | |
682 | cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0xffffffff); | |
683 | cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0); | |
684 | } | |
685 | return result; | |
686 | } | |
687 | ||
688 | ||
2cc0c0b5 | 689 | int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr) |
c8172625 | 690 | { |
691 | uint32_t vr_config; | |
692 | uint32_t dpm_table_start; | |
693 | ||
694 | uint16_t u16_boot_mvdd; | |
695 | uint32_t graphics_level_address, vr_config_address, graphics_level_size; | |
696 | ||
2cc0c0b5 | 697 | graphics_level_size = sizeof(avfs_graphics_level_polaris10); |
c8172625 | 698 | u16_boot_mvdd = PP_HOST_TO_SMC_US(1300 * VOLTAGE_SCALE); |
699 | ||
2cc0c0b5 | 700 | PP_ASSERT_WITH_CODE(0 == polaris10_read_smc_sram_dword(smumgr, |
c8172625 | 701 | SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, DpmTable), |
702 | &dpm_table_start, 0x40000), | |
2cc0c0b5 | 703 | "[AVFS][Polaris10_SetupGfxLvlStruct] SMU could not communicate starting address of DPM table", |
c8172625 | 704 | return -1); |
705 | ||
706 | /* Default value for VRConfig = VR_MERGED_WITH_VDDC + VR_STATIC_VOLTAGE(VDDCI) */ | |
707 | vr_config = 0x01000500; /* Real value:0x50001 */ | |
708 | ||
709 | vr_config_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, VRConfig); | |
710 | ||
2cc0c0b5 | 711 | PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, vr_config_address, |
c8172625 | 712 | (uint8_t *)&vr_config, sizeof(uint32_t), 0x40000), |
2cc0c0b5 | 713 | "[AVFS][Polaris10_SetupGfxLvlStruct] Problems copying VRConfig value over to SMC", |
c8172625 | 714 | return -1); |
715 | ||
716 | graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, GraphicsLevel); | |
717 | ||
2cc0c0b5 FC |
718 | PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address, |
719 | (uint8_t *)(&avfs_graphics_level_polaris10), | |
c8172625 | 720 | graphics_level_size, 0x40000), |
2cc0c0b5 | 721 | "[AVFS][Polaris10_SetupGfxLvlStruct] Copying of SCLK DPM table failed!", |
c8172625 | 722 | return -1); |
723 | ||
724 | graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, MemoryLevel); | |
725 | ||
2cc0c0b5 FC |
726 | PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address, |
727 | (uint8_t *)(&avfs_memory_level_polaris10), sizeof(avfs_memory_level_polaris10), 0x40000), | |
728 | "[AVFS][Polaris10_SetupGfxLvlStruct] Copying of MCLK DPM table failed!", | |
c8172625 | 729 | return -1); |
730 | ||
731 | /* MVDD Boot value - neccessary for getting rid of the hang that occurs during Mclk DPM enablement */ | |
732 | ||
733 | graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, BootMVdd); | |
734 | ||
2cc0c0b5 | 735 | PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address, |
c8172625 | 736 | (uint8_t *)(&u16_boot_mvdd), sizeof(u16_boot_mvdd), 0x40000), |
2cc0c0b5 | 737 | "[AVFS][Polaris10_SetupGfxLvlStruct] Copying of DPM table failed!", |
c8172625 | 738 | return -1); |
739 | ||
740 | return 0; | |
741 | } | |
742 | ||
2cc0c0b5 | 743 | int polaris10_avfs_event_mgr(struct pp_smumgr *smumgr, bool SMU_VFT_INTACT) |
c8172625 | 744 | { |
2cc0c0b5 | 745 | struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); |
c8172625 | 746 | |
747 | switch (smu_data->avfs.avfs_btc_status) { | |
748 | case AVFS_BTC_COMPLETED_PREVIOUSLY: | |
749 | break; | |
750 | ||
751 | case AVFS_BTC_BOOT: /* Cold Boot State - Post SMU Start */ | |
752 | ||
753 | smu_data->avfs.avfs_btc_status = AVFS_BTC_DPMTABLESETUP_FAILED; | |
2cc0c0b5 FC |
754 | PP_ASSERT_WITH_CODE(0 == polaris10_setup_graphics_level_structure(smumgr), |
755 | "[AVFS][Polaris10_AVFSEventMgr] Could not Copy Graphics Level table over to SMU", | |
c8172625 | 756 | return -1); |
757 | ||
758 | if (smu_data->avfs.avfs_btc_param > 1) { | |
2cc0c0b5 | 759 | printk("[AVFS][Polaris10_AVFSEventMgr] AC BTC has not been successfully verified on Fiji. There may be in this setting."); |
c8172625 | 760 | smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL; |
2cc0c0b5 FC |
761 | PP_ASSERT_WITH_CODE(-1 == polaris10_setup_pwr_virus(smumgr), |
762 | "[AVFS][Polaris10_AVFSEventMgr] Could not setup Pwr Virus for AVFS ", | |
c8172625 | 763 | return -1); |
764 | } | |
765 | ||
766 | smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED; | |
2cc0c0b5 FC |
767 | PP_ASSERT_WITH_CODE(0 == polaris10_perform_btc(smumgr), |
768 | "[AVFS][Polaris10_AVFSEventMgr] Failure at SmuPolaris10_PerformBTC. AVFS Disabled", | |
c8172625 | 769 | return -1); |
770 | ||
771 | break; | |
772 | ||
773 | case AVFS_BTC_DISABLED: | |
774 | case AVFS_BTC_NOTSUPPORTED: | |
775 | break; | |
776 | ||
777 | default: | |
778 | printk("[AVFS] Something is broken. See log!"); | |
779 | break; | |
780 | } | |
781 | ||
782 | return 0; | |
783 | } | |
784 | ||
2cc0c0b5 | 785 | static int polaris10_start_smu_in_protection_mode(struct pp_smumgr *smumgr) |
c8172625 | 786 | { |
787 | int result = 0; | |
788 | ||
789 | /* Wait for smc boot up */ | |
790 | /* SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, RCU_UC_EVENTS, boot_seq_done, 0) */ | |
791 | ||
792 | /* Assert reset */ | |
793 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
794 | SMC_SYSCON_RESET_CNTL, rst_reg, 1); | |
795 | ||
2cc0c0b5 | 796 | result = polaris10_upload_smu_firmware_image(smumgr); |
c8172625 | 797 | if (result != 0) |
798 | return result; | |
799 | ||
800 | /* Clear status */ | |
801 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMU_STATUS, 0); | |
802 | ||
803 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
804 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | |
805 | ||
806 | /* De-assert reset */ | |
807 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
808 | SMC_SYSCON_RESET_CNTL, rst_reg, 0); | |
809 | ||
810 | ||
811 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, RCU_UC_EVENTS, INTERRUPTS_ENABLED, 1); | |
812 | ||
813 | ||
814 | /* Call Test SMU message with 0x20000 offset to trigger SMU start */ | |
2cc0c0b5 | 815 | polaris10_send_msg_to_smc_offset(smumgr); |
c8172625 | 816 | |
817 | /* Wait done bit to be set */ | |
818 | /* Check pass/failed indicator */ | |
819 | ||
820 | SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, SMU_STATUS, SMU_DONE, 0); | |
821 | ||
822 | if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
823 | SMU_STATUS, SMU_PASS)) | |
824 | PP_ASSERT_WITH_CODE(false, "SMU Firmware start failed!", return -1); | |
825 | ||
c8172625 | 826 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, ixFIRMWARE_FLAGS, 0); |
827 | ||
828 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
829 | SMC_SYSCON_RESET_CNTL, rst_reg, 1); | |
830 | ||
c8172625 | 831 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, |
832 | SMC_SYSCON_RESET_CNTL, rst_reg, 0); | |
833 | ||
834 | /* Wait for firmware to initialize */ | |
835 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1); | |
836 | ||
837 | return result; | |
838 | } | |
839 | ||
2cc0c0b5 | 840 | static int polaris10_start_smu_in_non_protection_mode(struct pp_smumgr *smumgr) |
c8172625 | 841 | { |
842 | int result = 0; | |
843 | ||
844 | /* wait for smc boot up */ | |
845 | SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, RCU_UC_EVENTS, boot_seq_done, 0); | |
846 | ||
847 | /* Clear firmware interrupt enable flag */ | |
848 | /* SMUM_WRITE_VFPF_INDIRECT_FIELD(pSmuMgr, SMC_IND, SMC_SYSCON_MISC_CNTL, pre_fetcher_en, 1); */ | |
849 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
850 | ixFIRMWARE_FLAGS, 0); | |
851 | ||
852 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
853 | SMC_SYSCON_RESET_CNTL, | |
854 | rst_reg, 1); | |
855 | ||
2cc0c0b5 | 856 | result = polaris10_upload_smu_firmware_image(smumgr); |
c8172625 | 857 | if (result != 0) |
858 | return result; | |
859 | ||
860 | /* Set smc instruct start point at 0x0 */ | |
2cc0c0b5 | 861 | polaris10_program_jump_on_start(smumgr); |
c8172625 | 862 | |
863 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
864 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | |
865 | ||
866 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
867 | SMC_SYSCON_RESET_CNTL, rst_reg, 0); | |
868 | ||
869 | /* Wait for firmware to initialize */ | |
870 | ||
871 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, | |
872 | FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1); | |
873 | ||
874 | return result; | |
875 | } | |
876 | ||
2cc0c0b5 | 877 | static int polaris10_start_smu(struct pp_smumgr *smumgr) |
c8172625 | 878 | { |
879 | int result = 0; | |
2cc0c0b5 | 880 | struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend); |
c8172625 | 881 | bool SMU_VFT_INTACT; |
882 | ||
883 | /* Only start SMC if SMC RAM is not running */ | |
2cc0c0b5 | 884 | if (!polaris10_is_smc_ram_running(smumgr)) { |
c8172625 | 885 | SMU_VFT_INTACT = false; |
e85c7d66 | 886 | smu_data->protected_mode = (uint8_t) (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_MODE)); |
887 | smu_data->security_hard_key = (uint8_t) (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_SEL)); | |
888 | ||
c8172625 | 889 | /* Check if SMU is running in protected mode */ |
e85c7d66 | 890 | if (smu_data->protected_mode == 0) { |
2cc0c0b5 | 891 | result = polaris10_start_smu_in_non_protection_mode(smumgr); |
e85c7d66 | 892 | } else { |
2cc0c0b5 | 893 | result = polaris10_start_smu_in_protection_mode(smumgr); |
c8172625 | 894 | |
e85c7d66 | 895 | /* If failed, try with different security Key. */ |
896 | if (result != 0) { | |
897 | smu_data->security_hard_key ^= 1; | |
2cc0c0b5 | 898 | result = polaris10_start_smu_in_protection_mode(smumgr); |
e85c7d66 | 899 | } |
900 | } | |
901 | ||
c8172625 | 902 | if (result != 0) |
903 | PP_ASSERT_WITH_CODE(0, "Failed to load SMU ucode.", return result); | |
904 | ||
2cc0c0b5 | 905 | polaris10_avfs_event_mgr(smumgr, true); |
c8172625 | 906 | } else |
907 | SMU_VFT_INTACT = true; /*Driver went offline but SMU was still alive and contains the VFT table */ | |
908 | ||
909 | smu_data->post_initial_boot = true; | |
2cc0c0b5 | 910 | polaris10_avfs_event_mgr(smumgr, SMU_VFT_INTACT); |
c8172625 | 911 | /* Setup SoftRegsStart here for register lookup in case DummyBackEnd is used and ProcessFirmwareHeader is not executed */ |
2cc0c0b5 | 912 | polaris10_read_smc_sram_dword(smumgr, SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, SoftRegisters), |
c8172625 | 913 | &(smu_data->soft_regs_start), 0x40000); |
914 | ||
2cc0c0b5 | 915 | result = polaris10_request_smu_load_fw(smumgr); |
c8172625 | 916 | |
917 | return result; | |
918 | } | |
919 | ||
2cc0c0b5 | 920 | static int polaris10_smu_init(struct pp_smumgr *smumgr) |
c8172625 | 921 | { |
2cc0c0b5 | 922 | struct polaris10_smumgr *smu_data; |
c8172625 | 923 | uint8_t *internal_buf; |
924 | uint64_t mc_addr = 0; | |
925 | /* Allocate memory for backend private data */ | |
2cc0c0b5 | 926 | smu_data = (struct polaris10_smumgr *)(smumgr->backend); |
c8172625 | 927 | smu_data->header_buffer.data_size = |
928 | ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | |
929 | smu_data->smu_buffer.data_size = 200*4096; | |
930 | smu_data->avfs.avfs_btc_status = AVFS_BTC_NOTSUPPORTED; | |
931 | /* Allocate FW image data structure and header buffer and | |
932 | * send the header buffer address to SMU */ | |
933 | smu_allocate_memory(smumgr->device, | |
934 | smu_data->header_buffer.data_size, | |
935 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
936 | PAGE_SIZE, | |
937 | &mc_addr, | |
938 | &smu_data->header_buffer.kaddr, | |
939 | &smu_data->header_buffer.handle); | |
940 | ||
941 | smu_data->header = smu_data->header_buffer.kaddr; | |
942 | smu_data->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); | |
943 | smu_data->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); | |
944 | ||
945 | PP_ASSERT_WITH_CODE((NULL != smu_data->header), | |
946 | "Out of memory.", | |
947 | kfree(smumgr->backend); | |
948 | cgs_free_gpu_mem(smumgr->device, | |
949 | (cgs_handle_t)smu_data->header_buffer.handle); | |
950 | return -1); | |
951 | ||
952 | /* Allocate buffer for SMU internal buffer and send the address to SMU. | |
953 | * Iceland SMU does not need internal buffer.*/ | |
954 | smu_allocate_memory(smumgr->device, | |
955 | smu_data->smu_buffer.data_size, | |
956 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
957 | PAGE_SIZE, | |
958 | &mc_addr, | |
959 | &smu_data->smu_buffer.kaddr, | |
960 | &smu_data->smu_buffer.handle); | |
961 | ||
962 | internal_buf = smu_data->smu_buffer.kaddr; | |
963 | smu_data->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); | |
964 | smu_data->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); | |
965 | ||
966 | PP_ASSERT_WITH_CODE((NULL != internal_buf), | |
967 | "Out of memory.", | |
968 | kfree(smumgr->backend); | |
969 | cgs_free_gpu_mem(smumgr->device, | |
970 | (cgs_handle_t)smu_data->smu_buffer.handle); | |
971 | return -1;); | |
972 | ||
432c3a3c RZ |
973 | if (polaris10_is_hw_avfs_present(smumgr)) |
974 | smu_data->avfs.avfs_btc_status = AVFS_BTC_BOOT; | |
975 | else | |
976 | smu_data->avfs.avfs_btc_status = AVFS_BTC_NOTSUPPORTED; | |
977 | ||
c8172625 | 978 | return 0; |
979 | } | |
980 | ||
981 | static const struct pp_smumgr_func ellsemere_smu_funcs = { | |
2cc0c0b5 FC |
982 | .smu_init = polaris10_smu_init, |
983 | .smu_fini = polaris10_smu_fini, | |
984 | .start_smu = polaris10_start_smu, | |
985 | .check_fw_load_finish = polaris10_check_fw_load_finish, | |
986 | .request_smu_load_fw = polaris10_reload_firmware, | |
c8172625 | 987 | .request_smu_load_specific_fw = NULL, |
2cc0c0b5 FC |
988 | .send_msg_to_smc = polaris10_send_msg_to_smc, |
989 | .send_msg_to_smc_with_parameter = polaris10_send_msg_to_smc_with_parameter, | |
c8172625 | 990 | .download_pptable_settings = NULL, |
991 | .upload_pptable_settings = NULL, | |
992 | }; | |
993 | ||
2cc0c0b5 | 994 | int polaris10_smum_init(struct pp_smumgr *smumgr) |
c8172625 | 995 | { |
2cc0c0b5 | 996 | struct polaris10_smumgr *polaris10_smu = NULL; |
c8172625 | 997 | |
2cc0c0b5 | 998 | polaris10_smu = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL); |
c8172625 | 999 | |
2cc0c0b5 | 1000 | if (polaris10_smu == NULL) |
c8172625 | 1001 | return -1; |
1002 | ||
2cc0c0b5 | 1003 | smumgr->backend = polaris10_smu; |
c8172625 | 1004 | smumgr->smumgr_funcs = &ellsemere_smu_funcs; |
1005 | ||
1006 | return 0; | |
1007 | } |