amd-drm-next-7.1-2026-04-01:

amdgpu:
 - UserQ fixes
 - PASID handling fix
 - S4 fix for smu11 chips
 - devcoredump fixes
 - RAS fixes
 - Misc small fixes
 - DCN 4.2 updates
 - DVI fixes
 - DML fixes
 - DC pipe validation fixes
 - eDP DSC seamless boot
 - DC FP rework
 - swsmu cleanups
 - GC 11.5.4 updates
 - Add DC idle state manager
 - Add support for using multiple engines for buffer fills and clears
 - Misc SMU7 fixes
 
 amdkfd:
 - Non-4K page fixes
 - Logging cleanups
 - sysfs fixes
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCac1kDQAKCRC93/aFa7yZ
 2MHgAP45SqxOBmns0YnLQkeubzJDqSvsmwkrIU3hf5OiEFf/tAEAxbAuEow2ZaUK
 XIIRtWufXQ3Fi8vTinNDrMM6xXIXqgo=
 =h0mR
 -----END PGP SIGNATURE-----

Merge tag 'amd-drm-next-7.1-2026-04-01' of https://gitlab.freedesktop.org/agd5f/linux into drm-next

amd-drm-next-7.1-2026-04-01:

amdgpu:
- UserQ fixes
- PASID handling fix
- S4 fix for smu11 chips
- devcoredump fixes
- RAS fixes
- Misc small fixes
- DCN 4.2 updates
- DVI fixes
- DML fixes
- DC pipe validation fixes
- eDP DSC seamless boot
- DC FP rework
- swsmu cleanups
- GC 11.5.4 updates
- Add DC idle state manager
- Add support for using multiple engines for buffer fills and clears
- Misc SMU7 fixes

amdkfd:
- Non-4K page fixes
- Logging cleanups
- sysfs fixes

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260401184456.3576660-1-alexander.deucher@amd.com
master
Dave Airlie 2026-04-02 13:00:58 +10:00
commit cdd65e8bb9
303 changed files with 4153 additions and 1892 deletions

View File

@ -373,17 +373,148 @@ int amdgpu_atomfirmware_get_uma_carveout_info(struct amdgpu_device *adev,
return -ENODEV;
}
int
amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
int amdgpu_atomfirmware_get_integrated_system_info(struct amdgpu_device *adev,
int *vram_width, int *vram_type,
int *vram_vendor)
{
struct amdgpu_mode_info *mode_info = &adev->mode_info;
int index;
u16 data_offset, size;
union igp_info *igp_info;
u8 frev, crev;
u8 mem_type;
u32 mem_channel_number;
u32 mem_channel_width;
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
integratedsysteminfo);
if (amdgpu_atom_parse_data_header(mode_info->atom_context,
index, &size,
&frev, &crev, &data_offset)) {
igp_info = (union igp_info *)
(mode_info->atom_context->bios + data_offset);
switch (frev) {
case 1:
switch (crev) {
case 11:
case 12:
mem_channel_number = igp_info->v11.umachannelnumber;
if (!mem_channel_number)
mem_channel_number = 1;
mem_type = igp_info->v11.memorytype;
if (mem_type == LpDdr5MemType)
mem_channel_width = 32;
else
mem_channel_width = 64;
if (vram_width)
*vram_width = mem_channel_number * mem_channel_width;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
break;
default:
return -EINVAL;
}
break;
case 2:
switch (crev) {
case 1:
case 2:
mem_channel_number = igp_info->v21.umachannelnumber;
if (!mem_channel_number)
mem_channel_number = 1;
mem_type = igp_info->v21.memorytype;
if (mem_type == LpDdr5MemType)
mem_channel_width = 32;
else
mem_channel_width = 64;
if (vram_width)
*vram_width = mem_channel_number * mem_channel_width;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
break;
case 3:
mem_channel_number = igp_info->v23.umachannelnumber;
if (!mem_channel_number)
mem_channel_number = 1;
mem_type = igp_info->v23.memorytype;
if (mem_type == LpDdr5MemType)
mem_channel_width = 32;
else
mem_channel_width = 64;
if (vram_width)
*vram_width = mem_channel_number * mem_channel_width;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
} else {
return -EINVAL;
}
return 0;
}
int amdgpu_atomfirmware_get_umc_info(struct amdgpu_device *adev,
int *vram_width, int *vram_type,
int *vram_vendor)
{
struct amdgpu_mode_info *mode_info = &adev->mode_info;
int index;
u16 data_offset, size;
union umc_info *umc_info;
u8 frev, crev;
u8 mem_type;
u8 mem_vendor;
u32 mem_channel_number;
u32 mem_channel_width;
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, umc_info);
if (amdgpu_atom_parse_data_header(mode_info->atom_context,
index, &size,
&frev, &crev, &data_offset)) {
umc_info = (union umc_info *)(mode_info->atom_context->bios + data_offset);
if (frev == 4) {
switch (crev) {
case 0:
mem_channel_number = le32_to_cpu(umc_info->v40.channel_num);
mem_type = le32_to_cpu(umc_info->v40.vram_type);
mem_channel_width = le32_to_cpu(umc_info->v40.channel_width);
mem_vendor = RREG32(adev->bios_scratch_reg_offset + 4) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
break;
default:
return -EINVAL;
}
} else {
return -EINVAL;
}
} else {
return -EINVAL;
}
return 0;
}
int amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
int *vram_width, int *vram_type,
int *vram_vendor)
{
struct amdgpu_mode_info *mode_info = &adev->mode_info;
int index, i = 0;
u16 data_offset, size;
union igp_info *igp_info;
union vram_info *vram_info;
union umc_info *umc_info;
union vram_module *vram_module;
u8 frev, crev;
u8 mem_type;
@ -392,230 +523,130 @@ amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
u32 mem_channel_width;
u32 module_id;
if (adev->flags & AMD_IS_APU)
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
integratedsysteminfo);
else {
switch (amdgpu_ip_version(adev, GC_HWIP, 0)) {
case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 0, 1):
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, umc_info);
break;
default:
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, vram_info);
}
}
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, vram_info);
if (amdgpu_atom_parse_data_header(mode_info->atom_context,
index, &size,
&frev, &crev, &data_offset)) {
if (adev->flags & AMD_IS_APU) {
igp_info = (union igp_info *)
(mode_info->atom_context->bios + data_offset);
switch (frev) {
case 1:
switch (crev) {
case 11:
case 12:
mem_channel_number = igp_info->v11.umachannelnumber;
if (!mem_channel_number)
mem_channel_number = 1;
mem_type = igp_info->v11.memorytype;
if (mem_type == LpDdr5MemType)
mem_channel_width = 32;
else
mem_channel_width = 64;
if (vram_width)
*vram_width = mem_channel_number * mem_channel_width;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
break;
default:
return -EINVAL;
}
vram_info = (union vram_info *)
(mode_info->atom_context->bios + data_offset);
module_id = (RREG32(adev->bios_scratch_reg_offset + 4) & 0x00ff0000) >> 16;
if (frev == 3) {
switch (crev) {
/* v30 */
case 0:
vram_module = (union vram_module *)vram_info->v30.vram_module;
mem_vendor = (vram_module->v30.dram_vendor_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
mem_type = vram_info->v30.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_info->v30.channel_num;
mem_channel_width = vram_info->v30.channel_width;
if (vram_width)
*vram_width = mem_channel_number * 16;
break;
case 2:
switch (crev) {
case 1:
case 2:
mem_channel_number = igp_info->v21.umachannelnumber;
if (!mem_channel_number)
mem_channel_number = 1;
mem_type = igp_info->v21.memorytype;
if (mem_type == LpDdr5MemType)
mem_channel_width = 32;
else
mem_channel_width = 64;
if (vram_width)
*vram_width = mem_channel_number * mem_channel_width;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
break;
case 3:
mem_channel_number = igp_info->v23.umachannelnumber;
if (!mem_channel_number)
mem_channel_number = 1;
mem_type = igp_info->v23.memorytype;
if (mem_type == LpDdr5MemType)
mem_channel_width = 32;
else
mem_channel_width = 64;
if (vram_width)
*vram_width = mem_channel_number * mem_channel_width;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
break;
default:
return -EINVAL;
default:
return -EINVAL;
}
} else if (frev == 2) {
switch (crev) {
/* v23 */
case 3:
if (module_id > vram_info->v23.vram_module_num)
module_id = 0;
vram_module = (union vram_module *)vram_info->v23.vram_module;
while (i < module_id) {
vram_module = (union vram_module *)
((u8 *)vram_module + vram_module->v9.vram_module_size);
i++;
}
mem_type = vram_module->v9.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_module->v9.channel_num;
mem_channel_width = vram_module->v9.channel_width;
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
break;
/* v24 */
case 4:
if (module_id > vram_info->v24.vram_module_num)
module_id = 0;
vram_module = (union vram_module *)vram_info->v24.vram_module;
while (i < module_id) {
vram_module = (union vram_module *)
((u8 *)vram_module + vram_module->v10.vram_module_size);
i++;
}
mem_type = vram_module->v10.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_module->v10.channel_num;
mem_channel_width = vram_module->v10.channel_width;
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
mem_vendor = (vram_module->v10.vender_rev_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
break;
/* v25 */
case 5:
if (module_id > vram_info->v25.vram_module_num)
module_id = 0;
vram_module = (union vram_module *)vram_info->v25.vram_module;
while (i < module_id) {
vram_module = (union vram_module *)
((u8 *)vram_module + vram_module->v11.vram_module_size);
i++;
}
mem_type = vram_module->v11.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_module->v11.channel_num;
mem_channel_width = vram_module->v11.channel_width;
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
mem_vendor = (vram_module->v11.vender_rev_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
break;
/* v26 */
case 6:
if (module_id > vram_info->v26.vram_module_num)
module_id = 0;
vram_module = (union vram_module *)vram_info->v26.vram_module;
while (i < module_id) {
vram_module = (union vram_module *)
((u8 *)vram_module + vram_module->v9.vram_module_size);
i++;
}
mem_type = vram_module->v9.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_module->v9.channel_num;
mem_channel_width = vram_module->v9.channel_width;
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
break;
default:
return -EINVAL;
}
} else {
switch (amdgpu_ip_version(adev, GC_HWIP, 0)) {
case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 0, 1):
umc_info = (union umc_info *)(mode_info->atom_context->bios + data_offset);
if (frev == 4) {
switch (crev) {
case 0:
mem_channel_number = le32_to_cpu(umc_info->v40.channel_num);
mem_type = le32_to_cpu(umc_info->v40.vram_type);
mem_channel_width = le32_to_cpu(umc_info->v40.channel_width);
mem_vendor = RREG32(adev->bios_scratch_reg_offset + 4) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
break;
default:
return -EINVAL;
}
} else
return -EINVAL;
break;
default:
vram_info = (union vram_info *)
(mode_info->atom_context->bios + data_offset);
module_id = (RREG32(adev->bios_scratch_reg_offset + 4) & 0x00ff0000) >> 16;
if (frev == 3) {
switch (crev) {
/* v30 */
case 0:
vram_module = (union vram_module *)vram_info->v30.vram_module;
mem_vendor = (vram_module->v30.dram_vendor_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
mem_type = vram_info->v30.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_info->v30.channel_num;
mem_channel_width = vram_info->v30.channel_width;
if (vram_width)
*vram_width = mem_channel_number * 16;
break;
default:
return -EINVAL;
}
} else if (frev == 2) {
switch (crev) {
/* v23 */
case 3:
if (module_id > vram_info->v23.vram_module_num)
module_id = 0;
vram_module = (union vram_module *)vram_info->v23.vram_module;
while (i < module_id) {
vram_module = (union vram_module *)
((u8 *)vram_module + vram_module->v9.vram_module_size);
i++;
}
mem_type = vram_module->v9.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_module->v9.channel_num;
mem_channel_width = vram_module->v9.channel_width;
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
break;
/* v24 */
case 4:
if (module_id > vram_info->v24.vram_module_num)
module_id = 0;
vram_module = (union vram_module *)vram_info->v24.vram_module;
while (i < module_id) {
vram_module = (union vram_module *)
((u8 *)vram_module + vram_module->v10.vram_module_size);
i++;
}
mem_type = vram_module->v10.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_module->v10.channel_num;
mem_channel_width = vram_module->v10.channel_width;
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
mem_vendor = (vram_module->v10.vender_rev_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
break;
/* v25 */
case 5:
if (module_id > vram_info->v25.vram_module_num)
module_id = 0;
vram_module = (union vram_module *)vram_info->v25.vram_module;
while (i < module_id) {
vram_module = (union vram_module *)
((u8 *)vram_module + vram_module->v11.vram_module_size);
i++;
}
mem_type = vram_module->v11.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_module->v11.channel_num;
mem_channel_width = vram_module->v11.channel_width;
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
mem_vendor = (vram_module->v11.vender_rev_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
break;
/* v26 */
case 6:
if (module_id > vram_info->v26.vram_module_num)
module_id = 0;
vram_module = (union vram_module *)vram_info->v26.vram_module;
while (i < module_id) {
vram_module = (union vram_module *)
((u8 *)vram_module + vram_module->v9.vram_module_size);
i++;
}
mem_type = vram_module->v9.memory_type;
if (vram_type)
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
mem_channel_number = vram_module->v9.channel_num;
mem_channel_width = vram_module->v9.channel_width;
if (vram_width)
*vram_width = mem_channel_number * (1 << mem_channel_width);
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
if (vram_vendor)
*vram_vendor = mem_vendor;
break;
default:
return -EINVAL;
}
} else {
/* invalid frev */
return -EINVAL;
}
}
/* invalid frev */
return -EINVAL;
}
} else {
return -EINVAL;
}
return 0;

View File

@ -30,6 +30,10 @@ uint32_t amdgpu_atomfirmware_query_firmware_capability(struct amdgpu_device *ade
bool amdgpu_atomfirmware_gpu_virtualization_supported(struct amdgpu_device *adev);
void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev);
int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev);
int amdgpu_atomfirmware_get_integrated_system_info(struct amdgpu_device *adev,
int *vram_width, int *vram_type, int *vram_vendor);
int amdgpu_atomfirmware_get_umc_info(struct amdgpu_device *adev,
int *vram_width, int *vram_type, int *vram_vendor);
int amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
int *vram_width, int *vram_type, int *vram_vendor);
int amdgpu_atomfirmware_get_uma_carveout_info(struct amdgpu_device *adev,

View File

@ -908,9 +908,8 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
goto out_free_user_pages;
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
/* One fence for TTM and one for each CS job */
r = drm_exec_prepare_obj(&p->exec, &e->bo->tbo.base,
1 + p->gang_size);
TTM_NUM_MOVE_FENCES + p->gang_size);
drm_exec_retry_on_contention(&p->exec);
if (unlikely(r))
goto out_free_user_pages;
@ -920,7 +919,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
if (p->uf_bo) {
r = drm_exec_prepare_obj(&p->exec, &p->uf_bo->tbo.base,
1 + p->gang_size);
TTM_NUM_MOVE_FENCES + p->gang_size);
drm_exec_retry_on_contention(&p->exec);
if (unlikely(r))
goto out_free_user_pages;

View File

@ -35,6 +35,9 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
void amdgpu_coredump_init(struct amdgpu_device *adev)
{
}
void amdgpu_coredump_fini(struct amdgpu_device *adev)
{
}
#else
#define AMDGPU_CORE_DUMP_SIZE_MAX (256 * 1024 * 1024)
@ -192,12 +195,16 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev,
drm_printf(p, "VPE feature version: %u, fw version: 0x%08x\n",
adev->vpe.feature_version, adev->vpe.fw_version);
drm_printf(p, "\nVBIOS Information\n");
drm_printf(p, "vbios name : %s\n", ctx->name);
drm_printf(p, "vbios pn : %s\n", ctx->vbios_pn);
drm_printf(p, "vbios version : %d\n", ctx->version);
drm_printf(p, "vbios ver_str : %s\n", ctx->vbios_ver_str);
drm_printf(p, "vbios date : %s\n", ctx->date);
if (adev->bios) {
drm_printf(p, "\nVBIOS Information\n");
drm_printf(p, "vbios name : %s\n", ctx->name);
drm_printf(p, "vbios pn : %s\n", ctx->vbios_pn);
drm_printf(p, "vbios version : %d\n", ctx->version);
drm_printf(p, "vbios ver_str : %s\n", ctx->vbios_ver_str);
drm_printf(p, "vbios date : %s\n", ctx->date);
}else {
drm_printf(p, "\nVBIOS Information: NA\n");
}
}
static ssize_t
@ -436,4 +443,10 @@ void amdgpu_coredump_init(struct amdgpu_device *adev)
{
INIT_WORK(&adev->coredump_work, amdgpu_devcoredump_deferred_work);
}
void amdgpu_coredump_fini(struct amdgpu_device *adev)
{
/* Finish deferred coredump formatting before HW/IP teardown. */
flush_work(&adev->coredump_work);
}
#endif

View File

@ -50,4 +50,5 @@ struct amdgpu_coredump_info {
void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
bool vram_lost, struct amdgpu_job *job);
void amdgpu_coredump_init(struct amdgpu_device *adev);
void amdgpu_coredump_fini(struct amdgpu_device *adev);
#endif

View File

@ -4225,6 +4225,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
if (pci_dev_is_disconnected(adev->pdev))
amdgpu_amdkfd_device_fini_sw(adev);
amdgpu_coredump_fini(adev);
amdgpu_device_ip_fini_early(adev);
amdgpu_irq_fini_hw(adev);

View File

@ -2683,8 +2683,12 @@ static int amdgpu_pmops_freeze(struct device *dev)
if (r)
return r;
if (amdgpu_acpi_should_gpu_reset(adev))
return amdgpu_asic_reset(adev);
if (amdgpu_acpi_should_gpu_reset(adev)) {
amdgpu_device_lock_reset_domain(adev->reset_domain);
r = amdgpu_asic_reset(adev);
amdgpu_device_unlock_reset_domain(adev->reset_domain);
return r;
}
return 0;
}

View File

@ -403,6 +403,50 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
drm_dev_exit(idx);
}
/**
* amdgpu_gart_map_gfx9_mqd - map mqd and ctrl_stack dma_addresses into GART entries
*
* @adev: amdgpu_device pointer
* @offset: offset into the GPU's gart aperture
* @pages: number of pages to bind
* @dma_addr: DMA addresses of pages
* @flags: page table entry flags
*
* Map the MQD and control stack addresses into GART entries with the correct
* memory types on gfxv9. The MQD occupies the first 4KB and is followed by
* the control stack. The MQD uses UC (uncached) memory, while the control stack
* uses NC (non-coherent) memory.
*/
void amdgpu_gart_map_gfx9_mqd(struct amdgpu_device *adev, uint64_t offset,
int pages, dma_addr_t *dma_addr, uint64_t flags)
{
uint64_t page_base;
unsigned int i, j, t;
int idx;
uint64_t ctrl_flags = AMDGPU_PTE_MTYPE_VG10(flags, AMDGPU_MTYPE_NC);
void *dst;
if (!adev->gart.ptr)
return;
if (!drm_dev_enter(adev_to_drm(adev), &idx))
return;
t = offset / AMDGPU_GPU_PAGE_SIZE;
dst = adev->gart.ptr;
for (i = 0; i < pages; i++) {
page_base = dma_addr[i];
for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) {
if ((i == 0) && (j == 0))
amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, flags);
else
amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, ctrl_flags);
page_base += AMDGPU_GPU_PAGE_SIZE;
}
}
drm_dev_exit(idx);
}
/**
* amdgpu_gart_bind - bind pages into the gart page table
*

View File

@ -62,6 +62,8 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
void amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset,
int pages, dma_addr_t *dma_addr, uint64_t flags,
void *dst);
void amdgpu_gart_map_gfx9_mqd(struct amdgpu_device *adev, uint64_t offset,
int pages, dma_addr_t *dma_addr, uint64_t flags);
void amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
int pages, dma_addr_t *dma_addr, uint64_t flags);
void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,

View File

@ -34,6 +34,7 @@
#include "amdgpu_ras.h"
#include "amdgpu_reset.h"
#include "amdgpu_xgmi.h"
#include "amdgpu_atomfirmware.h"
#include <drm/drm_drv.h>
#include <drm/ttm/ttm_tt.h>
@ -1747,3 +1748,31 @@ int amdgpu_gmc_init_mem_ranges(struct amdgpu_device *adev)
return 0;
}
int amdgpu_gmc_get_vram_info(struct amdgpu_device *adev,
int *vram_width, int *vram_type, int *vram_vendor)
{
int ret = 0;
if (adev->flags & AMD_IS_APU)
return amdgpu_atomfirmware_get_integrated_system_info(adev,
vram_width, vram_type, vram_vendor);
switch (amdgpu_ip_version(adev, GC_HWIP, 0)) {
case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 0, 1):
return amdgpu_atomfirmware_get_umc_info(adev,
vram_width, vram_type, vram_vendor);
case IP_VERSION(9, 5, 0):
case IP_VERSION(9, 4, 4):
case IP_VERSION(9, 4, 3):
ret = amdgpu_atomfirmware_get_umc_info(adev,
vram_width, vram_type, vram_vendor);
if (vram_width && !ret)
*vram_width *= hweight32(adev->aid_mask);
return ret;
default:
return amdgpu_atomfirmware_get_vram_info(adev,
vram_width, vram_type, vram_vendor);
}
return 0;
}

View File

@ -482,4 +482,6 @@ amdgpu_gmc_query_memory_partition(struct amdgpu_device *adev);
int amdgpu_gmc_init_mem_ranges(struct amdgpu_device *adev);
void amdgpu_gmc_init_sw_mem_ranges(struct amdgpu_device *adev,
struct amdgpu_mem_partition_info *mem_ranges);
int amdgpu_gmc_get_vram_info(struct amdgpu_device *adev,
int *vram_width, int *vram_type, int *vram_vendor);
#endif

View File

@ -68,8 +68,11 @@ int amdgpu_pasid_alloc(unsigned int bits)
return -EINVAL;
spin_lock(&amdgpu_pasid_idr_lock);
/* TODO: Need to replace the idr with an xarry, and then
* handle the internal locking with ATOMIC safe paths.
*/
pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1,
1U << bits, GFP_KERNEL);
1U << bits, GFP_ATOMIC);
spin_unlock(&amdgpu_pasid_idr_lock);
if (pasid >= 0)

