162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2016 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1262306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <drm/amdgpu_drm.h>
2562306a36Sopenharmony_ci#include "amdgpu.h"
2662306a36Sopenharmony_ci#include "atomfirmware.h"
2762306a36Sopenharmony_ci#include "amdgpu_atomfirmware.h"
2862306a36Sopenharmony_ci#include "atom.h"
2962306a36Sopenharmony_ci#include "atombios.h"
3062306a36Sopenharmony_ci#include "soc15_hw_ip.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciunion firmware_info {
3362306a36Sopenharmony_ci	struct atom_firmware_info_v3_1 v31;
3462306a36Sopenharmony_ci	struct atom_firmware_info_v3_2 v32;
3562306a36Sopenharmony_ci	struct atom_firmware_info_v3_3 v33;
3662306a36Sopenharmony_ci	struct atom_firmware_info_v3_4 v34;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * Helper function to query firmware capability
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * @adev: amdgpu_device pointer
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Return firmware_capability in firmwareinfo table on success or 0 if not
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ciuint32_t amdgpu_atomfirmware_query_firmware_capability(struct amdgpu_device *adev)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct amdgpu_mode_info *mode_info = &adev->mode_info;
4962306a36Sopenharmony_ci	int index;
5062306a36Sopenharmony_ci	u16 data_offset, size;
5162306a36Sopenharmony_ci	union firmware_info *firmware_info;
5262306a36Sopenharmony_ci	u8 frev, crev;
5362306a36Sopenharmony_ci	u32 fw_cap = 0;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
5662306a36Sopenharmony_ci			firmwareinfo);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context,
5962306a36Sopenharmony_ci				index, &size, &frev, &crev, &data_offset)) {
6062306a36Sopenharmony_ci		/* support firmware_info 3.1 + */
6162306a36Sopenharmony_ci		if ((frev == 3 && crev >= 1) || (frev > 3)) {
6262306a36Sopenharmony_ci			firmware_info = (union firmware_info *)
6362306a36Sopenharmony_ci				(mode_info->atom_context->bios + data_offset);
6462306a36Sopenharmony_ci			fw_cap = le32_to_cpu(firmware_info->v31.firmware_capability);
6562306a36Sopenharmony_ci		}
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return fw_cap;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/*
7262306a36Sopenharmony_ci * Helper function to query gpu virtualizaiton capability
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * @adev: amdgpu_device pointer
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * Return true if gpu virtualization is supported or false if not
7762306a36Sopenharmony_ci */
7862306a36Sopenharmony_cibool amdgpu_atomfirmware_gpu_virtualization_supported(struct amdgpu_device *adev)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	u32 fw_cap;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	fw_cap = adev->mode_info.firmware_flags;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return (fw_cap & ATOM_FIRMWARE_CAP_GPU_VIRTUALIZATION) ? true : false;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_civoid amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
9062306a36Sopenharmony_ci						firmwareinfo);
9162306a36Sopenharmony_ci	uint16_t data_offset;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, NULL,
9462306a36Sopenharmony_ci					  NULL, NULL, &data_offset)) {
9562306a36Sopenharmony_ci		struct atom_firmware_info_v3_1 *firmware_info =
9662306a36Sopenharmony_ci			(struct atom_firmware_info_v3_1 *)(adev->mode_info.atom_context->bios +
9762306a36Sopenharmony_ci							   data_offset);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		adev->bios_scratch_reg_offset =
10062306a36Sopenharmony_ci			le32_to_cpu(firmware_info->bios_scratch_reg_startaddr);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic int amdgpu_atomfirmware_allocate_fb_v2_1(struct amdgpu_device *adev,
10562306a36Sopenharmony_ci	struct vram_usagebyfirmware_v2_1 *fw_usage, int *usage_bytes)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	u32 start_addr, fw_size, drv_size;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	start_addr = le32_to_cpu(fw_usage->start_address_in_kb);
11062306a36Sopenharmony_ci	fw_size = le16_to_cpu(fw_usage->used_by_firmware_in_kb);
11162306a36Sopenharmony_ci	drv_size = le16_to_cpu(fw_usage->used_by_driver_in_kb);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	DRM_DEBUG("atom firmware v2_1 requested %08x %dkb fw %dkb drv\n",
11462306a36Sopenharmony_ci			  start_addr,
11562306a36Sopenharmony_ci			  fw_size,
11662306a36Sopenharmony_ci			  drv_size);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if ((start_addr & ATOM_VRAM_OPERATION_FLAGS_MASK) ==
11962306a36Sopenharmony_ci		(u32)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION <<
12062306a36Sopenharmony_ci		ATOM_VRAM_OPERATION_FLAGS_SHIFT)) {
12162306a36Sopenharmony_ci		/* Firmware request VRAM reservation for SR-IOV */
12262306a36Sopenharmony_ci		adev->mman.fw_vram_usage_start_offset = (start_addr &
12362306a36Sopenharmony_ci			(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
12462306a36Sopenharmony_ci		adev->mman.fw_vram_usage_size = fw_size << 10;
12562306a36Sopenharmony_ci		/* Use the default scratch size */
12662306a36Sopenharmony_ci		*usage_bytes = 0;
12762306a36Sopenharmony_ci	} else {
12862306a36Sopenharmony_ci		*usage_bytes = drv_size << 10;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci	return 0;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int amdgpu_atomfirmware_allocate_fb_v2_2(struct amdgpu_device *adev,
13462306a36Sopenharmony_ci		struct vram_usagebyfirmware_v2_2 *fw_usage, int *usage_bytes)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	u32 fw_start_addr, fw_size, drv_start_addr, drv_size;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	fw_start_addr = le32_to_cpu(fw_usage->fw_region_start_address_in_kb);
13962306a36Sopenharmony_ci	fw_size = le16_to_cpu(fw_usage->used_by_firmware_in_kb);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	drv_start_addr = le32_to_cpu(fw_usage->driver_region0_start_address_in_kb);
14262306a36Sopenharmony_ci	drv_size = le32_to_cpu(fw_usage->used_by_driver_region0_in_kb);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	DRM_DEBUG("atom requested fw start at %08x %dkb and drv start at %08x %dkb\n",
14562306a36Sopenharmony_ci			  fw_start_addr,
14662306a36Sopenharmony_ci			  fw_size,
14762306a36Sopenharmony_ci			  drv_start_addr,
14862306a36Sopenharmony_ci			  drv_size);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (amdgpu_sriov_vf(adev) &&
15162306a36Sopenharmony_ci	    ((fw_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION <<
15262306a36Sopenharmony_ci		ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) {
15362306a36Sopenharmony_ci		/* Firmware request VRAM reservation for SR-IOV */
15462306a36Sopenharmony_ci		adev->mman.fw_vram_usage_start_offset = (fw_start_addr &
15562306a36Sopenharmony_ci			(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
15662306a36Sopenharmony_ci		adev->mman.fw_vram_usage_size = fw_size << 10;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (amdgpu_sriov_vf(adev) &&
16062306a36Sopenharmony_ci	    ((drv_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION <<
16162306a36Sopenharmony_ci		ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) {
16262306a36Sopenharmony_ci		/* driver request VRAM reservation for SR-IOV */
16362306a36Sopenharmony_ci		adev->mman.drv_vram_usage_start_offset = (drv_start_addr &
16462306a36Sopenharmony_ci			(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
16562306a36Sopenharmony_ci		adev->mman.drv_vram_usage_size = drv_size << 10;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	*usage_bytes = 0;
16962306a36Sopenharmony_ci	return 0;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciint amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	struct atom_context *ctx = adev->mode_info.atom_context;
17562306a36Sopenharmony_ci	int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
17662306a36Sopenharmony_ci						vram_usagebyfirmware);
17762306a36Sopenharmony_ci	struct vram_usagebyfirmware_v2_1 *fw_usage_v2_1;
17862306a36Sopenharmony_ci	struct vram_usagebyfirmware_v2_2 *fw_usage_v2_2;
17962306a36Sopenharmony_ci	u16 data_offset;
18062306a36Sopenharmony_ci	u8 frev, crev;
18162306a36Sopenharmony_ci	int usage_bytes = 0;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(ctx, index, NULL, &frev, &crev, &data_offset)) {
18462306a36Sopenharmony_ci		if (frev == 2 && crev == 1) {
18562306a36Sopenharmony_ci			fw_usage_v2_1 =
18662306a36Sopenharmony_ci				(struct vram_usagebyfirmware_v2_1 *)(ctx->bios + data_offset);
18762306a36Sopenharmony_ci			amdgpu_atomfirmware_allocate_fb_v2_1(adev,
18862306a36Sopenharmony_ci					fw_usage_v2_1,
18962306a36Sopenharmony_ci					&usage_bytes);
19062306a36Sopenharmony_ci		} else if (frev >= 2 && crev >= 2) {
19162306a36Sopenharmony_ci			fw_usage_v2_2 =
19262306a36Sopenharmony_ci				(struct vram_usagebyfirmware_v2_2 *)(ctx->bios + data_offset);
19362306a36Sopenharmony_ci			amdgpu_atomfirmware_allocate_fb_v2_2(adev,
19462306a36Sopenharmony_ci					fw_usage_v2_2,
19562306a36Sopenharmony_ci					&usage_bytes);
19662306a36Sopenharmony_ci		}
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	ctx->scratch_size_bytes = 0;
20062306a36Sopenharmony_ci	if (usage_bytes == 0)
20162306a36Sopenharmony_ci		usage_bytes = 20 * 1024;
20262306a36Sopenharmony_ci	/* allocate some scratch memory */
20362306a36Sopenharmony_ci	ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
20462306a36Sopenharmony_ci	if (!ctx->scratch)
20562306a36Sopenharmony_ci		return -ENOMEM;
20662306a36Sopenharmony_ci	ctx->scratch_size_bytes = usage_bytes;
20762306a36Sopenharmony_ci	return 0;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ciunion igp_info {
21162306a36Sopenharmony_ci	struct atom_integrated_system_info_v1_11 v11;
21262306a36Sopenharmony_ci	struct atom_integrated_system_info_v1_12 v12;
21362306a36Sopenharmony_ci	struct atom_integrated_system_info_v2_1 v21;
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ciunion umc_info {
21762306a36Sopenharmony_ci	struct atom_umc_info_v3_1 v31;
21862306a36Sopenharmony_ci	struct atom_umc_info_v3_2 v32;
21962306a36Sopenharmony_ci	struct atom_umc_info_v3_3 v33;
22062306a36Sopenharmony_ci	struct atom_umc_info_v4_0 v40;
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ciunion vram_info {
22462306a36Sopenharmony_ci	struct atom_vram_info_header_v2_3 v23;
22562306a36Sopenharmony_ci	struct atom_vram_info_header_v2_4 v24;
22662306a36Sopenharmony_ci	struct atom_vram_info_header_v2_5 v25;
22762306a36Sopenharmony_ci	struct atom_vram_info_header_v2_6 v26;
22862306a36Sopenharmony_ci	struct atom_vram_info_header_v3_0 v30;
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ciunion vram_module {
23262306a36Sopenharmony_ci	struct atom_vram_module_v9 v9;
23362306a36Sopenharmony_ci	struct atom_vram_module_v10 v10;
23462306a36Sopenharmony_ci	struct atom_vram_module_v11 v11;
23562306a36Sopenharmony_ci	struct atom_vram_module_v3_0 v30;
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int convert_atom_mem_type_to_vram_type(struct amdgpu_device *adev,
23962306a36Sopenharmony_ci					      int atom_mem_type)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	int vram_type;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (adev->flags & AMD_IS_APU) {
24462306a36Sopenharmony_ci		switch (atom_mem_type) {
24562306a36Sopenharmony_ci		case Ddr2MemType:
24662306a36Sopenharmony_ci		case LpDdr2MemType:
24762306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_DDR2;
24862306a36Sopenharmony_ci			break;
24962306a36Sopenharmony_ci		case Ddr3MemType:
25062306a36Sopenharmony_ci		case LpDdr3MemType:
25162306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_DDR3;
25262306a36Sopenharmony_ci			break;
25362306a36Sopenharmony_ci		case Ddr4MemType:
25462306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_DDR4;
25562306a36Sopenharmony_ci			break;
25662306a36Sopenharmony_ci		case LpDdr4MemType:
25762306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_LPDDR4;
25862306a36Sopenharmony_ci			break;
25962306a36Sopenharmony_ci		case Ddr5MemType:
26062306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_DDR5;
26162306a36Sopenharmony_ci			break;
26262306a36Sopenharmony_ci		case LpDdr5MemType:
26362306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_LPDDR5;
26462306a36Sopenharmony_ci			break;
26562306a36Sopenharmony_ci		default:
26662306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
26762306a36Sopenharmony_ci			break;
26862306a36Sopenharmony_ci		}
26962306a36Sopenharmony_ci	} else {
27062306a36Sopenharmony_ci		switch (atom_mem_type) {
27162306a36Sopenharmony_ci		case ATOM_DGPU_VRAM_TYPE_GDDR5:
27262306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_GDDR5;
27362306a36Sopenharmony_ci			break;
27462306a36Sopenharmony_ci		case ATOM_DGPU_VRAM_TYPE_HBM2:
27562306a36Sopenharmony_ci		case ATOM_DGPU_VRAM_TYPE_HBM2E:
27662306a36Sopenharmony_ci		case ATOM_DGPU_VRAM_TYPE_HBM3:
27762306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_HBM;
27862306a36Sopenharmony_ci			break;
27962306a36Sopenharmony_ci		case ATOM_DGPU_VRAM_TYPE_GDDR6:
28062306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_GDDR6;
28162306a36Sopenharmony_ci			break;
28262306a36Sopenharmony_ci		default:
28362306a36Sopenharmony_ci			vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
28462306a36Sopenharmony_ci			break;
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return vram_type;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ciint
29362306a36Sopenharmony_ciamdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
29462306a36Sopenharmony_ci				  int *vram_width, int *vram_type,
29562306a36Sopenharmony_ci				  int *vram_vendor)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct amdgpu_mode_info *mode_info = &adev->mode_info;
29862306a36Sopenharmony_ci	int index, i = 0;
29962306a36Sopenharmony_ci	u16 data_offset, size;
30062306a36Sopenharmony_ci	union igp_info *igp_info;
30162306a36Sopenharmony_ci	union vram_info *vram_info;
30262306a36Sopenharmony_ci	union vram_module *vram_module;
30362306a36Sopenharmony_ci	u8 frev, crev;
30462306a36Sopenharmony_ci	u8 mem_type;
30562306a36Sopenharmony_ci	u8 mem_vendor;
30662306a36Sopenharmony_ci	u32 mem_channel_number;
30762306a36Sopenharmony_ci	u32 mem_channel_width;
30862306a36Sopenharmony_ci	u32 module_id;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (adev->flags & AMD_IS_APU)
31162306a36Sopenharmony_ci		index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
31262306a36Sopenharmony_ci						    integratedsysteminfo);
31362306a36Sopenharmony_ci	else
31462306a36Sopenharmony_ci		index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
31562306a36Sopenharmony_ci						    vram_info);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(mode_info->atom_context,
31862306a36Sopenharmony_ci					  index, &size,
31962306a36Sopenharmony_ci					  &frev, &crev, &data_offset)) {
32062306a36Sopenharmony_ci		if (adev->flags & AMD_IS_APU) {
32162306a36Sopenharmony_ci			igp_info = (union igp_info *)
32262306a36Sopenharmony_ci				(mode_info->atom_context->bios + data_offset);
32362306a36Sopenharmony_ci			switch (frev) {
32462306a36Sopenharmony_ci			case 1:
32562306a36Sopenharmony_ci				switch (crev) {
32662306a36Sopenharmony_ci				case 11:
32762306a36Sopenharmony_ci				case 12:
32862306a36Sopenharmony_ci					mem_channel_number = igp_info->v11.umachannelnumber;
32962306a36Sopenharmony_ci					if (!mem_channel_number)
33062306a36Sopenharmony_ci						mem_channel_number = 1;
33162306a36Sopenharmony_ci					mem_type = igp_info->v11.memorytype;
33262306a36Sopenharmony_ci					if (mem_type == LpDdr5MemType)
33362306a36Sopenharmony_ci						mem_channel_width = 32;
33462306a36Sopenharmony_ci					else
33562306a36Sopenharmony_ci						mem_channel_width = 64;
33662306a36Sopenharmony_ci					if (vram_width)
33762306a36Sopenharmony_ci						*vram_width = mem_channel_number * mem_channel_width;
33862306a36Sopenharmony_ci					if (vram_type)
33962306a36Sopenharmony_ci						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
34062306a36Sopenharmony_ci					break;
34162306a36Sopenharmony_ci				default:
34262306a36Sopenharmony_ci					return -EINVAL;
34362306a36Sopenharmony_ci				}
34462306a36Sopenharmony_ci				break;
34562306a36Sopenharmony_ci			case 2:
34662306a36Sopenharmony_ci				switch (crev) {
34762306a36Sopenharmony_ci				case 1:
34862306a36Sopenharmony_ci				case 2:
34962306a36Sopenharmony_ci					mem_channel_number = igp_info->v21.umachannelnumber;
35062306a36Sopenharmony_ci					if (!mem_channel_number)
35162306a36Sopenharmony_ci						mem_channel_number = 1;
35262306a36Sopenharmony_ci					mem_type = igp_info->v21.memorytype;
35362306a36Sopenharmony_ci					if (mem_type == LpDdr5MemType)
35462306a36Sopenharmony_ci						mem_channel_width = 32;
35562306a36Sopenharmony_ci					else
35662306a36Sopenharmony_ci						mem_channel_width = 64;
35762306a36Sopenharmony_ci					if (vram_width)
35862306a36Sopenharmony_ci						*vram_width = mem_channel_number * mem_channel_width;
35962306a36Sopenharmony_ci					if (vram_type)
36062306a36Sopenharmony_ci						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
36162306a36Sopenharmony_ci					break;
36262306a36Sopenharmony_ci				default:
36362306a36Sopenharmony_ci					return -EINVAL;
36462306a36Sopenharmony_ci				}
36562306a36Sopenharmony_ci				break;
36662306a36Sopenharmony_ci			default:
36762306a36Sopenharmony_ci				return -EINVAL;
36862306a36Sopenharmony_ci			}
36962306a36Sopenharmony_ci		} else {
37062306a36Sopenharmony_ci			vram_info = (union vram_info *)
37162306a36Sopenharmony_ci				(mode_info->atom_context->bios + data_offset);
37262306a36Sopenharmony_ci			module_id = (RREG32(adev->bios_scratch_reg_offset + 4) & 0x00ff0000) >> 16;
37362306a36Sopenharmony_ci			if (frev == 3) {
37462306a36Sopenharmony_ci				switch (crev) {
37562306a36Sopenharmony_ci				/* v30 */
37662306a36Sopenharmony_ci				case 0:
37762306a36Sopenharmony_ci					vram_module = (union vram_module *)vram_info->v30.vram_module;
37862306a36Sopenharmony_ci					mem_vendor = (vram_module->v30.dram_vendor_id) & 0xF;
37962306a36Sopenharmony_ci					if (vram_vendor)
38062306a36Sopenharmony_ci						*vram_vendor = mem_vendor;
38162306a36Sopenharmony_ci					mem_type = vram_info->v30.memory_type;
38262306a36Sopenharmony_ci					if (vram_type)
38362306a36Sopenharmony_ci						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
38462306a36Sopenharmony_ci					mem_channel_number = vram_info->v30.channel_num;
38562306a36Sopenharmony_ci					mem_channel_width = vram_info->v30.channel_width;
38662306a36Sopenharmony_ci					if (vram_width)
38762306a36Sopenharmony_ci						*vram_width = mem_channel_number * (1 << mem_channel_width);
38862306a36Sopenharmony_ci					break;
38962306a36Sopenharmony_ci				default:
39062306a36Sopenharmony_ci					return -EINVAL;
39162306a36Sopenharmony_ci				}
39262306a36Sopenharmony_ci			} else if (frev == 2) {
39362306a36Sopenharmony_ci				switch (crev) {
39462306a36Sopenharmony_ci				/* v23 */
39562306a36Sopenharmony_ci				case 3:
39662306a36Sopenharmony_ci					if (module_id > vram_info->v23.vram_module_num)
39762306a36Sopenharmony_ci						module_id = 0;
39862306a36Sopenharmony_ci					vram_module = (union vram_module *)vram_info->v23.vram_module;
39962306a36Sopenharmony_ci					while (i < module_id) {
40062306a36Sopenharmony_ci						vram_module = (union vram_module *)
40162306a36Sopenharmony_ci							((u8 *)vram_module + vram_module->v9.vram_module_size);
40262306a36Sopenharmony_ci						i++;
40362306a36Sopenharmony_ci					}
40462306a36Sopenharmony_ci					mem_type = vram_module->v9.memory_type;
40562306a36Sopenharmony_ci					if (vram_type)
40662306a36Sopenharmony_ci						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
40762306a36Sopenharmony_ci					mem_channel_number = vram_module->v9.channel_num;
40862306a36Sopenharmony_ci					mem_channel_width = vram_module->v9.channel_width;
40962306a36Sopenharmony_ci					if (vram_width)
41062306a36Sopenharmony_ci						*vram_width = mem_channel_number * (1 << mem_channel_width);
41162306a36Sopenharmony_ci					mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
41262306a36Sopenharmony_ci					if (vram_vendor)
41362306a36Sopenharmony_ci						*vram_vendor = mem_vendor;
41462306a36Sopenharmony_ci					break;
41562306a36Sopenharmony_ci				/* v24 */
41662306a36Sopenharmony_ci				case 4:
41762306a36Sopenharmony_ci					if (module_id > vram_info->v24.vram_module_num)
41862306a36Sopenharmony_ci						module_id = 0;
41962306a36Sopenharmony_ci					vram_module = (union vram_module *)vram_info->v24.vram_module;
42062306a36Sopenharmony_ci					while (i < module_id) {
42162306a36Sopenharmony_ci						vram_module = (union vram_module *)
42262306a36Sopenharmony_ci							((u8 *)vram_module + vram_module->v10.vram_module_size);
42362306a36Sopenharmony_ci						i++;
42462306a36Sopenharmony_ci					}
42562306a36Sopenharmony_ci					mem_type = vram_module->v10.memory_type;
42662306a36Sopenharmony_ci					if (vram_type)
42762306a36Sopenharmony_ci						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
42862306a36Sopenharmony_ci					mem_channel_number = vram_module->v10.channel_num;
42962306a36Sopenharmony_ci					mem_channel_width = vram_module->v10.channel_width;
43062306a36Sopenharmony_ci					if (vram_width)
43162306a36Sopenharmony_ci						*vram_width = mem_channel_number * (1 << mem_channel_width);
43262306a36Sopenharmony_ci					mem_vendor = (vram_module->v10.vender_rev_id) & 0xF;
43362306a36Sopenharmony_ci					if (vram_vendor)
43462306a36Sopenharmony_ci						*vram_vendor = mem_vendor;
43562306a36Sopenharmony_ci					break;
43662306a36Sopenharmony_ci				/* v25 */
43762306a36Sopenharmony_ci				case 5:
43862306a36Sopenharmony_ci					if (module_id > vram_info->v25.vram_module_num)
43962306a36Sopenharmony_ci						module_id = 0;
44062306a36Sopenharmony_ci					vram_module = (union vram_module *)vram_info->v25.vram_module;
44162306a36Sopenharmony_ci					while (i < module_id) {
44262306a36Sopenharmony_ci						vram_module = (union vram_module *)
44362306a36Sopenharmony_ci							((u8 *)vram_module + vram_module->v11.vram_module_size);
44462306a36Sopenharmony_ci						i++;
44562306a36Sopenharmony_ci					}
44662306a36Sopenharmony_ci					mem_type = vram_module->v11.memory_type;
44762306a36Sopenharmony_ci					if (vram_type)
44862306a36Sopenharmony_ci						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
44962306a36Sopenharmony_ci					mem_channel_number = vram_module->v11.channel_num;
45062306a36Sopenharmony_ci					mem_channel_width = vram_module->v11.channel_width;
45162306a36Sopenharmony_ci					if (vram_width)
45262306a36Sopenharmony_ci						*vram_width = mem_channel_number * (1 << mem_channel_width);
45362306a36Sopenharmony_ci					mem_vendor = (vram_module->v11.vender_rev_id) & 0xF;
45462306a36Sopenharmony_ci					if (vram_vendor)
45562306a36Sopenharmony_ci						*vram_vendor = mem_vendor;
45662306a36Sopenharmony_ci					break;
45762306a36Sopenharmony_ci				/* v26 */
45862306a36Sopenharmony_ci				case 6:
45962306a36Sopenharmony_ci					if (module_id > vram_info->v26.vram_module_num)
46062306a36Sopenharmony_ci						module_id = 0;
46162306a36Sopenharmony_ci					vram_module = (union vram_module *)vram_info->v26.vram_module;
46262306a36Sopenharmony_ci					while (i < module_id) {
46362306a36Sopenharmony_ci						vram_module = (union vram_module *)
46462306a36Sopenharmony_ci							((u8 *)vram_module + vram_module->v9.vram_module_size);
46562306a36Sopenharmony_ci						i++;
46662306a36Sopenharmony_ci					}
46762306a36Sopenharmony_ci					mem_type = vram_module->v9.memory_type;
46862306a36Sopenharmony_ci					if (vram_type)
46962306a36Sopenharmony_ci						*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
47062306a36Sopenharmony_ci					mem_channel_number = vram_module->v9.channel_num;
47162306a36Sopenharmony_ci					mem_channel_width = vram_module->v9.channel_width;
47262306a36Sopenharmony_ci					if (vram_width)
47362306a36Sopenharmony_ci						*vram_width = mem_channel_number * (1 << mem_channel_width);
47462306a36Sopenharmony_ci					mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
47562306a36Sopenharmony_ci					if (vram_vendor)
47662306a36Sopenharmony_ci						*vram_vendor = mem_vendor;
47762306a36Sopenharmony_ci					break;
47862306a36Sopenharmony_ci				default:
47962306a36Sopenharmony_ci					return -EINVAL;
48062306a36Sopenharmony_ci				}
48162306a36Sopenharmony_ci			} else {
48262306a36Sopenharmony_ci				/* invalid frev */
48362306a36Sopenharmony_ci				return -EINVAL;
48462306a36Sopenharmony_ci			}
48562306a36Sopenharmony_ci		}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	return 0;
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/*
49362306a36Sopenharmony_ci * Return true if vbios enabled ecc by default, if umc info table is available
49462306a36Sopenharmony_ci * or false if ecc is not enabled or umc info table is not available
49562306a36Sopenharmony_ci */
49662306a36Sopenharmony_cibool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct amdgpu_mode_info *mode_info = &adev->mode_info;
49962306a36Sopenharmony_ci	int index;
50062306a36Sopenharmony_ci	u16 data_offset, size;
50162306a36Sopenharmony_ci	union umc_info *umc_info;
50262306a36Sopenharmony_ci	u8 frev, crev;
50362306a36Sopenharmony_ci	bool ecc_default_enabled = false;
50462306a36Sopenharmony_ci	u8 umc_config;
50562306a36Sopenharmony_ci	u32 umc_config1;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
50862306a36Sopenharmony_ci			umc_info);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(mode_info->atom_context,
51162306a36Sopenharmony_ci				index, &size, &frev, &crev, &data_offset)) {
51262306a36Sopenharmony_ci		umc_info = (union umc_info *)(mode_info->atom_context->bios + data_offset);
51362306a36Sopenharmony_ci		if (frev == 3) {
51462306a36Sopenharmony_ci			switch (crev) {
51562306a36Sopenharmony_ci			case 1:
51662306a36Sopenharmony_ci				umc_config = le32_to_cpu(umc_info->v31.umc_config);
51762306a36Sopenharmony_ci				ecc_default_enabled =
51862306a36Sopenharmony_ci					(umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ? true : false;
51962306a36Sopenharmony_ci				break;
52062306a36Sopenharmony_ci			case 2:
52162306a36Sopenharmony_ci				umc_config = le32_to_cpu(umc_info->v32.umc_config);
52262306a36Sopenharmony_ci				ecc_default_enabled =
52362306a36Sopenharmony_ci					(umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ? true : false;
52462306a36Sopenharmony_ci				break;
52562306a36Sopenharmony_ci			case 3:
52662306a36Sopenharmony_ci				umc_config = le32_to_cpu(umc_info->v33.umc_config);
52762306a36Sopenharmony_ci				umc_config1 = le32_to_cpu(umc_info->v33.umc_config1);
52862306a36Sopenharmony_ci				ecc_default_enabled =
52962306a36Sopenharmony_ci					((umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ||
53062306a36Sopenharmony_ci					 (umc_config1 & UMC_CONFIG1__ENABLE_ECC_CAPABLE)) ? true : false;
53162306a36Sopenharmony_ci				break;
53262306a36Sopenharmony_ci			default:
53362306a36Sopenharmony_ci				/* unsupported crev */
53462306a36Sopenharmony_ci				return false;
53562306a36Sopenharmony_ci			}
53662306a36Sopenharmony_ci		} else if (frev == 4) {
53762306a36Sopenharmony_ci			switch (crev) {
53862306a36Sopenharmony_ci			case 0:
53962306a36Sopenharmony_ci				umc_config1 = le32_to_cpu(umc_info->v40.umc_config1);
54062306a36Sopenharmony_ci				ecc_default_enabled =
54162306a36Sopenharmony_ci					(umc_config1 & UMC_CONFIG1__ENABLE_ECC_CAPABLE) ? true : false;
54262306a36Sopenharmony_ci				break;
54362306a36Sopenharmony_ci			default:
54462306a36Sopenharmony_ci				/* unsupported crev */
54562306a36Sopenharmony_ci				return false;
54662306a36Sopenharmony_ci			}
54762306a36Sopenharmony_ci		} else {
54862306a36Sopenharmony_ci			/* unsupported frev */
54962306a36Sopenharmony_ci			return false;
55062306a36Sopenharmony_ci		}
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	return ecc_default_enabled;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci/*
55762306a36Sopenharmony_ci * Helper function to query sram ecc capablity
55862306a36Sopenharmony_ci *
55962306a36Sopenharmony_ci * @adev: amdgpu_device pointer
56062306a36Sopenharmony_ci *
56162306a36Sopenharmony_ci * Return true if vbios supports sram ecc or false if not
56262306a36Sopenharmony_ci */
56362306a36Sopenharmony_cibool amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device *adev)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	u32 fw_cap;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	fw_cap = adev->mode_info.firmware_flags;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	return (fw_cap & ATOM_FIRMWARE_CAP_SRAM_ECC) ? true : false;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci/*
57362306a36Sopenharmony_ci * Helper function to query dynamic boot config capability
57462306a36Sopenharmony_ci *
57562306a36Sopenharmony_ci * @adev: amdgpu_device pointer
57662306a36Sopenharmony_ci *
57762306a36Sopenharmony_ci * Return true if vbios supports dynamic boot config or false if not
57862306a36Sopenharmony_ci */
57962306a36Sopenharmony_cibool amdgpu_atomfirmware_dynamic_boot_config_supported(struct amdgpu_device *adev)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	u32 fw_cap;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	fw_cap = adev->mode_info.firmware_flags;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	return (fw_cap & ATOM_FIRMWARE_CAP_DYNAMIC_BOOT_CFG_ENABLE) ? true : false;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci/**
58962306a36Sopenharmony_ci * amdgpu_atomfirmware_ras_rom_addr -- Get the RAS EEPROM addr from VBIOS
59062306a36Sopenharmony_ci * @adev: amdgpu_device pointer
59162306a36Sopenharmony_ci * @i2c_address: pointer to u8; if not NULL, will contain
59262306a36Sopenharmony_ci *    the RAS EEPROM address if the function returns true
59362306a36Sopenharmony_ci *
59462306a36Sopenharmony_ci * Return true if VBIOS supports RAS EEPROM address reporting,
59562306a36Sopenharmony_ci * else return false. If true and @i2c_address is not NULL,
59662306a36Sopenharmony_ci * will contain the RAS ROM address.
59762306a36Sopenharmony_ci */
59862306a36Sopenharmony_cibool amdgpu_atomfirmware_ras_rom_addr(struct amdgpu_device *adev,
59962306a36Sopenharmony_ci				      u8 *i2c_address)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct amdgpu_mode_info *mode_info = &adev->mode_info;
60262306a36Sopenharmony_ci	int index;
60362306a36Sopenharmony_ci	u16 data_offset, size;
60462306a36Sopenharmony_ci	union firmware_info *firmware_info;
60562306a36Sopenharmony_ci	u8 frev, crev;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
60862306a36Sopenharmony_ci					    firmwareinfo);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context,
61162306a36Sopenharmony_ci					  index, &size, &frev, &crev,
61262306a36Sopenharmony_ci					  &data_offset)) {
61362306a36Sopenharmony_ci		/* support firmware_info 3.4 + */
61462306a36Sopenharmony_ci		if ((frev == 3 && crev >= 4) || (frev > 3)) {
61562306a36Sopenharmony_ci			firmware_info = (union firmware_info *)
61662306a36Sopenharmony_ci				(mode_info->atom_context->bios + data_offset);
61762306a36Sopenharmony_ci			/* The ras_rom_i2c_slave_addr should ideally
61862306a36Sopenharmony_ci			 * be a 19-bit EEPROM address, which would be
61962306a36Sopenharmony_ci			 * used as is by the driver; see top of
62062306a36Sopenharmony_ci			 * amdgpu_eeprom.c.
62162306a36Sopenharmony_ci			 *
62262306a36Sopenharmony_ci			 * When this is the case, 0 is of course a
62362306a36Sopenharmony_ci			 * valid RAS EEPROM address, in which case,
62462306a36Sopenharmony_ci			 * we'll drop the first "if (firm...)" and only
62562306a36Sopenharmony_ci			 * leave the check for the pointer.
62662306a36Sopenharmony_ci			 *
62762306a36Sopenharmony_ci			 * The reason this works right now is because
62862306a36Sopenharmony_ci			 * ras_rom_i2c_slave_addr contains the EEPROM
62962306a36Sopenharmony_ci			 * device type qualifier 1010b in the top 4
63062306a36Sopenharmony_ci			 * bits.
63162306a36Sopenharmony_ci			 */
63262306a36Sopenharmony_ci			if (firmware_info->v34.ras_rom_i2c_slave_addr) {
63362306a36Sopenharmony_ci				if (i2c_address)
63462306a36Sopenharmony_ci					*i2c_address = firmware_info->v34.ras_rom_i2c_slave_addr;
63562306a36Sopenharmony_ci				return true;
63662306a36Sopenharmony_ci			}
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	return false;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ciunion smu_info {
64562306a36Sopenharmony_ci	struct atom_smu_info_v3_1 v31;
64662306a36Sopenharmony_ci	struct atom_smu_info_v4_0 v40;
64762306a36Sopenharmony_ci};
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ciunion gfx_info {
65062306a36Sopenharmony_ci	struct atom_gfx_info_v2_2 v22;
65162306a36Sopenharmony_ci	struct atom_gfx_info_v2_4 v24;
65262306a36Sopenharmony_ci	struct atom_gfx_info_v2_7 v27;
65362306a36Sopenharmony_ci	struct atom_gfx_info_v3_0 v30;
65462306a36Sopenharmony_ci};
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ciint amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	struct amdgpu_mode_info *mode_info = &adev->mode_info;
65962306a36Sopenharmony_ci	struct amdgpu_pll *spll = &adev->clock.spll;
66062306a36Sopenharmony_ci	struct amdgpu_pll *mpll = &adev->clock.mpll;
66162306a36Sopenharmony_ci	uint8_t frev, crev;
66262306a36Sopenharmony_ci	uint16_t data_offset;
66362306a36Sopenharmony_ci	int ret = -EINVAL, index;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
66662306a36Sopenharmony_ci					    firmwareinfo);
66762306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
66862306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
66962306a36Sopenharmony_ci		union firmware_info *firmware_info =
67062306a36Sopenharmony_ci			(union firmware_info *)(mode_info->atom_context->bios +
67162306a36Sopenharmony_ci						data_offset);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		adev->clock.default_sclk =
67462306a36Sopenharmony_ci			le32_to_cpu(firmware_info->v31.bootup_sclk_in10khz);
67562306a36Sopenharmony_ci		adev->clock.default_mclk =
67662306a36Sopenharmony_ci			le32_to_cpu(firmware_info->v31.bootup_mclk_in10khz);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		adev->pm.current_sclk = adev->clock.default_sclk;
67962306a36Sopenharmony_ci		adev->pm.current_mclk = adev->clock.default_mclk;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci		ret = 0;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
68562306a36Sopenharmony_ci					    smu_info);
68662306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
68762306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
68862306a36Sopenharmony_ci		union smu_info *smu_info =
68962306a36Sopenharmony_ci			(union smu_info *)(mode_info->atom_context->bios +
69062306a36Sopenharmony_ci					   data_offset);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		/* system clock */
69362306a36Sopenharmony_ci		if (frev == 3)
69462306a36Sopenharmony_ci			spll->reference_freq = le32_to_cpu(smu_info->v31.core_refclk_10khz);
69562306a36Sopenharmony_ci		else if (frev == 4)
69662306a36Sopenharmony_ci			spll->reference_freq = le32_to_cpu(smu_info->v40.core_refclk_10khz);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		spll->reference_div = 0;
69962306a36Sopenharmony_ci		spll->min_post_div = 1;
70062306a36Sopenharmony_ci		spll->max_post_div = 1;
70162306a36Sopenharmony_ci		spll->min_ref_div = 2;
70262306a36Sopenharmony_ci		spll->max_ref_div = 0xff;
70362306a36Sopenharmony_ci		spll->min_feedback_div = 4;
70462306a36Sopenharmony_ci		spll->max_feedback_div = 0xff;
70562306a36Sopenharmony_ci		spll->best_vco = 0;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		ret = 0;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
71162306a36Sopenharmony_ci					    umc_info);
71262306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
71362306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
71462306a36Sopenharmony_ci		union umc_info *umc_info =
71562306a36Sopenharmony_ci			(union umc_info *)(mode_info->atom_context->bios +
71662306a36Sopenharmony_ci					   data_offset);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		/* memory clock */
71962306a36Sopenharmony_ci		mpll->reference_freq = le32_to_cpu(umc_info->v31.mem_refclk_10khz);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		mpll->reference_div = 0;
72262306a36Sopenharmony_ci		mpll->min_post_div = 1;
72362306a36Sopenharmony_ci		mpll->max_post_div = 1;
72462306a36Sopenharmony_ci		mpll->min_ref_div = 2;
72562306a36Sopenharmony_ci		mpll->max_ref_div = 0xff;
72662306a36Sopenharmony_ci		mpll->min_feedback_div = 4;
72762306a36Sopenharmony_ci		mpll->max_feedback_div = 0xff;
72862306a36Sopenharmony_ci		mpll->best_vco = 0;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		ret = 0;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	/* if asic is Navi+, the rlc reference clock is used for system clock
73462306a36Sopenharmony_ci	 * from vbios gfx_info table */
73562306a36Sopenharmony_ci	if (adev->asic_type >= CHIP_NAVI10) {
73662306a36Sopenharmony_ci		index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
73762306a36Sopenharmony_ci						   gfx_info);
73862306a36Sopenharmony_ci		if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
73962306a36Sopenharmony_ci					  &frev, &crev, &data_offset)) {
74062306a36Sopenharmony_ci			union gfx_info *gfx_info = (union gfx_info *)
74162306a36Sopenharmony_ci				(mode_info->atom_context->bios + data_offset);
74262306a36Sopenharmony_ci			if ((frev == 3) ||
74362306a36Sopenharmony_ci			    (frev == 2 && crev == 6)) {
74462306a36Sopenharmony_ci				spll->reference_freq = le32_to_cpu(gfx_info->v30.golden_tsc_count_lower_refclk);
74562306a36Sopenharmony_ci				ret = 0;
74662306a36Sopenharmony_ci			} else if ((frev == 2) &&
74762306a36Sopenharmony_ci				   (crev >= 2) &&
74862306a36Sopenharmony_ci				   (crev != 6)) {
74962306a36Sopenharmony_ci				spll->reference_freq = le32_to_cpu(gfx_info->v22.rlc_gpu_timer_refclk);
75062306a36Sopenharmony_ci				ret = 0;
75162306a36Sopenharmony_ci			} else {
75262306a36Sopenharmony_ci				BUG();
75362306a36Sopenharmony_ci			}
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	return ret;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ciint amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	struct amdgpu_mode_info *mode_info = &adev->mode_info;
76362306a36Sopenharmony_ci	int index;
76462306a36Sopenharmony_ci	uint8_t frev, crev;
76562306a36Sopenharmony_ci	uint16_t data_offset;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
76862306a36Sopenharmony_ci					    gfx_info);
76962306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
77062306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
77162306a36Sopenharmony_ci		union gfx_info *gfx_info = (union gfx_info *)
77262306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset);
77362306a36Sopenharmony_ci		if (frev == 2) {
77462306a36Sopenharmony_ci			switch (crev) {
77562306a36Sopenharmony_ci			case 4:
77662306a36Sopenharmony_ci				adev->gfx.config.max_shader_engines = gfx_info->v24.max_shader_engines;
77762306a36Sopenharmony_ci				adev->gfx.config.max_cu_per_sh = gfx_info->v24.max_cu_per_sh;
77862306a36Sopenharmony_ci				adev->gfx.config.max_sh_per_se = gfx_info->v24.max_sh_per_se;
77962306a36Sopenharmony_ci				adev->gfx.config.max_backends_per_se = gfx_info->v24.max_backends_per_se;
78062306a36Sopenharmony_ci				adev->gfx.config.max_texture_channel_caches = gfx_info->v24.max_texture_channel_caches;
78162306a36Sopenharmony_ci				adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v24.gc_num_gprs);
78262306a36Sopenharmony_ci				adev->gfx.config.max_gs_threads = gfx_info->v24.gc_num_max_gs_thds;
78362306a36Sopenharmony_ci				adev->gfx.config.gs_vgt_table_depth = gfx_info->v24.gc_gs_table_depth;
78462306a36Sopenharmony_ci				adev->gfx.config.gs_prim_buffer_depth =
78562306a36Sopenharmony_ci					le16_to_cpu(gfx_info->v24.gc_gsprim_buff_depth);
78662306a36Sopenharmony_ci				adev->gfx.config.double_offchip_lds_buf =
78762306a36Sopenharmony_ci					gfx_info->v24.gc_double_offchip_lds_buffer;
78862306a36Sopenharmony_ci				adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v24.gc_wave_size);
78962306a36Sopenharmony_ci				adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v24.gc_max_waves_per_simd);
79062306a36Sopenharmony_ci				adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v24.gc_max_scratch_slots_per_cu;
79162306a36Sopenharmony_ci				adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v24.gc_lds_size);
79262306a36Sopenharmony_ci				return 0;
79362306a36Sopenharmony_ci			case 7:
79462306a36Sopenharmony_ci				adev->gfx.config.max_shader_engines = gfx_info->v27.max_shader_engines;
79562306a36Sopenharmony_ci				adev->gfx.config.max_cu_per_sh = gfx_info->v27.max_cu_per_sh;
79662306a36Sopenharmony_ci				adev->gfx.config.max_sh_per_se = gfx_info->v27.max_sh_per_se;
79762306a36Sopenharmony_ci				adev->gfx.config.max_backends_per_se = gfx_info->v27.max_backends_per_se;
79862306a36Sopenharmony_ci				adev->gfx.config.max_texture_channel_caches = gfx_info->v27.max_texture_channel_caches;
79962306a36Sopenharmony_ci				adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v27.gc_num_gprs);
80062306a36Sopenharmony_ci				adev->gfx.config.max_gs_threads = gfx_info->v27.gc_num_max_gs_thds;
80162306a36Sopenharmony_ci				adev->gfx.config.gs_vgt_table_depth = gfx_info->v27.gc_gs_table_depth;
80262306a36Sopenharmony_ci				adev->gfx.config.gs_prim_buffer_depth = le16_to_cpu(gfx_info->v27.gc_gsprim_buff_depth);
80362306a36Sopenharmony_ci				adev->gfx.config.double_offchip_lds_buf = gfx_info->v27.gc_double_offchip_lds_buffer;
80462306a36Sopenharmony_ci				adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v27.gc_wave_size);
80562306a36Sopenharmony_ci				adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v27.gc_max_waves_per_simd);
80662306a36Sopenharmony_ci				adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v27.gc_max_scratch_slots_per_cu;
80762306a36Sopenharmony_ci				adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v27.gc_lds_size);
80862306a36Sopenharmony_ci				return 0;
80962306a36Sopenharmony_ci			default:
81062306a36Sopenharmony_ci				return -EINVAL;
81162306a36Sopenharmony_ci			}
81262306a36Sopenharmony_ci		} else if (frev == 3) {
81362306a36Sopenharmony_ci			switch (crev) {
81462306a36Sopenharmony_ci			case 0:
81562306a36Sopenharmony_ci				adev->gfx.config.max_shader_engines = gfx_info->v30.max_shader_engines;
81662306a36Sopenharmony_ci				adev->gfx.config.max_cu_per_sh = gfx_info->v30.max_cu_per_sh;
81762306a36Sopenharmony_ci				adev->gfx.config.max_sh_per_se = gfx_info->v30.max_sh_per_se;
81862306a36Sopenharmony_ci				adev->gfx.config.max_backends_per_se = gfx_info->v30.max_backends_per_se;
81962306a36Sopenharmony_ci				adev->gfx.config.max_texture_channel_caches = gfx_info->v30.max_texture_channel_caches;
82062306a36Sopenharmony_ci				return 0;
82162306a36Sopenharmony_ci			default:
82262306a36Sopenharmony_ci				return -EINVAL;
82362306a36Sopenharmony_ci			}
82462306a36Sopenharmony_ci		} else {
82562306a36Sopenharmony_ci			return -EINVAL;
82662306a36Sopenharmony_ci		}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci	return -EINVAL;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci/*
83362306a36Sopenharmony_ci * Helper function to query two stage mem training capability
83462306a36Sopenharmony_ci *
83562306a36Sopenharmony_ci * @adev: amdgpu_device pointer
83662306a36Sopenharmony_ci *
83762306a36Sopenharmony_ci * Return true if two stage mem training is supported or false if not
83862306a36Sopenharmony_ci */
83962306a36Sopenharmony_cibool amdgpu_atomfirmware_mem_training_supported(struct amdgpu_device *adev)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	u32 fw_cap;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	fw_cap = adev->mode_info.firmware_flags;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	return (fw_cap & ATOM_FIRMWARE_CAP_ENABLE_2STAGE_BIST_TRAINING) ? true : false;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ciint amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	struct atom_context *ctx = adev->mode_info.atom_context;
85162306a36Sopenharmony_ci	union firmware_info *firmware_info;
85262306a36Sopenharmony_ci	int index;
85362306a36Sopenharmony_ci	u16 data_offset, size;
85462306a36Sopenharmony_ci	u8 frev, crev;
85562306a36Sopenharmony_ci	int fw_reserved_fb_size;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
85862306a36Sopenharmony_ci			firmwareinfo);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if (!amdgpu_atom_parse_data_header(ctx, index, &size,
86162306a36Sopenharmony_ci				&frev, &crev, &data_offset))
86262306a36Sopenharmony_ci		/* fail to parse data_header */
86362306a36Sopenharmony_ci		return 0;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	firmware_info = (union firmware_info *)(ctx->bios + data_offset);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (frev != 3)
86862306a36Sopenharmony_ci		return -EINVAL;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	switch (crev) {
87162306a36Sopenharmony_ci	case 4:
87262306a36Sopenharmony_ci		fw_reserved_fb_size =
87362306a36Sopenharmony_ci			(firmware_info->v34.fw_reserved_size_in_kb << 10);
87462306a36Sopenharmony_ci		break;
87562306a36Sopenharmony_ci	default:
87662306a36Sopenharmony_ci		fw_reserved_fb_size = 0;
87762306a36Sopenharmony_ci		break;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	return fw_reserved_fb_size;
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci/*
88462306a36Sopenharmony_ci * Helper function to execute asic_init table
88562306a36Sopenharmony_ci *
88662306a36Sopenharmony_ci * @adev: amdgpu_device pointer
88762306a36Sopenharmony_ci * @fb_reset: flag to indicate whether fb is reset or not
88862306a36Sopenharmony_ci *
88962306a36Sopenharmony_ci * Return 0 if succeed, otherwise failed
89062306a36Sopenharmony_ci */
89162306a36Sopenharmony_ciint amdgpu_atomfirmware_asic_init(struct amdgpu_device *adev, bool fb_reset)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	struct amdgpu_mode_info *mode_info = &adev->mode_info;
89462306a36Sopenharmony_ci	struct atom_context *ctx;
89562306a36Sopenharmony_ci	uint8_t frev, crev;
89662306a36Sopenharmony_ci	uint16_t data_offset;
89762306a36Sopenharmony_ci	uint32_t bootup_sclk_in10khz, bootup_mclk_in10khz;
89862306a36Sopenharmony_ci	struct asic_init_ps_allocation_v2_1 asic_init_ps_v2_1;
89962306a36Sopenharmony_ci	int index;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (!mode_info)
90262306a36Sopenharmony_ci		return -EINVAL;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	ctx = mode_info->atom_context;
90562306a36Sopenharmony_ci	if (!ctx)
90662306a36Sopenharmony_ci		return -EINVAL;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* query bootup sclk/mclk from firmware_info table */
90962306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
91062306a36Sopenharmony_ci					    firmwareinfo);
91162306a36Sopenharmony_ci	if (amdgpu_atom_parse_data_header(ctx, index, NULL,
91262306a36Sopenharmony_ci				&frev, &crev, &data_offset)) {
91362306a36Sopenharmony_ci		union firmware_info *firmware_info =
91462306a36Sopenharmony_ci			(union firmware_info *)(ctx->bios +
91562306a36Sopenharmony_ci						data_offset);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci		bootup_sclk_in10khz =
91862306a36Sopenharmony_ci			le32_to_cpu(firmware_info->v31.bootup_sclk_in10khz);
91962306a36Sopenharmony_ci		bootup_mclk_in10khz =
92062306a36Sopenharmony_ci			le32_to_cpu(firmware_info->v31.bootup_mclk_in10khz);
92162306a36Sopenharmony_ci	} else {
92262306a36Sopenharmony_ci		return -EINVAL;
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	index = get_index_into_master_table(atom_master_list_of_command_functions_v2_1,
92662306a36Sopenharmony_ci					asic_init);
92762306a36Sopenharmony_ci	if (amdgpu_atom_parse_cmd_header(mode_info->atom_context, index, &frev, &crev)) {
92862306a36Sopenharmony_ci		if (frev == 2 && crev >= 1) {
92962306a36Sopenharmony_ci			memset(&asic_init_ps_v2_1, 0, sizeof(asic_init_ps_v2_1));
93062306a36Sopenharmony_ci			asic_init_ps_v2_1.param.engineparam.sclkfreqin10khz = bootup_sclk_in10khz;
93162306a36Sopenharmony_ci			asic_init_ps_v2_1.param.memparam.mclkfreqin10khz = bootup_mclk_in10khz;
93262306a36Sopenharmony_ci			asic_init_ps_v2_1.param.engineparam.engineflag = b3NORMAL_ENGINE_INIT;
93362306a36Sopenharmony_ci			if (!fb_reset)
93462306a36Sopenharmony_ci				asic_init_ps_v2_1.param.memparam.memflag = b3DRAM_SELF_REFRESH_EXIT;
93562306a36Sopenharmony_ci			else
93662306a36Sopenharmony_ci				asic_init_ps_v2_1.param.memparam.memflag = 0;
93762306a36Sopenharmony_ci		} else {
93862306a36Sopenharmony_ci			return -EINVAL;
93962306a36Sopenharmony_ci		}
94062306a36Sopenharmony_ci	} else {
94162306a36Sopenharmony_ci		return -EINVAL;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	return amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, (uint32_t *)&asic_init_ps_v2_1);
94562306a36Sopenharmony_ci}
946