1*65332265Sriastradh /*	$NetBSD: amdgpu_smu8_smumgr.c,v 1.3 2021/12/19 12:21:30 riastradh Exp $	*/
21571a7a1Sriastradh 
31571a7a1Sriastradh /*
41571a7a1Sriastradh  * Copyright 2015 Advanced Micro Devices, Inc.
51571a7a1Sriastradh  *
61571a7a1Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
71571a7a1Sriastradh  * copy of this software and associated documentation files (the "Software"),
81571a7a1Sriastradh  * to deal in the Software without restriction, including without limitation
91571a7a1Sriastradh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
101571a7a1Sriastradh  * and/or sell copies of the Software, and to permit persons to whom the
111571a7a1Sriastradh  * Software is furnished to do so, subject to the following conditions:
121571a7a1Sriastradh  *
131571a7a1Sriastradh  * The above copyright notice and this permission notice shall be included in
141571a7a1Sriastradh  * all copies or substantial portions of the Software.
151571a7a1Sriastradh  *
161571a7a1Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171571a7a1Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181571a7a1Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
191571a7a1Sriastradh  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
201571a7a1Sriastradh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
211571a7a1Sriastradh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
221571a7a1Sriastradh  * OTHER DEALINGS IN THE SOFTWARE.
231571a7a1Sriastradh  *
241571a7a1Sriastradh  */
251571a7a1Sriastradh 
261571a7a1Sriastradh #include <sys/cdefs.h>
27*65332265Sriastradh __KERNEL_RCSID(0, "$NetBSD: amdgpu_smu8_smumgr.c,v 1.3 2021/12/19 12:21:30 riastradh Exp $");
281571a7a1Sriastradh 
291571a7a1Sriastradh #include <linux/delay.h>
301571a7a1Sriastradh #include <linux/gfp.h>
311571a7a1Sriastradh #include <linux/kernel.h>
321571a7a1Sriastradh #include <linux/ktime.h>
331571a7a1Sriastradh #include <linux/slab.h>
341571a7a1Sriastradh #include <linux/types.h>
351571a7a1Sriastradh 
361571a7a1Sriastradh #include "cgs_common.h"
371571a7a1Sriastradh #include "smu/smu_8_0_d.h"
381571a7a1Sriastradh #include "smu/smu_8_0_sh_mask.h"
391571a7a1Sriastradh #include "smu8.h"
401571a7a1Sriastradh #include "smu8_fusion.h"
411571a7a1Sriastradh #include "smu8_smumgr.h"
421571a7a1Sriastradh #include "cz_ppsmc.h"
431571a7a1Sriastradh #include "smu_ucode_xfer_cz.h"
441571a7a1Sriastradh #include "gca/gfx_8_0_d.h"
451571a7a1Sriastradh #include "gca/gfx_8_0_sh_mask.h"
461571a7a1Sriastradh #include "smumgr.h"
471571a7a1Sriastradh 
48*65332265Sriastradh #include <linux/nbsd-namespace.h>
49*65332265Sriastradh 
501571a7a1Sriastradh #define SIZE_ALIGN_32(x)    (((x) + 31) / 32 * 32)
511571a7a1Sriastradh 
521571a7a1Sriastradh static const enum smu8_scratch_entry firmware_list[] = {
531571a7a1Sriastradh 	SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0,
541571a7a1Sriastradh 	SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1,
551571a7a1Sriastradh 	SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE,
561571a7a1Sriastradh 	SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
571571a7a1Sriastradh 	SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME,
581571a7a1Sriastradh 	SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
591571a7a1Sriastradh 	SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
601571a7a1Sriastradh 	SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G,
611571a7a1Sriastradh };
621571a7a1Sriastradh 
smu8_get_argument(struct pp_hwmgr * hwmgr)631571a7a1Sriastradh static uint32_t smu8_get_argument(struct pp_hwmgr *hwmgr)
641571a7a1Sriastradh {
651571a7a1Sriastradh 	if (hwmgr == NULL || hwmgr->device == NULL)
661571a7a1Sriastradh 		return 0;
671571a7a1Sriastradh 
681571a7a1Sriastradh 	return cgs_read_register(hwmgr->device,
691571a7a1Sriastradh 					mmSMU_MP1_SRBM2P_ARG_0);
701571a7a1Sriastradh }
711571a7a1Sriastradh 
721571a7a1Sriastradh /* Send a message to the SMC, and wait for its response.*/
smu8_send_msg_to_smc_with_parameter(struct pp_hwmgr * hwmgr,uint16_t msg,uint32_t parameter)731571a7a1Sriastradh static int smu8_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
741571a7a1Sriastradh 					    uint16_t msg, uint32_t parameter)
751571a7a1Sriastradh {
761571a7a1Sriastradh 	int result = 0;
771571a7a1Sriastradh 	ktime_t t_start;
781571a7a1Sriastradh 	s64 elapsed_us;
791571a7a1Sriastradh 
801571a7a1Sriastradh 	if (hwmgr == NULL || hwmgr->device == NULL)
811571a7a1Sriastradh 		return -EINVAL;
821571a7a1Sriastradh 
831571a7a1Sriastradh 	result = PHM_WAIT_FIELD_UNEQUAL(hwmgr,
841571a7a1Sriastradh 					SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
851571a7a1Sriastradh 	if (result != 0) {
861571a7a1Sriastradh 		/* Read the last message to SMU, to report actual cause */
871571a7a1Sriastradh 		uint32_t val = cgs_read_register(hwmgr->device,
881571a7a1Sriastradh 						 mmSMU_MP1_SRBM2P_MSG_0);
891571a7a1Sriastradh 		pr_err("%s(0x%04x) aborted; SMU still servicing msg (0x%04x)\n",
901571a7a1Sriastradh 			__func__, msg, val);
911571a7a1Sriastradh 		return result;
921571a7a1Sriastradh 	}
931571a7a1Sriastradh 	t_start = ktime_get();
941571a7a1Sriastradh 
951571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter);
961571a7a1Sriastradh 
971571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0);
981571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg);
991571a7a1Sriastradh 
1001571a7a1Sriastradh 	result = PHM_WAIT_FIELD_UNEQUAL(hwmgr,
1011571a7a1Sriastradh 					SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
1021571a7a1Sriastradh 
1031571a7a1Sriastradh 	elapsed_us = ktime_us_delta(ktime_get(), t_start);
1041571a7a1Sriastradh 
105*65332265Sriastradh 	WARN(result, "%s(0x%04x, %#x) timed out after %"PRId64" us\n",
1061571a7a1Sriastradh 			__func__, msg, parameter, elapsed_us);
1071571a7a1Sriastradh 
1081571a7a1Sriastradh 	return result;
1091571a7a1Sriastradh }
1101571a7a1Sriastradh 
smu8_send_msg_to_smc(struct pp_hwmgr * hwmgr,uint16_t msg)1111571a7a1Sriastradh static int smu8_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
1121571a7a1Sriastradh {
1131571a7a1Sriastradh 	return smu8_send_msg_to_smc_with_parameter(hwmgr, msg, 0);
1141571a7a1Sriastradh }
1151571a7a1Sriastradh 
smu8_set_smc_sram_address(struct pp_hwmgr * hwmgr,uint32_t smc_address,uint32_t limit)1161571a7a1Sriastradh static int smu8_set_smc_sram_address(struct pp_hwmgr *hwmgr,
1171571a7a1Sriastradh 				     uint32_t smc_address, uint32_t limit)
1181571a7a1Sriastradh {
1191571a7a1Sriastradh 	if (hwmgr == NULL || hwmgr->device == NULL)
1201571a7a1Sriastradh 		return -EINVAL;
1211571a7a1Sriastradh 
1221571a7a1Sriastradh 	if (0 != (3 & smc_address)) {
1231571a7a1Sriastradh 		pr_err("SMC address must be 4 byte aligned\n");
1241571a7a1Sriastradh 		return -EINVAL;
1251571a7a1Sriastradh 	}
1261571a7a1Sriastradh 
1271571a7a1Sriastradh 	if (limit <= (smc_address + 3)) {
1281571a7a1Sriastradh 		pr_err("SMC address beyond the SMC RAM area\n");
1291571a7a1Sriastradh 		return -EINVAL;
1301571a7a1Sriastradh 	}
1311571a7a1Sriastradh 
1321571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX_0,
1331571a7a1Sriastradh 				SMN_MP1_SRAM_START_ADDR + smc_address);
1341571a7a1Sriastradh 
1351571a7a1Sriastradh 	return 0;
1361571a7a1Sriastradh }
1371571a7a1Sriastradh 
smu8_write_smc_sram_dword(struct pp_hwmgr * hwmgr,uint32_t smc_address,uint32_t value,uint32_t limit)1381571a7a1Sriastradh static int smu8_write_smc_sram_dword(struct pp_hwmgr *hwmgr,
1391571a7a1Sriastradh 		uint32_t smc_address, uint32_t value, uint32_t limit)
1401571a7a1Sriastradh {
1411571a7a1Sriastradh 	int result;
1421571a7a1Sriastradh 
1431571a7a1Sriastradh 	if (hwmgr == NULL || hwmgr->device == NULL)
1441571a7a1Sriastradh 		return -EINVAL;
1451571a7a1Sriastradh 
1461571a7a1Sriastradh 	result = smu8_set_smc_sram_address(hwmgr, smc_address, limit);
1471571a7a1Sriastradh 	if (!result)
1481571a7a1Sriastradh 		cgs_write_register(hwmgr->device, mmMP0PUB_IND_DATA_0, value);
1491571a7a1Sriastradh 
1501571a7a1Sriastradh 	return result;
1511571a7a1Sriastradh }
1521571a7a1Sriastradh 
smu8_check_fw_load_finish(struct pp_hwmgr * hwmgr,uint32_t firmware)1531571a7a1Sriastradh static int smu8_check_fw_load_finish(struct pp_hwmgr *hwmgr,
1541571a7a1Sriastradh 				   uint32_t firmware)
1551571a7a1Sriastradh {
1561571a7a1Sriastradh 	int i;
1571571a7a1Sriastradh 	uint32_t index = SMN_MP1_SRAM_START_ADDR +
1581571a7a1Sriastradh 			 SMU8_FIRMWARE_HEADER_LOCATION +
1591571a7a1Sriastradh 			 offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
1601571a7a1Sriastradh 
1611571a7a1Sriastradh 	if (hwmgr == NULL || hwmgr->device == NULL)
1621571a7a1Sriastradh 		return -EINVAL;
1631571a7a1Sriastradh 
1641571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index);
1651571a7a1Sriastradh 
1661571a7a1Sriastradh 	for (i = 0; i < hwmgr->usec_timeout; i++) {
1671571a7a1Sriastradh 		if (firmware ==
1681571a7a1Sriastradh 			(cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA) & firmware))
1691571a7a1Sriastradh 			break;
1701571a7a1Sriastradh 		udelay(1);
1711571a7a1Sriastradh 	}
1721571a7a1Sriastradh 
1731571a7a1Sriastradh 	if (i >= hwmgr->usec_timeout) {
1741571a7a1Sriastradh 		pr_err("SMU check loaded firmware failed.\n");
1751571a7a1Sriastradh 		return -EINVAL;
1761571a7a1Sriastradh 	}
1771571a7a1Sriastradh 
1781571a7a1Sriastradh 	return 0;
1791571a7a1Sriastradh }
1801571a7a1Sriastradh 
smu8_load_mec_firmware(struct pp_hwmgr * hwmgr)1811571a7a1Sriastradh static int smu8_load_mec_firmware(struct pp_hwmgr *hwmgr)
1821571a7a1Sriastradh {
1831571a7a1Sriastradh 	uint32_t reg_data;
1841571a7a1Sriastradh 	uint32_t tmp;
1851571a7a1Sriastradh 	int ret = 0;
1861571a7a1Sriastradh 	struct cgs_firmware_info info = {0};
1871571a7a1Sriastradh 
1881571a7a1Sriastradh 	if (hwmgr == NULL || hwmgr->device == NULL)
1891571a7a1Sriastradh 		return -EINVAL;
1901571a7a1Sriastradh 
1911571a7a1Sriastradh 	ret = cgs_get_firmware_info(hwmgr->device,
1921571a7a1Sriastradh 						CGS_UCODE_ID_CP_MEC, &info);
1931571a7a1Sriastradh 
1941571a7a1Sriastradh 	if (ret)
1951571a7a1Sriastradh 		return -EINVAL;
1961571a7a1Sriastradh 
1971571a7a1Sriastradh 	/* Disable MEC parsing/prefetching */
1981571a7a1Sriastradh 	tmp = cgs_read_register(hwmgr->device,
1991571a7a1Sriastradh 					mmCP_MEC_CNTL);
2001571a7a1Sriastradh 	tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1);
2011571a7a1Sriastradh 	tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1);
2021571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmCP_MEC_CNTL, tmp);
2031571a7a1Sriastradh 
2041571a7a1Sriastradh 	tmp = cgs_read_register(hwmgr->device,
2051571a7a1Sriastradh 					mmCP_CPC_IC_BASE_CNTL);
2061571a7a1Sriastradh 
2071571a7a1Sriastradh 	tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0);
2081571a7a1Sriastradh 	tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0);
2091571a7a1Sriastradh 	tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0);
2101571a7a1Sriastradh 	tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1);
2111571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_CNTL, tmp);
2121571a7a1Sriastradh 
2131571a7a1Sriastradh 	reg_data = lower_32_bits(info.mc_addr) &
2141571a7a1Sriastradh 			PHM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO);
2151571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_LO, reg_data);
2161571a7a1Sriastradh 
2171571a7a1Sriastradh 	reg_data = upper_32_bits(info.mc_addr) &
2181571a7a1Sriastradh 			PHM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI);
2191571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_HI, reg_data);
2201571a7a1Sriastradh 
2211571a7a1Sriastradh 	return 0;
2221571a7a1Sriastradh }
2231571a7a1Sriastradh 
smu8_translate_firmware_enum_to_arg(struct pp_hwmgr * hwmgr,enum smu8_scratch_entry firmware_enum)2241571a7a1Sriastradh static uint8_t smu8_translate_firmware_enum_to_arg(struct pp_hwmgr *hwmgr,
2251571a7a1Sriastradh 			enum smu8_scratch_entry firmware_enum)
2261571a7a1Sriastradh {
2271571a7a1Sriastradh 	uint8_t ret = 0;
2281571a7a1Sriastradh 
2291571a7a1Sriastradh 	switch (firmware_enum) {
2301571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0:
2311571a7a1Sriastradh 		ret = UCODE_ID_SDMA0;
2321571a7a1Sriastradh 		break;
2331571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1:
2341571a7a1Sriastradh 		if (hwmgr->chip_id == CHIP_STONEY)
2351571a7a1Sriastradh 			ret = UCODE_ID_SDMA0;
2361571a7a1Sriastradh 		else
2371571a7a1Sriastradh 			ret = UCODE_ID_SDMA1;
2381571a7a1Sriastradh 		break;
2391571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE:
2401571a7a1Sriastradh 		ret = UCODE_ID_CP_CE;
2411571a7a1Sriastradh 		break;
2421571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP:
2431571a7a1Sriastradh 		ret = UCODE_ID_CP_PFP;
2441571a7a1Sriastradh 		break;
2451571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME:
2461571a7a1Sriastradh 		ret = UCODE_ID_CP_ME;
2471571a7a1Sriastradh 		break;
2481571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1:
2491571a7a1Sriastradh 		ret = UCODE_ID_CP_MEC_JT1;
2501571a7a1Sriastradh 		break;
2511571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2:
2521571a7a1Sriastradh 		if (hwmgr->chip_id == CHIP_STONEY)
2531571a7a1Sriastradh 			ret = UCODE_ID_CP_MEC_JT1;
2541571a7a1Sriastradh 		else
2551571a7a1Sriastradh 			ret = UCODE_ID_CP_MEC_JT2;
2561571a7a1Sriastradh 		break;
2571571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG:
2581571a7a1Sriastradh 		ret = UCODE_ID_GMCON_RENG;
2591571a7a1Sriastradh 		break;
2601571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G:
2611571a7a1Sriastradh 		ret = UCODE_ID_RLC_G;
2621571a7a1Sriastradh 		break;
2631571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH:
2641571a7a1Sriastradh 		ret = UCODE_ID_RLC_SCRATCH;
2651571a7a1Sriastradh 		break;
2661571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM:
2671571a7a1Sriastradh 		ret = UCODE_ID_RLC_SRM_ARAM;
2681571a7a1Sriastradh 		break;
2691571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM:
2701571a7a1Sriastradh 		ret = UCODE_ID_RLC_SRM_DRAM;
2711571a7a1Sriastradh 		break;
2721571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM:
2731571a7a1Sriastradh 		ret = UCODE_ID_DMCU_ERAM;
2741571a7a1Sriastradh 		break;
2751571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM:
2761571a7a1Sriastradh 		ret = UCODE_ID_DMCU_IRAM;
2771571a7a1Sriastradh 		break;
2781571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING:
2791571a7a1Sriastradh 		ret = TASK_ARG_INIT_MM_PWR_LOG;
2801571a7a1Sriastradh 		break;
2811571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_HALT:
2821571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING:
2831571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS:
2841571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT:
2851571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_START:
2861571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS:
2871571a7a1Sriastradh 		ret = TASK_ARG_REG_MMIO;
2881571a7a1Sriastradh 		break;
2891571a7a1Sriastradh 	case SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE:
2901571a7a1Sriastradh 		ret = TASK_ARG_INIT_CLK_TABLE;
2911571a7a1Sriastradh 		break;
2921571a7a1Sriastradh 	}
2931571a7a1Sriastradh 
2941571a7a1Sriastradh 	return ret;
2951571a7a1Sriastradh }
2961571a7a1Sriastradh 
smu8_convert_fw_type_to_cgs(uint32_t fw_type)2971571a7a1Sriastradh static enum cgs_ucode_id smu8_convert_fw_type_to_cgs(uint32_t fw_type)
2981571a7a1Sriastradh {
2991571a7a1Sriastradh 	enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
3001571a7a1Sriastradh 
3011571a7a1Sriastradh 	switch (fw_type) {
3021571a7a1Sriastradh 	case UCODE_ID_SDMA0:
3031571a7a1Sriastradh 		result = CGS_UCODE_ID_SDMA0;
3041571a7a1Sriastradh 		break;
3051571a7a1Sriastradh 	case UCODE_ID_SDMA1:
3061571a7a1Sriastradh 		result = CGS_UCODE_ID_SDMA1;
3071571a7a1Sriastradh 		break;
3081571a7a1Sriastradh 	case UCODE_ID_CP_CE:
3091571a7a1Sriastradh 		result = CGS_UCODE_ID_CP_CE;
3101571a7a1Sriastradh 		break;
3111571a7a1Sriastradh 	case UCODE_ID_CP_PFP:
3121571a7a1Sriastradh 		result = CGS_UCODE_ID_CP_PFP;
3131571a7a1Sriastradh 		break;
3141571a7a1Sriastradh 	case UCODE_ID_CP_ME:
3151571a7a1Sriastradh 		result = CGS_UCODE_ID_CP_ME;
3161571a7a1Sriastradh 		break;
3171571a7a1Sriastradh 	case UCODE_ID_CP_MEC_JT1:
3181571a7a1Sriastradh 		result = CGS_UCODE_ID_CP_MEC_JT1;
3191571a7a1Sriastradh 		break;
3201571a7a1Sriastradh 	case UCODE_ID_CP_MEC_JT2:
3211571a7a1Sriastradh 		result = CGS_UCODE_ID_CP_MEC_JT2;
3221571a7a1Sriastradh 		break;
3231571a7a1Sriastradh 	case UCODE_ID_RLC_G:
3241571a7a1Sriastradh 		result = CGS_UCODE_ID_RLC_G;
3251571a7a1Sriastradh 		break;
3261571a7a1Sriastradh 	default:
3271571a7a1Sriastradh 		break;
3281571a7a1Sriastradh 	}
3291571a7a1Sriastradh 
3301571a7a1Sriastradh 	return result;
3311571a7a1Sriastradh }
3321571a7a1Sriastradh 
smu8_smu_populate_single_scratch_task(struct pp_hwmgr * hwmgr,enum smu8_scratch_entry fw_enum,uint8_t type,bool is_last)3331571a7a1Sriastradh static int smu8_smu_populate_single_scratch_task(
3341571a7a1Sriastradh 			struct pp_hwmgr *hwmgr,
3351571a7a1Sriastradh 			enum smu8_scratch_entry fw_enum,
3361571a7a1Sriastradh 			uint8_t type, bool is_last)
3371571a7a1Sriastradh {
3381571a7a1Sriastradh 	uint8_t i;
3391571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
3401571a7a1Sriastradh 	struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr;
3411571a7a1Sriastradh 	struct SMU_Task *task = &toc->tasks[smu8_smu->toc_entry_used_count++];
3421571a7a1Sriastradh 
3431571a7a1Sriastradh 	task->type = type;
3441571a7a1Sriastradh 	task->arg = smu8_translate_firmware_enum_to_arg(hwmgr, fw_enum);
3451571a7a1Sriastradh 	task->next = is_last ? END_OF_TASK_LIST : smu8_smu->toc_entry_used_count;
3461571a7a1Sriastradh 
3471571a7a1Sriastradh 	for (i = 0; i < smu8_smu->scratch_buffer_length; i++)
3481571a7a1Sriastradh 		if (smu8_smu->scratch_buffer[i].firmware_ID == fw_enum)
3491571a7a1Sriastradh 			break;
3501571a7a1Sriastradh 
3511571a7a1Sriastradh 	if (i >= smu8_smu->scratch_buffer_length) {
3521571a7a1Sriastradh 		pr_err("Invalid Firmware Type\n");
3531571a7a1Sriastradh 		return -EINVAL;
3541571a7a1Sriastradh 	}
3551571a7a1Sriastradh 
3561571a7a1Sriastradh 	task->addr.low = lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr);
3571571a7a1Sriastradh 	task->addr.high = upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr);
3581571a7a1Sriastradh 	task->size_bytes = smu8_smu->scratch_buffer[i].data_size;
3591571a7a1Sriastradh 
3601571a7a1Sriastradh 	if (SMU8_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) {
3611571a7a1Sriastradh 		struct smu8_ih_meta_data *pIHReg_restore =
3621571a7a1Sriastradh 		     (struct smu8_ih_meta_data *)smu8_smu->scratch_buffer[i].kaddr;
3631571a7a1Sriastradh 		pIHReg_restore->command =
3641571a7a1Sriastradh 			METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD;
3651571a7a1Sriastradh 	}
3661571a7a1Sriastradh 
3671571a7a1Sriastradh 	return 0;
3681571a7a1Sriastradh }
3691571a7a1Sriastradh 
smu8_smu_populate_single_ucode_load_task(struct pp_hwmgr * hwmgr,enum smu8_scratch_entry fw_enum,bool is_last)3701571a7a1Sriastradh static int smu8_smu_populate_single_ucode_load_task(
3711571a7a1Sriastradh 					struct pp_hwmgr *hwmgr,
3721571a7a1Sriastradh 					enum smu8_scratch_entry fw_enum,
3731571a7a1Sriastradh 					bool is_last)
3741571a7a1Sriastradh {
3751571a7a1Sriastradh 	uint8_t i;
3761571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
3771571a7a1Sriastradh 	struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr;
3781571a7a1Sriastradh 	struct SMU_Task *task = &toc->tasks[smu8_smu->toc_entry_used_count++];
3791571a7a1Sriastradh 
3801571a7a1Sriastradh 	task->type = TASK_TYPE_UCODE_LOAD;
3811571a7a1Sriastradh 	task->arg = smu8_translate_firmware_enum_to_arg(hwmgr, fw_enum);
3821571a7a1Sriastradh 	task->next = is_last ? END_OF_TASK_LIST : smu8_smu->toc_entry_used_count;
3831571a7a1Sriastradh 
3841571a7a1Sriastradh 	for (i = 0; i < smu8_smu->driver_buffer_length; i++)
3851571a7a1Sriastradh 		if (smu8_smu->driver_buffer[i].firmware_ID == fw_enum)
3861571a7a1Sriastradh 			break;
3871571a7a1Sriastradh 
3881571a7a1Sriastradh 	if (i >= smu8_smu->driver_buffer_length) {
3891571a7a1Sriastradh 		pr_err("Invalid Firmware Type\n");
3901571a7a1Sriastradh 		return -EINVAL;
3911571a7a1Sriastradh 	}
3921571a7a1Sriastradh 
3931571a7a1Sriastradh 	task->addr.low = lower_32_bits(smu8_smu->driver_buffer[i].mc_addr);
3941571a7a1Sriastradh 	task->addr.high = upper_32_bits(smu8_smu->driver_buffer[i].mc_addr);
3951571a7a1Sriastradh 	task->size_bytes = smu8_smu->driver_buffer[i].data_size;
3961571a7a1Sriastradh 
3971571a7a1Sriastradh 	return 0;
3981571a7a1Sriastradh }
3991571a7a1Sriastradh 
smu8_smu_construct_toc_for_rlc_aram_save(struct pp_hwmgr * hwmgr)4001571a7a1Sriastradh static int smu8_smu_construct_toc_for_rlc_aram_save(struct pp_hwmgr *hwmgr)
4011571a7a1Sriastradh {
4021571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
4031571a7a1Sriastradh 
4041571a7a1Sriastradh 	smu8_smu->toc_entry_aram = smu8_smu->toc_entry_used_count;
4051571a7a1Sriastradh 	smu8_smu_populate_single_scratch_task(hwmgr,
4061571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
4071571a7a1Sriastradh 				TASK_TYPE_UCODE_SAVE, true);
4081571a7a1Sriastradh 
4091571a7a1Sriastradh 	return 0;
4101571a7a1Sriastradh }
4111571a7a1Sriastradh 
smu8_smu_initialize_toc_empty_job_list(struct pp_hwmgr * hwmgr)4121571a7a1Sriastradh static int smu8_smu_initialize_toc_empty_job_list(struct pp_hwmgr *hwmgr)
4131571a7a1Sriastradh {
4141571a7a1Sriastradh 	int i;
4151571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
4161571a7a1Sriastradh 	struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr;
4171571a7a1Sriastradh 
4181571a7a1Sriastradh 	for (i = 0; i < NUM_JOBLIST_ENTRIES; i++)
4191571a7a1Sriastradh 		toc->JobList[i] = (uint8_t)IGNORE_JOB;
4201571a7a1Sriastradh 
4211571a7a1Sriastradh 	return 0;
4221571a7a1Sriastradh }
4231571a7a1Sriastradh 
smu8_smu_construct_toc_for_vddgfx_enter(struct pp_hwmgr * hwmgr)4241571a7a1Sriastradh static int smu8_smu_construct_toc_for_vddgfx_enter(struct pp_hwmgr *hwmgr)
4251571a7a1Sriastradh {
4261571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
4271571a7a1Sriastradh 	struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr;
4281571a7a1Sriastradh 
4291571a7a1Sriastradh 	toc->JobList[JOB_GFX_SAVE] = (uint8_t)smu8_smu->toc_entry_used_count;
4301571a7a1Sriastradh 	smu8_smu_populate_single_scratch_task(hwmgr,
4311571a7a1Sriastradh 				    SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
4321571a7a1Sriastradh 				    TASK_TYPE_UCODE_SAVE, false);
4331571a7a1Sriastradh 
4341571a7a1Sriastradh 	smu8_smu_populate_single_scratch_task(hwmgr,
4351571a7a1Sriastradh 				    SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
4361571a7a1Sriastradh 				    TASK_TYPE_UCODE_SAVE, true);
4371571a7a1Sriastradh 
4381571a7a1Sriastradh 	return 0;
4391571a7a1Sriastradh }
4401571a7a1Sriastradh 
4411571a7a1Sriastradh 
smu8_smu_construct_toc_for_vddgfx_exit(struct pp_hwmgr * hwmgr)4421571a7a1Sriastradh static int smu8_smu_construct_toc_for_vddgfx_exit(struct pp_hwmgr *hwmgr)
4431571a7a1Sriastradh {
4441571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
4451571a7a1Sriastradh 	struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr;
4461571a7a1Sriastradh 
4471571a7a1Sriastradh 	toc->JobList[JOB_GFX_RESTORE] = (uint8_t)smu8_smu->toc_entry_used_count;
4481571a7a1Sriastradh 
4491571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
4501571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
4511571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
4521571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
4531571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
4541571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
4551571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
4561571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
4571571a7a1Sriastradh 
4581571a7a1Sriastradh 	if (hwmgr->chip_id == CHIP_STONEY)
4591571a7a1Sriastradh 		smu8_smu_populate_single_ucode_load_task(hwmgr,
4601571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
4611571a7a1Sriastradh 	else
4621571a7a1Sriastradh 		smu8_smu_populate_single_ucode_load_task(hwmgr,
4631571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
4641571a7a1Sriastradh 
4651571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
4661571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, false);
4671571a7a1Sriastradh 
4681571a7a1Sriastradh 	/* populate scratch */
4691571a7a1Sriastradh 	smu8_smu_populate_single_scratch_task(hwmgr,
4701571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
4711571a7a1Sriastradh 				TASK_TYPE_UCODE_LOAD, false);
4721571a7a1Sriastradh 
4731571a7a1Sriastradh 	smu8_smu_populate_single_scratch_task(hwmgr,
4741571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
4751571a7a1Sriastradh 				TASK_TYPE_UCODE_LOAD, false);
4761571a7a1Sriastradh 
4771571a7a1Sriastradh 	smu8_smu_populate_single_scratch_task(hwmgr,
4781571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
4791571a7a1Sriastradh 				TASK_TYPE_UCODE_LOAD, true);
4801571a7a1Sriastradh 
4811571a7a1Sriastradh 	return 0;
4821571a7a1Sriastradh }
4831571a7a1Sriastradh 
smu8_smu_construct_toc_for_power_profiling(struct pp_hwmgr * hwmgr)4841571a7a1Sriastradh static int smu8_smu_construct_toc_for_power_profiling(struct pp_hwmgr *hwmgr)
4851571a7a1Sriastradh {
4861571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
4871571a7a1Sriastradh 
4881571a7a1Sriastradh 	smu8_smu->toc_entry_power_profiling_index = smu8_smu->toc_entry_used_count;
4891571a7a1Sriastradh 
4901571a7a1Sriastradh 	smu8_smu_populate_single_scratch_task(hwmgr,
4911571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
4921571a7a1Sriastradh 				TASK_TYPE_INITIALIZE, true);
4931571a7a1Sriastradh 	return 0;
4941571a7a1Sriastradh }
4951571a7a1Sriastradh 
smu8_smu_construct_toc_for_bootup(struct pp_hwmgr * hwmgr)4961571a7a1Sriastradh static int smu8_smu_construct_toc_for_bootup(struct pp_hwmgr *hwmgr)
4971571a7a1Sriastradh {
4981571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
4991571a7a1Sriastradh 
5001571a7a1Sriastradh 	smu8_smu->toc_entry_initialize_index = smu8_smu->toc_entry_used_count;
5011571a7a1Sriastradh 
5021571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
5031571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
5041571a7a1Sriastradh 	if (hwmgr->chip_id != CHIP_STONEY)
5051571a7a1Sriastradh 		smu8_smu_populate_single_ucode_load_task(hwmgr,
5061571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1, false);
5071571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
5081571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
5091571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
5101571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
5111571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
5121571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
5131571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
5141571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
5151571a7a1Sriastradh 	if (hwmgr->chip_id != CHIP_STONEY)
5161571a7a1Sriastradh 		smu8_smu_populate_single_ucode_load_task(hwmgr,
5171571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
5181571a7a1Sriastradh 	smu8_smu_populate_single_ucode_load_task(hwmgr,
5191571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, true);
5201571a7a1Sriastradh 
5211571a7a1Sriastradh 	return 0;
5221571a7a1Sriastradh }
5231571a7a1Sriastradh 
smu8_smu_construct_toc_for_clock_table(struct pp_hwmgr * hwmgr)5241571a7a1Sriastradh static int smu8_smu_construct_toc_for_clock_table(struct pp_hwmgr *hwmgr)
5251571a7a1Sriastradh {
5261571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
5271571a7a1Sriastradh 
5281571a7a1Sriastradh 	smu8_smu->toc_entry_clock_table = smu8_smu->toc_entry_used_count;
5291571a7a1Sriastradh 
5301571a7a1Sriastradh 	smu8_smu_populate_single_scratch_task(hwmgr,
5311571a7a1Sriastradh 				SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
5321571a7a1Sriastradh 				TASK_TYPE_INITIALIZE, true);
5331571a7a1Sriastradh 
5341571a7a1Sriastradh 	return 0;
5351571a7a1Sriastradh }
5361571a7a1Sriastradh 
smu8_smu_construct_toc(struct pp_hwmgr * hwmgr)5371571a7a1Sriastradh static int smu8_smu_construct_toc(struct pp_hwmgr *hwmgr)
5381571a7a1Sriastradh {
5391571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
5401571a7a1Sriastradh 
5411571a7a1Sriastradh 	smu8_smu->toc_entry_used_count = 0;
5421571a7a1Sriastradh 	smu8_smu_initialize_toc_empty_job_list(hwmgr);
5431571a7a1Sriastradh 	smu8_smu_construct_toc_for_rlc_aram_save(hwmgr);
5441571a7a1Sriastradh 	smu8_smu_construct_toc_for_vddgfx_enter(hwmgr);
5451571a7a1Sriastradh 	smu8_smu_construct_toc_for_vddgfx_exit(hwmgr);
5461571a7a1Sriastradh 	smu8_smu_construct_toc_for_power_profiling(hwmgr);
5471571a7a1Sriastradh 	smu8_smu_construct_toc_for_bootup(hwmgr);
5481571a7a1Sriastradh 	smu8_smu_construct_toc_for_clock_table(hwmgr);
5491571a7a1Sriastradh 
5501571a7a1Sriastradh 	return 0;
5511571a7a1Sriastradh }
5521571a7a1Sriastradh 
smu8_smu_populate_firmware_entries(struct pp_hwmgr * hwmgr)5531571a7a1Sriastradh static int smu8_smu_populate_firmware_entries(struct pp_hwmgr *hwmgr)
5541571a7a1Sriastradh {
5551571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
5561571a7a1Sriastradh 	uint32_t firmware_type;
5571571a7a1Sriastradh 	uint32_t i;
5581571a7a1Sriastradh 	int ret;
5591571a7a1Sriastradh 	enum cgs_ucode_id ucode_id;
5601571a7a1Sriastradh 	struct cgs_firmware_info info = {0};
5611571a7a1Sriastradh 
5621571a7a1Sriastradh 	smu8_smu->driver_buffer_length = 0;
5631571a7a1Sriastradh 
5641571a7a1Sriastradh 	for (i = 0; i < ARRAY_SIZE(firmware_list); i++) {
5651571a7a1Sriastradh 
5661571a7a1Sriastradh 		firmware_type = smu8_translate_firmware_enum_to_arg(hwmgr,
5671571a7a1Sriastradh 					firmware_list[i]);
5681571a7a1Sriastradh 
5691571a7a1Sriastradh 		ucode_id = smu8_convert_fw_type_to_cgs(firmware_type);
5701571a7a1Sriastradh 
5711571a7a1Sriastradh 		ret = cgs_get_firmware_info(hwmgr->device,
5721571a7a1Sriastradh 							ucode_id, &info);
5731571a7a1Sriastradh 
5741571a7a1Sriastradh 		if (ret == 0) {
5751571a7a1Sriastradh 			smu8_smu->driver_buffer[i].mc_addr = info.mc_addr;
5761571a7a1Sriastradh 
5771571a7a1Sriastradh 			smu8_smu->driver_buffer[i].data_size = info.image_size;
5781571a7a1Sriastradh 
5791571a7a1Sriastradh 			smu8_smu->driver_buffer[i].firmware_ID = firmware_list[i];
5801571a7a1Sriastradh 			smu8_smu->driver_buffer_length++;
5811571a7a1Sriastradh 		}
5821571a7a1Sriastradh 	}
5831571a7a1Sriastradh 
5841571a7a1Sriastradh 	return 0;
5851571a7a1Sriastradh }
5861571a7a1Sriastradh 
smu8_smu_populate_single_scratch_entry(struct pp_hwmgr * hwmgr,enum smu8_scratch_entry scratch_type,uint32_t ulsize_byte,struct smu8_buffer_entry * entry)5871571a7a1Sriastradh static int smu8_smu_populate_single_scratch_entry(
5881571a7a1Sriastradh 				struct pp_hwmgr *hwmgr,
5891571a7a1Sriastradh 				enum smu8_scratch_entry scratch_type,
5901571a7a1Sriastradh 				uint32_t ulsize_byte,
5911571a7a1Sriastradh 				struct smu8_buffer_entry *entry)
5921571a7a1Sriastradh {
5931571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
5941571a7a1Sriastradh 	uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte);
5951571a7a1Sriastradh 
5961571a7a1Sriastradh 	entry->data_size = ulsize_byte;
5971571a7a1Sriastradh 	entry->kaddr = (char *) smu8_smu->smu_buffer.kaddr +
5981571a7a1Sriastradh 				smu8_smu->smu_buffer_used_bytes;
5991571a7a1Sriastradh 	entry->mc_addr = smu8_smu->smu_buffer.mc_addr + smu8_smu->smu_buffer_used_bytes;
6001571a7a1Sriastradh 	entry->firmware_ID = scratch_type;
6011571a7a1Sriastradh 
6021571a7a1Sriastradh 	smu8_smu->smu_buffer_used_bytes += ulsize_aligned;
6031571a7a1Sriastradh 
6041571a7a1Sriastradh 	return 0;
6051571a7a1Sriastradh }
6061571a7a1Sriastradh 
smu8_download_pptable_settings(struct pp_hwmgr * hwmgr,void ** table)6071571a7a1Sriastradh static int smu8_download_pptable_settings(struct pp_hwmgr *hwmgr, void **table)
6081571a7a1Sriastradh {
6091571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
6101571a7a1Sriastradh 	unsigned long i;
6111571a7a1Sriastradh 
6121571a7a1Sriastradh 	for (i = 0; i < smu8_smu->scratch_buffer_length; i++) {
6131571a7a1Sriastradh 		if (smu8_smu->scratch_buffer[i].firmware_ID
6141571a7a1Sriastradh 			== SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
6151571a7a1Sriastradh 			break;
6161571a7a1Sriastradh 	}
6171571a7a1Sriastradh 
6181571a7a1Sriastradh 	*table = (struct SMU8_Fusion_ClkTable *)smu8_smu->scratch_buffer[i].kaddr;
6191571a7a1Sriastradh 
6201571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr,
6211571a7a1Sriastradh 				PPSMC_MSG_SetClkTableAddrHi,
6221571a7a1Sriastradh 				upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr));
6231571a7a1Sriastradh 
6241571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr,
6251571a7a1Sriastradh 				PPSMC_MSG_SetClkTableAddrLo,
6261571a7a1Sriastradh 				lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr));
6271571a7a1Sriastradh 
6281571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob,
6291571a7a1Sriastradh 				smu8_smu->toc_entry_clock_table);
6301571a7a1Sriastradh 
6311571a7a1Sriastradh 	smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToDram);
6321571a7a1Sriastradh 
6331571a7a1Sriastradh 	return 0;
6341571a7a1Sriastradh }
6351571a7a1Sriastradh 
smu8_upload_pptable_settings(struct pp_hwmgr * hwmgr)6361571a7a1Sriastradh static int smu8_upload_pptable_settings(struct pp_hwmgr *hwmgr)
6371571a7a1Sriastradh {
6381571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
6391571a7a1Sriastradh 	unsigned long i;
6401571a7a1Sriastradh 
6411571a7a1Sriastradh 	for (i = 0; i < smu8_smu->scratch_buffer_length; i++) {
6421571a7a1Sriastradh 		if (smu8_smu->scratch_buffer[i].firmware_ID
6431571a7a1Sriastradh 				== SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
6441571a7a1Sriastradh 			break;
6451571a7a1Sriastradh 	}
6461571a7a1Sriastradh 
6471571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr,
6481571a7a1Sriastradh 				PPSMC_MSG_SetClkTableAddrHi,
6491571a7a1Sriastradh 				upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr));
6501571a7a1Sriastradh 
6511571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr,
6521571a7a1Sriastradh 				PPSMC_MSG_SetClkTableAddrLo,
6531571a7a1Sriastradh 				lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr));
6541571a7a1Sriastradh 
6551571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob,
6561571a7a1Sriastradh 				smu8_smu->toc_entry_clock_table);
6571571a7a1Sriastradh 
6581571a7a1Sriastradh 	smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToSmu);
6591571a7a1Sriastradh 
6601571a7a1Sriastradh 	return 0;
6611571a7a1Sriastradh }
6621571a7a1Sriastradh 
smu8_request_smu_load_fw(struct pp_hwmgr * hwmgr)6631571a7a1Sriastradh static int smu8_request_smu_load_fw(struct pp_hwmgr *hwmgr)
6641571a7a1Sriastradh {
6651571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu = hwmgr->smu_backend;
6661571a7a1Sriastradh 	uint32_t smc_address;
6671571a7a1Sriastradh 	uint32_t fw_to_check = 0;
6681571a7a1Sriastradh 	int ret;
6691571a7a1Sriastradh 
6701571a7a1Sriastradh 	amdgpu_ucode_init_bo(hwmgr->adev);
6711571a7a1Sriastradh 
6721571a7a1Sriastradh 	smu8_smu_populate_firmware_entries(hwmgr);
6731571a7a1Sriastradh 
6741571a7a1Sriastradh 	smu8_smu_construct_toc(hwmgr);
6751571a7a1Sriastradh 
6761571a7a1Sriastradh 	smc_address = SMU8_FIRMWARE_HEADER_LOCATION +
6771571a7a1Sriastradh 		offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
6781571a7a1Sriastradh 
6791571a7a1Sriastradh 	smu8_write_smc_sram_dword(hwmgr, smc_address, 0, smc_address+4);
6801571a7a1Sriastradh 
6811571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr,
6821571a7a1Sriastradh 					PPSMC_MSG_DriverDramAddrHi,
6831571a7a1Sriastradh 					upper_32_bits(smu8_smu->toc_buffer.mc_addr));
6841571a7a1Sriastradh 
6851571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr,
6861571a7a1Sriastradh 					PPSMC_MSG_DriverDramAddrLo,
6871571a7a1Sriastradh 					lower_32_bits(smu8_smu->toc_buffer.mc_addr));
6881571a7a1Sriastradh 
6891571a7a1Sriastradh 	smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_InitJobs);
6901571a7a1Sriastradh 
6911571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr,
6921571a7a1Sriastradh 					PPSMC_MSG_ExecuteJob,
6931571a7a1Sriastradh 					smu8_smu->toc_entry_aram);
6941571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob,
6951571a7a1Sriastradh 				smu8_smu->toc_entry_power_profiling_index);
6961571a7a1Sriastradh 
6971571a7a1Sriastradh 	smu8_send_msg_to_smc_with_parameter(hwmgr,
6981571a7a1Sriastradh 					PPSMC_MSG_ExecuteJob,
6991571a7a1Sriastradh 					smu8_smu->toc_entry_initialize_index);
7001571a7a1Sriastradh 
7011571a7a1Sriastradh 	fw_to_check = UCODE_ID_RLC_G_MASK |
7021571a7a1Sriastradh 			UCODE_ID_SDMA0_MASK |
7031571a7a1Sriastradh 			UCODE_ID_SDMA1_MASK |
7041571a7a1Sriastradh 			UCODE_ID_CP_CE_MASK |
7051571a7a1Sriastradh 			UCODE_ID_CP_ME_MASK |
7061571a7a1Sriastradh 			UCODE_ID_CP_PFP_MASK |
7071571a7a1Sriastradh 			UCODE_ID_CP_MEC_JT1_MASK |
7081571a7a1Sriastradh 			UCODE_ID_CP_MEC_JT2_MASK;
7091571a7a1Sriastradh 
7101571a7a1Sriastradh 	if (hwmgr->chip_id == CHIP_STONEY)
7111571a7a1Sriastradh 		fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK);
7121571a7a1Sriastradh 
7131571a7a1Sriastradh 	ret = smu8_check_fw_load_finish(hwmgr, fw_to_check);
7141571a7a1Sriastradh 	if (ret) {
7151571a7a1Sriastradh 		pr_err("SMU firmware load failed\n");
7161571a7a1Sriastradh 		return ret;
7171571a7a1Sriastradh 	}
7181571a7a1Sriastradh 
7191571a7a1Sriastradh 	ret = smu8_load_mec_firmware(hwmgr);
7201571a7a1Sriastradh 	if (ret) {
7211571a7a1Sriastradh 		pr_err("Mec Firmware load failed\n");
7221571a7a1Sriastradh 		return ret;
7231571a7a1Sriastradh 	}
7241571a7a1Sriastradh 
7251571a7a1Sriastradh 	return 0;
7261571a7a1Sriastradh }
7271571a7a1Sriastradh 
smu8_start_smu(struct pp_hwmgr * hwmgr)7281571a7a1Sriastradh static int smu8_start_smu(struct pp_hwmgr *hwmgr)
7291571a7a1Sriastradh {
7301571a7a1Sriastradh 	struct amdgpu_device *adev;
7311571a7a1Sriastradh 
7321571a7a1Sriastradh 	uint32_t index = SMN_MP1_SRAM_START_ADDR +
7331571a7a1Sriastradh 			 SMU8_FIRMWARE_HEADER_LOCATION +
7341571a7a1Sriastradh 			 offsetof(struct SMU8_Firmware_Header, Version);
7351571a7a1Sriastradh 
7361571a7a1Sriastradh 	if (hwmgr == NULL || hwmgr->device == NULL)
7371571a7a1Sriastradh 		return -EINVAL;
7381571a7a1Sriastradh 
7391571a7a1Sriastradh 	adev = hwmgr->adev;
7401571a7a1Sriastradh 
7411571a7a1Sriastradh 	cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index);
7421571a7a1Sriastradh 	hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA);
7431571a7a1Sriastradh 	pr_info("smu version %02d.%02d.%02d\n",
7441571a7a1Sriastradh 		((hwmgr->smu_version >> 16) & 0xFF),
7451571a7a1Sriastradh 		((hwmgr->smu_version >> 8) & 0xFF),
7461571a7a1Sriastradh 		(hwmgr->smu_version & 0xFF));
7471571a7a1Sriastradh 	adev->pm.fw_version = hwmgr->smu_version >> 8;
7481571a7a1Sriastradh 
7491571a7a1Sriastradh 	return smu8_request_smu_load_fw(hwmgr);
7501571a7a1Sriastradh }
7511571a7a1Sriastradh 
smu8_smu_init(struct pp_hwmgr * hwmgr)7521571a7a1Sriastradh static int smu8_smu_init(struct pp_hwmgr *hwmgr)
7531571a7a1Sriastradh {
7541571a7a1Sriastradh 	int ret = 0;
7551571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu;
7561571a7a1Sriastradh 
7571571a7a1Sriastradh 	smu8_smu = kzalloc(sizeof(struct smu8_smumgr), GFP_KERNEL);
7581571a7a1Sriastradh 	if (smu8_smu == NULL)
7591571a7a1Sriastradh 		return -ENOMEM;
7601571a7a1Sriastradh 
7611571a7a1Sriastradh 	hwmgr->smu_backend = smu8_smu;
7621571a7a1Sriastradh 
7631571a7a1Sriastradh 	smu8_smu->toc_buffer.data_size = 4096;
7641571a7a1Sriastradh 	smu8_smu->smu_buffer.data_size =
7651571a7a1Sriastradh 		ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) +
7661571a7a1Sriastradh 		ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) +
7671571a7a1Sriastradh 		ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) +
7681571a7a1Sriastradh 		ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) +
7691571a7a1Sriastradh 		ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32);
7701571a7a1Sriastradh 
7711571a7a1Sriastradh 	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
7721571a7a1Sriastradh 				smu8_smu->toc_buffer.data_size,
7731571a7a1Sriastradh 				PAGE_SIZE,
7741571a7a1Sriastradh 				AMDGPU_GEM_DOMAIN_VRAM,
7751571a7a1Sriastradh 				&smu8_smu->toc_buffer.handle,
7761571a7a1Sriastradh 				&smu8_smu->toc_buffer.mc_addr,
7771571a7a1Sriastradh 				&smu8_smu->toc_buffer.kaddr);
7781571a7a1Sriastradh 	if (ret)
7791571a7a1Sriastradh 		goto err2;
7801571a7a1Sriastradh 
7811571a7a1Sriastradh 	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
7821571a7a1Sriastradh 				smu8_smu->smu_buffer.data_size,
7831571a7a1Sriastradh 				PAGE_SIZE,
7841571a7a1Sriastradh 				AMDGPU_GEM_DOMAIN_VRAM,
7851571a7a1Sriastradh 				&smu8_smu->smu_buffer.handle,
7861571a7a1Sriastradh 				&smu8_smu->smu_buffer.mc_addr,
7871571a7a1Sriastradh 				&smu8_smu->smu_buffer.kaddr);
7881571a7a1Sriastradh 	if (ret)
7891571a7a1Sriastradh 		goto err1;
7901571a7a1Sriastradh 
7911571a7a1Sriastradh 	if (0 != smu8_smu_populate_single_scratch_entry(hwmgr,
7921571a7a1Sriastradh 		SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
7931571a7a1Sriastradh 		UCODE_ID_RLC_SCRATCH_SIZE_BYTE,
7941571a7a1Sriastradh 		&smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) {
7951571a7a1Sriastradh 		pr_err("Error when Populate Firmware Entry.\n");
7961571a7a1Sriastradh 		goto err0;
7971571a7a1Sriastradh 	}
7981571a7a1Sriastradh 
7991571a7a1Sriastradh 	if (0 != smu8_smu_populate_single_scratch_entry(hwmgr,
8001571a7a1Sriastradh 		SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
8011571a7a1Sriastradh 		UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE,
8021571a7a1Sriastradh 		&smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) {
8031571a7a1Sriastradh 		pr_err("Error when Populate Firmware Entry.\n");
8041571a7a1Sriastradh 		goto err0;
8051571a7a1Sriastradh 	}
8061571a7a1Sriastradh 	if (0 != smu8_smu_populate_single_scratch_entry(hwmgr,
8071571a7a1Sriastradh 		SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
8081571a7a1Sriastradh 		UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE,
8091571a7a1Sriastradh 		&smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) {
8101571a7a1Sriastradh 		pr_err("Error when Populate Firmware Entry.\n");
8111571a7a1Sriastradh 		goto err0;
8121571a7a1Sriastradh 	}
8131571a7a1Sriastradh 
8141571a7a1Sriastradh 	if (0 != smu8_smu_populate_single_scratch_entry(hwmgr,
8151571a7a1Sriastradh 		SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
8161571a7a1Sriastradh 		sizeof(struct SMU8_MultimediaPowerLogData),
8171571a7a1Sriastradh 		&smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) {
8181571a7a1Sriastradh 		pr_err("Error when Populate Firmware Entry.\n");
8191571a7a1Sriastradh 		goto err0;
8201571a7a1Sriastradh 	}
8211571a7a1Sriastradh 
8221571a7a1Sriastradh 	if (0 != smu8_smu_populate_single_scratch_entry(hwmgr,
8231571a7a1Sriastradh 		SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
8241571a7a1Sriastradh 		sizeof(struct SMU8_Fusion_ClkTable),
8251571a7a1Sriastradh 		&smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) {
8261571a7a1Sriastradh 		pr_err("Error when Populate Firmware Entry.\n");
8271571a7a1Sriastradh 		goto err0;
8281571a7a1Sriastradh 	}
8291571a7a1Sriastradh 
8301571a7a1Sriastradh 	return 0;
8311571a7a1Sriastradh 
8321571a7a1Sriastradh err0:
8331571a7a1Sriastradh 	amdgpu_bo_free_kernel(&smu8_smu->smu_buffer.handle,
8341571a7a1Sriastradh 				&smu8_smu->smu_buffer.mc_addr,
8351571a7a1Sriastradh 				&smu8_smu->smu_buffer.kaddr);
8361571a7a1Sriastradh err1:
8371571a7a1Sriastradh 	amdgpu_bo_free_kernel(&smu8_smu->toc_buffer.handle,
8381571a7a1Sriastradh 				&smu8_smu->toc_buffer.mc_addr,
8391571a7a1Sriastradh 				&smu8_smu->toc_buffer.kaddr);
8401571a7a1Sriastradh err2:
8411571a7a1Sriastradh 	kfree(smu8_smu);
8421571a7a1Sriastradh 	return -EINVAL;
8431571a7a1Sriastradh }
8441571a7a1Sriastradh 
smu8_smu_fini(struct pp_hwmgr * hwmgr)8451571a7a1Sriastradh static int smu8_smu_fini(struct pp_hwmgr *hwmgr)
8461571a7a1Sriastradh {
8471571a7a1Sriastradh 	struct smu8_smumgr *smu8_smu;
8481571a7a1Sriastradh 
8491571a7a1Sriastradh 	if (hwmgr == NULL || hwmgr->device == NULL)
8501571a7a1Sriastradh 		return -EINVAL;
8511571a7a1Sriastradh 
8521571a7a1Sriastradh 	smu8_smu = hwmgr->smu_backend;
8531571a7a1Sriastradh 	if (smu8_smu) {
8541571a7a1Sriastradh 		amdgpu_bo_free_kernel(&smu8_smu->toc_buffer.handle,
8551571a7a1Sriastradh 					&smu8_smu->toc_buffer.mc_addr,
8561571a7a1Sriastradh 					&smu8_smu->toc_buffer.kaddr);
8571571a7a1Sriastradh 		amdgpu_bo_free_kernel(&smu8_smu->smu_buffer.handle,
8581571a7a1Sriastradh 					&smu8_smu->smu_buffer.mc_addr,
8591571a7a1Sriastradh 					&smu8_smu->smu_buffer.kaddr);
8601571a7a1Sriastradh 		kfree(smu8_smu);
8611571a7a1Sriastradh 	}
8621571a7a1Sriastradh 
8631571a7a1Sriastradh 	return 0;
8641571a7a1Sriastradh }
8651571a7a1Sriastradh 
smu8_dpm_check_smu_features(struct pp_hwmgr * hwmgr,unsigned long check_feature)8661571a7a1Sriastradh static bool smu8_dpm_check_smu_features(struct pp_hwmgr *hwmgr,
8671571a7a1Sriastradh 				unsigned long check_feature)
8681571a7a1Sriastradh {
8691571a7a1Sriastradh 	int result;
8701571a7a1Sriastradh 	unsigned long features;
8711571a7a1Sriastradh 
8721571a7a1Sriastradh 	result = smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetFeatureStatus, 0);
8731571a7a1Sriastradh 	if (result == 0) {
8741571a7a1Sriastradh 		features = smum_get_argument(hwmgr);
8751571a7a1Sriastradh 		if (features & check_feature)
8761571a7a1Sriastradh 			return true;
8771571a7a1Sriastradh 	}
8781571a7a1Sriastradh 
8791571a7a1Sriastradh 	return false;
8801571a7a1Sriastradh }
8811571a7a1Sriastradh 
smu8_is_dpm_running(struct pp_hwmgr * hwmgr)8821571a7a1Sriastradh static bool smu8_is_dpm_running(struct pp_hwmgr *hwmgr)
8831571a7a1Sriastradh {
8841571a7a1Sriastradh 	if (smu8_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn))
8851571a7a1Sriastradh 		return true;
8861571a7a1Sriastradh 	return false;
8871571a7a1Sriastradh }
8881571a7a1Sriastradh 
8891571a7a1Sriastradh const struct pp_smumgr_func smu8_smu_funcs = {
8901571a7a1Sriastradh 	.name = "smu8_smu",
8911571a7a1Sriastradh 	.smu_init = smu8_smu_init,
8921571a7a1Sriastradh 	.smu_fini = smu8_smu_fini,
8931571a7a1Sriastradh 	.start_smu = smu8_start_smu,
8941571a7a1Sriastradh 	.check_fw_load_finish = smu8_check_fw_load_finish,
8951571a7a1Sriastradh 	.request_smu_load_fw = NULL,
8961571a7a1Sriastradh 	.request_smu_load_specific_fw = NULL,
8971571a7a1Sriastradh 	.get_argument = smu8_get_argument,
8981571a7a1Sriastradh 	.send_msg_to_smc = smu8_send_msg_to_smc,
8991571a7a1Sriastradh 	.send_msg_to_smc_with_parameter = smu8_send_msg_to_smc_with_parameter,
9001571a7a1Sriastradh 	.download_pptable_settings = smu8_download_pptable_settings,
9011571a7a1Sriastradh 	.upload_pptable_settings = smu8_upload_pptable_settings,
9021571a7a1Sriastradh 	.is_dpm_running = smu8_is_dpm_running,
9031571a7a1Sriastradh };
9041571a7a1Sriastradh 
905