View File

@ -44,6 +44,7 @@
#include <drm/display/drm_dp_mst_helper.h>
#include "modules/inc/mod_freesync.h"
#include "amdgpu_dm_irq_params.h"
#include "amdgpu_dm_ism.h"
struct amdgpu_bo;
struct amdgpu_device;
@ -486,6 +487,10 @@ struct amdgpu_crtc {
int deferred_flip_completion;
/* parameters access from DM IRQ handler */
struct dm_irq_params dm_irq_params;
/* DM idle state manager */
struct amdgpu_dm_ism ism;
/* pll sharing */
struct amdgpu_atom_ss ss;
bool ss_enabled;

View File

@ -1325,7 +1325,8 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo)
if (r)
goto out;
r = amdgpu_fill_buffer(&adev->mman.clear_entity, abo, 0, &bo->base._resv,
r = amdgpu_fill_buffer(amdgpu_ttm_next_clear_entity(adev),
abo, 0, &bo->base._resv,
&fence, AMDGPU_KERNEL_JOB_ID_CLEAR_ON_RELEASE);
if (WARN_ON(r))
goto out;

View File

@ -1558,6 +1558,8 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control)
unsigned char buf[RAS_TABLE_HEADER_SIZE] = { 0 };
struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr;
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
int dev_var = adev->pdev->device & 0xF;
uint32_t vram_type = adev->gmc.vram_type;
int res;
if (amdgpu_ras_smu_eeprom_supported(adev))
@ -1597,6 +1599,12 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control)
return amdgpu_ras_eeprom_reset_table(control);
}
if (!(adev->flags & AMD_IS_APU) && (dev_var == 0x5) &&
(vram_type == AMDGPU_VRAM_TYPE_HBM3E) &&
(hdr->version < RAS_TABLE_VER_V3)) {
return amdgpu_ras_eeprom_reset_table(control);
}
switch (hdr->version) {
case RAS_TABLE_VER_V2_1:
case RAS_TABLE_VER_V3:

View File

@ -387,9 +387,11 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo,
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
struct amdgpu_ttm_buffer_entity *entity;
struct amdgpu_copy_mem src, dst;
struct dma_fence *fence = NULL;
int r;
u32 e;
src.bo = bo;
dst.bo = bo;
@ -398,8 +400,12 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo,
src.offset = 0;
dst.offset = 0;
e = atomic_inc_return(&adev->mman.next_move_entity) %
adev->mman.num_move_entities;
entity = &adev->mman.move_entities[e];
r = amdgpu_ttm_copy_mem_to_mem(adev,
&adev->mman.move_entity,
entity,
&src, &dst,
new_mem->size,
amdgpu_bo_encrypted(abo),
@ -411,9 +417,7 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo,
if (old_mem->mem_type == TTM_PL_VRAM &&
(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) {
struct dma_fence *wipe_fence = NULL;
r = amdgpu_fill_buffer(&adev->mman.move_entity,
abo, 0, NULL, &wipe_fence,
r = amdgpu_fill_buffer(entity, abo, 0, NULL, &wipe_fence,
AMDGPU_KERNEL_JOB_ID_MOVE_BLIT);
if (r) {
goto error;
@ -854,25 +858,15 @@ static void amdgpu_ttm_gart_bind_gfx9_mqd(struct amdgpu_device *adev,
int num_xcc = max(1U, adev->gfx.num_xcc_per_xcp);
uint64_t page_idx, pages_per_xcc;
int i;
uint64_t ctrl_flags = AMDGPU_PTE_MTYPE_VG10(flags, AMDGPU_MTYPE_NC);
pages_per_xcc = total_pages;
do_div(pages_per_xcc, num_xcc);
for (i = 0, page_idx = 0; i < num_xcc; i++, page_idx += pages_per_xcc) {
/* MQD page: use default flags */
amdgpu_gart_bind(adev,
amdgpu_gart_map_gfx9_mqd(adev,
gtt->offset + (page_idx << PAGE_SHIFT),
1, &gtt->ttm.dma_address[page_idx], flags);
/*
* Ctrl pages - modify the memory type to NC (ctrl_flags) from
* the second page of the BO onward.
*/
amdgpu_gart_bind(adev,
gtt->offset + ((page_idx + 1) << PAGE_SHIFT),
pages_per_xcc - 1,
&gtt->ttm.dma_address[page_idx + 1],
ctrl_flags);
pages_per_xcc, &gtt->ttm.dma_address[page_idx],
flags);
}
}
@ -2345,8 +2339,9 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
{
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
u32 num_clear_entities, num_move_entities;
uint64_t size;
int r;
int r, i, j;
if (!adev->mman.initialized || amdgpu_in_reset(adev) ||
adev->mman.buffer_funcs_enabled == enable || adev->gmc.is_app_apu)
@ -2361,6 +2356,8 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
return;
}
num_clear_entities = 1;
num_move_entities = 1;
ring = adev->mman.buffer_funcs_ring;
sched = &ring->sched;
r = amdgpu_ttm_buffer_entity_init(&adev->mman.gtt_mgr,
@ -2373,36 +2370,64 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
return;
}
r = amdgpu_ttm_buffer_entity_init(&adev->mman.gtt_mgr,
&adev->mman.clear_entity,
DRM_SCHED_PRIORITY_NORMAL,
&sched, 1, 1);
if (r < 0) {
dev_err(adev->dev,
"Failed setting up TTM BO clear entity (%d)\n", r);
adev->mman.clear_entities = kcalloc(num_clear_entities,
sizeof(struct amdgpu_ttm_buffer_entity),
GFP_KERNEL);
atomic_set(&adev->mman.next_clear_entity, 0);
if (!adev->mman.clear_entities)
goto error_free_default_entity;
adev->mman.num_clear_entities = num_clear_entities;
for (i = 0; i < num_clear_entities; i++) {
r = amdgpu_ttm_buffer_entity_init(
&adev->mman.gtt_mgr, &adev->mman.clear_entities[i],
DRM_SCHED_PRIORITY_NORMAL, &sched, 1, 1);
if (r < 0) {
for (j = 0; j < i; j++)
amdgpu_ttm_buffer_entity_fini(
&adev->mman.gtt_mgr, &adev->mman.clear_entities[j]);
kfree(adev->mman.clear_entities);
adev->mman.num_clear_entities = 0;
adev->mman.clear_entities = NULL;
goto error_free_default_entity;
}
}
r = amdgpu_ttm_buffer_entity_init(&adev->mman.gtt_mgr,
&adev->mman.move_entity,
DRM_SCHED_PRIORITY_NORMAL,
&sched, 1, 2);
if (r < 0) {
dev_err(adev->dev,
"Failed setting up TTM BO move entity (%d)\n", r);
goto error_free_clear_entity;
adev->mman.num_move_entities = num_move_entities;
atomic_set(&adev->mman.next_move_entity, 0);
for (i = 0; i < num_move_entities; i++) {
r = amdgpu_ttm_buffer_entity_init(
&adev->mman.gtt_mgr,
&adev->mman.move_entities[i],
DRM_SCHED_PRIORITY_NORMAL, &sched, 1, 2);
if (r < 0) {
for (j = 0; j < i; j++)
amdgpu_ttm_buffer_entity_fini(
&adev->mman.gtt_mgr, &adev->mman.move_entities[j]);
adev->mman.num_move_entities = 0;
goto error_free_clear_entities;
}
}
} else {
amdgpu_ttm_buffer_entity_fini(&adev->mman.gtt_mgr,
&adev->mman.default_entity);
amdgpu_ttm_buffer_entity_fini(&adev->mman.gtt_mgr,
&adev->mman.clear_entity);
amdgpu_ttm_buffer_entity_fini(&adev->mman.gtt_mgr,
&adev->mman.move_entity);
for (i = 0; i < adev->mman.num_clear_entities; i++)
amdgpu_ttm_buffer_entity_fini(&adev->mman.gtt_mgr,
&adev->mman.clear_entities[i]);
for (i = 0; i < adev->mman.num_move_entities; i++)
amdgpu_ttm_buffer_entity_fini(&adev->mman.gtt_mgr,
&adev->mman.move_entities[i]);
/* Drop all the old fences since re-creating the scheduler entities
* will allocate new contexts.
*/
ttm_resource_manager_cleanup(man);
kfree(adev->mman.clear_entities);
adev->mman.clear_entities = NULL;
adev->mman.num_clear_entities = 0;
adev->mman.num_move_entities = 0;
}
/* this just adjusts TTM size idea, which sets lpfn to the correct value */
@ -2415,9 +2440,13 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
return;
error_free_clear_entity:
amdgpu_ttm_buffer_entity_fini(&adev->mman.gtt_mgr,
&adev->mman.clear_entity);
error_free_clear_entities:
for (i = 0; i < adev->mman.num_clear_entities; i++)
amdgpu_ttm_buffer_entity_fini(&adev->mman.gtt_mgr,
&adev->mman.clear_entities[i]);
kfree(adev->mman.clear_entities);
adev->mman.clear_entities = NULL;
adev->mman.num_clear_entities = 0;
error_free_default_entity:
amdgpu_ttm_buffer_entity_fini(&adev->mman.gtt_mgr,
&adev->mman.default_entity);
@ -2567,8 +2596,7 @@ int amdgpu_ttm_clear_buffer(struct amdgpu_bo *bo,
if (!fence)
return -EINVAL;
entity = &adev->mman.clear_entity;
entity = &adev->mman.clear_entities[0];
*fence = dma_fence_get_stub();
amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &cursor);
@ -2620,11 +2648,8 @@ int amdgpu_fill_buffer(struct amdgpu_ttm_buffer_entity *entity,
struct amdgpu_res_cursor dst;
int r;
if (!adev->mman.buffer_funcs_enabled) {
dev_err(adev->dev,
"Trying to clear memory with ring turned off.\n");
if (!entity)
return -EINVAL;
}
amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &dst);
@ -2660,6 +2685,20 @@ error:
return r;
}
struct amdgpu_ttm_buffer_entity *
amdgpu_ttm_next_clear_entity(struct amdgpu_device *adev)
{
struct amdgpu_mman *mman = &adev->mman;
u32 i;
if (mman->num_clear_entities == 0)
return NULL;
i = atomic_inc_return(&mman->next_clear_entity) %
mman->num_clear_entities;
return &mman->clear_entities[i];
}
/**
* amdgpu_ttm_evict_resources - evict memory buffers
* @adev: amdgpu device object

View File

@ -72,8 +72,12 @@ struct amdgpu_mman {
/* @default_entity: for workarounds, has no gart windows */
struct amdgpu_ttm_buffer_entity default_entity;
struct amdgpu_ttm_buffer_entity clear_entity;
struct amdgpu_ttm_buffer_entity move_entity;
struct amdgpu_ttm_buffer_entity *clear_entities;
atomic_t next_clear_entity;
u32 num_clear_entities;
struct amdgpu_ttm_buffer_entity move_entities[TTM_NUM_MOVE_FENCES];
atomic_t next_move_entity;
u32 num_move_entities;
struct amdgpu_vram_mgr vram_mgr;
struct amdgpu_gtt_mgr gtt_mgr;
@ -191,6 +195,7 @@ int amdgpu_fill_buffer(struct amdgpu_ttm_buffer_entity *entity,
struct dma_resv *resv,
struct dma_fence **f,
u64 k_job_id);
struct amdgpu_ttm_buffer_entity *amdgpu_ttm_next_clear_entity(struct amdgpu_device *adev);
int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo);
void amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo);

View File

@ -600,6 +600,13 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
goto unpin_bo;
}
/* Validate doorbell_offset is within the doorbell BO */
if ((u64)db_info->doorbell_offset * db_size + db_size >
amdgpu_bo_size(db_obj->obj)) {
r = -EINVAL;
goto unpin_bo;
}
index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
db_info->doorbell_offset, db_size);
drm_dbg_driver(adev_to_drm(uq_mgr->adev),
@ -997,6 +1004,7 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
unsigned long queue_id;
int ret = 0, r;
mutex_lock(&uq_mgr->userq_mutex);
/* Resume all the queues for this process */
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
@ -1012,6 +1020,7 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
ret = r;
}
mutex_unlock(&uq_mgr->userq_mutex);
if (ret)
drm_file_err(uq_mgr->file, "Failed to map all the queues\n");
@ -1215,23 +1224,21 @@ static void amdgpu_userq_restore_worker(struct work_struct *work)
struct dma_fence *ev_fence;
int ret;
mutex_lock(&uq_mgr->userq_mutex);
ev_fence = amdgpu_evf_mgr_get_fence(&fpriv->evf_mgr);
if (!dma_fence_is_signaled(ev_fence))
goto unlock;
goto put_fence;
ret = amdgpu_userq_vm_validate(uq_mgr);
if (ret) {
drm_file_err(uq_mgr->file, "Failed to validate BOs to restore\n");
goto unlock;
goto put_fence;
}
ret = amdgpu_userq_restore_all(uq_mgr);
if (ret)
drm_file_err(uq_mgr->file, "Failed to restore all queues\n");
unlock:
mutex_unlock(&uq_mgr->userq_mutex);
put_fence:
dma_fence_put(ev_fence);
}
@ -1454,17 +1461,19 @@ int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev,
if (!adev->userq_halt_for_enforce_isolation)
dev_warn(adev->dev, "userq scheduling already started!\n");
adev->userq_halt_for_enforce_isolation = false;
xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
uqm = queue->userq_mgr;
mutex_lock(&uqm->userq_mutex);
if (((queue->queue_type == AMDGPU_HW_IP_GFX) ||
(queue->queue_type == AMDGPU_HW_IP_COMPUTE)) &&
(queue->xcp_id == idx)) {
if (((queue->queue_type == AMDGPU_HW_IP_GFX) ||
(queue->queue_type == AMDGPU_HW_IP_COMPUTE)) &&
(queue->xcp_id == idx)) {
r = amdgpu_userq_restore_helper(queue);
if (r)
ret = r;
}
}
mutex_unlock(&uqm->userq_mutex);
}

