1a5bde2f9SAlex Deucher /*
2a5bde2f9SAlex Deucher  * Copyright 2016 Advanced Micro Devices, Inc.
3a5bde2f9SAlex Deucher  *
4a5bde2f9SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
5a5bde2f9SAlex Deucher  * copy of this software and associated documentation files (the "Software"),
6a5bde2f9SAlex Deucher  * to deal in the Software without restriction, including without limitation
7a5bde2f9SAlex Deucher  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8a5bde2f9SAlex Deucher  * and/or sell copies of the Software, and to permit persons to whom the
9a5bde2f9SAlex Deucher  * Software is furnished to do so, subject to the following conditions:
10a5bde2f9SAlex Deucher  *
11a5bde2f9SAlex Deucher  * The above copyright notice and this permission notice shall be included in
12a5bde2f9SAlex Deucher  * all copies or substantial portions of the Software.
13a5bde2f9SAlex Deucher  *
14a5bde2f9SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15a5bde2f9SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16a5bde2f9SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17a5bde2f9SAlex Deucher  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18a5bde2f9SAlex Deucher  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19a5bde2f9SAlex Deucher  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20a5bde2f9SAlex Deucher  * OTHER DEALINGS IN THE SOFTWARE.
21a5bde2f9SAlex Deucher  *
22a5bde2f9SAlex Deucher  */
23fdf2f6c5SSam Ravnborg 
24a5bde2f9SAlex Deucher #include <drm/amdgpu_drm.h>
25a5bde2f9SAlex Deucher #include "amdgpu.h"
26a5bde2f9SAlex Deucher #include "atomfirmware.h"
27a5bde2f9SAlex Deucher #include "amdgpu_atomfirmware.h"
28a5bde2f9SAlex Deucher #include "atom.h"
29692bb1acSHuang Rui #include "atombios.h"
30efe4f000STianci.Yin #include "soc15_hw_ip.h"
31a5bde2f9SAlex Deucher 
325968c6a2SHawking Zhang union firmware_info {
335968c6a2SHawking Zhang 	struct atom_firmware_info_v3_1 v31;
345968c6a2SHawking Zhang 	struct atom_firmware_info_v3_2 v32;
355968c6a2SHawking Zhang 	struct atom_firmware_info_v3_3 v33;
365968c6a2SHawking Zhang 	struct atom_firmware_info_v3_4 v34;
375968c6a2SHawking Zhang };
385968c6a2SHawking Zhang 
395968c6a2SHawking Zhang /*
405968c6a2SHawking Zhang  * Helper function to query firmware capability
415968c6a2SHawking Zhang  *
425968c6a2SHawking Zhang  * @adev: amdgpu_device pointer
435968c6a2SHawking Zhang  *
445968c6a2SHawking Zhang  * Return firmware_capability in firmwareinfo table on success or 0 if not
455968c6a2SHawking Zhang  */
amdgpu_atomfirmware_query_firmware_capability(struct amdgpu_device * adev)465968c6a2SHawking Zhang uint32_t amdgpu_atomfirmware_query_firmware_capability(struct amdgpu_device *adev)
475968c6a2SHawking Zhang {
485968c6a2SHawking Zhang 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
495968c6a2SHawking Zhang 	int index;
505968c6a2SHawking Zhang 	u16 data_offset, size;
515968c6a2SHawking Zhang 	union firmware_info *firmware_info;
525968c6a2SHawking Zhang 	u8 frev, crev;
535968c6a2SHawking Zhang 	u32 fw_cap = 0;
545968c6a2SHawking Zhang 
555968c6a2SHawking Zhang 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
565968c6a2SHawking Zhang 			firmwareinfo);
575968c6a2SHawking Zhang 
585968c6a2SHawking Zhang 	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context,
595968c6a2SHawking Zhang 				index, &size, &frev, &crev, &data_offset)) {
605968c6a2SHawking Zhang 		/* support firmware_info 3.1 + */
615968c6a2SHawking Zhang 		if ((frev == 3 && crev >= 1) || (frev > 3)) {
625968c6a2SHawking Zhang 			firmware_info = (union firmware_info *)
635968c6a2SHawking Zhang 				(mode_info->atom_context->bios + data_offset);
645968c6a2SHawking Zhang 			fw_cap = le32_to_cpu(firmware_info->v31.firmware_capability);
655968c6a2SHawking Zhang 		}
665968c6a2SHawking Zhang 	}
675968c6a2SHawking Zhang 
685968c6a2SHawking Zhang 	return fw_cap;
695968c6a2SHawking Zhang }
705968c6a2SHawking Zhang 
7158ff791aSHawking Zhang /*
7258ff791aSHawking Zhang  * Helper function to query gpu virtualizaiton capability
7358ff791aSHawking Zhang  *
7458ff791aSHawking Zhang  * @adev: amdgpu_device pointer
7558ff791aSHawking Zhang  *
7658ff791aSHawking Zhang  * Return true if gpu virtualization is supported or false if not
7758ff791aSHawking Zhang  */
amdgpu_atomfirmware_gpu_virtualization_supported(struct amdgpu_device * adev)7858ff791aSHawking Zhang bool amdgpu_atomfirmware_gpu_virtualization_supported(struct amdgpu_device *adev)
79a5bde2f9SAlex Deucher {
8058ff791aSHawking Zhang 	u32 fw_cap;
81a5bde2f9SAlex Deucher 
8258ff791aSHawking Zhang 	fw_cap = adev->mode_info.firmware_flags;
83a5bde2f9SAlex Deucher 
8458ff791aSHawking Zhang 	return (fw_cap & ATOM_FIRMWARE_CAP_GPU_VIRTUALIZATION) ? true : false;
85a5bde2f9SAlex Deucher }
86a5bde2f9SAlex Deucher 
amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device * adev)87a5bde2f9SAlex Deucher void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev)
88a5bde2f9SAlex Deucher {
89a5bde2f9SAlex Deucher 	int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
90a5bde2f9SAlex Deucher 						firmwareinfo);
91a5bde2f9SAlex Deucher 	uint16_t data_offset;
92a5bde2f9SAlex Deucher 
93a5bde2f9SAlex Deucher 	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, NULL,
94a5bde2f9SAlex Deucher 					  NULL, NULL, &data_offset)) {
95a5bde2f9SAlex Deucher 		struct atom_firmware_info_v3_1 *firmware_info =
96a5bde2f9SAlex Deucher 			(struct atom_firmware_info_v3_1 *)(adev->mode_info.atom_context->bios +
97a5bde2f9SAlex Deucher 							   data_offset);
98a5bde2f9SAlex Deucher 
99a5bde2f9SAlex Deucher 		adev->bios_scratch_reg_offset =
100a5bde2f9SAlex Deucher 			le32_to_cpu(firmware_info->bios_scratch_reg_startaddr);
101a5bde2f9SAlex Deucher 	}
102a5bde2f9SAlex Deucher }
103a5bde2f9SAlex Deucher 
amdgpu_atomfirmware_allocate_fb_v2_1(struct amdgpu_device * adev,struct vram_usagebyfirmware_v2_1 * fw_usage,int * usage_bytes)1044864f2eeSTong Liu01 static int amdgpu_atomfirmware_allocate_fb_v2_1(struct amdgpu_device *adev,
1054864f2eeSTong Liu01 	struct vram_usagebyfirmware_v2_1 *fw_usage, int *usage_bytes)
106a5bde2f9SAlex Deucher {
1076d96ced7STong Liu01 	u32 start_addr, fw_size, drv_size;
108a5bde2f9SAlex Deucher 
1094864f2eeSTong Liu01 	start_addr = le32_to_cpu(fw_usage->start_address_in_kb);
1104864f2eeSTong Liu01 	fw_size = le16_to_cpu(fw_usage->used_by_firmware_in_kb);
1114864f2eeSTong Liu01 	drv_size = le16_to_cpu(fw_usage->used_by_driver_in_kb);
112a5bde2f9SAlex Deucher 
1134864f2eeSTong Liu01 	DRM_DEBUG("atom firmware v2_1 requested %08x %dkb fw %dkb drv\n",
1144864f2eeSTong Liu01 			  start_addr,
1154864f2eeSTong Liu01 			  fw_size,
1164864f2eeSTong Liu01 			  drv_size);
11724738d7cSMonk Liu 
1184864f2eeSTong Liu01 	if ((start_addr & ATOM_VRAM_OPERATION_FLAGS_MASK) ==
1196d96ced7STong Liu01 		(u32)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION <<
12024738d7cSMonk Liu 		ATOM_VRAM_OPERATION_FLAGS_SHIFT)) {
12124738d7cSMonk Liu 		/* Firmware request VRAM reservation for SR-IOV */
12287ded5caSAlex Deucher 		adev->mman.fw_vram_usage_start_offset = (start_addr &
12324738d7cSMonk Liu 			(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
1244864f2eeSTong Liu01 		adev->mman.fw_vram_usage_size = fw_size << 10;
12524738d7cSMonk Liu 		/* Use the default scratch size */
1264864f2eeSTong Liu01 		*usage_bytes = 0;
12724738d7cSMonk Liu 	} else {
1284864f2eeSTong Liu01 		*usage_bytes = drv_size << 10;
1294864f2eeSTong Liu01 	}
1304864f2eeSTong Liu01 	return 0;
1314864f2eeSTong Liu01 }
1324864f2eeSTong Liu01 
amdgpu_atomfirmware_allocate_fb_v2_2(struct amdgpu_device * adev,struct vram_usagebyfirmware_v2_2 * fw_usage,int * usage_bytes)1334864f2eeSTong Liu01 static int amdgpu_atomfirmware_allocate_fb_v2_2(struct amdgpu_device *adev,
1344864f2eeSTong Liu01 		struct vram_usagebyfirmware_v2_2 *fw_usage, int *usage_bytes)
1354864f2eeSTong Liu01 {
1366d96ced7STong Liu01 	u32 fw_start_addr, fw_size, drv_start_addr, drv_size;
1374864f2eeSTong Liu01 
1384864f2eeSTong Liu01 	fw_start_addr = le32_to_cpu(fw_usage->fw_region_start_address_in_kb);
1394864f2eeSTong Liu01 	fw_size = le16_to_cpu(fw_usage->used_by_firmware_in_kb);
1404864f2eeSTong Liu01 
1414864f2eeSTong Liu01 	drv_start_addr = le32_to_cpu(fw_usage->driver_region0_start_address_in_kb);
1424864f2eeSTong Liu01 	drv_size = le32_to_cpu(fw_usage->used_by_driver_region0_in_kb);
1434864f2eeSTong Liu01 
1444864f2eeSTong Liu01 	DRM_DEBUG("atom requested fw start at %08x %dkb and drv start at %08x %dkb\n",
1454864f2eeSTong Liu01 			  fw_start_addr,
1464864f2eeSTong Liu01 			  fw_size,
1474864f2eeSTong Liu01 			  drv_start_addr,
1484864f2eeSTong Liu01 			  drv_size);
1494864f2eeSTong Liu01 
150c0924ad7SLikun Gao 	if (amdgpu_sriov_vf(adev) &&
151c0924ad7SLikun Gao 	    ((fw_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION <<
152c0924ad7SLikun Gao 		ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) {
1534864f2eeSTong Liu01 		/* Firmware request VRAM reservation for SR-IOV */
1544864f2eeSTong Liu01 		adev->mman.fw_vram_usage_start_offset = (fw_start_addr &
1554864f2eeSTong Liu01 			(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
1564864f2eeSTong Liu01 		adev->mman.fw_vram_usage_size = fw_size << 10;
1574864f2eeSTong Liu01 	}
1584864f2eeSTong Liu01 
159c0924ad7SLikun Gao 	if (amdgpu_sriov_vf(adev) &&
160c0924ad7SLikun Gao 	    ((drv_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION <<
161c0924ad7SLikun Gao 		ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) {
1624864f2eeSTong Liu01 		/* driver request VRAM reservation for SR-IOV */
1634864f2eeSTong Liu01 		adev->mman.drv_vram_usage_start_offset = (drv_start_addr &
1644864f2eeSTong Liu01 			(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
1654864f2eeSTong Liu01 		adev->mman.drv_vram_usage_size = drv_size << 10;
1664864f2eeSTong Liu01 	}
1674864f2eeSTong Liu01 
1684864f2eeSTong Liu01 	*usage_bytes = 0;
1694864f2eeSTong Liu01 	return 0;
1704864f2eeSTong Liu01 }
1714864f2eeSTong Liu01 
amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device * adev)1724864f2eeSTong Liu01 int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev)
1734864f2eeSTong Liu01 {
1744864f2eeSTong Liu01 	struct atom_context *ctx = adev->mode_info.atom_context;
1754864f2eeSTong Liu01 	int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
1764864f2eeSTong Liu01 						vram_usagebyfirmware);
1774864f2eeSTong Liu01 	struct vram_usagebyfirmware_v2_1 *fw_usage_v2_1;
1784864f2eeSTong Liu01 	struct vram_usagebyfirmware_v2_2 *fw_usage_v2_2;
1796d96ced7STong Liu01 	u16 data_offset;
1806d96ced7STong Liu01 	u8 frev, crev;
1814864f2eeSTong Liu01 	int usage_bytes = 0;
1824864f2eeSTong Liu01 
1834864f2eeSTong Liu01 	if (amdgpu_atom_parse_data_header(ctx, index, NULL, &frev, &crev, &data_offset)) {
1844864f2eeSTong Liu01 		if (frev == 2 && crev == 1) {
1854864f2eeSTong Liu01 			fw_usage_v2_1 =
1864864f2eeSTong Liu01 				(struct vram_usagebyfirmware_v2_1 *)(ctx->bios + data_offset);
1874864f2eeSTong Liu01 			amdgpu_atomfirmware_allocate_fb_v2_1(adev,
1884864f2eeSTong Liu01 					fw_usage_v2_1,
1894864f2eeSTong Liu01 					&usage_bytes);
1904864f2eeSTong Liu01 		} else if (frev >= 2 && crev >= 2) {
1914864f2eeSTong Liu01 			fw_usage_v2_2 =
1924864f2eeSTong Liu01 				(struct vram_usagebyfirmware_v2_2 *)(ctx->bios + data_offset);
1934864f2eeSTong Liu01 			amdgpu_atomfirmware_allocate_fb_v2_2(adev,
1944864f2eeSTong Liu01 					fw_usage_v2_2,
1954864f2eeSTong Liu01 					&usage_bytes);
19624738d7cSMonk Liu 		}
197a5bde2f9SAlex Deucher 	}
1984864f2eeSTong Liu01 
199a5bde2f9SAlex Deucher 	ctx->scratch_size_bytes = 0;
200a5bde2f9SAlex Deucher 	if (usage_bytes == 0)
201a5bde2f9SAlex Deucher 		usage_bytes = 20 * 1024;
202a5bde2f9SAlex Deucher 	/* allocate some scratch memory */
203a5bde2f9SAlex Deucher 	ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
204a5bde2f9SAlex Deucher 	if (!ctx->scratch)
205a5bde2f9SAlex Deucher 		return -ENOMEM;
206a5bde2f9SAlex Deucher 	ctx->scratch_size_bytes = usage_bytes;
207a5bde2f9SAlex Deucher 	return 0;
208a5bde2f9SAlex Deucher }
20921f6bcb6SAlex Deucher 
21021f6bcb6SAlex Deucher union igp_info {
21121f6bcb6SAlex Deucher 	struct atom_integrated_system_info_v1_11 v11;
212836dab85SAlex Deucher 	struct atom_integrated_system_info_v1_12 v12;
21378683229SHuang Rui 	struct atom_integrated_system_info_v2_1 v21;
2144eff0702SLi Ma 	struct atom_integrated_system_info_v2_3 v23;
21521f6bcb6SAlex Deucher };
21621f6bcb6SAlex Deucher 
2171e09b053SHawking Zhang union umc_info {
2181e09b053SHawking Zhang 	struct atom_umc_info_v3_1 v31;
219b69d5c7eSHawking Zhang 	struct atom_umc_info_v3_2 v32;
220b69d5c7eSHawking Zhang 	struct atom_umc_info_v3_3 v33;
221e0c5c387SHawking Zhang 	struct atom_umc_info_v4_0 v40;
2221e09b053SHawking Zhang };
22327e39d3dSHawking Zhang 
22427e39d3dSHawking Zhang union vram_info {
22527e39d3dSHawking Zhang 	struct atom_vram_info_header_v2_3 v23;
22689d7a79cSHawking Zhang 	struct atom_vram_info_header_v2_4 v24;
2278b41903aSHawking Zhang 	struct atom_vram_info_header_v2_5 v25;
228147d082dSFeifei Xu 	struct atom_vram_info_header_v2_6 v26;
2297089dd3cSHawking Zhang 	struct atom_vram_info_header_v3_0 v30;
23027e39d3dSHawking Zhang };
23121f6bcb6SAlex Deucher 
232bd552027SAlex Deucher union vram_module {
233bd552027SAlex Deucher 	struct atom_vram_module_v9 v9;
234bd552027SAlex Deucher 	struct atom_vram_module_v10 v10;
2358b41903aSHawking Zhang 	struct atom_vram_module_v11 v11;
2367089dd3cSHawking Zhang 	struct atom_vram_module_v3_0 v30;
237bd552027SAlex Deucher };
23879077ee1SAlex Deucher 
convert_atom_mem_type_to_vram_type(struct amdgpu_device * adev,int atom_mem_type)2391e09b053SHawking Zhang static int convert_atom_mem_type_to_vram_type(struct amdgpu_device *adev,
2401e09b053SHawking Zhang 					      int atom_mem_type)
2411e09b053SHawking Zhang {
2421e09b053SHawking Zhang 	int vram_type;
2431e09b053SHawking Zhang 
2441e09b053SHawking Zhang 	if (adev->flags & AMD_IS_APU) {
2451e09b053SHawking Zhang 		switch (atom_mem_type) {
2461e09b053SHawking Zhang 		case Ddr2MemType:
2471e09b053SHawking Zhang 		case LpDdr2MemType:
2481e09b053SHawking Zhang 			vram_type = AMDGPU_VRAM_TYPE_DDR2;
2491e09b053SHawking Zhang 			break;
2501e09b053SHawking Zhang 		case Ddr3MemType:
2511e09b053SHawking Zhang 		case LpDdr3MemType:
2521e09b053SHawking Zhang 			vram_type = AMDGPU_VRAM_TYPE_DDR3;
2531e09b053SHawking Zhang 			break;
2541e09b053SHawking Zhang 		case Ddr4MemType:
2551e09b053SHawking Zhang 			vram_type = AMDGPU_VRAM_TYPE_DDR4;
2561e09b053SHawking Zhang 			break;
257d534ca71SAlex Deucher 		case LpDdr4MemType:
258d534ca71SAlex Deucher 			vram_type = AMDGPU_VRAM_TYPE_LPDDR4;
259d534ca71SAlex Deucher 			break;
26015c90a1fSHuang Rui 		case Ddr5MemType:
26115c90a1fSHuang Rui 			vram_type = AMDGPU_VRAM_TYPE_DDR5;
26215c90a1fSHuang Rui 			break;
263d534ca71SAlex Deucher 		case LpDdr5MemType:
264d534ca71SAlex Deucher 			vram_type = AMDGPU_VRAM_TYPE_LPDDR5;
265d534ca71SAlex Deucher 			break;
2661e09b053SHawking Zhang 		default:
2671e09b053SHawking Zhang 			vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
2681e09b053SHawking Zhang 			break;
2691e09b053SHawking Zhang 		}
2701e09b053SHawking Zhang 	} else {
2711e09b053SHawking Zhang 		switch (atom_mem_type) {
2721e09b053SHawking Zhang 		case ATOM_DGPU_VRAM_TYPE_GDDR5:
2731e09b053SHawking Zhang 			vram_type = AMDGPU_VRAM_TYPE_GDDR5;
2741e09b053SHawking Zhang 			break;
275801281feSHawking Zhang 		case ATOM_DGPU_VRAM_TYPE_HBM2:
2768081f8faSFeifei Xu 		case ATOM_DGPU_VRAM_TYPE_HBM2E:
277cd8d77f3SHawking Zhang 		case ATOM_DGPU_VRAM_TYPE_HBM3:
2781e09b053SHawking Zhang 			vram_type = AMDGPU_VRAM_TYPE_HBM;
2791e09b053SHawking Zhang 			break;
28089d7a79cSHawking Zhang 		case ATOM_DGPU_VRAM_TYPE_GDDR6:
28189d7a79cSHawking Zhang 			vram_type = AMDGPU_VRAM_TYPE_GDDR6;
28289d7a79cSHawking Zhang 			break;
2831e09b053SHawking Zhang 		default:
2841e09b053SHawking Zhang 			vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
2851e09b053SHawking Zhang 			break;
2861e09b053SHawking Zhang 		}
2871e09b053SHawking Zhang 	}
2881e09b053SHawking Zhang 
2891e09b053SHawking Zhang 	return vram_type;
2901e09b053SHawking Zhang }
291bd552027SAlex Deucher 
292ad02e08eSOri Messinger 
293ad02e08eSOri Messinger int
amdgpu_atomfirmware_get_vram_info(struct amdgpu_device * adev,int * vram_width,int * vram_type,int * vram_vendor)294ad02e08eSOri Messinger amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
295ad02e08eSOri Messinger 				  int *vram_width, int *vram_type,
296ad02e08eSOri Messinger 				  int *vram_vendor)
2971e09b053SHawking Zhang {
2981e09b053SHawking Zhang 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
299bd552027SAlex Deucher 	int index, i = 0;
3001e09b053SHawking Zhang 	u16 data_offset, size;
3011e09b053SHawking Zhang 	union igp_info *igp_info;
30227e39d3dSHawking Zhang 	union vram_info *vram_info;
303bd552027SAlex Deucher 	union vram_module *vram_module;
3041e09b053SHawking Zhang 	u8 frev, crev;
3051e09b053SHawking Zhang 	u8 mem_type;
306ad02e08eSOri Messinger 	u8 mem_vendor;
307bd552027SAlex Deucher 	u32 mem_channel_number;
308bd552027SAlex Deucher 	u32 mem_channel_width;
309bd552027SAlex Deucher 	u32 module_id;
310bd552027SAlex Deucher 
3111e09b053SHawking Zhang 	if (adev->flags & AMD_IS_APU)
3121e09b053SHawking Zhang 		index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
3131e09b053SHawking Zhang 						    integratedsysteminfo);
3141e09b053SHawking Zhang 	else
3151e09b053SHawking Zhang 		index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
31627e39d3dSHawking Zhang 						    vram_info);
317bd552027SAlex Deucher 
3181e09b053SHawking Zhang 	if (amdgpu_atom_parse_data_header(mode_info->atom_context,
3191e09b053SHawking Zhang 					  index, &size,
3201e09b053SHawking Zhang 					  &frev, &crev, &data_offset)) {
3211e09b053SHawking Zhang 		if (adev->flags & AMD_IS_APU) {
3221e09b053SHawking Zhang 			igp_info = (union igp_info *)
3231e09b053SHawking Zhang 				(mode_info->atom_context->bios + data_offset);
32478683229SHuang Rui 			switch (frev) {
32578683229SHuang Rui 			case 1:
3261e09b053SHawking Zhang 				switch (crev) {
3271e09b053SHawking Zhang 				case 11:
32878683229SHuang Rui 				case 12:
329bd552027SAlex Deucher 					mem_channel_number = igp_info->v11.umachannelnumber;
33078683229SHuang Rui 					if (!mem_channel_number)
33178683229SHuang Rui 						mem_channel_number = 1;
3321e09b053SHawking Zhang 					mem_type = igp_info->v11.memorytype;
333c09b3bf7SAlex Deucher 					if (mem_type == LpDdr5MemType)
334c09b3bf7SAlex Deucher 						mem_channel_width = 32;
335c09b3bf7SAlex Deucher 					else
336c09b3bf7SAlex Deucher 						mem_channel_width = 64;
337c09b3bf7SAlex Deucher 					if (vram_width)
338c09b3bf7SAlex Deucher 						*vram_width = mem_channel_number * mem_channel_width;
339bd552027SAlex Deucher 					if (vram_type)
340bd552027SAlex Deucher 						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
341bd552027SAlex Deucher 					break;
34278683229SHuang Rui 				default:
34378683229SHuang Rui 					return -EINVAL;
34478683229SHuang Rui 				}
34578683229SHuang Rui 				break;
34678683229SHuang Rui 			case 2:
34778683229SHuang Rui 				switch (crev) {
34878683229SHuang Rui 				case 1:
34978683229SHuang Rui 				case 2:
35078683229SHuang Rui 					mem_channel_number = igp_info->v21.umachannelnumber;
35178683229SHuang Rui 					if (!mem_channel_number)
35278683229SHuang Rui 						mem_channel_number = 1;
35378683229SHuang Rui 					mem_type = igp_info->v21.memorytype;
354c09b3bf7SAlex Deucher 					if (mem_type == LpDdr5MemType)
355c09b3bf7SAlex Deucher 						mem_channel_width = 32;
356c09b3bf7SAlex Deucher 					else
357c09b3bf7SAlex Deucher 						mem_channel_width = 64;
358c09b3bf7SAlex Deucher 					if (vram_width)
359c09b3bf7SAlex Deucher 						*vram_width = mem_channel_number * mem_channel_width;
360836dab85SAlex Deucher 					if (vram_type)
361836dab85SAlex Deucher 						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
362836dab85SAlex Deucher 					break;
3634eff0702SLi Ma 				case 3:
3644eff0702SLi Ma 					mem_channel_number = igp_info->v23.umachannelnumber;
3654eff0702SLi Ma 					if (!mem_channel_number)
3664eff0702SLi Ma 						mem_channel_number = 1;
3674eff0702SLi Ma 					mem_type = igp_info->v23.memorytype;
3684eff0702SLi Ma 					if (mem_type == LpDdr5MemType)
3694eff0702SLi Ma 						mem_channel_width = 32;
3704eff0702SLi Ma 					else
3714eff0702SLi Ma 						mem_channel_width = 64;
3724eff0702SLi Ma 					if (vram_width)
3734eff0702SLi Ma 						*vram_width = mem_channel_number * mem_channel_width;
3744eff0702SLi Ma 					if (vram_type)
3754eff0702SLi Ma 						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
3764eff0702SLi Ma 					break;
3771e09b053SHawking Zhang 				default:
378bd552027SAlex Deucher 					return -EINVAL;
3791e09b053SHawking Zhang 				}
38078683229SHuang Rui 				break;
38178683229SHuang Rui 			default:
38278683229SHuang Rui 				return -EINVAL;
38378683229SHuang Rui 			}
3841e09b053SHawking Zhang 		} else {
38527e39d3dSHawking Zhang 			vram_info = (union vram_info *)
3861e09b053SHawking Zhang 				(mode_info->atom_context->bios + data_offset);
387bd552027SAlex Deucher 			module_id = (RREG32(adev->bios_scratch_reg_offset + 4) & 0x00ff0000) >> 16;
3887089dd3cSHawking Zhang 			if (frev == 3) {
3891e09b053SHawking Zhang 				switch (crev) {
3907089dd3cSHawking Zhang 				/* v30 */
3917089dd3cSHawking Zhang 				case 0:
3927089dd3cSHawking Zhang 					vram_module = (union vram_module *)vram_info->v30.vram_module;
3937089dd3cSHawking Zhang 					mem_vendor = (vram_module->v30.dram_vendor_id) & 0xF;
3947089dd3cSHawking Zhang 					if (vram_vendor)
3957089dd3cSHawking Zhang 						*vram_vendor = mem_vendor;
3967089dd3cSHawking Zhang 					mem_type = vram_info->v30.memory_type;
3977089dd3cSHawking Zhang 					if (vram_type)
3987089dd3cSHawking Zhang 						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
3997089dd3cSHawking Zhang 					mem_channel_number = vram_info->v30.channel_num;
4007089dd3cSHawking Zhang 					mem_channel_width = vram_info->v30.channel_width;
4017089dd3cSHawking Zhang 					if (vram_width)
402*01f58871SAlex Deucher 						*vram_width = mem_channel_number * 16;
4037089dd3cSHawking Zhang 					break;
4047089dd3cSHawking Zhang 				default:
4057089dd3cSHawking Zhang 					return -EINVAL;
4067089dd3cSHawking Zhang 				}
4077089dd3cSHawking Zhang 			} else if (frev == 2) {
4087089dd3cSHawking Zhang 				switch (crev) {
4097089dd3cSHawking Zhang 				/* v23 */
41027e39d3dSHawking Zhang 				case 3:
411bd552027SAlex Deucher 					if (module_id > vram_info->v23.vram_module_num)
412bd552027SAlex Deucher 						module_id = 0;
413bd552027SAlex Deucher 					vram_module = (union vram_module *)vram_info->v23.vram_module;
414bd552027SAlex Deucher 					while (i < module_id) {
415bd552027SAlex Deucher 						vram_module = (union vram_module *)
416bd552027SAlex Deucher 							((u8 *)vram_module + vram_module->v9.vram_module_size);
417bd552027SAlex Deucher 						i++;
4181e09b053SHawking Zhang 					}
419bd552027SAlex Deucher 					mem_type = vram_module->v9.memory_type;
420bd552027SAlex Deucher 					if (vram_type)
421bd552027SAlex Deucher 						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
422bd552027SAlex Deucher 					mem_channel_number = vram_module->v9.channel_num;
423bd552027SAlex Deucher 					mem_channel_width = vram_module->v9.channel_width;
424bd552027SAlex Deucher 					if (vram_width)
425bd552027SAlex Deucher 						*vram_width = mem_channel_number * (1 << mem_channel_width);
426ad02e08eSOri Messinger 					mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
427ad02e08eSOri Messinger 					if (vram_vendor)
428ad02e08eSOri Messinger 						*vram_vendor = mem_vendor;
429bd552027SAlex Deucher 					break;
4307089dd3cSHawking Zhang 				/* v24 */
431bd552027SAlex Deucher 				case 4:
432bd552027SAlex Deucher 					if (module_id > vram_info->v24.vram_module_num)
433bd552027SAlex Deucher 						module_id = 0;
434bd552027SAlex Deucher 					vram_module = (union vram_module *)vram_info->v24.vram_module;
435bd552027SAlex Deucher 					while (i < module_id) {
436bd552027SAlex Deucher 						vram_module = (union vram_module *)
437bd552027SAlex Deucher 							((u8 *)vram_module + vram_module->v10.vram_module_size);
438bd552027SAlex Deucher 						i++;
439bd552027SAlex Deucher 					}
440bd552027SAlex Deucher 					mem_type = vram_module->v10.memory_type;
441bd552027SAlex Deucher 					if (vram_type)
442bd552027SAlex Deucher 						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
443bd552027SAlex Deucher 					mem_channel_number = vram_module->v10.channel_num;
444bd552027SAlex Deucher 					mem_channel_width = vram_module->v10.channel_width;
445bd552027SAlex Deucher 					if (vram_width)
446bd552027SAlex Deucher 						*vram_width = mem_channel_number * (1 << mem_channel_width);
447ad02e08eSOri Messinger 					mem_vendor = (vram_module->v10.vender_rev_id) & 0xF;
448ad02e08eSOri Messinger 					if (vram_vendor)
449ad02e08eSOri Messinger 						*vram_vendor = mem_vendor;
450bd552027SAlex Deucher 					break;
4517089dd3cSHawking Zhang 				/* v25 */
4528b41903aSHawking Zhang 				case 5:
4538b41903aSHawking Zhang 					if (module_id > vram_info->v25.vram_module_num)
4548b41903aSHawking Zhang 						module_id = 0;
4558b41903aSHawking Zhang 					vram_module = (union vram_module *)vram_info->v25.vram_module;
4568b41903aSHawking Zhang 					while (i < module_id) {
4578b41903aSHawking Zhang 						vram_module = (union vram_module *)
4588b41903aSHawking Zhang 							((u8 *)vram_module + vram_module->v11.vram_module_size);
4598b41903aSHawking Zhang 						i++;
4608b41903aSHawking Zhang 					}
4618b41903aSHawking Zhang 					mem_type = vram_module->v11.memory_type;
4628b41903aSHawking Zhang 					if (vram_type)
4638b41903aSHawking Zhang 						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
4648b41903aSHawking Zhang 					mem_channel_number = vram_module->v11.channel_num;
4658b41903aSHawking Zhang 					mem_channel_width = vram_module->v11.channel_width;
4668b41903aSHawking Zhang 					if (vram_width)
4678b41903aSHawking Zhang 						*vram_width = mem_channel_number * (1 << mem_channel_width);
4688b41903aSHawking Zhang 					mem_vendor = (vram_module->v11.vender_rev_id) & 0xF;
4698b41903aSHawking Zhang 					if (vram_vendor)
4708b41903aSHawking Zhang 						*vram_vendor = mem_vendor;
4718b41903aSHawking Zhang 					break;
4727089dd3cSHawking Zhang 				/* v26 */
473f31c4a11SHawking Zhang 				case 6:
474f31c4a11SHawking Zhang 					if (module_id > vram_info->v26.vram_module_num)
475f31c4a11SHawking Zhang 						module_id = 0;
476f31c4a11SHawking Zhang 					vram_module = (union vram_module *)vram_info->v26.vram_module;
477f31c4a11SHawking Zhang 					while (i < module_id) {
478f31c4a11SHawking Zhang 						vram_module = (union vram_module *)
479147d082dSFeifei Xu 							((u8 *)vram_module + vram_module->v9.vram_module_size);
480f31c4a11SHawking Zhang 						i++;
481f31c4a11SHawking Zhang 					}
482f31c4a11SHawking Zhang 					mem_type = vram_module->v9.memory_type;
483f31c4a11SHawking Zhang 					if (vram_type)
484f31c4a11SHawking Zhang 						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
485f31c4a11SHawking Zhang 					mem_channel_number = vram_module->v9.channel_num;
486f31c4a11SHawking Zhang 					mem_channel_width = vram_module->v9.channel_width;
487f31c4a11SHawking Zhang 					if (vram_width)
488f31c4a11SHawking Zhang 						*vram_width = mem_channel_number * (1 << mem_channel_width);
489f31c4a11SHawking Zhang 					mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
490f31c4a11SHawking Zhang 					if (vram_vendor)
491f31c4a11SHawking Zhang 						*vram_vendor = mem_vendor;
492f31c4a11SHawking Zhang 					break;
493bd552027SAlex Deucher 				default:
494bd552027SAlex Deucher 					return -EINVAL;
4951e09b053SHawking Zhang 				}
4967089dd3cSHawking Zhang 			} else {
4977089dd3cSHawking Zhang 				/* invalid frev */
4987089dd3cSHawking Zhang 				return -EINVAL;
4997089dd3cSHawking Zhang 			}
5001e09b053SHawking Zhang 		}
5011e09b053SHawking Zhang 
502bd552027SAlex Deucher 	}
503bd552027SAlex Deucher 
5041e09b053SHawking Zhang 	return 0;
5051e09b053SHawking Zhang }
5061e09b053SHawking Zhang 
507511c4348SHawking Zhang /*
508511c4348SHawking Zhang  * Return true if vbios enabled ecc by default, if umc info table is available
509511c4348SHawking Zhang  * or false if ecc is not enabled or umc info table is not available
510511c4348SHawking Zhang  */
amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device * adev)511511c4348SHawking Zhang bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev)
512511c4348SHawking Zhang {
513511c4348SHawking Zhang 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
514511c4348SHawking Zhang 	int index;
515511c4348SHawking Zhang 	u16 data_offset, size;
516511c4348SHawking Zhang 	union umc_info *umc_info;
517511c4348SHawking Zhang 	u8 frev, crev;
518511c4348SHawking Zhang 	bool ecc_default_enabled = false;
51997e27292SHawking Zhang 	u8 umc_config;
52097e27292SHawking Zhang 	u32 umc_config1;
521511c4348SHawking Zhang 
522511c4348SHawking Zhang 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
523511c4348SHawking Zhang 			umc_info);
524511c4348SHawking Zhang 
525511c4348SHawking Zhang 	if (amdgpu_atom_parse_data_header(mode_info->atom_context,
526511c4348SHawking Zhang 				index, &size, &frev, &crev, &data_offset)) {
527e0c5c387SHawking Zhang 		umc_info = (union umc_info *)(mode_info->atom_context->bios + data_offset);
528b69d5c7eSHawking Zhang 		if (frev == 3) {
529b69d5c7eSHawking Zhang 			switch (crev) {
530b69d5c7eSHawking Zhang 			case 1:
53197e27292SHawking Zhang 				umc_config = le32_to_cpu(umc_info->v31.umc_config);
532511c4348SHawking Zhang 				ecc_default_enabled =
53397e27292SHawking Zhang 					(umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ? true : false;
534b69d5c7eSHawking Zhang 				break;
535b69d5c7eSHawking Zhang 			case 2:
53697e27292SHawking Zhang 				umc_config = le32_to_cpu(umc_info->v32.umc_config);
537b69d5c7eSHawking Zhang 				ecc_default_enabled =
53897e27292SHawking Zhang 					(umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ? true : false;
539b69d5c7eSHawking Zhang 				break;
540b69d5c7eSHawking Zhang 			case 3:
54197e27292SHawking Zhang 				umc_config = le32_to_cpu(umc_info->v33.umc_config);
54297e27292SHawking Zhang 				umc_config1 = le32_to_cpu(umc_info->v33.umc_config1);
543b69d5c7eSHawking Zhang 				ecc_default_enabled =
54497e27292SHawking Zhang 					((umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ||
54597e27292SHawking Zhang 					 (umc_config1 & UMC_CONFIG1__ENABLE_ECC_CAPABLE)) ? true : false;
546b69d5c7eSHawking Zhang 				break;
547b69d5c7eSHawking Zhang 			default:
548b69d5c7eSHawking Zhang 				/* unsupported crev */
549b69d5c7eSHawking Zhang 				return false;
550b69d5c7eSHawking Zhang 			}
551e0c5c387SHawking Zhang 		} else if (frev == 4) {
552e0c5c387SHawking Zhang 			switch (crev) {
553e0c5c387SHawking Zhang 			case 0:
554e0c5c387SHawking Zhang 				umc_config1 = le32_to_cpu(umc_info->v40.umc_config1);
555e0c5c387SHawking Zhang 				ecc_default_enabled =
556e0c5c387SHawking Zhang 					(umc_config1 & UMC_CONFIG1__ENABLE_ECC_CAPABLE) ? true : false;
557e0c5c387SHawking Zhang 				break;
558e0c5c387SHawking Zhang 			default:
559e0c5c387SHawking Zhang 				/* unsupported crev */
560e0c5c387SHawking Zhang 				return false;
561e0c5c387SHawking Zhang 			}
562e0c5c387SHawking Zhang 		} else {
563e0c5c387SHawking Zhang 			/* unsupported frev */
564e0c5c387SHawking Zhang 			return false;
565511c4348SHawking Zhang 		}
566511c4348SHawking Zhang 	}
567511c4348SHawking Zhang 
568511c4348SHawking Zhang 	return ecc_default_enabled;
569511c4348SHawking Zhang }
570511c4348SHawking Zhang 
5718b6da23fSHawking Zhang /*
572698b1010SHawking Zhang  * Helper function to query sram ecc capablity
573698b1010SHawking Zhang  *
574698b1010SHawking Zhang  * @adev: amdgpu_device pointer
575698b1010SHawking Zhang  *
5768b6da23fSHawking Zhang  * Return true if vbios supports sram ecc or false if not
5778b6da23fSHawking Zhang  */
amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device * adev)5788b6da23fSHawking Zhang bool amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device *adev)
5798b6da23fSHawking Zhang {
580698b1010SHawking Zhang 	u32 fw_cap;
5818b6da23fSHawking Zhang 
582698b1010SHawking Zhang 	fw_cap = adev->mode_info.firmware_flags;
5838b6da23fSHawking Zhang 
584698b1010SHawking Zhang 	return (fw_cap & ATOM_FIRMWARE_CAP_SRAM_ECC) ? true : false;
5858b6da23fSHawking Zhang }
5868b6da23fSHawking Zhang 
587cffd6f9dSHawking Zhang /*
588cffd6f9dSHawking Zhang  * Helper function to query dynamic boot config capability
589cffd6f9dSHawking Zhang  *
590cffd6f9dSHawking Zhang  * @adev: amdgpu_device pointer
591cffd6f9dSHawking Zhang  *
592cffd6f9dSHawking Zhang  * Return true if vbios supports dynamic boot config or false if not
593cffd6f9dSHawking Zhang  */
amdgpu_atomfirmware_dynamic_boot_config_supported(struct amdgpu_device * adev)594cffd6f9dSHawking Zhang bool amdgpu_atomfirmware_dynamic_boot_config_supported(struct amdgpu_device *adev)
595cffd6f9dSHawking Zhang {
596cffd6f9dSHawking Zhang 	u32 fw_cap;
597cffd6f9dSHawking Zhang 
598cffd6f9dSHawking Zhang 	fw_cap = adev->mode_info.firmware_flags;
599cffd6f9dSHawking Zhang 
600cffd6f9dSHawking Zhang 	return (fw_cap & ATOM_FIRMWARE_CAP_DYNAMIC_BOOT_CFG_ENABLE) ? true : false;
601cffd6f9dSHawking Zhang }
602cffd6f9dSHawking Zhang 
603a6a355a2SLuben Tuikov /**
604a6a355a2SLuben Tuikov  * amdgpu_atomfirmware_ras_rom_addr -- Get the RAS EEPROM addr from VBIOS
605bbe04decSIsabella Basso  * @adev: amdgpu_device pointer
606bbe04decSIsabella Basso  * @i2c_address: pointer to u8; if not NULL, will contain
607a6a355a2SLuben Tuikov  *    the RAS EEPROM address if the function returns true
60814fb496aSJohn Clements  *
609a6a355a2SLuben Tuikov  * Return true if VBIOS supports RAS EEPROM address reporting,
610a6a355a2SLuben Tuikov  * else return false. If true and @i2c_address is not NULL,
611a6a355a2SLuben Tuikov  * will contain the RAS ROM address.
61214fb496aSJohn Clements  */
amdgpu_atomfirmware_ras_rom_addr(struct amdgpu_device * adev,u8 * i2c_address)613a6a355a2SLuben Tuikov bool amdgpu_atomfirmware_ras_rom_addr(struct amdgpu_device *adev,
614a6a355a2SLuben Tuikov 				      u8 *i2c_address)
61514fb496aSJohn Clements {
61614fb496aSJohn Clements 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
61714fb496aSJohn Clements 	int index;
61814fb496aSJohn Clements 	u16 data_offset, size;
61914fb496aSJohn Clements 	union firmware_info *firmware_info;
62014fb496aSJohn Clements 	u8 frev, crev;
62114fb496aSJohn Clements 
62214fb496aSJohn Clements 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
62314fb496aSJohn Clements 					    firmwareinfo);
62414fb496aSJohn Clements 
62514fb496aSJohn Clements 	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context,
626a6a355a2SLuben Tuikov 					  index, &size, &frev, &crev,
627a6a355a2SLuben Tuikov 					  &data_offset)) {
62814fb496aSJohn Clements 		/* support firmware_info 3.4 + */
62914fb496aSJohn Clements 		if ((frev == 3 && crev >= 4) || (frev > 3)) {
63014fb496aSJohn Clements 			firmware_info = (union firmware_info *)
63114fb496aSJohn Clements 				(mode_info->atom_context->bios + data_offset);
632a6a355a2SLuben Tuikov 			/* The ras_rom_i2c_slave_addr should ideally
633a6a355a2SLuben Tuikov 			 * be a 19-bit EEPROM address, which would be
634a6a355a2SLuben Tuikov 			 * used as is by the driver; see top of
635a6a355a2SLuben Tuikov 			 * amdgpu_eeprom.c.
636a6a355a2SLuben Tuikov 			 *
637a6a355a2SLuben Tuikov 			 * When this is the case, 0 is of course a
638a6a355a2SLuben Tuikov 			 * valid RAS EEPROM address, in which case,
639a6a355a2SLuben Tuikov 			 * we'll drop the first "if (firm...)" and only
640a6a355a2SLuben Tuikov 			 * leave the check for the pointer.
641a6a355a2SLuben Tuikov 			 *
642a6a355a2SLuben Tuikov 			 * The reason this works right now is because
643a6a355a2SLuben Tuikov 			 * ras_rom_i2c_slave_addr contains the EEPROM
644a6a355a2SLuben Tuikov 			 * device type qualifier 1010b in the top 4
645a6a355a2SLuben Tuikov 			 * bits.
646a6a355a2SLuben Tuikov 			 */
647a6a355a2SLuben Tuikov 			if (firmware_info->v34.ras_rom_i2c_slave_addr) {
648a6a355a2SLuben Tuikov 				if (i2c_address)
64914fb496aSJohn Clements 					*i2c_address = firmware_info->v34.ras_rom_i2c_slave_addr;
65014fb496aSJohn Clements 				return true;
651a6a355a2SLuben Tuikov 			}
652a6a355a2SLuben Tuikov 		}
653a6a355a2SLuben Tuikov 	}
65414fb496aSJohn Clements 
65514fb496aSJohn Clements 	return false;
65614fb496aSJohn Clements }
65714fb496aSJohn Clements 
65814fb496aSJohn Clements 
65979077ee1SAlex Deucher union smu_info {
66079077ee1SAlex Deucher 	struct atom_smu_info_v3_1 v31;
661f0b0a1b8SHawking Zhang 	struct atom_smu_info_v4_0 v40;
66279077ee1SAlex Deucher };
66379077ee1SAlex Deucher 
664a8d59943SHawking Zhang union gfx_info {
665a8d59943SHawking Zhang 	struct atom_gfx_info_v2_2 v22;
666a8d59943SHawking Zhang 	struct atom_gfx_info_v2_4 v24;
667a8d59943SHawking Zhang 	struct atom_gfx_info_v2_7 v27;
668a8d59943SHawking Zhang 	struct atom_gfx_info_v3_0 v30;
669a8d59943SHawking Zhang };
670a8d59943SHawking Zhang 
amdgpu_atomfirmware_get_clock_info(struct amdgpu_device * adev)67179077ee1SAlex Deucher int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev)
67279077ee1SAlex Deucher {
67379077ee1SAlex Deucher 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
67479077ee1SAlex Deucher 	struct amdgpu_pll *spll = &adev->clock.spll;
67579077ee1SAlex Deucher 	struct amdgpu_pll *mpll = &adev->clock.mpll;
67679077ee1SAlex Deucher 	uint8_t frev, crev;
67779077ee1SAlex Deucher 	uint16_t data_offset;
67879077ee1SAlex Deucher 	int ret = -EINVAL, index;
67979077ee1SAlex Deucher 
68079077ee1SAlex Deucher 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
68179077ee1SAlex Deucher 					    firmwareinfo);
68279077ee1SAlex Deucher 	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
68379077ee1SAlex Deucher 				   &frev, &crev, &data_offset)) {
68479077ee1SAlex Deucher 		union firmware_info *firmware_info =
68579077ee1SAlex Deucher 			(union firmware_info *)(mode_info->atom_context->bios +
68679077ee1SAlex Deucher 						data_offset);
68779077ee1SAlex Deucher 
68879077ee1SAlex Deucher 		adev->clock.default_sclk =
68979077ee1SAlex Deucher 			le32_to_cpu(firmware_info->v31.bootup_sclk_in10khz);
69079077ee1SAlex Deucher 		adev->clock.default_mclk =
69179077ee1SAlex Deucher 			le32_to_cpu(firmware_info->v31.bootup_mclk_in10khz);
69279077ee1SAlex Deucher 
69379077ee1SAlex Deucher 		adev->pm.current_sclk = adev->clock.default_sclk;
69479077ee1SAlex Deucher 		adev->pm.current_mclk = adev->clock.default_mclk;
69579077ee1SAlex Deucher 
69679077ee1SAlex Deucher 		ret = 0;
69779077ee1SAlex Deucher 	}
69879077ee1SAlex Deucher 
69979077ee1SAlex Deucher 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
70079077ee1SAlex Deucher 					    smu_info);
70179077ee1SAlex Deucher 	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
70279077ee1SAlex Deucher 				   &frev, &crev, &data_offset)) {
70379077ee1SAlex Deucher 		union smu_info *smu_info =
70479077ee1SAlex Deucher 			(union smu_info *)(mode_info->atom_context->bios +
70579077ee1SAlex Deucher 					   data_offset);
70679077ee1SAlex Deucher 
70779077ee1SAlex Deucher 		/* system clock */
708f0b0a1b8SHawking Zhang 		if (frev == 3)
70979077ee1SAlex Deucher 			spll->reference_freq = le32_to_cpu(smu_info->v31.core_refclk_10khz);
710f0b0a1b8SHawking Zhang 		else if (frev == 4)
711f0b0a1b8SHawking Zhang 			spll->reference_freq = le32_to_cpu(smu_info->v40.core_refclk_10khz);
71279077ee1SAlex Deucher 
71379077ee1SAlex Deucher 		spll->reference_div = 0;
71479077ee1SAlex Deucher 		spll->min_post_div = 1;
71579077ee1SAlex Deucher 		spll->max_post_div = 1;
71679077ee1SAlex Deucher 		spll->min_ref_div = 2;
71779077ee1SAlex Deucher 		spll->max_ref_div = 0xff;
71879077ee1SAlex Deucher 		spll->min_feedback_div = 4;
71979077ee1SAlex Deucher 		spll->max_feedback_div = 0xff;
72079077ee1SAlex Deucher 		spll->best_vco = 0;
72179077ee1SAlex Deucher 
72279077ee1SAlex Deucher 		ret = 0;
72379077ee1SAlex Deucher 	}
72479077ee1SAlex Deucher 
72579077ee1SAlex Deucher 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
72679077ee1SAlex Deucher 					    umc_info);
72779077ee1SAlex Deucher 	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
72879077ee1SAlex Deucher 				   &frev, &crev, &data_offset)) {
72979077ee1SAlex Deucher 		union umc_info *umc_info =
73079077ee1SAlex Deucher 			(union umc_info *)(mode_info->atom_context->bios +
73179077ee1SAlex Deucher 					   data_offset);
73279077ee1SAlex Deucher 
73379077ee1SAlex Deucher 		/* memory clock */
73479077ee1SAlex Deucher 		mpll->reference_freq = le32_to_cpu(umc_info->v31.mem_refclk_10khz);
73579077ee1SAlex Deucher 
73679077ee1SAlex Deucher 		mpll->reference_div = 0;
73779077ee1SAlex Deucher 		mpll->min_post_div = 1;
73879077ee1SAlex Deucher 		mpll->max_post_div = 1;
73979077ee1SAlex Deucher 		mpll->min_ref_div = 2;
74079077ee1SAlex Deucher 		mpll->max_ref_div = 0xff;
74179077ee1SAlex Deucher 		mpll->min_feedback_div = 4;
74279077ee1SAlex Deucher 		mpll->max_feedback_div = 0xff;
74379077ee1SAlex Deucher 		mpll->best_vco = 0;
74479077ee1SAlex Deucher 
74579077ee1SAlex Deucher 		ret = 0;
74679077ee1SAlex Deucher 	}
74779077ee1SAlex Deucher 
7489a530062SAaron Liu 	/* if asic is Navi+, the rlc reference clock is used for system clock
7499a530062SAaron Liu 	 * from vbios gfx_info table */
7509a530062SAaron Liu 	if (adev->asic_type >= CHIP_NAVI10) {
7519a530062SAaron Liu 		index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
7529a530062SAaron Liu 						   gfx_info);
7539a530062SAaron Liu 		if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
7549a530062SAaron Liu 					  &frev, &crev, &data_offset)) {
755a8d59943SHawking Zhang 			union gfx_info *gfx_info = (union gfx_info *)
7569a530062SAaron Liu 				(mode_info->atom_context->bios + data_offset);
757a8d59943SHawking Zhang 			if ((frev == 3) ||
758a8d59943SHawking Zhang 			    (frev == 2 && crev == 6)) {
759a8d59943SHawking Zhang 				spll->reference_freq = le32_to_cpu(gfx_info->v30.golden_tsc_count_lower_refclk);
7609a530062SAaron Liu 				ret = 0;
761a8d59943SHawking Zhang 			} else if ((frev == 2) &&
762a8d59943SHawking Zhang 				   (crev >= 2) &&
763a8d59943SHawking Zhang 				   (crev != 6)) {
764a8d59943SHawking Zhang 				spll->reference_freq = le32_to_cpu(gfx_info->v22.rlc_gpu_timer_refclk);
765a8d59943SHawking Zhang 				ret = 0;
766a8d59943SHawking Zhang 			} else {
767a8d59943SHawking Zhang 				BUG();
768a8d59943SHawking Zhang 			}
7699a530062SAaron Liu 		}
7709a530062SAaron Liu 	}
7719a530062SAaron Liu 
77279077ee1SAlex Deucher 	return ret;
77379077ee1SAlex Deucher }
77459b0b509SAlex Deucher 
amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device * adev)77559b0b509SAlex Deucher int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev)
77659b0b509SAlex Deucher {
77759b0b509SAlex Deucher 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
77859b0b509SAlex Deucher 	int index;
77959b0b509SAlex Deucher 	uint8_t frev, crev;
78059b0b509SAlex Deucher 	uint16_t data_offset;
78159b0b509SAlex Deucher 
78259b0b509SAlex Deucher 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
78359b0b509SAlex Deucher 					    gfx_info);
78459b0b509SAlex Deucher 	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
78559b0b509SAlex Deucher 				   &frev, &crev, &data_offset)) {
78659b0b509SAlex Deucher 		union gfx_info *gfx_info = (union gfx_info *)
78759b0b509SAlex Deucher 			(mode_info->atom_context->bios + data_offset);
788f5fb30b6SHawking Zhang 		if (frev == 2) {
78959b0b509SAlex Deucher 			switch (crev) {
79059b0b509SAlex Deucher 			case 4:
7910ae6afbfSHuang Rui 				adev->gfx.config.max_shader_engines = gfx_info->v24.max_shader_engines;
7920ae6afbfSHuang Rui 				adev->gfx.config.max_cu_per_sh = gfx_info->v24.max_cu_per_sh;
7930ae6afbfSHuang Rui 				adev->gfx.config.max_sh_per_se = gfx_info->v24.max_sh_per_se;
7940ae6afbfSHuang Rui 				adev->gfx.config.max_backends_per_se = gfx_info->v24.max_backends_per_se;
7950ae6afbfSHuang Rui 				adev->gfx.config.max_texture_channel_caches = gfx_info->v24.max_texture_channel_caches;
79659b0b509SAlex Deucher 				adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v24.gc_num_gprs);
79759b0b509SAlex Deucher 				adev->gfx.config.max_gs_threads = gfx_info->v24.gc_num_max_gs_thds;
79859b0b509SAlex Deucher 				adev->gfx.config.gs_vgt_table_depth = gfx_info->v24.gc_gs_table_depth;
79959b0b509SAlex Deucher 				adev->gfx.config.gs_prim_buffer_depth =
80059b0b509SAlex Deucher 					le16_to_cpu(gfx_info->v24.gc_gsprim_buff_depth);
80159b0b509SAlex Deucher 				adev->gfx.config.double_offchip_lds_buf =
80259b0b509SAlex Deucher 					gfx_info->v24.gc_double_offchip_lds_buffer;
803f9fb22a2SShaoyun Liu 				adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v24.gc_wave_size);
804f9fb22a2SShaoyun Liu 				adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v24.gc_max_waves_per_simd);
805f9fb22a2SShaoyun Liu 				adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v24.gc_max_scratch_slots_per_cu;
80659b0b509SAlex Deucher 				adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v24.gc_lds_size);
80759b0b509SAlex Deucher 				return 0;
8087159a36eSHawking Zhang 			case 7:
8097159a36eSHawking Zhang 				adev->gfx.config.max_shader_engines = gfx_info->v27.max_shader_engines;
8107159a36eSHawking Zhang 				adev->gfx.config.max_cu_per_sh = gfx_info->v27.max_cu_per_sh;
8117159a36eSHawking Zhang 				adev->gfx.config.max_sh_per_se = gfx_info->v27.max_sh_per_se;
8127159a36eSHawking Zhang 				adev->gfx.config.max_backends_per_se = gfx_info->v27.max_backends_per_se;
8137159a36eSHawking Zhang 				adev->gfx.config.max_texture_channel_caches = gfx_info->v27.max_texture_channel_caches;
8147159a36eSHawking Zhang 				adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v27.gc_num_gprs);
8157159a36eSHawking Zhang 				adev->gfx.config.max_gs_threads = gfx_info->v27.gc_num_max_gs_thds;
8167159a36eSHawking Zhang 				adev->gfx.config.gs_vgt_table_depth = gfx_info->v27.gc_gs_table_depth;
8177159a36eSHawking Zhang 				adev->gfx.config.gs_prim_buffer_depth = le16_to_cpu(gfx_info->v27.gc_gsprim_buff_depth);
8187159a36eSHawking Zhang 				adev->gfx.config.double_offchip_lds_buf = gfx_info->v27.gc_double_offchip_lds_buffer;
8197159a36eSHawking Zhang 				adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v27.gc_wave_size);
8207159a36eSHawking Zhang 				adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v27.gc_max_waves_per_simd);
8217159a36eSHawking Zhang 				adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v27.gc_max_scratch_slots_per_cu;
8227159a36eSHawking Zhang 				adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v27.gc_lds_size);
8237159a36eSHawking Zhang 				return 0;
82459b0b509SAlex Deucher 			default:
82559b0b509SAlex Deucher 				return -EINVAL;
82659b0b509SAlex Deucher 			}
827f5fb30b6SHawking Zhang 		} else if (frev == 3) {
828f5fb30b6SHawking Zhang 			switch (crev) {
829f5fb30b6SHawking Zhang 			case 0:
830f5fb30b6SHawking Zhang 				adev->gfx.config.max_shader_engines = gfx_info->v30.max_shader_engines;
831f5fb30b6SHawking Zhang 				adev->gfx.config.max_cu_per_sh = gfx_info->v30.max_cu_per_sh;
832f5fb30b6SHawking Zhang 				adev->gfx.config.max_sh_per_se = gfx_info->v30.max_sh_per_se;
833f5fb30b6SHawking Zhang 				adev->gfx.config.max_backends_per_se = gfx_info->v30.max_backends_per_se;
834f5fb30b6SHawking Zhang 				adev->gfx.config.max_texture_channel_caches = gfx_info->v30.max_texture_channel_caches;
835f5fb30b6SHawking Zhang 				return 0;
836f5fb30b6SHawking Zhang 			default:
837f5fb30b6SHawking Zhang 				return -EINVAL;
838f5fb30b6SHawking Zhang 			}
839f5fb30b6SHawking Zhang 		} else {
840f5fb30b6SHawking Zhang 			return -EINVAL;
841f5fb30b6SHawking Zhang 		}
84259b0b509SAlex Deucher 
84359b0b509SAlex Deucher 	}
84459b0b509SAlex Deucher 	return -EINVAL;
84559b0b509SAlex Deucher }
846efe4f000STianci.Yin 
847efe4f000STianci.Yin /*
84882a52030SHawking Zhang  * Helper function to query two stage mem training capability
84982a52030SHawking Zhang  *
85082a52030SHawking Zhang  * @adev: amdgpu_device pointer
85182a52030SHawking Zhang  *
85282a52030SHawking Zhang  * Return true if two stage mem training is supported or false if not
853efe4f000STianci.Yin  */
amdgpu_atomfirmware_mem_training_supported(struct amdgpu_device * adev)85482a52030SHawking Zhang bool amdgpu_atomfirmware_mem_training_supported(struct amdgpu_device *adev)
855efe4f000STianci.Yin {
85682a52030SHawking Zhang 	u32 fw_cap;
857efe4f000STianci.Yin 
85882a52030SHawking Zhang 	fw_cap = adev->mode_info.firmware_flags;
859efe4f000STianci.Yin 
86082a52030SHawking Zhang 	return (fw_cap & ATOM_FIRMWARE_CAP_ENABLE_2STAGE_BIST_TRAINING) ? true : false;
861efe4f000STianci.Yin }
862efe4f000STianci.Yin 
amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device * adev)8639a244ebeSHawking Zhang int amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev)
8649a244ebeSHawking Zhang {
8659a244ebeSHawking Zhang 	struct atom_context *ctx = adev->mode_info.atom_context;
8669a244ebeSHawking Zhang 	union firmware_info *firmware_info;
8679a244ebeSHawking Zhang 	int index;
8689a244ebeSHawking Zhang 	u16 data_offset, size;
8699a244ebeSHawking Zhang 	u8 frev, crev;
8709a244ebeSHawking Zhang 	int fw_reserved_fb_size;
8719a244ebeSHawking Zhang 
8729a244ebeSHawking Zhang 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
8739a244ebeSHawking Zhang 			firmwareinfo);
8749a244ebeSHawking Zhang 
8759a244ebeSHawking Zhang 	if (!amdgpu_atom_parse_data_header(ctx, index, &size,
8769a244ebeSHawking Zhang 				&frev, &crev, &data_offset))
8779a244ebeSHawking Zhang 		/* fail to parse data_header */
8789a244ebeSHawking Zhang 		return 0;
8799a244ebeSHawking Zhang 
8809a244ebeSHawking Zhang 	firmware_info = (union firmware_info *)(ctx->bios + data_offset);
8819a244ebeSHawking Zhang 
8829a244ebeSHawking Zhang 	if (frev != 3)
8839a244ebeSHawking Zhang 		return -EINVAL;
8849a244ebeSHawking Zhang 
8859a244ebeSHawking Zhang 	switch (crev) {
8869a244ebeSHawking Zhang 	case 4:
8879a244ebeSHawking Zhang 		fw_reserved_fb_size =
8889a244ebeSHawking Zhang 			(firmware_info->v34.fw_reserved_size_in_kb << 10);
8899a244ebeSHawking Zhang 		break;
8909a244ebeSHawking Zhang 	default:
8919a244ebeSHawking Zhang 		fw_reserved_fb_size = 0;
8929a244ebeSHawking Zhang 		break;
8939a244ebeSHawking Zhang 	}
8949a244ebeSHawking Zhang 
8959a244ebeSHawking Zhang 	return fw_reserved_fb_size;
8969a244ebeSHawking Zhang }
897ba75f6ebSHawking Zhang 
898ba75f6ebSHawking Zhang /*
899ba75f6ebSHawking Zhang  * Helper function to execute asic_init table
900ba75f6ebSHawking Zhang  *
901ba75f6ebSHawking Zhang  * @adev: amdgpu_device pointer
902ba75f6ebSHawking Zhang  * @fb_reset: flag to indicate whether fb is reset or not
903ba75f6ebSHawking Zhang  *
904ba75f6ebSHawking Zhang  * Return 0 if succeed, otherwise failed
905ba75f6ebSHawking Zhang  */
amdgpu_atomfirmware_asic_init(struct amdgpu_device * adev,bool fb_reset)906ba75f6ebSHawking Zhang int amdgpu_atomfirmware_asic_init(struct amdgpu_device *adev, bool fb_reset)
907ba75f6ebSHawking Zhang {
908ba75f6ebSHawking Zhang 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
909ba75f6ebSHawking Zhang 	struct atom_context *ctx;
910ba75f6ebSHawking Zhang 	uint8_t frev, crev;
911ba75f6ebSHawking Zhang 	uint16_t data_offset;
912ba75f6ebSHawking Zhang 	uint32_t bootup_sclk_in10khz, bootup_mclk_in10khz;
913ba75f6ebSHawking Zhang 	struct asic_init_ps_allocation_v2_1 asic_init_ps_v2_1;
914ba75f6ebSHawking Zhang 	int index;
915ba75f6ebSHawking Zhang 
916ba75f6ebSHawking Zhang 	if (!mode_info)
917ba75f6ebSHawking Zhang 		return -EINVAL;
918ba75f6ebSHawking Zhang 
919ba75f6ebSHawking Zhang 	ctx = mode_info->atom_context;
920ba75f6ebSHawking Zhang 	if (!ctx)
921ba75f6ebSHawking Zhang 		return -EINVAL;
922ba75f6ebSHawking Zhang 
923ba75f6ebSHawking Zhang 	/* query bootup sclk/mclk from firmware_info table */
924ba75f6ebSHawking Zhang 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
925ba75f6ebSHawking Zhang 					    firmwareinfo);
926ba75f6ebSHawking Zhang 	if (amdgpu_atom_parse_data_header(ctx, index, NULL,
927ba75f6ebSHawking Zhang 				&frev, &crev, &data_offset)) {
928ba75f6ebSHawking Zhang 		union firmware_info *firmware_info =
929ba75f6ebSHawking Zhang 			(union firmware_info *)(ctx->bios +
930ba75f6ebSHawking Zhang 						data_offset);
931ba75f6ebSHawking Zhang 
932ba75f6ebSHawking Zhang 		bootup_sclk_in10khz =
933ba75f6ebSHawking Zhang 			le32_to_cpu(firmware_info->v31.bootup_sclk_in10khz);
934ba75f6ebSHawking Zhang 		bootup_mclk_in10khz =
935ba75f6ebSHawking Zhang 			le32_to_cpu(firmware_info->v31.bootup_mclk_in10khz);
936ba75f6ebSHawking Zhang 	} else {
937ba75f6ebSHawking Zhang 		return -EINVAL;
938ba75f6ebSHawking Zhang 	}
939ba75f6ebSHawking Zhang 
940ba75f6ebSHawking Zhang 	index = get_index_into_master_table(atom_master_list_of_command_functions_v2_1,
941ba75f6ebSHawking Zhang 					asic_init);
942ba75f6ebSHawking Zhang 	if (amdgpu_atom_parse_cmd_header(mode_info->atom_context, index, &frev, &crev)) {
943ba75f6ebSHawking Zhang 		if (frev == 2 && crev >= 1) {
944ba75f6ebSHawking Zhang 			memset(&asic_init_ps_v2_1, 0, sizeof(asic_init_ps_v2_1));
945ba75f6ebSHawking Zhang 			asic_init_ps_v2_1.param.engineparam.sclkfreqin10khz = bootup_sclk_in10khz;
946ba75f6ebSHawking Zhang 			asic_init_ps_v2_1.param.memparam.mclkfreqin10khz = bootup_mclk_in10khz;
947ba75f6ebSHawking Zhang 			asic_init_ps_v2_1.param.engineparam.engineflag = b3NORMAL_ENGINE_INIT;
948ba75f6ebSHawking Zhang 			if (!fb_reset)
949ba75f6ebSHawking Zhang 				asic_init_ps_v2_1.param.memparam.memflag = b3DRAM_SELF_REFRESH_EXIT;
950ba75f6ebSHawking Zhang 			else
951ba75f6ebSHawking Zhang 				asic_init_ps_v2_1.param.memparam.memflag = 0;
952ba75f6ebSHawking Zhang 		} else {
953ba75f6ebSHawking Zhang 			return -EINVAL;
954ba75f6ebSHawking Zhang 		}
955ba75f6ebSHawking Zhang 	} else {
956ba75f6ebSHawking Zhang 		return -EINVAL;
957ba75f6ebSHawking Zhang 	}
958ba75f6ebSHawking Zhang 
959ba75f6ebSHawking Zhang 	return amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, (uint32_t *)&asic_init_ps_v2_1);
960ba75f6ebSHawking Zhang }
961