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