View File

@ -328,11 +328,9 @@ static int amdgpu_vkms_prepare_fb(struct drm_plane *plane,
return r;
}
r = dma_resv_reserve_fences(rbo->tbo.base.resv, 1);
if (r) {
dev_err(adev->dev, "allocating fence slot failed (%d)\n", r);
r = dma_resv_reserve_fences(rbo->tbo.base.resv, TTM_NUM_MOVE_FENCES);
if (r)
goto error_unlock;
}
if (plane->type != DRM_PLANE_TYPE_CURSOR)
domain = amdgpu_display_supported_domains(adev, rbo->flags);

View File

@ -173,7 +173,7 @@ struct amdgpu_bo_vm;
#define AMDGPU_VA_RESERVED_SEQ64_SIZE (2ULL << 20)
#define AMDGPU_VA_RESERVED_SEQ64_START(adev) (AMDGPU_VA_RESERVED_CSA_START(adev) \
- AMDGPU_VA_RESERVED_SEQ64_SIZE)
#define AMDGPU_VA_RESERVED_TRAP_SIZE (2ULL << 12)
#define AMDGPU_VA_RESERVED_TRAP_SIZE (1ULL << 16)
#define AMDGPU_VA_RESERVED_TRAP_START(adev) (AMDGPU_VA_RESERVED_SEQ64_START(adev) \
- AMDGPU_VA_RESERVED_TRAP_SIZE)
#define AMDGPU_VA_RESERVED_BOTTOM (1ULL << 16)

View File

@ -1722,6 +1722,20 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
}
}
break;
case IP_VERSION(11, 5, 4):
adev->gfx.cleaner_shader_ptr = gfx_11_0_3_cleaner_shader_hex;
adev->gfx.cleaner_shader_size = sizeof(gfx_11_0_3_cleaner_shader_hex);
if (adev->gfx.me_fw_version >= 4 &&
adev->gfx.pfp_fw_version >= 7 &&
adev->gfx.mec_fw_version >= 5) {
adev->gfx.enable_cleaner_shader = true;
r = amdgpu_gfx_cleaner_shader_sw_init(adev, adev->gfx.cleaner_shader_size);
if (r) {
adev->gfx.enable_cleaner_shader = false;
dev_err(adev->dev, "Failed to initialize cleaner shader\n");
}
}
break;
default:
adev->gfx.enable_cleaner_shader = false;
break;

View File

