1d03846afSChunming Zhou /*
2d03846afSChunming Zhou  * Copyright 2015 Advanced Micro Devices, Inc.
3d03846afSChunming Zhou  *
4d03846afSChunming Zhou  * Permission is hereby granted, free of charge, to any person obtaining a
5d03846afSChunming Zhou  * copy of this software and associated documentation files (the "Software"),
6d03846afSChunming Zhou  * to deal in the Software without restriction, including without limitation
7d03846afSChunming Zhou  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8d03846afSChunming Zhou  * and/or sell copies of the Software, and to permit persons to whom the
9d03846afSChunming Zhou  * Software is furnished to do so, subject to the following conditions:
10d03846afSChunming Zhou  *
11d03846afSChunming Zhou  * The above copyright notice and this permission notice shall be included in
12d03846afSChunming Zhou  * all copies or substantial portions of the Software.
13d03846afSChunming Zhou  *
14d03846afSChunming Zhou  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15d03846afSChunming Zhou  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16d03846afSChunming Zhou  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17d03846afSChunming Zhou  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18d03846afSChunming Zhou  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19d03846afSChunming Zhou  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20d03846afSChunming Zhou  * OTHER DEALINGS IN THE SOFTWARE.
21d03846afSChunming Zhou  *
22d03846afSChunming Zhou  *
23d03846afSChunming Zhou  */
2457ff96cfSChunming Zhou #include <linux/list.h>
25fdf2f6c5SSam Ravnborg #include <linux/pci.h>
2657ff96cfSChunming Zhou #include <linux/slab.h>
27fdf2f6c5SSam Ravnborg 
28bf3911b0SJammy Zhou #include <linux/firmware.h>
2957ff96cfSChunming Zhou #include <drm/amdgpu_drm.h>
30d03846afSChunming Zhou #include "amdgpu.h"
3125da4427SChunming Zhou #include "atom.h"
32bf3911b0SJammy Zhou #include "amdgpu_ucode.h"
33bf3911b0SJammy Zhou 
34d03846afSChunming Zhou struct amdgpu_cgs_device {
35d03846afSChunming Zhou 	struct cgs_device base;
36d03846afSChunming Zhou 	struct amdgpu_device *adev;
37d03846afSChunming Zhou };
38d03846afSChunming Zhou 
39d03846afSChunming Zhou #define CGS_FUNC_ADEV							\
40d03846afSChunming Zhou 	struct amdgpu_device *adev =					\
41d03846afSChunming Zhou 		((struct amdgpu_cgs_device *)cgs_device)->adev
42d03846afSChunming Zhou 
43ba89a3ecSRex Zhu 
amdgpu_cgs_read_register(struct cgs_device * cgs_device,unsigned int offset)445f95f003SSrinivasan Shanmugam static uint32_t amdgpu_cgs_read_register(struct cgs_device *cgs_device, unsigned int offset)
45d03846afSChunming Zhou {
46aba684d8SChunming Zhou 	CGS_FUNC_ADEV;
47aba684d8SChunming Zhou 	return RREG32(offset);
48d03846afSChunming Zhou }
49d03846afSChunming Zhou 
amdgpu_cgs_write_register(struct cgs_device * cgs_device,unsigned int offset,uint32_t value)505f95f003SSrinivasan Shanmugam static void amdgpu_cgs_write_register(struct cgs_device *cgs_device, unsigned int offset,
51d03846afSChunming Zhou 				      uint32_t value)
52d03846afSChunming Zhou {
53aba684d8SChunming Zhou 	CGS_FUNC_ADEV;
54aba684d8SChunming Zhou 	WREG32(offset, value);
55d03846afSChunming Zhou }
56d03846afSChunming Zhou 
amdgpu_cgs_read_ind_register(struct cgs_device * cgs_device,enum cgs_ind_reg space,unsigned int index)57110e6f26SDave Airlie static uint32_t amdgpu_cgs_read_ind_register(struct cgs_device *cgs_device,
58d03846afSChunming Zhou 					     enum cgs_ind_reg space,
595f95f003SSrinivasan Shanmugam 					     unsigned int index)
60d03846afSChunming Zhou {
61aba684d8SChunming Zhou 	CGS_FUNC_ADEV;
62aba684d8SChunming Zhou 	switch (space) {
63aba684d8SChunming Zhou 	case CGS_IND_REG__PCIE:
64aba684d8SChunming Zhou 		return RREG32_PCIE(index);
65aba684d8SChunming Zhou 	case CGS_IND_REG__SMC:
66aba684d8SChunming Zhou 		return RREG32_SMC(index);
67aba684d8SChunming Zhou 	case CGS_IND_REG__UVD_CTX:
68aba684d8SChunming Zhou 		return RREG32_UVD_CTX(index);
69aba684d8SChunming Zhou 	case CGS_IND_REG__DIDT:
70aba684d8SChunming Zhou 		return RREG32_DIDT(index);
71ccdbb20aSRex Zhu 	case CGS_IND_REG_GC_CAC:
72ccdbb20aSRex Zhu 		return RREG32_GC_CAC(index);
73c62a59d0SEvan Quan 	case CGS_IND_REG_SE_CAC:
74c62a59d0SEvan Quan 		return RREG32_SE_CAC(index);
75aba684d8SChunming Zhou 	case CGS_IND_REG__AUDIO_ENDPT:
76aba684d8SChunming Zhou 		DRM_ERROR("audio endpt register access not implemented.\n");
77aba684d8SChunming Zhou 		return 0;
783c888c16SHawking Zhang 	default:
793c888c16SHawking Zhang 		BUG();
80aba684d8SChunming Zhou 	}
81aba684d8SChunming Zhou 	WARN(1, "Invalid indirect register space");
82d03846afSChunming Zhou 	return 0;
83d03846afSChunming Zhou }
84d03846afSChunming Zhou 
amdgpu_cgs_write_ind_register(struct cgs_device * cgs_device,enum cgs_ind_reg space,unsigned int index,uint32_t value)85110e6f26SDave Airlie static void amdgpu_cgs_write_ind_register(struct cgs_device *cgs_device,
86d03846afSChunming Zhou 					  enum cgs_ind_reg space,
875f95f003SSrinivasan Shanmugam 					  unsigned int index, uint32_t value)
88d03846afSChunming Zhou {
89aba684d8SChunming Zhou 	CGS_FUNC_ADEV;
90aba684d8SChunming Zhou 	switch (space) {
91aba684d8SChunming Zhou 	case CGS_IND_REG__PCIE:
92aba684d8SChunming Zhou 		return WREG32_PCIE(index, value);
93aba684d8SChunming Zhou 	case CGS_IND_REG__SMC:
94aba684d8SChunming Zhou 		return WREG32_SMC(index, value);
95aba684d8SChunming Zhou 	case CGS_IND_REG__UVD_CTX:
96aba684d8SChunming Zhou 		return WREG32_UVD_CTX(index, value);
97aba684d8SChunming Zhou 	case CGS_IND_REG__DIDT:
98aba684d8SChunming Zhou 		return WREG32_DIDT(index, value);
99ccdbb20aSRex Zhu 	case CGS_IND_REG_GC_CAC:
100ccdbb20aSRex Zhu 		return WREG32_GC_CAC(index, value);
101c62a59d0SEvan Quan 	case CGS_IND_REG_SE_CAC:
102c62a59d0SEvan Quan 		return WREG32_SE_CAC(index, value);
103aba684d8SChunming Zhou 	case CGS_IND_REG__AUDIO_ENDPT:
104aba684d8SChunming Zhou 		DRM_ERROR("audio endpt register access not implemented.\n");
105d03846afSChunming Zhou 		return;
1063c888c16SHawking Zhang 	default:
1073c888c16SHawking Zhang 		BUG();
108d03846afSChunming Zhou 	}
109aba684d8SChunming Zhou 	WARN(1, "Invalid indirect register space");
110aba684d8SChunming Zhou }
111d03846afSChunming Zhou 
fw_type_convert(struct cgs_device * cgs_device,uint32_t fw_type)112110e6f26SDave Airlie static uint32_t fw_type_convert(struct cgs_device *cgs_device, uint32_t fw_type)
113bf3911b0SJammy Zhou {
114bf3911b0SJammy Zhou 	CGS_FUNC_ADEV;
115bf3911b0SJammy Zhou 	enum AMDGPU_UCODE_ID result = AMDGPU_UCODE_ID_MAXIMUM;
116bf3911b0SJammy Zhou 
117bf3911b0SJammy Zhou 	switch (fw_type) {
118bf3911b0SJammy Zhou 	case CGS_UCODE_ID_SDMA0:
119bf3911b0SJammy Zhou 		result = AMDGPU_UCODE_ID_SDMA0;
120bf3911b0SJammy Zhou 		break;
121bf3911b0SJammy Zhou 	case CGS_UCODE_ID_SDMA1:
122bf3911b0SJammy Zhou 		result = AMDGPU_UCODE_ID_SDMA1;
123bf3911b0SJammy Zhou 		break;
124bf3911b0SJammy Zhou 	case CGS_UCODE_ID_CP_CE:
125bf3911b0SJammy Zhou 		result = AMDGPU_UCODE_ID_CP_CE;
126bf3911b0SJammy Zhou 		break;
127bf3911b0SJammy Zhou 	case CGS_UCODE_ID_CP_PFP:
128bf3911b0SJammy Zhou 		result = AMDGPU_UCODE_ID_CP_PFP;
129bf3911b0SJammy Zhou 		break;
130bf3911b0SJammy Zhou 	case CGS_UCODE_ID_CP_ME:
131bf3911b0SJammy Zhou 		result = AMDGPU_UCODE_ID_CP_ME;
132bf3911b0SJammy Zhou 		break;
133bf3911b0SJammy Zhou 	case CGS_UCODE_ID_CP_MEC:
134bf3911b0SJammy Zhou 	case CGS_UCODE_ID_CP_MEC_JT1:
135bf3911b0SJammy Zhou 		result = AMDGPU_UCODE_ID_CP_MEC1;
136bf3911b0SJammy Zhou 		break;
137bf3911b0SJammy Zhou 	case CGS_UCODE_ID_CP_MEC_JT2:
1384c2b2453SMonk Liu 		/* for VI. JT2 should be the same as JT1, because:
1394c2b2453SMonk Liu 			1, MEC2 and MEC1 use exactly same FW.
1404c2b2453SMonk Liu 			2, JT2 is not pached but JT1 is.
1414c2b2453SMonk Liu 		*/
1424c2b2453SMonk Liu 		if (adev->asic_type >= CHIP_TOPAZ)
143bf3911b0SJammy Zhou 			result = AMDGPU_UCODE_ID_CP_MEC1;
1444c2b2453SMonk Liu 		else
1454c2b2453SMonk Liu 			result = AMDGPU_UCODE_ID_CP_MEC2;
146bf3911b0SJammy Zhou 		break;
147bf3911b0SJammy Zhou 	case CGS_UCODE_ID_RLC_G:
148bf3911b0SJammy Zhou 		result = AMDGPU_UCODE_ID_RLC_G;
149bf3911b0SJammy Zhou 		break;
150bed5712eSMonk Liu 	case CGS_UCODE_ID_STORAGE:
151bed5712eSMonk Liu 		result = AMDGPU_UCODE_ID_STORAGE;
152bed5712eSMonk Liu 		break;
153bf3911b0SJammy Zhou 	default:
154bf3911b0SJammy Zhou 		DRM_ERROR("Firmware type not supported\n");
155bf3911b0SJammy Zhou 	}
156bf3911b0SJammy Zhou 	return result;
157bf3911b0SJammy Zhou }
158bf3911b0SJammy Zhou 
amdgpu_get_firmware_version(struct cgs_device * cgs_device,enum cgs_ucode_id type)159fc76cbf4SFrank Min static uint16_t amdgpu_get_firmware_version(struct cgs_device *cgs_device,
160fc76cbf4SFrank Min 					enum cgs_ucode_id type)
161fc76cbf4SFrank Min {
162fc76cbf4SFrank Min 	CGS_FUNC_ADEV;
163188a301fSXiangliang Yu 	uint16_t fw_version = 0;
164fc76cbf4SFrank Min 
165fc76cbf4SFrank Min 	switch (type) {
166fc76cbf4SFrank Min 	case CGS_UCODE_ID_SDMA0:
167fc76cbf4SFrank Min 		fw_version = adev->sdma.instance[0].fw_version;
168fc76cbf4SFrank Min 		break;
169fc76cbf4SFrank Min 	case CGS_UCODE_ID_SDMA1:
170fc76cbf4SFrank Min 		fw_version = adev->sdma.instance[1].fw_version;
171fc76cbf4SFrank Min 		break;
172fc76cbf4SFrank Min 	case CGS_UCODE_ID_CP_CE:
173fc76cbf4SFrank Min 		fw_version = adev->gfx.ce_fw_version;
174fc76cbf4SFrank Min 		break;
175fc76cbf4SFrank Min 	case CGS_UCODE_ID_CP_PFP:
176fc76cbf4SFrank Min 		fw_version = adev->gfx.pfp_fw_version;
177fc76cbf4SFrank Min 		break;
178fc76cbf4SFrank Min 	case CGS_UCODE_ID_CP_ME:
179fc76cbf4SFrank Min 		fw_version = adev->gfx.me_fw_version;
180fc76cbf4SFrank Min 		break;
181fc76cbf4SFrank Min 	case CGS_UCODE_ID_CP_MEC:
182fc76cbf4SFrank Min 		fw_version = adev->gfx.mec_fw_version;
183fc76cbf4SFrank Min 		break;
184fc76cbf4SFrank Min 	case CGS_UCODE_ID_CP_MEC_JT1:
185fc76cbf4SFrank Min 		fw_version = adev->gfx.mec_fw_version;
186fc76cbf4SFrank Min 		break;
187fc76cbf4SFrank Min 	case CGS_UCODE_ID_CP_MEC_JT2:
188fc76cbf4SFrank Min 		fw_version = adev->gfx.mec_fw_version;
189fc76cbf4SFrank Min 		break;
190fc76cbf4SFrank Min 	case CGS_UCODE_ID_RLC_G:
191fc76cbf4SFrank Min 		fw_version = adev->gfx.rlc_fw_version;
192fc76cbf4SFrank Min 		break;
193188a301fSXiangliang Yu 	case CGS_UCODE_ID_STORAGE:
194188a301fSXiangliang Yu 		break;
195fc76cbf4SFrank Min 	default:
196fc76cbf4SFrank Min 		DRM_ERROR("firmware type %d do not have version\n", type);
197188a301fSXiangliang Yu 		break;
198fc76cbf4SFrank Min 	}
199fc76cbf4SFrank Min 	return fw_version;
200fc76cbf4SFrank Min }
201fc76cbf4SFrank Min 
amdgpu_cgs_get_firmware_info(struct cgs_device * cgs_device,enum cgs_ucode_id type,struct cgs_firmware_info * info)202110e6f26SDave Airlie static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
203bf3911b0SJammy Zhou 					enum cgs_ucode_id type,
204bf3911b0SJammy Zhou 					struct cgs_firmware_info *info)
205bf3911b0SJammy Zhou {
206bf3911b0SJammy Zhou 	CGS_FUNC_ADEV;
207bf3911b0SJammy Zhou 
2085f95f003SSrinivasan Shanmugam 	if (type != CGS_UCODE_ID_SMU && type != CGS_UCODE_ID_SMU_SK) {
209bf3911b0SJammy Zhou 		uint64_t gpu_addr;
210bf3911b0SJammy Zhou 		uint32_t data_size;
211bf3911b0SJammy Zhou 		const struct gfx_firmware_header_v1_0 *header;
212bf3911b0SJammy Zhou 		enum AMDGPU_UCODE_ID id;
213bf3911b0SJammy Zhou 		struct amdgpu_firmware_info *ucode;
214bf3911b0SJammy Zhou 
215bf3911b0SJammy Zhou 		id = fw_type_convert(cgs_device, type);
2168944acd0STim Huang 		if (id >= AMDGPU_UCODE_ID_MAXIMUM)
2178944acd0STim Huang 			return -EINVAL;
2188944acd0STim Huang 
219bf3911b0SJammy Zhou 		ucode = &adev->firmware.ucode[id];
220bf3911b0SJammy Zhou 		if (ucode->fw == NULL)
221bf3911b0SJammy Zhou 			return -EINVAL;
222bf3911b0SJammy Zhou 
223bf3911b0SJammy Zhou 		gpu_addr  = ucode->mc_addr;
224bf3911b0SJammy Zhou 		header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
225bf3911b0SJammy Zhou 		data_size = le32_to_cpu(header->header.ucode_size_bytes);
226bf3911b0SJammy Zhou 
227bf3911b0SJammy Zhou 		if ((type == CGS_UCODE_ID_CP_MEC_JT1) ||
228bf3911b0SJammy Zhou 		    (type == CGS_UCODE_ID_CP_MEC_JT2)) {
2294c2b2453SMonk Liu 			gpu_addr += ALIGN(le32_to_cpu(header->header.ucode_size_bytes), PAGE_SIZE);
230bf3911b0SJammy Zhou 			data_size = le32_to_cpu(header->jt_size) << 2;
231bf3911b0SJammy Zhou 		}
2324c2b2453SMonk Liu 
2334c2b2453SMonk Liu 		info->kptr = ucode->kaddr;
234bf3911b0SJammy Zhou 		info->image_size = data_size;
2354c2b2453SMonk Liu 		info->mc_addr = gpu_addr;
236bf3911b0SJammy Zhou 		info->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
2374c2b2453SMonk Liu 
2385f95f003SSrinivasan Shanmugam 		if (type == CGS_UCODE_ID_CP_MEC)
239e68760bfSEvan Quan 			info->image_size = le32_to_cpu(header->jt_offset) << 2;
2404c2b2453SMonk Liu 
241fc76cbf4SFrank Min 		info->fw_version = amdgpu_get_firmware_version(cgs_device, type);
242bf3911b0SJammy Zhou 		info->feature_version = (uint16_t)le32_to_cpu(header->ucode_feature_version);
243bf3911b0SJammy Zhou 	} else {
244bf3911b0SJammy Zhou 		char fw_name[30] = {0};
245bf3911b0SJammy Zhou 		int err = 0;
246bf3911b0SJammy Zhou 		uint32_t ucode_size;
247bf3911b0SJammy Zhou 		uint32_t ucode_start_address;
248bf3911b0SJammy Zhou 		const uint8_t *src;
249bf3911b0SJammy Zhou 		const struct smc_firmware_header_v1_0 *hdr;
250d1de1ed3SHuang Rui 		const struct common_firmware_header *header;
251d1de1ed3SHuang Rui 		struct amdgpu_firmware_info *ucode = NULL;
252bf3911b0SJammy Zhou 
2530b45541dSMykola Lysenko 		if (!adev->pm.fw) {
254bf3911b0SJammy Zhou 			switch (adev->asic_type) {
2556df9855fSRex Zhu 			case CHIP_TAHITI:
2566df9855fSRex Zhu 				strcpy(fw_name, "radeon/tahiti_smc.bin");
2576df9855fSRex Zhu 				break;
2586df9855fSRex Zhu 			case CHIP_PITCAIRN:
2596df9855fSRex Zhu 				if ((adev->pdev->revision == 0x81) &&
2606df9855fSRex Zhu 				    ((adev->pdev->device == 0x6810) ||
2616df9855fSRex Zhu 				    (adev->pdev->device == 0x6811))) {
2626df9855fSRex Zhu 					info->is_kicker = true;
2636df9855fSRex Zhu 					strcpy(fw_name, "radeon/pitcairn_k_smc.bin");
2646df9855fSRex Zhu 				} else {
2656df9855fSRex Zhu 					strcpy(fw_name, "radeon/pitcairn_smc.bin");
2666df9855fSRex Zhu 				}
2676df9855fSRex Zhu 				break;
2686df9855fSRex Zhu 			case CHIP_VERDE:
2696df9855fSRex Zhu 				if (((adev->pdev->device == 0x6820) &&
2706df9855fSRex Zhu 					((adev->pdev->revision == 0x81) ||
2716df9855fSRex Zhu 					(adev->pdev->revision == 0x83))) ||
2726df9855fSRex Zhu 				    ((adev->pdev->device == 0x6821) &&
2736df9855fSRex Zhu 					((adev->pdev->revision == 0x83) ||
2746df9855fSRex Zhu 					(adev->pdev->revision == 0x87))) ||
2756df9855fSRex Zhu 				    ((adev->pdev->revision == 0x87) &&
2766df9855fSRex Zhu 					((adev->pdev->device == 0x6823) ||
2776df9855fSRex Zhu 					(adev->pdev->device == 0x682b)))) {
2786df9855fSRex Zhu 					info->is_kicker = true;
2796df9855fSRex Zhu 					strcpy(fw_name, "radeon/verde_k_smc.bin");
2806df9855fSRex Zhu 				} else {
2816df9855fSRex Zhu 					strcpy(fw_name, "radeon/verde_smc.bin");
2826df9855fSRex Zhu 				}
2836df9855fSRex Zhu 				break;
2846df9855fSRex Zhu 			case CHIP_OLAND:
2856df9855fSRex Zhu 				if (((adev->pdev->revision == 0x81) &&
2866df9855fSRex Zhu 					((adev->pdev->device == 0x6600) ||
2876df9855fSRex Zhu 					(adev->pdev->device == 0x6604) ||
2886df9855fSRex Zhu 					(adev->pdev->device == 0x6605) ||
2896df9855fSRex Zhu 					(adev->pdev->device == 0x6610))) ||
2906df9855fSRex Zhu 				    ((adev->pdev->revision == 0x83) &&
2916df9855fSRex Zhu 					(adev->pdev->device == 0x6610))) {
2926df9855fSRex Zhu 					info->is_kicker = true;
2936df9855fSRex Zhu 					strcpy(fw_name, "radeon/oland_k_smc.bin");
2946df9855fSRex Zhu 				} else {
2956df9855fSRex Zhu 					strcpy(fw_name, "radeon/oland_smc.bin");
2966df9855fSRex Zhu 				}
2976df9855fSRex Zhu 				break;
2986df9855fSRex Zhu 			case CHIP_HAINAN:
2996df9855fSRex Zhu 				if (((adev->pdev->revision == 0x81) &&
3006df9855fSRex Zhu 					(adev->pdev->device == 0x6660)) ||
3016df9855fSRex Zhu 				    ((adev->pdev->revision == 0x83) &&
3026df9855fSRex Zhu 					((adev->pdev->device == 0x6660) ||
3036df9855fSRex Zhu 					(adev->pdev->device == 0x6663) ||
3046df9855fSRex Zhu 					(adev->pdev->device == 0x6665) ||
3056df9855fSRex Zhu 					 (adev->pdev->device == 0x6667)))) {
3066df9855fSRex Zhu 					info->is_kicker = true;
3076df9855fSRex Zhu 					strcpy(fw_name, "radeon/hainan_k_smc.bin");
3086df9855fSRex Zhu 				} else if ((adev->pdev->revision == 0xc3) &&
3096df9855fSRex Zhu 					 (adev->pdev->device == 0x6665)) {
3106df9855fSRex Zhu 					info->is_kicker = true;
3116df9855fSRex Zhu 					strcpy(fw_name, "radeon/banks_k_2_smc.bin");
3126df9855fSRex Zhu 				} else {
3136df9855fSRex Zhu 					strcpy(fw_name, "radeon/hainan_smc.bin");
3146df9855fSRex Zhu 				}
3156df9855fSRex Zhu 				break;
3166df9855fSRex Zhu 			case CHIP_BONAIRE:
3176df9855fSRex Zhu 				if ((adev->pdev->revision == 0x80) ||
3186df9855fSRex Zhu 					(adev->pdev->revision == 0x81) ||
3196df9855fSRex Zhu 					(adev->pdev->device == 0x665f)) {
3206df9855fSRex Zhu 					info->is_kicker = true;
321ce206464SAlex Deucher 					strcpy(fw_name, "amdgpu/bonaire_k_smc.bin");
3226df9855fSRex Zhu 				} else {
323ce206464SAlex Deucher 					strcpy(fw_name, "amdgpu/bonaire_smc.bin");
3246df9855fSRex Zhu 				}
3256df9855fSRex Zhu 				break;
3266df9855fSRex Zhu 			case CHIP_HAWAII:
3276df9855fSRex Zhu 				if (adev->pdev->revision == 0x80) {
3286df9855fSRex Zhu 					info->is_kicker = true;
329ce206464SAlex Deucher 					strcpy(fw_name, "amdgpu/hawaii_k_smc.bin");
3306df9855fSRex Zhu 				} else {
331ce206464SAlex Deucher 					strcpy(fw_name, "amdgpu/hawaii_smc.bin");
3326df9855fSRex Zhu 				}
3336df9855fSRex Zhu 				break;
334340efe28SHuang Rui 			case CHIP_TOPAZ:
3353b496626SAlex Deucher 				if (((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0x81)) ||
3363b496626SAlex Deucher 				    ((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0x83)) ||
337153573d8SAlex Deucher 				    ((adev->pdev->device == 0x6907) && (adev->pdev->revision == 0x87)) ||
338153573d8SAlex Deucher 				    ((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0xD1)) ||
339153573d8SAlex Deucher 				    ((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0xD3))) {
3405d7213b0SHuang Rui 					info->is_kicker = true;
3413b496626SAlex Deucher 					strcpy(fw_name, "amdgpu/topaz_k_smc.bin");
3425d7213b0SHuang Rui 				} else
343340efe28SHuang Rui 					strcpy(fw_name, "amdgpu/topaz_smc.bin");
344340efe28SHuang Rui 				break;
345bf3911b0SJammy Zhou 			case CHIP_TONGA:
346646cccb5SAlex Deucher 				if (((adev->pdev->device == 0x6939) && (adev->pdev->revision == 0xf1)) ||
3475d7213b0SHuang Rui 				    ((adev->pdev->device == 0x6938) && (adev->pdev->revision == 0xf1))) {
3485d7213b0SHuang Rui 					info->is_kicker = true;
349646cccb5SAlex Deucher 					strcpy(fw_name, "amdgpu/tonga_k_smc.bin");
3505d7213b0SHuang Rui 				} else
351bf3911b0SJammy Zhou 					strcpy(fw_name, "amdgpu/tonga_smc.bin");
352bf3911b0SJammy Zhou 				break;
353899fa4c0SEric Huang 			case CHIP_FIJI:
354899fa4c0SEric Huang 				strcpy(fw_name, "amdgpu/fiji_smc.bin");
355899fa4c0SEric Huang 				break;
3562cc0c0b5SFlora Cui 			case CHIP_POLARIS11:
357a52d120fSAlex Deucher 				if (type == CGS_UCODE_ID_SMU) {
35873275181SEvan Quan 					if (ASICID_IS_P21(adev->pdev->device, adev->pdev->revision)) {
3595d7213b0SHuang Rui 						info->is_kicker = true;
360a52d120fSAlex Deucher 						strcpy(fw_name, "amdgpu/polaris11_k_smc.bin");
36173275181SEvan Quan 					} else if (ASICID_IS_P31(adev->pdev->device, adev->pdev->revision)) {
362153573d8SAlex Deucher 						info->is_kicker = true;
363153573d8SAlex Deucher 						strcpy(fw_name, "amdgpu/polaris11_k2_smc.bin");
364153573d8SAlex Deucher 					} else {
3652cc0c0b5SFlora Cui 						strcpy(fw_name, "amdgpu/polaris11_smc.bin");
366153573d8SAlex Deucher 					}
367a52d120fSAlex Deucher 				} else if (type == CGS_UCODE_ID_SMU_SK) {
3682cc0c0b5SFlora Cui 					strcpy(fw_name, "amdgpu/polaris11_smc_sk.bin");
369a52d120fSAlex Deucher 				}
370c8172625Srezhu 				break;
3712cc0c0b5SFlora Cui 			case CHIP_POLARIS10:
372a52d120fSAlex Deucher 				if (type == CGS_UCODE_ID_SMU) {
37373275181SEvan Quan 					if (ASICID_IS_P20(adev->pdev->device, adev->pdev->revision)) {
3745d7213b0SHuang Rui 						info->is_kicker = true;
375a52d120fSAlex Deucher 						strcpy(fw_name, "amdgpu/polaris10_k_smc.bin");
37673275181SEvan Quan 					} else if (ASICID_IS_P30(adev->pdev->device, adev->pdev->revision)) {
377153573d8SAlex Deucher 						info->is_kicker = true;
378153573d8SAlex Deucher 						strcpy(fw_name, "amdgpu/polaris10_k2_smc.bin");
379153573d8SAlex Deucher 					} else {
3802cc0c0b5SFlora Cui 						strcpy(fw_name, "amdgpu/polaris10_smc.bin");
381153573d8SAlex Deucher 					}
382a52d120fSAlex Deucher 				} else if (type == CGS_UCODE_ID_SMU_SK) {
3832cc0c0b5SFlora Cui 					strcpy(fw_name, "amdgpu/polaris10_smc_sk.bin");
384a52d120fSAlex Deucher 				}
385c8172625Srezhu 				break;
386c4642a47SJunwei Zhang 			case CHIP_POLARIS12:
38773275181SEvan Quan 				if (ASICID_IS_P23(adev->pdev->device, adev->pdev->revision)) {
388153573d8SAlex Deucher 					info->is_kicker = true;
389153573d8SAlex Deucher 					strcpy(fw_name, "amdgpu/polaris12_k_smc.bin");
390153573d8SAlex Deucher 				} else {
391c4642a47SJunwei Zhang 					strcpy(fw_name, "amdgpu/polaris12_smc.bin");
392153573d8SAlex Deucher 				}
393c4642a47SJunwei Zhang 				break;
3945830bb98SLeo Liu 			case CHIP_VEGAM:
3955830bb98SLeo Liu 				strcpy(fw_name, "amdgpu/vegam_smc.bin");
3965830bb98SLeo Liu 				break;
397220ab9bdSKen Wang 			case CHIP_VEGA10:
398747f6c92SEvan Quan 				if ((adev->pdev->device == 0x687f) &&
399747f6c92SEvan Quan 					((adev->pdev->revision == 0xc0) ||
400747f6c92SEvan Quan 					(adev->pdev->revision == 0xc1) ||
401747f6c92SEvan Quan 					(adev->pdev->revision == 0xc3)))
402747f6c92SEvan Quan 					strcpy(fw_name, "amdgpu/vega10_acg_smc.bin");
403747f6c92SEvan Quan 				else
404220ab9bdSKen Wang 					strcpy(fw_name, "amdgpu/vega10_smc.bin");
405220ab9bdSKen Wang 				break;
406ad0ad9aaSHawking Zhang 			case CHIP_VEGA12:
407ad0ad9aaSHawking Zhang 				strcpy(fw_name, "amdgpu/vega12_smc.bin");
408ad0ad9aaSHawking Zhang 				break;
409a167ae25SFeifei Xu 			case CHIP_VEGA20:
410a167ae25SFeifei Xu 				strcpy(fw_name, "amdgpu/vega20_smc.bin");
411a167ae25SFeifei Xu 				break;
412bf3911b0SJammy Zhou 			default:
413bf3911b0SJammy Zhou 				DRM_ERROR("SMC firmware not supported\n");
414bf3911b0SJammy Zhou 				return -EINVAL;
415bf3911b0SJammy Zhou 			}
416bf3911b0SJammy Zhou 
417*ea5d4934SMario Limonciello 			err = amdgpu_ucode_request(adev, &adev->pm.fw,
418*ea5d4934SMario Limonciello 						   AMDGPU_UCODE_REQUIRED,
419*ea5d4934SMario Limonciello 						   "%s", fw_name);
420bf3911b0SJammy Zhou 			if (err) {
421bf3911b0SJammy Zhou 				DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
422e5a7d047SMario Limonciello 				amdgpu_ucode_release(&adev->pm.fw);
423bf3911b0SJammy Zhou 				return err;
424bf3911b0SJammy Zhou 			}
425d1de1ed3SHuang Rui 
426d1de1ed3SHuang Rui 			if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
427d1de1ed3SHuang Rui 				ucode = &adev->firmware.ucode[AMDGPU_UCODE_ID_SMC];
428d1de1ed3SHuang Rui 				ucode->ucode_id = AMDGPU_UCODE_ID_SMC;
429d1de1ed3SHuang Rui 				ucode->fw = adev->pm.fw;
430d1de1ed3SHuang Rui 				header = (const struct common_firmware_header *)ucode->fw->data;
431d1de1ed3SHuang Rui 				adev->firmware.fw_size +=
432d1de1ed3SHuang Rui 					ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE);
433d1de1ed3SHuang Rui 			}
4340b45541dSMykola Lysenko 		}
435bf3911b0SJammy Zhou 
436bf3911b0SJammy Zhou 		hdr = (const struct smc_firmware_header_v1_0 *)	adev->pm.fw->data;
437c66875b1Syanyang1 		amdgpu_ucode_print_smc_hdr(&hdr->header);
438bf3911b0SJammy Zhou 		adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
439bf3911b0SJammy Zhou 		ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
440bf3911b0SJammy Zhou 		ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
441bf3911b0SJammy Zhou 		src = (const uint8_t *)(adev->pm.fw->data +
442bf3911b0SJammy Zhou 		       le32_to_cpu(hdr->header.ucode_array_offset_bytes));
443bf3911b0SJammy Zhou 
444bf3911b0SJammy Zhou 		info->version = adev->pm.fw_version;
445bf3911b0SJammy Zhou 		info->image_size = ucode_size;
446340efe28SHuang Rui 		info->ucode_start_address = ucode_start_address;
447bf3911b0SJammy Zhou 		info->kptr = (void *)src;
448bf3911b0SJammy Zhou 	}
449bf3911b0SJammy Zhou 	return 0;
450bf3911b0SJammy Zhou }
451bf3911b0SJammy Zhou 
452d03846afSChunming Zhou static const struct cgs_ops amdgpu_cgs_ops = {
453613e61a0SKees Cook 	.read_register = amdgpu_cgs_read_register,
454613e61a0SKees Cook 	.write_register = amdgpu_cgs_write_register,
455613e61a0SKees Cook 	.read_ind_register = amdgpu_cgs_read_ind_register,
456613e61a0SKees Cook 	.write_ind_register = amdgpu_cgs_write_ind_register,
457613e61a0SKees Cook 	.get_firmware_info = amdgpu_cgs_get_firmware_info,
458d03846afSChunming Zhou };
459d03846afSChunming Zhou 
amdgpu_cgs_create_device(struct amdgpu_device * adev)460110e6f26SDave Airlie struct cgs_device *amdgpu_cgs_create_device(struct amdgpu_device *adev)
461d03846afSChunming Zhou {
462d03846afSChunming Zhou 	struct amdgpu_cgs_device *cgs_device =
463d03846afSChunming Zhou 		kmalloc(sizeof(*cgs_device), GFP_KERNEL);
464d03846afSChunming Zhou 
465d03846afSChunming Zhou 	if (!cgs_device) {
466d03846afSChunming Zhou 		DRM_ERROR("Couldn't allocate CGS device structure\n");
467d03846afSChunming Zhou 		return NULL;
468d03846afSChunming Zhou 	}
469d03846afSChunming Zhou 
470d03846afSChunming Zhou 	cgs_device->base.ops = &amdgpu_cgs_ops;
471d03846afSChunming Zhou 	cgs_device->adev = adev;
472d03846afSChunming Zhou 
473110e6f26SDave Airlie 	return (struct cgs_device *)cgs_device;
474d03846afSChunming Zhou }
475d03846afSChunming Zhou 
amdgpu_cgs_destroy_device(struct cgs_device * cgs_device)476110e6f26SDave Airlie void amdgpu_cgs_destroy_device(struct cgs_device *cgs_device)
477d03846afSChunming Zhou {
478d03846afSChunming Zhou 	kfree(cgs_device);
479d03846afSChunming Zhou }
480