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