@ -767,7 +767,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_GDDR6;
adev->gmc.vram_width = 1 * 128; /* numchan * chansize */
} else {
r = amdgpu_atomfirmware_get_vram_info(adev,
r = amdgpu_gmc_get_vram_info(adev,
&vram_width, &vram_type, &vram_vendor);
adev->gmc.vram_width = vram_width;

View File

@ -751,7 +751,7 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
spin_lock_init(&adev->gmc.invalidate_lock);
r = amdgpu_atomfirmware_get_vram_info(adev,
r = amdgpu_gmc_get_vram_info(adev,
&vram_width, &vram_type, &vram_vendor);
adev->gmc.vram_width = vram_width;

View File

@ -825,7 +825,7 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) {
gmc_v12_1_init_vram_info(adev);
} else {
r = amdgpu_atomfirmware_get_vram_info(adev,
r = amdgpu_gmc_get_vram_info(adev,
&vram_width, &vram_type, &vram_vendor);
adev->gmc.vram_width = vram_width;
adev->gmc.vram_type = vram_type;

View File

@ -1823,24 +1823,37 @@ static void gmc_v9_0_save_registers(struct amdgpu_device *adev)
adev->gmc.sdpif_register = RREG32_SOC15(DCE, 0, mmDCHUBBUB_SDPIF_MMIO_CNTRL_0);
}
static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev)
static void gmc_v9_0_init_vram_info(struct amdgpu_device *adev)
{
static const u32 regBIF_BIOS_SCRATCH_4 = 0x50;
int dev_var = adev->pdev->device & 0xF;
u32 vram_info;
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM;
adev->gmc.vram_width = 128 * 64;
if (adev->gmc.is_app_apu) {
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM;
adev->gmc.vram_width = 128 * 64;
} else if (adev->flags & AMD_IS_APU) {
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_DDR4;
adev->gmc.vram_width = 64 * 64;
} else if (amdgpu_is_multi_aid(adev)) {
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM;
adev->gmc.vram_width = 128 * 64;
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0))
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM3E;
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0))
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM3E;
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) &&
adev->rev_id == 0x3)
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM3E;
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) &&
adev->rev_id == 0x3)
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM3E;
if (!(adev->flags & AMD_IS_APU) && !amdgpu_sriov_vf(adev)) {
vram_info = RREG32(regBIF_BIOS_SCRATCH_4);
adev->gmc.vram_vendor = vram_info & 0xF;
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) &&
(dev_var == 0x5))
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM3E;
if (!(adev->flags & AMD_IS_APU) && !amdgpu_sriov_vf(adev)) {
vram_info = RREG32(regBIF_BIOS_SCRATCH_4);
adev->gmc.vram_vendor = vram_info & 0xF;
}
}
}
@ -1856,19 +1869,11 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
spin_lock_init(&adev->gmc.invalidate_lock);
if (amdgpu_is_multi_aid(adev)) {
gmc_v9_4_3_init_vram_info(adev);
} else if (!adev->bios) {
if (adev->flags & AMD_IS_APU) {
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_DDR4;
adev->gmc.vram_width = 64 * 64;
} else {
adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM;
adev->gmc.vram_width = 128 * 64;
}
if (!adev->bios) {
gmc_v9_0_init_vram_info(adev);
} else {
r = amdgpu_atomfirmware_get_vram_info(adev,
&vram_width, &vram_type, &vram_vendor);
r = amdgpu_gmc_get_vram_info(adev,
&vram_width, &vram_type, &vram_vendor);
if (amdgpu_sriov_vf(adev))
/* For Vega10 SR-IOV, vram_width can't be read from ATOM as RAVEN,
* and DF related registers is not readable, seems hardcord is the
@ -1896,6 +1901,7 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
adev->gmc.vram_type = vram_type;
adev->gmc.vram_vendor = vram_vendor;
}
switch (amdgpu_ip_version(adev, GC_HWIP, 0)) {
case IP_VERSION(9, 1, 0):
case IP_VERSION(9, 2, 2):

View File

@ -324,8 +324,10 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
r = amdgpu_userq_input_va_validate(adev, queue, compute_mqd->eop_va,
2048);
if (r)
if (r) {
kfree(compute_mqd);
goto free_mqd;
}
userq_props->eop_gpu_addr = compute_mqd->eop_va;
userq_props->hqd_pipe_priority = AMDGPU_GFX_PIPE_PRIO_NORMAL;
@ -365,12 +367,16 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->shadow_va,
shadow_info.shadow_size);
if (r)
if (r) {
kfree(mqd_gfx_v11);
goto free_mqd;
}
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->csa_va,
shadow_info.csa_size);
if (r)
if (r) {
kfree(mqd_gfx_v11);
goto free_mqd;
}
kfree(mqd_gfx_v11);
} else if (queue->queue_type == AMDGPU_HW_IP_DMA) {
@ -390,8 +396,10 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
}
r = amdgpu_userq_input_va_validate(adev, queue, mqd_sdma_v11->csa_va,
32);
if (r)
if (r) {
kfree(mqd_sdma_v11);
goto free_mqd;
}
userq_props->csa_addr = mqd_sdma_v11->csa_va;
kfree(mqd_sdma_v11);

View File

@ -170,7 +170,8 @@ static int psp_v11_0_wait_for_bootloader(struct psp_context *psp)
int retry_loop;
/* For a reset done at the end of S3, only wait for TOS to be unloaded */
if (adev->in_s3 && !(adev->flags & AMD_IS_APU) && amdgpu_in_reset(adev))
if ((adev->in_s4 || adev->in_s3) && !(adev->flags & AMD_IS_APU) &&
amdgpu_in_reset(adev))
return psp_v11_wait_for_tos_unload(psp);
for (retry_loop = 0; retry_loop < 20; retry_loop++) {

View File

@ -93,6 +93,11 @@ static void uvd_v4_2_ring_set_wptr(struct amdgpu_ring *ring)
static int uvd_v4_2_early_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
/* UVD doesn't work without DPM, it needs DPM to ungate it. */
if (!amdgpu_dpm)
return -ENOENT;
adev->uvd.num_uvd_inst = 1;
uvd_v4_2_set_ring_funcs(adev);

View File

@ -144,9 +144,10 @@ enum SQ_INTERRUPT_ERROR_TYPE {
#define KFD_CTXID0_DOORBELL_ID(ctxid0) ((ctxid0) & \
KFD_CTXID0_DOORBELL_ID_MASK)
static void print_sq_intr_info_auto(uint32_t context_id0, uint32_t context_id1)
static void print_sq_intr_info_auto(struct kfd_node *dev, uint32_t context_id0, uint32_t context_id1)
{
pr_debug_ratelimited(
dev_dbg_ratelimited(
dev->adev->dev,
"sq_intr: auto, ttrace %d, wlt %d, ttrace_buf0_full %d, ttrace_buf1_full %d ttrace_utc_err %d\n",
REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, THREAD_TRACE),
REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, WLT),
@ -155,9 +156,10 @@ static void print_sq_intr_info_auto(uint32_t context_id0, uint32_t context_id1)
REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, THREAD_TRACE_UTC_ERROR));
}
static void print_sq_intr_info_inst(uint32_t context_id0, uint32_t context_id1)
static void print_sq_intr_info_inst(struct kfd_node *dev, uint32_t context_id0, uint32_t context_id1)
{
pr_debug_ratelimited(
dev_dbg_ratelimited(
dev->adev->dev,
"sq_intr: inst, data 0x%08x, sh %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n",
REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, DATA),
REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, SA_ID),
@ -167,9 +169,10 @@ static void print_sq_intr_info_inst(uint32_t context_id0, uint32_t context_id1)
REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_WAVE_CTXID1, WGP_ID));
}
static void print_sq_intr_info_error(uint32_t context_id0, uint32_t context_id1)
static void print_sq_intr_info_error(struct kfd_node *dev, uint32_t context_id0, uint32_t context_id1)
{
pr_debug_ratelimited(
dev_warn_ratelimited(
dev->adev->dev,
"sq_intr: error, detail 0x%08x, type %d, sh %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n",
REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, DETAIL),
REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, TYPE),
@ -246,7 +249,8 @@ static bool event_interrupt_isr_v12_1(struct kfd_node *node,
vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry);
if (!kfd_irq_is_from_node(node, node_id, vmid)) {
pr_debug("Interrupt not for Node, node_id: %d, vmid: %d\n", node_id, vmid);
dev_dbg_ratelimited(node->adev->dev,
"Interrupt not for Node, node_id: %d, vmid: %d\n", node_id, vmid);
return false;
}
@ -266,9 +270,9 @@ static bool event_interrupt_isr_v12_1(struct kfd_node *node,
(context_id0 & AMDGPU_FENCE_MES_QUEUE_FLAG))
return false;
pr_debug("client id 0x%x, source id %d, vmid %d, pasid 0x%x. raw data:\n",
dev_dbg(node->adev->dev, "client id 0x%x, source id %d, vmid %d, pasid 0x%x. raw data:\n",
client_id, source_id, vmid, pasid);
pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n",
dev_dbg(node->adev->dev, "%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n",
data[0], data[1], data[2], data[3],
data[4], data[5], data[6], data[7]);
@ -361,10 +365,10 @@ static void event_interrupt_wq_v12_1(struct kfd_node *node,
SQ_INTERRUPT_WORD_WAVE_CTXID1, ENCODING);
switch (sq_int_enc) {
case SQ_INTERRUPT_WORD_ENCODING_AUTO:
print_sq_intr_info_auto(context_id0, context_id1);
print_sq_intr_info_auto(node, context_id0, context_id1);
break;
case SQ_INTERRUPT_WORD_ENCODING_INST:
print_sq_intr_info_inst(context_id0, context_id1);
print_sq_intr_info_inst(node, context_id0, context_id1);
sq_int_priv = REG_GET_FIELD(context_id0,
SQ_INTERRUPT_WORD_WAVE_CTXID0, PRIV);
if (sq_int_priv && (kfd_set_dbg_ev_from_interrupt(node, pasid,
@ -374,7 +378,7 @@ static void event_interrupt_wq_v12_1(struct kfd_node *node,
return;
break;
case SQ_INTERRUPT_WORD_ENCODING_ERROR:
print_sq_intr_info_error(context_id0, context_id1);
print_sq_intr_info_error(node, context_id0, context_id1);
sq_int_errtype = REG_GET_FIELD(context_id0,
SQ_INTERRUPT_WORD_ERROR_CTXID0, TYPE);
if (sq_int_errtype != SQ_INTERRUPT_ERROR_TYPE_ILLEGAL_INST &&

View File

@ -136,7 +136,7 @@ svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys,
u64 size;
int r;
entity = &adev->mman.move_entity;
entity = &adev->mman.move_entities[0];
mutex_lock(&entity->lock);

View File

@ -42,9 +42,16 @@ static uint64_t mqd_stride_v9(struct mqd_manager *mm,
struct queue_properties *q)
{
if (mm->dev->kfd->cwsr_enabled &&
q->type == KFD_QUEUE_TYPE_COMPUTE)
return ALIGN(q->ctl_stack_size, PAGE_SIZE) +
ALIGN(sizeof(struct v9_mqd), PAGE_SIZE);
q->type == KFD_QUEUE_TYPE_COMPUTE) {
/* On gfxv9, the MQD resides in the first 4K page,
* followed by the control stack. Align both to
* AMDGPU_GPU_PAGE_SIZE to maintain the required 4K boundary.
*/
return ALIGN(ALIGN(q->ctl_stack_size, AMDGPU_GPU_PAGE_SIZE) +
ALIGN(sizeof(struct v9_mqd), AMDGPU_GPU_PAGE_SIZE), PAGE_SIZE);
}
return mm->mqd_size;
}
@ -150,8 +157,8 @@ static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm,
if (!mqd_mem_obj)
return NULL;
retval = amdgpu_amdkfd_alloc_kernel_mem(node->adev,
(ALIGN(q->ctl_stack_size, PAGE_SIZE) +
ALIGN(sizeof(struct v9_mqd), PAGE_SIZE)) *
(ALIGN(ALIGN(q->ctl_stack_size, AMDGPU_GPU_PAGE_SIZE) +
ALIGN(sizeof(struct v9_mqd), AMDGPU_GPU_PAGE_SIZE), PAGE_SIZE)) *
NUM_XCC(node->xcc_mask),
mqd_on_vram(node->adev) ? AMDGPU_GEM_DOMAIN_VRAM :
AMDGPU_GEM_DOMAIN_GTT,
@ -359,7 +366,7 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
struct kfd_context_save_area_header header;
/* Control stack is located one page after MQD. */
void *mqd_ctl_stack = (void *)((uintptr_t)mqd + PAGE_SIZE);
void *mqd_ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE);
m = get_mqd(mqd);
@ -399,7 +406,7 @@ static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, voi
{
struct v9_mqd *m;
/* Control stack is located one page after MQD. */
void *ctl_stack = (void *)((uintptr_t)mqd + PAGE_SIZE);
void *ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE);
m = get_mqd(mqd);
@ -445,7 +452,7 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
*gart_addr = addr;
/* Control stack is located one page after MQD. */
ctl_stack = (void *)((uintptr_t)*mqd + PAGE_SIZE);
ctl_stack = (void *)((uintptr_t)*mqd + AMDGPU_GPU_PAGE_SIZE);
memcpy(ctl_stack, ctl_stack_src, ctl_stack_size);
m->cp_hqd_pq_doorbell_control =

View File

@ -102,8 +102,8 @@
* The first chunk is the TBA used for the CWSR ISA code. The second
* chunk is used as TMA for user-mode trap handler setup in daisy-chain mode.
*/
#define KFD_CWSR_TBA_TMA_SIZE (PAGE_SIZE * 2)
#define KFD_CWSR_TMA_OFFSET (PAGE_SIZE + 2048)
#define KFD_CWSR_TBA_TMA_SIZE (AMDGPU_GPU_PAGE_SIZE * 2)
#define KFD_CWSR_TMA_OFFSET (AMDGPU_GPU_PAGE_SIZE + 2048)
#define KFD_MAX_NUM_OF_QUEUES_PER_DEVICE \
(KFD_MAX_NUM_OF_PROCESSES * \

View File

@ -679,7 +679,7 @@ static void kfd_procfs_add_sysfs_files(struct kfd_process *p)
void kfd_procfs_del_queue(struct queue *q)
{
if (!q)
if (!q || !q->process->kobj)
return;
kobject_del(&q->kobj);
@ -858,6 +858,7 @@ int kfd_create_process_sysfs(struct kfd_process *process)
if (ret) {
pr_warn("Creating procfs pid directory failed");
kobject_put(process->kobj);
process->kobj = NULL;
return ret;
}

View File

@ -249,10 +249,10 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope
topo_dev->node_props.gfx_target_version < 90000)
/* metadata_queue_size not supported on GFX7/GFX8 */
expected_queue_size =
properties->queue_size / 2;
PAGE_ALIGN(properties->queue_size / 2);
else
expected_queue_size =
properties->queue_size + properties->metadata_queue_size;
PAGE_ALIGN(properties->queue_size + properties->metadata_queue_size);
vm = drm_priv_to_vm(pdd->drm_priv);
err = amdgpu_bo_reserve(vm->root.bo, false);
@ -492,10 +492,11 @@ void kfd_queue_ctx_save_restore_size(struct kfd_topology_device *dev)
cu_num = props->simd_count / props->simd_per_cu / NUM_XCC(dev->gpu->xcc_mask);
wave_num = get_num_waves(props, gfxv, cu_num);
wg_data_size = ALIGN(cu_num * WG_CONTEXT_DATA_SIZE_PER_CU(gfxv, props), PAGE_SIZE);
wg_data_size = ALIGN(cu_num * WG_CONTEXT_DATA_SIZE_PER_CU(gfxv, props),
AMDGPU_GPU_PAGE_SIZE);
ctl_stack_size = wave_num * CNTL_STACK_BYTES_PER_WAVE(gfxv) + 8;
ctl_stack_size = ALIGN(SIZEOF_HSA_USER_CONTEXT_SAVE_AREA_HEADER + ctl_stack_size,
PAGE_SIZE);
AMDGPU_GPU_PAGE_SIZE);
if ((gfxv / 10000 * 10000) == 100000) {
/* HW design limits control stack size to 0x7000.
@ -507,7 +508,7 @@ void kfd_queue_ctx_save_restore_size(struct kfd_topology_device *dev)
props->ctl_stack_size = ctl_stack_size;
props->debug_memory_size = ALIGN(wave_num * DEBUGGER_BYTES_PER_WAVE, DEBUGGER_BYTES_ALIGN);
props->cwsr_size = ctl_stack_size + wg_data_size;
props->cwsr_size = ALIGN(ctl_stack_size + wg_data_size, PAGE_SIZE);
if (gfxv == 80002) /* GFX_VERSION_TONGA */
props->eop_buffer_size = 0x8000;

View File

@ -628,9 +628,8 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
}
}
r = dma_resv_reserve_fences(bo->tbo.base.resv, 1);
r = dma_resv_reserve_fences(bo->tbo.base.resv, TTM_NUM_MOVE_FENCES);
if (r) {
pr_debug("failed %d to reserve bo\n", r);
amdgpu_bo_unreserve(bo);
goto reserve_bo_failed;
}

View File

@ -40,7 +40,8 @@ AMDGPUDM = \
amdgpu_dm_replay.o \
amdgpu_dm_quirks.o \
amdgpu_dm_wb.o \
amdgpu_dm_colorop.o
amdgpu_dm_colorop.o \
amdgpu_dm_ism.o
ifdef CONFIG_DRM_AMD_DC_FP
AMDGPUDM += dc_fpu.o

View File

@ -3283,6 +3283,7 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
mutex_lock(&dm->dc_lock);
amdgpu_dm_ism_disable(dm);
dc_allow_idle_optimizations(adev->dm.dc, false);
dm->cached_dc_state = dc_state_create_copy(dm->dc->current_state);
@ -3316,6 +3317,9 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
amdgpu_dm_irq_suspend(adev);
scoped_guard(mutex, &dm->dc_lock)
amdgpu_dm_ism_disable(dm);
hpd_rx_irq_work_suspend(dm);
dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
@ -3606,6 +3610,7 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
dc_resume(dm->dc);
amdgpu_dm_ism_enable(dm);
amdgpu_dm_irq_resume_early(adev);
for (i = 0; i < dc_state->stream_count; i++) {
@ -3666,6 +3671,9 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
/* program HPD filter */
dc_resume(dm->dc);
scoped_guard(mutex, &dm->dc_lock)
amdgpu_dm_ism_enable(dm);
/*
* early enable HPD Rx IRQ, should be done before set mode as short
* pulse interrupts are used for MST
@ -5581,6 +5589,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
case IP_VERSION(3, 5, 0):
case IP_VERSION(3, 5, 1):
case IP_VERSION(3, 6, 0):
case IP_VERSION(4, 2, 0):
replay_feature_enabled = true;
break;
@ -9333,31 +9342,7 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
if (acrtc_state) {
timing = &acrtc_state->stream->timing;
/*
* Depending on when the HW latching event of double-buffered
* registers happen relative to the PSR SDP deadline, and how
* bad the Panel clock has drifted since the last ALPM off
* event, there can be up to 3 frames of delay between sending
* the PSR exit cmd to DMUB fw, and when the panel starts
* displaying live frames.
*
* We can set:
*
* 20/100 * offdelay_ms = 3_frames_ms
* => offdelay_ms = 5 * 3_frames_ms
*
* This ensures that `3_frames_ms` will only be experienced as a
* 20% delay on top how long the display has been static, and
* thus make the delay less perceivable.
*/
if (acrtc_state->stream->link->psr_settings.psr_version <
DC_PSR_VERSION_UNSUPPORTED) {
offdelay = DIV64_U64_ROUND_UP((u64)5 * 3 * 10 *
timing->v_total *
timing->h_total,
timing->pix_clk_100hz);
config.offdelay_ms = offdelay ?: 30;
} else if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
IP_VERSION(3, 5, 0) ||
!(adev->flags & AMD_IS_APU)) {
/*
@ -9889,7 +9874,7 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_crtc *acrtc_attach,
}
/* Decrement skip count when SR is enabled and we're doing fast updates. */
if (acrtc_state->update_type <= UPDATE_TYPE_FAST &&
if (acrtc_state->update_type == UPDATE_TYPE_FAST &&
(psr->psr_feature_enabled || pr->config.replay_supported)) {
if (aconn->sr_skip_count > 0)
aconn->sr_skip_count--;
@ -10099,7 +10084,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
* fast updates.
*/
if (crtc->state->async_flip &&
(acrtc_state->update_type > UPDATE_TYPE_FAST ||
(acrtc_state->update_type != UPDATE_TYPE_FAST ||
get_mem_type(old_plane_state->fb) != get_mem_type(fb)))
drm_warn_once(state->dev,
"[PLANE:%d:%s] async flip with non-fast update\n",
@ -10107,7 +10092,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
bundle->flip_addrs[planes_count].flip_immediate =
crtc->state->async_flip &&
acrtc_state->update_type <= UPDATE_TYPE_FAST &&
acrtc_state->update_type == UPDATE_TYPE_FAST &&
get_mem_type(old_plane_state->fb) == get_mem_type(fb);
timestamp_ns = ktime_get_ns();

View File

@ -124,37 +124,37 @@ bool amdgpu_dm_crtc_vrr_active(const struct dm_crtc_state *dm_state)
* - Enable condition same as above
* - Disable when vblank counter is enabled
*/
static void amdgpu_dm_crtc_set_panel_sr_feature(
struct vblank_control_work *vblank_work,
void amdgpu_dm_crtc_set_panel_sr_feature(
struct amdgpu_display_manager *dm,
struct amdgpu_crtc *acrtc,
struct dc_stream_state *stream,
bool vblank_enabled, bool allow_sr_entry)
{
struct dc_link *link = vblank_work->stream->link;
struct dc_link *link = stream->link;
bool is_sr_active = (link->replay_settings.replay_allow_active ||
link->psr_settings.psr_allow_active);
bool is_crc_window_active = false;
bool vrr_active = amdgpu_dm_crtc_vrr_active_irq(vblank_work->acrtc);
bool vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
is_crc_window_active =
amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base);
amdgpu_dm_crc_window_is_activated(&acrtc->base);
#endif
if (link->replay_settings.replay_feature_enabled && !vrr_active &&
allow_sr_entry && !is_sr_active && !is_crc_window_active) {
amdgpu_dm_replay_enable(vblank_work->stream, true);
amdgpu_dm_replay_enable(stream, true);
} else if (vblank_enabled) {
if (link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && is_sr_active)
amdgpu_dm_psr_disable(vblank_work->stream, false);
amdgpu_dm_psr_disable(stream, false);
} else if (link->psr_settings.psr_feature_enabled && !vrr_active &&
allow_sr_entry && !is_sr_active && !is_crc_window_active) {
struct amdgpu_dm_connector *aconn =
(struct amdgpu_dm_connector *) vblank_work->stream->dm_stream_context;
(struct amdgpu_dm_connector *) stream->dm_stream_context;
if (!aconn->disallow_edp_enter_psr) {
struct amdgpu_display_manager *dm = vblank_work->dm;
amdgpu_dm_psr_enable(vblank_work->stream);
amdgpu_dm_psr_enable(stream);
if (dm->idle_workqueue &&
(dm->dc->config.disable_ips == DMUB_IPS_ENABLE) &&
dm->dc->idle_optimizations_allowed &&
@ -251,33 +251,15 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work)
mutex_lock(&dm->dc_lock);
if (vblank_work->enable)
if (vblank_work->enable) {
dm->active_vblank_irq_count++;
else if (dm->active_vblank_irq_count)
dm->active_vblank_irq_count--;
if (dm->active_vblank_irq_count > 0)
dc_allow_idle_optimizations(dm->dc, false);
/*
* Control PSR based on vblank requirements from OS
*
* If panel supports PSR SU, there's no need to disable PSR when OS is
* submitting fast atomic commits (we infer this by whether the OS
* requests vblank events). Fast atomic commits will simply trigger a
* full-frame-update (FFU); a specific case of selective-update (SU)
* where the SU region is the full hactive*vactive region. See
* fill_dc_dirty_rects().
*/
if (vblank_work->stream && vblank_work->stream->link && vblank_work->acrtc) {
amdgpu_dm_crtc_set_panel_sr_feature(
vblank_work, vblank_work->enable,
vblank_work->acrtc->dm_irq_params.allow_sr_entry);
}
if (dm->active_vblank_irq_count == 0) {
dc_post_update_surfaces_to_stream(dm->dc);
dc_allow_idle_optimizations(dm->dc, true);
amdgpu_dm_ism_commit_event(&vblank_work->acrtc->ism,
DM_ISM_EVENT_EXIT_IDLE_REQUESTED);
} else {
if (dm->active_vblank_irq_count > 0)
dm->active_vblank_irq_count--;
amdgpu_dm_ism_commit_event(&vblank_work->acrtc->ism,
DM_ISM_EVENT_ENTER_IDLE_REQUESTED);
}
mutex_unlock(&dm->dc_lock);
@ -476,6 +458,9 @@ static struct drm_crtc_state *amdgpu_dm_crtc_duplicate_state(struct drm_crtc *cr
static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
{
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
amdgpu_dm_ism_fini(&acrtc->ism);
drm_crtc_cleanup(crtc);
kfree(crtc);
}
@ -685,7 +670,7 @@ static int amdgpu_dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
* pitch, the DCC state, rotation, etc.
*/
if (crtc_state->async_flip &&
dm_crtc_state->update_type > UPDATE_TYPE_FAST) {
dm_crtc_state->update_type != UPDATE_TYPE_FAST) {
drm_dbg_atomic(crtc->dev,
"[CRTC:%d:%s] async flips are only supported for fast updates\n",
crtc->base.id, crtc->name);
@ -719,6 +704,35 @@ static const struct drm_crtc_helper_funcs amdgpu_dm_crtc_helper_funcs = {
.get_scanout_position = amdgpu_crtc_get_scanout_position,
};
/*
* This hysteresis filter as configured will:
*
* * Search through the latest 8[filter_history_size] entries in history,
* skipping entries that are older than [filter_old_history_threshold] frames
* (0 means ignore age)
* * Searches for short-idle-periods that lasted shorter than
* 4[filter_num_frames] frames-times
* * If there is at least 1[filter_entry_count] short-idle-period, then a delay
* of 4[activation_num_delay_frames] will applied before allowing idle
* optimizations again.
* * An additional delay of 11[sso_num_frames] is applied before enabling
* panel-specific optimizations.
*
* The values were determined empirically on another OS, optimizing for Z8
* residency on APUs when running a productivity + web browsing test.
*
* TODO: Run similar tests to determine if these values are also optimal for
* Linux, and if each APU generation benefits differently.
*/
static struct amdgpu_dm_ism_config default_ism_config = {
.filter_num_frames = 4,
.filter_history_size = 8,
.filter_entry_count = 1,
.activation_num_delay_frames = 4,
.filter_old_history_threshold = 0,
.sso_num_frames = 11,
};
int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
struct drm_plane *plane,
uint32_t crtc_index)
@ -749,6 +763,8 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
if (res)
goto fail;
amdgpu_dm_ism_init(&acrtc->ism, &default_ism_config);
drm_crtc_helper_add(&acrtc->base, &amdgpu_dm_crtc_helper_funcs);
/* Create (reset) the plane state */

View File

@ -27,6 +27,12 @@
#ifndef __AMDGPU_DM_CRTC_H__
#define __AMDGPU_DM_CRTC_H__
void amdgpu_dm_crtc_set_panel_sr_feature(
struct amdgpu_display_manager *dm,
struct amdgpu_crtc *acrtc,
struct dc_stream_state *stream,
bool vblank_enabled, bool allow_sr_entry);
void amdgpu_dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc);
bool amdgpu_dm_crtc_modeset_required(struct drm_crtc_state *crtc_state,

View File

@ -0,0 +1,598 @@
// SPDX-License-Identifier: MIT
/*
* Copyright 2026 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include <linux/types.h>
#include <drm/drm_vblank.h>
#include "dc.h"
#include "amdgpu.h"
#include "amdgpu_dm_ism.h"
#include "amdgpu_dm_crtc.h"
#include "amdgpu_dm_trace.h"
/**
* dm_ism_next_state - Get next state based on current state and event
*
* This function defines the idle state management FSM. Invalid transitions
* are ignored and will not progress the FSM.
*/
static bool dm_ism_next_state(enum amdgpu_dm_ism_state current_state,
enum amdgpu_dm_ism_event event,
enum amdgpu_dm_ism_state *next_state)
{
switch (STATE_EVENT(current_state, event)) {
case STATE_EVENT(DM_ISM_STATE_FULL_POWER_RUNNING,
DM_ISM_EVENT_ENTER_IDLE_REQUESTED):
*next_state = DM_ISM_STATE_HYSTERESIS_WAITING;
break;
case STATE_EVENT(DM_ISM_STATE_FULL_POWER_RUNNING,
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE):
*next_state = DM_ISM_STATE_FULL_POWER_BUSY;
break;
case STATE_EVENT(DM_ISM_STATE_FULL_POWER_BUSY,
DM_ISM_EVENT_ENTER_IDLE_REQUESTED):
*next_state = DM_ISM_STATE_HYSTERESIS_BUSY;
break;
case STATE_EVENT(DM_ISM_STATE_FULL_POWER_BUSY,
DM_ISM_EVENT_END_CURSOR_UPDATE):
*next_state = DM_ISM_STATE_FULL_POWER_RUNNING;
break;
case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING,
DM_ISM_EVENT_EXIT_IDLE_REQUESTED):
*next_state = DM_ISM_STATE_TIMER_ABORTED;
break;
case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING,
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE):
*next_state = DM_ISM_STATE_HYSTERESIS_BUSY;
break;
case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING,
DM_ISM_EVENT_TIMER_ELAPSED):
*next_state = DM_ISM_STATE_OPTIMIZED_IDLE;
break;
case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_WAITING,
DM_ISM_EVENT_IMMEDIATE):
*next_state = DM_ISM_STATE_OPTIMIZED_IDLE;
break;
case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_BUSY,
DM_ISM_EVENT_EXIT_IDLE_REQUESTED):
*next_state = DM_ISM_STATE_FULL_POWER_BUSY;
break;
case STATE_EVENT(DM_ISM_STATE_HYSTERESIS_BUSY,
DM_ISM_EVENT_END_CURSOR_UPDATE):
*next_state = DM_ISM_STATE_HYSTERESIS_WAITING;
break;
case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE,
DM_ISM_EVENT_EXIT_IDLE_REQUESTED):
*next_state = DM_ISM_STATE_FULL_POWER_RUNNING;
break;
case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE,
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE):
*next_state = DM_ISM_STATE_HYSTERESIS_BUSY;
break;
case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE,
DM_ISM_EVENT_SSO_TIMER_ELAPSED):
case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE,
DM_ISM_EVENT_IMMEDIATE):
*next_state = DM_ISM_STATE_OPTIMIZED_IDLE_SSO;
break;
case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE_SSO,
DM_ISM_EVENT_EXIT_IDLE_REQUESTED):
*next_state = DM_ISM_STATE_FULL_POWER_RUNNING;
break;
case STATE_EVENT(DM_ISM_STATE_OPTIMIZED_IDLE_SSO,
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE):
*next_state = DM_ISM_STATE_HYSTERESIS_BUSY;
break;
case STATE_EVENT(DM_ISM_STATE_TIMER_ABORTED,
DM_ISM_EVENT_IMMEDIATE):
*next_state = DM_ISM_STATE_FULL_POWER_RUNNING;
break;
default:
return false;
}
return true;
}
static uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
const struct dc_stream_state *stream)
{
const struct amdgpu_dm_ism_config *config = &ism->config;
uint32_t v_total, h_total;
uint64_t one_frame_ns, sso_delay_ns;
if (!stream)
return 0;
if (!config->sso_num_frames)
return 0;
v_total = stream->timing.v_total;
h_total = stream->timing.h_total;
one_frame_ns = div64_u64(v_total * h_total * 10000000ull,
stream->timing.pix_clk_100hz);
sso_delay_ns = config->sso_num_frames * one_frame_ns;
return sso_delay_ns;
}
/**
* dm_ism_get_idle_allow_delay - Calculate hysteresis-based idle allow delay
*/
static uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
const struct dc_stream_state *stream)
{
const struct amdgpu_dm_ism_config *config = &ism->config;
uint32_t v_total, h_total;
uint64_t one_frame_ns, short_idle_ns, old_hist_ns;
uint32_t history_size;
int pos;
uint32_t short_idle_count = 0;
uint64_t ret_ns = 0;
if (!stream)
return 0;
if (!config->filter_num_frames)
return 0;
if (!config->filter_entry_count)
return 0;
if (!config->activation_num_delay_frames)
return 0;
v_total = stream->timing.v_total;
h_total = stream->timing.h_total;
one_frame_ns = div64_u64(v_total * h_total * 10000000ull,
stream->timing.pix_clk_100hz);
short_idle_ns = config->filter_num_frames * one_frame_ns;
old_hist_ns = config->filter_old_history_threshold * one_frame_ns;
/*
* Look back into the recent history and count how many times we entered
* idle power state for a short duration of time
*/
history_size = min(
max(config->filter_history_size, config->filter_entry_count),
AMDGPU_DM_IDLE_HIST_LEN);
pos = ism->next_record_idx;
for (int k = 0; k < history_size; k++) {
if (pos <= 0 || pos > AMDGPU_DM_IDLE_HIST_LEN)
pos = AMDGPU_DM_IDLE_HIST_LEN;
pos -= 1;
if (ism->records[pos].duration_ns <= short_idle_ns)
short_idle_count += 1;
if (short_idle_count >= config->filter_entry_count)
break;
if (old_hist_ns > 0 &&
ism->last_idle_timestamp_ns - ism->records[pos].timestamp_ns > old_hist_ns)
break;
}
if (short_idle_count >= config->filter_entry_count)
ret_ns = config->activation_num_delay_frames * one_frame_ns;
return ret_ns;
}
/**
* dm_ism_insert_record - Insert a record into the circular history buffer
*/
static void dm_ism_insert_record(struct amdgpu_dm_ism *ism)
{
struct amdgpu_dm_ism_record *record;
if (ism->next_record_idx < 0 ||
ism->next_record_idx >= AMDGPU_DM_IDLE_HIST_LEN)
ism->next_record_idx = 0;
record = &ism->records[ism->next_record_idx];
ism->next_record_idx += 1;
record->timestamp_ns = ktime_get_ns();
record->duration_ns =
record->timestamp_ns - ism->last_idle_timestamp_ns;
}
static void dm_ism_set_last_idle_ts(struct amdgpu_dm_ism *ism)
{
ism->last_idle_timestamp_ns = ktime_get_ns();
}
static bool dm_ism_trigger_event(struct amdgpu_dm_ism *ism,
enum amdgpu_dm_ism_event event)
{
enum amdgpu_dm_ism_state next_state;
bool gotNextState = dm_ism_next_state(ism->current_state, event,
&next_state);
if (gotNextState) {
ism->previous_state = ism->current_state;
ism->current_state = next_state;
}
return gotNextState;
}
static void dm_ism_commit_idle_optimization_state(struct amdgpu_dm_ism *ism,
struct dc_stream_state *stream,
bool vblank_enabled,
bool allow_panel_sso)
{
struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism);
struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev);
struct amdgpu_display_manager *dm = &adev->dm;
int r;
trace_amdgpu_dm_ism_commit(dm->active_vblank_irq_count,
vblank_enabled,
allow_panel_sso);
/*
* If there is an active vblank requestor, or if SSO is being engaged,
* then disallow idle optimizations.
*/
if (vblank_enabled || allow_panel_sso)
dc_allow_idle_optimizations(dm->dc, false);
/*
* Control PSR based on vblank requirements from OS
*
* If panel supports PSR SU/Replay, there's no need to exit self-refresh
* when OS is submitting fast atomic commits, as they can allow
* self-refresh during vblank periods.
*/
if (stream && stream->link) {
/*
* If allow_panel_sso is true when disabling vblank, allow
* deeper panel sleep states such as PSR1 and Replay static
* screen optimization.
*/
if (!vblank_enabled && allow_panel_sso) {
amdgpu_dm_crtc_set_panel_sr_feature(
dm, acrtc, stream, false,
acrtc->dm_irq_params.allow_sr_entry);
} else if (vblank_enabled) {
/* Make sure to exit SSO on vblank enable */
amdgpu_dm_crtc_set_panel_sr_feature(
dm, acrtc, stream, true,
acrtc->dm_irq_params.allow_sr_entry);
}
/*
* Else, vblank_enabled == false and allow_panel_sso == false;
* do nothing here.
*/
}
/*
* Check for any active drm vblank requestors on other CRTCs
* (dm->active_vblank_irq_count) before allowing HW-wide idle
* optimizations.
*
* There's no need to have a "balanced" check when disallowing idle
* optimizations at the start of this func -- we should disallow
* whenever there's *an* active CRTC.
*/
if (!vblank_enabled && dm->active_vblank_irq_count == 0) {
dc_post_update_surfaces_to_stream(dm->dc);
r = amdgpu_dpm_pause_power_profile(adev, true);
if (r)
dev_warn(adev->dev, "failed to set default power profile mode\n");
dc_allow_idle_optimizations(dm->dc, true);
r = amdgpu_dpm_pause_power_profile(adev, false);
if (r)
dev_warn(adev->dev, "failed to restore the power profile mode\n");
}
}
static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state(
struct amdgpu_dm_ism *ism,
struct dm_crtc_state *acrtc_state,
enum amdgpu_dm_ism_event event)
{
enum amdgpu_dm_ism_event ret = event;
const struct amdgpu_dm_ism_config *config = &ism->config;
uint64_t delay_ns, sso_delay_ns;
switch (ism->previous_state) {
case DM_ISM_STATE_HYSTERESIS_WAITING:
/*
* Stop the timer if it was set, and we're not running from the
* idle allow worker.
*/
if (ism->current_state != DM_ISM_STATE_OPTIMIZED_IDLE &&
ism->current_state != DM_ISM_STATE_OPTIMIZED_IDLE_SSO)
cancel_delayed_work(&ism->delayed_work);
break;
case DM_ISM_STATE_OPTIMIZED_IDLE:
if (ism->current_state == DM_ISM_STATE_OPTIMIZED_IDLE_SSO)
break;
/* If idle disallow, cancel SSO work and insert record */
cancel_delayed_work(&ism->sso_delayed_work);
dm_ism_insert_record(ism);
dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream,
true, false);
break;
case DM_ISM_STATE_OPTIMIZED_IDLE_SSO:
/* Disable idle optimization */
dm_ism_insert_record(ism);
dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream,
true, false);
break;
default:
break;
}
switch (ism->current_state) {
case DM_ISM_STATE_HYSTERESIS_WAITING:
dm_ism_set_last_idle_ts(ism);
/* CRTC can be disabled; allow immediate idle */
if (!acrtc_state->stream) {
ret = DM_ISM_EVENT_IMMEDIATE;
break;
}
delay_ns = dm_ism_get_idle_allow_delay(ism,
acrtc_state->stream);
if (delay_ns == 0) {
ret = DM_ISM_EVENT_IMMEDIATE;
break;
}
/* Schedule worker */
mod_delayed_work(system_unbound_wq, &ism->delayed_work,
nsecs_to_jiffies(delay_ns));
break;
case DM_ISM_STATE_OPTIMIZED_IDLE:
sso_delay_ns = dm_ism_get_sso_delay(ism, acrtc_state->stream);
if (sso_delay_ns == 0)
ret = DM_ISM_EVENT_IMMEDIATE;
else if (config->sso_num_frames < config->filter_num_frames) {
/*
* If sso_num_frames is less than hysteresis frames, it
* indicates that allowing idle here, then disallowing
* idle after sso_num_frames has expired, will likely
* have a negative power impact. Skip idle allow here,
* and let the sso_delayed_work handle it.
*/
mod_delayed_work(system_unbound_wq,
&ism->sso_delayed_work,
nsecs_to_jiffies(sso_delay_ns));
} else {
/* Enable idle optimization without SSO */
dm_ism_commit_idle_optimization_state(
ism, acrtc_state->stream, false, false);
mod_delayed_work(system_unbound_wq,
&ism->sso_delayed_work,
nsecs_to_jiffies(sso_delay_ns));
}
break;
case DM_ISM_STATE_OPTIMIZED_IDLE_SSO:
/* Enable static screen optimizations. */
dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream,
false, true);
break;
case DM_ISM_STATE_TIMER_ABORTED:
dm_ism_insert_record(ism);
dm_ism_commit_idle_optimization_state(ism, acrtc_state->stream,
true, false);
ret = DM_ISM_EVENT_IMMEDIATE;
break;
default:
break;
}
return ret;
}
static char *dm_ism_events_str[DM_ISM_NUM_EVENTS] = {
[DM_ISM_EVENT_IMMEDIATE] = "IMMEDIATE",
[DM_ISM_EVENT_ENTER_IDLE_REQUESTED] = "ENTER_IDLE_REQUESTED",
[DM_ISM_EVENT_EXIT_IDLE_REQUESTED] = "EXIT_IDLE_REQUESTED",
[DM_ISM_EVENT_BEGIN_CURSOR_UPDATE] = "BEGIN_CURSOR_UPDATE",
[DM_ISM_EVENT_END_CURSOR_UPDATE] = "END_CURSOR_UPDATE",
[DM_ISM_EVENT_TIMER_ELAPSED] = "TIMER_ELAPSED",
[DM_ISM_EVENT_SSO_TIMER_ELAPSED] = "SSO_TIMER_ELAPSED",
};
static char *dm_ism_states_str[DM_ISM_NUM_STATES] = {
[DM_ISM_STATE_FULL_POWER_RUNNING] = "FULL_POWER_RUNNING",
[DM_ISM_STATE_FULL_POWER_BUSY] = "FULL_POWER_BUSY",
[DM_ISM_STATE_HYSTERESIS_WAITING] = "HYSTERESIS_WAITING",
[DM_ISM_STATE_HYSTERESIS_BUSY] = "HYSTERESIS_BUSY",
[DM_ISM_STATE_OPTIMIZED_IDLE] = "OPTIMIZED_IDLE",
[DM_ISM_STATE_OPTIMIZED_IDLE_SSO] = "OPTIMIZED_IDLE_SSO",
[DM_ISM_STATE_TIMER_ABORTED] = "TIMER_ABORTED",
};
void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism,
enum amdgpu_dm_ism_event event)
{
enum amdgpu_dm_ism_event next_event = event;
struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism);
struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev);
struct amdgpu_display_manager *dm = &adev->dm;
struct dm_crtc_state *acrtc_state = to_dm_crtc_state(acrtc->base.state);
/* ISM transitions must be called with mutex acquired */
ASSERT(mutex_is_locked(&dm->dc_lock));
if (!acrtc_state) {
trace_amdgpu_dm_ism_event(acrtc->crtc_id, "NO_STATE",
"NO_STATE", "N/A");
return;
}
do {
bool transition = dm_ism_trigger_event(ism, event);
next_event = DM_ISM_NUM_EVENTS;
if (transition) {
trace_amdgpu_dm_ism_event(
acrtc->crtc_id,
dm_ism_states_str[ism->previous_state],
dm_ism_states_str[ism->current_state],
dm_ism_events_str[event]);
next_event = dm_ism_dispatch_power_state(
ism, acrtc_state, next_event);
} else {
trace_amdgpu_dm_ism_event(
acrtc->crtc_id,
dm_ism_states_str[ism->current_state],
dm_ism_states_str[ism->current_state],
dm_ism_events_str[event]);
}
event = next_event;
} while (next_event < DM_ISM_NUM_EVENTS);
}
static void dm_ism_delayed_work_func(struct work_struct *work)
{
struct amdgpu_dm_ism *ism =
container_of(work, struct amdgpu_dm_ism, delayed_work.work);
struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism);
struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev);
struct amdgpu_display_manager *dm = &adev->dm;
guard(mutex)(&dm->dc_lock);
amdgpu_dm_ism_commit_event(ism, DM_ISM_EVENT_TIMER_ELAPSED);
}
static void dm_ism_sso_delayed_work_func(struct work_struct *work)
{
struct amdgpu_dm_ism *ism =
container_of(work, struct amdgpu_dm_ism, sso_delayed_work.work);
struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism);
struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev);
struct amdgpu_display_manager *dm = &adev->dm;
guard(mutex)(&dm->dc_lock);
amdgpu_dm_ism_commit_event(ism, DM_ISM_EVENT_SSO_TIMER_ELAPSED);
}
/**
* amdgpu_dm_ism_disable - Disable the ISM
*
* @dm: The amdgpu display manager
*
* Disable the idle state manager by disabling any ISM work, canceling pending
* work, and waiting for in-progress work to finish. After disabling, the system
* is left in DM_ISM_STATE_FULL_POWER_RUNNING state.
*/
void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm)
{
struct drm_crtc *crtc;
struct amdgpu_crtc *acrtc;
struct amdgpu_dm_ism *ism;
drm_for_each_crtc(crtc, dm->ddev) {
acrtc = to_amdgpu_crtc(crtc);
ism = &acrtc->ism;
/* Cancel and disable any pending work */
disable_delayed_work_sync(&ism->delayed_work);
disable_delayed_work_sync(&ism->sso_delayed_work);
/*
* When disabled, leave in FULL_POWER_RUNNING state.
* EXIT_IDLE will not queue any work
*/
amdgpu_dm_ism_commit_event(ism,
DM_ISM_EVENT_EXIT_IDLE_REQUESTED);
}
}
/**
* amdgpu_dm_ism_enable - enable the ISM
*
* @dm: The amdgpu display manager
*
* Re-enable the idle state manager by enabling work that was disabled by
* amdgpu_dm_ism_disable.
*/
void amdgpu_dm_ism_enable(struct amdgpu_display_manager *dm)
{
struct drm_crtc *crtc;
struct amdgpu_crtc *acrtc;
struct amdgpu_dm_ism *ism;
drm_for_each_crtc(crtc, dm->ddev) {
acrtc = to_amdgpu_crtc(crtc);
ism = &acrtc->ism;
enable_delayed_work(&ism->delayed_work);
enable_delayed_work(&ism->sso_delayed_work);
}
}
void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism,
struct amdgpu_dm_ism_config *config)
{
ism->config = *config;
ism->current_state = DM_ISM_STATE_FULL_POWER_RUNNING;
ism->previous_state = DM_ISM_STATE_FULL_POWER_RUNNING;
ism->next_record_idx = 0;
ism->last_idle_timestamp_ns = 0;
INIT_DELAYED_WORK(&ism->delayed_work, dm_ism_delayed_work_func);
INIT_DELAYED_WORK(&ism->sso_delayed_work, dm_ism_sso_delayed_work_func);
}
void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism)
{
cancel_delayed_work_sync(&ism->sso_delayed_work);
cancel_delayed_work_sync(&ism->delayed_work);
}

View File

@ -0,0 +1,151 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright 2026 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#ifndef __AMDGPU_DM_ISM_H__
#define __AMDGPU_DM_ISM_H__
#include <linux/workqueue.h>
struct amdgpu_crtc;
struct amdgpu_display_manager;
#define AMDGPU_DM_IDLE_HIST_LEN 16
enum amdgpu_dm_ism_state {
DM_ISM_STATE_FULL_POWER_RUNNING,
DM_ISM_STATE_FULL_POWER_BUSY,
DM_ISM_STATE_HYSTERESIS_WAITING,
DM_ISM_STATE_HYSTERESIS_BUSY,
DM_ISM_STATE_OPTIMIZED_IDLE,
DM_ISM_STATE_OPTIMIZED_IDLE_SSO,
DM_ISM_STATE_TIMER_ABORTED,
DM_ISM_NUM_STATES,
};
enum amdgpu_dm_ism_event {
DM_ISM_EVENT_IMMEDIATE,
DM_ISM_EVENT_ENTER_IDLE_REQUESTED,
DM_ISM_EVENT_EXIT_IDLE_REQUESTED,
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE,
DM_ISM_EVENT_END_CURSOR_UPDATE,
DM_ISM_EVENT_TIMER_ELAPSED,
DM_ISM_EVENT_SSO_TIMER_ELAPSED,
DM_ISM_NUM_EVENTS,
};
#define STATE_EVENT(state, event) (((state) << 8) | (event))
struct amdgpu_dm_ism_config {
/**
* @filter_num_frames: Idle periods shorter than this number of frames
* will be considered a "short idle period" for filtering.
*
* 0 indicates no filtering (i.e. no idle allow delay will be applied)
*/
unsigned int filter_num_frames;
/**
* @filter_history_size: Number of recent idle periods to consider when
* counting the number of short idle periods.
*/
unsigned int filter_history_size;
/**
* @filter_entry_count: When the number of short idle periods within
* recent &filter_history_size reaches this count, the idle allow delay
* will be applied.
*
* 0 indicates no filtering (i.e. no idle allow delay will be applied)
*/
unsigned int filter_entry_count;
/**
* @activation_num_delay_frames: Defines the number of frames to wait
* for the idle allow delay.
*
* 0 indicates no filtering (i.e. no idle allow delay will be applied)
*/
unsigned int activation_num_delay_frames;
/**
* @filter_old_history_threshold: A time-based restriction on top of
* &filter_history_size. Idle periods older than this threshold (in
* number of frames) will be ignored when counting the number of short
* idle periods.
*
* 0 indicates no time-based restriction, i.e. history is limited only
* by &filter_history_size.
*/
unsigned int filter_old_history_threshold;
/**
* @sso_num_frames: Number of frames to delay before enabling static
* screen optimizations, such as PSR1 and Replay low HZ idle mode.
*
* 0 indicates immediate SSO enable upon allowing idle.
*/
unsigned int sso_num_frames;
};
struct amdgpu_dm_ism_record {
/**
* @timestamp_ns: When idle was allowed
*/
unsigned long long timestamp_ns;
/**
* @duration_ns: How long idle was allowed
*/
unsigned long long duration_ns;
};
struct amdgpu_dm_ism {
struct amdgpu_dm_ism_config config;
unsigned long long last_idle_timestamp_ns;
enum amdgpu_dm_ism_state current_state;
enum amdgpu_dm_ism_state previous_state;
struct amdgpu_dm_ism_record records[AMDGPU_DM_IDLE_HIST_LEN];
int next_record_idx;
struct delayed_work delayed_work;
struct delayed_work sso_delayed_work;
};
#define ism_to_amdgpu_crtc(ism_ptr) \
container_of(ism_ptr, struct amdgpu_crtc, ism)
void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism,
struct amdgpu_dm_ism_config *config);
void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism);
void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism,
enum amdgpu_dm_ism_event event);
void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm);
void amdgpu_dm_ism_enable(struct amdgpu_display_manager *dm);
#endif

View File

@ -954,11 +954,9 @@ static int amdgpu_dm_plane_helper_prepare_fb(struct drm_plane *plane,
return r;
}
r = dma_resv_reserve_fences(rbo->tbo.base.resv, 1);
if (r) {
drm_err(adev_to_drm(adev), "reserving fence slot failed (%d)\n", r);
r = dma_resv_reserve_fences(rbo->tbo.base.resv, TTM_NUM_MOVE_FENCES);
if (r)
goto error_unlock;
}
if (plane->type != DRM_PLANE_TYPE_CURSOR)
domain = amdgpu_display_supported_domains(adev, rbo->flags);
@ -1374,8 +1372,16 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane,
/* turn off cursor */
if (crtc_state && crtc_state->stream) {
mutex_lock(&adev->dm.dc_lock);
amdgpu_dm_ism_commit_event(
&amdgpu_crtc->ism,
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE);
dc_stream_program_cursor_position(crtc_state->stream,
&position);
amdgpu_dm_ism_commit_event(
&amdgpu_crtc->ism,
DM_ISM_EVENT_END_CURSOR_UPDATE);
mutex_unlock(&adev->dm.dc_lock);
}
return;
@ -1405,6 +1411,10 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane,
if (crtc_state->stream) {
mutex_lock(&adev->dm.dc_lock);
amdgpu_dm_ism_commit_event(
&amdgpu_crtc->ism,
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE);
if (!dc_stream_program_cursor_attributes(crtc_state->stream,
&attributes))
DRM_ERROR("DC failed to set cursor attributes\n");
@ -1412,6 +1422,10 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane,
if (!dc_stream_program_cursor_position(crtc_state->stream,
&position))
DRM_ERROR("DC failed to set cursor position\n");
amdgpu_dm_ism_commit_event(
&amdgpu_crtc->ism,
DM_ISM_EVENT_END_CURSOR_UPDATE);
mutex_unlock(&adev->dm.dc_lock);
}
}

View File

@ -753,6 +753,69 @@ TRACE_EVENT(amdgpu_dm_brightness,
)
);
TRACE_EVENT(amdgpu_dm_ism_commit,
TP_PROTO(
int active_vblank_irq_count,
bool vblank_enabled,
bool allow_panel_sso
),
TP_ARGS(
active_vblank_irq_count,
vblank_enabled,
allow_panel_sso
),
TP_STRUCT__entry(
__field(int, active_vblank_irq_count)
__field(bool, vblank_enabled)
__field(bool, allow_panel_sso)
),
TP_fast_assign(
__entry->active_vblank_irq_count = active_vblank_irq_count;
__entry->vblank_enabled = vblank_enabled;
__entry->allow_panel_sso = allow_panel_sso;
),
TP_printk(
"active_vblank_irq_count=%d vblank_enabled=%d allow_panel_sso=%d",
__entry->active_vblank_irq_count,
__entry->vblank_enabled,
__entry->allow_panel_sso
)
);
TRACE_EVENT(amdgpu_dm_ism_event,
TP_PROTO(
int crtc_id,
const char *prev_state,
const char *curr_state,
const char *event
),
TP_ARGS(
crtc_id,
prev_state,
curr_state,
event
),
TP_STRUCT__entry(
__field(int, crtc_id)
__string(prev_state, prev_state)
__string(curr_state, curr_state)
__string(event, event)
),
TP_fast_assign(
__entry->crtc_id = crtc_id;
__assign_str(prev_state);
__assign_str(curr_state);
__assign_str(event);
),
TP_printk(
"[CRTC %d] %s -> %s on event %s",
__entry->crtc_id,
__get_str(prev_state),
__get_str(curr_state),
__get_str(event))
);
#endif /* _AMDGPU_DM_TRACE_H_ */
#undef TRACE_INCLUDE_PATH

View File

@ -106,11 +106,9 @@ static int amdgpu_dm_wb_prepare_job(struct drm_writeback_connector *wb_connector
return r;
}
r = dma_resv_reserve_fences(rbo->tbo.base.resv, 1);
if (r) {
drm_err(adev_to_drm(adev), "reserving fence slot failed (%d)\n", r);
r = dma_resv_reserve_fences(rbo->tbo.base.resv, TTM_NUM_MOVE_FENCES);
if (r)
goto error_unlock;
}
domain = amdgpu_display_supported_domains(adev, rbo->flags);

View File

@ -53,11 +53,30 @@ inline void dc_assert_fp_enabled(void)
{
int depth;
depth = __this_cpu_read(fpu_recursion_depth);
depth = this_cpu_read(fpu_recursion_depth);
ASSERT(depth >= 1);
}
/**
* dc_assert_fp_enabled - Check if FPU protection is enabled
*
* This function tells if the code is already under FPU protection or not. A
* function that works as an API for a set of FPU operations can use this
* function for checking if the caller invoked it after DC_FP_START(). For
* example, take a look at dcn20_fpu.c file.
*
* Similar to dc_assert_fp_enabled, but does not assert, returns status instead.
*/
inline bool dc_is_fp_enabled(void)
{
int depth;
depth = this_cpu_read(fpu_recursion_depth);
return (depth >= 1);
}
/**
* dc_fpu_begin - Enables FPU protection
* @function_name: A string containing the function name for debug purposes
@ -77,7 +96,7 @@ void dc_fpu_begin(const char *function_name, const int line)
WARN_ON_ONCE(!in_task());
preempt_disable();
depth = __this_cpu_inc_return(fpu_recursion_depth);
depth = this_cpu_inc_return(fpu_recursion_depth);
if (depth == 1) {
BUG_ON(!kernel_fpu_available());
kernel_fpu_begin();
@ -100,7 +119,7 @@ void dc_fpu_end(const char *function_name, const int line)
{
int depth;
depth = __this_cpu_dec_return(fpu_recursion_depth);
depth = this_cpu_dec_return(fpu_recursion_depth);
if (depth == 0) {
kernel_fpu_end();
} else {

View File

@ -28,15 +28,30 @@
#define __DC_FPU_H__
void dc_assert_fp_enabled(void);
bool dc_is_fp_enabled(void);
void dc_fpu_begin(const char *function_name, const int line);
void dc_fpu_end(const char *function_name, const int line);
#ifndef _LINUX_FPU_COMPILATION_UNIT
#define DC_FP_START() dc_fpu_begin(__func__, __LINE__)
#define DC_FP_END() dc_fpu_end(__func__, __LINE__)
#ifdef CONFIG_DRM_AMD_DC_FP
#define DC_RUN_WITH_PREEMPTION_ENABLED(code) \
do { \
bool dc_fp_enabled = dc_is_fp_enabled(); \
if (dc_fp_enabled) \
DC_FP_END(); \
code; \
if (dc_fp_enabled) \
DC_FP_START(); \
} while (0)
#else
#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
#endif // !CONFIG_DRM_AMD_DC_FP
#else
#define DC_FP_START() BUILD_BUG()
#define DC_FP_END() BUILD_BUG()
#endif
#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
#endif // !_LINUX_FPU_COMPILATION_UNIT
#endif /* __DC_FPU_H__ */

View File

@ -2010,10 +2010,10 @@ static void calculate_bandwidth(
}
/*output link bit per pixel supported*/
for (k = 0; k <= maximum_number_of_surfaces - 1; k++) {
data->output_bpphdmi[k] = bw_def_na;
data->output_bppdp4_lane_hbr[k] = bw_def_na;
data->output_bppdp4_lane_hbr2[k] = bw_def_na;
data->output_bppdp4_lane_hbr3[k] = bw_def_na;
data->output_bpphdmi[k] = (uint32_t)bw_def_na;
data->output_bppdp4_lane_hbr[k] = (uint32_t)bw_def_na;
data->output_bppdp4_lane_hbr2[k] = (uint32_t)bw_def_na;
data->output_bppdp4_lane_hbr3[k] = (uint32_t)bw_def_na;
if (data->enable[k]) {
data->output_bpphdmi[k] = bw_fixed_to_int(bw_mul(bw_div(bw_min2(bw_int_to_fixed(600), data->max_phyclk), data->pixel_rate[k]), bw_int_to_fixed(24)));
if (bw_meq(data->max_phyclk, bw_int_to_fixed(270))) {

View File

@ -503,6 +503,7 @@ struct fixed31_32 dc_fixpt_from_int_dy(unsigned int int_value,
unsigned int integer_bits,
unsigned int fractional_bits)
{
(void)integer_bits;
struct fixed31_32 fixpt_value = dc_fixpt_from_int(int_value);
fixpt_value.value |= (long long)frac_value << (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits);

View File

@ -56,6 +56,7 @@ static bool dal_vector_presized_costruct(struct vector *vector,
void *initial_value,
uint32_t struct_size)
{
(void)ctx;
uint32_t i;
vector->container = NULL;

View File

@ -1963,7 +1963,7 @@ static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
count = (le16_to_cpu(header->sHeader.usStructureSize)
- sizeof(ATOM_COMMON_TABLE_HEADER))
/ sizeof(ATOM_GPIO_I2C_ASSIGMENT);
if (count < record->sucI2cId.bfI2C_LineMux)
if (count <= record->sucI2cId.bfI2C_LineMux)
return BP_RESULT_BADBIOSTABLE;
/* get the GPIO_I2C_INFO */
@ -2696,6 +2696,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb,
struct slot_layout_info *slot_layout_info,
unsigned int record_offset)
{
(void)i;
unsigned int j;
struct bios_parser *bp;
ATOM_BRACKET_LAYOUT_RECORD *record;

View File

@ -205,6 +205,7 @@ static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb,
struct graphics_object_id object_id, uint32_t index,
struct graphics_object_id *src_object_id)
{
(void)index;
struct bios_parser *bp = BP_FROM_DCB(dcb);
unsigned int i;
enum bp_result bp_result = BP_RESULT_BADINPUT;
@ -765,6 +766,7 @@ static enum bp_result bios_parser_get_device_tag(
uint32_t device_tag_index,
struct connector_device_tag_info *info)
{
(void)device_tag_index;
struct bios_parser *bp = BP_FROM_DCB(dcb);
struct atom_display_object_path_v2 *object;
@ -809,6 +811,7 @@ static enum bp_result get_ss_info_v4_1(
uint32_t index,
struct spread_spectrum_info *ss_info)
{
(void)index;
enum bp_result result = BP_RESULT_OK;
struct atom_display_controller_info_v4_1 *disp_cntl_tbl = NULL;
struct atom_smu_info_v3_3 *smu_info = NULL;
@ -897,6 +900,7 @@ static enum bp_result get_ss_info_v4_2(
uint32_t index,
struct spread_spectrum_info *ss_info)
{
(void)index;
enum bp_result result = BP_RESULT_OK;
struct atom_display_controller_info_v4_2 *disp_cntl_tbl = NULL;
struct atom_smu_info_v3_1 *smu_info = NULL;
@ -977,6 +981,7 @@ static enum bp_result get_ss_info_v4_5(
uint32_t index,
struct spread_spectrum_info *ss_info)
{
(void)index;
enum bp_result result = BP_RESULT_OK;
struct atom_display_controller_info_v4_5 *disp_cntl_tbl = NULL;
@ -1604,6 +1609,8 @@ static uint32_t bios_parser_get_ss_entry_number(
struct dc_bios *dcb,
enum as_signal_type signal)
{
(void)dcb;
(void)signal;
/* TODO: DAL2 atomfirmware implementation does not need this.
* why DAL3 need this?
*/
@ -3536,6 +3543,8 @@ static uint16_t bios_parser_pack_data_tables(
struct dc_bios *dcb,
void *dst)
{
(void)dcb;
(void)dst;
// TODO: There is data bytes alignment issue, disable it for now.
return 0;
}

View File

@ -783,6 +783,8 @@ static enum bp_result external_encoder_control_v3(
struct bios_parser *bp,
struct bp_external_encoder_control *cntl)
{
(void)bp;
(void)cntl;
/* TODO */
return BP_RESULT_OK;
}

View File

@ -94,6 +94,7 @@ static uint8_t hpd_sel_to_atom(enum hpd_source_id id)
static uint8_t dig_encoder_sel_to_atom(enum engine_id id)
{
(void)id;
/* On any ASIC after DCE80, we manually program the DIG_FE
* selection (see connect_dig_be_to_fe function of the link
* encoder), so translation should always return 0 (no FE).

View File

@ -93,6 +93,7 @@ static uint8_t hpd_sel_to_atom(enum hpd_source_id id)
static uint8_t dig_encoder_sel_to_atom(enum engine_id id)
{
(void)id;
/* On any ASIC after DCE80, we manually program the DIG_FE
* selection (see connect_dig_be_to_fe function of the link
* encoder), so translation should always return 0 (no FE).

View File

@ -91,6 +91,7 @@ static uint8_t hpd_sel_to_atom(enum hpd_source_id id)
static uint8_t dig_encoder_sel_to_atom(enum engine_id id)
{
(void)id;
/* On any ASIC after DCE80, we manually program the DIG_FE
* selection (see connect_dig_be_to_fe function of the link
* encoder), so translation should always return 0 (no FE).

View File

@ -78,6 +78,7 @@ int clk_mgr_helper_get_active_plane_cnt(
struct dc *dc,
struct dc_state *context)
{
(void)dc;
int i, total_plane_count;
total_plane_count = 0;
@ -97,7 +98,7 @@ void clk_mgr_exit_optimized_pwr_state(const struct dc *dc, struct clk_mgr *clk_m
{
struct dc_link *edp_links[MAX_NUM_EDP];
struct dc_link *edp_link = NULL;
int edp_num;
unsigned int edp_num;
unsigned int panel_inst;
dc_get_edp_links(dc, edp_links, &edp_num);
@ -123,7 +124,7 @@ void clk_mgr_optimize_pwr_state(const struct dc *dc, struct clk_mgr *clk_mgr)
{
struct dc_link *edp_links[MAX_NUM_EDP];
struct dc_link *edp_link = NULL;
int edp_num;
unsigned int edp_num;
unsigned int panel_inst;
dc_get_edp_links(dc, edp_links, &edp_num);

View File

@ -92,7 +92,7 @@ static int determine_sclk_from_bounding_box(
uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context)
{
uint8_t j;
uint32_t min_vertical_blank_time = -1;
uint32_t min_vertical_blank_time = (uint32_t)-1;
for (j = 0; j < context->stream_count; j++) {
struct dc_stream_state *stream = context->streams[j];

View File

@ -740,7 +740,8 @@ void rn_clk_mgr_construct(
if (clk_mgr->base.dentist_vco_freq_khz == 0)
clk_mgr->base.dentist_vco_freq_khz = 3600000;
if (ctx->dc_bios->integrated_info->memory_type == LpDdr4MemType) {
if (ctx->dc_bios->integrated_info &&
ctx->dc_bios->integrated_info->memory_type == LpDdr4MemType) {
if (clk_mgr->periodic_retraining_disabled) {
rn_bw_params.wm_table = lpddr4_wm_table_with_disabled_ppt;
} else {

View File

@ -421,10 +421,8 @@ static void dcn3_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
clk_mgr_base->bw_params->dc_mode_softmax_memclk = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_UCLK);
/* Refresh bounding box */
DC_FP_START();
clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
clk_mgr->base.ctx->dc, clk_mgr_base->bw_params);
DC_FP_END();
}
static bool dcn3_is_smu_present(struct clk_mgr *clk_mgr_base)
@ -523,6 +521,7 @@ void dcn3_clk_mgr_construct(
struct pp_smu_funcs *pp_smu,
struct dccg *dccg)
{
(void)pp_smu;
struct clk_state_registers_and_bypass s = { 0 };
clk_mgr->base.ctx = ctx;

View File

@ -733,11 +733,12 @@ void vg_clk_mgr_construct(
if (clk_mgr->base.base.dentist_vco_freq_khz == 0)
clk_mgr->base.base.dentist_vco_freq_khz = 3600000;
if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
if (ctx->dc_bios->integrated_info &&
ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
vg_bw_params.wm_table = lpddr5_wm_table;
} else {
else
vg_bw_params.wm_table = ddr4_wm_table;
}
/* Saved clocks configured at boot for debug purposes */
vg_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);

View File

@ -329,6 +329,9 @@ bool dcn31_are_clock_states_equal(struct dc_clocks *a,
static void dcn31_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
{
(void)regs_and_bypass;
(void)clk_mgr_base;
(void)log_info;
return;
}
@ -725,11 +728,12 @@ void dcn31_clk_mgr_construct(
/* TODO: Check we get what we expect during bringup */
clk_mgr->base.base.dentist_vco_freq_khz = get_vco_frequency_from_reg(&clk_mgr->base);
if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
if (ctx->dc_bios->integrated_info &&
ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
dcn31_bw_params.wm_table = lpddr5_wm_table;
} else {
else
dcn31_bw_params.wm_table = ddr5_wm_table;
}
/* Saved clocks configured at boot for debug purposes */
dcn31_dump_clk_registers(&clk_mgr->base.base.boot_snapshot,
&clk_mgr->base.base, &log_info);

View File

@ -395,6 +395,9 @@ bool dcn314_are_clock_states_equal(struct dc_clocks *a,
static void dcn314_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
{
(void)regs_and_bypass;
(void)clk_mgr_base;
(void)log_info;
return;
}
@ -842,7 +845,8 @@ void dcn314_clk_mgr_construct(
/* TODO: Check we get what we expect during bringup */
clk_mgr->base.base.dentist_vco_freq_khz = get_vco_frequency_from_reg(&clk_mgr->base);
if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
if (ctx->dc_bios->integrated_info &&
ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
dcn314_bw_params.wm_table = lpddr5_wm_table;
else
dcn314_bw_params.wm_table = ddr5_wm_table;

View File

@ -247,6 +247,9 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
static void dcn315_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
{
(void)regs_and_bypass;
(void)clk_mgr_base;
(void)log_info;
return;
}
@ -652,11 +655,12 @@ void dcn315_clk_mgr_construct(
if (clk_mgr->base.smu_ver > 0)
clk_mgr->base.smu_present = true;
if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
if (ctx->dc_bios->integrated_info &&
ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
dcn315_bw_params.wm_table = lpddr5_wm_table;
} else {
else
dcn315_bw_params.wm_table = ddr5_wm_table;
}
/* Saved clocks configured at boot for debug purposes */
dcn315_dump_clk_registers(&clk_mgr->base.base.boot_snapshot,
&clk_mgr->base.base, &log_info);

View File

@ -255,6 +255,9 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base,
static void dcn316_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
{
(void)regs_and_bypass;
(void)clk_mgr_base;
(void)log_info;
return;
}
@ -636,11 +639,12 @@ void dcn316_clk_mgr_construct(
clk_mgr->base.base.dentist_vco_freq_khz = 2500000; /* 2400MHz */
if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
if (ctx->dc_bios->integrated_info &&
ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
dcn316_bw_params.wm_table = lpddr5_wm_table;
} else {
else
dcn316_bw_params.wm_table = ddr4_wm_table;
}
/* Saved clocks configured at boot for debug purposes */
dcn316_dump_clk_registers(&clk_mgr->base.base.boot_snapshot,
&clk_mgr->base.base, &log_info);

View File

@ -872,6 +872,7 @@ static uint32_t dcn32_get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mg
static void dcn32_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
{
(void)log_info;
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
uint32_t dprefclk_did = 0;
uint32_t dcfclk_did = 0;
@ -1059,11 +1060,9 @@ static void dcn32_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
if (!clk_mgr->dpm_present)
dcn32_patch_dpm_table(clk_mgr_base->bw_params);
DC_FP_START();
/* Refresh bounding box */
clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
clk_mgr->base.ctx->dc, clk_mgr_base->bw_params);
DC_FP_END();
}
static bool dcn32_are_clock_states_equal(struct dc_clocks *a,
@ -1147,6 +1146,7 @@ void dcn32_clk_mgr_construct(
struct pp_smu_funcs *pp_smu,
struct dccg *dccg)
{
(void)pp_smu;
struct clk_log_info log_info = {0};
clk_mgr->base.ctx = ctx;

View File

@ -1464,11 +1464,12 @@ void dcn35_clk_mgr_construct(
/* TODO: Check we get what we expect during bringup */
clk_mgr->base.base.dentist_vco_freq_khz = get_vco_frequency_from_reg(&clk_mgr->base);
if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
if (ctx->dc_bios->integrated_info &&
ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
dcn35_bw_params.wm_table = lpddr5_wm_table;
} else {
else
dcn35_bw_params.wm_table = ddr5_wm_table;
}
/* Saved clocks configured at boot for debug purposes */
dcn35_save_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr);

View File

@ -333,6 +333,7 @@ bool dcn401_is_dc_mode_present(struct clk_mgr *clk_mgr_base)
static void dcn401_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
{
(void)log_info;
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
uint32_t dprefclk_did = 0;
uint32_t dcfclk_did = 0;
@ -525,6 +526,7 @@ static void dcn401_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr
struct dc_state *context,
int ref_dtbclk_khz)
{
(void)ref_dtbclk_khz;
int i;
struct dccg *dccg = clk_mgr->dccg;
struct pipe_ctx *otg_master;
@ -614,6 +616,7 @@ static void dcn401_update_clocks_update_dentist(
struct clk_mgr_internal *clk_mgr,
struct dc_state *context)
{
(void)context;
uint32_t new_disp_divider = 0;
uint32_t new_dispclk_wdivider = 0;
uint32_t dentist_dispclk_wdivider_readback = 0;

View File

@ -43,8 +43,6 @@
#define DC_LOGGER_INIT(logger) \
struct dal_logger *dc_logger = logger
#define DCN42_CLKIP_REFCLK 48000
#undef FN
#define FN(reg_name, field_name) \
clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name
@ -160,6 +158,9 @@ void dcn42_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
struct dc_state *context,
int ref_dtbclk_khz)
{
(void)clk_mgr;
(void)context;
(void)ref_dtbclk_khz;
/* DCN42 does not implement set_dtbclk_dto function, so this is a no-op */
}
@ -255,6 +256,10 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
dcn42_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
/* Only attempt to enable dtbclk if currently disabled AND new state requests it.
* For dcn42b (no dtbclk hardware), init_clk_states sets dtbclk_en=false and
* new_clocks->dtbclk_en should always be false, so this block never executes.
*/
if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) {
int actual_dtbclk = 0;
@ -326,7 +331,7 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
}
/* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */
if (!dc->debug.disable_dtb_ref_clk_switch &&
if (!dc->debug.disable_dtb_ref_clk_switch && new_clocks->dtbclk_en &&
should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000,
clk_mgr_base->clks.ref_dtbclk_khz / 1000)) {
dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
@ -519,7 +524,7 @@ static void init_clk_states(struct clk_mgr *clk_mgr)
clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN;
}
static void dcn42_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
void dcn42_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
struct dcn42_smu_dpm_clks *smu_dpm_clks)
{
DpmClocks_t_dcn42 *table = smu_dpm_clks->dpm_clks;
@ -833,6 +838,7 @@ void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base)
void dcn42_exit_low_power_state(struct clk_mgr *clk_mgr_base)
{
(void)clk_mgr_base;
}
@ -842,7 +848,7 @@ static void dcn42_init_clocks_fpga(struct clk_mgr *clk_mgr)
}
static void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr,
void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr,
struct dc_state *context,
bool safe_to_lower)
{
@ -895,13 +901,13 @@ static void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr,
// Both fclk and ref_dppclk run on the same scemi clock.
clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz;
/* TODO: set dtbclk in correct place */
clk_mgr->clks.dtbclk_en = true;
dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks);
if (clk_mgr->clks.dtbclk_en) {
dcn42_update_clocks_update_dtb_dto(clk_mgr_int, context, clk_mgr->clks.ref_dtbclk_khz);
} else {
clk_mgr->clks.ref_dtbclk_khz = 0;
}
dcn42_update_clocks_update_dpp_dto(clk_mgr_int, context, safe_to_lower);
dcn42_update_clocks_update_dtb_dto(clk_mgr_int, context, clk_mgr->clks.ref_dtbclk_khz);
}
unsigned int dcn42_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_type clk_type)
@ -933,8 +939,9 @@ unsigned int dcn42_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_type
return 0;
}
static int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base)
int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base)
{
(void)clk_mgr_base;
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
uint32_t dispclk_wdivider;
int disp_divider;
@ -954,7 +961,7 @@ bool dcn42_is_smu_present(struct clk_mgr *clk_mgr_base)
return clk_mgr->smu_present;
}
static void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int)
void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int)
{
struct clk_mgr *clk_mgr_base = &clk_mgr_int->base;
struct dcn42_smu_dpm_clks smu_dpm_clks = { 0 };

View File

@ -27,6 +27,7 @@
#include "clk_mgr_internal.h"
#define NUM_CLOCK_SOURCES 5
#define DCN42_CLKIP_REFCLK 48000
struct dcn42_watermarks;
@ -71,9 +72,15 @@ void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base);
void dcn42_exit_low_power_state(struct clk_mgr *clk_mgr_base);
unsigned int dcn42_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_type clk_type);
bool dcn42_is_smu_present(struct clk_mgr *clk_mgr_base);
bool dcn42_has_active_display(struct dc *dc, const struct dc_state *context);
int dcn42_get_active_display_cnt_wa(struct dc *dc, struct dc_state *context, int *all_active_disps);
bool dcn42_has_active_display(struct dc *dc, const struct dc_state *context);
void dcn42_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, struct dc_state *context, bool safe_to_lower);
void dcn42_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr, struct dc_state *context, int ref_dtbclk_khz);
bool dcn42_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base);
bool dcn42_has_active_display(struct dc *dc, const struct dc_state *context);
struct dcn42_smu_dpm_clks; /* Forward declaration for pointer parameter below */
void dcn42_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, struct dcn42_smu_dpm_clks *smu_dpm_clks);
void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int);
void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr, struct dc_state *context, bool safe_to_lower);
int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base);
#endif //__DCN42_CLK_MGR_H__

File diff suppressed because it is too large Load Diff

View File

@ -249,6 +249,7 @@ void color_space_to_black_color(
enum dc_color_space colorspace,
struct tg_color *black_color)
{
(void)dc;
switch (colorspace) {
case COLOR_SPACE_YCBCR601:
case COLOR_SPACE_YCBCR709:

View File

@ -46,7 +46,7 @@ struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_index)
void dc_get_edp_links(const struct dc *dc,
struct dc_link **edp_links,
int *edp_num)
unsigned int *edp_num)
{
int i;
@ -68,7 +68,7 @@ bool dc_get_edp_link_panel_inst(const struct dc *dc,
unsigned int *inst_out)
{
struct dc_link *edp_links[MAX_NUM_EDP];
int edp_num, i;
unsigned int edp_num, i;
*inst_out = 0;
if (link->connector_signal != SIGNAL_TYPE_EDP)

View File

@ -1748,6 +1748,7 @@ enum dc_status resource_build_scaling_params_for_context(
const struct dc *dc,
struct dc_state *context)
{
(void)dc;
int i;
for (i = 0; i < MAX_PIPES; i++) {
@ -1825,6 +1826,7 @@ int resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master(
struct resource_context *new_res_ctx,
const struct pipe_ctx *cur_otg_master)
{
(void)cur_res_ctx;
const struct pipe_ctx *cur_sec_opp_head = cur_otg_master->next_odm_pipe;
struct pipe_ctx *new_pipe;
int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
@ -1846,6 +1848,7 @@ int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
struct resource_context *new_res_ctx,
const struct pipe_ctx *cur_opp_head)
{
(void)cur_res_ctx;
const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe;
struct pipe_ctx *new_pipe;
int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
@ -2941,6 +2944,7 @@ enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ct
const struct resource_pool *pool,
struct dc_stream_state *stream)
{
(void)pool;
struct dc *dc = stream->ctx->dc;
return dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
@ -3023,6 +3027,7 @@ static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe,
struct dc_plane_state *plane_state,
struct dc_state *context)
{
(void)context;
struct pipe_ctx *opp_head_pipe = otg_master_pipe;
while (opp_head_pipe) {
@ -3615,6 +3620,7 @@ static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for
const struct resource_pool *pool,
struct dc_stream_state *stream)
{
(void)stream;
int i;
for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
@ -3634,6 +3640,7 @@ static struct audio *find_first_free_audio(
enum engine_id id,
enum dce_version dc_version)
{
(void)dc_version;
int i, available_audio_count;
if (id == ENGINE_ID_UNKNOWN)
@ -5240,7 +5247,7 @@ unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
return 64;
default:
ASSERT_CRITICAL(false);
return -1;
return UINT_MAX;
}
}
static unsigned int get_max_audio_sample_rate(struct audio_mode *modes)

View File

@ -205,19 +205,33 @@ struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *p
state->power_source = params ? params->power_source : DC_POWER_SOURCE_AC;
#ifdef CONFIG_DRM_AMD_DC_FP
bool status;
if (dc->debug.using_dml2) {
if (!dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2)) {
DC_FP_START();
status = dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2);
DC_FP_END();
if (!status) {
dc_state_release(state);
return NULL;
}
if (dc->caps.dcmode_power_limits_present && !dml2_create(dc, &dc->dml2_dc_power_options, &state->bw_ctx.dml2_dc_power_source)) {
dc_state_release(state);
return NULL;
if (dc->caps.dcmode_power_limits_present) {
bool status;
DC_FP_START();
status = dml2_create(dc, &dc->dml2_dc_power_options, &state->bw_ctx.dml2_dc_power_source);
DC_FP_END();
if (!status) {
dc_state_release(state);
return NULL;
}
}
}
#endif
#endif // CONFIG_DRM_AMD_DC_FP
kref_init(&state->refcount);
return state;
@ -235,14 +249,20 @@ void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state)
#ifdef CONFIG_DRM_AMD_DC_FP
dst_state->bw_ctx.dml2 = dst_dml2;
if (src_state->bw_ctx.dml2)
if (src_state->bw_ctx.dml2) {
DC_FP_START();
dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2);
DC_FP_END();
}
dst_state->bw_ctx.dml2_dc_power_source = dst_dml2_dc_power_source;
if (src_state->bw_ctx.dml2_dc_power_source)
dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source);
#endif
if (src_state->bw_ctx.dml2_dc_power_source) {
DC_FP_START();
dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source);
DC_FP_END();
}
#endif // CONFIG_DRM_AMD_DC_FP
/* context refcount should not be overridden */
dst_state->refcount = refcount;
}
@ -258,22 +278,35 @@ struct dc_state *dc_state_create_copy(struct dc_state *src_state)
dc_state_copy_internal(new_state, src_state);
#ifdef CONFIG_DRM_AMD_DC_FP
bool status;
new_state->bw_ctx.dml2 = NULL;
new_state->bw_ctx.dml2_dc_power_source = NULL;
if (src_state->bw_ctx.dml2 &&
!dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) {
dc_state_release(new_state);
return NULL;
if (src_state->bw_ctx.dml2) {
DC_FP_START();
status = dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2);
DC_FP_END();
if (!status) {
dc_state_release(new_state);
return NULL;
}
}
if (src_state->bw_ctx.dml2_dc_power_source &&
!dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) {
dc_state_release(new_state);
return NULL;
}
#endif
if (src_state->bw_ctx.dml2_dc_power_source) {
DC_FP_START();
status = dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source,
src_state->bw_ctx.dml2_dc_power_source);
DC_FP_END();
if (!status) {
dc_state_release(new_state);
return NULL;
}
}
#endif // CONFIG_DRM_AMD_DC_FP
kref_init(&new_state->refcount);
return new_state;
@ -351,11 +384,13 @@ static void dc_state_free(struct kref *kref)
dc_state_destruct(state);
#ifdef CONFIG_DRM_AMD_DC_FP
DC_FP_START();
dml2_destroy(state->bw_ctx.dml2);
state->bw_ctx.dml2 = 0;
dml2_destroy(state->bw_ctx.dml2_dc_power_source);
state->bw_ctx.dml2_dc_power_source = 0;
DC_FP_END();
#endif
kvfree(state);
@ -374,6 +409,7 @@ enum dc_status dc_state_add_stream(
struct dc_state *state,
struct dc_stream_state *stream)
{
(void)dc;
enum dc_status res;
DC_LOGGER_INIT(dc->ctx->logger);
@ -749,6 +785,7 @@ struct dc_plane_state *dc_state_create_phantom_plane(const struct dc *dc,
struct dc_state *state,
struct dc_plane_state *main_plane)
{
(void)main_plane;
struct dc_plane_state *phantom_plane = dc_create_plane_state(dc);
DC_LOGGER_INIT(dc->ctx->logger);

View File

@ -42,6 +42,13 @@
#define MAX(x, y) ((x > y) ? x : y)
#endif
#include "dc_fpu.h"
#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
#endif // !DC_RUN_WITH_PREEMPTION_ENABLED
/*******************************************************************************
* Private functions
******************************************************************************/
@ -170,12 +177,14 @@ struct dc_stream_state *dc_create_stream_for_sink(
if (sink == NULL)
goto fail;
stream = kzalloc_obj(struct dc_stream_state, GFP_ATOMIC);
DC_RUN_WITH_PREEMPTION_ENABLED(stream = kzalloc_obj(struct dc_stream_state, GFP_ATOMIC));
if (stream == NULL)
goto fail;
stream->update_scratch = kzalloc((int32_t) dc_update_scratch_space_size(), GFP_ATOMIC);
DC_RUN_WITH_PREEMPTION_ENABLED(stream->update_scratch =
kzalloc((int32_t) dc_update_scratch_space_size(),
GFP_ATOMIC));
if (stream->update_scratch == NULL)
goto fail;

View File

@ -57,6 +57,7 @@ void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *plane_sta
void dc_plane_destruct(struct dc_plane_state *plane_state)
{
(void)plane_state;
// no more pointers to free within dc_plane_state
}

View File

@ -63,7 +63,7 @@ struct dcn_dsc_reg_state;
struct dcn_optc_reg_state;
struct dcn_dccg_reg_state;
#define DC_VER "3.2.375"
#define DC_VER "3.2.376"
/**
* MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
@ -467,7 +467,6 @@ struct dc_static_screen_params {
*/
enum surface_update_type {
UPDATE_TYPE_ADDR_ONLY, /* only surface address is being updated, no other programming needed */
UPDATE_TYPE_FAST, /* super fast, safe to execute in isr */
UPDATE_TYPE_MED, /* ISR safe, most of programming needed, no bw/clk change*/
UPDATE_TYPE_FULL, /* may need to shuffle resources */
@ -521,7 +520,7 @@ struct dc_config {
union allow_lttpr_non_transparent_mode allow_lttpr_non_transparent_mode;
bool multi_mon_pp_mclk_switch;
bool disable_dmcu;
bool enable_4to1MPC;
bool allow_4to1MPC;
bool enable_windowed_mpo_odm;
bool forceHBR2CP2520; // Used for switching between test patterns TPS4 and CP2520
uint32_t allow_edp_hotplug_detection;
@ -563,7 +562,6 @@ struct dc_config {
bool frame_update_cmd_version2;
struct spl_sharpness_range dcn_sharpness_range;
struct spl_sharpness_range dcn_override_sharpness_range;
bool no_native422_support;
};
enum visual_confirm {
@ -988,6 +986,7 @@ struct link_service;
* causing an issue or not.
*/
struct dc_debug_options {
bool native422_support;
bool disable_dsc;
enum visual_confirm visual_confirm;
int visual_confirm_rect_height;
@ -1881,6 +1880,20 @@ struct dc_scaling_info {
struct scaling_taps scaling_quality;
};
struct dc_fast_update {
const struct dc_flip_addrs *flip_addr;
const struct dc_gamma *gamma;
const struct colorspace_transform *gamut_remap_matrix;
const struct dc_csc_transform *input_csc_color_matrix;
const struct fixed31_32 *coeff_reduction_factor;
struct dc_transfer_func *out_transfer_func;
struct dc_csc_transform *output_csc_transform;
const struct dc_csc_transform *cursor_csc_color_matrix;
#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
struct cm_hist_control *cm_hist_control;
#endif
};
struct dc_surface_update {
struct dc_plane_state *surface;
@ -2019,7 +2032,12 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc);
void get_audio_check(struct audio_info *aud_modes,
struct audio_check *aud_chk);
/*
bool fast_nonaddr_updates_exist(struct dc_fast_update *fast_update, int surface_count);
void populate_fast_updates(struct dc_fast_update *fast_update,
struct dc_surface_update *srf_updates,
int surface_count,
struct dc_stream_update *stream_update);
/*
* Set up streams and links associated to drive sinks
* The streams parameter is an absolute set of all active streams.
*
@ -2062,7 +2080,7 @@ bool dc_get_edp_link_panel_inst(const struct dc *dc,
/* Return an array of link pointers to edp links. */
void dc_get_edp_links(const struct dc *dc,
struct dc_link **edp_links,
int *edp_num);
unsigned int *edp_num);
void dc_set_edp_power(const struct dc *dc, struct dc_link *edp_link,
bool powerOn);

View File

@ -958,7 +958,10 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
{
uint32_t i;
if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
if (!dc_dmub_srv)
return;
if (!dc_dmub_srv->dmub) {
DC_LOG_ERROR("%s: invalid parameters.", __func__);
return;
}
@ -1082,6 +1085,7 @@ static void dc_build_cursor_attribute_update_payload1(
struct dmub_cursor_attributes_cfg *pl_A, const uint8_t p_idx,
const struct hubp *hubp, const struct dpp *dpp)
{
(void)p_idx;
/* Hubp */
pl_A->aHubp.SURFACE_ADDR_HIGH = hubp->att.SURFACE_ADDR_HIGH;
pl_A->aHubp.SURFACE_ADDR = hubp->att.SURFACE_ADDR;
@ -1163,7 +1167,10 @@ void dc_dmub_srv_enable_dpia_trace(const struct dc *dc)
{
struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
if (!dc_dmub_srv)
return;
if (!dc_dmub_srv->dmub) {
DC_LOG_ERROR("%s: invalid parameters.", __func__);
return;
}

View File

@ -52,7 +52,6 @@ struct dc_dsc_policy {
uint32_t max_target_bpp;
uint32_t min_target_bpp;
bool enable_dsc_when_not_needed;
bool ycbcr422_simple;
};
struct dc_dsc_config_options {

View File

@ -108,6 +108,7 @@ static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask,
uint8_t shift1, uint32_t mask1, uint32_t field_value1,
va_list ap)
{
(void)addr;
uint32_t shift, mask, field_value;
int i = 1;

View File

@ -165,6 +165,7 @@ void dccg31_set_dpstreamclk(
int otg_inst,
int dp_hpo_inst)
{
(void)dp_hpo_inst;
if (src == REFCLK)
dccg31_disable_dpstreamclk(dccg, otg_inst);
else
@ -644,6 +645,7 @@ void dccg31_get_dccg_ref_freq(struct dccg *dccg,
unsigned int xtalin_freq_inKhz,
unsigned int *dccg_ref_freq_inKhz)
{
(void)dccg;
/*
* Assume refclk is sourced from xtalin
* expect 24MHz

View File

@ -265,6 +265,7 @@ static void dccg32_get_dccg_ref_freq(struct dccg *dccg,
unsigned int xtalin_freq_inKhz,
unsigned int *dccg_ref_freq_inKhz)
{
(void)dccg;
/*
* Assume refclk is sourced from xtalin
* expect 100MHz

View File

@ -558,6 +558,7 @@ static void dccg35_set_symclk32_se_src_new(
static int
dccg35_is_symclk32_se_src_functional_le_new(struct dccg *dccg, int symclk_32_se_inst, int symclk_32_le_inst)
{
(void)symclk_32_se_inst;
uint32_t en;
uint32_t src_sel;
@ -2373,6 +2374,7 @@ static void dccg35_disable_symclk_se_cb(
uint32_t stream_enc_inst,
uint32_t link_enc_inst)
{
(void)link_enc_inst;
dccg35_disable_symclk_fe_new(dccg, stream_enc_inst);
/* DMU PHY sequence switches SYMCLK_BE (link_enc_inst) to ref clock once PHY is turned off */

View File

@ -161,6 +161,7 @@ void dccg401_set_pixel_rate_div(
enum pixel_rate_div tmds_div,
enum pixel_rate_div unused)
{
(void)unused;
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
uint32_t dp_dto_int;
@ -353,6 +354,7 @@ void dccg401_get_dccg_ref_freq(struct dccg *dccg,
unsigned int xtalin_freq_inKhz,
unsigned int *dccg_ref_freq_inKhz)
{
(void)dccg;
/*
* Assume refclk is sourced from xtalin
* expect 100MHz
@ -526,10 +528,6 @@ static void dccg401_enable_dpstreamclk(struct dccg *dccg, int otg_inst, int dp_h
BREAK_TO_DEBUGGER();
return;
}
if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)
REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
DPSTREAMCLK_GATE_DISABLE, 1,
DPSTREAMCLK_ROOT_GATE_DISABLE, 1);
}
void dccg401_disable_dpstreamclk(struct dccg *dccg, int dp_hpo_inst)
@ -725,6 +723,7 @@ void dccg401_init(struct dccg *dccg)
void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst, uint32_t num_slices_h)
{
(void)num_slices_h;
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
switch (inst) {
@ -842,6 +841,7 @@ void dccg401_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint3
void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)
{
(void)link_enc_inst;
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
switch (stream_enc_inst) {

View File

@ -186,6 +186,7 @@ void dccg42_set_pixel_rate_div(
enum pixel_rate_div tmds_div,
enum pixel_rate_div unused)
{
(void)unused;
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
uint32_t dp_dto_int;

View File

@ -57,6 +57,7 @@
static bool dce_abm_set_pipe(struct abm *abm, uint32_t controller_id, uint32_t panel_inst)
{
(void)panel_inst;
struct dce_abm *abm_dce = TO_DCE_ABM(abm);
uint32_t rampingBoundary = 0xFFFF;

View File

@ -350,6 +350,7 @@ static uint32_t calculate_required_audio_bw_in_symbols(
uint32_t av_stream_map_lane_count,
uint32_t audio_sdp_overhead)
{
(void)channel_count;
/* DP spec recommends between 1.05 to 1.1 safety margin to prevent sample under-run */
struct fixed31_32 audio_sdp_margin = dc_fixpt_from_fraction(110, 100);
struct fixed31_32 horizontal_line_freq_khz = dc_fixpt_from_fraction(
@ -1027,6 +1028,7 @@ static void get_azalia_clock_info_hdmi(
uint32_t actual_pixel_clock_100Hz,
struct azalia_clock_info *azalia_clock_info)
{
(void)crtc_pixel_clock_100hz;
/* audio_dto_phase= 24 * 10,000;
* 24MHz in [100Hz] units */
azalia_clock_info->audio_dto_phase =
@ -1043,6 +1045,7 @@ static void get_azalia_clock_info_dp(
const struct audio_pll_info *pll_info,
struct azalia_clock_info *azalia_clock_info)
{
(void)requested_pixel_clock_100Hz;
/* Reported dpDtoSourceClockInkhz value for
* DCE8 already adjusted for SS, do not need any
* adjustment here anymore

View File

@ -539,6 +539,7 @@ static void dce112_get_pix_clk_dividers_helper (
struct pll_settings *pll_settings,
struct pixel_clk_params *pix_clk_params)
{
(void)clk_src;
uint32_t actual_pixel_clock_100hz;
actual_pixel_clock_100hz = pix_clk_params->requested_pix_clk_100hz;
@ -610,7 +611,7 @@ static uint32_t dce112_get_pix_clk_dividers(
|| pix_clk_params->requested_pix_clk_100hz == 0) {
DC_LOG_ERROR(
"%s: Invalid parameters!!\n", __func__);
return -1;
return (uint32_t)-1;
}
memset(pll_settings, 0, sizeof(*pll_settings));
@ -621,7 +622,7 @@ static uint32_t dce112_get_pix_clk_dividers(
pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
pll_settings->actual_pix_clk_100hz =
pix_clk_params->requested_pix_clk_100hz;
return -1;
return (uint32_t)-1;
}
dce112_get_pix_clk_dividers_helper(clk_src,
@ -847,6 +848,7 @@ static bool dce110_program_pix_clk(
enum dp_link_encoding encoding,
struct pll_settings *pll_settings)
{
(void)encoding;
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
struct bp_pixel_clock_parameters bp_pc_params = {0};
@ -921,6 +923,7 @@ static bool dce112_program_pix_clk(
enum dp_link_encoding encoding,
struct pll_settings *pll_settings)
{
(void)encoding;
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
struct bp_pixel_clock_parameters bp_pc_params = {0};
@ -1070,6 +1073,7 @@ static bool dcn401_program_pix_clk(
enum dp_link_encoding encoding,
struct pll_settings *pll_settings)
{
(void)encoding;
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
const struct pixel_rate_range_table_entry *e =
@ -1376,7 +1380,7 @@ static uint32_t dcn3_get_pix_clk_dividers(
|| pix_clk_params->requested_pix_clk_100hz == 0) {
DC_LOG_ERROR(
"%s: Invalid parameters!!\n", __func__);
return -1;
return UINT_MAX;
}
memset(pll_settings, 0, sizeof(*pll_settings));

View File

@ -71,6 +71,7 @@ static const uint32_t abm_gain_stepsize = 0x0060;
static bool dce_dmcu_init(struct dmcu *dmcu)
{
(void)dmcu;
// Do nothing
return true;
}

View File

@ -31,6 +31,7 @@ bool dce_i2c_oem_device_present(
size_t slave_address
)
{
(void)pool;
struct dc *dc = ddc->ctx->dc;
struct dc_bios *dcb = dc->ctx->dc_bios;
struct graphics_object_id id = {0};

View File

@ -69,6 +69,7 @@ static enum i2c_channel_operation_result get_channel_status(
struct dce_i2c_hw *dce_i2c_hw,
uint8_t *returned_bytes)
{
(void)returned_bytes;
uint32_t i2c_sw_status = 0;
uint32_t value =
REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
@ -631,6 +632,7 @@ bool dce_i2c_submit_command_hw(
struct i2c_command *cmd,
struct dce_i2c_hw *dce_i2c_hw)
{
(void)ddc;
uint8_t index_of_payload = 0;
bool result;

View File

@ -67,6 +67,7 @@ static void release_engine_dce_sw(
struct resource_pool *pool,
struct dce_i2c_sw *dce_i2c_sw)
{
(void)pool;
dal_ddc_close(dce_i2c_sw->ddc);
dce_i2c_sw->ddc = NULL;
}
@ -76,6 +77,7 @@ static bool wait_for_scl_high_sw(
struct ddc *ddc,
uint16_t clock_delay_div_4)
{
(void)ctx;
uint32_t scl_retry = 0;
uint32_t scl_retry_max = I2C_SW_TIMEOUT_DELAY / clock_delay_div_4;
@ -469,6 +471,7 @@ bool dce_i2c_submit_command_sw(
struct i2c_command *cmd,
struct dce_i2c_sw *dce_i2c_sw)
{
(void)ddc;
uint8_t index_of_payload = 0;
bool result;

View File

@ -43,6 +43,7 @@ static void dce_ipp_cursor_set_position(
const struct dc_cursor_position *position,
const struct dc_cursor_mi_param *param)
{
(void)param;
struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
/* lock cursor registers */

View File

@ -847,6 +847,7 @@ bool dce110_link_encoder_validate_dp_output(
const struct dce110_link_encoder *enc110,
const struct dc_crtc_timing *crtc_timing)
{
(void)enc110;
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
return false;

View File

@ -317,6 +317,7 @@ static void dce_mi_program_display_marks(
struct dce_watermarks urgent,
uint32_t total_dest_line_time_ns)
{
(void)stutter_enter;
struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
uint32_t stutter_en = mi->ctx->dc->debug.disable_stutter ? 0 : 1;
@ -370,6 +371,7 @@ static void dce112_mi_program_display_marks(struct mem_input *mi,
struct dce_watermarks urgent,
uint32_t total_dest_line_time_ns)
{
(void)stutter_entry;
struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
uint32_t stutter_en = mi->ctx->dc->debug.disable_stutter ? 0 : 1;
@ -656,6 +658,8 @@ static void dce_mi_program_surface_config(
struct dc_plane_dcc_param *dcc,
bool horizontal_mirror)
{
(void)dcc;
(void)horizontal_mirror;
struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
REG_UPDATE(GRPH_ENABLE, GRPH_ENABLE, 1);

View File

@ -600,6 +600,7 @@ void dce110_opp_set_dyn_expansion(
enum dc_color_depth color_dpth,
enum signal_type signal)
{
(void)color_sp;
struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,

View File

@ -271,6 +271,8 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
bool use_vsc_sdp_for_colorimetry,
uint32_t enable_sdp_splitting)
{
(void)use_vsc_sdp_for_colorimetry;
(void)enable_sdp_splitting;
uint32_t h_active_start;
uint32_t v_active_start;
uint32_t misc0 = 0;
@ -901,6 +903,7 @@ static void dce110_stream_encoder_dp_blank(
struct dc_link *link,
struct stream_encoder *enc)
{
(void)link;
struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
uint32_t reg1 = 0;
uint32_t max_retries = DP_BLANK_MAX_RETRY * 10;
@ -951,6 +954,7 @@ static void dce110_stream_encoder_dp_unblank(
struct stream_encoder *enc,
const struct encoder_unblank_param *param)
{
(void)link;
struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) {

View File

@ -282,6 +282,7 @@ static void calculate_inits(
const struct scaler_data *data,
struct scl_ratios_inits *inits)
{
(void)xfm_dce;
struct fixed31_32 h_init;
struct fixed31_32 v_init;
@ -1240,6 +1241,7 @@ static void program_color_matrix(
const struct out_csc_color_matrix *tbl_entry,
enum grph_color_adjust_option options)
{
(void)options;
{
REG_SET_2(OUTPUT_CSC_C11_C12, 0,
OUTPUT_CSC_C11, tbl_entry->regval[0],

View File

@ -41,8 +41,7 @@ static unsigned int abm_feature_support(struct abm *abm, unsigned int panel_inst
{
struct dc_context *dc = abm->ctx;
struct dc_link *edp_links[MAX_NUM_EDP];
int i;
int edp_num;
unsigned int i, edp_num;
unsigned int ret = ABM_FEATURE_NO_SUPPORT;
dc_get_edp_links(dc->dc, edp_links, &edp_num);
@ -174,6 +173,7 @@ static bool dmub_abm_set_backlight_level_pwm_ex(struct abm *abm,
unsigned int controller_id,
unsigned int panel_inst)
{
(void)controller_id;
bool ret = false;
unsigned int feature_support;

View File

@ -188,6 +188,7 @@ void dmub_abm_init_config(struct abm *abm,
bool dmub_abm_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int stream_inst)
{
(void)stream_inst;
union dmub_rb_cmd cmd;
struct dc_context *dc = abm->ctx;
uint8_t panel_mask = 0x01 << panel_inst;

Some files were not shown because too many files have changed in this diff Show More