diff options
| author | Rodrigo Vivi <rodrigo.vivi@intel.com> | 2026-04-08 15:56:19 -0400 |
|---|---|---|
| committer | Rodrigo Vivi <rodrigo.vivi@intel.com> | 2026-04-08 15:56:19 -0400 |
| commit | af35e741e2f2dbef75500921e8fce17cf4f08fbd (patch) | |
| tree | 155265a00862346154abd483cb51b3aab270b5c6 /drivers/gpu | |
| parent | 5150b57dacf9563ab29661c8e8a37a73f5a9fc54 (diff) | |
| parent | 4516432284e1b2ad9e70de8067f779c9c1072189 (diff) | |
Merge drm/drm-next into drm-xe-next
Sync drm-xe-next with drm-next to unblock some topic branches.
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Diffstat (limited to 'drivers/gpu')
811 files changed, 25662 insertions, 10657 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 5386248e75b6..8f5a8d3012e4 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -268,6 +268,13 @@ config DRM_GEM_SHMEM_HELPER help Choose this if you need the GEM shmem helper functions +config RUST_DRM_GEM_SHMEM_HELPER + bool + depends on DRM && MMU + select DRM_GEM_SHMEM_HELPER + help + Choose this if you need the GEM shmem helper functions In Rust + config DRM_SUBALLOC_HELPER tristate depends on DRM diff --git a/drivers/gpu/drm/Kconfig.debug b/drivers/gpu/drm/Kconfig.debug index 3b7886865335..1f4c98cbf090 100644 --- a/drivers/gpu/drm/Kconfig.debug +++ b/drivers/gpu/drm/Kconfig.debug @@ -85,7 +85,6 @@ config DRM_KUNIT_TEST config DRM_TTM_KUNIT_TEST tristate "KUnit tests for TTM" if !KUNIT_ALL_TESTS - default n depends on DRM && KUNIT && MMU && (UML || COMPILE_TEST) select DRM_TTM select DRM_BUDDY diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 9c9c73b73ac8..6a7e9bfec59e 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -213,6 +213,7 @@ amdgpu-y += \ vcn_v4_0_5.o \ vcn_v5_0_0.o \ vcn_v5_0_1.o \ + vcn_v5_0_2.o \ amdgpu_jpeg.o \ jpeg_v1_0.o \ jpeg_v2_0.o \ @@ -223,6 +224,7 @@ amdgpu-y += \ jpeg_v4_0_5.o \ jpeg_v5_0_0.o \ jpeg_v5_0_1.o \ + jpeg_v5_0_2.o \ jpeg_v5_3_0.o # add VPE block diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 59731014a55a..49e7881750fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -327,6 +327,7 @@ struct kfd_vm_fault_info; struct amdgpu_hive_info; struct amdgpu_reset_context; struct amdgpu_reset_control; +struct amdgpu_coredump_info; enum amdgpu_cp_irq { AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP = 0, @@ -689,6 +690,7 @@ enum amdgpu_uid_type { AMDGPU_UID_TYPE_XCD, AMDGPU_UID_TYPE_AID, AMDGPU_UID_TYPE_SOC, + AMDGPU_UID_TYPE_MID, AMDGPU_UID_TYPE_MAX }; @@ -1147,6 +1149,11 @@ struct amdgpu_device { struct amdgpu_reset_domain *reset_domain; +#ifdef CONFIG_DEV_COREDUMP + struct amdgpu_coredump_info *coredump; + struct work_struct coredump_work; +#endif + struct mutex benchmark_mutex; bool scpm_enabled; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 40c22438b1d2..4f27c75abedb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -692,9 +692,9 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev, goto err_ib_sched; } - /* Drop the initial kref_init count (see drm_sched_main as example) */ - dma_fence_put(f); ret = dma_fence_wait(f, false); + /* Drop the returned fence reference after the wait completes */ + dma_fence_put(f); err_ib_sched: amdgpu_job_free(job); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c index 965c7e688535..bcb180f9d3ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c @@ -330,7 +330,7 @@ static uint32_t kgd_gfx_v12_1_set_address_watch(struct amdgpu_device *adev, watch_address_cntl = 0; watch_address_low = lower_32_bits(watch_address); - watch_address_high = upper_32_bits(watch_address) & 0xffff; + watch_address_high = upper_32_bits(watch_address) & 0x1ffffff; watch_address_cntl = REG_SET_FIELD(watch_address_cntl, TCP_WATCH0_CNTL, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c index 7f4751e5caaf..cd9aa5b45e94 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c @@ -373,249 +373,280 @@ 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, i = 0; + int index; 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; - u8 mem_vendor; u32 mem_channel_number; 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, + 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); + 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: - index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, vram_info); + 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)) { - 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; - } - 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; - } + 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 { - 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; + 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 vram_info *vram_info; + union vram_module *vram_module; + u8 frev, crev; + u8 mem_type; + u8 mem_vendor; + u32 mem_channel_number; + u32 mem_channel_width; + u32 module_id; + + 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)) { + 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: - 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; + 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; } + + } else { + return -EINVAL; } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h index 67c8d105729b..0760e4510513 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h @@ -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, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 4662bfbe70b2..43864df8af04 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -36,6 +36,7 @@ #define AMDGPU_BO_LIST_MAX_PRIORITY 32u #define AMDGPU_BO_LIST_NUM_BUCKETS (AMDGPU_BO_LIST_MAX_PRIORITY + 1) +#define AMDGPU_BO_LIST_MAX_ENTRIES (128 * 1024) static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu) { @@ -188,6 +189,9 @@ int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, const uint32_t bo_number = in->bo_number; struct drm_amdgpu_bo_list_entry *info; + if (bo_number > AMDGPU_BO_LIST_MAX_ENTRIES) + return -EINVAL; + /* copy the handle array from userspace to a kernel buffer */ if (likely(info_size == bo_info_size)) { info = vmemdup_array_user(uptr, bo_number, info_size); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index aabe9d58c3dc..b04fa9fd90b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -1231,6 +1231,8 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector case CONNECTOR_OBJECT_ID_HDMI_TYPE_B: max_digital_pixel_clock_khz = max_dvi_single_link_pixel_clock * 2; break; + default: + return MODE_BAD; } /* When the display EDID claims that it's an HDMI display, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 70ea9b0831a0..b24d5d21be5f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -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; @@ -1740,6 +1739,13 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, struct drm_amdgpu_fence *fences; int r; + /* + * fence_count must be non-zero; dma_fence_wait_any_timeout() + * does not accept an empty fence array. + */ + if (!wait->in.fence_count) + return -EINVAL; + /* Get the fences from userspace */ fences = memdup_array_user(u64_to_user_ptr(wait->in.fences), wait->in.fence_count, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index aa9239b310a3..092fd3309099 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -618,6 +618,110 @@ out: } /** + * amdgpu_debugfs_regs_pcie64_read - Read from a 64-bit PCIE register + * + * @f: open file handle + * @buf: User buffer to store read data in + * @size: Number of bytes to read + * @pos: Offset to seek to + */ +static ssize_t amdgpu_debugfs_regs_pcie64_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = file_inode(f)->i_private; + ssize_t result = 0; + int r; + + if (size & 0x7 || *pos & 0x7) + return -EINVAL; + + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); + if (r < 0) { + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + return r; + } + + r = amdgpu_virt_enable_access_debugfs(adev); + if (r < 0) { + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + return r; + } + + while (size) { + uint64_t value; + + value = RREG64_PCIE_EXT(*pos); + + r = put_user(value, (uint64_t *)buf); + if (r) + goto out; + + result += 8; + buf += 8; + *pos += 8; + size -= 8; + } + + r = result; +out: + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_virt_disable_access_debugfs(adev); + return r; +} + +/** + * amdgpu_debugfs_regs_pcie64_write - Write to a 64-bit PCIE register + * + * @f: open file handle + * @buf: User buffer to write data from + * @size: Number of bytes to write + * @pos: Offset to seek to + */ +static ssize_t amdgpu_debugfs_regs_pcie64_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = file_inode(f)->i_private; + ssize_t result = 0; + int r; + + if (size & 0x7 || *pos & 0x7) + return -EINVAL; + + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); + if (r < 0) { + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + return r; + } + + r = amdgpu_virt_enable_access_debugfs(adev); + if (r < 0) { + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + return r; + } + + while (size) { + uint64_t value; + + r = get_user(value, (uint64_t *)buf); + if (r) + goto out; + + WREG64_PCIE_EXT(*pos, value); + + result += 8; + buf += 8; + *pos += 8; + size -= 8; + } + + r = result; +out: + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_virt_disable_access_debugfs(adev); + return r; +} + +/** * amdgpu_debugfs_regs_didt_read - Read from a DIDT register * * @f: open file handle @@ -1525,6 +1629,12 @@ static const struct file_operations amdgpu_debugfs_regs_pcie_fops = { .write = amdgpu_debugfs_regs_pcie_write, .llseek = default_llseek }; +static const struct file_operations amdgpu_debugfs_regs_pcie64_fops = { + .owner = THIS_MODULE, + .read = amdgpu_debugfs_regs_pcie64_read, + .write = amdgpu_debugfs_regs_pcie64_write, + .llseek = default_llseek +}; static const struct file_operations amdgpu_debugfs_regs_smc_fops = { .owner = THIS_MODULE, .read = amdgpu_debugfs_regs_smc_read, @@ -1587,6 +1697,7 @@ static const struct file_operations *debugfs_regs[] = { &amdgpu_debugfs_gprwave_fops, &amdgpu_debugfs_regs_didt_fops, &amdgpu_debugfs_regs_pcie_fops, + &amdgpu_debugfs_regs_pcie64_fops, &amdgpu_debugfs_regs_smc_fops, &amdgpu_debugfs_gca_config_fops, &amdgpu_debugfs_sensors_fops, @@ -1604,6 +1715,7 @@ static const char * const debugfs_regs_names[] = { "amdgpu_gprwave", "amdgpu_regs_didt", "amdgpu_regs_pcie", + "amdgpu_regs_pcie64", "amdgpu_regs_smc", "amdgpu_gca_config", "amdgpu_sensors", diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index 160f0704d1d3..fddf4e1252bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -32,8 +32,16 @@ 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) +{ +} #else +#define AMDGPU_CORE_DUMP_SIZE_MAX (256 * 1024 * 1024) + const char *hw_ip_names[MAX_HWIP] = { [GC_HWIP] = "GC", [HDP_HWIP] = "HDP", @@ -187,20 +195,22 @@ 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 -amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count, - void *data, size_t datalen) +amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_info *coredump) { struct drm_printer p; - struct amdgpu_coredump_info *coredump = data; struct drm_print_iterator iter; struct amdgpu_vm_fault_info *fault_info; struct amdgpu_ip_block *ip_block; @@ -208,7 +218,6 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count, iter.data = buffer; iter.offset = 0; - iter.start = offset; iter.remain = count; p = drm_coredump_printer(&iter); @@ -322,9 +331,63 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count, return count - iter.remain; } +static ssize_t +amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count, + void *data, size_t datalen) +{ + struct amdgpu_coredump_info *coredump = data; + ssize_t byte_copied; + + if (!coredump) + return -ENODEV; + + if (!coredump->formatted) + return -ENODEV; + + if (offset >= coredump->formatted_size) + return 0; + + byte_copied = count < coredump->formatted_size - offset ? count : + coredump->formatted_size - offset; + memcpy(buffer, coredump->formatted + offset, byte_copied); + + return byte_copied; +} + static void amdgpu_devcoredump_free(void *data) { - kfree(data); + struct amdgpu_coredump_info *coredump = data; + + kvfree(coredump->formatted); + kvfree(data); +} + +static void amdgpu_devcoredump_deferred_work(struct work_struct *work) +{ + struct amdgpu_device *adev = container_of(work, typeof(*adev), coredump_work); + struct amdgpu_coredump_info *coredump = adev->coredump; + + /* Do a one-time preparation of the coredump output because + * repeatingly calling drm_coredump_printer is very slow. + */ + coredump->formatted_size = amdgpu_devcoredump_format( + NULL, AMDGPU_CORE_DUMP_SIZE_MAX, coredump); + coredump->formatted = kvzalloc(coredump->formatted_size, GFP_KERNEL); + if (!coredump->formatted) { + amdgpu_devcoredump_free(coredump); + goto end; + } + + amdgpu_devcoredump_format(coredump->formatted, coredump->formatted_size, coredump); + + /* If there's an existing coredump for this device, the free function will be + * called immediately so coredump might be invalid after the call to dev_coredumpm. + */ + dev_coredumpm(coredump->adev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT, + amdgpu_devcoredump_read, amdgpu_devcoredump_free); + +end: + adev->coredump = NULL; } void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, @@ -334,6 +397,10 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, struct amdgpu_coredump_info *coredump; struct drm_sched_job *s_job; + /* No need to generate a new coredump if there's one in progress already. */ + if (work_pending(&adev->coredump_work)) + return; + coredump = kzalloc_obj(*coredump, GFP_NOWAIT); if (!coredump) return; @@ -360,11 +427,26 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, ktime_get_ts64(&coredump->reset_time); - dev_coredumpm(dev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT, - amdgpu_devcoredump_read, amdgpu_devcoredump_free); + /* Update the current coredump pointer (no lock needed, this function can only be called + * from a single thread) + */ + adev->coredump = coredump; + /* Kick off coredump formatting to a worker thread. */ + queue_work(system_unbound_wq, &adev->coredump_work); drm_info(dev, "AMDGPU device coredump file has been created\n"); drm_info(dev, "Check your /sys/class/drm/card%d/device/devcoredump/data\n", dev->primary->index); } + +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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h index ef9772c6bcc9..f8f2f4df129b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h @@ -35,12 +35,20 @@ struct amdgpu_coredump_info { struct amdgpu_device *adev; struct amdgpu_task_info reset_task_info; struct timespec64 reset_time; + bool skip_vram_check; bool reset_vram_lost; struct amdgpu_ring *ring; + /* Readable form of coredevdump, generate once to speed up + * reading it (see drm_coredump_printer's documentation). + */ + ssize_t formatted_size; + char *formatted; }; #endif 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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 711b4502653a..9c936519bb2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3498,7 +3498,8 @@ fail: static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev) { - char *input = amdgpu_lockup_timeout; + char buf[AMDGPU_MAX_TIMEOUT_PARAM_LENGTH]; + char *input = buf; char *timeout_setting = NULL; int index = 0; long timeout; @@ -3508,9 +3509,17 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev) adev->gfx_timeout = adev->compute_timeout = adev->sdma_timeout = adev->video_timeout = msecs_to_jiffies(2000); - if (!strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) + if (!strnlen(amdgpu_lockup_timeout, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) return 0; + /* + * strsep() destructively modifies its input by replacing delimiters + * with '\0'. Use a stack copy so the global module parameter buffer + * remains intact for multi-GPU systems where this function is called + * once per device. + */ + strscpy(buf, amdgpu_lockup_timeout, sizeof(buf)); + while ((timeout_setting = strsep(&input, ",")) && strnlen(timeout_setting, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) { ret = kstrtol(timeout_setting, 0, &timeout); @@ -3781,6 +3790,8 @@ int amdgpu_device_init(struct amdgpu_device *adev, INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func); INIT_WORK(&adev->userq_reset_work, amdgpu_userq_reset_work); + amdgpu_coredump_init(adev); + adev->gfx.gfx_off_req_count = 1; adev->gfx.gfx_off_residency = 0; adev->gfx.gfx_off_entrycount = 0; @@ -3878,9 +3889,21 @@ int amdgpu_device_init(struct amdgpu_device *adev, amdgpu_gmc_noretry_set(adev); /* Need to get xgmi info early to decide the reset behavior*/ if (adev->gmc.xgmi.supported) { - r = adev->gfxhub.funcs->get_xgmi_info(adev); - if (r) - return r; + if (adev->gfxhub.funcs && + adev->gfxhub.funcs->get_xgmi_info) { + r = adev->gfxhub.funcs->get_xgmi_info(adev); + if (r) + return r; + } + } + + if (adev->gmc.xgmi.connected_to_cpu) { + if (adev->mmhub.funcs && + adev->mmhub.funcs->get_xgmi_info) { + r = adev->mmhub.funcs->get_xgmi_info(adev); + if (r) + return r; + } } /* enable PCIE atomic ops */ @@ -4202,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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index f9f785c5d8ac..8ec5465c3349 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -112,8 +112,10 @@ #include "smuio_v15_0_8.h" #include "vcn_v5_0_0.h" #include "vcn_v5_0_1.h" +#include "vcn_v5_0_2.h" #include "jpeg_v5_0_0.h" #include "jpeg_v5_0_1.h" +#include "jpeg_v5_0_2.h" #include "jpeg_v5_3_0.h" #include "amdgpu_ras_mgr.h" @@ -296,13 +298,17 @@ static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev, if (vram_size) adev->discovery.offset = (vram_size << 20) - DISCOVERY_TMR_OFFSET; - if (amdgpu_sriov_vf(adev) && adev->virt.is_dynamic_crit_regn_enabled) { - adev->discovery.offset = - adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset; - adev->discovery.size = - adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb << 10; - if (!adev->discovery.offset || !adev->discovery.size) - return -EINVAL; + if (amdgpu_sriov_vf(adev)) { + if (adev->virt.is_dynamic_crit_regn_enabled) { + adev->discovery.offset = + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset; + adev->discovery.size = + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb << 10; + if (!adev->discovery.offset || !adev->discovery.size) + return -EINVAL; + } else { + goto out; + } } else { tmr_size = RREG32(mmDRIVER_SCRATCH_2); if (tmr_size) { @@ -318,11 +324,11 @@ static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev, ret = amdgpu_acpi_get_tmr_info(adev, &tmr_offset, &tmr_size); if (ret) return ret; - adev->discovery.size = (u32)tmr_size; + adev->discovery.size = DISCOVERY_TMR_SIZE; adev->discovery.offset = tmr_offset + tmr_size - DISCOVERY_TMR_OFFSET; } } - +out: adev->discovery.bin = kzalloc(adev->discovery.size, GFP_KERNEL); if (!adev->discovery.bin) return -ENOMEM; @@ -556,7 +562,7 @@ static int amdgpu_discovery_table_check(struct amdgpu_device *adev, checksum = le16_to_cpu(info->checksum); switch (table_id) { - case IP_DISCOVERY: + case IP_DISCOVERY: { struct ip_discovery_header *ihdr = (struct ip_discovery_header *)(discovery_bin + offset); act_val = le32_to_cpu(ihdr->signature); @@ -564,7 +570,8 @@ static int amdgpu_discovery_table_check(struct amdgpu_device *adev, table_size = le16_to_cpu(ihdr->size); table_name = "data table"; break; - case GC: + } + case GC: { struct gpu_info_header *ghdr = (struct gpu_info_header *)(discovery_bin + offset); act_val = le32_to_cpu(ghdr->table_id); @@ -572,7 +579,8 @@ static int amdgpu_discovery_table_check(struct amdgpu_device *adev, table_size = le16_to_cpu(ghdr->size); table_name = "gc table"; break; - case HARVEST_INFO: + } + case HARVEST_INFO: { struct harvest_info_header *hhdr = (struct harvest_info_header *)(discovery_bin + offset); act_val = le32_to_cpu(hhdr->signature); @@ -580,7 +588,8 @@ static int amdgpu_discovery_table_check(struct amdgpu_device *adev, table_size = sizeof(struct harvest_table); table_name = "harvest table"; break; - case VCN_INFO: + } + case VCN_INFO: { struct vcn_info_header *vhdr = (struct vcn_info_header *)(discovery_bin + offset); act_val = le32_to_cpu(vhdr->table_id); @@ -588,7 +597,8 @@ static int amdgpu_discovery_table_check(struct amdgpu_device *adev, table_size = le32_to_cpu(vhdr->size_bytes); table_name = "vcn table"; break; - case MALL_INFO: + } + case MALL_INFO: { struct mall_info_header *mhdr = (struct mall_info_header *)(discovery_bin + offset); act_val = le32_to_cpu(mhdr->table_id); @@ -597,6 +607,7 @@ static int amdgpu_discovery_table_check(struct amdgpu_device *adev, table_name = "mall table"; check_table = false; break; + } default: dev_err(adev->dev, "invalid ip discovery table id %d specified\n", table_id); check_table = false; @@ -1383,6 +1394,9 @@ static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev) struct list_head *el, *tmp; struct kset *die_kset; + if (!ip_top) + return; + die_kset = &ip_top->die_kset; spin_lock(&die_kset->list_lock); list_for_each_prev_safe(el, tmp, &die_kset->list) { @@ -1407,9 +1421,13 @@ void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p) struct ip_hw_instance *ip_inst; int i = 0, j; + if (!ip_top) + return; + die_kset = &ip_top->die_kset; drm_printf(p, "\nHW IP Discovery\n"); + spin_lock(&die_kset->list_lock); list_for_each(el_die, &die_kset->list) { drm_printf(p, "die %d\n", i++); @@ -1966,11 +1984,10 @@ static int amdgpu_discovery_refresh_nps_info(struct amdgpu_device *adev, int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev, uint32_t *nps_type, - struct amdgpu_gmc_memrange **ranges, + struct amdgpu_gmc_memrange *ranges, int *range_cnt, bool refresh) { uint8_t *discovery_bin = adev->discovery.bin; - struct amdgpu_gmc_memrange *mem_ranges; struct table_info *info; union nps_info *nps_info; union nps_info nps_data; @@ -2008,20 +2025,22 @@ int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev, switch (le16_to_cpu(nps_info->v1.header.version_major)) { case 1: - mem_ranges = kvzalloc_objs(*mem_ranges, nps_info->v1.count); - if (!mem_ranges) - return -ENOMEM; *nps_type = nps_info->v1.nps_type; + if (*range_cnt < nps_info->v1.count) { + dev_dbg(adev->dev, + "not enough space for nps ranges: %d < %d\n", + *range_cnt, nps_info->v1.count); + return -ENOSPC; + } *range_cnt = nps_info->v1.count; for (i = 0; i < *range_cnt; i++) { - mem_ranges[i].base_address = + ranges[i].base_address = nps_info->v1.instance_info[i].base_address; - mem_ranges[i].limit_address = + ranges[i].limit_address = nps_info->v1.instance_info[i].limit_address; - mem_ranges[i].nid_mask = -1; - mem_ranges[i].flags = 0; + ranges[i].nid_mask = -1; + ranges[i].flags = 0; } - *ranges = mem_ranges; break; default: dev_err(adev->dev, "Unhandled NPS info table %d.%d\n", @@ -2323,6 +2342,7 @@ static int amdgpu_discovery_set_smu_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &smu_v14_0_ip_block); break; case IP_VERSION(15, 0, 0): + case IP_VERSION(15, 0, 8): amdgpu_device_ip_block_add(adev, &smu_v15_0_ip_block); break; default: @@ -2640,6 +2660,10 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &vcn_v5_0_1_ip_block); amdgpu_device_ip_block_add(adev, &jpeg_v5_0_1_ip_block); break; + case IP_VERSION(5, 0, 2): + amdgpu_device_ip_block_add(adev, &vcn_v5_0_2_ip_block); + amdgpu_device_ip_block_add(adev, &jpeg_v5_0_2_ip_block); + break; default: dev_err(adev->dev, "Failed to add vcn/jpeg ip block(UVD_HWIP:0x%x)\n", diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h index a7aeb47887a3..0ff1a7923eed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h @@ -46,7 +46,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev); int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev, uint32_t *nps_type, - struct amdgpu_gmc_memrange **ranges, + struct amdgpu_gmc_memrange *ranges, int *range_cnt, bool refresh); void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 03814a23eb54..8ed637f92322 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -839,8 +839,8 @@ module_param_named_unsafe(no_queue_eviction_on_vm_fault, amdgpu_no_queue_evictio /** * DOC: mtype_local (int) */ -int amdgpu_mtype_local; -MODULE_PARM_DESC(mtype_local, "MTYPE for local memory (0 = MTYPE_RW (default), 1 = MTYPE_NC, 2 = MTYPE_CC)"); +int amdgpu_mtype_local = -1; +MODULE_PARM_DESC(mtype_local, "MTYPE for local memory (default: ASIC dependent, 0 = MTYPE_RW, 1 = MTYPE_NC, 2 = MTYPE_CC)"); module_param_named_unsafe(mtype_local, amdgpu_mtype_local, int, 0444); /** @@ -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; } @@ -2952,9 +2956,11 @@ static int amdgpu_drm_release(struct inode *inode, struct file *filp) int idx; if (fpriv && drm_dev_enter(dev, &idx)) { - fpriv->evf_mgr.fd_closing = true; - amdgpu_eviction_fence_destroy(&fpriv->evf_mgr); + amdgpu_evf_mgr_shutdown(&fpriv->evf_mgr); + amdgpu_userq_mgr_cancel_resume(&fpriv->userq_mgr); + amdgpu_evf_mgr_flush_suspend(&fpriv->evf_mgr); amdgpu_userq_mgr_fini(&fpriv->userq_mgr); + amdgpu_evf_mgr_fini(&fpriv->evf_mgr); drm_dev_exit(idx); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c index 3b588c7740ec..4c5e38dea4c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c @@ -25,9 +25,6 @@ #include <drm/drm_exec.h> #include "amdgpu.h" -#define work_to_evf_mgr(w, name) container_of(w, struct amdgpu_eviction_fence_mgr, name) -#define evf_mgr_to_fpriv(e) container_of(e, struct amdgpu_fpriv, evf_mgr) - static const char * amdgpu_eviction_fence_get_driver_name(struct dma_fence *fence) { @@ -43,127 +40,93 @@ amdgpu_eviction_fence_get_timeline_name(struct dma_fence *f) return ef->timeline_name; } -int -amdgpu_eviction_fence_replace_fence(struct amdgpu_eviction_fence_mgr *evf_mgr, - struct drm_exec *exec) +static bool amdgpu_eviction_fence_enable_signaling(struct dma_fence *f) { - struct amdgpu_eviction_fence *old_ef, *new_ef; - struct drm_gem_object *obj; - unsigned long index; - int ret; - - if (evf_mgr->ev_fence && - !dma_fence_is_signaled(&evf_mgr->ev_fence->base)) - return 0; - /* - * Steps to replace eviction fence: - * * lock all objects in exec (caller) - * * create a new eviction fence - * * update new eviction fence in evf_mgr - * * attach the new eviction fence to BOs - * * release the old fence - * * unlock the objects (caller) - */ - new_ef = amdgpu_eviction_fence_create(evf_mgr); - if (!new_ef) { - DRM_ERROR("Failed to create new eviction fence\n"); - return -ENOMEM; - } - - /* Update the eviction fence now */ - spin_lock(&evf_mgr->ev_fence_lock); - old_ef = evf_mgr->ev_fence; - evf_mgr->ev_fence = new_ef; - spin_unlock(&evf_mgr->ev_fence_lock); + struct amdgpu_eviction_fence *ev_fence = to_ev_fence(f); - /* Attach the new fence */ - drm_exec_for_each_locked_object(exec, index, obj) { - struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); - - if (!bo) - continue; - ret = amdgpu_eviction_fence_attach(evf_mgr, bo); - if (ret) { - DRM_ERROR("Failed to attch new eviction fence\n"); - goto free_err; - } - } - - /* Free old fence */ - if (old_ef) - dma_fence_put(&old_ef->base); - return 0; - -free_err: - kfree(new_ef); - return ret; + schedule_work(&ev_fence->evf_mgr->suspend_work); + return true; } +static const struct dma_fence_ops amdgpu_eviction_fence_ops = { + .get_driver_name = amdgpu_eviction_fence_get_driver_name, + .get_timeline_name = amdgpu_eviction_fence_get_timeline_name, + .enable_signaling = amdgpu_eviction_fence_enable_signaling, +}; + static void amdgpu_eviction_fence_suspend_worker(struct work_struct *work) { - struct amdgpu_eviction_fence_mgr *evf_mgr = work_to_evf_mgr(work, suspend_work.work); - struct amdgpu_fpriv *fpriv = evf_mgr_to_fpriv(evf_mgr); + struct amdgpu_eviction_fence_mgr *evf_mgr = + container_of(work, struct amdgpu_eviction_fence_mgr, + suspend_work); + struct amdgpu_fpriv *fpriv = + container_of(evf_mgr, struct amdgpu_fpriv, evf_mgr); struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr; - struct amdgpu_eviction_fence *ev_fence; + struct dma_fence *ev_fence; + bool cookie; mutex_lock(&uq_mgr->userq_mutex); - spin_lock(&evf_mgr->ev_fence_lock); - ev_fence = evf_mgr->ev_fence; - if (ev_fence) - dma_fence_get(&ev_fence->base); - else - goto unlock; - spin_unlock(&evf_mgr->ev_fence_lock); - amdgpu_userq_evict(uq_mgr, ev_fence); + /* + * This is intentionally after taking the userq_mutex since we do + * allocate memory while holding this lock, but only after ensuring that + * the eviction fence is signaled. + */ + cookie = dma_fence_begin_signalling(); - mutex_unlock(&uq_mgr->userq_mutex); - dma_fence_put(&ev_fence->base); - return; + ev_fence = amdgpu_evf_mgr_get_fence(evf_mgr); + amdgpu_userq_evict(uq_mgr); + + /* + * Signaling the eviction fence must be done while holding the + * userq_mutex. Otherwise we won't resume the queues before issuing the + * next fence. + */ + dma_fence_signal(ev_fence); + dma_fence_end_signalling(cookie); + dma_fence_put(ev_fence); + + if (!evf_mgr->shutdown) + schedule_delayed_work(&uq_mgr->resume_work, 0); -unlock: - spin_unlock(&evf_mgr->ev_fence_lock); mutex_unlock(&uq_mgr->userq_mutex); } -static bool amdgpu_eviction_fence_enable_signaling(struct dma_fence *f) +int amdgpu_evf_mgr_attach_fence(struct amdgpu_eviction_fence_mgr *evf_mgr, + struct amdgpu_bo *bo) { - struct amdgpu_eviction_fence_mgr *evf_mgr; - struct amdgpu_eviction_fence *ev_fence; - - if (!f) - return true; - - ev_fence = to_ev_fence(f); - evf_mgr = ev_fence->evf_mgr; + struct dma_fence *ev_fence = amdgpu_evf_mgr_get_fence(evf_mgr); + struct ttm_operation_ctx ctx = { false, false }; + struct dma_resv *resv = bo->tbo.base.resv; + int ret; - schedule_delayed_work(&evf_mgr->suspend_work, 0); - return true; -} + if (!dma_fence_is_signaled(ev_fence)) { -static const struct dma_fence_ops amdgpu_eviction_fence_ops = { - .get_driver_name = amdgpu_eviction_fence_get_driver_name, - .get_timeline_name = amdgpu_eviction_fence_get_timeline_name, - .enable_signaling = amdgpu_eviction_fence_enable_signaling, -}; + amdgpu_bo_placement_from_domain(bo, bo->allowed_domains); + ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); + if (!ret) + dma_resv_add_fence(resv, ev_fence, + DMA_RESV_USAGE_BOOKKEEP); + } else { + ret = 0; + } -void amdgpu_eviction_fence_signal(struct amdgpu_eviction_fence_mgr *evf_mgr, - struct amdgpu_eviction_fence *ev_fence) -{ - spin_lock(&evf_mgr->ev_fence_lock); - dma_fence_signal(&ev_fence->base); - spin_unlock(&evf_mgr->ev_fence_lock); + dma_fence_put(ev_fence); + return ret; } -struct amdgpu_eviction_fence * -amdgpu_eviction_fence_create(struct amdgpu_eviction_fence_mgr *evf_mgr) +int amdgpu_evf_mgr_rearm(struct amdgpu_eviction_fence_mgr *evf_mgr, + struct drm_exec *exec) { struct amdgpu_eviction_fence *ev_fence; + struct drm_gem_object *obj; + unsigned long index; + /* Create and initialize a new eviction fence */ ev_fence = kzalloc_obj(*ev_fence); if (!ev_fence) - return NULL; + return -ENOMEM; ev_fence->evf_mgr = evf_mgr; get_task_comm(ev_fence->timeline_name, current); @@ -171,56 +134,22 @@ amdgpu_eviction_fence_create(struct amdgpu_eviction_fence_mgr *evf_mgr) dma_fence_init64(&ev_fence->base, &amdgpu_eviction_fence_ops, &ev_fence->lock, evf_mgr->ev_fence_ctx, atomic_inc_return(&evf_mgr->ev_fence_seq)); - return ev_fence; -} - -void amdgpu_eviction_fence_destroy(struct amdgpu_eviction_fence_mgr *evf_mgr) -{ - struct amdgpu_eviction_fence *ev_fence; - - /* Wait for any pending work to execute */ - flush_delayed_work(&evf_mgr->suspend_work); - - spin_lock(&evf_mgr->ev_fence_lock); - ev_fence = evf_mgr->ev_fence; - spin_unlock(&evf_mgr->ev_fence_lock); - - if (!ev_fence) - return; - - dma_fence_wait(&ev_fence->base, false); - - /* Last unref of ev_fence */ - dma_fence_put(&ev_fence->base); -} -int amdgpu_eviction_fence_attach(struct amdgpu_eviction_fence_mgr *evf_mgr, - struct amdgpu_bo *bo) -{ - struct amdgpu_eviction_fence *ev_fence; - struct dma_resv *resv = bo->tbo.base.resv; - int ret; + /* Remember it for newly added BOs */ + dma_fence_put(evf_mgr->ev_fence); + evf_mgr->ev_fence = &ev_fence->base; - if (!resv) - return 0; + /* And add it to all existing BOs */ + drm_exec_for_each_locked_object(exec, index, obj) { + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); - ret = dma_resv_reserve_fences(resv, 1); - if (ret) { - DRM_DEBUG_DRIVER("Failed to resv fence space\n"); - return ret; + amdgpu_evf_mgr_attach_fence(evf_mgr, bo); } - - spin_lock(&evf_mgr->ev_fence_lock); - ev_fence = evf_mgr->ev_fence; - if (ev_fence) - dma_resv_add_fence(resv, &ev_fence->base, DMA_RESV_USAGE_BOOKKEEP); - spin_unlock(&evf_mgr->ev_fence_lock); - return 0; } -void amdgpu_eviction_fence_detach(struct amdgpu_eviction_fence_mgr *evf_mgr, - struct amdgpu_bo *bo) +void amdgpu_evf_mgr_detach_fence(struct amdgpu_eviction_fence_mgr *evf_mgr, + struct amdgpu_bo *bo) { struct dma_fence *stub = dma_fence_get_stub(); @@ -229,13 +158,31 @@ void amdgpu_eviction_fence_detach(struct amdgpu_eviction_fence_mgr *evf_mgr, dma_fence_put(stub); } -int amdgpu_eviction_fence_init(struct amdgpu_eviction_fence_mgr *evf_mgr) +void amdgpu_evf_mgr_init(struct amdgpu_eviction_fence_mgr *evf_mgr) { - /* This needs to be done one time per open */ atomic_set(&evf_mgr->ev_fence_seq, 0); evf_mgr->ev_fence_ctx = dma_fence_context_alloc(1); - spin_lock_init(&evf_mgr->ev_fence_lock); + evf_mgr->ev_fence = dma_fence_get_stub(); - INIT_DELAYED_WORK(&evf_mgr->suspend_work, amdgpu_eviction_fence_suspend_worker); - return 0; + INIT_WORK(&evf_mgr->suspend_work, amdgpu_eviction_fence_suspend_worker); +} + +void amdgpu_evf_mgr_shutdown(struct amdgpu_eviction_fence_mgr *evf_mgr) +{ + evf_mgr->shutdown = true; + /* Make sure that the shutdown is visible to the suspend work */ + flush_work(&evf_mgr->suspend_work); +} + +void amdgpu_evf_mgr_flush_suspend(struct amdgpu_eviction_fence_mgr *evf_mgr) +{ + dma_fence_wait(rcu_dereference_protected(evf_mgr->ev_fence, true), + false); + /* Make sure that we are done with the last suspend work */ + flush_work(&evf_mgr->suspend_work); +} + +void amdgpu_evf_mgr_fini(struct amdgpu_eviction_fence_mgr *evf_mgr) +{ + dma_fence_put(evf_mgr->ev_fence); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.h index fcd867b7147d..2a750add4e7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.h @@ -25,6 +25,8 @@ #ifndef AMDGPU_EV_FENCE_H_ #define AMDGPU_EV_FENCE_H_ +#include <linux/dma-fence.h> + struct amdgpu_eviction_fence { struct dma_fence base; spinlock_t lock; @@ -35,35 +37,36 @@ struct amdgpu_eviction_fence { struct amdgpu_eviction_fence_mgr { u64 ev_fence_ctx; atomic_t ev_fence_seq; - spinlock_t ev_fence_lock; - struct amdgpu_eviction_fence *ev_fence; - struct delayed_work suspend_work; - uint8_t fd_closing; -}; - -/* Eviction fence helper functions */ -struct amdgpu_eviction_fence * -amdgpu_eviction_fence_create(struct amdgpu_eviction_fence_mgr *evf_mgr); -void -amdgpu_eviction_fence_destroy(struct amdgpu_eviction_fence_mgr *evf_mgr); - -int -amdgpu_eviction_fence_attach(struct amdgpu_eviction_fence_mgr *evf_mgr, - struct amdgpu_bo *bo); + /* + * Only updated while holding the VM resv lock. + * Only signaled while holding the userq mutex. + */ + struct dma_fence __rcu *ev_fence; + struct work_struct suspend_work; + bool shutdown; +}; -void -amdgpu_eviction_fence_detach(struct amdgpu_eviction_fence_mgr *evf_mgr, - struct amdgpu_bo *bo); +static inline struct dma_fence * +amdgpu_evf_mgr_get_fence(struct amdgpu_eviction_fence_mgr *evf_mgr) +{ + struct dma_fence *ev_fence; -int -amdgpu_eviction_fence_init(struct amdgpu_eviction_fence_mgr *evf_mgr); + rcu_read_lock(); + ev_fence = dma_fence_get_rcu_safe(&evf_mgr->ev_fence); + rcu_read_unlock(); + return ev_fence; +} -void -amdgpu_eviction_fence_signal(struct amdgpu_eviction_fence_mgr *evf_mgr, - struct amdgpu_eviction_fence *ev_fence); +int amdgpu_evf_mgr_attach_fence(struct amdgpu_eviction_fence_mgr *evf_mgr, + struct amdgpu_bo *bo); +int amdgpu_evf_mgr_rearm(struct amdgpu_eviction_fence_mgr *evf_mgr, + struct drm_exec *exec); +void amdgpu_evf_mgr_detach_fence(struct amdgpu_eviction_fence_mgr *evf_mgr, + struct amdgpu_bo *bo); +void amdgpu_evf_mgr_init(struct amdgpu_eviction_fence_mgr *evf_mgr); +void amdgpu_evf_mgr_shutdown(struct amdgpu_eviction_fence_mgr *evf_mgr); +void amdgpu_evf_mgr_flush_suspend(struct amdgpu_eviction_fence_mgr *evf_mgr); +void amdgpu_evf_mgr_fini(struct amdgpu_eviction_fence_mgr *evf_mgr); -int -amdgpu_eviction_fence_replace_fence(struct amdgpu_eviction_fence_mgr *evf_mgr, - struct drm_exec *exec); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index d209591e3710..8048a4c04b47 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -438,7 +438,7 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring, * @ring: ring to init the fence driver on * * Init the fence driver for the requested ring (all asics). - * Helper function for amdgpu_fence_driver_init(). + * Helper function for amdgpu_fence_driver_sw_init(). */ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c index 514bd302365f..841e1b3a017e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c @@ -106,6 +106,7 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev, u32 *fru_addr) *fru_addr = FRU_EEPROM_MADDR_8; return true; case IP_VERSION(13, 0, 12): + case IP_VERSION(15, 0, 8): if (fru_addr) *fru_addr = FRU_EEPROM_MADDR_INV; return true; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index e2d32c29668a..bc772ca3dab7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -404,6 +404,50 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa, } /** + * 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 * * @adev: amdgpu_device pointer diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h index d3118275ddae..6ebd2da32ea6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h @@ -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, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index a6107109a2b8..5376035d32fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -30,6 +30,7 @@ #include <linux/pagemap.h> #include <linux/pci.h> #include <linux/dma-buf.h> +#include <linux/dma-fence-unwrap.h> #include <drm/amdgpu_drm.h> #include <drm/drm_drv.h> @@ -106,6 +107,7 @@ amdgpu_gem_update_timeline_node(struct drm_file *filp, *chain = dma_fence_chain_alloc(); if (!*chain) { drm_syncobj_put(*syncobj); + *syncobj = NULL; return -ENOMEM; } @@ -258,18 +260,15 @@ static int amdgpu_gem_object_open(struct drm_gem_object *obj, amdgpu_vm_bo_update_shared(abo); bo_va = amdgpu_vm_bo_find(vm, abo); - if (!bo_va) + if (!bo_va) { bo_va = amdgpu_vm_bo_add(adev, vm, abo); - else + r = amdgpu_evf_mgr_attach_fence(&fpriv->evf_mgr, abo); + if (r) + goto out_unlock; + } else { ++bo_va->ref_count; - - /* attach gfx eviction fence */ - r = amdgpu_eviction_fence_attach(&fpriv->evf_mgr, abo); - if (r) { - DRM_DEBUG_DRIVER("Failed to attach eviction fence to BO\n"); - amdgpu_bo_unreserve(abo); - return r; } + drm_exec_fini(&exec); /* Validate and add eviction fence to DMABuf imports with dynamic @@ -337,7 +336,7 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, } if (!amdgpu_vm_is_bo_always_valid(vm, bo)) - amdgpu_eviction_fence_detach(&fpriv->evf_mgr, bo); + amdgpu_evf_mgr_detach_fence(&fpriv->evf_mgr, bo); bo_va = amdgpu_vm_bo_find(vm, bo); if (!bo_va || --bo_va->ref_count) @@ -744,11 +743,10 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, struct dma_fence *fence; int r = 0; - /* Always start from the VM's existing last update fence. */ - fence = dma_fence_get(vm->last_update); - + /* If the VM is not ready return only a stub. */ if (!amdgpu_vm_ready(vm)) - return fence; + return dma_fence_get_stub(); + /* * First clean up any freed mappings in the VM. @@ -757,7 +755,7 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, * schedules GPU work. If nothing needs clearing, @fence can remain as * the original vm->last_update. */ - r = amdgpu_vm_clear_freed(adev, vm, &fence); + r = amdgpu_vm_clear_freed(adev, vm, &vm->last_update); if (r) goto error; @@ -774,47 +772,34 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, if (r) goto error; - /* - * Decide which fence best represents the last update: - * - * MAP/REPLACE: - * - For always-valid mappings, use vm->last_update. - * - Otherwise, export bo_va->last_pt_update. - * - * UNMAP/CLEAR: - * Keep the fence returned by amdgpu_vm_clear_freed(). If no work was - * needed, it can remain as vm->last_pt_update. - * - * The VM and BO update fences are always initialized to a valid value. - * vm->last_update and bo_va->last_pt_update always start as valid fences. - * and are never expected to be NULL. - */ - switch (operation) { - case AMDGPU_VA_OP_MAP: - case AMDGPU_VA_OP_REPLACE: + if ((operation == AMDGPU_VA_OP_MAP || + operation == AMDGPU_VA_OP_REPLACE) && + !amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) { + /* - * For MAP/REPLACE, return the page table update fence for the - * mapping we just modified. bo_va is expected to be valid here. + * For MAP/REPLACE of non per-VM BOs we need to sync to both the + * bo_va->last_pt_update and vm->last_update or otherwise we + * potentially miss the PDE updates. */ - dma_fence_put(fence); - - if (amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) - fence = dma_fence_get(vm->last_update); - else - fence = dma_fence_get(bo_va->last_pt_update); - break; - case AMDGPU_VA_OP_UNMAP: - case AMDGPU_VA_OP_CLEAR: - default: - /* keep @fence as returned by amdgpu_vm_clear_freed() */ - break; + fence = dma_fence_unwrap_merge(vm->last_update, + bo_va->last_pt_update); + if (!fence) { + /* As fallback in OOM situations */ + dma_fence_wait(vm->last_update, false); + dma_fence_wait(bo_va->last_pt_update, false); + fence = dma_fence_get_stub(); + } + } else { + fence = dma_fence_get(vm->last_update); } + return fence; + error: if (r && r != -ERESTARTSYS) DRM_ERROR("Couldn't update BO_VA (%d)\n", r); - return fence; + return dma_fence_get(vm->last_update); } int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, @@ -835,7 +820,6 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, struct amdgpu_bo_va *bo_va; struct drm_syncobj *timeline_syncobj = NULL; struct dma_fence_chain *timeline_chain = NULL; - struct dma_fence *fence; struct drm_exec exec; uint64_t vm_size; int r = 0; @@ -887,6 +871,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, return -EINVAL; } + if (args->flags & AMDGPU_VM_DELAY_UPDATE && + args->vm_timeline_syncobj_out) + return -EINVAL; + if ((args->operation != AMDGPU_VA_OP_CLEAR) && !(args->flags & AMDGPU_VM_PAGE_PRT)) { gobj = drm_gem_object_lookup(filp, args->handle); @@ -976,11 +964,13 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, * that represents the last relevant update for this mapping. This * fence can then be exported to the user-visible VM timeline. */ - if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !adev->debug_vm) { + if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && + (!adev->debug_vm || timeline_syncobj)) { + struct dma_fence *fence; + fence = amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, args->operation); - - if (timeline_syncobj && fence) { + if (timeline_syncobj) { if (!args->vm_timeline_point) { /* Replace the existing fence when no point is given. */ drm_syncobj_replace_fence(timeline_syncobj, @@ -991,6 +981,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, timeline_chain, fence, args->vm_timeline_point); + timeline_chain = NULL; } } dma_fence_put(fence); @@ -998,6 +989,9 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, } error: + dma_fence_chain_free(timeline_chain); + if (timeline_syncobj) + drm_syncobj_put(timeline_syncobj); drm_exec_fini(&exec); error_put_gobj: drm_gem_object_put(gobj); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 720ed3a2c78c..2785eda6fea5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -463,6 +463,7 @@ struct amdgpu_gfx { struct amdgpu_irq_src cp_ecc_error_irq; struct amdgpu_irq_src sq_irq; struct amdgpu_irq_src rlc_gc_fed_irq; + struct amdgpu_irq_src rlc_poison_irq; struct sq_work sq_work; /* gfx status */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index a0940db1cd36..ec74f3971732 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -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> @@ -1374,18 +1375,18 @@ int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev, struct amdgpu_mem_partition_info *mem_ranges, uint8_t *exp_ranges) { - struct amdgpu_gmc_memrange *ranges; + struct amdgpu_gmc_memrange ranges[AMDGPU_MAX_MEM_RANGES]; int range_cnt, ret, i, j; uint32_t nps_type; bool refresh; if (!mem_ranges || !exp_ranges) return -EINVAL; - + range_cnt = AMDGPU_MAX_MEM_RANGES; refresh = (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) && (adev->gmc.reset_flags & AMDGPU_GMC_INIT_RESET_NPS); - ret = amdgpu_discovery_get_nps_info(adev, &nps_type, &ranges, - &range_cnt, refresh); + ret = amdgpu_discovery_get_nps_info(adev, &nps_type, ranges, &range_cnt, + refresh); if (ret) return ret; @@ -1446,8 +1447,6 @@ int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev, if (!*exp_ranges) *exp_ranges = range_cnt; err: - kvfree(ranges); - return ret; } @@ -1749,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; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index b9fdc3276e81..32e73e8ba778 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 64c519cd7395..569c5a89ff10 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -35,10 +35,13 @@ * PASIDs are global address space identifiers that can be shared * between the GPU, an IOMMU and the driver. VMs on different devices * may use the same PASID if they share the same address - * space. Therefore PASIDs are allocated using a global IDA. VMs are - * looked up from the PASID per amdgpu_device. + * space. Therefore PASIDs are allocated using IDR cyclic allocator + * (similar to kernel PID allocation) which naturally delays reuse. + * VMs are looked up from the PASID per amdgpu_device. */ -static DEFINE_IDA(amdgpu_pasid_ida); + +static DEFINE_IDR(amdgpu_pasid_idr); +static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock); /* Helper to free pasid from a fence callback */ struct amdgpu_pasid_cb { @@ -50,8 +53,8 @@ struct amdgpu_pasid_cb { * amdgpu_pasid_alloc - Allocate a PASID * @bits: Maximum width of the PASID in bits, must be at least 1 * - * Allocates a PASID of the given width while keeping smaller PASIDs - * available if possible. + * Uses kernel's IDR cyclic allocator (same as PID allocation). + * Allocates sequentially with automatic wrap-around. * * Returns a positive integer on success. Returns %-EINVAL if bits==0. * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on @@ -59,14 +62,18 @@ struct amdgpu_pasid_cb { */ int amdgpu_pasid_alloc(unsigned int bits) { - int pasid = -EINVAL; + int pasid; - for (bits = min(bits, 31U); bits > 0; bits--) { - pasid = ida_alloc_range(&amdgpu_pasid_ida, 1U << (bits - 1), - (1U << bits) - 1, GFP_KERNEL); - if (pasid != -ENOSPC) - break; - } + if (bits == 0) + 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_ATOMIC); + spin_unlock(&amdgpu_pasid_idr_lock); if (pasid >= 0) trace_amdgpu_pasid_allocated(pasid); @@ -81,7 +88,10 @@ int amdgpu_pasid_alloc(unsigned int bits) void amdgpu_pasid_free(u32 pasid) { trace_amdgpu_pasid_freed(pasid); - ida_free(&amdgpu_pasid_ida, pasid); + + spin_lock(&amdgpu_pasid_idr_lock); + idr_remove(&amdgpu_pasid_idr, pasid); + spin_unlock(&amdgpu_pasid_idr_lock); } static void amdgpu_pasid_free_cb(struct dma_fence *fence, @@ -616,3 +626,15 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev) } } } + +/** + * amdgpu_pasid_mgr_cleanup - cleanup PASID manager + * + * Cleanup the IDR allocator. + */ +void amdgpu_pasid_mgr_cleanup(void) +{ + spin_lock(&amdgpu_pasid_idr_lock); + idr_destroy(&amdgpu_pasid_idr); + spin_unlock(&amdgpu_pasid_idr_lock); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h index b3649cd3af56..a57919478d3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h @@ -74,6 +74,7 @@ int amdgpu_pasid_alloc(unsigned int bits); void amdgpu_pasid_free(u32 pasid); void amdgpu_pasid_free_delayed(struct dma_resv *resv, u32 pasid); +void amdgpu_pasid_mgr_cleanup(void); bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, struct amdgpu_vmid *id); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 7f19554b9ad1..06efce38f323 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1522,10 +1522,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) "Failed to init usermode queue manager (%d), use legacy workload submission only\n", r); - r = amdgpu_eviction_fence_init(&fpriv->evf_mgr); - if (r) - goto error_vm; - + amdgpu_evf_mgr_init(&fpriv->evf_mgr); amdgpu_ctx_mgr_init(&fpriv->ctx_mgr, adev); file_priv->driver_priv = fpriv; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h index 1ca9d4ed8063..6b8214650e5d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h @@ -63,14 +63,40 @@ struct amdgpu_mmhub_funcs { uint64_t page_table_base); void (*update_power_gating)(struct amdgpu_device *adev, bool enable); + int (*get_xgmi_info)(struct amdgpu_device *adev); +}; + +struct amdgpu_mmhub_client_ids { + const char * const (*names)[2]; + unsigned int size; }; struct amdgpu_mmhub { struct ras_common_if *ras_if; const struct amdgpu_mmhub_funcs *funcs; struct amdgpu_mmhub_ras *ras; + struct amdgpu_mmhub_client_ids client_ids; }; +static inline void +amdgpu_mmhub_init_client_info(struct amdgpu_mmhub *mmhub, + const char * const (*names)[2], + unsigned int size) +{ + mmhub->client_ids.names = names; + mmhub->client_ids.size = size; +} + +static inline const char * +amdgpu_mmhub_client_name(struct amdgpu_mmhub *mmhub, + u32 cid, bool is_write) +{ + if (cid < mmhub->client_ids.size) + return mmhub->client_ids.names[cid][is_write]; + + return NULL; +} + int amdgpu_mmhub_ras_sw_init(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 90352284c5ee..51ab1a332615 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index cc004830a8a2..27f7567df7bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 741d1919ef88..6edcb7713299 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2250,6 +2250,7 @@ static bool amdgpu_ras_aca_is_supported(struct amdgpu_device *adev) case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 12): case IP_VERSION(13, 0, 14): + case IP_VERSION(13, 0, 15): ret = true; break; default: @@ -4000,6 +4001,7 @@ static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev) case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 12): case IP_VERSION(13, 0, 14): + case IP_VERSION(13, 0, 15): return true; default: return false; @@ -4013,6 +4015,7 @@ static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev) case IP_VERSION(13, 0, 10): case IP_VERSION(13, 0, 12): case IP_VERSION(13, 0, 14): + case IP_VERSION(13, 0, 15): case IP_VERSION(14, 0, 3): return true; default: @@ -4182,7 +4185,8 @@ init_ras_enabled_flag: adev->aca.is_enabled = (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6) || amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 12) || - amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14)); + amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14) || + amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 15)); } /* bad page feature is not applicable to specific app platform */ @@ -4270,6 +4274,7 @@ static void amdgpu_ras_init_reserved_vram_size(struct amdgpu_device *adev) case IP_VERSION(13, 0, 2): case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 12): + case IP_VERSION(13, 0, 15): con->reserved_pages_in_bytes = AMDGPU_RAS_RESERVED_VRAM_SIZE_DEFAULT; break; case IP_VERSION(13, 0, 14): diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 44fba4b6aa92..cdf4909592d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -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: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reg_access.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reg_access.c index bf8645390bdc..540040c76058 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reg_access.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reg_access.c @@ -314,7 +314,6 @@ uint64_t amdgpu_reg_get_smn_base64(struct amdgpu_device *adev, "SMN base address query not supported for this device\n"); return 0; } - return 0; } return adev->reg.smn.get_smn_base(adev, block, die_inst); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 341beec59537..0eecfaa3a94c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -103,10 +103,8 @@ int amdgpu_sched_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - if (!amdgpu_ctx_priority_is_valid(args->in.priority)) { - WARN(1, "Invalid context priority %d\n", args->in.priority); + if (!amdgpu_ctx_priority_is_valid(args->in.priority)) return -EINVAL; - } switch (args->in.op) { case AMDGPU_SCHED_OP_PROCESS_PRIORITY_OVERRIDE: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index b4ab309bf08a..afaaab6496de 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -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, >t->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, - >t->ttm.dma_address[page_idx + 1], - ctrl_flags); + pages_per_xcc, >t->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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index bf101215757e..3b1973611446 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 82333aeb4453..6d9e96fabd58 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -1150,7 +1150,7 @@ int amdgpu_ucode_create_bo(struct amdgpu_device *adev) if ((adev->firmware.load_type != AMDGPU_FW_LOAD_DIRECT) && (adev->firmware.load_type != AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO)) { amdgpu_bo_create_kernel(adev, adev->firmware.fw_size, PAGE_SIZE, - (amdgpu_sriov_vf(adev) || adev->debug_use_vram_fw_buf) ? + (amdgpu_sriov_vf(adev) || adev->debug_use_vram_fw_buf || adev->gmc.xgmi.connected_to_cpu) ? AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT, &adev->firmware.fw_buf, &adev->firmware.fw_buf_mc, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index 4df0f9d5ad11..0238c2798de4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -398,6 +398,17 @@ int amdgpu_umc_process_ecc_irq(struct amdgpu_device *adev, return 0; } +int amdgpu_umc_uniras_process_ecc_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + struct ras_ih_info ih_info = {0}; + + ih_info.block = RAS_BLOCK_ID__UMC; + amdgpu_ras_mgr_dispatch_interrupt(adev, &ih_info); + return 0; +} + int amdgpu_umc_fill_error_record(struct ras_err_data *err_data, uint64_t err_addr, uint64_t retired_page, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index 28dff750c47e..8494a55ebf76 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -161,6 +161,9 @@ int amdgpu_umc_pasid_poison_handler(struct amdgpu_device *adev, int amdgpu_umc_process_ecc_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry); +int amdgpu_umc_uniras_process_ecc_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry); int amdgpu_umc_fill_error_record(struct ras_err_data *err_data, uint64_t err_addr, uint64_t retired_page, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 6d964a6ee349..366728ed03e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -156,7 +156,7 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work) struct dma_fence *fence; struct amdgpu_userq_mgr *uq_mgr; - if (!queue || !queue->userq_mgr) + if (!queue->userq_mgr) return; uq_mgr = queue->userq_mgr; @@ -472,17 +472,16 @@ void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_eviction_fence_mgr *evf_mgr) { - struct amdgpu_eviction_fence *ev_fence; + struct dma_fence *ev_fence; retry: /* Flush any pending resume work to create ev_fence */ flush_delayed_work(&uq_mgr->resume_work); mutex_lock(&uq_mgr->userq_mutex); - spin_lock(&evf_mgr->ev_fence_lock); - ev_fence = evf_mgr->ev_fence; - spin_unlock(&evf_mgr->ev_fence_lock); - if (!ev_fence || dma_fence_is_signaled(&ev_fence->base)) { + ev_fence = amdgpu_evf_mgr_get_fence(evf_mgr); + if (dma_fence_is_signaled(ev_fence)) { + dma_fence_put(ev_fence); mutex_unlock(&uq_mgr->userq_mutex); /* * Looks like there was no pending resume work, @@ -491,6 +490,7 @@ retry: schedule_delayed_work(&uq_mgr->resume_work, 0); goto retry; } + dma_fence_put(ev_fence); } int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr, @@ -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), @@ -623,13 +630,14 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que int r = 0; cancel_delayed_work_sync(&uq_mgr->resume_work); + + /* Cancel any pending hang detection work and cleanup */ + cancel_delayed_work_sync(&queue->hang_detect_work); + mutex_lock(&uq_mgr->userq_mutex); + queue->hang_detect_fence = NULL; amdgpu_userq_wait_for_last_fence(queue); - /* Cancel any pending hang detection work and cleanup */ - if (queue->hang_detect_fence) { - cancel_delayed_work_sync(&queue->hang_detect_work); - queue->hang_detect_fence = NULL; - } + r = amdgpu_bo_reserve(queue->db_obj.obj, true); if (!r) { amdgpu_bo_unpin(queue->db_obj.obj); @@ -996,17 +1004,14 @@ 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) { - queue = amdgpu_userq_get(uq_mgr, queue_id); - if (!queue) - continue; if (!amdgpu_userq_buffer_vas_mapped(queue)) { drm_file_err(uq_mgr->file, "trying restore queue without va mapping\n"); queue->state = AMDGPU_USERQ_STATE_INVALID_VA; - amdgpu_userq_put(queue); continue; } @@ -1014,8 +1019,8 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) if (r) ret = r; - amdgpu_userq_put(queue); } + mutex_unlock(&uq_mgr->userq_mutex); if (ret) drm_file_err(uq_mgr->file, "Failed to map all the queues\n"); @@ -1040,12 +1045,12 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec, struct amdgpu_bo *bo; int ret; - spin_lock(&vm->invalidated_lock); + spin_lock(&vm->status_lock); while (!list_empty(&vm->invalidated)) { bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va, base.vm_status); - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); bo = bo_va->base.bo; ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 2); @@ -1062,9 +1067,9 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec, if (ret) return ret; - spin_lock(&vm->invalidated_lock); + spin_lock(&vm->status_lock); } - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); return 0; } @@ -1196,7 +1201,7 @@ retry_lock: dma_fence_wait(bo_va->last_pt_update, false); dma_fence_wait(vm->last_update, false); - ret = amdgpu_eviction_fence_replace_fence(&fpriv->evf_mgr, &exec); + ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec); if (ret) drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n"); @@ -1216,26 +1221,25 @@ static void amdgpu_userq_restore_worker(struct work_struct *work) { struct amdgpu_userq_mgr *uq_mgr = work_to_uq_mgr(work, resume_work.work); struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); + struct dma_fence *ev_fence; int ret; - flush_delayed_work(&fpriv->evf_mgr.suspend_work); - - mutex_lock(&uq_mgr->userq_mutex); + ev_fence = amdgpu_evf_mgr_get_fence(&fpriv->evf_mgr); + if (!dma_fence_is_signaled(ev_fence)) + 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) { + if (ret) drm_file_err(uq_mgr->file, "Failed to restore all queues\n"); - goto unlock; - } -unlock: - mutex_unlock(&uq_mgr->userq_mutex); +put_fence: + dma_fence_put(ev_fence); } static int @@ -1248,13 +1252,9 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr) amdgpu_userq_detect_and_reset_queues(uq_mgr); /* Try to unmap all the queues in this process ctx */ xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { - queue = amdgpu_userq_get(uq_mgr, queue_id); - if (!queue) - continue; r = amdgpu_userq_preempt_helper(queue); if (r) ret = r; - amdgpu_userq_put(queue); } if (ret) @@ -1287,35 +1287,26 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr) int ret; xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { - queue = amdgpu_userq_get(uq_mgr, queue_id); - if (!queue) - continue; - struct dma_fence *f = queue->last_fence; - if (!f || dma_fence_is_signaled(f)) { - amdgpu_userq_put(queue); + if (!f || dma_fence_is_signaled(f)) continue; - } + ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100)); if (ret <= 0) { drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n", f->context, f->seqno); - amdgpu_userq_put(queue); + return -ETIMEDOUT; } - amdgpu_userq_put(queue); } return 0; } void -amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr, - struct amdgpu_eviction_fence *ev_fence) +amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr) { - struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); - struct amdgpu_eviction_fence_mgr *evf_mgr = &fpriv->evf_mgr; struct amdgpu_device *adev = uq_mgr->adev; int ret; @@ -1328,16 +1319,6 @@ amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr, if (ret) dev_err(adev->dev, "Failed to evict userqueue\n"); - /* Signal current eviction fence */ - amdgpu_eviction_fence_signal(evf_mgr, ev_fence); - - if (evf_mgr->fd_closing) { - cancel_delayed_work_sync(&uq_mgr->resume_work); - return; - } - - /* Schedule a resume work */ - schedule_delayed_work(&uq_mgr->resume_work, 0); } int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv, @@ -1352,6 +1333,11 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f return 0; } +void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr) +{ + cancel_delayed_work_sync(&userq_mgr->resume_work); +} + void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr) { struct amdgpu_usermode_queue *queue; @@ -1475,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); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index 54e1997b3cc0..a4d44abf24fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -123,6 +123,7 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv, struct amdgpu_device *adev); +void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr); void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr); int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr, @@ -132,8 +133,7 @@ int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr, void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_userq_obj *userq_obj); -void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr, - struct amdgpu_eviction_fence *ev_fence); +void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr); void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr, struct amdgpu_eviction_fence_mgr *evf_mgr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index d8ce7b3733e7..fe6d83e859a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -597,11 +597,11 @@ exec_fini: put_gobj_write: for (i = 0; i < num_write_bo_handles; i++) drm_gem_object_put(gobj_write[i]); - kfree(gobj_write); + kvfree(gobj_write); put_gobj_read: for (i = 0; i < num_read_bo_handles; i++) drm_gem_object_put(gobj_read[i]); - kfree(gobj_read); + kvfree(gobj_read); free_syncobj: while (entry-- > 0) if (syncobj[entry]) @@ -616,339 +616,405 @@ free_syncobj_handles: return r; } -int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) +/* Count the number of expected fences so userspace can alloc a buffer */ +static int +amdgpu_userq_wait_count_fences(struct drm_file *filp, + struct drm_amdgpu_userq_wait *wait_info, + u32 *syncobj_handles, u32 *timeline_points, + u32 *timeline_handles, + struct drm_gem_object **gobj_write, + struct drm_gem_object **gobj_read) { - struct drm_amdgpu_userq_wait *wait_info = data; - const unsigned int num_write_bo_handles = wait_info->num_bo_write_handles; - const unsigned int num_read_bo_handles = wait_info->num_bo_read_handles; - struct drm_amdgpu_userq_fence_info *fence_info = NULL; - struct amdgpu_fpriv *fpriv = filp->driver_priv; - struct amdgpu_userq_mgr *userq_mgr = &fpriv->userq_mgr; - struct drm_gem_object **gobj_write, **gobj_read; - u32 *timeline_points, *timeline_handles; - struct amdgpu_usermode_queue *waitq = NULL; - u32 *syncobj_handles, num_syncobj; - struct dma_fence **fences = NULL; - u16 num_points, num_fences = 0; + int num_read_bo_handles, num_write_bo_handles; + struct dma_fence_unwrap iter; + struct dma_fence *fence, *f; + unsigned int num_fences = 0; struct drm_exec exec; - int r, i, cnt; - - if (!amdgpu_userq_enabled(dev)) - return -ENOTSUPP; - - if (wait_info->num_bo_write_handles > AMDGPU_USERQ_MAX_HANDLES || - wait_info->num_bo_read_handles > AMDGPU_USERQ_MAX_HANDLES) - return -EINVAL; - - num_syncobj = wait_info->num_syncobj_handles; - syncobj_handles = memdup_array_user(u64_to_user_ptr(wait_info->syncobj_handles), - num_syncobj, sizeof(u32)); - if (IS_ERR(syncobj_handles)) - return PTR_ERR(syncobj_handles); - + int i, r; + + /* + * This needs to be outside of the lock provided by drm_exec for + * DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT to work correctly. + */ + + /* Count timeline fences */ + for (i = 0; i < wait_info->num_syncobj_timeline_handles; i++) { + r = drm_syncobj_find_fence(filp, timeline_handles[i], + timeline_points[i], + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, + &fence); + if (r) + return r; + + dma_fence_unwrap_for_each(f, &iter, fence) + num_fences++; - num_points = wait_info->num_syncobj_timeline_handles; - timeline_handles = memdup_array_user(u64_to_user_ptr(wait_info->syncobj_timeline_handles), - num_points, sizeof(u32)); - if (IS_ERR(timeline_handles)) { - r = PTR_ERR(timeline_handles); - goto free_syncobj_handles; + dma_fence_put(fence); } - timeline_points = memdup_array_user(u64_to_user_ptr(wait_info->syncobj_timeline_points), - num_points, sizeof(u32)); + /* Count boolean fences */ + for (i = 0; i < wait_info->num_syncobj_handles; i++) { + r = drm_syncobj_find_fence(filp, syncobj_handles[i], 0, + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, + &fence); + if (r) + return r; - if (IS_ERR(timeline_points)) { - r = PTR_ERR(timeline_points); - goto free_timeline_handles; + num_fences++; + dma_fence_put(fence); } - r = drm_gem_objects_lookup(filp, - u64_to_user_ptr(wait_info->bo_read_handles), - num_read_bo_handles, - &gobj_read); - if (r) - goto free_timeline_points; - - r = drm_gem_objects_lookup(filp, - u64_to_user_ptr(wait_info->bo_write_handles), - num_write_bo_handles, - &gobj_write); - if (r) - goto put_gobj_read; - + /* Lock all the GEM objects */ + /* TODO: It is actually not necessary to lock them */ + num_read_bo_handles = wait_info->num_bo_read_handles; + num_write_bo_handles = wait_info->num_bo_write_handles; drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, - (num_read_bo_handles + num_write_bo_handles)); + num_read_bo_handles + num_write_bo_handles); - /* Lock all BOs with retry handling */ drm_exec_until_all_locked(&exec) { - r = drm_exec_prepare_array(&exec, gobj_read, num_read_bo_handles, 1); + r = drm_exec_prepare_array(&exec, gobj_read, + num_read_bo_handles, 1); drm_exec_retry_on_contention(&exec); - if (r) { - drm_exec_fini(&exec); - goto put_gobj_write; - } + if (r) + goto error_unlock; - r = drm_exec_prepare_array(&exec, gobj_write, num_write_bo_handles, 1); + r = drm_exec_prepare_array(&exec, gobj_write, + num_write_bo_handles, 1); drm_exec_retry_on_contention(&exec); - if (r) { - drm_exec_fini(&exec); - goto put_gobj_write; - } + if (r) + goto error_unlock; } - if (!wait_info->num_fences) { - if (num_points) { - struct dma_fence_unwrap iter; - struct dma_fence *fence; - struct dma_fence *f; - - for (i = 0; i < num_points; i++) { - r = drm_syncobj_find_fence(filp, timeline_handles[i], - timeline_points[i], - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, - &fence); - if (r) - goto exec_fini; - - dma_fence_unwrap_for_each(f, &iter, fence) - num_fences++; - - dma_fence_put(fence); - } - } + /* Count read fences */ + for (i = 0; i < num_read_bo_handles; i++) { + struct dma_resv_iter resv_cursor; + struct dma_fence *fence; - /* Count syncobj's fence */ - for (i = 0; i < num_syncobj; i++) { - struct dma_fence *fence; + dma_resv_for_each_fence(&resv_cursor, gobj_read[i]->resv, + DMA_RESV_USAGE_READ, fence) + num_fences++; + } - r = drm_syncobj_find_fence(filp, syncobj_handles[i], - 0, - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, - &fence); - if (r) - goto exec_fini; + /* Count write fences */ + for (i = 0; i < num_write_bo_handles; i++) { + struct dma_resv_iter resv_cursor; + struct dma_fence *fence; + dma_resv_for_each_fence(&resv_cursor, gobj_write[i]->resv, + DMA_RESV_USAGE_WRITE, fence) num_fences++; - dma_fence_put(fence); - } + } - /* Count GEM objects fence */ - for (i = 0; i < num_read_bo_handles; i++) { - struct dma_resv_iter resv_cursor; - struct dma_fence *fence; + wait_info->num_fences = min(num_fences, USHRT_MAX); + r = 0; - dma_resv_for_each_fence(&resv_cursor, gobj_read[i]->resv, - DMA_RESV_USAGE_READ, fence) - num_fences++; - } +error_unlock: + /* Unlock all the GEM objects */ + drm_exec_fini(&exec); + return r; +} - for (i = 0; i < num_write_bo_handles; i++) { - struct dma_resv_iter resv_cursor; - struct dma_fence *fence; +static int +amdgpu_userq_wait_add_fence(struct drm_amdgpu_userq_wait *wait_info, + struct dma_fence **fences, unsigned int *num_fences, + struct dma_fence *fence) +{ + /* As fallback shouldn't userspace allocate enough space */ + if (*num_fences >= wait_info->num_fences) + return dma_fence_wait(fence, true); - dma_resv_for_each_fence(&resv_cursor, gobj_write[i]->resv, - DMA_RESV_USAGE_WRITE, fence) - num_fences++; - } + fences[(*num_fences)++] = dma_fence_get(fence); + return 0; +} - /* - * Passing num_fences = 0 means that userspace doesn't want to - * retrieve userq_fence_info. If num_fences = 0 we skip filling - * userq_fence_info and return the actual number of fences on - * args->num_fences. - */ - wait_info->num_fences = num_fences; - } else { - /* Array of fence info */ - fence_info = kmalloc_array(wait_info->num_fences, sizeof(*fence_info), GFP_KERNEL); - if (!fence_info) { - r = -ENOMEM; - goto exec_fini; - } +static int +amdgpu_userq_wait_return_fence_info(struct drm_file *filp, + struct drm_amdgpu_userq_wait *wait_info, + u32 *syncobj_handles, u32 *timeline_points, + u32 *timeline_handles, + struct drm_gem_object **gobj_write, + struct drm_gem_object **gobj_read) +{ + struct amdgpu_fpriv *fpriv = filp->driver_priv; + struct amdgpu_userq_mgr *userq_mgr = &fpriv->userq_mgr; + struct drm_amdgpu_userq_fence_info *fence_info; + int num_read_bo_handles, num_write_bo_handles; + struct amdgpu_usermode_queue *waitq; + struct dma_fence **fences, *fence, *f; + struct dma_fence_unwrap iter; + int num_points, num_syncobj; + unsigned int num_fences = 0; + struct drm_exec exec; + int i, cnt, r; - /* Array of fences */ - fences = kmalloc_array(wait_info->num_fences, sizeof(*fences), GFP_KERNEL); - if (!fences) { - r = -ENOMEM; - goto free_fence_info; - } + fence_info = kmalloc_array(wait_info->num_fences, sizeof(*fence_info), + GFP_KERNEL); + if (!fence_info) + return -ENOMEM; - /* Retrieve GEM read objects fence */ - for (i = 0; i < num_read_bo_handles; i++) { - struct dma_resv_iter resv_cursor; - struct dma_fence *fence; + fences = kmalloc_array(wait_info->num_fences, sizeof(*fences), + GFP_KERNEL); + if (!fences) { + r = -ENOMEM; + goto free_fence_info; + } - dma_resv_for_each_fence(&resv_cursor, gobj_read[i]->resv, - DMA_RESV_USAGE_READ, fence) { - if (num_fences >= wait_info->num_fences) { - r = -EINVAL; - goto free_fences; - } + /* Retrieve timeline fences */ + num_points = wait_info->num_syncobj_timeline_handles; + for (i = 0; i < num_points; i++) { + r = drm_syncobj_find_fence(filp, timeline_handles[i], + timeline_points[i], + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, + &fence); + if (r) + goto free_fences; - fences[num_fences++] = fence; - dma_fence_get(fence); + dma_fence_unwrap_for_each(f, &iter, fence) { + r = amdgpu_userq_wait_add_fence(wait_info, fences, + &num_fences, f); + if (r) { + dma_fence_put(fence); + goto free_fences; } } - /* Retrieve GEM write objects fence */ - for (i = 0; i < num_write_bo_handles; i++) { - struct dma_resv_iter resv_cursor; - struct dma_fence *fence; + dma_fence_put(fence); + } - dma_resv_for_each_fence(&resv_cursor, gobj_write[i]->resv, - DMA_RESV_USAGE_WRITE, fence) { - if (num_fences >= wait_info->num_fences) { - r = -EINVAL; - goto free_fences; - } + /* Retrieve boolean fences */ + num_syncobj = wait_info->num_syncobj_handles; + for (i = 0; i < num_syncobj; i++) { + struct dma_fence *fence; - fences[num_fences++] = fence; - dma_fence_get(fence); - } - } + r = drm_syncobj_find_fence(filp, syncobj_handles[i], 0, + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, + &fence); + if (r) + goto free_fences; - if (num_points) { - struct dma_fence_unwrap iter; - struct dma_fence *fence; - struct dma_fence *f; - - for (i = 0; i < num_points; i++) { - r = drm_syncobj_find_fence(filp, timeline_handles[i], - timeline_points[i], - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, - &fence); - if (r) - goto free_fences; - - dma_fence_unwrap_for_each(f, &iter, fence) { - if (num_fences >= wait_info->num_fences) { - r = -EINVAL; - dma_fence_put(fence); - goto free_fences; - } - - dma_fence_get(f); - fences[num_fences++] = f; - } + r = amdgpu_userq_wait_add_fence(wait_info, fences, + &num_fences, fence); + dma_fence_put(fence); + if (r) + goto free_fences; - dma_fence_put(fence); - } - } + } - /* Retrieve syncobj's fence */ - for (i = 0; i < num_syncobj; i++) { - struct dma_fence *fence; + /* Lock all the GEM objects */ + num_read_bo_handles = wait_info->num_bo_read_handles; + num_write_bo_handles = wait_info->num_bo_write_handles; + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, + num_read_bo_handles + num_write_bo_handles); - r = drm_syncobj_find_fence(filp, syncobj_handles[i], - 0, - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, - &fence); - if (r) - goto free_fences; + drm_exec_until_all_locked(&exec) { + r = drm_exec_prepare_array(&exec, gobj_read, + num_read_bo_handles, 1); + drm_exec_retry_on_contention(&exec); + if (r) + goto error_unlock; - if (num_fences >= wait_info->num_fences) { - r = -EINVAL; - dma_fence_put(fence); - goto free_fences; - } + r = drm_exec_prepare_array(&exec, gobj_write, + num_write_bo_handles, 1); + drm_exec_retry_on_contention(&exec); + if (r) + goto error_unlock; + } - fences[num_fences++] = fence; + /* Retrieve GEM read objects fence */ + for (i = 0; i < num_read_bo_handles; i++) { + struct dma_resv_iter resv_cursor; + struct dma_fence *fence; + + dma_resv_for_each_fence(&resv_cursor, gobj_read[i]->resv, + DMA_RESV_USAGE_READ, fence) { + r = amdgpu_userq_wait_add_fence(wait_info, fences, + &num_fences, fence); + if (r) + goto error_unlock; } + } - /* - * Keep only the latest fences to reduce the number of values - * given back to userspace. - */ - num_fences = dma_fence_dedup_array(fences, num_fences); + /* Retrieve GEM write objects fence */ + for (i = 0; i < num_write_bo_handles; i++) { + struct dma_resv_iter resv_cursor; + struct dma_fence *fence; - waitq = amdgpu_userq_get(userq_mgr, wait_info->waitq_id); - if (!waitq) { - r = -EINVAL; - goto free_fences; + dma_resv_for_each_fence(&resv_cursor, gobj_write[i]->resv, + DMA_RESV_USAGE_WRITE, fence) { + r = amdgpu_userq_wait_add_fence(wait_info, fences, + &num_fences, fence); + if (r) + goto error_unlock; } + } - for (i = 0, cnt = 0; i < num_fences; i++) { - struct amdgpu_userq_fence_driver *fence_drv; - struct amdgpu_userq_fence *userq_fence; - u32 index; - - userq_fence = to_amdgpu_userq_fence(fences[i]); - if (!userq_fence) { - /* - * Just waiting on other driver fences should - * be good for now - */ - r = dma_fence_wait(fences[i], true); - if (r) { - dma_fence_put(fences[i]); - goto free_fences; - } - - dma_fence_put(fences[i]); - continue; - } + drm_exec_fini(&exec); - fence_drv = userq_fence->fence_drv; + /* + * Keep only the latest fences to reduce the number of values + * given back to userspace. + */ + num_fences = dma_fence_dedup_array(fences, num_fences); + + waitq = amdgpu_userq_get(userq_mgr, wait_info->waitq_id); + if (!waitq) { + r = -EINVAL; + goto free_fences; + } + + for (i = 0, cnt = 0; i < num_fences; i++) { + struct amdgpu_userq_fence_driver *fence_drv; + struct amdgpu_userq_fence *userq_fence; + u32 index; + + userq_fence = to_amdgpu_userq_fence(fences[i]); + if (!userq_fence) { /* - * We need to make sure the user queue release their reference - * to the fence drivers at some point before queue destruction. - * Otherwise, we would gather those references until we don't - * have any more space left and crash. + * Just waiting on other driver fences should + * be good for now */ - r = xa_alloc(&waitq->fence_drv_xa, &index, fence_drv, - xa_limit_32b, GFP_KERNEL); + r = dma_fence_wait(fences[i], true); if (r) - goto free_fences; + goto put_waitq; - amdgpu_userq_fence_driver_get(fence_drv); + continue; + } - /* Store drm syncobj's gpu va address and value */ - fence_info[cnt].va = fence_drv->va; - fence_info[cnt].value = fences[i]->seqno; + fence_drv = userq_fence->fence_drv; + /* + * We need to make sure the user queue release their reference + * to the fence drivers at some point before queue destruction. + * Otherwise, we would gather those references until we don't + * have any more space left and crash. + */ + r = xa_alloc(&waitq->fence_drv_xa, &index, fence_drv, + xa_limit_32b, GFP_KERNEL); + if (r) + goto put_waitq; - dma_fence_put(fences[i]); - /* Increment the actual userq fence count */ - cnt++; - } + amdgpu_userq_fence_driver_get(fence_drv); - wait_info->num_fences = cnt; - /* Copy userq fence info to user space */ - if (copy_to_user(u64_to_user_ptr(wait_info->out_fences), - fence_info, wait_info->num_fences * sizeof(*fence_info))) { - r = -EFAULT; - goto free_fences; - } + /* Store drm syncobj's gpu va address and value */ + fence_info[cnt].va = fence_drv->va; + fence_info[cnt].value = fences[i]->seqno; + + /* Increment the actual userq fence count */ + cnt++; } + wait_info->num_fences = cnt; + + /* Copy userq fence info to user space */ + if (copy_to_user(u64_to_user_ptr(wait_info->out_fences), + fence_info, cnt * sizeof(*fence_info))) + r = -EFAULT; + else + r = 0; + +put_waitq: + amdgpu_userq_put(waitq); free_fences: - if (fences) { - while (num_fences-- > 0) - dma_fence_put(fences[num_fences]); - kfree(fences); - } + while (num_fences--) + dma_fence_put(fences[num_fences]); + kfree(fences); + free_fence_info: kfree(fence_info); -exec_fini: + return r; + +error_unlock: drm_exec_fini(&exec); -put_gobj_write: - for (i = 0; i < num_write_bo_handles; i++) - drm_gem_object_put(gobj_write[i]); - kfree(gobj_write); + goto free_fences; +} + +int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + int num_points, num_syncobj, num_read_bo_handles, num_write_bo_handles; + u32 *syncobj_handles, *timeline_points, *timeline_handles; + struct drm_amdgpu_userq_wait *wait_info = data; + struct drm_gem_object **gobj_write; + struct drm_gem_object **gobj_read; + void __user *ptr; + int r; + + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + + if (wait_info->num_bo_write_handles > AMDGPU_USERQ_MAX_HANDLES || + wait_info->num_bo_read_handles > AMDGPU_USERQ_MAX_HANDLES) + return -EINVAL; + + num_syncobj = wait_info->num_syncobj_handles; + ptr = u64_to_user_ptr(wait_info->syncobj_handles); + syncobj_handles = memdup_array_user(ptr, num_syncobj, sizeof(u32)); + if (IS_ERR(syncobj_handles)) + return PTR_ERR(syncobj_handles); + + num_points = wait_info->num_syncobj_timeline_handles; + ptr = u64_to_user_ptr(wait_info->syncobj_timeline_handles); + timeline_handles = memdup_array_user(ptr, num_points, sizeof(u32)); + if (IS_ERR(timeline_handles)) { + r = PTR_ERR(timeline_handles); + goto free_syncobj_handles; + } + + ptr = u64_to_user_ptr(wait_info->syncobj_timeline_points); + timeline_points = memdup_array_user(ptr, num_points, sizeof(u32)); + if (IS_ERR(timeline_points)) { + r = PTR_ERR(timeline_points); + goto free_timeline_handles; + } + + num_read_bo_handles = wait_info->num_bo_read_handles; + ptr = u64_to_user_ptr(wait_info->bo_read_handles); + r = drm_gem_objects_lookup(filp, ptr, num_read_bo_handles, &gobj_read); + if (r) + goto free_timeline_points; + + num_write_bo_handles = wait_info->num_bo_write_handles; + ptr = u64_to_user_ptr(wait_info->bo_write_handles); + r = drm_gem_objects_lookup(filp, ptr, num_write_bo_handles, + &gobj_write); + if (r) + goto put_gobj_read; + + /* + * Passing num_fences = 0 means that userspace doesn't want to + * retrieve userq_fence_info. If num_fences = 0 we skip filling + * userq_fence_info and return the actual number of fences on + * args->num_fences. + */ + if (!wait_info->num_fences) { + r = amdgpu_userq_wait_count_fences(filp, wait_info, + syncobj_handles, + timeline_points, + timeline_handles, + gobj_write, + gobj_read); + } else { + r = amdgpu_userq_wait_return_fence_info(filp, wait_info, + syncobj_handles, + timeline_points, + timeline_handles, + gobj_write, + gobj_read); + } + + while (num_write_bo_handles--) + drm_gem_object_put(gobj_write[num_write_bo_handles]); + kvfree(gobj_write); + put_gobj_read: - for (i = 0; i < num_read_bo_handles; i++) - drm_gem_object_put(gobj_read[i]); - kfree(gobj_read); + while (num_read_bo_handles--) + drm_gem_object_put(gobj_read[num_read_bo_handles]); + kvfree(gobj_read); + free_timeline_points: kfree(timeline_points); free_timeline_handles: kfree(timeline_handles); free_syncobj_handles: kfree(syncobj_handles); - - if (waitq) - amdgpu_userq_put(waitq); - return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 75ae9b429420..03d95dca93d7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -63,6 +63,7 @@ #define FIRMWARE_VCN4_0_6_1 "amdgpu/vcn_4_0_6_1.bin" #define FIRMWARE_VCN5_0_0 "amdgpu/vcn_5_0_0.bin" #define FIRMWARE_VCN5_0_1 "amdgpu/vcn_5_0_1.bin" +#define FIRMWARE_VCN5_0_2 "amdgpu/vcn_5_0_2.bin" #define FIRMWARE_VCN5_3_0 "amdgpu/vcn_5_3_0.bin" MODULE_FIRMWARE(FIRMWARE_RAVEN); @@ -91,6 +92,7 @@ MODULE_FIRMWARE(FIRMWARE_VCN4_0_6); MODULE_FIRMWARE(FIRMWARE_VCN4_0_6_1); MODULE_FIRMWARE(FIRMWARE_VCN5_0_0); MODULE_FIRMWARE(FIRMWARE_VCN5_0_1); +MODULE_FIRMWARE(FIRMWARE_VCN5_0_2); MODULE_FIRMWARE(FIRMWARE_VCN5_3_0); static void amdgpu_vcn_idle_work_handler(struct work_struct *work); @@ -1095,7 +1097,8 @@ int amdgpu_vcn_unified_ring_test_ib(struct amdgpu_ring *ring, long timeout) long r; if ((amdgpu_ip_version(adev, UVD_HWIP, 0) != IP_VERSION(4, 0, 3)) && - (amdgpu_ip_version(adev, UVD_HWIP, 0) != IP_VERSION(5, 0, 1))) { + (amdgpu_ip_version(adev, UVD_HWIP, 0) != IP_VERSION(5, 0, 1)) && + (amdgpu_ip_version(adev, UVD_HWIP, 0) != IP_VERSION(5, 0, 2))) { r = amdgpu_vcn_enc_ring_test_ib(ring, timeout); if (r) goto error; @@ -1132,7 +1135,8 @@ void amdgpu_vcn_setup_ucode(struct amdgpu_device *adev, int i) return; if ((amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(4, 0, 3) || - amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(5, 0, 1)) + amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(5, 0, 1) || + amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(5, 0, 2)) && (i > 0)) return; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 275745aa5829..dba7ea16a10d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -605,10 +605,10 @@ static int amdgpu_virt_write_vf2pf_data(struct amdgpu_device *adev) #ifdef MODULE if (THIS_MODULE->version != NULL) - strcpy(vf2pf_info->driver_version, THIS_MODULE->version); + strscpy(vf2pf_info->driver_version, THIS_MODULE->version); else #endif - strcpy(vf2pf_info->driver_version, "N/A"); + strscpy(vf2pf_info->driver_version, "N/A"); vf2pf_info->pf2vf_version_required = 0; // no requirement, guest understands all vf2pf_info->driver_cert = 0; @@ -950,11 +950,6 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) if (adev->virt.req_init_data_ver != GPU_CRIT_REGION_V2) return 0; - if (init_hdr_offset < 0) { - dev_err(adev->dev, "Invalid init header offset\n"); - return -EINVAL; - } - vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); if (!vram_size || vram_size == U32_MAX) return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c index 5cef8cd14148..e54295b56282 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 76248a0276ef..73abac6be5b3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -139,6 +139,20 @@ static void amdgpu_vm_assert_locked(struct amdgpu_vm *vm) } /** + * amdgpu_vm_is_bo_always_valid - check if the BO is VM always valid + * + * @vm: VM to test against. + * @bo: BO to be tested. + * + * Returns true if the BO shares the dma_resv object with the root PD and is + * always guaranteed to be valid inside the VM. + */ +bool amdgpu_vm_is_bo_always_valid(struct amdgpu_vm *vm, struct amdgpu_bo *bo) +{ + return bo && bo->tbo.base.resv == vm->root.bo->tbo.base.resv; +} + +/** * amdgpu_vm_bo_evicted - vm_bo is evicted * * @vm_bo: vm_bo which is evicted @@ -153,10 +167,12 @@ static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo) vm_bo->moved = true; amdgpu_vm_assert_locked(vm); + spin_lock(&vm_bo->vm->status_lock); if (bo->tbo.type == ttm_bo_type_kernel) list_move(&vm_bo->vm_status, &vm->evicted); else list_move_tail(&vm_bo->vm_status, &vm->evicted); + spin_unlock(&vm_bo->vm->status_lock); } /** * amdgpu_vm_bo_moved - vm_bo is moved @@ -169,7 +185,9 @@ static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo) static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo) { amdgpu_vm_assert_locked(vm_bo->vm); + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->moved); + spin_unlock(&vm_bo->vm->status_lock); } /** @@ -183,7 +201,9 @@ static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo) static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo) { amdgpu_vm_assert_locked(vm_bo->vm); + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->idle); + spin_unlock(&vm_bo->vm->status_lock); vm_bo->moved = false; } @@ -197,9 +217,9 @@ static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo) */ static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo) { - spin_lock(&vm_bo->vm->invalidated_lock); + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->invalidated); - spin_unlock(&vm_bo->vm->invalidated_lock); + spin_unlock(&vm_bo->vm->status_lock); } /** @@ -212,9 +232,10 @@ static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo) */ static void amdgpu_vm_bo_evicted_user(struct amdgpu_vm_bo_base *vm_bo) { - amdgpu_vm_assert_locked(vm_bo->vm); vm_bo->moved = true; + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->evicted_user); + spin_unlock(&vm_bo->vm->status_lock); } /** @@ -228,10 +249,13 @@ static void amdgpu_vm_bo_evicted_user(struct amdgpu_vm_bo_base *vm_bo) static void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo) { amdgpu_vm_assert_locked(vm_bo->vm); - if (vm_bo->bo->parent) + if (vm_bo->bo->parent) { + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->relocated); - else + spin_unlock(&vm_bo->vm->status_lock); + } else { amdgpu_vm_bo_idle(vm_bo); + } } /** @@ -245,7 +269,9 @@ static void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo) static void amdgpu_vm_bo_done(struct amdgpu_vm_bo_base *vm_bo) { amdgpu_vm_assert_locked(vm_bo->vm); + spin_lock(&vm_bo->vm->status_lock); list_move(&vm_bo->vm_status, &vm_bo->vm->done); + spin_unlock(&vm_bo->vm->status_lock); } /** @@ -259,13 +285,13 @@ static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm) { struct amdgpu_vm_bo_base *vm_bo, *tmp; - spin_lock(&vm->invalidated_lock); + amdgpu_vm_assert_locked(vm); + + spin_lock(&vm->status_lock); list_splice_init(&vm->done, &vm->invalidated); list_for_each_entry(vm_bo, &vm->invalidated, vm_status) vm_bo->moved = true; - spin_unlock(&vm->invalidated_lock); - amdgpu_vm_assert_locked(vm); list_for_each_entry_safe(vm_bo, tmp, &vm->idle, vm_status) { struct amdgpu_bo *bo = vm_bo->bo; @@ -275,13 +301,14 @@ static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm) else if (bo->parent) list_move(&vm_bo->vm_status, &vm_bo->vm->relocated); } + spin_unlock(&vm->status_lock); } /** * amdgpu_vm_update_shared - helper to update shared memory stat * @base: base structure for tracking BO usage in a VM * - * Takes the vm stats_lock and updates the shared memory stat. If the basic + * Takes the vm status_lock and updates the shared memory stat. If the basic * stat changed (e.g. buffer was moved) amdgpu_vm_update_stats need to be called * as well. */ @@ -294,7 +321,7 @@ static void amdgpu_vm_update_shared(struct amdgpu_vm_bo_base *base) bool shared; dma_resv_assert_held(bo->tbo.base.resv); - spin_lock(&vm->stats_lock); + spin_lock(&vm->status_lock); shared = drm_gem_object_is_shared_for_memory_stats(&bo->tbo.base); if (base->shared != shared) { base->shared = shared; @@ -306,7 +333,7 @@ static void amdgpu_vm_update_shared(struct amdgpu_vm_bo_base *base) vm->stats[bo_memtype].drm.private += size; } } - spin_unlock(&vm->stats_lock); + spin_unlock(&vm->status_lock); } /** @@ -331,11 +358,11 @@ void amdgpu_vm_bo_update_shared(struct amdgpu_bo *bo) * be bo->tbo.resource * @sign: if we should add (+1) or subtract (-1) from the stat * - * Caller need to have the vm stats_lock held. Useful for when multiple update + * Caller need to have the vm status_lock held. Useful for when multiple update * need to happen at the same time. */ static void amdgpu_vm_update_stats_locked(struct amdgpu_vm_bo_base *base, - struct ttm_resource *res, int sign) + struct ttm_resource *res, int sign) { struct amdgpu_vm *vm = base->vm; struct amdgpu_bo *bo = base->bo; @@ -359,8 +386,7 @@ static void amdgpu_vm_update_stats_locked(struct amdgpu_vm_bo_base *base, */ if (bo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) vm->stats[res_memtype].drm.purgeable += size; - if (!(bo->preferred_domains & - amdgpu_mem_type_to_domain(res_memtype))) + if (!(bo->preferred_domains & amdgpu_mem_type_to_domain(res_memtype))) vm->stats[bo_memtype].evicted += size; } } @@ -379,9 +405,9 @@ void amdgpu_vm_update_stats(struct amdgpu_vm_bo_base *base, { struct amdgpu_vm *vm = base->vm; - spin_lock(&vm->stats_lock); + spin_lock(&vm->status_lock); amdgpu_vm_update_stats_locked(base, res, sign); - spin_unlock(&vm->stats_lock); + spin_unlock(&vm->status_lock); } /** @@ -407,10 +433,10 @@ void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base, base->next = bo->vm_bo; bo->vm_bo = base; - spin_lock(&vm->stats_lock); + spin_lock(&vm->status_lock); base->shared = drm_gem_object_is_shared_for_memory_stats(&bo->tbo.base); amdgpu_vm_update_stats_locked(base, bo->tbo.resource, +1); - spin_unlock(&vm->stats_lock); + spin_unlock(&vm->status_lock); if (!amdgpu_vm_is_bo_always_valid(vm, bo)) return; @@ -469,25 +495,25 @@ int amdgpu_vm_lock_done_list(struct amdgpu_vm *vm, struct drm_exec *exec, int ret; /* We can only trust prev->next while holding the lock */ - spin_lock(&vm->invalidated_lock); + spin_lock(&vm->status_lock); while (!list_is_head(prev->next, &vm->done)) { bo_va = list_entry(prev->next, typeof(*bo_va), base.vm_status); bo = bo_va->base.bo; if (bo) { amdgpu_bo_ref(bo); - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 1); amdgpu_bo_unref(&bo); if (unlikely(ret)) return ret; - spin_lock(&vm->invalidated_lock); + spin_lock(&vm->status_lock); } prev = prev->next; } - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); return 0; } @@ -583,7 +609,7 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, void *param) { uint64_t new_vm_generation = amdgpu_vm_generation(adev, vm); - struct amdgpu_vm_bo_base *bo_base, *tmp; + struct amdgpu_vm_bo_base *bo_base; struct amdgpu_bo *bo; int r; @@ -596,7 +622,13 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, return r; } - list_for_each_entry_safe(bo_base, tmp, &vm->evicted, vm_status) { + spin_lock(&vm->status_lock); + while (!list_empty(&vm->evicted)) { + bo_base = list_first_entry(&vm->evicted, + struct amdgpu_vm_bo_base, + vm_status); + spin_unlock(&vm->status_lock); + bo = bo_base->bo; r = validate(param, bo); @@ -609,21 +641,26 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, vm->update_funcs->map_table(to_amdgpu_bo_vm(bo)); amdgpu_vm_bo_relocated(bo_base); } + spin_lock(&vm->status_lock); } + while (ticket && !list_empty(&vm->evicted_user)) { + bo_base = list_first_entry(&vm->evicted_user, + struct amdgpu_vm_bo_base, + vm_status); + spin_unlock(&vm->status_lock); - if (ticket) { - list_for_each_entry_safe(bo_base, tmp, &vm->evicted_user, - vm_status) { - bo = bo_base->bo; - dma_resv_assert_held(bo->tbo.base.resv); + bo = bo_base->bo; + dma_resv_assert_held(bo->tbo.base.resv); - r = validate(param, bo); - if (r) - return r; + r = validate(param, bo); + if (r) + return r; - amdgpu_vm_bo_invalidated(bo_base); - } + amdgpu_vm_bo_invalidated(bo_base); + + spin_lock(&vm->status_lock); } + spin_unlock(&vm->status_lock); amdgpu_vm_eviction_lock(vm); vm->evicting = false; @@ -652,7 +689,9 @@ bool amdgpu_vm_ready(struct amdgpu_vm *vm) ret = !vm->evicting; amdgpu_vm_eviction_unlock(vm); + spin_lock(&vm->status_lock); ret &= list_empty(&vm->evicted); + spin_unlock(&vm->status_lock); spin_lock(&vm->immediate.lock); ret &= !vm->immediate.stopped; @@ -946,13 +985,18 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, struct amdgpu_vm *vm, bool immediate) { struct amdgpu_vm_update_params params; - struct amdgpu_vm_bo_base *entry, *tmp; + struct amdgpu_vm_bo_base *entry; bool flush_tlb_needed = false; + LIST_HEAD(relocated); int r, idx; amdgpu_vm_assert_locked(vm); - if (list_empty(&vm->relocated)) + spin_lock(&vm->status_lock); + list_splice_init(&vm->relocated, &relocated); + spin_unlock(&vm->status_lock); + + if (list_empty(&relocated)) return 0; if (!drm_dev_enter(adev_to_drm(adev), &idx)) @@ -968,7 +1012,7 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, if (r) goto error; - list_for_each_entry(entry, &vm->relocated, vm_status) { + list_for_each_entry(entry, &relocated, vm_status) { /* vm_flush_needed after updating moved PDEs */ flush_tlb_needed |= entry->moved; @@ -984,7 +1028,9 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, if (flush_tlb_needed) atomic64_inc(&vm->tlb_seq); - list_for_each_entry_safe(entry, tmp, &vm->relocated, vm_status) { + while (!list_empty(&relocated)) { + entry = list_first_entry(&relocated, struct amdgpu_vm_bo_base, + vm_status); amdgpu_vm_bo_idle(entry); } @@ -1041,7 +1087,10 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params, } /* Prepare a TLB flush fence to be attached to PTs */ - if (!params->unlocked) { + /* The check for need_tlb_fence should be dropped once we + * sort out the issues with KIQ/MES TLB invalidation timeouts. + */ + if (!params->unlocked && vm->need_tlb_fence) { amdgpu_vm_tlb_fence_create(params->adev, vm, fence); /* Makes sure no PD/PT is freed before the flush */ @@ -1211,9 +1260,9 @@ error_free: void amdgpu_vm_get_memory(struct amdgpu_vm *vm, struct amdgpu_mem_stats stats[__AMDGPU_PL_NUM]) { - spin_lock(&vm->stats_lock); + spin_lock(&vm->status_lock); memcpy(stats, vm->stats, sizeof(*stats) * __AMDGPU_PL_NUM); - spin_unlock(&vm->stats_lock); + spin_unlock(&vm->status_lock); } /** @@ -1580,24 +1629,29 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket) { - struct amdgpu_bo_va *bo_va, *tmp; + struct amdgpu_bo_va *bo_va; struct dma_resv *resv; bool clear, unlock; int r; - list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) { + spin_lock(&vm->status_lock); + while (!list_empty(&vm->moved)) { + bo_va = list_first_entry(&vm->moved, struct amdgpu_bo_va, + base.vm_status); + spin_unlock(&vm->status_lock); + /* Per VM BOs never need to bo cleared in the page tables */ r = amdgpu_vm_bo_update(adev, bo_va, false); if (r) return r; + spin_lock(&vm->status_lock); } - spin_lock(&vm->invalidated_lock); while (!list_empty(&vm->invalidated)) { bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va, base.vm_status); resv = bo_va->base.bo->tbo.base.resv; - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); /* Try to reserve the BO to avoid clearing its ptes */ if (!adev->debug_vm && dma_resv_trylock(resv)) { @@ -1629,9 +1683,9 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, bo_va->base.bo->tbo.resource->mem_type == TTM_PL_SYSTEM)) amdgpu_vm_bo_evicted_user(&bo_va->base); - spin_lock(&vm->invalidated_lock); + spin_lock(&vm->status_lock); } - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); return 0; } @@ -2174,9 +2228,9 @@ void amdgpu_vm_bo_del(struct amdgpu_device *adev, } } - spin_lock(&vm->invalidated_lock); + spin_lock(&vm->status_lock); list_del(&bo_va->base.vm_status); - spin_unlock(&vm->invalidated_lock); + spin_unlock(&vm->status_lock); list_for_each_entry_safe(mapping, next, &bo_va->valids, list) { list_del(&mapping->list); @@ -2284,10 +2338,10 @@ void amdgpu_vm_bo_move(struct amdgpu_bo *bo, struct ttm_resource *new_mem, for (bo_base = bo->vm_bo; bo_base; bo_base = bo_base->next) { struct amdgpu_vm *vm = bo_base->vm; - spin_lock(&vm->stats_lock); + spin_lock(&vm->status_lock); amdgpu_vm_update_stats_locked(bo_base, bo->tbo.resource, -1); amdgpu_vm_update_stats_locked(bo_base, new_mem, +1); - spin_unlock(&vm->stats_lock); + spin_unlock(&vm->status_lock); } amdgpu_vm_bo_invalidate(bo, evicted); @@ -2556,12 +2610,11 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, INIT_LIST_HEAD(&vm->relocated); INIT_LIST_HEAD(&vm->moved); INIT_LIST_HEAD(&vm->idle); - spin_lock_init(&vm->invalidated_lock); INIT_LIST_HEAD(&vm->invalidated); + spin_lock_init(&vm->status_lock); INIT_LIST_HEAD(&vm->freed); INIT_LIST_HEAD(&vm->done); INIT_KFIFO(vm->faults); - spin_lock_init(&vm->stats_lock); r = amdgpu_vm_init_entities(adev, vm); if (r) @@ -2570,6 +2623,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, ttm_lru_bulk_move_init(&vm->lru_bulk_move); vm->is_compute_context = false; + vm->need_tlb_fence = amdgpu_userq_enabled(&adev->ddev); vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode & AMDGPU_VM_USE_CPU_FOR_GFX); @@ -2707,6 +2761,7 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm) dma_fence_put(vm->last_update); vm->last_update = dma_fence_get_stub(); vm->is_compute_context = true; + vm->need_tlb_fence = true; unreserve_bo: amdgpu_bo_unreserve(vm->root.bo); @@ -2861,6 +2916,7 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev) xa_destroy(&adev->vm_manager.pasids); amdgpu_vmid_mgr_fini(adev); + amdgpu_pasid_mgr_cleanup(); } /** @@ -2936,14 +2992,14 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid, if (!root) return false; - addr /= AMDGPU_GPU_PAGE_SIZE; - if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid, - node_id, addr, ts, write_fault)) { + node_id, addr >> PAGE_SHIFT, ts, write_fault)) { amdgpu_bo_unref(&root); return true; } + addr /= AMDGPU_GPU_PAGE_SIZE; + r = amdgpu_bo_reserve(root, true); if (r) goto error_unref; @@ -3029,6 +3085,7 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m) amdgpu_vm_assert_locked(vm); + spin_lock(&vm->status_lock); seq_puts(m, "\tIdle BOs:\n"); list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) { if (!bo_va->base.bo) @@ -3066,13 +3123,11 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m) id = 0; seq_puts(m, "\tInvalidated BOs:\n"); - spin_lock(&vm->invalidated_lock); list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) { if (!bo_va->base.bo) continue; total_invalidated += amdgpu_bo_print_info(id++, bo_va->base.bo, m); } - spin_unlock(&vm->invalidated_lock); total_invalidated_objs = id; id = 0; @@ -3082,6 +3137,7 @@ void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m) continue; total_done += amdgpu_bo_print_info(id++, bo_va->base.bo, m); } + spin_unlock(&vm->status_lock); total_done_objs = id; seq_printf(m, "\tTotal idle size: %12lld\tobjs:\t%d\n", total_idle, @@ -3156,20 +3212,6 @@ void amdgpu_vm_update_fault_cache(struct amdgpu_device *adev, xa_unlock_irqrestore(&adev->vm_manager.pasids, flags); } -/** - * amdgpu_vm_is_bo_always_valid - check if the BO is VM always valid - * - * @vm: VM to test against. - * @bo: BO to be tested. - * - * Returns true if the BO shares the dma_resv object with the root PD and is - * always guaranteed to be valid inside the VM. - */ -bool amdgpu_vm_is_bo_always_valid(struct amdgpu_vm *vm, struct amdgpu_bo *bo) -{ - return bo && bo->tbo.base.resv == vm->root.bo->tbo.base.resv; -} - void amdgpu_vm_print_task_info(struct amdgpu_device *adev, struct amdgpu_task_info *task_info) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 87b0617d4661..3b32f41c3655 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -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) @@ -205,11 +205,11 @@ struct amdgpu_vm_bo_base { /* protected by bo being reserved */ struct amdgpu_vm_bo_base *next; - /* protected by vm reservation and invalidated_lock */ + /* protected by vm status_lock */ struct list_head vm_status; /* if the bo is counted as shared in mem stats - * protected by vm BO being reserved */ + * protected by vm status_lock */ bool shared; /* protected by the BO being reserved */ @@ -345,8 +345,10 @@ struct amdgpu_vm { bool evicting; unsigned int saved_flags; - /* Memory statistics for this vm, protected by stats_lock */ - spinlock_t stats_lock; + /* Lock to protect vm_bo add/del/move on all lists of vm */ + spinlock_t status_lock; + + /* Memory statistics for this vm, protected by status_lock */ struct amdgpu_mem_stats stats[__AMDGPU_PL_NUM]; /* @@ -354,8 +356,6 @@ struct amdgpu_vm { * PDs, PTs or per VM BOs. The state transits are: * * evicted -> relocated (PDs, PTs) or moved (per VM BOs) -> idle - * - * Lists are protected by the root PD dma_resv lock. */ /* Per-VM and PT BOs who needs a validation */ @@ -376,10 +376,7 @@ struct amdgpu_vm { * state transits are: * * evicted_user or invalidated -> done - * - * Lists are protected by the invalidated_lock. */ - spinlock_t invalidated_lock; /* BOs for user mode queues that need a validation */ struct list_head evicted_user; @@ -444,6 +441,8 @@ struct amdgpu_vm { struct ttm_lru_bulk_move lru_bulk_move; /* Flag to indicate if VM is used for compute */ bool is_compute_context; + /* Flag to indicate if VM needs a TLB fence (KFD or KGD) */ + bool need_tlb_fence; /* Memory partition number, -1 means any partition */ int8_t mem_id; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c index 7bdd664f0770..31a437ce9570 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c @@ -544,7 +544,9 @@ static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry) entry->bo->vm_bo = NULL; ttm_bo_set_bulk_move(&entry->bo->tbo, NULL); + spin_lock(&entry->vm->status_lock); list_del(&entry->vm_status); + spin_unlock(&entry->vm->status_lock); amdgpu_bo_unref(&entry->bo); } @@ -588,6 +590,7 @@ static void amdgpu_vm_pt_add_list(struct amdgpu_vm_update_params *params, struct amdgpu_vm_pt_cursor seek; struct amdgpu_vm_bo_base *entry; + spin_lock(¶ms->vm->status_lock); for_each_amdgpu_vm_pt_dfs_safe(params->adev, params->vm, cursor, seek, entry) { if (entry && entry->bo) list_move(&entry->vm_status, ¶ms->tlb_flush_waitlist); @@ -595,6 +598,7 @@ static void amdgpu_vm_pt_add_list(struct amdgpu_vm_update_params *params, /* enter start node now */ list_move(&cursor->entry->vm_status, ¶ms->tlb_flush_waitlist); + spin_unlock(¶ms->vm->status_lock); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index e36c287b3289..e63d05c477a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -472,12 +472,12 @@ static ssize_t amdgpu_xgmi_show_num_hops(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); struct psp_xgmi_topology_info *top = &adev->psp.xgmi_context.top_info; - int i; + int i, offset = 0; for (i = 0; i < top->num_nodes; i++) - sprintf(buf + 3 * i, "%02x ", top->nodes[i].num_hops); + offset += sysfs_emit_at(buf, offset, "%02x ", top->nodes[i].num_hops); - return sysfs_emit(buf, "%s\n", buf); + return offset + sysfs_emit_at(buf, offset, "\n"); } static ssize_t amdgpu_xgmi_show_num_links(struct device *dev, @@ -487,12 +487,12 @@ static ssize_t amdgpu_xgmi_show_num_links(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); struct psp_xgmi_topology_info *top = &adev->psp.xgmi_context.top_info; - int i; + int i, offset = 0; for (i = 0; i < top->num_nodes; i++) - sprintf(buf + 3 * i, "%02x ", top->nodes[i].num_links); + offset += sysfs_emit_at(buf, offset, "%02x ", top->nodes[i].num_links); - return sysfs_emit(buf, "%s\n", buf); + return offset + sysfs_emit_at(buf, offset, "\n"); } static ssize_t amdgpu_xgmi_show_connected_port_num(struct device *dev, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 1893ceeeb26c..8b60299b73ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -6752,7 +6752,7 @@ static void gfx_v10_0_gfx_mqd_set_priority(struct amdgpu_device *adev, /* set up default queue priority level * 0x0 = low priority, 0x1 = high priority */ - if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) + if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) priority = 1; tmp = RREG32_SOC15(GC, 0, mmCP_GFX_HQD_QUEUE_PRIORITY); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index b1a1b8a10a08..ae39b9e1f7d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -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; @@ -4088,7 +4102,7 @@ static void gfx_v11_0_gfx_mqd_set_priority(struct amdgpu_device *adev, /* set up default queue priority level * 0x0 = low priority, 0x1 = high priority */ - if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) + if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) priority = 1; tmp = regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c index 4e02b62cdbb3..db49582a211f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c @@ -45,6 +45,7 @@ #include "v12_structs.h" #include "gfx_v12_1.h" #include "mes_v12_1.h" +#include "amdgpu_ras_mgr.h" #define GFX12_MEC_HPD_SIZE 2048 #define NUM_SIMD_PER_CU_GFX12_1 4 @@ -136,7 +137,6 @@ static void gfx_v12_1_kiq_map_queues(struct amdgpu_ring *kiq_ring, PACKET3_MAP_QUEUES_PIPE(ring->pipe) | PACKET3_MAP_QUEUES_ME((me)) | PACKET3_MAP_QUEUES_QUEUE_TYPE(0) | /*queue_type: normal compute queue */ - PACKET3_MAP_QUEUES_ALLOC_FORMAT(0) | /* alloc format: all_on_one_pipe */ PACKET3_MAP_QUEUES_ENGINE_SEL(eng_sel) | PACKET3_MAP_QUEUES_NUM_QUEUES(1)); /* num_queues: must be 1 */ amdgpu_ring_write(kiq_ring, PACKET3_MAP_QUEUES_DOORBELL_OFFSET(ring->doorbell_index)); @@ -245,8 +245,7 @@ static void gfx_v12_1_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, /* memory (1) or register (0) */ (WAIT_REG_MEM_MEM_SPACE(mem_space) | WAIT_REG_MEM_OPERATION(opt) | /* wait */ - WAIT_REG_MEM_FUNCTION(3) | /* equal */ - WAIT_REG_MEM_ENGINE(eng_sel))); + WAIT_REG_MEM_FUNCTION(3))); /* equal */ if (mem_space) BUG_ON(addr0 & 0x3); /* Dword align */ @@ -1186,6 +1185,13 @@ static int gfx_v12_1_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; + /* RLC POISON Error */ + r = amdgpu_irq_add_id(adev, SOC_V1_0_IH_CLIENTID_RLC, + GFX_12_1_0__SRCID__RLC_POISON_INTERRUPT, + &adev->gfx.rlc_poison_irq); + if (r) + return r; + adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; r = gfx_v12_1_rlc_init(adev); @@ -2631,24 +2637,6 @@ static void gfx_v12_1_xcc_disable_gpa_mode(struct amdgpu_device *adev, WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCPG_PSP_DEBUG, data); } -static void gfx_v12_1_xcc_setup_tcp_thrashing_ctrl(struct amdgpu_device *adev, - int xcc_id) -{ - uint32_t val; - - /* Set the TCP UTCL0 register to enable atomics */ - val = RREG32_SOC15(GC, GET_INST(GC, xcc_id), - regTCP_UTCL0_THRASHING_CTRL); - val = REG_SET_FIELD(val, TCP_UTCL0_THRASHING_CTRL, THRASHING_EN, 0x2); - val = REG_SET_FIELD(val, TCP_UTCL0_THRASHING_CTRL, - RETRY_FRAGMENT_THRESHOLD_UP_EN, 0x1); - val = REG_SET_FIELD(val, TCP_UTCL0_THRASHING_CTRL, - RETRY_FRAGMENT_THRESHOLD_DOWN_EN, 0x1); - - WREG32_SOC15(GC, GET_INST(GC, xcc_id), - regTCP_UTCL0_THRASHING_CTRL, val); -} - static void gfx_v12_1_xcc_enable_atomics(struct amdgpu_device *adev, int xcc_id) { @@ -2697,7 +2685,6 @@ static void gfx_v12_1_init_golden_registers(struct amdgpu_device *adev) for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); i++) { gfx_v12_1_xcc_disable_burst(adev, i); gfx_v12_1_xcc_enable_atomics(adev, i); - gfx_v12_1_xcc_setup_tcp_thrashing_ctrl(adev, i); gfx_v12_1_xcc_disable_early_write_ack(adev, i); gfx_v12_1_xcc_disable_tcp_spill_cache(adev, i); } @@ -3431,11 +3418,10 @@ static void gfx_v12_1_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, static void gfx_v12_1_ring_emit_pipeline_sync(struct amdgpu_ring *ring) { - int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX); uint32_t seq = ring->fence_drv.sync_seq; uint64_t addr = ring->fence_drv.gpu_addr; - gfx_v12_1_wait_reg_mem(ring, usepfp, 1, 0, lower_32_bits(addr), + gfx_v12_1_wait_reg_mem(ring, 0, 1, 0, lower_32_bits(addr), upper_32_bits(addr), seq, 0xffffffff, 4); } @@ -3474,8 +3460,7 @@ static void gfx_v12_1_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, /* write fence seq to the "addr" */ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | - WRITE_DATA_DST_SEL(5) | WR_CONFIRM)); + amdgpu_ring_write(ring, (WRITE_DATA_DST_SEL(5) | WR_CONFIRM)); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -3483,8 +3468,7 @@ static void gfx_v12_1_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, if (flags & AMDGPU_FENCE_FLAG_INT) { /* set register to trigger INT */ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | - WRITE_DATA_DST_SEL(0) | WR_CONFIRM)); + amdgpu_ring_write(ring, (WRITE_DATA_DST_SEL(0) | WR_CONFIRM)); amdgpu_ring_write(ring, SOC15_REG_OFFSET(GC, GET_INST(GC, 0), regCPC_INT_STATUS)); amdgpu_ring_write(ring, 0); amdgpu_ring_write(ring, 0x20000000); /* src_id is 178 */ @@ -3543,9 +3527,7 @@ static void gfx_v12_1_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring, uint32_t reg0, uint32_t reg1, uint32_t ref, uint32_t mask) { - int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX); - - gfx_v12_1_wait_reg_mem(ring, usepfp, 0, 1, reg0, reg1, + gfx_v12_1_wait_reg_mem(ring, 0, 0, 1, reg0, reg1, ref, mask, 0x20); } @@ -3804,6 +3786,35 @@ static int gfx_v12_1_priv_inst_irq(struct amdgpu_device *adev, return 0; } +static int gfx_v12_1_rlc_poison_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + uint32_t rlc_fed_status = 0; + uint32_t ras_blk = RAS_BLOCK_ID__GFX; + struct ras_ih_info ih_info = {0}; + int i, num_xcc; + + num_xcc = NUM_XCC(adev->gfx.xcc_mask); + for (i = 0; i < num_xcc; i++) + rlc_fed_status |= RREG32(SOC15_REG_OFFSET(GC, + GET_INST(GC, i), regRLC_RLCS_FED_STATUS)); + + if (!rlc_fed_status) + return 0; + + if (REG_GET_FIELD(rlc_fed_status, RLC_RLCS_FED_STATUS, SDMA0_FED_ERR) || + REG_GET_FIELD(rlc_fed_status, RLC_RLCS_FED_STATUS, SDMA1_FED_ERR)) + ras_blk = RAS_BLOCK_ID__SDMA; + + dev_warn(adev->dev, "RLC %d FED IRQ\n", ras_blk); + + ih_info.block = ras_blk; + ih_info.reset = AMDGPU_RAS_GPU_RESET_MODE2_RESET; + amdgpu_ras_mgr_dispatch_interrupt(adev, &ih_info); + return 0; +} + static void gfx_v12_1_emit_mem_sync(struct amdgpu_ring *ring) { const unsigned int gcr_cntl = @@ -3928,6 +3939,10 @@ static const struct amdgpu_irq_src_funcs gfx_v12_1_priv_inst_irq_funcs = { .process = gfx_v12_1_priv_inst_irq, }; +static const struct amdgpu_irq_src_funcs gfx_v12_1_rlc_poison_irq_funcs = { + .process = gfx_v12_1_rlc_poison_irq, +}; + static void gfx_v12_1_set_irq_funcs(struct amdgpu_device *adev) { adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST; @@ -3938,6 +3953,9 @@ static void gfx_v12_1_set_irq_funcs(struct amdgpu_device *adev) adev->gfx.priv_inst_irq.num_types = 1; adev->gfx.priv_inst_irq.funcs = &gfx_v12_1_priv_inst_irq_funcs; + + adev->gfx.rlc_poison_irq.num_types = 1; + adev->gfx.rlc_poison_irq.funcs = &gfx_v12_1_rlc_poison_irq_funcs; } static void gfx_v12_1_set_imu_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1_pkt.h b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1_pkt.h index 9a5c82c8db53..21a07530c64d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1_pkt.h +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1_pkt.h @@ -53,16 +53,10 @@ /* Packet 3 types */ #define PACKET3_NOP 0x10 -#define PACKET3_SET_BASE 0x11 -#define PACKET3_BASE_INDEX(x) ((x) << 0) -#define CE_PARTITION_BASE 3 #define PACKET3_CLEAR_STATE 0x12 #define PACKET3_INDEX_BUFFER_SIZE 0x13 #define PACKET3_DISPATCH_DIRECT 0x15 #define PACKET3_DISPATCH_INDIRECT 0x16 -#define PACKET3_INDIRECT_BUFFER_END 0x17 -#define PACKET3_INDIRECT_BUFFER_CNST_END 0x19 -#define PACKET3_ATOMIC_GDS 0x1D #define PACKET3_ATOMIC_MEM 0x1E #define PACKET3_OCCLUSION_QUERY 0x1F #define PACKET3_SET_PREDICATION 0x20 @@ -74,47 +68,42 @@ #define PACKET3_INDEX_BASE 0x26 #define PACKET3_DRAW_INDEX_2 0x27 #define PACKET3_CONTEXT_CONTROL 0x28 -#define PACKET3_INDEX_TYPE 0x2A #define PACKET3_DRAW_INDIRECT_MULTI 0x2C #define PACKET3_DRAW_INDEX_AUTO 0x2D #define PACKET3_NUM_INSTANCES 0x2F #define PACKET3_DRAW_INDEX_MULTI_AUTO 0x30 -#define PACKET3_INDIRECT_BUFFER_PRIV 0x32 -#define PACKET3_INDIRECT_BUFFER_CNST 0x33 -#define PACKET3_COND_INDIRECT_BUFFER_CNST 0x33 -#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34 #define PACKET3_DRAW_INDEX_OFFSET_2 0x35 -#define PACKET3_DRAW_PREAMBLE 0x36 #define PACKET3_WRITE_DATA 0x37 -#define WRITE_DATA_DST_SEL(x) ((x) << 8) +#define WRITE_DATA_DST_SEL(x) (((x) & 0xf) << 8) /* 0 - register - * 1 - memory (sync - via GRBM) - * 2 - gl2 - * 3 - gds + * 1 - reserved + * 2 - tc_l2 + * 3 - reserved * 4 - reserved - * 5 - memory (async - direct) + * 5 - memory (same as tc_l2) + * 6 - memory_mapped_adc_persistent_state */ -#define WR_ONE_ADDR (1 << 16) +#define WRITE_DATA_SCOPE(x) (((x) & 0x3) << 12) +#define WRITE_DATA_MODE(x) (((x) & 0x3) << 14) + /* 0 - local xcd + * 1 - remote/local aid + * 2 - remote xcd + * 3 - remote mid + */ +#define WRITE_DATA_ADDR_INCR (1 << 16) +#define WRITE_DATA_MID_DIE_ID(x) (((x) & 0x3) << 18) #define WR_CONFIRM (1 << 20) -#define WRITE_DATA_CACHE_POLICY(x) ((x) << 25) - /* 0 - LRU - * 1 - Stream - */ -#define WRITE_DATA_ENGINE_SEL(x) ((x) << 30) - /* 0 - me - * 1 - pfp - * 2 - ce +#define WRITE_DATA_XCD_DIE_ID(x) (((x) & 0xf) << 21) +#define WRITE_DATA_TEMPORAL(x) (((x) & 0x3) << 25) + /* 0 - rt + * 1 - nt + * 2 - ht + * 3 - lu */ +#define WRITE_DATA_COOP_DISABLE (1 << 27) #define PACKET3_DRAW_INDEX_INDIRECT_MULTI 0x38 -#define PACKET3_MEM_SEMAPHORE 0x39 -# define PACKET3_SEM_USE_MAILBOX (0x1 << 16) -# define PACKET3_SEM_SEL_SIGNAL_TYPE (0x1 << 20) /* 0 = increment, 1 = write 1 */ -# define PACKET3_SEM_SEL_SIGNAL (0x6 << 29) -# define PACKET3_SEM_SEL_WAIT (0x7 << 29) -#define PACKET3_DRAW_INDEX_MULTI_INST 0x3A -#define PACKET3_COPY_DW 0x3B #define PACKET3_WAIT_REG_MEM 0x3C -#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) +#define WAIT_REG_MEM_FUNCTION(x) (((x) & 0x7) << 0) /* 0 - always * 1 - < * 2 - <= @@ -123,33 +112,66 @@ * 5 - >= * 6 - > */ -#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) +#define WAIT_REG_MEM_MEM_SPACE(x) (((x) & 0x3) << 4) /* 0 - reg * 1 - mem */ -#define WAIT_REG_MEM_OPERATION(x) ((x) << 6) +#define WAIT_REG_MEM_OPERATION(x) (((x) & 0x3) << 6) /* 0 - wait_reg_mem * 1 - wr_wait_wr_reg */ -#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) - /* 0 - me - * 1 - pfp +#define WAIT_REG_MEM_MODE(x) (((x) & 0x3) << 10) + /* 0 - local xcd + * 1 - remote/local aid + * 2 - remote xcd + * 3 - remote mid + */ +#define WAIT_REG_MEM_MID_DIE_ID(x) (((x) & 0x3) << 12) +#define WAIT_REG_MEM_XCD_DIE_ID(x) (((x) & 0xf) << 14) +#define WAIT_REG_MEM_MES_INTR_PIPE(x) (((x) & 0x3) << 22) +#define WAIT_REG_MEM_MES_ACTION(x) (((x) & 0x1) << 24) +#define WAIT_REG_MEM_TEMPORAL(x) (((x) & 0x3) << 25) + /* 0 - rt + * 1 - nt + * 2 - ht + * 3 - lu */ #define PACKET3_INDIRECT_BUFFER 0x3F #define INDIRECT_BUFFER_VALID (1 << 23) -#define INDIRECT_BUFFER_CACHE_POLICY(x) ((x) << 28) - /* 0 - LRU - * 1 - Stream - * 2 - Bypass +#define INDIRECT_BUFFER_TEMPORAL(x) (x) << 28) + /* 0 - rt + * 1 - nt + * 2 - ht + * 3 - lu */ -#define INDIRECT_BUFFER_PRE_ENB(x) ((x) << 21) -#define INDIRECT_BUFFER_PRE_RESUME(x) ((x) << 30) #define PACKET3_COND_INDIRECT_BUFFER 0x3F #define PACKET3_COPY_DATA 0x40 -#define PACKET3_CP_DMA 0x41 +#define COPY_DATA_SRC_SEL(x) (((x) & 0xf) << 0) +#define COPY_DATA_DST_SEL(x) (((x) & 0xf) << 8) +#define COPY_DATA_SRC_SCOPE(x) (((x) & 0x3) << 4) +#define COPY_DATA_DST_SCOPE(x) (((x) & 0x3) << 27) +#define COPY_DATA_MODE(x) (((x) & 0x3) << 6) + /* 0 - local xcd + * 1 - remote/local aid + * 2 - remote xcd + * 3 - remote mid + */ +#define COPY_DATA_SRC_TEMPORAL(x) (((x) & 0x3) << 13) +#define COPY_DATA_DST_TEMPORAL(x) (((x) & 0x3) << 25) + /* 0 - rt + * 1 - nt + * 2 - ht + * 3 - lu + */ +#define COPY_DATA_COUNT_SEL (1 << 16) +#define COPY_DATA_SRC_DST_REMOTE_MODE(x) (((x)) & 0x1 << 16) + /* 0 - src remote + * 1 - dst remote + */ +#define COPY_DATA_MID_DIE_ID(x) (((x) & 0x3) << 18) +#define COPY_DATA_XCD_DIE_ID(x) (((x) & 0xf) << 21) +#define COPY_DATA_PQ_EXE_STATUS (1 << 27) #define PACKET3_PFP_SYNC_ME 0x42 -#define PACKET3_SURFACE_SYNC 0x43 -#define PACKET3_ME_INITIALIZE 0x44 #define PACKET3_COND_WRITE 0x45 #define PACKET3_EVENT_WRITE 0x46 #define EVENT_TYPE(x) ((x) << 0) @@ -160,8 +182,6 @@ * 3 - SAMPLE_STREAMOUTSTAT* * 4 - *S_PARTIAL_FLUSH */ -#define PACKET3_EVENT_WRITE_EOP 0x47 -#define PACKET3_EVENT_WRITE_EOS 0x48 #define PACKET3_RELEASE_MEM 0x49 #define PACKET3_RELEASE_MEM_EVENT_TYPE(x) ((x) << 0) #define PACKET3_RELEASE_MEM_EVENT_INDEX(x) ((x) << 8) @@ -180,27 +200,30 @@ * 2 - temporal__release_mem__ht * 3 - temporal__release_mem__lu */ -#define PACKET3_RELEASE_MEM_EXECUTE (1 << 28) +#define PACKET3_RELEASE_MEM_PQ_EXE_STATUS (1 << 28) +#define PACKET3_RELEASE_MEM_GCR_GLK_INV (1 << 30) -#define PACKET3_RELEASE_MEM_DATA_SEL(x) ((x) << 29) - /* 0 - discard - * 1 - send low 32bit data - * 2 - send 64bit data - * 3 - send 64bit GPU counter value - * 4 - send 64bit sys counter value +#define PACKET3_RELEASE_MEM_DST_SEL(x) ((x) << 16) + /* 0 - memory controller + * 1 - TC/L2 + * 2 - register */ +#define PACKET3_RELEASE_MEM_MES_INTR_PIPE(x) ((x) << 20) +#define PACKET3_RELEASE_MEM_MES_ACTION_ID(x) ((x) << 22) #define PACKET3_RELEASE_MEM_INT_SEL(x) ((x) << 24) /* 0 - none * 1 - interrupt only (DATA_SEL = 0) * 2 - interrupt when data write is confirmed */ -#define PACKET3_RELEASE_MEM_DST_SEL(x) ((x) << 16) - /* 0 - MC - * 1 - TC/L2 +#define PACKET3_RELEASE_MEM_ADD_DOOREBLL_OFFSET(x) (1 << 28) +#define PACKET3_RELEASE_MEM_DATA_SEL(x) ((x) << 29) + /* 0 - discard + * 1 - send low 32bit data + * 2 - send 64bit data + * 3 - send 64bit GPU counter value + * 4 - send 64bit sys counter value */ - - #define PACKET3_PREAMBLE_CNTL 0x4A # define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE (2 << 28) # define PACKET3_PREAMBLE_END_CLEAR_STATE (3 << 28) @@ -218,26 +241,29 @@ /* 0 - ME * 1 - PFP */ -# define PACKET3_DMA_DATA_SRC_CACHE_POLICY(x) ((x) << 13) - /* 0 - LRU - * 1 - Stream +# define PACKET3_DMA_DATA_SRC_TEMPORAL(x) ((x) << 13) + /* 0 - rt + * 1 - nt + * 2 - ht + * 3 - lu */ -# define PACKET3_DMA_DATA_DST_SEL(x) ((x) << 20) +# define PACKET3_DMA_DATA_SRC_SCOPE(x) ((x) << 15) +# define PACKET3_DMA_DATA_DST_SEL(x) ((x) << 20) /* 0 - DST_ADDR using DAS * 1 - GDS * 3 - DST_ADDR using L2 */ -# define PACKET3_DMA_DATA_DST_CACHE_POLICY(x) ((x) << 25) +# define PACKET3_DMA_DATA_DST_TEMPORAL(x) ((x) << 25) /* 0 - LRU * 1 - Stream */ -# define PACKET3_DMA_DATA_SRC_SEL(x) ((x) << 29) +# define PACKET3_DMA_DATA_DST_SCOPE(x) ((x) << 27) +# define PACKET3_DMA_DATA_SRC_SEL(x) ((x) << 29) /* 0 - SRC_ADDR using SAS * 1 - GDS * 2 - DATA * 3 - SRC_ADDR using L2 */ -# define PACKET3_DMA_DATA_CP_SYNC (1 << 31) /* COMMAND */ # define PACKET3_DMA_DATA_CMD_SAS (1 << 26) /* 0 - memory @@ -247,13 +273,11 @@ /* 0 - memory * 1 - register */ -# define PACKET3_DMA_DATA_CMD_SAIC (1 << 28) -# define PACKET3_DMA_DATA_CMD_DAIC (1 << 29) -# define PACKET3_DMA_DATA_CMD_RAW_WAIT (1 << 30) +# define PACKET3_DMA_DATA_CMD_SAIC (1 << 28) +# define PACKET3_DMA_DATA_CMD_DAIC (1 << 29) +# define PACKET3_DMA_DATA_CMD_RAW_WAIT (1 << 30) +# define PACKET3_DMA_DATA_CMD_DIS_WC (1 << 30) #define PACKET3_CONTEXT_REG_RMW 0x51 -#define PACKET3_GFX_CNTX_UPDATE 0x52 -#define PACKET3_BLK_CNTX_UPDATE 0x53 -#define PACKET3_INCR_UPDT_STATE 0x55 #define PACKET3_ACQUIRE_MEM 0x58 /* 1. HEADER * 2. COHER_CNTL [30:0] @@ -307,10 +331,7 @@ * 2: REVERSE */ #define PACKET3_ACQUIRE_MEM_GCR_RANGE_IS_PA (1 << 18) -#define PACKET3_REWIND 0x59 -#define PACKET3_INTERRUPT 0x5A #define PACKET3_GEN_PDEPTE 0x5B -#define PACKET3_INDIRECT_BUFFER_PASID 0x5C #define PACKET3_PRIME_UTCL2 0x5D #define PACKET3_LOAD_UCONFIG_REG 0x5E #define PACKET3_LOAD_SH_REG 0x5F @@ -324,12 +345,6 @@ #define PACKET3_SET_CONTEXT_REG 0x69 #define PACKET3_SET_CONTEXT_REG_START 0x0000a000 #define PACKET3_SET_CONTEXT_REG_END 0x0000a400 -#define PACKET3_SET_CONTEXT_REG_INDEX 0x6A -#define PACKET3_SET_VGPR_REG_DI_MULTI 0x71 -#define PACKET3_SET_SH_REG_DI 0x72 -#define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73 -#define PACKET3_SET_SH_REG_DI_MULTI 0x74 -#define PACKET3_GFX_PIPE_LOCK 0x75 #define PACKET3_SET_SH_REG 0x76 #define PACKET3_SET_SH_REG_START 0x00002c00 #define PACKET3_SET_SH_REG_END 0x00003000 @@ -339,47 +354,19 @@ #define PACKET3_SET_UCONFIG_REG_START 0x0000c000 #define PACKET3_SET_UCONFIG_REG_END 0x0000c400 #define PACKET3_SET_UCONFIG_REG_INDEX 0x7A -#define PACKET3_FORWARD_HEADER 0x7C -#define PACKET3_SCRATCH_RAM_WRITE 0x7D -#define PACKET3_SCRATCH_RAM_READ 0x7E -#define PACKET3_LOAD_CONST_RAM 0x80 -#define PACKET3_WRITE_CONST_RAM 0x81 -#define PACKET3_DUMP_CONST_RAM 0x83 -#define PACKET3_INCREMENT_CE_COUNTER 0x84 -#define PACKET3_INCREMENT_DE_COUNTER 0x85 -#define PACKET3_WAIT_ON_CE_COUNTER 0x86 -#define PACKET3_WAIT_ON_DE_COUNTER_DIFF 0x88 -#define PACKET3_SWITCH_BUFFER 0x8B #define PACKET3_DISPATCH_DRAW_PREAMBLE 0x8C -#define PACKET3_DISPATCH_DRAW_PREAMBLE_ACE 0x8C #define PACKET3_DISPATCH_DRAW 0x8D -#define PACKET3_DISPATCH_DRAW_ACE 0x8D -#define PACKET3_GET_LOD_STATS 0x8E -#define PACKET3_DRAW_MULTI_PREAMBLE 0x8F -#define PACKET3_FRAME_CONTROL 0x90 -# define FRAME_TMZ (1 << 0) -# define FRAME_CMD(x) ((x) << 28) - /* - * x=0: tmz_begin - * x=1: tmz_end - */ #define PACKET3_INDEX_ATTRIBUTES_INDIRECT 0x91 #define PACKET3_WAIT_REG_MEM64 0x93 -#define PACKET3_COND_PREEMPT 0x94 #define PACKET3_HDP_FLUSH 0x95 -#define PACKET3_COPY_DATA_RB 0x96 #define PACKET3_INVALIDATE_TLBS 0x98 #define PACKET3_INVALIDATE_TLBS_DST_SEL(x) ((x) << 0) #define PACKET3_INVALIDATE_TLBS_ALL_HUB(x) ((x) << 4) #define PACKET3_INVALIDATE_TLBS_PASID(x) ((x) << 5) #define PACKET3_INVALIDATE_TLBS_FLUSH_TYPE(x) ((x) << 29) -#define PACKET3_AQL_PACKET 0x99 #define PACKET3_DMA_DATA_FILL_MULTI 0x9A #define PACKET3_SET_SH_REG_INDEX 0x9B -#define PACKET3_DRAW_INDIRECT_COUNT_MULTI 0x9C -#define PACKET3_DRAW_INDEX_INDIRECT_COUNT_MULTI 0x9D -#define PACKET3_DUMP_CONST_RAM_OFFSET 0x9E #define PACKET3_LOAD_CONTEXT_REG_INDEX 0x9F #define PACKET3_SET_RESOURCES 0xA0 /* 1. header @@ -394,7 +381,6 @@ # define PACKET3_SET_RESOURCES_VMID_MASK(x) ((x) << 0) # define PACKET3_SET_RESOURCES_UNMAP_LATENTY(x) ((x) << 16) # define PACKET3_SET_RESOURCES_QUEUE_TYPE(x) ((x) << 29) -#define PACKET3_MAP_PROCESS 0xA1 #define PACKET3_MAP_QUEUES 0xA2 /* 1. header * 2. CONTROL @@ -411,11 +397,10 @@ # define PACKET3_MAP_QUEUES_PIPE(x) ((x) << 16) # define PACKET3_MAP_QUEUES_ME(x) ((x) << 18) # define PACKET3_MAP_QUEUES_QUEUE_TYPE(x) ((x) << 21) -# define PACKET3_MAP_QUEUES_ALLOC_FORMAT(x) ((x) << 24) +# define PACKET3_MAP_QUEUES_QUEUE_GROUP(x) ((x) << 24) # define PACKET3_MAP_QUEUES_ENGINE_SEL(x) ((x) << 26) # define PACKET3_MAP_QUEUES_NUM_QUEUES(x) ((x) << 29) /* CONTROL2 */ -# define PACKET3_MAP_QUEUES_CHECK_DISABLE(x) ((x) << 1) # define PACKET3_MAP_QUEUES_DOORBELL_OFFSET(x) ((x) << 2) #define PACKET3_UNMAP_QUEUES 0xA3 /* 1. header @@ -464,12 +449,6 @@ # define PACKET3_QUERY_STATUS_PASID(x) ((x) << 0) /* CONTROL2b */ # define PACKET3_QUERY_STATUS_DOORBELL_OFFSET(x) ((x) << 2) -# define PACKET3_QUERY_STATUS_ENG_SEL(x) ((x) << 25) -#define PACKET3_RUN_LIST 0xA5 -#define PACKET3_MAP_PROCESS_VM 0xA6 -/* GFX11 */ -#define PACKET3_SET_Q_PREEMPTION_MODE 0xF0 -# define PACKET3_SET_Q_PREEMPTION_MODE_IB_VMID(x) ((x) << 0) -# define PACKET3_SET_Q_PREEMPTION_MODE_INIT_SHADOW_MEM (1 << 0) +# define PACKET3_QUERY_STATUS_ENG_SEL(x) ((x) << 28) #endif diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c index 4aa004ee2c4d..3544eb42dca6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c @@ -146,71 +146,15 @@ static void gfxhub_v12_1_xcc_init_system_aperture_regs(struct amdgpu_device *ade uint32_t tmp; int i; - for_each_inst(i, xcc_mask) { - /* Program the AGP BAR */ - WREG32_SOC15_RLC(GC, GET_INST(GC, i), - regGCMC_VM_AGP_BASE_LO32, 0); - WREG32_SOC15_RLC(GC, GET_INST(GC, i), - regGCMC_VM_AGP_BASE_HI32, 0); - WREG32_SOC15_RLC(GC, GET_INST(GC, i), - regGCMC_VM_AGP_BOT_LO32, - lower_32_bits(adev->gmc.agp_start >> 24)); - WREG32_SOC15_RLC(GC, GET_INST(GC, i), - regGCMC_VM_AGP_BOT_HI32, - upper_32_bits(adev->gmc.agp_start >> 24)); - WREG32_SOC15_RLC(GC, GET_INST(GC, i), - regGCMC_VM_AGP_TOP_LO32, - lower_32_bits(adev->gmc.agp_end >> 24)); - WREG32_SOC15_RLC(GC, GET_INST(GC, i), - regGCMC_VM_AGP_TOP_HI32, - upper_32_bits(adev->gmc.agp_end >> 24)); + /*TODO: revisit whether the SRIOV guest access to theseregisters + * is blocked by security policy or not */ + if (amdgpu_sriov_vf(adev)) + return; - if (!amdgpu_sriov_vf(adev)) { - /* Program the system aperture low logical page number. */ - WREG32_SOC15(GC, GET_INST(GC, i), - regGCMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32, - lower_32_bits(min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18)); - WREG32_SOC15(GC, GET_INST(GC, i), - regGCMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32, - upper_32_bits(min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18)); - WREG32_SOC15(GC, GET_INST(GC, i), - regGCMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, - lower_32_bits(max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18)); - WREG32_SOC15(GC, GET_INST(GC, i), - regGCMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, - upper_32_bits(max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18)); - - /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); - WREG32_SOC15(GC, GET_INST(GC, i), - regGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, - (u32)(value >> 12)); - WREG32_SOC15(GC, GET_INST(GC, i), - regGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, - (u32)(value >> 44)); - - /* Program "protection fault". */ - WREG32_SOC15(GC, GET_INST(GC, i), - regGCVM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, - (u32)(adev->dummy_page_addr >> 12)); - WREG32_SOC15(GC, GET_INST(GC, i), - regGCVM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, - (u32)((u64)adev->dummy_page_addr >> 44)); - - tmp = RREG32_SOC15(GC, GET_INST(GC, i), - regGCVM_L2_PROTECTION_FAULT_CNTL2); - tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL2, - ACTIVE_PAGE_MIGRATION_PTE_READ_RETRY, 1); - tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL2, - ENABLE_RETRY_FAULT_INTERRUPT, 0x1); - WREG32_SOC15(GC, GET_INST(GC, i), - regGCVM_L2_PROTECTION_FAULT_CNTL2, tmp); - } - - /* In the case squeezing vram into GART aperture, we don't use - * FB aperture and AGP aperture. Disable them. - */ + for_each_inst(i, xcc_mask) { if (adev->gmc.pdb0_bo) { + /* Disable agp and system aperture + * when vmid0 page table is enabled */ WREG32_SOC15(GC, GET_INST(GC, i), regGCMC_VM_FB_LOCATION_TOP_LO32, 0); WREG32_SOC15(GC, GET_INST(GC, i), @@ -225,7 +169,8 @@ static void gfxhub_v12_1_xcc_init_system_aperture_regs(struct amdgpu_device *ade WREG32_SOC15(GC, GET_INST(GC, i), regGCMC_VM_AGP_TOP_HI32, 0); WREG32_SOC15(GC, GET_INST(GC, i), - regGCMC_VM_AGP_BOT_LO32, 0xFFFFFFFF); + regGCMC_VM_AGP_BOT_LO32, + 0xFFFFFFFF); WREG32_SOC15(GC, GET_INST(GC, i), regGCMC_VM_AGP_BOT_HI32, 1); WREG32_SOC15(GC, GET_INST(GC, i), @@ -238,7 +183,69 @@ static void gfxhub_v12_1_xcc_init_system_aperture_regs(struct amdgpu_device *ade regGCMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, 0); WREG32_SOC15(GC, GET_INST(GC, i), regGCMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, 0); + } else { + /* Program the AGP BAR */ + WREG32_SOC15_RLC(GC, GET_INST(GC, i), + regGCMC_VM_AGP_BASE_LO32, 0); + WREG32_SOC15_RLC(GC, GET_INST(GC, i), + regGCMC_VM_AGP_BASE_HI32, 0); + WREG32_SOC15_RLC(GC, GET_INST(GC, i), + regGCMC_VM_AGP_BOT_LO32, + lower_32_bits(adev->gmc.agp_start >> 24)); + WREG32_SOC15_RLC(GC, GET_INST(GC, i), + regGCMC_VM_AGP_BOT_HI32, + upper_32_bits(adev->gmc.agp_start >> 24)); + WREG32_SOC15_RLC(GC, GET_INST(GC, i), + regGCMC_VM_AGP_TOP_LO32, + lower_32_bits(adev->gmc.agp_end >> 24)); + WREG32_SOC15_RLC(GC, GET_INST(GC, i), + regGCMC_VM_AGP_TOP_HI32, + upper_32_bits(adev->gmc.agp_end >> 24)); + + /* Program the system aperture low logical page number. */ + WREG32_SOC15(GC, GET_INST(GC, i), + regGCMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32, + lower_32_bits(min(adev->gmc.fb_start, + adev->gmc.agp_start) >> 18)); + WREG32_SOC15(GC, GET_INST(GC, i), + regGCMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32, + upper_32_bits(min(adev->gmc.fb_start, + adev->gmc.agp_start) >> 18)); + WREG32_SOC15(GC, GET_INST(GC, i), + regGCMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, + lower_32_bits(max(adev->gmc.fb_end, + adev->gmc.agp_end) >> 18)); + WREG32_SOC15(GC, GET_INST(GC, i), + regGCMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, + upper_32_bits(max(adev->gmc.fb_end, + adev->gmc.agp_end) >> 18)); } + + /* Set default page address. */ + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); + WREG32_SOC15(GC, GET_INST(GC, i), + regGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, + (u32)(value >> 12)); + WREG32_SOC15(GC, GET_INST(GC, i), + regGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, + (u32)(value >> 44)); + + /* Program "protection fault". */ + WREG32_SOC15(GC, GET_INST(GC, i), + regGCVM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, + (u32)(adev->dummy_page_addr >> 12)); + WREG32_SOC15(GC, GET_INST(GC, i), + regGCVM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, + (u32)((u64)adev->dummy_page_addr >> 44)); + + tmp = RREG32_SOC15(GC, GET_INST(GC, i), + regGCVM_L2_PROTECTION_FAULT_CNTL2); + tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL2, + ACTIVE_PAGE_MIGRATION_PTE_READ_RETRY, 1); + tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL2, + ENABLE_RETRY_FAULT_INTERRUPT, 0x1); + WREG32_SOC15(GC, GET_INST(GC, i), + regGCVM_L2_PROTECTION_FAULT_CNTL2, tmp); } } @@ -325,10 +332,18 @@ static void gfxhub_v12_1_xcc_init_cache_regs(struct amdgpu_device *adev, WREG32_SOC15_RLC(GC, GET_INST(GC, i), regGCVM_L2_CNTL3, tmp); tmp = regGCVM_L2_CNTL4_DEFAULT; - tmp = REG_SET_FIELD(tmp, GCVM_L2_CNTL4, - VMC_TAP_PDE_REQUEST_PHYSICAL, 1); - tmp = REG_SET_FIELD(tmp, GCVM_L2_CNTL4, - VMC_TAP_PTE_REQUEST_PHYSICAL, 1); + if (adev->gmc.xgmi.connected_to_cpu) { + tmp = REG_SET_FIELD(tmp, GCVM_L2_CNTL4, + VMC_TAP_PDE_REQUEST_PHYSICAL, 1); + tmp = REG_SET_FIELD(tmp, GCVM_L2_CNTL4, + VMC_TAP_PTE_REQUEST_PHYSICAL, 1); + } else { + tmp = REG_SET_FIELD(tmp, GCVM_L2_CNTL4, + VMC_TAP_PDE_REQUEST_PHYSICAL, 0); + tmp = REG_SET_FIELD(tmp, GCVM_L2_CNTL4, + VMC_TAP_PTE_REQUEST_PHYSICAL, 0); + } + WREG32_SOC15_RLC(GC, GET_INST(GC, i), regGCVM_L2_CNTL4, tmp); tmp = regGCVM_L2_CNTL5_DEFAULT; @@ -807,47 +822,6 @@ static void gfxhub_v12_1_init(struct amdgpu_device *adev) gfxhub_v12_1_xcc_init(adev, xcc_mask); } -static int gfxhub_v12_1_get_xgmi_info(struct amdgpu_device *adev) -{ - u32 max_num_physical_nodes; - u32 max_physical_node_id; - u32 xgmi_lfb_cntl; - u32 max_region; - u64 seg_size; - - xgmi_lfb_cntl = RREG32_SOC15(GC, GET_INST(GC, 0), - regGCMC_VM_XGMI_LFB_CNTL); - seg_size = REG_GET_FIELD(RREG32_SOC15(GC, GET_INST(GC, 0), - regGCMC_VM_XGMI_LFB_SIZE), - GCMC_VM_XGMI_LFB_SIZE, PF_LFB_SIZE) << 24; - max_region = REG_GET_FIELD(xgmi_lfb_cntl, - GCMC_VM_XGMI_LFB_CNTL, - PF_MAX_REGION); - - max_num_physical_nodes = 8; - max_physical_node_id = 7; - - /* PF_MAX_REGION=0 means xgmi is disabled */ - if (max_region || adev->gmc.xgmi.connected_to_cpu) { - adev->gmc.xgmi.num_physical_nodes = max_region + 1; - - if (adev->gmc.xgmi.num_physical_nodes > max_num_physical_nodes) - return -EINVAL; - - adev->gmc.xgmi.physical_node_id = - REG_GET_FIELD(xgmi_lfb_cntl, - GCMC_VM_XGMI_LFB_CNTL, - PF_LFB_REGION); - - if (adev->gmc.xgmi.physical_node_id > max_physical_node_id) - return -EINVAL; - - adev->gmc.xgmi.node_segment_size = seg_size; - } - - return 0; -} - const struct amdgpu_gfxhub_funcs gfxhub_v12_1_funcs = { .get_fb_location = gfxhub_v12_1_get_fb_location, .get_mc_fb_offset = gfxhub_v12_1_get_mc_fb_offset, @@ -856,7 +830,6 @@ const struct amdgpu_gfxhub_funcs gfxhub_v12_1_funcs = { .gart_disable = gfxhub_v12_1_gart_disable, .set_fault_enable_default = gfxhub_v12_1_set_fault_enable_default, .init = gfxhub_v12_1_init, - .get_xgmi_info = gfxhub_v12_1_get_xgmi_info, }; static int gfxhub_v12_1_xcp_resume(void *handle, uint32_t inst_mask) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index 2568eeaae945..fd691b2a6e21 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index 6349e239a367..e6db87b94eb1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c index da4a0cf4aad0..6e184ea069ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c @@ -636,6 +636,11 @@ static int gmc_v12_0_early_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; + if (adev->smuio.funcs && + adev->smuio.funcs->is_host_gpu_xgmi_supported) + adev->gmc.xgmi.connected_to_cpu = + adev->smuio.funcs->is_host_gpu_xgmi_supported(adev); + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(12, 1, 0): gmc_v12_1_set_gmc_funcs(adev); @@ -691,17 +696,23 @@ static void gmc_v12_0_vram_gtt_location(struct amdgpu_device *adev, base = adev->mmhub.funcs->get_fb_location(adev); - amdgpu_gmc_set_agp_default(adev, mc); - amdgpu_gmc_vram_location(adev, &adev->gmc, base); - amdgpu_gmc_gart_location(adev, mc, AMDGPU_GART_PLACEMENT_LOW); - if (!amdgpu_sriov_vf(adev) && (amdgpu_agp == 1)) - amdgpu_gmc_agp_location(adev, mc); - + if (amdgpu_gmc_is_pdb0_enabled(adev)) { + amdgpu_gmc_sysvm_location(adev, mc); + } else { + amdgpu_gmc_set_agp_default(adev, mc); + amdgpu_gmc_vram_location(adev, &adev->gmc, base); + amdgpu_gmc_gart_location(adev, mc, AMDGPU_GART_PLACEMENT_LOW); + if (!amdgpu_sriov_vf(adev) && (amdgpu_agp == 1)) + amdgpu_gmc_agp_location(adev, mc); + } /* base offset of vram pages */ if (amdgpu_sriov_vf(adev)) adev->vm_manager.vram_base_offset = 0; else adev->vm_manager.vram_base_offset = adev->mmhub.funcs->get_mc_fb_offset(adev); + + adev->vm_manager.vram_base_offset += + adev->gmc.xgmi.physical_node_id * adev->gmc.xgmi.node_segment_size; } /** @@ -717,12 +728,17 @@ static int gmc_v12_0_mc_init(struct amdgpu_device *adev) { int r; - /* size in MB on si */ - adev->gmc.mc_vram_size = - adev->nbio.funcs->get_memsize(adev) * 1024ULL * 1024ULL; + if (adev->gmc.xgmi.connected_to_cpu) + adev->gmc.mc_vram_size = + adev->gmc.xgmi.node_segment_size * adev->gmc.xgmi.num_physical_nodes; + else + adev->gmc.mc_vram_size = + adev->nbio.funcs->get_memsize(adev) * 1024ULL * 1024ULL; + adev->gmc.real_vram_size = adev->gmc.mc_vram_size; - if (!(adev->flags & AMD_IS_APU)) { + if (!(adev->flags & AMD_IS_APU) && + !adev->gmc.xgmi.connected_to_cpu) { r = amdgpu_device_resize_fb_bar(adev); if (r) return r; @@ -732,8 +748,12 @@ static int gmc_v12_0_mc_init(struct amdgpu_device *adev) adev->gmc.aper_size = pci_resource_len(adev->pdev, 0); #ifdef CONFIG_X86_64 - if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev)) { - adev->gmc.aper_base = adev->mmhub.funcs->get_mc_fb_offset(adev); + if (((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev)) || + (adev->gmc.xgmi.connected_to_cpu)) { + adev->gmc.aper_base = + adev->mmhub.funcs->get_mc_fb_offset(adev) + + adev->gmc.xgmi.physical_node_id * + adev->gmc.xgmi.node_segment_size; adev->gmc.aper_size = adev->gmc.real_vram_size; } #endif @@ -762,6 +782,14 @@ static int gmc_v12_0_gart_init(struct amdgpu_device *adev) return 0; } + if (amdgpu_gmc_is_pdb0_enabled(adev)) { + adev->gmc.vmid0_page_table_depth = 1; + adev->gmc.vmid0_page_table_block_size = 12; + } else { + adev->gmc.vmid0_page_table_depth = 0; + adev->gmc.vmid0_page_table_block_size = 0; + } + /* Initialize common gart structure */ r = amdgpu_gart_init(adev); if (r) @@ -772,7 +800,14 @@ static int gmc_v12_0_gart_init(struct amdgpu_device *adev) AMDGPU_PTE_EXECUTABLE | AMDGPU_PTE_IS_PTE; - return amdgpu_gart_table_vram_alloc(adev); + r = amdgpu_gart_table_vram_alloc(adev); + if (r) + return r; + + if (amdgpu_gmc_is_pdb0_enabled(adev)) + r = amdgpu_gmc_pdb0_alloc(adev); + + return r; } static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block) @@ -790,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; @@ -858,11 +893,15 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; - if ((amdgpu_ip_version(adev, GC_HWIP, 0) != IP_VERSION(12, 1, 0)) && - !amdgpu_sriov_vf(adev)) { + if (!amdgpu_sriov_vf(adev)) { /* interrupt sent to DF. */ - r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_DF, 0, + if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 0, 0)) + r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_DF, 0, + &adev->gmc.ecc_irq); + else + r = amdgpu_irq_add_id(adev, SOC_V1_0_IH_CLIENTID_DF, 0, &adev->gmc.ecc_irq); + if (r) return r; } @@ -944,6 +983,7 @@ static int gmc_v12_0_sw_fini(struct amdgpu_ip_block *ip_block) amdgpu_vm_manager_fini(adev); gmc_v12_0_gart_fini(adev); amdgpu_gem_force_release(adev); + amdgpu_bo_free_kernel(&adev->gmc.pdb0_bo, NULL, &adev->gmc.ptr_pdb0); amdgpu_bo_fini(adev); return 0; @@ -963,6 +1003,9 @@ static int gmc_v12_0_gart_enable(struct amdgpu_device *adev) int r; bool value; + if (adev->gmc.xgmi.connected_to_cpu) + amdgpu_gmc_init_pdb0(adev); + if (adev->gart.bo == NULL) { dev_err(adev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; @@ -984,6 +1027,7 @@ static int gmc_v12_0_gart_enable(struct amdgpu_device *adev) drm_info(adev_to_drm(adev), "PCIE GART of %uM enabled (table at 0x%016llX).\n", (unsigned)(adev->gmc.gart_size >> 20), + (adev->gmc.pdb0_bo) ? (unsigned long long)amdgpu_bo_gpu_offset(adev->gmc.pdb0_bo) : (unsigned long long)amdgpu_bo_gpu_offset(adev->gart.bo)); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c index c49112d8300e..7ea7b9c30bca 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_1.c @@ -524,20 +524,27 @@ static void gmc_v12_1_get_coherence_flags(struct amdgpu_device *adev, bool ext_coherent = bo->flags & AMDGPU_GEM_CREATE_EXT_COHERENT; uint32_t gc_ip_version = amdgpu_ip_version(adev, GC_HWIP, 0); bool uncached = bo->flags & AMDGPU_GEM_CREATE_UNCACHED; - unsigned int mtype, mtype_local; + unsigned int mtype, mtype_local, mtype_remote; bool snoop = false; bool is_local = false; + bool is_aid_a1; switch (gc_ip_version) { case IP_VERSION(12, 1, 0): - mtype_local = MTYPE_RW; - if (amdgpu_mtype_local == 1) { + is_aid_a1 = (adev->rev_id & 0x10); + + mtype_local = is_aid_a1 ? MTYPE_RW : MTYPE_NC; + mtype_remote = is_aid_a1 ? MTYPE_NC : MTYPE_UC; + if (amdgpu_mtype_local == 0) { + DRM_INFO_ONCE("Using MTYPE_RW for local memory\n"); + mtype_local = MTYPE_RW; + } else if (amdgpu_mtype_local == 1) { DRM_INFO_ONCE("Using MTYPE_NC for local memory\n"); mtype_local = MTYPE_NC; } else if (amdgpu_mtype_local == 2) { - DRM_INFO_ONCE("MTYPE_CC not supported, using MTYPE_RW instead for local memory\n"); + DRM_INFO_ONCE("MTYPE_CC not supported, using %s for local memory\n", is_aid_a1 ? "MTYPE_RW" : "MTYPE_NC"); } else { - DRM_INFO_ONCE("Using MTYPE_RW for local memory\n"); + DRM_INFO_ONCE("Using %s for local memory\n", is_aid_a1 ? "MTYPE_RW" : "MTYPE_NC"); } is_local = (is_vram && adev == bo_adev); @@ -547,10 +554,7 @@ static void gmc_v12_1_get_coherence_flags(struct amdgpu_device *adev, } else if (ext_coherent) { mtype = is_local ? mtype_local : MTYPE_UC; } else { - if (is_local) - mtype = mtype_local; - else - mtype = MTYPE_NC; + mtype = is_local ? mtype_local : mtype_remote; } break; default: @@ -621,10 +625,17 @@ static const struct amdgpu_irq_src_funcs gmc_v12_1_irq_funcs = { .process = gmc_v12_1_process_interrupt, }; +static const struct amdgpu_irq_src_funcs gmc_v12_1_ecc_funcs = { + .process = amdgpu_umc_uniras_process_ecc_irq, +}; + void gmc_v12_1_set_irq_funcs(struct amdgpu_device *adev) { adev->gmc.vm_fault.num_types = 1; adev->gmc.vm_fault.funcs = &gmc_v12_1_irq_funcs; + + adev->gmc.ecc_irq.num_types = 1; + adev->gmc.ecc_irq.funcs = &gmc_v12_1_ecc_funcs; } void gmc_v12_1_init_vram_info(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index e35ed0cc2ec6..d865059e884a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -660,35 +660,7 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, gfxhub_client_ids[cid], cid); } else { - switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { - case IP_VERSION(9, 0, 0): - mmhub_cid = mmhub_client_ids_vega10[cid][rw]; - break; - case IP_VERSION(9, 3, 0): - mmhub_cid = mmhub_client_ids_vega12[cid][rw]; - break; - case IP_VERSION(9, 4, 0): - mmhub_cid = mmhub_client_ids_vega20[cid][rw]; - break; - case IP_VERSION(9, 4, 1): - mmhub_cid = mmhub_client_ids_arcturus[cid][rw]; - break; - case IP_VERSION(9, 1, 0): - case IP_VERSION(9, 2, 0): - mmhub_cid = mmhub_client_ids_raven[cid][rw]; - break; - case IP_VERSION(1, 5, 0): - case IP_VERSION(2, 4, 0): - mmhub_cid = mmhub_client_ids_renoir[cid][rw]; - break; - case IP_VERSION(1, 8, 0): - case IP_VERSION(9, 4, 2): - mmhub_cid = mmhub_client_ids_aldebaran[cid][rw]; - break; - default: - mmhub_cid = NULL; - break; - } + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); } @@ -1428,6 +1400,52 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev) } } +static void gmc_v9_0_init_mmhub_client_info(struct amdgpu_device *adev) +{ + switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { + case IP_VERSION(9, 0, 0): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_vega10, + ARRAY_SIZE(mmhub_client_ids_vega10)); + break; + case IP_VERSION(9, 3, 0): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_vega12, + ARRAY_SIZE(mmhub_client_ids_vega12)); + break; + case IP_VERSION(9, 4, 0): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_vega20, + ARRAY_SIZE(mmhub_client_ids_vega20)); + break; + case IP_VERSION(9, 4, 1): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_arcturus, + ARRAY_SIZE(mmhub_client_ids_arcturus)); + break; + case IP_VERSION(9, 1, 0): + case IP_VERSION(9, 2, 0): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_raven, + ARRAY_SIZE(mmhub_client_ids_raven)); + break; + case IP_VERSION(1, 5, 0): + case IP_VERSION(2, 4, 0): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_renoir, + ARRAY_SIZE(mmhub_client_ids_renoir)); + break; + case IP_VERSION(1, 8, 0): + case IP_VERSION(9, 4, 2): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_aldebaran, + ARRAY_SIZE(mmhub_client_ids_aldebaran)); + break; + default: + break; + } +} + static void gmc_v9_0_set_mmhub_funcs(struct amdgpu_device *adev) { switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { @@ -1445,6 +1463,8 @@ static void gmc_v9_0_set_mmhub_funcs(struct amdgpu_device *adev) adev->mmhub.funcs = &mmhub_v1_0_funcs; break; } + + gmc_v9_0_init_mmhub_client_info(adev); } static void gmc_v9_0_set_mmhub_ras_funcs(struct amdgpu_device *adev) @@ -1803,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 (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 (!(adev->flags & AMD_IS_APU) && !amdgpu_sriov_vf(adev)) { - vram_info = RREG32(regBIF_BIOS_SCRATCH_4); - adev->gmc.vram_vendor = vram_info & 0xF; + 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, 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, 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; + } } } @@ -1836,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 @@ -1876,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): diff --git a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c index b3590b33cab9..485ecdec9618 100644 --- a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c +++ b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c @@ -129,7 +129,7 @@ static int isp_genpd_add_device(struct device *dev, void *data) if (!pdev) return -EINVAL; - if (!dev->type->name) { + if (!dev->type || !dev->type->name) { drm_dbg(&adev->ddev, "Invalid device type to add\n"); goto exit; } @@ -165,7 +165,7 @@ static int isp_genpd_remove_device(struct device *dev, void *data) if (!pdev) return -EINVAL; - if (!dev->type->name) { + if (!dev->type || !dev->type->name) { drm_dbg(&adev->ddev, "Invalid device type to remove\n"); goto exit; } diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.c new file mode 100644 index 000000000000..285c459379c4 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.c @@ -0,0 +1,840 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Copyright 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * 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. + */ + +#include "amdgpu.h" +#include "amdgpu_jpeg.h" +#include "amdgpu_pm.h" +#include "soc15.h" +#include "soc15d.h" +#include "jpeg_v4_0_3.h" +#include "jpeg_v5_0_2.h" +#include "mmsch_v5_0.h" + +#include "vcn/vcn_5_0_0_offset.h" +#include "vcn/vcn_5_0_0_sh_mask.h" +#include "ivsrcid/vcn/irqsrcs_vcn_5_0.h" + +static void jpeg_v5_0_2_set_dec_ring_funcs(struct amdgpu_device *adev); +static void jpeg_v5_0_2_set_irq_funcs(struct amdgpu_device *adev); +static int jpeg_v5_0_2_set_powergating_state(struct amdgpu_ip_block *ip_block, + enum amd_powergating_state state); +static void jpeg_v5_0_2_dec_ring_set_wptr(struct amdgpu_ring *ring); + +static int amdgpu_ih_srcid_jpeg[] = { + VCN_5_0__SRCID__JPEG_DECODE, + VCN_5_0__SRCID__JPEG1_DECODE, + VCN_5_0__SRCID__JPEG2_DECODE, + VCN_5_0__SRCID__JPEG3_DECODE, + VCN_5_0__SRCID__JPEG4_DECODE, + VCN_5_0__SRCID__JPEG5_DECODE, + VCN_5_0__SRCID__JPEG6_DECODE, + VCN_5_0__SRCID__JPEG7_DECODE, + VCN_5_0__SRCID__JPEG8_DECODE, + VCN_5_0__SRCID__JPEG9_DECODE, +}; + +static const struct amdgpu_hwip_reg_entry jpeg_reg_list_5_0_2[] = { + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JPEG_POWER_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JPEG_INT_STAT), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC0_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC0_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC0_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regJPEG_DEC_ADDR_MODE), + SOC15_REG_ENTRY_STR(JPEG, 0, regJPEG_DEC_GFX10_ADDR_CONFIG), + SOC15_REG_ENTRY_STR(JPEG, 0, regJPEG_DEC_Y_GFX10_TILING_SURFACE), + SOC15_REG_ENTRY_STR(JPEG, 0, regJPEG_DEC_UV_GFX10_TILING_SURFACE), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JPEG_PITCH), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JPEG_UV_PITCH), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC1_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC1_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC1_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC2_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC2_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC2_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC3_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC3_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC3_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC4_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC4_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC4_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC5_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC5_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC5_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC6_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC6_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC6_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC7_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC7_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC7_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC8_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC8_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC8_UVD_JRBC_STATUS), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC9_UVD_JRBC_RB_RPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC9_UVD_JRBC_RB_WPTR), + SOC15_REG_ENTRY_STR(JPEG, 0, regUVD_JRBC9_UVD_JRBC_STATUS), +}; + +static int jpeg_v5_0_2_core_reg_offset(u32 pipe) +{ + if (pipe <= AMDGPU_MAX_JPEG_RINGS_4_0_3) + return ((0x40 * pipe) - 0xc80); + else + return ((0x40 * pipe) - 0x440); +} + +/** + * jpeg_v5_0_2_early_init - set function pointers + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Set ring and irq function pointers + */ +static int jpeg_v5_0_2_early_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + + if (!adev->jpeg.num_jpeg_inst || adev->jpeg.num_jpeg_inst > AMDGPU_MAX_JPEG_INSTANCES) + return -ENOENT; + + adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS; + jpeg_v5_0_2_set_dec_ring_funcs(adev); + jpeg_v5_0_2_set_irq_funcs(adev); + + return 0; +} + +/** + * jpeg_v5_0_2_sw_init - sw init for JPEG block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Load firmware and sw initialization + */ +static int jpeg_v5_0_2_sw_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_ring *ring; + int i, j, r, jpeg_inst; + + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + /* JPEG TRAP */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, + amdgpu_ih_srcid_jpeg[j], &adev->jpeg.inst->irq); + if (r) + return r; + } + + r = amdgpu_jpeg_sw_init(adev); + if (r) + return r; + + r = amdgpu_jpeg_resume(adev); + if (r) + return r; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + jpeg_inst = GET_INST(JPEG, i); + + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + ring = &adev->jpeg.inst[i].ring_dec[j]; + ring->use_doorbell = false; + ring->vm_hub = AMDGPU_MMHUB0(adev->jpeg.inst[i].aid_id); + ring->doorbell_index = + (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + + 1 + j + 11 * jpeg_inst; + sprintf(ring->name, "jpeg_dec_%d.%d", adev->jpeg.inst[i].aid_id, j); + r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0, + AMDGPU_RING_PRIO_DEFAULT, NULL); + if (r) + return r; + + adev->jpeg.internal.jpeg_pitch[j] = + regUVD_JRBC0_UVD_JRBC_SCRATCH0_INTERNAL_OFFSET; + adev->jpeg.inst[i].external.jpeg_pitch[j] = + SOC15_REG_OFFSET1(JPEG, jpeg_inst, regUVD_JRBC_SCRATCH0, + (j ? jpeg_v5_0_2_core_reg_offset(j) : 0)); + } + } + + r = amdgpu_jpeg_reg_dump_init(adev, jpeg_reg_list_5_0_2, ARRAY_SIZE(jpeg_reg_list_5_0_2)); + if (r) + return r; + + adev->jpeg.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->jpeg.inst[0].ring_dec[0]); + adev->jpeg.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + r = amdgpu_jpeg_sysfs_reset_mask_init(adev); + + return r; +} + +/** + * jpeg_v5_0_2_sw_fini - sw fini for JPEG block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * JPEG suspend and free up sw allocation + */ +static int jpeg_v5_0_2_sw_fini(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int r; + + r = amdgpu_jpeg_suspend(adev); + if (r) + return r; + + amdgpu_jpeg_sysfs_reset_mask_fini(adev); + + r = amdgpu_jpeg_sw_fini(adev); + + return r; +} + +/** + * jpeg_v5_0_2_hw_init - start and test JPEG block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + */ +static int jpeg_v5_0_2_hw_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_ring *ring; + int i, j, r, jpeg_inst, tmp; + + if (RREG32_SOC15(VCN, GET_INST(VCN, 0), regVCN_RRMT_CNTL) & 0x100) + adev->jpeg.caps |= AMDGPU_JPEG_CAPS(RRMT_ENABLED); + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + jpeg_inst = GET_INST(JPEG, i); + ring = adev->jpeg.inst[i].ring_dec; + + /* Remove JPEG Tile antihang mechanism */ + tmp = RREG32_SOC15(JPEG, jpeg_inst, regUVD_JPEG_POWER_STATUS); + tmp &= (~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK); + WREG32_SOC15(JPEG, jpeg_inst, regUVD_JPEG_POWER_STATUS, tmp); + + if (ring->use_doorbell) + adev->nbio.funcs->vcn_doorbell_range(adev, ring->use_doorbell, + (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 11 * jpeg_inst, + adev->jpeg.inst[i].aid_id); + + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + ring = &adev->jpeg.inst[i].ring_dec[j]; + if (ring->use_doorbell) + WREG32_SOC15_OFFSET(VCN, GET_INST(VCN, i), regVCN_JPEG_DB_CTRL, + ring->pipe, + ring->doorbell_index << + VCN_JPEG_DB_CTRL__OFFSET__SHIFT | + VCN_JPEG_DB_CTRL__EN_MASK); + r = amdgpu_ring_test_helper(ring); + if (r) + return r; + } + } + + return 0; +} + +/** + * jpeg_v5_0_2_hw_fini - stop the hardware block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Stop the JPEG block, mark ring as not ready any more + */ +static int jpeg_v5_0_2_hw_fini(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int ret = 0; + + cancel_delayed_work_sync(&adev->jpeg.idle_work); + + if (adev->jpeg.cur_state != AMD_PG_STATE_GATE) + ret = jpeg_v5_0_2_set_powergating_state(ip_block, AMD_PG_STATE_GATE); + + return ret; +} + +/** + * jpeg_v5_0_2_suspend - suspend JPEG block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * HW fini and suspend JPEG block + */ +static int jpeg_v5_0_2_suspend(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int r; + + r = jpeg_v5_0_2_hw_fini(ip_block); + if (r) + return r; + + r = amdgpu_jpeg_suspend(adev); + + return r; +} + +/** + * jpeg_v5_0_2_resume - resume JPEG block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Resume firmware and hw init JPEG block + */ +static int jpeg_v5_0_2_resume(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int r; + + r = amdgpu_jpeg_resume(adev); + if (r) + return r; + + r = jpeg_v5_0_2_hw_init(ip_block); + + return r; +} + +static void jpeg_v5_0_2_init_inst(struct amdgpu_device *adev, int i) +{ + int jpeg_inst = GET_INST(JPEG, i); + + /* disable anti hang mechanism */ + WREG32_P(SOC15_REG_OFFSET(JPEG, jpeg_inst, regUVD_JPEG_POWER_STATUS), 0, + ~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK); + + /* keep the JPEG in static PG mode */ + WREG32_P(SOC15_REG_OFFSET(JPEG, jpeg_inst, regUVD_JPEG_POWER_STATUS), 0, + ~UVD_JPEG_POWER_STATUS__JPEG_PG_MODE_MASK); + + /* MJPEG global tiling registers */ + WREG32_SOC15(JPEG, 0, regJPEG_DEC_GFX10_ADDR_CONFIG, + adev->gfx.config.gb_addr_config); + + /* enable JMI channel */ + WREG32_P(SOC15_REG_OFFSET(JPEG, jpeg_inst, regUVD_JMI_CNTL), 0, + ~UVD_JMI_CNTL__SOFT_RESET_MASK); +} + +static void jpeg_v5_0_2_deinit_inst(struct amdgpu_device *adev, int i) +{ + int jpeg_inst = GET_INST(JPEG, i); + /* reset JMI */ + WREG32_P(SOC15_REG_OFFSET(JPEG, jpeg_inst, regUVD_JMI_CNTL), + UVD_JMI_CNTL__SOFT_RESET_MASK, + ~UVD_JMI_CNTL__SOFT_RESET_MASK); + + /* enable anti hang mechanism */ + WREG32_P(SOC15_REG_OFFSET(JPEG, jpeg_inst, regUVD_JPEG_POWER_STATUS), + UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK, + ~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK); +} + +static void jpeg_v5_0_2_init_jrbc(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + u32 reg, data, mask; + int jpeg_inst = GET_INST(JPEG, ring->me); + int reg_offset = ring->pipe ? jpeg_v5_0_2_core_reg_offset(ring->pipe) : 0; + + /* enable System Interrupt for JRBC */ + reg = SOC15_REG_OFFSET(JPEG, jpeg_inst, regJPEG_SYS_INT_EN); + if (ring->pipe < AMDGPU_MAX_JPEG_RINGS_4_0_3) { + data = JPEG_SYS_INT_EN__DJRBC0_MASK << ring->pipe; + mask = ~(JPEG_SYS_INT_EN__DJRBC0_MASK << ring->pipe); + WREG32_P(reg, data, mask); + } else { + data = JPEG_SYS_INT_EN__DJRBC0_MASK << (ring->pipe+12); + mask = ~(JPEG_SYS_INT_EN__DJRBC0_MASK << (ring->pipe+12)); + WREG32_P(reg, data, mask); + } + + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_LMI_JRBC_RB_VMID, + reg_offset, 0); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JRBC_RB_CNTL, + reg_offset, + (0x00000001L | 0x00000002L)); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_LMI_JRBC_RB_64BIT_BAR_LOW, + reg_offset, lower_32_bits(ring->gpu_addr)); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, + reg_offset, upper_32_bits(ring->gpu_addr)); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JRBC_RB_RPTR, + reg_offset, 0); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JRBC_RB_WPTR, + reg_offset, 0); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JRBC_RB_CNTL, + reg_offset, 0x00000002L); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JRBC_RB_SIZE, + reg_offset, ring->ring_size / 4); + ring->wptr = RREG32_SOC15_OFFSET(JPEG, jpeg_inst, regUVD_JRBC_RB_WPTR, + reg_offset); +} + +/** + * jpeg_v5_0_2_start - start JPEG block + * + * @adev: amdgpu_device pointer + * + * Setup and start the JPEG block + */ +static int jpeg_v5_0_2_start(struct amdgpu_device *adev) +{ + struct amdgpu_ring *ring; + int i, j; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + jpeg_v5_0_2_init_inst(adev, i); + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + ring = &adev->jpeg.inst[i].ring_dec[j]; + jpeg_v5_0_2_init_jrbc(ring); + } + } + + return 0; +} + +/** + * jpeg_v5_0_2_stop - stop JPEG block + * + * @adev: amdgpu_device pointer + * + * stop the JPEG block + */ +static int jpeg_v5_0_2_stop(struct amdgpu_device *adev) +{ + int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) + jpeg_v5_0_2_deinit_inst(adev, i); + + return 0; +} + +/** + * jpeg_v5_0_2_dec_ring_get_rptr - get read pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware read pointer + */ +static uint64_t jpeg_v5_0_2_dec_ring_get_rptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + return RREG32_SOC15_OFFSET(JPEG, GET_INST(JPEG, ring->me), regUVD_JRBC_RB_RPTR, + ring->pipe ? jpeg_v5_0_2_core_reg_offset(ring->pipe) : 0); +} + +/** + * jpeg_v5_0_2_dec_ring_get_wptr - get write pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware write pointer + */ +static uint64_t jpeg_v5_0_2_dec_ring_get_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring->use_doorbell) + return adev->wb.wb[ring->wptr_offs]; + + return RREG32_SOC15_OFFSET(JPEG, GET_INST(JPEG, ring->me), regUVD_JRBC_RB_WPTR, + ring->pipe ? jpeg_v5_0_2_core_reg_offset(ring->pipe) : 0); +} + +/** + * jpeg_v5_0_2_dec_ring_set_wptr - set write pointer + * + * @ring: amdgpu_ring pointer + * + * Commits the write pointer to the hardware + */ +static void jpeg_v5_0_2_dec_ring_set_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring->use_doorbell) { + adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr); + WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr)); + } else { + WREG32_SOC15_OFFSET(JPEG, GET_INST(JPEG, ring->me), + regUVD_JRBC_RB_WPTR, + (ring->pipe ? jpeg_v5_0_2_core_reg_offset(ring->pipe) : 0), + lower_32_bits(ring->wptr)); + } +} + +static bool jpeg_v5_0_2_is_idle(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + bool ret = false; + int i, j; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + int reg_offset = (j ? jpeg_v5_0_2_core_reg_offset(j) : 0); + + ret &= ((RREG32_SOC15_OFFSET(JPEG, GET_INST(JPEG, i), + regUVD_JRBC_STATUS, reg_offset) & + UVD_JRBC_STATUS__RB_JOB_DONE_MASK) == + UVD_JRBC_STATUS__RB_JOB_DONE_MASK); + } + } + + return ret; +} + +static int jpeg_v5_0_2_wait_for_idle(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int ret = 0; + int i, j; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + int reg_offset = (j ? jpeg_v5_0_2_core_reg_offset(j) : 0); + + ret &= SOC15_WAIT_ON_RREG_OFFSET(JPEG, GET_INST(JPEG, i), + regUVD_JRBC_STATUS, reg_offset, + UVD_JRBC_STATUS__RB_JOB_DONE_MASK, + UVD_JRBC_STATUS__RB_JOB_DONE_MASK); + } + } + return ret; +} + +static int jpeg_v5_0_2_set_clockgating_state(struct amdgpu_ip_block *ip_block, + enum amd_clockgating_state state) +{ + struct amdgpu_device *adev = ip_block->adev; + bool enable = state == AMD_CG_STATE_GATE; + + int i; + + if (!enable) + return 0; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (!jpeg_v5_0_2_is_idle(ip_block)) + return -EBUSY; + } + + return 0; +} + +static int jpeg_v5_0_2_set_powergating_state(struct amdgpu_ip_block *ip_block, + enum amd_powergating_state state) +{ + struct amdgpu_device *adev = ip_block->adev; + int ret; + + if (state == adev->jpeg.cur_state) + return 0; + + if (state == AMD_PG_STATE_GATE) + ret = jpeg_v5_0_2_stop(adev); + else + ret = jpeg_v5_0_2_start(adev); + + if (!ret) + adev->jpeg.cur_state = state; + + return ret; +} + +static int jpeg_v5_0_2_set_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + +static int jpeg_v5_0_2_process_interrupt(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + u32 i, inst; + + i = node_id_to_phys_map[entry->node_id]; + DRM_DEV_DEBUG(adev->dev, "IH: JPEG TRAP\n"); + + for (inst = 0; inst < adev->jpeg.num_jpeg_inst; ++inst) + if (adev->jpeg.inst[inst].aid_id == i) + break; + + if (inst >= adev->jpeg.num_jpeg_inst) { + dev_WARN_ONCE(adev->dev, 1, + "Interrupt received for unknown JPEG instance %d", + entry->node_id); + return 0; + } + + switch (entry->src_id) { + case VCN_5_0__SRCID__JPEG_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[0]); + break; + case VCN_5_0__SRCID__JPEG1_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[1]); + break; + case VCN_5_0__SRCID__JPEG2_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[2]); + break; + case VCN_5_0__SRCID__JPEG3_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[3]); + break; + case VCN_5_0__SRCID__JPEG4_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[4]); + break; + case VCN_5_0__SRCID__JPEG5_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[5]); + break; + case VCN_5_0__SRCID__JPEG6_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[6]); + break; + case VCN_5_0__SRCID__JPEG7_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[7]); + break; + case VCN_5_0__SRCID__JPEG8_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[8]); + break; + case VCN_5_0__SRCID__JPEG9_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[inst].ring_dec[9]); + break; + default: + DRM_DEV_ERROR(adev->dev, "Unhandled interrupt: %d %d\n", + entry->src_id, entry->src_data[0]); + break; + } + + return 0; +} + +static void jpeg_v5_0_2_core_stall_reset(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + int jpeg_inst = GET_INST(JPEG, ring->me); + int reg_offset = ring->pipe ? jpeg_v5_0_2_core_reg_offset(ring->pipe) : 0; + + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JMI0_UVD_JMI_CLIENT_STALL, + reg_offset, 0x1F); + SOC15_WAIT_ON_RREG_OFFSET(JPEG, jpeg_inst, + regUVD_JMI0_UVD_JMI_CLIENT_CLEAN_STATUS, + reg_offset, 0x1F, 0x1F); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JMI0_JPEG_LMI_DROP, + reg_offset, 0x1F); + WREG32_SOC15(JPEG, jpeg_inst, regJPEG_CORE_RST_CTRL, 1 << ring->pipe); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JMI0_UVD_JMI_CLIENT_STALL, + reg_offset, 0x00); + WREG32_SOC15_OFFSET(JPEG, jpeg_inst, + regUVD_JMI0_JPEG_LMI_DROP, + reg_offset, 0x00); + WREG32_SOC15(JPEG, jpeg_inst, regJPEG_CORE_RST_CTRL, 0x00); +} + +static int jpeg_v5_0_2_ring_reset(struct amdgpu_ring *ring, + unsigned int vmid, + struct amdgpu_fence *timedout_fence) +{ + amdgpu_ring_reset_helper_begin(ring, timedout_fence); + jpeg_v5_0_2_core_stall_reset(ring); + jpeg_v5_0_2_init_jrbc(ring); + return amdgpu_ring_reset_helper_end(ring, timedout_fence); +} + +static const struct amd_ip_funcs jpeg_v5_0_2_ip_funcs = { + .name = "jpeg_v5_0_2", + .early_init = jpeg_v5_0_2_early_init, + .late_init = NULL, + .sw_init = jpeg_v5_0_2_sw_init, + .sw_fini = jpeg_v5_0_2_sw_fini, + .hw_init = jpeg_v5_0_2_hw_init, + .hw_fini = jpeg_v5_0_2_hw_fini, + .suspend = jpeg_v5_0_2_suspend, + .resume = jpeg_v5_0_2_resume, + .is_idle = jpeg_v5_0_2_is_idle, + .wait_for_idle = jpeg_v5_0_2_wait_for_idle, + .check_soft_reset = NULL, + .pre_soft_reset = NULL, + .soft_reset = NULL, + .post_soft_reset = NULL, + .set_clockgating_state = jpeg_v5_0_2_set_clockgating_state, + .set_powergating_state = jpeg_v5_0_2_set_powergating_state, + .dump_ip_state = amdgpu_jpeg_dump_ip_state, + .print_ip_state = amdgpu_jpeg_print_ip_state, +}; + +static const struct amdgpu_ring_funcs jpeg_v5_0_2_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, + .get_rptr = jpeg_v5_0_2_dec_ring_get_rptr, + .get_wptr = jpeg_v5_0_2_dec_ring_get_wptr, + .set_wptr = jpeg_v5_0_2_dec_ring_set_wptr, + .emit_frame_size = + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + + 8 + /* jpeg_v5_0_2_dec_ring_emit_vm_flush */ + 22 + 22 + /* jpeg_v5_0_2_dec_ring_emit_fence x2 vm fence */ + 8 + 16, + .emit_ib_size = 22, /* jpeg_v5_0_2_dec_ring_emit_ib */ + .emit_ib = jpeg_v4_0_3_dec_ring_emit_ib, + .emit_fence = jpeg_v4_0_3_dec_ring_emit_fence, + .emit_vm_flush = jpeg_v4_0_3_dec_ring_emit_vm_flush, + .emit_hdp_flush = jpeg_v4_0_3_ring_emit_hdp_flush, + .test_ring = amdgpu_jpeg_dec_ring_test_ring, + .test_ib = amdgpu_jpeg_dec_ring_test_ib, + .insert_nop = jpeg_v4_0_3_dec_ring_nop, + .insert_start = jpeg_v4_0_3_dec_ring_insert_start, + .insert_end = jpeg_v4_0_3_dec_ring_insert_end, + .pad_ib = amdgpu_ring_generic_pad_ib, + .begin_use = amdgpu_jpeg_ring_begin_use, + .end_use = amdgpu_jpeg_ring_end_use, + .emit_wreg = jpeg_v4_0_3_dec_ring_emit_wreg, + .emit_reg_wait = jpeg_v4_0_3_dec_ring_emit_reg_wait, + .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, + .reset = jpeg_v5_0_2_ring_reset, +}; + +static void jpeg_v5_0_2_set_dec_ring_funcs(struct amdgpu_device *adev) +{ + int i, j, jpeg_inst; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + adev->jpeg.inst[i].ring_dec[j].funcs = &jpeg_v5_0_2_dec_ring_vm_funcs; + adev->jpeg.inst[i].ring_dec[j].me = i; + adev->jpeg.inst[i].ring_dec[j].pipe = j; + } + jpeg_inst = GET_INST(JPEG, i); + adev->jpeg.inst[i].aid_id = + jpeg_inst / adev->jpeg.num_inst_per_aid; + } +} + +static const struct amdgpu_irq_src_funcs jpeg_v5_0_2_irq_funcs = { + .set = jpeg_v5_0_2_set_interrupt_state, + .process = jpeg_v5_0_2_process_interrupt, +}; + +static void jpeg_v5_0_2_set_irq_funcs(struct amdgpu_device *adev) +{ + int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) + adev->jpeg.inst->irq.num_types += adev->jpeg.num_jpeg_rings; + + adev->jpeg.inst->irq.funcs = &jpeg_v5_0_2_irq_funcs; +} + +const struct amdgpu_ip_block_version jpeg_v5_0_2_ip_block = { + .type = AMD_IP_BLOCK_TYPE_JPEG, + .major = 5, + .minor = 0, + .rev = 2, + .funcs = &jpeg_v5_0_2_ip_funcs, +}; + +#if 0 +static int jpeg_v5_0_2_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, + enum aca_smu_type type, void *data) +{ + struct aca_bank_info info; + u64 misc0; + int ret; + + ret = aca_bank_info_decode(bank, &info); + if (ret) + return ret; + + misc0 = bank->regs[ACA_REG_IDX_MISC0]; + switch (type) { + case ACA_SMU_TYPE_UE: + bank->aca_err_type = ACA_ERROR_TYPE_UE; + ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, + 1ULL); + break; + case ACA_SMU_TYPE_CE: + bank->aca_err_type = ACA_ERROR_TYPE_CE; + ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, + ACA_REG__MISC0__ERRCNT(misc0)); + break; + default: + return -EINVAL; + } + + return ret; +} + +/* reference to smu driver if header file */ +static int jpeg_v5_0_2_err_codes[] = { + 16, 17, 18, 19, 20, 21, 22, 23, /* JPEG[0-9][S|D] */ + 24, 25, 26, 27, 28, 29, 30, 31, + 48, 49, 50, 51, +}; + +static bool jpeg_v5_0_2_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, + enum aca_smu_type type, void *data) +{ + u32 instlo; + + instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); + instlo &= GENMASK(31, 1); + + if (instlo != mmSMNAID_AID0_MCA_SMU) + return false; + + if (aca_bank_check_error_codes(handle->adev, bank, + jpeg_v5_0_2_err_codes, + ARRAY_SIZE(jpeg_v5_0_2_err_codes))) + return false; + + return true; +} + +static const struct aca_bank_ops jpeg_v5_0_2_aca_bank_ops = { + .aca_bank_parser = jpeg_v5_0_2_aca_bank_parser, + .aca_bank_is_valid = jpeg_v5_0_2_aca_bank_is_valid, +}; + +static const struct aca_info jpeg_v5_0_2_aca_info = { + .hwip = ACA_HWIP_TYPE_SMU, + .mask = ACA_ERROR_UE_MASK, + .bank_ops = &jpeg_v5_0_2_aca_bank_ops, +}; +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.h new file mode 100644 index 000000000000..c201a2c42a0d --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.h @@ -0,0 +1,111 @@ +/* + * Copyright 2025-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. + * + */ + +#ifndef __JPEG_V5_0_2_H__ +#define __JPEG_V5_0_2_H__ + +extern const struct amdgpu_ip_block_version jpeg_v5_0_2_ip_block; + +#define regUVD_JRBC0_UVD_JRBC_SCRATCH0_INTERNAL_OFFSET 0x4094 +#define regUVD_JRBC_EXTERNAL_MCM_ADDR_INTERNAL_OFFSET 0x1bffe + +#define regUVD_JRBC0_UVD_JRBC_RB_WPTR 0x0640 +#define regUVD_JRBC0_UVD_JRBC_RB_WPTR_BASE_IDX 1 +#define regUVD_JRBC0_UVD_JRBC_STATUS 0x0649 +#define regUVD_JRBC0_UVD_JRBC_STATUS_BASE_IDX 1 +#define regUVD_JRBC0_UVD_JRBC_RB_RPTR 0x064a +#define regUVD_JRBC0_UVD_JRBC_RB_RPTR_BASE_IDX 1 +#define regUVD_JRBC1_UVD_JRBC_RB_WPTR 0x0000 +#define regUVD_JRBC1_UVD_JRBC_RB_WPTR_BASE_IDX 0 +#define regUVD_JRBC1_UVD_JRBC_STATUS 0x0009 +#define regUVD_JRBC1_UVD_JRBC_STATUS_BASE_IDX 0 +#define regUVD_JRBC1_UVD_JRBC_RB_RPTR 0x000a +#define regUVD_JRBC1_UVD_JRBC_RB_RPTR_BASE_IDX 0 +#define regUVD_JRBC2_UVD_JRBC_RB_WPTR 0x0040 +#define regUVD_JRBC2_UVD_JRBC_RB_WPTR_BASE_IDX 0 +#define regUVD_JRBC2_UVD_JRBC_STATUS 0x0049 +#define regUVD_JRBC2_UVD_JRBC_STATUS_BASE_IDX 0 +#define regUVD_JRBC2_UVD_JRBC_RB_RPTR 0x004a +#define regUVD_JRBC2_UVD_JRBC_RB_RPTR_BASE_IDX 0 +#define regUVD_JRBC3_UVD_JRBC_RB_WPTR 0x0080 +#define regUVD_JRBC3_UVD_JRBC_RB_WPTR_BASE_IDX 0 +#define regUVD_JRBC3_UVD_JRBC_STATUS 0x0089 +#define regUVD_JRBC3_UVD_JRBC_STATUS_BASE_IDX 0 +#define regUVD_JRBC3_UVD_JRBC_RB_RPTR 0x008a +#define regUVD_JRBC3_UVD_JRBC_RB_RPTR_BASE_IDX 0 +#define regUVD_JRBC4_UVD_JRBC_RB_WPTR 0x00c0 +#define regUVD_JRBC4_UVD_JRBC_RB_WPTR_BASE_IDX 0 +#define regUVD_JRBC4_UVD_JRBC_STATUS 0x00c9 +#define regUVD_JRBC4_UVD_JRBC_STATUS_BASE_IDX 0 +#define regUVD_JRBC4_UVD_JRBC_RB_RPTR 0x00ca +#define regUVD_JRBC4_UVD_JRBC_RB_RPTR_BASE_IDX 0 +#define regUVD_JRBC5_UVD_JRBC_RB_WPTR 0x0100 +#define regUVD_JRBC5_UVD_JRBC_RB_WPTR_BASE_IDX 0 +#define regUVD_JRBC5_UVD_JRBC_STATUS 0x0109 +#define regUVD_JRBC5_UVD_JRBC_STATUS_BASE_IDX 0 +#define regUVD_JRBC5_UVD_JRBC_RB_RPTR 0x010a +#define regUVD_JRBC5_UVD_JRBC_RB_RPTR_BASE_IDX 0 +#define regUVD_JRBC6_UVD_JRBC_RB_WPTR 0x0140 +#define regUVD_JRBC6_UVD_JRBC_RB_WPTR_BASE_IDX 0 +#define regUVD_JRBC6_UVD_JRBC_STATUS 0x0149 +#define regUVD_JRBC6_UVD_JRBC_STATUS_BASE_IDX 0 +#define regUVD_JRBC6_UVD_JRBC_RB_RPTR 0x014a +#define regUVD_JRBC6_UVD_JRBC_RB_RPTR_BASE_IDX 0 +#define regUVD_JRBC7_UVD_JRBC_RB_WPTR 0x0180 +#define regUVD_JRBC7_UVD_JRBC_RB_WPTR_BASE_IDX 0 +#define regUVD_JRBC7_UVD_JRBC_STATUS 0x0189 +#define regUVD_JRBC7_UVD_JRBC_STATUS_BASE_IDX 0 +#define regUVD_JRBC7_UVD_JRBC_RB_RPTR 0x018a +#define regUVD_JRBC7_UVD_JRBC_RB_RPTR_BASE_IDX 0 +#define regUVD_JRBC8_UVD_JRBC_RB_WPTR 0x01c0 +#define regUVD_JRBC8_UVD_JRBC_RB_WPTR_BASE_IDX 0 +#define regUVD_JRBC8_UVD_JRBC_STATUS 0x01c9 +#define regUVD_JRBC8_UVD_JRBC_STATUS_BASE_IDX 0 +#define regUVD_JRBC8_UVD_JRBC_RB_RPTR 0x01ca +#define regUVD_JRBC8_UVD_JRBC_RB_RPTR_BASE_IDX 0 +#define regUVD_JRBC9_UVD_JRBC_RB_WPTR 0x0440 +#define regUVD_JRBC9_UVD_JRBC_RB_WPTR_BASE_IDX 1 +#define regUVD_JRBC9_UVD_JRBC_STATUS 0x0449 +#define regUVD_JRBC9_UVD_JRBC_STATUS_BASE_IDX 1 +#define regUVD_JRBC9_UVD_JRBC_RB_RPTR 0x044a +#define regUVD_JRBC9_UVD_JRBC_RB_RPTR_BASE_IDX 1 +#define regUVD_JMI0_JPEG_LMI_DROP 0x0663 +#define regUVD_JMI0_JPEG_LMI_DROP_BASE_IDX 1 +#define regUVD_JMI0_UVD_JMI_CLIENT_STALL 0x067a +#define regUVD_JMI0_UVD_JMI_CLIENT_STALL_BASE_IDX 1 +#define regUVD_JMI0_UVD_JMI_CLIENT_CLEAN_STATUS 0x067b +#define regUVD_JMI0_UVD_JMI_CLIENT_CLEAN_STATUS_BASE_IDX 1 +#define regJPEG_CORE_RST_CTRL 0x072e +#define regJPEG_CORE_RST_CTRL_BASE_IDX 1 + +#define regVCN_RRMT_CNTL 0x0940 +#define regVCN_RRMT_CNTL_BASE_IDX 1 + +enum amdgpu_jpeg_v5_0_2_sub_block { + AMDGPU_JPEG_V5_0_2_JPEG0 = 0, + AMDGPU_JPEG_V5_0_2_JPEG1, + + AMDGPU_JPEG_V5_0_2_MAX_SUB_BLOCK, +}; + +#endif /* __JPEG_V5_0_2_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c index 8c74894254f7..faac21ee5739 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c index d8e4b52bdfd5..0e9089544769 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c @@ -31,6 +31,8 @@ #include "gc/gc_11_0_0_default.h" #include "v12_structs.h" #include "mes_v12_api_def.h" +#include "gfx_v12_1_pkt.h" +#include "sdma_v7_1_0_pkt_open.h" MODULE_FIRMWARE("amdgpu/gc_12_1_0_mes.bin"); MODULE_FIRMWARE("amdgpu/gc_12_1_0_mes1.bin"); @@ -41,6 +43,7 @@ static int mes_v12_1_xcc_hw_init(struct amdgpu_ip_block *ip_block, int xcc_id); static int mes_v12_1_hw_fini(struct amdgpu_ip_block *ip_block); static int mes_v12_1_kiq_hw_init(struct amdgpu_device *adev, uint32_t xcc_id); static int mes_v12_1_kiq_hw_fini(struct amdgpu_device *adev, uint32_t xcc_id); +static int mes_v12_1_self_test(struct amdgpu_device *adev, int xcc_id); #define MES_EOP_SIZE 2048 @@ -491,16 +494,12 @@ static int mes_v12_1_query_sched_status(struct amdgpu_mes *mes, } static uint32_t mes_v12_1_get_xcc_from_reg(uint32_t reg_offset) { - /* Check xcc reg offset range */ - uint32_t xcc = (reg_offset & XCC_MID_MASK) ? 4 : 0; - /* Each XCC has two register ranges. - * These are represented in reg_offset[17:16] - */ - return ((reg_offset >> 16) & 0x3) + xcc; + return ((reg_offset >> 16) & 0x7); } static void mes_v12_1_get_rrmt(uint32_t reg, uint32_t xcc_id, - struct RRMT_OPTION *rrmt_opt) + struct RRMT_OPTION *rrmt_opt, + uint32_t *out_reg) { uint32_t normalized_reg = soc_v1_0_normalize_xcc_reg_offset(reg); @@ -509,8 +508,12 @@ static void mes_v12_1_get_rrmt(uint32_t reg, uint32_t xcc_id, rrmt_opt->mode = (xcc_id == rrmt_opt->xcd_die_id) ? MES_RRMT_MODE_LOCAL_XCD : MES_RRMT_MODE_REMOTE_XCD; } else { - rrmt_opt->mode = MES_RRMT_MODE_LOCAL_REMOTE_AID; + rrmt_opt->mode = MES_RRMT_MODE_REMOTE_MID; + if (soc_v1_0_mid1_reg_range(reg)) + rrmt_opt->mid_die_id = 1; } + + *out_reg = soc_v1_0_normalize_reg_offset(reg); } static int mes_v12_1_misc_op(struct amdgpu_mes *mes, @@ -534,65 +537,44 @@ static int mes_v12_1_misc_op(struct amdgpu_mes *mes, switch (input->op) { case MES_MISC_OP_READ_REG: misc_pkt.opcode = MESAPI_MISC__READ_REG; - misc_pkt.read_reg.reg_offset = input->read_reg.reg_offset; misc_pkt.read_reg.buffer_addr = input->read_reg.buffer_addr; mes_v12_1_get_rrmt(input->read_reg.reg_offset, GET_INST(GC, input->xcc_id), - &misc_pkt.read_reg.rrmt_opt); - if (misc_pkt.read_reg.rrmt_opt.mode != MES_RRMT_MODE_REMOTE_MID) { - misc_pkt.read_reg.reg_offset = - soc_v1_0_normalize_xcc_reg_offset(misc_pkt.read_reg.reg_offset); - } + &misc_pkt.read_reg.rrmt_opt, + &misc_pkt.read_reg.reg_offset); break; case MES_MISC_OP_WRITE_REG: misc_pkt.opcode = MESAPI_MISC__WRITE_REG; - misc_pkt.write_reg.reg_offset = input->write_reg.reg_offset; misc_pkt.write_reg.reg_value = input->write_reg.reg_value; mes_v12_1_get_rrmt(input->write_reg.reg_offset, GET_INST(GC, input->xcc_id), - &misc_pkt.write_reg.rrmt_opt); - if (misc_pkt.write_reg.rrmt_opt.mode != MES_RRMT_MODE_REMOTE_MID) { - misc_pkt.write_reg.reg_offset = - soc_v1_0_normalize_xcc_reg_offset(misc_pkt.write_reg.reg_offset); - } + &misc_pkt.write_reg.rrmt_opt, + &misc_pkt.write_reg.reg_offset); break; case MES_MISC_OP_WRM_REG_WAIT: misc_pkt.opcode = MESAPI_MISC__WAIT_REG_MEM; misc_pkt.wait_reg_mem.op = WRM_OPERATION__WAIT_REG_MEM; misc_pkt.wait_reg_mem.reference = input->wrm_reg.ref; misc_pkt.wait_reg_mem.mask = input->wrm_reg.mask; - misc_pkt.wait_reg_mem.reg_offset1 = input->wrm_reg.reg0; misc_pkt.wait_reg_mem.reg_offset2 = 0; mes_v12_1_get_rrmt(input->wrm_reg.reg0, GET_INST(GC, input->xcc_id), - &misc_pkt.wait_reg_mem.rrmt_opt1); - if (misc_pkt.wait_reg_mem.rrmt_opt1.mode != MES_RRMT_MODE_REMOTE_MID) { - misc_pkt.wait_reg_mem.reg_offset1 = - soc_v1_0_normalize_xcc_reg_offset(misc_pkt.wait_reg_mem.reg_offset1); - } + &misc_pkt.wait_reg_mem.rrmt_opt1, + &misc_pkt.wait_reg_mem.reg_offset1); break; case MES_MISC_OP_WRM_REG_WR_WAIT: misc_pkt.opcode = MESAPI_MISC__WAIT_REG_MEM; misc_pkt.wait_reg_mem.op = WRM_OPERATION__WR_WAIT_WR_REG; misc_pkt.wait_reg_mem.reference = input->wrm_reg.ref; misc_pkt.wait_reg_mem.mask = input->wrm_reg.mask; - misc_pkt.wait_reg_mem.reg_offset1 = input->wrm_reg.reg0; - misc_pkt.wait_reg_mem.reg_offset2 = input->wrm_reg.reg1; mes_v12_1_get_rrmt(input->wrm_reg.reg0, GET_INST(GC, input->xcc_id), - &misc_pkt.wait_reg_mem.rrmt_opt1); + &misc_pkt.wait_reg_mem.rrmt_opt1, + &misc_pkt.wait_reg_mem.reg_offset1); mes_v12_1_get_rrmt(input->wrm_reg.reg1, GET_INST(GC, input->xcc_id), - &misc_pkt.wait_reg_mem.rrmt_opt2); - - if (misc_pkt.wait_reg_mem.rrmt_opt1.mode != MES_RRMT_MODE_REMOTE_MID) { - misc_pkt.wait_reg_mem.reg_offset1 = - soc_v1_0_normalize_xcc_reg_offset(misc_pkt.wait_reg_mem.reg_offset1); - } - if (misc_pkt.wait_reg_mem.rrmt_opt2.mode != MES_RRMT_MODE_REMOTE_MID) { - misc_pkt.wait_reg_mem.reg_offset2 = - soc_v1_0_normalize_xcc_reg_offset(misc_pkt.wait_reg_mem.reg_offset2); - } + &misc_pkt.wait_reg_mem.rrmt_opt2, + &misc_pkt.wait_reg_mem.reg_offset2); break; case MES_MISC_OP_SET_SHADER_DEBUGGER: pipe = AMDGPU_MES_SCHED_PIPE; @@ -1949,10 +1931,31 @@ static int mes_v12_1_early_init(struct amdgpu_ip_block *ip_block) return 0; } +static int mes_v12_1_late_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int xcc_id, num_xcc = NUM_XCC(adev->gfx.xcc_mask); + + /* TODO: remove it if issue fixed. */ + if (adev->mes.enable_coop_mode) + return 0; + + for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) { + /* for COOP mode, only test master xcc. */ + if (adev->mes.enable_coop_mode && + adev->mes.master_xcc_ids[xcc_id] != xcc_id) + continue; + + mes_v12_1_self_test(adev, xcc_id); + } + + return 0; +} + static const struct amd_ip_funcs mes_v12_1_ip_funcs = { .name = "mes_v12_1", .early_init = mes_v12_1_early_init, - .late_init = NULL, + .late_init = mes_v12_1_late_init, .sw_init = mes_v12_1_sw_init, .sw_fini = mes_v12_1_sw_fini, .hw_init = mes_v12_1_hw_init, @@ -1968,3 +1971,312 @@ const struct amdgpu_ip_block_version mes_v12_1_ip_block = { .rev = 0, .funcs = &mes_v12_1_ip_funcs, }; + +static int mes_v12_1_alloc_test_buf(struct amdgpu_device *adev, + struct amdgpu_bo **bo, uint64_t *addr, + void **ptr, int size) +{ + amdgpu_bo_create_kernel(adev, size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, + bo, addr, ptr); + if (!*bo) { + dev_err(adev->dev, "failed to allocate test buffer bo\n"); + return -ENOMEM; + } + memset(*ptr, 0, size); + return 0; +} + +static int mes_v12_1_map_test_bo(struct amdgpu_device *adev, + struct amdgpu_bo *bo, struct amdgpu_vm *vm, + struct amdgpu_bo_va **bo_va, u64 va, int size) +{ + struct amdgpu_sync sync; + int r; + + r = amdgpu_map_static_csa(adev, vm, bo, bo_va, va, size); + if (r) + return r; + + amdgpu_sync_create(&sync); + + r = amdgpu_vm_bo_update(adev, *bo_va, false); + if (r) { + dev_err(adev->dev, "failed to do vm_bo_update on meta data\n"); + goto error; + } + amdgpu_sync_fence(&sync, (*bo_va)->last_pt_update, GFP_KERNEL); + + r = amdgpu_vm_update_pdes(adev, vm, false); + if (r) { + dev_err(adev->dev, "failed to update pdes on meta data\n"); + goto error; + } + amdgpu_sync_fence(&sync, vm->last_update, GFP_KERNEL); + amdgpu_sync_wait(&sync, false); + +error: + amdgpu_sync_free(&sync); + return 0; +} + +static int mes_v12_1_test_ring(struct amdgpu_device *adev, int xcc_id, + u32 *queue_ptr, u64 fence_gpu_addr, + void *fence_cpu_ptr, void *wptr_cpu_addr, + u64 doorbell_idx, int queue_type) +{ + volatile uint32_t *cpu_ptr = fence_cpu_ptr; + int num_xcc = NUM_XCC(adev->gfx.xcc_mask); + int sdma_ring_align = 0x10, compute_ring_align = 0x100; + uint32_t tmp, xcc_offset; + int r = 0, i, wptr = 0; + + if (queue_type == AMDGPU_RING_TYPE_COMPUTE) { + if (!adev->mes.enable_coop_mode) { + WREG32_SOC15(GC, GET_INST(GC, xcc_id), + regSCRATCH_REG0, 0xCAFEDEAD); + } else { + for (i = 0; i < num_xcc; i++) { + if (adev->mes.master_xcc_ids[i] == xcc_id) + WREG32_SOC15(GC, GET_INST(GC, i), + regSCRATCH_REG0, 0xCAFEDEAD); + } + } + + xcc_offset = SOC15_REG_OFFSET(GC, 0, regSCRATCH_REG0); + queue_ptr[wptr++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + queue_ptr[wptr++] = xcc_offset - PACKET3_SET_UCONFIG_REG_START; + queue_ptr[wptr++] = 0xDEADBEEF; + + for (i = wptr; i < compute_ring_align; i++) + queue_ptr[wptr++] = PACKET3(PACKET3_NOP, 0x3FFF); + + } else if (queue_type == AMDGPU_RING_TYPE_SDMA) { + *cpu_ptr = 0xCAFEDEAD; + + queue_ptr[wptr++] = SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_WRITE) | + SDMA_PKT_COPY_LINEAR_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR); + queue_ptr[wptr++] = lower_32_bits(fence_gpu_addr); + queue_ptr[wptr++] = upper_32_bits(fence_gpu_addr); + queue_ptr[wptr++] = SDMA_PKT_WRITE_UNTILED_DW_3_COUNT(0); + queue_ptr[wptr++] = 0xDEADBEEF; + + for (i = wptr; i < sdma_ring_align; i++) + queue_ptr[wptr++] = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP); + + wptr <<= 2; + } + + atomic64_set((atomic64_t *)wptr_cpu_addr, wptr); + WDOORBELL64(doorbell_idx, wptr); + + for (i = 0; i < adev->usec_timeout; i++) { + if (queue_type == AMDGPU_RING_TYPE_SDMA) { + tmp = le32_to_cpu(*cpu_ptr); + } else { + if (!adev->mes.enable_coop_mode) { + tmp = RREG32_SOC15(GC, GET_INST(GC, xcc_id), + regSCRATCH_REG0); + } else { + for (i = 0; i < num_xcc; i++) { + if (xcc_id != adev->mes.master_xcc_ids[i]) + continue; + + tmp = RREG32_SOC15(GC, GET_INST(GC, i), + regSCRATCH_REG0); + if (tmp != 0xDEADBEEF) + break; + } + } + } + + if (tmp == 0xDEADBEEF) + break; + + if (amdgpu_emu_mode == 1) + msleep(1); + else + udelay(1); + } + + if (i >= adev->usec_timeout) { + dev_err(adev->dev, "xcc%d: mes self test (%s) failed\n", xcc_id, + queue_type == AMDGPU_RING_TYPE_SDMA ? "sdma" : "compute"); + + while (halt_if_hws_hang) + schedule(); + + r = -ETIMEDOUT; + } else { + dev_info(adev->dev, "xcc%d: mes self test (%s) pass\n", xcc_id, + queue_type == AMDGPU_RING_TYPE_SDMA ? "sdma" : "compute"); + } + + return r; +} + +#define USER_CTX_SIZE (PAGE_SIZE * 2) +#define USER_CTX_VA AMDGPU_VA_RESERVED_BOTTOM +#define RING_OFFSET(addr) ((addr)) +#define EOP_OFFSET(addr) ((addr) + PAGE_SIZE) +#define WPTR_OFFSET(addr) ((addr) + USER_CTX_SIZE - sizeof(u64)) +#define RPTR_OFFSET(addr) ((addr) + USER_CTX_SIZE - sizeof(u64) * 2) +#define FENCE_OFFSET(addr) ((addr) + USER_CTX_SIZE - sizeof(u64) * 3) + +static int mes_v12_1_test_queue(struct amdgpu_device *adev, int xcc_id, + int pasid, struct amdgpu_vm *vm, u64 meta_gpu_addr, + u64 queue_gpu_addr, void *ctx_ptr, int queue_type) +{ + struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_GFXHUB(0)]; + struct amdgpu_mqd *mqd_mgr = &adev->mqds[queue_type]; + struct amdgpu_mqd_prop mqd_prop = {0}; + struct mes_add_queue_input add_queue = {0}; + struct mes_remove_queue_input remove_queue = {0}; + struct amdgpu_bo *mqd_bo = NULL; + int num_xcc = NUM_XCC(adev->gfx.xcc_mask); + int i, r, off, mqd_size, mqd_count = 1; + void *mqd_ptr = NULL; + u64 mqd_gpu_addr, doorbell_idx; + + /* extra one page size padding for mes fw */ + mqd_size = mqd_mgr->mqd_size + PAGE_SIZE; + + if (queue_type == AMDGPU_RING_TYPE_SDMA) { + doorbell_idx = adev->mes.db_start_dw_offset + \ + adev->doorbell_index.sdma_engine[0]; + } else { + doorbell_idx = adev->mes.db_start_dw_offset + \ + adev->doorbell_index.userqueue_start; + } + + if (adev->mes.enable_coop_mode && + queue_type == AMDGPU_RING_TYPE_COMPUTE) { + for (i = 0, mqd_count = 0; i < num_xcc; i++) { + if (adev->mes.master_xcc_ids[i] == xcc_id) + mqd_count++; + } + mqd_size *= mqd_count; + } + + r = mes_v12_1_alloc_test_buf(adev, &mqd_bo, &mqd_gpu_addr, + &mqd_ptr, mqd_size * mqd_count); + if (r < 0) + return r; + + mqd_prop.mqd_gpu_addr = mqd_gpu_addr; + mqd_prop.hqd_base_gpu_addr = RING_OFFSET(USER_CTX_VA); + mqd_prop.eop_gpu_addr = EOP_OFFSET(USER_CTX_VA); + mqd_prop.wptr_gpu_addr = WPTR_OFFSET(USER_CTX_VA); + mqd_prop.rptr_gpu_addr = RPTR_OFFSET(USER_CTX_VA); + mqd_prop.doorbell_index = doorbell_idx; + mqd_prop.queue_size = PAGE_SIZE; + mqd_prop.mqd_stride_size = mqd_size; + mqd_prop.use_doorbell = true; + mqd_prop.hqd_active = false; + + mqd_mgr->init_mqd(adev, mqd_ptr, &mqd_prop); + if (mqd_count > 1) { + for (i = 1; i < mqd_count; i++) { + off = mqd_size * i; + mqd_prop.mqd_gpu_addr = mqd_gpu_addr + off; + mqd_mgr->init_mqd(adev, (char *)mqd_ptr + off, + &mqd_prop); + } + } + + add_queue.xcc_id = xcc_id; + add_queue.process_id = pasid; + add_queue.page_table_base_addr = adev->vm_manager.vram_base_offset + + amdgpu_bo_gpu_offset(vm->root.bo) - adev->gmc.vram_start; + add_queue.process_va_start = 0; + add_queue.process_va_end = adev->vm_manager.max_pfn - 1; + add_queue.process_context_addr = meta_gpu_addr; + add_queue.gang_context_addr = meta_gpu_addr + AMDGPU_MES_PROC_CTX_SIZE; + add_queue.doorbell_offset = doorbell_idx; + add_queue.mqd_addr = mqd_gpu_addr; + add_queue.wptr_addr = mqd_prop.wptr_gpu_addr; + add_queue.wptr_mc_addr = WPTR_OFFSET(queue_gpu_addr); + add_queue.queue_type = queue_type; + add_queue.vm_cntx_cntl = hub->vm_cntx_cntl; + + r = mes_v12_1_add_hw_queue(&adev->mes, &add_queue); + if (r) + goto error; + + mes_v12_1_test_ring(adev, xcc_id, (u32 *)RING_OFFSET((char *)ctx_ptr), + FENCE_OFFSET(USER_CTX_VA), + FENCE_OFFSET((char *)ctx_ptr), + WPTR_OFFSET((char *)ctx_ptr), + doorbell_idx, queue_type); + + remove_queue.xcc_id = xcc_id; + remove_queue.doorbell_offset = doorbell_idx; + remove_queue.gang_context_addr = add_queue.gang_context_addr; + r = mes_v12_1_remove_hw_queue(&adev->mes, &remove_queue); + +error: + amdgpu_bo_free_kernel(&mqd_bo, &mqd_gpu_addr, &mqd_ptr); + return r; +} + +static int mes_v12_1_self_test(struct amdgpu_device *adev, int xcc_id) +{ + int queue_types[] = { AMDGPU_RING_TYPE_COMPUTE, + /* AMDGPU_RING_TYPE_SDMA */ }; + struct amdgpu_bo_va *bo_va = NULL; + struct amdgpu_vm *vm = NULL; + struct amdgpu_bo *meta_bo = NULL, *ctx_bo = NULL; + void *meta_ptr = NULL, *ctx_ptr = NULL; + u64 meta_gpu_addr, ctx_gpu_addr; + int size, i, r, pasid; + + pasid = amdgpu_pasid_alloc(16); + if (pasid < 0) + pasid = 0; + + size = AMDGPU_MES_PROC_CTX_SIZE + AMDGPU_MES_GANG_CTX_SIZE; + r = mes_v12_1_alloc_test_buf(adev, &meta_bo, &meta_gpu_addr, + &meta_ptr, size); + if (r < 0) + goto err2; + + r = mes_v12_1_alloc_test_buf(adev, &ctx_bo, &ctx_gpu_addr, + &ctx_ptr, USER_CTX_SIZE); + if (r < 0) + goto err2; + + vm = kzalloc(sizeof(*vm), GFP_KERNEL); + if (!vm) { + r = -ENOMEM; + goto err2; + } + + r = amdgpu_vm_init(adev, vm, -1, pasid); + if (r) + goto err1; + + r = mes_v12_1_map_test_bo(adev, ctx_bo, vm, &bo_va, + USER_CTX_VA, USER_CTX_SIZE); + if (r) + goto err0; + + for (i = 0; i < ARRAY_SIZE(queue_types); i++) { + memset(ctx_ptr, 0, USER_CTX_SIZE); + + r = mes_v12_1_test_queue(adev, xcc_id, pasid, vm, meta_gpu_addr, + ctx_gpu_addr, ctx_ptr, queue_types[i]); + if (r) + break; + } + + amdgpu_unmap_static_csa(adev, vm, ctx_bo, bo_va, USER_CTX_VA); +err0: + amdgpu_vm_fini(adev, vm); +err1: + kfree(vm); +err2: + amdgpu_bo_free_kernel(&meta_bo, &meta_gpu_addr, &meta_ptr); + amdgpu_bo_free_kernel(&ctx_bo, &ctx_gpu_addr, &ctx_ptr); + amdgpu_pasid_free(pasid); + return r; +} + diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c index a0cc8e218ca1..42a09a277ec3 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c @@ -141,7 +141,7 @@ mmhub_v2_0_print_l2_protection_fault_status(struct amdgpu_device *adev, uint32_t status) { uint32_t cid, rw; - const char *mmhub_cid = NULL; + const char *mmhub_cid; cid = REG_GET_FIELD(status, MMVM_L2_PROTECTION_FAULT_STATUS, CID); @@ -151,22 +151,7 @@ mmhub_v2_0_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", status); - switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { - case IP_VERSION(2, 0, 0): - case IP_VERSION(2, 0, 2): - mmhub_cid = mmhub_client_ids_navi1x[cid][rw]; - break; - case IP_VERSION(2, 1, 0): - case IP_VERSION(2, 1, 1): - mmhub_cid = mmhub_client_ids_sienna_cichlid[cid][rw]; - break; - case IP_VERSION(2, 1, 2): - mmhub_cid = mmhub_client_ids_beige_goby[cid][rw]; - break; - default: - mmhub_cid = NULL; - break; - } + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", @@ -518,6 +503,31 @@ static const struct amdgpu_vmhub_funcs mmhub_v2_0_vmhub_funcs = { .get_invalidate_req = mmhub_v2_0_get_invalidate_req, }; +static void mmhub_v2_0_init_client_info(struct amdgpu_device *adev) +{ + switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { + case IP_VERSION(2, 0, 0): + case IP_VERSION(2, 0, 2): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_navi1x, + ARRAY_SIZE(mmhub_client_ids_navi1x)); + break; + case IP_VERSION(2, 1, 0): + case IP_VERSION(2, 1, 1): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_sienna_cichlid, + ARRAY_SIZE(mmhub_client_ids_sienna_cichlid)); + break; + case IP_VERSION(2, 1, 2): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_beige_goby, + ARRAY_SIZE(mmhub_client_ids_beige_goby)); + break; + default: + break; + } +} + static void mmhub_v2_0_init(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB0(0)]; @@ -558,6 +568,8 @@ static void mmhub_v2_0_init(struct amdgpu_device *adev) MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; hub->vmhub_funcs = &mmhub_v2_0_vmhub_funcs; + + mmhub_v2_0_init_client_info(adev); } static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c index 5eb8122e2746..31c479d76c42 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c @@ -80,7 +80,7 @@ mmhub_v2_3_print_l2_protection_fault_status(struct amdgpu_device *adev, uint32_t status) { uint32_t cid, rw; - const char *mmhub_cid = NULL; + const char *mmhub_cid; cid = REG_GET_FIELD(status, MMVM_L2_PROTECTION_FAULT_STATUS, CID); @@ -90,16 +90,7 @@ mmhub_v2_3_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", status); - switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { - case IP_VERSION(2, 3, 0): - case IP_VERSION(2, 4, 0): - case IP_VERSION(2, 4, 1): - mmhub_cid = mmhub_client_ids_vangogh[cid][rw]; - break; - default: - mmhub_cid = NULL; - break; - } + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", @@ -486,6 +477,10 @@ static void mmhub_v2_3_init(struct amdgpu_device *adev) MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; hub->vmhub_funcs = &mmhub_v2_3_vmhub_funcs; + + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_vangogh, + ARRAY_SIZE(mmhub_client_ids_vangogh)); } static void diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c index 7d5242df58a5..3d82cfa0f1b5 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c @@ -97,7 +97,7 @@ mmhub_v3_0_print_l2_protection_fault_status(struct amdgpu_device *adev, uint32_t status) { uint32_t cid, rw; - const char *mmhub_cid = NULL; + const char *mmhub_cid; cid = REG_GET_FIELD(status, MMVM_L2_PROTECTION_FAULT_STATUS, CID); @@ -107,15 +107,7 @@ mmhub_v3_0_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", status); - switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { - case IP_VERSION(3, 0, 0): - case IP_VERSION(3, 0, 1): - mmhub_cid = mmhub_client_ids_v3_0_0[cid][rw]; - break; - default: - mmhub_cid = NULL; - break; - } + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", @@ -520,6 +512,10 @@ static void mmhub_v3_0_init(struct amdgpu_device *adev) SOC15_REG_OFFSET(MMHUB, 0, regMMVM_CONTEXTS_DISABLE); hub->vmhub_funcs = &mmhub_v3_0_vmhub_funcs; + + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_v3_0_0, + ARRAY_SIZE(mmhub_client_ids_v3_0_0)); } static u64 mmhub_v3_0_get_fb_location(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c index 910337dc28d1..a1b0b7b39a42 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c @@ -104,7 +104,7 @@ mmhub_v3_0_1_print_l2_protection_fault_status(struct amdgpu_device *adev, uint32_t status) { uint32_t cid, rw; - const char *mmhub_cid = NULL; + const char *mmhub_cid; cid = REG_GET_FIELD(status, MMVM_L2_PROTECTION_FAULT_STATUS, CID); @@ -114,16 +114,7 @@ mmhub_v3_0_1_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", status); - - switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { - case IP_VERSION(3, 0, 1): - mmhub_cid = mmhub_client_ids_v3_0_1[cid][rw]; - break; - default: - mmhub_cid = NULL; - break; - } - + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", @@ -503,6 +494,10 @@ static void mmhub_v3_0_1_init(struct amdgpu_device *adev) MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; hub->vmhub_funcs = &mmhub_v3_0_1_vmhub_funcs; + + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_v3_0_1, + ARRAY_SIZE(mmhub_client_ids_v3_0_1)); } static u64 mmhub_v3_0_1_get_fb_location(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c index f0f182f033b9..34e8dbd47c0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c @@ -97,7 +97,7 @@ mmhub_v3_0_2_print_l2_protection_fault_status(struct amdgpu_device *adev, uint32_t status) { uint32_t cid, rw; - const char *mmhub_cid = NULL; + const char *mmhub_cid; cid = REG_GET_FIELD(status, MMVM_L2_PROTECTION_FAULT_STATUS, CID); @@ -107,8 +107,7 @@ mmhub_v3_0_2_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", status); - - mmhub_cid = mmhub_client_ids_v3_0_2[cid][rw]; + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", @@ -509,6 +508,10 @@ static void mmhub_v3_0_2_init(struct amdgpu_device *adev) SOC15_REG_OFFSET(MMHUB, 0, regMMVM_L2_BANK_SELECT_RESERVED_CID2); hub->vmhub_funcs = &mmhub_v3_0_2_vmhub_funcs; + + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_v3_0_2, + ARRAY_SIZE(mmhub_client_ids_v3_0_2)); } static u64 mmhub_v3_0_2_get_fb_location(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c index daf1f8ad4cca..cfce7e1297d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c @@ -217,7 +217,7 @@ mmhub_v3_3_print_l2_protection_fault_status(struct amdgpu_device *adev, uint32_t status) { uint32_t cid, rw; - const char *mmhub_cid = NULL; + const char *mmhub_cid; cid = REG_GET_FIELD(status, MMVM_L2_PROTECTION_FAULT_STATUS, CID); @@ -227,29 +227,10 @@ mmhub_v3_3_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", status); - - switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { - case IP_VERSION(3, 3, 0): - case IP_VERSION(3, 3, 2): - mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_3) ? - mmhub_client_ids_v3_3[cid][rw] : - cid == 0x140 ? "UMSCH" : NULL; - break; - case IP_VERSION(3, 3, 1): - mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_3_1) ? - mmhub_client_ids_v3_3_1[cid][rw] : - cid == 0x140 ? "UMSCH" : NULL; - break; - case IP_VERSION(3, 4, 0): - mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_4) ? - mmhub_client_ids_v3_4[cid][rw] : - cid == 0x140 ? "UMSCH" : NULL; - break; - default: - mmhub_cid = NULL; - break; - } - + if (cid == 0x140) + mmhub_cid = "UMSCH"; + else + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", @@ -640,6 +621,30 @@ static const struct amdgpu_vmhub_funcs mmhub_v3_3_vmhub_funcs = { .get_invalidate_req = mmhub_v3_3_get_invalidate_req, }; +static void mmhub_v3_3_init_client_info(struct amdgpu_device *adev) +{ + switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { + case IP_VERSION(3, 3, 0): + case IP_VERSION(3, 3, 2): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_v3_3, + ARRAY_SIZE(mmhub_client_ids_v3_3)); + break; + case IP_VERSION(3, 3, 1): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_v3_3_1, + ARRAY_SIZE(mmhub_client_ids_v3_3_1)); + break; + case IP_VERSION(3, 4, 0): + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_v3_4, + ARRAY_SIZE(mmhub_client_ids_v3_4)); + break; + default: + break; + } +} + static void mmhub_v3_3_init(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB0(0)]; @@ -680,6 +685,8 @@ static void mmhub_v3_3_init(struct amdgpu_device *adev) MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; hub->vmhub_funcs = &mmhub_v3_3_vmhub_funcs; + + mmhub_v3_3_init_client_info(adev); } static u64 mmhub_v3_3_get_fb_location(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c index 951998454b25..bef75c4c48d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c @@ -90,7 +90,7 @@ mmhub_v4_1_0_print_l2_protection_fault_status(struct amdgpu_device *adev, uint32_t status) { uint32_t cid, rw; - const char *mmhub_cid = NULL; + const char *mmhub_cid; cid = REG_GET_FIELD(status, MMVM_L2_PROTECTION_FAULT_STATUS_LO32, CID); @@ -100,14 +100,7 @@ mmhub_v4_1_0_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS_LO32:0x%08X\n", status); - switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { - case IP_VERSION(4, 1, 0): - mmhub_cid = mmhub_client_ids_v4_1_0[cid][rw]; - break; - default: - mmhub_cid = NULL; - break; - } + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", @@ -514,6 +507,10 @@ static void mmhub_v4_1_0_init(struct amdgpu_device *adev) SOC15_REG_OFFSET(MMHUB, 0, regMMVM_CONTEXTS_DISABLE); hub->vmhub_funcs = &mmhub_v4_1_0_vmhub_funcs; + + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_v4_1_0, + ARRAY_SIZE(mmhub_client_ids_v4_1_0)); } static u64 mmhub_v4_1_0_get_fb_location(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c index a72770e3d0e9..29f7ed466858 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c @@ -72,6 +72,45 @@ static const char *mmhub_client_ids_v4_2_0[][2] = { [23][1] = "VCN1", }; +static int mmhub_v4_2_0_get_xgmi_info(struct amdgpu_device *adev) +{ + u32 max_num_physical_nodes; + u32 max_physical_node_id; + u32 xgmi_lfb_cntl; + u32 max_region; + u64 seg_size; + + /* limit this callback to A + A configuration only */ + if (!adev->gmc.xgmi.connected_to_cpu) + return 0; + + xgmi_lfb_cntl = RREG32_SOC15(MMHUB, GET_INST(MMHUB, 0), + regMMMC_VM_XGMI_LFB_CNTL); + seg_size = REG_GET_FIELD( + RREG32_SOC15(MMHUB, GET_INST(MMHUB, 0), regMMMC_VM_XGMI_LFB_SIZE), + MMMC_VM_XGMI_LFB_SIZE, PF_LFB_SIZE) << 24; + max_region = + REG_GET_FIELD(xgmi_lfb_cntl, MMMC_VM_XGMI_LFB_CNTL, PF_MAX_REGION); + + max_num_physical_nodes = 4; + max_physical_node_id = 3; + + adev->gmc.xgmi.num_physical_nodes = max_region + 1; + + if (adev->gmc.xgmi.num_physical_nodes > max_num_physical_nodes) + return -EINVAL; + + adev->gmc.xgmi.physical_node_id = + REG_GET_FIELD(xgmi_lfb_cntl, MMMC_VM_XGMI_LFB_CNTL, PF_LFB_REGION); + + if (adev->gmc.xgmi.physical_node_id > max_physical_node_id) + return -EINVAL; + + adev->gmc.xgmi.node_segment_size = seg_size; + + return 0; +} + static u64 mmhub_v4_2_0_get_fb_location(struct amdgpu_device *adev) { u64 base; @@ -131,7 +170,7 @@ static void mmhub_v4_2_0_setup_vm_pt_regs(struct amdgpu_device *adev, static void mmhub_v4_2_0_mid_init_gart_aperture_regs(struct amdgpu_device *adev, uint32_t mid_mask) { - uint64_t pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); + uint64_t pt_base; int i; if (adev->gmc.pdb0_bo) @@ -152,10 +191,10 @@ static void mmhub_v4_2_0_mid_init_gart_aperture_regs(struct amdgpu_device *adev, WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), regMMVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, - (u32)(adev->gmc.fb_end >> 12)); + (u32)(adev->gmc.gart_end >> 12)); WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), regMMVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, - (u32)(adev->gmc.fb_end >> 44)); + (u32)(adev->gmc.gart_end >> 44)); } else { WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), regMMVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, @@ -190,41 +229,74 @@ static void mmhub_v4_2_0_mid_init_system_aperture_regs(struct amdgpu_device *ade return; for_each_inst(i, mid_mask) { - /* Program the AGP BAR */ - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_BASE_LO32, 0); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_BASE_HI32, 0); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_BOT_LO32, - lower_32_bits(adev->gmc.agp_start >> 24)); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_BOT_HI32, - upper_32_bits(adev->gmc.agp_start >> 24)); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_TOP_LO32, - lower_32_bits(adev->gmc.agp_end >> 24)); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_TOP_HI32, - upper_32_bits(adev->gmc.agp_end >> 24)); + if (adev->gmc.pdb0_bo) { + /* Disable agp and system aperture + * when vmid0 page table is enabled */ + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_FB_LOCATION_TOP_LO32, 0); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_FB_LOCATION_TOP_HI32, 0); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_FB_LOCATION_BASE_LO32, + 0xFFFFFFFF); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_FB_LOCATION_BASE_HI32, 1); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_TOP_LO32, 0); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_TOP_HI32, 0); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_BOT_LO32, + 0xFFFFFFFF); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_BOT_HI32, 1); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32, + 0xFFFFFFFF); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32, + 0x7F); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, 0); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, 0); + } else { + /* Program the AGP BAR */ + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_BASE_LO32, 0); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_BASE_HI32, 0); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_BOT_LO32, + lower_32_bits(adev->gmc.agp_start >> 24)); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_BOT_HI32, + upper_32_bits(adev->gmc.agp_start >> 24)); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_TOP_LO32, + lower_32_bits(adev->gmc.agp_end >> 24)); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_AGP_TOP_HI32, + upper_32_bits(adev->gmc.agp_end >> 24)); - /* Program the system aperture low logical page number. */ - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32, - lower_32_bits(min(adev->gmc.fb_start, - adev->gmc.agp_start) >> 18)); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32, - upper_32_bits(min(adev->gmc.fb_start, - adev->gmc.agp_start) >> 18)); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, - lower_32_bits(max(adev->gmc.fb_end, - adev->gmc.agp_end) >> 18)); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, - upper_32_bits(max(adev->gmc.fb_end, - adev->gmc.agp_end) >> 18)); + /* Program the system aperture low logical page number. */ + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32, + lower_32_bits(min(adev->gmc.fb_start, + adev->gmc.agp_start) >> 18)); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32, + upper_32_bits(min(adev->gmc.fb_start, + adev->gmc.agp_start) >> 18)); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, + lower_32_bits(max(adev->gmc.fb_end, + adev->gmc.agp_end) >> 18)); + WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), + regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, + upper_32_bits(max(adev->gmc.fb_end, + adev->gmc.agp_end) >> 18)); + } /* Set default page address. */ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); @@ -252,38 +324,6 @@ static void mmhub_v4_2_0_mid_init_system_aperture_regs(struct amdgpu_device *ade WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), regMMVM_L2_PROTECTION_FAULT_CNTL2, tmp); } - - /* In the case squeezing vram into GART aperture, we don't use - * FB aperture and AGP aperture. Disable them. - */ - if (adev->gmc.pdb0_bo) { - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_FB_LOCATION_TOP_LO32, 0); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_FB_LOCATION_TOP_HI32, 0); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_FB_LOCATION_BASE_LO32, 0xFFFFFFFF); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_FB_LOCATION_BASE_HI32, 1); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_TOP_LO32, 0); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_TOP_HI32, 0); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_BOT_LO32, 0xFFFFFFFF); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_AGP_BOT_HI32, 1); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32, - 0xFFFFFFFF); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32, - 0x7F); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, 0); - WREG32_SOC15(MMHUB, GET_INST(MMHUB, i), - regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, 0); - } } static void mmhub_v4_2_0_mid_init_tlb_regs(struct amdgpu_device *adev, @@ -676,7 +716,7 @@ mmhub_v4_2_0_print_l2_protection_fault_status(struct amdgpu_device *adev, uint32_t status) { uint32_t cid, rw; - const char *mmhub_cid = NULL; + const char *mmhub_cid; cid = REG_GET_FIELD(status, MMVM_L2_PROTECTION_FAULT_STATUS_LO32, CID); @@ -686,14 +726,7 @@ mmhub_v4_2_0_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS_LO32:0x%08X\n", status); - switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { - case IP_VERSION(4, 2, 0): - mmhub_cid = mmhub_client_ids_v4_2_0[cid][rw]; - break; - default: - mmhub_cid = NULL; - break; - } + mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw); dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", mmhub_cid ? mmhub_cid : "unknown", cid); dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", @@ -784,6 +817,10 @@ static void mmhub_v4_2_0_init(struct amdgpu_device *adev) mid_mask = adev->aid_mask; mmhub_v4_2_0_mid_init(adev, mid_mask); + + amdgpu_mmhub_init_client_info(&adev->mmhub, + mmhub_client_ids_v4_2_0, + ARRAY_SIZE(mmhub_client_ids_v4_2_0)); } static void @@ -883,6 +920,7 @@ const struct amdgpu_mmhub_funcs mmhub_v4_2_0_funcs = { .set_fault_enable_default = mmhub_v4_2_0_set_fault_enable_default, .set_clockgating = mmhub_v4_2_0_set_clockgating, .get_clockgating = mmhub_v4_2_0_get_clockgating, + .get_xgmi_info = mmhub_v4_2_0_get_xgmi_info, }; static int mmhub_v4_2_0_xcp_resume(void *handle, uint32_t inst_mask) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c index 9aa988982304..fb7aaf5ae05c 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c @@ -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++) { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c index 03bf1f86098f..f20e0fc3fc74 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c @@ -1129,12 +1129,21 @@ static void sdma_v7_1_vm_set_pte_pde(struct amdgpu_ib *ib, /* for physically contiguous pages (vram) */ u32 header = SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_PTEPDE); - if (amdgpu_mtype_local) - header |= SDMA_PKT_PTEPDE_COPY_HEADER_MTYPE(0x3); - else - header |= (SDMA_PKT_PTEPDE_COPY_HEADER_MTYPE(0x2) | - SDMA_PKT_PTEPDE_COPY_HEADER_SNOOP(0x1) | - SDMA_PKT_PTEPDE_COPY_HEADER_SCOPE(0x3)); + /* TODO: + * When VM_L2_CNTL5.WALKER_FETCH_PDE_MTYPE_ENABLE is enabled, change below MTYPE + * to RW for AID A1 and UC for AID A0. NC needs additional GCR flush and need not + * be supported. Also, honour amdgpu_mtype_local override. RW would additionally + * require setting SCOPE bits in the header. + * + * header |= (SDMA_PKT_PTEPDE_COPY_HEADER_MTYPE(0x2:RW) | + * SDMA_PKT_PTEPDE_COPY_HEADER_SNOOP(0x1) | + * SDMA_PKT_PTEPDE_COPY_HEADER_SCOPE(0x3:SYS_SCOPE)); + */ + + /* VM_L2_CNTL5.WALKER_FETCH_PDE_MTYPE_ENABLE is 0 which defaults to UC. So, + * use MTYPE_UC (0x3). For ref. MTYPE_RW=0x2 MTYPE_NC=0x0 + */ + header |= SDMA_PKT_PTEPDE_COPY_HEADER_MTYPE(0x3) | SDMA_PKT_PTEPDE_COPY_HEADER_SNOOP(0x1); ib->ptr[ib->length_dw++] = header; ib->ptr[ib->length_dw++] = lower_32_bits(pe); /* dst addr */ diff --git a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c index 0c7759b82fa6..709b1669b07b 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c @@ -41,6 +41,44 @@ #define NORMALIZE_XCC_REG_OFFSET(offset) \ (offset & 0xFFFF) +#define MID1_REG_RANGE_0_LOW 0x40000 +#define MID1_REG_RANGE_0_HIGH 0x80000 +#define NORMALIZE_MID_REG_OFFSET(offset) \ + (offset & 0x3FFFF) + +static const struct amdgpu_video_codecs vcn_5_0_2_video_codecs_encode_vcn0 = { + .codec_count = 0, + .codec_array = NULL, +}; + +static const struct amdgpu_video_codec_info vcn_5_0_2_video_codecs_decode_array_vcn0[] = { + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, +}; + +static const struct amdgpu_video_codecs vcn_5_0_2_video_codecs_decode_vcn0 = { + .codec_count = ARRAY_SIZE(vcn_5_0_2_video_codecs_decode_array_vcn0), + .codec_array = vcn_5_0_2_video_codecs_decode_array_vcn0, +}; + +static int soc_v1_0_query_video_codecs(struct amdgpu_device *adev, bool encode, + const struct amdgpu_video_codecs **codecs) +{ + switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) { + case IP_VERSION(5, 0, 2): + if (encode) + *codecs = &vcn_5_0_2_video_codecs_encode_vcn0; + else + *codecs = &vcn_5_0_2_video_codecs_decode_vcn0; + return 0; + default: + return -EINVAL; + } +} + /* Initialized doorbells for amdgpu including multimedia * KFD can use all the rest in 2M doorbell bar */ static void soc_v1_0_doorbell_index_init(struct amdgpu_device *adev) @@ -257,6 +295,7 @@ static const struct amdgpu_asic_funcs soc_v1_0_asic_funcs = { .encode_ext_smn_addressing = &soc_v1_0_encode_ext_smn_addressing, .reset = soc_v1_0_asic_reset, .reset_method = &soc_v1_0_asic_reset_method, + .query_video_codecs = &soc_v1_0_query_video_codecs, }; static int soc_v1_0_common_early_init(struct amdgpu_ip_block *ip_block) @@ -283,7 +322,7 @@ static int soc_v1_0_common_early_init(struct amdgpu_ip_block *ip_block) case IP_VERSION(12, 1, 0): adev->cg_flags = AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_CGLS; - adev->pg_flags = 0; + adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG; adev->external_rev_id = adev->rev_id + 0x50; break; default: @@ -870,3 +909,31 @@ uint32_t soc_v1_0_normalize_xcc_reg_offset(uint32_t reg) else return reg; } + +bool soc_v1_0_mid1_reg_range(uint32_t reg) +{ + uint32_t normalized_reg = soc_v1_0_normalize_xcc_reg_offset(reg); + + if (soc_v1_0_normalize_xcc_reg_range(normalized_reg)) + return false; + + if ((reg >= MID1_REG_RANGE_0_LOW) && (reg < MID1_REG_RANGE_0_HIGH)) + return true; + else + return false; +} + +uint32_t soc_v1_0_normalize_reg_offset(uint32_t reg) +{ + uint32_t normalized_reg = soc_v1_0_normalize_xcc_reg_offset(reg); + + if (soc_v1_0_normalize_xcc_reg_range(normalized_reg)) + return soc_v1_0_normalize_xcc_reg_offset(reg); + + /* check if the reg offset is inside MID1. */ + if (soc_v1_0_mid1_reg_range(reg)) + return NORMALIZE_MID_REG_OFFSET(reg); + + return reg; +} + diff --git a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.h b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.h index 146996101aa0..16c220fcc4e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.h +++ b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.h @@ -31,7 +31,9 @@ void soc_v1_0_grbm_select(struct amdgpu_device *adev, int xcc_id); int soc_v1_0_init_soc_config(struct amdgpu_device *adev); bool soc_v1_0_normalize_xcc_reg_range(uint32_t reg); +bool soc_v1_0_mid1_reg_range(uint32_t reg); uint32_t soc_v1_0_normalize_xcc_reg_offset(uint32_t reg); +uint32_t soc_v1_0_normalize_reg_offset(uint32_t reg); u64 soc_v1_0_encode_ext_smn_addressing(int ext_id); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c index 1f80045775f5..db505ab32fa0 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c @@ -183,50 +183,97 @@ static void umc_v12_0_get_retire_flip_bits(struct amdgpu_device *adev) if (adev->gmc.gmc_funcs->query_mem_partition_mode) nps = adev->gmc.gmc_funcs->query_mem_partition_mode(adev); - /* default setting */ - flip_bits->flip_bits_in_pa[0] = UMC_V12_0_PA_C2_BIT; - flip_bits->flip_bits_in_pa[1] = UMC_V12_0_PA_C3_BIT; - flip_bits->flip_bits_in_pa[2] = UMC_V12_0_PA_C4_BIT; - flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R13_BIT; - flip_bits->flip_row_bit = 13; - flip_bits->bit_num = 4; - flip_bits->r13_in_pa = UMC_V12_0_PA_R13_BIT; - - if (nps == AMDGPU_NPS2_PARTITION_MODE) { + if (adev->gmc.num_umc == 16) { + /* default setting */ + flip_bits->flip_bits_in_pa[0] = UMC_V12_0_PA_C2_BIT; + flip_bits->flip_bits_in_pa[1] = UMC_V12_0_PA_C3_BIT; + flip_bits->flip_bits_in_pa[2] = UMC_V12_0_PA_C4_BIT; + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R13_BIT; + flip_bits->flip_row_bit = 13; + flip_bits->bit_num = 4; + flip_bits->r13_in_pa = UMC_V12_0_PA_R13_BIT; + + if (nps == AMDGPU_NPS2_PARTITION_MODE) { + flip_bits->flip_bits_in_pa[0] = UMC_V12_0_PA_CH5_BIT; + flip_bits->flip_bits_in_pa[1] = UMC_V12_0_PA_C2_BIT; + flip_bits->flip_bits_in_pa[2] = UMC_V12_0_PA_B1_BIT; + flip_bits->r13_in_pa = UMC_V12_0_PA_R12_BIT; + } else if (nps == AMDGPU_NPS4_PARTITION_MODE) { + flip_bits->flip_bits_in_pa[0] = UMC_V12_0_PA_CH4_BIT; + flip_bits->flip_bits_in_pa[1] = UMC_V12_0_PA_CH5_BIT; + flip_bits->flip_bits_in_pa[2] = UMC_V12_0_PA_B0_BIT; + flip_bits->r13_in_pa = UMC_V12_0_PA_R11_BIT; + } + + switch (vram_type) { + case AMDGPU_VRAM_TYPE_HBM: + /* other nps modes are taken as nps1 */ + if (nps == AMDGPU_NPS2_PARTITION_MODE) + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R12_BIT; + else if (nps == AMDGPU_NPS4_PARTITION_MODE) + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R11_BIT; + + break; + case AMDGPU_VRAM_TYPE_HBM3E: + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R12_BIT; + flip_bits->flip_row_bit = 12; + + if (nps == AMDGPU_NPS2_PARTITION_MODE) + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R11_BIT; + else if (nps == AMDGPU_NPS4_PARTITION_MODE) + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R10_BIT; + + break; + default: + dev_warn(adev->dev, + "Unknown HBM type, set RAS retire flip bits to the value in NPS1 mode.\n"); + break; + } + } else if (adev->gmc.num_umc == 8) { + /* default setting */ flip_bits->flip_bits_in_pa[0] = UMC_V12_0_PA_CH5_BIT; flip_bits->flip_bits_in_pa[1] = UMC_V12_0_PA_C2_BIT; flip_bits->flip_bits_in_pa[2] = UMC_V12_0_PA_B1_BIT; + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R11_BIT; + flip_bits->flip_row_bit = 12; + flip_bits->bit_num = 4; flip_bits->r13_in_pa = UMC_V12_0_PA_R12_BIT; - } else if (nps == AMDGPU_NPS4_PARTITION_MODE) { - flip_bits->flip_bits_in_pa[0] = UMC_V12_0_PA_CH4_BIT; - flip_bits->flip_bits_in_pa[1] = UMC_V12_0_PA_CH5_BIT; - flip_bits->flip_bits_in_pa[2] = UMC_V12_0_PA_B0_BIT; - flip_bits->r13_in_pa = UMC_V12_0_PA_R11_BIT; - } - switch (vram_type) { - case AMDGPU_VRAM_TYPE_HBM: - /* other nps modes are taken as nps1 */ - if (nps == AMDGPU_NPS2_PARTITION_MODE) + if (nps == AMDGPU_NPS2_PARTITION_MODE) { + flip_bits->flip_bits_in_pa[0] = UMC_V12_0_PA_CH4_BIT; + flip_bits->flip_bits_in_pa[1] = UMC_V12_0_PA_CH5_BIT; + flip_bits->flip_bits_in_pa[2] = UMC_V12_0_PA_B0_BIT; + flip_bits->r13_in_pa = UMC_V12_0_PA_R11_BIT; + } + + switch (vram_type) { + case AMDGPU_VRAM_TYPE_HBM: flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R12_BIT; - else if (nps == AMDGPU_NPS4_PARTITION_MODE) - flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R11_BIT; - break; - case AMDGPU_VRAM_TYPE_HBM3E: - flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R12_BIT; - flip_bits->flip_row_bit = 12; + /* other nps modes are taken as nps1 */ + if (nps == AMDGPU_NPS2_PARTITION_MODE) + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R11_BIT; - if (nps == AMDGPU_NPS2_PARTITION_MODE) + break; + case AMDGPU_VRAM_TYPE_HBM3E: flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R11_BIT; - else if (nps == AMDGPU_NPS4_PARTITION_MODE) - flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R10_BIT; + flip_bits->flip_row_bit = 12; - break; - default: + if (nps == AMDGPU_NPS2_PARTITION_MODE) + flip_bits->flip_bits_in_pa[3] = UMC_V12_0_PA_R10_BIT; + + break; + default: + dev_warn(adev->dev, + "Unknown HBM type, set RAS retire flip bits to the value in NPS1 mode.\n"); + break; + } + } else { dev_warn(adev->dev, - "Unknown HBM type, set RAS retire flip bits to the value in NPS1 mode.\n"); - break; + "Unsupported UMC number(%d), failed to set RAS flip bits.\n", + adev->gmc.num_umc); + + return; } adev->umc.retire_unit = 0x1 << flip_bits->bit_num; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c index 73ce3d211ed6..8a9ba2276275 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c index e78526a4e521..ff3013b97abd 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c @@ -134,6 +134,21 @@ static int vcn_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) return 0; } +static bool vcn_v4_0_3_is_psp_fw_reset_supported(struct amdgpu_device *adev) +{ + uint32_t fw_ver = adev->psp.sos.fw_version; + uint32_t pgm = (fw_ver >> 8) & 0xFF; + + /* + * FWDEV-159155: PSP SOS FW must be >= 0x0036015f for program 0x01 + * before enabling VCN per-queue reset. + */ + if (pgm == 1) + return fw_ver >= 0x0036015f; + + return true; +} + static int vcn_v4_0_3_late_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; @@ -141,7 +156,9 @@ static int vcn_v4_0_3_late_init(struct amdgpu_ip_block *ip_block) adev->vcn.supported_reset = amdgpu_get_soft_full_reset_mask(&adev->vcn.inst[0].ring_enc[0]); - if (amdgpu_dpm_reset_vcn_is_supported(adev) && !amdgpu_sriov_vf(adev)) + if (amdgpu_dpm_reset_vcn_is_supported(adev) && + vcn_v4_0_3_is_psp_fw_reset_supported(adev) && + !amdgpu_sriov_vf(adev)) adev->vcn.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.c new file mode 100644 index 000000000000..c3d3cc023058 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.c @@ -0,0 +1,1219 @@ +/* + * Copyright 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * 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. + * + */ + +#include <linux/firmware.h> +#include "amdgpu.h" +#include "amdgpu_vcn.h" +#include "amdgpu_pm.h" +#include "soc15.h" +#include "soc15d.h" +#include "soc15_hw_ip.h" +#include "vcn_v2_0.h" +#include "vcn_v4_0_3.h" + +#include "vcn/vcn_5_0_0_offset.h" +#include "vcn/vcn_5_0_0_sh_mask.h" +#include "ivsrcid/vcn/irqsrcs_vcn_5_0.h" +#include "vcn_v5_0_0.h" +#include "vcn_v5_0_1.h" +#include "vcn_v5_0_2.h" + +#include <drm/drm_drv.h> + +static void vcn_v5_0_2_set_unified_ring_funcs(struct amdgpu_device *adev); +static void vcn_v5_0_2_set_irq_funcs(struct amdgpu_device *adev); +static int vcn_v5_0_2_set_pg_state(struct amdgpu_vcn_inst *vinst, + enum amd_powergating_state state); +static void vcn_v5_0_2_unified_ring_set_wptr(struct amdgpu_ring *ring); + +/** + * vcn_v5_0_2_early_init - set function pointers and load microcode + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Set ring and irq function pointers + * Load microcode from filesystem + */ +static int vcn_v5_0_2_early_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int i, r; + + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) + /* re-use enc ring as unified ring */ + adev->vcn.inst[i].num_enc_rings = 1; + + vcn_v5_0_2_set_unified_ring_funcs(adev); + vcn_v5_0_2_set_irq_funcs(adev); + + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + adev->vcn.inst[i].set_pg_state = vcn_v5_0_2_set_pg_state; + + r = amdgpu_vcn_early_init(adev, i); + if (r) + return r; + } + + return 0; +} + +static void vcn_v5_0_2_fw_shared_init(struct amdgpu_device *adev, int inst_idx) +{ + struct amdgpu_vcn5_fw_shared *fw_shared; + + fw_shared = adev->vcn.inst[inst_idx].fw_shared.cpu_addr; + + if (fw_shared->sq.is_enabled) + return; + fw_shared->present_flag_0 = + cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE); + fw_shared->sq.is_enabled = 1; + + if (amdgpu_vcnfw_log) + amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst_idx]); +} + +/** + * vcn_v5_0_2_sw_init - sw init for VCN block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Load firmware and sw initialization + */ +static int vcn_v5_0_2_sw_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_ring *ring; + int i, r, vcn_inst; + + /* VCN UNIFIED TRAP */ + r = amdgpu_irq_add_id(adev, SOC_V1_0_IH_CLIENTID_VCN, + VCN_5_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst->irq); + if (r) + return r; + + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + vcn_inst = GET_INST(VCN, i); + + r = amdgpu_vcn_sw_init(adev, i); + if (r) + return r; + + amdgpu_vcn_setup_ucode(adev, i); + + r = amdgpu_vcn_resume(adev, i); + if (r) + return r; + + ring = &adev->vcn.inst[i].ring_enc[0]; + ring->use_doorbell = true; + + ring->doorbell_index = + (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 32 * vcn_inst; + + ring->vm_hub = AMDGPU_MMHUB0(adev->vcn.inst[i].aid_id); + sprintf(ring->name, "vcn_unified_%d", adev->vcn.inst[i].aid_id); + + r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0, + AMDGPU_RING_PRIO_DEFAULT, &adev->vcn.inst[i].sched_score); + if (r) + return r; + + vcn_v5_0_2_fw_shared_init(adev, i); + } + + /* TODO: Add queue reset mask when FW fully supports it */ + adev->vcn.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->vcn.inst[0].ring_enc[0]); + + return amdgpu_vcn_sysfs_reset_mask_init(adev); +} + +/** + * vcn_v5_0_2_sw_fini - sw fini for VCN block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * VCN suspend and free up sw allocation + */ +static int vcn_v5_0_2_sw_fini(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int i, r, idx; + + if (drm_dev_enter(adev_to_drm(adev), &idx)) { + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + struct amdgpu_vcn5_fw_shared *fw_shared; + + fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr; + fw_shared->present_flag_0 = 0; + fw_shared->sq.is_enabled = 0; + } + + drm_dev_exit(idx); + } + + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + r = amdgpu_vcn_suspend(adev, i); + if (r) + return r; + } + + for (i = 0; i < adev->vcn.num_vcn_inst; i++) + amdgpu_vcn_sw_fini(adev, i); + + amdgpu_vcn_sysfs_reset_mask_fini(adev); + + kfree(adev->vcn.ip_dump); //TODO check + + return 0; +} + +/** + * vcn_v5_0_2_hw_init - start and test VCN block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Initialize the hardware, boot up the VCPU and do some testing + */ +static int vcn_v5_0_2_hw_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_ring *ring; + int i, r, vcn_inst; + uint32_t tmp; + + if (RREG32_SOC15(VCN, GET_INST(VCN, 0), regVCN_RRMT_CNTL) & 0x200) + adev->vcn.caps |= AMDGPU_VCN_CAPS(RRMT_ENABLED); + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + vcn_inst = GET_INST(VCN, i); + ring = &adev->vcn.inst[i].ring_enc[0]; + + /* Remove Video Tiles antihang mechanism */ + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_POWER_STATUS); + tmp &= (~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK); + WREG32_SOC15(VCN, vcn_inst, regUVD_POWER_STATUS, tmp); + + if (ring->use_doorbell) + adev->nbio.funcs->vcn_doorbell_range(adev, ring->use_doorbell, + ((adev->doorbell_index.vcn.vcn_ring0_1 << 1) + + 11 * vcn_inst), + adev->vcn.inst[i].aid_id); + + /* Re-init fw_shared, if required */ + vcn_v5_0_2_fw_shared_init(adev, i); + + r = amdgpu_ring_test_helper(ring); + if (r) + return r; + } + + return 0; +} + +/** + * vcn_v5_0_2_hw_fini - stop the hardware block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Stop the VCN block, mark ring as not ready any more + */ +static int vcn_v5_0_2_hw_fini(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int i; + + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[i]; + + cancel_delayed_work_sync(&adev->vcn.inst[i].idle_work); + if (vinst->cur_state != AMD_PG_STATE_GATE) + vinst->set_pg_state(vinst, AMD_PG_STATE_GATE); + } + + return 0; +} + +/** + * vcn_v5_0_2_suspend - suspend VCN block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * HW fini and suspend VCN block + */ +static int vcn_v5_0_2_suspend(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int r, i; + + r = vcn_v5_0_2_hw_fini(ip_block); + if (r) + return r; + + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + r = amdgpu_vcn_suspend(ip_block->adev, i); + if (r) + return r; + } + + return r; +} + +/** + * vcn_v5_0_2_resume - resume VCN block + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Resume firmware and hw init VCN block + */ +static int vcn_v5_0_2_resume(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int r, i; + + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[i]; + + if (amdgpu_in_reset(adev)) + vinst->cur_state = AMD_PG_STATE_GATE; + + r = amdgpu_vcn_resume(ip_block->adev, i); + if (r) + return r; + } + + r = vcn_v5_0_2_hw_init(ip_block); + + return r; +} + +/** + * vcn_v5_0_2_mc_resume - memory controller programming + * + * @vinst: VCN instance + * + * Let the VCN memory controller know it's offsets + */ +static void vcn_v5_0_2_mc_resume(struct amdgpu_vcn_inst *vinst) +{ + struct amdgpu_device *adev = vinst->adev; + int inst = vinst->inst; + uint32_t offset, size, vcn_inst; + const struct common_firmware_header *hdr; + + hdr = (const struct common_firmware_header *)adev->vcn.inst[inst].fw->data; + size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8); + + vcn_inst = GET_INST(VCN, inst); + /* cache window 0: fw */ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW, + (adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + inst].tmr_mc_addr_lo)); + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH, + (adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + inst].tmr_mc_addr_hi)); + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_CACHE_OFFSET0, 0); + offset = 0; + } else { + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW, + lower_32_bits(adev->vcn.inst[inst].gpu_addr)); + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH, + upper_32_bits(adev->vcn.inst[inst].gpu_addr)); + offset = size; + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_CACHE_OFFSET0, + AMDGPU_UVD_FIRMWARE_OFFSET >> 3); + } + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_CACHE_SIZE0, size); + + /* cache window 1: stack */ + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW, + lower_32_bits(adev->vcn.inst[inst].gpu_addr + offset)); + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH, + upper_32_bits(adev->vcn.inst[inst].gpu_addr + offset)); + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_CACHE_OFFSET1, 0); + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_CACHE_SIZE1, AMDGPU_VCN_STACK_SIZE); + + /* cache window 2: context */ + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW, + lower_32_bits(adev->vcn.inst[inst].gpu_addr + offset + AMDGPU_VCN_STACK_SIZE)); + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH, + upper_32_bits(adev->vcn.inst[inst].gpu_addr + offset + AMDGPU_VCN_STACK_SIZE)); + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_CACHE_OFFSET2, 0); + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_CACHE_SIZE2, AMDGPU_VCN_CONTEXT_SIZE); + + /* non-cache window */ + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_NC0_64BIT_BAR_LOW, + lower_32_bits(adev->vcn.inst[inst].fw_shared.gpu_addr)); + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_VCPU_NC0_64BIT_BAR_HIGH, + upper_32_bits(adev->vcn.inst[inst].fw_shared.gpu_addr)); + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_NONCACHE_OFFSET0, 0); + WREG32_SOC15(VCN, vcn_inst, regUVD_VCPU_NONCACHE_SIZE0, + AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn5_fw_shared))); +} + +/** + * vcn_v5_0_2_mc_resume_dpg_mode - memory controller programming for dpg mode + * + * @vinst: VCN instance + * @indirect: indirectly write sram + * + * Let the VCN memory controller know it's offsets with dpg mode + */ +static void vcn_v5_0_2_mc_resume_dpg_mode(struct amdgpu_vcn_inst *vinst, + bool indirect) +{ + struct amdgpu_device *adev = vinst->adev; + int inst_idx = vinst->inst; + uint32_t offset, size; + const struct common_firmware_header *hdr; + + hdr = (const struct common_firmware_header *)adev->vcn.inst[inst_idx].fw->data; + size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8); + + /* cache window 0: fw */ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + if (!indirect) { + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + (adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + + inst_idx].tmr_mc_addr_lo), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + (adev->firmware.ucode[AMDGPU_UCODE_ID_VCN + + inst_idx].tmr_mc_addr_hi), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_OFFSET0), 0, 0, indirect); + } else { + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), 0, 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), 0, 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_OFFSET0), 0, 0, indirect); + } + offset = 0; + } else { + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst[inst_idx].gpu_addr), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst[inst_idx].gpu_addr), 0, indirect); + offset = size; + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_OFFSET0), + AMDGPU_UVD_FIRMWARE_OFFSET >> 3, 0, indirect); + } + + if (!indirect) + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_SIZE0), size, 0, indirect); + else + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_SIZE0), 0, 0, indirect); + + /* cache window 1: stack */ + if (!indirect) { + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst[inst_idx].gpu_addr + offset), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst[inst_idx].gpu_addr + offset), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_OFFSET1), 0, 0, indirect); + } else { + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), 0, 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), 0, 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_OFFSET1), 0, 0, indirect); + } + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_SIZE1), AMDGPU_VCN_STACK_SIZE, 0, indirect); + + /* cache window 2: context */ + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst[inst_idx].gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst[inst_idx].gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_OFFSET2), 0, 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CACHE_SIZE2), AMDGPU_VCN_CONTEXT_SIZE, 0, indirect); + + /* non-cache window */ + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_NC0_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst[inst_idx].fw_shared.gpu_addr), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_VCPU_NC0_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst[inst_idx].fw_shared.gpu_addr), 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_NONCACHE_OFFSET0), 0, 0, indirect); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_NONCACHE_SIZE0), + AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_vcn5_fw_shared)), 0, indirect); + + /* VCN global tiling registers */ + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_GFX10_ADDR_CONFIG), adev->gfx.config.gb_addr_config, 0, indirect); +} + +/** + * vcn_v5_0_2_disable_clock_gating - disable VCN clock gating + * + * @vinst: VCN instance + * + * Disable clock gating for VCN block + */ +static void vcn_v5_0_2_disable_clock_gating(struct amdgpu_vcn_inst *vinst) +{ +} + +/** + * vcn_v5_0_2_enable_clock_gating - enable VCN clock gating + * + * @vinst: VCN instance + * + * Enable clock gating for VCN block + */ +static void vcn_v5_0_2_enable_clock_gating(struct amdgpu_vcn_inst *vinst) +{ +} + +/** + * vcn_v5_0_2_pause_dpg_mode - VCN pause with dpg mode + * + * @vinst: VCN instance + * @new_state: pause state + * + * Pause dpg mode for VCN block + */ +static int vcn_v5_0_2_pause_dpg_mode(struct amdgpu_vcn_inst *vinst, + struct dpg_pause_state *new_state) +{ + struct amdgpu_device *adev = vinst->adev; + uint32_t reg_data = 0; + int vcn_inst; + + vcn_inst = GET_INST(VCN, vinst->inst); + + /* pause/unpause if state is changed */ + if (vinst->pause_state.fw_based != new_state->fw_based) { + DRM_DEV_DEBUG(adev->dev, "dpg pause state changed %d -> %d %s\n", + vinst->pause_state.fw_based, new_state->fw_based, + new_state->fw_based ? "VCN_DPG_STATE__PAUSE" : "VCN_DPG_STATE__UNPAUSE"); + reg_data = RREG32_SOC15(VCN, vcn_inst, regUVD_DPG_PAUSE) & + (~UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK); + + if (new_state->fw_based == VCN_DPG_STATE__PAUSE) { + /* pause DPG */ + reg_data |= UVD_DPG_PAUSE__NJ_PAUSE_DPG_REQ_MASK; + WREG32_SOC15(VCN, vcn_inst, regUVD_DPG_PAUSE, reg_data); + + /* wait for ACK */ + SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_DPG_PAUSE, + UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK, + UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK); + } else { + /* unpause DPG, no need to wait */ + reg_data &= ~UVD_DPG_PAUSE__NJ_PAUSE_DPG_REQ_MASK; + WREG32_SOC15(VCN, vcn_inst, regUVD_DPG_PAUSE, reg_data); + } + vinst->pause_state.fw_based = new_state->fw_based; + } + + return 0; +} + +/** + * vcn_v5_0_2_start_dpg_mode - VCN start with dpg mode + * + * @vinst: VCN instance + * @indirect: indirectly write sram + * + * Start VCN block with dpg mode + */ +static int vcn_v5_0_2_start_dpg_mode(struct amdgpu_vcn_inst *vinst, + bool indirect) +{ + struct amdgpu_device *adev = vinst->adev; + int inst_idx = vinst->inst; + struct amdgpu_vcn5_fw_shared *fw_shared = + adev->vcn.inst[inst_idx].fw_shared.cpu_addr; + struct amdgpu_ring *ring; + struct dpg_pause_state state = {.fw_based = VCN_DPG_STATE__PAUSE}; + int vcn_inst, ret; + uint32_t tmp; + + vcn_inst = GET_INST(VCN, inst_idx); + + /* disable register anti-hang mechanism */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_POWER_STATUS), 1, + ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK); + + /* enable dynamic power gating mode */ + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_POWER_STATUS); + tmp |= UVD_POWER_STATUS__UVD_PG_MODE_MASK; + WREG32_SOC15(VCN, vcn_inst, regUVD_POWER_STATUS, tmp); + + if (indirect) { + adev->vcn.inst[inst_idx].dpg_sram_curr_addr = + (uint32_t *)adev->vcn.inst[inst_idx].dpg_sram_cpu_addr; + /* Use dummy register 0xDEADBEEF passing AID selection to PSP FW */ + WREG32_SOC24_DPG_MODE(inst_idx, 0xDEADBEEF, + adev->vcn.inst[inst_idx].aid_id, 0, true); + } + + /* enable VCPU clock */ + tmp = (0xFF << UVD_VCPU_CNTL__PRB_TIMEOUT_VAL__SHIFT); + tmp |= UVD_VCPU_CNTL__CLK_EN_MASK | UVD_VCPU_CNTL__BLK_RST_MASK; + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CNTL), tmp, 0, indirect); + + /* disable master interrupt */ + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_MASTINT_EN), 0, 0, indirect); + + /* setup regUVD_LMI_CTRL */ + tmp = (UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK | + UVD_LMI_CTRL__REQ_MODE_MASK | + UVD_LMI_CTRL__CRC_RESET_MASK | + UVD_LMI_CTRL__MASK_MC_URGENT_MASK | + UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK | + UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK | + (8 << UVD_LMI_CTRL__WRITE_CLEAN_TIMER__SHIFT) | + 0x00100000L); + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_CTRL), tmp, 0, indirect); + + vcn_v5_0_2_mc_resume_dpg_mode(vinst, indirect); + + tmp = (0xFF << UVD_VCPU_CNTL__PRB_TIMEOUT_VAL__SHIFT); + tmp |= UVD_VCPU_CNTL__CLK_EN_MASK; + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_VCPU_CNTL), tmp, 0, indirect); + + /* enable LMI MC and UMC channels */ + tmp = 0x1f << UVD_LMI_CTRL2__RE_OFLD_MIF_WR_REQ_NUM__SHIFT; + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_LMI_CTRL2), tmp, 0, indirect); + + /* enable master interrupt */ + WREG32_SOC24_DPG_MODE(inst_idx, SOC24_DPG_MODE_OFFSET( + VCN, 0, regUVD_MASTINT_EN), + UVD_MASTINT_EN__VCPU_EN_MASK, 0, indirect); + + if (indirect) { + ret = amdgpu_vcn_psp_update_sram(adev, inst_idx, AMDGPU_UCODE_ID_VCN0_RAM); + if (ret) { + dev_err(adev->dev, "vcn sram load failed %d\n", ret); + return ret; + } + } + + /* resetting ring, fw should not check RB ring */ + fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET; + + /* Pause dpg */ + vcn_v5_0_2_pause_dpg_mode(vinst, &state); + + ring = &adev->vcn.inst[inst_idx].ring_enc[0]; + + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_LO, lower_32_bits(ring->gpu_addr)); + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_SIZE, ring->ring_size / sizeof(uint32_t)); + + tmp = RREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE); + tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK); + WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp); + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_RPTR, 0); + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR, 0); + + ring->wptr = RREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR); + + tmp = RREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE); + tmp |= VCN_RB_ENABLE__RB1_EN_MASK; + WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp); + /* resetting done, fw can check RB ring */ + fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF); + + WREG32_SOC15(VCN, vcn_inst, regVCN_RB1_DB_CTRL, + ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT | + VCN_RB1_DB_CTRL__EN_MASK); + /* Read DB_CTRL to flush the write DB_CTRL command. */ + RREG32_SOC15(VCN, vcn_inst, regVCN_RB1_DB_CTRL); + + return 0; +} + +/** + * vcn_v5_0_2_start - VCN start + * + * @vinst: VCN instance + * + * Start VCN block + */ +static int vcn_v5_0_2_start(struct amdgpu_vcn_inst *vinst) +{ + struct amdgpu_device *adev = vinst->adev; + int i = vinst->inst; + struct amdgpu_vcn5_fw_shared *fw_shared; + struct amdgpu_ring *ring; + uint32_t tmp; + int j, k, r, vcn_inst; + + fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr; + + if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) + return vcn_v5_0_2_start_dpg_mode(vinst, adev->vcn.inst[i].indirect_sram); + + vcn_inst = GET_INST(VCN, i); + + /* set VCN status busy */ + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS) | UVD_STATUS__UVD_BUSY; + WREG32_SOC15(VCN, vcn_inst, regUVD_STATUS, tmp); + + /* enable VCPU clock */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), + UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK); + + /* disable master interrupt */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_MASTINT_EN), 0, + ~UVD_MASTINT_EN__VCPU_EN_MASK); + + /* enable LMI MC and UMC channels */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_LMI_CTRL2), 0, + ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK); + + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET); + tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK; + tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK; + WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp); + + /* setup regUVD_LMI_CTRL */ + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL); + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL, tmp | + UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK | + UVD_LMI_CTRL__MASK_MC_URGENT_MASK | + UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK | + UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK); + + vcn_v5_0_2_mc_resume(vinst); + + /* VCN global tiling registers */ + WREG32_SOC15(VCN, vcn_inst, regUVD_GFX10_ADDR_CONFIG, + adev->gfx.config.gb_addr_config); + + /* unblock VCPU register access */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_RB_ARB_CTRL), 0, + ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK); + + /* release VCPU reset to boot */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), 0, + ~UVD_VCPU_CNTL__BLK_RST_MASK); + + for (j = 0; j < 10; ++j) { + uint32_t status; + + for (k = 0; k < 100; ++k) { + status = RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS); + if (status & 2) + break; + mdelay(1000); + if (amdgpu_emu_mode == 1) + msleep(520); + } + + if (amdgpu_emu_mode == 1) { + r = -1; + if (status & 2) { + r = 0; + break; + } + } else { + r = 0; + if (status & 2) + break; + + dev_err(adev->dev, + "VCN[%d] is not responding, trying to reset the VCPU!!!\n", i); + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), + UVD_VCPU_CNTL__BLK_RST_MASK, + ~UVD_VCPU_CNTL__BLK_RST_MASK); + mdelay(10); + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), 0, + ~UVD_VCPU_CNTL__BLK_RST_MASK); + + mdelay(10); + r = -1; + } + } + + if (r) { + dev_err(adev->dev, "VCN[%d] is not responding, giving up!!!\n", i); + return r; + } + + /* enable master interrupt */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_MASTINT_EN), + UVD_MASTINT_EN__VCPU_EN_MASK, + ~UVD_MASTINT_EN__VCPU_EN_MASK); + + /* clear the busy bit of VCN_STATUS */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_STATUS), 0, + ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT)); + + ring = &adev->vcn.inst[i].ring_enc[0]; + + WREG32_SOC15(VCN, vcn_inst, regVCN_RB1_DB_CTRL, + ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT | + VCN_RB1_DB_CTRL__EN_MASK); + + /* Read DB_CTRL to flush the write DB_CTRL command. */ + RREG32_SOC15(VCN, vcn_inst, regVCN_RB1_DB_CTRL); + + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_LO, ring->gpu_addr); + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_SIZE, ring->ring_size / 4); + + tmp = RREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE); + tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK); + WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp); + fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET; + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_RPTR, 0); + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR, 0); + + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_RB_RPTR); + WREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR, tmp); + ring->wptr = RREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR); + + tmp = RREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE); + tmp |= VCN_RB_ENABLE__RB1_EN_MASK; + WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp); + fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF); + + return 0; +} + +/** + * vcn_v5_0_2_stop_dpg_mode - VCN stop with dpg mode + * + * @vinst: VCN instance + * + * Stop VCN block with dpg mode + */ +static void vcn_v5_0_2_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) +{ + struct amdgpu_device *adev = vinst->adev; + int inst_idx = vinst->inst; + uint32_t tmp; + int vcn_inst; + struct dpg_pause_state state = {.fw_based = VCN_DPG_STATE__UNPAUSE}; + + vcn_inst = GET_INST(VCN, inst_idx); + + /* Unpause dpg */ + vcn_v5_0_2_pause_dpg_mode(vinst, &state); + + /* Wait for power status to be 1 */ + SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_POWER_STATUS, 1, + UVD_POWER_STATUS__UVD_POWER_STATUS_MASK); + + /* wait for read ptr to be equal to write ptr */ + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR); + SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_RB_RPTR, tmp, 0xFFFFFFFF); + + /* disable dynamic power gating mode */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_POWER_STATUS), 0, + ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); +} + +/** + * vcn_v5_0_2_stop - VCN stop + * + * @vinst: VCN instance + * + * Stop VCN block + */ +static int vcn_v5_0_2_stop(struct amdgpu_vcn_inst *vinst) +{ + struct amdgpu_device *adev = vinst->adev; + int i = vinst->inst; + struct amdgpu_vcn5_fw_shared *fw_shared; + uint32_t tmp; + int r = 0, vcn_inst; + + vcn_inst = GET_INST(VCN, i); + + fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr; + fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF; + + if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) { + vcn_v5_0_2_stop_dpg_mode(vinst); + return 0; + } + + /* wait for vcn idle */ + r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_STATUS, UVD_STATUS__IDLE, 0x7); + if (r) + return r; + + tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK | + UVD_LMI_STATUS__READ_CLEAN_MASK | + UVD_LMI_STATUS__WRITE_CLEAN_MASK | + UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK; + r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_LMI_STATUS, tmp, tmp); + if (r) + return r; + + /* disable LMI UMC channel */ + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL2); + tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK; + WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL2, tmp); + tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK | + UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK; + r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_LMI_STATUS, tmp, tmp); + if (r) + return r; + + /* block VCPU register access */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_RB_ARB_CTRL), + UVD_RB_ARB_CTRL__VCPU_DIS_MASK, + ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK); + + /* reset VCPU */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), + UVD_VCPU_CNTL__BLK_RST_MASK, + ~UVD_VCPU_CNTL__BLK_RST_MASK); + + /* disable VCPU clock */ + WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), 0, + ~(UVD_VCPU_CNTL__CLK_EN_MASK)); + + /* apply soft reset */ + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET); + tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK; + WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp); + tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET); + tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK; + WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp); + + /* clear status */ + WREG32_SOC15(VCN, vcn_inst, regUVD_STATUS, 0); + + return 0; +} + +/** + * vcn_v5_0_2_unified_ring_get_rptr - get unified read pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware unified read pointer + */ +static uint64_t vcn_v5_0_2_unified_ring_get_rptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring != &adev->vcn.inst[ring->me].ring_enc[0]) + DRM_ERROR("wrong ring id is identified in %s", __func__); + + return RREG32_SOC15(VCN, GET_INST(VCN, ring->me), regUVD_RB_RPTR); +} + +/** + * vcn_v5_0_2_unified_ring_get_wptr - get unified write pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware unified write pointer + */ +static uint64_t vcn_v5_0_2_unified_ring_get_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring != &adev->vcn.inst[ring->me].ring_enc[0]) + DRM_ERROR("wrong ring id is identified in %s", __func__); + + if (ring->use_doorbell) + return *ring->wptr_cpu_addr; + else + return RREG32_SOC15(VCN, GET_INST(VCN, ring->me), regUVD_RB_WPTR); +} + +/** + * vcn_v5_0_2_unified_ring_set_wptr - set enc write pointer + * + * @ring: amdgpu_ring pointer + * + * Commits the enc write pointer to the hardware + */ +static void vcn_v5_0_2_unified_ring_set_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring != &adev->vcn.inst[ring->me].ring_enc[0]) + DRM_ERROR("wrong ring id is identified in %s", __func__); + + if (ring->use_doorbell) { + *ring->wptr_cpu_addr = lower_32_bits(ring->wptr); + WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr)); + } else { + WREG32_SOC15(VCN, GET_INST(VCN, ring->me), regUVD_RB_WPTR, + lower_32_bits(ring->wptr)); + } +} + +static const struct amdgpu_ring_funcs vcn_v5_0_2_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, + .get_rptr = vcn_v5_0_2_unified_ring_get_rptr, + .get_wptr = vcn_v5_0_2_unified_ring_get_wptr, + .set_wptr = vcn_v5_0_2_unified_ring_set_wptr, + .emit_frame_size = SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 + + 4 + /* vcn_v2_0_enc_ring_emit_vm_flush */ + 5 + + 5 + /* vcn_v2_0_enc_ring_emit_fence x2 vm fence */ + 1, /* vcn_v2_0_enc_ring_insert_end */ + .emit_ib_size = 5, /* vcn_v2_0_enc_ring_emit_ib */ + .emit_ib = vcn_v2_0_enc_ring_emit_ib, + .emit_fence = vcn_v2_0_enc_ring_emit_fence, + .emit_vm_flush = vcn_v4_0_3_enc_ring_emit_vm_flush, + .emit_hdp_flush = vcn_v4_0_3_ring_emit_hdp_flush, + .test_ring = amdgpu_vcn_enc_ring_test_ring, + .test_ib = amdgpu_vcn_unified_ring_test_ib, + .insert_nop = amdgpu_ring_insert_nop, + .insert_end = vcn_v2_0_enc_ring_insert_end, + .pad_ib = amdgpu_ring_generic_pad_ib, + .begin_use = amdgpu_vcn_ring_begin_use, + .end_use = amdgpu_vcn_ring_end_use, + .emit_wreg = vcn_v4_0_3_enc_ring_emit_wreg, + .emit_reg_wait = vcn_v4_0_3_enc_ring_emit_reg_wait, + .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, +}; + +/** + * vcn_v5_0_2_set_unified_ring_funcs - set unified ring functions + * + * @adev: amdgpu_device pointer + * + * Set unified ring functions + */ +static void vcn_v5_0_2_set_unified_ring_funcs(struct amdgpu_device *adev) +{ + int i, vcn_inst; + + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + adev->vcn.inst[i].ring_enc[0].funcs = &vcn_v5_0_2_unified_ring_vm_funcs; + adev->vcn.inst[i].ring_enc[0].me = i; + vcn_inst = GET_INST(VCN, i); + adev->vcn.inst[i].aid_id = vcn_inst / adev->vcn.num_inst_per_aid; + } +} + +/** + * vcn_v5_0_2_is_idle - check VCN block is idle + * + * @ip_block: Pointer to the amdgpu_ip_block structure + * + * Check whether VCN block is idle + */ +static bool vcn_v5_0_2_is_idle(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int i, ret = 1; + + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) + ret &= (RREG32_SOC15(VCN, GET_INST(VCN, i), regUVD_STATUS) == UVD_STATUS__IDLE); + + return ret; +} + +/** + * vcn_v5_0_2_wait_for_idle - wait for VCN block idle + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * + * Wait for VCN block idle + */ +static int vcn_v5_0_2_wait_for_idle(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + int i, ret = 0; + + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + ret = SOC15_WAIT_ON_RREG(VCN, GET_INST(VCN, i), regUVD_STATUS, UVD_STATUS__IDLE, + UVD_STATUS__IDLE); + if (ret) + return ret; + } + + return ret; +} + +/** + * vcn_v5_0_2_set_clockgating_state - set VCN block clockgating state + * + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. + * @state: clock gating state + * + * Set VCN block clockgating state + */ +static int vcn_v5_0_2_set_clockgating_state(struct amdgpu_ip_block *ip_block, + enum amd_clockgating_state state) +{ + struct amdgpu_device *adev = ip_block->adev; + bool enable = state == AMD_CG_STATE_GATE; + int i; + + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[i]; + + if (enable) { + if (RREG32_SOC15(VCN, GET_INST(VCN, i), regUVD_STATUS) != UVD_STATUS__IDLE) + return -EBUSY; + vcn_v5_0_2_enable_clock_gating(vinst); + } else { + vcn_v5_0_2_disable_clock_gating(vinst); + } + } + + return 0; +} + +static int vcn_v5_0_2_set_pg_state(struct amdgpu_vcn_inst *vinst, + enum amd_powergating_state state) +{ + int ret = 0; + + if (state == vinst->cur_state) + return 0; + + if (state == AMD_PG_STATE_GATE) + ret = vcn_v5_0_2_stop(vinst); + else + ret = vcn_v5_0_2_start(vinst); + + if (!ret) + vinst->cur_state = state; + + return ret; +} + +/** + * vcn_v5_0_2_process_interrupt - process VCN block interrupt + * + * @adev: amdgpu_device pointer + * @source: interrupt sources + * @entry: interrupt entry from clients and sources + * + * Process VCN block interrupt + */ +static int vcn_v5_0_2_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + uint32_t i, inst; + + i = node_id_to_phys_map[entry->node_id]; + + DRM_DEV_DEBUG(adev->dev, "IH: VCN TRAP\n"); + + for (inst = 0; inst < adev->vcn.num_vcn_inst; ++inst) + if (adev->vcn.inst[inst].aid_id == i) + break; + + if (inst >= adev->vcn.num_vcn_inst) { + dev_WARN_ONCE(adev->dev, 1, + "Interrupt received for unknown VCN instance %d", + entry->node_id); + return 0; + } + + switch (entry->src_id) { + case VCN_5_0__SRCID__UVD_ENC_GENERAL_PURPOSE: + amdgpu_fence_process(&adev->vcn.inst[inst].ring_enc[0]); + break; + default: + DRM_DEV_ERROR(adev->dev, "Unhandled interrupt: %d %d\n", + entry->src_id, entry->src_data[0]); + break; + } + + return 0; +} + +static const struct amdgpu_irq_src_funcs vcn_v5_0_2_irq_funcs = { + .process = vcn_v5_0_2_process_interrupt, +}; + +/** + * vcn_v5_0_2_set_irq_funcs - set VCN block interrupt irq functions + * + * @adev: amdgpu_device pointer + * + * Set VCN block interrupt irq functions + */ +static void vcn_v5_0_2_set_irq_funcs(struct amdgpu_device *adev) +{ + int i; + + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) + adev->vcn.inst->irq.num_types++; + adev->vcn.inst->irq.funcs = &vcn_v5_0_2_irq_funcs; +} + +static const struct amd_ip_funcs vcn_v5_0_2_ip_funcs = { + .name = "vcn_v5_0_2", + .early_init = vcn_v5_0_2_early_init, + .late_init = NULL, + .sw_init = vcn_v5_0_2_sw_init, + .sw_fini = vcn_v5_0_2_sw_fini, + .hw_init = vcn_v5_0_2_hw_init, + .hw_fini = vcn_v5_0_2_hw_fini, + .suspend = vcn_v5_0_2_suspend, + .resume = vcn_v5_0_2_resume, + .is_idle = vcn_v5_0_2_is_idle, + .wait_for_idle = vcn_v5_0_2_wait_for_idle, + .check_soft_reset = NULL, + .pre_soft_reset = NULL, + .soft_reset = NULL, + .post_soft_reset = NULL, + .set_clockgating_state = vcn_v5_0_2_set_clockgating_state, + .set_powergating_state = vcn_set_powergating_state, +}; + +const struct amdgpu_ip_block_version vcn_v5_0_2_ip_block = { + .type = AMD_IP_BLOCK_TYPE_VCN, + .major = 5, + .minor = 0, + .rev = 2, + .funcs = &vcn_v5_0_2_ip_funcs, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.h b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.h new file mode 100644 index 000000000000..461bdda91eb6 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.h @@ -0,0 +1,29 @@ +/* + * Copyright 2025-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * 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. + * + */ + +#ifndef __VCN_v5_0_2_H__ +#define __VCN_v5_0_2_H__ + +extern const struct amdgpu_ip_block_version vcn_v5_0_2_ip_block; + +#endif /* __VCN_v5_0_2_H__ */ diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c index 73acbe0b7c21..b799c70f5742 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c +++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c @@ -97,11 +97,11 @@ static void cik_event_interrupt_wq(struct kfd_node *dev, return; if (ihre->source_id == CIK_INTSRC_CP_END_OF_PIPE) - kfd_signal_event_interrupt(pasid, context_id, 28); + kfd_signal_event_interrupt(pasid, context_id, 28, true); else if (ihre->source_id == CIK_INTSRC_SDMA_TRAP) - kfd_signal_event_interrupt(pasid, context_id, 28); + kfd_signal_event_interrupt(pasid, context_id, 28, true); else if (ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG) - kfd_signal_event_interrupt(pasid, context_id & 0xff, 8); + kfd_signal_event_interrupt(pasid, context_id & 0xff, 8, true); else if (ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE) kfd_signal_hw_exception_event(pasid); else if (ihre->source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT || diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 09dabb3b3297..462a32abf720 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -3170,11 +3170,11 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v struct kfd_process *process; int ret; - /* Each FD owns only one kfd_process */ - if (p->context_id != KFD_CONTEXT_ID_PRIMARY) + if (!filep->private_data || !p) return -EINVAL; - if (!filep->private_data || !p) + /* Each FD owns only one kfd_process */ + if (p->context_id != KFD_CONTEXT_ID_PRIMARY) return -EINVAL; mutex_lock(&kfd_processes_mutex); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index bafc7b699dcc..44150a71ffd5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -142,6 +142,7 @@ static struct kfd_event *lookup_event_by_id(struct kfd_process *p, uint32_t id) * @p: Pointer to struct kfd_process * @id: ID to look up * @bits: Number of valid bits in @id + * @signal_mailbox_updated: flag indicates if FW updates signal mailbox entry * * Finds the first signaled event with a matching partial ID. If no * matching signaled event is found, returns NULL. In that case the @@ -155,7 +156,8 @@ static struct kfd_event *lookup_event_by_id(struct kfd_process *p, uint32_t id) * driver. */ static struct kfd_event *lookup_signaled_event_by_partial_id( - struct kfd_process *p, uint32_t id, uint32_t bits) + struct kfd_process *p, uint32_t id, uint32_t bits, + bool signal_mailbox_updated) { struct kfd_event *ev; @@ -166,7 +168,8 @@ static struct kfd_event *lookup_signaled_event_by_partial_id( * and we only need a single lookup. */ if (bits > 31 || (1U << bits) >= KFD_SIGNAL_EVENT_LIMIT) { - if (page_slots(p->signal_page)[id] == UNSIGNALED_EVENT_SLOT) + if (signal_mailbox_updated && + page_slots(p->signal_page)[id] == UNSIGNALED_EVENT_SLOT) return NULL; return idr_find(&p->event_idr, id); @@ -724,7 +727,7 @@ static void set_event_from_interrupt(struct kfd_process *p, } void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id, - uint32_t valid_id_bits) + uint32_t valid_id_bits, bool signal_mailbox_updated) { struct kfd_event *ev = NULL; @@ -742,7 +745,8 @@ void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id, if (valid_id_bits) ev = lookup_signaled_event_by_partial_id(p, partial_id, - valid_id_bits); + valid_id_bits, + signal_mailbox_updated); if (ev) { set_event_from_interrupt(p, ev); } else if (p->signal_page) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.h b/drivers/gpu/drm/amd/amdkfd/kfd_events.h index 52ccfd397c2b..1dc21c13833b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.h @@ -85,6 +85,7 @@ struct kfd_event { #define KFD_EVENT_TYPE_MEMORY 8 extern void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id, - uint32_t valid_id_bits); + uint32_t valid_id_bits, + bool signal_mailbox_updated); #endif diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c index 3e1ad8974797..19406ab92c5b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c @@ -211,7 +211,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, client_id == SOC15_IH_CLIENTID_SE2SH || client_id == SOC15_IH_CLIENTID_SE3SH) { if (source_id == SOC15_INTSRC_CP_END_OF_PIPE) - kfd_signal_event_interrupt(pasid, context_id0, 32); + kfd_signal_event_interrupt(pasid, context_id0, 32, true); else if (source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG) { encoding = REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_WAVE_CTXID1, ENCODING); @@ -324,7 +324,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, default: break; } - kfd_signal_event_interrupt(pasid, context_id0 & 0x7fffff, 23); + kfd_signal_event_interrupt(pasid, context_id0 & 0x7fffff, 23, true); } else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE && KFD_DBG_EC_TYPE_IS_PACKET(KFD_DEBUG_CP_BAD_OP_ECODE(context_id0))) { kfd_set_dbg_ev_from_interrupt(dev, pasid, @@ -344,7 +344,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, client_id == SOC15_IH_CLIENTID_SDMA6 || client_id == SOC15_IH_CLIENTID_SDMA7) { if (source_id == SOC15_INTSRC_SDMA_TRAP) { - kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28); + kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28, true); } } else if (client_id == SOC15_IH_CLIENTID_VMC || client_id == SOC15_IH_CLIENTID_VMC1 || diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c index 2788a52714d1..12d81abed748 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c @@ -353,7 +353,7 @@ static void event_interrupt_wq_v11(struct kfd_node *dev, /* CP */ if (source_id == SOC15_INTSRC_CP_END_OF_PIPE) - kfd_signal_event_interrupt(pasid, context_id0, 32); + kfd_signal_event_interrupt(pasid, context_id0, 32, true); else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE && KFD_DBG_EC_TYPE_IS_PACKET(KFD_CTXID0_CP_BAD_OP_ECODE(context_id0))) { u32 doorbell_id = KFD_CTXID0_DOORBELL_ID(context_id0); @@ -366,7 +366,7 @@ static void event_interrupt_wq_v11(struct kfd_node *dev, /* SDMA */ else if (source_id == SOC21_INTSRC_SDMA_TRAP) - kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28); + kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28, true); else if (source_id == SOC21_INTSRC_SDMA_ECC) { event_interrupt_poison_consumption_v11(dev, pasid, source_id); return; @@ -404,7 +404,7 @@ static void event_interrupt_wq_v11(struct kfd_node *dev, default: break; } - kfd_signal_event_interrupt(pasid, context_id0 & 0xffffff, 24); + kfd_signal_event_interrupt(pasid, context_id0 & 0xffffff, 24, true); } } else if (KFD_IRQ_IS_FENCE(client_id, source_id)) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v12_1.c index 230e57dbcec5..0da7e1db55c9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v12_1.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v12_1.c @@ -28,6 +28,7 @@ #include "ivsrcid/vmc/irqsrcs_vmc_1_0.h" #include "kfd_smi_events.h" #include "kfd_debug.h" +#include "amdgpu_ras_mgr.h" /* * GFX12.1 SQ Interrupts @@ -143,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), @@ -154,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), @@ -166,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), @@ -185,6 +189,7 @@ static void event_interrupt_poison_consumption_v12_1(struct kfd_node *node, enum amdgpu_ras_block block = 0; int ret = -EINVAL; uint32_t reset = 0; + u64 event_id = RAS_EVENT_INVALID_ID; struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, NULL); if (!p) @@ -220,7 +225,15 @@ static void event_interrupt_poison_consumption_v12_1(struct kfd_node *node, * resetting queue passes, do page retirement without gpu reset * resetting queue fails, fallback to gpu reset solution */ - amdgpu_amdkfd_ras_poison_consumption_handler(node->adev, block, reset); + if (amdgpu_uniras_enabled(node->adev)) + event_id = amdgpu_ras_mgr_gen_ras_event_seqno(node->adev, + RAS_SEQNO_TYPE_POISON_CONSUMPTION); + + RAS_EVENT_LOG(node->adev, event_id, + "poison is consumed by source %d, kick off gpu reset flow\n", source_id); + + amdgpu_amdkfd_ras_pasid_poison_consumption_handler(node->adev, + block, pasid, NULL, NULL, reset); } static bool event_interrupt_isr_v12_1(struct kfd_node *node, @@ -236,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; } @@ -256,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]); @@ -326,7 +340,7 @@ static void event_interrupt_wq_v12_1(struct kfd_node *node, /* CP */ if (source_id == SOC15_INTSRC_CP_END_OF_PIPE) - kfd_signal_event_interrupt(pasid, context_id0, 32); + kfd_signal_event_interrupt(pasid, context_id0, 32, false); else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE && KFD_DBG_EC_TYPE_IS_PACKET(KFD_CTXID0_CP_BAD_OP_ECODE(context_id0))) { u32 doorbell_id = KFD_CTXID0_DOORBELL_ID(context_id0); @@ -339,7 +353,7 @@ static void event_interrupt_wq_v12_1(struct kfd_node *node, /* SDMA */ else if (source_id == SOC21_INTSRC_SDMA_TRAP) - kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28); + kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28, true); else if (source_id == SOC21_INTSRC_SDMA_ECC) { event_interrupt_poison_consumption_v12_1(node, pasid, source_id); return; @@ -351,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, @@ -364,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 && @@ -377,7 +391,7 @@ static void event_interrupt_wq_v12_1(struct kfd_node *node, default: break; } - kfd_signal_event_interrupt(pasid, context_id0 & 0xffffff, 24); + kfd_signal_event_interrupt(pasid, context_id0 & 0xffffff, 24, true); } } else if (KFD_IRQ_IS_FENCE(client_id, source_id)) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c index d76fb61869c7..1688d8e595f2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c @@ -379,7 +379,7 @@ static void event_interrupt_wq_v9(struct kfd_node *dev, client_id == SOC15_IH_CLIENTID_SE2SH || client_id == SOC15_IH_CLIENTID_SE3SH) { if (source_id == SOC15_INTSRC_CP_END_OF_PIPE) - kfd_signal_event_interrupt(pasid, context_id0, 32); + kfd_signal_event_interrupt(pasid, context_id0, 32, true); else if (source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG) { sq_int_data = KFD_CONTEXT_ID_GET_SQ_INT_DATA(context_id0, context_id1); encoding = REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID, ENCODING); @@ -513,7 +513,7 @@ static void event_interrupt_wq_v9(struct kfd_node *dev, default: break; } - kfd_signal_event_interrupt(pasid, sq_int_data, 24); + kfd_signal_event_interrupt(pasid, sq_int_data, 24, true); } else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE && KFD_DBG_EC_TYPE_IS_PACKET(KFD_DEBUG_CP_BAD_OP_ECODE(context_id0))) { kfd_set_dbg_ev_from_interrupt(dev, pasid, @@ -530,7 +530,7 @@ static void event_interrupt_wq_v9(struct kfd_node *dev, client_id == SOC15_IH_CLIENTID_SDMA6 || client_id == SOC15_IH_CLIENTID_SDMA7) { if (source_id == SOC15_INTSRC_SDMA_TRAP) { - kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28); + kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28, true); } else if (source_id == SOC15_INTSRC_SDMA_ECC) { event_interrupt_poison_consumption_v9(dev, pasid, client_id); return; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 10bc81ce37cb..964efa325908 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -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); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 979ae94ac966..e8f97de9d6e4 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -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 = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index e5b56412931b..fa025bea9b4f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -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 * \ @@ -1525,7 +1525,7 @@ int kfd_wait_on_events(struct kfd_process *p, bool all, uint32_t *user_timeout_ms, uint32_t *wait_result); void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id, - uint32_t valid_id_bits); + uint32_t valid_id_bits, bool signal_mailbox_updated); void kfd_signal_hw_exception_event(u32 pasid); int kfd_set_event(struct kfd_process *p, uint32_t event_id); int kfd_reset_event(struct kfd_process *p, uint32_t event_id); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index a031166f270c..bcd21204aa50 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -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; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index cc2621ae12f9..44e39ce222b7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -590,7 +590,8 @@ int pqm_update_queue_properties(struct process_queue_manager *pqm, return err; if (kfd_queue_buffer_get(vm, (void *)p->queue_address, &p->ring_bo, - p->queue_size)) { + p->queue_size + + pqn->q->properties.metadata_queue_size)) { pr_debug("ring buf 0x%llx size 0x%llx not mapped on GPU\n", p->queue_address, p->queue_size); amdgpu_bo_unreserve(vm->root.bo); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c index bbe869ceae3f..28354a4e5dd5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 080242f9981b..b120fdb0ef77 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -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; } @@ -1219,7 +1218,8 @@ svm_range_get_pte_flags(struct kfd_node *node, struct amdgpu_vm *vm, bool snoop = (domain != SVM_RANGE_VRAM_DOMAIN); bool coherent = flags & (KFD_IOCTL_SVM_FLAG_COHERENT | KFD_IOCTL_SVM_FLAG_EXT_COHERENT); bool ext_coherent = flags & KFD_IOCTL_SVM_FLAG_EXT_COHERENT; - unsigned int mtype_local; + unsigned int mtype_local, mtype_remote; + bool is_aid_a1, is_local; if (domain == SVM_RANGE_VRAM_DOMAIN) bo_node = prange->svm_bo->node; @@ -1307,20 +1307,23 @@ svm_range_get_pte_flags(struct kfd_node *node, struct amdgpu_vm *vm, mapping_flags |= AMDGPU_VM_MTYPE_NC; break; case IP_VERSION(12, 1, 0): + is_aid_a1 = (node->adev->rev_id & 0x10); + is_local = (domain == SVM_RANGE_VRAM_DOMAIN) && + (bo_node->adev == node->adev); + + mtype_local = amdgpu_mtype_local == 0 ? AMDGPU_VM_MTYPE_RW : + amdgpu_mtype_local == 1 ? AMDGPU_VM_MTYPE_NC : + is_aid_a1 ? AMDGPU_VM_MTYPE_RW : AMDGPU_VM_MTYPE_NC; + mtype_remote = is_aid_a1 ? AMDGPU_VM_MTYPE_NC : AMDGPU_VM_MTYPE_UC; snoop = true; - if (domain == SVM_RANGE_VRAM_DOMAIN) { - mtype_local = amdgpu_mtype_local == 1 ? AMDGPU_VM_MTYPE_NC : - AMDGPU_VM_MTYPE_RW; - /* local HBM */ - if (bo_node->adev == node->adev) - mapping_flags |= mtype_local; - /* Remote GPU memory */ - else - mapping_flags |= ext_coherent ? AMDGPU_VM_MTYPE_UC : - AMDGPU_VM_MTYPE_NC; - /* system memory accessed by the dGPU */ + + if (is_local) /* local HBM */ { + mapping_flags |= mtype_local; + } else if (ext_coherent) { + mapping_flags |= AMDGPU_VM_MTYPE_UC; } else { - mapping_flags |= ext_coherent ? AMDGPU_VM_MTYPE_UC : AMDGPU_VM_MTYPE_NC; + /* system memory or remote VRAM */ + mapping_flags |= mtype_remote; } break; default: diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 8e949fe77312..89350aa9ca7e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -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 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 65b256a7b6c4..21635e80349a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2290,6 +2290,11 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) &adev->dm.dmub_bo_gpu_addr, &adev->dm.dmub_bo_cpu_addr); + if (adev->dm.boot_time_crc_info.bo_ptr) + amdgpu_bo_free_kernel(&adev->dm.boot_time_crc_info.bo_ptr, + &adev->dm.boot_time_crc_info.gpu_addr, + &adev->dm.boot_time_crc_info.cpu_addr); + if (adev->dm.hpd_rx_offload_wq && adev->dm.dc) { for (i = 0; i < adev->dm.dc->caps.max_links; i++) { if (adev->dm.hpd_rx_offload_wq[i].wq) { @@ -2577,7 +2582,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + PSP_HEADER_BYTES_256; - fw_meta_info_params.fw_bss_data = region_params.bss_data_size ? adev->dm.dmub_fw->data + + fw_meta_info_params.fw_bss_data = fw_meta_info_params.bss_data_size ? adev->dm.dmub_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + le32_to_cpu(hdr->inst_const_bytes) : NULL; fw_meta_info_params.custom_psp_footer_size = 0; @@ -2738,6 +2743,54 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev) return ret; } +static void amdgpu_dm_boot_time_crc_init(struct amdgpu_device *adev) +{ + struct dm_boot_time_crc_info *bootcrc_info = NULL; + struct dmub_srv *dmub = NULL; + union dmub_fw_boot_options option = {0}; + int ret = 0; + const uint32_t fb_size = 3 * 1024 * 1024; /* 3MB for DCC pattern */ + + if (!adev || !adev->dm.dc || !adev->dm.dc->ctx || + !adev->dm.dc->ctx->dmub_srv) { + return; + } + + dmub = adev->dm.dc->ctx->dmub_srv->dmub; + bootcrc_info = &adev->dm.boot_time_crc_info; + + if (!dmub || !dmub->hw_funcs.get_fw_boot_option) { + drm_dbg(adev_to_drm(adev), "failed to init boot time crc buffer\n"); + return; + } + + option = dmub->hw_funcs.get_fw_boot_option(dmub); + + /* Return if boot time CRC is not enabled */ + if (option.bits.bootcrc_en_at_S0i3 == 0) + return; + + /* Create a buffer for boot time CRC */ + ret = amdgpu_bo_create_kernel(adev, fb_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT, + &bootcrc_info->bo_ptr, + &bootcrc_info->gpu_addr, + &bootcrc_info->cpu_addr); + + if (ret) { + drm_dbg(adev_to_drm(adev), "failed to create boot time crc buffer\n"); + } else { + bootcrc_info->size = fb_size; + + drm_dbg(adev_to_drm(adev), "boot time crc buffer created addr 0x%llx, size %u\n", + bootcrc_info->gpu_addr, bootcrc_info->size); + + /* Send the buffer info to DMUB */ + dc_dmub_srv_boot_time_crc_init(adev->dm.dc, + bootcrc_info->gpu_addr, bootcrc_info->size); + } +} + static int dm_late_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; @@ -2749,6 +2802,11 @@ static int dm_late_init(struct amdgpu_ip_block *ip_block) dmcu = adev->dm.dc->res_pool->dmcu; + /* Init the boot time CRC (skip in resume) */ + if ((adev->in_suspend == 0) && + (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(3, 6, 0))) + amdgpu_dm_boot_time_crc_init(adev); + for (i = 0; i < 16; i++) linear_lut[i] = 0xFFFF * i / 15; @@ -3225,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); @@ -3258,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); @@ -3548,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++) { @@ -3608,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 @@ -3936,8 +4002,9 @@ void amdgpu_dm_update_connector_after_detect( aconnector->dc_sink = sink; dc_sink_retain(aconnector->dc_sink); + drm_edid_free(aconnector->drm_edid); + aconnector->drm_edid = NULL; if (sink->dc_edid.length == 0) { - aconnector->drm_edid = NULL; hdmi_cec_unset_edid(aconnector); if (aconnector->dc_link->aux_mode) { drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); @@ -4846,14 +4913,37 @@ static void dm_atomic_destroy_state(struct drm_private_obj *obj, kfree(dm_state); } +static struct drm_private_state * +dm_atomic_create_state(struct drm_private_obj *obj) +{ + struct amdgpu_device *adev = drm_to_adev(obj->dev); + struct dm_atomic_state *dm_state; + struct dc_state *context; + + dm_state = kzalloc_obj(*dm_state); + if (!dm_state) + return ERR_PTR(-ENOMEM); + + context = dc_state_create_current_copy(adev->dm.dc); + if (!context) { + kfree(dm_state); + return ERR_PTR(-ENOMEM); + } + + __drm_atomic_helper_private_obj_create_state(obj, &dm_state->base); + dm_state->context = context; + + return &dm_state->base; +} + static struct drm_private_state_funcs dm_atomic_state_funcs = { + .atomic_create_state = dm_atomic_create_state, .atomic_duplicate_state = dm_atomic_duplicate_state, .atomic_destroy_state = dm_atomic_destroy_state, }; static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) { - struct dm_atomic_state *state; int r; adev->mode_info.mode_config_initialized = true; @@ -4873,42 +4963,22 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) /* indicates support for immediate flip */ adev_to_drm(adev)->mode_config.async_page_flip = true; - state = kzalloc_obj(*state); - if (!state) - return -ENOMEM; - - state->context = dc_state_create_current_copy(adev->dm.dc); - if (!state->context) { - kfree(state); - return -ENOMEM; - } - drm_atomic_private_obj_init(adev_to_drm(adev), &adev->dm.atomic_obj, - &state->base, &dm_atomic_state_funcs); r = amdgpu_display_modeset_create_props(adev); - if (r) { - dc_state_release(state->context); - kfree(state); + if (r) return r; - } #ifdef AMD_PRIVATE_COLOR - if (amdgpu_dm_create_color_properties(adev)) { - dc_state_release(state->context); - kfree(state); + if (amdgpu_dm_create_color_properties(adev)) return -ENOMEM; - } #endif r = amdgpu_dm_audio_init(adev); - if (r) { - dc_state_release(state->context); - kfree(state); + if (r) return r; - } return 0; } @@ -5359,7 +5429,7 @@ static void setup_backlight_device(struct amdgpu_display_manager *dm, caps = &dm->backlight_caps[aconnector->bl_idx]; /* Only offer ABM property when non-OLED and user didn't turn off by module parameter */ - if (!caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0) + if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0) drm_object_attach_property(&aconnector->base.base, dm->adev->mode_info.abm_level_property, ABM_SYSFS_CONTROL); @@ -5519,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; @@ -6659,11 +6730,11 @@ static void fill_stream_properties_from_drm_display_mode( && aconnector && aconnector->force_yuv420_output) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; - else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR422) + else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) && aconnector && aconnector->force_yuv422_output) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422; - else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444) + else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; else @@ -9271,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)) { /* @@ -9840,7 +9887,8 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_crtc *acrtc_attach, * a vblank event disable request to enable PSR/RP. PSR SU/RP * can be enabled immediately once OS demonstrates an * adequate number of fast atomic commits to notify KMD - * of update events. See `vblank_control_worker()`. + * of update events. + * See `amdgpu_dm_crtc_vblank_control_worker()`. */ if (!vrr_active && acrtc_attach->dm_irq_params.allow_sr_entry && @@ -10008,8 +10056,9 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, /* * If the dirty regions changed, PSR-SU need to be disabled temporarily * and enabled it again after dirty regions are stable to avoid video glitch. - * PSR-SU will be enabled in vblank_control_worker() if user pause the video - * during the PSR-SU was disabled. + * PSR-SU will be enabled in + * amdgpu_dm_crtc_vblank_control_worker() if user + * pause the video during the PSR-SU was disabled. */ if (acrtc_state->stream->link->psr_settings.psr_version >= DC_PSR_VERSION_SU_1 && acrtc_attach->dm_irq_params.allow_sr_entry && @@ -12471,6 +12520,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (dc_resource_is_dsc_encoding_supported(dc)) { for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + dm_new_crtc_state->mode_changed_independent_from_dsc = new_crtc_state->mode_changed; + } + + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { ret = add_affected_mst_dsc_crtcs(state, crtc); if (ret) { @@ -13067,7 +13121,7 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector, u16 min_vfreq; u16 max_vfreq; - if (edid == NULL || edid->extensions == 0) + if (!edid || !edid->extensions) return; /* Find DisplayID extension */ @@ -13077,7 +13131,7 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector, break; } - if (edid_ext == NULL) + if (i == edid->extensions) return; while (j < EDID_LENGTH) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 800813671748..d1a14e0c12bd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -123,6 +123,20 @@ struct dm_compressor_info { uint64_t gpu_addr; }; +/** + * struct dm_boot_time_crc_info - Buffer info used by boot time CRC + * @cpu_addr: MMIO cpu addr + * @bo_ptr: Pointer to the buffer object + * @gpu_addr: MMIO gpu addr + * @size: Size of the buffer + */ +struct dm_boot_time_crc_info { + void *cpu_addr; + struct amdgpu_bo *bo_ptr; + uint64_t gpu_addr; + uint32_t size; +}; + typedef void (*dmub_notify_interrupt_callback_t)(struct amdgpu_device *adev, struct dmub_notification *notify); /** @@ -698,6 +712,13 @@ struct amdgpu_display_manager { struct completion replied; char reply_data[0x40]; // Cannot include dmub_cmd here } fused_io[8]; + + /** + * @dm_boot_time_crc_info: + * + * Buffer info for the boot time crc. + */ + struct dm_boot_time_crc_info boot_time_crc_info; }; enum dsc_clock_force_state { @@ -984,6 +1005,7 @@ struct dm_crtc_state { bool freesync_vrr_info_changed; + bool mode_changed_independent_from_dsc; bool dsc_force_changed; bool vrr_supported; struct mod_freesync_config freesync_config; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c index 3e05e48a8792..7ee051cb3c05 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c @@ -37,19 +37,19 @@ const u64 amdgpu_dm_supported_degam_tfs = BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) | BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) | BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) | - BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV); + BIT(DRM_COLOROP_1D_CURVE_GAMMA22); const u64 amdgpu_dm_supported_shaper_tfs = BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) | BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF) | BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF) | - BIT(DRM_COLOROP_1D_CURVE_GAMMA22); + BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV); const u64 amdgpu_dm_supported_blnd_tfs = BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) | BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) | BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) | - BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV); + BIT(DRM_COLOROP_1D_CURVE_GAMMA22); #define MAX_COLOR_PIPELINE_OPS 10 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index b96fbc03c371..62573173e2ac 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -812,7 +812,6 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) unsigned long flags1; bool forward_roi_change = false; bool notify_ta = false; - bool all_crc_ready = true; struct dc_stream_state *stream_state; int i; @@ -936,9 +935,6 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) continue; } - if (!crtc_ctx->crc_info.crc[i].crc_ready) - all_crc_ready = false; - if (reset_crc_frame_count[i] || crtc_ctx->crc_info.crc[i].frame_count == UINT_MAX) /* Reset the reference frame count after user update the ROI * or it reaches the maximum value. @@ -948,9 +944,6 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) crtc_ctx->crc_info.crc[i].frame_count += 1; } spin_unlock_irqrestore(&crtc_ctx->crc_info.lock, flags1); - - if (all_crc_ready) - complete_all(&crtc_ctx->crc_info.completion); } void amdgpu_dm_crtc_secure_display_create_contexts(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h index 95bdb8699d7f..8538513ea879 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h @@ -70,7 +70,6 @@ struct crc_data { struct crc_info { struct crc_data crc[MAX_CRC_WINDOW_NUM]; - struct completion completion; spinlock_t lock; }; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 304437c2284d..c3c588294665 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -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); } @@ -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 */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h index c1212947a77b..3a8094013a5d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h @@ -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, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 24bc2a86904b..2409ac72b166 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -3305,6 +3305,52 @@ static int disallow_edp_enter_psr_set(void *data, u64 val) return 0; } +/* check if kernel disallow eDP enter replay state + * cat /sys/kernel/debug/dri/0/eDP-X/disallow_edp_enter_replay + * 0: allow edp enter replay; 1: disallow + */ +static int disallow_edp_enter_replay_get(void *data, u64 *val) +{ + struct amdgpu_dm_connector *aconnector = data; + + *val = (u64) aconnector->disallow_edp_enter_replay; + return 0; +} + +/* set kernel disallow eDP enter replay state + * echo 0x0 /sys/kernel/debug/dri/0/eDP-X/disallow_edp_enter_replay + * 0: allow edp enter replay; 1: disallow + * + * usage: test app read crc from PSR eDP rx. + * + * during kernel boot up, kernel write dpcd 0x37b to + * notify eDP rx replay enable. + * rx fw will start checking crc for rx internal logic. + * crc read count within dpcd 0x246 is not updated and + * value is 0. when eDP tx driver wants to read rx crc + * from dpcd 0x246, 0x270, read count 0 lead tx driver + * timeout. + * + * to avoid this, we add this debugfs to let test app to disbable + * rx replay. then test app can read non-zero crc read count. + * + * expected app sequence is as below: + * 1. disable eDP PHY and notify eDP rx with dpcd 0x600 = 2. + * 2. echo 0x1 /sys/kernel/debug/dri/0/eDP-X/disallow_edp_enter_replay + * 3. enable eDP PHY and notify eDP rx with dpcd 0x600 = 1 but + * without programming dpcd 0x37b. + * 4. read crc from rx dpcd 0x270, 0x246, etc. + * 5. echo 0x0 /sys/kernel/debug/dri/0/eDP-X/disallow_edp_enter_replay. + * this will let eDP back to normal with replay setup dpcd 0x37b. + */ +static int disallow_edp_enter_replay_set(void *data, u64 val) +{ + struct amdgpu_dm_connector *aconnector = data; + + aconnector->disallow_edp_enter_replay = val ? true : false; + return 0; +} + static int dmub_trace_mask_set(void *data, u64 val) { struct amdgpu_device *adev = data; @@ -3433,6 +3479,10 @@ DEFINE_DEBUGFS_ATTRIBUTE(disallow_edp_enter_psr_fops, disallow_edp_enter_psr_get, disallow_edp_enter_psr_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(disallow_edp_enter_replay_fops, + disallow_edp_enter_replay_get, + disallow_edp_enter_replay_set, "%llu\n"); + DEFINE_DEBUGFS_ATTRIBUTE(ips_residency_cntl_fops, ips_residency_cntl_get, ips_residency_cntl_set, "%llu\n"); DEFINE_SHOW_ATTRIBUTE(current_backlight); @@ -3635,6 +3685,8 @@ void connector_debugfs_init(struct amdgpu_dm_connector *connector) &allow_edp_hotplug_detection_fops); debugfs_create_file("disallow_edp_enter_psr", 0644, dir, connector, &disallow_edp_enter_psr_fops); + debugfs_create_file("disallow_edp_enter_replay", 0644, dir, connector, + &disallow_edp_enter_replay_fops); } for (i = 0; i < ARRAY_SIZE(connector_debugfs_entries); i++) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c new file mode 100644 index 000000000000..65a5cfe1e106 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c @@ -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); +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h new file mode 100644 index 000000000000..fde0ddc8d4e4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h @@ -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 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 7be50e8c0636..5d8c4c7020b1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -1744,9 +1744,11 @@ int pre_validate_dsc(struct drm_atomic_state *state, int ind = find_crtc_index_in_state_by_stream(state, stream); if (ind >= 0) { + struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(state->crtcs[ind].new_state); + DRM_INFO_ONCE("%s:%d MST_DSC no mode changed for stream 0x%p\n", __func__, __LINE__, stream); - state->crtcs[ind].new_state->mode_changed = 0; + dm_new_crtc_state->base.mode_changed = dm_new_crtc_state->mode_changed_independent_from_dsc; } } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index d8c69fc94abb..81e43534ec59 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -62,9 +62,6 @@ static const uint32_t rgb_formats[] = { DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB565, - DRM_FORMAT_NV21, - DRM_FORMAT_NV12, - DRM_FORMAT_P010 }; static const uint32_t overlay_formats[] = { @@ -707,21 +704,21 @@ static void amdgpu_dm_plane_add_gfx12_modifiers(struct amdgpu_device *adev, uint8_t max_comp_block[] = {2, 1, 0}; uint64_t max_comp_block_mod[ARRAY_SIZE(max_comp_block)] = {0}; uint8_t i = 0, j = 0; - uint64_t gfx12_modifiers[] = {mod_256k, mod_64k, mod_4k, mod_256b, DRM_FORMAT_MOD_LINEAR}; + /* Note, linear (no DCC) gets added to the modifier list for all chips by the caller. */ + uint64_t gfx12_modifiers[] = {mod_256k, mod_64k, mod_4k, mod_256b}; for (i = 0; i < ARRAY_SIZE(max_comp_block); i++) max_comp_block_mod[i] = AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, max_comp_block[i]); /* With DCC: Best choice should be kept first. Hence, add all 256k modifiers of different * max compressed blocks first and then move on to the next smaller sized layouts. - * Do not add the linear modifier here, and hence the condition of size-1 for the loop */ - for (j = 0; j < ARRAY_SIZE(gfx12_modifiers) - 1; j++) + for (j = 0; j < ARRAY_SIZE(gfx12_modifiers); j++) for (i = 0; i < ARRAY_SIZE(max_comp_block); i++) amdgpu_dm_plane_add_modifier(mods, size, capacity, ver | dcc | max_comp_block_mod[i] | gfx12_modifiers[j]); - /* Without DCC. Add all modifiers including linear at the end */ + /* Without DCC. */ for (i = 0; i < ARRAY_SIZE(gfx12_modifiers); i++) amdgpu_dm_plane_add_modifier(mods, size, capacity, gfx12_modifiers[i]); @@ -957,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); @@ -1377,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; @@ -1408,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"); @@ -1415,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); } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h index aa56fd6d56c3..e0fab8878d19 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h @@ -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 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c index d9527c05fc87..110f0173eee6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index e46f8ce41d87..8ba9b4f56f87 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -53,12 +53,31 @@ 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 * (usually __func__) @@ -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 { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h index 4e921632bc4e..5e95419d3798 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h @@ -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__ */ diff --git a/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c index 8c54c02a0e26..f37a43f4172e 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c @@ -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))) { diff --git a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c index 6073cadde76c..fa10f85df3db 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c +++ b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/dc/basics/vector.c b/drivers/gpu/drm/amd/display/dc/basics/vector.c index a8b750ff8573..e8736c134b8d 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/vector.c +++ b/drivers/gpu/drm/amd/display/dc/basics/vector.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index f947f82013c6..dd362071a6c9 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 94fddf22f5a9..a1c08e1cc411 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -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; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index f2b1720a6a66..17ef515c6c69 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -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; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c b/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c index 3099128223df..cec61c9d7263 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c @@ -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). diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c index 349f0e5d5856..478465fba224 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c +++ b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c @@ -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). diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c index 1a5fefcde8af..6b8a87f2c49e 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c +++ b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c @@ -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). diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c index e91636d033c7..880bce368238 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c @@ -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); @@ -244,6 +245,10 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p BREAK_TO_DEBUGGER(); return NULL; } + if (ctx->dce_version == DCN_VERSION_2_01) { + dcn201_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); + return &clk_mgr->base; + } if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev)) { dcn3_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); return &clk_mgr->base; @@ -256,10 +261,6 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p dcn3_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); return &clk_mgr->base; } - if (ctx->dce_version == DCN_VERSION_2_01) { - dcn201_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); - return &clk_mgr->base; - } dcn20_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); return &clk_mgr->base; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c index d50b9440210e..cd4c45516616 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c @@ -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]; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c index e18097f82091..09e83097a623 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c @@ -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 { diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c index b48522480dfd..dcec9d0f8c34 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c index 7aee02d56292..57ba7bc4d16e 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index 051052bd10c9..89fc482947ef 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c index 0cb37827a62b..b08a70a2f571 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c index c49268db85f6..3a651c1a866d 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c index 1769b1f26e75..e9d492d8c8d4 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index 2856b0337e87..fda6cade30a8 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 6fc524752613..2798088842f4 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c index 03464f21d119..82c1a55a2271 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c index 97c9f0ce13e4..ec888aed207d 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c @@ -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; @@ -291,6 +296,11 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base, if (should_set_clock(safe_to_lower, new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; + + /* Clamp the requested clock to PMFW based on DCN limit. */ + if (dc->debug.min_deep_sleep_dcfclk_khz > 0 && clk_mgr_base->clks.dcfclk_deep_sleep_khz < dc->debug.min_deep_sleep_dcfclk_khz) + clk_mgr_base->clks.dcfclk_deep_sleep_khz = dc->debug.min_deep_sleep_dcfclk_khz; + dcn42_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz); } @@ -321,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); @@ -469,6 +479,9 @@ static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs DC_LOG_SMU("CLK1_CLK1_CURRENT_CNT,%d,dppclk\n", internal.CLK8_CLK1_CURRENT_CNT); + DC_LOG_SMU("CLK1_CLK4_CURRENT_CNT,%d,dtbclk\n", + internal.CLK8_CLK4_CURRENT_CNT); + DC_LOG_SMU("CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass\n", internal.CLK8_CLK3_BYPASS_CNTL); @@ -511,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; @@ -569,7 +582,6 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base) { struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int); - struct dcn42_smu_dpm_clks smu_dpm_clks = { 0 }; DC_LOGGER_INIT(clk_mgr_base->ctx->logger); (void)dc_logger; @@ -587,131 +599,7 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base) dcn42_dump_clk_registers(&clk_mgr_base->boot_snapshot, clk_mgr); clk_mgr_base->clks.ref_dtbclk_khz = clk_mgr_base->boot_snapshot.dtbclk * 10; - if (clk_mgr_base->boot_snapshot.dtbclk > 59000) { - /*dtbclk enabled based on*/ - clk_mgr_base->clks.dtbclk_en = true; - } - - if (clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels != 0) { - /*skip to get clock table and notify pmfw watermark range again*/ - DC_LOG_SMU("skip to get dpm_clks from pmfw from resume and acr\n"); - return; - } - - smu_dpm_clks.dpm_clks = (DpmClocks_t_dcn42 *)dm_helpers_allocate_gpu_mem( - clk_mgr_base->ctx, - DC_MEM_ALLOC_TYPE_GART, - sizeof(DpmClocks_t_dcn42), - &smu_dpm_clks.mc_address.quad_part); - - ASSERT(smu_dpm_clks.dpm_clks); - if (clk_mgr_base->ctx->dc->debug.pstate_enabled && clk_mgr_int->smu_present && smu_dpm_clks.mc_address.quad_part != 0) { - int i; - DpmClocks_t_dcn42 *dpm_clks = smu_dpm_clks.dpm_clks; - - dcn42_get_dpm_table_from_smu(clk_mgr_int, &smu_dpm_clks); - DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n" - "NumDispClkLevelsEnabled: %d\n" - "NumSocClkLevelsEnabled: %d\n" - "VcnClkLevelsEnabled: %d\n" - "FClkLevelsEnabled: %d\n" - "NumMemPstatesEnabled: %d\n" - "MinGfxClk: %d\n" - "MaxGfxClk: %d\n", - dpm_clks->NumDcfClkLevelsEnabled, - dpm_clks->NumDispClkLevelsEnabled, - dpm_clks->NumSocClkLevelsEnabled, - dpm_clks->VcnClkLevelsEnabled, - dpm_clks->NumFclkLevelsEnabled, - dpm_clks->NumMemPstatesEnabled, - dpm_clks->MinGfxClk, - dpm_clks->MaxGfxClk); - - for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) { - DC_LOG_SMU("dpm_clks->DcfClocks[%d] = %d\n", - i, - dpm_clks->DcfClocks[i]); - } - for (i = 0; i < NUM_DISPCLK_DPM_LEVELS; i++) { - DC_LOG_SMU("dpm_clks->DispClocks[%d] = %d\n", - i, dpm_clks->DispClocks[i]); - } - for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) { - DC_LOG_SMU("dpm_clks->SocClocks[%d] = %d\n", - i, dpm_clks->SocClocks[i]); - } - for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) { - DC_LOG_SMU("dpm_clks->FclkClocks_Freq[%d] = %d\n", - i, dpm_clks->FclkClocks_Freq[i]); - DC_LOG_SMU("dpm_clks->FclkClocks_Voltage[%d] = %d\n", - i, dpm_clks->FclkClocks_Voltage[i]); - } - for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) - DC_LOG_SMU("dpm_clks->SocVoltage[%d] = %d\n", - i, dpm_clks->SocVoltage[i]); - - for (i = 0; i < NUM_MEM_PSTATE_LEVELS; i++) { - DC_LOG_SMU("dpm_clks.MemPstateTable[%d].UClk = %d\n" - "dpm_clks->MemPstateTable[%d].MemClk= %d\n" - "dpm_clks->MemPstateTable[%d].Voltage = %d\n", - i, dpm_clks->MemPstateTable[i].UClk, - i, dpm_clks->MemPstateTable[i].MemClk, - i, dpm_clks->MemPstateTable[i].Voltage); - } - - if (clk_mgr_base->ctx->dc_bios->integrated_info && clk_mgr_base->ctx->dc->config.use_default_clock_table == false) { - /* DCFCLK */ - dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz, - dpm_clks->DcfClocks, - dpm_clks->NumDcfClkLevelsEnabled); - clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels = dpm_clks->NumDcfClkLevelsEnabled; - - /* SOCCLK */ - dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz, - dpm_clks->SocClocks, - dpm_clks->NumSocClkLevelsEnabled); - clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_socclk_levels = dpm_clks->NumSocClkLevelsEnabled; - - /* DISPCLK */ - dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz, - dpm_clks->DispClocks, - dpm_clks->NumDispClkLevelsEnabled); - clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels = dpm_clks->NumDispClkLevelsEnabled; - - /* DPPCLK */ - dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz, - dpm_clks->DppClocks, - dpm_clks->NumDispClkLevelsEnabled); - clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dppclk_levels = dpm_clks->NumDispClkLevelsEnabled; - - /* FCLK */ - dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz, - dpm_clks->FclkClocks_Freq, - NUM_FCLK_DPM_LEVELS); - clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels = dpm_clks->NumFclkLevelsEnabled; - clk_mgr_base->bw_params->clk_table.num_entries = dpm_clks->NumFclkLevelsEnabled; - - /* Memory Pstate table is in reverse order*/ - ASSERT(dpm_clks->NumMemPstatesEnabled <= NUM_MEM_PSTATE_LEVELS); - if (dpm_clks->NumMemPstatesEnabled > NUM_MEM_PSTATE_LEVELS) - dpm_clks->NumMemPstatesEnabled = NUM_MEM_PSTATE_LEVELS; - for (i = 0; i < dpm_clks->NumMemPstatesEnabled; i++) { - clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].memclk_mhz = dpm_clks->MemPstateTable[i].UClk; - clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].wck_ratio = dcn42_convert_wck_ratio(dpm_clks->MemPstateTable[i].WckRatio) ; - } - clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels = dpm_clks->NumMemPstatesEnabled; - - /* DTBCLK*/ - clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz = clk_mgr_base->clks.ref_dtbclk_khz / 1000; - clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels = 1; - /* 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); - } - } - if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0) - dm_helpers_free_gpu_mem(clk_mgr_base->ctx, DC_MEM_ALLOC_TYPE_GART, - smu_dpm_clks.dpm_clks); + clk_mgr_base->clks.dtbclk_en = clk_mgr_base->boot_snapshot.dtbclk > 59000; } static struct clk_bw_params dcn42_bw_params = { @@ -950,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; } @@ -959,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) { @@ -1012,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) @@ -1050,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; @@ -1071,6 +961,127 @@ bool dcn42_is_smu_present(struct clk_mgr *clk_mgr_base) return clk_mgr->smu_present; } +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 }; + + DC_LOGGER_INIT(clk_mgr_base->ctx->logger); + (void)dc_logger; + + smu_dpm_clks.dpm_clks = (DpmClocks_t_dcn42 *)dm_helpers_allocate_gpu_mem( + clk_mgr_base->ctx, + DC_MEM_ALLOC_TYPE_GART, + sizeof(DpmClocks_t_dcn42), + &smu_dpm_clks.mc_address.quad_part); + + ASSERT(smu_dpm_clks.dpm_clks); + if (clk_mgr_base->ctx->dc->debug.pstate_enabled && smu_dpm_clks.mc_address.quad_part != 0) { + int i; + DpmClocks_t_dcn42 *dpm_clks = smu_dpm_clks.dpm_clks; + + dcn42_get_dpm_table_from_smu(clk_mgr_int, &smu_dpm_clks); + DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n" + "NumDispClkLevelsEnabled: %d\n" + "NumSocClkLevelsEnabled: %d\n" + "VcnClkLevelsEnabled: %d\n" + "FClkLevelsEnabled: %d\n" + "NumMemPstatesEnabled: %d\n" + "MinGfxClk: %d\n" + "MaxGfxClk: %d\n", + dpm_clks->NumDcfClkLevelsEnabled, + dpm_clks->NumDispClkLevelsEnabled, + dpm_clks->NumSocClkLevelsEnabled, + dpm_clks->VcnClkLevelsEnabled, + dpm_clks->NumFclkLevelsEnabled, + dpm_clks->NumMemPstatesEnabled, + dpm_clks->MinGfxClk, + dpm_clks->MaxGfxClk); + + for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) { + DC_LOG_SMU("dpm_clks->DcfClocks[%d] = %d\n", + i, + dpm_clks->DcfClocks[i]); + } + for (i = 0; i < NUM_DISPCLK_DPM_LEVELS; i++) { + DC_LOG_SMU("dpm_clks->DispClocks[%d] = %d\n", + i, dpm_clks->DispClocks[i]); + } + for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) { + DC_LOG_SMU("dpm_clks->SocClocks[%d] = %d\n", + i, dpm_clks->SocClocks[i]); + } + for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) { + DC_LOG_SMU("dpm_clks->FclkClocks_Freq[%d] = %d\n", + i, dpm_clks->FclkClocks_Freq[i]); + DC_LOG_SMU("dpm_clks->FclkClocks_Voltage[%d] = %d\n", + i, dpm_clks->FclkClocks_Voltage[i]); + } + for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) + DC_LOG_SMU("dpm_clks->SocVoltage[%d] = %d\n", + i, dpm_clks->SocVoltage[i]); + + for (i = 0; i < NUM_MEM_PSTATE_LEVELS; i++) { + DC_LOG_SMU("dpm_clks.MemPstateTable[%d].UClk = %d\n" + "dpm_clks->MemPstateTable[%d].MemClk= %d\n" + "dpm_clks->MemPstateTable[%d].Voltage = %d\n", + i, dpm_clks->MemPstateTable[i].UClk, + i, dpm_clks->MemPstateTable[i].MemClk, + i, dpm_clks->MemPstateTable[i].Voltage); + } + + if (clk_mgr_base->ctx->dc_bios->integrated_info && clk_mgr_base->ctx->dc->config.use_default_clock_table == false) { + /* DCFCLK */ + dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz, + dpm_clks->DcfClocks, + dpm_clks->NumDcfClkLevelsEnabled); + clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels = dpm_clks->NumDcfClkLevelsEnabled; + + /* SOCCLK */ + dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz, + dpm_clks->SocClocks, + dpm_clks->NumSocClkLevelsEnabled); + clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_socclk_levels = dpm_clks->NumSocClkLevelsEnabled; + + /* DISPCLK */ + dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz, + dpm_clks->DispClocks, + dpm_clks->NumDispClkLevelsEnabled); + clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels = dpm_clks->NumDispClkLevelsEnabled; + + /* DPPCLK */ + dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz, + dpm_clks->DppClocks, + dpm_clks->NumDispClkLevelsEnabled); + clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dppclk_levels = dpm_clks->NumDispClkLevelsEnabled; + + /* FCLK */ + dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz, + dpm_clks->FclkClocks_Freq, + NUM_FCLK_DPM_LEVELS); + clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels = dpm_clks->NumFclkLevelsEnabled; + clk_mgr_base->bw_params->clk_table.num_entries = dpm_clks->NumFclkLevelsEnabled; + + /* Memory Pstate table is in reverse order*/ + ASSERT(dpm_clks->NumMemPstatesEnabled <= NUM_MEM_PSTATE_LEVELS); + if (dpm_clks->NumMemPstatesEnabled > NUM_MEM_PSTATE_LEVELS) + dpm_clks->NumMemPstatesEnabled = NUM_MEM_PSTATE_LEVELS; + for (i = 0; i < dpm_clks->NumMemPstatesEnabled; i++) { + clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].memclk_mhz = dpm_clks->MemPstateTable[i].MemClk; + clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].wck_ratio = dcn42_convert_wck_ratio(dpm_clks->MemPstateTable[i].WckRatio) ; + } + clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels = dpm_clks->NumMemPstatesEnabled; + + /* DTBCLK*/ + clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz = 600; /* Fixed on platform */ + clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels = 1; + } + } + if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0) + dm_helpers_free_gpu_mem(clk_mgr_base->ctx, DC_MEM_ALLOC_TYPE_GART, + smu_dpm_clks.dpm_clks); +} + static struct clk_mgr_funcs dcn42_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, @@ -1139,6 +1150,11 @@ void dcn42_clk_mgr_construct( dcn42_bw_params.num_channels = ctx->dc_bios->integrated_info->ma_channel_number ? ctx->dc_bios->integrated_info->ma_channel_number : 1; clk_mgr->base.base.dprefclk_khz = dcn42_smu_get_dprefclk(&clk_mgr->base); clk_mgr->base.base.clks.ref_dtbclk_khz = dcn42_smu_get_dtbclk(&clk_mgr->base); + + clk_mgr->base.base.bw_params = &dcn42_bw_params; + + if (clk_mgr->base.smu_present) + dcn42_get_smu_clocks(&clk_mgr->base); } /* in case we don't get a value from the BIOS, use default */ if (clk_mgr->base.base.dentist_vco_freq_khz == 0) @@ -1153,6 +1169,8 @@ void dcn42_clk_mgr_construct( dcn42_read_ss_info_from_lut(&clk_mgr->base); clk_mgr->base.base.bw_params = &dcn42_bw_params; + if (clk_mgr->base.smu_present) + dcn42_get_smu_clocks(&clk_mgr->base); } void dcn42_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h index 5ad027a9edaf..9568ca06f00f 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h @@ -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__ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 31589f22aae0..419f894c87b0 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1096,11 +1096,8 @@ static bool dc_construct(struct dc *dc, #ifdef CONFIG_DRM_AMD_DC_FP dc->clk_mgr->force_smu_not_present = init_params->force_smu_not_present; - if (dc->res_pool->funcs->update_bw_bounding_box) { - DC_FP_START(); + if (dc->res_pool->funcs->update_bw_bounding_box) dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params); - DC_FP_END(); - } dc->soc_and_ip_translator = dc_create_soc_and_ip_translator(dc_ctx->dce_version); if (!dc->soc_and_ip_translator) goto fail; @@ -1137,6 +1134,8 @@ static void disable_all_writeback_pipes_for_stream( struct dc_stream_state *stream, struct dc_state *context) { + (void)dc; + (void)context; int i; for (i = 0; i < stream->num_wb_info; i++) @@ -1148,6 +1147,8 @@ static void apply_ctx_interdependent_lock(struct dc *dc, struct dc_stream_state *stream, bool lock) { + (void)dc; + (void)context; int i; /* Checks if interdependent update function pointer is NULL or not, takes care of DCE110 case */ @@ -1563,8 +1564,7 @@ static void detect_edp_presence(struct dc *dc) struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link = NULL; enum dc_connection_type type; - int i; - int edp_num; + unsigned int i, edp_num; dc_get_edp_links(dc, edp_links, &edp_num); if (!edp_num) @@ -1923,10 +1923,77 @@ bool dc_validate_boot_timing(const struct dc *dc, return false; } - /* block DSC for now, as VBIOS does not currently support DSC timings */ if (crtc_timing->flags.DSC) { - DC_LOG_DEBUG("boot timing validation failed due to DSC\n"); - return false; + struct display_stream_compressor *dsc = NULL; + struct dcn_dsc_state dsc_state = {0}; + + /* Find DSC associated with this timing generator */ + if (tg_inst < dc->res_pool->res_cap->num_dsc) { + dsc = dc->res_pool->dscs[tg_inst]; + } + + if (!dsc || !dsc->funcs->dsc_read_state) { + DC_LOG_DEBUG("boot timing validation failed due to no DSC resource or read function\n"); + return false; + } + + /* Read current DSC hardware state */ + dsc->funcs->dsc_read_state(dsc, &dsc_state); + + /* Check if DSC is actually enabled in hardware */ + if (dsc_state.dsc_clock_en == 0) { + DC_LOG_DEBUG("boot timing validation failed due to DSC not enabled in hardware\n"); + return false; + } + + uint32_t num_slices_h = 0; + uint32_t num_slices_v = 0; + + if (dsc_state.dsc_slice_width > 0) { + num_slices_h = (crtc_timing->h_addressable + dsc_state.dsc_slice_width - 1) / dsc_state.dsc_slice_width; + } + + if (dsc_state.dsc_slice_height > 0) { + num_slices_v = (crtc_timing->v_addressable + dsc_state.dsc_slice_height - 1) / dsc_state.dsc_slice_height; + } + + if (crtc_timing->dsc_cfg.num_slices_h != num_slices_h) { + DC_LOG_DEBUG("boot timing validation failed due to num_slices_h mismatch\n"); + return false; + } + + if (crtc_timing->dsc_cfg.num_slices_v != num_slices_v) { + DC_LOG_DEBUG("boot timing validation failed due to num_slices_v mismatch\n"); + return false; + } + + if (crtc_timing->dsc_cfg.bits_per_pixel != dsc_state.dsc_bits_per_pixel) { + DC_LOG_DEBUG("boot timing validation failed due to bits_per_pixel mismatch\n"); + return false; + } + + if (crtc_timing->dsc_cfg.block_pred_enable != dsc_state.dsc_block_pred_enable) { + DC_LOG_DEBUG("boot timing validation failed due to block_pred_enable mismatch\n"); + return false; + } + + if (crtc_timing->dsc_cfg.linebuf_depth != dsc_state.dsc_line_buf_depth) { + DC_LOG_DEBUG("boot timing validation failed due to linebuf_depth mismatch\n"); + return false; + } + + if (crtc_timing->dsc_cfg.version_minor != dsc_state.dsc_version_minor) { + DC_LOG_DEBUG("boot timing validation failed due to version_minor mismatch\n"); + return false; + } + + if (crtc_timing->dsc_cfg.ycbcr422_simple != dsc_state.dsc_simple_422) { + DC_LOG_DEBUG("boot timing validation failed due to pixel encoding mismatch\n"); + return false; + } + + // Skip checks for is_frl, is_dp, and rc_buffer_size which are not programmed by vbios + // or not necessary for seamless boot validation. } if (dc_is_dp_signal(link->connector_signal)) { @@ -2617,6 +2684,16 @@ void dc_post_update_surfaces_to_stream(struct dc *dc) dc->optimized_required = false; } +void dc_get_default_tiling_info(const struct dc *dc, struct dc_tiling_info *tiling_info) +{ + if (!dc || !tiling_info) + return; + if (dc->res_pool && dc->res_pool->funcs && dc->res_pool->funcs->get_default_tiling_info) { + dc->res_pool->funcs->get_default_tiling_info(tiling_info); + return; + } +} + bool dc_set_generic_gpio_for_stereo(bool enable, struct gpio_service *gpio_service) { @@ -2759,28 +2836,12 @@ static struct surface_update_descriptor get_plane_info_update_type(const struct if (memcmp(tiling, &u->surface->tiling_info, sizeof(*tiling)) != 0) { update_flags->bits.swizzle_change = 1; - elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); - switch (tiling->gfxversion) { - case DcGfxVersion9: - case DcGfxVersion10: - case DcGfxVersion11: - if (tiling->gfx9.swizzle != DC_SW_LINEAR) { - update_flags->bits.bandwidth_change = 1; - elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); - } - break; - case DcGfxAddr3: - if (tiling->gfx_addr3.swizzle != DC_ADDR3_SW_LINEAR) { - update_flags->bits.bandwidth_change = 1; - elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); - } - break; - case DcGfxVersion7: - case DcGfxVersion8: - case DcGfxVersionUnknown: - default: - break; + if (tiling->flags.avoid_full_update_on_tiling_change) { + elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); + } else { + update_flags->bits.bandwidth_change = 1; + elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } } @@ -2950,6 +3011,7 @@ static struct surface_update_descriptor det_surface_update( */ static void force_immediate_gsl_plane_flip(struct dc *dc, struct dc_surface_update *updates, int surface_count) { + (void)dc; bool has_flip_immediate_plane = false; int i; @@ -3228,6 +3290,7 @@ static void copy_stream_update_to_stream(struct dc *dc, struct dc_stream_state *stream, struct dc_stream_update *update) { + (void)context; struct dc_context *dc_ctx = dc->ctx; if (update == NULL || stream == NULL) @@ -3503,6 +3566,7 @@ static void restore_minimal_pipe_split_policy(struct dc *dc, * @surface_count: surface update count * @stream: Corresponding stream to be updated * @stream_update: stream update + * @update_descriptor: describes what plane and stream changes to apply * @new_update_type: [out] determined update type by the function * @new_context: [out] new context allocated and validated if update type is * FULL, reference to current context if update type is less than FULL. @@ -3831,6 +3895,7 @@ static void commit_planes_do_stream_update(struct dc *dc, static bool dc_dmub_should_send_dirty_rect_cmd(struct dc *dc, struct dc_stream_state *stream) { + (void)dc; if ((stream->link->psr_settings.psr_version == DC_PSR_VERSION_SU_1 || stream->link->psr_settings.psr_version == DC_PSR_VERSION_1) && stream->ctx->dce_version >= DCN_VERSION_3_1) @@ -4631,6 +4696,7 @@ static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc, int surface_count, bool *is_plane_addition) { + (void)srf_updates; struct dc_stream_status *cur_stream_status = stream_get_status(dc->current_state, stream); bool force_minimal_pipe_splitting = false; @@ -5055,7 +5121,9 @@ void populate_fast_updates(struct dc_fast_update *fast_update, fast_update[i].input_csc_color_matrix = srf_updates[i].input_csc_color_matrix; fast_update[i].coeff_reduction_factor = srf_updates[i].coeff_reduction_factor; fast_update[i].cursor_csc_color_matrix = srf_updates[i].cursor_csc_color_matrix; +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) fast_update[i].cm_hist_control = srf_updates[i].cm_hist_control; +#endif } } @@ -5073,7 +5141,9 @@ static bool fast_updates_exist(const struct dc_fast_update *fast_update, int sur fast_update[i].gamut_remap_matrix || fast_update[i].input_csc_color_matrix || fast_update[i].cursor_csc_color_matrix || +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) fast_update[i].cm_hist_control || +#endif fast_update[i].coeff_reduction_factor) return true; } @@ -5094,7 +5164,9 @@ bool fast_nonaddr_updates_exist(struct dc_fast_update *fast_update, int surface_ fast_update[i].gamma || fast_update[i].gamut_remap_matrix || fast_update[i].coeff_reduction_factor || +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) fast_update[i].cm_hist_control || +#endif fast_update[i].cursor_csc_color_matrix) return true; } @@ -5109,6 +5181,7 @@ static bool full_update_required_weak( const struct dc_stream_update *stream_update, const struct dc_stream_state *stream) { + (void)stream_update; const struct dc_state *context = dc->current_state; if (srf_updates) for (int i = 0; i < surface_count; i++) @@ -5478,6 +5551,7 @@ void dc_commit_updates_for_stream(struct dc *dc, struct dc_stream_update *stream_update, struct dc_state *state) { + (void)state; bool ret = false; dc_exit_ips_for_hw_access(dc); @@ -5787,6 +5861,7 @@ void dc_lock_memory_clock_frequency(struct dc *dc) static void blank_and_force_memclk(struct dc *dc, bool apply, unsigned int memclk_mhz) { + (void)apply; struct dc_state *context = dc->current_state; struct hubp *hubp; struct pipe_ctx *pipe; @@ -6331,8 +6406,7 @@ void dc_disable_accelerated_mode(struct dc *dc) */ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bool enable) { - int i; - int edp_num; + unsigned int i, edp_num; struct pipe_ctx *pipe = NULL; struct dc_link *link = stream->sink->link; struct dc_link *edp_links[MAX_NUM_EDP]; @@ -6386,8 +6460,7 @@ bool dc_abm_save_restore( struct dc_stream_state *stream, struct abm_save_restore *pData) { - int i; - int edp_num; + unsigned int i, edp_num; struct pipe_ctx *pipe = NULL; struct dc_link *link = stream->sink->link; struct dc_link *edp_links[MAX_NUM_EDP]; @@ -6463,6 +6536,7 @@ void dc_query_current_properties(struct dc *dc, struct dc_current_properties *pr void dc_set_edp_power(const struct dc *dc, struct dc_link *edp_link, bool powerOn) { + (void)dc; if (edp_link->connector_signal != SIGNAL_TYPE_EDP) return; @@ -6589,6 +6663,7 @@ void dc_get_underflow_debug_data_for_otg(struct dc *dc, int primary_otg_inst, void dc_get_power_feature_status(struct dc *dc, int primary_otg_inst, struct power_features *out_data) { + (void)primary_otg_inst; out_data->uclk_p_state = dc->current_state->clk_mgr->clks.p_state_change_support; out_data->fams = dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 5b3695e72e19..db86e346307c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -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: diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c index 7bb4504889be..f4e99ca7918f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c @@ -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) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 8271b12c1a66..66597a1f5b78 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -749,10 +749,10 @@ struct clock_source *resource_find_used_clk_src_for_sharing( return NULL; } -static enum pixel_format convert_pixel_format_to_dalsurface( +static enum dc_pixel_format convert_pixel_format_to_dalsurface( enum surface_pixel_format surface_pixel_format) { - enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN; + enum dc_pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN; switch (surface_pixel_format) { case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: @@ -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) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c index a40e5c44143f..40f7aa732258 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c @@ -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 (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; + if (!status) { + 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); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 908f79b02102..e16de323f39c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -33,7 +33,6 @@ #include "dc_dmub_srv.h" #include "dc_state_priv.h" #include "dc_stream_priv.h" -#include "dce/dmub_hw_lock_mgr.h" #define DC_LOGGER dc->ctx->logger #ifndef MIN @@ -43,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 ******************************************************************************/ @@ -171,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; @@ -259,7 +267,6 @@ void program_cursor_attributes( struct resource_context *res_ctx; struct pipe_ctx *pipe_to_program = NULL; bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); - bool unlock_dmub = false; if (!stream) return; @@ -278,12 +285,6 @@ void program_cursor_attributes( if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) { dc->hwss.begin_cursor_offload_update(dc, pipe_ctx); } else { - if (dc->hwss.dmub_hw_control_lock && pipe_ctx->stream && - should_use_dmub_inbox0_lock_for_link(dc, pipe_ctx->stream->link)) { - dc->hwss.dmub_hw_control_lock(dc, dc->current_state, true); - unlock_dmub = true; - } - dc->hwss.cursor_lock(dc, pipe_to_program, true); if (pipe_to_program->next_odm_pipe) dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true); @@ -306,9 +307,6 @@ void program_cursor_attributes( dc->hwss.cursor_lock(dc, pipe_to_program, false); if (pipe_to_program->next_odm_pipe) dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false); - - if (unlock_dmub) - dc->hwss.dmub_hw_control_lock(dc, dc->current_state, false); } } } @@ -416,7 +414,6 @@ void program_cursor_position( struct resource_context *res_ctx; struct pipe_ctx *pipe_to_program = NULL; bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); - bool unlock_dmub = false; if (!stream) return; @@ -436,16 +433,10 @@ void program_cursor_position( if (!pipe_to_program) { pipe_to_program = pipe_ctx; - if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) { + if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) dc->hwss.begin_cursor_offload_update(dc, pipe_ctx); - } else { - if (dc->hwss.dmub_hw_control_lock && pipe_ctx->stream && - should_use_dmub_inbox0_lock_for_link(dc, pipe_ctx->stream->link)) { - dc->hwss.dmub_hw_control_lock(dc, dc->current_state, true); - unlock_dmub = true; - } + else dc->hwss.cursor_lock(dc, pipe_to_program, true); - } } dc->hwss.set_cursor_position(pipe_ctx); @@ -457,14 +448,10 @@ void program_cursor_position( } if (pipe_to_program) { - if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) { + if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) dc->hwss.commit_cursor_offload_update(dc, pipe_to_program); - } else { + else dc->hwss.cursor_lock(dc, pipe_to_program, false); - - if (unlock_dmub) - dc->hwss.dmub_hw_control_lock(dc, dc->current_state, false); - } } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index 5f12dcca7f71..a59b176d8e55 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -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 } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index c7a09724f569..55ec281db3b7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -63,7 +63,7 @@ struct dcn_dsc_reg_state; struct dcn_optc_reg_state; struct dcn_dccg_reg_state; -#define DC_VER "3.2.373" +#define DC_VER "3.2.376" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC @@ -520,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; @@ -1215,6 +1215,7 @@ struct dc_debug_options { bool enable_dmu_recovery; unsigned int force_vmin_threshold; bool enable_otg_frame_sync_pwa; + unsigned int min_deep_sleep_dcfclk_khz; }; @@ -1888,7 +1889,9 @@ struct dc_fast_update { 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 { @@ -1970,6 +1973,15 @@ void dc_plane_cm_retain(struct dc_plane_cm *cm); void dc_post_update_surfaces_to_stream( struct dc *dc); +/* + * dc_get_default_tiling_info() - Retrieve an ASIC-appropriate default tiling + * description for (typically) linear surfaces. + * + * This is used by OS/DM paths that need a valid, fully-initialized tiling + * description without hardcoding gfx-version specifics in the caller. + */ +void dc_get_default_tiling_info(const struct dc *dc, struct dc_tiling_info *tiling_info); + /** * struct dc_validation_set - Struct to store surface/stream associations for validation */ @@ -2068,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); diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index b15360bcdacf..79c8b4cab053 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -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; } @@ -2349,6 +2356,33 @@ bool dc_dmub_srv_is_cursor_offload_enabled(const struct dc *dc) return dc->ctx->dmub_srv && dc->ctx->dmub_srv->cursor_offload_enabled; } +void dc_dmub_srv_boot_time_crc_init(const struct dc *dc, uint64_t gpu_addr, uint32_t size) +{ + struct dc_dmub_srv *dc_dmub_srv; + struct dc_context *dc_ctx; + union dmub_rb_cmd cmd = {0}; + bool result = false; + + if (!dc || !dc->ctx || !dc->ctx->dmub_srv || size == 0) + return; + + dc_dmub_srv = dc->ctx->dmub_srv; + dc_ctx = dc_dmub_srv->ctx; + + memset(&cmd, 0, sizeof(cmd)); + cmd.boot_time_crc_init.header.type = DMUB_CMD__BOOT_TIME_CRC; + cmd.boot_time_crc_init.header.sub_type = DMUB_CMD__BOOT_TIME_CRC_INIT_MEM; + cmd.boot_time_crc_init.header.payload_bytes = + sizeof(struct dmub_rb_cmd_boot_time_crc_init); + cmd.boot_time_crc_init.data.buffer_addr.quad_part = gpu_addr; + cmd.boot_time_crc_init.data.buffer_size = size; + + result = dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + + if (!result) + DC_ERROR("Boot time crc init failed in DMUB"); +} + void dc_dmub_srv_release_hw(const struct dc *dc) { struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index 72e0a41f39f0..6579cf9cce3c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -362,6 +362,15 @@ void dc_dmub_srv_program_cursor_now(struct dc *dc, const struct pipe_ctx *pipe); bool dc_dmub_srv_is_cursor_offload_enabled(const struct dc *dc); /** + * dc_dmub_srv_boot_time_crc_init() - Initializes DMUB boot time CRC. + * + * @dc - pointer to DC object + * @gpu_addr - address for the boot time CRC buffer + * @size - size of the boot time CRC buffer + */ +void dc_dmub_srv_boot_time_crc_init(const struct dc *dc, uint64_t gpu_addr, uint32_t size); + +/** * dc_dmub_srv_release_hw() - Notifies DMUB service that HW access is no longer required. * * @dc - pointer to DC object diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index 04b8b798dfff..77299767096f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 9bf853edc46f..c2ca08d26e37 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -218,7 +218,7 @@ enum surface_pixel_format { /* Pixel format */ -enum pixel_format { +enum dc_pixel_format { /*graph*/ PIXEL_FORMAT_UNINITIALIZED, PIXEL_FORMAT_INDEX8, @@ -445,6 +445,10 @@ enum dc_gfxversion { enum swizzle_mode_addr3_values swizzle; } gfx_addr3;/*gfx with addr3 and above*/ }; + + struct { + bool avoid_full_update_on_tiling_change; + } flags; }; /* Rotation angle */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c b/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c index ba7bf23f2b2f..52ed8deebf63 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c +++ b/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c @@ -63,7 +63,8 @@ static void populate_inits_from_splinits(struct scl_inits *inits, inits->h_c = dc_fixpt_from_int_dy(spl_inits->h_filter_init_int_c, spl_inits->h_filter_init_frac_c >> 5, 0, 19); inits->v_c = dc_fixpt_from_int_dy(spl_inits->v_filter_init_int_c, spl_inits->v_filter_init_frac_c >> 5, 0, 19); } -static void populate_splformat_from_format(enum spl_pixel_format *spl_pixel_format, const enum pixel_format pixel_format) +static void populate_splformat_from_format(enum spl_pixel_format *spl_pixel_format, + const enum dc_pixel_format pixel_format) { if (pixel_format < PIXEL_FORMAT_INVALID) *spl_pixel_format = (enum spl_pixel_format)pixel_format; diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index e224077c8902..fd8ec1660312 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1144,10 +1144,12 @@ union replay_low_refresh_rate_enable_options { union replay_optimization { struct { - //BIT[0-3]: Replay Teams Optimization + //BIT[0-1]: Replay Teams Optimization unsigned int TEAMS_OPTIMIZATION_VER_1 :1; unsigned int TEAMS_OPTIMIZATION_VER_2 :1; - unsigned int RESERVED_2_3 :2; + //BIT[2]: Replay Live Capture with CVT + unsigned int LIVE_CAPTURE_WITH_CVT :1; + unsigned int RESERVED_3 :1; } bits; unsigned int raw; @@ -1196,6 +1198,8 @@ struct replay_config { bool frame_skip_supported; /* Replay Received Frame Skipping Error HPD. */ bool received_frame_skipping_error_hpd; + /* Live capture with CVT is activated */ + bool live_capture_with_cvt_activated; }; /* Replay feature flags*/ diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c index 7f58acfe1177..a72bf413fad6 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c @@ -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 diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c index e817cd7c2b6a..18b9c5ceed43 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c @@ -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 diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c index 0b7908fbb115..efac64165ccd 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c @@ -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 */ diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c index 4b9a14c679d3..97605a416031 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c @@ -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) { diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c index 19dfc3fe5c3a..b813310763e5 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h index d9831b0f8235..2076565b1caa 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h @@ -122,6 +122,7 @@ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 0, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 1, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 2, mask_sh),\ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c index 41169b42534c..469b4b8f88a3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index 0807d20985c7..77df61bfaf27 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -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 diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 5722be965422..34e54fdb9d13 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -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)); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index e871b72e43ef..25ebd8a52ae4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -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; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c index f5cd2392fc5f..f5261e8d7678 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c @@ -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}; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c index 365dd2e37aea..fe239a96121e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c index 2d73b94c515c..52e05b9185f1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c b/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c index 34bff9aef66c..ee55ec21d270 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c @@ -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 */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 2ba3d3a3aac5..5f40ae9e3120 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -122,6 +122,33 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = { .program_hpd_filter = dce110_program_hpd_filter, }; +static const struct link_encoder_funcs dce110_lnk_enc_funcs_no_hpd = { + .validate_output_with_stream = + dce110_link_encoder_validate_output_with_stream, + .hw_init = dce110_link_encoder_hw_init, + .setup = dce110_link_encoder_setup, + .enable_tmds_output = dce110_link_encoder_enable_tmds_output, + .enable_dp_output = dce110_link_encoder_enable_dp_output, + .enable_dp_mst_output = dce110_link_encoder_enable_dp_mst_output, + .enable_lvds_output = dce110_link_encoder_enable_lvds_output, + .enable_analog_output = dce110_link_encoder_enable_analog_output, + .disable_output = dce110_link_encoder_disable_output, + .dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings, + .dp_set_phy_pattern = dce110_link_encoder_dp_set_phy_pattern, + .update_mst_stream_allocation_table = + dce110_link_encoder_update_mst_stream_allocation_table, + .psr_program_dp_dphy_fast_training = + dce110_psr_program_dp_dphy_fast_training, + .psr_program_secondary_packet = dce110_psr_program_secondary_packet, + .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe, + .is_dig_enabled = dce110_is_dig_enabled, + .destroy = dce110_link_encoder_destroy, + .get_max_link_cap = dce110_link_encoder_get_max_link_cap, + .get_dig_frontend = dce110_get_dig_frontend, + .get_hpd_state = dce110_get_hpd_state, + .program_hpd_filter = dce110_program_hpd_filter, +}; + static enum bp_result link_transmitter_control( struct dce110_link_encoder *enc110, struct bp_transmitter_control *cntl) @@ -820,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; @@ -865,7 +893,10 @@ void dce110_link_encoder_construct( const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; enum bp_result result = BP_RESULT_OK; - enc110->base.funcs = &dce110_lnk_enc_funcs; + if (hpd_regs) + enc110->base.funcs = &dce110_lnk_enc_funcs; + else + enc110->base.funcs = &dce110_lnk_enc_funcs_no_hpd; enc110->base.ctx = init_data->ctx; enc110->base.id = init_data->encoder; enc110->base.analog_id = init_data->analog_encoder; @@ -1855,6 +1886,33 @@ static const struct link_encoder_funcs dce60_lnk_enc_funcs = { .program_hpd_filter = dce110_program_hpd_filter, }; +static const struct link_encoder_funcs dce60_lnk_enc_funcs_no_hpd = { + .validate_output_with_stream = + dce110_link_encoder_validate_output_with_stream, + .hw_init = dce110_link_encoder_hw_init, + .setup = dce110_link_encoder_setup, + .enable_tmds_output = dce110_link_encoder_enable_tmds_output, + .enable_dp_output = dce60_link_encoder_enable_dp_output, + .enable_dp_mst_output = dce60_link_encoder_enable_dp_mst_output, + .enable_lvds_output = dce110_link_encoder_enable_lvds_output, + .enable_analog_output = dce110_link_encoder_enable_analog_output, + .disable_output = dce110_link_encoder_disable_output, + .dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings, + .dp_set_phy_pattern = dce60_link_encoder_dp_set_phy_pattern, + .update_mst_stream_allocation_table = + dce110_link_encoder_update_mst_stream_allocation_table, + .psr_program_dp_dphy_fast_training = + dce110_psr_program_dp_dphy_fast_training, + .psr_program_secondary_packet = dce110_psr_program_secondary_packet, + .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe, + .is_dig_enabled = dce110_is_dig_enabled, + .destroy = dce110_link_encoder_destroy, + .get_max_link_cap = dce110_link_encoder_get_max_link_cap, + .get_dig_frontend = dce110_get_dig_frontend, + .get_hpd_state = dce110_get_hpd_state, + .program_hpd_filter = dce110_program_hpd_filter, +}; + void dce60_link_encoder_construct( struct dce110_link_encoder *enc110, const struct encoder_init_data *init_data, @@ -1867,7 +1925,10 @@ void dce60_link_encoder_construct( const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; enum bp_result result = BP_RESULT_OK; - enc110->base.funcs = &dce60_lnk_enc_funcs; + if (hpd_regs) + enc110->base.funcs = &dce60_lnk_enc_funcs; + else + enc110->base.funcs = &dce60_lnk_enc_funcs_no_hpd; enc110->base.ctx = init_data->ctx; enc110->base.id = init_data->encoder; enc110->base.analog_id = init_data->analog_encoder; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c index 1c2009e38aa1..168c2d0a5eaa 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c b/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c index f342da5a5e50..61d478cfca6d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c @@ -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, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index 87c19f17c799..ed407e779c12 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -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) { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index 1ab5ae9b5ea5..c1448ae47366 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -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], diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c index b686d89b79b2..93550c5e4d02 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c index a641ae04450c..806b5709c9e7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c index d0ffa99f1fe0..52673e2f504c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c @@ -82,7 +82,7 @@ bool dmub_hw_lock_mgr_does_link_require_lock(const struct dc *dc, const struct d if (link->psr_settings.psr_version == DC_PSR_VERSION_1) { struct dc_link *edp_links[MAX_NUM_EDP]; - int edp_num; + unsigned int edp_num; dc_get_edp_links(dc, edp_links, &edp_num); if (edp_num == 1) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c index 28a218149b8b..0af1b8e0a49e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c @@ -216,6 +216,7 @@ static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub, uint8_t panel_inst, uint16_t frame_skip_number) { + (void)panel_inst; union dmub_rb_cmd cmd; struct dc_context *dc = dmub->ctx; struct dmub_rb_cmd_replay_set_coasting_vtotal *pCmd = NULL; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c index 2c43c2422638..b265a72eeb70 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c @@ -40,6 +40,7 @@ static void set_flip_control( struct dce_mem_input *mem_input110, bool immediate) { + (void)immediate; uint32_t value = 0; value = dm_read_reg( @@ -165,6 +166,7 @@ static void program_tiling( const struct dc_tiling_info *info, const enum surface_pixel_format pixel_format) { + (void)pixel_format; uint32_t value = 0; set_reg_field_value(value, info->gfx8.num_banks, @@ -642,6 +644,8 @@ static void dce_mem_input_v_program_surface_config( struct dc_plane_dcc_param *dcc, bool horizotal_mirror) { + (void)dcc; + (void)horizotal_mirror; struct dce_mem_input *mem_input110 = TO_DCE_MEM_INPUT(mem_input); enable(mem_input110); @@ -927,6 +931,7 @@ static void dce_mem_input_v_program_display_marks( struct dce_watermarks urgent, uint32_t total_dest_line_time_ns) { + (void)stutter_enter; program_urgency_watermark_l( mem_input->ctx, urgent, @@ -970,6 +975,9 @@ static void dce110_allocate_mem_input_v( uint32_t pix_clk_khz,/* for current stream */ uint32_t total_stream_num) { + (void)h_total; + (void)v_total; + (void)total_stream_num; uint32_t addr; uint32_t value; uint32_t pix_dur; @@ -1009,6 +1017,8 @@ static void dce110_free_mem_input_v( struct mem_input *mi, uint32_t total_stream_num) { + (void)mi; + (void)total_stream_num; } static const struct mem_input_funcs dce110_mem_input_v_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c index e096d2b95ef9..cf63fac82832 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c @@ -110,6 +110,7 @@ static void program_color_matrix_v( const struct out_csc_color_matrix *tbl_entry, enum grph_color_adjust_option options) { + (void)options; struct dc_context *ctx = xfm_dce->base.ctx; uint32_t cntl_value = dm_read_reg(ctx, mmCOL_MAN_OUTPUT_CSC_CONTROL); bool use_set_a = (get_reg_field_value(cntl_value, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma_v.c index 9b65b77e8823..a4e76db46c9c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma_v.c @@ -551,5 +551,7 @@ void dce110_opp_set_regamma_mode_v( struct transform *xfm, enum opp_regamma mode) { + (void)xfm; + (void)mode; // TODO: need to implement the function } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c index 61b0807693fb..b015b27cd1c6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c @@ -66,6 +66,7 @@ static void dce110_timing_generator_apply_front_porch_workaround( struct timing_generator *tg, struct dc_crtc_timing *timing) { + (void)tg; if (timing->flags.INTERLACE == 1) { if (timing->v_front_porch < 2) timing->v_front_porch = 2; @@ -1115,6 +1116,7 @@ bool dce110_timing_generator_validate_timing( const struct dc_crtc_timing *timing, enum signal_type signal) { + (void)signal; uint32_t h_blank; uint32_t h_back_porch, hsync_offset, h_sync_start; @@ -1490,6 +1492,7 @@ void dce110_timing_generator_enable_reset_trigger( struct timing_generator *tg, int source_tg_inst) { + (void)source_tg_inst; uint32_t value; uint32_t rising_edge = 0; uint32_t falling_edge = 0; @@ -1959,6 +1962,12 @@ void dce110_tg_program_timing(struct timing_generator *tg, const enum signal_type signal, bool use_vbios) { + (void)vready_offset; + (void)vstartup_start; + (void)vupdate_offset; + (void)vupdate_width; + (void)pstate_keepout; + (void)signal; if (use_vbios) dce110_timing_generator_program_timing_generator(tg, timing); else diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c index 9837dec837ff..ba22c93acd81 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c @@ -442,6 +442,12 @@ static void dce110_timing_generator_v_program_timing(struct timing_generator *tg const enum signal_type signal, bool use_vbios) { + (void)vready_offset; + (void)vstartup_start; + (void)vupdate_offset; + (void)vupdate_width; + (void)pstate_keepout; + (void)signal; if (use_vbios) dce110_timing_generator_program_timing_generator(tg, timing); else @@ -621,6 +627,7 @@ static void dce110_timing_generator_v_setup_global_swap_lock( struct timing_generator *tg, const struct dcp_gsl_params *gsl_params) { + (void)gsl_params; DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); return; } @@ -629,6 +636,7 @@ static void dce110_timing_generator_v_enable_reset_trigger( struct timing_generator *tg, int source_tg_inst) { + (void)source_tg_inst; DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); return; } @@ -650,6 +658,7 @@ static void dce110_timing_generator_v_tear_down_global_swap_lock( static void dce110_timing_generator_v_disable_vga( struct timing_generator *tg) { + (void)tg; return; } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c index 28d3b2663cd3..6be18665b1f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c @@ -371,6 +371,9 @@ static void calculate_inits( struct rect *luma_viewport, struct rect *chroma_viewport) { + (void)xfm_dce; + (void)luma_viewport; + (void)chroma_viewport; inits->h_int_scale_ratio_luma = dc_fixpt_u2d19(data->ratios.horz) << 5; inits->v_int_scale_ratio_luma = @@ -619,6 +622,8 @@ static void dce110_xfmv_set_gamut_remap( struct transform *xfm, const struct xfm_grph_csc_adjustment *adjust) { + (void)xfm; + (void)adjust; /* DO NOTHING*/ } @@ -627,6 +632,7 @@ static void dce110_xfmv_set_pixel_storage_depth( enum lb_pixel_depth depth, const struct bit_depth_reduction_params *bit_depth_params) { + (void)bit_depth_params; struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); int pixel_depth = 0; int expan_mode = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c index 187f45a7f5e1..fe97d3946cab 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c @@ -284,6 +284,7 @@ static uint32_t align_to_chunks_number_per_line( struct dce112_compressor *cp110, uint32_t pixels) { + (void)cp110; return 256 * ((pixels + 255) / 256); } diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c index 31c4f44ceaac..70410ef0c291 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c @@ -304,6 +304,7 @@ static void dce120_timing_generator_enable_reset_trigger( struct timing_generator *tg, int source) { + (void)source; enum trigger_source_select trig_src_select = TRIGGER_SOURCE_SELECT_LOGIC_ZERO; struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); uint32_t rising_edge = 0; @@ -701,6 +702,12 @@ static void dce120_tg_program_timing(struct timing_generator *tg, const enum signal_type signal, bool use_vbios) { + (void)vready_offset; + (void)vstartup_start; + (void)vupdate_offset; + (void)vupdate_width; + (void)pstate_keepout; + (void)signal; if (use_vbios) dce110_timing_generator_program_timing_generator(tg, timing); else diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c index 88e7a1fc9a30..53c03364f5d4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c @@ -115,6 +115,12 @@ static void dce80_timing_generator_program_timing(struct timing_generator *tg, const enum signal_type signal, bool use_vbios) { + (void)vready_offset; + (void)vstartup_start; + (void)vupdate_offset; + (void)vupdate_width; + (void)pstate_keepout; + (void)signal; if (!use_vbios) program_pix_dur(tg, timing->pix_clk_100hz); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index dcd2cdfe91eb..c702a30563f9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -381,10 +381,10 @@ bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx, } for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) - seg_distr[i] = -1; + seg_distr[i] = (uint32_t)-1; for (k = 0; k < MAX_REGIONS_NUMBER; k++) { - if (seg_distr[k] != -1) + if (seg_distr[k] != (uint32_t)-1) hw_points += (1 << seg_distr[k]); } @@ -565,7 +565,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format( for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) - seg_distr[i] = -1; + seg_distr[i] = (uint32_t)-1; /* 12 segments * segments are from 2^-12 to 0 */ @@ -573,7 +573,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format( seg_distr[i] = 4; for (k = 0; k < MAX_REGIONS_NUMBER; k++) { - if (seg_distr[k] != -1) + if (seg_distr[k] != (uint32_t)-1) hw_points += (1 << seg_distr[k]); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c index 365a3215f6d5..e9efbb49586e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c @@ -44,6 +44,7 @@ static bool dwb1_get_caps(struct dwbc *dwbc, struct dwb_caps *caps) { + (void)dwbc; if (caps) { caps->adapter_id = 0; /* we only support 1 adapter currently */ caps->hw_version = DCN_VERSION_1_0; @@ -63,6 +64,7 @@ static bool dwb1_get_caps(struct dwbc *dwbc, struct dwb_caps *caps) static bool dwb1_enable(struct dwbc *dwbc, struct dc_dwb_params *params) { + (void)params; struct dcn10_dwbc *dwbc10 = TO_DCN10_DWBC(dwbc); /* disable first. */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c index a0d437f0ce2b..f73c5f42ea68 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c @@ -746,7 +746,7 @@ bool dwb_program_horz_scalar(struct dcn20_dwbc *dwbc20, src_width, dest_width); if (dc_fixpt_floor(tmp_h_ratio_luma) == 8) - h_ratio_luma = -1; + h_ratio_luma = (uint32_t)-1; else h_ratio_luma = dc_fixpt_u3d19(tmp_h_ratio_luma) << 5; @@ -824,7 +824,7 @@ bool dwb_program_vert_scalar(struct dcn20_dwbc *dwbc20, src_height, dest_height); if (dc_fixpt_floor(tmp_v_ratio_luma) == 8) - v_ratio_luma = -1; + v_ratio_luma = (uint32_t)-1; else v_ratio_luma = dc_fixpt_u3d19(tmp_v_ratio_luma) << 5; diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c index 227aa8672d17..9dbccf58dde5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c @@ -159,10 +159,10 @@ bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx, } for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) - seg_distr[i] = -1; + seg_distr[i] = (uint32_t)-1; for (k = 0; k < MAX_REGIONS_NUMBER; k++) { - if (seg_distr[k] != -1) + if (seg_distr[k] != (uint32_t)-1) hw_points += (1 << seg_distr[k]); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c index 05aac3e444b4..4c7e4fe3c680 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c @@ -77,6 +77,7 @@ static void apg31_se_audio_setup( unsigned int az_inst, struct audio_info *audio_info) { + (void)az_inst; struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg); ASSERT(audio_info); diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c index d928b4dcf6b8..d913f065ecca 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c @@ -249,6 +249,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting) { + (void)enable_sdp_splitting; uint32_t h_active_start; uint32_t v_active_start; uint32_t misc0 = 0; @@ -783,6 +784,7 @@ void enc1_stream_encoder_send_immediate_sdp_message( const uint8_t *custom_sdp_message, unsigned int sdp_message_size) { + (void)sdp_message_size; struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); uint32_t value = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c index 3e85e9c3d2cb..d1fd5462dca5 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c @@ -394,6 +394,8 @@ void enc314_dp_set_dsc_config(struct stream_encoder *enc, uint32_t dsc_bytes_per_pixel, uint32_t dsc_slice_width) { + (void)dsc_bytes_per_pixel; + (void)dsc_slice_width; struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); REG_UPDATE(DP_DSC_CNTL, DP_DSC_MODE, dsc_mode == OPTC_DSC_DISABLED ? 0 : 1); diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c index 3523d1cdc1a3..edafa3808455 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_stream_encoder.c @@ -356,6 +356,8 @@ static void enc32_dp_set_dsc_config(struct stream_encoder *enc, uint32_t dsc_bytes_per_pixel, uint32_t dsc_slice_width) { + (void)dsc_bytes_per_pixel; + (void)dsc_slice_width; struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); REG_UPDATE(DP_DSC_CNTL, DP_DSC_MODE, dsc_mode == OPTC_DSC_DISABLED ? 0 : 1); diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c index fd5d1dbf9dc6..de24dcd27e6c 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_stream_encoder.c @@ -369,6 +369,7 @@ static void enc35_stream_encoder_map_to_link( uint32_t stream_enc_inst, uint32_t link_enc_inst) { + (void)stream_enc_inst; struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); ASSERT(stream_enc_inst < 5 && link_enc_inst < 5); diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c index 99aab70ef3e1..2d33ed0c062d 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c @@ -57,6 +57,8 @@ static void enc401_dp_set_odm_combine( struct stream_encoder *enc, bool odm_combine) { + (void)enc; + (void)odm_combine; } /* setup stream encoder in dvi mode */ @@ -710,6 +712,7 @@ void enc401_stream_encoder_map_to_link( uint32_t stream_enc_inst, uint32_t link_enc_inst) { + (void)stream_enc_inst; struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); REG_UPDATE(STREAM_MAPPER_CONTROL, diff --git a/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c index 2655bc194a35..5b2bba0eff0e 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_link_encoder.c @@ -30,52 +30,92 @@ static bool virtual_link_encoder_validate_output_with_stream( struct link_encoder *enc, - const struct dc_stream_state *stream) { return true; } + const struct dc_stream_state *stream) { + (void)enc; + (void)stream; + return true; + } -static void virtual_link_encoder_hw_init(struct link_encoder *enc) {} +static void virtual_link_encoder_hw_init(struct link_encoder *enc) +{ + (void)enc; +} static void virtual_link_encoder_setup( - struct link_encoder *enc, - enum signal_type signal) {} + struct link_encoder *enc, enum signal_type signal) { + (void)enc; + (void)signal; + } static void virtual_link_encoder_enable_tmds_output( struct link_encoder *enc, enum clock_source_id clock_source, enum dc_color_depth color_depth, enum signal_type signal, - uint32_t pixel_clock) {} + uint32_t pixel_clock) { + (void)enc; + (void)clock_source; + (void)color_depth; + (void)signal; + (void)pixel_clock; + } static void virtual_link_encoder_enable_dp_output( struct link_encoder *enc, const struct dc_link_settings *link_settings, - enum clock_source_id clock_source) {} + enum clock_source_id clock_source) { + (void)enc; + (void)link_settings; + (void)clock_source; + } static void virtual_link_encoder_enable_dp_mst_output( struct link_encoder *enc, const struct dc_link_settings *link_settings, - enum clock_source_id clock_source) {} + enum clock_source_id clock_source) { + (void)enc; + (void)link_settings; + (void)clock_source; + } static void virtual_link_encoder_disable_output( struct link_encoder *link_enc, - enum signal_type signal) {} + enum signal_type signal) { + (void)link_enc; + (void)signal; + } static void virtual_link_encoder_dp_set_lane_settings( struct link_encoder *enc, const struct dc_link_settings *link_settings, - const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) {} + const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) { + (void)enc; + (void)link_settings; + (void)lane_settings; + } static void virtual_link_encoder_dp_set_phy_pattern( struct link_encoder *enc, - const struct encoder_set_dp_phy_pattern_param *param) {} + const struct encoder_set_dp_phy_pattern_param *param) { + (void)enc; + (void)param; + } static void virtual_link_encoder_update_mst_stream_allocation_table( struct link_encoder *enc, - const struct link_mst_stream_allocation_table *table) {} + const struct link_mst_stream_allocation_table *table) { + (void)enc; + (void)table; + } static void virtual_link_encoder_connect_dig_be_to_fe( struct link_encoder *enc, enum engine_id engine, - bool connect) {} + bool connect) { + (void)enc; + (void)engine; + (void)connect; + } static void virtual_link_encoder_destroy(struct link_encoder **enc) { @@ -86,6 +126,7 @@ static void virtual_link_encoder_destroy(struct link_encoder **enc) static void virtual_link_encoder_get_max_link_cap(struct link_encoder *enc, struct dc_link_settings *link_settings) { + (void)enc; /* Set Default link settings */ struct dc_link_settings max_link_cap = {LANE_COUNT_FOUR, LINK_RATE_HIGH, LINK_SPREAD_05_DOWNSPREAD_30KHZ, false, 0}; diff --git a/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c index a9c8857476ac..27448f2b2467 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/virtual/virtual_stream_encoder.c @@ -31,80 +31,127 @@ static void virtual_stream_encoder_dp_set_stream_attribute( struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space, bool use_vsc_sdp_for_colorimetry, - uint32_t enable_sdp_splitting) {} + uint32_t enable_sdp_splitting) { + (void)enc; + (void)crtc_timing; + (void)output_color_space; + (void)use_vsc_sdp_for_colorimetry; + (void)enable_sdp_splitting; + } static void virtual_stream_encoder_hdmi_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, int actual_pix_clk_khz, - bool enable_audio) {} + bool enable_audio) { + (void)enc; + (void)crtc_timing; + (void)actual_pix_clk_khz; + (void)enable_audio; + } static void virtual_stream_encoder_dvi_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, - bool is_dual_link) {} + bool is_dual_link) { + (void)enc; + (void)crtc_timing; + (void)is_dual_link; + } static void virtual_stream_encoder_set_throttled_vcp_size( struct stream_encoder *enc, - struct fixed31_32 avg_time_slots_per_mtp) -{} + struct fixed31_32 avg_time_slots_per_mtp) { + (void)enc; + (void)avg_time_slots_per_mtp; + } static void virtual_stream_encoder_update_hdmi_info_packets( struct stream_encoder *enc, - const struct encoder_info_frame *info_frame) {} + const struct encoder_info_frame *info_frame) { + (void)enc; + (void)info_frame; + } static void virtual_stream_encoder_stop_hdmi_info_packets( - struct stream_encoder *enc) {} + struct stream_encoder *enc) { + (void)enc; + } static void virtual_stream_encoder_set_avmute( - struct stream_encoder *enc, - bool enable) {} + struct stream_encoder *enc, bool enable) { + (void)enc; + (void)enable; + } static void virtual_stream_encoder_update_dp_info_packets( struct stream_encoder *enc, - const struct encoder_info_frame *info_frame) {} + const struct encoder_info_frame *info_frame) { + (void)enc; + (void)info_frame; + } static void virtual_stream_encoder_stop_dp_info_packets( - struct stream_encoder *enc) {} + struct stream_encoder *enc) { + (void)enc; + } static void virtual_stream_encoder_dp_blank( struct dc_link *link, - struct stream_encoder *enc) {} + struct stream_encoder *enc) { + (void)link; + (void)enc; + } static void virtual_stream_encoder_dp_unblank( struct dc_link *link, struct stream_encoder *enc, - const struct encoder_unblank_param *param) {} + const struct encoder_unblank_param *param) { + (void)enc; + (void)link; + (void)param; + } static void virtual_audio_mute_control( - struct stream_encoder *enc, - bool mute) {} + struct stream_encoder *enc, bool mute) { + (void)enc; + (void)mute; + } static void virtual_stream_encoder_reset_hdmi_stream_attribute( - struct stream_encoder *enc) -{} + struct stream_encoder *enc) +{ + (void)enc; +} static void virtual_enc_dp_set_odm_combine( - struct stream_encoder *enc, - bool odm_combine) -{} + struct stream_encoder *enc, bool odm_combine) { + (void)enc; + (void)odm_combine; + } static void virtual_dig_connect_to_otg( - struct stream_encoder *enc, - int tg_inst) -{} + struct stream_encoder *enc, int tg_inst) { + (void)enc; + (void)tg_inst; + } static void virtual_setup_stereo_sync( - struct stream_encoder *enc, - int tg_inst, - bool enable) -{} + struct stream_encoder *enc, + int tg_inst, bool enable) { + (void)enc; + (void)tg_inst; + (void)enable; + } static void virtual_stream_encoder_set_dsc_pps_info_packet( - struct stream_encoder *enc, - bool enable, - uint8_t *dsc_packed_pps, - bool immediate_update) -{} + struct stream_encoder *enc, bool enable, uint8_t *dsc_packed_pps, + bool immediate_update) +{ + (void)enc; + (void)enable; + (void)dsc_packed_pps; + (void)immediate_update; +} static const struct stream_encoder_funcs virtual_str_enc_funcs = { .dp_set_odm_combine = diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c index 74962791302f..61553e24d53e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c @@ -525,6 +525,7 @@ static void split_stream_across_pipes( struct pipe_ctx *primary_pipe, struct pipe_ctx *secondary_pipe) { + (void)res_ctx; int pipe_idx = secondary_pipe->pipe_idx; if (!primary_pipe->plane_state) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c index c5e84190c17a..5679b79d6f53 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c @@ -76,7 +76,7 @@ struct _vcs_dpi_ip_params_st dcn1_0_ip = { .line_buffer_size_bits = 589824, .max_line_buffer_lines = 12, .IsLineBufferBppFixed = 0, - .LineBufferFixedBpp = -1, + .LineBufferFixedBpp = (unsigned int)-1, .writeback_luma_buffer_size_kbytes = 12, .writeback_chroma_buffer_size_kbytes = 8, .max_num_dpp = 4, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index 7aaf13bbd4e4..887744d56d6a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -1316,6 +1316,7 @@ int dcn20_populate_dml_pipes_from_context(struct dc *dc, display_e2e_pipe_params_st *pipes, enum dc_validate_mode validate_mode) { + (void)validate_mode; int pipe_cnt, i; bool synchronized_vblank = true; struct resource_context *res_ctx = &context->res_ctx; @@ -2335,7 +2336,7 @@ bool dcn21_validate_bandwidth_fp(struct dc *dc, struct dc_state *context, /*Unsafe due to current pipe merge and split logic*/ ASSERT(context != dc->current_state); - out = dcn21_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel, validate_mode); + out = dcn21_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel, validate_mode, false); if (pipe_cnt == 0) goto validate_out; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c index 0c8c4a080c50..f5f636afe33c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c @@ -501,6 +501,8 @@ static bool CalculatePrefetchSchedule( double *VUpdateWidthPix, double *VReadyOffsetPix) { + (void)mode_lib; + bool MyError = false; unsigned int DPPCycles, DISPCLKCycles; double DSTTotalPixelsAfterScaler, TotalRepeaterDelayTime; @@ -878,6 +880,7 @@ static unsigned int CalculateVMAndRowBytes( unsigned int *dpte_row_height, unsigned int *meta_row_height) { + (void)ViewportWidth; unsigned int MetaRequestHeight; unsigned int MetaRequestWidth; unsigned int MetaSurfWidth; @@ -2953,6 +2956,7 @@ static double CalculateRemoteSurfaceFlipDelay( double *TInitXFill, double *TslvChk) { + (void)mode_lib; double TSlvSetup, AvgfillRate, result; *SrcActiveDrainRate = VRatio * SwathWidth * Bpp / LineTime; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c index c935903b68e1..95b0a3501880 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c @@ -495,6 +495,7 @@ static bool CalculateDelayAfterScaler( double *DSTYAfterScaler ) { + (void)ReturnBW; unsigned int DPPCycles, DISPCLKCycles; double DataFabricLineDeliveryTimeLuma; double DataFabricLineDeliveryTimeChroma; @@ -592,6 +593,8 @@ static bool CalculatePrefetchSchedule( double *VUpdateWidthPix, double *VReadyOffsetPix) { + (void)mode_lib; + bool MyError = false; double TotalRepeaterDelayTime; double Tdm, LineTime, Tsetup; @@ -938,6 +941,7 @@ static unsigned int CalculateVMAndRowBytes( unsigned int *dpte_row_height, unsigned int *meta_row_height) { + (void)ViewportWidth; unsigned int MetaRequestHeight; unsigned int MetaRequestWidth; unsigned int MetaSurfWidth; @@ -3026,6 +3030,7 @@ static double CalculateRemoteSurfaceFlipDelay( double *TInitXFill, double *TslvChk) { + (void)mode_lib; double TSlvSetup, AvgfillRate, result; *SrcActiveDrainRate = VRatio * SwathWidth * Bpp / LineTime; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c index 9c58ff1069d6..591d9618bdc0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c @@ -126,6 +126,7 @@ static double get_refcyc_per_delivery(struct display_mode_lib *mode_lib, unsigned int delivery_width, unsigned int req_per_swath_ub) { + (void)mode_lib; double refcyc_per_delivery = 0.0; if (vratio <= 1.0) { @@ -1538,6 +1539,9 @@ void dml20_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib, const bool ignore_viewport_pos, const bool immediate_flip_support) { + (void)vm_en; + (void)ignore_viewport_pos; + (void)immediate_flip_support; display_rq_params_st rq_param = {0}; display_dlg_sys_params_st dlg_sys_param = {0}; @@ -1588,6 +1592,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, unsigned int cur_width, enum cursor_bpp cur_bpp) { + (void)mode_lib; unsigned int cur_src_width = cur_width; unsigned int cur_req_size = 0; unsigned int cur_req_width = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c index 570e6e39eb45..d4dddc9d535a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c @@ -126,6 +126,7 @@ static double get_refcyc_per_delivery(struct display_mode_lib *mode_lib, unsigned int delivery_width, unsigned int req_per_swath_ub) { + (void)mode_lib; double refcyc_per_delivery = 0.0; if (vratio <= 1.0) { @@ -1539,6 +1540,9 @@ void dml20v2_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib, const bool ignore_viewport_pos, const bool immediate_flip_support) { + (void)vm_en; + (void)ignore_viewport_pos; + (void)immediate_flip_support; display_rq_params_st rq_param = {0}; display_dlg_sys_params_st dlg_sys_param = {0}; @@ -1589,6 +1593,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, unsigned int cur_width, enum cursor_bpp cur_bpp) { + (void)mode_lib; unsigned int cur_src_width = cur_width; unsigned int cur_req_size = 0; unsigned int cur_req_width = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c index cd8cca651419..11570a0c9427 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c @@ -695,6 +695,9 @@ static bool CalculatePrefetchSchedule( double *VUpdateWidthPix, double *VReadyOffsetPix) { + (void)mode_lib; + (void)XFCEnabled; + bool MyError = false; unsigned int DPPCycles, DISPCLKCycles; double DSTTotalPixelsAfterScaler, TotalRepeaterDelayTime; @@ -1290,6 +1293,8 @@ static unsigned int CalculateVMAndRowBytes( unsigned int *DPDE0BytesFrame, unsigned int *MetaPTEBytesFrame) { + (void)SourcePixelFormat; + (void)ViewportWidth; unsigned int MPDEBytesFrame; unsigned int DCCMetaSurfaceBytes; unsigned int MacroTileSizeBytes; @@ -3040,6 +3045,7 @@ static double CalculateRemoteSurfaceFlipDelay( double *TInitXFill, double *TslvChk) { + (void)mode_lib; double TSlvSetup, AvgfillRate, result; *SrcActiveDrainRate = VRatio * SwathWidth * Bpp / LineTime; @@ -3187,6 +3193,7 @@ static void CalculateFlipSchedule( double *final_flip_bw, bool *ImmediateFlipSupportedForPipe) { + (void)mode_lib; double min_row_time = 0.0; unsigned int HostVMDynamicLevels; double TimeForFetchingMetaPTEImmediateFlip; @@ -5294,6 +5301,15 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( double *StutterEnterPlusExitWatermark, double *MinActiveDRAMClockChangeLatencySupported) { + (void)DPPCLK; + (void)SwathWidthSingleDPPY; + (void)DCFCLK; + (void)UrgentOutOfOrderReturn; + (void)ReturnBW; + (void)GPUVMEnable; + (void)dpte_group_bytes; + (void)MetaChunkSize; + double EffectiveLBLatencyHidingY; double EffectiveLBLatencyHidingC; double DPPOutputBufferLinesY; @@ -5304,7 +5320,7 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( double LinesInDETC; unsigned int LinesInDETYRoundedDownToSwath[DC__NUM_DPP__MAX]; unsigned int LinesInDETCRoundedDownToSwath; - double FullDETBufferingTimeY[DC__NUM_DPP__MAX]; + double FullDETBufferingTimeY[DC__NUM_DPP__MAX] = { 0 }; double FullDETBufferingTimeC; double ActiveDRAMClockChangeLatencyMarginY; double ActiveDRAMClockChangeLatencyMarginC; @@ -5885,6 +5901,9 @@ static void CalculateMetaAndPTETimes( double TimePerVMRequestVBlank[], double TimePerVMRequestFlip[]) { + (void)VRatioPrefetchY; + (void)VRatioPrefetchC; + unsigned int meta_chunk_width; unsigned int min_meta_chunk_width; unsigned int meta_chunk_per_row_int; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c index f549da082c01..8a611b3bec33 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c @@ -102,6 +102,7 @@ static double get_refcyc_per_delivery( unsigned int delivery_width, unsigned int req_per_swath_ub) { + (void)mode_lib; double refcyc_per_delivery = 0.0; if (vratio <= 1.0) { @@ -1647,6 +1648,9 @@ void dml21_rq_dlg_get_dlg_reg( const bool ignore_viewport_pos, const bool immediate_flip_support) { + (void)vm_en; + (void)ignore_viewport_pos; + (void)immediate_flip_support; display_rq_params_st rq_param = {0}; display_dlg_sys_params_st dlg_sys_param = {0}; @@ -1702,6 +1706,7 @@ static void calculate_ttu_cursor( unsigned int cur_width, enum cursor_bpp cur_bpp) { + (void)mode_lib; unsigned int cur_src_width = cur_width; unsigned int cur_req_size = 0; unsigned int cur_req_width = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c index e5f5c0663750..0cdd60869ce1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c @@ -571,6 +571,7 @@ void dcn30_fpu_update_bw_bounding_box(struct dc *dc, unsigned int *dcfclk_mhz, unsigned int *dram_speed_mts) { + (void)bw_params; unsigned int i; dc_assert_fp_enabled(); @@ -720,6 +721,7 @@ void dcn3_fpu_build_wm_range_table(struct clk_mgr *base) void patch_dcn30_soc_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *dcn3_0_ip) { + (void)dcn3_0_ip; dc_assert_fp_enabled(); if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index 1df3412be346..634982173190 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -778,6 +778,8 @@ static bool CalculatePrefetchSchedule( double *RequiredPrefetchPixDataBWChroma, bool *NotEnoughTimeForDynamicMetadata) { + (void)SwathWidthY; + (void)SwathWidthC; struct vba_vars_st *v = &mode_lib->vba; double DPPCLKDelaySubtotalPlusCNVCFormater = v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater; bool MyError = false; @@ -1233,6 +1235,10 @@ static void CalculateDCCConfiguration( unsigned int *IndependentBlockLuma, unsigned int *IndependentBlockChroma) { + (void)SurfaceWidthChroma; + (void)SurfaceHeightChroma; + (void)BytePerPixelDETY; + (void)BytePerPixelDETC; int yuv420 = 0; int horz_div_l = 0; int horz_div_c = 0; @@ -1595,6 +1601,7 @@ static unsigned int CalculateVMAndRowBytes( unsigned int *DPDE0BytesFrame, unsigned int *MetaPTEBytesFrame) { + (void)SourcePixelFormat; unsigned int MPDEBytesFrame = 0; unsigned int DCCMetaSurfaceBytes = 0; unsigned int MacroTileSizeBytes = 0; @@ -3068,6 +3075,8 @@ double dml30_CalculateWriteBackDISPCLK( unsigned int HTotal, unsigned int WritebackLineBufferSize) { + (void)WritebackPixelFormat; + (void)WritebackVRatio; double DISPCLK_H = 0, DISPCLK_V = 0, DISPCLK_HB = 0; DISPCLK_H = PixelClock * dml_ceil(WritebackHTaps / 8.0, 1) / WritebackHRatio; @@ -3086,6 +3095,8 @@ static double CalculateWriteBackDelay( long WritebackSourceHeight, unsigned int HTotal) { + (void)WritebackPixelFormat; + (void)WritebackHRatio; double CalculateWriteBackDelay = 0; double Line_length = 0; double Output_lines_last_notclamped = 0; @@ -3199,6 +3210,8 @@ static void CalculateFlipSchedule( double *final_flip_bw, bool *ImmediateFlipSupportedForPipe) { + (void)mode_lib; + (void)HostVMMinPageSize; double min_row_time = 0.0; unsigned int HostVMDynamicLevelsTrips = 0; double TimeForFetchingMetaPTEImmediateFlip = 0; @@ -4968,6 +4981,10 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( double BytePerPixelDETC[], enum clock_change_support *DRAMClockChangeSupport) { + (void)DCFCLK; + (void)ReturnBW; + (void)DPPCLK; + (void)DETBufferSizeC; struct vba_vars_st *v = &mode_lib->vba; double EffectiveLBLatencyHidingY = 0; double EffectiveLBLatencyHidingC = 0; @@ -5212,6 +5229,8 @@ static void CalculateUrgentBurstFactor( double *UrgentBurstFactorChroma, bool *NotEnoughUrgentLatencyHiding) { + (void)DETBufferSizeInKByte; + (void)VRatioC; double LinesInDETLuma = 0; double LinesInDETChroma = 0; unsigned int LinesInCursorBuffer = 0; @@ -5575,6 +5594,8 @@ static void CalculateVMGroupAndRequestTimes( double TimePerVMRequestVBlank[], double TimePerVMRequestFlip[]) { + (void)dpte_row_width_luma_ub; + (void)dpte_row_width_chroma_ub; int num_group_per_lower_vm_stage = 0; int num_req_per_lower_vm_stage = 0; unsigned int k; @@ -5857,6 +5878,7 @@ static void CalculateSwathAndDETConfiguration( bool ViewportSizeSupportPerPlane[], bool *ViewportSizeSupport) { + (void)HRatioChroma; int MaximumSwathHeightY[DC__NUM_DPP__MAX] = { 0 }; int MaximumSwathHeightC[DC__NUM_DPP__MAX] = { 0 }; int MinimumSwathHeightY = 0; @@ -6039,6 +6061,7 @@ static void CalculateSwathWidth( unsigned int swath_width_luma_ub[], unsigned int swath_width_chroma_ub[]) { + (void)BytePerPixY; unsigned int k, j; long surface_width_ub_l; long surface_height_ub_l; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c index 4fb37df54d59..472ac5ee165f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c @@ -50,6 +50,7 @@ static double get_refcyc_per_delivery(struct display_mode_lib *mode_lib, unsigned int delivery_width, unsigned int req_per_swath_ub) { + (void)mode_lib; double refcyc_per_delivery = 0.0; if (vratio <= 1.0) { @@ -804,6 +805,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, unsigned int cur_width, enum cursor_bpp cur_bpp) { + (void)mode_lib; unsigned int cur_src_width = cur_width; unsigned int cur_req_size = 0; unsigned int cur_req_width = 0; @@ -896,6 +898,9 @@ static void dml_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib, const bool ignore_viewport_pos, const bool immediate_flip_support) { + (void)vm_en; + (void)ignore_viewport_pos; + (void)immediate_flip_support; const display_pipe_source_params_st *src = &e2e_pipe_param[pipe_idx].pipe.src; const display_pipe_dest_params_st *dst = &e2e_pipe_param[pipe_idx].pipe.dest; const display_output_params_st *dout = &e2e_pipe_param[pipe_idx].dout; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index ed59c77bc6f6..9833467722b9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -873,6 +873,11 @@ static bool CalculatePrefetchSchedule( double *VUpdateWidthPix, double *VReadyOffsetPix) { + (void)mode_lib; + (void)HostVMMinPageSize; + (void)SwathWidthY; + (void)SwathWidthC; + bool MyError = false; unsigned int DPPCycles, DISPCLKCycles; double DSTTotalPixelsAfterScaler; @@ -1491,6 +1496,10 @@ static void CalculateDCCConfiguration( unsigned int *IndependentBlockLuma, unsigned int *IndependentBlockChroma) { + (void)SurfaceWidthChroma; + (void)SurfaceHeightChroma; + (void)BytePerPixelDETY; + (void)BytePerPixelDETC; int yuv420; int horz_div_l; int horz_div_c; @@ -1823,6 +1832,7 @@ static unsigned int CalculateVMAndRowBytes( int *DPDE0BytesFrame, int *MetaPTEBytesFrame) { + (void)SourcePixelFormat; struct vba_vars_st *v = &mode_lib->vba; unsigned int MPDEBytesFrame; unsigned int DCCMetaSurfaceBytes; @@ -3365,6 +3375,8 @@ double dml31_CalculateWriteBackDISPCLK( unsigned int HTotal, unsigned int WritebackLineBufferSize) { + (void)WritebackPixelFormat; + (void)WritebackVRatio; double DISPCLK_H, DISPCLK_V, DISPCLK_HB; DISPCLK_H = PixelClock * dml_ceil(WritebackHTaps / 8.0, 1) / WritebackHRatio; @@ -3383,6 +3395,8 @@ static double CalculateWriteBackDelay( int WritebackSourceHeight, unsigned int HTotal) { + (void)WritebackPixelFormat; + (void)WritebackHRatio; double CalculateWriteBackDelay; double Line_length; double Output_lines_last_notclamped; @@ -5566,6 +5580,9 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( double *Z8StutterExitWatermark, double *Z8StutterEnterPlusExitWatermark) { + (void)DCFCLK; + (void)ReturnBW; + (void)DETBufferSizeC; struct vba_vars_st *v = &mode_lib->vba; double EffectiveLBLatencyHidingY; double EffectiveLBLatencyHidingC; @@ -5831,6 +5848,7 @@ static void CalculateUrgentBurstFactor( double *UrgentBurstFactorChroma, bool *NotEnoughUrgentLatencyHiding) { + (void)VRatioC; double LinesInDETLuma; double LinesInDETChroma; unsigned int LinesInCursorBuffer; @@ -6213,6 +6231,8 @@ static void CalculateVMGroupAndRequestTimes( double TimePerVMRequestVBlank[], double TimePerVMRequestFlip[]) { + (void)dpte_row_width_luma_ub; + (void)dpte_row_width_chroma_ub; int num_group_per_lower_vm_stage; int num_req_per_lower_vm_stage; int k; @@ -6350,6 +6370,8 @@ static void CalculateStutterEfficiency( int *Z8NumberOfStutterBurstsPerFrame, double *StutterPeriod) { + (void)ConfigReturnBufferSizeInKByte; + struct vba_vars_st *v = &mode_lib->vba; double DETBufferingTimeY; @@ -6649,6 +6671,7 @@ static void CalculateSwathAndDETConfiguration( bool ViewportSizeSupportPerPlane[], bool *ViewportSizeSupport) { + (void)HRatioChroma; int MaximumSwathHeightY[DC__NUM_DPP__MAX]; int MaximumSwathHeightC[DC__NUM_DPP__MAX]; int MinimumSwathHeightY; @@ -6823,6 +6846,7 @@ static void CalculateSwathWidth( int swath_width_luma_ub[], int swath_width_chroma_ub[]) { + (void)BytePerPixY; enum odm_combine_mode MainPlaneODMCombine; int j, k; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c index bfeb01477f0c..dfa1bc31eb0a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c @@ -51,6 +51,7 @@ static double get_refcyc_per_delivery( unsigned int delivery_width, unsigned int req_per_swath_ub) { + (void)mode_lib; double refcyc_per_delivery = 0.0; if (vratio <= 1.0) { @@ -785,6 +786,7 @@ static void calculate_ttu_cursor( unsigned int cur_width, enum cursor_bpp cur_bpp) { + (void)mode_lib; unsigned int cur_src_width = cur_width; unsigned int cur_req_size = 0; unsigned int cur_req_width = 0; @@ -859,6 +861,12 @@ static void dml_rq_dlg_get_dlg_params( const bool ignore_viewport_pos, const bool immediate_flip_support) { + (void)cstate_en; + (void)pstate_en; + (void)vm_en; + (void)ignore_viewport_pos; + (void)immediate_flip_support; + (void)dlg_sys_param; const display_pipe_source_params_st *src = &e2e_pipe_param[pipe_idx].pipe.src; const display_pipe_dest_params_st *dst = &e2e_pipe_param[pipe_idx].pipe.dest; const display_clocks_and_cfg_st *clks = &e2e_pipe_param[pipe_idx].clks_cfg; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c index df9d50b9b57c..ab016c294ba7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c @@ -391,13 +391,9 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c } context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_14_DEFAULT_DET_SIZE; - dc->config.enable_4to1MPC = false; if (pipe_cnt == 1 && pipe->plane_state && pipe->plane_state->rotation == ROTATION_ANGLE_0 && !dc->debug.disable_z9_mpc) { - if (is_dual_plane(pipe->plane_state->format) - && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) { - dc->config.enable_4to1MPC = true; - } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) { + if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) { /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */ context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; pipes[0].pipe.src.unbounded_req_mode = true; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index 9f3938a50240..033fde774337 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -891,6 +891,11 @@ static bool CalculatePrefetchSchedule( double *VUpdateWidthPix, double *VReadyOffsetPix) { + (void)mode_lib; + (void)HostVMMinPageSize; + (void)SwathWidthY; + (void)SwathWidthC; + bool MyError = false; unsigned int DPPCycles, DISPCLKCycles; double DSTTotalPixelsAfterScaler; @@ -1508,6 +1513,10 @@ static void CalculateDCCConfiguration( unsigned int *IndependentBlockLuma, unsigned int *IndependentBlockChroma) { + (void)SurfaceWidthChroma; + (void)SurfaceHeightChroma; + (void)BytePerPixelDETY; + (void)BytePerPixelDETC; int yuv420; int horz_div_l; int horz_div_c; @@ -1840,6 +1849,7 @@ static unsigned int CalculateVMAndRowBytes( int *DPDE0BytesFrame, int *MetaPTEBytesFrame) { + (void)SourcePixelFormat; struct vba_vars_st *v = &mode_lib->vba; unsigned int MPDEBytesFrame; unsigned int DCCMetaSurfaceBytes; @@ -3471,6 +3481,8 @@ double dml314_CalculateWriteBackDISPCLK( unsigned int HTotal, unsigned int WritebackLineBufferSize) { + (void)WritebackPixelFormat; + (void)WritebackVRatio; double DISPCLK_H, DISPCLK_V, DISPCLK_HB; DISPCLK_H = PixelClock * dml_ceil(WritebackHTaps / 8.0, 1) / WritebackHRatio; @@ -3489,6 +3501,8 @@ static double CalculateWriteBackDelay( int WritebackSourceHeight, unsigned int HTotal) { + (void)WritebackPixelFormat; + (void)WritebackHRatio; double CalculateWriteBackDelay; double Line_length; double Output_lines_last_notclamped; @@ -5660,6 +5674,9 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( double *Z8StutterExitWatermark, double *Z8StutterEnterPlusExitWatermark) { + (void)DCFCLK; + (void)ReturnBW; + (void)DETBufferSizeC; struct vba_vars_st *v = &mode_lib->vba; double EffectiveLBLatencyHidingY; double EffectiveLBLatencyHidingC; @@ -5925,6 +5942,7 @@ static void CalculateUrgentBurstFactor( double *UrgentBurstFactorChroma, bool *NotEnoughUrgentLatencyHiding) { + (void)VRatioC; double LinesInDETLuma; double LinesInDETChroma; unsigned int LinesInCursorBuffer; @@ -6308,6 +6326,8 @@ static void CalculateVMGroupAndRequestTimes( double TimePerVMRequestVBlank[], double TimePerVMRequestFlip[]) { + (void)dpte_row_width_luma_ub; + (void)dpte_row_width_chroma_ub; int num_group_per_lower_vm_stage; int num_req_per_lower_vm_stage; int k; @@ -6445,6 +6465,8 @@ static void CalculateStutterEfficiency( int *Z8NumberOfStutterBurstsPerFrame, double *StutterPeriod) { + (void)ConfigReturnBufferSizeInKByte; + struct vba_vars_st *v = &mode_lib->vba; double DETBufferingTimeY; @@ -6743,6 +6765,7 @@ static void CalculateSwathAndDETConfiguration( bool ViewportSizeSupportPerPlane[], bool *ViewportSizeSupport) { + (void)HRatioChroma; int MaximumSwathHeightY[DC__NUM_DPP__MAX]; int MaximumSwathHeightC[DC__NUM_DPP__MAX]; int MinimumSwathHeightY; @@ -6914,6 +6937,7 @@ static void CalculateSwathWidth( int swath_width_luma_ub[], int swath_width_chroma_ub[]) { + (void)BytePerPixY; enum odm_combine_mode MainPlaneODMCombine; int j, k; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c index 04df263ff65e..40a916c2a9c6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c @@ -139,6 +139,7 @@ static double get_refcyc_per_delivery( unsigned int delivery_width, unsigned int req_per_swath_ub) { + (void)mode_lib; double refcyc_per_delivery = 0.0; if (vratio <= 1.0) { @@ -872,6 +873,7 @@ static void calculate_ttu_cursor( unsigned int cur_width, enum cursor_bpp cur_bpp) { + (void)mode_lib; unsigned int cur_src_width = cur_width; unsigned int cur_req_size = 0; unsigned int cur_req_width = 0; @@ -944,6 +946,12 @@ static void dml_rq_dlg_get_dlg_params( const bool ignore_viewport_pos, const bool immediate_flip_support) { + (void)cstate_en; + (void)pstate_en; + (void)vm_en; + (void)ignore_viewport_pos; + (void)immediate_flip_support; + (void)dlg_sys_param; const display_pipe_source_params_st *src = &e2e_pipe_param[pipe_idx].pipe.src; const display_pipe_dest_params_st *dst = &e2e_pipe_param[pipe_idx].pipe.dest; const display_clocks_and_cfg_st *clks = &e2e_pipe_param[pipe_idx].clks_cfg; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 8a0f128722b0..e29497204df7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -3488,6 +3488,7 @@ bool dcn32_allow_subvp_high_refresh_rate(struct dc *dc, struct dc_state *context */ double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *context) { + (void)dc; double max_vratio_pre = __DML_MAX_BW_RATIO_PRE__; // Default value is 4 int i; @@ -3593,6 +3594,7 @@ bool dcn32_find_vactive_pipe(struct dc *dc, const struct dc_state *context, stru void dcn32_set_clock_limits(const struct _vcs_dpi_soc_bounding_box_st *soc_bb) { + (void)soc_bb; dc_assert_fp_enabled(); dcn3_2_soc.clock_limits[0].dcfclk_mhz = 1200.0; } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c index 0748ef36a16a..5e72966a8daf 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c @@ -457,10 +457,11 @@ void dml32_CalculateSwathAndDETConfiguration( bool ViewportSizeSupportPerSurface[], bool *ViewportSizeSupport) { + (void)HRatioChroma; unsigned int MaximumSwathHeightY[DC__NUM_DPP__MAX]; unsigned int MaximumSwathHeightC[DC__NUM_DPP__MAX]; - unsigned int RoundedUpMaxSwathSizeBytesY[DC__NUM_DPP__MAX]; - unsigned int RoundedUpMaxSwathSizeBytesC[DC__NUM_DPP__MAX]; + unsigned int RoundedUpMaxSwathSizeBytesY[DC__NUM_DPP__MAX] = { 0 }; + unsigned int RoundedUpMaxSwathSizeBytesC[DC__NUM_DPP__MAX] = { 0 }; unsigned int RoundedUpSwathSizeBytesY; unsigned int RoundedUpSwathSizeBytesC; double SwathWidthdoubleDPP[DC__NUM_DPP__MAX]; @@ -716,6 +717,7 @@ void dml32_CalculateSwathWidth( unsigned int swath_width_luma_ub[], // per-pipe unsigned int swath_width_chroma_ub[]) // per-pipe { + (void)BytePerPixY; unsigned int k, j; enum odm_combine_mode MainSurfaceODMMode; @@ -2304,6 +2306,7 @@ unsigned int dml32_CalculateVMAndRowBytes( unsigned int *DPDE0BytesFrame, unsigned int *MetaPTEBytesFrame) { + (void)SourcePixelFormat; unsigned int MPDEBytesFrame; unsigned int DCCMetaSurfaceBytes; unsigned int ExtraDPDEBytesFrame; @@ -2745,6 +2748,7 @@ void dml32_CalculateUrgentBurstFactor( double *UrgentBurstFactorChroma, bool *NotEnoughUrgentLatencyHiding) { + (void)VRatioC; double LinesInDETLuma; double LinesInDETChroma; unsigned int LinesInCursorBuffer; @@ -2900,6 +2904,8 @@ double dml32_CalculateWriteBackDelay( unsigned int WritebackSourceHeight, unsigned int HTotal) { + (void)WritebackPixelFormat; + (void)WritebackHRatio; double CalculateWriteBackDelay; double Line_length; double Output_lines_last_notclamped; @@ -2977,6 +2983,9 @@ void dml32_UseMinimumDCFCLK( /* Output */ double DCFCLKState[][2]) { + (void)MaxAveragePercentOfIdealSDPPortBWDisplayCanUseInNormalSystemOperation; + (void)ReadBandwidthLuma; + (void)ReadBandwidthChroma; unsigned int i, j, k; unsigned int dummy1; double dummy2, dummy3; @@ -2988,7 +2997,7 @@ void dml32_UseMinimumDCFCLK( for (j = 0; j <= 1; ++j) { double PixelDCFCLKCyclesRequiredInPrefetch[DC__NUM_DPP__MAX]; double PrefetchPixelLinesTime[DC__NUM_DPP__MAX]; - double DCFCLKRequiredForPeakBandwidthPerSurface[DC__NUM_DPP__MAX]; + double DCFCLKRequiredForPeakBandwidthPerSurface[DC__NUM_DPP__MAX] = { 0 }; double DynamicMetadataVMExtraLatency[DC__NUM_DPP__MAX]; double MinimumTWait = 0.0; double DPTEBandwidth; @@ -3447,6 +3456,8 @@ bool dml32_CalculatePrefetchSchedule( double *VUpdateWidthPix, double *VReadyOffsetPix) { + (void)SwathWidthY; + (void)SwathWidthC; double DPPCLKDelaySubtotalPlusCNVCFormater = v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater; bool MyError = false; unsigned int DPPCycles, DISPCLKCycles; @@ -4145,6 +4156,7 @@ void dml32_CalculateFlipSchedule( double *final_flip_bw, bool *ImmediateFlipSupportedForPipe) { + (void)HostVMMinPageSize; double min_row_time = 0.0; unsigned int HostVMDynamicLevelsTrips; double TimeForFetchingMetaPTEImmediateFlip; @@ -4287,6 +4299,8 @@ void dml32_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport( bool *USRRetrainingSupport, double ActiveDRAMClockChangeLatencyMargin[]) { + (void)DCFCLK; + (void)ReturnBW; unsigned int i, j, k; unsigned int SurfaceWithMinActiveFCLKChangeMargin = 0; unsigned int DRAMClockChangeSupportNumber = 0; @@ -4655,6 +4669,8 @@ double dml32_CalculateWriteBackDISPCLK( unsigned int WritebackLineBufferSize, double DISPCLKDPPCLKVCOSpeed) { + (void)WritebackPixelFormat; + (void)WritebackVRatio; double DISPCLK_H, DISPCLK_V, DISPCLK_HB; DISPCLK_H = PixelClock * dml_ceil(WritebackHTaps / 8.0, 1) / WritebackHRatio; @@ -5166,6 +5182,8 @@ void dml32_CalculateVMGroupAndRequestTimes( double TimePerVMRequestVBlank[], double TimePerVMRequestFlip[]) { + (void)dpte_row_width_luma_ub; + (void)dpte_row_width_chroma_ub; unsigned int k; unsigned int num_group_per_lower_vm_stage; unsigned int num_req_per_lower_vm_stage; @@ -5321,6 +5339,11 @@ void dml32_CalculateDCCConfiguration( unsigned int *IndependentBlockLuma, unsigned int *IndependentBlockChroma) { + (void)SurfaceWidthChroma; + (void)SurfaceHeightChroma; + (void)TilingFormat; + (void)BytePerPixelDETY; + (void)BytePerPixelDETC; typedef enum { REQ_256Bytes, REQ_128BytesNonContiguous, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c index 8a177d5ae213..7f40048dd67d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c @@ -202,6 +202,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_5_soc = { void dcn35_build_wm_range_table_fpu(struct clk_mgr *clk_mgr) { + (void)clk_mgr; //TODO } @@ -528,14 +529,9 @@ int dcn35_populate_dml_pipes_from_context_fpu(struct dc *dc, } context->bw_ctx.dml.ip.det_buffer_size_kbytes = 384;/*per guide*/ - dc->config.enable_4to1MPC = false; if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) { - if (is_dual_plane(pipe->plane_state->format) - && pipe->plane_state->src_rect.width <= 1920 && - pipe->plane_state->src_rect.height <= 1080) { - dc->config.enable_4to1MPC = true; - } else if (!is_dual_plane(pipe->plane_state->format) && + if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) { /* * Limit to 5k max to avoid forced pipe split when there diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c index 77023b619f1e..73c2aee57f28 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c @@ -561,14 +561,9 @@ int dcn351_populate_dml_pipes_from_context_fpu(struct dc *dc, } context->bw_ctx.dml.ip.det_buffer_size_kbytes = 384;/*per guide*/ - dc->config.enable_4to1MPC = false; if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) { - if (is_dual_plane(pipe->plane_state->format) - && pipe->plane_state->src_rect.width <= 1920 && - pipe->plane_state->src_rect.height <= 1080) { - dc->config.enable_4to1MPC = true; - } else if (!is_dual_plane(pipe->plane_state->format) && + if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) { /* * Limit to 5k max to avoid forced pipe split when there diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index da0cfbb071e6..684779ee54a3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c @@ -162,6 +162,7 @@ void dml_log_pipe_params( display_e2e_pipe_params_st *pipes, int pipe_cnt) { + (void)mode_lib; display_pipe_source_params_st *pipe_src; display_pipe_dest_params_st *pipe_dest; scaler_ratio_depth_st *scale_ratio_depth; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c b/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c index 12ff65b6a7e5..3f27293a41cb 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c @@ -49,6 +49,8 @@ void print__rq_params_st(struct display_mode_lib *mode_lib, const struct _vcs_dp void print__data_rq_sizing_params_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi_display_data_rq_sizing_params_st *rq_sizing) { + (void)mode_lib; + (void)rq_sizing; dml_print("DML_RQ_DLG_CALC: =====================================\n"); dml_print("DML_RQ_DLG_CALC: DISPLAY_DATA_RQ_SIZING_PARAM_ST\n"); dml_print("DML_RQ_DLG_CALC: chunk_bytes = %0d\n", rq_sizing->chunk_bytes); @@ -64,6 +66,8 @@ void print__data_rq_sizing_params_st(struct display_mode_lib *mode_lib, const st void print__data_rq_dlg_params_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi_display_data_rq_dlg_params_st *rq_dlg_param) { + (void)mode_lib; + (void)rq_dlg_param; dml_print("DML_RQ_DLG_CALC: =====================================\n"); dml_print("DML_RQ_DLG_CALC: DISPLAY_DATA_RQ_DLG_PARAM_ST\n"); dml_print( @@ -107,6 +111,8 @@ void print__data_rq_dlg_params_st(struct display_mode_lib *mode_lib, const struc void print__data_rq_misc_params_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi_display_data_rq_misc_params_st *rq_misc_param) { + (void)mode_lib; + (void)rq_misc_param; dml_print("DML_RQ_DLG_CALC: =====================================\n"); dml_print("DML_RQ_DLG_CALC: DISPLAY_DATA_RQ_MISC_PARAM_ST\n"); dml_print( @@ -124,6 +130,8 @@ void print__data_rq_misc_params_st(struct display_mode_lib *mode_lib, const stru void print__dlg_sys_params_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi_display_dlg_sys_params_st *dlg_sys_param) { + (void)dlg_sys_param; + (void)mode_lib; dml_print("DML_RQ_DLG_CALC: =====================================\n"); dml_print("DML_RQ_DLG_CALC: DISPLAY_RQ_DLG_PARAM_ST\n"); dml_print("DML_RQ_DLG_CALC: t_mclk_wm_us = %3.2f\n", dlg_sys_param->t_mclk_wm_us); @@ -144,6 +152,8 @@ void print__dlg_sys_params_st(struct display_mode_lib *mode_lib, const struct _v void print__data_rq_regs_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi_display_data_rq_regs_st *rq_regs) { + (void)mode_lib; + (void)rq_regs; dml_print("DML_RQ_DLG_CALC: =====================================\n"); dml_print("DML_RQ_DLG_CALC: DISPLAY_DATA_RQ_REGS_ST\n"); dml_print("DML_RQ_DLG_CALC: chunk_size = 0x%0x\n", rq_regs->chunk_size); @@ -179,6 +189,8 @@ void print__rq_regs_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi_ void print__dlg_regs_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi_display_dlg_regs_st *dlg_regs) { + (void)dlg_regs; + (void)mode_lib; dml_print("DML_RQ_DLG_CALC: =====================================\n"); dml_print("DML_RQ_DLG_CALC: DISPLAY_DLG_REGS_ST\n"); dml_print( @@ -316,6 +328,8 @@ void print__dlg_regs_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi void print__ttu_regs_st(struct display_mode_lib *mode_lib, const struct _vcs_dpi_display_ttu_regs_st *ttu_regs) { + (void)mode_lib; + (void)ttu_regs; dml_print("DML_RQ_DLG_CALC: =====================================\n"); dml_print("DML_RQ_DLG_CALC: DISPLAY_TTU_REGS_ST\n"); dml_print( diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c index 88dc2b97e7bf..cf194bcba455 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c @@ -104,6 +104,7 @@ static double get_refcyc_per_delivery( unsigned int delivery_width, unsigned int req_per_swath_ub) { + (void)mode_lib; double refcyc_per_delivery = 0.0; if (vratio <= 1.0) { @@ -133,6 +134,7 @@ static double get_vratio_pre( double vinit, double l_sw) { + (void)mode_lib; double prefill = dml_floor(vinit, 1); double vratio_pre = 1.0; @@ -174,6 +176,7 @@ static void get_swath_need( unsigned int swath_height, double vinit) { + (void)mode_lib; double prefill = dml_floor(vinit, 1); unsigned int max_partial_sw_int; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile index 70d9f2cd0b60..2625943d7f7e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile @@ -53,25 +53,29 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/src/inc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/inc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/ -CFLAGS_$(AMDDALPATH)/dc/dml2_0/display_mode_core.o := $(dml2_ccflags) $(frame_warn_flag) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/display_mode_util.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper_fpu.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_utils.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_policy.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_translation_helper.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_mall_phantom.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml_display_rq_dlg_calc.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_dc_resource_mgmt.o := $(dml2_ccflags) +# Add FPU flags to all dml2 files by default, remove NO_FPU flags. +# FPU flags step 1: Find all .c files in dal/dc/dml2_0 and it's subfolders +DML2_ABS_PATH := $(FULL_AMD_DISPLAY_PATH)/dc/dml2_0 +DML2_C_FILES := $(shell find $(DML2_ABS_PATH) -name '*.c' -type f) + +# FPU flags step 2: Convert to .o and make paths relative to $(AMDDALPATH)/dc/dml2_0/ +DML2_RELATIVE_O_FILES := $(patsubst $(DML2_ABS_PATH)/%,dc/dml2_0/%,$(patsubst %.c,%.o,$(DML2_C_FILES))) +# FPU flags step 3: Apply FPU flags to all .o files from dal/dc/dml2_0 and it's subfolders +$(foreach obj,$(DML2_RELATIVE_O_FILES),$(eval CFLAGS_$(AMDDALPATH)/$(obj) := $(dml2_ccflags))) +$(foreach obj,$(DML2_RELATIVE_O_FILES),$(eval CFLAGS_REMOVE_$(AMDDALPATH)/$(obj) := $(dml2_rcflags))) + +# FPU flags step 4: Replace CFLAGS per file for files with additional flags beyond dml2_ccflags and dml2_rcflags +CFLAGS_$(AMDDALPATH)/dc/dml2_0/display_mode_core.o := $(dml2_ccflags) $(frame_warn_flag) +CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_ccflags) $(frame_warn_flag) +CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_ccflags) $(frame_warn_flag) +CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper.o := $(dml2_rcflags) +CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_wrapper.o := $(dml2_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/display_mode_core.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/display_mode_util.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper_fpu.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_utils.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_policy.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_translation_helper.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_mall_phantom.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml_display_rq_dlg_calc.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_dc_resource_mgmt.o := $(dml2_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper.o := $(dml2_ccflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_wrapper.o := $(dml2_ccflags) DML2 = display_mode_core.o display_mode_util.o dml2_wrapper_fpu.o dml2_wrapper.o \ dml2_utils.o dml2_policy.o dml2_translation_helper.o dml2_dc_resource_mgmt.o dml2_mall_phantom.o \ @@ -81,41 +85,6 @@ AMD_DAL_DML2 = $(addprefix $(AMDDALPATH)/dc/dml2_0/,$(DML2)) AMD_DISPLAY_FILES += $(AMD_DAL_DML2) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_ccflags) $(frame_warn_flag) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_ccflags) $(frame_warn_flag) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_interfaces.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn3.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_translation_helper.o := $(dml2_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_utils.o := $(dml2_ccflags) - -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_interfaces.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn3.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_translation_helper.o := $(dml2_rcflags) -CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_utils.o := $(dml2_rcflags) DML21 := src/dml2_top/dml2_top_interfaces.o DML21 += src/dml2_top/dml2_top_soc15.o @@ -134,6 +103,7 @@ DML21 += src/dml2_pmo/dml2_pmo_dcn4_fams2.o DML21 += src/dml2_standalone_libraries/lib_float_math.o DML21 += dml21_translation_helper.o DML21 += dml21_wrapper.o +DML21 += dml21_wrapper_fpu.o DML21 += dml21_utils.o AMD_DAL_DML21 = $(addprefix $(AMDDALPATH)/dc/dml2_0/dml21/,$(DML21)) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c index 847fab508750..2f0e0048bea8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c @@ -90,7 +90,8 @@ static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf struct pipe_ctx *pipe_ctx, struct dml2_context *dml_ctx) { - unsigned int hblank_start, vblank_start, min_hardware_refresh_in_uhz; + unsigned int hblank_start, vblank_start; + uint64_t min_hardware_refresh_in_uhz; uint32_t pix_clk_100hz; timing->h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right + pipe_ctx->dsc_padding_params.dsc_hactive_padding; @@ -105,7 +106,7 @@ static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf timing->h_total = stream->timing.h_total + pipe_ctx->dsc_padding_params.dsc_htotal_padding; timing->v_total = stream->timing.v_total; timing->h_sync_width = stream->timing.h_sync_width; - timing->interlaced = stream->timing.flags.INTERLACE; + timing->interlaced = (stream->timing.flags.INTERLACE != 0); hblank_start = stream->timing.h_total - stream->timing.h_front_porch; @@ -137,7 +138,11 @@ static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf (timing->h_total * (long long)calc_max_hardware_v_total(stream))); } - timing->drr_config.min_refresh_uhz = max(stream->timing.min_refresh_in_uhz, min_hardware_refresh_in_uhz); + { + uint64_t min_refresh = max((uint64_t)stream->timing.min_refresh_in_uhz, min_hardware_refresh_in_uhz); + ASSERT(min_refresh <= ULONG_MAX); + timing->drr_config.min_refresh_uhz = (unsigned long)min_refresh; + } if (dml_ctx->config.callbacks.get_max_flickerless_instant_vtotal_increase && stream->ctx->dc->config.enable_fpo_flicker_detection == 1) @@ -601,27 +606,33 @@ static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dm plane->composition.viewport.stationary = false; - if (plane_state->cm.flags.bits.lut3d_dma_enable) { + if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) { plane->tdlut.setup_for_tdlut = true; - switch (plane_state->cm.lut3d_dma.swizzle) { - case CM_LUT_3D_SWIZZLE_LINEAR_RGB: - case CM_LUT_3D_SWIZZLE_LINEAR_BGR: + switch (plane_state->mcm_luts.lut3d_data.gpu_mem_params.layout) { + case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB: + case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR: plane->tdlut.tdlut_addressing_mode = dml2_tdlut_sw_linear; break; - case CM_LUT_1D_PACKED_LINEAR: - default: + case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR: plane->tdlut.tdlut_addressing_mode = dml2_tdlut_simple_linear; break; } - switch (plane_state->cm.lut3d_dma.size) { - case CM_LUT_SIZE_333333: + switch (plane_state->mcm_luts.lut3d_data.gpu_mem_params.size) { + case DC_CM2_GPU_MEM_SIZE_171717: + plane->tdlut.tdlut_width_mode = dml2_tdlut_width_17_cube; + break; + case DC_CM2_GPU_MEM_SIZE_333333: plane->tdlut.tdlut_width_mode = dml2_tdlut_width_33_cube; break; - case CM_LUT_SIZE_171717: + // handling when use case and HW support available + case DC_CM2_GPU_MEM_SIZE_454545: + case DC_CM2_GPU_MEM_SIZE_656565: + break; + case DC_CM2_GPU_MEM_SIZE_TRANSFORMED: default: - plane->tdlut.tdlut_width_mode = dml2_tdlut_width_17_cube; + //plane->tdlut.tdlut_width_mode = dml2_tdlut_width_flatten; // dml2_tdlut_width_flatten undefined break; } } @@ -691,7 +702,7 @@ unsigned int map_plane_to_dml21_display_cfg(const struct dml2_context *dml_ctx, if (!dml21_wrapper_get_plane_id(context, stream_id, plane, &plane_id)) { ASSERT(false); - return -1; + return UINT_MAX; } for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c index ab7ec24268be..4724b08c77e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c @@ -420,8 +420,12 @@ static unsigned int dml21_build_fams2_stream_programming_v2(const struct dc *dc, type = static_base_state->stream_v1.base.type; /* get information from context */ - static_base_state->stream_v1.base.num_planes = context->stream_status[dc_stream_idx].plane_count; - static_base_state->stream_v1.base.otg_inst = context->stream_status[dc_stream_idx].primary_otg_inst; + ASSERT(context->stream_status[dc_stream_idx].plane_count >= 0 && + context->stream_status[dc_stream_idx].plane_count <= 0xFF); + ASSERT(context->stream_status[dc_stream_idx].primary_otg_inst >= 0 && + context->stream_status[dc_stream_idx].primary_otg_inst <= 0xFF); + static_base_state->stream_v1.base.num_planes = (uint8_t)context->stream_status[dc_stream_idx].plane_count; + static_base_state->stream_v1.base.otg_inst = (uint8_t)context->stream_status[dc_stream_idx].primary_otg_inst; /* populate pipe masks for planes */ for (dc_plane_idx = 0; dc_plane_idx < context->stream_status[dc_stream_idx].plane_count; dc_plane_idx++) { @@ -458,7 +462,9 @@ static unsigned int dml21_build_fams2_stream_programming_v2(const struct dc *dc, switch (dc->debug.fams_version.minor) { case 1: default: - static_sub_state->stream_v1.sub_state.subvp.phantom_otg_inst = phantom_status->primary_otg_inst; + ASSERT(phantom_status->primary_otg_inst >= 0 && + phantom_status->primary_otg_inst <= 0xFF); + static_sub_state->stream_v1.sub_state.subvp.phantom_otg_inst = (uint8_t)phantom_status->primary_otg_inst; /* populate pipe masks for phantom planes */ for (dc_plane_idx = 0; dc_plane_idx < phantom_status->plane_count; dc_plane_idx++) { @@ -516,7 +522,8 @@ void dml21_build_fams2_programming(const struct dc *dc, context->bw_ctx.bw.dcn.fams2_global_config.num_streams = num_fams2_streams; } - context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable; + context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = + (context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable != 0); } bool dml21_is_plane1_enabled(enum dml2_source_format_class source_format) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c index 2623e917ec28..7398f8b69adb 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c @@ -9,6 +9,10 @@ #include "dml21_utils.h" #include "dml21_translation_helper.h" #include "dml2_dc_resource_mgmt.h" +#include "dml2_wrapper.h" +#include "dml2_wrapper_fpu.h" +#include "dml21_wrapper.h" +#include "dml21_wrapper_fpu.h" #include "dc_fpu.h" #if !defined(DC_RUN_WITH_PREEMPTION_ENABLED) @@ -34,50 +38,18 @@ static bool dml21_allocate_memory(struct dml2_context **dml_ctx) (*dml_ctx)->v21.mode_programming.display_config = (*dml_ctx)->v21.mode_support.display_config; DC_RUN_WITH_PREEMPTION_ENABLED((*dml_ctx)->v21.mode_programming.programming = vzalloc(sizeof(struct dml2_display_cfg_programming))); + if (!((*dml_ctx)->v21.mode_programming.programming)) return false; return true; } -static void dml21_populate_configuration_options(const struct dc *in_dc, - struct dml2_context *dml_ctx, - const struct dml2_configuration_options *config) -{ - dml_ctx->config = *config; - - /* UCLK P-State options */ - if (in_dc->debug.dml21_force_pstate_method) { - dml_ctx->config.pmo.force_pstate_method_enable = true; - for (int i = 0; i < MAX_PIPES; i++) - dml_ctx->config.pmo.force_pstate_method_values[i] = in_dc->debug.dml21_force_pstate_method_values[i]; - } else { - dml_ctx->config.pmo.force_pstate_method_enable = false; - } -} - -static void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config) -{ - - dml_ctx->architecture = dml2_architecture_21; - - dml21_populate_configuration_options(in_dc, dml_ctx, config); - - DC_FP_START(); - - dml21_populate_dml_init_params(&dml_ctx->v21.dml_init, &dml_ctx->config, in_dc); - - dml2_initialize_instance(&dml_ctx->v21.dml_init); - - DC_FP_END(); -} - bool dml21_create(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config) { /* Allocate memory for initializing DML21 instance */ - if (!dml21_allocate_memory(dml_ctx)) { + if (!dml21_allocate_memory(dml_ctx)) return false; - } dml21_init(in_dc, *dml_ctx, config); @@ -90,337 +62,6 @@ void dml21_destroy(struct dml2_context *dml2) vfree(dml2->v21.mode_programming.programming); } -static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state, - struct dml2_context *in_ctx, unsigned int pipe_cnt) -{ - unsigned int dml_prog_idx = 0, dc_pipe_index = 0, num_dpps_required = 0; - struct dml2_per_plane_programming *pln_prog = NULL; - struct dml2_per_stream_programming *stream_prog = NULL; - struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__]; - struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}; - int num_pipes; - unsigned int dml_phantom_prog_idx; - - context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; - - /* copy global DCHUBBUB arbiter registers */ - memcpy(&context->bw_ctx.bw.dcn.arb_regs, &in_ctx->v21.mode_programming.programming->global_regs.arb_regs, sizeof(struct dml2_display_arb_regs)); - - /* legacy only */ - context->bw_ctx.bw.dcn.compbuf_size_kb = (int)in_ctx->v21.mode_programming.programming->global_regs.arb_regs.compbuf_size * 64; - - context->bw_ctx.bw.dcn.mall_ss_size_bytes = 0; - context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0; - context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0; - - /* phantom's start after main planes */ - dml_phantom_prog_idx = in_ctx->v21.mode_programming.programming->display_config.num_planes; - - for (dml_prog_idx = 0; dml_prog_idx < DML2_MAX_PLANES; dml_prog_idx++) { - pln_prog = &in_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; - - if (!pln_prog->plane_descriptor) - continue; - - stream_prog = &in_ctx->v21.mode_programming.programming->stream_programming[pln_prog->plane_descriptor->stream_index]; - num_dpps_required = pln_prog->num_dpps_required; - - if (num_dpps_required == 0) { - continue; - } - num_pipes = dml21_find_dc_pipes_for_plane(dc, context, in_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); - - if (num_pipes <= 0) - continue; - - /* program each pipe */ - for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { - dml21_program_dc_pipe(in_ctx, context, dc_main_pipes[dc_pipe_index], pln_prog, stream_prog); - - if (pln_prog->phantom_plane.valid && dc_phantom_pipes[dc_pipe_index]) { - dml21_program_dc_pipe(in_ctx, context, dc_phantom_pipes[dc_pipe_index], pln_prog, stream_prog); - } - } - - /* copy per plane mcache allocation */ - memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx], &pln_prog->mcache_allocation, sizeof(struct dml2_mcache_surface_allocation)); - if (pln_prog->phantom_plane.valid) { - memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx], - &pln_prog->phantom_plane.mcache_allocation, - sizeof(struct dml2_mcache_surface_allocation)); - - dml_phantom_prog_idx++; - } - } - - /* assign global clocks */ - context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz; - context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz; - if (in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values > 1) { - context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = - in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values] * 1000; - } else { - context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[0] * 1000; - } - - if (in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values > 1) { - context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = - in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values] * 1000; - } else { - context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[0] * 1000; - } - - /* get global mall allocation */ - if (dc->res_pool->funcs->calculate_mall_ways_from_bytes) { - context->bw_ctx.bw.dcn.clk.num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, context->bw_ctx.bw.dcn.mall_subvp_size_bytes); - } else { - context->bw_ctx.bw.dcn.clk.num_ways = 0; - } -} - -static void dml21_prepare_mcache_params(struct dml2_context *dml_ctx, struct dc_state *context, struct dc_mcache_params *mcache_params) -{ - int dc_plane_idx = 0; - int dml_prog_idx, stream_idx, plane_idx; - struct dml2_per_plane_programming *pln_prog = NULL; - - for (stream_idx = 0; stream_idx < context->stream_count; stream_idx++) { - for (plane_idx = 0; plane_idx < context->stream_status[stream_idx].plane_count; plane_idx++) { - dml_prog_idx = map_plane_to_dml21_display_cfg(dml_ctx, context->streams[stream_idx]->stream_id, context->stream_status[stream_idx].plane_states[plane_idx], context); - if (dml_prog_idx == INVALID) { - continue; - } - pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; - mcache_params[dc_plane_idx].valid = pln_prog->mcache_allocation.valid; - mcache_params[dc_plane_idx].num_mcaches_plane0 = pln_prog->mcache_allocation.num_mcaches_plane0; - mcache_params[dc_plane_idx].num_mcaches_plane1 = pln_prog->mcache_allocation.num_mcaches_plane1; - mcache_params[dc_plane_idx].requires_dedicated_mall_mcache = pln_prog->mcache_allocation.requires_dedicated_mall_mcache; - mcache_params[dc_plane_idx].last_slice_sharing.plane0_plane1 = pln_prog->mcache_allocation.last_slice_sharing.plane0_plane1; - memcpy(mcache_params[dc_plane_idx].mcache_x_offsets_plane0, - pln_prog->mcache_allocation.mcache_x_offsets_plane0, - sizeof(int) * (DML2_MAX_MCACHES + 1)); - memcpy(mcache_params[dc_plane_idx].mcache_x_offsets_plane1, - pln_prog->mcache_allocation.mcache_x_offsets_plane1, - sizeof(int) * (DML2_MAX_MCACHES + 1)); - dc_plane_idx++; - } - } -} - -static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) -{ - bool result = false; - struct dml2_build_mode_programming_in_out *mode_programming = &dml_ctx->v21.mode_programming; - struct dc_mcache_params mcache_params[MAX_PLANES] = {0}; - - memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg)); - memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping)); - memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params, 0, sizeof(struct dml2_core_mode_programming_in_out)); - - if (!context) - return true; - - if (context->stream_count == 0) { - dml21_init_min_clocks_for_dc_state(dml_ctx, context); - dml21_build_fams2_programming(in_dc, context, dml_ctx); - return true; - } - - /* scrub phantom's from current dc_state */ - dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context); - dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context); - - /* Populate stream, plane mappings and other fields in display config. */ - result = dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx); - if (!result) - return false; - - DC_FP_START(); - result = dml2_build_mode_programming(mode_programming); - DC_FP_END(); - if (!result) - return false; - - /* Check and map HW resources */ - if (result && !dml_ctx->config.skip_hw_state_mapping) { - dml21_map_hw_resources(dml_ctx); - dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, in_dc->current_state); - /* if subvp phantoms are present, expand them into dc context */ - dml21_handle_phantom_streams_planes(in_dc, context, dml_ctx); - - if (in_dc->res_pool->funcs->program_mcache_pipe_config) { - //Prepare mcache params for each plane based on mcache output from DML - dml21_prepare_mcache_params(dml_ctx, context, mcache_params); - - //populate mcache regs to each pipe - dml_ctx->config.callbacks.allocate_mcache(context, mcache_params); - } - } - - /* Copy DML CLK, WM and REG outputs to bandwidth context */ - if (result && !dml_ctx->config.skip_hw_state_mapping) { - dml21_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml_ctx, in_dc->res_pool->pipe_count); - dml21_copy_clocks_to_dc_state(dml_ctx, context); - dml21_extract_watermark_sets(in_dc, &context->bw_ctx.bw.dcn.watermarks, dml_ctx); - dml21_build_fams2_programming(in_dc, context, dml_ctx); - } - - return true; -} - -static bool dml21_check_mode_support(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) -{ - bool is_supported = false; - struct dml2_initialize_instance_in_out *dml_init = &dml_ctx->v21.dml_init; - struct dml2_check_mode_supported_in_out *mode_support = &dml_ctx->v21.mode_support; - - memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg)); - memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping)); - memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.check_mode_supported_locals.mode_support_params, 0, sizeof(struct dml2_core_mode_support_in_out)); - - if (!context || context->stream_count == 0) - return true; - - /* Scrub phantom's from current dc_state */ - dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context); - dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context); - - mode_support->dml2_instance = dml_init->dml2_instance; - dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx); - dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params.programming = dml_ctx->v21.mode_programming.programming; - DC_FP_START(); - is_supported = dml2_check_mode_supported(mode_support); - DC_FP_END(); - if (!is_supported) - return false; - - return true; -} - -bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx, - enum dc_validate_mode validate_mode) -{ - bool out = false; - - /* Use dml21_check_mode_support for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX path */ - if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING) - out = dml21_check_mode_support(in_dc, context, dml_ctx); - else - out = dml21_mode_check_and_programming(in_dc, context, dml_ctx); - - return out; -} - -void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) -{ - unsigned int dml_prog_idx, dml_phantom_prog_idx, dc_pipe_index; - int num_pipes; - struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__]; - struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}; - - struct dml2_per_plane_programming *pln_prog = NULL; - struct dml2_plane_mcache_configuration_descriptor *mcache_config = NULL; - struct prepare_mcache_programming_locals *l = &dml_ctx->v21.scratch.prepare_mcache_locals; - - if (context->stream_count == 0) { - return; - } - - memset(&l->build_mcache_programming_params, 0, sizeof(struct dml2_build_mcache_programming_in_out)); - l->build_mcache_programming_params.dml2_instance = dml_ctx->v21.dml_init.dml2_instance; - - /* phantom's start after main planes */ - dml_phantom_prog_idx = dml_ctx->v21.mode_programming.programming->display_config.num_planes; - - /* Build mcache programming parameters per plane per pipe */ - for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) { - pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; - - mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_prog_idx]; - memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor)); - mcache_config->plane_descriptor = pln_prog->plane_descriptor; - mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx]; - mcache_config->num_pipes = pln_prog->num_dpps_required; - l->build_mcache_programming_params.num_configurations++; - - if (pln_prog->num_dpps_required == 0) { - continue; - } - - num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); - if (num_pipes <= 0 || dc_main_pipes[0]->stream == NULL || - dc_main_pipes[0]->plane_state == NULL) - continue; - - /* get config for each pipe */ - for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { - ASSERT(dc_main_pipes[dc_pipe_index]); - dml21_get_pipe_mcache_config(context, dc_main_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]); - } - - /* get config for each phantom pipe */ - if (pln_prog->phantom_plane.valid && - dc_phantom_pipes[0] && - dc_main_pipes[0]->stream && - dc_phantom_pipes[0]->plane_state) { - mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_phantom_prog_idx]; - memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor)); - mcache_config->plane_descriptor = pln_prog->plane_descriptor; - mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx]; - mcache_config->num_pipes = pln_prog->num_dpps_required; - l->build_mcache_programming_params.num_configurations++; - - for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { - ASSERT(dc_phantom_pipes[dc_pipe_index]); - dml21_get_pipe_mcache_config(context, dc_phantom_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]); - } - - /* increment phantom index */ - dml_phantom_prog_idx++; - } - } - - /* Call to generate mcache programming per plane per pipe for the given display configuration */ - dml2_build_mcache_programming(&l->build_mcache_programming_params); - - /* get per plane per pipe mcache programming */ - for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) { - pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; - - num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); - if (num_pipes <= 0 || dc_main_pipes[0]->stream == NULL || - dc_main_pipes[0]->plane_state == NULL) - continue; - - /* get config for each pipe */ - for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { - ASSERT(dc_main_pipes[dc_pipe_index]); - if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index]) { - memcpy(&dc_main_pipes[dc_pipe_index]->mcache_regs, - l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index], - sizeof(struct dml2_hubp_pipe_mcache_regs)); - } - } - - /* get config for each phantom pipe */ - if (pln_prog->phantom_plane.valid && - dc_phantom_pipes[0] && - dc_main_pipes[0]->stream && - dc_phantom_pipes[0]->plane_state) { - for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { - ASSERT(dc_phantom_pipes[dc_pipe_index]); - if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index]) { - memcpy(&dc_phantom_pipes[dc_pipe_index]->mcache_regs, - l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index], - sizeof(struct dml2_hubp_pipe_mcache_regs)); - } - } - /* increment phantom index */ - dml_phantom_prog_idx++; - } - } -} - void dml21_copy(struct dml2_context *dst_dml_ctx, struct dml2_context *src_dml_ctx) { @@ -446,12 +87,8 @@ void dml21_copy(struct dml2_context *dst_dml_ctx, dst_dml_ctx->v21.mode_programming.programming = dst_dml2_programming; - DC_FP_START(); - /* need to initialize copied instance for internal references to be correct */ dml2_initialize_instance(&dst_dml_ctx->v21.dml_init); - - DC_FP_END(); } bool dml21_create_copy(struct dml2_context **dst_dml_ctx, @@ -466,8 +103,3 @@ bool dml21_create_copy(struct dml2_context **dst_dml_ctx, return true; } -void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config) -{ - dml21_init(in_dc, dml_ctx, config); -} - diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.h index b508bbcc0e16..c4813c51251b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.h @@ -34,36 +34,6 @@ void dml21_copy(struct dml2_context *dst_dml_ctx, struct dml2_context *src_dml_ctx); bool dml21_create_copy(struct dml2_context **dst_dml_ctx, struct dml2_context *src_dml_ctx); -void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config); - -/** - * dml21_validate - Determines if a display configuration is supported or not. - * @in_dc: dc. - * @context: dc_state to be validated. - * @dml_ctx: dml21 context. - * @validate_mode: DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX - * will not populate context.res_ctx. - * - * Based on fast_validate option internally would call: - * - * -dml21_mode_check_and_programming - for DC_VALIDATE_MODE_AND_PROGRAMMING option - * Calculates if dc_state can be supported on the input display - * configuration. If supported, generates the necessary HW - * programming for the new dc_state. - * - * -dml21_check_mode_support - for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX option - * Calculates if dc_state can be supported for the input display - * config. - * - * Context: Two threads may not invoke this function concurrently unless they reference - * separate dc_states for validation. - * Return: True if mode is supported, false otherwise. - */ -bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx, - enum dc_validate_mode validate_mode); - -/* Prepare hubp mcache_regs for hubp mcache ID and split coordinate programming */ -void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx); /* Structure for inputting external SOCBB and DCNIP values for tool based debugging. */ struct socbb_ip_params_external { diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c new file mode 100644 index 000000000000..cc992af6ac9c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2026 Advanced Micro Devices, Inc. + +#include "dml2_internal_types.h" +#include "dml_top.h" +#include "dml2_core_dcn4_calcs.h" +#include "dml2_internal_shared_types.h" +#include "dml21_utils.h" +#include "dml21_translation_helper.h" +#include "dml2_dc_resource_mgmt.h" +#include "dml2_wrapper.h" +#include "dml2_wrapper_fpu.h" +#include "dml21_wrapper.h" +#include "dml21_wrapper_fpu.h" + +#define INVALID -1 + +static void dml21_populate_configuration_options(const struct dc *in_dc, + struct dml2_context *dml_ctx, + const struct dml2_configuration_options *config) +{ + dml_ctx->config = *config; + + /* UCLK P-State options */ + if (in_dc->debug.dml21_force_pstate_method) { + dml_ctx->config.pmo.force_pstate_method_enable = true; + for (int i = 0; i < MAX_PIPES; i++) + dml_ctx->config.pmo.force_pstate_method_values[i] = in_dc->debug.dml21_force_pstate_method_values[i]; + } else { + dml_ctx->config.pmo.force_pstate_method_enable = false; + } +} + +void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config) +{ + dml_ctx->architecture = dml2_architecture_21; + + dml21_populate_configuration_options(in_dc, dml_ctx, config); + + dml21_populate_dml_init_params(&dml_ctx->v21.dml_init, &dml_ctx->config, in_dc); + + dml2_initialize_instance(&dml_ctx->v21.dml_init); +} + +void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config) +{ + dml21_init(in_dc, dml_ctx, config); +} + +static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state, + struct dml2_context *in_ctx, unsigned int pipe_cnt) +{ + unsigned int dml_prog_idx = 0, dc_pipe_index = 0, num_dpps_required = 0; + struct dml2_per_plane_programming *pln_prog = NULL; + struct dml2_per_stream_programming *stream_prog = NULL; + struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__]; + struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}; + int num_pipes; + unsigned int dml_phantom_prog_idx; + + context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; + + /* copy global DCHUBBUB arbiter registers */ + memcpy(&context->bw_ctx.bw.dcn.arb_regs, &in_ctx->v21.mode_programming.programming->global_regs.arb_regs, sizeof(struct dml2_display_arb_regs)); + + /* legacy only */ + context->bw_ctx.bw.dcn.compbuf_size_kb = (int)in_ctx->v21.mode_programming.programming->global_regs.arb_regs.compbuf_size * 64; + + context->bw_ctx.bw.dcn.mall_ss_size_bytes = 0; + context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0; + context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0; + + /* phantom's start after main planes */ + dml_phantom_prog_idx = in_ctx->v21.mode_programming.programming->display_config.num_planes; + + for (dml_prog_idx = 0; dml_prog_idx < DML2_MAX_PLANES; dml_prog_idx++) { + pln_prog = &in_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; + + if (!pln_prog->plane_descriptor) + continue; + + stream_prog = &in_ctx->v21.mode_programming.programming->stream_programming[pln_prog->plane_descriptor->stream_index]; + num_dpps_required = pln_prog->num_dpps_required; + + if (num_dpps_required == 0) { + continue; + } + num_pipes = dml21_find_dc_pipes_for_plane(dc, context, in_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); + + if (num_pipes <= 0) + continue; + + /* program each pipe */ + for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { + dml21_program_dc_pipe(in_ctx, context, dc_main_pipes[dc_pipe_index], pln_prog, stream_prog); + + if (pln_prog->phantom_plane.valid && dc_phantom_pipes[dc_pipe_index]) { + dml21_program_dc_pipe(in_ctx, context, dc_phantom_pipes[dc_pipe_index], pln_prog, stream_prog); + } + } + + /* copy per plane mcache allocation */ + memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx], &pln_prog->mcache_allocation, sizeof(struct dml2_mcache_surface_allocation)); + if (pln_prog->phantom_plane.valid) { + memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx], + &pln_prog->phantom_plane.mcache_allocation, + sizeof(struct dml2_mcache_surface_allocation)); + + dml_phantom_prog_idx++; + } + } + + /* assign global clocks */ + context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz; + context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz; + if (in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values > 1) { + context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = + in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values] * 1000; + } else { + context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[0] * 1000; + } + + if (in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values > 1) { + context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = + in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values] * 1000; + } else { + context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[0] * 1000; + } + + /* get global mall allocation */ + if (dc->res_pool->funcs->calculate_mall_ways_from_bytes) { + context->bw_ctx.bw.dcn.clk.num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, context->bw_ctx.bw.dcn.mall_subvp_size_bytes); + } else { + context->bw_ctx.bw.dcn.clk.num_ways = 0; + } +} + +static void dml21_prepare_mcache_params(struct dml2_context *dml_ctx, struct dc_state *context, struct dc_mcache_params *mcache_params) +{ + int dc_plane_idx = 0; + int dml_prog_idx, stream_idx, plane_idx; + struct dml2_per_plane_programming *pln_prog = NULL; + + for (stream_idx = 0; stream_idx < context->stream_count; stream_idx++) { + for (plane_idx = 0; plane_idx < context->stream_status[stream_idx].plane_count; plane_idx++) { + dml_prog_idx = map_plane_to_dml21_display_cfg(dml_ctx, context->streams[stream_idx]->stream_id, context->stream_status[stream_idx].plane_states[plane_idx], context); + if (dml_prog_idx == INVALID) { + continue; + } + pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; + mcache_params[dc_plane_idx].valid = pln_prog->mcache_allocation.valid; + mcache_params[dc_plane_idx].num_mcaches_plane0 = pln_prog->mcache_allocation.num_mcaches_plane0; + mcache_params[dc_plane_idx].num_mcaches_plane1 = pln_prog->mcache_allocation.num_mcaches_plane1; + mcache_params[dc_plane_idx].requires_dedicated_mall_mcache = pln_prog->mcache_allocation.requires_dedicated_mall_mcache; + mcache_params[dc_plane_idx].last_slice_sharing.plane0_plane1 = pln_prog->mcache_allocation.last_slice_sharing.plane0_plane1; + memcpy(mcache_params[dc_plane_idx].mcache_x_offsets_plane0, + pln_prog->mcache_allocation.mcache_x_offsets_plane0, + sizeof(int) * (DML2_MAX_MCACHES + 1)); + memcpy(mcache_params[dc_plane_idx].mcache_x_offsets_plane1, + pln_prog->mcache_allocation.mcache_x_offsets_plane1, + sizeof(int) * (DML2_MAX_MCACHES + 1)); + dc_plane_idx++; + } + } +} + +static bool dml21_check_mode_support(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) +{ + bool is_supported = false; + struct dml2_initialize_instance_in_out *dml_init = &dml_ctx->v21.dml_init; + struct dml2_check_mode_supported_in_out *mode_support = &dml_ctx->v21.mode_support; + + memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg)); + memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping)); + memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.check_mode_supported_locals.mode_support_params, 0, sizeof(struct dml2_core_mode_support_in_out)); + + if (!context || context->stream_count == 0) + return true; + + /* Scrub phantom's from current dc_state */ + dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context); + dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context); + + mode_support->dml2_instance = dml_init->dml2_instance; + dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx); + dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params.programming = dml_ctx->v21.mode_programming.programming; + + is_supported = dml2_check_mode_supported(mode_support); + + if (!is_supported) + return false; + + return true; +} + +static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) +{ + bool result = false; + struct dml2_build_mode_programming_in_out *mode_programming = &dml_ctx->v21.mode_programming; + struct dc_mcache_params mcache_params[MAX_PLANES] = {0}; + + memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg)); + memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping)); + memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params, 0, sizeof(struct dml2_core_mode_programming_in_out)); + + if (!context) + return true; + + if (context->stream_count == 0) { + dml21_init_min_clocks_for_dc_state(dml_ctx, context); + dml21_build_fams2_programming(in_dc, context, dml_ctx); + return true; + } + + /* scrub phantom's from current dc_state */ + dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context); + dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context); + + /* Populate stream, plane mappings and other fields in display config. */ + result = dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx); + if (!result) + return false; + + result = dml2_build_mode_programming(mode_programming); + + if (!result) + return false; + + /* Check and map HW resources */ + if (result && !dml_ctx->config.skip_hw_state_mapping) { + dml21_map_hw_resources(dml_ctx); + dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, in_dc->current_state); + /* if subvp phantoms are present, expand them into dc context */ + dml21_handle_phantom_streams_planes(in_dc, context, dml_ctx); + + if (in_dc->res_pool->funcs->program_mcache_pipe_config) { + //Prepare mcache params for each plane based on mcache output from DML + dml21_prepare_mcache_params(dml_ctx, context, mcache_params); + + //populate mcache regs to each pipe + dml_ctx->config.callbacks.allocate_mcache(context, mcache_params); + } + } + + /* Copy DML CLK, WM and REG outputs to bandwidth context */ + if (result && !dml_ctx->config.skip_hw_state_mapping) { + dml21_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml_ctx, in_dc->res_pool->pipe_count); + dml21_copy_clocks_to_dc_state(dml_ctx, context); + dml21_extract_watermark_sets(in_dc, &context->bw_ctx.bw.dcn.watermarks, dml_ctx); + dml21_build_fams2_programming(in_dc, context, dml_ctx); + } + + return true; +} + +bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx, + enum dc_validate_mode validate_mode) +{ + bool out = false; + + /* Use dml21_check_mode_support for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX path */ + if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING) + out = dml21_check_mode_support(in_dc, context, dml_ctx); + else + out = dml21_mode_check_and_programming(in_dc, context, dml_ctx); + + return out; +} + +void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) +{ + unsigned int dml_prog_idx, dml_phantom_prog_idx, dc_pipe_index; + int num_pipes; + struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__]; + struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}; + + struct dml2_per_plane_programming *pln_prog = NULL; + struct dml2_plane_mcache_configuration_descriptor *mcache_config = NULL; + struct prepare_mcache_programming_locals *l = &dml_ctx->v21.scratch.prepare_mcache_locals; + + if (context->stream_count == 0) { + return; + } + + memset(&l->build_mcache_programming_params, 0, sizeof(struct dml2_build_mcache_programming_in_out)); + l->build_mcache_programming_params.dml2_instance = dml_ctx->v21.dml_init.dml2_instance; + + /* phantom's start after main planes */ + dml_phantom_prog_idx = dml_ctx->v21.mode_programming.programming->display_config.num_planes; + + /* Build mcache programming parameters per plane per pipe */ + for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) { + pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; + + mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_prog_idx]; + memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor)); + mcache_config->plane_descriptor = pln_prog->plane_descriptor; + mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx]; + ASSERT(pln_prog->num_dpps_required <= 0x7F); + mcache_config->num_pipes = (char)pln_prog->num_dpps_required; + l->build_mcache_programming_params.num_configurations++; + + if (pln_prog->num_dpps_required == 0) { + continue; + } + + num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); + if (num_pipes <= 0 || dc_main_pipes[0]->stream == NULL || + dc_main_pipes[0]->plane_state == NULL) + continue; + + /* get config for each pipe */ + for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { + ASSERT(dc_main_pipes[dc_pipe_index]); + dml21_get_pipe_mcache_config(context, dc_main_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]); + } + + /* get config for each phantom pipe */ + if (pln_prog->phantom_plane.valid && + dc_phantom_pipes[0] && + dc_main_pipes[0]->stream && + dc_phantom_pipes[0]->plane_state) { + mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_phantom_prog_idx]; + memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor)); + mcache_config->plane_descriptor = pln_prog->plane_descriptor; + mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx]; + ASSERT(pln_prog->num_dpps_required <= 0x7F); + mcache_config->num_pipes = (char)pln_prog->num_dpps_required; + l->build_mcache_programming_params.num_configurations++; + + for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { + ASSERT(dc_phantom_pipes[dc_pipe_index]); + dml21_get_pipe_mcache_config(context, dc_phantom_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]); + } + + /* increment phantom index */ + dml_phantom_prog_idx++; + } + } + + /* Call to generate mcache programming per plane per pipe for the given display configuration */ + dml2_build_mcache_programming(&l->build_mcache_programming_params); + + /* get per plane per pipe mcache programming */ + for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) { + pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; + + num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); + if (num_pipes <= 0 || dc_main_pipes[0]->stream == NULL || + dc_main_pipes[0]->plane_state == NULL) + continue; + + /* get config for each pipe */ + for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { + ASSERT(dc_main_pipes[dc_pipe_index]); + if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index]) { + memcpy(&dc_main_pipes[dc_pipe_index]->mcache_regs, + l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index], + sizeof(struct dml2_hubp_pipe_mcache_regs)); + } + } + + /* get config for each phantom pipe */ + if (pln_prog->phantom_plane.valid && + dc_phantom_pipes[0] && + dc_main_pipes[0]->stream && + dc_phantom_pipes[0]->plane_state) { + for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { + ASSERT(dc_phantom_pipes[dc_pipe_index]); + if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index]) { + memcpy(&dc_phantom_pipes[dc_pipe_index]->mcache_regs, + l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index], + sizeof(struct dml2_hubp_pipe_mcache_regs)); + } + } + /* increment phantom index */ + dml_phantom_prog_idx++; + } + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h new file mode 100644 index 000000000000..e5d9a456645f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2026 Advanced Micro Devices, Inc. + +#ifndef _DML21_WRAPPER_FPU_H_ +#define _DML21_WRAPPER_FPU_H_ + +#include "os_types.h" +#include "dml_top_soc_parameter_types.h" +#include "dml_top_display_cfg_types.h" + +struct dc; +struct dc_state; +struct dml2_configuration_options; +struct dml2_context; +enum dc_validate_mode; + +/** + * dml21_init - Initialize DML21 context + * @in_dc: dc. + * @dml_ctx: DML21 context to initialize. + * @config: dml21 configuration options. + * + * Performs FPU-requiring initialization. Must be called with FPU protection. + */ +void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config); + +/** + * dml21_validate - Determines if a display configuration is supported or not. + * @in_dc: dc. + * @context: dc_state to be validated. + * @dml_ctx: dml21 context. + * @validate_mode: DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX + * will not populate context.res_ctx. + * + * Based on fast_validate option internally would call: + * + * -dml21_mode_check_and_programming - for DC_VALIDATE_MODE_AND_PROGRAMMING option + * Calculates if dc_state can be supported on the input display + * configuration. If supported, generates the necessary HW + * programming for the new dc_state. + * + * -dml21_check_mode_support - for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX option + * Calculates if dc_state can be supported for the input display + * config. + * + * Context: Two threads may not invoke this function concurrently unless they reference + * separate dc_states for validation. + * Return: True if mode is supported, false otherwise. + */ + +void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, + const struct dml2_configuration_options *config); +bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx, + enum dc_validate_mode validate_mode); + +/* Prepare hubp mcache_regs for hubp mcache ID and split coordinate programming */ +void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx); + +#endif /* _DML21_WRAPPER_FPU_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h index ddbb8dfa9ff8..6152155d6073 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h @@ -192,6 +192,7 @@ struct dml2_ip_capabilities { unsigned int max_flip_time_us; unsigned int max_flip_time_lines; unsigned int hostvm_mode; + bool dcn_mrq_present; unsigned int subvp_drr_scheduling_margin_us; unsigned int subvp_prefetch_end_to_mall_start_us; unsigned int subvp_fw_processing_delay; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c index 608b4a305c65..99fc2f0666e2 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c @@ -187,6 +187,7 @@ static void patch_ip_params_with_ip_caps(struct dml2_core_ip_params *ip_params, { ip_params->max_num_dpp = ip_caps->pipe_count; ip_params->max_num_otg = ip_caps->otg_count; + ip_params->max_num_opp = ip_caps->otg_count; ip_params->num_dsc = ip_caps->num_dsc; ip_params->max_num_dp2p0_streams = ip_caps->max_num_dp2p0_streams; ip_params->max_num_dp2p0_outputs = ip_caps->max_num_dp2p0_outputs; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index ca5ac3c0deb5..f6402e199354 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -202,7 +202,7 @@ static unsigned int dml_round_to_multiple(unsigned int num, unsigned int multipl return (num - remainder); } -static unsigned int dml_get_num_active_pipes(int unsigned num_planes, const struct core_display_cfg_support_info *cfg_support_info) +static unsigned int dml_get_num_active_pipes(unsigned int num_planes, const struct core_display_cfg_support_info *cfg_support_info) { unsigned int num_active_pipes = 0; @@ -546,9 +546,9 @@ static bool dml_is_vertical_rotation(enum dml2_rotation_angle Scan) return is_vert; } -static int unsigned dml_get_gfx_version(enum dml2_swizzle_mode sw_mode) +static unsigned int dml_get_gfx_version(enum dml2_swizzle_mode sw_mode) { - int unsigned version = 0; + unsigned int version = 0; if (sw_mode == dml2_sw_linear || sw_mode == dml2_sw_256b_2d || @@ -1761,7 +1761,7 @@ static unsigned int CalculateVMAndRowBytes(struct dml2_core_shared_calculate_vm_ *p->PixelPTEBytesPerRow = (unsigned int)((double)*p->dpte_row_width_ub / (double)*p->PixelPTEReqWidth * *p->PTERequestSize); // VBA_DELTA, VBA doesn't have programming value for pte row height linear. - *p->dpte_row_height_linear = (unsigned int)1 << (unsigned int)math_floor2(math_log((float)(p->PTEBufferSizeInRequests * PixelPTEReqWidth_linear / p->Pitch), 2.0), 1); + *p->dpte_row_height_linear = 1U << (unsigned int)math_floor2(math_log((float)(p->PTEBufferSizeInRequests * PixelPTEReqWidth_linear / p->Pitch), 2.0), 1); if (*p->dpte_row_height_linear > 128) *p->dpte_row_height_linear = 128; @@ -3377,7 +3377,7 @@ static void calculate_cursor_req_attributes( DML_LOG_VERBOSE("DML::%s: cursor_bytes_per_line = %d\n", __func__, *cursor_bytes_per_line); DML_LOG_VERBOSE("DML::%s: cursor_bytes_per_chunk = %d\n", __func__, *cursor_bytes_per_chunk); DML_LOG_VERBOSE("DML::%s: cursor_bytes = %d\n", __func__, *cursor_bytes); - DML_LOG_VERBOSE("DML::%s: cursor_pitch = %d\n", __func__, cursor_bpp == 2 ? 256 : (unsigned int)1 << (unsigned int)math_ceil2(math_log((float)cursor_width, 2), 1)); + DML_LOG_VERBOSE("DML::%s: cursor_pitch = %d\n", __func__, cursor_bpp == 2 ? 256 : 1U << (unsigned int)math_ceil2(math_log((float)cursor_width, 2), 1)); #endif } @@ -12205,15 +12205,15 @@ static void rq_dlg_get_wm_regs(const struct dml2_display_cfg *display_cfg, const { double refclk_freq_in_mhz = (display_cfg->overrides.hw.dlg_ref_clk_mhz > 0) ? (double)display_cfg->overrides.hw.dlg_ref_clk_mhz : mode_lib->soc.dchub_refclk_mhz; - wm_regs->fclk_pstate = (int unsigned)(mode_lib->mp.Watermark.FCLKChangeWatermark * refclk_freq_in_mhz); - wm_regs->sr_enter = (int unsigned)(mode_lib->mp.Watermark.StutterEnterPlusExitWatermark * refclk_freq_in_mhz); - wm_regs->sr_exit = (int unsigned)(mode_lib->mp.Watermark.StutterExitWatermark * refclk_freq_in_mhz); - wm_regs->sr_enter_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterEnterPlusExitWatermark * refclk_freq_in_mhz); - wm_regs->sr_exit_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterExitWatermark * refclk_freq_in_mhz); - wm_regs->temp_read_or_ppt = (int unsigned)(mode_lib->mp.Watermark.temp_read_or_ppt_watermark_us * refclk_freq_in_mhz); - wm_regs->uclk_pstate = (int unsigned)(mode_lib->mp.Watermark.DRAMClockChangeWatermark * refclk_freq_in_mhz); - wm_regs->urgent = (int unsigned)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz); - wm_regs->usr = (int unsigned)(mode_lib->mp.Watermark.USRRetrainingWatermark * refclk_freq_in_mhz); + wm_regs->fclk_pstate = (unsigned int)(mode_lib->mp.Watermark.FCLKChangeWatermark * refclk_freq_in_mhz); + wm_regs->sr_enter = (unsigned int)(mode_lib->mp.Watermark.StutterEnterPlusExitWatermark * refclk_freq_in_mhz); + wm_regs->sr_exit = (unsigned int)(mode_lib->mp.Watermark.StutterExitWatermark * refclk_freq_in_mhz); + wm_regs->sr_enter_z8 = (unsigned int)(mode_lib->mp.Watermark.Z8StutterEnterPlusExitWatermark * refclk_freq_in_mhz); + wm_regs->sr_exit_z8 = (unsigned int)(mode_lib->mp.Watermark.Z8StutterExitWatermark * refclk_freq_in_mhz); + wm_regs->temp_read_or_ppt = (unsigned int)(mode_lib->mp.Watermark.temp_read_or_ppt_watermark_us * refclk_freq_in_mhz); + wm_regs->uclk_pstate = (unsigned int)(mode_lib->mp.Watermark.DRAMClockChangeWatermark * refclk_freq_in_mhz); + wm_regs->urgent = (unsigned int)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz); + wm_regs->usr = (unsigned int)(mode_lib->mp.Watermark.USRRetrainingWatermark * refclk_freq_in_mhz); wm_regs->refcyc_per_trip_to_mem = (unsigned int)(mode_lib->mp.UrgentLatency * refclk_freq_in_mhz); wm_regs->refcyc_per_meta_trip_to_mem = (unsigned int)(mode_lib->mp.MetaTripToMemory * refclk_freq_in_mhz); wm_regs->frac_urg_bw_flip = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidthImmediateFlip * 1000); @@ -12262,11 +12262,15 @@ static void rq_dlg_get_rq_reg(struct dml2_display_rq_regs *rq_regs, unsigned int pixel_chunk_bytes = 0; unsigned int min_pixel_chunk_bytes = 0; + unsigned int meta_chunk_bytes = 0; + unsigned int min_meta_chunk_bytes = 0; unsigned int dpte_group_bytes = 0; unsigned int mpte_group_bytes = 0; unsigned int p1_pixel_chunk_bytes = 0; unsigned int p1_min_pixel_chunk_bytes = 0; + unsigned int p1_meta_chunk_bytes = 0; + unsigned int p1_min_meta_chunk_bytes = 0; unsigned int p1_dpte_group_bytes = 0; unsigned int p1_mpte_group_bytes = 0; @@ -12287,8 +12291,13 @@ static void rq_dlg_get_rq_reg(struct dml2_display_rq_regs *rq_regs, dpte_group_bytes = (unsigned int)(dml_get_dpte_group_size_in_bytes(mode_lib, pipe_idx)); mpte_group_bytes = (unsigned int)(dml_get_vm_group_size_in_bytes(mode_lib, pipe_idx)); + meta_chunk_bytes = (unsigned int)(mode_lib->ip.meta_chunk_size_kbytes * 1024); + min_meta_chunk_bytes = (unsigned int)(mode_lib->ip.min_meta_chunk_size_bytes); + p1_pixel_chunk_bytes = pixel_chunk_bytes; p1_min_pixel_chunk_bytes = min_pixel_chunk_bytes; + p1_meta_chunk_bytes = meta_chunk_bytes; + p1_min_meta_chunk_bytes = min_meta_chunk_bytes; p1_dpte_group_bytes = dpte_group_bytes; p1_mpte_group_bytes = mpte_group_bytes; @@ -12309,6 +12318,19 @@ static void rq_dlg_get_rq_reg(struct dml2_display_rq_regs *rq_regs, else rq_regs->rq_regs_c.min_chunk_size = log_and_substract_if_non_zero(p1_min_pixel_chunk_bytes, 8 - 1); + rq_regs->rq_regs_l.meta_chunk_size = log_and_substract_if_non_zero(meta_chunk_bytes, 10); + rq_regs->rq_regs_c.meta_chunk_size = log_and_substract_if_non_zero(p1_meta_chunk_bytes, 10); + + if (min_meta_chunk_bytes == 0) + rq_regs->rq_regs_l.min_meta_chunk_size = 0; + else + rq_regs->rq_regs_l.min_meta_chunk_size = log_and_substract_if_non_zero(min_meta_chunk_bytes, 6 - 1); + + if (min_meta_chunk_bytes == 0) + rq_regs->rq_regs_c.min_meta_chunk_size = 0; + else + rq_regs->rq_regs_c.min_meta_chunk_size = log_and_substract_if_non_zero(p1_min_meta_chunk_bytes, 6 - 1); + rq_regs->rq_regs_l.dpte_group_size = log_and_substract_if_non_zero(dpte_group_bytes, 6); rq_regs->rq_regs_l.mpte_group_size = log_and_substract_if_non_zero(mpte_group_bytes, 6); rq_regs->rq_regs_c.dpte_group_size = log_and_substract_if_non_zero(p1_dpte_group_bytes, 6); @@ -12670,7 +12692,7 @@ static void rq_dlg_get_dlg_reg( disp_dlg_regs->refcyc_per_vm_req_flip = (unsigned int)(math_pow(2, 23) - 1); - DML_ASSERT(disp_dlg_regs->dst_y_after_scaler < (unsigned int)8); + DML_ASSERT(disp_dlg_regs->dst_y_after_scaler < 8U); DML_ASSERT(disp_dlg_regs->refcyc_x_after_scaler < (unsigned int)math_pow(2, 13)); if (disp_dlg_regs->dst_y_per_pte_row_nom_l >= (unsigned int)math_pow(2, 17)) { @@ -13226,7 +13248,7 @@ void dml2_core_calcs_get_informative(const struct dml2_core_internal_display_mod out->informative.misc.cstate_max_cap_mode = dml_get_cstate_max_cap_mode(mode_lib); - out->min_clocks.dcn4x.dpprefclk_khz = (int unsigned)dml_get_global_dppclk_khz(mode_lib); + out->min_clocks.dcn4x.dpprefclk_khz = (unsigned int)dml_get_global_dppclk_khz(mode_lib); out->informative.qos.max_active_fclk_change_latency_supported = dml_get_fclk_change_latency(mode_lib); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c index d17e59d684fd..ab0b4a4b5d65 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c @@ -279,6 +279,26 @@ static bool round_up_and_copy_to_next_dpm(unsigned long min_value, unsigned long bool result = false; int index = 0; + /* Guard against empty clock tables (e.g. DTBCLK on DCN42B where the + * clock is tied off and num_clk_values == 0). Without this check the + * else-if branch below would evaluate + * clk_values_khz[num_clk_values - 1] with num_clk_values == 0, which + * wraps the unsigned char index to 255 — a 235-element out-of-bounds + * read on an array of DML_MAX_CLK_TABLE_SIZE (20) entries. + * + * Semantic: if the clock doesn't exist on this ASIC but no frequency + * is required (min_value == 0), the request is trivially satisfied. + * If a non-zero frequency is required but the clock is absent, the + * configuration is unsupportable. + */ + if (clock_table->num_clk_values == 0) { + if (min_value == 0) { + *rounded_value = 0; + return true; + } + return false; + } + if (clock_table->num_clk_values > 2) { while (index < clock_table->num_clk_values && clock_table->clk_values_khz[index] < min_value) index++; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c index a265f254152c..eab13e1c96fd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c @@ -178,9 +178,12 @@ static bool build_min_clock_table(const struct dml2_soc_bb *soc_bb, struct dml2_ min_table->max_clocks_khz.dispclk = soc_bb->clk_table.dispclk.clk_values_khz[soc_bb->clk_table.dispclk.num_clk_values - 1]; min_table->max_clocks_khz.dppclk = soc_bb->clk_table.dppclk.clk_values_khz[soc_bb->clk_table.dppclk.num_clk_values - 1]; - min_table->max_clocks_khz.dscclk = soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values - 1]; - min_table->max_clocks_khz.dtbclk = soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values - 1]; - min_table->max_clocks_khz.phyclk = soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values - 1]; + min_table->max_clocks_khz.dscclk = (soc_bb->clk_table.dscclk.num_clk_values > 0) ? + soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values - 1] : 0; + min_table->max_clocks_khz.dtbclk = (soc_bb->clk_table.dtbclk.num_clk_values > 0) ? + soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values - 1] : 0; + min_table->max_clocks_khz.phyclk = (soc_bb->clk_table.phyclk.num_clk_values > 0) ? + soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values - 1] : 0; min_table->max_ss_clocks_khz.dispclk = (unsigned int)((double)min_table->max_clocks_khz.dispclk / (1.0 + soc_bb->dcn_downspread_percent / 100.0)); min_table->max_ss_clocks_khz.dppclk = (unsigned int)((double)min_table->max_clocks_khz.dppclk / (1.0 + soc_bb->dcn_downspread_percent / 100.0)); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.c index 1f67cbc2c236..3eaeff39ee79 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.c @@ -54,9 +54,12 @@ static bool build_min_clock_table(const struct dml2_soc_bb *soc_bb, struct dml2_ min_table->max_clocks_khz.dispclk = soc_bb->clk_table.dispclk.clk_values_khz[soc_bb->clk_table.dispclk.num_clk_values - 1]; min_table->max_clocks_khz.dppclk = soc_bb->clk_table.dppclk.clk_values_khz[soc_bb->clk_table.dppclk.num_clk_values - 1]; - min_table->max_clocks_khz.dscclk = soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values - 1]; - min_table->max_clocks_khz.dtbclk = soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values - 1]; - min_table->max_clocks_khz.phyclk = soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values - 1]; + min_table->max_clocks_khz.dscclk = (soc_bb->clk_table.dscclk.num_clk_values > 0) ? + soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values - 1] : 0; + min_table->max_clocks_khz.dtbclk = (soc_bb->clk_table.dtbclk.num_clk_values > 0) ? + soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values - 1] : 0; + min_table->max_clocks_khz.phyclk = (soc_bb->clk_table.phyclk.num_clk_values > 0) ? + soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values - 1] : 0; min_table->max_ss_clocks_khz.dispclk = (unsigned int)((double)min_table->max_clocks_khz.dispclk / (1.0 + soc_bb->dcn_downspread_percent / 100.0)); min_table->max_ss_clocks_khz.dppclk = (unsigned int)((double)min_table->max_clocks_khz.dppclk / (1.0 + soc_bb->dcn_downspread_percent / 100.0)); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c index 74812a7d5e28..6ef93c6fc1cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_dc_resource_mgmt.c @@ -35,7 +35,7 @@ #define MAX_MPCC_FACTOR 4 struct dc_plane_pipe_pool { - int pipes_assigned_to_plane[MAX_ODM_FACTOR][MAX_MPCC_FACTOR]; + unsigned int pipes_assigned_to_plane[MAX_ODM_FACTOR][MAX_MPCC_FACTOR]; bool pipe_used[MAX_ODM_FACTOR][MAX_MPCC_FACTOR]; int num_pipes_assigned_to_plane_for_mpcc_combine; int num_pipes_assigned_to_plane_for_odm_combine; @@ -143,7 +143,7 @@ static unsigned int find_pipes_assigned_to_plane(struct dml2_context *ctx, { int i; unsigned int num_found = 0; - unsigned int plane_id_assigned_to_pipe = -1; + unsigned int plane_id_assigned_to_pipe = UINT_MAX; for (i = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; @@ -340,8 +340,8 @@ static bool is_pipe_in_candidate_array(const unsigned int pipe_idx, static bool find_more_pipes_for_stream(struct dml2_context *ctx, struct dc_state *state, // The state we want to find a free mapping in unsigned int stream_id, // The stream we want this pipe to drive - int *assigned_pipes, - int *assigned_pipe_count, + unsigned int *assigned_pipes, + unsigned int *assigned_pipe_count, int pipes_needed, const struct dc_state *existing_state) // The state (optional) that we want to minimize remapping relative to { @@ -366,7 +366,8 @@ static bool find_more_pipes_for_stream(struct dml2_context *ctx, if (!is_plane_using_pipe(pipe)) { pipes_needed--; // TODO: This doens't make sense really, pipe_idx should always be valid - pipe->pipe_idx = preferred_pipe_candidates[i]; + ASSERT(preferred_pipe_candidates[i] <= 0xFF); + pipe->pipe_idx = (uint8_t)preferred_pipe_candidates[i]; assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; } } @@ -382,7 +383,8 @@ static bool find_more_pipes_for_stream(struct dml2_context *ctx, if (!is_plane_using_pipe(pipe)) { pipes_needed--; // TODO: This doens't make sense really, pipe_idx should always be valid - pipe->pipe_idx = i; + ASSERT(i >= 0 && i <= 0xFF); + pipe->pipe_idx = (uint8_t)i; assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; } } @@ -393,7 +395,8 @@ static bool find_more_pipes_for_stream(struct dml2_context *ctx, if (!is_plane_using_pipe(pipe)) { pipes_needed--; // TODO: This doens't make sense really, pipe_idx should always be valid - pipe->pipe_idx = last_resort_pipe_candidates[i]; + ASSERT(last_resort_pipe_candidates[i] <= 0xFF); + pipe->pipe_idx = (uint8_t)last_resort_pipe_candidates[i]; assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; } } @@ -406,8 +409,8 @@ static bool find_more_pipes_for_stream(struct dml2_context *ctx, static bool find_more_free_pipes(struct dml2_context *ctx, struct dc_state *state, // The state we want to find a free mapping in unsigned int stream_id, // The stream we want this pipe to drive - int *assigned_pipes, - int *assigned_pipe_count, + unsigned int *assigned_pipes, + unsigned int *assigned_pipe_count, int pipes_needed, const struct dc_state *existing_state) // The state (optional) that we want to minimize remapping relative to { @@ -432,7 +435,8 @@ static bool find_more_free_pipes(struct dml2_context *ctx, if (is_pipe_free(pipe)) { pipes_needed--; // TODO: This doens't make sense really, pipe_idx should always be valid - pipe->pipe_idx = preferred_pipe_candidates[i]; + ASSERT(preferred_pipe_candidates[i] <= 0xFF); + pipe->pipe_idx = (uint8_t)preferred_pipe_candidates[i]; assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; } } @@ -448,7 +452,8 @@ static bool find_more_free_pipes(struct dml2_context *ctx, if (is_pipe_free(pipe)) { pipes_needed--; // TODO: This doens't make sense really, pipe_idx should always be valid - pipe->pipe_idx = i; + ASSERT(i >= 0 && i <= 0xFF); + pipe->pipe_idx = (uint8_t)i; assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; } } @@ -459,7 +464,8 @@ static bool find_more_free_pipes(struct dml2_context *ctx, if (is_pipe_free(pipe)) { pipes_needed--; // TODO: This doens't make sense really, pipe_idx should always be valid - pipe->pipe_idx = last_resort_pipe_candidates[i]; + ASSERT(last_resort_pipe_candidates[i] <= 0xFF); + pipe->pipe_idx = (uint8_t)last_resort_pipe_candidates[i]; assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx; } } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_mall_phantom.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_mall_phantom.c index d56e58ce26c7..9bbe4e058be7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_mall_phantom.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_mall_phantom.c @@ -555,7 +555,8 @@ static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct dc_state * if (!found && pipe_mall_type == SUBVP_NONE) { // Found pipe which is not SubVP or Phantom (i.e. the VBLANK pipe). - vblank_index = i; + ASSERT(i <= 0xFF); + vblank_index = (uint8_t)i; found = true; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_translation_helper.c index d834cb595afa..cf3a69aba638 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_translation_helper.c @@ -330,8 +330,8 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, { struct dml2_policy_build_synthetic_soc_states_scratch *s = &dml2->v20.scratch.create_scratch.build_synthetic_socbb_scratch; struct dml2_policy_build_synthetic_soc_states_params *p = &dml2->v20.scratch.build_synthetic_socbb_params; - unsigned int dcfclk_stas_mhz[NUM_DCFCLK_STAS] = {0}; - unsigned int dcfclk_stas_mhz_new[NUM_DCFCLK_STAS_NEW] = {0}; + int dcfclk_stas_mhz[NUM_DCFCLK_STAS] = {0}; + int dcfclk_stas_mhz_new[NUM_DCFCLK_STAS_NEW] = {0}; unsigned int dml_project = dml2->v20.dml_core_ctx.project; unsigned int i = 0; @@ -765,7 +765,7 @@ static void populate_dml_timing_cfg_from_stream_state(struct dml_timing_cfg_st * out->PixelClock[location] *= 2; out->HTotal[location] = in->timing.h_total; out->VTotal[location] = in->timing.v_total; - out->Interlace[location] = in->timing.flags.INTERLACE; + out->Interlace[location] = (in->timing.flags.INTERLACE != 0); hblank_start = in->timing.h_total - in->timing.h_front_porch; out->HBlankEnd[location] = hblank_start - in->timing.h_addressable @@ -1174,12 +1174,12 @@ static unsigned int map_plane_to_dml_display_cfg(const struct dml2_context *dml2 const struct dc_state *context, const struct dml_display_cfg_st *dml_dispcfg, unsigned int stream_id, int plane_index) { unsigned int plane_id; - int i = 0; - int location = -1; + unsigned int i = 0; + unsigned int location = UINT_MAX; if (!get_plane_id(context->bw_ctx.dml2, context, plane, stream_id, plane_index, &plane_id)) { ASSERT(false); - return -1; + return UINT_MAX; } for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c index 9a33158b63bf..6c7cdf102906 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_utils.c @@ -255,7 +255,8 @@ static void populate_pipe_ctx_dlg_params_from_dml(struct pipe_ctx *pipe_ctx, str pipe_ctx->pipe_dlg_param.vupdate_width = dml_get_vupdate_width(mode_lib, pipe_idx); pipe_ctx->pipe_dlg_param.vready_offset = dml_get_vready_offset(mode_lib, pipe_idx); - pipe_ctx->pipe_dlg_param.otg_inst = pipe_ctx->stream_res.tg->inst; + ASSERT(pipe_ctx->stream_res.tg->inst >= 0 && pipe_ctx->stream_res.tg->inst <= 0xFF); + pipe_ctx->pipe_dlg_param.otg_inst = (unsigned char)pipe_ctx->stream_res.tg->inst; pipe_ctx->pipe_dlg_param.hactive = hactive; pipe_ctx->pipe_dlg_param.vactive = vactive; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c index 408559d6fb2d..93b7613fc4f2 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c @@ -6,8 +6,24 @@ */ #include "dml2_internal_types.h" +#include "dml2_wrapper.h" #include "dml2_wrapper_fpu.h" +#include "dml21_wrapper.h" +#include "dml21_wrapper_fpu.h" +#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 + +struct dml2_context *dml2_allocate_memory(void) +{ + struct dml2_context *dml2; + + DC_RUN_WITH_PREEMPTION_ENABLED(dml2 = vzalloc(sizeof(struct dml2_context))); + return dml2; +} bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2, enum dc_validate_mode validate_mode) { @@ -23,16 +39,12 @@ bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2 return out; } - DC_FP_START(); - /* Use dml_validate_only for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX path */ if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING) out = dml2_validate_only(context, validate_mode); else out = dml2_validate_and_build_resource(in_dc, context, validate_mode); - DC_FP_END(); - return out; } @@ -70,15 +82,12 @@ static void dml2_init(const struct dc *in_dc, const struct dml2_configuration_op break; } - DC_FP_START(); - initialize_dml2_ip_params(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.ip); initialize_dml2_soc_bbox(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc); initialize_dml2_soc_states(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc, &(*dml2)->v20.dml_core_ctx.states); - DC_FP_END(); } bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c index 203eef747262..66624cfc27b1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c @@ -31,8 +31,10 @@ #include "dml2_translation_helper.h" #include "dml2_mall_phantom.h" #include "dml2_dc_resource_mgmt.h" -#include "dml21_wrapper.h" +#include "dml2_wrapper.h" #include "dml2_wrapper_fpu.h" +#include "dml21_wrapper.h" +#include "dml21_wrapper_fpu.h" void initialize_dml2_ip_params(struct dml2_context *dml2, const struct dc *in_dc, struct ip_params_st *out) { @@ -546,11 +548,6 @@ void dml2_apply_debug_options(const struct dc *dc, struct dml2_context *dml2) } } -inline struct dml2_context *dml2_allocate_memory(void) -{ - return (struct dml2_context *) vzalloc(sizeof(struct dml2_context)); -} - void dml2_destroy(struct dml2_context *dml2) { if (!dml2) diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c index 0e70ffc784b1..ef605e0a75e3 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c @@ -288,6 +288,7 @@ void dpp1_cnv_setup ( enum dc_color_space input_color_space, struct cnv_alpha_2bit_lut *alpha_2bit_lut) { + (void)alpha_2bit_lut; uint32_t pixel_format; uint32_t alpha_en; enum pixel_format_description fmt ; diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_dscl.c index 808bca9fb804..0d2c9fcd3362 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_dscl.c @@ -102,7 +102,7 @@ static int dpp1_dscl_get_pixel_depth_val(enum lb_pixel_depth depth) } } -static bool dpp1_dscl_is_video_format(enum pixel_format format) +static bool dpp1_dscl_is_video_format(enum dc_pixel_format format) { if (format >= PIXEL_FORMAT_VIDEO_BEGIN && format <= PIXEL_FORMAT_VIDEO_END) @@ -111,7 +111,7 @@ static bool dpp1_dscl_is_video_format(enum pixel_format format) return false; } -static bool dpp1_dscl_is_420_format(enum pixel_format format) +static bool dpp1_dscl_is_420_format(enum dc_pixel_format format) { if (format == PIXEL_FORMAT_420BPP8 || format == PIXEL_FORMAT_420BPP10) diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp.c index c433f4b876e9..8d5000790904 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp.c @@ -92,7 +92,10 @@ void dpp2_power_on_obuf( void dpp2_dummy_program_input_lut( struct dpp *dpp_base, const struct dc_gamma *gamma) -{} +{ + (void)dpp_base; + (void)gamma; +} static void dpp2_cnv_setup ( struct dpp *dpp_base, @@ -369,7 +372,11 @@ void oppn20_dummy_program_regamma_pwl( struct dpp *dpp, const struct pwl_params *params, enum opp_regamma mode) -{} +{ + (void)dpp; + (void)params; + (void)mode; +} static struct dpp_funcs dcn20_dpp_funcs = { .dpp_read_state = dpp20_read_state, diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp_cm.c index 31613372e214..26f9485f165d 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp_cm.c @@ -1016,6 +1016,7 @@ static void dpp20_set_3dlut_mode( bool is_color_channel_12bits, bool is_lut_size17x17x17) { + (void)is_color_channel_12bits; uint32_t lut_mode; struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c index 8a146968ee15..e7880fc61b4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c @@ -1307,6 +1307,7 @@ static void dpp3_set_3dlut_mode( bool is_color_channel_12bits, bool is_lut_size17x17x17) { + (void)is_color_channel_12bits; uint32_t lut_mode; struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c index 3284084ca7ad..8170a86ad0ea 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c @@ -80,6 +80,7 @@ static void dpp3_program_gammcor_lut( uint32_t num, bool is_ram_a) { + (void)is_ram_a; uint32_t i; struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); uint32_t last_base_value_red = rgb[num-1].red_reg + rgb[num-1].delta_red_reg; diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c index 62bf7cea21d8..821d5173b59f 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c @@ -132,6 +132,9 @@ void dpp401_set_cursor_position( uint32_t width, uint32_t height) { + (void)param; + (void)width; + (void)height; struct dcn401_dpp *dpp = TO_DCN401_DPP(dpp_base); uint32_t cur_en = pos->enable ? 1 : 0; @@ -237,6 +240,8 @@ void dpp401_set_cursor_matrix( enum dc_color_space color_space, struct dc_csc_transform cursor_csc_color_matrix) { + (void)color_space; + (void)cursor_csc_color_matrix; //Since we don't have cursor matrix information, force bypass mode by passing in unknown color space dpp401_program_cursor_csc(dpp_base, COLOR_SPACE_UNKNOWN, NULL); } diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_dscl.c index 8b6155f9122f..8b7e55e337d3 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_dscl.c @@ -94,7 +94,7 @@ static int dpp401_dscl_get_pixel_depth_val(enum lb_pixel_depth depth) } } -static bool dpp401_dscl_is_video_format(enum pixel_format format) +static bool dpp401_dscl_is_video_format(enum dc_pixel_format format) { if (format >= PIXEL_FORMAT_VIDEO_BEGIN && format <= PIXEL_FORMAT_VIDEO_END) @@ -103,7 +103,7 @@ static bool dpp401_dscl_is_video_format(enum pixel_format format) return false; } -static bool dpp401_dscl_is_420_format(enum pixel_format format) +static bool dpp401_dscl_is_420_format(enum dc_pixel_format format) { if (format == PIXEL_FORMAT_420BPP8 || format == PIXEL_FORMAT_420BPP10) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c index c1bdbb38c690..3bf737195bac 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c @@ -107,6 +107,11 @@ void dsc401_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_sta REG_GET(DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, &s->dsc_slice_bpg_offset); REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &s->dsc_fw_en, DSCRM_DSC_OPP_PIPE_SOURCE, &s->dsc_opp_source); + REG_GET(DSCC_PPS_CONFIG1, BLOCK_PRED_ENABLE, &s->dsc_block_pred_enable); + REG_GET(DSCC_PPS_CONFIG0, LINEBUF_DEPTH, &s->dsc_line_buf_depth); + REG_GET(DSCC_PPS_CONFIG0, DSC_VERSION_MINOR, &s->dsc_version_minor); + REG_GET(DSCC_CONFIG1, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, &s->dsc_rc_buffer_size); + REG_GET(DSCC_PPS_CONFIG0, SIMPLE_422, &s->dsc_simple_422); } diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dsc.h b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h index ad7ef83694ea..a16c60d8532f 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h @@ -64,6 +64,11 @@ struct dcn_dsc_state { uint32_t dsc_chunk_size; uint32_t dsc_fw_en; uint32_t dsc_opp_source; + uint32_t dsc_block_pred_enable; + uint32_t dsc_line_buf_depth; + uint32_t dsc_version_minor; + uint32_t dsc_rc_buffer_size; + uint32_t dsc_simple_422; }; struct dcn_dsc_reg_state { diff --git a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_dwb.c b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_dwb.c index bc058f682438..0ee4f83a02eb 100644 --- a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_dwb.c +++ b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_dwb.c @@ -45,6 +45,7 @@ static bool dwb3_get_caps(struct dwbc *dwbc, struct dwb_caps *caps) { + (void)dwbc; if (caps) { caps->adapter_id = 0; /* we only support 1 adapter currently */ caps->hw_version = DCN_VERSION_3_0; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn42/hw_translate_dcn42.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn42/hw_translate_dcn42.c index dcbcf6b85abf..e7e1d9979876 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn42/hw_translate_dcn42.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn42/hw_translate_dcn42.c @@ -45,6 +45,7 @@ static bool offset_to_id( enum gpio_id *id, uint32_t *en) { + (void)mask; switch (offset) { /* HPD */ case REG(HPD0_DC_HPD_INT_STATUS): diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c index f3d562c8df4c..d81a71ac00d2 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -60,6 +60,7 @@ bool dal_hw_factory_init( enum dce_version dce_version, enum dce_environment dce_environment) { + (void)dce_environment; switch (dce_version) { #if defined(CONFIG_DRM_AMD_DC_SI) case DCE_VERSION_6_0: diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_gpio.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_gpio.c index 660510842ecf..f0d400972897 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_gpio.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_gpio.c @@ -199,5 +199,6 @@ void dal_hw_gpio_construct( void dal_hw_gpio_destruct( struct hw_gpio *pin) { + (void)pin; ASSERT(!pin->base.opened); } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index 1c977fc4d0e3..e6e36a912b13 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -64,6 +64,7 @@ bool dal_hw_translate_init( enum dce_version dce_version, enum dce_environment dce_environment) { + (void)dce_environment; switch (dce_version) { #if defined(CONFIG_DRM_AMD_DC_SI) case DCE_VERSION_6_0: diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c index 5a03758e3de6..3c298192f359 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c @@ -943,6 +943,7 @@ static void hubbub31_get_dchub_ref_freq(struct hubbub *hubbub, unsigned int dccg_ref_freq_inKhz, unsigned int *dchub_ref_freq_inKhz) { + (void)dccg_ref_freq_inKhz; struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); uint32_t ref_div = 0; uint32_t ref_en = 0; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c index 43ba399f4822..82d4e3e0e5e8 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c @@ -259,6 +259,7 @@ void hubbub35_get_dchub_ref_freq(struct hubbub *hubbub, unsigned int dccg_ref_freq_inKhz, unsigned int *dchub_ref_freq_inKhz) { + (void)dccg_ref_freq_inKhz; struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); uint32_t ref_div = 0; uint32_t ref_en = 0; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c index b0a4b68cf359..3b9542c08f3d 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c @@ -70,6 +70,7 @@ bool hubbub401_program_urgent_watermarks( unsigned int refclk_mhz, bool safe_to_lower) { + (void)refclk_mhz; struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); bool wm_pending = false; @@ -188,6 +189,7 @@ bool hubbub401_program_stutter_watermarks( unsigned int refclk_mhz, bool safe_to_lower) { + (void)refclk_mhz; struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); bool wm_pending = false; @@ -287,6 +289,7 @@ bool hubbub401_program_pstate_watermarks( unsigned int refclk_mhz, bool safe_to_lower) { + (void)refclk_mhz; struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); bool wm_pending = false; @@ -414,6 +417,7 @@ bool hubbub401_program_usr_watermarks( unsigned int refclk_mhz, bool safe_to_lower) { + (void)refclk_mhz; struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); bool wm_pending = false; diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c index d6e6fbaa041b..73b6b0ffcb74 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c @@ -6,6 +6,7 @@ #include "dcn31/dcn31_hubbub.h" #include "dcn32/dcn32_hubbub.h" #include "dcn35/dcn35_hubbub.h" +#include "dcn401/dcn401_hubbub.h" #include "dcn42/dcn42_hubbub.h" #include "dm_services.h" #include "reg_helper.h" @@ -429,15 +430,6 @@ static void hubbub42_allow_self_refresh_control(struct hubbub *hubbub, bool allo REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow); - - if (!allow && hubbub->ctx->dc->debug.disable_stutter) {/*controlled by registry key*/ - REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, - DCHUBBUB_ARB_ALLOW_DCFCLK_DEEP_SLEEP_FORCE_VALUE, 0, - DCHUBBUB_ARB_ALLOW_DCFCLK_DEEP_SLEEP_FORCE_ENABLE, 1); - REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, - DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0, - DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1); - } } static void hubbub42_set_sdp_control(struct hubbub *hubbub, bool dc_control) { @@ -494,6 +486,48 @@ static bool hubbub42_program_watermarks( return wm_pending; } +static void hubbub42_set_request_limit(struct hubbub *hubbub, int memory_channel_count, int words_per_channel) +{ + (void)memory_channel_count; + (void)words_per_channel; + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + uint32_t request_limit = 96; //MAX(12 * memory_channel_count, 96); + + REG_UPDATE(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, request_limit); +} + +static bool dcn42_program_arbiter(struct hubbub *hubbub, struct dml2_display_arb_regs *arb_regs, + bool safe_to_lower) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + + bool wm_pending = false; + uint32_t temp; + + /* request backpressure and outstanding return threshold (unused)*/ + //REG_UPDATE(DCHUBBUB_TIMEOUT_DETECTION_CTRL1, DCHUBBUB_TIMEOUT_REQ_STALL_THRESHOLD, arb_regs->req_stall_threshold); + + /* 401 delta: do not update P-State stall threshold (handled by fw) */ + // REG_UPDATE(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_PSTATE_STALL_THRESHOLD, arb_regs->pstate_stall_threshold); + + if (safe_to_lower || arb_regs->allow_sdpif_rate_limit_when_cstate_req > hubbub2->allow_sdpif_rate_limit_when_cstate_req) { + hubbub2->allow_sdpif_rate_limit_when_cstate_req = arb_regs->allow_sdpif_rate_limit_when_cstate_req; + + /* only update the required bits */ + REG_GET(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, &temp); + if (hubbub2->allow_sdpif_rate_limit_when_cstate_req) { + temp |= (1 << 5); + } else { + temp &= ~(1 << 5); + } + REG_UPDATE(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, temp); + } else { + wm_pending = true; + } + + return wm_pending; +} + static const struct hubbub_funcs hubbub42_funcs = { .update_dchub = hubbub2_update_dchub, .init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx, @@ -509,13 +543,16 @@ static const struct hubbub_funcs hubbub42_funcs = { .force_wm_propagate_to_pipes = hubbub32_force_wm_propagate_to_pipes, .force_pstate_change_control = hubbub3_force_pstate_change_control, .init_watermarks = hubbub35_init_watermarks, - .program_det_size = dcn32_program_det_size, - .program_compbuf_size = dcn35_program_compbuf_size, - .init_crb = dcn35_init_crb, + .init_crb = dcn401_init_crb, + .dchvm_init = dcn35_dchvm_init, .hubbub_read_state = hubbub2_read_state, .force_usr_retraining_allow = hubbub32_force_usr_retraining_allow, - .dchubbub_init = hubbub35_init, - .dchvm_init = dcn35_dchvm_init, + .set_request_limit = hubbub42_set_request_limit, + .program_det_segments = dcn401_program_det_segments, + .program_compbuf_segments = dcn401_program_compbuf_segments, + .wait_for_det_update = dcn401_wait_for_det_update, + .program_arbiter = dcn42_program_arbiter, + .hubbub_read_reg_state = hubbub3_read_reg_state }; void hubbub42_construct(struct dcn20_hubbub *hubbub2, diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c index 6378e3fd7249..7c97a774141f 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c @@ -143,6 +143,7 @@ void hubp1_program_tiling( const struct dc_tiling_info *info, const enum surface_pixel_format pixel_format) { + (void)pixel_format; struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); REG_UPDATE_6(DCSURF_ADDR_CONFIG, @@ -563,6 +564,7 @@ void hubp1_program_surface_config( bool horizontal_mirror, unsigned int compat_level) { + (void)compat_level; hubp1_dcc_control(hubp, dcc->enable, dcc->independent_64b_blks); hubp1_program_tiling(hubp, tiling_info, format); hubp1_program_size(hubp, format, plane_size, dcc); diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c index 92288de4cc10..ceee5165fd6a 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c @@ -313,6 +313,7 @@ static void hubp2_program_tiling( const struct dc_tiling_info *info, const enum surface_pixel_format pixel_format) { + (void)pixel_format; REG_UPDATE_3(DCSURF_ADDR_CONFIG, NUM_PIPES, log_2(info->gfx9.num_pipes), PIPE_INTERLEAVE, info->gfx9.pipe_interleave, @@ -557,6 +558,7 @@ void hubp2_program_surface_config( bool horizontal_mirror, unsigned int compat_level) { + (void)compat_level; struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); hubp2_dcc_control(hubp, dcc->enable, dcc->independent_64b_blks); diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c index 0cc6f4558989..e2708e30eb1b 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c @@ -321,6 +321,7 @@ void hubp3_program_tiling( const struct dc_tiling_info *info, const enum surface_pixel_format pixel_format) { + (void)pixel_format; REG_UPDATE_4(DCSURF_ADDR_CONFIG, NUM_PIPES, log_2(info->gfx9.num_pipes), PIPE_INTERLEAVE, info->gfx9.pipe_interleave, @@ -418,6 +419,7 @@ void hubp3_program_surface_config( bool horizontal_mirror, unsigned int compat_level) { + (void)compat_level; struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); hubp3_dcc_control_sienna_cichlid(hubp, dcc); diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn35/dcn35_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn35/dcn35_hubp.c index 79c583e258c7..c879f4901c7d 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn35/dcn35_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn35/dcn35_hubp.c @@ -179,6 +179,7 @@ void hubp35_program_surface_config( bool horizontal_mirror, unsigned int compat_level) { + (void)compat_level; struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); hubp3_dcc_control_sienna_cichlid(hubp, dcc); diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c index 4985e885952d..5a816442deee 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c @@ -657,6 +657,7 @@ void hubp401_program_tiling( const struct dc_tiling_info *info, const enum surface_pixel_format pixel_format) { + (void)pixel_format; /* DCSURF_ADDR_CONFIG still shows up in reg spec, but does not need to be programmed for DCN4x * All 4 fields NUM_PIPES, PIPE_INTERLEAVE, MAX_COMPRESSED_FRAGS and NUM_PKRS are irrelevant. * @@ -671,6 +672,7 @@ void hubp401_program_size( const struct plane_size *plane_size, struct dc_plane_dcc_param *dcc) { + (void)dcc; struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); uint32_t pitch, pitch_c; bool use_pitch_c = false; @@ -709,6 +711,7 @@ void hubp401_program_surface_config( bool horizontal_mirror, unsigned int compat_level) { + (void)compat_level; struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); hubp401_dcc_control(hubp, dcc); @@ -812,9 +815,8 @@ void hubp401_cursor_set_position( int x_pos_viewport = 0; int x_hot_viewport = 0; uint32_t cur_en = pos->enable ? 1 : 0; - + uint32_t x_hotspot_clamped = pos->x_hotspot; hubp->curs_pos = *pos; - /* Recout is zero for pipes if the entire dst_rect is contained * within preceeding ODM slices. */ @@ -845,6 +847,8 @@ void hubp401_cursor_set_position( ASSERT(param->h_scale_ratio.value); + if (x_hotspot_clamped > 0xFF) + x_hotspot_clamped = 0xFF; if (param->h_scale_ratio.value) dst_x_offset = dc_fixpt_floor(dc_fixpt_div( dc_fixpt_from_int(dst_x_offset), @@ -865,7 +869,7 @@ void hubp401_cursor_set_position( CURSOR_Y_POSITION, pos->y); REG_SET_2(CURSOR_HOT_SPOT, 0, - CURSOR_HOT_SPOT_X, pos->x_hotspot, + CURSOR_HOT_SPOT_X, x_hotspot_clamped, CURSOR_HOT_SPOT_Y, pos->y_hotspot); REG_SET(CURSOR_DST_OFFSET, 0, diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c index 0e33c739f459..ad6badcceb12 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c @@ -245,6 +245,39 @@ static void hubp42_program_deadline( REFCYC_PER_VM_DMDATA, dlg_attr->refcyc_per_vm_dmdata); } +void hubp42_program_requestor( + struct hubp *hubp, + struct dml2_display_rq_regs *rq_regs) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, rq_regs->plane1_base_address); + REG_SET_4(DCN_EXPANSION_MODE, 0, + DRQ_EXPANSION_MODE, rq_regs->drq_expansion_mode, + PRQ_EXPANSION_MODE, rq_regs->prq_expansion_mode, + MRQ_EXPANSION_MODE, rq_regs->mrq_expansion_mode, + CRQ_EXPANSION_MODE, rq_regs->crq_expansion_mode); + REG_SET_8(DCHUBP_REQ_SIZE_CONFIG, 0, + CHUNK_SIZE, rq_regs->rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, rq_regs->rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, rq_regs->rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, rq_regs->rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, rq_regs->rq_regs_l.dpte_group_size, + VM_GROUP_SIZE, rq_regs->rq_regs_l.mpte_group_size, + SWATH_HEIGHT, rq_regs->rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, rq_regs->rq_regs_l.pte_row_height_linear); + REG_SET_7(DCHUBP_REQ_SIZE_CONFIG_C, 0, + CHUNK_SIZE_C, rq_regs->rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, rq_regs->rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, rq_regs->rq_regs_c.dpte_group_size, + SWATH_HEIGHT_C, rq_regs->rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, rq_regs->rq_regs_c.pte_row_height_linear); +} + + void hubp42_setup( struct hubp *hubp, struct dml2_dchub_per_pipe_register_set *pipe_regs, @@ -255,7 +288,7 @@ void hubp42_setup( * disable the requestors is not needed */ hubp401_vready_at_or_After_vsync(hubp, pipe_global_sync, timing); - hubp401_program_requestor(hubp, &pipe_regs->rq_regs); + hubp42_program_requestor(hubp, &pipe_regs->rq_regs); hubp42_program_deadline(hubp, &pipe_regs->dlg_regs, &pipe_regs->ttu_regs); } static void hubp42_program_surface_config( @@ -268,6 +301,7 @@ static void hubp42_program_surface_config( bool horizontal_mirror, unsigned int compat_level) { + (void)compat_level; struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); hubp3_dcc_control_sienna_cichlid(hubp, dcc); diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.h index 486c8907413a..88bb1337ab9d 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.h @@ -48,6 +48,8 @@ HUBP_SF(CURSOR0_0_HUBP_3DLUT_ADDRESS_LOW, HUBP_3DLUT_ADDRESS_LOW, mask_sh),\ HUBP_SF(CURSOR0_0_HUBP_3DLUT_DLG_PARAM, REFCYC_PER_3DLUT_GROUP, mask_sh) +struct dml2_display_rq_regs; + bool hubp42_construct( struct dcn20_hubp *hubp2, struct dc_context *ctx, @@ -64,6 +66,10 @@ void hubp42_program_3dlut_fl_config(struct hubp *hubp, void hubp42_read_state(struct hubp *hubp); +void hubp42_program_requestor( + struct hubp *hubp, + struct dml2_display_rq_regs *rq_regs); + void hubp42_setup( struct hubp *hubp, struct dml2_dchub_per_pipe_register_set *pipe_regs, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 8a17cc036399..5273ca09fe12 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -201,6 +201,8 @@ static void enable_display_pipe_clock_gating( struct dc_context *ctx, bool clock_gating) { + (void)ctx; + (void)clock_gating; /*TODO*/ } @@ -284,6 +286,7 @@ static bool dce110_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) { + (void)dc; struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; const struct dc_transfer_func *tf = NULL; struct ipp_prescale_params prescale_params = { 0 }; @@ -488,15 +491,15 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, seg_distr[8] = 4; seg_distr[9] = 4; seg_distr[10] = 0; - seg_distr[11] = -1; - seg_distr[12] = -1; - seg_distr[13] = -1; - seg_distr[14] = -1; - seg_distr[15] = -1; + seg_distr[11] = (uint32_t)-1; + seg_distr[12] = (uint32_t)-1; + seg_distr[13] = (uint32_t)-1; + seg_distr[14] = (uint32_t)-1; + seg_distr[15] = (uint32_t)-1; } for (k = 0; k < 16; k++) { - if (seg_distr[k] != -1) + if (seg_distr[k] != (uint32_t)-1) hw_points += (1 << seg_distr[k]); } @@ -607,6 +610,7 @@ static bool dce110_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) { + (void)dc; struct transform *xfm = pipe_ctx->plane_res.xfm; xfm->funcs->opp_power_on_regamma_lut(xfm, true); @@ -1539,6 +1543,7 @@ static enum dc_status dce110_enable_stream_timing( struct dc_state *context, struct dc *dc) { + (void)context; struct dc_stream_state *stream = pipe_ctx->stream; struct pipe_ctx *pipe_ctx_old = &dc->current_state->res_ctx. pipe_ctx[pipe_ctx->pipe_idx]; @@ -1568,7 +1573,7 @@ static enum dc_status dce110_enable_stream_timing( return DC_ERROR_UNEXPECTED; } - if (dc_is_hdmi_tmds_signal(stream->signal)) { + if (dc_is_tmds_signal(stream->signal)) { stream->link->phy_state.symclk_ref_cnts.otg = 1; if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; @@ -1986,7 +1991,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) struct pipe_ctx *pipe_ctx = NULL; struct dce_hwseq *hws = dc->hwseq; int edp_with_sink_num; - int edp_num; + unsigned int edp_num; int edp_stream_num; int i; bool can_apply_edp_fast_boot = false; @@ -2418,7 +2423,7 @@ static void dce110_reset_hw_ctx_wrap( BREAK_TO_DEBUGGER(); } pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg); - if (dc_is_hdmi_tmds_signal(pipe_ctx_old->stream->signal)) + if (dc_is_tmds_signal(pipe_ctx_old->stream->signal)) pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; pipe_ctx_old->plane_res.mi->funcs->free_mem_input( pipe_ctx_old->plane_res.mi, dc->current_state->stream_count); @@ -2728,6 +2733,7 @@ static void program_gamut_remap(struct pipe_ctx *pipe_ctx) static void update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) { + (void)dc; struct dc_plane_state *plane_state = pipe_ctx->plane_state; if (plane_state == NULL) @@ -2814,6 +2820,8 @@ static void dce110_enable_timing_synchronization( int group_size, struct pipe_ctx *grouped_pipes[]) { + (void)state; + (void)group_index; struct dcp_gsl_params gsl_params = { 0 }; int i; DC_LOGGER_INIT(dc->ctx); @@ -2889,6 +2897,8 @@ static void dce110_enable_per_frame_crtc_position_reset( static void dce110_init_pipes(struct dc *dc, struct dc_state *context) { + (void)context; + (void)dc; // Do nothing } @@ -3154,10 +3164,13 @@ static void dce110_post_unlock_program_front_end( struct dc *dc, struct dc_state *context) { + (void)dc; + (void)context; } static void dce110_power_down_fe(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx) { + (void)state; struct dce_hwseq *hws = dc->hwseq; int fe_idx = pipe_ctx->plane_res.mi ? pipe_ctx->plane_res.mi->inst : pipe_ctx->pipe_idx; @@ -3178,6 +3191,9 @@ static void dce110_wait_for_mpcc_disconnect( struct resource_pool *res_pool, struct pipe_ctx *pipe_ctx) { + (void)dc; + (void)res_pool; + (void)pipe_ctx; /* do nothing*/ } @@ -3187,6 +3203,10 @@ static void program_output_csc(struct dc *dc, uint16_t *matrix, int opp_id) { + (void)dc; + (void)colorspace; + (void)matrix; + (void)opp_id; int i; struct out_csc_color_matrix tbl_entry; @@ -3331,6 +3351,7 @@ void dce110_enable_lvds_link_output(struct dc_link *link, enum clock_source_id clock_source, uint32_t pixel_clock) { + (void)link_res; link->link_enc->funcs->enable_lvds_output( link->link_enc, clock_source, @@ -3345,6 +3366,7 @@ void dce110_enable_tmds_link_output(struct dc_link *link, enum dc_color_depth color_depth, uint32_t pixel_clock) { + (void)link_res; link->link_enc->funcs->enable_tmds_output( link->link_enc, clock_source, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.c index 2a62f63d0357..0689bbf12ad8 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.c @@ -154,6 +154,10 @@ static bool dce120_enable_display_power_gating( struct dc_bios *dcb, enum pipe_gating_control power_gating) { + (void)dc; + (void)controller_id; + (void)dcb; + (void)power_gating; /* disable for bringup */ #if 0 enum bp_result bp_result = BP_RESULT_OK; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index 17ff66d9a617..756ce8379538 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -86,6 +86,7 @@ static void print_microsec(struct dc_context *dc_ctx, struct dc_log_buffer_ctx *log_ctx, uint32_t ref_cycle) { + (void)log_ctx; const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; static const unsigned int frac = 1000; uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz; @@ -252,6 +253,7 @@ void dcn10_lock_all_pipes(struct dc *dc, static void log_mpc_crc(struct dc *dc, struct dc_log_buffer_ctx *log_ctx) { + (void)log_ctx; struct dc_context *dc_ctx = dc->ctx; struct dce_hwseq *hws = dc->hwseq; @@ -450,6 +452,7 @@ static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) static void dcn10_log_color_state(struct dc *dc, struct dc_log_buffer_ctx *log_ctx) { + (void)log_ctx; struct dc_context *dc_ctx = dc->ctx; struct resource_pool *pool = dc->res_pool; bool is_gamut_remap_available = false; @@ -813,6 +816,7 @@ void dcn10_log_hw_state(struct dc *dc, bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) { + (void)dc; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct timing_generator *tg = pipe_ctx->stream_res.tg; @@ -1181,6 +1185,7 @@ enum dc_status dcn10_enable_stream_timing( struct dc_state *context, struct dc *dc) { + (void)context; struct dc_stream_state *stream = pipe_ctx->stream; enum dc_color_space color_space; struct tg_color black_color = {0}; @@ -1284,6 +1289,7 @@ static void dcn10_reset_back_end_for_pipe( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + (void)context; int i; struct dc_link *link; DC_LOGGER_INIT(dc->ctx); @@ -1551,6 +1557,7 @@ void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) void dcn10_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx) { + (void)state; struct dce_hwseq *hws = dc->hwseq; DC_LOGGER_INIT(dc->ctx); @@ -1904,7 +1911,7 @@ void dcn10_power_down_on_boot(struct dc *dc) { struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link = NULL; - int edp_num; + unsigned int edp_num; int i = 0; dc_get_edp_links(dc, edp_links, &edp_num); @@ -2004,6 +2011,7 @@ static bool patch_address_for_sbs_tb_stereo( void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) { + (void)dc; bool addr_patched = false; PHYSICAL_ADDRESS_LOC addr; struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -2030,6 +2038,7 @@ void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) { + (void)dc; struct dpp *dpp_base = pipe_ctx->plane_res.dpp; const struct dc_transfer_func *tf = NULL; bool result = true; @@ -2472,6 +2481,7 @@ void dcn10_enable_vblanks_synchronization( int group_size, struct pipe_ctx *grouped_pipes[]) { + (void)group_index; struct output_pixel_processor *opp; struct timing_generator *tg; int i, width = 0, height = 0, master; @@ -2537,6 +2547,7 @@ void dcn10_enable_timing_synchronization( int group_size, struct pipe_ctx *grouped_pipes[]) { + (void)group_index; struct output_pixel_processor *opp; struct timing_generator *tg; int i, width = 0, height = 0; @@ -2641,6 +2652,7 @@ static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1, struct vm_system_aperture_param *apt, struct dce_hwseq *hws) { + (void)hubp1; PHYSICAL_ADDRESS_LOC physical_page_number; uint32_t logical_addr_low; uint32_t logical_addr_high; @@ -2666,6 +2678,7 @@ static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1, struct vm_context0_param *vm0, struct dce_hwseq *hws) { + (void)hubp1; PHYSICAL_ADDRESS_LOC fb_base; PHYSICAL_ADDRESS_LOC fb_offset; uint32_t fb_base_value; @@ -2724,6 +2737,7 @@ static void dcn10_enable_plane( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + (void)context; struct dce_hwseq *hws = dc->hwseq; if (dc->debug.sanity_checks) { @@ -2821,6 +2835,8 @@ void dcn10_program_output_csc(struct dc *dc, uint16_t *matrix, int opp_id) { + (void)dc; + (void)opp_id; if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) { @@ -3586,6 +3602,10 @@ bool dcn10_dummy_display_power_gating( struct dc_bios *dcb, enum pipe_gating_control power_gating) { + (void)dc; + (void)controller_id; + (void)dcb; + (void)power_gating; return true; } @@ -4052,6 +4072,7 @@ enum dc_status dcn10_set_clock(struct dc *dc, uint32_t clk_khz, uint32_t stepping) { + (void)stepping; struct dc_state *context = dc->current_state; struct dc_clock_config clock_cfg = {0}; struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index 307e8f8060e6..288e4edaa9a2 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -75,6 +75,7 @@ void dcn20_log_color_state(struct dc *dc, struct dc_log_buffer_ctx *log_ctx) { + (void)log_ctx; struct dc_context *dc_ctx = dc->ctx; struct resource_pool *pool = dc->res_pool; bool is_gamut_remap_available = false; @@ -379,6 +380,7 @@ void dcn20_program_triple_buffer( struct pipe_ctx *pipe_ctx, bool enable_triple_buffer) { + (void)dc; if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) { pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer( pipe_ctx->plane_res.hubp, @@ -893,7 +895,7 @@ enum dc_status dcn20_enable_stream_timing( dccg->funcs->set_dtbclk_dto(dccg, &dto_params); } - if (dc_is_hdmi_tmds_signal(stream->signal)) { + if (dc_is_tmds_signal(stream->signal)) { stream->link->phy_state.symclk_ref_cnts.otg = 1; if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; @@ -1175,6 +1177,8 @@ bool dcn20_set_input_transfer_func(struct dc *dc, void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) { + (void)context; + (void)dc; struct pipe_ctx *odm_pipe; int opp_cnt = 1; int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; @@ -1297,6 +1301,7 @@ static void dcn20_power_on_plane_resources( void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { + (void)context; //if (dc->debug.sanity_checks) { // dcn10_verify_allow_pstate_change_high(dc); //} @@ -2652,6 +2657,7 @@ void dcn20_init_vm_ctx( struct dc_virtual_addr_space_config *va_config, int vmid) { + (void)hws; struct dcn_hubbub_virt_addr_config config; if (vmid == 0) { @@ -2670,6 +2676,7 @@ void dcn20_init_vm_ctx( int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) { + (void)hws; struct dcn_hubbub_phys_addr_config config; config.system_aperture.fb_top = pa_config->system_aperture.fb_top; @@ -2799,6 +2806,7 @@ void dcn20_reset_back_end_for_pipe( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + (void)context; struct dc_link *link = pipe_ctx->stream->link; const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); struct dccg *dccg = dc->res_pool->dccg; @@ -2856,7 +2864,7 @@ void dcn20_reset_back_end_for_pipe( * the case where the same symclk is shared across multiple otg * instances */ - if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) + if (dc_is_tmds_signal(pipe_ctx->stream->signal)) link->phy_state.symclk_ref_cnts.otg = 0; if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { link_hwss->disable_link_output(link, @@ -3245,6 +3253,7 @@ void dcn20_set_disp_pattern_generator(const struct dc *dc, const struct tg_color *solid_color, int width, int height, int offset) { + (void)dc; pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern, color_space, color_depth, solid_color, width, height, offset); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index d04cfd403b7e..2aa0f1de8103 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -75,6 +75,7 @@ void dcn30_log_color_state(struct dc *dc, struct dc_log_buffer_ctx *log_ctx) { + (void)log_ctx; struct dc_context *dc_ctx = dc->ctx; struct resource_pool *pool = dc->res_pool; bool is_gamut_remap_available = false; @@ -645,7 +646,7 @@ void dcn30_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; int i; - int edp_num; + unsigned int edp_num; uint32_t backlight = MAX_BACKLIGHT_LEVEL; uint32_t user_level = MAX_BACKLIGHT_LEVEL; @@ -1183,6 +1184,7 @@ void dcn30_set_disp_pattern_generator(const struct dc *dc, const struct tg_color *solid_color, int width, int height, int offset) { + (void)dc; pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern, color_space, color_depth, solid_color, width, height, offset); } @@ -1237,6 +1239,7 @@ void dcn30_get_underflow_debug_data(const struct dc *dc, struct timing_generator *tg, struct dc_underflow_debug_data *out_data) { + (void)tg; struct hubbub *hubbub = dc->res_pool->hubbub; if (hubbub) { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.c index 3bc56ac346f3..6e1877a8682d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.c @@ -45,20 +45,31 @@ void dcn303_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) { + (void)dpp_inst; + (void)hws; + (void)power_on; /*DCN303 removes PG registers*/ } void dcn303_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) { + (void)hubp_inst; + (void)hws; + (void)power_on; /*DCN303 removes PG registers*/ } void dcn303_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on) { + (void)dsc_inst; + (void)hws; + (void)power_on; /*DCN303 removes PG registers*/ } void dcn303_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) { + (void)enable; + (void)hws; /*DCN303 removes PG registers*/ } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c index 94f63fd54e3e..b4afb2bc4493 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -484,6 +484,7 @@ void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool p int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) { + (void)hws; struct dcn_hubbub_phys_addr_config config = {0}; config.system_aperture.fb_top = pa_config->system_aperture.fb_top; @@ -511,6 +512,7 @@ static void dcn31_reset_back_end_for_pipe( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + (void)context; struct dc_link *link; if (pipe_ctx->stream_res.stream_enc == NULL) { @@ -548,7 +550,7 @@ static void dcn31_reset_back_end_for_pipe( * the case where the same symclk is shared across multiple otg * instances */ - if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) + if (dc_is_tmds_signal(pipe_ctx->stream->signal)) link->phy_state.symclk_ref_cnts.otg = 0; if (pipe_ctx->top_pipe == NULL) { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c index 3e239124c17d..858a06b03b57 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c @@ -172,6 +172,7 @@ static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_ void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) { + (void)context; struct pipe_ctx *odm_pipe; int opp_cnt = 0; int opp_inst[MAX_PIPES] = {0}; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index a0aaa727e9fa..b45ceb570a5c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -570,6 +570,7 @@ bool dcn32_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) { + (void)dc; int mpcc_id = pipe_ctx->plane_res.hubp->inst; struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; const struct pwl_params *params = NULL; @@ -757,6 +758,9 @@ static void dcn32_initialize_min_clocks(struct dc *dc) { struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk; + if (!dc->clk_mgr || !dc->clk_mgr->bw_params || !dc->clk_mgr->funcs) + return; + clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ; clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000; clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000; @@ -765,9 +769,10 @@ static void dcn32_initialize_min_clocks(struct dc *dc) clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; clocks->fclk_p_state_change_support = true; clocks->p_state_change_support = true; + if (dc->debug.disable_boot_optimizations) { clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000; - } else { + } else if (dc->clk_mgr->funcs->get_dispclk_from_dentist) { /* Even though DPG_EN = 1 for the connected display, it still requires the * correct timing so we cannot set DISPCLK to min freq or it could cause * audio corruption. Read current DISPCLK from DENTIST and request the same @@ -776,10 +781,10 @@ static void dcn32_initialize_min_clocks(struct dc *dc) clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr); } - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - dc->current_state, - true); + if (dc->clk_mgr->funcs->update_clocks) + dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, + dc->current_state, + true); } void dcn32_init_hw(struct dc *dc) @@ -789,7 +794,7 @@ void dcn32_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; int i; - int edp_num; + unsigned int edp_num; uint32_t backlight = MAX_BACKLIGHT_LEVEL; uint32_t user_level = MAX_BACKLIGHT_LEVEL; @@ -1007,7 +1012,8 @@ void dcn32_init_hw(struct dc *dc) DMUB_FW_VERSION(7, 0, 35)) { /* FAMS2 is disabled */ dc->debug.fams2_config.bits.enable = false; - if (dc->debug.using_dml2 && dc->res_pool->funcs->update_bw_bounding_box) { + if (dc->debug.using_dml2 && dc->res_pool->funcs->update_bw_bounding_box && + dc->clk_mgr && dc->clk_mgr->bw_params) { /* update bounding box if FAMS2 disabled */ dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params); } @@ -1138,6 +1144,7 @@ static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) { + (void)context; struct pipe_ctx *odm_pipe; int opp_cnt = 0; int opp_inst[MAX_PIPES] = {0}; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index b5f60f59382e..f133b52ea958 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -428,6 +428,7 @@ static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) { + (void)context; struct pipe_ctx *odm_pipe; int opp_cnt = 0; int opp_inst[MAX_PIPES] = {0}; @@ -520,7 +521,7 @@ void dcn35_power_down_on_boot(struct dc *dc) { struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link = NULL; - int edp_num; + unsigned int edp_num; int i = 0; dc_get_edp_links(dc, edp_links, &edp_num); @@ -816,6 +817,7 @@ void dcn35_init_pipes(struct dc *dc, struct dc_state *context) void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { + (void)context; struct dpp *dpp = pipe_ctx->plane_res.dpp; /* enable DCFCLK current DCHUB */ @@ -921,7 +923,7 @@ void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, bool hpo_frl_stream_enc_acquired = false; bool hpo_dp_stream_enc_acquired = false; int i = 0, j = 0; - int edp_num = 0; + unsigned int edp_num = 0; struct dc_link *edp_links[MAX_NUM_EDP] = { NULL }; memset(update_state, 0, sizeof(struct pg_block_update)); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index 357899116ecd..9768b8f6b6fb 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -140,9 +140,10 @@ void dcn401_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; int i; - int edp_num; + unsigned int edp_num; uint32_t backlight = MAX_BACKLIGHT_LEVEL; uint32_t user_level = MAX_BACKLIGHT_LEVEL; + bool dchub_ref_freq_changed; int current_dchub_ref_freq = 0; if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) { @@ -357,20 +358,25 @@ void dcn401_init_hw(struct dc *dc) dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0; dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver; + + /* sw and fw FAMS versions must match for support */ dc->debug.fams2_config.bits.enable &= - dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support - if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box) - || res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) { + dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; + dchub_ref_freq_changed = + res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq; + if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) && + dc->res_pool->funcs->update_bw_bounding_box && + dc->clk_mgr && dc->clk_mgr->bw_params) { /* update bounding box if FAMS2 disabled, or if dchub clk has changed */ - if (dc->clk_mgr) - dc->res_pool->funcs->update_bw_bounding_box(dc, - dc->clk_mgr->bw_params); + dc->res_pool->funcs->update_bw_bounding_box(dc, + dc->clk_mgr->bw_params); } } } void dcn401_trigger_3dlut_dma_load(struct dc *dc, struct pipe_ctx *pipe_ctx) { + (void)dc; struct hubp *hubp = pipe_ctx->plane_res.hubp; if (hubp->funcs->hubp_enable_3dlut_fl) { @@ -551,6 +557,7 @@ bool dcn401_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) { + (void)dc; int mpcc_id = pipe_ctx->plane_res.hubp->inst; struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; const struct pwl_params *params = NULL; @@ -612,6 +619,7 @@ static void enable_stream_timing_calc( struct drr_params *params, unsigned int *event_triggers) { + (void)dc; struct dc_stream_state *stream = pipe_ctx->stream; int i; @@ -1389,6 +1397,7 @@ void dcn401_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock) { + (void)context; /* use always for now */ union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; @@ -1863,6 +1872,7 @@ void dcn401_reset_back_end_for_pipe( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + (void)context; struct dc_link *link = pipe_ctx->stream->link; const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); @@ -1918,7 +1928,7 @@ void dcn401_reset_back_end_for_pipe( * the case where the same symclk is shared across multiple otg * instances */ - if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) + if (dc_is_tmds_signal(pipe_ctx->stream->signal)) link->phy_state.symclk_ref_cnts.otg = 0; if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { link_hwss->disable_link_output(link, @@ -3238,6 +3248,7 @@ void dcn401_update_writeback_sequence( struct dc_state *context, struct block_sequence_state *seq_state) { + (void)context; struct dwbc *dwb; struct mcif_wb *mcif_wb; @@ -3443,6 +3454,7 @@ void dcn401_enable_plane_sequence(struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context, struct block_sequence_state *seq_state) { + (void)context; struct dce_hwseq *hws = dc->hwseq; uint32_t org_ip_request_cntl = 0; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c index 8e12dc1297c4..46f2f9833d9e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c @@ -66,9 +66,10 @@ void dcn42_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; int i; - int edp_num; + unsigned int edp_num; uint32_t backlight = MAX_BACKLIGHT_LEVEL; uint32_t user_level = MAX_BACKLIGHT_LEVEL; + bool dchub_ref_freq_changed; int current_dchub_ref_freq = 0; if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) { @@ -203,7 +204,8 @@ void dcn42_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; - if (link->link_enc->funcs->is_dig_enabled && + if (link && link->link_enc && + link->link_enc->funcs->is_dig_enabled && link->link_enc->funcs->is_dig_enabled(link->link_enc) && hws->funcs.power_down) { hws->funcs.power_down(dc); @@ -260,8 +262,12 @@ void dcn42_init_hw(struct dc *dc) if (dc->res_pool->hubbub->funcs->init_crb) dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); - if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0) - dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->clk_mgr->bw_params->num_channels, dc->config.sdpif_request_limit_words_per_umc); + if (dc->res_pool->hubbub->funcs->set_request_limit && + dc->clk_mgr && dc->clk_mgr->bw_params && + dc->config.sdpif_request_limit_words_per_umc > 0) + dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, + dc->clk_mgr->bw_params->num_channels, + dc->config.sdpif_request_limit_words_per_umc); // Get DMCUB capabilities if (dc->ctx->dmub_srv) { @@ -269,13 +275,18 @@ void dcn42_init_hw(struct dc *dc) dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0; dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver; + + /* sw and fw FAMS versions must match for support */ dc->debug.fams2_config.bits.enable &= - dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support - if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box) - || res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) { + dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; + dchub_ref_freq_changed = + res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq; + + if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) && + dc->res_pool->funcs->update_bw_bounding_box && + dc->clk_mgr && dc->clk_mgr->bw_params) { /* update bounding box if FAMS2 disabled, or if dchub clk has changed */ - if (dc->clk_mgr) - dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params); + dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params); } } if (dc->res_pool->pg_cntl) { @@ -375,6 +386,7 @@ void dcn42_program_cm_hist( struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) { + (void)dc; struct dpp *dpp = pipe_ctx->plane_res.dpp; if (dpp && dpp->funcs->dpp_cm_hist_control) @@ -989,6 +1001,7 @@ void dcn42_root_clock_control(struct dc *dc, } void dcn42_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) { + (void)dc; struct crtc_stereo_flags flags = { 0 }; struct dc_stream_state *stream = pipe_ctx->stream; @@ -1052,7 +1065,7 @@ void dcn42_power_down_on_boot(struct dc *dc) { struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link = NULL; - int edp_num; + unsigned int edp_num; int i = 0; dc_get_edp_links(dc, edp_links, &edp_num); diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 43579b0e1482..e960ca9062ad 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -214,6 +214,7 @@ struct resource_funcs { unsigned int index); void (*get_panel_config_defaults)(struct dc_panel_config *panel_config); + void (*get_default_tiling_info)(struct dc_tiling_info *tiling_info); void (*build_pipe_pix_clk_params)(struct pipe_ctx *pipe_ctx); /* * Get indicator of power from a context that went through full validation diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index b152f6879495..51581c10fd6b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -256,7 +256,7 @@ struct default_adjustment { enum dc_color_space out_color_space; enum dc_color_space in_color_space; enum dc_color_depth color_depth; - enum pixel_format surface_pixel_format; + enum dc_pixel_format surface_pixel_format; enum graphics_csc_adjust_type csc_adjust_type; bool force_hw_default; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h index 5a1d9b708a9d..30990355985d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h @@ -160,7 +160,7 @@ struct scaler_data { struct scaling_ratios ratios; struct scl_inits inits; struct sharpness_adj sharpness; - enum pixel_format format; + enum dc_pixel_format format; struct line_buffer_params lb_params; // Below struct holds the scaler values to program hw registers struct dscl_prog_data dscl_prog_data; diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c index 676df39079fc..015f3659cf77 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c @@ -92,7 +92,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\ .enable_value = {\ DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\ - ~DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK\ + (uint32_t)~DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK\ },\ .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\ @@ -107,7 +107,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\ .enable_value = {\ DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\ - ~DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK },\ + (uint32_t)~DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK },\ .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\ .ack_value = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\ @@ -121,7 +121,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ .enable_value = {\ GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ - ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\ + (uint32_t)~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\ .ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\ .ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ .ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ @@ -136,7 +136,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ .enable_value = {\ CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ - ~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\ + (uint32_t)~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\ .ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\ .ack_mask =\ CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\ @@ -152,7 +152,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ .enable_value = {\ CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ - ~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\ + (uint32_t)~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\ .ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ .ack_mask =\ CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ @@ -183,6 +183,7 @@ bool dal_irq_service_dummy_set(struct irq_service *irq_service, const struct irq_source_info *info, bool enable) { + (void)enable; DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n", __func__, info->src_id, info->ext_id); @@ -328,6 +329,7 @@ enum dc_irq_source to_dal_irq_source_dce110( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; switch (src_id) { case VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0: return DC_IRQ_SOURCE_VBLANK1; diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c b/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c index b473dae2abbb..dbab6e3737a1 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c @@ -79,7 +79,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c b/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c index b5c5f42cf8f2..3e19dfdd0474 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c @@ -68,7 +68,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { .enable_mask = DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK,\ .enable_value = {\ DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK,\ - ~DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK\ + (uint32_t)~DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK\ },\ .ack_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\ .ack_mask = DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK,\ @@ -83,7 +83,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { .enable_mask = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK,\ .enable_value = {\ DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK,\ - ~DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK },\ + (uint32_t)~DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK },\ .ack_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\ .ack_mask = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_ACK_MASK,\ .ack_value = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_ACK_MASK,\ @@ -98,7 +98,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ .enable_value = {\ GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ - ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\ + (uint32_t)~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\ .ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\ .ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ .ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ @@ -113,7 +113,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ .enable_value = {\ CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ - ~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\ + (uint32_t)~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\ .ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\ .ack_mask =\ CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\ @@ -129,7 +129,7 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = { CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ .enable_value = {\ CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ - ~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\ + (uint32_t)~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\ .ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ .ack_mask =\ CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c index ca2e13702fbb..0bdb62b883aa 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c @@ -42,6 +42,9 @@ static enum dc_irq_source to_dal_irq_source_dcn10(struct irq_service *irq_servic uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -176,7 +179,7 @@ static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c index 1c4c51abc259..8a0f4b5d6956 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c @@ -43,6 +43,9 @@ static enum dc_irq_source to_dal_irq_source_dcn20( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -179,7 +182,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c index 9e0881472e38..9d13c0cc91f0 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c @@ -42,6 +42,9 @@ static enum dc_irq_source to_dal_irq_source_dcn21(struct irq_service *irq_servic uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -189,7 +192,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c index 92bcd35723ca..78338af86666 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c @@ -50,6 +50,9 @@ static enum dc_irq_source to_dal_irq_source_dcn30( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -196,7 +199,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c b/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c index 16685d066c1a..2f47a9fbcd43 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn302/irq_service_dcn302.c @@ -37,6 +37,9 @@ static enum dc_irq_source to_dal_irq_source_dcn302(struct irq_service *irq_service, uint32_t src_id, uint32_t ext_id) { + (void)ext_id; + (void)irq_service; + (void)src_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -180,7 +183,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { .enable_mask = block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\ @@ -199,7 +202,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ reg1 ## __ ## mask1 ## _MASK,\ - ~reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI_DMUB(reg2),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c index 01d83e1922d6..236a7278a8cf 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c @@ -38,6 +38,9 @@ static enum dc_irq_source to_dal_irq_source_dcn303(struct irq_service *irq_servi uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -123,7 +126,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { .enable_mask = block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c index 2114c5669e6e..213e5da31b19 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn31/irq_service_dcn31.c @@ -40,6 +40,9 @@ static enum dc_irq_source to_dal_irq_source_dcn31(struct irq_service *irq_servic uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -184,7 +187,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ @@ -198,7 +201,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ reg1 ## __ ## mask1 ## _MASK,\ - ~reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI_DMUB(reg2),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c b/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c index 16f158e0fb60..8aacc229b002 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn314/irq_service_dcn314.c @@ -42,6 +42,9 @@ static enum dc_irq_source to_dal_irq_source_dcn314(struct irq_service *irq_servi uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -186,7 +189,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ @@ -200,7 +203,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ reg1 ## __ ## mask1 ## _MASK,\ - ~reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI_DMUB(reg2),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c index 8ee03c006ad6..b3bddc87afed 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c @@ -47,6 +47,9 @@ static enum dc_irq_source to_dal_irq_source_dcn315( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -191,7 +194,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ @@ -205,7 +208,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ reg1 ## __ ## mask1 ## _MASK,\ - ~reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI_DMUB(reg2),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c index 07e6f7dd6b99..f407ba72acdb 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c @@ -41,6 +41,9 @@ static enum dc_irq_source to_dal_irq_source_dcn32( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -195,7 +198,7 @@ static struct irq_source_info_funcs vline2_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ @@ -209,7 +212,7 @@ static struct irq_source_info_funcs vline2_irq_info_funcs = { reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ reg1 ## __ ## mask1 ## _MASK,\ - ~reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI_DMUB(reg2),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c b/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c index 3d28a5007f53..2f2985075f88 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn35/irq_service_dcn35.c @@ -39,6 +39,9 @@ static enum dc_irq_source to_dal_irq_source_dcn35( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -184,7 +187,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { REG_STRUCT[base + reg_num].enable_value[0] = \ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ REG_STRUCT[base + reg_num].enable_value[1] = \ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK, \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK, \ REG_STRUCT[base + reg_num].ack_reg = SRI(reg2, block, reg_num),\ REG_STRUCT[base + reg_num].ack_mask = \ block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\ @@ -198,7 +201,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { REG_STRUCT[base].enable_value[0] = \ reg1 ## __ ## mask1 ## _MASK,\ REG_STRUCT[base].enable_value[1] = \ - ~reg1 ## __ ## mask1 ## _MASK, \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK, \ REG_STRUCT[base].ack_reg = SRI_DMUB(reg2),\ REG_STRUCT[base].ack_mask = \ reg2 ## __ ## mask2 ## _MASK,\ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c b/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c index f716c2590876..1ed75b53e131 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn351/irq_service_dcn351.c @@ -18,6 +18,9 @@ static enum dc_irq_source to_dal_irq_source_dcn351( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -163,7 +166,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { REG_STRUCT[base + reg_num].enable_value[0] = \ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ REG_STRUCT[base + reg_num].enable_value[1] = \ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK, \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK, \ REG_STRUCT[base + reg_num].ack_reg = SRI(reg2, block, reg_num),\ REG_STRUCT[base + reg_num].ack_mask = \ block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\ @@ -177,7 +180,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { REG_STRUCT[base].enable_value[0] = \ reg1 ## __ ## mask1 ## _MASK,\ REG_STRUCT[base].enable_value[1] = \ - ~reg1 ## __ ## mask1 ## _MASK, \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK, \ REG_STRUCT[base].ack_reg = SRI_DMUB(reg2),\ REG_STRUCT[base].ack_mask = \ reg2 ## __ ## mask2 ## _MASK,\ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c b/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c index e718004901cf..4c321c26f02f 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c @@ -17,6 +17,9 @@ static enum dc_irq_source to_dal_irq_source_dcn36( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -162,7 +165,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { REG_STRUCT[base + reg_num].enable_value[0] = \ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ REG_STRUCT[base + reg_num].enable_value[1] = \ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK, \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK, \ REG_STRUCT[base + reg_num].ack_reg = SRI(reg2, block, reg_num),\ REG_STRUCT[base + reg_num].ack_mask = \ block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\ @@ -176,7 +179,7 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { REG_STRUCT[base].enable_value[0] = \ reg1 ## __ ## mask1 ## _MASK,\ REG_STRUCT[base].enable_value[1] = \ - ~reg1 ## __ ## mask1 ## _MASK, \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK, \ REG_STRUCT[base].ack_reg = SRI_DMUB(reg2),\ REG_STRUCT[base].ack_mask = \ reg2 ## __ ## mask2 ## _MASK,\ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c index 2cde50b2ae22..059c5c636fd9 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c @@ -20,6 +20,9 @@ static enum dc_irq_source to_dal_irq_source_dcn401( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -175,7 +178,7 @@ static struct irq_source_info_funcs vline2_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ @@ -189,7 +192,7 @@ static struct irq_source_info_funcs vline2_irq_info_funcs = { reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ reg1 ## __ ## mask1 ## _MASK,\ - ~reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI_DMUB(reg2),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c b/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c index 19e0741c62cd..f4d1ce9079de 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn42/irq_service_dcn42.c @@ -19,6 +19,9 @@ static enum dc_irq_source to_dal_irq_source_dcn42( uint32_t src_id, uint32_t ext_id) { + (void)irq_service; + (void)src_id; + (void)ext_id; switch (src_id) { case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: return DC_IRQ_SOURCE_VBLANK1; @@ -173,7 +176,7 @@ static struct irq_source_info_funcs vline2_irq_info_funcs = { block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ - ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI(reg2, block, reg_num),\ .ack_mask = \ @@ -187,7 +190,7 @@ static struct irq_source_info_funcs vline2_irq_info_funcs = { reg1 ## __ ## mask1 ## _MASK,\ .enable_value = {\ reg1 ## __ ## mask1 ## _MASK,\ - ~reg1 ## __ ## mask1 ## _MASK \ + (uint32_t)~reg1 ## __ ## mask1 ## _MASK \ },\ .ack_reg = SRI_DMUB(reg2),\ .ack_mask = \ diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c index 693d852b1c40..060460abc377 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c @@ -66,6 +66,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link, struct dc_link_settings *link_setting, bool skip_video_pattern) { + (void)skip_video_pattern; struct pipe_ctx *pipes[MAX_PIPES]; struct dc_state *state = link->dc->current_state; struct dc_stream_update stream_update = { 0 }; @@ -483,6 +484,7 @@ static void set_crtc_test_pattern(struct dc_link *link, enum dp_test_pattern test_pattern, enum dp_test_pattern_color_space test_pattern_color_space) { + (void)test_pattern_color_space; enum controller_dp_test_pattern controller_test_pattern; enum dc_color_depth color_depth = pipe_ctx-> stream->timing.display_color_depth; diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c index 81bf3c5e1fdf..2a87b23582f3 100644 --- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c @@ -81,6 +81,10 @@ static void set_dio_dpia_lane_settings(struct dc_link *link, const struct dc_link_settings *link_settings, const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) { + (void)link; + (void)link_res; + (void)link_settings; + (void)lane_settings; } static void enable_dpia_link_output(struct dc_link *link, @@ -145,13 +149,9 @@ static void disable_dpia_link_output(struct dc_link *link, } static const struct link_hwss dpia_link_hwss = { - .setup_stream_encoder = setup_dio_stream_encoder, - .reset_stream_encoder = reset_dio_stream_encoder, - .setup_stream_attribute = setup_dio_stream_attribute, - .disable_link_output = disable_dpia_link_output, - .setup_audio_output = setup_dio_audio_output, - .enable_audio_packet = enable_dio_audio_packet, - .disable_audio_packet = disable_dio_audio_packet, + /* Ensure initialization order matches the declaration in link_hwss.h + * for strict compiler compliance and consistency across HWSS implementations + */ .ext = { .set_throttled_vcp_size = set_dio_throttled_vcp_size, .enable_dp_link_output = enable_dpia_link_output, @@ -159,6 +159,14 @@ static const struct link_hwss dpia_link_hwss = { .set_dp_lane_settings = set_dio_dpia_lane_settings, .update_stream_allocation_table = update_dpia_stream_allocation_table, }, + + .setup_stream_encoder = setup_dio_stream_encoder, + .reset_stream_encoder = reset_dio_stream_encoder, + .setup_stream_attribute = setup_dio_stream_attribute, + .disable_link_output = disable_dpia_link_output, + .setup_audio_output = setup_dio_audio_output, + .enable_audio_packet = enable_dio_audio_packet, + .disable_audio_packet = disable_dio_audio_packet, }; bool can_use_dpia_link_hwss(const struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c index cec68c5dba13..dbbedeeed298 100644 --- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c +++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c @@ -110,6 +110,8 @@ void enable_hpo_dp_link_output(struct dc_link *link, enum clock_source_id clock_source, const struct dc_link_settings *link_settings) { + (void)signal; + (void)clock_source; if (!link_res->hpo_dp_link_enc) { DC_LOG_ERROR("%s: invalid hpo_dp_link_enc\n", __func__); return; @@ -160,6 +162,7 @@ static void set_hpo_dp_lane_settings(struct dc_link *link, const struct dc_link_settings *link_settings, const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) { + (void)link; link_res->hpo_dp_link_enc->funcs->set_ffe( link_res->hpo_dp_link_enc, link_settings, @@ -170,6 +173,7 @@ void update_hpo_dp_stream_allocation_table(struct dc_link *link, const struct link_resource *link_res, const struct link_mst_stream_allocation_table *table) { + (void)link; link_res->hpo_dp_link_enc->funcs->update_stream_allocation_table( link_res->hpo_dp_link_enc, table); @@ -178,6 +182,7 @@ void update_hpo_dp_stream_allocation_table(struct dc_link *link, void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx, struct audio_output *audio_output, uint32_t audio_inst) { + (void)audio_output; pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup( pipe_ctx->stream_res.hpo_dp_stream_enc, audio_inst, @@ -218,6 +223,7 @@ static const struct link_hwss hpo_dp_link_hwss = { bool can_use_hpo_dp_link_hwss(const struct dc_link *link, const struct link_resource *link_res) { + (void)link; return link_res->hpo_dp_link_enc != NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.c index 55c5148de800..6d5b7450b205 100644 --- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.c +++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.c @@ -74,6 +74,7 @@ static void dp_hpo_fixed_vs_pe_retimer_set_tx_ffe(struct dc_link *link, static void dp_hpo_fixed_vs_pe_retimer_program_override_test_pattern(struct dc_link *link, struct encoder_set_dp_phy_pattern_param *tp_params) { + (void)tp_params; uint8_t clk_src = 0xC4; uint8_t pattern = 0x4F; /* SQ128 */ diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_virtual.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_virtual.c index 64742c24f7e6..3aa1375cec71 100644 --- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_virtual.c +++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_virtual.c @@ -27,20 +27,26 @@ void virtual_setup_stream_encoder(struct pipe_ctx *pipe_ctx) { + (void)pipe_ctx; } void virtual_setup_stream_attribute(struct pipe_ctx *pipe_ctx) { + (void)pipe_ctx; } void virtual_reset_stream_encoder(struct pipe_ctx *pipe_ctx) { + (void)pipe_ctx; } static void virtual_disable_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal) { + (void)link; + (void)link_res; + (void)signal; } static const struct link_hwss virtual_link_hwss = { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index f992c2d16748..59851924bfcd 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -784,6 +784,7 @@ static void verify_link_capability_destructive(struct dc_link *link, struct dc_sink *sink, enum dc_detect_reason reason) { + (void)sink; bool should_prepare_phy_clocks = should_prepare_phy_clocks_for_link_verification(link->dc, reason); @@ -822,6 +823,7 @@ static void verify_link_capability_non_destructive(struct dc_link *link) static bool should_verify_link_capability_destructively(struct dc_link *link, enum dc_detect_reason reason) { + (void)reason; bool destrictive = false; struct dc_link_settings max_link_cap; bool is_link_enc_unavailable = false; diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c b/drivers/gpu/drm/amd/display/dc/link/link_validation.c index acdc162de535..eb791285ed06 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_validation.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c @@ -391,6 +391,7 @@ static const struct dc_tunnel_settings *get_dp_tunnel_settings(const struct dc_s */ enum dc_status link_validate_dp_tunnel_bandwidth(const struct dc *dc, const struct dc_state *new_ctx) { + (void)dc; struct dc_validation_dpia_set dpia_link_sets[MAX_DPIA_NUM] = { 0 }; uint8_t link_count = 0; enum dc_status result = DC_OK; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c index 08e2b572e0ff..ddff0db4ce70 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c @@ -554,6 +554,7 @@ enum link_training_result dp_check_link_loss_status( struct dc_link *link, const struct link_training_settings *link_training_setting) { + (void)link_training_setting; enum link_training_result status = LINK_TRAINING_SUCCESS; union lane_status lane_status; union lane_align_status_updated dpcd_lane_status_updated; @@ -1387,6 +1388,7 @@ bool dp_set_hw_training_pattern( enum dc_dp_training_pattern pattern, uint32_t offset) { + (void)offset; enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; switch (pattern) { diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c index 11565f187ac7..1a6bfc45927d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c @@ -158,6 +158,7 @@ static enum link_training_result dp_perform_128b_132b_cds_done_sequence( const struct link_resource *link_res, struct link_training_settings *lt_settings) { + (void)link_res; /* Assumption: assume hardware has transmitted eq pattern */ enum dc_status status = DC_OK; enum link_training_result result = LINK_TRAINING_SUCCESS; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c index 603537ffd128..34fa76d97b83 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c @@ -172,6 +172,7 @@ static uint8_t dpia_build_set_config_data( struct dc_link *link, struct link_training_settings *lt_settings) { + (void)link; union dpia_set_config_data data; data.raw = 0; @@ -290,6 +291,7 @@ static enum link_training_result dpia_training_cr_non_transparent( struct link_training_settings *lt_settings, uint32_t hop) { + (void)link_res; enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0; uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */ enum dc_status status = DC_ERROR_UNEXPECTED; @@ -457,6 +459,7 @@ static enum link_training_result dpia_training_cr_transparent( const struct link_resource *link_res, struct link_training_settings *lt_settings) { + (void)link_res; enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0; enum dc_status status; uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */ @@ -585,6 +588,7 @@ static enum link_training_result dpia_training_eq_non_transparent( struct link_training_settings *lt_settings, uint32_t hop) { + (void)link_res; enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ; uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */ uint32_t retries_eq = 0; @@ -730,6 +734,7 @@ static enum link_training_result dpia_training_eq_transparent( const struct link_resource *link_res, struct link_training_settings *lt_settings) { + (void)link_res; enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ; uint32_t retries_eq = 0; enum dc_status status; @@ -991,6 +996,7 @@ enum link_training_result dpia_perform_link_training( const struct dc_link_settings *link_setting, bool skip_video_pattern) { + (void)skip_video_pattern; enum link_training_result result; struct link_training_settings lt_settings = {0}; uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c index 584b9295a12a..e4c2aa2bc364 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c @@ -180,6 +180,7 @@ static void dpcd_reduce_address_range( uint8_t * const reduced_data, const uint32_t reduced_size) { + (void)extended_size; const uint32_t offset = reduced_address - extended_address; /* diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c index 6bfd2c1294e5..4c7bb0522a8c 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c @@ -117,6 +117,9 @@ void mpc3_set_out_rate_control( bool rate_2x_mode, struct mpc_dwb_flow_control *flow_control) { + (void)enable; + (void)rate_2x_mode; + (void)flow_control; struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); /* Always disable mpc out rate and flow control. @@ -908,6 +911,7 @@ static void mpc3_set_3dlut_mode( bool is_lut_size17x17x17, uint32_t rmu_idx) { + (void)is_color_channel_12bits; uint32_t lut_mode; struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); @@ -1428,7 +1432,7 @@ uint32_t mpcc3_acquire_rmu(struct mpc *mpc, int mpcc_id, int rmu_idx) } //no vacant RMU units or invalid parameters acquire_post_bldn_3dlut - return -1; + return (uint32_t)-1; } static int mpcc3_release_rmu(struct mpc *mpc, int mpcc_id) diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c index badcef027b84..1f15ada109b6 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c @@ -884,6 +884,7 @@ void mpc32_set_3dlut_mode( bool is_lut_size17x17x17, uint32_t mpcc_id) { + (void)is_color_channel_12bits; uint32_t lut_mode; struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); diff --git a/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c index 45d418636d0c..b49bd155cad4 100644 --- a/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c +++ b/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c @@ -250,6 +250,7 @@ void opp1_set_dyn_expansion( enum dc_color_depth color_dpth, enum signal_type signal) { + (void)color_sp; struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp); REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c index 6f7b0f816f2a..9e66b9b97c63 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c @@ -164,6 +164,7 @@ void optc1_program_timing( const enum signal_type signal, bool use_vbios) { + (void)use_vbios; struct dc_crtc_timing patched_crtc_timing; uint32_t asic_blank_end; uint32_t asic_blank_start; @@ -855,6 +856,8 @@ void optc1_set_early_control( struct timing_generator *optc, uint32_t early_cntl) { + (void)optc; + (void)early_cntl; /* asic design change, do not need this control * empty for share caller logic */ @@ -1249,6 +1252,7 @@ void optc1_get_crtc_scanoutpos( static void optc1_enable_stereo(struct timing_generator *optc, const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) { + (void)timing; struct optc *optc1 = DCN10TG_FROM_TG(optc); if (flags) { diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c index e7a90a437fff..39ce4d4a61a1 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c @@ -181,6 +181,7 @@ void optc2_set_odm_bypass(struct timing_generator *optc, void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, int segment_width, int last_segment_width) { + (void)last_segment_width; struct optc *optc1 = DCN10TG_FROM_TG(optc); uint32_t memory_mask; @@ -261,6 +262,7 @@ static void optc2_align_vblanks( uint8_t master_clock_divider, uint8_t slave_clock_divider) { + (void)slave_clock_divider; /* accessing slave OTG registers */ struct optc *optc1 = DCN10TG_FROM_TG(optc_slave); diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c index ee4665aa49e9..d72574db1f07 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c @@ -218,6 +218,7 @@ void optc3_set_odm_bypass(struct timing_generator *optc, void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, int segment_width, int last_segment_width) { + (void)last_segment_width; struct optc *optc1 = DCN10TG_FROM_TG(optc); uint32_t memory_mask = 0; diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c index 893d2aff1f82..5f53f8747812 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c @@ -43,6 +43,7 @@ static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, int segment_width, int last_segment_width) { + (void)last_segment_width; struct optc *optc1 = DCN10TG_FROM_TG(optc); uint32_t memory_mask = 0; int mem_count_per_opp = (segment_width + 2559) / 2560; diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c index 43ff957288b2..a7cf34937b2f 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c @@ -50,6 +50,7 @@ static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, int segment_width, int last_segment_width) { + (void)last_segment_width; struct optc *optc1 = DCN10TG_FROM_TG(optc); uint32_t memory_mask = 0; int h_active = segment_width * opp_cnt; diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c index 3dcb0d0c931c..60e546b69a05 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c @@ -45,6 +45,7 @@ static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, int segment_width, int last_segment_width) { + (void)last_segment_width; struct optc *optc1 = DCN10TG_FROM_TG(optc); uint32_t memory_mask = 0; int h_active = segment_width * opp_cnt; diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c index 5aafd0eedf66..a880e4a6d165 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c @@ -58,6 +58,7 @@ static void optc35_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, int segment_width, int last_segment_width) { + (void)last_segment_width; struct optc *optc1 = DCN10TG_FROM_TG(optc); uint32_t memory_mask = 0; int h_active = segment_width * opp_cnt; diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c index 3685080ce9dc..96290538a889 100644 --- a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c @@ -176,11 +176,12 @@ void pg_cntl42_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; bool block_enabled; + bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || + pg_cntl->ctx->dc->debug.disable_hubp_power_gate || + pg_cntl->ctx->dc->debug.disable_dpp_power_gate || + pg_cntl->ctx->dc->idle_optimizations_allowed; - if (pg_cntl->ctx->dc->debug.ignore_pg || - pg_cntl->ctx->dc->debug.disable_hubp_power_gate || - pg_cntl->ctx->dc->debug.disable_dpp_power_gate || - pg_cntl->ctx->dc->idle_optimizations_allowed) + if (skip_pg && !power_on) return; block_enabled = pg_cntl42_hubp_dpp_pg_status(pg_cntl, hubp_dpp_inst); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c index 92c123aca0c9..caafebe92129 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c @@ -632,6 +632,7 @@ static struct link_encoder *dce100_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dce110_link_encoder *enc110 = kzalloc_obj(struct dce110_link_encoder); int link_regs_id; @@ -650,9 +651,6 @@ static struct link_encoder *dce100_link_encoder_create( return &enc110->base; } - if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) - return NULL; - link_regs_id = map_transmitter_id_to_phy_instance(enc_init_data->transmitter); @@ -661,7 +659,8 @@ static struct link_encoder *dce100_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } @@ -851,6 +850,7 @@ static enum dc_status build_mapped_resource( struct dc_state *context, struct dc_stream_state *stream) { + (void)dc; struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); if (!pipe_ctx) @@ -868,6 +868,7 @@ enum dc_status dce100_validate_bandwidth( struct dc_state *context, enum dc_validate_mode validate_mode) { + (void)validate_mode; int i; bool at_least_one_pipe = false; struct dc_stream_state *stream = NULL; @@ -928,6 +929,7 @@ enum dc_status dce100_validate_global( struct dc *dc, struct dc_state *context) { + (void)dc; if (!dce100_validate_surface_sets(context)) return DC_FAIL_SURFACE_VALIDATE; @@ -963,6 +965,7 @@ static void dce100_destroy_resource_pool(struct resource_pool **pool) enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps) { + (void)caps; if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) return DC_OK; @@ -1041,7 +1044,7 @@ static bool dce100_resource_construct( pool->base.res_cap = &res_cap; pool->base.funcs = &dce100_res_pool_funcs; - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; bp = ctx->dc_bios; @@ -1113,7 +1116,7 @@ static bool dce100_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = res_cap.num_timing_generator; pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 200; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c index 95852d277c22..f83acfe7a15e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c @@ -667,11 +667,12 @@ static struct link_encoder *dce110_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dce110_link_encoder *enc110 = kzalloc_obj(struct dce110_link_encoder); int link_regs_id; - if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) + if (!enc110) return NULL; link_regs_id = @@ -682,7 +683,8 @@ static struct link_encoder *dce110_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } @@ -970,6 +972,7 @@ static enum dc_status dce110_validate_bandwidth( struct dc_state *context, enum dc_validate_mode validate_mode) { + (void)validate_mode; bool result = false; DC_LOG_BANDWIDTH_CALCS( @@ -1042,6 +1045,7 @@ static enum dc_status dce110_validate_bandwidth( static enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps) { + (void)caps; if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) return DC_FAIL_SURFACE_VALIDATE; @@ -1098,6 +1102,7 @@ static enum dc_status dce110_validate_global( struct dc *dc, struct dc_state *context) { + (void)dc; if (!dce110_validate_surface_sets(context)) return DC_FAIL_SURFACE_VALIDATE; @@ -1129,6 +1134,7 @@ static struct pipe_ctx *dce110_acquire_underlay( const struct resource_pool *pool, const struct pipe_ctx *opp_head_pipe) { + (void)cur_ctx; struct dc_stream_state *stream = opp_head_pipe->stream; struct dc *dc = stream->ctx->dc; struct dce_hwseq *hws = dc->hwseq; @@ -1353,6 +1359,7 @@ static bool dce110_resource_construct( struct dce110_resource_pool *pool, struct hw_asic_id asic_id) { + (void)asic_id; unsigned int i; struct dc_context *ctx = dc->ctx; struct dc_bios *bp; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c index 58c6a00397cf..458b14e4cb97 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c @@ -628,11 +628,12 @@ static struct link_encoder *dce112_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dce110_link_encoder *enc110 = kzalloc_obj(struct dce110_link_encoder); int link_regs_id; - if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) + if (!enc110) return NULL; link_regs_id = @@ -643,7 +644,8 @@ static struct link_encoder *dce112_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } @@ -851,6 +853,7 @@ static struct clock_source *find_matching_pll( const struct resource_pool *pool, const struct dc_stream_state *const stream) { + (void)res_ctx; switch (stream->link->link_enc->transmitter) { case TRANSMITTER_UNIPHY_A: return pool->clock_sources[DCE112_CLK_SRC_PLL0]; @@ -874,6 +877,7 @@ static enum dc_status build_mapped_resource( struct dc_state *context, struct dc_stream_state *stream) { + (void)dc; struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); if (!pipe_ctx) @@ -891,6 +895,7 @@ enum dc_status dce112_validate_bandwidth( struct dc_state *context, enum dc_validate_mode validate_mode) { + (void)validate_mode; bool result = false; DC_LOG_BANDWIDTH_CALCS( @@ -1036,6 +1041,7 @@ static enum dc_status dce112_validate_global( struct dc *dc, struct dc_state *context) { + (void)dc; if (!dce112_validate_surface_sets(context)) return DC_FAIL_SURFACE_VALIDATE; @@ -1239,7 +1245,7 @@ static bool dce112_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 200; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c index 71d76b021375..56bbf9dc1691 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c @@ -712,11 +712,12 @@ static struct link_encoder *dce120_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dce110_link_encoder *enc110 = kzalloc_obj(struct dce110_link_encoder); int link_regs_id; - if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) + if (!enc110) return NULL; link_regs_id = @@ -727,7 +728,8 @@ static struct link_encoder *dce120_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } @@ -1080,7 +1082,7 @@ static bool dce120_resource_construct( /* TODO: Fill more data from GreenlandAsicCapability.cpp */ pool->base.pipe_count = res_cap.num_timing_generator; pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 100; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c index a57d68427812..6a25dcfcdf17 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c @@ -746,18 +746,16 @@ static struct link_encoder *dce60_link_encoder_create( return &enc110->base; } - if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) - return NULL; - link_regs_id = map_transmitter_id_to_phy_instance(enc_init_data->transmitter); dce60_link_encoder_construct(enc110, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c index d66d8ac6d897..33be49b3c1b1 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c @@ -734,6 +734,7 @@ static struct link_encoder *dce80_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dce110_link_encoder *enc110 = kzalloc_obj(struct dce110_link_encoder); int link_regs_id; @@ -752,9 +753,6 @@ static struct link_encoder *dce80_link_encoder_create( return &enc110->base; } - if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) - return NULL; - link_regs_id = map_transmitter_id_to_phy_instance(enc_init_data->transmitter); @@ -763,7 +761,8 @@ static struct link_encoder *dce80_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } @@ -936,7 +935,7 @@ static bool dce80_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = res_cap.num_timing_generator; pool->base.timing_generator_count = res_cap.num_timing_generator; dc->caps.max_downscale_ratio = 200; @@ -1139,7 +1138,7 @@ static bool dce81_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = res_cap_81.num_timing_generator; pool->base.timing_generator_count = res_cap_81.num_timing_generator; dc->caps.max_downscale_ratio = 200; @@ -1339,7 +1338,7 @@ static bool dce83_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = res_cap_83.num_timing_generator; pool->base.timing_generator_count = res_cap_83.num_timing_generator; dc->caps.max_downscale_ratio = 200; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c index bbe185e15eb6..0fdebe63d355 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c @@ -71,6 +71,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f @@ -444,6 +445,33 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN10(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn10_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static int map_transmitter_id_to_phy_instance( enum transmitter transmitter) { @@ -736,6 +764,7 @@ static struct link_encoder *dcn10_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn10_link_encoder *enc10 = kzalloc_obj(struct dcn10_link_encoder); int link_regs_id; @@ -917,6 +946,11 @@ static void dcn10_resource_destruct(struct dcn10_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.opps[i] != NULL) pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); @@ -1049,6 +1083,7 @@ static enum dc_status build_mapped_resource( struct dc_state *context, struct dc_stream_state *stream) { + (void)dc; struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); if (!pipe_ctx) @@ -1083,6 +1118,7 @@ static struct pipe_ctx *dcn10_acquire_free_pipe_for_layer( const struct resource_pool *pool, const struct pipe_ctx *opp_head_pipe) { + (void)cur_ctx; struct resource_context *res_ctx = &new_ctx->res_ctx; struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream); struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); @@ -1273,6 +1309,12 @@ static const struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn10_get_dcc_compression_cap }; +void dcn10_get_default_tiling_info(struct dc_tiling_info *tiling_info) +{ + tiling_info->gfxversion = DcGfxVersion9; + tiling_info->gfx9.swizzle = DC_SW_LINEAR; +} + static const struct resource_funcs dcn10_res_pool_funcs = { .destroy = dcn10_destroy_resource_pool, .link_enc_create = dcn10_link_encoder_create, @@ -1284,7 +1326,8 @@ static const struct resource_funcs dcn10_res_pool_funcs = { .add_stream_to_ctx = dcn10_add_stream_to_ctx, .patch_unknown_plane_state = dcn10_patch_unknown_plane_state, .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, - .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe + .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static uint32_t read_pipe_fuses(struct dc_context *ctx) @@ -1339,7 +1382,7 @@ static bool dcn10_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; /* max pipe num for ASIC before check pipe fuses */ pool->base.pipe_count = pool->base.res_cap->num_timing_generator; @@ -1653,6 +1696,14 @@ static bool dcn10_resource_construct( goto fail; } + /* DIO */ + pool->base.dio = dcn10_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto fail; + } + if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) goto fail; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h index 7bc1be53e800..c7409298caa9 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h @@ -53,5 +53,7 @@ struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( unsigned int dcn10_get_vstartup_for_pipe(struct pipe_ctx *pipe_ctx); +void dcn10_get_default_tiling_info(struct dc_tiling_info *tiling_info); + #endif /* __DC_RESOURCE_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c index 366576b1c617..a99829f23965 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c @@ -82,6 +82,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #include "vm_helper.h" #include "link_enc_cfg.h" @@ -550,6 +551,33 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN20(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn20_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + #define vmid_regs(id)\ [id] = {\ DCN20_VMID_REG_LIST(id)\ @@ -916,6 +944,7 @@ struct link_encoder *dcn20_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); int link_regs_id; @@ -1104,6 +1133,12 @@ static void dcn20_resource_destruct(struct dcn20_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn20_dpp_destroy(&pool->base.dpps[i]); @@ -1310,6 +1345,7 @@ static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx) enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream) { + (void)dc; enum dc_status status = DC_OK; struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); @@ -1537,6 +1573,7 @@ void dcn20_split_stream_for_mpc( struct pipe_ctx *primary_pipe, struct pipe_ctx *secondary_pipe) { + (void)res_ctx; int pipe_idx = secondary_pipe->pipe_idx; struct pipe_ctx *sec_bot_pipe = secondary_pipe->bottom_pipe; @@ -1682,6 +1719,7 @@ struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, const struct resource_pool *pool, const struct pipe_ctx *primary_pipe) { + (void)pool; struct pipe_ctx *secondary_pipe = NULL; if (dc && primary_pipe) { @@ -1814,6 +1852,11 @@ void dcn20_merge_pipes_for_validate( } } +static bool is_dual_plane(enum surface_pixel_format format) +{ + return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; +} + int dcn20_validate_apply_pipe_split_flags( struct dc *dc, struct dc_state *context, @@ -1898,8 +1941,15 @@ int dcn20_validate_apply_pipe_split_flags( for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; int pipe_plane = v->pipe_plane[pipe_idx]; - bool split4mpc = context->stream_count == 1 && plane_count == 1 - && dc->config.enable_4to1MPC && dc->res_pool->pipe_count >= 4; + bool split4mpc = false; + + if (context->stream_count == 1 && plane_count == 1 + && dc->config.allow_4to1MPC && dc->res_pool->pipe_count >= 4 + && !dc->debug.disable_z9_mpc + && pipe->plane_state && is_dual_plane(pipe->plane_state->format) + && pipe->plane_state->src_rect.width <= 1920 + && pipe->plane_state->src_rect.height <= 1080) + split4mpc = true; if (!context->res_ctx.pipe_ctx[i].stream) continue; @@ -2149,6 +2199,7 @@ struct pipe_ctx *dcn20_acquire_free_pipe_for_layer( const struct resource_pool *pool, const struct pipe_ctx *opp_head) { + (void)cur_ctx; struct resource_context *res_ctx = &new_ctx->res_ctx; struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(res_ctx, opp_head->stream); struct pipe_ctx *sec_dpp_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, otg_master); @@ -2232,7 +2283,8 @@ static const struct resource_funcs dcn20_res_pool_funcs = { .set_mcif_arb_params = dcn20_set_mcif_arb_params, .populate_dml_pipes = dcn20_populate_dml_pipes_from_context, .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, - .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe + .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, + .get_default_tiling_info = dcn10_get_default_tiling_info }; bool dcn20_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) @@ -2330,6 +2382,7 @@ static struct _vcs_dpi_ip_params_st *get_asic_rev_ip_params( static enum dml_project get_dml_project_version(uint32_t hw_internal_rev) { + (void)hw_internal_rev; return DML_PROJECT_NAVI10v2; } @@ -2416,7 +2469,7 @@ static bool dcn20_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 100; @@ -2690,6 +2743,14 @@ static bool dcn20_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn20_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { pool->base.dscs[i] = dcn20_dsc_create(ctx, i); if (pool->base.dscs[i] == NULL) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c index 4ea76e46ab15..02b7dc07ad53 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c @@ -56,6 +56,7 @@ #include "dce/dce_aux.h" #include "dce/dce_i2c.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "cyan_skillfish_ip_offset.h" @@ -755,6 +756,33 @@ static struct hubbub *dcn201_hubbub_create(struct dc_context *ctx) return &hubbub->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn201_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn201_timing_generator_create( struct dc_context *ctx, uint32_t instance) @@ -930,6 +958,11 @@ static void dcn201_resource_destruct(struct dcn201_resource_pool *pool) pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn201_dpp_destroy(&pool->base.dpps[i]); @@ -1081,7 +1114,8 @@ static struct resource_funcs dcn201_res_pool_funcs = { .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .set_mcif_arb_params = dcn20_set_mcif_arb_params, .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, - .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe + .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static bool dcn201_resource_construct( @@ -1276,6 +1310,14 @@ static bool dcn201_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn201_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) goto create_fail; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c index 0f4307f8f3dd..54ebf8cf607f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c @@ -84,6 +84,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #include "dcn21_resource.h" #include "vm_helper.h" #include "dcn20/dcn20_vmid.h" @@ -329,6 +330,25 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN21(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +static const struct dcn_dio_shift dio_shift = { 0 }; + +static const struct dcn_dio_mask dio_mask = { 0 }; + +static struct dio *dcn21_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} #define vmid_regs(id)\ [id] = {\ @@ -677,6 +697,12 @@ static void dcn21_resource_destruct(struct dcn21_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn20_dpp_destroy(&pool->base.dpps[i]); @@ -772,7 +798,8 @@ bool dcn21_fast_validate_bw(struct dc *dc, int *pipe_cnt_out, int *pipe_split_from, int *vlevel_out, - enum dc_validate_mode validate_mode) + enum dc_validate_mode validate_mode, + bool allow_self_refresh_only) { bool out = false; int split[MAX_PIPES] = { 0 }; @@ -803,18 +830,23 @@ bool dcn21_fast_validate_bw(struct dc *dc, vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); if (vlevel > context->bw_ctx.dml.soc.num_states) { - /* - * If mode is unsupported or there's still no p-state support then - * fall back to favoring voltage. - * - * We don't actually support prefetch mode 2, so require that we - * at least support prefetch mode 1. - */ - context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = - dm_allow_self_refresh; - vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); - if (vlevel > context->bw_ctx.dml.soc.num_states) + + if (allow_self_refresh_only) { + /* + * If mode is unsupported or there's still no p-state support then + * fall back to favoring voltage. + * + * We don't actually support prefetch mode 2, so require that we + * at least support prefetch mode 1. + */ + context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = + dm_allow_self_refresh; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + if (vlevel > context->bw_ctx.dml.soc.num_states) + goto validate_fail; + } else { goto validate_fail; + } } vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); @@ -1293,6 +1325,7 @@ static struct link_encoder *dcn21_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn21_link_encoder *enc21 = kzalloc_obj(struct dcn21_link_encoder); int link_regs_id; @@ -1378,7 +1411,8 @@ static const struct resource_funcs dcn21_res_pool_funcs = { .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, .update_bw_bounding_box = dcn21_update_bw_bounding_box, .get_panel_config_defaults = dcn21_get_panel_config_defaults, - .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe + .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static bool dcn21_resource_construct( @@ -1401,7 +1435,7 @@ static bool dcn21_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; /* max pipe num for ASIC before check pipe fuses */ pool->base.pipe_count = pool->base.res_cap->num_timing_generator; @@ -1654,6 +1688,14 @@ static bool dcn21_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn21_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { pool->base.dscs[i] = dcn21_dsc_create(ctx, i); if (pool->base.dscs[i] == NULL) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h index a017fd9854d1..23d3a36872bb 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h @@ -51,6 +51,7 @@ bool dcn21_fast_validate_bw( int *pipe_cnt_out, int *pipe_split_from, int *vlevel_out, - enum dc_validate_mode validate_mode); + enum dc_validate_mode validate_mode, + bool allow_self_refresh_only); #endif /* _DCN21_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c index 2fa86b9587ed..4a864689c44f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -60,6 +60,7 @@ #include "dml/display_mode_vba.h" #include "dcn30/dcn30_dccg.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" #include "dce/dce_panel_cntl.h" @@ -886,6 +887,33 @@ static struct hubbub *dcn30_hubbub_create(struct dc_context *ctx) return &hubbub3->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn30_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn30_timing_generator_create( struct dc_context *ctx, uint32_t instance) @@ -924,6 +952,7 @@ static struct link_encoder *dcn30_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1095,6 +1124,12 @@ static void dcn30_resource_destruct(struct dcn30_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn30_dpp_destroy(&pool->base.dpps[i]); @@ -1641,6 +1676,8 @@ noinline bool dcn30_internal_validate_bw( if (!pipes) return false; + dcn20_merge_pipes_for_validate(dc, context); + context->bw_ctx.dml.vba.maxMpcComb = 0; context->bw_ctx.dml.vba.VoltageLevel = 0; context->bw_ctx.dml.vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; @@ -2248,7 +2285,8 @@ static const struct resource_funcs dcn30_res_pool_funcs = { .update_bw_bounding_box = dcn30_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn30_get_panel_config_defaults, - .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe + .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, + .get_default_tiling_info = dcn10_get_default_tiling_info }; #define CTX ctx @@ -2294,7 +2332,7 @@ static bool dcn30_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; @@ -2464,6 +2502,14 @@ static bool dcn30_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn30_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn30_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c index 7842bee57e63..a74b150cbe9c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c @@ -59,6 +59,7 @@ #include "dml/display_mode_vba.h" #include "dcn301/dcn301_dccg.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "dcn30/dcn30_dio_stream_encoder.h" #include "dcn301/dcn301_dio_link_encoder.h" #include "dcn301/dcn301_panel_cntl.h" @@ -843,6 +844,33 @@ static struct hubbub *dcn301_hubbub_create(struct dc_context *ctx) return &hubbub3->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn301_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn301_timing_generator_create( struct dc_context *ctx, uint32_t instance) { @@ -880,6 +908,7 @@ static struct link_encoder *dcn301_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1066,6 +1095,12 @@ static void dcn301_destruct(struct dcn301_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn301_dpp_destroy(&pool->base.dpps[i]); @@ -1400,7 +1435,8 @@ static struct resource_funcs dcn301_res_pool_funcs = { .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, .update_bw_bounding_box = dcn301_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe + .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, + .get_default_tiling_info = dcn10_get_default_tiling_info, }; static bool dcn301_resource_construct( @@ -1427,7 +1463,7 @@ static bool dcn301_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; @@ -1582,6 +1618,14 @@ static bool dcn301_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn301_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + j = 0; /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c index 1874d5d6b782..539c5aa6bffa 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c @@ -46,6 +46,7 @@ #include "dml/dcn30/dcn30_fpu.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" @@ -253,6 +254,33 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn302_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn302_hubbub_create(struct dc_context *ctx) { int i; @@ -894,6 +922,7 @@ static struct link_encoder *dcn302_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) @@ -1022,6 +1051,11 @@ static void dcn302_resource_destruct(struct resource_pool *pool) pool->hubbub = NULL; } + if (pool->dio != NULL) { + kfree(TO_DCN10_DIO(pool->dio)); + pool->dio = NULL; + } + for (i = 0; i < pool->pipe_count; i++) { if (pool->dpps[i] != NULL) { kfree(TO_DCN20_DPP(pool->dpps[i])); @@ -1155,7 +1189,8 @@ static struct resource_funcs dcn302_res_pool_funcs = { .update_bw_bounding_box = dcn302_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn302_get_panel_config_defaults, - .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe + .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static struct dc_cap_funcs cap_funcs = { @@ -1217,7 +1252,7 @@ static bool dcn302_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->pipe_count = pool->res_cap->num_timing_generator; pool->mpcc_count = pool->res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; @@ -1372,6 +1407,14 @@ static bool dcn302_resource_construct( goto create_fail; } + /* DIO */ + pool->dio = dcn302_dio_create(ctx); + if (pool->dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->pipe_count; i++) { pool->hubps[i] = dcn302_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c index d52201cb359f..529eccb4ed3b 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c @@ -46,6 +46,7 @@ #include "dml/dcn30/dcn30_fpu.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" @@ -249,6 +250,33 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn303_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn303_hubbub_create(struct dc_context *ctx) { int i; @@ -839,6 +867,7 @@ static struct link_encoder *dcn303_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) @@ -966,6 +995,11 @@ static void dcn303_resource_destruct(struct resource_pool *pool) pool->hubbub = NULL; } + if (pool->dio != NULL) { + kfree(TO_DCN10_DIO(pool->dio)); + pool->dio = NULL; + } + for (i = 0; i < pool->pipe_count; i++) { if (pool->dpps[i] != NULL) { kfree(TO_DCN20_DPP(pool->dpps[i])); @@ -1099,7 +1133,8 @@ static struct resource_funcs dcn303_res_pool_funcs = { .update_bw_bounding_box = dcn303_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn303_get_panel_config_defaults, - .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe + .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static struct dc_cap_funcs cap_funcs = { @@ -1158,7 +1193,7 @@ static bool dcn303_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->pipe_count = pool->res_cap->num_timing_generator; pool->mpcc_count = pool->res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; @@ -1304,6 +1339,14 @@ static bool dcn303_resource_construct( goto create_fail; } + /* DIO */ + pool->dio = dcn303_dio_create(ctx); + if (pool->dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->pipe_count; i++) { pool->hubps[i] = dcn303_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index 2055f1f8af65..ee4bc2c2e73a 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -64,6 +64,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -810,6 +811,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1021,6 +1037,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn31_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1090,6 +1118,7 @@ static struct link_encoder *dcn31_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1396,6 +1425,10 @@ static void dcn31_resource_destruct(struct dcn31_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -1699,12 +1732,9 @@ int dcn31_populate_dml_pipes_from_context( pipe_cnt++; } context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_1_DEFAULT_DET_SIZE; - dc->config.enable_4to1MPC = false; + if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) { - if (is_dual_plane(pipe->plane_state->format) - && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) { - dc->config.enable_4to1MPC = true; - } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) { + if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) { /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */ context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; pipes[0].pipe.src.unbounded_req_mode = true; @@ -1851,6 +1881,7 @@ static struct resource_funcs dcn31_res_pool_funcs = { .get_det_buffer_size = dcn31_get_det_buffer_size, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, .update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch, + .get_default_tiling_info = dcn10_get_default_tiling_info, .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params }; @@ -1896,7 +1927,7 @@ static bool dcn31_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; @@ -1921,6 +1952,9 @@ static bool dcn31_resource_construct( dc->caps.is_apu = true; dc->caps.zstate_support = true; + /* Enable 4to1MPC by default */ + dc->config.allow_4to1MPC = true; + /* Color pipeline capabilities */ dc->caps.color.dpp.dcn_arch = 1; dc->caps.color.dpp.input_lut_shared = 0; @@ -2063,6 +2097,14 @@ static bool dcn31_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn31_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); @@ -2242,6 +2284,7 @@ enum dc_status dcn31_update_dc_state_for_encoder_switch(struct dc_link *link, struct pipe_ctx *pipes, struct audio_output *audio_output) { + (void)link_setting; struct dc_state *state = link->dc->current_state; int i; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c index 1939f720ba29..5acc545bbe7f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c @@ -66,6 +66,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -822,6 +823,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn314 = { .num_timing_generator = 4, .num_opp = 4, @@ -1079,6 +1095,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn314_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1148,6 +1176,7 @@ static struct link_encoder *dcn31_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1455,6 +1484,10 @@ static void dcn314_resource_destruct(struct dcn314_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -1782,7 +1815,8 @@ static struct resource_funcs dcn314_res_pool_funcs = { .get_det_buffer_size = dcn31_get_det_buffer_size, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, .update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch, - .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static struct clock_source *dcn30_clock_source_create( @@ -1826,9 +1860,12 @@ static bool dcn314_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; + + /* Enable 4to1MPC by default */ + dc->config.allow_4to1MPC = true; dc->caps.max_downscale_ratio = 400; dc->caps.i2c_speed_in_khz = 100; dc->caps.i2c_speed_in_khz_hdcp = 100; @@ -1987,6 +2024,14 @@ static bool dcn314_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn314_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c index e8377c190f63..2ca673114841 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -63,6 +63,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -809,6 +810,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1020,6 +1036,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn315_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1089,6 +1117,7 @@ static struct link_encoder *dcn31_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1397,6 +1426,10 @@ static void dcn315_resource_destruct(struct dcn315_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -1785,11 +1818,9 @@ static int dcn315_populate_dml_pipes_from_context( if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_15_MAX_DET_SIZE) context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_15_MAX_DET_SIZE; - dc->config.enable_4to1MPC = false; if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) { if (is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) { - dc->config.enable_4to1MPC = true; context->bw_ctx.dml.ip.det_buffer_size_kbytes = (max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / 4) * DCN3_15_CRB_SEGMENT_SIZE_KB; } else if (!is_dual_plane(pipe->plane_state->format) @@ -1846,7 +1877,8 @@ static struct resource_funcs dcn315_res_pool_funcs = { .get_det_buffer_size = dcn31_get_det_buffer_size, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, .update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch, - .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static bool dcn315_resource_construct( @@ -1867,8 +1899,11 @@ static bool dcn315_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + + /* Enable 4to1MPC by default */ + dc->config.allow_4to1MPC = true; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; dc->caps.i2c_speed_in_khz = 100; @@ -2012,6 +2047,14 @@ static bool dcn315_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn315_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c index 045ce01bd74e..2242df112a3f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c @@ -63,6 +63,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -804,6 +805,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1013,6 +1029,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn316_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1082,6 +1110,7 @@ static struct link_encoder *dcn31_link_encoder_create( struct dc_context *ctx, const struct encoder_init_data *enc_init_data) { + (void)ctx; struct dcn20_link_encoder *enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1392,6 +1421,10 @@ static void dcn316_resource_destruct(struct dcn316_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -1669,11 +1702,9 @@ static int dcn316_populate_dml_pipes_from_context( if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_16_MAX_DET_SIZE) context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_16_MAX_DET_SIZE; ASSERT(context->bw_ctx.dml.ip.det_buffer_size_kbytes >= DCN3_16_DEFAULT_DET_SIZE); - dc->config.enable_4to1MPC = false; if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) { if (is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) { - dc->config.enable_4to1MPC = true; context->bw_ctx.dml.ip.det_buffer_size_kbytes = (max_usable_det / DCN3_16_CRB_SEGMENT_SIZE_KB / 4) * DCN3_16_CRB_SEGMENT_SIZE_KB; } else if (!is_dual_plane(pipe->plane_state->format)) { @@ -1721,7 +1752,8 @@ static struct resource_funcs dcn316_res_pool_funcs = { .get_det_buffer_size = dcn31_get_det_buffer_size, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, .update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch, - .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static bool dcn316_resource_construct( @@ -1742,9 +1774,13 @@ static bool dcn316_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; + + /* Enable 4to1MPC by default */ + dc->config.allow_4to1MPC = true; + dc->caps.max_downscale_ratio = 600; dc->caps.i2c_speed_in_khz = 100; dc->caps.i2c_speed_in_khz_hdcp = 5; /*1.5 w/a applied by default*/ @@ -1887,6 +1923,14 @@ static bool dcn316_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn316_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c index 7ebb7d1193af..82f81b586986 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -66,6 +66,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dml/display_mode_vba.h" #include "dcn32/dcn32_dccg.h" #include "dcn10/dcn10_resource.h" @@ -643,6 +644,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn32 = { .num_timing_generator = 4, .num_opp = 4, @@ -833,6 +847,22 @@ static struct clock_source *dcn32_clock_source_create( return NULL; } +static struct dio *dcn32_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn32_hubbub_create(struct dc_context *ctx) { int i; @@ -1494,6 +1524,11 @@ static void dcn32_resource_destruct(struct dcn32_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + if (pool->base.oem_device != NULL) { struct dc *dc = pool->base.oem_device->ctx->dc; @@ -1785,7 +1820,10 @@ static bool dml1_validate(struct dc *dc, struct dc_state *context, enum dc_valid dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel); + DC_FP_START(); dcn32_override_min_req_memclk(dc, context); + DC_FP_END(); + dcn32_override_min_req_dcfclk(dc, context); BW_VAL_TRACE_END_WATERMARKS(); @@ -2109,6 +2147,7 @@ static struct resource_funcs dcn32_res_pool_funcs = { .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, .add_phantom_pipes = dcn32_add_phantom_pipes, + .get_default_tiling_info = dcn10_get_default_tiling_info, .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, .calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, @@ -2187,7 +2226,7 @@ static bool dcn32_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.timing_generator_count = num_pipes; pool->base.pipe_count = num_pipes; pool->base.mpcc_count = num_pipes; @@ -2370,6 +2409,14 @@ static bool dcn32_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn32_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs, TGs, ABMs */ for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource_helpers.c index f5a4e97c40ce..4808c793590f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource_helpers.c @@ -41,6 +41,7 @@ uint32_t dcn32_helper_calculate_mall_bytes_for_cursor( struct pipe_ctx *pipe_ctx, bool ignore_cursor_buf) { + (void)dc; struct hubp *hubp = pipe_ctx->plane_res.hubp; uint32_t cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height; uint32_t cursor_mall_size_bytes = 0; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c index c1582c27ac87..c8c81870d50e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -69,6 +69,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dml/display_mode_vba.h" #include "dcn32/dcn32_dccg.h" #include "dcn10/dcn10_resource.h" @@ -639,6 +640,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn321 = { .num_timing_generator = 4, .num_opp = 4, @@ -827,6 +841,22 @@ static struct clock_source *dcn321_clock_source_create( return NULL; } +static struct dio *dcn321_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn321_hubbub_create(struct dc_context *ctx) { int i; @@ -1474,6 +1504,11 @@ static void dcn321_resource_destruct(struct dcn321_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + if (pool->base.oem_device != NULL) { struct dc *dc = pool->base.oem_device->ctx->dc; @@ -1619,6 +1654,7 @@ static struct resource_funcs dcn321_res_pool_funcs = { .calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, .get_max_hw_cursor_size = dcn32_get_max_hw_cursor_size, + .get_default_tiling_info = dcn10_get_default_tiling_info, }; static uint32_t read_pipe_fuses(struct dc_context *ctx) @@ -1694,7 +1730,7 @@ static bool dcn321_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.timing_generator_count = num_pipes; pool->base.pipe_count = num_pipes; pool->base.mpcc_count = num_pipes; @@ -1872,6 +1908,14 @@ static bool dcn321_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn321_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs, TGs, ABMs */ for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 3494a40cea99..2a1b0b152501 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -71,6 +71,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -664,6 +665,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn35 = { .num_timing_generator = 4, .num_opp = 4, @@ -973,6 +987,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn35_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1563,6 +1593,11 @@ static void dcn35_resource_destruct(struct dcn35_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -1738,9 +1773,11 @@ static enum dc_status dcn35_validate_bandwidth(struct dc *dc, { bool out = false; + DC_FP_START(); out = dml2_validate(dc, context, context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2, validate_mode); + DC_FP_END(); if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING) return out ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE; @@ -1774,6 +1811,12 @@ static int populate_dml_pipes_from_context_fpu(struct dc *dc, return ret; } +void dcn35_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn35_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} static struct resource_funcs dcn35_res_pool_funcs = { .destroy = dcn35_destroy_resource_pool, .link_enc_create = dcn35_link_encoder_create, @@ -1795,14 +1838,15 @@ static struct resource_funcs dcn35_res_pool_funcs = { .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, .acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut, .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, - .update_bw_bounding_box = dcn35_update_bw_bounding_box_fpu, + .update_bw_bounding_box = dcn35_update_bw_bounding_box, .patch_unknown_plane_state = dcn35_patch_unknown_plane_state, .get_panel_config_defaults = dcn35_get_panel_config_defaults, .get_preferred_eng_id_dpia = dcn35_get_preferred_eng_id_dpia, .get_det_buffer_size = dcn31_get_det_buffer_size, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, .update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch, - .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static bool dcn35_resource_construct( @@ -1826,6 +1870,9 @@ static bool dcn35_resource_construct( clk_src_regs_init(3, D), clk_src_regs_init(4, E); + /* Enable 4to1MPC by default */ + dc->config.allow_4to1MPC = true; + #undef REG_STRUCT #define REG_STRUCT abm_regs abm_regs_init(0), @@ -1846,7 +1893,7 @@ static bool dcn35_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; @@ -2033,6 +2080,14 @@ static bool dcn35_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn35_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h index 9c56ae76e0c7..6c2c61c711b9 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h @@ -312,4 +312,5 @@ struct resource_pool *dcn35_create_resource_pool( #define DPP_REG_LIST_DCN35_RI(id)\ DPP_REG_LIST_DCN30_COMMON_RI(id) +void dcn35_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); #endif /* _DCN35_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c index 080bc7f24ffa..bfd1016aa780 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c @@ -50,6 +50,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -644,6 +645,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn351 = { .num_timing_generator = 4, .num_opp = 4, @@ -953,6 +967,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn351_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1543,6 +1573,11 @@ static void dcn351_resource_destruct(struct dcn351_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -1718,9 +1753,11 @@ static enum dc_status dcn351_validate_bandwidth(struct dc *dc, { bool out = false; + DC_FP_START(); out = dml2_validate(dc, context, context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2, validate_mode); + DC_FP_END(); if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING) return out ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE; @@ -1747,6 +1784,12 @@ static int populate_dml_pipes_from_context_fpu(struct dc *dc, } +static void dcn351_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn351_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} static struct resource_funcs dcn351_res_pool_funcs = { .destroy = dcn351_destroy_resource_pool, .link_enc_create = dcn35_link_encoder_create, @@ -1768,14 +1811,15 @@ static struct resource_funcs dcn351_res_pool_funcs = { .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, .acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut, .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, - .update_bw_bounding_box = dcn351_update_bw_bounding_box_fpu, + .update_bw_bounding_box = dcn351_update_bw_bounding_box, .patch_unknown_plane_state = dcn35_patch_unknown_plane_state, .get_panel_config_defaults = dcn35_get_panel_config_defaults, .get_preferred_eng_id_dpia = dcn351_get_preferred_eng_id_dpia, .get_det_buffer_size = dcn31_get_det_buffer_size, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, .update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch, - .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static bool dcn351_resource_construct( @@ -1799,6 +1843,9 @@ static bool dcn351_resource_construct( clk_src_regs_init(3, D), clk_src_regs_init(4, E); + /* Enable 4to1MPC by default */ + dc->config.allow_4to1MPC = true; + #undef REG_STRUCT #define REG_STRUCT abm_regs abm_regs_init(0), @@ -1819,7 +1866,7 @@ static bool dcn351_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; @@ -2005,6 +2052,14 @@ static bool dcn351_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn351_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c index af51ac4ea59e..07a6675a7329 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c @@ -50,6 +50,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -651,6 +652,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn36 = { .num_timing_generator = 4, .num_opp = 4, @@ -960,6 +974,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn36_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1550,6 +1580,11 @@ static void dcn36_resource_destruct(struct dcn36_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -1725,9 +1760,11 @@ static enum dc_status dcn35_validate_bandwidth(struct dc *dc, { bool out = false; + DC_FP_START(); out = dml2_validate(dc, context, context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2, validate_mode); + DC_FP_END(); if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING) return out ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE; @@ -1775,13 +1812,14 @@ static struct resource_funcs dcn36_res_pool_funcs = { .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, .acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut, .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, - .update_bw_bounding_box = dcn35_update_bw_bounding_box_fpu, + .update_bw_bounding_box = dcn35_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn35_get_panel_config_defaults, .get_preferred_eng_id_dpia = dcn36_get_preferred_eng_id_dpia, .get_vstartup_for_pipe = dcn10_get_vstartup_for_pipe, .update_dc_state_for_encoder_switch = dcn31_update_dc_state_for_encoder_switch, - .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, + .get_default_tiling_info = dcn10_get_default_tiling_info, }; static bool dcn36_resource_construct( @@ -1825,7 +1863,7 @@ static bool dcn36_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; @@ -2012,6 +2050,14 @@ static bool dcn36_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn36_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c index e37aab939a41..cb93bfbe9e9e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c @@ -1643,8 +1643,10 @@ static struct dc_cap_funcs cap_funcs = { .get_subvp_en = dcn32_subvp_in_use, }; -static void dcn401_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +static void dcn401_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params) { + dc_assert_fp_enabled(); + /* re-calculate the available MALL size if required */ if (bw_params->num_channels > 0) { dc->caps.max_cab_allocation_bytes = dcn401_calc_num_avail_chans_for_mall( @@ -1653,17 +1655,19 @@ static void dcn401_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *b dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes; } - DC_FP_START(); - if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2) dml2_reinit(dc, &dc->dml2_options, &dc->current_state->bw_ctx.dml2); if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2_dc_power_source) dml2_reinit(dc, &dc->dml2_dc_power_options, &dc->current_state->bw_ctx.dml2_dc_power_source); +} +static void dcn401_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn401_update_bw_bounding_box_fpu(dc, bw_params); DC_FP_END(); } - enum dc_status dcn401_patch_unknown_plane_state(struct dc_plane_state *plane_state) { plane_state->tiling_info.gfxversion = DcGfxAddr3; @@ -1688,10 +1692,13 @@ enum dc_status dcn401_validate_bandwidth(struct dc *dc, } } - if (dc->debug.using_dml2) + if (dc->debug.using_dml2) { + DC_FP_START(); status = dml2_validate(dc, context, context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2, validate_mode) ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE; + DC_FP_END(); + } if (validate_mode == DC_VALIDATE_MODE_AND_PROGRAMMING && status == DC_OK && dc_state_is_subvp_in_use(context)) { /* check new stream configuration still supports cursor if subvp used */ @@ -1710,10 +1717,13 @@ enum dc_status dcn401_validate_bandwidth(struct dc *dc, if (validate_mode == DC_VALIDATE_MODE_AND_PROGRAMMING && status == DC_FAIL_HW_CURSOR_SUPPORT) { /* attempt to validate again with subvp disabled due to cursor */ - if (dc->debug.using_dml2) + if (dc->debug.using_dml2) { + DC_FP_START(); status = dml2_validate(dc, context, context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2, validate_mode) ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE; + DC_FP_END(); + } } return status; @@ -1722,9 +1732,13 @@ enum dc_status dcn401_validate_bandwidth(struct dc *dc, void dcn401_prepare_mcache_programming(struct dc *dc, struct dc_state *context) { - if (dc->debug.using_dml21) + if (dc->debug.using_dml21) { + DC_FP_START(); dml2_prepare_mcache_programming(dc, context, - context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2); + context->power_source == DC_POWER_SOURCE_DC ? + context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2); + DC_FP_END(); + } } static void dcn401_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx) @@ -1790,7 +1804,7 @@ static void dcn401_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx) } } -static int dcn401_get_power_profile(const struct dc_state *context) +int dcn401_get_power_profile(const struct dc_state *context) { int uclk_mhz = context->bw_ctx.bw.dcn.clk.dramclk_khz / 1000; int dpm_level = 0; @@ -1839,9 +1853,16 @@ static struct resource_funcs dcn401_res_pool_funcs = { .calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes, .get_power_profile = dcn401_get_power_profile, .get_vstartup_for_pipe = dcn401_get_vstartup_for_pipe, - .get_max_hw_cursor_size = dcn32_get_max_hw_cursor_size + .get_max_hw_cursor_size = dcn32_get_max_hw_cursor_size, + .get_default_tiling_info = dcn401_get_default_tiling_info }; +void dcn401_get_default_tiling_info(struct dc_tiling_info *tiling_info) +{ + tiling_info->gfxversion = DcGfxAddr3; + tiling_info->gfx_addr3.swizzle = DC_ADDR3_SW_LINEAR; +} + static uint32_t read_pipe_fuses(struct dc_context *ctx) { uint32_t value = REG_READ(CC_DC_PIPE_DIS); @@ -1908,7 +1929,7 @@ static bool dcn401_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.timing_generator_count = num_pipes; pool->base.pipe_count = num_pipes; pool->base.mpcc_count = num_pipes; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.h index 08bec1755617..47f82b818262 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.h @@ -28,8 +28,11 @@ enum dc_status dcn401_validate_bandwidth(struct dc *dc, void dcn401_prepare_mcache_programming(struct dc *dc, struct dc_state *context); +void dcn401_get_default_tiling_info(struct dc_tiling_info *tiling_info); + unsigned int dcn401_get_vstartup_for_pipe(struct pipe_ctx *pipe_ctx); +int dcn401_get_power_profile(const struct dc_state *context); /* Following are definitions for run time init of reg offsets */ /* HUBP */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c index aef187bcf5c3..c0d37f00fed9 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c @@ -760,6 +760,9 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = false, .ignore_pg = true, .disable_stutter_for_wm_program = true, + .min_deep_sleep_dcfclk_khz = 8000, + .replay_skip_crtc_disabled = true, + .psr_skip_crtc_disable = true, }; static const struct dc_check_config config_defaults = { @@ -1693,37 +1696,51 @@ static void dcn42_destroy_resource_pool(struct resource_pool **pool) static struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn20_get_dcc_compression_cap}; -static void dcn42_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +static void dcn42_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params) { - DC_FP_START(); + (void)bw_params; + dc_assert_fp_enabled(); + if (dc->current_state && dc->current_state->bw_ctx.dml2) dml2_reinit(dc, &dc->dml2_options, &dc->current_state->bw_ctx.dml2); - DC_FP_END(); } +static void dcn42_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn42_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} enum dc_status dcn42_validate_bandwidth(struct dc *dc, struct dc_state *context, enum dc_validate_mode validate_mode) { bool out = false; + DC_FP_START(); + out = dml2_validate(dc, context, context->bw_ctx.dml2, validate_mode); - DC_FP_START(); + if (validate_mode == DC_VALIDATE_MODE_AND_PROGRAMMING) { /*not required for mode enumeration*/ dcn42_decide_zstate_support(dc, context); } + DC_FP_END(); + return out ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE; } void dcn42_prepare_mcache_programming(struct dc *dc, struct dc_state *context) { - if (dc->debug.using_dml21) + if (dc->debug.using_dml21) { + DC_FP_START(); dml2_prepare_mcache_programming(dc, context, context->power_source == DC_POWER_SOURCE_DC ? - context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2); + context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2); + DC_FP_END(); + } } /* Create a minimal link encoder object not associated with a particular * physical connector. @@ -1758,6 +1775,8 @@ static unsigned int dcn42_get_max_hw_cursor_size(const struct dc *dc, struct dc_state *state, const struct dc_stream_state *stream) { + (void)state; + (void)stream; return dc->caps.max_cursor_size; } static struct resource_funcs dcn42_res_pool_funcs = { @@ -1782,7 +1801,7 @@ static struct resource_funcs dcn42_res_pool_funcs = { .acquire_post_bldn_3dlut = dcn32_acquire_post_bldn_3dlut, .release_post_bldn_3dlut = dcn32_release_post_bldn_3dlut, .update_bw_bounding_box = dcn42_update_bw_bounding_box, - .patch_unknown_plane_state = dcn401_patch_unknown_plane_state, + .patch_unknown_plane_state = dcn35_patch_unknown_plane_state, .get_panel_config_defaults = dcn42_get_panel_config_defaults, .get_preferred_eng_id_dpia = dcn42_get_preferred_eng_id_dpia, .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, @@ -1790,8 +1809,10 @@ static struct resource_funcs dcn42_res_pool_funcs = { .calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes, .prepare_mcache_programming = dcn42_prepare_mcache_programming, .build_pipe_pix_clk_params = dcn42_build_pipe_pix_clk_params, + .get_power_profile = dcn401_get_power_profile, .get_vstartup_for_pipe = dcn401_get_vstartup_for_pipe, .get_max_hw_cursor_size = dcn42_get_max_hw_cursor_size, + .get_default_tiling_info = dcn10_get_default_tiling_info }; static uint32_t read_pipe_fuses(struct dc_context *ctx) @@ -1861,7 +1882,7 @@ static bool dcn42_resource_construct( /************************************************* * Resource + asic cap harcoding * *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE; pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; pool->base.pipe_count = num_pipes; pool->base.mpcc_count = num_pipes; @@ -2015,7 +2036,7 @@ static bool dcn42_resource_construct( dc->config.dcn_override_sharpness_range.hdr_rgb_mid = 1500; dc->config.use_pipe_ctx_sync_logic = true; - dc->config.dc_mode_clk_limit_support = true; + dc->config.dc_mode_clk_limit_support = false; dc->config.enable_windowed_mpo_odm = true; /* Use psp mailbox to enable assr */ dc->config.use_assr_psp_message = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.h index a9b26df14520..60acf0e423d9 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.h @@ -481,6 +481,8 @@ SRI_ARR(OPTC_INPUT_CLOCK_CONTROL, ODM, inst), \ SRI_ARR(OPTC_DATA_SOURCE_SELECT, ODM, inst), \ SRI_ARR(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst), \ + SRI_ARR(OPTC_RSMU_UNDERFLOW, ODM, inst), \ + SRI_ARR(OPTC_UNDERFLOW_THRESHOLD, ODM, inst), \ SRI_ARR(CONTROL, VTG, inst), \ SRI_ARR(OTG_VERT_SYNC_CONTROL, OTG, inst), \ SRI_ARR(OTG_GSL_CONTROL, OTG, inst), \ @@ -584,5 +586,6 @@ enum dc_status dcn42_validate_bandwidth(struct dc *dc, enum dc_validate_mode validate_mode); void dcn42_prepare_mcache_programming(struct dc *dc, struct dc_state *context); +int dcn42_get_power_profile(const struct dc_state *context); #endif /* _DCN42_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c index fd9c24b5df53..146a6e47934b 100644 --- a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c @@ -93,6 +93,10 @@ static void dcn42_convert_dc_clock_table_to_soc_bb_clock_table( } } vmin_limit->dispclk_khz = min(dc_clk_table->entries[0].dispclk_mhz * 1000, vmin_limit->dispclk_khz); + /* dispclk is always fine-grain */ + dml_clk_table->dispclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dispclk_levels >= 2 ? 2 : 1; + dml_clk_table->dispclk.clk_values_khz[0] = 0; + dml_clk_table->dispclk.clk_values_khz[1] = dc_clk_table->entries[dc_clk_table->num_entries_per_clk.num_dispclk_levels - 1].dispclk_mhz * 1000; } /* dppclk */ @@ -105,6 +109,10 @@ static void dcn42_convert_dc_clock_table_to_soc_bb_clock_table( dml_clk_table->dppclk.clk_values_khz[i] = 0; } } + /* dppclk is always fine-grain */ + dml_clk_table->dppclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dppclk_levels >= 2 ? 2 : 1; + dml_clk_table->dppclk.clk_values_khz[0] = 0; + dml_clk_table->dppclk.clk_values_khz[1] = dc_clk_table->entries[dc_clk_table->num_entries_per_clk.num_dppclk_levels - 1].dppclk_mhz * 1000; } /* dtbclk */ @@ -151,6 +159,7 @@ static void dcn42_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb *soc static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) { + (void)config; /* Individual modification can be overwritten even if it was obtained by a previous function. * Modifications are acquired in order of priority (lowest to highest). */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index e11e32afac6b..fe9431cea3e5 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -4437,6 +4437,7 @@ enum dmub_cmd_replay_general_subtype { REPLAY_GENERAL_CMD_VIDEO_CONFERENCING, REPLAY_GENERAL_CMD_SET_CONTINUOUSLY_RESYNC, REPLAY_GENERAL_CMD_SET_COASTING_VTOTAL_WITHOUT_FRAME_UPDATE, + REPLAY_GENERAL_CMD_LIVE_CAPTURE_WITH_CVT, }; struct dmub_alpm_auxless_data { @@ -6271,6 +6272,7 @@ struct dmub_cmd_edid_cea_amd_vsdb { uint16_t amd_vsdb_version; /**< AMD VSDB version */ uint16_t min_frame_rate; /**< Maximum frame rate */ uint16_t max_frame_rate; /**< Minimum frame rate */ + uint8_t freesync_mccs_vcp_code; /**< Freesync MCCS VCP code */ }; /** diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c index 54df2147e4dc..0b152926f75b 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c @@ -194,6 +194,7 @@ void dmub_dcn20_setup_windows(struct dmub_srv *dmub, const struct dmub_window *cw6, const struct dmub_window *region6) { + (void)region6; union dmub_addr offset; uint64_t fb_base, fb_offset; @@ -396,6 +397,7 @@ union dmub_fw_boot_status dmub_dcn20_get_fw_boot_status(struct dmub_srv *dmub) void dmub_dcn20_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params) { + (void)params; union dmub_fw_boot_options boot_options = {0}; REG_WRITE(DMCUB_SCRATCH14, boot_options.all); @@ -460,20 +462,26 @@ void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub) dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); - dmub->debug.is_dmcub_enabled = is_dmub_enabled; + ASSERT(is_dmub_enabled <= 0xFF); + dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_SOFT_RESET, &is_soft_reset); - dmub->debug.is_dmcub_soft_reset = is_soft_reset; + ASSERT(is_soft_reset <= 0xFF); + dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); - dmub->debug.is_dmcub_secure_reset = is_sec_reset; + ASSERT(is_sec_reset <= 0xFF); + dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); - dmub->debug.is_traceport_en = is_traceport_enabled; + ASSERT(is_traceport_enabled <= 0xFF); + dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); - dmub->debug.is_cw0_enabled = is_cw0_enabled; + ASSERT(is_cw0_enabled <= 0xFF); + dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); - dmub->debug.is_cw6_enabled = is_cw6_enabled; + ASSERT(is_cw6_enabled <= 0xFF); + dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; } diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c index 84a6eb3f677d..23a33db07edc 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c @@ -127,6 +127,7 @@ void dmub_dcn30_setup_windows(struct dmub_srv *dmub, const struct dmub_window *cw6, const struct dmub_window *region6) { + (void)region6; union dmub_addr offset; /* sienna_cichlid has hardwired virtual addressing for CW2-CW7 */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c index a0cefc03b21d..478d79a6e246 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c @@ -195,6 +195,8 @@ void dmub_dcn31_setup_windows(struct dmub_srv *dmub, const struct dmub_window *cw6, const struct dmub_window *region6) { + (void)cw2; + (void)region6; union dmub_addr offset; offset = cw3->offset; @@ -466,25 +468,32 @@ void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub) dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); - dmub->debug.is_dmcub_enabled = is_dmub_enabled; + ASSERT(is_dmub_enabled <= 0xFF); + dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); - dmub->debug.is_pwait = is_pwait; + ASSERT(is_pwait <= 0xFF); + dmub->debug.is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); - dmub->debug.is_dmcub_soft_reset = is_soft_reset; + ASSERT(is_soft_reset <= 0xFF); + dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); - dmub->debug.is_dmcub_secure_reset = is_sec_reset; + ASSERT(is_sec_reset <= 0xFF); + dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); - dmub->debug.is_traceport_en = is_traceport_enabled; + ASSERT(is_traceport_enabled <= 0xFF); + dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); - dmub->debug.is_cw0_enabled = is_cw0_enabled; + ASSERT(is_cw0_enabled <= 0xFF); + dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); - dmub->debug.is_cw6_enabled = is_cw6_enabled; + ASSERT(is_cw6_enabled <= 0xFF); + dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; } bool dmub_dcn31_should_detect(struct dmub_srv *dmub) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c index 2f99a2772599..3f9fb9e05b79 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c @@ -237,6 +237,8 @@ void dmub_dcn32_setup_windows(struct dmub_srv *dmub, const struct dmub_window *cw6, const struct dmub_window *region6) { + (void)cw2; + (void)region6; union dmub_addr offset; offset = cw3->offset; @@ -486,19 +488,24 @@ void dmub_dcn32_get_diagnostic_data(struct dmub_srv *dmub) dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); - dmub->debug.is_dmcub_enabled = is_dmub_enabled; + ASSERT(is_dmub_enabled <= 0xFF); + dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); - dmub->debug.is_pwait = is_pwait; + ASSERT(is_pwait <= 0xFF); + dmub->debug.is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); - dmub->debug.is_dmcub_soft_reset = is_soft_reset; + ASSERT(is_soft_reset <= 0xFF); + dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); - dmub->debug.is_traceport_en = is_traceport_enabled; + ASSERT(is_traceport_enabled <= 0xFF); + dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); - dmub->debug.is_cw6_enabled = is_cw6_enabled; + ASSERT(is_cw6_enabled <= 0xFF); + dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c index 639f9835e5e9..69fb6084232e 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c @@ -222,6 +222,7 @@ void dmub_dcn35_setup_windows(struct dmub_srv *dmub, const struct dmub_window *cw6, const struct dmub_window *region6) { + (void)cw2; union dmub_addr offset; offset = cw3->offset; @@ -402,7 +403,7 @@ void dmub_dcn35_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmu union dmub_fw_boot_options boot_options = {0}; if (!dmub->dpia_supported) { - dmub->dpia_supported = dmub_dcn35_get_fw_boot_option(dmub).bits.enable_dpia; + dmub->dpia_supported = dmub_dcn35_get_fw_boot_option(dmub).bits.enable_dpia != 0; } boot_options.bits.z10_disable = params->disable_z10; @@ -508,19 +509,24 @@ void dmub_dcn35_get_diagnostic_data(struct dmub_srv *dmub) dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); - dmub->debug.is_dmcub_enabled = is_dmub_enabled; + ASSERT(is_dmub_enabled <= 0xFF); + dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); - dmub->debug.is_pwait = is_pwait; + ASSERT(is_pwait <= 0xFF); + dmub->debug.is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); - dmub->debug.is_dmcub_soft_reset = is_soft_reset; + ASSERT(is_soft_reset <= 0xFF); + dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); - dmub->debug.is_traceport_en = is_traceport_enabled; + ASSERT(is_traceport_enabled <= 0xFF); + dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); - dmub->debug.is_cw6_enabled = is_cw6_enabled; + ASSERT(is_cw6_enabled <= 0xFF); + dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c index 16ed07f0e96d..e5a78df80d72 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c @@ -213,6 +213,7 @@ void dmub_dcn401_setup_windows(struct dmub_srv *dmub, const struct dmub_window *cw6, const struct dmub_window *region6) { + (void)cw2; union dmub_addr offset; offset = cw3->offset; @@ -473,25 +474,32 @@ void dmub_dcn401_get_diagnostic_data(struct dmub_srv *dmub) dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); - dmub->debug.is_dmcub_enabled = is_dmub_enabled; + ASSERT(is_dmub_enabled <= 0xFF); + dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); - dmub->debug.is_pwait = is_pwait; + ASSERT(is_pwait <= 0xFF); + dmub->debug.is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); - dmub->debug.is_dmcub_soft_reset = is_soft_reset; + ASSERT(is_soft_reset <= 0xFF); + dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); - dmub->debug.is_dmcub_secure_reset = is_sec_reset; + ASSERT(is_sec_reset <= 0xFF); + dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); - dmub->debug.is_traceport_en = is_traceport_enabled; + ASSERT(is_traceport_enabled <= 0xFF); + dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); - dmub->debug.is_cw0_enabled = is_cw0_enabled; + ASSERT(is_cw0_enabled <= 0xFF); + dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); - dmub->debug.is_cw6_enabled = is_cw6_enabled; + ASSERT(is_cw6_enabled <= 0xFF); + dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.c index 4d274b7034e8..a09aa19ad379 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.c @@ -39,13 +39,14 @@ void dmub_srv_dcn42_regs_init(struct dmub_srv *dmub, struct dc_context *ctx) void dmub_dcn42_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params) { union dmub_fw_boot_options boot_options = {0}; - union dmub_fw_boot_options cur_boot_options = {0}; - cur_boot_options = dmub_dcn42_get_fw_boot_option(dmub); + if (!dmub->dpia_supported) { + dmub->dpia_supported = dmub_dcn42_get_fw_boot_option(dmub).bits.enable_dpia != 0; + } boot_options.bits.z10_disable = params->disable_z10; boot_options.bits.dpia_supported = params->dpia_supported; - boot_options.bits.enable_dpia = cur_boot_options.bits.enable_dpia && !params->disable_dpia; + boot_options.bits.enable_dpia = dmub->dpia_supported && !params->disable_dpia; boot_options.bits.usb4_cm_version = params->usb4_cm_version; boot_options.bits.dpia_hpd_int_enable_supported = params->dpia_hpd_int_enable_supported; boot_options.bits.power_optimization = params->power_optimization; @@ -228,6 +229,7 @@ void dmub_dcn42_setup_windows(struct dmub_srv *dmub, const struct dmub_window *cw6, const struct dmub_window *region6) { + (void)cw2; union dmub_addr offset; offset = cw3->offset; @@ -320,11 +322,9 @@ void dmub_dcn42_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset) bool dmub_dcn42_is_supported(struct dmub_srv *dmub) { - uint32_t supported = 0; - - REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported); - - return supported; + // DCN without DMUB is not a supported configuration; safe to assume that it is always + // present. + return true; } union dmub_fw_boot_options dmub_dcn42_get_fw_boot_option(struct dmub_srv *dmub) @@ -677,25 +677,32 @@ void dmub_dcn42_get_diagnostic_data(struct dmub_srv *dmub) dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); - dmub->debug.is_dmcub_enabled = is_dmub_enabled; + ASSERT(is_dmub_enabled <= 0xFF); + dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); - dmub->debug.is_pwait = is_pwait; + ASSERT(is_pwait <= 0xFF); + dmub->debug.is_pwait = (uint8_t)is_pwait; REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); - dmub->debug.is_dmcub_soft_reset = is_soft_reset; + ASSERT(is_soft_reset <= 0xFF); + dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); - dmub->debug.is_dmcub_secure_reset = is_sec_reset; + ASSERT(is_sec_reset <= 0xFF); + dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); - dmub->debug.is_traceport_en = is_traceport_enabled; + ASSERT(is_traceport_enabled <= 0xFF); + dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); - dmub->debug.is_cw0_enabled = is_cw0_enabled; + ASSERT(is_cw0_enabled <= 0xFF); + dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); - dmub->debug.is_cw6_enabled = is_cw6_enabled; + ASSERT(is_cw6_enabled <= 0xFF); + dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); } diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.h index a49d88ab0455..c53f7691d1a8 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn42.h @@ -34,7 +34,101 @@ struct dmub_srv; /* DCN42 register definitions. */ #define DMUB_DCN42_REGS() \ - DMUB_DCN35_REGS() \ + DMUB_SR(DMCUB_CNTL) \ + DMUB_SR(DMCUB_CNTL2) \ + DMUB_SR(DMCUB_SEC_CNTL) \ + DMUB_SR(DMCUB_INBOX0_SIZE) \ + DMUB_SR(DMCUB_INBOX0_RPTR) \ + DMUB_SR(DMCUB_INBOX0_WPTR) \ + DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_INBOX1_SIZE) \ + DMUB_SR(DMCUB_INBOX1_RPTR) \ + DMUB_SR(DMCUB_INBOX1_WPTR) \ + DMUB_SR(DMCUB_OUTBOX0_BASE_ADDRESS) \ + DMUB_SR(DMCUB_OUTBOX0_SIZE) \ + DMUB_SR(DMCUB_OUTBOX0_RPTR) \ + DMUB_SR(DMCUB_OUTBOX0_WPTR) \ + DMUB_SR(DMCUB_OUTBOX1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_OUTBOX1_SIZE) \ + DMUB_SR(DMCUB_OUTBOX1_RPTR) \ + DMUB_SR(DMCUB_OUTBOX1_WPTR) \ + DMUB_SR(DMCUB_REGION3_CW0_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW1_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW2_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW3_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW4_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW5_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW6_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW7_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW0_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW1_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW2_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW3_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW4_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW5_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW6_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW7_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW0_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW2_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW3_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW4_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW5_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW6_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW7_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW0_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW1_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW2_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW3_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW4_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW5_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW6_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW7_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION4_OFFSET) \ + DMUB_SR(DMCUB_REGION4_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION4_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION5_OFFSET) \ + DMUB_SR(DMCUB_REGION5_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION5_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION6_OFFSET) \ + DMUB_SR(DMCUB_REGION6_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION6_TOP_ADDRESS) \ + DMUB_SR(DMCUB_SCRATCH0) \ + DMUB_SR(DMCUB_SCRATCH1) \ + DMUB_SR(DMCUB_SCRATCH2) \ + DMUB_SR(DMCUB_SCRATCH3) \ + DMUB_SR(DMCUB_SCRATCH4) \ + DMUB_SR(DMCUB_SCRATCH5) \ + DMUB_SR(DMCUB_SCRATCH6) \ + DMUB_SR(DMCUB_SCRATCH7) \ + DMUB_SR(DMCUB_SCRATCH8) \ + DMUB_SR(DMCUB_SCRATCH9) \ + DMUB_SR(DMCUB_SCRATCH10) \ + DMUB_SR(DMCUB_SCRATCH11) \ + DMUB_SR(DMCUB_SCRATCH12) \ + DMUB_SR(DMCUB_SCRATCH13) \ + DMUB_SR(DMCUB_SCRATCH14) \ + DMUB_SR(DMCUB_SCRATCH15) \ + DMUB_SR(DMCUB_SCRATCH16) \ + DMUB_SR(DMCUB_SCRATCH17) \ + DMUB_SR(DMCUB_SCRATCH18) \ + DMUB_SR(DMCUB_SCRATCH19) \ + DMUB_SR(DMCUB_SCRATCH20) \ + DMUB_SR(DMCUB_SCRATCH21) \ + DMUB_SR(DMCUB_GPINT_DATAIN0) \ + DMUB_SR(DMCUB_GPINT_DATAIN1) \ + DMUB_SR(DMCUB_GPINT_DATAOUT) \ + DMUB_SR(MMHUBBUB_SOFT_RESET) \ + DMUB_SR(DCN_VM_FB_LOCATION_BASE) \ + DMUB_SR(DCN_VM_FB_OFFSET) \ + DMUB_SR(DMCUB_TIMER_CURRENT) \ + DMUB_SR(DMCUB_INST_FETCH_FAULT_ADDR) \ + DMUB_SR(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR) \ + DMUB_SR(DMCUB_DATA_WRITE_FAULT_ADDR) \ + DMUB_SR(DMCUB_REGION3_TMR_AXI_SPACE) \ + DMUB_SR(DMCUB_INTERRUPT_ENABLE) \ + DMUB_SR(DMCUB_INTERRUPT_ACK) \ + DMUB_SR(DMU_CLK_CNTL) \ DMUB_SR(DMCUB_INTERRUPT_STATUS) \ DMUB_SR(DMCUB_REG_INBOX0_RDY) \ DMUB_SR(DMCUB_REG_INBOX0_MSG0) \ @@ -59,7 +153,45 @@ struct dmub_srv; DMUB_SR(HOST_INTERRUPT_CSR) #define DMUB_DCN42_FIELDS() \ - DMUB_DCN35_FIELDS() \ + DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \ + DMUB_SF(DMCUB_CNTL, DMCUB_TRACEPORT_EN) \ + DMUB_SF(DMCUB_CNTL2, DMCUB_SOFT_RESET) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS) \ + DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_ENABLE) \ + DMUB_SF(DMCUB_REGION4_TOP_ADDRESS, DMCUB_REGION4_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION4_TOP_ADDRESS, DMCUB_REGION4_ENABLE) \ + DMUB_SF(DMCUB_REGION5_TOP_ADDRESS, DMCUB_REGION5_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION5_TOP_ADDRESS, DMCUB_REGION5_ENABLE) \ + DMUB_SF(DMCUB_REGION6_TOP_ADDRESS, DMCUB_REGION6_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION6_TOP_ADDRESS, DMCUB_REGION6_ENABLE) \ + DMUB_SF(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET) \ + DMUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE) \ + DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET) \ + DMUB_SF(DMCUB_INBOX0_WPTR, DMCUB_INBOX0_WPTR) \ + DMUB_SF(DMCUB_REGION3_TMR_AXI_SPACE, DMCUB_REGION3_TMR_AXI_SPACE) \ + DMUB_SF(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN) \ + DMUB_SF(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK) \ + DMUB_SF(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS) \ + DMUB_SF(DMU_CLK_CNTL, LONO_DISPCLK_GATE_DISABLE) \ + DMUB_SF(DMU_CLK_CNTL, LONO_SOCCLK_GATE_DISABLE) \ + DMUB_SF(DMU_CLK_CNTL, LONO_DMCUBCLK_GATE_DISABLE) \ DMUB_SF(DMCUB_INTERRUPT_STATUS, DMCUB_REG_OUTBOX0_RSP_INT_STAT) \ DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK) \ DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_STAT) \ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c index ca0c8a54b635..b5566ef8d4f3 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c @@ -45,6 +45,7 @@ static void set_reg_field_values(struct dmub_reg_value_masks *field_value_mask, uint32_t mask1, uint32_t field_value1, va_list ap) { + (void)addr; uint32_t shift, mask, field_value; int i = 1; @@ -57,8 +58,9 @@ static void set_reg_field_values(struct dmub_reg_value_masks *field_value_mask, mask = va_arg(ap, uint32_t); field_value = va_arg(ap, uint32_t); + ASSERT(shift <= 0xFF); set_reg_field_value_masks(field_value_mask, field_value, mask, - shift); + (uint8_t)shift); i++; } } diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index 3bba256a288d..10d23f5f5d94 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -1034,8 +1034,8 @@ enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub, static void dmub_srv_update_reg_inbox0_status(struct dmub_srv *dmub) { if (dmub->reg_inbox0.is_pending) { - dmub->reg_inbox0.is_pending = dmub->hw_funcs.read_reg_inbox0_rsp_int_status && - !dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub); + dmub->reg_inbox0.is_pending = (dmub->hw_funcs.read_reg_inbox0_rsp_int_status && + !dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub)) != 0; if (!dmub->reg_inbox0.is_pending) { /* ack the rsp interrupt */ @@ -1320,7 +1320,7 @@ void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_t enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_cmd *cmd) { - uint32_t num_pending = 0; + uint64_t num_pending = 0; if (!dmub->hw_init) return DMUB_STATUS_INVALID; @@ -1348,7 +1348,7 @@ enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_c dmub->reg_inbox0.num_submitted++; dmub->reg_inbox0.is_pending = true; - dmub->reg_inbox0.is_multi_pending = cmd->cmd_common.header.multi_cmd_pending; + dmub->reg_inbox0.is_multi_pending = cmd->cmd_common.header.multi_cmd_pending != 0; return DMUB_STATUS_OK; } diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 2639163b8ba2..1f225d0d6c44 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -896,6 +896,7 @@ static void build_de_pq(struct pwl_float_data_ex *de_pq, uint32_t hw_points_num, const struct hw_x_point *coordinate_x) { + (void)coordinate_x; uint32_t i; struct fixed31_32 output; struct fixed31_32 *de_pq_table = mod_color_get_table(type_de_pq_table); @@ -1339,6 +1340,7 @@ static void scale_gamma_dx(struct pwl_float_data *pwl_rgb, const struct dc_gamma *ramp, struct dividers dividers) { + (void)dividers; uint32_t i; struct fixed31_32 min = dc_fixpt_zero; struct fixed31_32 max = dc_fixpt_one; diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 19de72173052..c9150019aab0 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -114,6 +114,7 @@ static unsigned int calc_duration_in_us_from_v_total( const struct mod_vrr_params *in_vrr, unsigned int v_total) { + (void)in_vrr; unsigned int duration_in_us = (unsigned int)(div64_u64(((unsigned long long)(v_total) * 10000) * stream->timing.h_total, @@ -218,6 +219,7 @@ static void update_v_total_for_static_ramp( const struct dc_stream_state *stream, struct mod_vrr_params *in_out_vrr) { + (void)core_freesync; unsigned int v_total = 0; unsigned int current_duration_in_us = calc_duration_in_us_from_v_total( @@ -292,6 +294,7 @@ static void apply_below_the_range(struct core_freesync *core_freesync, unsigned int last_render_time_in_us, struct mod_vrr_params *in_out_vrr) { + (void)core_freesync; unsigned int inserted_frame_duration_in_us = 0; unsigned int mid_point_frames_ceil = 0; unsigned int mid_point_frames_floor = 0; @@ -447,6 +450,7 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync, unsigned int last_render_time_in_us, struct mod_vrr_params *in_out_vrr) { + (void)core_freesync; bool update = false; unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us; @@ -545,6 +549,7 @@ static bool vrr_settings_require_update(struct core_freesync *core_freesync, unsigned int max_refresh_in_uhz, struct mod_vrr_params *in_vrr) { + (void)core_freesync; if (in_vrr->state != in_config->state) { return true; } else if (in_vrr->state == VRR_STATE_ACTIVE_FIXED && @@ -946,6 +951,7 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, struct dc_info_packet *infopacket, bool pack_sdp_v1_3) { + (void)mod_freesync; /* SPD info packet for FreeSync * VTEM info packet for HdmiVRR * Check if Freesync is supported. Return if false. If true, diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h index 26a351a184f3..d07387a961dd 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h @@ -501,6 +501,7 @@ static inline void callback_in_ms(uint16_t time, struct mod_hdcp_output *output) static inline void set_watchdog_in_ms(struct mod_hdcp *hdcp, uint16_t time, struct mod_hdcp_output *output) { + (void)hdcp; output->watchdog_timer_needed = 1; output->watchdog_timer_delay = time; } diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_2_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_2_0_offset.h index 52fbf2dc1899..3755a984681a 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_2_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_2_0_offset.h @@ -9036,6 +9036,8 @@ // base address: 0x40 #define regODM1_OPTC_INPUT_GLOBAL_CONTROL 0x1ada #define regODM1_OPTC_INPUT_GLOBAL_CONTROL_BASE_IDX 2 +#define regODM1_OPTC_RSMU_UNDERFLOW 0x1adb +#define regODM1_OPTC_RSMU_UNDERFLOW_BASE_IDX 2 #define regODM1_OPTC_UNDERFLOW_THRESHOLD 0x1adc #define regODM1_OPTC_UNDERFLOW_THRESHOLD_BASE_IDX 2 #define regODM1_OPTC_DATA_SOURCE_SELECT 0x1add @@ -9060,6 +9062,8 @@ // base address: 0x80 #define regODM2_OPTC_INPUT_GLOBAL_CONTROL 0x1aea #define regODM2_OPTC_INPUT_GLOBAL_CONTROL_BASE_IDX 2 +#define regODM2_OPTC_RSMU_UNDERFLOW 0x1aeb +#define regODM2_OPTC_RSMU_UNDERFLOW_BASE_IDX 2 #define regODM2_OPTC_UNDERFLOW_THRESHOLD 0x1aec #define regODM2_OPTC_UNDERFLOW_THRESHOLD_BASE_IDX 2 #define regODM2_OPTC_DATA_SOURCE_SELECT 0x1aed @@ -9084,6 +9088,8 @@ // base address: 0xc0 #define regODM3_OPTC_INPUT_GLOBAL_CONTROL 0x1afa #define regODM3_OPTC_INPUT_GLOBAL_CONTROL_BASE_IDX 2 +#define regODM3_OPTC_RSMU_UNDERFLOW 0x1afb +#define regODM3_OPTC_RSMU_UNDERFLOW_BASE_IDX 2 #define regODM3_OPTC_UNDERFLOW_THRESHOLD 0x1afc #define regODM3_OPTC_UNDERFLOW_THRESHOLD_BASE_IDX 2 #define regODM3_OPTC_DATA_SOURCE_SELECT 0x1afd diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h index 18f9642a42ee..62f7ed0b2066 100644 --- a/drivers/gpu/drm/amd/include/atomfirmware.h +++ b/drivers/gpu/drm/amd/include/atomfirmware.h @@ -1695,7 +1695,9 @@ struct atom_integrated_system_info_v2_3 { uint8_t gpu_package_id; struct edp_info_table edp1_info; struct edp_info_table edp2_info; - uint32_t reserved2[8]; + uint32_t cpuid; + uint32_t vram_bit_width; + uint32_t reserved2[6]; struct atom_external_display_connection_info extdispconninfo; uint8_t UMACarveoutVersion; uint8_t UMACarveoutIndexMax; @@ -1770,6 +1772,7 @@ enum atom_dmi_t17_mem_type_def{ Hbm2MemType, ///< Assign 33 to HBM2 Ddr5MemType, ///< Assign 34 to DDR5 LpDdr5MemType, ///< Assign 35 to LPDDR5 + LpDdr5xMemType, ///< Assign 36 to LPDDR5x }; diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index a9b73f4fd466..1bbf531de5ed 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -119,6 +119,7 @@ enum pp_clock_type { PP_ISPXCLK, OD_SCLK, OD_MCLK, + OD_FCLK, OD_VDDC_CURVE, OD_RANGE, OD_VDDGFX_OFFSET, @@ -208,6 +209,7 @@ enum { enum PP_OD_DPM_TABLE_COMMAND { PP_OD_EDIT_SCLK_VDDC_TABLE, PP_OD_EDIT_MCLK_VDDC_TABLE, + PP_OD_EDIT_FCLK_TABLE, PP_OD_EDIT_CCLK_VDDC_TABLE, PP_OD_EDIT_VDDC_CURVE, PP_OD_RESTORE_DEFAULT_TABLE, @@ -585,8 +587,61 @@ enum amdgpu_metrics_attr_id { AMDGPU_METRICS_ATTR_ID_GFX_LOW_UTILIZATION_ACC, AMDGPU_METRICS_ATTR_ID_GFX_BELOW_HOST_LIMIT_TOTAL_ACC, AMDGPU_METRICS_ATTR_ID_TEMPERATURE_HBM, + AMDGPU_METRICS_ATTR_ID_TEMPERATURE_MID, AMDGPU_METRICS_ATTR_ID_TEMPERATURE_AID, AMDGPU_METRICS_ATTR_ID_TEMPERATURE_XCD, + AMDGPU_METRICS_ATTR_ID_LABEL_VERSION, + AMDGPU_METRICS_ATTR_ID_NODE_ID, + AMDGPU_METRICS_ATTR_ID_NODE_TEMP_RETIMER, + AMDGPU_METRICS_ATTR_ID_NODE_TEMP_IBC, + AMDGPU_METRICS_ATTR_ID_NODE_TEMP_IBC_2, + AMDGPU_METRICS_ATTR_ID_NODE_TEMP_VDD18_VR, + AMDGPU_METRICS_ATTR_ID_NODE_TEMP_04_HBM_B_VR, + AMDGPU_METRICS_ATTR_ID_NODE_TEMP_04_HBM_D_VR, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_SOCIO_A, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_SOCIO_C, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_X0, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_X1, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_HBM_B, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_HBM_D, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_04_HBM_B, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_04_HBM_D, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_HBM_B, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_HBM_D, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_075_HBM_B, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_075_HBM_D, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_11_GTA_A, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_11_GTA_C, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDAN_075_GTA_A, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDAN_075_GTA_C, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDCR_075_UCIE, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_065_UCIEAA, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_065_UCIEAM_A, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDIO_065_UCIEAM_C, + AMDGPU_METRICS_ATTR_ID_VR_TEMP_VDDAN_075, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_FPGA, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_FRONT, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_BACK, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_OAM7, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_IBC, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_UFPGA, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_OAM1, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_OAM_0_1_HSC, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_OAM_2_3_HSC, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_OAM_4_5_HSC, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_OAM_6_7_HSC, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_FPGA_0V72_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_UBB_FPGA_3V3_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_RETIMER_0_1_0V9_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_RETIMER_4_5_0V9_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_RETIMER_2_3_0V9_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_RETIMER_6_7_0V9_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_IBC_HSC, + AMDGPU_METRICS_ATTR_ID_SYSTEM_TEMP_IBC, AMDGPU_METRICS_ATTR_ID_MAX, }; @@ -1839,4 +1894,16 @@ enum amdgpu_xgmi_link_status { AMDGPU_XGMI_LINK_NA = 2, }; +struct amdgpu_gpuboard_temp_metrics_v1_1 { + struct metrics_table_header common_header; + int attr_count; + struct gpu_metrics_attr metrics_attrs[]; +}; + +struct amdgpu_baseboard_temp_metrics_v1_1 { + struct metrics_table_header common_header; + int attr_count; + struct gpu_metrics_attr metrics_attrs[]; +}; + #endif diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index eca93a9d0b84..62b0b1ef0d10 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -33,6 +33,7 @@ #include <linux/hwmon-sysfs.h> #include <linux/nospec.h> #include <linux/pm_runtime.h> +#include <linux/string_choices.h> #include <asm/processor.h> #define MAX_NUM_OF_FEATURES_PER_SUBSET 8 @@ -680,6 +681,8 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, * - minimum(not available for Vega20 and Navi1x) and maximum memory * clock labeled OD_MCLK * + * - minimum and maximum fabric clock labeled OD_FCLK (SMU13) + * * - three <frequency, voltage> points labeled OD_VDDC_CURVE. * They can be used to calibrate the sclk voltage curve. This is * available for Vega20 and NV1X. @@ -715,10 +718,11 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, * - First select manual using power_dpm_force_performance_level * * - For clock frequency setting, enter a new value by writing a - * string that contains "s/m index clock" to the file. The index + * string that contains "s/m/f index clock" to the file. The index * should be 0 if to set minimum clock. And 1 if to set maximum * clock. E.g., "s 0 500" will update minimum sclk to be 500 MHz. - * "m 1 800" will update maximum mclk to be 800Mhz. For core + * "m 1 800" will update maximum mclk to be 800Mhz. "f 1 1600" will + * update maximum fabric clock to be 1600Mhz. For core * clocks on VanGogh, the string contains "p core index clock". * E.g., "p 2 0 800" would set the minimum core clock on core * 2 to 800Mhz. @@ -768,6 +772,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, type = PP_OD_EDIT_CCLK_VDDC_TABLE; else if (*buf == 'm') type = PP_OD_EDIT_MCLK_VDDC_TABLE; + else if (*buf == 'f') + type = PP_OD_EDIT_FCLK_TABLE; else if (*buf == 'r') type = PP_OD_RESTORE_DEFAULT_TABLE; else if (*buf == 'c') @@ -843,9 +849,10 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, struct amdgpu_device *adev = drm_to_adev(ddev); int size = 0; int ret; - enum pp_clock_type od_clocks[6] = { + enum pp_clock_type od_clocks[] = { OD_SCLK, OD_MCLK, + OD_FCLK, OD_VDDC_CURVE, OD_RANGE, OD_VDDGFX_OFFSET, @@ -857,10 +864,8 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, if (ret) return ret; - for (clk_index = 0 ; clk_index < 6 ; clk_index++) { - ret = amdgpu_dpm_emit_clock_levels(adev, od_clocks[clk_index], buf, &size); - if (ret) - break; + for (clk_index = 0 ; clk_index < ARRAY_SIZE(od_clocks) ; clk_index++) { + amdgpu_dpm_emit_clock_levels(adev, od_clocks[clk_index], buf, &size); } if (size == 0) @@ -1588,7 +1593,7 @@ static ssize_t amdgpu_get_thermal_throttling_logging(struct device *dev, return sysfs_emit(buf, "%s: thermal throttling logging %s, with interval %d seconds\n", adev_to_drm(adev)->unique, - atomic_read(&adev->throttling_logging_enabled) ? "enabled" : "disabled", + str_enabled_disabled(atomic_read(&adev->throttling_logging_enabled)), adev->throttling_logging_rs.interval / HZ + 1); } @@ -1910,8 +1915,6 @@ static int ss_bias_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ static int pp_od_clk_voltage_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr, uint32_t mask, enum amdgpu_device_attr_states *states) { - uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0); - *states = ATTR_STATE_SUPPORTED; if (!amdgpu_dpm_is_overdrive_supported(adev)) { @@ -1919,10 +1922,8 @@ static int pp_od_clk_voltage_attr_update(struct amdgpu_device *adev, struct amdg return 0; } - /* Enable pp_od_clk_voltage node for gc 9.4.3, 9.4.4, 9.5.0 SRIOV/BM support */ - if (gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4) || - gc_ver == IP_VERSION(9, 5, 0)) { + /* Enable pp_od_clk_voltage node for gc 9.4.3, 9.4.4, 9.5.0, 12.1.0 SRIOV/BM support */ + if (amdgpu_is_multi_aid(adev)) { if (amdgpu_sriov_multi_vf_mode(adev)) *states = ATTR_STATE_UNSUPPORTED; return 0; @@ -2000,9 +2001,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd gc_ver == IP_VERSION(11, 5, 0) || gc_ver == IP_VERSION(11, 0, 2) || gc_ver == IP_VERSION(11, 0, 3) || - gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4) || - gc_ver == IP_VERSION(9, 5, 0))) + amdgpu_is_multi_aid(adev))) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_dpm_vclk1)) { if (!((gc_ver == IP_VERSION(10, 3, 1) || @@ -2023,9 +2022,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd gc_ver == IP_VERSION(11, 5, 0) || gc_ver == IP_VERSION(11, 0, 2) || gc_ver == IP_VERSION(11, 0, 3) || - gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4) || - gc_ver == IP_VERSION(9, 5, 0))) + amdgpu_is_multi_aid(adev))) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_dpm_dclk1)) { if (!((gc_ver == IP_VERSION(10, 3, 1) || @@ -2035,9 +2032,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_dpm_pcie)) { if (gc_ver == IP_VERSION(9, 4, 2) || - gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4) || - gc_ver == IP_VERSION(9, 5, 0)) + amdgpu_is_multi_aid(adev)) *states = ATTR_STATE_UNSUPPORTED; } @@ -2241,7 +2236,7 @@ static ssize_t amdgpu_show_npm_status(struct device *dev, if (r) return r; - return sysfs_emit(buf, "%s\n", npower ? "enabled" : "disabled"); + return sysfs_emit(buf, "%s\n", str_enabled_disabled(npower)); } /** @@ -2651,6 +2646,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ case IP_VERSION(11, 0, 3): case IP_VERSION(12, 0, 0): case IP_VERSION(12, 0, 1): + case IP_VERSION(12, 1, 0): *states = ATTR_STATE_SUPPORTED; break; default: @@ -3732,8 +3728,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, /* Skip crit temp on APU */ if ((((adev->flags & AMD_IS_APU) && (adev->family >= AMDGPU_FAMILY_CZ)) || - (gc_ver == IP_VERSION(9, 4, 3) || gc_ver == IP_VERSION(9, 4, 4) || - gc_ver == IP_VERSION(9, 5, 0))) && + amdgpu_is_multi_aid(adev)) && (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr || attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)) return 0; @@ -3815,18 +3810,14 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, if ((adev->family == AMDGPU_FAMILY_SI || /* not implemented yet */ adev->family == AMDGPU_FAMILY_KV || /* not implemented yet */ - (gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4) || - gc_ver == IP_VERSION(9, 5, 0))) && + amdgpu_is_multi_aid(adev)) && (attr == &sensor_dev_attr_in0_input.dev_attr.attr || attr == &sensor_dev_attr_in0_label.dev_attr.attr)) return 0; /* only APUs other than gc 9,4,3 have vddnb */ if ((!(adev->flags & AMD_IS_APU) || - (gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4) || - gc_ver == IP_VERSION(9, 5, 0))) && + amdgpu_is_multi_aid(adev)) && (attr == &sensor_dev_attr_in1_input.dev_attr.attr || attr == &sensor_dev_attr_in1_label.dev_attr.attr)) return 0; @@ -3855,9 +3846,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, return 0; /* hotspot temperature for gc 9,4,3*/ - if (gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4) || - gc_ver == IP_VERSION(9, 5, 0)) { + if (amdgpu_is_multi_aid(adev)) { if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr || attr == &sensor_dev_attr_temp1_emergency.dev_attr.attr || attr == &sensor_dev_attr_temp1_label.dev_attr.attr) diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c index 61b1c5aa74cb..36942467d4ad 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c @@ -3454,9 +3454,11 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, if (adev->asic_type == CHIP_HAINAN) { if ((adev->pdev->revision == 0x81) || (adev->pdev->revision == 0xC3) || + (adev->pdev->device == 0x6660) || (adev->pdev->device == 0x6664) || (adev->pdev->device == 0x6665) || - (adev->pdev->device == 0x6667)) { + (adev->pdev->device == 0x6667) || + (adev->pdev->device == 0x666F)) { max_sclk = 75000; } if ((adev->pdev->revision == 0xC3) || diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c index 2b5ac21fee39..1d6e30269d56 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c @@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) PP_GFXOFF_MASK); hwmgr->pp_table_version = PP_TABLE_V0; hwmgr->od_enabled = false; + switch (hwmgr->chip_id) { + case CHIP_BONAIRE: + /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM + * R7 260X cards with old MC ucode: MCLK DPM is unstable + */ + if (adev->pdev->subsystem_vendor == 0x106B || + adev->pdev->device == 0x6658) { + dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); + adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; + hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; + } + break; + default: + break; + } smu7_init_function_pointers(hwmgr); break; case AMDGPU_FAMILY_CZ: diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c index e38222877f7e..8c37aa452569 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c @@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) hwmgr->dyn_state.vddc_dependency_on_mclk; struct phm_cac_leakage_table *std_voltage_table = hwmgr->dyn_state.cac_leakage_table; - uint32_t i; + uint32_t i, clk; PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, "SCLK dependency table is missing. This table is mandatory", return -EINVAL); @@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) data->dpm_table.sclk_table.count = 0; for (i = 0; i < allowed_vdd_sclk_table->count; i++) { + clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != - allowed_vdd_sclk_table->entries[i].clk) { + clk) { data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = - allowed_vdd_sclk_table->entries[i].clk; + clk; data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; data->dpm_table.sclk_table.count++; } @@ -2794,11 +2796,11 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) if (tmp) return -EINVAL; - tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dep_on_dal_pwrl); + tmp = smu7_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk); if (tmp) return -EINVAL; - tmp = smu7_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk); + tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); if (tmp) return -EINVAL; @@ -2883,8 +2885,8 @@ static int smu7_set_private_data_based_on_pptable_v0(struct pp_hwmgr *hwmgr) static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) { - kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; + kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); + hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; kfree(hwmgr->backend); hwmgr->backend = NULL; @@ -2955,6 +2957,70 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) return ret; } +static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) +{ + struct phm_clock_voltage_dependency_table *table; + + if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) + return 0; + + table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); + if (!table) + return -ENOMEM; + + if (hwmgr->chip_id >= CHIP_POLARIS10) { + table->entries[0].clk = 38918; + table->entries[1].clk = 45900; + table->entries[2].clk = 66700; + table->entries[3].clk = 113200; + + table->entries[0].v = 700; + table->entries[1].v = 740; + table->entries[2].v = 800; + table->entries[3].v = 900; + } else { + if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { + table->entries[0].clk = 35200; + table->entries[1].clk = 35200; + table->entries[2].clk = 46700; + table->entries[3].clk = 64300; + } else { + table->entries[0].clk = 0; + table->entries[1].clk = 35200; + table->entries[2].clk = 54000; + table->entries[3].clk = 62500; + } + + table->entries[0].v = 0; + table->entries[1].v = 720; + table->entries[2].v = 810; + table->entries[3].v = 900; + } + + table->count = 4; + hwmgr->dyn_state.vddc_dependency_on_display_clock = table; + return 0; +} + +static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + + data->sclk_cap = 0xffffffff; + + if (hwmgr->od_enabled) + return; + + /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ + if (adev->pdev->device == 0x67B0 && + adev->pdev->subsystem_vendor == 0x1043) + data->sclk_cap = 104000; /* 1040 MHz */ + + if (data->sclk_cap != 0xffffffff) + dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); +} + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; @@ -2966,6 +3032,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) return -ENOMEM; hwmgr->backend = data; + smu7_set_sclk_cap(hwmgr); smu7_patch_voltage_workaround(hwmgr); smu7_init_dpm_defaults(hwmgr); @@ -2983,6 +3050,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) smu7_get_elb_voltages(hwmgr); } + result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); + if (result) + goto fail; + if (hwmgr->pp_table_version == PP_TABLE_V1) { smu7_complete_dependency_tables(hwmgr); smu7_set_private_data_based_on_pptable_v1(hwmgr); @@ -2991,9 +3062,6 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) smu7_set_private_data_based_on_pptable_v0(hwmgr); } - /* Initalize Dynamic State Adjustment Rule Settings */ - result = phm_initializa_dynamic_state_adjustment_rule_settings(hwmgr); - if (result) goto fail; @@ -3079,13 +3147,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) return 0; } +static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) +{ + const struct amd_pp_display_configuration *cfg = hwmgr->display_config; + const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = + hwmgr->dyn_state.vddc_dependency_on_display_clock; + uint32_t i; + + if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || + !cfg || !cfg->num_display || !cfg->display_clk) + return 0; + + /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ + for (i = 1; i < vddc_dep_on_dispclk->count; ++i) + if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) + return vddc_dep_on_dispclk->entries[i].v; + + return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; +} + +static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) +{ + uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); + + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_VddC_Request, + req_vddc * VOLTAGE_SCALE, + NULL); +} + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - if (hwmgr->pp_table_version == PP_TABLE_V1) - phm_apply_dal_min_voltage_request(hwmgr); -/* TO DO for v0 iceland and Ci*/ + smu7_apply_minimum_dce_voltage_request(hwmgr); if (!data->sclk_dpm_key_disabled) { if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) @@ -3821,7 +3916,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, /* Performance levels are arranged from low to high. */ performance_level->memory_clock = memory_clock; - performance_level->engine_clock = engine_clock; + performance_level->engine_clock = min(engine_clock, data->sclk_cap); pcie_gen_from_bios = visland_clk_info->ucPCIEGen; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h index d9e8b386bd4d..66adabeab6a3 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h @@ -234,6 +234,7 @@ struct smu7_hwmgr { uint32_t pcie_gen_cap; uint32_t pcie_lane_cap; uint32_t pcie_spc_cap; + uint32_t sclk_cap; struct smu7_leakage_voltage vddc_leakage; struct smu7_leakage_voltage vddci_leakage; struct smu7_leakage_voltage vddcgfx_leakage; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c index 40ecaac6c604..30d83e18db40 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c @@ -484,52 +484,6 @@ int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, return 0; } -/** - * phm_initializa_dynamic_state_adjustment_rule_settings - Initialize Dynamic State Adjustment Rule Settings - * - * @hwmgr: the address of the powerplay hardware manager. - */ -int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr) -{ - struct phm_clock_voltage_dependency_table *table_clk_vlt; - struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); - - /* initialize vddc_dep_on_dal_pwrl table */ - table_clk_vlt = kzalloc_flex(*table_clk_vlt, entries, 4); - - if (NULL == table_clk_vlt) { - pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n"); - return -ENOMEM; - } else { - table_clk_vlt->count = 4; - table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW; - if (hwmgr->chip_id >= CHIP_POLARIS10 && - hwmgr->chip_id <= CHIP_VEGAM) - table_clk_vlt->entries[0].v = 700; - else - table_clk_vlt->entries[0].v = 0; - table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW; - if (hwmgr->chip_id >= CHIP_POLARIS10 && - hwmgr->chip_id <= CHIP_VEGAM) - table_clk_vlt->entries[1].v = 740; - else - table_clk_vlt->entries[1].v = 720; - table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL; - if (hwmgr->chip_id >= CHIP_POLARIS10 && - hwmgr->chip_id <= CHIP_VEGAM) - table_clk_vlt->entries[2].v = 800; - else - table_clk_vlt->entries[2].v = 810; - table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE; - table_clk_vlt->entries[3].v = 900; - if (pptable_info != NULL) - pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt; - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; - } - - return 0; -} - uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) { uint32_t level = 0; @@ -540,43 +494,6 @@ uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) return level; } -void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr) -{ - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)hwmgr->pptable; - struct phm_clock_voltage_dependency_table *table = - table_info->vddc_dep_on_dal_pwrl; - struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table; - enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level; - uint32_t req_vddc = 0, req_volt, i; - - if (!table || table->count <= 0 - || dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW - || dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE) - return; - - for (i = 0; i < table->count; i++) { - if (dal_power_level == table->entries[i].clk) { - req_vddc = table->entries[i].v; - break; - } - } - - vddc_table = table_info->vdd_dep_on_sclk; - for (i = 0; i < vddc_table->count; i++) { - if (req_vddc <= vddc_table->entries[i].vddc) { - req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE); - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_VddC_Request, - req_volt, - NULL); - return; - } - } - pr_err("DAL requested level can not" - " found a available voltage in VDDC DPM Table \n"); -} - int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t id, uint16_t *voltage) { diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h index 83b3c9315143..d370bfd0764d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h @@ -87,9 +87,7 @@ extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_t extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level); extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t virtual_voltage_id, int32_t *sclk); -extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr); extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask); -extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t id, uint16_t *voltage); diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h index c661185753b4..3ae45eac0c5c 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h @@ -631,6 +631,7 @@ struct phm_dynamic_state_info { struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; struct phm_clock_array *valid_sclk_values; struct phm_clock_array *valid_mclk_values; @@ -772,7 +773,6 @@ struct pp_hwmgr { const struct pp_smumgr_func *smumgr_funcs; bool is_kicker; - enum PP_DAL_POWERLEVEL dal_power_level; struct phm_dynamic_state_info dyn_state; const struct pp_hwmgr_func *hwmgr_func; const struct pp_table_func *pptable_func; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c index 62ebec1c6fe3..731355bdb9bc 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c @@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) smu_data->power_tune_defaults = &defaults_hawaii_pro; break; case 0x67B8: - case 0x66B0: + case 0x67B0: smu_data->power_tune_defaults = &defaults_hawaii_xt; break; case 0x6640: @@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) { struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; - uint32_t temp; if (ci_read_smc_sram_dword(hwmgr, fuse_table_offset + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), - (uint32_t *)&temp, SMC_RAM_END)) + (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) PP_ASSERT_WITH_CODE(false, "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", return -EINVAL); @@ -1217,7 +1216,7 @@ static int ci_populate_single_memory_level( } memory_level->EnabledForThrottle = 1; - memory_level->EnabledForActivity = 1; + memory_level->EnabledForActivity = 0; memory_level->UpH = data->current_profile_setting.mclk_up_hyst; memory_level->DownH = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownH = 0; @@ -1322,6 +1321,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) return result; } + if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { + /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ + for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { + levels[i] = levels[dpm_table->mclk_table.count - 1]; + levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; + } + } + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; dev_id = adev->pdev->device; diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 26b43a6276d0..8faf7de7aaa9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -47,6 +47,7 @@ #include "smu_v14_0_0_ppt.h" #include "smu_v14_0_2_ppt.h" #include "smu_v15_0_0_ppt.h" +#include "smu_v15_0_8_ppt.h" #include "amd_pcie.h" /* @@ -802,6 +803,10 @@ static int smu_set_funcs(struct amdgpu_device *adev) case IP_VERSION(15, 0, 0): smu_v15_0_0_set_ppt_funcs(smu); break; + case IP_VERSION(15, 0, 8): + smu_v15_0_8_set_ppt_funcs(smu); + smu->od_enabled = true; + break; default: return -EINVAL; } @@ -2965,6 +2970,7 @@ int smu_get_power_limit(void *handle, case IP_VERSION(11, 0, 11): case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): + case IP_VERSION(15, 0, 8): ret = smu_get_asic_power_limits(smu, &smu->current_power_limit, NULL, NULL, NULL); @@ -3056,6 +3062,8 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type) clk_type = SMU_OD_SCLK; break; case OD_MCLK: clk_type = SMU_OD_MCLK; break; + case OD_FCLK: + clk_type = SMU_OD_FCLK; break; case OD_VDDC_CURVE: clk_type = SMU_OD_VDDC_CURVE; break; case OD_RANGE: diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 90346e70a614..609f5ab07d8a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -389,6 +389,7 @@ struct smu_table_context { void *metrics_table; void *clocks_table; void *watermarks_table; + struct mutex metrics_lock; void *max_sustainable_clocks; struct smu_bios_boot_up_values boot_values; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h new file mode 100644 index 000000000000..6993d866183d --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h @@ -0,0 +1,295 @@ +/* + * Copyright 2025 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. + * + */ +#ifndef SMU_15_0_8_DRIVER_IF_H +#define SMU_15_0_8_DRIVER_IF_H + +//I2C Interface +#define NUM_I2C_CONTROLLERS 8 +#define I2C_CONTROLLER_ENABLED 1 +#define I2C_CONTROLLER_DISABLED 0 + +#define MAX_SW_I2C_COMMANDS 24 + +typedef enum { + I2C_CONTROLLER_PORT_0, + I2C_CONTROLLER_PORT_COUNT, +} I2cControllerPort_e; + +typedef enum { + /* 50 Kbits/s not supported anymore! */ + UNSUPPORTED_1, + /* 100 Kbits/s */ + I2C_SPEED_STANDARD_100K, + /* 400 Kbits/s */ + I2C_SPEED_FAST_400K, + /* 1 Mbits/s (in fast mode) */ + I2C_SPEED_FAST_PLUS_1M, + /* 1 Mbits/s (in high speed mode) not supported anymore!*/ + UNSUPPORTED_2, + /* 2.3 Mbits/s not supported anymore! */ + UNSUPPORTED_3, + I2C_SPEED_COUNT, +} I2cSpeed_e; + +typedef enum { + I2C_CMD_READ, + I2C_CMD_WRITE, + I2C_CMD_COUNT, +} I2cCmdType_e; + +#define CMDCONFIG_STOP_BIT 0 +#define CMDCONFIG_RESTART_BIT 1 +/* bit should be 0 for read, 1 for write */ +#define CMDCONFIG_READWRITE_BIT 2 + +#define CMDCONFIG_STOP_MASK (1 << CMDCONFIG_STOP_BIT) +#define CMDCONFIG_RESTART_MASK (1 << CMDCONFIG_RESTART_BIT) +#define CMDCONFIG_READWRITE_MASK (1 << CMDCONFIG_READWRITE_BIT) + +/* 64 Bit register offsets for PPSMC_MSG_McaBankDumpDW, PPSMC_MSG_McaBankCeDumpDW messages + * eg to read MCA_BANK_OFFSET_SYND for CE index, call PPSMC_MSG_McaBankCeDumpDW twice, + * (index << 16 + MCA_BANK_OFFSET_SYND*8) argument for 1st DWORD, and + * ((index << 16 ) + MCA_BANK_OFFSET_SYND*8 + 4) argument for 2nd DWORD */ +typedef enum { + MCA_BANK_OFFSET_CTL = 0, + MCA_BANK_OFFSET_STATUS = 1, + MCA_BANK_OFFSET_ADDR = 2, + MCA_BANK_OFFSET_MISC = 3, + MCA_BANK_OFFSET_IPID = 5, + MCA_BANK_OFFSET_SYND = 6, + MCA_BANK_OFFSET_MAX = 16, +} MCA_BANK_OFFSET_e; + +/* Firmware MP1 AID MCA Error Codes stored in MCA_MP_MP1:MCMP1_SYNDT0 errorinformation */ +typedef enum { + /* MMHUB */ + CODE_DAGB0 = 0, + CODE_DAGB1 = 1, + CODE_DAGB2 = 2, + CODE_DAGB3 = 3, + CODE_DAGB4 = 4, + CODE_EA0 = 5, + CODE_EA1 = 6, + CODE_EA2 = 7, + CODE_EA3 = 8, + CODE_EA4 = 9, + CODE_UTCL2_ROUTER = 10, + CODE_VML2 = 11, + CODE_VML2_WALKER = 12, + CODE_MMCANE = 13, + + /* VCN VCPU */ + CODE_VIDD = 14, + CODE_VIDV = 15, + /* VCN JPEG */ + CODE_JPEG0S = 16, + CODE_JPEG0D = 17, + CODE_JPEG1S = 18, + CODE_JPEG1D = 19, + CODE_JPEG2S = 20, + CODE_JPEG2D = 21, + CODE_JPEG3S = 22, + CODE_JPEG3D = 23, + CODE_JPEG4S = 24, + CODE_JPEG4D = 25, + CODE_JPEG5S = 26, + CODE_JPEG5D = 27, + CODE_JPEG6S = 28, + CODE_JPEG6D = 29, + CODE_JPEG7S = 30, + CODE_JPEG7D = 31, + /* VCN MMSCH */ + CODE_MMSCHD = 32, + + /* SDMA */ + CODE_SDMA0 = 33, + CODE_SDMA1 = 34, + CODE_SDMA2 = 35, + CODE_SDMA3 = 36, + + /* SOC */ + CODE_HDP = 37, + CODE_ATHUB = 38, + CODE_IH = 39, + CODE_XHUB_POISON = 40, + CODE_SMN_SLVERR = 41, + CODE_WDT = 42, + + CODE_UNKNOWN = 43, + CODE_DMA = 44, + CODE_COUNT = 45, +} ERR_CODE_e; + +/* Firmware MP5 XCD MCA Error Codes stored in MCA_MP_MP5:MCMP5_SYNDT0 errorinformation */ +typedef enum { + /* SH POISON FED */ + SH_FED_CODE = 0, + /* GCEA Pin UE_ERR regs */ + GCEA_CODE = 1, + SQ_CODE = 2, + LDS_CODE = 3, + GDS_CODE = 4, + SP0_CODE = 5, + SP1_CODE = 6, + TCC_CODE = 7, + TCA_CODE = 8, + TCX_CODE = 9, + CPC_CODE = 10, + CPF_CODE = 11, + CPG_CODE = 12, + SPI_CODE = 13, + RLC_CODE = 14, + /* GCEA Pin, UE_EDC regs */ + SQC_CODE = 15, + TA_CODE = 16, + TD_CODE = 17, + TCP_CODE = 18, + TCI_CODE = 19, + /* GC Router */ + GC_ROUTER_CODE = 20, + VML2_CODE = 21, + VML2_WALKER_CODE = 22, + ATCL2_CODE = 23, + GC_CANE_CODE = 24, + + /* SOC error codes 41-43 are common with ERR_CODE_e */ + MP5_CODE_SMN_SLVERR = CODE_SMN_SLVERR, + MP5_CODE_UNKNOWN = CODE_UNKNOWN, +} GC_ERROR_CODE_e; + +/* SW I2C Command Table */ +typedef struct { + /* Return data for read. Data to send for write*/ + uint8_t ReadWriteData; + /* Includes whether associated command should have a stop or restart command, + * and is a read or write */ + uint8_t CmdConfig; +} SwI2cCmd_t; + +/* SW I2C Request Table */ +typedef struct { + /* CKSVII2C0(0) or //CKSVII2C1(1) */ + uint8_t I2CcontrollerPort; + /* Use I2cSpeed_e to indicate speed to select */ + uint8_t I2CSpeed; + /* Slave address of device */ + uint8_t SlaveAddress; + /* Number of commands */ + uint8_t NumCmds; + SwI2cCmd_t SwI2cCmds[MAX_SW_I2C_COMMANDS]; +} SwI2cRequest_t; + +typedef struct { + SwI2cRequest_t SwI2cRequest; + uint32_t Spare[8]; + /* SMU internal use */ + uint32_t MmHubPadding[8]; +} SwI2cRequestExternal_t; + +typedef enum { + PPCLK_UCLK, + PPCLK_COUNT, +} PPCLK_e; + +typedef enum { + GPIO_INT_POLARITY_ACTIVE_LOW, + GPIO_INT_POLARITY_ACTIVE_HIGH, +} GpioIntPolarity_e; + +/* TODO confirm if this is used in MI300 PPSMC_MSG_SetUclkDpmMode */ +typedef enum { + UCLK_DPM_MODE_BANDWIDTH, + UCLK_DPM_MODE_LATENCY, +} UCLK_DPM_MODE_e; + +typedef struct { + /* 2 AVFS.PSM chains */ + uint16_t AvgPsmCount_Chain0[13]; + uint16_t AvgPsmCount_Chain1[15]; + uint16_t MinPsmCount_Chain0[13]; + uint16_t MinPsmCount_Chain1[15]; + float MaxTemperature; + + /* For voltage conversions, these are the array indexes + * 0:SOCIO + * 1:065_UCIE + * 2:075_UCIE + * 3:11_GTA + * 4:075_GTA */ + float MinPsmVoltage[5]; + float AvgPsmVoltage[5]; +} AvfsDebugTableMid_t; + +typedef struct { + /* 7 AVFS.PSM chains - not including TRO */ + uint16_t AvgPsmCount_Chain0[15]; + uint16_t AvgPsmCount_Chain1[15]; + uint16_t AvgPsmCount_Chain2[13]; + uint16_t AvgPsmCount_Chain3[13]; + uint16_t AvgPsmCount_Chain4[15]; + uint16_t AvgPsmCount_Chain5[15]; + uint16_t AvgPsmCount_Chain6[5]; + uint16_t MinPsmCount_Chain0[15]; + uint16_t MinPsmCount_Chain1[15]; + uint16_t MinPsmCount_Chain2[13]; + uint16_t MinPsmCount_Chain3[13]; + uint16_t MinPsmCount_Chain4[15]; + uint16_t MinPsmCount_Chain5[15]; + uint16_t MinPsmCount_Chain6[5]; + float MaxTemperature; + + /* For voltage conversions, these are the array indexes + * 0:VDDX */ + float MinPsmVoltage; + float AvgPsmVoltage; +} AvfsDebugTableAid_t; + +typedef struct { + /* 0-27 GFX, 28-29 SOC */ + uint16_t avgPsmCount[30]; + uint16_t minPsmCount[30]; + float avgPsmVoltage[30]; + float minPsmVoltage[30]; +} AvfsDebugTableXcd_t; + +/* Defines used for IH-based thermal interrupts to GFX driver - A/X only */ +#define IH_INTERRUPT_ID_TO_DRIVER 0xFE +#define IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING 0x7 +#define IH_INTERRUPT_VFFLR_INT 0xA + +/* thermal over-temp mask defines for IH interrup to host */ +#define THROTTLER_PROCHOT_BIT 0 +#define THROTTLER_RESERVED 1 +/* AID, XCD, CCD throttling */ +#define THROTTLER_THERMAL_SOCKET_BIT 2 +/* VRHOT */ +#define THROTTLER_THERMAL_VR_BIT 3 +#define THROTTLER_THERMAL_HBM_BIT 4 +/* UEs are always reported, set flag to 0 to prevent clearing of UEs */ +#define ClearMcaOnRead_UE_FLAG_MASK 0x1 +/* Enable CE logging and clearing to driver */ +#define ClearMcaOnRead_CE_POLL_MASK 0x2 +/* AID MMHUB client IP CE Logging and clearing */ +#define ClearMcaOnRead_MMHUB_POLL_MASK 0x4 + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h new file mode 100644 index 000000000000..a3401c4cc20b --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h @@ -0,0 +1,427 @@ +/* + * Copyright 2025 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. + * + */ +#ifndef SMU_15_0_8_PMFW_H +#define SMU_15_0_8_PMFW_H + +#define NUM_VCLK_DPM_LEVELS 4 +#define NUM_DCLK_DPM_LEVELS 4 +#define NUM_SOCCLK_DPM_LEVELS 4 +#define NUM_LCLK_DPM_LEVELS 4 +#define NUM_UCLK_DPM_LEVELS 4 +#define NUM_FCLK_DPM_LEVELS 4 +#define NUM_XGMI_DPM_LEVELS 2 +#define NUM_PCIE_BITRATES 4 +#define NUM_XGMI_BITRATES 4 +#define NUM_XGMI_WIDTHS 3 +#define NUM_GFX_P2S_TABLES 8 +#define NUM_PSM_DIDT_THRESHOLDS 3 +#define NUM_XCD_XVMIN_VMIN_THRESHOLDS 3 + +#define PRODUCT_MODEL_NUMBER_LEN 20 +#define PRODUCT_NAME_LEN 64 +#define PRODUCT_SERIAL_LEN 20 +#define PRODUCT_MANUFACTURER_NAME_LEN 32 +#define PRODUCT_FRU_ID_LEN 32 + +//Feature ID list +#define FEATURE_ID_DATA_CALCULATION 1 +#define FEATURE_ID_DPM_FCLK 2 +#define FEATURE_ID_DPM_GFXCLK 3 +#define FEATURE_ID_DPM_SPARE_4 4 +#define FEATURE_ID_DPM_SPARE_5 5 +#define FEATURE_ID_DPM_UCLK 6 +#define FEATURE_ID_DPM_SPARE_7 7 +#define FEATURE_ID_DPM_XGMI 8 +#define FEATURE_ID_DS_FCLK 9 +#define FEATURE_ID_DS_GFXCLK 10 +#define FEATURE_ID_DS_LCLK 11 +#define FEATURE_ID_DS_MP0CLK 12 +#define FEATURE_ID_DS_MP1CLK 13 +#define FEATURE_ID_DS_MPIOCLK 14 +#define FEATURE_ID_DS_SOCCLK 15 +#define FEATURE_ID_DS_VCN 16 +#define FEATURE_ID_PPT 17 +#define FEATURE_ID_TDC 18 +#define FEATURE_ID_THERMAL 19 +#define FEATURE_ID_SOC_PCC 20 +#define FEATURE_ID_PROCHOT 21 +#define FEATURE_ID_XVMIN0_VMIN_AID 22 +#define FEATURE_ID_XVMIN1_DD_AID 23 +#define FEATURE_ID_XVMIN0_VMIN_XCD 24 +#define FEATURE_ID_XVMIN1_DD_XCD 25 +#define FEATURE_ID_FW_CTF 26 +#define FEATURE_ID_MGCG 27 +#define FEATURE_ID_PSI7 28 +#define FEATURE_ID_XGMI_PER_LINK_PWR_DOWN 29 +#define FEATURE_ID_SOC_DC_RTC 30 +#define FEATURE_ID_GFX_DC_RTC 31 +#define FEATURE_ID_DVM_MIN_PSM 32 +#define FEATURE_ID_PRC 33 +#define FEATURE_ID_PSM_DIDT 34 +#define FEATURE_ID_PIT 35 +#define FEATURE_ID_DVO 36 +#define FEATURE_ID_XVMIN_CLKSTOP_DS 37 +#define FEATURE_ID_HBM_THROTTLE_CTRL 38 +#define FEATURE_ID_DPM_GL2CLK 39 +#define FEATURE_ID_GC_CAC_EDC 40 +#define FEATURE_ID_DS_DMABECLK 41 +#define FEATURE_ID_DS_MPIFOECLK 42 +#define FEATURE_ID_DS_MPRASCLK 43 +#define FEATURE_ID_DS_MPNHTCLK 44 +#define FEATURE_ID_DS_FIOCLK 45 +#define FEATURE_ID_DS_DXIOCLK 46 +#define FEATURE_ID_PCC 47 +#define FEATURE_ID_OCP 48 +#define FEATURE_ID_TRO 49 +#define FEATURE_ID_GL2_CAC_EDC 50 +#define FEATURE_ID_SPARE_51 51 +#define FEATURE_ID_GL2_CGCG 52 +#define FEATURE_ID_XCAC 53 +#define FEATURE_ID_DS_GL2CLK 54 +#define FEATURE_ID_FCS_VIN_PCC 55 +#define FEATURE_ID_FCS_VDDX_OCP_WARN 56 +#define FEATURE_ID_FCS_PWRBRK 57 +#define FEATURE_ID_DF_CSTATE 58 +#define FEATURE_ID_ARO 59 +#define FEATURE_ID_PS_PsPowerLimit 60 +#define FEATURE_ID_PS_PsPowerFloor 61 +#define FEATURE_ID_OCPWARNRC 62 +#define FEATURE_ID_XGMI_FOLDING 63 +#define FEATURE_ID_SMU_CG 64 +#define NUM_FEATURES 65 + +//MGCG Feature ID List +#define WAFL_CG 0 +#define SMU_FUSE_CG_DEEPSLEEP 1 +#define SMUIO_CG 2 +#define RSMU_MGCG 3 +#define SMU_CLK_MGCG 4 +#define MP5_CG 5 +#define UMC_CG 6 +#define WAFL0_CLK 7 +#define WAFL1_CLK 8 +#define VCN_MGCG 9 +#define GL2_MGCG 10 +#define MGCG_NUM_FEATURES 11 + +/* enum for MPIO PCIe gen speed msgs */ +typedef enum { + PCIE_LINK_SPEED_INDEX_TABLE_GEN1, + PCIE_LINK_SPEED_INDEX_TABLE_GEN2, + PCIE_LINK_SPEED_INDEX_TABLE_GEN3, + PCIE_LINK_SPEED_INDEX_TABLE_GEN4, + PCIE_LINK_SPEED_INDEX_TABLE_GEN5, + PCIE_LINK_SPEED_INDEX_TABLE_GEN6, + PCIE_LINK_SPEED_INDEX_TABLE_GEN6_ESM, + PCIE_LINK_SPEED_INDEX_TABLE_COUNT +} PCIE_LINK_SPEED_INDEX_TABLE_e; + +typedef enum { + GFX_GUARDBAND_OFFSET_0, + GFX_GUARDBAND_OFFSET_1, + GFX_GUARDBAND_OFFSET_2, + GFX_GUARDBAND_OFFSET_3, + GFX_GUARDBAND_OFFSET_4, + GFX_GUARDBAND_OFFSET_5, + GFX_GUARDBAND_OFFSET_6, + GFX_GUARDBAND_OFFSET_7, + GFX_GUARDBAND_OFFSET_COUNT +} GFX_GUARDBAND_OFFSET_e; + +typedef enum { + GFX_DVM_MARGINHI_0, + GFX_DVM_MARGINHI_1, + GFX_DVM_MARGINHI_2, + GFX_DVM_MARGINHI_3, + GFX_DVM_MARGINHI_4, + GFX_DVM_MARGINHI_5, + GFX_DVM_MARGINHI_6, + GFX_DVM_MARGINHI_7, + GFX_DVM_MARGINLO_0, + GFX_DVM_MARGINLO_1, + GFX_DVM_MARGINLO_2, + GFX_DVM_MARGINLO_3, + GFX_DVM_MARGINLO_4, + GFX_DVM_MARGINLO_5, + GFX_DVM_MARGINLO_6, + GFX_DVM_MARGINLO_7, + GFX_DVM_MARGIN_COUNT +} GFX_DVM_MARGIN_e; + +typedef enum{ + SYSTEM_TEMP_UBB_FPGA, + SYSTEM_TEMP_UBB_FRONT, + SYSTEM_TEMP_UBB_BACK, + SYSTEM_TEMP_UBB_OAM7, + SYSTEM_TEMP_UBB_IBC, + SYSTEM_TEMP_UBB_UFPGA, + SYSTEM_TEMP_UBB_OAM1, + SYSTEM_TEMP_OAM_0_1_HSC, + SYSTEM_TEMP_OAM_2_3_HSC, + SYSTEM_TEMP_OAM_4_5_HSC, + SYSTEM_TEMP_OAM_6_7_HSC, + SYSTEM_TEMP_UBB_FPGA_0V72_VR, + SYSTEM_TEMP_UBB_FPGA_3V3_VR, + SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR, + SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR, + SYSTEM_TEMP_RETIMER_0_1_0V9_VR, + SYSTEM_TEMP_RETIMER_4_5_0V9_VR, + SYSTEM_TEMP_RETIMER_2_3_0V9_VR, + SYSTEM_TEMP_RETIMER_6_7_0V9_VR, + SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR, + SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR, + SYSTEM_TEMP_IBC_HSC, + SYSTEM_TEMP_IBC, + SYSTEM_TEMP_MAX_ENTRIES = 32 +} SYSTEM_TEMP_e; + +typedef enum{ + NODE_TEMP_RETIMER, + NODE_TEMP_IBC_TEMP, + NODE_TEMP_IBC_2_TEMP, + NODE_TEMP_VDD18_VR_TEMP, + NODE_TEMP_04_HBM_B_VR_TEMP, + NODE_TEMP_04_HBM_D_VR_TEMP, + NODE_TEMP_MAX_TEMP_ENTRIES = 12 +} NODE_TEMP_e; + +typedef enum { + SVI_PLANE_VDDCR_X0_TEMP, + SVI_PLANE_VDDCR_X1_TEMP, + + SVI_PLANE_VDDIO_HBM_B_TEMP, + SVI_PLANE_VDDIO_HBM_D_TEMP, + SVI_PLANE_VDDIO_04_HBM_B_TEMP, + SVI_PLANE_VDDIO_04_HBM_D_TEMP, + SVI_PLANE_VDDCR_HBM_B_TEMP, + SVI_PLANE_VDDCR_HBM_D_TEMP, + SVI_PLANE_VDDCR_075_HBM_B_TEMP, + SVI_PLANE_VDDCR_075_HBM_D_TEMP, + + SVI_PLANE_VDDIO_11_GTA_A_TEMP, + SVI_PLANE_VDDIO_11_GTA_C_TEMP, + SVI_PLANE_VDDAN_075_GTA_A_TEMP, + SVI_PLANE_VDDAN_075_GTA_C_TEMP, + + SVI_PLANE_VDDCR_075_UCIE_TEMP, + SVI_PLANE_VDDIO_065_UCIEAA_TEMP, + SVI_PLANE_VDDIO_065_UCIEAM_A_TEMP, + SVI_PLANE_VDDIO_065_UCIEAM_C_TEMP, + + SVI_PLANE_VDDCR_SOCIO_A_TEMP, + SVI_PLANE_VDDCR_SOCIO_C_TEMP, + + SVI_PLANE_VDDAN_075_TEMP, + SVI_MAX_TEMP_ENTRIES, //22 +} SVI_TEMP_e; + +typedef enum{ + SYSTEM_POWER_UBB_POWER, + SYSTEM_POWER_UBB_POWER_THRESHOLD, + SYSTEM_POWER_MAX_ENTRIES_WO_RESERVED, + SYSTEM_POWER_MAX_ENTRIES = 4 +} SYSTEM_POWER_e; + +#define SMU_METRICS_TABLE_VERSION 0xF + +typedef struct __attribute__((packed, aligned(4))) { + uint64_t AccumulationCounter; + + //TEMPERATURE + uint32_t MaxSocketTemperature; + uint32_t MaxVrTemperature; + uint32_t HbmTemperature[12]; + uint64_t MaxSocketTemperatureAcc; + uint64_t MaxVrTemperatureAcc; + uint64_t HbmTemperatureAcc[12]; + uint32_t MidTemperature[2]; + uint32_t AidTemperature[2]; + uint32_t XcdTemperature[8]; + + //POWER + uint32_t SocketPowerLimit; + uint32_t SocketPower; + + //ENERGY + uint64_t Timestamp; + uint64_t SocketEnergyAcc; + uint64_t HbmEnergyAcc; + + //FREQUENCY + uint32_t GfxclkFrequencyLimit; + uint32_t FclkFrequency[2]; + uint32_t UclkFrequency[2]; + uint64_t GfxclkFrequencyAcc[8]; + uint32_t GfxclkFrequency[8]; + uint32_t SocclkFrequency[2]; + uint32_t VclkFrequency[4]; + uint32_t DclkFrequency[4]; + uint32_t LclkFrequency[2]; + + //XGMI: + uint32_t XgmiWidth; + uint32_t XgmiBitrate; + uint64_t XgmiReadBandwidthAcc; + uint64_t XgmiWriteBandwidthAcc; + + //ACTIVITY: + uint32_t SocketGfxBusy; + uint32_t DramBandwidthUtilization; + uint64_t SocketGfxBusyAcc; + uint64_t DramBandwidthAcc; + uint32_t MaxDramBandwidth; + uint64_t DramBandwidthUtilizationAcc; + uint64_t PcieBandwidthAcc[2]; + + //THROTTLERS + uint64_t ProchotResidencyAcc; + uint64_t PptResidencyAcc; + uint64_t SocketThmResidencyAcc; + uint64_t VrThmResidencyAcc; + uint64_t HbmThmResidencyAcc; + + //PCIE BW Data and error count + uint32_t PcieBandwidth[2]; + uint64_t PCIeL0ToRecoveryCountAcc; + uint64_t PCIenReplayAAcc; + uint64_t PCIenReplayARolloverCountAcc; + uint64_t PCIeNAKSentCountAcc; + uint64_t PCIeNAKReceivedCountAcc; + uint64_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated + + // VCN/JPEG ACTIVITY + uint32_t VcnBusy[4]; + uint32_t JpegBusy[40]; + + // PCIE LINK Speed and width + uint32_t PCIeLinkSpeed; + uint32_t PCIeLinkWidth; + + // PER XCD ACTIVITY + uint32_t GfxBusy[8]; + uint64_t GfxBusyAcc[8]; + + //NVML-Parity: Total App Clock Counter + uint64_t GfxclkBelowHostLimitPptAcc[8]; + uint64_t GfxclkBelowHostLimitThmAcc[8]; + uint64_t GfxclkBelowHostLimitTotalAcc[8]; + uint64_t GfxclkLowUtilizationAcc[8]; +} MetricsTable_t; + +#define SMU_SYSTEM_METRICS_TABLE_VERSION 0x1 + +#pragma pack(push, 4) +typedef struct { + uint64_t AccumulationCounter; // Last update timestamp + uint16_t LabelVersion; //Defaults to 0. + uint16_t NodeIdentifier; + int16_t SystemTemperatures[SYSTEM_TEMP_MAX_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF + int16_t NodeTemperatures[NODE_TEMP_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF + int16_t VrTemperatures[SVI_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius, 13 entries, + int16_t spare[7]; + + //NPM: NODE POWER MANAGEMENT + uint32_t NodePowerLimit; + uint32_t NodePower; + uint32_t GlobalPPTResidencyAcc; + + uint16_t SystemPower[SYSTEM_POWER_MAX_ENTRIES]; // UBB Current Power and Power Threshold +} SystemMetricsTable_t; +#pragma pack(pop) + +#define SMU_VF_METRICS_TABLE_VERSION 0x5 + +typedef struct __attribute__((packed, aligned(4))) { + uint32_t AccumulationCounter; + uint32_t InstGfxclk_TargFreq; + uint64_t AccGfxclk_TargFreq; + uint64_t AccGfxRsmuDpm_Busy; + uint64_t AccGfxclkBelowHostLimit; +} VfMetricsTable_t; + +/* FRU product information */ +typedef struct __attribute__((aligned(4))) { + uint8_t ModelNumber[PRODUCT_MODEL_NUMBER_LEN]; + uint8_t Name[PRODUCT_NAME_LEN]; + uint8_t Serial[PRODUCT_SERIAL_LEN]; + uint8_t ManufacturerName[PRODUCT_MANUFACTURER_NAME_LEN]; + uint8_t FruId[PRODUCT_FRU_ID_LEN]; +} FRUProductInfo_t; + +#define SMU_STATIC_METRICS_TABLE_VERSION 0x1 + +#pragma pack(push, 4) +typedef struct { + //FRU PRODUCT INFO + FRUProductInfo_t ProductInfo; //from i2c + + //POWER + uint32_t MaxSocketPowerLimit; + + //FREQUENCY RANGE + uint32_t MaxGfxclkFrequency; + uint32_t MinGfxclkFrequency; + uint32_t MaxFclkFrequency; + uint32_t MinFclkFrequency; + uint32_t MaxGl2clkFrequency; + uint32_t MinGl2clkFrequency; + uint32_t UclkFrequencyTable[4]; + uint32_t SocclkFrequency; + uint32_t LclkFrequency; + uint32_t VclkFrequency; + uint32_t DclkFrequency; + + //CTF limits + uint32_t CTFLimit_MID; + uint32_t CTFLimit_AID; + uint32_t CTFLimit_XCD; + uint32_t CTFLimit_HBM; + + //Thermal Throttling limits + uint32_t ThermalLimit_MID; + uint32_t ThermalLimit_AID; + uint32_t ThermalLimit_XCD; + uint32_t ThermalLimit_HBM; + + //PSNs + uint64_t PublicSerialNumber_MID[2]; + uint64_t PublicSerialNumber_AID[2]; + uint64_t PublicSerialNumber_XCD[8]; + + //XGMI + uint32_t MaxXgmiWidth; + uint32_t MaxXgmiBitrate; + + // Telemetry + uint32_t InputTelemetryVoltageInmV; + + // General info + uint32_t pldmVersion[2]; + + uint32_t PPT1Max; + uint32_t PPT1Min; + uint32_t PPT1Default; +} StaticMetricsTable_t; +#pragma pack(pop) + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h new file mode 100644 index 000000000000..7ffb445f4c0c --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h @@ -0,0 +1,100 @@ +/* + * Copyright 2025 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. + * + */ +#ifndef SMU_15_0_8_PPSMC_H +#define SMU_15_0_8_PPSMC_H + +/* SMU Response Codes */ +#define PPSMC_Result_OK 0x1 +#define PPSMC_Result_Failed 0xFF +#define PPSMC_Result_UnknownCmd 0xFE +#define PPSMC_Result_CmdRejectedPrereq 0xFD +#define PPSMC_Result_CmdRejectedBusy 0xFC + +/* Message Definitions */ +#define PPSMC_MSG_TestMessage 0x1 +#define PPSMC_MSG_GetSmuVersion 0x2 +#define PPSMC_MSG_GfxDriverReset 0x3 +#define PPSMC_MSG_GetDriverIfVersion 0x4 +#define PPSMC_MSG_EnableAllSmuFeatures 0x5 +#define PPSMC_MSG_GetMetricsVersion 0x6 +#define PPSMC_MSG_GetMetricsTable 0x7 +#define PPSMC_MSG_GetEnabledSmuFeatures 0x8 +#define PPSMC_MSG_SetDriverDramAddr 0x9 //ARG0: low address, ARG1: high address +#define PPSMC_MSG_SetToolsDramAddr 0xA //ARG0: low address, ARG1: high address +//#define PPSMC_MSG_SetSystemVirtualDramAddr 0xB +#define PPSMC_MSG_SetSoftMaxByFreq 0xC +#define PPSMC_MSG_SetPptLimit 0xD +#define PPSMC_MSG_GetPptLimit 0xE +#define PPSMC_MSG_DramLogSetDramAddr 0xF //ARG0: low address, ARG1: high address, ARG2: size +#define PPSMC_MSG_HeavySBR 0x10 +#define PPSMC_MSG_DFCstateControl 0x11 +#define PPSMC_MSG_GfxDriverResetRecovery 0x12 +#define PPSMC_MSG_TriggerVFFLR 0x13 +#define PPSMC_MSG_SetSoftMinGfxClk 0x14 +#define PPSMC_MSG_SetSoftMaxGfxClk 0x15 +#define PPSMC_MSG_PrepareForDriverUnload 0x16 +#define PPSMC_MSG_QueryValidMcaCount 0x17 +#define PPSMC_MSG_McaBankDumpDW 0x18 +#define PPSMC_MSG_ClearMcaOnRead 0x19 +#define PPSMC_MSG_QueryValidMcaCeCount 0x1A +#define PPSMC_MSG_McaBankCeDumpDW 0x1B +#define PPSMC_MSG_SelectPLPDMode 0x1C +#define PPSMC_MSG_SetThrottlingPolicy 0x1D +#define PPSMC_MSG_ResetSDMA 0x1E +#define PPSMC_MSG_GetRasTableVersion 0x1F +#define PPSMC_MSG_GetRmaStatus 0x20 +#define PPSMC_MSG_GetBadPageCount 0x21 +#define PPSMC_MSG_GetBadPageMcaAddress 0x22 +#define PPSMC_MSG_GetBadPagePaAddress 0x23 +#define PPSMC_MSG_SetTimestamp 0x24 +#define PPSMC_MSG_GetTimestamp 0x25 +#define PPSMC_MSG_GetRasPolicy 0x26 +#define PPSMC_MSG_GetBadPageIpIdLoHi 0x27 +#define PPSMC_MSG_EraseRasTable 0x28 +#define PPSMC_MSG_GetStaticMetricsTable 0x29 +#define PPSMC_MSG_ResetVfArbitersByIndex 0x2A +#define PPSMC_MSG_GetBadPageSeverity 0x2B +#define PPSMC_MSG_GetSystemMetricsTable 0x2C +#define PPSMC_MSG_GetSystemMetricsVersion 0x2D +#define PPSMC_MSG_ResetVCN 0x2E +#define PPSMC_MSG_SetFastPptLimit 0x2F +#define PPSMC_MSG_GetFastPptLimit 0x30 +#define PPSMC_MSG_SetSoftMinGl2clk 0x31 +#define PPSMC_MSG_SetSoftMaxGl2clk 0x32 +#define PPSMC_MSG_SetSoftMinFclk 0x33 +#define PPSMC_MSG_SetSoftMaxFclk 0x34 +#define PPSMC_Message_Count 0x35 + +/* PSMC Reset Types for driver msg argument */ +#define PPSMC_RESET_TYPE_DRIVER_MODE_1_RESET 0x1 +#define PPSMC_RESET_TYPE_DRIVER_MODE_2_RESET 0x2 +#define PPSMC_RESET_TYPE_DRIVER_MODE_3_RESET 0x3 + +/* PLPD modes */ +#define PPSMC_PLPD_MODE_DEFAULT 0x1 +#define PPSMC_PLPD_MODE_OPTIMIZED 0x2 + +typedef uint32_t PPSMC_Result; +typedef uint32_t PPSMC_MSG; + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h index 584c4cfd0c16..636ff90923d9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -42,8 +42,10 @@ __SMU_DUMMY_MAP(SetPptLimit), \ __SMU_DUMMY_MAP(SetDriverDramAddrHigh), \ __SMU_DUMMY_MAP(SetDriverDramAddrLow), \ + __SMU_DUMMY_MAP(SetDriverDramAddr), \ __SMU_DUMMY_MAP(SetToolsDramAddrHigh), \ __SMU_DUMMY_MAP(SetToolsDramAddrLow), \ + __SMU_DUMMY_MAP(SetToolsDramAddr), \ __SMU_DUMMY_MAP(TransferTableSmu2Dram), \ __SMU_DUMMY_MAP(TransferTableDram2Smu), \ __SMU_DUMMY_MAP(UseDefaultPPTable), \ @@ -292,7 +294,12 @@ __SMU_DUMMY_MAP(AllowZstates), \ __SMU_DUMMY_MAP(GetSmartShiftStatus), \ __SMU_DUMMY_MAP(EnableLSdma), \ - __SMU_DUMMY_MAP(DisableLSdma), + __SMU_DUMMY_MAP(DisableLSdma), \ + __SMU_DUMMY_MAP(InitializeGfx), \ + __SMU_DUMMY_MAP(SetSoftMaxFclk), \ + __SMU_DUMMY_MAP(SetSoftMaxGl2clk), \ + __SMU_DUMMY_MAP(SetSoftMinGl2clk), \ + __SMU_DUMMY_MAP(GetSystemMetricsVersion), #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(type) SMU_MSG_##type @@ -324,6 +331,7 @@ enum smu_clk_type { SMU_OD_CCLK, SMU_OD_SCLK, SMU_OD_MCLK, + SMU_OD_FCLK, SMU_OD_VDDC_CURVE, SMU_OD_RANGE, SMU_OD_VDDGFX_OFFSET, @@ -334,6 +342,7 @@ enum smu_clk_type { SMU_OD_FAN_MINIMUM_PWM, SMU_OD_FAN_ZERO_RPM_ENABLE, SMU_OD_FAN_ZERO_RPM_STOP_TEMP, + SMU_GL2CLK, SMU_CLK_COUNT, }; @@ -472,6 +481,14 @@ enum smu_clk_type { __SMU_DUMMY_MAP(GFX_DIDT_XVMIN), \ __SMU_DUMMY_MAP(FAN_ABNORMAL), \ __SMU_DUMMY_MAP(PIT), \ + __SMU_DUMMY_MAP(DS_DMABECLK), \ + __SMU_DUMMY_MAP(DS_MPIFOECLK), \ + __SMU_DUMMY_MAP(DS_MPRASCLK), \ + __SMU_DUMMY_MAP(DS_MPNHTCLK), \ + __SMU_DUMMY_MAP(DS_FIOCLK), \ + __SMU_DUMMY_MAP(DS_DXIOCLK), \ + __SMU_DUMMY_MAP(DS_GL2CLK), \ + __SMU_DUMMY_MAP(DPM_GL2CLK), \ __SMU_DUMMY_MAP(HROM_EN), #undef __SMU_DUMMY_MAP diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h index 7c1701ed3e11..dd94e8a9e218 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h @@ -25,18 +25,6 @@ #include "amdgpu_smu.h" -#define SMU11_DRIVER_IF_VERSION_INV 0xFFFFFFFF -#define SMU11_DRIVER_IF_VERSION_ARCT 0x17 -#define SMU11_DRIVER_IF_VERSION_NV10 0x37 -#define SMU11_DRIVER_IF_VERSION_NV12 0x38 -#define SMU11_DRIVER_IF_VERSION_NV14 0x38 -#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x40 -#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0xE -#define SMU11_DRIVER_IF_VERSION_VANGOGH 0x03 -#define SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish 0xF -#define SMU11_DRIVER_IF_VERSION_Beige_Goby 0xD -#define SMU11_DRIVER_IF_VERSION_Cyan_Skillfish 0x8 - /* MP Apertures */ #define MP0_Public 0x03800000 #define MP0_SRAM 0x03900000 @@ -148,8 +136,6 @@ int smu_v11_0_setup_pptable(struct smu_context *smu); int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu); -int smu_v11_0_check_fw_version(struct smu_context *smu); - int smu_v11_0_set_driver_table_location(struct smu_context *smu); int smu_v11_0_set_tool_table_location(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h index fd3937b08662..2346d9c6e162 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h @@ -35,8 +35,6 @@ int smu_v12_0_check_fw_status(struct smu_context *smu); -int smu_v12_0_check_fw_version(struct smu_context *smu); - int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate); int smu_v12_0_powergate_vcn(struct smu_context *smu, bool gate); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index b0d6b7b0946d..89bbda0670ef 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -132,8 +132,6 @@ int smu_v13_0_setup_pptable(struct smu_context *smu); int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu); -int smu_v13_0_check_fw_version(struct smu_context *smu); - int smu_v13_0_set_driver_table_location(struct smu_context *smu); int smu_v13_0_set_tool_table_location(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h index b453e6efc7c9..4eb40ff8aff2 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h @@ -25,11 +25,6 @@ #include "amdgpu_smu.h" -#define SMU14_DRIVER_IF_VERSION_INV 0xFFFFFFFF -#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7 -#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_1 0x6 -#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x2E - #define FEATURE_MASK(feature) (1ULL << feature) /* MP Apertures */ @@ -124,8 +119,6 @@ int smu_v14_0_setup_pptable(struct smu_context *smu); int smu_v14_0_get_vbios_bootup_values(struct smu_context *smu); -int smu_v14_0_check_fw_version(struct smu_context *smu); - int smu_v14_0_set_driver_table_location(struct smu_context *smu); int smu_v14_0_set_tool_table_location(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h index ab4a64f54e79..e6fd8be2cc4a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h @@ -41,7 +41,10 @@ #define smnMP1_FIRMWARE_FLAGS 0x3010024 #define smnMP1_PUB_CTRL 0x3010d10 -#define MAX_DPM_LEVELS 16 +#define SMU15_DRIVER_IF_VERSION_SMU_V15_0_8 0x007D0000 + +#define FEATURE_MASK(feature) (1ULL << feature) + #define MAX_PCIE_CONF 3 #define SMU15_TOOL_SIZE 0x19000 @@ -65,45 +68,28 @@ struct smu_15_0_max_sustainable_clocks { uint32_t soc_clock; }; -struct smu_15_0_dpm_clk_level { - bool enabled; - uint32_t value; -}; - -struct smu_15_0_dpm_table { - uint32_t min; /* MHz */ - uint32_t max; /* MHz */ - uint32_t count; - bool is_fine_grained; - struct smu_15_0_dpm_clk_level dpm_levels[MAX_DPM_LEVELS]; -}; - -struct smu_15_0_pcie_table { - uint8_t pcie_gen[MAX_PCIE_CONF]; - uint8_t pcie_lane[MAX_PCIE_CONF]; - uint16_t clk_freq[MAX_PCIE_CONF]; - uint32_t num_of_link_levels; -}; - struct smu_15_0_dpm_tables { - struct smu_15_0_dpm_table soc_table; - struct smu_15_0_dpm_table gfx_table; - struct smu_15_0_dpm_table uclk_table; - struct smu_15_0_dpm_table eclk_table; - struct smu_15_0_dpm_table vclk_table; - struct smu_15_0_dpm_table dclk_table; - struct smu_15_0_dpm_table dcef_table; - struct smu_15_0_dpm_table pixel_table; - struct smu_15_0_dpm_table display_table; - struct smu_15_0_dpm_table phy_table; - struct smu_15_0_dpm_table fclk_table; - struct smu_15_0_pcie_table pcie_table; + struct smu_dpm_table soc_table; + struct smu_dpm_table gfx_table; + struct smu_dpm_table uclk_table; + struct smu_dpm_table eclk_table; + struct smu_dpm_table vclk_table; + struct smu_dpm_table dclk_table; + struct smu_dpm_table dcef_table; + struct smu_dpm_table pixel_table; + struct smu_dpm_table display_table; + struct smu_dpm_table phy_table; + struct smu_dpm_table fclk_table; + struct smu_pcie_table pcie_table; + struct smu_dpm_table gl2_table; }; struct smu_15_0_dpm_context { struct smu_15_0_dpm_tables dpm_tables; uint32_t workload_policy_mask; uint32_t dcef_min_ds_clk; + uint64_t caps; + uint32_t board_volt; }; enum smu_15_0_power_state { @@ -118,6 +104,7 @@ struct smu_15_0_power_context { uint32_t power_source; uint8_t in_power_limit_boost_mode; enum smu_15_0_power_state power_state; + atomic_t throttle_status; }; #if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) @@ -142,8 +129,6 @@ int smu_v15_0_setup_pptable(struct smu_context *smu); int smu_v15_0_get_vbios_bootup_values(struct smu_context *smu); -int smu_v15_0_check_fw_version(struct smu_context *smu); - int smu_v15_0_set_driver_table_location(struct smu_context *smu); int smu_v15_0_set_tool_table_location(struct smu_context *smu); @@ -199,7 +184,7 @@ int smu_v15_0_set_power_source(struct smu_context *smu, int smu_v15_0_set_single_dpm_table(struct smu_context *smu, enum smu_clk_type clk_type, - struct smu_15_0_dpm_table *single_dpm_table); + struct smu_dpm_table *single_dpm_table); int smu_v15_0_gfx_ulv_control(struct smu_context *smu, bool enablement); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 74c818e3fbd0..54d3dba7d354 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -65,6 +65,8 @@ #define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 #define SMU_FEATURES_HIGH_SHIFT 32 +#define SMU11_DRIVER_IF_VERSION_ARCT 0x17 + static const struct smu_feature_bits arcturus_dpm_features = { .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT), SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), @@ -1905,7 +1907,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = { /* pptable related */ .setup_pptable = arcturus_setup_pptable, .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v11_0_set_driver_table_location, .set_tool_table_location = smu_v11_0_set_tool_table_location, @@ -1958,5 +1960,6 @@ void arcturus_set_ppt_funcs(struct smu_context *smu) smu->table_map = arcturus_table_map; smu->pwr_src_map = arcturus_pwr_src_map; smu->workload_map = arcturus_workload_map; + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_ARCT; smu_v11_0_init_msg_ctl(smu, arcturus_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c index 4e70308a455e..e6e009df9840 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c @@ -582,7 +582,7 @@ cyan_skillfish_get_enabled_mask(struct smu_context *smu, static const struct pptable_funcs cyan_skillfish_ppt_funcs = { .check_fw_status = smu_v11_0_check_fw_status, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_power = smu_v11_0_init_power, .fini_power = smu_v11_0_fini_power, .init_smc_tables = cyan_skillfish_init_smc_tables, @@ -605,5 +605,6 @@ void cyan_skillfish_set_ppt_funcs(struct smu_context *smu) smu->ppt_funcs = &cyan_skillfish_ppt_funcs; smu->table_map = cyan_skillfish_table_map; smu->is_apu = true; + smu->smc_driver_if_version = MP1_DRIVER_IF_VERSION; smu_v11_0_init_msg_ctl(smu, cyan_skillfish_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 163e09ca0730..cd0457e13f54 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -73,6 +73,10 @@ static const struct smu_feature_bits navi10_dpm_features = { #define SMU_11_0_GFX_BUSY_THRESHOLD 15 +#define SMU11_DRIVER_IF_VERSION_NV10 0x37 +#define SMU11_DRIVER_IF_VERSION_NV12 0x38 +#define SMU11_DRIVER_IF_VERSION_NV14 0x38 + static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -3308,7 +3312,7 @@ static const struct pptable_funcs navi10_ppt_funcs = { .check_fw_status = smu_v11_0_check_fw_status, .setup_pptable = navi10_setup_pptable, .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v11_0_set_driver_table_location, .set_tool_table_location = smu_v11_0_set_tool_table_location, @@ -3361,11 +3365,26 @@ static const struct pptable_funcs navi10_ppt_funcs = { void navi10_set_ppt_funcs(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; + smu->ppt_funcs = &navi10_ppt_funcs; smu->clock_map = navi10_clk_map; smu->feature_map = navi10_feature_mask_map; smu->table_map = navi10_table_map; smu->pwr_src_map = navi10_pwr_src_map; smu->workload_map = navi10_workload_map; + + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(11, 0, 0): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV10; + break; + case IP_VERSION(11, 0, 9): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV12; + break; + case IP_VERSION(11, 0, 5): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV14; + break; + } + smu_v11_0_init_msg_ctl(smu, navi10_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index cf030af18aad..f799e489b481 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3119,7 +3119,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .check_fw_status = smu_v11_0_check_fw_status, .setup_pptable = sienna_cichlid_setup_pptable, .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v11_0_set_driver_table_location, .set_tool_table_location = smu_v11_0_set_tool_table_location, @@ -3176,13 +3176,36 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .mode2_reset = sienna_cichlid_mode2_reset, }; +#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x40 +#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0xE +#define SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish 0xF +#define SMU11_DRIVER_IF_VERSION_Beige_Goby 0xD + void sienna_cichlid_set_ppt_funcs(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; + smu->ppt_funcs = &sienna_cichlid_ppt_funcs; smu->clock_map = sienna_cichlid_clk_map; smu->feature_map = sienna_cichlid_feature_mask_map; smu->table_map = sienna_cichlid_table_map; smu->pwr_src_map = sienna_cichlid_pwr_src_map; smu->workload_map = sienna_cichlid_workload_map; + + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(11, 0, 7): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Sienna_Cichlid; + break; + case IP_VERSION(11, 0, 11): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Navy_Flounder; + break; + case IP_VERSION(11, 0, 12): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish; + break; + case IP_VERSION(11, 0, 13): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Beige_Goby; + break; + } + smu_v11_0_init_msg_ctl(smu, sienna_cichlid_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 12b052d920f5..d68ceee16d8f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -192,82 +192,6 @@ int smu_v11_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v11_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - if (smu->is_apu) - adev->pm.fw_version = smu_version; - - switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { - case IP_VERSION(11, 0, 0): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV10; - break; - case IP_VERSION(11, 0, 9): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV12; - break; - case IP_VERSION(11, 0, 5): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV14; - break; - case IP_VERSION(11, 0, 7): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Sienna_Cichlid; - break; - case IP_VERSION(11, 0, 11): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Navy_Flounder; - break; - case IP_VERSION(11, 5, 0): - case IP_VERSION(11, 5, 2): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_VANGOGH; - break; - case IP_VERSION(11, 0, 12): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish; - break; - case IP_VERSION(11, 0, 13): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Beige_Goby; - break; - case IP_VERSION(11, 0, 8): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Cyan_Skillfish; - break; - case IP_VERSION(11, 0, 2): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_ARCT; - break; - default: - dev_err(smu->adev->dev, "smu unsupported IP version: 0x%x.\n", - amdgpu_ip_version(adev, MP1_HWIP, 0)); - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_INV; - break; - } - - /* - * 1. if_version mismatch is not critical as our fw is designed - * to be backward compatible. - * 2. New fw usually brings some optimizations. But that's visible - * only on the paired driver. - * Considering above, we just leave user a verbal message instead - * of halt driver loading. - */ - if (if_version != smu->smc_driver_if_version) { - dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " - "smu fw program = %d, version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(smu->adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - static int smu_v11_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index 5eabaf55dfc5..d269b505aefb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2511,7 +2511,7 @@ static u32 vangogh_get_gfxoff_entrycount(struct smu_context *smu, uint64_t *entr static const struct pptable_funcs vangogh_ppt_funcs = { .check_fw_status = smu_v11_0_check_fw_status, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = vangogh_init_smc_tables, .fini_smc_tables = smu_v11_0_fini_smc_tables, .init_power = smu_v11_0_init_power, @@ -2561,5 +2561,6 @@ void vangogh_set_ppt_funcs(struct smu_context *smu) smu->table_map = vangogh_table_map; smu->workload_map = vangogh_workload_map; smu->is_apu = true; + smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION; smu_v11_0_init_msg_ctl(smu, vangogh_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index 186020ed6708..75335da224c7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -1457,7 +1457,7 @@ static const struct pptable_funcs renoir_ppt_funcs = { .get_power_profile_mode = renoir_get_power_profile_mode, .read_sensor = renoir_read_sensor, .check_fw_status = smu_v12_0_check_fw_status, - .check_fw_version = smu_v12_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .powergate_sdma = smu_v12_0_powergate_sdma, .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg, .gfx_off_control = smu_v12_0_gfx_off_control, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index 2c20624caca4..f09da4d14510 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -70,43 +70,6 @@ int smu_v12_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v12_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - if (smu->is_apu) - adev->pm.fw_version = smu_version; - - /* - * 1. if_version mismatch is not critical as our fw is designed - * to be backward compatible. - * 2. New fw usually brings some optimizations. But that's visible - * only on the paired driver. - * Considering above, we just leave user a verbal message instead - * of halt driver loading. - */ - if (if_version != smu->smc_driver_if_version) { - dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " - "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(smu->adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate) { if (!smu->is_apu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 2b4faab37693..dc056f1e4b64 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1988,7 +1988,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { /* pptable related */ .setup_pptable = aldebaran_setup_pptable, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v13_0_set_driver_table_location, .set_tool_table_location = smu_v13_0_set_tool_table_location, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 4e09eda77d8b..be9a7a32de99 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -258,49 +258,6 @@ int smu_v13_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v13_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - adev->pm.fw_version = smu_version; - - /* only for dGPU w/ SMU13*/ - if (adev->pm.fw) - dev_dbg(smu->adev->dev, "smu fw reported program %d, version = 0x%08x (%d.%d.%d)\n", - smu_program, smu_version, smu_major, smu_minor, smu_debug); - - /* - * 1. if_version mismatch is not critical as our fw is designed - * to be backward compatible. - * 2. New fw usually brings some optimizations. But that's visible - * only on the paired driver. - * Considering above, we just leave user a verbal message instead - * of halt driver loading. - */ - dev_info_once(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " - "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - - if (smu->smc_driver_if_version != SMU_IGNORE_IF_VERSION && - if_version != smu->smc_driver_if_version) { - dev_info(adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - static int smu_v13_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; @@ -2509,4 +2466,6 @@ void smu_v13_0_reset_custom_level(struct smu_context *smu) pstate_table->uclk_pstate.custom.max = 0; pstate_table->gfxclk_pstate.custom.min = 0; pstate_table->gfxclk_pstate.custom.max = 0; + pstate_table->fclk_pstate.custom.min = 0; + pstate_table->fclk_pstate.custom.max = 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index a8d63d4d1f6e..b414a74d29fd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -59,6 +59,10 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) +static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + static const struct smu_feature_bits smu_v13_0_0_dpm_features = { .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), @@ -1043,8 +1047,35 @@ static bool smu_v13_0_0_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + + smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } + +out: + return feature_enabled; } static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, @@ -3133,7 +3164,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .fini_power = smu_v13_0_fini_power, .check_fw_status = smu_v13_0_check_fw_status, .setup_pptable = smu_v13_0_0_setup_pptable, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v13_0_set_driver_table_location, .system_features_control = smu_v13_0_0_system_features_control, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index 5b1a038d6a19..ba91bf590eed 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -1098,7 +1098,7 @@ static int smu_v13_0_4_set_fine_grain_gfx_freq_parameters(struct smu_context *sm static const struct pptable_funcs smu_v13_0_4_ppt_funcs = { .check_fw_status = smu_v13_0_check_fw_status, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = smu_v13_0_4_init_smc_tables, .fini_smc_tables = smu_v13_0_4_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index d534723fef91..27372a60e83d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -1102,7 +1102,7 @@ static int smu_v13_0_5_set_fine_grain_gfx_freq_parameters(struct smu_context *sm static const struct pptable_funcs smu_v13_0_5_ppt_funcs = { .check_fw_status = smu_v13_0_check_fw_status, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = smu_v13_0_5_init_smc_tables, .fini_smc_tables = smu_v13_0_5_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 8dc8674b7ce1..475541189782 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -461,6 +461,7 @@ static void smu_v13_0_6_init_caps(struct smu_context *smu) smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET)); if ((pgm == 0 && fw_ver >= 0x00558200) || + (pgm == 4 && fw_ver >= 0x04557100) || (pgm == 7 && fw_ver >= 0x07551400)) smu_v13_0_6_cap_set(smu, SMU_CAP(VCN_RESET)); } @@ -481,7 +482,7 @@ static int smu_v13_0_6_check_fw_version(struct smu_context *smu) { int r; - r = smu_v13_0_check_fw_version(smu); + r = smu_cmn_check_fw_version(smu); /* Initialize caps flags once fw version is fetched */ if (!r) smu_v13_0_x_init_caps(smu); @@ -1199,6 +1200,7 @@ static int smu_v13_0_6_populate_umd_state_clk(struct smu_context *smu) struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); @@ -1216,6 +1218,12 @@ static int smu_v13_0_6_populate_umd_state_clk(struct smu_context *smu) pstate_table->socclk_pstate.curr.min = SMU_DPM_TABLE_MIN(soc_table); pstate_table->socclk_pstate.curr.max = SMU_DPM_TABLE_MAX(soc_table); + pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table); + pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table); + pstate_table->fclk_pstate.curr.min = SMU_DPM_TABLE_MIN(fclk_table); + pstate_table->fclk_pstate.curr.max = SMU_DPM_TABLE_MAX(fclk_table); + pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table); + if (gfx_table->count > SMU_13_0_6_UMD_PSTATE_GFXCLK_LEVEL && mem_table->count > SMU_13_0_6_UMD_PSTATE_MCLK_LEVEL && soc_table->count > SMU_13_0_6_UMD_PSTATE_SOCCLK_LEVEL) { @@ -1394,14 +1402,22 @@ static int smu_v13_0_6_emit_clk_levels(struct smu_context *smu, break; case SMU_OD_MCLK: if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SET_UCLK_MAX))) - return 0; + return -EOPNOTSUPP; size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK"); size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", pstate_table->uclk_pstate.curr.min, pstate_table->uclk_pstate.curr.max); break; + case SMU_OD_FCLK: + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) + return -EOPNOTSUPP; + size += sysfs_emit_at(buf, size, "%s:\n", "OD_FCLK"); + size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", + pstate_table->fclk_pstate.curr.min, + pstate_table->fclk_pstate.curr.max); + break; case SMU_SCLK: case SMU_GFXCLK: single_dpm_table = &(dpm_context->dpm_tables.gfx_table); @@ -2043,7 +2059,7 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, int ret = 0; if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK && - clk_type != SMU_UCLK) + clk_type != SMU_UCLK && clk_type != SMU_FCLK) return -EINVAL; if ((smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) && @@ -2084,6 +2100,15 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, pstate_table->uclk_pstate.curr.max = max; } + if (clk_type == SMU_FCLK) { + if (max == pstate_table->fclk_pstate.curr.max) + return 0; + + ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_FCLK, 0, max, false); + if (!ret) + pstate_table->fclk_pstate.curr.max = max; + } + return ret; } @@ -2125,6 +2150,8 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, { struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; + struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; uint32_t min_clk; uint32_t max_clk; @@ -2205,6 +2232,40 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, pstate_table->uclk_pstate.custom.max = input[1]; } break; + case PP_OD_EDIT_FCLK_TABLE: + if (size != 2) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + + if (!smu_cmn_feature_is_enabled(smu, + SMU_FEATURE_DPM_FCLK_BIT)) { + dev_warn(smu->adev->dev, + "FCLK limits setting not supported!\n"); + return -EOPNOTSUPP; + } + + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.fclk_table); + if (input[0] == 0) { + dev_info(smu->adev->dev, + "Setting min FCLK level is not supported\n"); + return -EOPNOTSUPP; + } else if (input[0] == 1) { + if (input[1] > max_clk) { + dev_warn(smu->adev->dev, + "Maximum FCLK (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", + input[1], max_clk); + pstate_table->fclk_pstate.custom.max = + pstate_table->fclk_pstate.curr.max; + return -EINVAL; + } + + pstate_table->fclk_pstate.custom.max = input[1]; + } else { + return -EINVAL; + } + break; case PP_OD_RESTORE_DEFAULT_TABLE: if (size != 0) { @@ -2224,14 +2285,27 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, if (ret) return ret; - min_clk = SMU_DPM_TABLE_MIN( - &dpm_context->dpm_tables.uclk_table); - max_clk = SMU_DPM_TABLE_MAX( - &dpm_context->dpm_tables.uclk_table); - ret = smu_v13_0_6_set_soft_freq_limited_range( - smu, SMU_UCLK, min_clk, max_clk, false); - if (ret) - return ret; + if (SMU_DPM_TABLE_MAX(uclk_table) != + pstate_table->uclk_pstate.curr.max) { + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table); + ret = smu_v13_0_6_set_soft_freq_limited_range(smu, + SMU_UCLK, min_clk, + max_clk, false); + if (ret) + return ret; + } + + if (SMU_DPM_TABLE_MAX(fclk_table) != + pstate_table->fclk_pstate.curr.max) { + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.fclk_table); + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.fclk_table); + ret = smu_v13_0_6_set_soft_freq_limited_range(smu, + SMU_FCLK, min_clk, + max_clk, false); + if (ret) + return ret; + } smu_v13_0_reset_custom_level(smu); } break; @@ -2258,6 +2332,16 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, if (ret) return ret; + if (pstate_table->fclk_pstate.custom.max) { + min_clk = pstate_table->fclk_pstate.curr.min; + max_clk = pstate_table->fclk_pstate.custom.max; + ret = smu_v13_0_6_set_soft_freq_limited_range(smu, + SMU_FCLK, min_clk, + max_clk, false); + if (ret) + return ret; + } + if (!pstate_table->uclk_pstate.custom.max) return 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 5500a0f12f0e..fd0b6215364f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -59,6 +59,10 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) +static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + static const struct smu_feature_bits smu_v13_0_7_dpm_features = { .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), @@ -1053,8 +1057,35 @@ static bool smu_v13_0_7_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + + smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } + +out: + return feature_enabled; } static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, @@ -2788,7 +2819,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .fini_power = smu_v13_0_fini_power, .check_fw_status = smu_v13_0_7_check_fw_status, .setup_pptable = smu_v13_0_7_setup_pptable, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v13_0_set_driver_table_location, .system_features_control = smu_v13_0_system_features_control, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index f43a91ac6970..7bf88ffd311b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -1331,7 +1331,7 @@ static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *sm static const struct pptable_funcs yellow_carp_ppt_funcs = { .check_fw_status = smu_v13_0_check_fw_status, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = yellow_carp_init_smc_tables, .fini_smc_tables = yellow_carp_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index cec2df1ad0af..d0a8df1aa6b6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -229,67 +229,6 @@ int smu_v14_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v14_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - if (smu->is_apu) - adev->pm.fw_version = smu_version; - - switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { - case IP_VERSION(14, 0, 0): - case IP_VERSION(14, 0, 4): - case IP_VERSION(14, 0, 5): - smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_0; - break; - case IP_VERSION(14, 0, 1): - smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_1; - break; - case IP_VERSION(14, 0, 2): - case IP_VERSION(14, 0, 3): - smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_2; - break; - default: - dev_err(adev->dev, "smu unsupported IP version: 0x%x.\n", - amdgpu_ip_version(adev, MP1_HWIP, 0)); - smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_INV; - break; - } - - if (adev->pm.fw) - dev_dbg(smu->adev->dev, "smu fw reported program %d, version = 0x%08x (%d.%d.%d)\n", - smu_program, smu_version, smu_major, smu_minor, smu_debug); - - /* - * 1. if_version mismatch is not critical as our fw is designed - * to be backward compatible. - * 2. New fw usually brings some optimizations. But that's visible - * only on the paired driver. - * Considering above, we just leave user a verbal message instead - * of halt driver loading. - */ - if (if_version != smu->smc_driver_if_version) { - dev_info(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " - "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - static int smu_v14_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c index 2353524b8821..a28624d4847a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c @@ -65,6 +65,9 @@ #define SMU_MALL_PG_CONFIG_DEFAULT SMU_MALL_PG_CONFIG_DRIVER_CONTROL_ALWAYS_ON +#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7 +#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_1 0x6 + #define SMU_14_0_0_UMD_PSTATE_GFXCLK 700 #define SMU_14_0_0_UMD_PSTATE_SOCCLK 678 #define SMU_14_0_0_UMD_PSTATE_FCLK 1800 @@ -1699,7 +1702,7 @@ static int smu_v14_0_0_restore_user_od_settings(struct smu_context *smu) static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .check_fw_status = smu_v14_0_check_fw_status, - .check_fw_version = smu_v14_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = smu_v14_0_0_init_smc_tables, .fini_smc_tables = smu_v14_0_0_fini_smc_tables, .get_vbios_bootup_values = smu_v14_0_get_vbios_bootup_values, @@ -1750,10 +1753,23 @@ static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu) void smu_v14_0_0_set_ppt_funcs(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; + smu->ppt_funcs = &smu_v14_0_0_ppt_funcs; smu->feature_map = smu_v14_0_0_feature_mask_map; smu->table_map = smu_v14_0_0_table_map; smu->is_apu = true; + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(14, 0, 0): + case IP_VERSION(14, 0, 4): + case IP_VERSION(14, 0, 5): + smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_0; + break; + case IP_VERSION(14, 0, 1): + smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_1; + break; + } + smu_v14_0_0_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 73762d9b5969..31f9566f7979 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -56,6 +56,10 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) +static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + static const struct smu_feature_bits smu_v14_0_2_dpm_features = { .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), @@ -64,6 +68,8 @@ static const struct smu_feature_bits smu_v14_0_2_dpm_features = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT) } }; +#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x2E + #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 #define DEBUGSMC_MSG_Mode1Reset 2 #define LINK_SPEED_MAX 3 @@ -922,8 +928,35 @@ static bool smu_v14_0_2_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; + + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); + smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } + +out: + return feature_enabled; } static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, @@ -2767,7 +2800,7 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { .fini_power = smu_v14_0_fini_power, .check_fw_status = smu_v14_0_check_fw_status, .setup_pptable = smu_v14_0_2_setup_pptable, - .check_fw_version = smu_v14_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .set_driver_table_location = smu_v14_0_set_driver_table_location, .system_features_control = smu_v14_0_system_features_control, .set_allowed_mask = smu_v14_0_set_allowed_mask, @@ -2832,5 +2865,6 @@ void smu_v14_0_2_set_ppt_funcs(struct smu_context *smu) smu->table_map = smu_v14_0_2_table_map; smu->pwr_src_map = smu_v14_0_2_pwr_src_map; smu->workload_map = smu_v14_0_2_workload_map; + smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_2; smu_v14_0_2_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile index 7f59a0aabdeb..fa083ad46c0f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile @@ -23,7 +23,7 @@ # Makefile for the 'smu manager' sub-component of powerplay. # It provides the smu management services for the driver. -SMU15_MGR = smu_v15_0.o smu_v15_0_0_ppt.o +SMU15_MGR = smu_v15_0.o smu_v15_0_0_ppt.o smu_v15_0_8_ppt.o AMD_SWSMU_SMU15MGR = $(addprefix $(AMD_SWSMU_PATH)/smu15/,$(SMU15_MGR)) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c index 3fd84dd85e9b..c3cb36813806 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c @@ -207,58 +207,6 @@ int smu_v15_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v15_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - if (smu->is_apu) - adev->pm.fw_version = smu_version; - - switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { - case IP_VERSION(15, 0, 0): - smu->smc_driver_if_version = SMU15_DRIVER_IF_VERSION_SMU_V15_0; - break; - default: - dev_err(adev->dev, "smu unsupported IP version: 0x%x.\n", - amdgpu_ip_version(adev, MP1_HWIP, 0)); - smu->smc_driver_if_version = SMU15_DRIVER_IF_VERSION_INV; - break; - } - - if (adev->pm.fw) - dev_dbg(smu->adev->dev, "smu fw reported program %d, version = 0x%08x (%d.%d.%d)\n", - smu_program, smu_version, smu_major, smu_minor, smu_debug); - - /* - * 1. if_version mismatch is not critical as our fw is designed - * to be backward compatible. - * 2. New fw usually brings some optimizations. But that's visible - * only on the paired driver. - * Considering above, we just leave user a verbal message instead - * of halt driver loading. - */ - if (if_version != smu->smc_driver_if_version) { - dev_info(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " - "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - static int smu_v15_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; @@ -641,71 +589,52 @@ int smu_v15_0_notify_memory_pool_location(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *memory_pool = &smu_table->memory_pool; - int ret = 0; - uint64_t address; - uint32_t address_low, address_high; + struct smu_msg_args args = { + .msg = SMU_MSG_DramLogSetDramAddr, + .num_args = 3, + .num_out_args = 0, + }; if (memory_pool->size == 0 || memory_pool->cpu_addr == NULL) - return ret; - - address = memory_pool->mc_address; - address_high = (uint32_t)upper_32_bits(address); - address_low = (uint32_t)lower_32_bits(address); + return 0; - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramAddrHigh, - address_high, NULL); - if (ret) - return ret; - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramAddrLow, - address_low, NULL); - if (ret) - return ret; - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramSize, - (uint32_t)memory_pool->size, NULL); - if (ret) - return ret; + /* SMU_MSG_DramLogSetDramAddr: ARG0=low, ARG1=high, ARG2=size */ + args.args[0] = lower_32_bits(memory_pool->mc_address); + args.args[1] = upper_32_bits(memory_pool->mc_address); + args.args[2] = (u32)memory_pool->size; - return ret; + return smu->msg_ctl.ops->send_msg(&smu->msg_ctl, &args); } int smu_v15_0_set_driver_table_location(struct smu_context *smu) { struct smu_table *driver_table = &smu->smu_table.driver_table; - int ret = 0; + struct smu_msg_args args = { + .msg = SMU_MSG_SetDriverDramAddr, + .num_args = 2, + .num_out_args = 0, + }; - if (driver_table->mc_address) { - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetDriverDramAddrHigh, - upper_32_bits(driver_table->mc_address), - NULL); - if (!ret) - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetDriverDramAddrLow, - lower_32_bits(driver_table->mc_address), - NULL); - } + args.args[0] = lower_32_bits(driver_table->mc_address); + args.args[1] = upper_32_bits(driver_table->mc_address); - return ret; + return smu->msg_ctl.ops->send_msg(&smu->msg_ctl, &args); } int smu_v15_0_set_tool_table_location(struct smu_context *smu) { - int ret = 0; struct smu_table *tool_table = &smu->smu_table.tables[SMU_TABLE_PMSTATUSLOG]; + struct smu_msg_args args = { + .msg = SMU_MSG_SetToolsDramAddr, + .num_args = 2, + .num_out_args = 0, + }; - if (tool_table->mc_address) { - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetToolsDramAddrHigh, - upper_32_bits(tool_table->mc_address), - NULL); - if (!ret) - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetToolsDramAddrLow, - lower_32_bits(tool_table->mc_address), - NULL); - } + /* SMU_MSG_SetToolsDramAddr: ARG0=low, ARG1=high */ + args.args[0] = lower_32_bits(tool_table->mc_address); + args.args[1] = upper_32_bits(tool_table->mc_address); - return ret; + return smu->msg_ctl.ops->send_msg(&smu->msg_ctl, &args); } int smu_v15_0_set_allowed_mask(struct smu_context *smu) @@ -752,8 +681,7 @@ int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable) return ret; } -int smu_v15_0_system_features_control(struct smu_context *smu, - bool en) +int smu_v15_0_system_features_control(struct smu_context *smu, bool en) { return smu_cmn_send_smc_msg(smu, (en ? SMU_MSG_EnableAllSmuFeatures : SMU_MSG_DisableAllSmuFeatures), NULL); @@ -957,7 +885,8 @@ static int smu_v15_0_wait_for_reset_complete(struct smu_context *smu, return ret; } -int smu_v15_0_wait_for_event(struct smu_context *smu, enum smu_event_type event, +int smu_v15_0_wait_for_event(struct smu_context *smu, + enum smu_event_type event, uint64_t event_arg) { int ret = -EINVAL; @@ -1129,18 +1058,12 @@ int smu_v15_0_set_performance_level(struct smu_context *smu, { struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_15_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; - struct smu_15_0_dpm_table *mem_table = - &dpm_context->dpm_tables.uclk_table; - struct smu_15_0_dpm_table *soc_table = - &dpm_context->dpm_tables.soc_table; - struct smu_15_0_dpm_table *vclk_table = - &dpm_context->dpm_tables.vclk_table; - struct smu_15_0_dpm_table *dclk_table = - &dpm_context->dpm_tables.dclk_table; - struct smu_15_0_dpm_table *fclk_table = - &dpm_context->dpm_tables.fclk_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table; + struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; struct amdgpu_device *adev = smu->adev; @@ -1155,34 +1078,34 @@ int smu_v15_0_set_performance_level(struct smu_context *smu, switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: - sclk_min = sclk_max = gfx_table->max; - mclk_min = mclk_max = mem_table->max; - socclk_min = socclk_max = soc_table->max; - vclk_min = vclk_max = vclk_table->max; - dclk_min = dclk_max = dclk_table->max; - fclk_min = fclk_max = fclk_table->max; + sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table); + vclk_min = vclk_max = SMU_DPM_TABLE_MAX(vclk_table); + dclk_min = dclk_max = SMU_DPM_TABLE_MAX(dclk_table); + fclk_min = fclk_max = SMU_DPM_TABLE_MAX(fclk_table); break; case AMD_DPM_FORCED_LEVEL_LOW: - sclk_min = sclk_max = gfx_table->min; - mclk_min = mclk_max = mem_table->min; - socclk_min = socclk_max = soc_table->min; - vclk_min = vclk_max = vclk_table->min; - dclk_min = dclk_max = dclk_table->min; - fclk_min = fclk_max = fclk_table->min; + sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table); + vclk_min = vclk_max = SMU_DPM_TABLE_MIN(vclk_table); + dclk_min = dclk_max = SMU_DPM_TABLE_MIN(dclk_table); + fclk_min = fclk_max = SMU_DPM_TABLE_MIN(fclk_table); break; case AMD_DPM_FORCED_LEVEL_AUTO: - sclk_min = gfx_table->min; - sclk_max = gfx_table->max; - mclk_min = mem_table->min; - mclk_max = mem_table->max; - socclk_min = soc_table->min; - socclk_max = soc_table->max; - vclk_min = vclk_table->min; - vclk_max = vclk_table->max; - dclk_min = dclk_table->min; - dclk_max = dclk_table->max; - fclk_min = fclk_table->min; - fclk_max = fclk_table->max; + sclk_min = SMU_DPM_TABLE_MIN(gfx_table); + sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = SMU_DPM_TABLE_MIN(mem_table); + mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = SMU_DPM_TABLE_MIN(soc_table); + socclk_max = SMU_DPM_TABLE_MAX(soc_table); + vclk_min = SMU_DPM_TABLE_MIN(vclk_table); + vclk_max = SMU_DPM_TABLE_MAX(vclk_table); + dclk_min = SMU_DPM_TABLE_MIN(dclk_table); + dclk_max = SMU_DPM_TABLE_MAX(dclk_table); + fclk_min = SMU_DPM_TABLE_MIN(fclk_table); + fclk_max = SMU_DPM_TABLE_MAX(fclk_table); auto_level = true; break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: @@ -1404,10 +1327,11 @@ static int smu_v15_0_get_fine_grained_status(struct smu_context *smu, int smu_v15_0_set_single_dpm_table(struct smu_context *smu, enum smu_clk_type clk_type, - struct smu_15_0_dpm_table *single_dpm_table) + struct smu_dpm_table *single_dpm_table) { int ret = 0; uint32_t clk; + bool is_fine_grained; int i; ret = smu_v15_0_get_dpm_level_count(smu, @@ -1420,12 +1344,15 @@ int smu_v15_0_set_single_dpm_table(struct smu_context *smu, ret = smu_v15_0_get_fine_grained_status(smu, clk_type, - &single_dpm_table->is_fine_grained); + &is_fine_grained); if (ret) { dev_err(smu->adev->dev, "[%s] failed to get fine grained status!\n", __func__); return ret; } + if (is_fine_grained) + single_dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; + for (i = 0; i < single_dpm_table->count; i++) { ret = smu_v15_0_get_dpm_freq_by_index(smu, clk_type, @@ -1438,11 +1365,6 @@ int smu_v15_0_set_single_dpm_table(struct smu_context *smu, single_dpm_table->dpm_levels[i].value = clk; single_dpm_table->dpm_levels[i].enabled = true; - - if (i == 0) - single_dpm_table->min = clk; - else if (i == single_dpm_table->count - 1) - single_dpm_table->max = clk; } return 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c index 49cf2b9d931e..8d092c347076 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c @@ -1416,7 +1416,7 @@ static int smu_v15_0_common_get_dpm_table(struct smu_context *smu, struct dpm_cl static const struct pptable_funcs smu_v15_0_0_ppt_funcs = { .check_fw_status = smu_v15_0_check_fw_status, - .check_fw_version = smu_v15_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = smu_v15_0_0_init_smc_tables, .fini_smc_tables = smu_v15_0_0_fini_smc_tables, .get_vbios_bootup_values = smu_v15_0_get_vbios_bootup_values, @@ -1468,6 +1468,7 @@ void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu) smu->feature_map = smu_v15_0_0_feature_mask_map; smu->table_map = smu_v15_0_0_table_map; smu->is_apu = true; + smu->smc_driver_if_version = SMU15_DRIVER_IF_VERSION_SMU_V15_0; smu_v15_0_0_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c new file mode 100644 index 000000000000..cc2babc6a341 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -0,0 +1,2270 @@ +/* + * Copyright 2025 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. + * + */ + +#define SWSMU_CODE_LAYER_L2 + +#include <linux/firmware.h> +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "smu_v15_0_8_pmfw.h" +#include "smu15_driver_if_v15_0_8.h" +#include "smu_v15_0_8_ppsmc.h" +#include "smu_v15_0_8_ppt.h" +#include <linux/pci.h> +#include "smu_cmn.h" +#include "mp/mp_15_0_8_offset.h" +#include "mp/mp_15_0_8_sh_mask.h" +#include "smu_v15_0.h" +#include "amdgpu_fru_eeprom.h" + +#undef MP1_Public + +/* address block */ +#define MP1_Public 0x03b00000 +#define smnMP1_FIRMWARE_FLAGS_15_0_8 0x3010024 +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + +#define SMUQ10_TO_UINT(x) ((x) >> 10) +#define SMUQ10_FRAC(x) ((x) & 0x3ff) +#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200)) + +#define hbm_stack_mask_valid(umc_mask) \ + (((umc_mask) & 0xF) == 0xF) + +#define for_each_hbm_stack(stack_idx, umc_mask) \ + for ((stack_idx) = 0; (umc_mask); \ + (umc_mask) >>= 4, (stack_idx)++) \ + +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) + +#define SMU_15_0_8_FEA_MAP(smu_feature, smu_15_0_8_feature) \ + [smu_feature] = { 1, (smu_15_0_8_feature) } + +#define FEATURE_MASK(feature) (1ULL << feature) + +static const struct smu_feature_bits smu_v15_0_8_dpm_features = { + .bits = { SMU_FEATURE_BIT_INIT(FEATURE_ID_DATA_CALCULATION), + SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_GFXCLK), + SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_UCLK), + SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_FCLK), + SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_GL2CLK) } +}; + +static const struct cmn2asic_msg_mapping smu_v15_0_8_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), + MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI | SMU_MSG_NO_PRECHECK), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), + MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0), + MSG_MAP(GetMetricsVersion, PPSMC_MSG_GetMetricsVersion, 1), + MSG_MAP(GetMetricsTable, PPSMC_MSG_GetMetricsTable, 1), + MSG_MAP(GetEnabledSmuFeatures, PPSMC_MSG_GetEnabledSmuFeatures, 1), + MSG_MAP(SetDriverDramAddr, PPSMC_MSG_SetDriverDramAddr, 1), + MSG_MAP(SetToolsDramAddr, PPSMC_MSG_SetToolsDramAddr, 0), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), + MSG_MAP(DramLogSetDramAddr, PPSMC_MSG_DramLogSetDramAddr, 0), + MSG_MAP(HeavySBR, PPSMC_MSG_HeavySBR, 0), + MSG_MAP(DFCstateControl, PPSMC_MSG_DFCstateControl, 0), + MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0), + MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1), + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0), + MSG_MAP(QueryValidMcaCount, PPSMC_MSG_QueryValidMcaCount, SMU_MSG_RAS_PRI), + MSG_MAP(McaBankDumpDW, PPSMC_MSG_McaBankDumpDW, SMU_MSG_RAS_PRI), + MSG_MAP(ClearMcaOnRead, PPSMC_MSG_ClearMcaOnRead, 0), + MSG_MAP(QueryValidMcaCeCount, PPSMC_MSG_QueryValidMcaCeCount, SMU_MSG_RAS_PRI), + MSG_MAP(McaBankCeDumpDW, PPSMC_MSG_McaBankCeDumpDW, SMU_MSG_RAS_PRI), + MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0), + MSG_MAP(SetThrottlingPolicy, PPSMC_MSG_SetThrottlingPolicy, 0), + MSG_MAP(ResetSDMA, PPSMC_MSG_ResetSDMA, 0), + MSG_MAP(GetRASTableVersion, PPSMC_MSG_GetRasTableVersion, 0), + MSG_MAP(SetTimestamp, PPSMC_MSG_SetTimestamp, 0), + MSG_MAP(GetTimestamp, PPSMC_MSG_GetTimestamp, 0), + MSG_MAP(GetBadPageIpid, PPSMC_MSG_GetBadPageIpIdLoHi, 0), + MSG_MAP(EraseRasTable, PPSMC_MSG_EraseRasTable, 0), + MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1), + MSG_MAP(GetSystemMetricsTable, PPSMC_MSG_GetSystemMetricsTable, 1), + MSG_MAP(GetSystemMetricsVersion, PPSMC_MSG_GetSystemMetricsVersion, 0), + MSG_MAP(ResetVCN, PPSMC_MSG_ResetVCN, 0), + MSG_MAP(SetFastPptLimit, PPSMC_MSG_SetFastPptLimit, 0), + MSG_MAP(GetFastPptLimit, PPSMC_MSG_GetFastPptLimit, 0), + MSG_MAP(SetSoftMinGl2clk, PPSMC_MSG_SetSoftMinGl2clk, 0), + MSG_MAP(SetSoftMaxGl2clk, PPSMC_MSG_SetSoftMaxGl2clk, 0), + MSG_MAP(SetSoftMinFclk, PPSMC_MSG_SetSoftMinFclk, 0), + MSG_MAP(SetSoftMaxFclk, PPSMC_MSG_SetSoftMaxFclk, 0), +}; + +/* TODO: Update the clk map once enum PPCLK is updated in smu15_driver_if_v15_0_8.h */ +static struct cmn2asic_mapping smu_v15_0_8_clk_map[SMU_CLK_COUNT] = { + CLK_MAP(UCLK, PPCLK_UCLK), +}; + +static const struct cmn2asic_mapping smu_v15_0_8_feature_mask_map[SMU_FEATURE_COUNT] = { + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DATA_CALCULATIONS_BIT, FEATURE_ID_DATA_CALCULATION), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_GFXCLK_BIT, FEATURE_ID_DPM_GFXCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_UCLK_BIT, FEATURE_ID_DPM_UCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_FCLK_BIT, FEATURE_ID_DPM_FCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_GL2CLK_BIT, FEATURE_ID_DPM_GL2CLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_GFXCLK_BIT, FEATURE_ID_DS_GFXCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_SOCCLK_BIT, FEATURE_ID_DS_SOCCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_LCLK_BIT, FEATURE_ID_DS_LCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_FCLK_BIT, FEATURE_ID_DS_FCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_DMABECLK_BIT, FEATURE_ID_DS_DMABECLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPIFOECLK_BIT, FEATURE_ID_DS_MPIFOECLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPRASCLK_BIT, FEATURE_ID_DS_MPRASCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPNHTCLK_BIT, FEATURE_ID_DS_MPNHTCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_FIOCLK_BIT, FEATURE_ID_DS_FIOCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_DXIOCLK_BIT, FEATURE_ID_DS_DXIOCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_GL2CLK_BIT, FEATURE_ID_DS_GL2CLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_PPT_BIT, FEATURE_ID_PPT), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_TDC_BIT, FEATURE_ID_TDC), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_MP1_CG_BIT, FEATURE_ID_SMU_CG), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_FW_CTF_BIT, FEATURE_ID_FW_CTF), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_THERMAL_BIT, FEATURE_ID_THERMAL), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_SOC_PCC_BIT, FEATURE_ID_SOC_PCC), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT, FEATURE_ID_XGMI_PER_LINK_PWR_DOWN), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_VCN_BIT, FEATURE_ID_DS_VCN), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MP1CLK_BIT, FEATURE_ID_DS_MP1CLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPIOCLK_BIT, FEATURE_ID_DS_MPIOCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MP0CLK_BIT, FEATURE_ID_DS_MP0CLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_PIT_BIT, FEATURE_ID_PIT), +}; + +#define TABLE_PMSTATUSLOG 0 +#define TABLE_SMU_METRICS 1 +#define TABLE_I2C_COMMANDS 2 +#define TABLE_COUNT 3 + +static const struct cmn2asic_mapping smu_v15_0_8_table_map[SMU_TABLE_COUNT] = { + TAB_MAP(PMSTATUSLOG), + TAB_MAP(SMU_METRICS), + TAB_MAP(I2C_COMMANDS), +}; + +static size_t smu_v15_0_8_get_system_metrics_size(void) +{ + return sizeof(SystemMetricsTable_t); +} + +static int smu_v15_0_8_tables_init(struct smu_context *smu) +{ + struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics; + struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics; + struct smu_table_context *smu_table = &smu->smu_table; + int ret, gpu_metrcs_size = sizeof(MetricsTable_t); + struct smu_table *tables = smu_table->tables; + struct smu_v15_0_8_gpu_metrics *gpu_metrics; + void *driver_pptable __free(kfree) = NULL; + void *metrics_table __free(kfree) = NULL; + + SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU15_TOOL_SIZE, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, + gpu_metrcs_size, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT); + SMU_TABLE_INIT(tables, SMU_TABLE_PMFW_SYSTEM_METRICS, + smu_v15_0_8_get_system_metrics_size(), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT); + + metrics_table = kzalloc(gpu_metrcs_size, GFP_KERNEL); + if (!metrics_table) + return -ENOMEM; + + smu_table->metrics_time = 0; + + driver_pptable = kzalloc(sizeof(PPTable_t), GFP_KERNEL); + if (!driver_pptable) + return -ENOMEM; + + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct smu_v15_0_8_gpu_metrics), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) + return ret; + + gpu_metrics = (struct smu_v15_0_8_gpu_metrics *)smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_GPU_METRICS); + smu_v15_0_8_gpu_metrics_init(gpu_metrics, 1, 9); + + ret = smu_table_cache_init(smu, SMU_TABLE_PMFW_SYSTEM_METRICS, + smu_v15_0_8_get_system_metrics_size(), 5); + + if (ret) + return ret; + + /* Initialize base board temperature metrics */ + ret = smu_driver_table_init(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS, + sizeof(*baseboard_temp_metrics), 50); + if (ret) + return ret; + baseboard_temp_metrics = (struct smu_v15_0_8_baseboard_temp_metrics *) + smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_v15_0_8_baseboard_temp_metrics_init(baseboard_temp_metrics, 1, 1); + /* Initialize GPU board temperature metrics */ + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS, + sizeof(*gpuboard_temp_metrics), 50); + if (ret) { + smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS); + smu_driver_table_fini(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + return ret; + } + gpuboard_temp_metrics = (struct smu_v15_0_8_gpuboard_temp_metrics *) + smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_v15_0_8_gpuboard_temp_metrics_init(gpuboard_temp_metrics, 1, 1); + + smu_table->metrics_table = no_free_ptr(metrics_table); + smu_table->driver_pptable = no_free_ptr(driver_pptable); + + mutex_init(&smu_table->metrics_lock); + + return 0; +} + +static int smu_v15_0_8_allocate_dpm_context(struct smu_context *smu) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + + smu_dpm->dpm_context = + kzalloc(sizeof(struct smu_15_0_dpm_context), GFP_KERNEL); + if (!smu_dpm->dpm_context) + return -ENOMEM; + smu_dpm->dpm_context_size = sizeof(struct smu_15_0_dpm_context); + + smu_dpm->dpm_policies = + kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL); + if (!smu_dpm->dpm_policies) { + kfree(smu_dpm->dpm_context); + return -ENOMEM; + } + + return 0; +} + +static int smu_v15_0_8_init_smc_tables(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_v15_0_8_tables_init(smu); + if (ret) + return ret; + + ret = smu_v15_0_8_allocate_dpm_context(smu); + + return ret; +} + +static int smu_v15_0_8_tables_fini(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS); + mutex_destroy(&smu_table->metrics_lock); + + return 0; +} + +static int smu_v15_0_8_fini_smc_tables(struct smu_context *smu) +{ + int ret; + + ret = smu_v15_0_8_tables_fini(smu); + if (ret) + return ret; + + ret = smu_v15_0_fini_smc_tables(smu); + if (ret) + return ret; + + return ret; +} + +static int smu_v15_0_8_init_allowed_features(struct smu_context *smu) +{ + /* pptable will handle the features to enable */ + smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED); + + return 0; +} + +static int smu_v15_0_8_get_metrics_table_internal(struct smu_context *smu, uint32_t tmo, void *data) +{ + struct smu_table_context *smu_table = &smu->smu_table; + uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size; + struct smu_table *table = &smu_table->driver_table; + struct amdgpu_device *adev = smu->adev; + + mutex_lock(&smu_table->metrics_lock); + + if (!tmo || !smu_table->metrics_time || + time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(tmo))) { + int ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsTable, NULL); + if (ret) { + dev_info(adev->dev, + "Failed to export SMU metrics table!\n"); + mutex_unlock(&smu_table->metrics_lock); + return ret; + } + + amdgpu_device_invalidate_hdp(smu->adev, NULL); + memcpy(smu_table->metrics_table, table->cpu_addr, table_size); + + smu_table->metrics_time = jiffies; + } + + if (data) + memcpy(data, smu_table->metrics_table, table_size); + mutex_unlock(&smu_table->metrics_lock); + return 0; +} + +static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, uint32_t *value) +{ + struct smu_table_context *smu_table = &smu->smu_table; + MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table; + struct amdgpu_device *adev = smu->adev; + int ret, xcc_id; + + ret = smu_v15_0_8_get_metrics_table_internal(smu, 10, NULL); + if (ret) + return ret; + + switch (member) { + case METRICS_CURR_GFXCLK: + case METRICS_AVERAGE_GFXCLK: + xcc_id = GET_INST(GC, 0); + *value = SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]); + break; + case METRICS_CURR_SOCCLK: + case METRICS_AVERAGE_SOCCLK: + *value = SMUQ10_ROUND(metrics->SocclkFrequency[0]); + break; + case METRICS_CURR_UCLK: + case METRICS_AVERAGE_UCLK: + *value = SMUQ10_ROUND(metrics->UclkFrequency[0]); + break; + case METRICS_CURR_VCLK: + *value = SMUQ10_ROUND(metrics->VclkFrequency[0]); + break; + case METRICS_CURR_DCLK: + *value = SMUQ10_ROUND(metrics->DclkFrequency[0]); + break; + case METRICS_CURR_FCLK: + *value = SMUQ10_ROUND(metrics->FclkFrequency[0]); + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = SMUQ10_ROUND(metrics->SocketGfxBusy); + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = SMUQ10_ROUND(metrics->DramBandwidthUtilization); + break; + case METRICS_CURR_SOCKETPOWER: + *value = SMUQ10_ROUND(metrics->SocketPower) << 8; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + { + struct amdgpu_device *adev = smu->adev; + u32 max_hbm_temp = 0; + + /* Find max temperature across all HBM stacks */ + if (adev->umc.active_mask) { + u64 mask = adev->umc.active_mask; + int stack_idx; + + for_each_hbm_stack(stack_idx, mask) { + u32 temp; + + if (!hbm_stack_mask_valid(mask)) + continue; + + temp = SMUQ10_ROUND(metrics->HbmTemperature[stack_idx]); + if (temp > max_hbm_temp) + max_hbm_temp = temp; + } + } + *value = max_hbm_temp * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + } + /* This is the max of all VRs and not just SOC VR. + */ + case METRICS_TEMPERATURE_VRSOC: + *value = SMUQ10_ROUND(metrics->MaxVrTemperature) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + default: + *value = UINT_MAX; + break; + } + + return 0; +} + +static int smu_v15_0_8_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + MetricsMember_t member_type; + + if (!value) + return -EINVAL; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + member_type = METRICS_CURR_GFXCLK; + break; + case SMU_UCLK: + case SMU_MCLK: + member_type = METRICS_CURR_UCLK; + break; + case SMU_SOCCLK: + member_type = METRICS_CURR_SOCCLK; + break; + case SMU_VCLK: + member_type = METRICS_CURR_VCLK; + break; + case SMU_DCLK: + member_type = METRICS_CURR_DCLK; + break; + case SMU_FCLK: + member_type = METRICS_CURR_FCLK; + break; + default: + return -EINVAL; + } + + return smu_v15_0_8_get_smu_metrics_data(smu, member_type, value); +} + +static int smu_v15_0_8_get_current_activity_percent(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + + if (!value) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = smu_v15_0_8_get_smu_metrics_data(smu, + METRICS_AVERAGE_GFXACTIVITY, value); + break; + case AMDGPU_PP_SENSOR_MEM_LOAD: + ret = smu_v15_0_8_get_smu_metrics_data(smu, + METRICS_AVERAGE_MEMACTIVITY, value); + break; + default: + dev_err(smu->adev->dev, + "Invalid sensor for retrieving clock activity\n"); + return -EINVAL; + } + + return ret; +} + +static int smu_v15_0_8_thermal_get_temperature(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + + if (!value) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + ret = smu_v15_0_8_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_HOTSPOT, value); + break; + case AMDGPU_PP_SENSOR_MEM_TEMP: + ret = smu_v15_0_8_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_MEM, value); + break; + default: + dev_err(smu->adev->dev, "Invalid sensor for retrieving temp\n"); + return -EINVAL; + } + + return ret; +} + +static int smu_v15_0_8_get_system_metrics_table(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *table = &smu_table->driver_table; + struct smu_table *tables = smu_table->tables; + struct smu_table *sys_table; + int ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + if (smu_table_cache_is_valid(sys_table)) + return 0; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetSystemMetricsTable, NULL); + if (ret) { + dev_info(smu->adev->dev, + "Failed to export system metrics table!\n"); + return ret; + } + + amdgpu_hdp_invalidate(smu->adev, NULL); + smu_table_cache_update_time(sys_table, jiffies); + memcpy(sys_table->cache.buffer, table->cpu_addr, + sizeof(SystemMetricsTable_t)); + + return 0; +} + +static int smu_v15_0_8_get_npm_data(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + SystemMetricsTable_t *metrics; + struct smu_table *sys_table; + int ret; + + if (sensor == AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT) { + /*TBD as of now put 0 */ + *value = 0; + return 0; + } + + ret = smu_v15_0_8_get_system_metrics_table(smu); + if (ret) + return ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + metrics = (SystemMetricsTable_t *)sys_table->cache.buffer; + + switch (sensor) { + case AMDGPU_PP_SENSOR_NODEPOWERLIMIT: + *value = SMUQ10_ROUND(metrics->NodePowerLimit); + break; + case AMDGPU_PP_SENSOR_NODEPOWER: + *value = SMUQ10_ROUND(metrics->NodePower); + break; + case AMDGPU_PP_SENSOR_GPPTRESIDENCY: + *value = SMUQ10_ROUND(metrics->GlobalPPTResidencyAcc); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smu_v15_0_8_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, void *data, + uint32_t *size) +{ + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + int ret = 0; + + if (amdgpu_ras_intr_triggered()) + return 0; + + if (!data || !size) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_MEM_LOAD: + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = smu_v15_0_8_get_current_activity_percent(smu, sensor, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: + ret = smu_v15_0_8_get_smu_metrics_data(smu, + METRICS_CURR_SOCKETPOWER, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + case AMDGPU_PP_SENSOR_MEM_TEMP: + ret = smu_v15_0_8_thermal_get_temperature(smu, sensor, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = smu_v15_0_8_get_current_clk_freq_by_table(smu, + SMU_UCLK, (uint32_t *)data); + /* the output clock frequency in 10K unit */ + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = smu_v15_0_8_get_current_clk_freq_by_table(smu, + SMU_GFXCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDBOARD: + *(uint32_t *)data = dpm_context->board_volt; + *size = 4; + break; + case AMDGPU_PP_SENSOR_NODEPOWERLIMIT: + case AMDGPU_PP_SENSOR_NODEPOWER: + case AMDGPU_PP_SENSOR_GPPTRESIDENCY: + case AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT: + ret = smu_v15_0_8_get_npm_data(smu, sensor, (uint32_t *)data); + if (ret) + return ret; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_AVG_POWER: + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static int smu_v15_0_8_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type type, char *buf, + int *offset) +{ + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + struct smu_15_0_dpm_context *dpm_context; + struct smu_dpm_table *single_dpm_table = NULL; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + int ret, now, size = *offset; + + if (amdgpu_ras_intr_triggered()) { + sysfs_emit_at(buf, size, "unavailable\n"); + return -EBUSY; + } + + dpm_context = smu_dpm->dpm_context; + + switch (type) { + case SMU_OD_SCLK: + size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); + size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", + pstate_table->gfxclk_pstate.curr.min, + pstate_table->gfxclk_pstate.curr.max); + break; + case SMU_OD_MCLK: + size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK"); + size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", + pstate_table->uclk_pstate.curr.min, + pstate_table->uclk_pstate.curr.max); + break; + case SMU_SCLK: + case SMU_GFXCLK: + single_dpm_table = &dpm_context->dpm_tables.gfx_table; + break; + case SMU_MCLK: + case SMU_UCLK: + single_dpm_table = &dpm_context->dpm_tables.uclk_table; + break; + case SMU_SOCCLK: + single_dpm_table = &dpm_context->dpm_tables.soc_table; + break; + case SMU_FCLK: + single_dpm_table = &dpm_context->dpm_tables.fclk_table; + break; + case SMU_VCLK: + single_dpm_table = &dpm_context->dpm_tables.vclk_table; + break; + case SMU_DCLK: + single_dpm_table = &dpm_context->dpm_tables.dclk_table; + break; + default: + break; + } + + if (single_dpm_table) { + ret = smu_v15_0_8_get_current_clk_freq_by_table(smu, type, &now); + if (ret) { + dev_err(smu->adev->dev, + "Attempt to get current clk Failed!"); + return ret; + } + ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, now, + buf, offset); + if (ret < 0) + return ret; + + return 0; + } + + *offset = size; + + return 0; +} + +static int smu_v15_0_8_get_dpm_ultimate_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max) +{ + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + struct smu_dpm_table *dpm_table; + uint32_t min_clk = 0, max_clk = 0; + + if (!pptable->init) + return -EINVAL; + + /* Try cached DPM tables first */ + if (dpm_context) { + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + dpm_table = &dpm_context->dpm_tables.uclk_table; + break; + case SMU_GFXCLK: + case SMU_SCLK: + dpm_table = &dpm_context->dpm_tables.gfx_table; + break; + case SMU_SOCCLK: + dpm_table = &dpm_context->dpm_tables.soc_table; + break; + case SMU_FCLK: + dpm_table = &dpm_context->dpm_tables.fclk_table; + break; + case SMU_GL2CLK: + dpm_table = &dpm_context->dpm_tables.gl2_table; + break; + case SMU_VCLK: + dpm_table = &dpm_context->dpm_tables.vclk_table; + break; + case SMU_DCLK: + dpm_table = &dpm_context->dpm_tables.dclk_table; + break; + default: + dpm_table = NULL; + break; + } + + if (dpm_table && dpm_table->count > 0) { + min_clk = SMU_DPM_TABLE_MIN(dpm_table); + max_clk = SMU_DPM_TABLE_MAX(dpm_table); + + if (min_clk && max_clk) { + if (min) + *min = min_clk; + if (max) + *max = max_clk; + return 0; + } + } + } + + /* Fall back to pptable */ + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + min_clk = pptable->MinGfxclkFrequency; + max_clk = pptable->MaxGfxclkFrequency; + break; + case SMU_FCLK: + min_clk = pptable->MinFclkFrequency; + max_clk = pptable->MaxFclkFrequency; + break; + case SMU_GL2CLK: + min_clk = pptable->MinGl2clkFrequency; + max_clk = pptable->MaxGl2clkFrequency; + break; + case SMU_MCLK: + case SMU_UCLK: + min_clk = pptable->UclkFrequencyTable[0]; + max_clk = pptable->UclkFrequencyTable[ARRAY_SIZE(pptable->UclkFrequencyTable) - 1]; + break; + case SMU_SOCCLK: + min_clk = pptable->SocclkFrequency; + max_clk = pptable->SocclkFrequency; + break; + case SMU_VCLK: + min_clk = pptable->VclkFrequency; + max_clk = pptable->VclkFrequency; + break; + case SMU_DCLK: + min_clk = pptable->DclkFrequency; + max_clk = pptable->DclkFrequency; + break; + default: + return -EINVAL; + } + + if (min) + *min = min_clk; + if (max) + *max = max_clk; + + return 0; +} + +static int smu_v15_0_8_set_dpm_table(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_dpm_table *dpm_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + int i, ret; + uint32_t gfxclkmin, gfxclkmax; + + /* gfxclk dpm table setup - fine-grained */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + dpm_table->clk_type = SMU_GFXCLK; + dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { + ret = smu_v15_0_8_get_dpm_ultimate_freq(smu, SMU_GFXCLK, + &gfxclkmin, &gfxclkmax); + if (ret) + return ret; + + dpm_table->count = 2; + dpm_table->dpm_levels[0].value = gfxclkmin; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->dpm_levels[1].value = gfxclkmax; + dpm_table->dpm_levels[1].enabled = true; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->MinGfxclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + } + + /* fclk dpm table setup - fine-grained */ + dpm_table = &dpm_context->dpm_tables.fclk_table; + dpm_table->clk_type = SMU_FCLK; + dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { + dpm_table->count = 2; + dpm_table->dpm_levels[0].value = pptable->MinFclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->dpm_levels[1].value = pptable->MaxFclkFrequency; + dpm_table->dpm_levels[1].enabled = true; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->MinFclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + } + + /* gl2clk dpm table setup - fine-grained */ + dpm_table = &dpm_context->dpm_tables.gl2_table; + dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GL2CLK_BIT)) { + dpm_table->count = 2; + dpm_table->dpm_levels[0].value = pptable->MinGl2clkFrequency; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->dpm_levels[1].value = pptable->MaxGl2clkFrequency; + dpm_table->dpm_levels[1].enabled = true; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->MinGl2clkFrequency; + dpm_table->dpm_levels[0].enabled = true; + } + + /* uclk dpm table setup - discrete levels */ + dpm_table = &dpm_context->dpm_tables.uclk_table; + dpm_table->clk_type = SMU_UCLK; + dpm_table->flags = 0; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + dpm_table->count = ARRAY_SIZE(pptable->UclkFrequencyTable); + for (i = 0; i < dpm_table->count; ++i) { + dpm_table->dpm_levels[i].value = pptable->UclkFrequencyTable[i]; + dpm_table->dpm_levels[i].enabled = true; + } + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->UclkFrequencyTable[0]; + dpm_table->dpm_levels[0].enabled = true; + } + + /* socclk dpm table setup - single boot-time value */ + dpm_table = &dpm_context->dpm_tables.soc_table; + dpm_table->clk_type = SMU_SOCCLK; + dpm_table->flags = 0; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->SocclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + + /* vclk dpm table setup - single boot-time value */ + dpm_table = &dpm_context->dpm_tables.vclk_table; + dpm_table->clk_type = SMU_VCLK; + dpm_table->flags = 0; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->VclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + + /* dclk dpm table setup - single boot-time value */ + dpm_table = &dpm_context->dpm_tables.dclk_table; + dpm_table->clk_type = SMU_DCLK; + dpm_table->flags = 0; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->DclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + + return 0; +} + +static int smu_v15_0_8_setup_pptable(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + + /* TODO: PPTable is not available. + * 1) Find an alternate way to get 'PPTable values' here. + * 2) Check if there is SW CTF + */ + table_context->thermal_controller_type = 0; + + return 0; +} + +static int smu_v15_0_8_check_fw_status(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t mp1_fw_flags; + + mp1_fw_flags = RREG32_PCIE(MP1_Public | + (smnMP1_FIRMWARE_FLAGS_15_0_8 & 0xffffffff)); + + if ((mp1_fw_flags & MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> + MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) + return 0; + + return -EIO; +} + +static int smu_v15_0_8_get_static_metrics_table(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size; + struct smu_table *table = &smu_table->driver_table; + int ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetStaticMetricsTable, NULL); + if (ret) { + dev_err(smu->adev->dev, + "Failed to export static metrics table!\n"); + return ret; + } + + amdgpu_hdp_invalidate(smu->adev, NULL); + memcpy(smu_table->metrics_table, table->cpu_addr, table_size); + + return 0; +} + +static int smu_v15_0_8_fru_get_product_info(struct smu_context *smu, + StaticMetricsTable_t *static_metrics) +{ + struct amdgpu_fru_info *fru_info; + struct amdgpu_device *adev = smu->adev; + + if (!adev->fru_info) { + adev->fru_info = kzalloc(sizeof(*adev->fru_info), GFP_KERNEL); + if (!adev->fru_info) + return -ENOMEM; + } + + fru_info = adev->fru_info; + strscpy(fru_info->product_number, static_metrics->ProductInfo.ModelNumber, + sizeof(fru_info->product_number)); + strscpy(fru_info->product_name, static_metrics->ProductInfo.Name, + sizeof(fru_info->product_name)); + strscpy(fru_info->serial, static_metrics->ProductInfo.Serial, + sizeof(fru_info->serial)); + strscpy(fru_info->manufacturer_name, static_metrics->ProductInfo.ManufacturerName, + sizeof(fru_info->manufacturer_name)); + strscpy(fru_info->fru_id, static_metrics->ProductInfo.FruId, + sizeof(fru_info->fru_id)); + + return 0; +} + +static void smu_v15_0_8_init_xgmi_data(struct smu_context *smu, + StaticMetricsTable_t *static_metrics) +{ + uint16_t max_speed; + uint8_t max_width; + + max_width = (uint8_t)static_metrics->MaxXgmiWidth; + max_speed = (uint16_t)static_metrics->MaxXgmiBitrate; + amgpu_xgmi_set_max_speed_width(smu->adev, max_speed, max_width); +} + +static int smu_v15_0_8_set_driver_pptable(struct smu_context *smu) +{ + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_table_context *smu_table = &smu->smu_table; + StaticMetricsTable_t *static_metrics = (StaticMetricsTable_t *)smu_table->metrics_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + int ret, i, n; + uint32_t table_version; + + if (!pptable->init) { + ret = smu_v15_0_8_get_static_metrics_table(smu); + if (ret) + return ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsVersion, + &table_version); + if (ret) + return ret; + smu_table->tables[SMU_TABLE_SMU_METRICS].version = + table_version; + + pptable->MaxSocketPowerLimit = + SMUQ10_ROUND(static_metrics->MaxSocketPowerLimit); + pptable->MaxGfxclkFrequency = + SMUQ10_ROUND(static_metrics->MaxGfxclkFrequency); + pptable->MinGfxclkFrequency = + SMUQ10_ROUND(static_metrics->MinGfxclkFrequency); + pptable->MaxFclkFrequency = + SMUQ10_ROUND(static_metrics->MaxFclkFrequency); + pptable->MinFclkFrequency = + SMUQ10_ROUND(static_metrics->MinFclkFrequency); + pptable->MaxGl2clkFrequency = + SMUQ10_ROUND(static_metrics->MaxGl2clkFrequency); + pptable->MinGl2clkFrequency = + SMUQ10_ROUND(static_metrics->MinGl2clkFrequency); + + for (i = 0; i < ARRAY_SIZE(static_metrics->UclkFrequencyTable); ++i) + pptable->UclkFrequencyTable[i] = + SMUQ10_ROUND(static_metrics->UclkFrequencyTable[i]); + + pptable->SocclkFrequency = SMUQ10_ROUND(static_metrics->SocclkFrequency); + pptable->LclkFrequency = SMUQ10_ROUND(static_metrics->LclkFrequency); + pptable->VclkFrequency = SMUQ10_ROUND(static_metrics->VclkFrequency); + pptable->DclkFrequency = SMUQ10_ROUND(static_metrics->DclkFrequency); + + pptable->CTFLimitMID = SMUQ10_ROUND(static_metrics->CTFLimit_MID); + pptable->CTFLimitAID = SMUQ10_ROUND(static_metrics->CTFLimit_AID); + pptable->CTFLimitXCD = SMUQ10_ROUND(static_metrics->CTFLimit_XCD); + pptable->CTFLimitHBM = SMUQ10_ROUND(static_metrics->CTFLimit_HBM); + pptable->ThermalLimitMID = SMUQ10_ROUND(static_metrics->ThermalLimit_MID); + pptable->ThermalLimitAID = SMUQ10_ROUND(static_metrics->ThermalLimit_AID); + pptable->ThermalLimitXCD = SMUQ10_ROUND(static_metrics->ThermalLimit_XCD); + pptable->ThermalLimitHBM = SMUQ10_ROUND(static_metrics->ThermalLimit_HBM); + + /* use MID0 serial number by default */ + pptable->PublicSerialNumberMID = + static_metrics->PublicSerialNumber_MID[0]; + + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_SOC, + 0, pptable->PublicSerialNumberMID); + pptable->PublicSerialNumberAID = + static_metrics->PublicSerialNumber_AID[0]; + pptable->PublicSerialNumberXCD = + static_metrics->PublicSerialNumber_XCD[0]; + n = ARRAY_SIZE(static_metrics->PublicSerialNumber_MID); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_MID, i, + static_metrics->PublicSerialNumber_MID[i]); + } + n = ARRAY_SIZE(static_metrics->PublicSerialNumber_AID); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_AID, i, + static_metrics->PublicSerialNumber_AID[i]); + } + n = ARRAY_SIZE(static_metrics->PublicSerialNumber_XCD); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_XCD, i, + static_metrics->PublicSerialNumber_XCD[i]); + } + + ret = smu_v15_0_8_fru_get_product_info(smu, static_metrics); + if (ret) + return ret; + pptable->PPT1Max = static_metrics->PPT1Max; + pptable->PPT1Min = static_metrics->PPT1Min; + pptable->PPT1Default = static_metrics->PPT1Default; + + if (static_metrics->pldmVersion[0] != 0xFFFFFFFF) + smu->adev->firmware.pldm_version = + static_metrics->pldmVersion[0]; + dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV; + smu_v15_0_8_init_xgmi_data(smu, static_metrics); + pptable->init = true; + } + + return 0; +} + +static int smu_v15_0_8_set_default_dpm_table(struct smu_context *smu) +{ + int ret; + + ret = smu_v15_0_8_set_driver_pptable(smu); + if (ret) + return ret; + + ret = smu_v15_0_8_set_dpm_table(smu); + if (ret) + return ret; + + return 0; +} + +static int smu_v15_0_8_irq_process(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_15_0_power_context *power_context = smu_power->power_context; + uint32_t client_id = entry->client_id; + uint32_t ctxid = entry->src_data[0]; + uint32_t src_id = entry->src_id; + uint32_t data; + + if (client_id == SOC_V1_0_IH_CLIENTID_MP1) { + if (src_id == IH_INTERRUPT_ID_TO_DRIVER) { + /* ACK SMUToHost interrupt */ + data = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); + data = REG_SET_FIELD(data, MP1_SMN_IH_SW_INT_CTRL, INT_ACK, 1); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, data); + /* + * ctxid is used to distinguish different events for SMCToHost + * interrupt. + */ + switch (ctxid) { + case IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING: + /* + * Increment the throttle interrupt counter + */ + atomic64_inc(&smu->throttle_int_counter); + + if (!atomic_read(&adev->throttling_logging_enabled)) + return 0; + + /* This uses the new method which fixes the + * incorrect throttling status reporting + * through metrics table. For older FWs, + * it will be ignored. + */ + if (__ratelimit(&adev->throttling_logging_rs)) { + atomic_set( + &power_context->throttle_status, + entry->src_data[1]); + schedule_work(&smu->throttling_logging_work); + } + break; + default: + dev_dbg(adev->dev, "Unhandled context id %d from client:%d!\n", + ctxid, client_id); + break; + } + } + } + + return 0; +} + +static int smu_v15_0_8_set_irq_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned type, + enum amdgpu_interrupt_state state) +{ + uint32_t val = 0; + + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + /* For MP1 SW irqs */ + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 1); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val); + + break; + case AMDGPU_IRQ_STATE_ENABLE: + /* For MP1 SW irqs */ + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, ID, 0xFE); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, VALID, 0); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT, val); + + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 0); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val); + + break; + default: + break; + } + + return 0; +} + +static const struct amdgpu_irq_src_funcs smu_v15_0_8_irq_funcs = { + .set = smu_v15_0_8_set_irq_state, + .process = smu_v15_0_8_irq_process, +}; + +static int smu_v15_0_8_register_irq_handler(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct amdgpu_irq_src *irq_src = &smu->irq_source; + int ret = 0; + + if (amdgpu_sriov_vf(adev)) + return 0; + + irq_src->num_types = 1; + irq_src->funcs = &smu_v15_0_8_irq_funcs; + + ret = amdgpu_irq_add_id(adev, SOC_V1_0_IH_CLIENTID_MP1, + IH_INTERRUPT_ID_TO_DRIVER, + irq_src); + if (ret) + return ret; + + return ret; +} + +static int smu_v15_0_8_notify_unload(struct smu_context *smu) +{ + if (amdgpu_in_reset(smu->adev)) + return 0; + + dev_dbg(smu->adev->dev, "Notify PMFW about driver unload"); + /* Ignore return, just intimate FW that driver is not going to be there */ + smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); + + return 0; +} + + +static int smu_v15_0_8_system_features_control(struct smu_context *smu, + bool enable) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (amdgpu_sriov_vf(adev)) + return 0; + + if (enable) + ret = smu_v15_0_system_features_control(smu, enable); + else + smu_v15_0_8_notify_unload(smu); + + return ret; +} + +/** + * smu_v15_0_8_get_enabled_mask - Get enabled SMU features (128-bit) + * @smu: SMU context + * @feature_mask: feature mask structure + * + * SMU 15 returns all 128 feature bits in a single message via out_args[0..3]. + * For backward compatibility, this function returns only the first 64 bits. + * + * Return: 0 on success, negative errno on failure + */ +static int smu_v15_0_8_get_enabled_mask(struct smu_context *smu, + struct smu_feature_bits *feature_mask) +{ + struct smu_msg_args args = { + .msg = SMU_MSG_GetEnabledSmuFeatures, + .num_args = 0, + .num_out_args = 2, + }; + int ret; + + if (!feature_mask) + return -EINVAL; + + ret = smu->msg_ctl.ops->send_msg(&smu->msg_ctl, &args); + + if (ret) + return ret; + + smu_feature_bits_from_arr32(feature_mask, args.out_args, + SMU_FEATURE_NUM_DEFAULT); + + return 0; +} + +static bool smu_v15_0_8_is_dpm_running(struct smu_context *smu) +{ + int ret = 0; + struct smu_feature_bits feature_enabled; + + ret = smu_v15_0_8_get_enabled_mask(smu, &feature_enabled); + if (ret) + return false; + + return smu_feature_bits_test_mask(&feature_enabled, + smu_v15_0_8_dpm_features.bits); +} + +static ssize_t smu_v15_0_8_get_pm_metrics(struct smu_context *smu, + void *metrics, size_t max_size) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct amdgpu_pm_metrics *pm_metrics = (struct amdgpu_pm_metrics *)metrics; + uint32_t table_version = smu_table->tables[SMU_TABLE_SMU_METRICS].version; + uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size; + uint32_t pmfw_version; + int ret; + + if (!pm_metrics || !max_size) + return -EINVAL; + + if (max_size < (table_size + sizeof(pm_metrics->common_header))) + return -EOVERFLOW; + + /* Don't use cached metrics data */ + ret = smu_v15_0_8_get_metrics_table_internal(smu, 0, pm_metrics->data); + if (ret) + return ret; + + smu_cmn_get_smc_version(smu, NULL, &pmfw_version); + memset(&pm_metrics->common_header, 0, sizeof(pm_metrics->common_header)); + pm_metrics->common_header.mp1_ip_discovery_version = + amdgpu_ip_version(smu->adev, MP1_HWIP, 0); + pm_metrics->common_header.pmfw_version = pmfw_version; + pm_metrics->common_header.pmmetrics_version = table_version; + pm_metrics->common_header.structure_size = + sizeof(pm_metrics->common_header) + table_size; + + return pm_metrics->common_header.structure_size; +} + +static int smu_v15_0_8_mode2_reset(struct smu_context *smu) +{ + struct smu_msg_ctl *ctl = &smu->msg_ctl; + struct amdgpu_device *adev = smu->adev; + int timeout = 10; + int ret = 0; + + mutex_lock(&ctl->lock); + + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2); + + if (ret) + goto out; + + /* Reset takes a bit longer, wait for 200ms. */ + msleep(200); + + dev_dbg(adev->dev, "wait for reset ack\n"); + do { + ret = smu_msg_wait_response(ctl, 0); + /* Wait a bit more time for getting ACK */ + if (ret == -ETIME) { + --timeout; + usleep_range(500, 1000); + continue; + } + + if (ret) + goto out; + + } while (ret == -ETIME && timeout); + +out: + mutex_unlock(&ctl->lock); + + if (ret) + dev_err(adev->dev, "failed to send mode2 reset, error code %d", + ret); + + return ret; +} + +static bool smu_v15_0_8_is_temp_metrics_supported(struct smu_context *smu, + enum smu_temp_metric_type type) +{ + switch (type) { + case SMU_TEMP_METRIC_BASEBOARD: + if (smu->adev->gmc.xgmi.physical_node_id == 0) + return true; + return false; + case SMU_TEMP_METRIC_GPUBOARD: + return true; + default: + return false; + } +} + +static void smu_v15_0_8_fill_baseboard_temp_metrics( + struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics, + const SystemMetricsTable_t *metrics) +{ + baseboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter; + baseboard_temp_metrics->label_version = metrics->LabelVersion; + baseboard_temp_metrics->node_id = metrics->NodeIdentifier; + + baseboard_temp_metrics->system_temp_ubb_fpga = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA]; + baseboard_temp_metrics->system_temp_ubb_front = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FRONT]; + baseboard_temp_metrics->system_temp_ubb_back = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_BACK]; + baseboard_temp_metrics->system_temp_ubb_oam7 = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_OAM7]; + baseboard_temp_metrics->system_temp_ubb_ibc = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_IBC]; + baseboard_temp_metrics->system_temp_ubb_ufpga = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_UFPGA]; + baseboard_temp_metrics->system_temp_ubb_oam1 = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_OAM1]; + baseboard_temp_metrics->system_temp_oam_0_1_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_0_1_HSC]; + baseboard_temp_metrics->system_temp_oam_2_3_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_2_3_HSC]; + baseboard_temp_metrics->system_temp_oam_4_5_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_4_5_HSC]; + baseboard_temp_metrics->system_temp_oam_6_7_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_6_7_HSC]; + baseboard_temp_metrics->system_temp_ubb_fpga_0v72_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA_0V72_VR]; + baseboard_temp_metrics->system_temp_ubb_fpga_3v3_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA_3V3_VR]; + baseboard_temp_metrics->system_temp_retimer_0_1_2_3_1v2_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR]; + baseboard_temp_metrics->system_temp_retimer_4_5_6_7_1v2_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR]; + baseboard_temp_metrics->system_temp_retimer_0_1_0v9_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_0_1_0V9_VR]; + baseboard_temp_metrics->system_temp_retimer_4_5_0v9_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_4_5_0V9_VR]; + baseboard_temp_metrics->system_temp_retimer_2_3_0v9_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_2_3_0V9_VR]; + baseboard_temp_metrics->system_temp_retimer_6_7_0v9_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_6_7_0V9_VR]; + baseboard_temp_metrics->system_temp_oam_0_1_2_3_3v3_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR]; + baseboard_temp_metrics->system_temp_oam_4_5_6_7_3v3_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR]; + baseboard_temp_metrics->system_temp_ibc_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_IBC_HSC]; + baseboard_temp_metrics->system_temp_ibc = + metrics->SystemTemperatures[SYSTEM_TEMP_IBC]; +} + +static void smu_v15_0_8_fill_gpuboard_temp_metrics( + struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics, + const SystemMetricsTable_t *metrics) +{ + gpuboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter; + gpuboard_temp_metrics->label_version = metrics->LabelVersion; + gpuboard_temp_metrics->node_id = metrics->NodeIdentifier; + + gpuboard_temp_metrics->node_temp_retimer = + metrics->NodeTemperatures[NODE_TEMP_RETIMER]; + gpuboard_temp_metrics->node_temp_ibc = + metrics->NodeTemperatures[NODE_TEMP_IBC_TEMP]; + gpuboard_temp_metrics->node_temp_ibc_2 = + metrics->NodeTemperatures[NODE_TEMP_IBC_2_TEMP]; + gpuboard_temp_metrics->node_temp_vdd18_vr = + metrics->NodeTemperatures[NODE_TEMP_VDD18_VR_TEMP]; + gpuboard_temp_metrics->node_temp_04_hbm_b_vr = + metrics->NodeTemperatures[NODE_TEMP_04_HBM_B_VR_TEMP]; + gpuboard_temp_metrics->node_temp_04_hbm_d_vr = + metrics->NodeTemperatures[NODE_TEMP_04_HBM_D_VR_TEMP]; + + gpuboard_temp_metrics->vr_temp_vddcr_socio_a = + metrics->VrTemperatures[SVI_PLANE_VDDCR_SOCIO_A_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_socio_c = + metrics->VrTemperatures[SVI_PLANE_VDDCR_SOCIO_C_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_x0 = + metrics->VrTemperatures[SVI_PLANE_VDDCR_X0_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_x1 = + metrics->VrTemperatures[SVI_PLANE_VDDCR_X1_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_hbm_b = + metrics->VrTemperatures[SVI_PLANE_VDDIO_HBM_B_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_hbm_d = + metrics->VrTemperatures[SVI_PLANE_VDDIO_HBM_D_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_04_hbm_b = + metrics->VrTemperatures[SVI_PLANE_VDDIO_04_HBM_B_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_04_hbm_d = + metrics->VrTemperatures[SVI_PLANE_VDDIO_04_HBM_D_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_hbm_b = + metrics->VrTemperatures[SVI_PLANE_VDDCR_HBM_B_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_hbm_d = + metrics->VrTemperatures[SVI_PLANE_VDDCR_HBM_D_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_075_hbm_b = + metrics->VrTemperatures[SVI_PLANE_VDDCR_075_HBM_B_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_075_hbm_d = + metrics->VrTemperatures[SVI_PLANE_VDDCR_075_HBM_D_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_11_gta_a = + metrics->VrTemperatures[SVI_PLANE_VDDIO_11_GTA_A_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_11_gta_c = + metrics->VrTemperatures[SVI_PLANE_VDDIO_11_GTA_C_TEMP]; + gpuboard_temp_metrics->vr_temp_vddan_075_gta_a = + metrics->VrTemperatures[SVI_PLANE_VDDAN_075_GTA_A_TEMP]; + gpuboard_temp_metrics->vr_temp_vddan_075_gta_c = + metrics->VrTemperatures[SVI_PLANE_VDDAN_075_GTA_C_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_075_ucie = + metrics->VrTemperatures[SVI_PLANE_VDDCR_075_UCIE_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_065_ucieaa = + metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAA_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_065_ucieam_a = + metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAM_A_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_065_ucieam_c = + metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAM_C_TEMP]; + gpuboard_temp_metrics->vr_temp_vddan_075 = + metrics->VrTemperatures[SVI_PLANE_VDDAN_075_TEMP]; +} + +static ssize_t smu_v15_0_8_get_temp_metrics(struct smu_context *smu, + enum smu_temp_metric_type type, + void *table) +{ + struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics; + struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics; + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + SystemMetricsTable_t *metrics; + struct smu_table *sys_table; + int ret; + + ret = smu_v15_0_8_get_system_metrics_table(smu); + if (ret) + return ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + metrics = (SystemMetricsTable_t *)sys_table->cache.buffer; + + switch (type) { + case SMU_TEMP_METRIC_GPUBOARD: + gpuboard_temp_metrics = + (struct smu_v15_0_8_gpuboard_temp_metrics *) + smu_driver_table_ptr(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_v15_0_8_fill_gpuboard_temp_metrics(gpuboard_temp_metrics, + metrics); + memcpy(table, gpuboard_temp_metrics, sizeof(*gpuboard_temp_metrics)); + return sizeof(*gpuboard_temp_metrics); + case SMU_TEMP_METRIC_BASEBOARD: + baseboard_temp_metrics = + (struct smu_v15_0_8_baseboard_temp_metrics *) + smu_driver_table_ptr(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_v15_0_8_fill_baseboard_temp_metrics(baseboard_temp_metrics, + metrics); + memcpy(table, baseboard_temp_metrics, sizeof(*baseboard_temp_metrics)); + return sizeof(*baseboard_temp_metrics); + default: + return -EINVAL; + } +} + +static ssize_t smu_v15_0_8_get_gpu_metrics(struct smu_context *smu, void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_v15_0_8_gpu_metrics *gpu_metrics; + struct amdgpu_device *adev = smu->adev; + int ret = 0, xcc_id, inst, i, j, idx; + uint32_t aid_mask = adev->aid_mask; + uint32_t mid_mask = adev->aid_mask; + MetricsTable_t *metrics; + + metrics = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL); + + ret = smu_v15_0_8_get_metrics_table_internal(smu, 1, NULL); + if (ret) + return ret; + + metrics = (MetricsTable_t *)smu_table->metrics_table; + gpu_metrics = (struct smu_v15_0_8_gpu_metrics *)smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_GPU_METRICS); + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + + gpu_metrics->temperature_hotspot = SMUQ10_ROUND(metrics->MaxSocketTemperature); + + /* Per-HBM stack temperatures */ + if (adev->umc.active_mask) { + u64 mask = adev->umc.active_mask; + int out_idx = 0; + int stack_idx; + + if (unlikely(hweight64(mask)/4 > SMU_15_0_8_MAX_HBM_STACKS)) + dev_warn(adev->dev, "Invalid umc mask %lld\n", mask); + else { + for_each_hbm_stack(stack_idx, mask) { + if (!hbm_stack_mask_valid(mask)) + continue; + gpu_metrics->temperature_hbm[out_idx++] = + SMUQ10_ROUND(metrics->HbmTemperature[stack_idx]); + } + } + } + + /* Reports max temperature of all voltage rails */ + gpu_metrics->temperature_vrsoc = SMUQ10_ROUND(metrics->MaxVrTemperature); + /* MID, AID, XCD temperatures */ + idx = 0; + for_each_inst(i, mid_mask) { + gpu_metrics->temperature_mid[idx] = SMUQ10_ROUND(metrics->MidTemperature[i]); + idx++; + } + + idx = 0; + for_each_inst(i, aid_mask) { + gpu_metrics->temperature_aid[idx] = SMUQ10_ROUND(metrics->AidTemperature[i]); + idx++; + } + + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) { + xcc_id = GET_INST(GC, i); + if (xcc_id >= 0) + gpu_metrics->temperature_xcd[i] = SMUQ10_ROUND(metrics->XcdTemperature[xcc_id]); + } + /* Power */ + gpu_metrics->curr_socket_power = SMUQ10_ROUND(metrics->SocketPower); + + gpu_metrics->average_gfx_activity = SMUQ10_ROUND(metrics->SocketGfxBusy); + gpu_metrics->average_umc_activity = SMUQ10_ROUND(metrics->DramBandwidthUtilization); + gpu_metrics->mem_max_bandwidth = SMUQ10_ROUND(metrics->MaxDramBandwidth); + + /* Energy counter reported in 15.259uJ (2^-16) units */ + gpu_metrics->energy_accumulator = metrics->SocketEnergyAcc; + + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) { + xcc_id = GET_INST(GC, i); + if (xcc_id >= 0) { + gpu_metrics->current_gfxclk[i] = + SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]); + } + } + + /* Per-MID clocks */ + idx = 0; + for_each_inst(i, mid_mask) { + gpu_metrics->current_socclk[idx] = SMUQ10_ROUND(metrics->SocclkFrequency[i]); + idx++; + } + + /* Per-VCN clocks */ + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + inst = GET_INST(VCN, i); + if (inst >= 0) { + gpu_metrics->current_vclk0[i] = SMUQ10_ROUND(metrics->VclkFrequency[inst]); + gpu_metrics->current_dclk0[i] = SMUQ10_ROUND(metrics->DclkFrequency[inst]); + } + } + + /* Per-AID clocks */ + idx = 0; + for_each_inst(i, aid_mask) { + gpu_metrics->current_uclk[idx] = SMUQ10_ROUND(metrics->UclkFrequency[i]); + idx++; + } + + /* Total accumulated cycle counter */ + gpu_metrics->accumulation_counter = metrics->AccumulationCounter; + + /* Accumulated throttler residencies */ + gpu_metrics->prochot_residency_acc = metrics->ProchotResidencyAcc; + gpu_metrics->ppt_residency_acc = metrics->PptResidencyAcc; + gpu_metrics->socket_thm_residency_acc = metrics->SocketThmResidencyAcc; + gpu_metrics->vr_thm_residency_acc = metrics->VrThmResidencyAcc; + gpu_metrics->hbm_thm_residency_acc = metrics->HbmThmResidencyAcc; + + gpu_metrics->gfx_activity_acc = SMUQ10_ROUND(metrics->SocketGfxBusyAcc); + gpu_metrics->mem_activity_acc = SMUQ10_ROUND(metrics->DramBandwidthUtilizationAcc); + + for (i = 0; i < NUM_XGMI_LINKS; i++) { + j = amdgpu_xgmi_get_ext_link(adev, i); + if (j < 0 || j >= NUM_XGMI_LINKS) + continue; + ret = amdgpu_get_xgmi_link_status(adev, i); + if (ret >= 0) + gpu_metrics->xgmi_link_status[j] = ret; + } + + gpu_metrics->xgmi_read_data_acc = SMUQ10_ROUND(metrics->XgmiReadBandwidthAcc); + gpu_metrics->xgmi_write_data_acc = SMUQ10_ROUND(metrics->XgmiWriteBandwidthAcc); + + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) { + inst = GET_INST(GC, i); + gpu_metrics->gfx_busy_inst[i] = SMUQ10_ROUND(metrics->GfxBusy[inst]); + gpu_metrics->gfx_busy_acc[i] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]); + gpu_metrics->gfx_below_host_limit_ppt_acc[i] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]); + gpu_metrics->gfx_below_host_limit_thm_acc[i] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]); + gpu_metrics->gfx_low_utilization_acc[i] = + SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]); + gpu_metrics->gfx_below_host_limit_total_acc[i] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]); + } + + gpu_metrics->xgmi_link_width = metrics->XgmiWidth; + gpu_metrics->xgmi_link_speed = metrics->XgmiBitrate; + + gpu_metrics->firmware_timestamp = metrics->Timestamp; + + *table = gpu_metrics; + + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + + return sizeof(*gpu_metrics); +} + +static void smu_v15_0_8_get_unique_id(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + + adev->unique_id = pptable->PublicSerialNumberMID; +} + +static int smu_v15_0_8_get_power_limit(struct smu_context *smu, + uint32_t *current_power_limit, + uint32_t *default_power_limit, + uint32_t *max_power_limit, + uint32_t *min_power_limit) +{ + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + uint32_t power_limit = 0; + int ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit, &power_limit); + if (ret) { + dev_err(smu->adev->dev, "Couldn't get PPT limit"); + return -EINVAL; + } + + if (current_power_limit) + *current_power_limit = power_limit; + + if (default_power_limit) + *max_power_limit = pptable->MaxSocketPowerLimit; + + if (max_power_limit) + *max_power_limit = pptable->MaxSocketPowerLimit; + + if (min_power_limit) + *min_power_limit = 0; + + return 0; +} + +static int smu_v15_0_8_populate_umd_state_clk(struct smu_context *smu) +{ + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + + pstate_table->gfxclk_pstate.curr.min = SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.curr.max = SMU_DPM_TABLE_MAX(gfx_table); + + pstate_table->uclk_pstate.curr.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.curr.max = SMU_DPM_TABLE_MAX(mem_table); + return 0; +} + +static int smu_v15_0_8_set_gfx_soft_freq_limited_range(struct smu_context *smu, + uint32_t min, + uint32_t max) +{ + int ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, + max & 0xffff, NULL); + if (ret) + return ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinGfxclk, + min & 0xffff, NULL); + + return ret; +} + +static int smu_v15_0_8_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_15_0_dpm_context *dpm_context = smu_dpm->dpm_context; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table; + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + int ret; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM: + /* Determinism not supported on SMU v15.0.8 */ + ret = -EOPNOTSUPP; + break; + + case AMD_DPM_FORCED_LEVEL_AUTO: + /* Restore GFXCLK to default range */ + if ((SMU_DPM_TABLE_MIN(gfx_table) != + pstate_table->gfxclk_pstate.curr.min) || + (SMU_DPM_TABLE_MAX(gfx_table) != + pstate_table->gfxclk_pstate.curr.max)) { + ret = smu_v15_0_8_set_gfx_soft_freq_limited_range( + smu, SMU_DPM_TABLE_MIN(gfx_table), + SMU_DPM_TABLE_MAX(gfx_table)); + if (ret) + goto out; + + pstate_table->gfxclk_pstate.curr.min = + SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.curr.max = + SMU_DPM_TABLE_MAX(gfx_table); + } + + /* Restore UCLK to default max */ + if (SMU_DPM_TABLE_MAX(uclk_table) != + pstate_table->uclk_pstate.curr.max) { + /* Min UCLK is not expected to be changed */ + ret = smu_v15_0_set_soft_freq_limited_range(smu, + SMU_UCLK, 0, + SMU_DPM_TABLE_MAX(uclk_table), + false); + if (ret) + goto out; + + pstate_table->uclk_pstate.curr.max = + SMU_DPM_TABLE_MAX(uclk_table); + } + + if (ret) + goto out; + + smu_cmn_reset_custom_level(smu); + + break; + case AMD_DPM_FORCED_LEVEL_MANUAL: + ret = 0; + break; + default: + ret = -EOPNOTSUPP; + break; + } + +out: + return ret; +} + +static int smu_v15_0_8_set_soft_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, uint32_t max, + bool automatic) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + int ret = 0; + + if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK && + clk_type != SMU_UCLK) + return -EINVAL; + + if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + return -EINVAL; + + if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { + if (min >= max) { + dev_err(smu->adev->dev, + "Minimum clk should be less than the maximum allowed clock\n"); + return -EINVAL; + } + + if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) { + if ((min == pstate_table->gfxclk_pstate.curr.min) && + (max == pstate_table->gfxclk_pstate.curr.max)) + return 0; + + ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu, + min, max); + if (!ret) { + pstate_table->gfxclk_pstate.curr.min = min; + pstate_table->gfxclk_pstate.curr.max = max; + } + } + + if (clk_type == SMU_UCLK) { + if (max == pstate_table->uclk_pstate.curr.max) + return 0; + + ret = smu_v15_0_set_soft_freq_limited_range(smu, + SMU_UCLK, + 0, max, + false); + if (!ret) + pstate_table->uclk_pstate.curr.max = max; + } + + return ret; + } + + return 0; +} + +static int smu_v15_0_8_od_edit_dpm_table(struct smu_context *smu, + enum PP_OD_DPM_TABLE_COMMAND type, + long input[], uint32_t size) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + struct smu_15_0_dpm_context *dpm_context = smu_dpm->dpm_context; + uint32_t min_clk, max_clk; + int ret; + + /* Only allowed in manual mode */ + if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + return -EINVAL; + + switch (type) { + case PP_OD_EDIT_SCLK_VDDC_TABLE: + if (size != 2) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table); + if (input[0] == 0) { + if (input[1] < min_clk) { + dev_warn(smu->adev->dev, + "Minimum GFX clk (%ld) MHz specified is less than the minimum allowed (%d) MHz\n", + input[1], min_clk); + pstate_table->gfxclk_pstate.custom.min = + pstate_table->gfxclk_pstate.curr.min; + return -EINVAL; + } + + pstate_table->gfxclk_pstate.custom.min = input[1]; + } else if (input[0] == 1) { + if (input[1] > max_clk) { + dev_warn(smu->adev->dev, + "Maximum GFX clk (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", + input[1], max_clk); + pstate_table->gfxclk_pstate.custom.max = + pstate_table->gfxclk_pstate.curr.max; + return -EINVAL; + } + + pstate_table->gfxclk_pstate.custom.max = input[1]; + } else { + return -EINVAL; + } + break; + case PP_OD_EDIT_MCLK_VDDC_TABLE: + if (size != 2) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + dev_warn(smu->adev->dev, + "UCLK_LIMITS setting not supported!\n"); + return -EOPNOTSUPP; + } + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table); + if (input[0] == 0) { + dev_info(smu->adev->dev, + "Setting min UCLK level is not supported"); + return -EINVAL; + } else if (input[0] == 1) { + if (input[1] > max_clk) { + dev_warn(smu->adev->dev, + "Maximum UCLK (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", + input[1], max_clk); + pstate_table->uclk_pstate.custom.max = + pstate_table->uclk_pstate.curr.max; + + return -EINVAL; + } + + pstate_table->uclk_pstate.custom.max = input[1]; + } + break; + case PP_OD_RESTORE_DEFAULT_TABLE: + if (size != 0) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + + /* Use the default frequencies for manual mode */ + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table); + + ret = smu_v15_0_8_set_soft_freq_limited_range(smu, + SMU_GFXCLK, + min_clk, max_clk, + false); + if (ret) + return ret; + + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table); + ret = smu_v15_0_8_set_soft_freq_limited_range(smu, + SMU_UCLK, + min_clk, max_clk, + false); + if (ret) + return ret; + + smu_cmn_reset_custom_level(smu); + break; + case PP_OD_COMMIT_DPM_TABLE: + if (size != 0) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + + if (!pstate_table->gfxclk_pstate.custom.min) + pstate_table->gfxclk_pstate.custom.min = + pstate_table->gfxclk_pstate.curr.min; + + if (!pstate_table->gfxclk_pstate.custom.max) + pstate_table->gfxclk_pstate.custom.max = + pstate_table->gfxclk_pstate.curr.max; + + min_clk = pstate_table->gfxclk_pstate.custom.min; + max_clk = pstate_table->gfxclk_pstate.custom.max; + + ret = smu_v15_0_8_set_soft_freq_limited_range(smu, + SMU_GFXCLK, + min_clk, max_clk, + false); + if (ret) + return ret; + + /* Commit UCLK custom range (only max supported) */ + if (pstate_table->uclk_pstate.custom.max) { + min_clk = pstate_table->uclk_pstate.curr.min; + max_clk = pstate_table->uclk_pstate.custom.max; + ret = smu_v15_0_8_set_soft_freq_limited_range(smu, + SMU_UCLK, + min_clk, max_clk, + false); + if (ret) + return ret; + } + + break; + default: + return -ENOSYS; + } + + return 0; +} + +static int smu_v15_0_8_get_thermal_temperature_range(struct smu_context *smu, + struct smu_temperature_range *range) +{ + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + uint32_t max_ctf, max_thm; + + if (amdgpu_sriov_multi_vf_mode(smu->adev)) + return 0; + + if (!range) + return -EINVAL; + + /* CTF (Critical Temperature Fault) limits */ + max_ctf = max3(pptable->CTFLimitMID, pptable->CTFLimitXCD, + pptable->CTFLimitAID); + range->hotspot_emergency_max = max_ctf * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + range->mem_emergency_max = pptable->CTFLimitHBM * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + /* Thermal throttling limits */ + max_thm = max3(pptable->ThermalLimitMID, pptable->ThermalLimitXCD, + pptable->ThermalLimitAID); + range->hotspot_crit_max = max_thm * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + range->mem_crit_max = pptable->ThermalLimitHBM * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + +static int smu_v15_0_8_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) +{ + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + int ret; + + if (limit_type == SMU_FAST_PPT_LIMIT) { + if (!pptable->PPT1Max) + return -EOPNOTSUPP; + + if (limit > pptable->PPT1Max || limit < pptable->PPT1Min) { + dev_err(smu->adev->dev, + "New PPT1 limit (%d) should be between min %d and max %d\n", + limit, pptable->PPT1Min, pptable->PPT1Max); + return -EINVAL; + } + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetFastPptLimit, + limit, NULL); + if (ret) + dev_err(smu->adev->dev, "Set fast PPT limit failed!\n"); + + return ret; + } + + return smu_v15_0_set_power_limit(smu, limit_type, limit); +} + +static int smu_v15_0_8_get_ppt_limit(struct smu_context *smu, + uint32_t *ppt_limit, + enum smu_ppt_limit_type type, + enum smu_ppt_limit_level level) +{ + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + int ret = 0; + + if (!ppt_limit) + return -EINVAL; + + if (type == SMU_FAST_PPT_LIMIT) { + if (!pptable->PPT1Max) + return -EOPNOTSUPP; + + switch (level) { + case SMU_PPT_LIMIT_MAX: + *ppt_limit = pptable->PPT1Max; + break; + case SMU_PPT_LIMIT_CURRENT: + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit, + ppt_limit); + if (ret) + dev_err(smu->adev->dev, + "Get fast PPT limit failed!\n"); + break; + case SMU_PPT_LIMIT_DEFAULT: + *ppt_limit = pptable->PPT1Default; + break; + case SMU_PPT_LIMIT_MIN: + *ppt_limit = pptable->PPT1Min; + break; + default: + return -EOPNOTSUPP; + } + return ret; + } + + return -EOPNOTSUPP; +} + +static const struct pptable_funcs smu_v15_0_8_ppt_funcs = { + .init_allowed_features = smu_v15_0_8_init_allowed_features, + .set_default_dpm_table = smu_v15_0_8_set_default_dpm_table, + .is_dpm_running = smu_v15_0_8_is_dpm_running, + .init_smc_tables = smu_v15_0_8_init_smc_tables, + .fini_smc_tables = smu_v15_0_8_fini_smc_tables, + .init_power = smu_v15_0_init_power, + .fini_power = smu_v15_0_fini_power, + .check_fw_status = smu_v15_0_8_check_fw_status, + .check_fw_version = smu_cmn_check_fw_version, + .set_driver_table_location = smu_v15_0_set_driver_table_location, + .set_tool_table_location = smu_v15_0_set_tool_table_location, + .notify_memory_pool_location = smu_v15_0_notify_memory_pool_location, + .system_features_control = smu_v15_0_8_system_features_control, + .get_enabled_mask = smu_v15_0_8_get_enabled_mask, + .feature_is_enabled = smu_cmn_feature_is_enabled, + .register_irq_handler = smu_v15_0_8_register_irq_handler, + .setup_pptable = smu_v15_0_8_setup_pptable, + .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, + .wait_for_event = smu_v15_0_wait_for_event, + .get_pm_metrics = smu_v15_0_8_get_pm_metrics, + .mode2_reset = smu_v15_0_8_mode2_reset, + .get_dpm_ultimate_freq = smu_v15_0_8_get_dpm_ultimate_freq, + .get_gpu_metrics = smu_v15_0_8_get_gpu_metrics, + .get_unique_id = smu_v15_0_8_get_unique_id, + .get_power_limit = smu_v15_0_8_get_power_limit, + .set_power_limit = smu_v15_0_8_set_power_limit, + .get_ppt_limit = smu_v15_0_8_get_ppt_limit, + .emit_clk_levels = smu_v15_0_8_emit_clk_levels, + .read_sensor = smu_v15_0_8_read_sensor, + .populate_umd_state_clk = smu_v15_0_8_populate_umd_state_clk, + .set_performance_level = smu_v15_0_8_set_performance_level, + .od_edit_dpm_table = smu_v15_0_8_od_edit_dpm_table, + .get_thermal_temperature_range = smu_v15_0_8_get_thermal_temperature_range, +}; + +static void smu_v15_0_8_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_40); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_41); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_42); + ctl->config.arg_regs[1] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_43); + ctl->config.arg_regs[2] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_44); + ctl->config.arg_regs[3] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_45); + ctl->config.num_arg_regs = 4; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; +} + +static const struct smu_temp_funcs smu_v15_0_8_temp_funcs = { + .temp_metrics_is_supported = smu_v15_0_8_is_temp_metrics_supported, + .get_temp_metrics = smu_v15_0_8_get_temp_metrics, +}; + +void smu_v15_0_8_set_ppt_funcs(struct smu_context *smu) +{ + smu->ppt_funcs = &smu_v15_0_8_ppt_funcs; + smu->clock_map = smu_v15_0_8_clk_map; + smu->feature_map = smu_v15_0_8_feature_mask_map; + smu->table_map = smu_v15_0_8_table_map; + smu_v15_0_8_init_msg_ctl(smu, smu_v15_0_8_message_map); + smu->smu_temp.temp_funcs = &smu_v15_0_8_temp_funcs; + smu->smc_driver_if_version = SMU15_DRIVER_IF_VERSION_SMU_V15_0_8; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h new file mode 100644 index 000000000000..398ce4482174 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h @@ -0,0 +1,313 @@ +/* + * Copyright 2025 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. + * + */ +#ifndef __SMU_15_0_8_PPT_H__ +#define __SMU_15_0_8_PPT_H__ + +#define SMU_15_0_8_NUM_XGMI_LINKS 8 +#define SMU_15_0_8_MAX_GFX_CLKS 8 +#define SMU_15_0_8_MAX_CLKS 4 +#define SMU_15_0_8_MAX_XCC 8 +#define SMU_15_0_8_MAX_VCN 4 +#define SMU_15_0_8_MAX_JPEG 40 +#define SMU_15_0_8_MAX_AID 2 +#define SMU_15_0_8_MAX_MID 2 +#define SMU_15_0_8_MAX_HBM_STACKS 12 +extern void smu_v15_0_8_set_ppt_funcs(struct smu_context *smu); + +typedef struct { + uint32_t MaxSocketPowerLimit; + uint32_t MaxGfxclkFrequency; + uint32_t MinGfxclkFrequency; + uint32_t MaxFclkFrequency; + uint32_t MinFclkFrequency; + uint32_t MaxGl2clkFrequency; + uint32_t MinGl2clkFrequency; + uint32_t UclkFrequencyTable[4]; + uint32_t SocclkFrequency; + uint32_t LclkFrequency; + uint32_t VclkFrequency; + uint32_t DclkFrequency; + uint32_t CTFLimitMID; + uint32_t CTFLimitAID; + uint32_t CTFLimitXCD; + uint32_t CTFLimitHBM; + uint32_t ThermalLimitMID; + uint32_t ThermalLimitAID; + uint32_t ThermalLimitXCD; + uint32_t ThermalLimitHBM; + uint64_t PublicSerialNumberMID; + uint64_t PublicSerialNumberAID; + uint64_t PublicSerialNumberXCD; + uint32_t PPT1Max; + uint32_t PPT1Min; + uint32_t PPT1Default; + bool init; +} PPTable_t; + +#if defined(SWSMU_CODE_LAYER_L2) +#include "smu_cmn.h" + +/* SMUv 15.0.8 GPU metrics*/ +#define SMU_15_0_8_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_HOTSPOT), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_hotspot); \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_MEM), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_mem); \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_VRSOC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_vrsoc); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_HBM), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_hbm, \ + SMU_15_0_8_MAX_HBM_STACKS); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_MID), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_mid, SMU_15_0_8_MAX_MID); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_AID), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_aid, SMU_15_0_8_MAX_AID); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_XCD), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_xcd, SMU_15_0_8_MAX_XCC); \ + SMU_SCALAR(SMU_MATTR(CURR_SOCKET_POWER), SMU_MUNIT(POWER_1), \ + SMU_MTYPE(U16), curr_socket_power); \ + SMU_SCALAR(SMU_MATTR(AVERAGE_GFX_ACTIVITY), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U16), average_gfx_activity); \ + SMU_SCALAR(SMU_MATTR(AVERAGE_UMC_ACTIVITY), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U16), average_umc_activity); \ + SMU_SCALAR(SMU_MATTR(MEM_MAX_BANDWIDTH), SMU_MUNIT(BW_1), \ + SMU_MTYPE(U64), mem_max_bandwidth); \ + SMU_SCALAR(SMU_MATTR(ENERGY_ACCUMULATOR), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), energy_accumulator); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_CLOCK_COUNTER), SMU_MUNIT(TIME_1), \ + SMU_MTYPE(U64), system_clock_counter); \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(PROCHOT_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), prochot_residency_acc); \ + SMU_SCALAR(SMU_MATTR(PPT_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), ppt_residency_acc); \ + SMU_SCALAR(SMU_MATTR(SOCKET_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), socket_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(VR_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), vr_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(HBM_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), hbm_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(GFXCLK_LOCK_STATUS), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), gfxclk_lock_status); \ + SMU_SCALAR(SMU_MATTR(PCIE_LINK_WIDTH), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), pcie_link_width); \ + SMU_SCALAR(SMU_MATTR(PCIE_LINK_SPEED), SMU_MUNIT(SPEED_2), \ + SMU_MTYPE(U16), pcie_link_speed); \ + SMU_SCALAR(SMU_MATTR(XGMI_LINK_WIDTH), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), xgmi_link_width); \ + SMU_SCALAR(SMU_MATTR(XGMI_LINK_SPEED), SMU_MUNIT(SPEED_1), \ + SMU_MTYPE(U16), xgmi_link_speed); \ + SMU_SCALAR(SMU_MATTR(GFX_ACTIVITY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_activity_acc); \ + SMU_SCALAR(SMU_MATTR(MEM_ACTIVITY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), mem_activity_acc); \ + SMU_ARRAY(SMU_MATTR(PCIE_BANDWIDTH_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_bandwidth_acc, SMU_15_0_8_MAX_MID); \ + SMU_ARRAY(SMU_MATTR(PCIE_BANDWIDTH_INST), SMU_MUNIT(BW_1), \ + SMU_MTYPE(U32), pcie_bandwidth_inst, SMU_15_0_8_MAX_MID); \ + SMU_SCALAR(SMU_MATTR(PCIE_L0_TO_RECOV_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_l0_to_recov_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_replay_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_ROVER_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_replay_rover_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_NAK_SENT_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_nak_sent_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_NAK_RCVD_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_nak_rcvd_count_acc); \ + SMU_ARRAY(SMU_MATTR(XGMI_LINK_STATUS), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), xgmi_link_status, \ + SMU_15_0_8_NUM_XGMI_LINKS); \ + SMU_SCALAR(SMU_MATTR(XGMI_READ_DATA_ACC), SMU_MUNIT(DATA_1), \ + SMU_MTYPE(U64), xgmi_read_data_acc); \ + SMU_SCALAR(SMU_MATTR(XGMI_WRITE_DATA_ACC), SMU_MUNIT(DATA_1), \ + SMU_MTYPE(U64), xgmi_write_data_acc); \ + SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \ + SMU_MTYPE(U64), firmware_timestamp); \ + SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_gfxclk, SMU_15_0_8_MAX_GFX_CLKS); \ + SMU_ARRAY(SMU_MATTR(CURRENT_SOCCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_socclk, SMU_15_0_8_MAX_MID); \ + SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_vclk0, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_dclk0, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(CURRENT_UCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_uclk, SMU_15_0_8_MAX_AID); \ + SMU_SCALAR(SMU_MATTR(PCIE_LC_PERF_OTHER_END_RECOVERY), \ + SMU_MUNIT(NONE), SMU_MTYPE(U64), \ + pcie_lc_perf_other_end_recovery); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U32), gfx_busy_inst, SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \ + jpeg_busy, SMU_15_0_8_MAX_JPEG); \ + SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \ + vcn_busy, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(NONE), SMU_MTYPE(U64), \ + gfx_busy_acc, SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_low_utilization_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \ + SMU_15_0_8_MAX_XCC); + +DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_gpu_metrics, SMU_15_0_8_METRICS_FIELDS); + +/* Maximum temperature sensor counts for system metrics */ +#define SMU_15_0_8_MAX_SYSTEM_TEMP_ENTRIES 32 +#define SMU_15_0_8_MAX_NODE_TEMP_ENTRIES 12 +#define SMU_15_0_8_MAX_VR_TEMP_ENTRIES 22 + +/* SMUv 15.0.8 GPU board temperature metrics */ +#define SMU_15_0_8_GPUBOARD_TEMP_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(LABEL_VERSION), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), label_version); \ + SMU_SCALAR(SMU_MATTR(NODE_ID), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), node_id); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_RETIMER), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_retimer); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_IBC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_ibc); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_IBC_2), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_ibc_2); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_VDD18_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_vdd18_vr); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_04_HBM_B_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_04_hbm_b_vr); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_04_HBM_D_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_04_hbm_d_vr); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_SOCIO_A), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_socio_a); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_SOCIO_C), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_socio_c); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_X0), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_x0); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_X1), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_x1); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_HBM_B), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_hbm_b); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_HBM_D), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_hbm_d); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_04_HBM_B), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_04_hbm_b); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_04_HBM_D), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_04_hbm_d); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_HBM_B), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_hbm_b); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_HBM_D), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_hbm_d); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_HBM_B), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_075_hbm_b); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_HBM_D), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_075_hbm_d); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_11_GTA_A), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_11_gta_a); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_11_GTA_C), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_11_gta_c); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075_GTA_A), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddan_075_gta_a); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075_GTA_C), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddan_075_gta_c); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_UCIE), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_075_ucie); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAA), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_065_ucieaa); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAM_A), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_065_ucieam_a); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAM_C), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_065_ucieam_c); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddan_075); + +DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_gpuboard_temp_metrics, + SMU_15_0_8_GPUBOARD_TEMP_METRICS_FIELDS); + +/* SMUv 15.0.8 Baseboard temperature metrics - ID-based approach */ +#define SMU_15_0_8_BASEBOARD_TEMP_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(LABEL_VERSION), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), label_version); \ + SMU_SCALAR(SMU_MATTR(NODE_ID), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), node_id); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_fpga); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FRONT), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_front); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_BACK), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_back); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_OAM7), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_oam7); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_IBC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_ibc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_UFPGA), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_ufpga); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_OAM1), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_oam1); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_0_1_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_0_1_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_2_3_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_2_3_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_4_5_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_4_5_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_6_7_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_6_7_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA_0V72_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_fpga_0v72_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA_3V3_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_fpga_3v3_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_0_1_2_3_1v2_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_4_5_6_7_1v2_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_0_1_0V9_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_0_1_0v9_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_4_5_0V9_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_4_5_0v9_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_2_3_0V9_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_2_3_0v9_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_6_7_0V9_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_6_7_0v9_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_0_1_2_3_3v3_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_4_5_6_7_3v3_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_IBC_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ibc_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_IBC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ibc); + +DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_baseboard_temp_metrics, + SMU_15_0_8_BASEBOARD_TEMP_METRICS_FIELDS); +#endif +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 326c86b920a2..7bd8c435466a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -1035,6 +1035,31 @@ int smu_cmn_get_smc_version(struct smu_context *smu, return ret; } +int smu_cmn_check_fw_version(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t if_version = 0xff, smu_version = 0xff; + uint8_t smu_program, smu_major, smu_minor, smu_debug; + int ret; + + ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); + if (ret) + return ret; + + smu_program = (smu_version >> 24) & 0xff; + smu_major = (smu_version >> 16) & 0xff; + smu_minor = (smu_version >> 8) & 0xff; + smu_debug = (smu_version >> 0) & 0xff; + adev->pm.fw_version = smu_version; + + dev_info_once(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " + "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", + smu->smc_driver_if_version, if_version, + smu_program, smu_version, smu_major, smu_minor, smu_debug); + + return 0; +} + int smu_cmn_update_table(struct smu_context *smu, enum smu_table_id table_index, int argument, @@ -1276,6 +1301,16 @@ void smu_cmn_get_backend_workload_mask(struct smu_context *smu, } } +void smu_cmn_reset_custom_level(struct smu_context *smu) +{ + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + + pstate_table->gfxclk_pstate.custom.min = 0; + pstate_table->gfxclk_pstate.custom.max = 0; + pstate_table->uclk_pstate.custom.min = 0; + pstate_table->uclk_pstate.custom.max = 0; +} + static inline bool smu_cmn_freqs_match(uint32_t freq1, uint32_t freq2) { /* Frequencies within 25 MHz are considered equal */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index b7bfddc65fb2..b76e86df5da7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -204,9 +204,11 @@ int smu_cmn_print_pcie_levels(struct smu_context *smu, struct smu_pcie_table *pcie_table, uint32_t cur_gen, uint32_t cur_lane, char *buf, int *offset); +void smu_cmn_reset_custom_level(struct smu_context *smu); int smu_cmn_dpm_pcie_gen_idx(int gen); int smu_cmn_dpm_pcie_width_idx(int width); +int smu_cmn_check_fw_version(struct smu_context *smu); /*SMU gpu metrics */ diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c index 4b86a58e8149..d213eea71cff 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c @@ -535,6 +535,37 @@ int amdgpu_ras_mgr_handle_controller_interrupt(struct amdgpu_device *adev, void return ret; } +int amdgpu_ras_mgr_dispatch_interrupt(struct amdgpu_device *adev, struct ras_ih_info *ih_info) +{ + struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev); + uint64_t seq_no = 0; + int ret = 0; + + if (!amdgpu_ras_mgr_is_ready(adev)) + return -EPERM; + + if (!ih_info) + return 0; + + if (ih_info->block == RAS_BLOCK_ID__UMC) { + if (ras_mgr->ras_core->poison_supported) { + seq_no = amdgpu_ras_mgr_gen_ras_event_seqno(adev, RAS_SEQNO_TYPE_DE); + RAS_DEV_INFO(adev, + "{%llu} RAS poison is created, no user action is needed.\n", + seq_no); + } + + ret = amdgpu_ras_process_handle_umc_interrupt(adev, ih_info); + } else if (ras_mgr->ras_core->poison_supported) { + ret = amdgpu_ras_process_handle_consumption_interrupt(adev, ih_info); + } else { + RAS_DEV_WARN(adev, + "No RAS interrupt handler for non-UMC block with poison disabled.\n"); + } + + return ret; +} + int amdgpu_ras_mgr_handle_consumer_interrupt(struct amdgpu_device *adev, void *data) { if (!amdgpu_ras_mgr_is_ready(adev)) diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h index 23c411c98231..4f44a917d48b 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h @@ -67,6 +67,7 @@ bool amdgpu_uniras_enabled(struct amdgpu_device *adev); int amdgpu_ras_mgr_handle_fatal_interrupt(struct amdgpu_device *adev, void *data); int amdgpu_ras_mgr_handle_controller_interrupt(struct amdgpu_device *adev, void *data); int amdgpu_ras_mgr_handle_consumer_interrupt(struct amdgpu_device *adev, void *data); +int amdgpu_ras_mgr_dispatch_interrupt(struct amdgpu_device *adev, struct ras_ih_info *ih_info); int amdgpu_ras_mgr_update_ras_ecc(struct amdgpu_device *adev); int amdgpu_ras_mgr_reset_gpu(struct amdgpu_device *adev, uint32_t flags); uint64_t amdgpu_ras_mgr_gen_ras_event_seqno(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_process.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_process.c index 5782c007de71..285d81a85a99 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_process.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_process.c @@ -103,6 +103,16 @@ int amdgpu_ras_process_handle_consumption_interrupt(struct amdgpu_device *adev, if (!ih_info) return -EINVAL; + if (amdgpu_sriov_vf(adev)) { + if (adev->virt.ops && adev->virt.ops->ras_poison_handler) + adev->virt.ops->ras_poison_handler(adev, ih_info->block); + else + dev_warn(adev->dev, + "No ras_poison_handler interface in SRIOV for block[%d]!\n", + ih_info->block); + return 0; + } + memset(&req, 0, sizeof(req)); req.block = ih_info->block; req.data = ih_info->data; diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_core.c b/drivers/gpu/drm/amd/ras/rascore/ras_core.c index bbf13c076a94..49b3aa7489ff 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_core.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_core.c @@ -69,6 +69,9 @@ int ras_core_convert_timestamp_to_time(struct ras_core_context *ras_core, int seconds_per_minute = 60; int days, remaining_seconds; + if (!tm) + return -EINVAL; + days = div64_u64_rem(timestamp, seconds_per_day, &remainder); /* remainder will always be less than seconds_per_day. */ remaining_seconds = remainder; @@ -116,6 +119,9 @@ bool ras_core_gpu_in_reset(struct ras_core_context *ras_core) { uint32_t status = 0; + if (!ras_core) + return false; + if (ras_core->sys_fn && ras_core->sys_fn->check_gpu_status) ras_core->sys_fn->check_gpu_status(ras_core, &status); @@ -127,6 +133,9 @@ bool ras_core_gpu_is_vf(struct ras_core_context *ras_core) { uint32_t status = 0; + if (!ras_core) + return false; + if (ras_core->sys_fn && ras_core->sys_fn->check_gpu_status) ras_core->sys_fn->check_gpu_status(ras_core, &status); @@ -271,6 +280,9 @@ struct ras_core_context *ras_core_create(struct ras_core_config *init_config) struct ras_core_context *ras_core; struct ras_core_config *config; + if (!init_config) + return NULL; + ras_core = kzalloc_obj(*ras_core); if (!ras_core) return NULL; @@ -479,6 +491,9 @@ int ras_core_handle_fatal_error(struct ras_core_context *ras_core) uint32_t ras_core_get_curr_nps_mode(struct ras_core_context *ras_core) { + if (!ras_core) + return 0; + if (ras_core->ras_nbio.ip_func && ras_core->ras_nbio.ip_func->get_memory_partition_mode) return ras_core->ras_nbio.ip_func->get_memory_partition_mode(ras_core); @@ -527,8 +542,11 @@ bool ras_core_is_enabled(struct ras_core_context *ras_core) uint64_t ras_core_get_utc_second_timestamp(struct ras_core_context *ras_core) { - if (ras_core && ras_core->sys_fn && - ras_core->sys_fn->get_utc_second_timestamp) + if (!ras_core) + return 0; + + if (ras_core->sys_fn && + ras_core->sys_fn->get_utc_second_timestamp) return ras_core->sys_fn->get_utc_second_timestamp(ras_core); RAS_DEV_ERR(ras_core->dev, "Failed to get system timestamp!\n"); @@ -550,13 +568,17 @@ bool ras_core_ras_interrupt_detected(struct ras_core_context *ras_core) ras_core->sys_fn->detect_ras_interrupt) return ras_core->sys_fn->detect_ras_interrupt(ras_core); - RAS_DEV_ERR(ras_core->dev, "Failed to detect ras interrupt!\n"); + if (ras_core && ras_core->dev) + RAS_DEV_ERR(ras_core->dev, "Failed to detect ras interrupt!\n"); + return false; } int ras_core_get_gpu_mem(struct ras_core_context *ras_core, enum gpu_mem_type mem_type, struct gpu_mem_block *gpu_mem) { + if (!ras_core || !gpu_mem) + return -EINVAL; if (ras_core->sys_fn && ras_core->sys_fn->get_gpu_mem) return ras_core->sys_fn->get_gpu_mem(ras_core, mem_type, gpu_mem); @@ -567,6 +589,8 @@ int ras_core_get_gpu_mem(struct ras_core_context *ras_core, int ras_core_put_gpu_mem(struct ras_core_context *ras_core, enum gpu_mem_type mem_type, struct gpu_mem_block *gpu_mem) { + if (!ras_core || !gpu_mem) + return -EINVAL; if (ras_core->sys_fn && ras_core->sys_fn->put_gpu_mem) return ras_core->sys_fn->put_gpu_mem(ras_core, mem_type, gpu_mem); @@ -620,6 +644,9 @@ int ras_core_event_notify(struct ras_core_context *ras_core, int ras_core_get_device_system_info(struct ras_core_context *ras_core, struct device_system_info *dev_info) { + if (!dev_info) + return -EINVAL; + if (ras_core && ras_core->sys_fn && ras_core->sys_fn->get_device_system_info) return ras_core->sys_fn->get_device_system_info(ras_core, dev_info); diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_umc.c b/drivers/gpu/drm/amd/ras/rascore/ras_umc.c index 23118f41eb96..c7ae005ea705 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_umc.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_umc.c @@ -222,7 +222,7 @@ int ras_umc_log_pending_bad_bank(struct ras_core_context *ras_core) mutex_lock(&ras_umc->pending_ecc_lock); list_for_each_entry_safe(ecc_node, tmp, &ras_umc->pending_ecc_list, node){ - if (ecc_node && !ras_umc_log_bad_bank(ras_core, &ecc_node->ecc)) { + if (!ras_umc_log_bad_bank(ras_core, &ecc_node->ecc)) { list_del(&ecc_node->node); kfree(ecc_node); } diff --git a/drivers/gpu/drm/arm/display/include/malidp_product.h b/drivers/gpu/drm/arm/display/include/malidp_product.h index 16a8a2c22c42..6f954bcdf40e 100644 --- a/drivers/gpu/drm/arm/display/include/malidp_product.h +++ b/drivers/gpu/drm/arm/display/include/malidp_product.h @@ -20,6 +20,7 @@ /* Mali-display product IDs */ #define MALIDP_D71_PRODUCT_ID 0x0071 #define MALIDP_D32_PRODUCT_ID 0x0032 +#define LINLONDP_D6_PRODUCT_ID 0x0060 union komeda_config_id { struct { diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c index 67e5d3b4190f..27ca2930cdac 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c @@ -1080,11 +1080,11 @@ static void d71_improc_update(struct komeda_component *c, mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; /* config color format */ - if (st->color_format == DRM_COLOR_FORMAT_YCBCR420) + if (st->color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; - else if (st->color_format == DRM_COLOR_FORMAT_YCBCR422) + else if (st->color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422; - else if (st->color_format == DRM_COLOR_FORMAT_YCBCR444) + else if (st->color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR444) ctrl |= IPS_CTRL_YUV; malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); @@ -1145,12 +1145,12 @@ static int d71_improc_init(struct d71_dev *d71, improc = to_improc(c); improc->supported_color_depths = BIT(8) | BIT(10); - improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 | - DRM_COLOR_FORMAT_YCBCR444 | - DRM_COLOR_FORMAT_YCBCR422; + improc->supported_color_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422); value = malidp_read32(reg, BLK_INFO); if (value & IPS_INFO_CHD420) - improc->supported_color_formats |= DRM_COLOR_FORMAT_YCBCR420; + improc->supported_color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420); improc->supports_csc = true; improc->supports_gamma = true; diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c index 80973975bfdb..f105e3a2dce2 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c @@ -628,6 +628,7 @@ d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip) switch (product_id) { case MALIDP_D71_PRODUCT_ID: case MALIDP_D32_PRODUCT_ID: + case LINLONDP_D6_PRODUCT_ID: funcs = &d71_chip_funcs; break; default: diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 9c8b8da531a7..714af5c889d7 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -40,7 +40,7 @@ void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st, /* connector doesn't config any color_format, use RGB444 as default */ if (!conn_color_formats) - conn_color_formats = DRM_COLOR_FORMAT_RGB444; + conn_color_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444); *color_depths = GENMASK(min_bpc, 0); *color_formats = conn_color_formats; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index 358c1512b087..4bb5f250e95e 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -104,6 +104,7 @@ free_mdrv: static const struct of_device_id komeda_of_match[] = { { .compatible = "arm,mali-d71", .data = d71_identify, }, { .compatible = "arm,mali-d32", .data = d71_identify, }, + { .compatible = "armchina,linlon-d6", .data = d71_identify, }, {}, }; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h index 37b9e9220244..bbee6da43164 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h @@ -319,7 +319,7 @@ struct komeda_splitter_state { struct komeda_improc { struct komeda_component base; - u32 supported_color_formats; /* DRM_RGB/YUV444/YUV420*/ + u32 supported_color_formats; /* BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444/YUV444/YUV420) */ u32 supported_color_depths; /* BIT(8) | BIT(10)*/ u8 supports_degamma : 1; u8 supports_csc : 1; @@ -328,7 +328,8 @@ struct komeda_improc { struct komeda_improc_state { struct komeda_component_state base; - u8 color_format, color_depth; + enum drm_output_color_format color_format; + u8 color_depth; u16 hsize, vsize; u32 fgamma_coeffs[KOMEDA_N_GAMMA_COEFFS]; u32 ctm_coeffs[KOMEDA_N_CTM_COEFFS]; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c index f4e76b46ca32..6f9b10cc831f 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -799,7 +799,7 @@ komeda_improc_validate(struct komeda_improc *improc, } st->color_depth = __fls(avail_depths); - st->color_format = BIT(__ffs(avail_formats)); + st->color_format = __ffs(avail_formats); } if (kcrtc_st->base.color_mgmt_changed) { diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c index 49b934c6dbdf..77b3f361091f 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c @@ -65,7 +65,7 @@ static const struct drm_private_state_funcs komeda_layer_obj_funcs = { static int komeda_layer_obj_add(struct komeda_kms_dev *kms, struct komeda_layer *layer) { - drm_atomic_private_obj_init(&kms->base, &layer->base.obj, NULL, + drm_atomic_private_obj_init(&kms->base, &layer->base.obj, &komeda_layer_obj_funcs); return 0; } @@ -118,7 +118,7 @@ static int komeda_scaler_obj_add(struct komeda_kms_dev *kms, struct komeda_scaler *scaler) { drm_atomic_private_obj_init(&kms->base, - &scaler->base.obj, NULL, + &scaler->base.obj, &komeda_scaler_obj_funcs); return 0; } @@ -170,7 +170,7 @@ static const struct drm_private_state_funcs komeda_compiz_obj_funcs = { static int komeda_compiz_obj_add(struct komeda_kms_dev *kms, struct komeda_compiz *compiz) { - drm_atomic_private_obj_init(&kms->base, &compiz->base.obj, NULL, + drm_atomic_private_obj_init(&kms->base, &compiz->base.obj, &komeda_compiz_obj_funcs); return 0; @@ -224,7 +224,7 @@ static int komeda_splitter_obj_add(struct komeda_kms_dev *kms, struct komeda_splitter *splitter) { drm_atomic_private_obj_init(&kms->base, - &splitter->base.obj, NULL, + &splitter->base.obj, &komeda_splitter_obj_funcs); return 0; @@ -277,7 +277,7 @@ static int komeda_merger_obj_add(struct komeda_kms_dev *kms, struct komeda_merger *merger) { drm_atomic_private_obj_init(&kms->base, - &merger->base.obj, NULL, + &merger->base.obj, &komeda_merger_obj_funcs); return 0; @@ -330,7 +330,7 @@ static const struct drm_private_state_funcs komeda_improc_obj_funcs = { static int komeda_improc_obj_add(struct komeda_kms_dev *kms, struct komeda_improc *improc) { - drm_atomic_private_obj_init(&kms->base, &improc->base.obj, NULL, + drm_atomic_private_obj_init(&kms->base, &improc->base.obj, &komeda_improc_obj_funcs); return 0; @@ -383,7 +383,7 @@ static const struct drm_private_state_funcs komeda_timing_ctrlr_obj_funcs = { static int komeda_timing_ctrlr_obj_add(struct komeda_kms_dev *kms, struct komeda_timing_ctrlr *ctrlr) { - drm_atomic_private_obj_init(&kms->base, &ctrlr->base.obj, NULL, + drm_atomic_private_obj_init(&kms->base, &ctrlr->base.obj, &komeda_timing_ctrlr_obj_funcs); return 0; @@ -437,7 +437,7 @@ static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = { static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms, struct komeda_pipeline *pipe) { - drm_atomic_private_obj_init(&kms->base, &pipe->obj, NULL, + drm_atomic_private_obj_init(&kms->base, &pipe->obj, &komeda_pipeline_obj_funcs); return 0; diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index 9e19d8c17730..677c52c0d99a 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -436,7 +436,7 @@ static void ast_init_analog(struct ast_device *ast) /* Finally, clear bits [17:16] of SCU2c */ data = ast_read32(ast, 0x1202c); data &= 0xfffcffff; - ast_write32(ast, 0, data); + ast_write32(ast, 0x1202c, data); /* Disable DVO */ ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x00); diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 1cabfa1d2b2e..c3209b0f4678 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -191,6 +191,17 @@ config DRM_LONTIUM_LT9611UXC HDMI signals Please say Y if you have such hardware. +config DRM_LONTIUM_LT8713SX + tristate "Lontium LT8713SX DP MST bridge" + depends on OF + select CRC8 + select REGMAP_I2C + help + Driver for Lontium LT8713SX DP MST bridge + chip firmware upgrade, which converts Type-C/DP1.4 + to 3 configurable Type-C/DP1.4/HDMI2.0 outputs + Please say Y if you have such hardware. + config DRM_ITE_IT66121 tristate "ITE IT66121 HDMI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index fb0cf0bf8875..beab5b695a6e 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o +obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 1050bb62280b..6bd76c1fb007 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -228,7 +228,7 @@ static void adv7511_set_config_csc(struct adv7511 *adv7511, config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; if ((connector->display_info.color_formats & - DRM_COLOR_FORMAT_YCBCR422) && + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) && connector->display_info.is_hdmi) { config.csc_enable = false; output_format_422 = true; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index b1687a4aa047..8dee5f2fbde5 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -281,77 +281,14 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) if (retval < 0) return retval; - for (lane = 0; lane < lane_count; lane++) - buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | - DP_TRAIN_VOLTAGE_SWING_LEVEL_0; - - retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, - lane_count); + retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, + dp->link_train.training_lane, lane_count); if (retval < 0) return retval; return 0; } -static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane) -{ - int shift = (lane & 1) * 4; - u8 link_value = link_status[lane >> 1]; - - return (link_value >> shift) & 0xf; -} - -static int analogix_dp_clock_recovery_ok(u8 link_status[2], int lane_count) -{ - int lane; - u8 lane_status; - - for (lane = 0; lane < lane_count; lane++) { - lane_status = analogix_dp_get_lane_status(link_status, lane); - if ((lane_status & DP_LANE_CR_DONE) == 0) - return -EINVAL; - } - return 0; -} - -static int analogix_dp_channel_eq_ok(u8 link_status[2], u8 link_align, - int lane_count) -{ - int lane; - u8 lane_status; - - if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) - return -EINVAL; - - for (lane = 0; lane < lane_count; lane++) { - lane_status = analogix_dp_get_lane_status(link_status, lane); - lane_status &= DP_CHANNEL_EQ_BITS; - if (lane_status != DP_CHANNEL_EQ_BITS) - return -EINVAL; - } - - return 0; -} - -static unsigned char -analogix_dp_get_adjust_request_voltage(u8 adjust_request[2], int lane) -{ - int shift = (lane & 1) * 4; - u8 link_value = adjust_request[lane >> 1]; - - return (link_value >> shift) & 0x3; -} - -static unsigned char analogix_dp_get_adjust_request_pre_emphasis( - u8 adjust_request[2], - int lane) -{ - int shift = (lane & 1) * 4; - u8 link_value = adjust_request[lane >> 1]; - - return ((link_value >> shift) & 0xc) >> 2; -} - static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp) { analogix_dp_training_pattern_dis(dp); @@ -361,17 +298,15 @@ static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp) } static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp, - u8 adjust_request[2]) + u8 link_status[DP_LINK_STATUS_SIZE]) { int lane, lane_count; u8 voltage_swing, pre_emphasis, training_lane; lane_count = dp->link_train.lane_count; for (lane = 0; lane < lane_count; lane++) { - voltage_swing = analogix_dp_get_adjust_request_voltage( - adjust_request, lane); - pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( - adjust_request, lane); + voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane); + pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane); training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | DPCD_PRE_EMPHASIS_SET(pre_emphasis); @@ -388,17 +323,17 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) { int lane, lane_count, retval; u8 voltage_swing, pre_emphasis, training_lane; - u8 link_status[2], adjust_request[2]; + u8 link_status[DP_LINK_STATUS_SIZE]; usleep_range(100, 101); lane_count = dp->link_train.lane_count; - retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); + retval = drm_dp_dpcd_read_link_status(&dp->aux, link_status); if (retval < 0) return retval; - if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { + if (drm_dp_clock_recovery_ok(link_status, lane_count)) { /* set training pattern 2 for EQ */ analogix_dp_set_training_pattern(dp, TRAINING_PTN2); @@ -414,15 +349,10 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) return 0; } - retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, - adjust_request, 2); - if (retval < 0) - return retval; - for (lane = 0; lane < lane_count; lane++) { training_lane = analogix_dp_get_lane_link_training(dp, lane); - voltage_swing = analogix_dp_get_adjust_request_voltage(adjust_request, lane); - pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis(adjust_request, lane); + voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane); + pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane); if (DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing && DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis) @@ -439,7 +369,7 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) } } - analogix_dp_get_adjust_training_lane(dp, adjust_request); + analogix_dp_get_adjust_training_lane(dp, link_status); analogix_dp_set_lane_link_training(dp); retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, @@ -454,34 +384,24 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) { int lane_count, retval; u32 reg; - u8 link_align, link_status[2], adjust_request[2]; + u8 link_status[DP_LINK_STATUS_SIZE]; usleep_range(400, 401); lane_count = dp->link_train.lane_count; - retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); + retval = drm_dp_dpcd_read_link_status(&dp->aux, link_status); if (retval < 0) return retval; - if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { + if (!drm_dp_clock_recovery_ok(link_status, lane_count)) { analogix_dp_reduce_link_rate(dp); return -EIO; } - retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, - adjust_request, 2); - if (retval < 0) - return retval; - - retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, - &link_align); - if (retval < 0) - return retval; - - analogix_dp_get_adjust_training_lane(dp, adjust_request); + analogix_dp_get_adjust_training_lane(dp, link_status); - if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) { + if (drm_dp_channel_eq_ok(link_status, lane_count)) { /* traing pattern Set to Normal */ retval = analogix_dp_training_pattern_dis(dp); if (retval < 0) @@ -619,7 +539,7 @@ static int analogix_dp_full_link_train(struct analogix_dp_device *dp, static int analogix_dp_fast_link_train(struct analogix_dp_device *dp) { int ret; - u8 link_align, link_status[2]; + u8 link_status[DP_LINK_STATUS_SIZE]; analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); ret = analogix_dp_wait_pll_locked(dp); @@ -653,31 +573,20 @@ static int analogix_dp_fast_link_train(struct analogix_dp_device *dp) * speed */ if (verify_fast_training) { - ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, - &link_align); - if (ret < 0) { - DRM_DEV_ERROR(dp->dev, "Read align status failed %d\n", - ret); - return ret; - } - - ret = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, - 2); + ret = drm_dp_dpcd_read_link_status(&dp->aux, link_status); if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Read link status failed %d\n", ret); return ret; } - if (analogix_dp_clock_recovery_ok(link_status, - dp->link_train.lane_count)) { + if (!drm_dp_clock_recovery_ok(link_status, dp->link_train.lane_count)) { DRM_DEV_ERROR(dp->dev, "Clock recovery failed\n"); analogix_dp_reduce_link_rate(dp); return -EIO; } - if (analogix_dp_channel_eq_ok(link_status, link_align, - dp->link_train.lane_count)) { + if (!drm_dp_channel_eq_ok(link_status, dp->link_train.lane_count)) { DRM_DEV_ERROR(dp->dev, "Channel EQ failed\n"); analogix_dp_reduce_link_rate(dp); return -EIO; @@ -1223,9 +1132,9 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, video->color_depth = COLOR_8; break; } - if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444) + if (display_info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) video->color_space = COLOR_YCBCR444; - else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422) + else if (display_info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) video->color_space = COLOR_YCBCR422; else video->color_space = COLOR_RGB; diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 945bb47c172b..064c6915c896 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -1448,14 +1448,14 @@ static u32 cdns_mhdp_get_bpp(struct cdns_mhdp_display_fmt *fmt) return fmt->bpc; switch (fmt->color_format) { - case DRM_COLOR_FORMAT_RGB444: - case DRM_COLOR_FORMAT_YCBCR444: + case DRM_OUTPUT_COLOR_FORMAT_RGB444: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: bpp = fmt->bpc * 3; break; - case DRM_COLOR_FORMAT_YCBCR422: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: bpp = fmt->bpc * 2; break; - case DRM_COLOR_FORMAT_YCBCR420: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420: bpp = fmt->bpc * 3 / 2; break; default: @@ -1552,26 +1552,26 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, * If YCBCR supported and stream not SD, use ITU709 * Need to handle ITU version with YCBCR420 when supported */ - if ((pxlfmt == DRM_COLOR_FORMAT_YCBCR444 || - pxlfmt == DRM_COLOR_FORMAT_YCBCR422) && mode->crtc_vdisplay >= 720) + if ((pxlfmt == DRM_OUTPUT_COLOR_FORMAT_YCBCR444 || + pxlfmt == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) && mode->crtc_vdisplay >= 720) misc0 = DP_YCBCR_COEFFICIENTS_ITU709; bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt); switch (pxlfmt) { - case DRM_COLOR_FORMAT_RGB444: + case DRM_OUTPUT_COLOR_FORMAT_RGB444: pxl_repr = CDNS_DP_FRAMER_RGB << CDNS_DP_FRAMER_PXL_FORMAT; misc0 |= DP_COLOR_FORMAT_RGB; break; - case DRM_COLOR_FORMAT_YCBCR444: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: pxl_repr = CDNS_DP_FRAMER_YCBCR444 << CDNS_DP_FRAMER_PXL_FORMAT; misc0 |= DP_COLOR_FORMAT_YCbCr444 | DP_TEST_DYNAMIC_RANGE_CEA; break; - case DRM_COLOR_FORMAT_YCBCR422: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: pxl_repr = CDNS_DP_FRAMER_YCBCR422 << CDNS_DP_FRAMER_PXL_FORMAT; misc0 |= DP_COLOR_FORMAT_YCbCr422 | DP_TEST_DYNAMIC_RANGE_CEA; break; - case DRM_COLOR_FORMAT_YCBCR420: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420: pxl_repr = CDNS_DP_FRAMER_YCBCR420 << CDNS_DP_FRAMER_PXL_FORMAT; break; default: @@ -1667,7 +1667,7 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, if (mhdp->display_fmt.y_only) misc1 |= CDNS_DP_TEST_COLOR_FORMAT_RAW_Y_ONLY; /* Use VSC SDP for Y420 */ - if (pxlfmt == DRM_COLOR_FORMAT_YCBCR420) + if (pxlfmt == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) misc1 = CDNS_DP_TEST_VSC_SDP; cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_MISC(stream_id), @@ -2356,7 +2356,7 @@ static int cdns_mhdp_probe(struct platform_device *pdev) /* The only currently supported format */ mhdp->display_fmt.y_only = false; - mhdp->display_fmt.color_format = DRM_COLOR_FORMAT_RGB444; + mhdp->display_fmt.color_format = DRM_OUTPUT_COLOR_FORMAT_RGB444; mhdp->display_fmt.bpc = 8; mhdp->bridge.of_node = pdev->dev.of_node; diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h index b297db53ba28..b53335b0d22c 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h @@ -306,7 +306,7 @@ struct cdns_mhdp_sink { }; struct cdns_mhdp_display_fmt { - u32 color_format; + enum drm_output_color_format color_format; u32 bpc; bool y_only; }; diff --git a/drivers/gpu/drm/bridge/inno-hdmi.c b/drivers/gpu/drm/bridge/inno-hdmi.c index a26b99b101c4..87422d15d9a2 100644 --- a/drivers/gpu/drm/bridge/inno-hdmi.c +++ b/drivers/gpu/drm/bridge/inno-hdmi.c @@ -653,7 +653,7 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi, v_VIDEO_INPUT_CSP(0); hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); - if (conn_state->hdmi.output_format == HDMI_COLORSPACE_RGB) { + if (conn_state->hdmi.output_format == DRM_OUTPUT_COLOR_FORMAT_RGB444) { if (conn_state->hdmi.is_limited_range) { csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; @@ -672,14 +672,14 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi, } } else { if (colorimetry == HDMI_COLORIMETRY_ITU_601) { - if (conn_state->hdmi.output_format == HDMI_COLORSPACE_YUV444) { + if (conn_state->hdmi.output_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR444) { csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; } } else { - if (conn_state->hdmi.output_format == HDMI_COLORSPACE_YUV444) { + if (conn_state->hdmi.output_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR444) { csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c index e77681047bb2..4f3ebb7af4d4 100644 --- a/drivers/gpu/drm/bridge/ite-it6263.c +++ b/drivers/gpu/drm/bridge/ite-it6263.c @@ -666,7 +666,7 @@ it6263_bridge_mode_valid(struct drm_bridge *bridge, { unsigned long long rate; - rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444); if (rate == 0) return MODE_NOCLOCK; diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c new file mode 100644 index 000000000000..18fac6a46db4 --- /dev/null +++ b/drivers/gpu/drm/bridge/lontium-lt8713sx.c @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/crc8.h> +#include <linux/firmware.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/sizes.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +#include <drm/drm_bridge.h> +#include <drm/drm_of.h> + +#define FW_FILE "lt8713sx_fw.bin" + +#define REG_PAGE_CONTROL 0xff + +#define LT8713SX_PAGE_SIZE 256 + +DECLARE_CRC8_TABLE(lt8713sx_crc_table); + +struct lt8713sx { + struct device *dev; + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + + struct regmap *regmap; + /* Protects all accesses to registers by stopping the on-chip MCU */ + struct mutex ocm_lock; + + struct gpio_desc *reset_gpio; + struct gpio_desc *enable_gpio; + + struct i2c_client *client; + const struct firmware *fw; + + u8 *fw_buffer; + + u32 main_crc_value; + u32 bank_crc_value[17]; + + int bank_num; +}; + +static void lt8713sx_reset(struct lt8713sx *lt8713sx); + +static const struct regmap_range lt8713sx_ranges[] = { + { + .range_min = 0x0000, + .range_max = 0xffff + }, +}; + +static const struct regmap_access_table lt8713sx_table = { + .yes_ranges = lt8713sx_ranges, + .n_yes_ranges = ARRAY_SIZE(lt8713sx_ranges), +}; + +static const struct regmap_range_cfg lt8713sx_range_cfg = { + .name = "lt8713sx", + .range_min = 0x0000, + .range_max = 0xffff, + .selector_reg = REG_PAGE_CONTROL, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, +}; + +static const struct regmap_config lt8713sx_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = <8713sx_table, + .ranges = <8713sx_range_cfg, + .num_ranges = 1, + .cache_type = REGCACHE_NONE, + .max_register = 0xffff, +}; + +static void lt8713sx_i2c_enable(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe0ee, 0x01); +} + +static void lt8713sx_i2c_disable(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe0ee, 0x00); +} + +static int lt8713sx_prepare_firmware_data(struct lt8713sx *lt8713sx) +{ + int ret = 0; + size_t sz_12k = 12 * SZ_1K; + + ret = request_firmware(<8713sx->fw, FW_FILE, lt8713sx->dev); + if (ret < 0) { + dev_err(lt8713sx->dev, "request firmware failed\n"); + return ret; + } + + dev_dbg(lt8713sx->dev, "Firmware size: %zu bytes\n", lt8713sx->fw->size); + + if (lt8713sx->fw->size > SZ_256K - 1) { + dev_err(lt8713sx->dev, "Firmware size exceeds 256KB limit\n"); + release_firmware(lt8713sx->fw); + return -EINVAL; + } + + lt8713sx->fw_buffer = kvmalloc(SZ_256K, GFP_KERNEL); + if (!lt8713sx->fw_buffer) { + release_firmware(lt8713sx->fw); + return -ENOMEM; + } + + memset(lt8713sx->fw_buffer, 0xff, SZ_256K); + + /* main firmware */ + memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, SZ_64K - 1); + + lt8713sx->fw_buffer[SZ_64K - 1] = + crc8(lt8713sx_crc_table, lt8713sx->fw_buffer, SZ_64K - 1, 0); + lt8713sx->main_crc_value = lt8713sx->fw_buffer[SZ_64K - 1]; + dev_dbg(lt8713sx->dev, + "Main Firmware Data Crc = 0x%02X\n", lt8713sx->main_crc_value); + + /* bank firmware */ + memcpy(lt8713sx->fw_buffer + SZ_64K, + lt8713sx->fw->data + SZ_64K, + lt8713sx->fw->size - SZ_64K); + + lt8713sx->bank_num = (lt8713sx->fw->size - SZ_64K + sz_12k - 1) / sz_12k; + dev_dbg(lt8713sx->dev, "Bank Number Total is %d.\n", lt8713sx->bank_num); + + for (int i = 0; i < lt8713sx->bank_num; i++) { + lt8713sx->bank_crc_value[i] = + crc8(lt8713sx_crc_table, lt8713sx->fw_buffer + SZ_64K + i * sz_12k, + sz_12k, 0); + dev_dbg(lt8713sx->dev, "Bank number:%d; Firmware Data Crc:0x%02X\n", + i, lt8713sx->bank_crc_value[i]); + } + return 0; +} + +static void lt8713sx_config_parameters(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe05e, 0xc1); + regmap_write(lt8713sx->regmap, 0xe058, 0x00); + regmap_write(lt8713sx->regmap, 0xe059, 0x50); + regmap_write(lt8713sx->regmap, 0xe05a, 0x10); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); + regmap_write(lt8713sx->regmap, 0xe058, 0x21); +} + +static void lt8713sx_wren(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe103, 0xbf); + regmap_write(lt8713sx->regmap, 0xe103, 0xff); + regmap_write(lt8713sx->regmap, 0xe05a, 0x04); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); +} + +static void lt8713sx_wrdi(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe05a, 0x08); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); +} + +static void lt8713sx_fifo_reset(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe103, 0xbf); + regmap_write(lt8713sx->regmap, 0xe103, 0xff); +} + +static void lt8713sx_disable_sram_write(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe055, 0x00); +} + +static void lt8713sx_sram_to_flash(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe05a, 0x30); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); +} + +static void lt8713sx_i2c_to_sram(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe055, 0x80); + regmap_write(lt8713sx->regmap, 0xe05e, 0xc0); + regmap_write(lt8713sx->regmap, 0xe058, 0x21); +} + +static u8 lt8713sx_read_flash_status(struct lt8713sx *lt8713sx) +{ + u32 flash_status = 0; + + regmap_write(lt8713sx->regmap, 0xe103, 0x3f); + regmap_write(lt8713sx->regmap, 0xe103, 0xff); + + regmap_write(lt8713sx->regmap, 0xe05e, 0x40); + regmap_write(lt8713sx->regmap, 0xe056, 0x05); /* opcode=read status register */ + regmap_write(lt8713sx->regmap, 0xe055, 0x25); + regmap_write(lt8713sx->regmap, 0xe055, 0x01); + regmap_write(lt8713sx->regmap, 0xe058, 0x21); + + regmap_read(lt8713sx->regmap, 0xe05f, &flash_status); + dev_dbg(lt8713sx->dev, "flash_status:%x\n", flash_status); + + return flash_status; +} + +static void lt8713sx_block_erase(struct lt8713sx *lt8713sx) +{ + u32 i = 0; + u8 flash_status = 0; + u8 blocknum = 0x00; + u32 flashaddr = 0x00; + + for (blocknum = 0; blocknum < 8; blocknum++) { + flashaddr = blocknum * SZ_32K; + regmap_write(lt8713sx->regmap, 0xe05a, 0x04); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); + regmap_write(lt8713sx->regmap, 0xe05b, flashaddr >> 16); + regmap_write(lt8713sx->regmap, 0xe05c, flashaddr >> 8); + regmap_write(lt8713sx->regmap, 0xe05d, flashaddr); + regmap_write(lt8713sx->regmap, 0xe05a, 0x01); + regmap_write(lt8713sx->regmap, 0xe05a, 0x00); + msleep(100); + i = 0; + while (1) { + flash_status = lt8713sx_read_flash_status(lt8713sx); + if ((flash_status & 0x01) == 0) + break; + + if (i > 50) + break; + + i++; + msleep(50); + } + } + dev_dbg(lt8713sx->dev, "erase flash done.\n"); +} + +static void lt8713sx_load_main_fw_to_sram(struct lt8713sx *lt8713sx) +{ + regmap_write(lt8713sx->regmap, 0xe068, 0x00); + regmap_write(lt8713sx->regmap, 0xe069, 0x00); + regmap_write(lt8713sx->regmap, 0xe06a, 0x00); + regmap_write(lt8713sx->regmap, 0xe065, 0x00); + regmap_write(lt8713sx->regmap, 0xe066, 0xff); + regmap_write(lt8713sx->regmap, 0xe067, 0xff); + regmap_write(lt8713sx->regmap, 0xe06b, 0x00); + regmap_write(lt8713sx->regmap, 0xe06c, 0x00); + regmap_write(lt8713sx->regmap, 0xe060, 0x01); + msleep(200); + regmap_write(lt8713sx->regmap, 0xe060, 0x00); +} + +static void lt8713sx_load_bank_fw_to_sram(struct lt8713sx *lt8713sx, u64 addr) +{ + regmap_write(lt8713sx->regmap, 0xe068, ((addr & 0xff0000) >> 16)); + regmap_write(lt8713sx->regmap, 0xe069, ((addr & 0x00ff00) >> 8)); + regmap_write(lt8713sx->regmap, 0xe06a, (addr & 0x0000ff)); + regmap_write(lt8713sx->regmap, 0xe065, 0x00); + regmap_write(lt8713sx->regmap, 0xe066, 0x30); + regmap_write(lt8713sx->regmap, 0xe067, 0x00); + regmap_write(lt8713sx->regmap, 0xe06b, 0x00); + regmap_write(lt8713sx->regmap, 0xe06c, 0x00); + regmap_write(lt8713sx->regmap, 0xe060, 0x01); + msleep(50); + regmap_write(lt8713sx->regmap, 0xe060, 0x00); +} + +static int lt8713sx_write_data(struct lt8713sx *lt8713sx, const u8 *data, u64 filesize) +{ + int page = 0, num = 0, i = 0, val; + + page = (filesize % LT8713SX_PAGE_SIZE) ? + ((filesize / LT8713SX_PAGE_SIZE) + 1) : (filesize / LT8713SX_PAGE_SIZE); + + dev_dbg(lt8713sx->dev, + "Writing to Sram=%u pages, total size = %llu bytes\n", page, filesize); + + for (num = 0; num < page; num++) { + dev_dbg(lt8713sx->dev, "page[%d]\n", num); + lt8713sx_i2c_to_sram(lt8713sx); + + for (i = 0; i < LT8713SX_PAGE_SIZE; i++) { + if ((num * LT8713SX_PAGE_SIZE + i) < filesize) + val = *(data + (num * LT8713SX_PAGE_SIZE + i)); + else + val = 0xff; + regmap_write(lt8713sx->regmap, 0xe059, val); + } + + lt8713sx_wren(lt8713sx); + lt8713sx_sram_to_flash(lt8713sx); + } + + lt8713sx_wrdi(lt8713sx); + lt8713sx_disable_sram_write(lt8713sx); + + return 0; +} + +static void lt8713sx_main_upgrade_result(struct lt8713sx *lt8713sx) +{ + u32 main_crc_result; + + regmap_read(lt8713sx->regmap, 0xe023, &main_crc_result); + + dev_dbg(lt8713sx->dev, "Main CRC HW: 0x%02X\n", main_crc_result); + dev_dbg(lt8713sx->dev, "Main CRC FW: 0x%02X\n", lt8713sx->main_crc_value); + + if (main_crc_result == lt8713sx->main_crc_value) + dev_info(lt8713sx->dev, "Main Firmware Upgrade Success.\n"); + else + dev_err(lt8713sx->dev, "Main Firmware Upgrade Failed.\n"); +} + +static void lt8713sx_bank_upgrade_result(struct lt8713sx *lt8713sx, u8 banknum) +{ + u32 bank_crc_result; + + regmap_read(lt8713sx->regmap, 0xe023, &bank_crc_result); + + dev_dbg(lt8713sx->dev, "Bank %d CRC Result: 0x%02X\n", banknum, bank_crc_result); + + if (bank_crc_result == lt8713sx->bank_crc_value[banknum]) + dev_info(lt8713sx->dev, "Bank %d Firmware Upgrade Success.\n", banknum); + else + dev_err(lt8713sx->dev, "Bank %d Firmware Upgrade Failed.\n", banknum); +} + +static void lt8713sx_bank_result_check(struct lt8713sx *lt8713sx) +{ + int i; + u64 addr = 0x010000; + + for (i = 0; i < lt8713sx->bank_num; i++) { + lt8713sx_load_bank_fw_to_sram(lt8713sx, addr); + lt8713sx_bank_upgrade_result(lt8713sx, i); + addr += 0x3000; + } +} + +static int lt8713sx_firmware_upgrade(struct lt8713sx *lt8713sx) +{ + int ret; + + lt8713sx_config_parameters(lt8713sx); + + lt8713sx_block_erase(lt8713sx); + + if (lt8713sx->fw->size < SZ_64K) { + ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, SZ_64K); + if (ret < 0) { + dev_err(lt8713sx->dev, "Failed to write firmware data: %d\n", ret); + return ret; + } + } else { + ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, lt8713sx->fw->size); + if (ret < 0) { + dev_err(lt8713sx->dev, "Failed to write firmware data: %d\n", ret); + return ret; + } + } + dev_dbg(lt8713sx->dev, "Write Data done.\n"); + + return 0; +} + +static int lt8713sx_firmware_update(struct lt8713sx *lt8713sx) +{ + int ret = 0; + + guard(mutex)(<8713sx->ocm_lock); + lt8713sx_i2c_enable(lt8713sx); + + ret = lt8713sx_prepare_firmware_data(lt8713sx); + if (ret < 0) { + dev_err(lt8713sx->dev, "Failed to prepare firmware data: %d\n", ret); + goto error; + } + + ret = lt8713sx_firmware_upgrade(lt8713sx); + if (ret < 0) { + dev_err(lt8713sx->dev, "Upgrade failure.\n"); + goto error; + } + + /* Validate CRC */ + lt8713sx_load_main_fw_to_sram(lt8713sx); + lt8713sx_main_upgrade_result(lt8713sx); + lt8713sx_wrdi(lt8713sx); + lt8713sx_fifo_reset(lt8713sx); + lt8713sx_bank_result_check(lt8713sx); + lt8713sx_wrdi(lt8713sx); + +error: + lt8713sx_i2c_disable(lt8713sx); + if (!ret) + lt8713sx_reset(lt8713sx); + + kvfree(lt8713sx->fw_buffer); + lt8713sx->fw_buffer = NULL; + + if (lt8713sx->fw) { + release_firmware(lt8713sx->fw); + lt8713sx->fw = NULL; + } + + return ret; +} + +static void lt8713sx_reset(struct lt8713sx *lt8713sx) +{ + dev_dbg(lt8713sx->dev, "reset bridge.\n"); + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1); + msleep(20); + + gpiod_set_value_cansleep(lt8713sx->reset_gpio, 0); + msleep(20); + + dev_dbg(lt8713sx->dev, "reset done.\n"); +} + +static int lt8713sx_regulator_enable(struct lt8713sx *lt8713sx) +{ + int ret; + + ret = devm_regulator_get_enable(lt8713sx->dev, "vdd"); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to enable vdd regulator\n"); + + usleep_range(1000, 10000); + + ret = devm_regulator_get_enable(lt8713sx->dev, "vcc"); + if (ret < 0) + return dev_err_probe(lt8713sx->dev, ret, "failed to enable vcc regulator\n"); + return 0; +} + +static int lt8713sx_bridge_attach(struct drm_bridge *bridge, + struct drm_encoder *encoder, + enum drm_bridge_attach_flags flags) +{ + struct lt8713sx *lt8713sx = container_of(bridge, struct lt8713sx, bridge); + + return drm_bridge_attach(encoder, + lt8713sx->next_bridge, + bridge, flags); +} + +static int lt8713sx_gpio_init(struct lt8713sx *lt8713sx) +{ + struct device *dev = lt8713sx->dev; + + lt8713sx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(lt8713sx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->reset_gpio), + "failed to acquire reset gpio\n"); + + /* power enable gpio */ + lt8713sx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(lt8713sx->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->enable_gpio), + "failed to acquire enable gpio\n"); + return 0; +} + +static ssize_t lt8713sx_firmware_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct lt8713sx *lt8713sx = dev_get_drvdata(dev); + int ret; + + ret = lt8713sx_firmware_update(lt8713sx); + if (ret < 0) + return ret; + return len; +} + +static DEVICE_ATTR_WO(lt8713sx_firmware); + +static struct attribute *lt8713sx_attrs[] = { + &dev_attr_lt8713sx_firmware.attr, + NULL, +}; + +static const struct attribute_group lt8713sx_attr_group = { + .attrs = lt8713sx_attrs, +}; + +static const struct attribute_group *lt8713sx_attr_groups[] = { + <8713sx_attr_group, + NULL, +}; + +static const struct drm_bridge_funcs lt8713sx_bridge_funcs = { + .attach = lt8713sx_bridge_attach, +}; + +static int lt8713sx_probe(struct i2c_client *client) +{ + struct lt8713sx *lt8713sx; + struct device *dev = &client->dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return dev_err_probe(dev, -ENODEV, "device doesn't support I2C\n"); + + lt8713sx = devm_drm_bridge_alloc(dev, struct lt8713sx, bridge, <8713sx_bridge_funcs); + if (IS_ERR(lt8713sx)) + return PTR_ERR(lt8713sx); + + lt8713sx->dev = dev; + lt8713sx->client = client; + i2c_set_clientdata(client, lt8713sx); + + ret = devm_mutex_init(lt8713sx->dev, <8713sx->ocm_lock); + if (ret) + return ret; + + lt8713sx->regmap = devm_regmap_init_i2c(client, <8713sx_regmap_config); + if (IS_ERR(lt8713sx->regmap)) + return dev_err_probe(dev, PTR_ERR(lt8713sx->regmap), "regmap i2c init failed\n"); + + ret = drm_of_find_panel_or_bridge(lt8713sx->dev->of_node, 1, -1, NULL, + <8713sx->next_bridge); + if (ret < 0) + return ret; + + ret = lt8713sx_gpio_init(lt8713sx); + if (ret < 0) + return ret; + + ret = lt8713sx_regulator_enable(lt8713sx); + if (ret) + return ret; + + lt8713sx_reset(lt8713sx); + + lt8713sx->bridge.funcs = <8713sx_bridge_funcs; + lt8713sx->bridge.of_node = dev->of_node; + lt8713sx->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; + drm_bridge_add(<8713sx->bridge); + + crc8_populate_msb(lt8713sx_crc_table, 0x31); + + return 0; +} + +static void lt8713sx_remove(struct i2c_client *client) +{ + struct lt8713sx *lt8713sx = i2c_get_clientdata(client); + + drm_bridge_remove(<8713sx->bridge); +} + +static struct i2c_device_id lt8713sx_id[] = { + { "lontium,lt8713sx", 0 }, + { /* sentinel */ } +}; + +static const struct of_device_id lt8713sx_match_table[] = { + { .compatible = "lontium,lt8713sx" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lt8713sx_match_table); + +static struct i2c_driver lt8713sx_driver = { + .driver = { + .name = "lt8713sx", + .of_match_table = lt8713sx_match_table, + .dev_groups = lt8713sx_attr_groups, + }, + .probe = lt8713sx_probe, + .remove = lt8713sx_remove, + .id_table = lt8713sx_id, +}; + +module_i2c_driver(lt8713sx_driver); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("lt8713sx drm bridge driver"); +MODULE_AUTHOR("Vishnu Saini <vishnu.saini@oss.qualcomm.com>"); +MODULE_FIRMWARE(FW_FILE); diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index ec632f268644..c3eb437ef1b0 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1988,9 +1988,7 @@ of_find_panel_or_bridge: return 0; err_release_next_bridge: - drm_bridge_put(dsi->bridge.next_bridge); - dsi->bridge.next_bridge = NULL; - + drm_bridge_clear_and_put(&dsi->bridge.next_bridge); if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO)) samsung_dsim_unregister_te_irq(dsi); err_remove_bridge: @@ -2007,8 +2005,7 @@ static int samsung_dsim_host_detach(struct mipi_dsi_host *host, if (pdata->host_ops && pdata->host_ops->detach) pdata->host_ops->detach(dsi, device); - drm_bridge_put(dsi->bridge.next_bridge); - dsi->bridge.next_bridge = NULL; + drm_bridge_clear_and_put(&dsi->bridge.next_bridge); samsung_dsim_unregister_te_irq(dsi); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c index e7bef9150f6a..45b37885d719 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c @@ -379,7 +379,7 @@ enum { struct dw_dp_output_format { u32 bus_format; - u32 color_format; + enum drm_output_color_format color_format; u8 video_mapping; u8 bpc; u8 bpp; @@ -388,15 +388,15 @@ struct dw_dp_output_format { #define to_dw_dp_bridge_state(s) container_of(s, struct dw_dp_bridge_state, base) static const struct dw_dp_output_format dw_dp_output_formats[] = { - { MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_10BIT, 10, 30 }, - { MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_8BIT, 8, 24 }, - { MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCBCR444, DW_DP_YCBCR444_10BIT, 10, 30 }, - { MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCBCR444, DW_DP_YCBCR444_8BIT, 8, 24}, - { MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCBCR422, DW_DP_YCBCR422_10BIT, 10, 20 }, - { MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCBCR422, DW_DP_YCBCR422_8BIT, 8, 16 }, - { MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCBCR420, DW_DP_YCBCR420_10BIT, 10, 15 }, - { MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCBCR420, DW_DP_YCBCR420_8BIT, 8, 12 }, - { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_6BIT, 6, 18 }, + { MEDIA_BUS_FMT_RGB101010_1X30, DRM_OUTPUT_COLOR_FORMAT_RGB444, DW_DP_RGB_10BIT, 10, 30 }, + { MEDIA_BUS_FMT_RGB888_1X24, DRM_OUTPUT_COLOR_FORMAT_RGB444, DW_DP_RGB_8BIT, 8, 24 }, + { MEDIA_BUS_FMT_YUV10_1X30, DRM_OUTPUT_COLOR_FORMAT_YCBCR444, DW_DP_YCBCR444_10BIT, 10, 30 }, + { MEDIA_BUS_FMT_YUV8_1X24, DRM_OUTPUT_COLOR_FORMAT_YCBCR444, DW_DP_YCBCR444_8BIT, 8, 24}, + { MEDIA_BUS_FMT_YUYV10_1X20, DRM_OUTPUT_COLOR_FORMAT_YCBCR422, DW_DP_YCBCR422_10BIT, 10, 20 }, + { MEDIA_BUS_FMT_YUYV8_1X16, DRM_OUTPUT_COLOR_FORMAT_YCBCR422, DW_DP_YCBCR422_8BIT, 8, 16 }, + { MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_OUTPUT_COLOR_FORMAT_YCBCR420, DW_DP_YCBCR420_10BIT, 10, 15 }, + { MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_OUTPUT_COLOR_FORMAT_YCBCR420, DW_DP_YCBCR420_8BIT, 8, 12 }, + { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_OUTPUT_COLOR_FORMAT_RGB444, DW_DP_RGB_6BIT, 6, 18 }, }; static const struct dw_dp_output_format *dw_dp_get_output_format(u32 bus_format) @@ -1091,22 +1091,22 @@ static int dw_dp_send_vsc_sdp(struct dw_dp *dp) sdp.flags = DW_DP_SDP_VERTICAL_INTERVAL; switch (state->color_format) { - case DRM_COLOR_FORMAT_YCBCR444: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: vsc.pixelformat = DP_PIXELFORMAT_YUV444; break; - case DRM_COLOR_FORMAT_YCBCR420: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420: vsc.pixelformat = DP_PIXELFORMAT_YUV420; break; - case DRM_COLOR_FORMAT_YCBCR422: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: vsc.pixelformat = DP_PIXELFORMAT_YUV422; break; - case DRM_COLOR_FORMAT_RGB444: + case DRM_OUTPUT_COLOR_FORMAT_RGB444: default: vsc.pixelformat = DP_PIXELFORMAT_RGB; break; } - if (state->color_format == DRM_COLOR_FORMAT_RGB444) { + if (state->color_format == DRM_OUTPUT_COLOR_FORMAT_RGB444) { vsc.colorimetry = DP_COLORIMETRY_DEFAULT; vsc.dynamic_range = DP_DYNAMIC_RANGE_VESA; } else { @@ -1148,14 +1148,15 @@ static bool dw_dp_video_need_vsc_sdp(struct dw_dp *dp) if (!link->vsc_sdp_supported) return false; - if (state->color_format == DRM_COLOR_FORMAT_YCBCR420) + if (state->color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) return true; return false; } -static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc, - u16 vstart, u16 hstart) +static int dw_dp_video_set_msa(struct dw_dp *dp, + enum drm_output_color_format color_format, + u8 bpc, u16 vstart, u16 hstart) { u16 misc = 0; @@ -1163,16 +1164,16 @@ static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc, misc |= DP_MSA_MISC_COLOR_VSC_SDP; switch (color_format) { - case DRM_COLOR_FORMAT_RGB444: + case DRM_OUTPUT_COLOR_FORMAT_RGB444: misc |= DP_MSA_MISC_COLOR_RGB; break; - case DRM_COLOR_FORMAT_YCBCR444: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: misc |= DP_MSA_MISC_COLOR_YCBCR_444_BT709; break; - case DRM_COLOR_FORMAT_YCBCR422: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: misc |= DP_MSA_MISC_COLOR_YCBCR_422_BT709; break; - case DRM_COLOR_FORMAT_YCBCR420: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420: break; default: return -EINVAL; @@ -1304,9 +1305,9 @@ static int dw_dp_video_enable(struct dw_dp *dp) if (dp->pixel_mode == DW_DP_MP_SINGLE_PIXEL) { if (average_bytes_per_tu < 6) init_threshold = 32; - else if (hblank <= 80 && color_format != DRM_COLOR_FORMAT_YCBCR420) + else if (hblank <= 80 && color_format != DRM_OUTPUT_COLOR_FORMAT_YCBCR420) init_threshold = 12; - else if (hblank <= 40 && color_format == DRM_COLOR_FORMAT_YCBCR420) + else if (hblank <= 40 && color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) init_threshold = 3; else init_threshold = 16; @@ -1318,7 +1319,7 @@ static int dw_dp_video_enable(struct dw_dp *dp) t1 = (4 * 1000 / 9) * link->lanes; break; case 8: - if (color_format == DRM_COLOR_FORMAT_YCBCR422) { + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) { t1 = (1000 / 2) * link->lanes; } else { if (dp->pixel_mode == DW_DP_MP_DUAL_PIXEL) @@ -1328,13 +1329,13 @@ static int dw_dp_video_enable(struct dw_dp *dp) } break; case 10: - if (color_format == DRM_COLOR_FORMAT_YCBCR422) + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) t1 = (2000 / 5) * link->lanes; else t1 = (4000 / 15) * link->lanes; break; case 12: - if (color_format == DRM_COLOR_FORMAT_YCBCR422) { + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) { if (dp->pixel_mode == DW_DP_MP_DUAL_PIXEL) t1 = (1000 / 6) * link->lanes; else @@ -1344,7 +1345,7 @@ static int dw_dp_video_enable(struct dw_dp *dp) } break; case 16: - if (color_format != DRM_COLOR_FORMAT_YCBCR422 && + if (color_format != DRM_OUTPUT_COLOR_FORMAT_YCBCR422 && dp->pixel_mode == DW_DP_MP_DUAL_PIXEL) t1 = (1000 / 6) * link->lanes; else @@ -1354,7 +1355,7 @@ static int dw_dp_video_enable(struct dw_dp *dp) return -EINVAL; } - if (color_format == DRM_COLOR_FORMAT_YCBCR420) + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) t2 = (link->rate / 4) * 1000 / (mode->clock / 2); else t2 = (link->rate / 4) * 1000 / mode->clock; @@ -1574,13 +1575,13 @@ static enum drm_mode_status dw_dp_bridge_mode_valid(struct drm_bridge *bridge, struct dw_dp_link *link = &dp->link; u32 min_bpp; - if (info->color_formats & DRM_COLOR_FORMAT_YCBCR420 && + if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) && link->vsc_sdp_supported && (drm_mode_is_420_only(info, mode) || drm_mode_is_420_also(info, mode))) min_bpp = 12; - else if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) + else if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) min_bpp = 16; - else if (info->color_formats & DRM_COLOR_FORMAT_RGB444) + else if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444)) min_bpp = 18; else min_bpp = 24; @@ -1777,14 +1778,14 @@ static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, if (fmt->bpc > conn_state->max_bpc) continue; - if (!(fmt->color_format & di->color_formats)) + if (!(BIT(fmt->color_format) & di->color_formats)) continue; - if (fmt->color_format == DRM_COLOR_FORMAT_YCBCR420 && + if (fmt->color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420 && !link->vsc_sdp_supported) continue; - if (fmt->color_format != DRM_COLOR_FORMAT_YCBCR420 && + if (fmt->color_format != DRM_OUTPUT_COLOR_FORMAT_YCBCR420 && drm_mode_is_420_only(di, &mode)) continue; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index ee88c0e793b0..0296e110ce65 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -2664,7 +2664,7 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, struct drm_display_mode *mode = &crtc_state->mode; u8 max_bpc = conn_state->max_requested_bpc; bool is_hdmi2_sink = info->hdmi.scdc.supported || - (info->color_formats & DRM_COLOR_FORMAT_YCBCR420); + (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)); u32 *output_fmts; unsigned int i = 0; @@ -2723,36 +2723,36 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; if (max_bpc >= 16 && info->bpc == 16) { - if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) + if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; } if (max_bpc >= 12 && info->bpc >= 12) { - if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) + if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; - if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) + if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; } if (max_bpc >= 10 && info->bpc >= 10) { - if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) + if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; - if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) + if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; } - if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) + if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; - if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) + if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; *num_output_fmts = i; diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index f6736b4457bb..17a885244e1e 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -351,9 +351,9 @@ static u8 sn65dsi83_get_dsi_range(struct sn65dsi83 *ctx, * DSI_CLK = mode clock * bpp / dsi_data_lanes / 2 * the 2 is there because the bus is DDR. */ - return DIV_ROUND_UP(clamp((unsigned int)mode->clock * - mipi_dsi_pixel_format_to_bpp(ctx->dsi->format) / - ctx->dsi->lanes / 2, 40000U, 500000U), 5000U); + return clamp((unsigned int)mode->clock * + mipi_dsi_pixel_format_to_bpp(ctx->dsi->format) / + ctx->dsi->lanes / 2, 40000U, 500000U) / 5000U; } static u8 sn65dsi83_get_dsi_div(struct sn65dsi83 *ctx) @@ -517,6 +517,7 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, struct drm_atomic_state *state) { struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); + const unsigned int dual_factor = ctx->lvds_dual_link ? 2 : 1; const struct drm_bridge_state *bridge_state; const struct drm_crtc_state *crtc_state; const struct drm_display_mode *mode; @@ -653,18 +654,18 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, /* 32 + 1 pixel clock to ensure proper operation */ le16val = cpu_to_le16(32 + 1); regmap_bulk_write(ctx->regmap, REG_VID_CHA_SYNC_DELAY_LOW, &le16val, 2); - le16val = cpu_to_le16(mode->hsync_end - mode->hsync_start); + le16val = cpu_to_le16((mode->hsync_end - mode->hsync_start) / dual_factor); regmap_bulk_write(ctx->regmap, REG_VID_CHA_HSYNC_PULSE_WIDTH_LOW, &le16val, 2); le16val = cpu_to_le16(mode->vsync_end - mode->vsync_start); regmap_bulk_write(ctx->regmap, REG_VID_CHA_VSYNC_PULSE_WIDTH_LOW, &le16val, 2); regmap_write(ctx->regmap, REG_VID_CHA_HORIZONTAL_BACK_PORCH, - mode->htotal - mode->hsync_end); + (mode->htotal - mode->hsync_end) / dual_factor); regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_BACK_PORCH, mode->vtotal - mode->vsync_end); regmap_write(ctx->regmap, REG_VID_CHA_HORIZONTAL_FRONT_PORCH, - mode->hsync_start - mode->hdisplay); + (mode->hsync_start - mode->hdisplay) / dual_factor); regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_FRONT_PORCH, mode->vsync_start - mode->vdisplay); regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN, 0x00); diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c index 0497c7ecbc7a..32d40414adb9 100644 --- a/drivers/gpu/drm/bridge/waveshare-dsi.c +++ b/drivers/gpu/drm/bridge/waveshare-dsi.c @@ -66,11 +66,13 @@ static int ws_bridge_attach_dsi(struct ws_bridge *ws) dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->lanes = drm_of_get_data_lanes_count_ep(dev->of_node, 0, 0, 1, 4); - if (dsi->lanes < 0) { + ret = drm_of_get_data_lanes_count_ep(dev->of_node, 0, 0, 1, 4); + if (ret < 0) { dev_warn(dev, "Invalid or missing DSI lane count %d, falling back to 2 lanes\n", - dsi->lanes); + ret); dsi->lanes = 2; /* Old DT backward compatibility */ + } else { + dsi->lanes = ret; } ret = devm_mipi_dsi_attach(dev, dsi); diff --git a/drivers/gpu/drm/ci/arm64.config b/drivers/gpu/drm/ci/arm64.config index ea0e30737c4d..563a69669a7b 100644 --- a/drivers/gpu/drm/ci/arm64.config +++ b/drivers/gpu/drm/ci/arm64.config @@ -83,6 +83,7 @@ CONFIG_SC_DISPCC_7180=y CONFIG_SC_GPUCC_7180=y CONFIG_SM_GPUCC_8350=y CONFIG_QCOM_SPMI_ADC5=y +CONFIG_QCOM_SPMI_VADC=y CONFIG_DRM_PARADE_PS8640=y CONFIG_DRM_LONTIUM_LT9611UXC=y CONFIG_PHY_QCOM_USB_HS=y @@ -208,3 +209,8 @@ CONFIG_ARM_TEGRA_DEVFREQ=y CONFIG_TEGRA_SOCTHERM=y CONFIG_DRM_TEGRA_DEBUG=y CONFIG_PWM_TEGRA=y + +# For Rockchip rk3588 +CONFIG_DRM_PANTHOR=m +CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY=y +CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX=y diff --git a/drivers/gpu/drm/ci/build.sh b/drivers/gpu/drm/ci/build.sh index ac5e7ed195cf..d00d549cbd9c 100644 --- a/drivers/gpu/drm/ci/build.sh +++ b/drivers/gpu/drm/ci/build.sh @@ -3,9 +3,6 @@ set -ex -# Clean up stale rebases that GitLab might not have removed when reusing a checkout dir -rm -rf .git/rebase-apply - . .gitlab-ci/container/container_pre_build.sh # libssl-dev was uninstalled because it was considered an ephemeral package @@ -19,6 +16,7 @@ if [[ "$KERNEL_ARCH" = "arm64" ]]; then GCC_ARCH="aarch64-linux-gnu" DEBIAN_ARCH="arm64" DEVICE_TREES="arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dtb" @@ -61,25 +59,24 @@ export PATH=$NEWPATH:$PATH git config --global user.email "fdo@example.com" git config --global user.name "freedesktop.org CI" -git config --global pull.rebase true # cleanup git state on the worker -rm -rf .git/rebase-merge +rm -rf .git/rebase-merge .git/rebase-apply # Try to merge fixes from target repo if [ "$(git ls-remote --exit-code --heads ${UPSTREAM_REPO} ${TARGET_BRANCH}-external-fixes)" ]; then - git pull ${UPSTREAM_REPO} ${TARGET_BRANCH}-external-fixes + git pull --no-rebase ${UPSTREAM_REPO} ${TARGET_BRANCH}-external-fixes fi # Try to merge fixes from local repo if this isn't a merge request # otherwise try merging the fixes from the merge target if [ -z "$CI_MERGE_REQUEST_PROJECT_PATH" ]; then if [ "$(git ls-remote --exit-code --heads origin ${TARGET_BRANCH}-external-fixes)" ]; then - git pull origin ${TARGET_BRANCH}-external-fixes + git pull --no-rebase origin ${TARGET_BRANCH}-external-fixes fi else if [ "$(git ls-remote --exit-code --heads ${CI_MERGE_REQUEST_PROJECT_URL} ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}-external-fixes)" ]; then - git pull ${CI_MERGE_REQUEST_PROJECT_URL} ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}-external-fixes + git pull --no-rebase ${CI_MERGE_REQUEST_PROJECT_URL} ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}-external-fixes fi fi diff --git a/drivers/gpu/drm/ci/build.yml b/drivers/gpu/drm/ci/build.yml index af27ff5de369..efbcaae49807 100644 --- a/drivers/gpu/drm/ci/build.yml +++ b/drivers/gpu/drm/ci/build.yml @@ -1,6 +1,6 @@ .build: extends: - - .container+build-rules + - .build-rules stage: build-only artifacts: paths: @@ -133,6 +133,10 @@ debian-arm32-asan: rules: - when: never +debian-x86_64-msan: + rules: + - when: never + debian-arm64: rules: - when: never @@ -153,7 +157,7 @@ debian-arm64-ubsan: rules: - when: never -debian-build-testing: +debian-build-x86_64: rules: - when: never @@ -177,31 +181,31 @@ debian-release: rules: - when: never -debian-s390x: +debian-riscv64: rules: - when: never -debian-testing: +debian-s390x: rules: - when: never -debian-testing-asan: +debian-vulkan: rules: - when: never -debian-testing-msan: +debian-x86_32: rules: - when: never -debian-testing-ubsan: +debian-x86_64: rules: - when: never -debian-vulkan: +debian-x86_64-asan: rules: - when: never -debian-x86_32: +debian-x86_64-ubsan: rules: - when: never diff --git a/drivers/gpu/drm/ci/container.yml b/drivers/gpu/drm/ci/container.yml index 5f90508578a3..ce6007a45a07 100644 --- a/drivers/gpu/drm/ci/container.yml +++ b/drivers/gpu/drm/ci/container.yml @@ -5,21 +5,29 @@ debian/x86_64_build-base: variables: - EXTRA_LOCAL_PACKAGES: "libcairo-dev libdw-dev libjson-c-dev libkmod2 libkmod-dev libpciaccess-dev libproc2-dev libudev-dev libunwind-dev python3-docutils bc python3-ply libssl-dev bc" + EXTRA_LOCAL_PACKAGES: "libcairo-dev libdw-dev libjson-c-dev libkmod-dev libpciaccess-dev libproc2-dev libudev-dev libunwind-dev python3-docutils bc python3-ply libssl-dev bc" + +debian/arm64_build: + variables: + EXTRA_LOCAL_PACKAGES: "libcairo-dev libdw-dev libjson-c-dev libproc2-dev libkmod-dev libpciaccess-dev libudev-dev libunwind-dev python3-docutils libssl-dev crossbuild-essential-armhf libkmod-dev:armhf libproc2-dev:armhf libunwind-dev:armhf libdw-dev:armhf libpixman-1-dev:armhf libcairo-dev:armhf libudev-dev:armhf libjson-c-dev:armhf" debian/x86_64_test-gl: variables: - EXTRA_LOCAL_PACKAGES: "jq libasound2 libcairo2 libdw1 libglib2.0-0 libjson-c5 libkmod-dev libkmod2 libgles2 libproc2-dev" + EXTRA_LOCAL_PACKAGES: "jq libasound2t64 libcairo2 libdw1t64 libglib2.0-0t64 libjson-c5 libkmod2 libgles2 libdrm-nouveau2 libdrm-amdgpu1" -debian/arm64_build: +debian/arm64_test-gl: variables: - EXTRA_LOCAL_PACKAGES: "libcairo-dev libdw-dev libjson-c-dev libproc2-dev libkmod2 libkmod-dev libpciaccess-dev libudev-dev libunwind-dev python3-docutils libssl-dev crossbuild-essential-armhf libkmod-dev:armhf libproc2-dev:armhf libunwind-dev:armhf libdw-dev:armhf libpixman-1-dev:armhf libcairo-dev:armhf libudev-dev:armhf libjson-c-dev:armhf" + EXTRA_LOCAL_PACKAGES: "jq libasound2t64 libcairo2 libdw1t64 libglib2.0-0t64 libjson-c5 libkmod2 libgles2 libdrm-nouveau2 libdrm-amdgpu1" -.kernel+rootfs: +debian/arm32_test-gl: variables: - EXTRA_LOCAL_PACKAGES: "jq libasound2 libcairo2 libdw1 libglib2.0-0 libjson-c5" + EXTRA_LOCAL_PACKAGES: "jq libasound2t64 libcairo2 libdw1t64 libglib2.0-0t64 libjson-c5 libkmod2 libgles2 libdrm-nouveau2 libdrm-amdgpu1 libunwind8" # Disable container jobs that we won't use +alpine/x86_64_build: + rules: + - when: never + debian/arm64_test-vk: rules: - when: never @@ -28,6 +36,10 @@ debian/baremetal_arm32_test-gl: rules: - when: never +debian/baremetal_arm64_test-gl: + rules: + - when: never + debian/baremetal_arm64_test-vk: rules: - when: never @@ -36,6 +48,10 @@ debian/ppc64el_build: rules: - when: never +debian/riscv64_build: + rules: + - when: never + debian/s390x_build: rules: - when: never diff --git a/drivers/gpu/drm/ci/gitlab-ci.yml b/drivers/gpu/drm/ci/gitlab-ci.yml index 56638814bb28..56088c5393cd 100644 --- a/drivers/gpu/drm/ci/gitlab-ci.yml +++ b/drivers/gpu/drm/ci/gitlab-ci.yml @@ -1,6 +1,6 @@ variables: DRM_CI_PROJECT_PATH: &drm-ci-project-path mesa/mesa - DRM_CI_COMMIT_SHA: &drm-ci-commit-sha 02337aec715c25dae7ff2479d986f831c77fe536 + DRM_CI_COMMIT_SHA: &drm-ci-commit-sha 25881c701a56233dd8fc7f92db6884a73949d63d UPSTREAM_REPO: https://gitlab.freedesktop.org/drm/kernel.git TARGET_BRANCH: drm-next @@ -11,7 +11,7 @@ variables: DEQP_RUNNER_GIT_TAG: v0.20.0 FDO_UPSTREAM_REPO: helen.fornazier/linux # The repo where the git-archive daily runs - MESA_TEMPLATES_COMMIT: &ci-templates-commit c6aeb16f86e32525fa630fb99c66c4f3e62fc3cb + MESA_TEMPLATES_COMMIT: &ci-templates-commit aec7a6ce7bb38902c70641526f6611e27141784a DRM_CI_PROJECT_URL: https://gitlab.freedesktop.org/${DRM_CI_PROJECT_PATH} CI_PRE_CLONE_SCRIPT: |- set -o xtrace @@ -30,6 +30,8 @@ variables: S3_GITCACHE_BUCKET: git-cache # Bucket for the pipeline artifacts pushed to S3 S3_ARTIFACTS_BUCKET: artifacts + # Base path used for various artifacts + S3_BASE_PATH: "${S3_HOST}/${S3_KERNEL_BUCKET}" # per-pipeline artifact storage on MinIO PIPELINE_ARTIFACTS_BASE: ${S3_HOST}/${S3_ARTIFACTS_BUCKET}/${CI_PROJECT_PATH}/${CI_PIPELINE_ID} # per-job artifact storage on MinIO @@ -44,6 +46,8 @@ variables: ARTIFACTS_BASE_URL: https://${CI_PROJECT_ROOT_NAMESPACE}.${CI_PAGES_DOMAIN}/-/${CI_PROJECT_NAME}/-/jobs/${CI_JOB_ID}/artifacts # Python scripts for structured logger PYTHONPATH: "$PYTHONPATH:$CI_PROJECT_DIR/install" + # Mesa-specific variables that shouldn't be forwarded to DUTs and crosvm + CI_EXCLUDE_ENV_VAR_REGEX: 'SCRIPTS_DIR|RESULTS_DIR' default: @@ -84,10 +88,11 @@ include: - project: *drm-ci-project-path ref: *drm-ci-commit-sha file: + - '/.gitlab-ci/bare-metal/gitlab-ci.yml' - '/.gitlab-ci/build/gitlab-ci.yml' - '/.gitlab-ci/container/gitlab-ci.yml' - '/.gitlab-ci/farm-rules.yml' - - '/.gitlab-ci/lava/lava-gitlab-ci.yml' + - '/.gitlab-ci/lava/gitlab-ci.yml' - '/.gitlab-ci/test-source-dep.yml' - '/.gitlab-ci/test/gitlab-ci.yml' - '/src/amd/ci/gitlab-ci-inc.yml' @@ -131,6 +136,7 @@ stages: - meson - msm - panfrost + - panthor - powervr - rockchip - software-driver @@ -147,10 +153,10 @@ stages: - if: &is-merge-attempt $GITLAB_USER_LOGIN == "marge-bot" && $CI_PIPELINE_SOURCE == "merge_request_event" # post-merge pipeline - if: &is-post-merge $GITLAB_USER_LOGIN == "marge-bot" && $CI_PIPELINE_SOURCE == "push" - # Pre-merge pipeline - - if: &is-pre-merge $CI_PIPELINE_SOURCE == "merge_request_event" + # Pre-merge pipeline (because merge pipelines are already caught above) + - if: &is-merge-request $CI_PIPELINE_SOURCE == "merge_request_event" # Push to a branch on a fork - - if: &is-fork-push $CI_PIPELINE_SOURCE == "push" + - if: &is-push-to-fork $CI_PIPELINE_SOURCE == "push" # nightly pipeline - if: &is-scheduled-pipeline $CI_PIPELINE_SOURCE == "schedule" # pipeline for direct pushes that bypassed the CI @@ -160,17 +166,59 @@ stages: # Rules applied to every job in the pipeline .common-rules: rules: - - if: *is-fork-push + - if: *is-push-to-fork when: manual - .never-post-merge-rules: rules: - if: *is-post-merge when: never -.container+build-rules: +# Note: make sure the branches in this list are the same as in +# `.build-only-delayed-rules` below. +.container-rules: + rules: + - !reference [.common-rules, rules] + # Run when re-enabling a disabled farm, but not when disabling it + - !reference [.disable-farm-mr-rules, rules] + # Never run immediately after merging, as we just ran everything + - !reference [.never-post-merge-rules, rules] + # Only rebuild containers in merge pipelines if any tags have been + # changed, else we'll just use the already-built containers + - if: *is-merge-attempt + changes: &image_tags_path + - drivers/gpu/drm/ci/image-tags.yml + when: on_success + # Skip everything for pre-merge and merge pipelines which don't change + # anything in the build; we only do this for marge-bot and not user + # pipelines in a MR, because we might still need to run it to copy the + # container into the user's namespace. + - if: *is-merge-attempt + when: never + # Any MR pipeline which changes image-tags.yml needs to be able to + # rebuild the containers + - if: *is-merge-request + changes: *image_tags_path + when: manual + # ... however for MRs running inside the user namespace, we may need to + # run these jobs to copy the container images from upstream + - if: *is-merge-request + when: manual + # Build everything after someone bypassed the CI + - if: *is-direct-push + when: manual + # Scheduled pipelines reuse already-built containers + - if: *is-scheduled-pipeline + when: never + # Allow building everything in fork pipelines, but build nothing unless + # manually triggered + - when: manual + + +# Note: make sure the branches in this list are the same as in +# `.build-only-delayed-rules` below. +.build-rules: rules: - !reference [.common-rules, rules] # Run when re-enabling a disabled farm, but not when disabling it @@ -181,7 +229,7 @@ stages: - if: *is-merge-attempt when: on_success # Same as above, but for pre-merge pipelines - - if: *is-pre-merge + - if: *is-merge-request when: manual # Build everything after someone bypassed the CI - if: *is-direct-push @@ -197,7 +245,7 @@ stages: # Repeat of the above but with `when: on_success` replaced with # `when: delayed` + `start_in:`, for build-only jobs. # Note: make sure the branches in this list are the same as in -# `.container+build-rules` above. +# `.build-rules` above. .build-only-delayed-rules: rules: - !reference [.common-rules, rules] @@ -210,7 +258,7 @@ stages: when: delayed start_in: &build-delay 5 minutes # Same as above, but for pre-merge pipelines - - if: *is-pre-merge + - if: *is-merge-request when: manual # Build everything after someone bypassed the CI - if: *is-direct-push @@ -237,11 +285,6 @@ stages: - _build/meson-logs/strace -python-artifacts: - variables: - GIT_DEPTH: 10 - - # Git archive make-git-archive: extends: @@ -273,7 +316,7 @@ sanity: tags: - $FDO_RUNNER_JOB_PRIORITY_TAG_X86_64 rules: - - if: *is-pre-merge + - if: *is-merge-request when: on_success - when: never variables: @@ -284,7 +327,6 @@ sanity: - | set -eu image_tags=( - ALPINE_X86_64_LAVA_SSH_TAG CONTAINER_TAG DEBIAN_BASE_TAG DEBIAN_BUILD_TAG @@ -347,3 +389,19 @@ linkcheck-docs: test-docs: rules: - when: never + +.ci-tron-x86_64-test-vk: + rules: + - when: never + +.ci-tron-x86_64-test-gl-manual: + rules: + - when: never + +.ci-tron-arm64-test-gl: + rules: + - when: never + +.ci-tron-x86_64-test-gl: + rules: + - when: never diff --git a/drivers/gpu/drm/ci/igt_runner.sh b/drivers/gpu/drm/ci/igt_runner.sh index b24d4bc53cda..741d30655ab5 100755 --- a/drivers/gpu/drm/ci/igt_runner.sh +++ b/drivers/gpu/drm/ci/igt_runner.sh @@ -1,6 +1,8 @@ -#!/bin/sh +#!/usr/bin/env bash # SPDX-License-Identifier: MIT +. "${SCRIPTS_DIR}/setup-test-env.sh" + set -ex export IGT_FORCE_DRIVER=${DRIVER_NAME} @@ -21,7 +23,7 @@ set -e mkdir -p /lib/modules case "$DRIVER_NAME" in - amdgpu|vkms) + amdgpu|vkms|panthor) # Cannot use HWCI_KERNEL_MODULES as at that point we don't have the module in /lib mv /install/modules/lib/modules/* /lib/modules/. || true modprobe --first-time $DRIVER_NAME diff --git a/drivers/gpu/drm/ci/image-tags.yml b/drivers/gpu/drm/ci/image-tags.yml index 7acc2e2a8eaa..7c43ae22bfd3 100644 --- a/drivers/gpu/drm/ci/image-tags.yml +++ b/drivers/gpu/drm/ci/image-tags.yml @@ -1,18 +1,22 @@ variables: - CONTAINER_TAG: "20250502-mesa-uprev" - DEBIAN_BASE_TAG: "${CONTAINER_TAG}" + CONTAINER_TAG: "20260108-mesa-igt" + + DEBIAN_BUILD_BASE_TAG: "${CONTAINER_TAG}" DEBIAN_BUILD_TAG: "${CONTAINER_TAG}" + DEBIAN_TEST_BASE_TAG: "${CONTAINER_TAG}" DEBIAN_TEST_GL_TAG: "${CONTAINER_TAG}" # default kernel for rootfs before injecting the current kernel tree - KERNEL_TAG: "v6.14-mesa-0bdd" + KERNEL_TAG: "v6.16-mesa-9d85" KERNEL_REPO: "gfx-ci/linux" - PKG_REPO_REV: "95bf62c" - - DEBIAN_PYUTILS_TAG: "${CONTAINER_TAG}" + PKG_REPO_REV: "0d2527f6" + FIRMWARE_TAG: "8fc31b97" + FIRMWARE_REPO: "gfx-ci/firmware" ALPINE_X86_64_BUILD_TAG: "${CONTAINER_TAG}" - ALPINE_X86_64_LAVA_SSH_TAG: "${CONTAINER_TAG}" - CONDITIONAL_BUILD_ANGLE_TAG: 384145a4023315dae658259bee07c43a - CONDITIONAL_BUILD_PIGLIT_TAG: a19e424b8a3f020dbf1b9dd29f220a4f + CONDITIONAL_BUILD_ANGLE_TAG: efd57e99d51361944f87b9466356b0ce + CONDITIONAL_BUILD_CROSVM_TAG: 4079babd375b09761d59eacb25a0598a + CONDITIONAL_BUILD_PIGLIT_TAG: 21ab2c66f54777163dd038dc4cfcfde6 + + CROSVM_TAG: ${CONDITIONAL_BUILD_CROSVM_TAG} diff --git a/drivers/gpu/drm/ci/lava-submit.sh b/drivers/gpu/drm/ci/lava-submit.sh index a295102c3468..405055aa9cc4 100755 --- a/drivers/gpu/drm/ci/lava-submit.sh +++ b/drivers/gpu/drm/ci/lava-submit.sh @@ -3,27 +3,18 @@ # shellcheck disable=SC2086 # we want word splitting # shellcheck disable=SC1091 # paths only become valid at runtime -# If we run in the fork (not from mesa or Marge-bot), reuse mainline kernel and rootfs, if exist. -_check_artifact_path() { - _url="https://${1}/${2}" - if curl -s -o /dev/null -I -L -f --retry 4 --retry-delay 15 "${_url}"; then - echo -n "${_url}" - fi -} +# shellcheck disable=SC1090 +source "${FDO_CI_BASH_HELPERS}" -get_path_to_artifact() { - _mainline_artifact="$(_check_artifact_path ${BASE_SYSTEM_MAINLINE_HOST_PATH} ${1})" - if [ -n "${_mainline_artifact}" ]; then - echo -n "${_mainline_artifact}" - return - fi - _fork_artifact="$(_check_artifact_path ${BASE_SYSTEM_FORK_HOST_PATH} ${1})" - if [ -n "${_fork_artifact}" ]; then - echo -n "${_fork_artifact}" - return - fi +fdo_log_section_start_collapsed prepare_rootfs "Preparing root filesystem" + +set -ex + +# If we run in the fork (not from mesa or Marge-bot), reuse mainline kernel and rootfs, if exist. +ROOTFS_URL="$(fdo_find_s3_path "$LAVA_ROOTFS_PATH")" || +{ set +x - error "Sorry, I couldn't find a viable built path for ${1} in either mainline or a fork." >&2 + fdo_log_section_error "Sorry, I couldn't find a viable built path for ${LAVA_ROOTFS_PATH} in either mainline or a fork." >&2 echo "" >&2 echo "If you're working on CI, this probably means that you're missing a dependency:" >&2 echo "this job ran ahead of the job which was supposed to upload that artifact." >&2 @@ -35,38 +26,51 @@ get_path_to_artifact() { exit 1 } -. "${SCRIPTS_DIR}/setup-test-env.sh" - -section_start prepare_rootfs "Preparing root filesystem" - -set -ex - -ROOTFS_URL="$(get_path_to_artifact lava-rootfs.tar.zst)" -[ $? != 1 ] || exit 1 - rm -rf results -mkdir -p results/job-rootfs-overlay/ +mkdir results -artifacts/ci-common/export-gitlab-job-env-for-dut.sh \ - > results/job-rootfs-overlay/set-job-env-vars.sh -cp artifacts/ci-common/init-*.sh results/job-rootfs-overlay/ -cp "$SCRIPTS_DIR"/setup-test-env.sh results/job-rootfs-overlay/ +fdo_filter_env_vars > dut-env-vars.sh +# Set SCRIPTS_DIR to point to the Mesa install we download for the DUT +echo "export SCRIPTS_DIR='$CI_PROJECT_DIR/install'" >> dut-env-vars.sh -tar zcf job-rootfs-overlay.tar.gz -C results/job-rootfs-overlay/ . -ci-fairy s3cp --token-file "${S3_JWT_FILE}" job-rootfs-overlay.tar.gz "https://${JOB_ROOTFS_OVERLAY_PATH}" +fdo_log_section_end prepare_rootfs # Prepare env vars for upload. -section_switch variables "Environment variables passed through to device:" -cat results/job-rootfs-overlay/set-job-env-vars.sh +fdo_log_section_start_collapsed variables "Environment variables passed through to device:" +cat dut-env-vars.sh +fdo_log_section_end variables -section_switch lava_submit "Submitting job for scheduling" +fdo_log_section_start_collapsed lava_submit "Submitting job for scheduling" touch results/lava.log tail -f results/lava.log & # Ensure that we are printing the commands that are being executed, # making it easier to debug the job in case it fails. set -x -PYTHONPATH=artifacts/ artifacts/lava/lava_job_submitter.py \ + +# List of optional overlays +LAVA_EXTRA_OVERLAYS=() +if [ -n "${LAVA_FIRMWARE:-}" ]; then + for fw in $LAVA_FIRMWARE; do + LAVA_EXTRA_OVERLAYS+=( + - append-overlay + --name=linux-firmware + --url="https://${S3_BASE_PATH}/${FIRMWARE_REPO}/${fw}-${FIRMWARE_TAG}.tar" + --path="/" + --format=tar + ) + done +fi +LAVA_EXTRA_OVERLAYS+=( + - append-overlay \ + --name=kernel-build \ + --url="${FDO_HTTP_CACHE_URI:-}https://${PIPELINE_ARTIFACTS_BASE}/${DEBIAN_ARCH}/kernel-files.tar.zst" \ + --compression=zstd \ + --path="${CI_PROJECT_DIR}" \ + --format=tar \ +) + +lava-job-submitter \ --farm "${FARM}" \ --device-type "${DEVICE_TYPE}" \ --boot-method "${BOOT_METHOD}" \ @@ -75,9 +79,8 @@ PYTHONPATH=artifacts/ artifacts/lava/lava_job_submitter.py \ --pipeline-info "$CI_JOB_NAME: $CI_PIPELINE_URL on $CI_COMMIT_REF_NAME ${CI_NODE_INDEX}/${CI_NODE_TOTAL}" \ --rootfs-url "${ROOTFS_URL}" \ --kernel-url-prefix "https://${PIPELINE_ARTIFACTS_BASE}/${DEBIAN_ARCH}" \ - --kernel-external "${EXTERNAL_KERNEL_TAG}" \ - --first-stage-init artifacts/ci-common/init-stage1.sh \ --dtb-filename "${DTB}" \ + --env-file dut-env-vars.sh \ --jwt-file "${S3_JWT_FILE}" \ --kernel-image-name "${KERNEL_IMAGE_NAME}" \ --kernel-image-type "${KERNEL_IMAGE_TYPE}" \ @@ -86,20 +89,10 @@ PYTHONPATH=artifacts/ artifacts/lava/lava_job_submitter.py \ --mesa-job-name "$CI_JOB_NAME" \ --structured-log-file "results/lava_job_detail.json" \ --ssh-client-image "${LAVA_SSH_CLIENT_IMAGE}" \ + --project-dir "${CI_PROJECT_DIR}" \ --project-name "${CI_PROJECT_NAME}" \ - --starting-section "${CURRENT_SECTION}" \ + --starting-section lava_submit \ --job-submitted-at "${CI_JOB_STARTED_AT}" \ - - append-overlay \ - --name=kernel-build \ - --url="${FDO_HTTP_CACHE_URI:-}https://${PIPELINE_ARTIFACTS_BASE}/${DEBIAN_ARCH}/kernel-files.tar.zst" \ - --compression=zstd \ - --path="${CI_PROJECT_DIR}" \ - --format=tar \ - - append-overlay \ - --name=job-overlay \ - --url="https://${JOB_ROOTFS_OVERLAY_PATH}" \ - --compression=gz \ - --path="/" \ - --format=tar \ + "${LAVA_EXTRA_OVERLAYS[@]}" \ - submit \ >> results/lava.log diff --git a/drivers/gpu/drm/ci/static-checks.yml b/drivers/gpu/drm/ci/static-checks.yml index 13ffa827b7fa..712d3efe99c6 100644 --- a/drivers/gpu/drm/ci/static-checks.yml +++ b/drivers/gpu/drm/ci/static-checks.yml @@ -1,4 +1,5 @@ check-patch: + stage: static-checks extends: - .build - .use-debian/x86_64_build diff --git a/drivers/gpu/drm/ci/test.yml b/drivers/gpu/drm/ci/test.yml index 81147e86bfd0..f6bee5b67931 100644 --- a/drivers/gpu/drm/ci/test.yml +++ b/drivers/gpu/drm/ci/test.yml @@ -7,13 +7,16 @@ .lava-test: extends: - - .container+build-rules + - .build-rules - .allow_failure_lockdep timeout: "1h30m" rules: - !reference [.scheduled_pipeline-rules, rules] - !reference [.collabora-farm-rules, rules] - when: on_success + before_script: + # lava-submit.sh is a part of the archive, unlike Mesa CI + - eval "$S3_JWT_FILE_SCRIPT" script: # Note: Build dir (and thus install) may be dirty due to GIT_STRATEGY - rm -rf install @@ -32,9 +35,7 @@ dependencies: - testing:arm32 needs: - - alpine/x86_64_lava_ssh_client - debian/arm32_test-gl - - python-artifacts - testing:arm32 - igt:arm32 @@ -48,9 +49,7 @@ dependencies: - testing:arm64 needs: - - alpine/x86_64_lava_ssh_client - debian/arm64_test-gl - - python-artifacts - testing:arm64 - igt:arm64 @@ -64,37 +63,10 @@ dependencies: - testing:x86_64 needs: - - alpine/x86_64_lava_ssh_client - debian/x86_64_test-gl - - python-artifacts - testing:x86_64 - igt:x86_64 -.baremetal-igt-arm64: - extends: - - .baremetal-test-arm64-gl - - .use-debian/baremetal_arm64_test-gl - - .allow_failure_lockdep - timeout: "1h30m" - rules: - - !reference [.scheduled_pipeline-rules, rules] - - !reference [.google-freedreno-farm-rules, rules] - - when: on_success - variables: - FDO_CI_CONCURRENT: 10 - HWCI_TEST_SCRIPT: "/install/igt_runner.sh" - S3_ARTIFACT_NAME: "arm64/kernel-files" - BM_KERNEL: https://${PIPELINE_ARTIFACTS_BASE}/arm64/Image.gz - BM_CMDLINE: "ip=dhcp console=ttyMSM0,115200n8 $BM_KERNEL_EXTRA_ARGS root=/dev/nfs rw nfsrootdebug nfsroot=,tcp,nfsvers=4.2 init=/init $BM_KERNELARGS" - FARM: google - needs: - - debian/baremetal_arm64_test-gl - - job: testing:arm64 - artifacts: false - - igt:arm64 - tags: - - $RUNNER_TAG - .software-driver: stage: software-driver extends: @@ -110,6 +82,7 @@ - !reference [default, before_script] - rm -rf install - tar -xf artifacts/install.tar + - mkdir -p /kernel script: - ln -sf $CI_PROJECT_DIR/install /install - mv install/bzImage /kernel/bzImage @@ -127,6 +100,7 @@ DRIVER_NAME: msm BOOT_METHOD: depthcharge KERNEL_IMAGE_TYPE: "" + LAVA_FIRMWARE: qcom-lava msm:sc7180-trogdor-lazor-limozeen: extends: @@ -150,40 +124,43 @@ msm:sc7180-trogdor-kingoftown: msm:apq8016: extends: - - .baremetal-igt-arm64 + - .lava-igt:arm64 stage: msm + parallel: 3 variables: - DEVICE_TYPE: apq8016-sbc-usb-host + BOOT_METHOD: fastboot + DEVICE_TYPE: dragonboard-410c DRIVER_NAME: msm - BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/${DEVICE_TYPE}.dtb + DTB: apq8016-sbc-usb-host + FARM: collabora GPU_VERSION: apq8016 - # disabling unused clocks congests with the MDSS runtime PM trying to - # disable those clocks and causes boot to fail. - # Reproducer: DRM_MSM=y, DRM_I2C_ADV7511=m - BM_KERNEL_EXTRA_ARGS: clk_ignore_unused - RUNNER_TAG: google-freedreno-db410c - script: - - ./install/bare-metal/fastboot.sh || exit $? + KERNEL_IMAGE_NAME: "Image.gz" + KERNEL_IMAGE_TYPE: "" + RUNNER_TAG: mesa-ci-x86-64-lava-dragonboard-410c + LAVA_FIRMWARE: qcom-lava msm:apq8096: extends: - - .baremetal-igt-arm64 + - .lava-igt:arm64 stage: msm + parallel: 3 variables: - DEVICE_TYPE: apq8096-db820c + BOOT_METHOD: fastboot + DEVICE_TYPE: dragonboard-820c DRIVER_NAME: msm - BM_KERNEL_EXTRA_ARGS: maxcpus=2 - BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/${DEVICE_TYPE}.dtb + DTB: apq8096-db820c + FARM: collabora GPU_VERSION: apq8096 - RUNNER_TAG: google-freedreno-db820c - script: - - ./install/bare-metal/fastboot.sh || exit $? + KERNEL_IMAGE_NAME: "Image.gz" + KERNEL_IMAGE_TYPE: "" + RUNNER_TAG: mesa-ci-x86-64-lava-dragonboard-820c + LAVA_FIRMWARE: qcom-lava msm:sm8350-hdk: extends: - .lava-igt:arm64 stage: msm - parallel: 4 + parallel: 2 variables: BOOT_METHOD: fastboot DEVICE_TYPE: sm8350-hdk @@ -194,11 +171,14 @@ msm:sm8350-hdk: KERNEL_IMAGE_NAME: "Image.gz" KERNEL_IMAGE_TYPE: "" RUNNER_TAG: mesa-ci-x86-64-lava-sm8350-hdk + LAVA_FIRMWARE: qcom-lava + LAVA_FASTBOOT_CMD: "set_active a" .rockchip-device: variables: DTB: ${DEVICE_TYPE} BOOT_METHOD: depthcharge + LAVA_FIRMWARE: arm .rockchip-display: stage: rockchip @@ -226,6 +206,19 @@ msm:sm8350-hdk: KERNEL_IMAGE_TYPE: "" RUNNER_TAG: mesa-ci-x86-64-lava-rk3399-gru-kevin +.rk3588: + extends: + - .lava-igt:arm64 + - .rockchip-device + parallel: 2 + variables: + DEVICE_TYPE: rk3588-rock-5b + GPU_VERSION: rk3588 + BOOT_METHOD: u-boot + KERNEL_IMAGE_NAME: Image + KERNEL_IMAGE_TYPE: "image" + RUNNER_TAG: mesa-ci-x86-64-lava-rk3588-rock-5b + rockchip:rk3288: extends: - .rk3288 @@ -246,6 +239,16 @@ panfrost:rk3399: - .rk3399 - .panfrost-gpu +rockchip:rk3588: + extends: + - .rk3588 + - .rockchip-display + +panthor:rk3588: + extends: + - .rk3588 + - .panthor-gpu + .i915: extends: - .lava-igt:x86_64 @@ -255,6 +258,7 @@ panfrost:rk3399: DTB: "" BOOT_METHOD: depthcharge KERNEL_IMAGE_TYPE: "" + LAVA_FIRMWARE: i915 i915:apl: extends: @@ -277,7 +281,7 @@ i915:glk: i915:amly: extends: - .i915 - parallel: 2 + parallel: 3 variables: DEVICE_TYPE: asus-C433TA-AJ0005-rammus GPU_VERSION: amly @@ -304,11 +308,11 @@ i915:whl: i915:cml: extends: - .i915 - parallel: 2 + parallel: 5 variables: - DEVICE_TYPE: asus-C436FA-Flip-hatch + DEVICE_TYPE: acer-chromebox-cxi4-puff GPU_VERSION: cml - RUNNER_TAG: mesa-ci-x86-64-lava-asus-C436FA-Flip-hatch + RUNNER_TAG: mesa-ci-x86-64-lava-acer-chromebox-cxi4-puff i915:tgl: extends: @@ -337,6 +341,7 @@ i915:jsl: DTB: "" BOOT_METHOD: depthcharge KERNEL_IMAGE_TYPE: "" + LAVA_FIRMWARE: amdgpu-lava amdgpu:stoney: extends: @@ -355,6 +360,7 @@ amdgpu:stoney: DTB: ${DEVICE_TYPE} BOOT_METHOD: depthcharge KERNEL_IMAGE_TYPE: "" + LAVA_FIRMWARE: arm .mediatek-display: stage: mediatek @@ -371,6 +377,11 @@ amdgpu:stoney: variables: DRIVER_NAME: panfrost +.panthor-gpu: + stage: panthor + variables: + DRIVER_NAME: panthor + .mt8173: extends: - .mediatek-device diff --git a/drivers/gpu/drm/ci/xfails/amdgpu-stoney-fails.txt b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-fails.txt index f44dbce3151a..442d3bc3d90b 100644 --- a/drivers/gpu/drm/ci/xfails/amdgpu-stoney-fails.txt +++ b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-fails.txt @@ -3,9 +3,10 @@ amdgpu/amd_abm@abm_gradual,Fail amdgpu/amd_abm@backlight_monotonic_abm,Fail amdgpu/amd_abm@backlight_monotonic_basic,Fail amdgpu/amd_abm@dpms_cycle,Fail -amdgpu/amd_assr@assr-links,Fail amdgpu/amd_assr@assr-links-dpms,Fail -amdgpu/amd_mall@static-screen,Crash +amdgpu/amd_assr@assr-links,Fail +amdgpu/amd_basic@cs-gfx-with-IP-GFX,Fail +amdgpu/amd_basic@cs-multi-fence-with-IP-GFX,Fail amdgpu/amd_mode_switch@mode-switch-first-last-pipe-2,Crash amdgpu/amd_plane@mpo-pan-nv12,Fail amdgpu/amd_plane@mpo-pan-p010,Fail @@ -13,11 +14,13 @@ amdgpu/amd_plane@mpo-pan-rgb,Crash amdgpu/amd_plane@mpo-scale-nv12,Fail amdgpu/amd_plane@mpo-scale-p010,Fail amdgpu/amd_plane@mpo-scale-rgb,Crash -amdgpu/amd_plane@mpo-swizzle-toggle,Fail +amdgpu/amd_plane@mpo-swizzle-toggle,Crash amdgpu/amd_uvd_dec@amdgpu_uvd_decode,Fail +core_setmaster@master-drop-set-user,Fail kms_addfb_basic@bad-pitch-65536,Fail kms_addfb_basic@bo-too-small,Fail kms_addfb_basic@too-high,Fail +kms_async_flips@basic-modeset-with-all-modifiers-formats,Crash kms_atomic_transition@plane-all-modeset-transition-internal-panels,Fail kms_atomic_transition@plane-all-transition,Fail kms_atomic_transition@plane-all-transition-nonblocking,Fail @@ -33,8 +36,10 @@ kms_cursor_crc@cursor-sliding-64x64,Fail kms_cursor_edge_walk@64x64-left-edge,Fail kms_flip@flip-vs-modeset-vs-hang,Fail kms_flip@flip-vs-panning-vs-hang,Fail +kms_invalid_mode@int-max-clock,Fail +kms_invalid_mode@overflow-vrefresh,Fail kms_lease@lease-uevent,Fail -kms_plane@pixel-format,Fail kms_plane_cursor@primary,Fail +kms_plane@pixel-format,Fail kms_rotation_crc@primary-rotation-180,Fail perf@i915-ref-count,Fail diff --git a/drivers/gpu/drm/ci/xfails/amdgpu-stoney-flakes.txt b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-flakes.txt index adffb011298a..8b81af104b30 100644 --- a/drivers/gpu/drm/ci/xfails/amdgpu-stoney-flakes.txt +++ b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-flakes.txt @@ -32,3 +32,10 @@ kms_async_flips@async-flip-with-page-flip-events-atomic # IGT Version: 1.29-g33adea9eb # Linux Version: 6.13.0-rc2 kms_async_flips@crc-atomic + +# Board Name: hp-11A-G6-EE-grunt +# Bug Report: https://gitlab.freedesktop.org/drm/amd/-/issues/4406 +# Failure Rate: 20 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_async_flips@alternate-sync-async-flip diff --git a/drivers/gpu/drm/ci/xfails/i915-amly-fails.txt b/drivers/gpu/drm/ci/xfails/i915-amly-fails.txt index 8e2b5504004e..ff0c10626004 100644 --- a/drivers/gpu/drm/ci/xfails/i915-amly-fails.txt +++ b/drivers/gpu/drm/ci/xfails/i915-amly-fails.txt @@ -1,43 +1,18 @@ -core_setmaster_vs_auth,Fail i915_module_load@load,Fail i915_module_load@reload,Fail i915_module_load@reload-no-display,Fail i915_module_load@resize-bar,Fail i915_pm_rpm@gem-execbuf-stress,Timeout i915_pm_rpm@module-reload,Fail -kms_ccs@ccs-on-another-bo-y-tiled-gen12-rc-ccs-cc,Timeout -kms_fb_coherency@memset-crc,Crash -kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling,Fail kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling,Fail -kms_frontbuffer_tracking@fbc-rgb101010-draw-mmap-cpu,Timeout kms_lease@lease-uevent,Fail kms_plane_alpha_blend@alpha-basic,Fail kms_plane_alpha_blend@alpha-opaque-fb,Fail kms_plane_alpha_blend@alpha-transparent-fb,Fail kms_plane_alpha_blend@constant-alpha-max,Fail -kms_plane_scaling@planes-upscale-factor-0-25,Timeout -kms_pm_backlight@brightness-with-dpms,Crash -kms_pm_backlight@fade,Crash -kms_prop_blob@invalid-set-prop-any,Fail -kms_properties@connector-properties-legacy,Timeout +kms_pm_rpm@modeset-stress-extra-wait,Timeout kms_universal_plane@disable-primary-vs-flip,Timeout perf@i915-ref-count,Fail perf_pmu@module-unload,Fail diff --git a/drivers/gpu/drm/ci/xfails/i915-apl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-apl-fails.txt index 7353ab11e940..032f7adeeff2 100644 --- a/drivers/gpu/drm/ci/xfails/i915-apl-fails.txt +++ b/drivers/gpu/drm/ci/xfails/i915-apl-fails.txt @@ -1,29 +1,9 @@ +core_setmaster@master-drop-set-user,Fail i915_module_load@load,Fail i915_module_load@reload,Fail i915_module_load@reload-no-display,Fail i915_module_load@resize-bar,Fail -kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling,Fail +kms_flip@flip-vs-wf_vblank-interruptible,Fail kms_lease@lease-uevent,Fail kms_plane_alpha_blend@alpha-basic,Fail kms_plane_alpha_blend@alpha-opaque-fb,Fail diff --git a/drivers/gpu/drm/ci/xfails/i915-cml-fails.txt b/drivers/gpu/drm/ci/xfails/i915-cml-fails.txt index 6fef7c1e56ea..351cb06228ff 100644 --- a/drivers/gpu/drm/ci/xfails/i915-cml-fails.txt +++ b/drivers/gpu/drm/ci/xfails/i915-cml-fails.txt @@ -1,4 +1,5 @@ -core_setmaster_vs_auth,Fail +api_intel_bb@intel-bb-blit-none,Timeout +core_setmaster@master-drop-set-user,Fail i915_module_load@load,Fail i915_module_load@reload,Fail i915_module_load@reload-no-display,Fail @@ -8,18 +9,15 @@ i915_pipe_stress@stress-xrgb8888-ytiled,Fail i915_pm_rpm@gem-execbuf-stress,Timeout i915_pm_rpm@module-reload,Fail i915_pm_rpm@system-suspend-execbuf,Timeout -kms_ccs@ccs-on-another-bo-y-tiled-gen12-rc-ccs-cc,Timeout -kms_cursor_crc@cursor-suspend,Timeout -kms_fb_coherency@memset-crc,Crash kms_flip@busy-flip,Timeout kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling,Fail +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling,Fail +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling,Fail @@ -31,39 +29,18 @@ kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling,Fail +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail kms_lease@lease-uevent,Fail -kms_pipe_stress@stress-xrgb8888-untiled,Fail -kms_pipe_stress@stress-xrgb8888-ytiled,Fail -kms_plane_alpha_blend@alpha-basic,Fail -kms_plane_alpha_blend@alpha-opaque-fb,Fail -kms_plane_alpha_blend@alpha-transparent-fb,Fail -kms_plane_alpha_blend@constant-alpha-max,Fail -kms_plane_scaling@planes-upscale-factor-0-25,Timeout -kms_pm_backlight@brightness-with-dpms,Crash -kms_pm_backlight@fade,Crash -kms_prop_blob@invalid-set-prop-any,Fail -kms_properties@connector-properties-legacy,Timeout +kms_pm_rpm@basic-rte,Fail kms_psr2_sf@cursor-plane-update-sf,Fail kms_psr2_sf@overlay-plane-update-continuous-sf,Fail kms_psr2_sf@overlay-plane-update-sf-dmg-area,Fail kms_psr2_sf@overlay-primary-update-sf-dmg-area,Fail kms_psr2_sf@plane-move-sf-dmg-area,Fail -kms_psr2_sf@primary-plane-update-sf-dmg-area,Fail kms_psr2_sf@primary-plane-update-sf-dmg-area-big-fb,Fail -kms_psr2_sf@psr2-cursor-plane-update-sf,Fail -kms_psr2_sf@psr2-overlay-plane-update-continuous-sf,Fail -kms_psr2_sf@psr2-overlay-plane-update-sf-dmg-area,Fail -kms_psr2_sf@psr2-overlay-primary-update-sf-dmg-area,Fail -kms_psr2_sf@psr2-plane-move-sf-dmg-area,Fail -kms_psr2_sf@psr2-primary-plane-update-sf-dmg-area,Fail -kms_psr2_sf@psr2-primary-plane-update-sf-dmg-area-big-fb,Fail -kms_psr2_su@page_flip-NV12,Fail -kms_psr2_su@page_flip-P010,Fail -kms_setmode@basic,Fail -kms_universal_plane@disable-primary-vs-flip,Timeout +kms_psr2_sf@primary-plane-update-sf-dmg-area,Fail perf@i915-ref-count,Fail perf_pmu@module-unload,Fail perf_pmu@rc6,Crash diff --git a/drivers/gpu/drm/ci/xfails/i915-cml-flakes.txt b/drivers/gpu/drm/ci/xfails/i915-cml-flakes.txt index 5343cc1c8696..5e5b9901a08e 100644 --- a/drivers/gpu/drm/ci/xfails/i915-cml-flakes.txt +++ b/drivers/gpu/drm/ci/xfails/i915-cml-flakes.txt @@ -32,3 +32,10 @@ kms_async_flips@crc # IGT Version: 1.29-g33adea9eb # Linux Version: 6.13.0-rc2 gen9_exec_parse@unaligned-access + +# Board Name: asus-C436FA-Flip-hatch +# Bug Report: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14625 +# Failure Rate: 100 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +perf_pmu@most-busy-check-all diff --git a/drivers/gpu/drm/ci/xfails/i915-glk-fails.txt b/drivers/gpu/drm/ci/xfails/i915-glk-fails.txt index 8adf5f0a6e80..5d79b65cd354 100644 --- a/drivers/gpu/drm/ci/xfails/i915-glk-fails.txt +++ b/drivers/gpu/drm/ci/xfails/i915-glk-fails.txt @@ -4,41 +4,31 @@ i915_module_load@load,Fail i915_module_load@reload,Fail i915_module_load@reload-no-display,Fail i915_module_load@resize-bar,Fail +kms_dirtyfb@default-dirtyfb-ioctl,Fail kms_dirtyfb@drrs-dirtyfb-ioctl,Fail +kms_dirtyfb@fbc-dirtyfb-ioctl,Fail kms_flip@blocking-wf_vblank,Fail -kms_flip@wf_vblank-ts-check,Fail -kms_flip@wf_vblank-ts-check-interruptible,Fail -kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling,Fail +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling,Fail kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling,Fail -kms_frontbuffer_tracking@fbc-rgb101010-draw-mmap-cpu,Timeout +kms_flip@wf_vblank-ts-check,Fail +kms_flip@wf_vblank-ts-check-interruptible,Fail +kms_frontbuffer_tracking@fbcdrrs-tiling-linear,Fail kms_frontbuffer_tracking@fbc-tiling-linear,Fail kms_lease@lease-uevent,Fail kms_plane_alpha_blend@alpha-opaque-fb,Fail kms_plane_scaling@planes-upscale-factor-0-25,Timeout -kms_pm_backlight@brightness-with-dpms,Crash -kms_pm_backlight@fade,Crash kms_prop_blob@invalid-set-prop-any,Fail kms_properties@connector-properties-legacy,Timeout kms_rotation_crc@multiplane-rotation,Fail -kms_rotation_crc@multiplane-rotation-cropping-top,Fail kms_universal_plane@disable-primary-vs-flip,Timeout perf@non-zero-reason,Timeout sysfs_heartbeat_interval@long,Timeout diff --git a/drivers/gpu/drm/ci/xfails/i915-jsl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-jsl-fails.txt index 57453e340040..9ad246917598 100644 --- a/drivers/gpu/drm/ci/xfails/i915-jsl-fails.txt +++ b/drivers/gpu/drm/ci/xfails/i915-jsl-fails.txt @@ -1,45 +1,24 @@ +core_setmaster@master-drop-set-root,Fail drm_fdinfo@busy-check-all,Fail i915_module_load@load,Fail i915_module_load@reload,Fail i915_module_load@reload-no-display,Fail i915_module_load@resize-bar,Fail i915_pm_rpm@gem-execbuf-stress,Timeout +i915_pm_rpm@module-reload,Fail kms_flip@dpms-off-confusion,Fail -kms_flip@nonexisting-fb,Fail -kms_flip@single-buffer-flip-vs-dpms-off-vs-modeset,Fail -kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-downscaling,UnexpectedImprovement(Skip) -kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling,Fail +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling,Fail kms_lease@lease-uevent,Fail kms_pm_rpm@modeset-stress-extra-wait,Timeout -kms_rotation_crc@bad-pixel-format,Fail kms_rotation_crc@multiplane-rotation,Fail -kms_rotation_crc@multiplane-rotation-cropping-bottom,Fail -kms_rotation_crc@multiplane-rotation-cropping-top,Fail perf@i915-ref-count,Fail perf_pmu@module-unload,Fail -perf_pmu@most-busy-idle-check-all,Fail perf_pmu@rc6,Crash -prime_busy@before-wait,Fail sysfs_heartbeat_interval@long,Timeout sysfs_heartbeat_interval@off,Timeout sysfs_preempt_timeout@off,Timeout diff --git a/drivers/gpu/drm/ci/xfails/i915-kbl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-kbl-fails.txt index 117098bc95d9..f37302331516 100644 --- a/drivers/gpu/drm/ci/xfails/i915-kbl-fails.txt +++ b/drivers/gpu/drm/ci/xfails/i915-kbl-fails.txt @@ -1,11 +1,12 @@ +core_setmaster@master-drop-set-user,Fail i915_module_load@load,Fail i915_module_load@reload,Fail i915_module_load@reload-no-display,Fail i915_module_load@resize-bar,Fail i915_pm_rpm@gem-execbuf-stress,Timeout kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling,Fail +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-upscaling,Fail @@ -17,6 +18,8 @@ perf@i915-ref-count,Fail perf_pmu@busy-accuracy-50,Fail perf_pmu@module-unload,Fail perf_pmu@rc6,Crash +prime_busy@after-wait,Fail +prime_busy@before,Fail sysfs_heartbeat_interval@long,Timeout sysfs_heartbeat_interval@off,Timeout sysfs_preempt_timeout@off,Timeout diff --git a/drivers/gpu/drm/ci/xfails/i915-tgl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-tgl-fails.txt index 462c050a8b2d..102c4b3eef4d 100644 --- a/drivers/gpu/drm/ci/xfails/i915-tgl-fails.txt +++ b/drivers/gpu/drm/ci/xfails/i915-tgl-fails.txt @@ -1,14 +1,14 @@ api_intel_allocator@reopen,Timeout api_intel_bb@destroy-bb,Timeout core_hotunplug@hotrebind-lateclose,Timeout +core_setmaster@master-drop-set-user,Fail +drm_read@short-buffer-block,Timeout dumb_buffer@map-valid,Timeout i915_module_load@load,Fail i915_module_load@reload,Fail i915_module_load@reload-no-display,Fail i915_module_load@resize-bar,Fail -i915_pm_rpm@gem-execbuf-stress,Timeout i915_pm_rps@engine-order,Timeout -i915_pm_rps@waitboost,Fail kms_lease@lease-uevent,Fail kms_rotation_crc@multiplane-rotation,Fail perf@i915-ref-count,Fail @@ -17,7 +17,6 @@ perf_pmu@enable-race,Timeout perf_pmu@module-unload,Fail perf_pmu@rc6,Crash perf_pmu@semaphore-wait-idle,Timeout -prime_busy@before,Fail prime_mmap@test_refcounting,Timeout sriov_basic@enable-vfs-bind-unbind-each-numvfs-all,Timeout syncobj_basic@illegal-fd-to-handle,Timeout diff --git a/drivers/gpu/drm/ci/xfails/i915-tgl-flakes.txt b/drivers/gpu/drm/ci/xfails/i915-tgl-flakes.txt new file mode 100644 index 000000000000..9738006e3759 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-tgl-flakes.txt @@ -0,0 +1,6 @@ +# Board Name: acer-cp514-2h-1130g7-volteer +# Bug Report: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14624 +# Failure Rate: 100 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +perf@gen12-unprivileged-single-ctx-counters diff --git a/drivers/gpu/drm/ci/xfails/i915-whl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-whl-fails.txt index 0f167cfd503c..3bb5496036d8 100644 --- a/drivers/gpu/drm/ci/xfails/i915-whl-fails.txt +++ b/drivers/gpu/drm/ci/xfails/i915-whl-fails.txt @@ -6,17 +6,17 @@ i915_module_load@resize-bar,Fail i915_pm_rpm@gem-execbuf-stress,Timeout i915_pm_rpm@module-reload,Fail i915_pm_rpm@system-suspend-execbuf,Timeout -kms_ccs@ccs-on-another-bo-y-tiled-gen12-rc-ccs-cc,Timeout -kms_cursor_crc@cursor-suspend,Timeout +kms_dirtyfb@default-dirtyfb-ioctl,Fail +kms_dirtyfb@fbc-dirtyfb-ioctl,Fail kms_fb_coherency@memset-crc,Crash kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling,Fail kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling,Fail +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling,Fail +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling,Fail kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling,Fail @@ -26,10 +26,9 @@ kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling,Fail -kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling,Fail kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling,Fail -kms_frontbuffer_tracking@fbc-rgb101010-draw-mmap-cpu,Timeout +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling,Fail kms_frontbuffer_tracking@fbc-tiling-linear,Fail kms_lease@lease-uevent,Fail kms_plane_alpha_blend@alpha-basic,Fail @@ -37,8 +36,6 @@ kms_plane_alpha_blend@alpha-opaque-fb,Fail kms_plane_alpha_blend@alpha-transparent-fb,Fail kms_plane_alpha_blend@constant-alpha-max,Fail kms_plane_scaling@planes-upscale-factor-0-25,Timeout -kms_pm_backlight@brightness-with-dpms,Crash -kms_pm_backlight@fade,Crash kms_prop_blob@invalid-set-prop-any,Fail kms_properties@connector-properties-legacy,Timeout kms_universal_plane@disable-primary-vs-flip,Timeout diff --git a/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt index 592d7d69e6fc..31b8a0b27e13 100644 --- a/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt +++ b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt @@ -1,7 +1,8 @@ +core_setmaster@master-drop-set-root,Fail +core_setmaster@master-drop-set-shared-fd,Fail +core_setmaster@master-drop-set-user,Fail kms_3d,Fail -kms_bw@connected-linear-tiling-1-displays-1920x1080p,Fail kms_bw@connected-linear-tiling-1-displays-2560x1440p,Fail -kms_bw@connected-linear-tiling-1-displays-3840x2160p,Fail kms_bw@connected-linear-tiling-2-displays-1920x1080p,Fail kms_bw@connected-linear-tiling-2-displays-2160x1440p,Fail kms_bw@connected-linear-tiling-2-displays-2560x1440p,Fail @@ -14,9 +15,7 @@ kms_bw@linear-tiling-2-displays-1920x1080p,Fail kms_bw@linear-tiling-2-displays-2160x1440p,Fail kms_bw@linear-tiling-2-displays-2560x1440p,Fail kms_bw@linear-tiling-2-displays-3840x2160p,Fail -kms_color@invalid-gamma-lut-sizes,Fail kms_cursor_legacy@cursor-vs-flip-atomic,Fail -kms_cursor_legacy@cursor-vs-flip-legacy,Fail kms_cursor_legacy@flip-vs-cursor-atomic,Fail kms_cursor_legacy@flip-vs-cursor-legacy,Fail kms_cursor_legacy@flip-vs-cursor-toggle,Fail @@ -24,9 +23,9 @@ kms_cursor_legacy@flip-vs-cursor-varying-size,Fail kms_flip@basic-plain-flip,Fail kms_flip@dpms-off-confusion,Fail kms_flip@dpms-off-confusion-interruptible,Fail -kms_flip@flip-vs-absolute-wf_vblank,Fail -kms_flip@flip-vs-absolute-wf_vblank-interruptible,Fail kms_flip@flip-vs-blocking-wf-vblank,Fail +kms_flip@flip-vs-dpms-on-nop,Fail +kms_flip@flip-vs-dpms-on-nop-interruptible,Fail kms_flip@flip-vs-expired-vblank,Fail kms_flip@flip-vs-expired-vblank-interruptible,Fail kms_flip@flip-vs-modeset-vs-hang,Fail @@ -40,5 +39,4 @@ kms_flip@plain-flip-fb-recreate-interruptible,Fail kms_flip@plain-flip-interruptible,Fail kms_flip@plain-flip-ts-check,Fail kms_flip@plain-flip-ts-check-interruptible,Fail -kms_invalid_mode@overflow-vrefresh,Fail kms_lease@lease-uevent,Fail diff --git a/drivers/gpu/drm/ci/xfails/mediatek-mt8173-flakes.txt b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-flakes.txt index 443596d9e662..6f4d41e16e19 100644 --- a/drivers/gpu/drm/ci/xfails/mediatek-mt8173-flakes.txt +++ b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-flakes.txt @@ -53,3 +53,38 @@ kms_bw@connected-linear-tiling-1-displays-2160x1440p # IGT Version: 1.30-g04bedb923 # Linux Version: 6.14.0-rc4 kms_flip@flip-vs-wf_vblank-interruptible + +# Board Name: mt8173-elm-hana +# Bug Report: https://lore.kernel.org/dri-devel/7559dd68-c9dd-410f-880f-201679e2dd54@collabora.com/T/#u +# Failure Rate: 20 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_flip@blocking-wf_vblank + +# Board Name: mt8173-elm-hana +# Bug Report: https://lore.kernel.org/dri-devel/953ab66e-9dda-4003-9b98-9e0d81e18a1f@collabora.com/T/#u +# Failure Rate: 40 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_flip@busy-flip + +# Board Name: mt8173-elm-hana +# Bug Report: https://lore.kernel.org/dri-devel/6ab7f59c-042e-4c7a-baaa-86c7d47ab308@collabora.com/ +# Failure Rate: 40 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_flip@flip-vs-rmfb + +# Board Name: mt8173-elm-hana +# Bug Report: https://lore.kernel.org/dri-devel/30b3f8b0-3409-4329-bb60-b6287e1a439d@collabora.com/ +# Failure Rate: 60 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_atomic_transition@plane-all-modeset-transition-internal-panels + +# Board Name: mt8173-elm-hana +# Bug Report: https://lore.kernel.org/dri-devel/4c9e1501-52cd-4659-a894-8a2ac58c3996@collabora.com/ +# Failure Rate: 40 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_flip@absolute-wf_vblank diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt index 72c469021b66..4546363447ff 100644 --- a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt +++ b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt @@ -1,5 +1,9 @@ +core_setmaster@master-drop-set-user,Fail kms_3d,Fail +kms_cursor_legacy@forked-move,Fail +kms_cursor_legacy@single-bo,Fail kms_force_connector_basic@force-edid,Fail kms_hdmi_inject@inject-4k,Fail kms_lease@lease-uevent,Fail +msm/msm_mapping@memptrs,Fail msm/msm_mapping@ring,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt b/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt index 2893f98a6b97..0d5cb2a87e67 100644 --- a/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt +++ b/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt @@ -1,2 +1,4 @@ +core_setmaster@master-drop-set-user,Fail kms_3d,Fail kms_lease@lease-uevent,Fail +msm/msm_mapping@memptrs,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-kingoftown-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-kingoftown-fails.txt index ae36a39619c6..2daf4ab879a9 100644 --- a/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-kingoftown-fails.txt +++ b/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-kingoftown-fails.txt @@ -1,3 +1,4 @@ +core_setmaster@master-drop-set-user,Fail kms_color@ctm-0-25,Fail kms_color@ctm-0-50,Fail kms_color@ctm-0-75,Fail @@ -14,8 +15,8 @@ kms_flip@flip-vs-modeset-vs-hang,Fail kms_flip@flip-vs-panning-vs-hang,Fail kms_lease@lease-uevent,Fail kms_pipe_crc_basic@compare-crc-sanitycheck-nv12,Fail -kms_plane@pixel-format,Fail -kms_plane@pixel-format-source-clamping,Fail kms_plane_alpha_blend@alpha-7efc,Fail kms_plane_alpha_blend@coverage-7efc,Fail kms_plane_alpha_blend@coverage-vs-premult-vs-constant,Fail +kms_plane@pixel-format,Fail +kms_plane@pixel-format-source-clamping,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-lazor-limozeen-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-lazor-limozeen-fails.txt index ae36a39619c6..2daf4ab879a9 100644 --- a/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-lazor-limozeen-fails.txt +++ b/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-lazor-limozeen-fails.txt @@ -1,3 +1,4 @@ +core_setmaster@master-drop-set-user,Fail kms_color@ctm-0-25,Fail kms_color@ctm-0-50,Fail kms_color@ctm-0-75,Fail @@ -14,8 +15,8 @@ kms_flip@flip-vs-modeset-vs-hang,Fail kms_flip@flip-vs-panning-vs-hang,Fail kms_lease@lease-uevent,Fail kms_pipe_crc_basic@compare-crc-sanitycheck-nv12,Fail -kms_plane@pixel-format,Fail -kms_plane@pixel-format-source-clamping,Fail kms_plane_alpha_blend@alpha-7efc,Fail kms_plane_alpha_blend@coverage-7efc,Fail kms_plane_alpha_blend@coverage-vs-premult-vs-constant,Fail +kms_plane@pixel-format,Fail +kms_plane@pixel-format-source-clamping,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sm8350-hdk-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sm8350-hdk-fails.txt index 8d26b23133aa..f387c73193c6 100644 --- a/drivers/gpu/drm/ci/xfails/msm-sm8350-hdk-fails.txt +++ b/drivers/gpu/drm/ci/xfails/msm-sm8350-hdk-fails.txt @@ -1,3 +1,4 @@ +core_setmaster@master-drop-set-user,Fail kms_3d,Fail kms_cursor_legacy@forked-bo,Fail kms_cursor_legacy@forked-move,Fail diff --git a/drivers/gpu/drm/ci/xfails/panfrost-mt8183-fails.txt b/drivers/gpu/drm/ci/xfails/panfrost-mt8183-fails.txt index abd1ccb71561..cc5f7fe98dd7 100644 --- a/drivers/gpu/drm/ci/xfails/panfrost-mt8183-fails.txt +++ b/drivers/gpu/drm/ci/xfails/panfrost-mt8183-fails.txt @@ -1,2 +1,3 @@ +core_setmaster@master-drop-set-user,Fail panfrost/panfrost_prime@gem-prime-import,Fail panfrost/panfrost_submit@pan-submit-error-bad-requirements,Fail diff --git a/drivers/gpu/drm/ci/xfails/panfrost-rk3288-fails.txt b/drivers/gpu/drm/ci/xfails/panfrost-rk3288-fails.txt index 8330b934602a..8d0b7682e640 100644 --- a/drivers/gpu/drm/ci/xfails/panfrost-rk3288-fails.txt +++ b/drivers/gpu/drm/ci/xfails/panfrost-rk3288-fails.txt @@ -1,2 +1,3 @@ +core_setmaster@master-drop-set-user,Crash panfrost/panfrost_prime@gem-prime-import,Crash panfrost/panfrost_submit@pan-submit-error-bad-requirements,Crash diff --git a/drivers/gpu/drm/ci/xfails/panfrost-rk3399-fails.txt b/drivers/gpu/drm/ci/xfails/panfrost-rk3399-fails.txt index abd1ccb71561..cc5f7fe98dd7 100644 --- a/drivers/gpu/drm/ci/xfails/panfrost-rk3399-fails.txt +++ b/drivers/gpu/drm/ci/xfails/panfrost-rk3399-fails.txt @@ -1,2 +1,3 @@ +core_setmaster@master-drop-set-user,Fail panfrost/panfrost_prime@gem-prime-import,Fail panfrost/panfrost_submit@pan-submit-error-bad-requirements,Fail diff --git a/drivers/gpu/drm/ci/xfails/panthor-rk3588-fails.txt b/drivers/gpu/drm/ci/xfails/panthor-rk3588-fails.txt new file mode 100644 index 000000000000..7407bd0128d4 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/panthor-rk3588-fails.txt @@ -0,0 +1,5 @@ +core_hotunplug@hotreplug,Fail +core_hotunplug@hotreplug-lateclose,Fail +core_hotunplug@hotunplug-rescan,Fail +core_hotunplug@unplug-rescan,Fail +core_setmaster@master-drop-set-user,Fail diff --git a/drivers/gpu/drm/ci/xfails/panthor-rk3588-skips.txt b/drivers/gpu/drm/ci/xfails/panthor-rk3588-skips.txt new file mode 100644 index 000000000000..b724cf04e3b3 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/panthor-rk3588-skips.txt @@ -0,0 +1,20 @@ +# Skip driver specific tests +^amdgpu.* +^msm.* +nouveau_.* +^v3d.* +^vc4.* +^vmwgfx* + +# Skip intel specific tests +gem_.* +i915_.* +tools_test.* +kms_dp_link_training.* + +# Panfrost is not a KMS driver, so skip the KMS tests +kms_.* + +# Skip display functionality tests for GPU-only drivers +dumb_buffer.* +fbdev.* diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3288-fails.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-fails.txt index 61122ea7f008..526f582038d3 100644 --- a/drivers/gpu/drm/ci/xfails/rockchip-rk3288-fails.txt +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-fails.txt @@ -2,8 +2,17 @@ core_setmaster@master-drop-set-root,Crash core_setmaster@master-drop-set-shared-fd,Crash core_setmaster@master-drop-set-user,Crash core_setmaster_vs_auth,Crash -dumb_buffer@create-clear,Crash fbdev@pan,Crash -kms_cursor_legacy@basic-flip-before-cursor-legacy,Fail -kms_prop_blob@invalid-set-prop,Crash +kms_cursor_crc@cursor-dpms,Crash +kms_cursor_crc@cursor-sliding-32x32,Crash +kms_cursor_legacy@basic-flip-before-cursor-atomic,Crash +kms_cursor_legacy@cursor-vs-flip-atomic,Crash +kms_flip@basic-flip-vs-wf_vblank,Crash +kms_flip@flip-vs-panning-vs-hang,Crash +kms_flip@plain-flip-fb-recreate-interruptible,Crash +kms_pipe_crc_basic@read-crc-frame-sequence,Crash +kms_plane_cursor@overlay,Crash +kms_plane_cursor@viewport,Crash kms_prop_blob@invalid-set-prop-any,Crash +kms_prop_blob@invalid-set-prop,Crash +kms_properties@get_properties-sanity-non-atomic,Fail diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3288-flakes.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-flakes.txt index cd0b27d8b636..34f43e95a51b 100644 --- a/drivers/gpu/drm/ci/xfails/rockchip-rk3288-flakes.txt +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-flakes.txt @@ -32,3 +32,24 @@ kms_flip@plain-flip-ts-check # IGT Version: 1.28-ga73311079 # Linux Version: 6.11.0-rc2 kms_cursor_crc@cursor-alpha-opaque + +# Board Name: rk3288-veyron-jaq +# Bug Report: https://lore.kernel.org/dri-devel/acfd5838-d861-4dd9-97c3-99fffc9bfa04@collabora.com/T/#u +# Failure Rate: 40 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_flip@flip-vs-absolute-wf_vblank + +# Board Name: rk3288-veyron-jaq +# Bug Report: https://lore.kernel.org/dri-devel/81e13fcc-d916-4eb8-91cd-f74f64f53f72@collabora.com/T/#u +# Failure Rate: 40 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_flip@flip-vs-dpms-on-nop-interruptible + +# Board Name: rk3288-veyron-jaq +# Bug Report: https://lore.kernel.org/dri-devel/10c5abab-c8fe-4eff-8eed-009038436b49@collabora.com/T/#u +# Failure Rate: 20 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_flip@plain-flip-fb-recreate diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3399-fails.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-fails.txt index 45dd8d493f6e..5110ce2dc56e 100644 --- a/drivers/gpu/drm/ci/xfails/rockchip-rk3399-fails.txt +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-fails.txt @@ -1,9 +1,9 @@ -dumb_buffer@create-clear,Crash +core_setmaster@master-drop-set-user,Fail kms_atomic_transition@modeset-transition,Fail kms_atomic_transition@modeset-transition-fencing,Fail kms_atomic_transition@plane-toggle-modeset-transition,Fail -kms_color@gamma,Fail -kms_color@legacy-gamma,Fail +kms_cursor_crc@async-cursor-crc-framebuffer-change,Fail +kms_cursor_crc@async-cursor-crc-position-change,Fail kms_cursor_crc@cursor-alpha-opaque,Fail kms_cursor_crc@cursor-alpha-transparent,Fail kms_cursor_crc@cursor-dpms,Fail @@ -41,8 +41,11 @@ kms_cursor_legacy@flip-vs-cursor-crc-atomic,Fail kms_cursor_legacy@flip-vs-cursor-crc-legacy,Fail kms_cursor_legacy@flip-vs-cursor-legacy,Fail kms_cursor_legacy@long-nonblocking-modeset-vs-cursor-atomic,Fail +kms_flip@basic-flip-vs-dpms,Fail kms_flip@basic-flip-vs-wf_vblank,Fail kms_flip@blocking-wf_vblank,Fail +kms_flip@flip-vs-dpms-on-nop,Fail +kms_flip@flip-vs-dpms-on-nop-interruptible,Fail kms_flip@flip-vs-modeset-vs-hang,Fail kms_flip@flip-vs-panning,Fail kms_flip@flip-vs-panning-interruptible,Fail @@ -51,7 +54,6 @@ kms_flip@modeset-vs-vblank-race,Fail kms_flip@plain-flip-fb-recreate,Fail kms_flip@plain-flip-fb-recreate-interruptible,Fail kms_flip@plain-flip-ts-check,Fail -kms_flip@plain-flip-ts-check-interruptible,Fail kms_flip@wf_vblank-ts-check-interruptible,Fail kms_invalid_mode@int-max-clock,Fail kms_invalid_mode@overflow-vrefresh,Fail @@ -64,11 +66,11 @@ kms_pipe_crc_basic@nonblocking-crc,Fail kms_pipe_crc_basic@nonblocking-crc-frame-sequence,Fail kms_pipe_crc_basic@read-crc,Fail kms_pipe_crc_basic@read-crc-frame-sequence,Fail +kms_plane_cursor@primary,Fail kms_plane@pixel-format,Fail kms_plane@pixel-format-source-clamping,Fail kms_plane@plane-panning-bottom-right,Fail kms_plane@plane-panning-top-left,Fail kms_plane@plane-position-covered,Fail kms_plane@plane-position-hole,Fail -kms_plane_cursor@primary,Fail kms_universal_plane@universal-plane-functional,Fail diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3399-flakes.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-flakes.txt index b467991d4094..918dd33c2092 100644 --- a/drivers/gpu/drm/ci/xfails/rockchip-rk3399-flakes.txt +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-flakes.txt @@ -144,3 +144,38 @@ kms_bw@connected-linear-tiling-1-displays-2160x1440p # IGT Version: 1.30-g04bedb923 # Linux Version: 6.14.0-rc4 kms_bw@linear-tiling-1-displays-3840x2160p + +# Board Name: rk3399-gru-kevin +# Bug Report: https://lore.kernel.org/dri-devel/7b6e2e3b-2ea2-4cd7-92a5-68d23a63e426@collabora.com/T/#u +# Failure Rate: 60 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_color@gamma + +# Board Name: rk3399-gru-kevin +# Bug Report: https://lore.kernel.org/dri-devel/e29c2892-08f2-423f-af72-e4d8b207fd1c@collabora.com/T/#u +# Failure Rate: 60 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_bw@connected-linear-tiling-1-displays-3840x2160p + +# Board Name: rk3399-gru-kevin +# Bug Report: https://lore.kernel.org/dri-devel/ad9ce463-c803-4502-ae89-381a6b6eb19f@collabora.com/T/#u +# Failure Rate: 40 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_color@legacy-gamma + +# Board Name: rk3399-gru-kevin +# Bug Report: https://lore.kernel.org/dri-devel/59724e10-12ca-4481-b0e4-72d7b6e4dae0@collabora.com/T/#u +# Failure Rate: 40 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_flip@plain-flip-ts-check-interruptible + +# Board Name: rk3399-gru-kevin +# Bug Report: https://lore.kernel.org/dri-devel/d790db5f-a1ba-47f9-9af0-d3287ef3274c@collabora.com/T/#u +# Failure Rate: 20 +# IGT Version: 2.1-g26ddb59c1 +# Linux Version: 6.16.0-rc2 +kms_bw@linear-tiling-2-displays-3840x2160p diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3588-fails.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3588-fails.txt new file mode 100644 index 000000000000..799c3b04c3f2 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3588-fails.txt @@ -0,0 +1,9 @@ +core_setmaster@master-drop-set-user,Fail +kms_3d,Fail +kms_cursor_legacy@forked-bo,Fail +kms_cursor_legacy@forked-move,Fail +kms_cursor_legacy@single-bo,Fail +kms_cursor_legacy@single-move,Fail +kms_cursor_legacy@torture-bo,Fail +kms_cursor_legacy@torture-move,Fail +kms_lease@lease-uevent,Fail diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3588-skips.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3588-skips.txt new file mode 100644 index 000000000000..a165fccd8a93 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3588-skips.txt @@ -0,0 +1,14 @@ +# Skip driver specific tests +^amdgpu.* +^msm.* +nouveau_.* +^panfrost.* +^v3d.* +^vc4.* +^vmwgfx* + +# Skip intel specific tests +gem_.* +i915_.* +tools_test.* +kms_dp_link_training.* diff --git a/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt index 9749ddb75121..62cb7b94f3fd 100644 --- a/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt +++ b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt @@ -2,11 +2,6 @@ kms_addfb_basic@bad-pitch-65536,Fail kms_addfb_basic@bo-too-small,Fail kms_addfb_basic@size-max,Fail kms_addfb_basic@too-high,Fail -kms_atomic_transition@plane-primary-toggle-with-vblank-wait,Fail -kms_bw@connected-linear-tiling-1-displays-1920x1080p,Fail -kms_bw@connected-linear-tiling-1-displays-2160x1440p,Fail -kms_bw@connected-linear-tiling-1-displays-2560x1440p,Fail -kms_bw@connected-linear-tiling-1-displays-3840x2160p,Fail kms_bw@connected-linear-tiling-10-displays-1920x1080p,Fail kms_bw@connected-linear-tiling-10-displays-2160x1440p,Fail kms_bw@connected-linear-tiling-10-displays-2560x1440p,Fail @@ -35,6 +30,10 @@ kms_bw@connected-linear-tiling-16-displays-1920x1080p,Fail kms_bw@connected-linear-tiling-16-displays-2160x1440p,Fail kms_bw@connected-linear-tiling-16-displays-2560x1440p,Fail kms_bw@connected-linear-tiling-16-displays-3840x2160p,Fail +kms_bw@connected-linear-tiling-1-displays-1920x1080p,Fail +kms_bw@connected-linear-tiling-1-displays-2160x1440p,Fail +kms_bw@connected-linear-tiling-1-displays-2560x1440p,Fail +kms_bw@connected-linear-tiling-1-displays-3840x2160p,Fail kms_bw@connected-linear-tiling-2-displays-1920x1080p,Fail kms_bw@connected-linear-tiling-2-displays-2160x1440p,Fail kms_bw@connected-linear-tiling-2-displays-2560x1440p,Fail @@ -67,10 +66,6 @@ kms_bw@connected-linear-tiling-9-displays-1920x1080p,Fail kms_bw@connected-linear-tiling-9-displays-2160x1440p,Fail kms_bw@connected-linear-tiling-9-displays-2560x1440p,Fail kms_bw@connected-linear-tiling-9-displays-3840x2160p,Fail -kms_bw@linear-tiling-1-displays-1920x1080p,Fail -kms_bw@linear-tiling-1-displays-2160x1440p,Fail -kms_bw@linear-tiling-1-displays-2560x1440p,Fail -kms_bw@linear-tiling-1-displays-3840x2160p,Fail kms_bw@linear-tiling-10-displays-1920x1080p,Fail kms_bw@linear-tiling-10-displays-2160x1440p,Fail kms_bw@linear-tiling-10-displays-2560x1440p,Fail @@ -99,6 +94,10 @@ kms_bw@linear-tiling-16-displays-1920x1080p,Fail kms_bw@linear-tiling-16-displays-2160x1440p,Fail kms_bw@linear-tiling-16-displays-2560x1440p,Fail kms_bw@linear-tiling-16-displays-3840x2160p,Fail +kms_bw@linear-tiling-1-displays-1920x1080p,Fail +kms_bw@linear-tiling-1-displays-2160x1440p,Fail +kms_bw@linear-tiling-1-displays-2560x1440p,Fail +kms_bw@linear-tiling-1-displays-3840x2160p,Fail kms_bw@linear-tiling-2-displays-1920x1080p,Fail kms_bw@linear-tiling-2-displays-2160x1440p,Fail kms_bw@linear-tiling-2-displays-2560x1440p,Fail @@ -131,60 +130,11 @@ kms_bw@linear-tiling-9-displays-1920x1080p,Fail kms_bw@linear-tiling-9-displays-2160x1440p,Fail kms_bw@linear-tiling-9-displays-2560x1440p,Fail kms_bw@linear-tiling-9-displays-3840x2160p,Fail -kms_flip@absolute-wf_vblank,Fail -kms_flip@absolute-wf_vblank-interruptible,Fail -kms_flip@basic-flip-vs-wf_vblank,Fail -kms_flip@blocking-absolute-wf_vblank,Fail -kms_flip@blocking-absolute-wf_vblank-interruptible,Fail -kms_flip@blocking-wf_vblank,Fail -kms_flip@busy-flip,Fail -kms_flip@dpms-vs-vblank-race,Fail -kms_flip@dpms-vs-vblank-race-interruptible,Fail -kms_flip@flip-vs-absolute-wf_vblank,Fail -kms_flip@flip-vs-absolute-wf_vblank-interruptible,Fail -kms_flip@flip-vs-blocking-wf-vblank,Fail -kms_flip@flip-vs-expired-vblank,Fail -kms_flip@flip-vs-expired-vblank-interruptible,Fail kms_flip@flip-vs-modeset-vs-hang,Fail kms_flip@flip-vs-panning-vs-hang,Fail -kms_flip@flip-vs-wf_vblank-interruptible,Fail -kms_flip@modeset-vs-vblank-race,Fail -kms_flip@modeset-vs-vblank-race-interruptible,Fail -kms_flip@plain-flip-fb-recreate,Fail -kms_flip@plain-flip-fb-recreate-interruptible,Fail -kms_flip@plain-flip-ts-check,Fail -kms_flip@plain-flip-ts-check-interruptible,Fail -kms_flip@wf_vblank-ts-check,Fail -kms_flip@wf_vblank-ts-check-interruptible,Fail kms_invalid_mode@int-max-clock,Fail kms_invalid_mode@overflow-vrefresh,Fail -kms_lease@cursor-implicit-plane,Fail kms_lease@lease-uevent,Fail -kms_lease@page-flip-implicit-plane,Fail -kms_lease@setcrtc-implicit-plane,Fail -kms_lease@simple-lease,Fail -kms_sequence@get-busy,Fail -kms_sequence@get-forked,Fail -kms_sequence@get-forked-busy,Fail -kms_sequence@get-idle,Fail -kms_sequence@queue-busy,Fail -kms_sequence@queue-idle,Fail -kms_setmode@basic,Fail -kms_vblank@accuracy-idle,Fail -kms_vblank@crtc-id,Fail -kms_vblank@invalid,Fail -kms_vblank@query-busy,Fail -kms_vblank@query-forked,Fail -kms_vblank@query-forked-busy,Fail -kms_vblank@query-idle,Fail -kms_vblank@ts-continuation-dpms-rpm,Fail kms_vblank@ts-continuation-dpms-suspend,Fail -kms_vblank@ts-continuation-idle,Fail -kms_vblank@ts-continuation-modeset,Fail -kms_vblank@ts-continuation-modeset-rpm,Fail kms_vblank@ts-continuation-suspend,Fail -kms_vblank@wait-busy,Fail -kms_vblank@wait-forked,Fail -kms_vblank@wait-forked-busy,Fail -kms_vblank@wait-idle,Fail perf@i915-ref-count,Fail diff --git a/drivers/gpu/drm/ci/xfails/vkms-none-fails.txt b/drivers/gpu/drm/ci/xfails/vkms-none-fails.txt index 6ebcc7d89fbd..029bd4956e85 100644 --- a/drivers/gpu/drm/ci/xfails/vkms-none-fails.txt +++ b/drivers/gpu/drm/ci/xfails/vkms-none-fails.txt @@ -16,6 +16,8 @@ kms_flip@flip-vs-panning-vs-hang,Fail kms_flip@flip-vs-suspend,Fail kms_flip@flip-vs-suspend-interruptible,Fail kms_lease@lease-uevent,Fail +kms_plane@pixel-format-source-clamping,Timeout +kms_plane@pixel-format,Timeout kms_writeback@writeback-check-output,Fail kms_writeback@writeback-check-output-XRGB2101010,Fail kms_writeback@writeback-fb-id,Fail diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index f686aa5c0ed9..39cc18f78eda 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -789,7 +789,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, struct drm_connector *connector; struct i2c_adapter *ddc = NULL; struct drm_bridge *panel_bridge __free(drm_bridge_put) = NULL; - unsigned int supported_formats = BIT(HDMI_COLORSPACE_RGB); + unsigned int supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444); unsigned int max_bpc = 8; bool support_hdcp = false; int connector_type; @@ -960,7 +960,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, if (bridge_connector->bridge_hdmi) { if (!connector->ycbcr_420_allowed) - supported_formats &= ~BIT(HDMI_COLORSPACE_YUV420); + supported_formats &= ~BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420); bridge_connector->hdmi_funcs = drm_bridge_connector_hdmi_funcs; diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index d8a732f21d3c..8757972e8e24 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -5765,7 +5765,6 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, mgr->conn_base_id = conn_base_id; drm_atomic_private_obj_init(dev, &mgr->base, - NULL, &drm_dp_mst_topology_state_funcs); return 0; diff --git a/drivers/gpu/drm/display/drm_dp_tunnel.c b/drivers/gpu/drm/display/drm_dp_tunnel.c index f442430d8de7..6519b4244728 100644 --- a/drivers/gpu/drm/display/drm_dp_tunnel.c +++ b/drivers/gpu/drm/display/drm_dp_tunnel.c @@ -1600,7 +1600,7 @@ static bool init_group(struct drm_dp_tunnel_mgr *mgr, struct drm_dp_tunnel_group group->available_bw = -1; INIT_LIST_HEAD(&group->tunnels); - drm_atomic_private_obj_init(mgr->dev, &group->base, NULL, + drm_atomic_private_obj_init(mgr->dev, &group->base, &tunnel_group_funcs); return true; diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c index a237dc55805d..5cb0b033b171 100644 --- a/drivers/gpu/drm/display/drm_hdmi_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_helper.c @@ -210,7 +210,8 @@ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); */ unsigned long long drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode, - unsigned int bpc, enum hdmi_colorspace fmt) + unsigned int bpc, + enum drm_output_color_format fmt) { unsigned long long clock = mode->clock * 1000ULL; unsigned int vic = drm_match_cea_mode(mode); @@ -222,7 +223,7 @@ drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode, if (vic == 1 && bpc != 8) return 0; - if (fmt == HDMI_COLORSPACE_YUV422) { + if (fmt == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) { /* * HDMI 1.0 Spec, section 6.5 - Pixel Encoding states that * YUV422 sends 24 bits over three channels, with Cb and Cr @@ -248,7 +249,7 @@ drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode, * specifies that YUV420 encoding is carried at a TMDS Character Rate * equal to half the pixel clock rate. */ - if (fmt == HDMI_COLORSPACE_YUV420) + if (fmt == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) clock = clock / 2; if (mode->flags & DRM_MODE_FLAG_DBLCLK) diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c index a1d16762ac7a..9f3b696aceeb 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -326,6 +326,25 @@ void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector, } EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset); +static enum hdmi_colorspace +output_color_format_to_hdmi_colorspace(const struct drm_connector *connector, + enum drm_output_color_format fmt) +{ + switch (fmt) { + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420: + return HDMI_COLORSPACE_YUV420; + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: + return HDMI_COLORSPACE_YUV422; + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: + return HDMI_COLORSPACE_YUV444; + default: + drm_warn(connector->dev, "Unsupported output color format. Defaulting to RGB."); + fallthrough; + case DRM_OUTPUT_COLOR_FORMAT_RGB444: + return HDMI_COLORSPACE_RGB; + } +} + static const struct drm_display_mode * connector_state_get_mode(const struct drm_connector_state *conn_state) { @@ -360,7 +379,7 @@ static bool hdmi_is_limited_range(const struct drm_connector *connector, * i915 just assumes limited range for YCbCr output, so let's * just do the same. */ - if (conn_state->hdmi.output_format != HDMI_COLORSPACE_RGB) + if (conn_state->hdmi.output_format != DRM_OUTPUT_COLOR_FORMAT_RGB444) return true; if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_FULL) @@ -379,7 +398,8 @@ static bool sink_supports_format_bpc(const struct drm_connector *connector, const struct drm_display_info *info, const struct drm_display_mode *mode, - unsigned int format, unsigned int bpc) + enum drm_output_color_format format, + unsigned int bpc) { struct drm_device *dev = connector->dev; u8 vic = drm_match_cea_mode(mode); @@ -400,7 +420,7 @@ sink_supports_format_bpc(const struct drm_connector *connector, } if (!info->is_hdmi && - (format != HDMI_COLORSPACE_RGB || bpc != 8)) { + (format != DRM_OUTPUT_COLOR_FORMAT_RGB444 || bpc != 8)) { drm_dbg_kms(dev, "DVI Monitors require an RGB output at 8 bpc\n"); return false; } @@ -411,13 +431,13 @@ sink_supports_format_bpc(const struct drm_connector *connector, return false; } - if (drm_mode_is_420_only(info, mode) && format != HDMI_COLORSPACE_YUV420) { + if (drm_mode_is_420_only(info, mode) && format != DRM_OUTPUT_COLOR_FORMAT_YCBCR420) { drm_dbg_kms(dev, "Mode can be only supported in YUV420 format.\n"); return false; } switch (format) { - case HDMI_COLORSPACE_RGB: + case DRM_OUTPUT_COLOR_FORMAT_RGB444: drm_dbg_kms(dev, "RGB Format, checking the constraints.\n"); /* @@ -428,7 +448,7 @@ sink_supports_format_bpc(const struct drm_connector *connector, * supported so we can keep things going and light up * the display. */ - if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444)) + if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))) drm_warn(dev, "HDMI Sink doesn't support RGB, something's wrong.\n"); if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) { @@ -445,10 +465,10 @@ sink_supports_format_bpc(const struct drm_connector *connector, return true; - case HDMI_COLORSPACE_YUV420: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420: drm_dbg_kms(dev, "YUV420 format, checking the constraints.\n"); - if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR420)) { + if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))) { drm_dbg_kms(dev, "Sink doesn't support YUV420.\n"); return false; } @@ -477,10 +497,10 @@ sink_supports_format_bpc(const struct drm_connector *connector, return true; - case HDMI_COLORSPACE_YUV422: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: drm_dbg_kms(dev, "YUV422 format, checking the constraints.\n"); - if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) { + if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))) { drm_dbg_kms(dev, "Sink doesn't support YUV422.\n"); return false; } @@ -500,10 +520,10 @@ sink_supports_format_bpc(const struct drm_connector *connector, return true; - case HDMI_COLORSPACE_YUV444: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: drm_dbg_kms(dev, "YUV444 format, checking the constraints.\n"); - if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR444)) { + if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))) { drm_dbg_kms(dev, "Sink doesn't support YUV444.\n"); return false; } @@ -553,7 +573,7 @@ static int hdmi_compute_clock(const struct drm_connector *connector, struct drm_connector_state *conn_state, const struct drm_display_mode *mode, - unsigned int bpc, enum hdmi_colorspace fmt) + unsigned int bpc, enum drm_output_color_format fmt) { enum drm_mode_status status; unsigned long long clock; @@ -575,7 +595,7 @@ static bool hdmi_try_format_bpc(const struct drm_connector *connector, struct drm_connector_state *conn_state, const struct drm_display_mode *mode, - unsigned int bpc, enum hdmi_colorspace fmt) + unsigned int bpc, enum drm_output_color_format fmt) { const struct drm_display_info *info = &connector->display_info; struct drm_device *dev = connector->dev; @@ -611,7 +631,7 @@ static int hdmi_compute_format_bpc(const struct drm_connector *connector, struct drm_connector_state *conn_state, const struct drm_display_mode *mode, - unsigned int max_bpc, enum hdmi_colorspace fmt) + unsigned int max_bpc, enum drm_output_color_format fmt) { struct drm_device *dev = connector->dev; unsigned int bpc; @@ -652,12 +672,12 @@ hdmi_compute_config(const struct drm_connector *connector, int ret; ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc, - HDMI_COLORSPACE_RGB); + DRM_OUTPUT_COLOR_FORMAT_RGB444); if (ret) { if (connector->ycbcr_420_allowed) { ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc, - HDMI_COLORSPACE_YUV420); + DRM_OUTPUT_COLOR_FORMAT_YCBCR420); if (ret) drm_dbg_kms(connector->dev, "YUV420 output format doesn't work.\n"); @@ -691,7 +711,9 @@ static int hdmi_generate_avi_infoframe(const struct drm_connector *connector, if (ret) return ret; - frame->colorspace = conn_state->hdmi.output_format; + frame->colorspace = + output_color_format_to_hdmi_colorspace(connector, + conn_state->hdmi.output_format); /* * FIXME: drm_hdmi_avi_infoframe_quant_range() doesn't handle @@ -889,7 +911,7 @@ drm_hdmi_connector_mode_valid(struct drm_connector *connector, { unsigned long long clock; - clock = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); + clock = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444); if (!clock) return MODE_ERROR; diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 04925166df98..41c57063f3b4 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -475,6 +475,7 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p, drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask); drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask); drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); + drm_printf(p, "\tbackground_color=%llx\n", state->background_color); if (crtc->funcs->atomic_print_state) crtc->funcs->atomic_print_state(p, state); @@ -920,7 +921,6 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, * drm_atomic_private_obj_init - initialize private object * @dev: DRM device this object will be attached to * @obj: private object - * @state: initial private object state * @funcs: pointer to the struct of function pointers that identify the object * type * @@ -932,9 +932,9 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, */ int drm_atomic_private_obj_init(struct drm_device *dev, struct drm_private_obj *obj, - struct drm_private_state *state, const struct drm_private_state_funcs *funcs) { + struct drm_private_state *state; memset(obj, 0, sizeof(*obj)); drm_modeset_lock_init(&obj->lock); @@ -943,22 +943,11 @@ int drm_atomic_private_obj_init(struct drm_device *dev, obj->funcs = funcs; list_add_tail(&obj->head, &dev->mode_config.privobj_list); - /* - * Not all users of drm_atomic_private_obj_init have been - * converted to using &drm_private_obj_funcs.atomic_create_state yet. - * For the time being, let's only call reset if the passed state is - * NULL. Otherwise, we will fallback to the previous behaviour. - */ - if (!state) { - state = obj->funcs->atomic_create_state(obj); - if (IS_ERR(state)) - return PTR_ERR(state); + state = obj->funcs->atomic_create_state(obj); + if (IS_ERR(state)) + return PTR_ERR(state); - obj->state = state; - } else { - obj->state = state; - state->obj = obj; - } + obj->state = state; return 0; } @@ -1587,6 +1576,7 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state, const struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); struct drm_plane *plane; + int ret; WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); @@ -1600,6 +1590,12 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state, if (IS_ERR(plane_state)) return PTR_ERR(plane_state); + + if (plane_state->color_pipeline) { + ret = drm_atomic_add_affected_colorops(state, plane); + if (ret) + return ret; + } } return 0; } diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index bd6faa09f83b..76746ad4a1bb 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -75,6 +75,7 @@ __drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *crtc_state, struct drm_crtc *crtc) { crtc_state->crtc = crtc; + crtc_state->background_color = DRM_ARGB64_PREP(0xffff, 0, 0, 0); } EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_reset); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 87de41fb4459..5bd5bf6661df 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -454,6 +454,8 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, &replaced); state->color_mgmt_changed |= replaced; return ret; + } else if (property == config->background_color_property) { + state->background_color = val; } else if (property == config->prop_out_fence_ptr) { s32 __user *fence_ptr = u64_to_user_ptr(val); @@ -501,6 +503,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val = (state->ctm) ? state->ctm->base.id : 0; else if (property == config->gamma_lut_property) *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; + else if (property == config->background_color_property) + *val = state->background_color; else if (property == config->prop_out_fence_ptr) *val = 0; else if (property == crtc->scaling_filter_property) diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 3b1f5f72885e..1f3af27d2418 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -191,10 +191,6 @@ * plane does not expose the "alpha" property, then this is * assumed to be 1.0 * - * Note that all the property extensions described here apply either to the - * plane or the CRTC (e.g. for the background color, which currently is not - * exposed and assumed to be black). - * * SCALING_FILTER: * Indicates scaling filter to be used for plane scaler * @@ -207,6 +203,25 @@ * * Drivers can set up this property for a plane by calling * drm_plane_create_scaling_filter_property + * + * The property extensions described above all apply to the plane. Drivers + * may also expose the following crtc property extension: + * + * BACKGROUND_COLOR: + * Background color is set up with drm_crtc_attach_background_color_property(), + * and expects a 64-bit ARGB value following DRM_FORMAT_ARGB16161616, as + * generated by the DRM_ARGB64_PREP*() helpers. It controls the color of a + * full-screen layer that exists below all planes. This color will be used + * for pixels not covered by any plane and may also be blended with plane + * contents as allowed by a plane's alpha values. + * The background color defaults to black, and is assumed to be black for + * drivers that do not expose this property. Although background color + * isn't a plane, it is assumed that the color provided here undergoes the + * CRTC degamma/CSC/gamma transformations applied after the planes blending. + * Note that the color value includes an alpha channel, hence non-opaque + * background color values are allowed, but since physically transparent + * monitors do not (yet) exists, the final alpha value may not reach the + * video sink or it may simply ignore it. */ /** @@ -621,3 +636,19 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, return 0; } EXPORT_SYMBOL(drm_plane_create_blend_mode_property); + +/** + * drm_crtc_attach_background_color_property - attach background color property + * @crtc: drm crtc + * + * Attaches the background color property to @crtc. The property defaults to + * solid black and will accept 64-bit ARGB values in the format generated by + * DRM_ARGB64_PREP*() helpers. + */ +void drm_crtc_attach_background_color_property(struct drm_crtc *crtc) +{ + drm_object_attach_property(&crtc->base, + crtc->dev->mode_config.background_color_property, + DRM_ARGB64_PREP(0xffff, 0, 0, 0)); +} +EXPORT_SYMBOL(drm_crtc_attach_background_color_property); diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index f8b0333a0a3b..d6f512b73389 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -304,6 +304,9 @@ EXPORT_SYMBOL(drm_bridge_get); * * This function decrements the bridge's reference count and frees the * object if the reference count drops to zero. + * + * See also drm_bridge_clear_and_put() if you also need to set the pointer + * to NULL */ void drm_bridge_put(struct drm_bridge *bridge) { @@ -313,6 +316,37 @@ void drm_bridge_put(struct drm_bridge *bridge) EXPORT_SYMBOL(drm_bridge_put); /** + * drm_bridge_clear_and_put - Given a bridge pointer, clear the pointer + * then put the bridge + * @bridge_pp: pointer to pointer to a struct drm_bridge; ``bridge_pp`` + * must be non-NULL; if ``*bridge_pp`` is NULL this function + * does nothing + * + * Helper to put a DRM bridge, but only after setting its pointer to + * NULL. Useful when a struct drm_bridge reference must be dropped without + * leaving a use-after-free window where the pointed bridge might have been + * freed while still holding a pointer to it. + * + * For struct ``drm_bridge *some_bridge``, this code:: + * + * drm_bridge_clear_and_put(&some_bridge); + * + * is equivalent to the more complex:: + * + * struct drm_bridge *temp = some_bridge; + * some_bridge = NULL; + * drm_bridge_put(temp); + */ +void drm_bridge_clear_and_put(struct drm_bridge **bridge_pp) +{ + struct drm_bridge *bridge = *bridge_pp; + + *bridge_pp = NULL; + drm_bridge_put(bridge); +} +EXPORT_SYMBOL(drm_bridge_clear_and_put); + +/** * drm_bridge_put_void - wrapper to drm_bridge_put() taking a void pointer * * @data: pointer to @struct drm_bridge, cast to a void pointer @@ -387,7 +421,7 @@ void drm_bridge_add(struct drm_bridge *bridge) if (bridge->ops & DRM_BRIDGE_OP_HDMI) bridge->ycbcr_420_allowed = !!(bridge->supported_formats & - BIT(HDMI_COLORSPACE_YUV420)); + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)); mutex_lock(&bridge_lock); list_add_tail(&bridge->list, &bridge_list); @@ -553,7 +587,6 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, if (drm_bridge_is_atomic(bridge)) drm_atomic_private_obj_init(bridge->dev, &bridge->base, - NULL, &drm_bridge_priv_state_funcs); return 0; @@ -1570,11 +1603,17 @@ EXPORT_SYMBOL(devm_drm_put_bridge); static void drm_bridge_debugfs_show_bridge(struct drm_printer *p, struct drm_bridge *bridge, unsigned int idx, - bool lingering) + bool lingering, + bool scoped) { + unsigned int refcount = kref_read(&bridge->refcount); + + if (scoped) + refcount--; + drm_printf(p, "bridge[%u]: %ps\n", idx, bridge->funcs); - drm_printf(p, "\trefcount: %u%s\n", kref_read(&bridge->refcount), + drm_printf(p, "\trefcount: %u%s\n", refcount, lingering ? " [lingering]" : ""); drm_printf(p, "\ttype: [%d] %s\n", @@ -1608,10 +1647,10 @@ static int allbridges_show(struct seq_file *m, void *data) mutex_lock(&bridge_lock); list_for_each_entry(bridge, &bridge_list, list) - drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false); + drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, false); list_for_each_entry(bridge, &bridge_lingering_list, list) - drm_bridge_debugfs_show_bridge(&p, bridge, idx++, true); + drm_bridge_debugfs_show_bridge(&p, bridge, idx++, true, false); mutex_unlock(&bridge_lock); @@ -1626,7 +1665,7 @@ static int encoder_bridges_show(struct seq_file *m, void *data) unsigned int idx = 0; drm_for_each_bridge_in_chain_scoped(encoder, bridge) - drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false); + drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, true); return 0; } diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c index f421c623b3f0..566816e3c6f0 100644 --- a/drivers/gpu/drm/drm_colorop.c +++ b/drivers/gpu/drm/drm_colorop.c @@ -171,12 +171,8 @@ void drm_colorop_cleanup(struct drm_colorop *colorop) list_del(&colorop->head); config->num_colorop--; - if (colorop->state && colorop->state->data) { - drm_property_blob_put(colorop->state->data); - colorop->state->data = NULL; - } - - kfree(colorop->state); + if (colorop->state) + drm_colorop_atomic_destroy_state(colorop, colorop->state); } EXPORT_SYMBOL(drm_colorop_cleanup); @@ -466,8 +462,6 @@ static void __drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colo if (state->data) drm_property_blob_get(state->data); - - state->bypass = true; } struct drm_colorop_state * @@ -485,9 +479,23 @@ drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop) return state; } +/** + * __drm_atomic_helper_colorop_destroy_state - release colorop state + * @state: colorop state object to release + * + * Releases all resources stored in the colorop state without actually freeing + * the memory of the colorop state. This is useful for drivers that subclass the + * colorop state. + */ +static void __drm_atomic_helper_colorop_destroy_state(struct drm_colorop_state *state) +{ + drm_property_blob_put(state->data); +} + void drm_colorop_atomic_destroy_state(struct drm_colorop *colorop, struct drm_colorop_state *state) { + __drm_atomic_helper_colorop_destroy_state(state); kfree(state); } @@ -538,7 +546,9 @@ static void __drm_colorop_reset(struct drm_colorop *colorop, void drm_colorop_reset(struct drm_colorop *colorop) { - kfree(colorop->state); + if (colorop->state) + drm_colorop_atomic_destroy_state(colorop, colorop->state); + colorop->state = kzalloc_obj(*colorop->state); if (colorop->state) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index e70699c59c43..47dc53c4a738 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -552,7 +552,7 @@ EXPORT_SYMBOL(drmm_connector_init); * @hdmi_funcs: HDMI-related callbacks for this connector * @connector_type: user visible type of the connector * @ddc: optional pointer to the associated ddc adapter - * @supported_formats: Bitmask of @hdmi_colorspace listing supported output formats + * @supported_formats: Bitmask of @drm_output_color_format listing supported output formats * @max_bpc: Maximum bits per char the HDMI connector supports * * Initialises a preallocated HDMI connector. Connectors can be @@ -591,10 +591,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev, connector_type == DRM_MODE_CONNECTOR_HDMIB)) return -EINVAL; - if (!supported_formats || !(supported_formats & BIT(HDMI_COLORSPACE_RGB))) + if (!supported_formats || !(supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))) return -EINVAL; - if (connector->ycbcr_420_allowed != !!(supported_formats & BIT(HDMI_COLORSPACE_YUV420))) + if (connector->ycbcr_420_allowed != !!(supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))) return -EINVAL; if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12)) @@ -1431,10 +1431,10 @@ drm_hdmi_connector_get_broadcast_rgb_name(enum drm_hdmi_broadcast_rgb broadcast_ EXPORT_SYMBOL(drm_hdmi_connector_get_broadcast_rgb_name); static const char * const output_format_str[] = { - [HDMI_COLORSPACE_RGB] = "RGB", - [HDMI_COLORSPACE_YUV420] = "YUV 4:2:0", - [HDMI_COLORSPACE_YUV422] = "YUV 4:2:2", - [HDMI_COLORSPACE_YUV444] = "YUV 4:4:4", + [DRM_OUTPUT_COLOR_FORMAT_RGB444] = "RGB", + [DRM_OUTPUT_COLOR_FORMAT_YCBCR420] = "YUV 4:2:0", + [DRM_OUTPUT_COLOR_FORMAT_YCBCR422] = "YUV 4:2:2", + [DRM_OUTPUT_COLOR_FORMAT_YCBCR444] = "YUV 4:4:4", }; /* @@ -1445,7 +1445,7 @@ static const char * const output_format_str[] = { * valid. */ const char * -drm_hdmi_connector_get_output_format_name(enum hdmi_colorspace fmt) +drm_hdmi_connector_get_output_format_name(enum drm_output_color_format fmt) { if (fmt >= ARRAY_SIZE(output_format_str)) return NULL; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 8d6f721c2c9a..63ead8ba6756 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -340,8 +340,7 @@ static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc * * Inits a new object created as base part of a driver crtc object. Drivers * should use this function instead of drm_crtc_init(), which is only provided * for backwards compatibility with drivers which do not yet support universal - * planes). For really simple hardware which has only 1 plane look at - * drm_simple_display_pipe_init() instead. + * planes). * The &drm_crtc_funcs.destroy hook should call drm_crtc_cleanup() and kfree() * the crtc structure. The crtc structure should not be allocated with * devm_kzalloc(). @@ -424,8 +423,7 @@ static int __drmm_crtc_init_with_planes(struct drm_device *dev, * Inits a new object created as base part of a driver crtc object. Drivers * should use this function instead of drm_crtc_init(), which is only provided * for backwards compatibility with drivers which do not yet support universal - * planes). For really simple hardware which has only 1 plane look at - * drm_simple_display_pipe_init() instead. + * planes). * * Cleanup is automatically handled through registering * drmm_crtc_cleanup() with drmm_add_action(). The crtc structure should diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 6b965c3d3307..985c283cf59f 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -587,7 +587,7 @@ int drm_dev_wedged_event(struct drm_device *dev, unsigned long method, snprintf(event_string, sizeof(event_string), "%s", "WEDGED=unknown"); drm_info(dev, "device wedged, %s\n", method == DRM_WEDGE_RECOVERY_NONE ? - "but recovered through reset" : "needs recovery"); + "but no recovery needed" : "needs recovery"); if (info && (info->comm[0] != '\0') && (info->pid >= 0)) { snprintf(pid_string, sizeof(pid_string), "PID=%u", info->pid); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ff432ac6b569..5f9fcd7d9ce4 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5316,7 +5316,7 @@ static void parse_cta_y420cmdb(struct drm_connector *connector, out: if (map) - info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; + info->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420); *y420cmdb_map = map; } @@ -6092,7 +6092,7 @@ static void parse_cta_y420vdb(struct drm_connector *connector, continue; bitmap_set(hdmi->y420_vdb_modes, vic, 1); - info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; + info->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420); } } @@ -6426,11 +6426,11 @@ static void drm_parse_cea_ext(struct drm_connector *connector, info->cea_rev, edid_ext[1]); /* The existence of a CTA extension should imply RGB support */ - info->color_formats = DRM_COLOR_FORMAT_RGB444; + info->color_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444); if (edid_ext[3] & EDID_CEA_YCRCB444) - info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; + info->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444); if (edid_ext[3] & EDID_CEA_YCRCB422) - info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; + info->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422); if (edid_ext[3] & EDID_BASIC_AUDIO) info->has_audio = true; @@ -6698,7 +6698,7 @@ static void update_display_info(struct drm_connector *connector, if (!drm_edid_is_digital(drm_edid)) goto out; - info->color_formats |= DRM_COLOR_FORMAT_RGB444; + info->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_parse_cea_ext(connector, drm_edid); update_displayid_info(connector, drm_edid); @@ -6752,9 +6752,9 @@ static void update_display_info(struct drm_connector *connector, connector->base.id, connector->name, info->bpc); if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) - info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; + info->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444); if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) - info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; + info->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422); drm_update_mso(connector, drm_edid); @@ -7229,7 +7229,7 @@ static bool is_hdmi2_sink(const struct drm_connector *connector) return true; return connector->display_info.hdmi.scdc.supported || - connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR420; + connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420); } static u8 drm_mode_hdmi_vic(const struct drm_connector *connector, diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index fdf08cae1c5b..0377a5fd402d 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -821,13 +821,14 @@ err: * Takes an array of userspace handles and returns a newly allocated array of * GEM objects. * - * For a single handle lookup, use drm_gem_object_lookup(). + * After a successful lookup GEM objects need to be released using + * drm_gem_object_put() and the array returned in @objs_out must be freed using + * kvfree(). * - * Returns: - * @objs filled in with GEM object pointers. Returned GEM objects need to be - * released with drm_gem_object_put(). -ENOENT is returned on a lookup - * failure. 0 is returned on success. + * For a single handle lookup, use drm_gem_object_lookup(). * + * Return: + * Zero on success or a negative error code. */ int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, int count, struct drm_gem_object ***objs_out) diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index 421c460ac972..abef865c5f2c 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -87,28 +87,6 @@ * A mapping address for each of the framebuffer's buffer object is stored in * struct &drm_shadow_plane_state.map. The mappings are valid while the state * is being used. - * - * Drivers that use struct drm_simple_display_pipe can use - * %DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS to initialize the rsp - * callbacks. Access to shadow-buffer mappings is similar to regular - * atomic_update. - * - * .. code-block:: c - * - * struct drm_simple_display_pipe_funcs driver_pipe_funcs = { - * ..., - * DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, - * }; - * - * void driver_pipe_enable(struct drm_simple_display_pipe *pipe, - * struct drm_crtc_state *crtc_state, - * struct drm_plane_state *plane_state) - * { - * struct drm_shadow_plane_state *shadow_plane_state = - * to_drm_shadow_plane_state(plane_state); - * - * // access shadow buffer via shadow_plane_state->map - * } */ /* diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c index ecb9746f4da8..1c00a71ab3c9 100644 --- a/drivers/gpu/drm/drm_gem_dma_helper.c +++ b/drivers/gpu/drm/drm_gem_dma_helper.c @@ -146,12 +146,13 @@ struct drm_gem_dma_object *drm_gem_dma_create(struct drm_device *drm, return dma_obj; if (dma_obj->map_noncoherent) { - dma_obj->vaddr = dma_alloc_noncoherent(drm->dev, size, + dma_obj->vaddr = dma_alloc_noncoherent(drm_dev_dma_dev(drm), + size, &dma_obj->dma_addr, DMA_TO_DEVICE, GFP_KERNEL | __GFP_NOWARN); } else { - dma_obj->vaddr = dma_alloc_wc(drm->dev, size, + dma_obj->vaddr = dma_alloc_wc(drm_dev_dma_dev(drm), size, &dma_obj->dma_addr, GFP_KERNEL | __GFP_NOWARN); } @@ -236,12 +237,14 @@ void drm_gem_dma_free(struct drm_gem_dma_object *dma_obj) drm_prime_gem_destroy(gem_obj, dma_obj->sgt); } else if (dma_obj->vaddr) { if (dma_obj->map_noncoherent) - dma_free_noncoherent(gem_obj->dev->dev, dma_obj->base.size, + dma_free_noncoherent(drm_dev_dma_dev(gem_obj->dev), + dma_obj->base.size, dma_obj->vaddr, dma_obj->dma_addr, DMA_TO_DEVICE); else - dma_free_wc(gem_obj->dev->dev, dma_obj->base.size, - dma_obj->vaddr, dma_obj->dma_addr); + dma_free_wc(drm_dev_dma_dev(gem_obj->dev), + dma_obj->base.size, dma_obj->vaddr, + dma_obj->dma_addr); } drm_gem_object_release(gem_obj); @@ -432,7 +435,7 @@ struct sg_table *drm_gem_dma_get_sg_table(struct drm_gem_dma_object *dma_obj) if (!sgt) return ERR_PTR(-ENOMEM); - ret = dma_get_sgtable(obj->dev->dev, sgt, dma_obj->vaddr, + ret = dma_get_sgtable(drm_dev_dma_dev(obj->dev), sgt, dma_obj->vaddr, dma_obj->dma_addr, obj->size); if (ret < 0) goto out; @@ -534,17 +537,17 @@ int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct * * the whole buffer. */ vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); - vm_flags_mod(vma, VM_DONTEXPAND, VM_PFNMAP); + vm_flags_mod(vma, VM_DONTDUMP | VM_DONTEXPAND, VM_PFNMAP); if (dma_obj->map_noncoherent) { vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - ret = dma_mmap_pages(dma_obj->base.dev->dev, + ret = dma_mmap_pages(drm_dev_dma_dev(dma_obj->base.dev), vma, vma->vm_end - vma->vm_start, virt_to_page(dma_obj->vaddr)); } else { - ret = dma_mmap_wc(dma_obj->base.dev->dev, vma, dma_obj->vaddr, - dma_obj->dma_addr, + ret = dma_mmap_wc(drm_dev_dma_dev(dma_obj->base.dev), vma, + dma_obj->vaddr, dma_obj->dma_addr, vma->vm_end - vma->vm_start); } if (ret) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 4500deef4127..2062ca607833 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -554,23 +554,27 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, } EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); -static vm_fault_t drm_gem_shmem_try_insert_pfn_pmd(struct vm_fault *vmf, unsigned long pfn) +static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order, + unsigned long pfn) { + if (!order) { + return vmf_insert_pfn(vmf->vma, vmf->address, pfn); #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP - unsigned long paddr = pfn << PAGE_SHIFT; - bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK); - - if (aligned && pmd_none(*vmf->pmd)) { - /* Read-only mapping; split upon write fault */ - pfn &= PMD_MASK >> PAGE_SHIFT; - return vmf_insert_pfn_pmd(vmf, pfn, false); - } + } else if (order == PMD_ORDER) { + unsigned long paddr = pfn << PAGE_SHIFT; + bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK); + + if (aligned && + folio_test_pmd_mappable(page_folio(pfn_to_page(pfn)))) { + pfn &= PMD_MASK >> PAGE_SHIFT; + return vmf_insert_pfn_pmd(vmf, pfn, false); + } #endif - - return 0; + } + return VM_FAULT_FALLBACK; } -static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) +static vm_fault_t drm_gem_shmem_any_fault(struct vm_fault *vmf, unsigned int order) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; @@ -584,6 +588,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) struct folio *folio; unsigned long pfn; + if (order && order != PMD_ORDER) + return VM_FAULT_FALLBACK; + dma_resv_lock(obj->resv, NULL); if (page_offset >= num_pages || drm_WARN_ON_ONCE(dev, !shmem->pages) || @@ -597,11 +604,7 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) pfn = page_to_pfn(page); - if (folio_test_pmd_mappable(folio)) - ret = drm_gem_shmem_try_insert_pfn_pmd(vmf, pfn); - if (ret != VM_FAULT_NOPAGE) - ret = vmf_insert_pfn(vma, vmf->address, pfn); - + ret = try_insert_pfn(vmf, order, pfn); if (ret == VM_FAULT_NOPAGE) folio_mark_accessed(folio); @@ -611,6 +614,11 @@ out: return ret; } +static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) +{ + return drm_gem_shmem_any_fault(vmf, 0); +} + static void drm_gem_shmem_vm_open(struct vm_area_struct *vma) { struct drm_gem_object *obj = vma->vm_private_data; @@ -665,6 +673,9 @@ static vm_fault_t drm_gem_shmem_pfn_mkwrite(struct vm_fault *vmf) const struct vm_operations_struct drm_gem_shmem_vm_ops = { .fault = drm_gem_shmem_fault, +#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP + .huge_fault = drm_gem_shmem_any_fault, +#endif .open = drm_gem_shmem_vm_open, .close = drm_gem_shmem_vm_close, .pfn_mkwrite = drm_gem_shmem_pfn_mkwrite, diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index e6b5b06de148..f3e40d1e6098 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -28,6 +28,7 @@ * IN THE SOFTWARE. */ #include <linux/compat.h> +#include <linux/nospec.h> #include <linux/ratelimit.h> #include <linux/export.h> @@ -374,6 +375,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (nr >= ARRAY_SIZE(drm_compat_ioctls)) return drm_ioctl(filp, cmd, arg); + nr = array_index_nospec(nr, ARRAY_SIZE(drm_compat_ioctls)); fn = drm_compat_ioctls[nr].fn; if (!fn) return drm_ioctl(filp, cmd, arg); diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index 00482227a9cd..9ab6113d74a2 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -14,7 +14,7 @@ #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> -#include <drm/drm_connector.h> +#include <drm/drm_atomic.h> #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -22,12 +22,9 @@ #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem.h> -#include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_modes.h> #include <drm/drm_print.h> -#include <drm/drm_probe_helper.h> #include <drm/drm_rect.h> #include <video/mipi_display.h> @@ -317,94 +314,87 @@ err_msg: } /** - * mipi_dbi_pipe_mode_valid - MIPI DBI mode-valid helper - * @pipe: Simple display pipe + * drm_mipi_dbi_crtc_helper_mode_valid - MIPI DBI mode-valid helper + * @crtc: The CRTC * @mode: The mode to test * * This function validates a given display mode against the MIPI DBI's hardware - * display. Drivers can use this as their &drm_simple_display_pipe_funcs->mode_valid + * display. Drivers can use this as their struct &drm_crtc_helper_funcs.mode_valid * callback. */ -enum drm_mode_status mipi_dbi_pipe_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +enum drm_mode_status drm_mipi_dbi_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(crtc->dev); - return drm_crtc_helper_mode_valid_fixed(&pipe->crtc, mode, &dbidev->mode); + return drm_crtc_helper_mode_valid_fixed(crtc, mode, &dbidev->mode); } -EXPORT_SYMBOL(mipi_dbi_pipe_mode_valid); +EXPORT_SYMBOL(drm_mipi_dbi_crtc_helper_mode_valid); /** - * mipi_dbi_pipe_update - Display pipe update helper - * @pipe: Simple display pipe - * @old_state: Old plane state + * drm_mipi_dbi_plane_helper_atomic_check - MIPI DBI plane check helper + * @plane: Plane to check + * @state: Atomic state * - * This function handles framebuffer flushing and vblank events. Drivers can use - * this as their &drm_simple_display_pipe_funcs->update callback. + * This function performs the default checks on the primary plane + * of a MIPI DBI device. Drivers can use this as their + * struct &drm_crtc_helper_funcs.atomic_check callback. + * + * Returns: + * 0 on success, or a negative errno code otherwise. */ -void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +int drm_mipi_dbi_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) { - struct drm_plane_state *state = pipe->plane.state; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); - struct drm_framebuffer *fb = state->fb; - struct drm_rect rect; - int idx; - - if (!pipe->crtc.state->active) - return; - - if (WARN_ON(!fb)) - return; + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc_state *new_crtc_state = NULL; + int ret; - if (!drm_dev_enter(fb->dev, &idx)) - return; + if (new_plane_state->crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); - if (drm_atomic_helper_damage_merged(old_state, state, &rect)) - mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect, - &shadow_plane_state->fmtcnv_state); + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + else if (!new_plane_state->visible) + return 0; - drm_dev_exit(idx); + return 0; } -EXPORT_SYMBOL(mipi_dbi_pipe_update); +EXPORT_SYMBOL(drm_mipi_dbi_plane_helper_atomic_check); /** - * mipi_dbi_enable_flush - MIPI DBI enable helper - * @dbidev: MIPI DBI device structure - * @crtc_state: CRTC state - * @plane_state: Plane state - * - * Flushes the whole framebuffer and enables the backlight. Drivers can use this - * in their &drm_simple_display_pipe_funcs->enable callback. + * drm_mipi_dbi_plane_helper_atomic_update - Display update helper + * @plane: Plane + * @state: Atomic state * - * Note: Drivers which don't use mipi_dbi_pipe_update() because they have custom - * framebuffer flushing, can't use this function since they both use the same - * flushing code. + * This function handles framebuffer flushing and vblank events. Drivers can use + * this as their struct &drm_plane_helper_funcs.atomic_update callback. */ -void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +void drm_mipi_dbi_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) { + struct drm_plane_state *plane_state = plane->state; struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; - struct drm_rect rect = { - .x1 = 0, - .x2 = fb->width, - .y1 = 0, - .y2 = fb->height, - }; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_rect rect; int idx; - if (!drm_dev_enter(&dbidev->drm, &idx)) + if (!fb) return; - mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect, - &shadow_plane_state->fmtcnv_state); - backlight_enable(dbidev->backlight); - - drm_dev_exit(idx); + if (drm_dev_enter(plane->dev, &idx)) { + if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect)) + mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); + drm_dev_exit(idx); + } } -EXPORT_SYMBOL(mipi_dbi_enable_flush); +EXPORT_SYMBOL(drm_mipi_dbi_plane_helper_atomic_update); static void mipi_dbi_blank(struct mipi_dbi_dev *dbidev) { @@ -432,18 +422,48 @@ static void mipi_dbi_blank(struct mipi_dbi_dev *dbidev) } /** - * mipi_dbi_pipe_disable - MIPI DBI pipe disable helper - * @pipe: Display pipe + * drm_mipi_dbi_crtc_helper_atomic_check - MIPI DBI CRTC check helper + * @crtc: CRTC to check + * @state: Atomic state + * + * This function performs the default checks on the CRTC of a MIPI DBI + * device and ensures that the primary plane as been set up correctly. + * Drivers can use this as their struct &drm_crtc_helper_funcs.atomic_check + * callback. + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int drm_mipi_dbi_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + int ret; + + if (!crtc_state->enable) + goto out; + + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + +out: + return drm_atomic_add_affected_planes(state, crtc); +} +EXPORT_SYMBOL(drm_mipi_dbi_crtc_helper_atomic_check); + +/** + * drm_mipi_dbi_crtc_helper_atomic_disable - MIPI DBI CRTC disable helper + * @crtc: CRTC to disable + * @state: Atomic state * * This function disables backlight if present, if not the display memory is * blanked. The regulator is disabled if in use. Drivers can use this as their - * &drm_simple_display_pipe_funcs->disable callback. + * struct &drm_crtc_helper_funcs.atomic_disable callback. */ -void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe) +void drm_mipi_dbi_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); - - DRM_DEBUG_KMS("\n"); + struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(crtc->dev); if (dbidev->backlight) backlight_disable(dbidev->backlight); @@ -455,110 +475,26 @@ void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe) if (dbidev->io_regulator) regulator_disable(dbidev->io_regulator); } -EXPORT_SYMBOL(mipi_dbi_pipe_disable); +EXPORT_SYMBOL(drm_mipi_dbi_crtc_helper_atomic_disable); /** - * mipi_dbi_pipe_begin_fb_access - MIPI DBI pipe begin-access helper - * @pipe: Display pipe - * @plane_state: Plane state - * - * This function implements struct &drm_simple_display_funcs.begin_fb_access. + * drm_mipi_dbi_connector_helper_get_modes - Duplicates the MIPI DBI mode for the connector + * @connector: The connector * - * See drm_gem_begin_shadow_fb_access() for details and mipi_dbi_pipe_cleanup_fb() - * for cleanup. + * Sets the connecto rmodes from the MIPI DBI mode. Drivers can use this as their + * &drm_connector_helper_funcs->get_mods callback. See drm_gem_destroy_shadow_plane_state() + * for additional details. * * Returns: - * 0 on success, or a negative errno code otherwise. - */ -int mipi_dbi_pipe_begin_fb_access(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state) -{ - return drm_gem_begin_shadow_fb_access(&pipe->plane, plane_state); -} -EXPORT_SYMBOL(mipi_dbi_pipe_begin_fb_access); - -/** - * mipi_dbi_pipe_end_fb_access - MIPI DBI pipe end-access helper - * @pipe: Display pipe - * @plane_state: Plane state - * - * This function implements struct &drm_simple_display_funcs.end_fb_access. - * - * See mipi_dbi_pipe_begin_fb_access(). - */ -void mipi_dbi_pipe_end_fb_access(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state) -{ - drm_gem_end_shadow_fb_access(&pipe->plane, plane_state); -} -EXPORT_SYMBOL(mipi_dbi_pipe_end_fb_access); - -/** - * mipi_dbi_pipe_reset_plane - MIPI DBI plane-reset helper - * @pipe: Display pipe - * - * This function implements struct &drm_simple_display_funcs.reset_plane - * for MIPI DBI planes. + * The number of created modes. */ -void mipi_dbi_pipe_reset_plane(struct drm_simple_display_pipe *pipe) -{ - drm_gem_reset_shadow_plane(&pipe->plane); -} -EXPORT_SYMBOL(mipi_dbi_pipe_reset_plane); - -/** - * mipi_dbi_pipe_duplicate_plane_state - duplicates MIPI DBI plane state - * @pipe: Display pipe - * - * This function implements struct &drm_simple_display_funcs.duplicate_plane_state - * for MIPI DBI planes. - * - * See drm_gem_duplicate_shadow_plane_state() for additional details. - * - * Returns: - * A pointer to a new plane state on success, or NULL otherwise. - */ -struct drm_plane_state *mipi_dbi_pipe_duplicate_plane_state(struct drm_simple_display_pipe *pipe) -{ - return drm_gem_duplicate_shadow_plane_state(&pipe->plane); -} -EXPORT_SYMBOL(mipi_dbi_pipe_duplicate_plane_state); - -/** - * mipi_dbi_pipe_destroy_plane_state - cleans up MIPI DBI plane state - * @pipe: Display pipe - * @plane_state: Plane state - * - * This function implements struct drm_simple_display_funcs.destroy_plane_state - * for MIPI DBI planes. - * - * See drm_gem_destroy_shadow_plane_state() for additional details. - */ -void mipi_dbi_pipe_destroy_plane_state(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state) -{ - drm_gem_destroy_shadow_plane_state(&pipe->plane, plane_state); -} -EXPORT_SYMBOL(mipi_dbi_pipe_destroy_plane_state); - -static int mipi_dbi_connector_get_modes(struct drm_connector *connector) +int drm_mipi_dbi_connector_helper_get_modes(struct drm_connector *connector) { struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(connector->dev); return drm_connector_helper_get_modes_fixed(connector, &dbidev->mode); } - -static const struct drm_connector_helper_funcs mipi_dbi_connector_hfuncs = { - .get_modes = mipi_dbi_connector_get_modes, -}; - -static const struct drm_connector_funcs mipi_dbi_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; +EXPORT_SYMBOL(drm_mipi_dbi_connector_helper_get_modes); static int mipi_dbi_rotate_mode(struct drm_display_mode *mode, unsigned int rotation) @@ -577,59 +513,36 @@ static int mipi_dbi_rotate_mode(struct drm_display_mode *mode, } } -static const struct drm_mode_config_funcs mipi_dbi_mode_config_funcs = { - .fb_create = drm_gem_fb_create_with_dirty, - .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, -}; - -static const uint32_t mipi_dbi_formats[] = { - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, -}; - /** - * mipi_dbi_dev_init_with_formats - MIPI DBI device initialization with custom formats + * drm_mipi_dbi_dev_init - MIPI DBI device initialization * @dbidev: MIPI DBI device structure to initialize - * @funcs: Display pipe functions - * @formats: Array of supported formats (DRM_FORMAT\_\*). - * @format_count: Number of elements in @formats - * @mode: Display mode + * @mode: Hardware display mode + * @format: Hardware color format (DRM_FORMAT\_\*). * @rotation: Initial rotation in degrees Counter Clock Wise - * @tx_buf_size: Allocate a transmit buffer of this size. - * - * This function sets up a &drm_simple_display_pipe with a &drm_connector that - * has one fixed &drm_display_mode which is rotated according to @rotation. - * This mode is used to set the mode config min/max width/height properties. - * - * Use mipi_dbi_dev_init() if you want native RGB565 and emulated XRGB8888 format. + * @tx_buf_size: Allocate a transmit buffer of at least this size. * - * Note: - * Some of the helper functions expects RGB565 to be the default format and the - * transmit buffer sized to fit that. + * Initializes a MIPI-DBI device. The minimum size of the transmit buffer + * in @tx_buf_size is optional. Pass 0 to allocate enough memory to transmit + * a single scanline of the display. * * Returns: * Zero on success, negative error code on failure. */ -int mipi_dbi_dev_init_with_formats(struct mipi_dbi_dev *dbidev, - const struct drm_simple_display_pipe_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - const struct drm_display_mode *mode, - unsigned int rotation, size_t tx_buf_size) +int drm_mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev, const struct drm_display_mode *mode, + u32 format, unsigned int rotation, size_t tx_buf_size) { - static const uint64_t modifiers[] = { - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID - }; struct drm_device *drm = &dbidev->drm; int ret; if (!dbidev->dbi.command) return -EINVAL; - ret = drmm_mode_config_init(drm); - if (ret) - return ret; + if (!tx_buf_size) { + const struct drm_format_info *info = drm_format_info(format); + + tx_buf_size = drm_format_info_min_pitch(info, 0, mode->hdisplay) * + mode->vdisplay; + } dbidev->tx_buf = devm_kmalloc(drm->dev, tx_buf_size, GFP_KERNEL); if (!dbidev->tx_buf) @@ -638,69 +551,20 @@ int mipi_dbi_dev_init_with_formats(struct mipi_dbi_dev *dbidev, drm_mode_copy(&dbidev->mode, mode); ret = mipi_dbi_rotate_mode(&dbidev->mode, rotation); if (ret) { - DRM_ERROR("Illegal rotation value %u\n", rotation); + drm_err(drm, "Illegal rotation value %u\n", rotation); return -EINVAL; } - drm_connector_helper_add(&dbidev->connector, &mipi_dbi_connector_hfuncs); - ret = drm_connector_init(drm, &dbidev->connector, &mipi_dbi_connector_funcs, - DRM_MODE_CONNECTOR_SPI); - if (ret) - return ret; - - ret = drm_simple_display_pipe_init(drm, &dbidev->pipe, funcs, formats, format_count, - modifiers, &dbidev->connector); - if (ret) - return ret; - - drm_plane_enable_fb_damage_clips(&dbidev->pipe.plane); - - drm->mode_config.funcs = &mipi_dbi_mode_config_funcs; - drm->mode_config.min_width = dbidev->mode.hdisplay; - drm->mode_config.max_width = dbidev->mode.hdisplay; - drm->mode_config.min_height = dbidev->mode.vdisplay; - drm->mode_config.max_height = dbidev->mode.vdisplay; dbidev->rotation = rotation; - dbidev->pixel_format = formats[0]; - if (formats[0] == DRM_FORMAT_RGB888) - dbidev->dbi.write_memory_bpw = 8; + drm_dbg(drm, "rotation = %u\n", rotation); - DRM_DEBUG_KMS("rotation = %u\n", rotation); + dbidev->pixel_format = format; + if (dbidev->pixel_format == DRM_FORMAT_RGB888) + dbidev->dbi.write_memory_bpw = 8; return 0; } -EXPORT_SYMBOL(mipi_dbi_dev_init_with_formats); - -/** - * mipi_dbi_dev_init - MIPI DBI device initialization - * @dbidev: MIPI DBI device structure to initialize - * @funcs: Display pipe functions - * @mode: Display mode - * @rotation: Initial rotation in degrees Counter Clock Wise - * - * This function sets up a &drm_simple_display_pipe with a &drm_connector that - * has one fixed &drm_display_mode which is rotated according to @rotation. - * This mode is used to set the mode config min/max width/height properties. - * Additionally &mipi_dbi.tx_buf is allocated. - * - * Supported formats: Native RGB565 and emulated XRGB8888. - * - * Returns: - * Zero on success, negative error code on failure. - */ -int mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev, - const struct drm_simple_display_pipe_funcs *funcs, - const struct drm_display_mode *mode, unsigned int rotation) -{ - size_t bufsize = (u32)mode->vdisplay * mode->hdisplay * sizeof(u16); - - dbidev->drm.mode_config.preferred_depth = 16; - - return mipi_dbi_dev_init_with_formats(dbidev, funcs, mipi_dbi_formats, - ARRAY_SIZE(mipi_dbi_formats), mode, - rotation, bufsize); -} -EXPORT_SYMBOL(mipi_dbi_dev_init); +EXPORT_SYMBOL(drm_mipi_dbi_dev_init); /** * mipi_dbi_hw_reset - Hardware reset of controller diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 84ae8a23a367..66f7dc37b597 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -380,6 +380,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.gamma_lut_size_property = prop; + prop = drm_property_create_range(dev, 0, + "BACKGROUND_COLOR", 0, U64_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.background_color_property = prop; + prop = drm_property_create(dev, DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_BLOB, "IN_FORMATS", 0); diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index a57f6a10ada4..d7721df744e7 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -135,9 +135,6 @@ static const struct drm_plane_funcs primary_plane_funcs = { * * This is purely a backwards compatibility helper for old drivers. Drivers * should instead implement their own primary plane. Atomic drivers must do so. - * Drivers with the above hardware restriction can look into using &struct - * drm_simple_display_pipe, which encapsulates the above limitations into a nice - * interface. * * Returns: * Zero on success, error code on failure. diff --git a/drivers/gpu/drm/drm_pagemap_util.c b/drivers/gpu/drm/drm_pagemap_util.c index 14ddb948a32e..6111d90a38e2 100644 --- a/drivers/gpu/drm/drm_pagemap_util.c +++ b/drivers/gpu/drm/drm_pagemap_util.c @@ -65,18 +65,14 @@ static void drm_pagemap_cache_fini(void *arg) drm_dbg(cache->shrinker->drm, "Destroying dpagemap cache.\n"); spin_lock(&cache->lock); dpagemap = cache->dpagemap; - if (!dpagemap) { - spin_unlock(&cache->lock); - goto out; - } + cache->dpagemap = NULL; + if (dpagemap && !drm_pagemap_shrinker_cancel(dpagemap)) + dpagemap = NULL; + spin_unlock(&cache->lock); - if (drm_pagemap_shrinker_cancel(dpagemap)) { - cache->dpagemap = NULL; - spin_unlock(&cache->lock); + if (dpagemap) drm_pagemap_destroy(dpagemap, false); - } -out: mutex_destroy(&cache->lookup_mutex); kfree(cache); } diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 51fdb06d3e9f..9b44c78cd77f 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -859,7 +859,7 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev, return ERR_PTR(-ENOMEM); if (dev) - max_segment = dma_max_mapping_size(dev->dev); + max_segment = dma_max_mapping_size(drm_dev_dma_dev(dev)); if (max_segment == 0) max_segment = UINT_MAX; err = sg_alloc_table_from_pages_segment(sg, pages, nr_pages, 0, diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index fcbcaaa36b5f..4d91513a1e34 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -16,55 +16,10 @@ #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> -/** - * DOC: overview - * - * This helper library provides helpers for drivers for simple display - * hardware. - * - * drm_simple_display_pipe_init() initializes a simple display pipeline - * which has only one full-screen scanout buffer feeding one output. The - * pipeline is represented by &struct drm_simple_display_pipe and binds - * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed - * entity. Some flexibility for code reuse is provided through a separately - * allocated &drm_connector object and supporting optional &drm_bridge - * encoder drivers. - * - * Many drivers require only a very simple encoder that fulfills the minimum - * requirements of the display pipeline and does not add additional - * functionality. The function drm_simple_encoder_init() provides an - * implementation of such an encoder. - */ - static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = { .destroy = drm_encoder_cleanup, }; -/** - * drm_simple_encoder_init - Initialize a preallocated encoder with - * basic functionality. - * @dev: drm device - * @encoder: the encoder to initialize - * @encoder_type: user visible type of the encoder - * - * Initialises a preallocated encoder that has no further functionality. - * Settings for possible CRTC and clones are left to their initial values. - * The encoder will be cleaned up automatically as part of the mode-setting - * cleanup. - * - * The caller of drm_simple_encoder_init() is responsible for freeing - * the encoder's memory after the encoder has been cleaned up. At the - * moment this only works reliably if the encoder data structure is - * stored in the device structure. Free the encoder's memory as part of - * the device release function. - * - * Note: consider using drmm_simple_encoder_alloc() instead of - * drm_simple_encoder_init() to let the DRM managed resource infrastructure - * take care of cleanup and deallocation. - * - * Returns: - * Zero on success, error code on failure. - */ int drm_simple_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, int encoder_type) @@ -370,20 +325,6 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = { .format_mod_supported = drm_simple_kms_format_mod_supported, }; -/** - * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe - * @pipe: simple display pipe object - * @bridge: bridge to attach - * - * Makes it possible to still use the drm_simple_display_pipe helpers when - * a DRM bridge has to be used. - * - * Note that you probably want to initialize the pipe by passing a NULL - * connector to drm_simple_display_pipe_init(). - * - * Returns: - * Zero on success, negative error code on failure. - */ int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe, struct drm_bridge *bridge) { @@ -391,30 +332,6 @@ int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe, } EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge); -/** - * drm_simple_display_pipe_init - Initialize a simple display pipeline - * @dev: DRM device - * @pipe: simple display pipe object to initialize - * @funcs: callbacks for the display pipe (optional) - * @formats: array of supported formats (DRM_FORMAT\_\*) - * @format_count: number of elements in @formats - * @format_modifiers: array of formats modifiers - * @connector: connector to attach and register (optional) - * - * Sets up a display pipeline which consist of a really simple - * plane-crtc-encoder pipe. - * - * If a connector is supplied, the pipe will be coupled with the provided - * connector. You may supply a NULL connector when using drm bridges, that - * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()). - * - * Teardown of a simple display pipe is all handled automatically by the drm - * core through calling drm_mode_config_cleanup(). Drivers afterwards need to - * release the memory for the structure themselves. - * - * Returns: - * Zero on success, negative error code on failure. - */ int drm_simple_display_pipe_init(struct drm_device *dev, struct drm_simple_display_pipe *pipe, const struct drm_simple_display_pipe_funcs *funcs, diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 250734dee928..8d9fd1917c6e 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -602,7 +602,7 @@ int drm_syncobj_get_handle(struct drm_file *file_private, drm_syncobj_get(syncobj); ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b, - GFP_NOWAIT); + GFP_KERNEL); if (ret) drm_syncobj_put(syncobj); @@ -716,7 +716,7 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private, drm_syncobj_get(syncobj); ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b, - GFP_NOWAIT); + GFP_KERNEL); if (ret) drm_syncobj_put(syncobj); diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index d0122d477610..17c2dead2c13 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -339,7 +339,9 @@ static int gud_stats_debugfs(struct seq_file *m, void *data) } static const struct drm_crtc_helper_funcs gud_crtc_helper_funcs = { - .atomic_check = drm_crtc_helper_atomic_check + .atomic_check = drm_crtc_helper_atomic_check, + .atomic_enable = gud_crtc_atomic_enable, + .atomic_disable = gud_crtc_atomic_disable, }; static const struct drm_crtc_funcs gud_crtc_funcs = { @@ -364,6 +366,10 @@ static const struct drm_plane_funcs gud_plane_funcs = { DRM_GEM_SHADOW_PLANE_FUNCS, }; +static const struct drm_mode_config_helper_funcs gud_mode_config_helpers = { + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, +}; + static const struct drm_mode_config_funcs gud_mode_config_funcs = { .fb_create = drm_gem_fb_create_with_dirty, .atomic_check = drm_atomic_helper_check, @@ -499,6 +505,7 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id) drm->mode_config.min_height = le32_to_cpu(desc.min_height); drm->mode_config.max_height = le32_to_cpu(desc.max_height); drm->mode_config.funcs = &gud_mode_config_funcs; + drm->mode_config.helper_private = &gud_mode_config_helpers; /* Format init */ formats_dev = devm_kmalloc(dev, GUD_FORMATS_MAX_NUM, GFP_KERNEL); diff --git a/drivers/gpu/drm/gud/gud_internal.h b/drivers/gpu/drm/gud/gud_internal.h index d27c31648341..8eec8335f5f9 100644 --- a/drivers/gpu/drm/gud/gud_internal.h +++ b/drivers/gpu/drm/gud/gud_internal.h @@ -62,6 +62,10 @@ int gud_usb_set_u8(struct gud_device *gdrm, u8 request, u8 val); void gud_clear_damage(struct gud_device *gdrm); void gud_flush_work(struct work_struct *work); +void gud_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state); +void gud_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state); int gud_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state); void gud_plane_atomic_update(struct drm_plane *plane, diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 11e7441de63b..495804e1d200 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -580,6 +580,39 @@ out: return ret; } +void gud_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct gud_device *gdrm = to_gud_device(drm); + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + + gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 1); + gud_usb_set(gdrm, GUD_REQ_SET_STATE_COMMIT, 0, NULL, 0); + gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, 1); + + drm_dev_exit(idx); +} + +void gud_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct gud_device *gdrm = to_gud_device(drm); + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + + gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, 0); + gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 0); + + drm_dev_exit(idx); +} + void gud_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *atomic_state) { @@ -607,24 +640,12 @@ void gud_plane_atomic_update(struct drm_plane *plane, mutex_unlock(&gdrm->damage_lock); } - if (!drm_dev_enter(drm, &idx)) + if (!crtc || !drm_dev_enter(drm, &idx)) return; - if (!old_state->fb) - gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 1); - - if (fb && (crtc->state->mode_changed || crtc->state->connectors_changed)) - gud_usb_set(gdrm, GUD_REQ_SET_STATE_COMMIT, 0, NULL, 0); - - if (crtc->state->active_changed) - gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, crtc->state->active); - - if (!fb) - goto ctrl_disable; - ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); if (ret) - goto ctrl_disable; + goto out; drm_atomic_helper_damage_iter_init(&iter, old_state, new_state); drm_atomic_for_each_plane_damage(&iter, &damage) @@ -632,9 +653,6 @@ void gud_plane_atomic_update(struct drm_plane *plane, drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); -ctrl_disable: - if (!crtc->state->enable) - gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 0); - +out: drm_dev_exit(idx); } diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index be976a90c5a6..b677720a1c2d 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -254,6 +254,7 @@ i915-y += \ display/intel_crtc_state_dump.o \ display/intel_cursor.o \ display/intel_dbuf_bw.o \ + display/intel_de.o \ display/intel_display.o \ display/intel_display_conversion.o \ display/intel_display_driver.o \ diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index d7de329abf19..5e74d8a3ba5c 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -136,7 +136,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, intel_dp->DP |= DP_SYNC_VS_HIGH; intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; - if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + if (pipe_config->enhanced_framing) intel_dp->DP |= DP_ENHANCED_FRAMING; intel_dp->DP |= DP_PIPE_SEL_IVB(crtc->pipe); diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index c04327979678..afbaa0465842 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -711,7 +711,7 @@ gen11_dsi_configure_transcoder(struct intel_encoder *encoder, dsi_trans = dsi_port_to_transcoder(port); tmp = intel_de_read(display, DSI_TRANS_FUNC_CONF(dsi_trans)); - if (intel_dsi->eotp_pkt) + if (intel_dsi->eot_pkt) tmp &= ~EOTP_DISABLED; else tmp |= EOTP_DISABLED; @@ -729,6 +729,12 @@ gen11_dsi_configure_transcoder(struct intel_encoder *encoder, else tmp |= CLK_HS_CONTINUOUS; + if (DISPLAY_VER(display) >= 12 && + intel_dsi->lp_clock_during_lpm) + tmp |= LP_CLK_DURING_LPM; + else + tmp &= ~LP_CLK_DURING_LPM; + /* configure buffer threshold limit to minimum */ tmp &= ~PIX_BUF_THRESHOLD_MASK; tmp |= PIX_BUF_THRESHOLD_1_4; @@ -765,10 +771,11 @@ gen11_dsi_configure_transcoder(struct intel_encoder *encoder, } } - if (DISPLAY_VER(display) >= 12) { - if (is_vid_mode(intel_dsi)) - tmp |= BLANKING_PACKET_ENABLE; - } + if (DISPLAY_VER(display) >= 12 && + is_vid_mode(intel_dsi) && intel_dsi->blanking_pkt) + tmp |= BLANKING_PACKET_ENABLE; + else + tmp &= ~BLANKING_PACKET_ENABLE; /* program DSI operation mode */ if (is_vid_mode(intel_dsi)) { @@ -888,7 +895,7 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, * non-compressed link speeds, and simplifies down to the ratio between * compressed and non-compressed bpp. */ - if (crtc_state->dsc.compression_enable) { + if (is_vid_mode(intel_dsi) && crtc_state->dsc.compression_enable) { mul = fxp_q4_to_int(crtc_state->dsc.compressed_bpp_x16); div = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); } @@ -1502,7 +1509,7 @@ static void gen11_dsi_get_timings(struct intel_encoder *encoder, struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - if (pipe_config->dsc.compressed_bpp_x16) { + if (is_vid_mode(intel_dsi) && pipe_config->dsc.compressed_bpp_x16) { int div = fxp_q4_to_int(pipe_config->dsc.compressed_bpp_x16); int mul = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); diff --git a/drivers/gpu/drm/i915/display/icl_dsi_regs.h b/drivers/gpu/drm/i915/display/icl_dsi_regs.h index b601b7632339..55ab57adcb0f 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi_regs.h +++ b/drivers/gpu/drm/i915/display/icl_dsi_regs.h @@ -227,12 +227,13 @@ #define CLK_ENTER_LP_AFTER_DATA (0x0 << 8) #define CLK_HS_OR_LP (0x2 << 8) #define CLK_HS_CONTINUOUS (0x3 << 8) +#define LP_CLK_DURING_LPM (1 << 7) /* tgl+ */ #define LINK_CALIBRATION_MASK (0x3 << 4) #define LINK_CALIBRATION_SHIFT 4 #define CALIBRATION_DISABLED (0x0 << 4) #define CALIBRATION_ENABLED_INITIAL_ONLY (0x2 << 4) #define CALIBRATION_ENABLED_INITIAL_PERIODIC (0x3 << 4) -#define BLANKING_PACKET_ENABLE (1 << 2) +#define BLANKING_PACKET_ENABLE (1 << 2) /* tgl+ */ #define S3D_ORIENTATION_LANDSCAPE (1 << 1) #define EOTP_DISABLED (1 << 0) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 121a12c5b8ac..a47736613f6e 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2972,6 +2972,53 @@ static int intel_cdclk_update_crtc_min_cdclk(struct intel_atomic_state *state, return 0; } +static int intel_cdclk_update_crtc_min_voltage_level(struct intel_atomic_state *state, + struct intel_crtc *crtc, + u8 old_min_voltage_level, + u8 new_min_voltage_level, + bool *need_cdclk_calc) +{ + struct intel_display *display = to_intel_display(state); + struct intel_cdclk_state *cdclk_state; + bool allow_voltage_level_decrease = intel_any_crtc_needs_modeset(state); + int ret; + + if (new_min_voltage_level == old_min_voltage_level) + return 0; + + if (!allow_voltage_level_decrease && + new_min_voltage_level < old_min_voltage_level) + return 0; + + cdclk_state = intel_atomic_get_cdclk_state(state); + if (IS_ERR(cdclk_state)) + return PTR_ERR(cdclk_state); + + old_min_voltage_level = cdclk_state->min_voltage_level[crtc->pipe]; + + if (new_min_voltage_level == old_min_voltage_level) + return 0; + + if (!allow_voltage_level_decrease && + new_min_voltage_level < old_min_voltage_level) + return 0; + + cdclk_state->min_voltage_level[crtc->pipe] = new_min_voltage_level; + + ret = intel_atomic_lock_global_state(&cdclk_state->base); + if (ret) + return ret; + + *need_cdclk_calc = true; + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] min voltage level: %d -> %d\n", + crtc->base.base.id, crtc->base.name, + old_min_voltage_level, new_min_voltage_level); + + return 0; +} + int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state, int old_min_cdclk, int new_min_cdclk, bool *need_cdclk_calc) @@ -3387,6 +3434,13 @@ static int intel_crtcs_calc_min_cdclk(struct intel_atomic_state *state, need_cdclk_calc); if (ret) return ret; + + ret = intel_cdclk_update_crtc_min_voltage_level(state, crtc, + old_crtc_state->min_voltage_level, + new_crtc_state->min_voltage_level, + need_cdclk_calc); + if (ret) + return ret; } return 0; diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 6a471c021c0e..7e59409bbf01 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2180,7 +2180,7 @@ static int intel_c10pll_calc_state(const struct intel_crtc_state *crtc_state, return 0; } -static int readout_enabled_lane_count(struct intel_encoder *encoder) +int intel_readout_lane_count(struct intel_encoder *encoder, int lane0, int lane1) { struct intel_display *display = to_intel_display(encoder); u8 enabled_tx_lane_count = 0; @@ -2212,7 +2212,7 @@ static int readout_enabled_lane_count(struct intel_encoder *encoder) max_tx_lane_count = round_up(max_tx_lane_count, 2); for (tx_lane = 0; tx_lane < max_tx_lane_count; tx_lane++) { - u8 phy_lane_mask = tx_lane < 2 ? INTEL_CX0_LANE0 : INTEL_CX0_LANE1; + u8 phy_lane_mask = tx_lane < 2 ? lane0 : lane1; int tx = tx_lane % 2 + 1; u8 val; @@ -2252,7 +2252,8 @@ static void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, */ intel_c10_msgbus_access_begin(encoder, lane); - cx0pll_state->lane_count = readout_enabled_lane_count(encoder); + cx0pll_state->lane_count = intel_readout_lane_count(encoder, INTEL_CX0_LANE0, + INTEL_CX0_LANE1); for (i = 0; i < ARRAY_SIZE(pll_state->pll); i++) pll_state->pll[i] = intel_cx0_read(encoder, lane, PHY_C10_VDR_PLL(i)); @@ -2707,7 +2708,8 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, wakeref = intel_cx0_phy_transaction_begin(encoder); - cx0pll_state->lane_count = readout_enabled_lane_count(encoder); + cx0pll_state->lane_count = intel_readout_lane_count(encoder, INTEL_CX0_LANE0, + INTEL_CX0_LANE1); /* 1. Read VDR params and current context selection */ intel_c20_readout_vdr_params(encoder, &pll_state->vdr, &cntx); diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 1d4480b8bf39..1428e7a5a318 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -28,6 +28,7 @@ struct intel_hdmi; void intel_cx0_clear_response_ready_flag(struct intel_encoder *encoder, int lane); bool intel_encoder_is_c10phy(struct intel_encoder *encoder); +int intel_readout_lane_count(struct intel_encoder *encoder, int lane0, int lane1); void intel_mtl_pll_enable(struct intel_encoder *encoder, struct intel_dpll *pll, const struct intel_dpll_hw_state *dpll_hw_state); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 7f1576bfe4b0..ebefa889bc8c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4243,21 +4243,6 @@ void intel_ddi_get_clock(struct intel_encoder *encoder, &crtc_state->dpll_hw_state); } -static void xe3plpd_ddi_get_config(struct intel_encoder *encoder, - struct intel_crtc_state *crtc_state) -{ - struct intel_display *display = to_intel_display(encoder); - - intel_lt_phy_pll_readout_hw_state(encoder, crtc_state, &crtc_state->dpll_hw_state.ltpll); - - if (crtc_state->dpll_hw_state.ltpll.tbt_mode) - crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); - else - crtc_state->port_clock = - intel_lt_phy_calc_port_clock(display, &crtc_state->dpll_hw_state.ltpll); - intel_ddi_get_config(encoder, crtc_state); -} - static bool icl_ddi_tc_pll_is_tbt(const struct intel_dpll *pll) { return pll->info->id == DPLL_ID_ICL_TBTPLL; @@ -5298,10 +5283,13 @@ void intel_ddi_init(struct intel_display *display, encoder->pipe_mask = ~0; if (HAS_LT_PHY(display)) { - encoder->enable_clock = intel_xe3plpd_pll_enable; - encoder->disable_clock = intel_xe3plpd_pll_disable; - encoder->port_pll_type = intel_mtl_port_pll_type; - encoder->get_config = xe3plpd_ddi_get_config; + encoder->enable_clock = intel_mtl_pll_enable_clock; + encoder->disable_clock = intel_mtl_pll_disable_clock; + encoder->port_pll_type = icl_ddi_tc_port_pll_type; + if (intel_encoder_is_tc(encoder)) + encoder->get_config = mtl_ddi_tc_phy_get_config; + else + encoder->get_config = mtl_ddi_non_tc_phy_get_config; } else if (DISPLAY_VER(display) >= 14) { encoder->enable_clock = intel_mtl_pll_enable_clock; encoder->disable_clock = intel_mtl_pll_disable_clock; diff --git a/drivers/gpu/drm/i915/display/intel_de.c b/drivers/gpu/drm/i915/display/intel_de.c new file mode 100644 index 000000000000..d2a418da2d54 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_de.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include <linux/delay.h> + +#include <drm/drm_print.h> + +#include "intel_de.h" + +static int __intel_de_wait_for_register(struct intel_display *display, + i915_reg_t reg, u32 mask, u32 value, + unsigned int timeout_us, + u32 (*read)(struct intel_display *display, i915_reg_t reg), + u32 *out_val, bool is_atomic) +{ + const ktime_t end = ktime_add_us(ktime_get_raw(), timeout_us); + int wait_max = 1000; + int wait = 10; + u32 reg_value; + int ret; + + might_sleep_if(!is_atomic); + + if (timeout_us <= 10) { + is_atomic = true; + wait = 1; + } + + for (;;) { + bool expired = ktime_after(ktime_get_raw(), end); + + /* guarantee the condition is evaluated after timeout expired */ + barrier(); + + reg_value = read(display, reg); + if ((reg_value & mask) == value) { + ret = 0; + break; + } + + if (expired) { + ret = -ETIMEDOUT; + break; + } + + if (is_atomic) + udelay(wait); + else + usleep_range(wait, wait << 1); + + if (wait < wait_max) + wait <<= 1; + } + + if (out_val) + *out_val = reg_value; + + return ret; +} + +static int intel_de_wait_for_register(struct intel_display *display, + i915_reg_t reg, u32 mask, u32 value, + unsigned int fast_timeout_us, + unsigned int slow_timeout_us, + u32 (*read)(struct intel_display *display, i915_reg_t reg), + u32 *out_value, bool is_atomic) +{ + int ret = -EINVAL; + + if (fast_timeout_us) + ret = __intel_de_wait_for_register(display, reg, mask, value, + fast_timeout_us, read, + out_value, is_atomic); + + if (ret && slow_timeout_us) + ret = __intel_de_wait_for_register(display, reg, mask, value, + slow_timeout_us, read, + out_value, is_atomic); + + return ret; +} + +int intel_de_wait_us(struct intel_display *display, i915_reg_t reg, + u32 mask, u32 value, unsigned int timeout_us, + u32 *out_value) +{ + int ret; + + intel_dmc_wl_get(display, reg); + + ret = intel_de_wait_for_register(display, reg, mask, value, + timeout_us, 0, + intel_de_read, + out_value, false); + + intel_dmc_wl_put(display, reg); + + return ret; +} + +int intel_de_wait_ms(struct intel_display *display, i915_reg_t reg, + u32 mask, u32 value, unsigned int timeout_ms, + u32 *out_value) +{ + int ret; + + intel_dmc_wl_get(display, reg); + + ret = intel_de_wait_for_register(display, reg, mask, value, + 2, timeout_ms * 1000, + intel_de_read, + out_value, false); + + intel_dmc_wl_put(display, reg); + + return ret; +} + +int intel_de_wait_fw_ms(struct intel_display *display, i915_reg_t reg, + u32 mask, u32 value, unsigned int timeout_ms, + u32 *out_value) +{ + return intel_de_wait_for_register(display, reg, mask, value, + 2, timeout_ms * 1000, + intel_de_read_fw, + out_value, false); +} + +int intel_de_wait_fw_us_atomic(struct intel_display *display, i915_reg_t reg, + u32 mask, u32 value, unsigned int timeout_us, + u32 *out_value) +{ + return intel_de_wait_for_register(display, reg, mask, value, + timeout_us, 0, + intel_de_read_fw, + out_value, true); +} + +int intel_de_wait_for_set_us(struct intel_display *display, i915_reg_t reg, + u32 mask, unsigned int timeout_us) +{ + return intel_de_wait_us(display, reg, mask, mask, timeout_us, NULL); +} + +int intel_de_wait_for_clear_us(struct intel_display *display, i915_reg_t reg, + u32 mask, unsigned int timeout_us) +{ + return intel_de_wait_us(display, reg, mask, 0, timeout_us, NULL); +} + +int intel_de_wait_for_set_ms(struct intel_display *display, i915_reg_t reg, + u32 mask, unsigned int timeout_ms) +{ + return intel_de_wait_ms(display, reg, mask, mask, timeout_ms, NULL); +} + +int intel_de_wait_for_clear_ms(struct intel_display *display, i915_reg_t reg, + u32 mask, unsigned int timeout_ms) +{ + return intel_de_wait_ms(display, reg, mask, 0, timeout_ms, NULL); +} + +u8 intel_de_read8(struct intel_display *display, i915_reg_t reg) +{ + /* this is only used on VGA registers (possible on pre-g4x) */ + drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 5 || display->platform.g4x); + + return intel_uncore_read8(__to_uncore(display), reg); +} + +void intel_de_write8(struct intel_display *display, i915_reg_t reg, u8 val) +{ + drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 5 || display->platform.g4x); + + intel_uncore_write8(__to_uncore(display), reg, val); +} diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h index f30f3f8ebee1..f87b84ab9d6d 100644 --- a/drivers/gpu/drm/i915/display/intel_de.h +++ b/drivers/gpu/drm/i915/display/intel_de.h @@ -6,8 +6,6 @@ #ifndef __INTEL_DE_H__ #define __INTEL_DE_H__ -#include <drm/drm_print.h> - #include "intel_display_core.h" #include "intel_dmc_wl.h" #include "intel_dsb.h" @@ -19,6 +17,9 @@ static inline struct intel_uncore *__to_uncore(struct intel_display *display) return to_intel_uncore(display->drm); } +u8 intel_de_read8(struct intel_display *display, i915_reg_t reg); +void intel_de_write8(struct intel_display *display, i915_reg_t reg, u8 val); + static inline u32 intel_de_read(struct intel_display *display, i915_reg_t reg) { @@ -33,23 +34,6 @@ intel_de_read(struct intel_display *display, i915_reg_t reg) return val; } -static inline u8 -intel_de_read8(struct intel_display *display, i915_reg_t reg) -{ - /* this is only used on VGA registers (possible on pre-g4x) */ - drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 5 || display->platform.g4x); - - return intel_uncore_read8(__to_uncore(display), reg); -} - -static inline void -intel_de_write8(struct intel_display *display, i915_reg_t reg, u8 val) -{ - drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 5 || display->platform.g4x); - - intel_uncore_write8(__to_uncore(display), reg, val); -} - static inline u64 intel_de_read64_2x32(struct intel_display *display, i915_reg_t lower_reg, i915_reg_t upper_reg) @@ -102,85 +86,26 @@ intel_de_rmw(struct intel_display *display, i915_reg_t reg, u32 clear, u32 set) return val; } -static inline int -intel_de_wait_us(struct intel_display *display, i915_reg_t reg, - u32 mask, u32 value, unsigned int timeout_us, - u32 *out_value) -{ - int ret; - - intel_dmc_wl_get(display, reg); - - ret = __intel_wait_for_register(__to_uncore(display), reg, mask, - value, timeout_us, 0, out_value); - - intel_dmc_wl_put(display, reg); - - return ret; -} - -static inline int -intel_de_wait_ms(struct intel_display *display, i915_reg_t reg, - u32 mask, u32 value, unsigned int timeout_ms, - u32 *out_value) -{ - int ret; - - intel_dmc_wl_get(display, reg); - - ret = __intel_wait_for_register(__to_uncore(display), reg, mask, - value, 2, timeout_ms, out_value); - - intel_dmc_wl_put(display, reg); - - return ret; -} - -static inline int -intel_de_wait_fw_ms(struct intel_display *display, i915_reg_t reg, - u32 mask, u32 value, unsigned int timeout_ms, - u32 *out_value) -{ - return __intel_wait_for_register_fw(__to_uncore(display), reg, mask, - value, 2, timeout_ms, out_value); -} - -static inline int -intel_de_wait_fw_us_atomic(struct intel_display *display, i915_reg_t reg, - u32 mask, u32 value, unsigned int timeout_us, - u32 *out_value) -{ - return __intel_wait_for_register_fw(__to_uncore(display), reg, mask, - value, timeout_us, 0, out_value); -} - -static inline int -intel_de_wait_for_set_us(struct intel_display *display, i915_reg_t reg, - u32 mask, unsigned int timeout_us) -{ - return intel_de_wait_us(display, reg, mask, mask, timeout_us, NULL); -} - -static inline int -intel_de_wait_for_clear_us(struct intel_display *display, i915_reg_t reg, - u32 mask, unsigned int timeout_us) -{ - return intel_de_wait_us(display, reg, mask, 0, timeout_us, NULL); -} - -static inline int -intel_de_wait_for_set_ms(struct intel_display *display, i915_reg_t reg, - u32 mask, unsigned int timeout_ms) -{ - return intel_de_wait_ms(display, reg, mask, mask, timeout_ms, NULL); -} - -static inline int -intel_de_wait_for_clear_ms(struct intel_display *display, i915_reg_t reg, - u32 mask, unsigned int timeout_ms) -{ - return intel_de_wait_ms(display, reg, mask, 0, timeout_ms, NULL); -} +int intel_de_wait_us(struct intel_display *display, i915_reg_t reg, + u32 mask, u32 value, unsigned int timeout_us, + u32 *out_value); +int intel_de_wait_ms(struct intel_display *display, i915_reg_t reg, + u32 mask, u32 value, unsigned int timeout_ms, + u32 *out_value); +int intel_de_wait_fw_ms(struct intel_display *display, i915_reg_t reg, + u32 mask, u32 value, unsigned int timeout_ms, + u32 *out_value); +int intel_de_wait_fw_us_atomic(struct intel_display *display, i915_reg_t reg, + u32 mask, u32 value, unsigned int timeout_us, + u32 *out_value); +int intel_de_wait_for_set_us(struct intel_display *display, i915_reg_t reg, + u32 mask, unsigned int timeout_us); +int intel_de_wait_for_clear_us(struct intel_display *display, i915_reg_t reg, + u32 mask, unsigned int timeout_us); +int intel_de_wait_for_set_ms(struct intel_display *display, i915_reg_t reg, + u32 mask, unsigned int timeout_ms); +int intel_de_wait_for_clear_ms(struct intel_display *display, i915_reg_t reg, + u32 mask, unsigned int timeout_ms); /* * Unlocked mmio-accessors, think carefully before using these. diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b18ce0c36a64..10b6c6fcb03f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4640,6 +4640,7 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state, struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct intel_crtc_state *saved_state; + int err; saved_state = intel_crtc_state_alloc(crtc); if (!saved_state) @@ -4648,7 +4649,12 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state, /* free the old crtc_state->hw members */ intel_crtc_free_hw_state(crtc_state); - intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state); + err = intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state); + if (err) { + kfree(saved_state); + + return err; + } /* FIXME: before the switch to atomic started, a new pipe_config was * kzalloc'd. Code that depends on any field being zero should be @@ -5057,24 +5063,6 @@ static bool allow_vblank_delay_fastset(const struct intel_crtc_state *old_crtc_s !intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DSI); } -static void -pipe_config_lt_phy_pll_mismatch(struct drm_printer *p, bool fastset, - const struct intel_crtc *crtc, - const char *name, - const struct intel_lt_phy_pll_state *a, - const struct intel_lt_phy_pll_state *b) -{ - struct intel_display *display = to_intel_display(crtc); - char *chipname = "LTPHY"; - - pipe_config_mismatch(p, fastset, crtc, name, chipname); - - drm_printf(p, "expected:\n"); - intel_lt_phy_dump_hw_state(display, a); - drm_printf(p, "found:\n"); - intel_lt_phy_dump_hw_state(display, b); -} - bool intel_pipe_config_compare(const struct intel_crtc_state *current_config, const struct intel_crtc_state *pipe_config, @@ -5189,16 +5177,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, } \ } while (0) -#define PIPE_CONF_CHECK_PLL_LT(name) do { \ - if (!intel_lt_phy_pll_compare_hw_state(¤t_config->name, \ - &pipe_config->name)) { \ - pipe_config_lt_phy_pll_mismatch(&p, fastset, crtc, __stringify(name), \ - ¤t_config->name, \ - &pipe_config->name); \ - ret = false; \ - } \ -} while (0) - #define PIPE_CONF_CHECK_TIMINGS(name) do { \ PIPE_CONF_CHECK_I(name.crtc_hdisplay); \ PIPE_CONF_CHECK_I(name.crtc_htotal); \ @@ -5425,10 +5403,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, if (display->dpll.mgr || HAS_GMCH(display)) PIPE_CONF_CHECK_PLL(dpll_hw_state); - /* FIXME convert MTL+ platforms over to dpll_mgr */ - if (HAS_LT_PHY(display)) - PIPE_CONF_CHECK_PLL_LT(dpll_hw_state.ltpll); - PIPE_CONF_CHECK_X(dsi_pll.ctrl); PIPE_CONF_CHECK_X(dsi_pll.div); @@ -7890,7 +7864,8 @@ static bool intel_ddi_crt_present(struct intel_display *display) bool assert_port_valid(struct intel_display *display, enum port port) { - return !drm_WARN(display->drm, !(DISPLAY_RUNTIME_INFO(display)->port_mask & BIT(port)), + return !drm_WARN(display->drm, + !(port >= 0 && DISPLAY_RUNTIME_INFO(display)->port_mask & BIT(port)), "Platform does not support port %c\n", port_name(port)); } diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index a8ef1e6193b8..be55ef8ea617 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1654,6 +1654,28 @@ static void display_platforms_or(struct intel_display_platforms *dst, bitmap_or(dst->bitmap, dst->bitmap, src->bitmap, display_platforms_num_bits()); } +#define __STEP_NAME(name) [STEP_##name] = #name, + +static void initialize_step(struct intel_display *display, enum intel_step step) +{ + static const char step_names[][3] = { + STEP_NAME_LIST(__STEP_NAME) + }; + + DISPLAY_RUNTIME_INFO(display)->step = step; + + /* Step name will remain an empty string if not applicable */ + if (step >= 0 && step < ARRAY_SIZE(step_names)) + strscpy(DISPLAY_RUNTIME_INFO(display)->step_name, step_names[step]); +} + +#undef __STEP_NAME + +static const char *step_name(const struct intel_display_runtime_info *runtime) +{ + return strlen(runtime->step_name) ? runtime->step_name : "N/A"; +} + struct intel_display *intel_display_device_probe(struct pci_dev *pdev, const struct intel_display_parent_interface *parent) { @@ -1731,14 +1753,14 @@ struct intel_display *intel_display_device_probe(struct pci_dev *pdev, subdesc ? &subdesc->step_info : NULL); } - DISPLAY_RUNTIME_INFO(display)->step = step; + initialize_step(display, step); drm_info(display->drm, "Found %s%s%s (device ID %04x) %s display version %u.%02u stepping %s\n", desc->name, subdesc ? "/" : "", subdesc ? subdesc->name : "", pdev->device, display->platform.dgfx ? "discrete" : "integrated", DISPLAY_RUNTIME_INFO(display)->ip.ver, DISPLAY_RUNTIME_INFO(display)->ip.rel, - step != STEP_NONE ? intel_step_name(step) : "N/A"); + step_name(DISPLAY_RUNTIME_INFO(display))); return display; @@ -1954,7 +1976,7 @@ void intel_display_device_info_print(const struct intel_display_device_info *inf drm_printf(p, "display version: %u\n", runtime->ip.ver); - drm_printf(p, "display stepping: %s\n", intel_step_name(runtime->step)); + drm_printf(p, "display stepping: %s\n", step_name(runtime)); #define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, str_yes_no(info->name)) DEV_INFO_DISPLAY_FOR_EACH_FLAG(PRINT_FLAG); diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index e84c190dcc4f..1170ac346615 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -287,6 +287,7 @@ struct intel_display_runtime_info { u16 step; /* hardware */ } ip; int step; /* symbolic */ + char step_name[3]; /* empty string if not applicable */ u32 rawclk_freq; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e189f8c39ccb..e2496db1642a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -835,6 +835,7 @@ struct intel_pipe_wm { struct skl_wm_level { u16 min_ddb_alloc; + u16 min_ddb_alloc_uv; /* for pre-icl */ u16 blocks; u8 lines; bool enable; @@ -845,13 +846,11 @@ struct skl_wm_level { struct skl_plane_wm { struct skl_wm_level wm[8]; - struct skl_wm_level uv_wm[8]; struct skl_wm_level trans_wm; struct { struct skl_wm_level wm0; struct skl_wm_level trans_wm; } sagv; - bool is_planar; }; struct skl_pipe_wm { @@ -1188,6 +1187,7 @@ struct intel_crtc_state { u32 dc3co_exitline; u16 su_y_granularity; u8 active_non_psr_pipes; + u8 entry_setup_frames; const char *no_psr_reason; /* diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 90ba932d940a..1667a829e708 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -39,7 +39,6 @@ #include "intel_dmc.h" #include "intel_dmc_regs.h" #include "intel_flipq.h" -#include "intel_step.h" /** * DOC: DMC Firmware Support @@ -418,15 +417,12 @@ bool intel_dmc_has_payload(struct intel_display *display) return has_dmc_id_fw(display, DMC_FW_MAIN); } -static const struct stepping_info * -intel_get_stepping_info(struct intel_display *display, - struct stepping_info *si) +static void initialize_stepping_info(struct intel_display *display, struct stepping_info *si) { - const char *step_name = intel_step_name(INTEL_DISPLAY_STEP(display)); + const char *step_name = DISPLAY_RUNTIME_INFO(display)->step_name; - si->stepping = step_name[0]; - si->substepping = step_name[1]; - return si; + si->stepping = step_name[0] ?: '*'; + si->substepping = step_name[1] ?: '*'; } static void gen9_set_dc_state_debugmask(struct intel_display *display) @@ -1274,8 +1270,7 @@ static int parse_dmc_fw(struct intel_dmc *dmc, const struct firmware *fw) struct intel_css_header *css_header; struct intel_package_header *package_header; struct intel_dmc_header_base *dmc_header; - struct stepping_info display_info = { '*', '*'}; - const struct stepping_info *si = intel_get_stepping_info(display, &display_info); + struct stepping_info si = {}; enum intel_dmc_id dmc_id; u32 readcount = 0; u32 r, offset; @@ -1283,6 +1278,8 @@ static int parse_dmc_fw(struct intel_dmc *dmc, const struct firmware *fw) if (!fw) return -EINVAL; + initialize_stepping_info(display, &si); + /* Extract CSS Header information */ css_header = (struct intel_css_header *)fw->data; r = parse_dmc_fw_css(dmc, css_header, fw->size); @@ -1293,7 +1290,7 @@ static int parse_dmc_fw(struct intel_dmc *dmc, const struct firmware *fw) /* Extract Package Header information */ package_header = (struct intel_package_header *)&fw->data[readcount]; - r = parse_dmc_fw_package(dmc, package_header, si, fw->size - readcount); + r = parse_dmc_fw_package(dmc, package_header, &si, fw->size - readcount); if (!r) return -EINVAL; diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index a7b186d0e3c4..d0c76632a946 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -610,6 +610,34 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, } static bool +check_if_vesa_backlight_possible(struct intel_dp *intel_dp) +{ + int ret; + u8 bit_min, bit_max; + + if (!(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) + return true; + + ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &bit_min); + if (ret < 0) + return false; + + bit_min &= DP_EDP_PWMGEN_BIT_COUNT_MASK; + if (bit_min < 1) + return false; + + ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX, &bit_max); + if (ret < 0) + return false; + + bit_max &= DP_EDP_PWMGEN_BIT_COUNT_MASK; + if (bit_max < bit_min) + return false; + + return true; +} + +static bool intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector) { struct intel_display *display = to_intel_display(connector); @@ -625,12 +653,14 @@ intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector) return true; } - if (drm_edp_backlight_supported(intel_dp->edp_dpcd)) { + if (drm_edp_backlight_supported(intel_dp->edp_dpcd) && + check_if_vesa_backlight_possible(intel_dp)) { drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s] AUX Backlight Control Supported!\n", connector->base.base.id, connector->base.name); return true; } + return false; } diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c index 1fd1ac8d556d..7363c9817297 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c @@ -659,19 +659,27 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, * * Clear any DP tunnel stream BW requirement set by * intel_dp_tunnel_atomic_compute_stream_bw(). + * + * Returns 0 in case of success, a negative error code otherwise. */ -void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, - struct intel_crtc_state *crtc_state) +int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + int err; if (!crtc_state->dp_tunnel_ref.tunnel) - return; + return 0; + + err = drm_dp_tunnel_atomic_set_stream_bw(&state->base, + crtc_state->dp_tunnel_ref.tunnel, + crtc->pipe, 0); + if (err) + return err; - drm_dp_tunnel_atomic_set_stream_bw(&state->base, - crtc_state->dp_tunnel_ref.tunnel, - crtc->pipe, 0); drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref); + + return 0; } /** diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h index 7f0f720e8dca..10ab9eebcef6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h @@ -40,8 +40,8 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, struct intel_dp *intel_dp, const struct intel_connector *connector, struct intel_crtc_state *crtc_state); -void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, - struct intel_crtc_state *crtc_state); +int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state); int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state, struct intel_crtc *crtc); @@ -88,9 +88,12 @@ intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, return 0; } -static inline void +static inline int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, - struct intel_crtc_state *crtc_state) {} + struct intel_crtc_state *crtc_state) +{ + return 0; +} static inline int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 8433e3ff0319..c7d37e74fbe9 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -1212,29 +1212,6 @@ static int dg2_crtc_compute_clock(struct intel_atomic_state *state, return 0; } -static int xe3plpd_crtc_compute_clock(struct intel_atomic_state *state, - struct intel_crtc *crtc) -{ - struct intel_crtc_state *crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); - struct intel_encoder *encoder = - intel_get_crtc_new_encoder(state, crtc_state); - struct intel_display *display = to_intel_display(encoder); - int ret; - - ret = intel_lt_phy_pll_calc_state(crtc_state, encoder); - if (ret) - return ret; - - /* TODO: Do the readback via intel_compute_shared_dplls() */ - crtc_state->port_clock = - intel_lt_phy_calc_port_clock(display, &crtc_state->dpll_hw_state.ltpll); - - crtc_state->hw.adjusted_mode.crtc_clock = intel_crtc_dotclock(crtc_state); - - return 0; -} - static int ilk_fb_cb_factor(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); @@ -1695,7 +1672,8 @@ static int i8xx_crtc_compute_clock(struct intel_atomic_state *state, } static const struct intel_dpll_global_funcs xe3plpd_dpll_funcs = { - .crtc_compute_clock = xe3plpd_crtc_compute_clock, + .crtc_compute_clock = hsw_crtc_compute_clock, + .crtc_get_dpll = hsw_crtc_get_dpll, }; static const struct intel_dpll_global_funcs mtl_dpll_funcs = { diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index f35a9252f4e1..f5d4f7146fbc 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -4571,6 +4571,170 @@ static const struct intel_dpll_mgr mtl_pll_mgr = { .compare_hw_state = mtl_compare_hw_state, }; +static bool xe3plpd_pll_get_hw_state(struct intel_display *display, + struct intel_dpll *pll, + struct intel_dpll_hw_state *dpll_hw_state) +{ + struct intel_encoder *encoder = get_intel_encoder(display, pll); + + if (!encoder) + return false; + + return intel_lt_phy_pll_readout_hw_state(encoder, &dpll_hw_state->ltpll); +} + +static int xe3plpd_pll_get_freq(struct intel_display *display, + const struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state) +{ + struct intel_encoder *encoder = get_intel_encoder(display, pll); + + if (drm_WARN_ON(display->drm, !encoder)) + return -EINVAL; + + return intel_lt_phy_calc_port_clock(display, &dpll_hw_state->ltpll); +} + +static void xe3plpd_pll_enable(struct intel_display *display, + struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state) +{ + struct intel_encoder *encoder = get_intel_encoder(display, pll); + + if (drm_WARN_ON(display->drm, !encoder)) + return; + + intel_xe3plpd_pll_enable(encoder, pll, dpll_hw_state); +} + +static void xe3plpd_pll_disable(struct intel_display *display, + struct intel_dpll *pll) +{ + struct intel_encoder *encoder = get_intel_encoder(display, pll); + + if (drm_WARN_ON(display->drm, !encoder)) + return; + + intel_xe3plpd_pll_disable(encoder); +} + +static const struct intel_dpll_funcs xe3plpd_tbt_pll_funcs = { + .enable = mtl_tbt_pll_enable, + .disable = mtl_tbt_pll_disable, + .get_hw_state = intel_lt_phy_tbt_pll_readout_hw_state, + .get_freq = mtl_tbt_pll_get_freq, +}; + +static const struct intel_dpll_funcs xe3plpd_pll_funcs = { + .enable = xe3plpd_pll_enable, + .disable = xe3plpd_pll_disable, + .get_hw_state = xe3plpd_pll_get_hw_state, + .get_freq = xe3plpd_pll_get_freq, +}; + +static const struct dpll_info xe3plpd_plls[] = { + { .name = "DPLL 0", .funcs = &xe3plpd_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &xe3plpd_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "TBT PLL", .funcs = &xe3plpd_tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, + .is_alt_port_dpll = true, .always_on = true }, + { .name = "TC PLL 1", .funcs = &xe3plpd_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, + { .name = "TC PLL 2", .funcs = &xe3plpd_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, + { .name = "TC PLL 3", .funcs = &xe3plpd_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, + { .name = "TC PLL 4", .funcs = &xe3plpd_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, }, + {} +}; + +static int xe3plpd_compute_non_tc_phy_dpll(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + struct intel_display *display = to_intel_display(encoder); + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct icl_port_dpll *port_dpll = + &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT]; + int ret; + + ret = intel_lt_phy_pll_calc_state(crtc_state, encoder, &port_dpll->hw_state); + if (ret) + return ret; + + /* this is mainly for the fastset check */ + icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT); + + crtc_state->port_clock = intel_lt_phy_calc_port_clock(display, &port_dpll->hw_state.ltpll); + + return 0; +} + +static int xe3plpd_compute_tc_phy_dplls(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + struct intel_display *display = to_intel_display(encoder); + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + struct icl_port_dpll *port_dpll; + int ret; + + port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT]; + intel_lt_phy_tbt_pll_calc_state(&port_dpll->hw_state); + + port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY]; + ret = intel_lt_phy_pll_calc_state(crtc_state, encoder, &port_dpll->hw_state); + if (ret) + return ret; + + /* this is mainly for the fastset check */ + if (old_crtc_state->intel_dpll && + old_crtc_state->intel_dpll->info->id == DPLL_ID_ICL_TBTPLL) + icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT); + else + icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_MG_PHY); + + crtc_state->port_clock = intel_lt_phy_calc_port_clock(display, &port_dpll->hw_state.ltpll); + + return 0; +} + +static int xe3plpd_compute_dplls(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + if (intel_encoder_is_tc(encoder)) + return xe3plpd_compute_tc_phy_dplls(state, crtc, encoder); + else + return xe3plpd_compute_non_tc_phy_dpll(state, crtc, encoder); +} + +static void xe3plpd_dump_hw_state(struct drm_printer *p, + const struct intel_dpll_hw_state *dpll_hw_state) +{ + intel_lt_phy_dump_hw_state(p, &dpll_hw_state->ltpll); +} + +static bool xe3plpd_compare_hw_state(const struct intel_dpll_hw_state *_a, + const struct intel_dpll_hw_state *_b) +{ + const struct intel_lt_phy_pll_state *a = &_a->ltpll; + const struct intel_lt_phy_pll_state *b = &_b->ltpll; + + return intel_lt_phy_pll_compare_hw_state(a, b); +} + +static const struct intel_dpll_mgr xe3plpd_pll_mgr = { + .dpll_info = xe3plpd_plls, + .compute_dplls = xe3plpd_compute_dplls, + .get_dplls = mtl_get_dplls, + .put_dplls = icl_put_dplls, + .update_active_dpll = icl_update_active_dpll, + .update_ref_clks = icl_update_dpll_ref_clks, + .dump_hw_state = xe3plpd_dump_hw_state, + .compare_hw_state = xe3plpd_compare_hw_state, +}; + /** * intel_dpll_init - Initialize DPLLs * @display: intel_display device @@ -4585,9 +4749,11 @@ void intel_dpll_init(struct intel_display *display) mutex_init(&display->dpll.lock); - if (DISPLAY_VER(display) >= 35 || display->platform.dg2) - /* No shared DPLLs on NVL or DG2; port PLLs are part of the PHY */ + if (display->platform.dg2) + /* No shared DPLLs on DG2; port PLLs are part of the PHY */ dpll_mgr = NULL; + else if (DISPLAY_VER(display) >= 35) + dpll_mgr = &xe3plpd_pll_mgr; else if (DISPLAY_VER(display) >= 14) dpll_mgr = &mtl_pll_mgr; else if (display->platform.alderlake_p) @@ -4910,6 +5076,7 @@ verify_single_dpll_state(struct intel_display *display, const struct intel_crtc_state *new_crtc_state) { struct intel_dpll_hw_state dpll_hw_state = {}; + bool pll_mismatch = false; u8 pipe_mask; bool active; @@ -4951,9 +5118,18 @@ verify_single_dpll_state(struct intel_display *display, "%s: pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n", pll->info->name, pipe_mask, pll->state.pipe_mask); - if (INTEL_DISPLAY_STATE_WARN(display, - pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state, - sizeof(dpll_hw_state)), + if (pll->on) { + const struct intel_dpll_mgr *dpll_mgr = display->dpll.mgr; + + if (HAS_LT_PHY(display)) + pll_mismatch = !dpll_mgr->compare_hw_state(&pll->state.hw_state, + &dpll_hw_state); + else + pll_mismatch = memcmp(&pll->state.hw_state, &dpll_hw_state, + sizeof(dpll_hw_state)); + } + + if (INTEL_DISPLAY_STATE_WARN(display, pll_mismatch, "%s: pll hw state mismatch\n", pll->info->name)) { struct drm_printer p = drm_dbg_printer(display->drm, DRM_UT_KMS, NULL); diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index 4cc14ce5eebe..d408ccf6f902 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -278,6 +278,7 @@ struct intel_lt_phy_pll_state { u8 config[3]; bool ssc_enabled; bool tbt_mode; + int lane_count; }; struct intel_dpll_hw_state { diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h index 489d26ffd235..9fcdabbf3740 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi.h +++ b/drivers/gpu/drm/i915/display/intel_dsi.h @@ -80,9 +80,10 @@ struct intel_dsi { /* NON_BURST_SYNC_PULSE, NON_BURST_SYNC_EVENTS, or BURST_MODE */ int video_mode; - /* eot for MIPI_EOT_DISABLE register */ - u8 eotp_pkt; - u8 clock_stop; + bool lp_clock_during_lpm; + bool blanking_pkt; + bool eot_pkt; + bool clock_stop; u8 escape_clk_div; u8 dual_link; diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 18755a8e613d..fe12041e913c 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -718,8 +718,10 @@ void intel_dsi_log_params(struct intel_dsi *intel_dsi) "burst" : "<unknown>"); drm_printf(&p, "Burst mode ratio %d\n", intel_dsi->burst_mode_ratio); drm_printf(&p, "Reset timer %d\n", intel_dsi->rst_timer_val); - drm_printf(&p, "Eot %s\n", str_enabled_disabled(intel_dsi->eotp_pkt)); - drm_printf(&p, "Clockstop %s\n", str_enabled_disabled(!intel_dsi->clock_stop)); + drm_printf(&p, "LP clock during LPM %s\n", str_enabled_disabled(intel_dsi->lp_clock_during_lpm)); + drm_printf(&p, "Blanking packets during BLLP %s\n", str_enabled_disabled(intel_dsi->blanking_pkt)); + drm_printf(&p, "EoT packet %s\n", str_enabled_disabled(intel_dsi->eot_pkt)); + drm_printf(&p, "Clock stop during BLLP %s\n", str_enabled_disabled(intel_dsi->clock_stop)); drm_printf(&p, "Mode %s\n", intel_dsi->operation_mode ? "command" : "video"); if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) drm_printf(&p, "Dual link: DSI_DUAL_LINK_FRONT_BACK\n"); @@ -770,8 +772,10 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) drm_dbg_kms(display->drm, "\n"); - intel_dsi->eotp_pkt = mipi_config->eot_pkt_disabled ? 0 : 1; - intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0; + intel_dsi->lp_clock_during_lpm = mipi_config->lp_clock_during_lpm; + intel_dsi->blanking_pkt = mipi_config->blanking_packets_during_bllp; + intel_dsi->eot_pkt = !mipi_config->eot_pkt_disabled; + intel_dsi->clock_stop = mipi_config->enable_clk_stop; intel_dsi->lane_count = mipi_config->lane_cnt + 1; intel_dsi->pixel_format = vbt_to_dsi_pixel_format(mipi_config->videomode_color_format); diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index df48f27f1cc1..ea5cf8f51b31 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -495,8 +495,10 @@ gmbus_xfer_read_chunk(struct intel_display *display, val = intel_de_read_fw(display, GMBUS3(display)); do { - if (extra_byte_added && len == 1) + if (extra_byte_added && len == 1) { + len--; break; + } *buf++ = val & 0xff; val >>= 8; @@ -692,7 +694,7 @@ retry: goto clear_err; } - /* Generate a STOP condition on the bus. Note that gmbus can't generata + /* Generate a STOP condition on the bus. Note that gmbus can't generate * a STOP on the very first cycle. To simplify the code we * unconditionally generate the STOP condition with an additional gmbus * cycle. */ diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index eced8493e566..657ad5cb0eff 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -11,6 +11,7 @@ #include "intel_ddi_buf_trans.h" #include "intel_de.h" #include "intel_display.h" +#include "intel_display_regs.h" #include "intel_display_types.h" #include "intel_display_utils.h" #include "intel_dpll.h" @@ -32,6 +33,7 @@ INTEL_LT_PHY_LANE0) #define MODE_DP 3 #define MODE_HDMI_20 4 +#define MODE_HDMI_FRL 5 #define Q32_TO_INT(x) ((x) >> 32) #define Q32_TO_FRAC(x) ((x) & 0xFFFFFFFF) #define DCO_MIN_FREQ_MHZ 11850 @@ -1176,9 +1178,30 @@ intel_lt_phy_lane_reset(struct intel_encoder *encoder, intel_de_rmw(display, XELPDP_PORT_BUF_CTL2(display, port), lane_phy_pulse_status, 0); } +static bool intel_lt_phy_is_hdmi(const struct intel_lt_phy_pll_state *ltpll) +{ + u8 mode = REG_FIELD_GET8(LT_PHY_VDR_MODE_ENCODING_MASK, ltpll->config[0]); + + if (mode == MODE_HDMI_20 || mode == MODE_HDMI_FRL) + return true; + + return false; +} + +static bool intel_lt_phy_is_dp(const struct intel_lt_phy_pll_state *ltpll) +{ + u8 mode = REG_FIELD_GET8(LT_PHY_VDR_MODE_ENCODING_MASK, ltpll->config[0]); + + if (mode == MODE_DP) + return true; + + return false; +} + static void intel_lt_phy_program_port_clock_ctl(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, + const struct intel_lt_phy_pll_state *ltpll, + int port_clock, bool lane_reversal) { struct intel_display *display = to_intel_display(encoder); @@ -1195,17 +1218,16 @@ intel_lt_phy_program_port_clock_ctl(struct intel_encoder *encoder, * but since the register bits still remain the same we use * the same definition */ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) && - intel_hdmi_is_frl(crtc_state->port_clock)) + if (intel_lt_phy_is_hdmi(ltpll) && intel_hdmi_is_frl(port_clock)) val |= XELPDP_DDI_CLOCK_SELECT_PREP(display, XELPDP_DDI_CLOCK_SELECT_DIV18CLK); else val |= XELPDP_DDI_CLOCK_SELECT_PREP(display, XELPDP_DDI_CLOCK_SELECT_MAXPCLK); /* DP2.0 10G and 20G rates enable MPLLA*/ - if (crtc_state->port_clock == 1000000 || crtc_state->port_clock == 2000000) + if (port_clock == 1000000 || port_clock == 2000000) val |= XELPDP_SSC_ENABLE_PLLA; else - val |= crtc_state->dpll_hw_state.ltpll.ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; + val |= ltpll->ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder->port), XELPDP_LANE1_PHY_CLOCK_SELECT | XELPDP_FORWARD_CLOCK_UNGATE | @@ -1248,7 +1270,8 @@ static u32 intel_lt_phy_get_dp_clock(u8 rate) static bool intel_lt_phy_config_changed(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) + const struct intel_lt_phy_pll_state *ltpll, + u32 port_clock) { u8 val, rate; u32 clock; @@ -1262,9 +1285,9 @@ intel_lt_phy_config_changed(struct intel_encoder *encoder, * using 1.62 Gbps clock since PHY PLL defaults to that * otherwise we always need to reconfigure it. */ - if (intel_crtc_has_dp_encoder(crtc_state)) { + if (intel_lt_phy_is_dp(ltpll)) { clock = intel_lt_phy_get_dp_clock(rate); - if (crtc_state->port_clock == 1620000 && crtc_state->port_clock == clock) + if (port_clock == 1620000 && port_clock == clock) return false; } @@ -1723,12 +1746,15 @@ intel_lt_phy_calc_port_clock(struct intel_display *display, int intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state, - struct intel_encoder *encoder) + struct intel_encoder *encoder, + struct intel_dpll_hw_state *hw_state) { struct intel_display *display = to_intel_display(crtc_state); const struct intel_lt_phy_pll_params *tables; int i; + memset(hw_state, 0, sizeof(*hw_state)); + tables = intel_lt_phy_pll_tables_get(crtc_state, encoder); if (!tables) return -EINVAL; @@ -1738,62 +1764,71 @@ intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state, drm_WARN_ON(display->drm, !intel_dpll_clock_matches(clock, tables[i].clock_rate)); if (intel_dpll_clock_matches(crtc_state->port_clock, clock)) { - crtc_state->dpll_hw_state.ltpll = *tables[i].state; + hw_state->ltpll = *tables[i].state; if (intel_crtc_has_dp_encoder(crtc_state)) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - crtc_state->dpll_hw_state.ltpll.config[2] = 1; + hw_state->ltpll.config[2] = 1; } - crtc_state->dpll_hw_state.ltpll.ssc_enabled = + hw_state->ltpll.ssc_enabled = intel_lt_phy_pll_is_ssc_enabled(crtc_state, encoder); + hw_state->ltpll.lane_count = crtc_state->lane_count; return 0; } } if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { - return intel_lt_phy_calculate_hdmi_state(&crtc_state->dpll_hw_state.ltpll, + hw_state->ltpll.lane_count = crtc_state->lane_count; + return intel_lt_phy_calculate_hdmi_state(&hw_state->ltpll, crtc_state->port_clock); } return -EINVAL; } +void intel_lt_phy_tbt_pll_calc_state(struct intel_dpll_hw_state *hw_state) +{ + memset(hw_state, 0, sizeof(*hw_state)); + + hw_state->ltpll.tbt_mode = true; +} + static void intel_lt_phy_program_pll(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) + const struct intel_lt_phy_pll_state *ltpll) { u8 owned_lane_mask = intel_lt_phy_get_owned_lane_mask(encoder); int i, j, k; intel_lt_phy_write(encoder, owned_lane_mask, LT_PHY_VDR_0_CONFIG, - crtc_state->dpll_hw_state.ltpll.config[0], MB_WRITE_COMMITTED); + ltpll->config[0], MB_WRITE_COMMITTED); intel_lt_phy_write(encoder, INTEL_LT_PHY_LANE0, LT_PHY_VDR_1_CONFIG, - crtc_state->dpll_hw_state.ltpll.config[1], MB_WRITE_COMMITTED); + ltpll->config[1], MB_WRITE_COMMITTED); intel_lt_phy_write(encoder, owned_lane_mask, LT_PHY_VDR_2_CONFIG, - crtc_state->dpll_hw_state.ltpll.config[2], MB_WRITE_COMMITTED); + ltpll->config[2], MB_WRITE_COMMITTED); for (i = 0; i <= 12; i++) { intel_lt_phy_write(encoder, INTEL_LT_PHY_LANE0, LT_PHY_VDR_X_ADDR_MSB(i), - crtc_state->dpll_hw_state.ltpll.addr_msb[i], + ltpll->addr_msb[i], MB_WRITE_COMMITTED); intel_lt_phy_write(encoder, INTEL_LT_PHY_LANE0, LT_PHY_VDR_X_ADDR_LSB(i), - crtc_state->dpll_hw_state.ltpll.addr_lsb[i], + ltpll->addr_lsb[i], MB_WRITE_COMMITTED); for (j = 3, k = 0; j >= 0; j--, k++) intel_lt_phy_write(encoder, INTEL_LT_PHY_LANE0, LT_PHY_VDR_X_DATAY(i, j), - crtc_state->dpll_hw_state.ltpll.data[i][k], + ltpll->data[i][k], MB_WRITE_COMMITTED); } } static void intel_lt_phy_enable_disable_tx(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) + const struct intel_lt_phy_pll_state *ltpll) { struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool lane_reversal = dig_port->lane_reversal; - u8 lane_count = crtc_state->lane_count; + u8 lane_count = ltpll->lane_count; bool is_dp_alt = intel_tc_port_in_dp_alt_mode(dig_port); enum intel_tc_pin_assignment tc_pin = @@ -1874,9 +1909,11 @@ intel_lt_phy_enable_disable_tx(struct intel_encoder *encoder, } void intel_lt_phy_pll_enable(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) + struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state) { struct intel_display *display = to_intel_display(encoder); + int port_clock = intel_lt_phy_calc_port_clock(display, &dpll_hw_state->ltpll); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool lane_reversal = dig_port->lane_reversal; u8 owned_lane_mask = intel_lt_phy_get_owned_lane_mask(encoder); @@ -1892,10 +1929,11 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder, wakeref = intel_lt_phy_transaction_begin(encoder); /* 1. Enable MacCLK at default 162 MHz frequency. */ - intel_lt_phy_lane_reset(encoder, crtc_state->lane_count); + intel_lt_phy_lane_reset(encoder, dpll_hw_state->ltpll.lane_count); /* 2. Program PORT_CLOCK_CTL register to configure clock muxes, gating, and SSC. */ - intel_lt_phy_program_port_clock_ctl(encoder, crtc_state, lane_reversal); + intel_lt_phy_program_port_clock_ctl(encoder, &dpll_hw_state->ltpll, + port_clock, lane_reversal); /* 3. Change owned PHY lanes power to Ready state. */ intel_lt_phy_powerdown_change_sequence(encoder, owned_lane_mask, @@ -1905,12 +1943,12 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder, * 4. Read the PHY message bus VDR register PHY_VDR_0_Config check enabled PLL type, * encoded rate and encoded mode. */ - if (intel_lt_phy_config_changed(encoder, crtc_state)) { + if (intel_lt_phy_config_changed(encoder, &dpll_hw_state->ltpll, port_clock)) { /* * 5. Program the PHY internal PLL registers over PHY message bus for the desired * frequency and protocol type */ - intel_lt_phy_program_pll(encoder, crtc_state); + intel_lt_phy_program_pll(encoder, &dpll_hw_state->ltpll); /* 6. Use the P2P transaction flow */ /* @@ -1942,8 +1980,7 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder, * Change. We handle this step in bxt_set_cdclk(). */ /* 10. Program DDI_CLK_VALFREQ to match intended DDI clock frequency. */ - intel_de_write(display, DDI_CLK_VALFREQ(encoder->port), - crtc_state->port_clock); + intel_de_write(display, DDI_CLK_VALFREQ(encoder->port), port_clock); /* 11. Program PORT_CLOCK_CTL[PCLK PLL Request LN0] = 1. */ intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, port), @@ -1990,7 +2027,7 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder, lane_phy_pulse_status, lane_phy_pulse_status); } else { - intel_de_write(display, DDI_CLK_VALFREQ(encoder->port), crtc_state->port_clock); + intel_de_write(display, DDI_CLK_VALFREQ(encoder->port), port_clock); } /* @@ -2001,7 +2038,7 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder, intel_lt_phy_powerdown_change_sequence(encoder, owned_lane_mask, XELPDP_P0_STATE_ACTIVE); - intel_lt_phy_enable_disable_tx(encoder, crtc_state); + intel_lt_phy_enable_disable_tx(encoder, &dpll_hw_state->ltpll); intel_lt_phy_transaction_end(encoder, wakeref); } @@ -2136,21 +2173,23 @@ void intel_lt_phy_set_signal_levels(struct intel_encoder *encoder, intel_lt_phy_transaction_end(encoder, wakeref); } -void intel_lt_phy_dump_hw_state(struct intel_display *display, +void intel_lt_phy_dump_hw_state(struct drm_printer *p, const struct intel_lt_phy_pll_state *hw_state) { int i, j; - drm_dbg_kms(display->drm, "lt_phy_pll_hw_state:\n"); + drm_printf(p, "lt_phy_pll_hw_state: lane count: %d, ssc enabled: %d, tbt mode: %d\n", + hw_state->lane_count, hw_state->ssc_enabled, hw_state->tbt_mode); + for (i = 0; i < 3; i++) { - drm_dbg_kms(display->drm, "config[%d] = 0x%.4x,\n", - i, hw_state->config[i]); + drm_printf(p, "config[%d] = 0x%.4x,\n", + i, hw_state->config[i]); } for (i = 0; i <= 12; i++) for (j = 3; j >= 0; j--) - drm_dbg_kms(display->drm, "vdr_data[%d][%d] = 0x%.4x,\n", - i, j, hw_state->data[i][j]); + drm_printf(p, "vdr_data[%d][%d] = 0x%.4x,\n", + i, j, hw_state->data[i][j]); } bool @@ -2174,8 +2213,26 @@ intel_lt_phy_pll_compare_hw_state(const struct intel_lt_phy_pll_state *a, return false; } -void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, +static bool intel_lt_phy_pll_is_enabled(struct intel_encoder *encoder) +{ + struct intel_display *display = to_intel_display(encoder); + + return intel_de_read(display, XELPDP_PORT_CLOCK_CTL(display, encoder->port)) & + XELPDP_LANE_PCLK_PLL_ACK(0); +} + +bool intel_lt_phy_tbt_pll_readout_hw_state(struct intel_display *display, + struct intel_dpll *pll, + struct intel_dpll_hw_state *hw_state) +{ + memset(hw_state, 0, sizeof(*hw_state)); + + hw_state->ltpll.tbt_mode = true; + + return true; +} + +bool intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, struct intel_lt_phy_pll_state *pll_state) { u8 owned_lane_mask; @@ -2183,14 +2240,19 @@ void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, struct ref_tracker *wakeref; int i, j, k; + if (!intel_lt_phy_pll_is_enabled(encoder)) + return false; + pll_state->tbt_mode = intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder)); if (pll_state->tbt_mode) - return; + return false; owned_lane_mask = intel_lt_phy_get_owned_lane_mask(encoder); lane = owned_lane_mask & INTEL_LT_PHY_LANE0 ? : INTEL_LT_PHY_LANE1; wakeref = intel_lt_phy_transaction_begin(encoder); + pll_state->lane_count = intel_readout_lane_count(encoder, INTEL_LT_PHY_LANE0, + INTEL_LT_PHY_LANE1); pll_state->config[0] = intel_lt_phy_read(encoder, lane, LT_PHY_VDR_0_CONFIG); pll_state->config[1] = intel_lt_phy_read(encoder, INTEL_LT_PHY_LANE0, LT_PHY_VDR_1_CONFIG); pll_state->config[2] = intel_lt_phy_read(encoder, lane, LT_PHY_VDR_2_CONFIG); @@ -2203,56 +2265,15 @@ void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, } intel_lt_phy_transaction_end(encoder, wakeref); -} - -void intel_lt_phy_pll_state_verify(struct intel_atomic_state *state, - struct intel_crtc *crtc) -{ - struct intel_display *display = to_intel_display(state); - struct intel_digital_port *dig_port; - const struct intel_crtc_state *new_crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); - struct intel_encoder *encoder; - struct intel_lt_phy_pll_state pll_hw_state = {}; - const struct intel_lt_phy_pll_state *pll_sw_state = &new_crtc_state->dpll_hw_state.ltpll; - - if (DISPLAY_VER(display) < 35) - return; - if (!new_crtc_state->hw.active) - return; - - /* intel_get_crtc_new_encoder() only works for modeset/fastset commits */ - if (!intel_crtc_needs_modeset(new_crtc_state) && - !intel_crtc_needs_fastset(new_crtc_state)) - return; - - encoder = intel_get_crtc_new_encoder(state, new_crtc_state); - intel_lt_phy_pll_readout_hw_state(encoder, new_crtc_state, &pll_hw_state); - - dig_port = enc_to_dig_port(encoder); - if (intel_tc_port_in_tbt_alt_mode(dig_port)) - return; - - INTEL_DISPLAY_STATE_WARN(display, pll_hw_state.config[0] != pll_sw_state->config[0], - "[CRTC:%d:%s] mismatch in LT PHY PLL CONFIG 0: (expected 0x%04x, found 0x%04x)", - crtc->base.base.id, crtc->base.name, - pll_sw_state->config[0], pll_hw_state.config[0]); - INTEL_DISPLAY_STATE_WARN(display, pll_hw_state.config[2] != pll_sw_state->config[2], - "[CRTC:%d:%s] mismatch in LT PHY PLL CONFIG 2: (expected 0x%04x, found 0x%04x)", - crtc->base.base.id, crtc->base.name, - pll_sw_state->config[2], pll_hw_state.config[2]); + return true; } void intel_xe3plpd_pll_enable(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) + struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state) { - struct intel_digital_port *dig_port = enc_to_dig_port(encoder); - - if (intel_tc_port_in_tbt_alt_mode(dig_port)) - intel_mtl_tbt_pll_enable_clock(encoder, crtc_state->port_clock); - else - intel_lt_phy_pll_enable(encoder, crtc_state); + intel_lt_phy_pll_enable(encoder, pll, dpll_hw_state); } void intel_xe3plpd_pll_disable(struct intel_encoder *encoder) @@ -2294,7 +2315,7 @@ static void intel_lt_phy_pll_verify_clock(struct intel_display *display, drm_printf(&p, "PLL state %s (%s):\n", pll_state_name, is_precomputed_state ? "precomputed" : "computed"); - intel_lt_phy_dump_hw_state(display, pll_state); + intel_lt_phy_dump_hw_state(&p, pll_state); } static void intel_lt_phy_pll_verify_params(struct intel_display *display, diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.h b/drivers/gpu/drm/i915/display/intel_lt_phy.h index db905668f86d..16de39484779 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.h +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.h @@ -8,38 +8,45 @@ #include <linux/types.h> +struct drm_printer; struct intel_atomic_state; struct intel_display; +struct intel_dpll; +struct intel_dpll_hw_state; struct intel_encoder; struct intel_crtc_state; struct intel_crtc; struct intel_lt_phy_pll_state; void intel_lt_phy_pll_enable(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); + struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state); void intel_lt_phy_pll_disable(struct intel_encoder *encoder); int intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state, - struct intel_encoder *encoder); + struct intel_encoder *encoder, + struct intel_dpll_hw_state *hw_state); +void intel_lt_phy_tbt_pll_calc_state(struct intel_dpll_hw_state *hw_state); int intel_lt_phy_calc_port_clock(struct intel_display *display, const struct intel_lt_phy_pll_state *lt_state); void intel_lt_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); -void intel_lt_phy_dump_hw_state(struct intel_display *display, +void intel_lt_phy_dump_hw_state(struct drm_printer *p, const struct intel_lt_phy_pll_state *hw_state); bool intel_lt_phy_pll_compare_hw_state(const struct intel_lt_phy_pll_state *a, const struct intel_lt_phy_pll_state *b); -void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, +bool intel_lt_phy_tbt_pll_readout_hw_state(struct intel_display *display, + struct intel_dpll *pll, + struct intel_dpll_hw_state *hw_state); +bool intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, struct intel_lt_phy_pll_state *pll_state); -void intel_lt_phy_pll_state_verify(struct intel_atomic_state *state, - struct intel_crtc *crtc); int intel_lt_phy_calculate_hdmi_state(struct intel_lt_phy_pll_state *lt_state, u32 frequency_khz); void intel_xe3plpd_pll_enable(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); + struct intel_dpll *pll, + const struct intel_dpll_hw_state *dpll_hw_state); void intel_xe3plpd_pll_disable(struct intel_encoder *encoder); void intel_lt_phy_verify_plls(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 12a00121c274..2ec17c2bfe0f 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -246,7 +246,6 @@ void intel_modeset_verify_crtc(struct intel_atomic_state *state, verify_crtc_state(state, crtc); intel_dpll_state_verify(state, crtc); intel_mpllb_state_verify(state, crtc); - intel_lt_phy_pll_state_verify(state, crtc); } void intel_modeset_verify_disabled(struct intel_atomic_state *state) diff --git a/drivers/gpu/drm/i915/display/intel_pch.c b/drivers/gpu/drm/i915/display/intel_pch.c index 65359a36df48..d2c1b1751838 100644 --- a/drivers/gpu/drm/i915/display/intel_pch.c +++ b/drivers/gpu/drm/i915/display/intel_pch.c @@ -5,6 +5,9 @@ #include <drm/drm_print.h> +#include "intel_de.h" +#include "intel_display.h" +#include "intel_display_regs.h" #include "intel_display_core.h" #include "intel_display_utils.h" #include "intel_pch.h" @@ -214,6 +217,96 @@ intel_pch_type(const struct intel_display *display, unsigned short id) } } +static void intel_pch_ibx_init_clock_gating(struct intel_display *display) +{ + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + intel_de_write(display, SOUTH_DSPCLK_GATE_D, + PCH_DPLSUNIT_CLOCK_GATE_DISABLE); +} + +static void intel_pch_cpt_init_clock_gating(struct intel_display *display) +{ + enum pipe pipe; + u32 val; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + intel_de_write(display, SOUTH_DSPCLK_GATE_D, + PCH_DPLSUNIT_CLOCK_GATE_DISABLE | + PCH_DPLUNIT_CLOCK_GATE_DISABLE | + PCH_CPUNIT_CLOCK_GATE_DISABLE); + intel_de_rmw(display, SOUTH_CHICKEN2, 0, DPLS_EDP_PPS_FIX_DIS); + + /* The below fixes the weird display corruption, a few pixels shifted + * downward, on (only) LVDS of some HP laptops with IVY. + */ + for_each_pipe(display, pipe) { + val = intel_de_read(display, TRANS_CHICKEN2(pipe)); + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; + val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED; + if (display->vbt.fdi_rx_polarity_inverted) + val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; + val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER; + val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH; + intel_de_write(display, TRANS_CHICKEN2(pipe), val); + } + + /* WADP0ClockGatingDisable */ + for_each_pipe(display, pipe) + intel_de_write(display, TRANS_CHICKEN1(pipe), + TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); +} + +static void intel_pch_lpt_init_clock_gating(struct intel_display *display) +{ + /* + * TODO: this bit should only be enabled when really needed, then + * disabled when not needed anymore in order to save power. + */ + if (HAS_PCH_LPT_LP(display)) + intel_de_rmw(display, SOUTH_DSPCLK_GATE_D, 0, + PCH_LP_PARTITION_LEVEL_DISABLE); + + /* WADPOClockGatingDisable:hsw */ + intel_de_rmw(display, TRANS_CHICKEN1(PIPE_A), 0, + TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); +} + +static void intel_pch_cnp_init_clock_gating(struct intel_display *display) +{ + /* Display WA #1181 WaSouthDisplayDisablePWMCGEGating: cnp */ + intel_de_rmw(display, SOUTH_DSPCLK_GATE_D, 0, + CNP_PWM_CGE_GATING_DISABLE); +} + +void intel_pch_init_clock_gating(struct intel_display *display) +{ + switch (INTEL_PCH_TYPE(display)) { + case PCH_IBX: + intel_pch_ibx_init_clock_gating(display); + break; + case PCH_CPT: + intel_pch_cpt_init_clock_gating(display); + break; + case PCH_LPT_H: + case PCH_LPT_LP: + intel_pch_lpt_init_clock_gating(display); + break; + case PCH_CNP: + intel_pch_cnp_init_clock_gating(display); + break; + default: + break; + } +} + static bool intel_is_virt_pch(unsigned short id, unsigned short svendor, unsigned short sdevice) { diff --git a/drivers/gpu/drm/i915/display/intel_pch.h b/drivers/gpu/drm/i915/display/intel_pch.h index 19cac7412d0a..aa971fa141e7 100644 --- a/drivers/gpu/drm/i915/display/intel_pch.h +++ b/drivers/gpu/drm/i915/display/intel_pch.h @@ -52,5 +52,6 @@ enum intel_pch { #define HAS_PCH_SPLIT(display) (INTEL_PCH_TYPE(display) != PCH_NONE) void intel_pch_detect(struct intel_display *display); +void intel_pch_init_clock_gating(struct intel_display *display); #endif /* __INTEL_PCH__ */ diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index e06a0618b4c6..5390ceb21ca4 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -436,11 +436,38 @@ void intel_plane_copy_hw_state(struct intel_plane_state *plane_state, drm_framebuffer_get(plane_state->hw.fb); } +static void unlink_nv12_plane(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + + if (!plane_state->planar_linked_plane) + return; + + plane_state->planar_linked_plane = NULL; + + if (!plane_state->is_y_plane) + return; + + drm_WARN_ON(display->drm, plane_state->uapi.visible); + + plane_state->is_y_plane = false; + + crtc_state->enabled_planes &= ~BIT(plane->id); + crtc_state->active_planes &= ~BIT(plane->id); + crtc_state->update_planes |= BIT(plane->id); + crtc_state->data_rate[plane->id] = 0; + crtc_state->rel_data_rate[plane->id] = 0; +} + void intel_plane_set_invisible(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + unlink_nv12_plane(crtc_state, plane_state); + crtc_state->active_planes &= ~BIT(plane->id); crtc_state->scaled_planes &= ~BIT(plane->id); crtc_state->nv12_planes &= ~BIT(plane->id); @@ -1507,28 +1534,6 @@ static void link_nv12_planes(struct intel_crtc_state *crtc_state, icl_link_nv12_planes(uv_plane_state, y_plane_state); } -static void unlink_nv12_plane(struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) -{ - struct intel_display *display = to_intel_display(plane_state); - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - - plane_state->planar_linked_plane = NULL; - - if (!plane_state->is_y_plane) - return; - - drm_WARN_ON(display->drm, plane_state->uapi.visible); - - plane_state->is_y_plane = false; - - crtc_state->enabled_planes &= ~BIT(plane->id); - crtc_state->active_planes &= ~BIT(plane->id); - crtc_state->update_planes |= BIT(plane->id); - crtc_state->data_rate[plane->id] = 0; - crtc_state->rel_data_rate[plane->id] = 0; -} - static int icl_check_nv12_planes(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -1542,18 +1547,6 @@ static int icl_check_nv12_planes(struct intel_atomic_state *state, if (DISPLAY_VER(display) < 11) return 0; - /* - * Destroy all old plane links and make the Y plane invisible - * in the crtc_state->active_planes mask. - */ - for_each_new_intel_plane_in_state(state, plane, plane_state, i) { - if (plane->pipe != crtc->pipe) - continue; - - if (plane_state->planar_linked_plane) - unlink_nv12_plane(crtc_state, plane_state); - } - if (!crtc_state->nv12_planes) return 0; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 5041a5a138d1..2f1b48cd8efd 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -49,6 +49,7 @@ #include "intel_hdmi.h" #include "intel_psr.h" #include "intel_psr_regs.h" +#include "intel_quirks.h" #include "intel_snps_phy.h" #include "intel_step.h" #include "intel_vblank.h" @@ -609,6 +610,13 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp, struct intel_conn if (intel_dp->mst_detect == DRM_DP_MST) return; + if (intel_dp_is_edp(intel_dp) && + intel_has_dpcd_quirk(intel_dp, QUIRK_DISABLE_EDP_PANEL_REPLAY)) { + drm_dbg_kms(display->drm, + "Panel Replay support not currently available for this setup\n"); + return; + } + ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PANEL_REPLAY_CAP_SUPPORT, &connector->dp.panel_replay_caps.dpcd, sizeof(connector->dp.panel_replay_caps.dpcd)); @@ -1716,7 +1724,7 @@ static bool _psr_compute_config(struct intel_dp *intel_dp, entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, conn_state, adjusted_mode); if (entry_setup_frames >= 0) { - intel_dp->psr.entry_setup_frames = entry_setup_frames; + crtc_state->entry_setup_frames = entry_setup_frames; } else { crtc_state->no_psr_reason = "PSR setup timing not met"; drm_dbg_kms(display->drm, @@ -1814,7 +1822,7 @@ static bool intel_psr_needs_wa_18037818876(struct intel_dp *intel_dp, { struct intel_display *display = to_intel_display(intel_dp); - return (DISPLAY_VER(display) == 20 && intel_dp->psr.entry_setup_frames > 0 && + return (DISPLAY_VER(display) == 20 && crtc_state->entry_setup_frames > 0 && !crtc_state->has_sel_update); } @@ -2190,6 +2198,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, intel_dp->psr.pkg_c_latency_used = crtc_state->pkg_c_latency_used; intel_dp->psr.io_wake_lines = crtc_state->alpm_state.io_wake_lines; intel_dp->psr.fast_wake_lines = crtc_state->alpm_state.fast_wake_lines; + intel_dp->psr.entry_setup_frames = crtc_state->entry_setup_frames; if (!psr_interrupt_error_check(intel_dp)) return; @@ -3112,6 +3121,8 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state, * - Display WA #1136: skl, bxt */ if (intel_crtc_needs_modeset(new_crtc_state) || + new_crtc_state->update_m_n || + new_crtc_state->update_lrr || !new_crtc_state->has_psr || !new_crtc_state->active_planes || new_crtc_state->has_sel_update != psr->sel_update_enabled || diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c index 1abbdd426e58..883f297d4b83 100644 --- a/drivers/gpu/drm/i915/display/intel_quirks.c +++ b/drivers/gpu/drm/i915/display/intel_quirks.c @@ -86,6 +86,14 @@ static void quirk_edp_limit_rate_hbr2(struct intel_display *display) drm_info(display->drm, "Applying eDP Limit rate to HBR2 quirk\n"); } +static void quirk_disable_edp_panel_replay(struct intel_dp *intel_dp) +{ + struct intel_display *display = to_intel_display(intel_dp); + + intel_set_dpcd_quirk(intel_dp, QUIRK_DISABLE_EDP_PANEL_REPLAY); + drm_info(display->drm, "Applying disable Panel Replay quirk\n"); +} + struct intel_quirk { int device; int subsystem_vendor; @@ -108,6 +116,8 @@ struct intel_dpcd_quirk { #define SINK_DEVICE_ID_ANY SINK_DEVICE_ID(0, 0, 0, 0, 0, 0) +#define DEVICE_ID_ANY 0 + /* For systems that don't have a meaningful PCI subdevice/subvendor ID */ struct intel_dmi_quirk { void (*hook)(struct intel_display *display); @@ -251,7 +261,14 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = { .sink_oui = SINK_OUI(0x38, 0xec, 0x11), .hook = quirk_fw_sync_len, }, - + /* Dell XPS 14 DA14260 */ + { + .device = DEVICE_ID_ANY, + .subsystem_vendor = 0x1028, + .subsystem_device = 0x0db9, + .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), + .hook = quirk_disable_edp_panel_replay, + }, }; void intel_init_quirks(struct intel_display *display) @@ -262,7 +279,8 @@ void intel_init_quirks(struct intel_display *display) for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) { struct intel_quirk *q = &intel_quirks[i]; - if (d->device == q->device && + if ((d->device == q->device || + q->device == DEVICE_ID_ANY) && (d->subsystem_vendor == q->subsystem_vendor || q->subsystem_vendor == PCI_ANY_ID) && (d->subsystem_device == q->subsystem_device || @@ -285,7 +303,8 @@ void intel_init_dpcd_quirks(struct intel_dp *intel_dp, for (i = 0; i < ARRAY_SIZE(intel_dpcd_quirks); i++) { const struct intel_dpcd_quirk *q = &intel_dpcd_quirks[i]; - if (d->device == q->device && + if ((d->device == q->device || + q->device == DEVICE_ID_ANY) && (d->subsystem_vendor == q->subsystem_vendor || q->subsystem_vendor == PCI_ANY_ID) && (d->subsystem_device == q->subsystem_device || diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h index 06da0e286c67..83214eb94b0c 100644 --- a/drivers/gpu/drm/i915/display/intel_quirks.h +++ b/drivers/gpu/drm/i915/display/intel_quirks.h @@ -21,6 +21,7 @@ enum intel_quirk_id { QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK, QUIRK_FW_SYNC_LEN, QUIRK_EDP_LIMIT_RATE_HBR2, + QUIRK_DISABLE_EDP_PANEL_REPLAY, }; void intel_init_quirks(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index b1f9546b8cda..d45b3bcc6ef0 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -63,7 +63,6 @@ static void skl_sagv_disable(struct intel_display *display); struct skl_wm_params { bool x_tiled, y_tiled; bool rc_surface; - bool is_planar; u32 width; u8 cpp; u32 plane_pixel_rate; @@ -1357,14 +1356,13 @@ skl_check_wm_level(struct skl_wm_level *wm, const struct skl_ddb_entry *ddb) } static void -skl_check_nv12_wm_level(struct skl_wm_level *wm, struct skl_wm_level *uv_wm, - const struct skl_ddb_entry *ddb_y, const struct skl_ddb_entry *ddb) +skl_check_wm_level_nv12(struct skl_wm_level *wm, + const struct skl_ddb_entry *ddb_y, + const struct skl_ddb_entry *ddb) { if (wm->min_ddb_alloc > skl_ddb_entry_size(ddb_y) || - uv_wm->min_ddb_alloc > skl_ddb_entry_size(ddb)) { + wm->min_ddb_alloc_uv > skl_ddb_entry_size(ddb)) memset(wm, 0, sizeof(*wm)); - memset(uv_wm, 0, sizeof(*uv_wm)); - } } static bool skl_need_wm_copy_wa(struct intel_display *display, int level, @@ -1391,10 +1389,9 @@ struct skl_plane_ddb_iter { }; static void -skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, - struct skl_ddb_entry *ddb, - const struct skl_wm_level *wm, - u64 data_rate) +_skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, + u16 min_ddb_alloc, + struct skl_ddb_entry *ddb, u64 data_rate) { u16 size, extra = 0; @@ -1411,12 +1408,30 @@ skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, * to avoid skl_ddb_add_affected_planes() adding them to * the state when other planes change their allocations. */ - size = wm->min_ddb_alloc + extra; + size = min_ddb_alloc + extra; if (size) iter->start = skl_ddb_entry_init(ddb, iter->start, iter->start + size); } +static void +skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, + const struct skl_wm_level *wm, + struct skl_ddb_entry *ddb, u64 data_rate) +{ + _skl_allocate_plane_ddb(iter, wm->min_ddb_alloc, ddb, data_rate); +} + +static void +skl_allocate_plane_ddb_nv12(struct skl_plane_ddb_iter *iter, + const struct skl_wm_level *wm, + struct skl_ddb_entry *ddb_y, u64 data_rate_y, + struct skl_ddb_entry *ddb, u64 data_rate) +{ + _skl_allocate_plane_ddb(iter, wm->min_ddb_alloc, ddb_y, data_rate_y); + _skl_allocate_plane_ddb(iter, wm->min_ddb_alloc_uv, ddb, data_rate); +} + static int skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, struct intel_crtc *crtc) @@ -1482,7 +1497,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, } blocks += wm->wm[level].min_ddb_alloc; - blocks += wm->uv_wm[level].min_ddb_alloc; + blocks += wm->wm[level].min_ddb_alloc_uv; } if (blocks <= iter.size) { @@ -1523,15 +1538,13 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, continue; if (DISPLAY_VER(display) < 11 && - crtc_state->nv12_planes & BIT(plane_id)) { - skl_allocate_plane_ddb(&iter, ddb_y, &wm->wm[level], - crtc_state->rel_data_rate_y[plane_id]); - skl_allocate_plane_ddb(&iter, ddb, &wm->uv_wm[level], - crtc_state->rel_data_rate[plane_id]); - } else { - skl_allocate_plane_ddb(&iter, ddb, &wm->wm[level], - crtc_state->rel_data_rate[plane_id]); - } + crtc_state->nv12_planes & BIT(plane_id)) + skl_allocate_plane_ddb_nv12(&iter, &wm->wm[level], + ddb_y, crtc_state->rel_data_rate_y[plane_id], + ddb, crtc_state->rel_data_rate[plane_id]); + else + skl_allocate_plane_ddb(&iter, &wm->wm[level], + ddb, crtc_state->rel_data_rate[plane_id]); if (DISPLAY_VER(display) >= 30) { *min_ddb = wm->wm[0].min_ddb_alloc; @@ -1557,9 +1570,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, if (DISPLAY_VER(display) < 11 && crtc_state->nv12_planes & BIT(plane_id)) - skl_check_nv12_wm_level(&wm->wm[level], - &wm->uv_wm[level], - ddb_y, ddb); + skl_check_wm_level_nv12(&wm->wm[level], ddb_y, ddb); else skl_check_wm_level(&wm->wm[level], ddb); @@ -1675,10 +1686,9 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, wp->y_tiled = modifier != I915_FORMAT_MOD_X_TILED && intel_fb_is_tiled_modifier(modifier); wp->rc_surface = intel_fb_is_ccs_modifier(modifier); - wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier); wp->width = width; - if (color_plane == 1 && wp->is_planar) + if (color_plane == 1 && intel_format_info_is_yuv_semiplanar(format, modifier)) wp->width /= 2; wp->cpp = format->cpp[color_plane]; @@ -2069,11 +2079,11 @@ static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state, struct intel_plane *plane) { + struct intel_display *display = to_intel_display(crtc_state); struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane->id]; + struct skl_wm_level uv_wm[ARRAY_SIZE(wm->wm)] = {}; struct skl_wm_params wm_params; - int ret; - - wm->is_planar = true; + int ret, level; /* uv plane watermarks must also be validated for NV12/Planar */ ret = skl_compute_plane_wm_params(crtc_state, plane_state, @@ -2081,7 +2091,14 @@ static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state, if (ret) return ret; - skl_compute_wm_levels(crtc_state, plane, &wm_params, wm->uv_wm); + skl_compute_wm_levels(crtc_state, plane, &wm_params, uv_wm); + + /* + * Only keep the min_ddb_alloc for UV as + * the hardware needs nothing else. + */ + for (level = 0; level < display->wm.num_levels; level++) + wm->wm[level].min_ddb_alloc_uv = uv_wm[level].min_ddb_alloc; return 0; } @@ -2304,7 +2321,6 @@ static int skl_wm_check_vblank(struct intel_crtc_state *crtc_state) * thing as bad via min_ddb_alloc=U16_MAX? */ wm->wm[level].enable = false; - wm->uv_wm[level].enable = false; } } @@ -2375,11 +2391,6 @@ static bool skl_plane_wm_equals(struct intel_display *display, int level; for (level = 0; level < display->wm.num_levels; level++) { - /* - * We don't check uv_wm as the hardware doesn't actually - * use it. It only gets used for calculating the required - * ddb allocation. - */ if (!skl_wm_level_equals(&wm1->wm[level], &wm2->wm[level])) return false; } @@ -2590,14 +2601,30 @@ static char enast(bool enable) return enable ? '*' : ' '; } +static void +skl_print_plane_ddb_changes(struct intel_plane *plane, + const struct skl_ddb_entry *old, + const struct skl_ddb_entry *new, + const char *ddb_name) +{ + struct intel_display *display = to_intel_display(plane); + + drm_dbg_kms(display->drm, + "[PLANE:%d:%s] %5s (%4d - %4d) -> (%4d - %4d), size %4d -> %4d\n", + plane->base.base.id, plane->base.name, ddb_name, + old->start, old->end, new->start, new->end, + skl_ddb_entry_size(old), skl_ddb_entry_size(new)); +} + static noinline_for_stack void -skl_print_plane_changes(struct intel_display *display, - struct intel_plane *plane, - const struct skl_plane_wm *old_wm, - const struct skl_plane_wm *new_wm) +skl_print_plane_wm_changes(struct intel_plane *plane, + const struct skl_plane_wm *old_wm, + const struct skl_plane_wm *new_wm) { + struct intel_display *display = to_intel_display(plane); + drm_dbg_kms(display->drm, - "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm" + "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm" " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm\n", plane->base.base.id, plane->base.name, enast(old_wm->wm[0].enable), enast(old_wm->wm[1].enable), @@ -2616,7 +2643,7 @@ skl_print_plane_changes(struct intel_display *display, enast(new_wm->sagv.trans_wm.enable)); drm_dbg_kms(display->drm, - "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d" + "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d" " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d\n", plane->base.base.id, plane->base.name, enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].lines, @@ -2643,7 +2670,7 @@ skl_print_plane_changes(struct intel_display *display, enast(new_wm->sagv.trans_wm.ignore_lines), new_wm->sagv.trans_wm.lines); drm_dbg_kms(display->drm, - "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" + "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", plane->base.base.id, plane->base.name, old_wm->wm[0].blocks, old_wm->wm[1].blocks, @@ -2662,7 +2689,7 @@ skl_print_plane_changes(struct intel_display *display, new_wm->sagv.trans_wm.blocks); drm_dbg_kms(display->drm, - "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" + "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", plane->base.base.id, plane->base.name, old_wm->wm[0].min_ddb_alloc, old_wm->wm[1].min_ddb_alloc, @@ -2679,6 +2706,28 @@ skl_print_plane_changes(struct intel_display *display, new_wm->trans_wm.min_ddb_alloc, new_wm->sagv.wm0.min_ddb_alloc, new_wm->sagv.trans_wm.min_ddb_alloc); + + if (DISPLAY_VER(display) >= 11) + return; + + drm_dbg_kms(display->drm, + "[PLANE:%d:%s] min_ddb_uv %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" + " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", + plane->base.base.id, plane->base.name, + old_wm->wm[0].min_ddb_alloc_uv, old_wm->wm[1].min_ddb_alloc_uv, + old_wm->wm[2].min_ddb_alloc_uv, old_wm->wm[3].min_ddb_alloc_uv, + old_wm->wm[4].min_ddb_alloc_uv, old_wm->wm[5].min_ddb_alloc_uv, + old_wm->wm[6].min_ddb_alloc_uv, old_wm->wm[7].min_ddb_alloc_uv, + old_wm->trans_wm.min_ddb_alloc_uv, + old_wm->sagv.wm0.min_ddb_alloc_uv, + old_wm->sagv.trans_wm.min_ddb_alloc_uv, + new_wm->wm[0].min_ddb_alloc_uv, new_wm->wm[1].min_ddb_alloc_uv, + new_wm->wm[2].min_ddb_alloc_uv, new_wm->wm[3].min_ddb_alloc_uv, + new_wm->wm[4].min_ddb_alloc_uv, new_wm->wm[5].min_ddb_alloc_uv, + new_wm->wm[6].min_ddb_alloc_uv, new_wm->wm[7].min_ddb_alloc_uv, + new_wm->trans_wm.min_ddb_alloc_uv, + new_wm->sagv.wm0.min_ddb_alloc_uv, + new_wm->sagv.trans_wm.min_ddb_alloc_uv); } static void @@ -2708,13 +2757,17 @@ skl_print_wm_changes(struct intel_atomic_state *state) old = &old_crtc_state->wm.skl.plane_ddb[plane_id]; new = &new_crtc_state->wm.skl.plane_ddb[plane_id]; - if (skl_ddb_entry_equal(old, new)) + if (!skl_ddb_entry_equal(old, new)) + skl_print_plane_ddb_changes(plane, old, new, "ddb"); + + if (DISPLAY_VER(display) >= 11) continue; - drm_dbg_kms(display->drm, - "[PLANE:%d:%s] ddb (%4d - %4d) -> (%4d - %4d), size %4d -> %4d\n", - plane->base.base.id, plane->base.name, - old->start, old->end, new->start, new->end, - skl_ddb_entry_size(old), skl_ddb_entry_size(new)); + + old = &old_crtc_state->wm.skl.plane_ddb_y[plane_id]; + new = &new_crtc_state->wm.skl.plane_ddb_y[plane_id]; + + if (!skl_ddb_entry_equal(old, new)) + skl_print_plane_ddb_changes(plane, old, new, "ddb_y"); } for_each_intel_plane_on_crtc(display->drm, crtc, plane) { @@ -2727,7 +2780,7 @@ skl_print_wm_changes(struct intel_atomic_state *state) if (skl_plane_wm_equals(display, old_wm, new_wm)) continue; - skl_print_plane_changes(display, plane, old_wm, new_wm); + skl_print_plane_wm_changes(plane, old_wm, new_wm); } } } @@ -2740,11 +2793,6 @@ static bool skl_plane_selected_wm_equals(struct intel_plane *plane, int level; for (level = 0; level < display->wm.num_levels; level++) { - /* - * We don't check uv_wm as the hardware doesn't actually - * use it. It only gets used for calculating the required - * ddb allocation. - */ if (!skl_wm_level_equals(skl_plane_wm_level(old_pipe_wm, plane->id, level), skl_plane_wm_level(new_pipe_wm, plane->id, level))) return false; diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 36591d724638..d4db73c184e5 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1367,7 +1367,7 @@ static void intel_dsi_prepare(struct intel_encoder *encoder, } tmp = 0; - if (intel_dsi->eotp_pkt == 0) + if (!intel_dsi->eot_pkt) tmp |= EOT_DISABLE; if (intel_dsi->clock_stop) tmp |= CLOCKSTOP; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index e7918f896a26..942f4eed817f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -898,6 +898,8 @@ static struct i915_vma *eb_lookup_vma(struct i915_execbuffer *eb, u32 handle) vma = radix_tree_lookup(&eb->gem_context->handles_vma, handle); if (likely(vma && vma->vm == vm)) vma = i915_vma_tryget(vma); + else + vma = NULL; rcu_read_unlock(); if (likely(vma)) return vma; diff --git a/drivers/gpu/drm/i915/gvt/edid.c b/drivers/gpu/drm/i915/gvt/edid.c index 021afff1cd5d..ca5b54466a65 100644 --- a/drivers/gpu/drm/i915/gvt/edid.c +++ b/drivers/gpu/drm/i915/gvt/edid.c @@ -535,16 +535,7 @@ void intel_gvt_i2c_handle_aux_ch_write(struct intel_vgpu *vgpu, i2c_edid->edid_available = true; } } - } else if ((op & 0x1) == DP_AUX_I2C_WRITE) { - /* TODO - * We only support EDID reading from I2C_over_AUX. And - * we do not expect the index mode to be used. Right now - * the WRITE operation is ignored. It is good enough to - * support the gfx driver to do EDID access. - */ - } else { - if (drm_WARN_ON(&i915->drm, (op & 0x1) != DP_AUX_I2C_READ)) - return; + } else if ((op & 0x1) == DP_AUX_I2C_READ) { if (drm_WARN_ON(&i915->drm, msg_length != 4)) return; if (i2c_edid->edid_available && i2c_edid->target_selected) { @@ -553,6 +544,13 @@ void intel_gvt_i2c_handle_aux_ch_write(struct intel_vgpu *vgpu, aux_data_for_write = (val << 16); } else aux_data_for_write = (0xff << 16); + } else { + /* TODO + * We only support EDID reading from I2C_over_AUX. And + * we do not expect the index mode to be used. Right now + * the WRITE operation is ignored. It is good enough to + * support the gfx driver to do EDID access. + */ } /* write the return value in AUX_CH_DATA reg which includes: * ACK of I2C_WRITE diff --git a/drivers/gpu/drm/i915/i915_initial_plane.c b/drivers/gpu/drm/i915/i915_initial_plane.c index 5594548f51d8..390a9248d631 100644 --- a/drivers/gpu/drm/i915/i915_initial_plane.c +++ b/drivers/gpu/drm/i915/i915_initial_plane.c @@ -115,7 +115,8 @@ initial_plane_vma(struct drm_i915_private *i915, * important and we should probably use that space with FBC or other * features. */ - if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && + if (IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) && + IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && mem == i915->mm.stolen_region && !intel_fbdev_fb_prefer_stolen(&i915->drm, size)) { drm_dbg_kms(&i915->drm, "Initial FB size exceeds half of stolen, discarding\n"); diff --git a/drivers/gpu/drm/i915/i915_wait_util.h b/drivers/gpu/drm/i915/i915_wait_util.h index 7376898e3bf8..e1ed7921ec70 100644 --- a/drivers/gpu/drm/i915/i915_wait_util.h +++ b/drivers/gpu/drm/i915/i915_wait_util.h @@ -25,9 +25,9 @@ might_sleep(); \ for (;;) { \ const bool expired__ = ktime_after(ktime_get_raw(), end__); \ - OP; \ /* Guarantee COND check prior to timeout */ \ barrier(); \ + OP; \ if (COND) { \ ret__ = 0; \ break; \ diff --git a/drivers/gpu/drm/i915/intel_clock_gating.c b/drivers/gpu/drm/i915/intel_clock_gating.c index 68a6f94f2a37..ee2489a2fbe7 100644 --- a/drivers/gpu/drm/i915/intel_clock_gating.c +++ b/drivers/gpu/drm/i915/intel_clock_gating.c @@ -33,6 +33,7 @@ #include "display/intel_display.h" #include "display/intel_display_core.h" #include "display/intel_display_regs.h" +#include "display/intel_pch.h" #include "gt/intel_engine_regs.h" #include "gt/intel_gt.h" #include "gt/intel_gt_mcr.h" @@ -124,16 +125,6 @@ static void glk_init_clock_gating(struct drm_i915_private *i915) PWM1_GATING_DIS | PWM2_GATING_DIS); } -static void ibx_init_clock_gating(struct drm_i915_private *i915) -{ - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - intel_uncore_write(&i915->uncore, SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); -} - static void g4x_disable_trickle_feed(struct drm_i915_private *dev_priv) { struct intel_display *display = dev_priv->display; @@ -202,42 +193,7 @@ static void ilk_init_clock_gating(struct drm_i915_private *i915) g4x_disable_trickle_feed(i915); - ibx_init_clock_gating(i915); -} - -static void cpt_init_clock_gating(struct drm_i915_private *i915) -{ - struct intel_display *display = i915->display; - enum pipe pipe; - u32 val; - - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - intel_uncore_write(&i915->uncore, SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE | - PCH_DPLUNIT_CLOCK_GATE_DISABLE | - PCH_CPUNIT_CLOCK_GATE_DISABLE); - intel_uncore_rmw(&i915->uncore, SOUTH_CHICKEN2, 0, DPLS_EDP_PPS_FIX_DIS); - /* The below fixes the weird display corruption, a few pixels shifted - * downward, on (only) LVDS of some HP laptops with IVY. - */ - for_each_pipe(display, pipe) { - val = intel_uncore_read(&i915->uncore, TRANS_CHICKEN2(pipe)); - val |= TRANS_CHICKEN2_TIMING_OVERRIDE; - val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED; - if (display->vbt.fdi_rx_polarity_inverted) - val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; - val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER; - val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH; - intel_uncore_write(&i915->uncore, TRANS_CHICKEN2(pipe), val); - } - /* WADP0ClockGatingDisable */ - for_each_pipe(display, pipe) { - intel_uncore_write(&i915->uncore, TRANS_CHICKEN1(pipe), - TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); - } + intel_pch_init_clock_gating(i915->display); } static void gen6_check_mch_setup(struct drm_i915_private *i915) @@ -305,28 +261,11 @@ static void gen6_init_clock_gating(struct drm_i915_private *i915) g4x_disable_trickle_feed(i915); - cpt_init_clock_gating(i915); + intel_pch_init_clock_gating(i915->display); gen6_check_mch_setup(i915); } -static void lpt_init_clock_gating(struct drm_i915_private *i915) -{ - struct intel_display *display = i915->display; - - /* - * TODO: this bit should only be enabled when really needed, then - * disabled when not needed anymore in order to save power. - */ - if (HAS_PCH_LPT_LP(display)) - intel_uncore_rmw(&i915->uncore, SOUTH_DSPCLK_GATE_D, - 0, PCH_LP_PARTITION_LEVEL_DISABLE); - - /* WADPOClockGatingDisable:hsw */ - intel_uncore_rmw(&i915->uncore, TRANS_CHICKEN1(PIPE_A), - 0, TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); -} - static void gen8_set_l3sqc_credits(struct drm_i915_private *i915, int general_prio_credits, int high_prio_credits) @@ -360,20 +299,9 @@ static void dg2_init_clock_gating(struct drm_i915_private *i915) SGSI_SIDECLK_DIS); } -static void cnp_init_clock_gating(struct drm_i915_private *i915) -{ - struct intel_display *display = i915->display; - - if (!HAS_PCH_CNP(display)) - return; - - /* Display WA #1181 WaSouthDisplayDisablePWMCGEGating: cnp */ - intel_uncore_rmw(&i915->uncore, SOUTH_DSPCLK_GATE_D, 0, CNP_PWM_CGE_GATING_DISABLE); -} - static void cfl_init_clock_gating(struct drm_i915_private *i915) { - cnp_init_clock_gating(i915); + intel_pch_init_clock_gating(i915->display); gen9_init_clock_gating(i915); /* WAC6entrylatency:cfl */ @@ -466,7 +394,7 @@ static void bdw_init_clock_gating(struct drm_i915_private *i915) intel_uncore_rmw(&i915->uncore, CHICKEN_PAR2_1, 0, KVM_CONFIG_CHANGE_NOTIFICATION_SELECT); - lpt_init_clock_gating(i915); + intel_pch_init_clock_gating(i915->display); /* WaDisableDopClockGating:bdw * @@ -500,7 +428,7 @@ static void hsw_init_clock_gating(struct drm_i915_private *i915) /* WaSwitchSolVfFArbitrationPriority:hsw */ intel_uncore_rmw(&i915->uncore, GAM_ECOCHK, 0, HSW_ECOCHK_ARB_PRIO_SOL); - lpt_init_clock_gating(i915); + intel_pch_init_clock_gating(i915->display); } static void ivb_init_clock_gating(struct drm_i915_private *i915) @@ -545,7 +473,7 @@ static void ivb_init_clock_gating(struct drm_i915_private *i915) GEN6_MBC_SNPCR_MED); if (!HAS_PCH_NOP(display)) - cpt_init_clock_gating(i915); + intel_pch_init_clock_gating(display); gen6_check_mch_setup(i915); } diff --git a/drivers/gpu/drm/i915/intel_step.h b/drivers/gpu/drm/i915/intel_step.h index 22f1d6905160..2ca36eae4b5a 100644 --- a/drivers/gpu/drm/i915/intel_step.h +++ b/drivers/gpu/drm/i915/intel_step.h @@ -8,6 +8,8 @@ #include <linux/types.h> +#include <drm/intel/step.h> + struct drm_i915_private; struct intel_step_info { @@ -19,61 +21,6 @@ struct intel_step_info { u8 media_step; }; -#define STEP_ENUM_VAL(name) STEP_##name, - -#define STEP_NAME_LIST(func) \ - func(A0) \ - func(A1) \ - func(A2) \ - func(A3) \ - func(B0) \ - func(B1) \ - func(B2) \ - func(B3) \ - func(C0) \ - func(C1) \ - func(C2) \ - func(C3) \ - func(D0) \ - func(D1) \ - func(D2) \ - func(D3) \ - func(E0) \ - func(E1) \ - func(E2) \ - func(E3) \ - func(F0) \ - func(F1) \ - func(F2) \ - func(F3) \ - func(G0) \ - func(G1) \ - func(G2) \ - func(G3) \ - func(H0) \ - func(H1) \ - func(H2) \ - func(H3) \ - func(I0) \ - func(I1) \ - func(I2) \ - func(I3) \ - func(J0) \ - func(J1) \ - func(J2) \ - func(J3) - -/* - * Symbolic steppings that do not match the hardware. These are valid both as gt - * and display steppings as symbolic names. - */ -enum intel_step { - STEP_NONE = 0, - STEP_NAME_LIST(STEP_ENUM_VAL) - STEP_FUTURE, - STEP_FOREVER, -}; - void intel_step_init(struct drm_i915_private *i915); const char *intel_step_name(enum intel_step step); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 5b698d4d7a7f..170e83a8c9fc 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -399,6 +399,35 @@ static void fw_domains_get_with_thread_status(struct intel_uncore *uncore, __gen6_gt_wait_for_thread_c0(uncore); } +static void +gen6_check_for_fifo_debug(struct intel_uncore *uncore) +{ + u32 fifodbg; + + fifodbg = __raw_uncore_read32(uncore, GTFIFODBG); + + if (unlikely(fifodbg)) { + drm_dbg(&uncore->i915->drm, "GTFIFODBG = 0x08%x\n", fifodbg); + __raw_uncore_write32(uncore, GTFIFODBG, fifodbg); + } +} + +static void +fw_domains_get_normal_fifo(struct intel_uncore *uncore, + enum forcewake_domains fw_domains) +{ + gen6_check_for_fifo_debug(uncore); + fw_domains_get_normal(uncore, fw_domains); +} + +static void +fw_domains_get_with_thread_status_fifo(struct intel_uncore *uncore, + enum forcewake_domains fw_domains) +{ + gen6_check_for_fifo_debug(uncore); + fw_domains_get_with_thread_status(uncore, fw_domains); +} + static inline u32 fifo_free_entries(struct intel_uncore *uncore) { u32 count = __raw_uncore_read32(uncore, GTFIFOCTL); @@ -562,21 +591,6 @@ vlv_check_for_unclaimed_mmio(struct intel_uncore *uncore) } static bool -gen6_check_for_fifo_debug(struct intel_uncore *uncore) -{ - u32 fifodbg; - - fifodbg = __raw_uncore_read32(uncore, GTFIFODBG); - - if (unlikely(fifodbg)) { - drm_dbg(&uncore->i915->drm, "GTFIFODBG = 0x08%x\n", fifodbg); - __raw_uncore_write32(uncore, GTFIFODBG, fifodbg); - } - - return fifodbg; -} - -static bool check_for_unclaimed_mmio(struct intel_uncore *uncore) { bool ret = false; @@ -592,9 +606,6 @@ check_for_unclaimed_mmio(struct intel_uncore *uncore) if (intel_uncore_has_dbg_unclaimed(uncore)) ret |= vlv_check_for_unclaimed_mmio(uncore); - if (intel_uncore_has_fifo(uncore)) - ret |= gen6_check_for_fifo_debug(uncore); - return ret; } @@ -611,6 +622,9 @@ static void forcewake_early_sanitize(struct intel_uncore *uncore, GT_FIFO_CTL_RC6_POLICY_STALL); } + if (intel_uncore_has_fifo(uncore)) + gen6_check_for_fifo_debug(uncore); + iosf_mbi_punit_acquire(); intel_uncore_forcewake_reset(uncore); if (restore_forcewake) { @@ -2155,6 +2169,14 @@ static const struct intel_uncore_fw_get uncore_get_thread_status = { .force_wake_get = fw_domains_get_with_thread_status }; +static const struct intel_uncore_fw_get uncore_get_normal_fifo = { + .force_wake_get = fw_domains_get_normal_fifo, +}; + +static const struct intel_uncore_fw_get uncore_get_thread_status_fifo = { + .force_wake_get = fw_domains_get_with_thread_status_fifo +}; + static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) { struct drm_i915_private *i915 = uncore->i915; @@ -2218,13 +2240,19 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA, FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9); } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { - uncore->fw_get_funcs = &uncore_get_normal; + if (intel_uncore_has_fifo(uncore)) + uncore->fw_get_funcs = &uncore_get_normal_fifo; + else + uncore->fw_get_funcs = &uncore_get_normal; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE_VLV, FORCEWAKE_ACK_VLV); fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA, FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV); } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) { - uncore->fw_get_funcs = &uncore_get_thread_status; + if (intel_uncore_has_fifo(uncore)) + uncore->fw_get_funcs = &uncore_get_thread_status_fifo; + else + uncore->fw_get_funcs = &uncore_get_thread_status; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE_MT, FORCEWAKE_ACK_HSW); } else if (IS_IVYBRIDGE(i915)) { @@ -2239,7 +2267,7 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) * (correctly) interpreted by the test below as MT * forcewake being disabled. */ - uncore->fw_get_funcs = &uncore_get_thread_status; + uncore->fw_get_funcs = &uncore_get_thread_status_fifo; /* We need to init first for ECOBUS access and then * determine later if we want to reinit, in case of MT access is @@ -2270,7 +2298,7 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) FORCEWAKE, FORCEWAKE_ACK); } } else if (GRAPHICS_VER(i915) == 6) { - uncore->fw_get_funcs = &uncore_get_thread_status; + uncore->fw_get_funcs = &uncore_get_thread_status_fifo; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, FORCEWAKE, FORCEWAKE_ACK); } diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index 507bf42a1aaf..514d2200751b 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -272,67 +272,6 @@ out_rpm: return err; } -static int live_forcewake_domains(void *arg) -{ -#define FW_RANGE 0x40000 - struct intel_gt *gt = arg; - struct intel_uncore *uncore = gt->uncore; - struct drm_i915_private *i915 = gt->i915; - struct intel_display *display = i915->display; - unsigned long *valid; - u32 offset; - int err; - - if (!HAS_FPGA_DBG_UNCLAIMED(display) && - !IS_VALLEYVIEW(i915) && - !IS_CHERRYVIEW(i915)) - return 0; - - /* - * This test may lockup the machine or cause GPU hangs afterwards. - */ - if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN)) - return 0; - - valid = bitmap_zalloc(FW_RANGE, GFP_KERNEL); - if (!valid) - return -ENOMEM; - - intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL); - - check_for_unclaimed_mmio(uncore); - for (offset = 0; offset < FW_RANGE; offset += 4) { - i915_reg_t reg = { offset }; - - intel_uncore_posting_read_fw(uncore, reg); - if (!check_for_unclaimed_mmio(uncore)) - set_bit(offset, valid); - } - - intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL); - - err = 0; - for_each_set_bit(offset, valid, FW_RANGE) { - i915_reg_t reg = { offset }; - - iosf_mbi_punit_acquire(); - intel_uncore_forcewake_reset(uncore); - iosf_mbi_punit_release(); - - check_for_unclaimed_mmio(uncore); - - intel_uncore_posting_read_fw(uncore, reg); - if (check_for_unclaimed_mmio(uncore)) { - pr_err("Unclaimed mmio read to register 0x%04x\n", - offset); - err = -EINVAL; - } - } - - bitmap_free(valid); - return err; -} - static int live_fw_table(void *arg) { struct intel_gt *gt = arg; @@ -348,7 +287,6 @@ int intel_uncore_live_selftests(struct drm_i915_private *i915) static const struct i915_subtest tests[] = { SUBTEST(live_fw_table), SUBTEST(live_forcewake_ops), - SUBTEST(live_forcewake_domains), }; return intel_gt_live_subtests(tests, to_gt(i915)); diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile index f5072f06b4c4..1222a14262e4 100644 --- a/drivers/gpu/drm/imagination/Makefile +++ b/drivers/gpu/drm/imagination/Makefile @@ -8,6 +8,7 @@ powervr-y := \ pvr_device.o \ pvr_device_info.o \ pvr_drv.o \ + pvr_dump.o \ pvr_free_list.o \ pvr_fw.o \ pvr_fw_meta.o \ diff --git a/drivers/gpu/drm/imagination/pvr_ccb.c b/drivers/gpu/drm/imagination/pvr_ccb.c index f89db5e3baa2..4accf18e2341 100644 --- a/drivers/gpu/drm/imagination/pvr_ccb.c +++ b/drivers/gpu/drm/imagination/pvr_ccb.c @@ -4,6 +4,7 @@ #include "pvr_ccb.h" #include "pvr_device.h" #include "pvr_drv.h" +#include "pvr_dump.h" #include "pvr_free_list.h" #include "pvr_fw.h" #include "pvr_gem.h" @@ -165,6 +166,10 @@ process_fwccb_command(struct pvr_device *pvr_dev, struct rogue_fwif_fwccb_cmd *c * suppress the "unknown" warning when receiving this command. */ break; + case ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_NOTIFICATION: + pvr_dump_context_reset_notification(pvr_dev, + &cmd->cmd_data.cmd_context_reset_notification); + break; default: drm_info(drm_dev, "Received unknown FWCCB command (type=%d)\n", diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c index f58bb66a6327..dbb6f5a8ded1 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -225,29 +225,12 @@ static irqreturn_t pvr_device_irq_thread_handler(int irq, void *data) } if (pvr_dev->has_safety_events) { - int err; - - /* - * Ensure the GPU is powered on since some safety events (such - * as ECC faults) can happen outside of job submissions, which - * are otherwise the only time a power reference is held. - */ - err = pvr_power_get(pvr_dev); - if (err) { - drm_err_ratelimited(drm_dev, - "%s: could not take power reference (%d)\n", - __func__, err); - return ret; - } - while (pvr_device_safety_irq_pending(pvr_dev)) { pvr_device_safety_irq_clear(pvr_dev); pvr_device_handle_safety_events(pvr_dev); ret = IRQ_HANDLED; } - - pvr_power_put(pvr_dev); } return ret; diff --git a/drivers/gpu/drm/imagination/pvr_dump.c b/drivers/gpu/drm/imagination/pvr_dump.c new file mode 100644 index 000000000000..52e95fce2817 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_dump.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* Copyright (c) 2026 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_dump.h" +#include "pvr_rogue_fwif.h" + +#include <drm/drm_print.h> +#include <linux/types.h> + +static const char * +get_reset_reason_desc(enum rogue_context_reset_reason reason) +{ + switch (reason) { + case ROGUE_CONTEXT_RESET_REASON_NONE: + return "None"; + case ROGUE_CONTEXT_RESET_REASON_GUILTY_LOCKUP: + return "Guilty lockup"; + case ROGUE_CONTEXT_RESET_REASON_INNOCENT_LOCKUP: + return "Innocent lockup"; + case ROGUE_CONTEXT_RESET_REASON_GUILTY_OVERRUNING: + return "Guilty overrunning"; + case ROGUE_CONTEXT_RESET_REASON_INNOCENT_OVERRUNING: + return "Innocent overrunning"; + case ROGUE_CONTEXT_RESET_REASON_HARD_CONTEXT_SWITCH: + return "Hard context switch"; + case ROGUE_CONTEXT_RESET_REASON_WGP_CHECKSUM: + return "CDM Mission/safety checksum mismatch"; + case ROGUE_CONTEXT_RESET_REASON_TRP_CHECKSUM: + return "TRP checksum mismatch"; + case ROGUE_CONTEXT_RESET_REASON_GPU_ECC_OK: + return "GPU ECC error (corrected, OK)"; + case ROGUE_CONTEXT_RESET_REASON_GPU_ECC_HWR: + return "GPU ECC error (uncorrected, HWR)"; + case ROGUE_CONTEXT_RESET_REASON_FW_ECC_OK: + return "Firmware ECC error (corrected, OK)"; + case ROGUE_CONTEXT_RESET_REASON_FW_ECC_ERR: + return "Firmware ECC error (uncorrected, ERR)"; + case ROGUE_CONTEXT_RESET_REASON_FW_WATCHDOG: + return "Firmware watchdog"; + case ROGUE_CONTEXT_RESET_REASON_FW_PAGEFAULT: + return "Firmware pagefault"; + case ROGUE_CONTEXT_RESET_REASON_FW_EXEC_ERR: + return "Firmware execution error"; + case ROGUE_CONTEXT_RESET_REASON_HOST_WDG_FW_ERR: + return "Host watchdog"; + case ROGUE_CONTEXT_GEOM_OOM_DISABLED: + return "Geometry OOM disabled"; + + default: + return "Unknown"; + } +} + +static const char * +get_dm_name(u32 dm) +{ + switch (dm) { + case PVR_FWIF_DM_GP: + return "General purpose"; + /* PVR_FWIF_DM_TDM has the same index, but is discriminated by a device feature */ + case PVR_FWIF_DM_2D: + return "2D or TDM"; + case PVR_FWIF_DM_GEOM: + return "Geometry"; + case PVR_FWIF_DM_FRAG: + return "Fragment"; + case PVR_FWIF_DM_CDM: + return "Compute"; + case PVR_FWIF_DM_RAY: + return "Raytracing"; + case PVR_FWIF_DM_GEOM2: + return "Geometry 2"; + case PVR_FWIF_DM_GEOM3: + return "Geometry 3"; + case PVR_FWIF_DM_GEOM4: + return "Geometry 4"; + + default: + return "Unknown"; + } +} + +/** + * pvr_dump_context_reset_notification() - Handle context reset notification from FW + * @pvr_dev: Device pointer. + * @data: Data provided by FW. + * + * This will decode the data structure provided by FW and print the results via drm_info(). + */ +void +pvr_dump_context_reset_notification(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_context_reset_data *data) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + + if (data->flags & ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_ALL_CTXS) { + drm_info(drm_dev, "Received context reset notification for all contexts\n"); + } else { + drm_info(drm_dev, "Received context reset notification on context %u\n", + data->server_common_context_id); + } + + drm_info(drm_dev, " Reset reason=%u (%s)\n", data->reset_reason, + get_reset_reason_desc((enum rogue_context_reset_reason)data->reset_reason)); + drm_info(drm_dev, " Data Master=%u (%s)\n", data->dm, get_dm_name(data->dm)); + drm_info(drm_dev, " Job ref=%u\n", data->reset_job_ref); + + if (data->flags & ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_PF) { + drm_info(drm_dev, " Page fault occurred, fault address=%llx\n", + data->fault_address); + } +} diff --git a/drivers/gpu/drm/imagination/pvr_dump.h b/drivers/gpu/drm/imagination/pvr_dump.h new file mode 100644 index 000000000000..3c0728c05596 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_dump.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* Copyright (c) 2026 Imagination Technologies Ltd. */ + +#ifndef PVR_DUMP_H +#define PVR_DUMP_H + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_rogue_fwif.h. */ +struct rogue_fwif_fwccb_cmd_context_reset_data; + +void +pvr_dump_context_reset_notification(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_context_reset_data *data); + +#endif /* PVR_DUMP_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_startstop.c b/drivers/gpu/drm/imagination/pvr_fw_startstop.c index dcbb9903e791..e24ed6fc4362 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_startstop.c +++ b/drivers/gpu/drm/imagination/pvr_fw_startstop.c @@ -209,18 +209,32 @@ pvr_fw_stop(struct pvr_device *pvr_dev) ROGUE_CR_SIDEKICK_IDLE_SOCIF_EN | ROGUE_CR_SIDEKICK_IDLE_HOSTIF_EN); bool skip_garten_idle = false; + u64 layout_mars_value = 0; + bool layout_mars = false; + bool meta_fw = pvr_dev->fw_dev.processor_type == PVR_FW_PROCESSOR_TYPE_META; u32 reg_value; int err; + if (PVR_FEATURE_VALUE(pvr_dev, layout_mars, &layout_mars_value) == 0) + layout_mars = layout_mars_value > 0; + /* - * Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper. - * For cores with the LAYOUT_MARS feature, SIDEKICK would have been + * For cores with the LAYOUT_MARS feature, SIDEKICK and SLC would have been * powered down by the FW. */ - err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask, - sidekick_idle_mask, POLL_TIMEOUT_USEC); - if (err) - return err; + if (!layout_mars) { + /* Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask, + sidekick_idle_mask, POLL_TIMEOUT_USEC); + if (err) + return err; + + /* Wait for SLC to signal IDLE. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SLC_IDLE, ROGUE_CR_SLC_IDLE_MASKFULL, + ROGUE_CR_SLC_IDLE_MASKFULL, POLL_TIMEOUT_USEC); + if (err) + return err; + } /* Unset MTS DM association with threads. */ pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC, @@ -229,12 +243,15 @@ pvr_fw_stop(struct pvr_device *pvr_dev) pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC, ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_MASKFULL & ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK); - pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC, - ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_MASKFULL & - ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK); - pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC, - ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_MASKFULL & - ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK); + + if (meta_fw) { + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC, + ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK); + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC, + ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK); + } /* Extra Idle checks. */ err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIF_STATUS_MMU, 0, @@ -270,27 +287,25 @@ pvr_fw_stop(struct pvr_device *pvr_dev) return err; /* - * Wait for SLC to signal IDLE. - * For cores with the LAYOUT_MARS feature, SLC would have been powered - * down by the FW. + * For cores with the LAYOUT_MARS feature, SIDEKICK and SLC would have been + * powered down by the FW. */ - err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SLC_IDLE, - ROGUE_CR_SLC_IDLE_MASKFULL, - ROGUE_CR_SLC_IDLE_MASKFULL, POLL_TIMEOUT_USEC); - if (err) - return err; + if (!layout_mars) { + /* Wait for SLC to signal IDLE. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SLC_IDLE, + ROGUE_CR_SLC_IDLE_MASKFULL, + ROGUE_CR_SLC_IDLE_MASKFULL, POLL_TIMEOUT_USEC); + if (err) + return err; - /* - * Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper. - * For cores with the LAYOUT_MARS feature, SIDEKICK would have been powered - * down by the FW. - */ - err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask, - sidekick_idle_mask, POLL_TIMEOUT_USEC); - if (err) - return err; + /* Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask, + sidekick_idle_mask, POLL_TIMEOUT_USEC); + if (err) + return err; + } - if (pvr_dev->fw_dev.processor_type == PVR_FW_PROCESSOR_TYPE_META) { + if (meta_fw) { err = pvr_meta_cr_read32(pvr_dev, META_CR_TxVECINT_BHALT, ®_value); if (err) return err; @@ -304,11 +319,28 @@ pvr_fw_stop(struct pvr_device *pvr_dev) skip_garten_idle = true; } - if (!skip_garten_idle) { - err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, - ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN, - ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN, + if (meta_fw || !layout_mars) { + if (!skip_garten_idle) { + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, + ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN, + ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN, + POLL_TIMEOUT_USEC); + if (err) + return err; + } + } else { + /* + * As FW core has been moved from SIDEKICK to the new MARS domain, checking + * idle bits for CPU & System Arbiter excluding SOCIF which will never be + * idle if Host polling on this register + */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_MARS_IDLE, + ROGUE_CR_MARS_IDLE_CPU_EN | + ROGUE_CR_MARS_IDLE_MH_SYSARB0_EN, + ROGUE_CR_MARS_IDLE_CPU_EN | + ROGUE_CR_MARS_IDLE_MH_SYSARB0_EN, POLL_TIMEOUT_USEC); + if (err) return err; } diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imagination/pvr_power.c index 7a8765c0c1ed..88fcce433d12 100644 --- a/drivers/gpu/drm/imagination/pvr_power.c +++ b/drivers/gpu/drm/imagination/pvr_power.c @@ -90,11 +90,11 @@ pvr_power_request_pwr_off(struct pvr_device *pvr_dev) } static int -pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset) +pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset, bool rpm_suspend) { - if (!hard_reset) { - int err; + int err; + if (!hard_reset) { cancel_delayed_work_sync(&pvr_dev->watchdog.work); err = pvr_power_request_idle(pvr_dev); @@ -106,29 +106,47 @@ pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset) return err; } - return pvr_fw_stop(pvr_dev); + if (rpm_suspend) { + /* This also waits for late processing of GPU or firmware IRQs in other cores */ + disable_irq(pvr_dev->irq); + } + + err = pvr_fw_stop(pvr_dev); + if (err && rpm_suspend) + enable_irq(pvr_dev->irq); + + return err; } static int -pvr_power_fw_enable(struct pvr_device *pvr_dev) +pvr_power_fw_enable(struct pvr_device *pvr_dev, bool rpm_resume) { int err; + if (rpm_resume) + enable_irq(pvr_dev->irq); + err = pvr_fw_start(pvr_dev); if (err) - return err; + goto out; err = pvr_wait_for_fw_boot(pvr_dev); if (err) { drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n"); pvr_fw_stop(pvr_dev); - return err; + goto out; } queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work, msecs_to_jiffies(WATCHDOG_TIME_MS)); return 0; + +out: + if (rpm_resume) + disable_irq(pvr_dev->irq); + + return err; } bool @@ -361,7 +379,7 @@ pvr_power_device_suspend(struct device *dev) return -EIO; if (pvr_dev->fw_dev.booted) { - err = pvr_power_fw_disable(pvr_dev, false); + err = pvr_power_fw_disable(pvr_dev, false, true); if (err) goto err_drm_dev_exit; } @@ -391,7 +409,7 @@ pvr_power_device_resume(struct device *dev) goto err_drm_dev_exit; if (pvr_dev->fw_dev.booted) { - err = pvr_power_fw_enable(pvr_dev); + err = pvr_power_fw_enable(pvr_dev, true); if (err) goto err_power_off; } @@ -510,7 +528,16 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) } /* Disable IRQs for the duration of the reset. */ - disable_irq(pvr_dev->irq); + if (hard_reset) { + disable_irq(pvr_dev->irq); + } else { + /* + * Soft reset is triggered as a response to a FW command to the Host and is + * processed from the threaded IRQ handler. This code cannot (nor needs to) + * wait for any IRQ processing to complete. + */ + disable_irq_nosync(pvr_dev->irq); + } do { if (hard_reset) { @@ -518,7 +545,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) queues_disabled = true; } - err = pvr_power_fw_disable(pvr_dev, hard_reset); + err = pvr_power_fw_disable(pvr_dev, hard_reset, false); if (!err) { if (hard_reset) { pvr_dev->fw_dev.booted = false; @@ -541,7 +568,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) pvr_fw_irq_clear(pvr_dev); - err = pvr_power_fw_enable(pvr_dev); + err = pvr_power_fw_enable(pvr_dev, false); } if (err && hard_reset) diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h index 172886be4c82..5d590c4c2566 100644 --- a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h @@ -1347,8 +1347,12 @@ struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data { struct rogue_fwif_fwccb_cmd_context_reset_data { /* Context affected by the reset */ u32 server_common_context_id; - /* Reason for reset */ - enum rogue_context_reset_reason reset_reason; + /* + * Reason for reset + * The valid values for reset_reason are the ones from + * enum rogue_context_reset_reason + */ + u32 reset_reason; /* Data Master affected by the reset */ u32 dm; /* Job ref running at the time of reset */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h index 6c09c15bf9bd..869d904e3649 100644 --- a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h @@ -236,6 +236,18 @@ enum rogue_context_reset_reason { ROGUE_CONTEXT_RESET_REASON_INNOCENT_OVERRUNING = 4, /* Forced reset to ensure scheduling requirements */ ROGUE_CONTEXT_RESET_REASON_HARD_CONTEXT_SWITCH = 5, + /* CDM Mission/safety checksum mismatch */ + ROGUE_CONTEXT_RESET_REASON_WGP_CHECKSUM = 6, + /* TRP checksum mismatch */ + ROGUE_CONTEXT_RESET_REASON_TRP_CHECKSUM = 7, + /* GPU ECC error (corrected, OK) */ + ROGUE_CONTEXT_RESET_REASON_GPU_ECC_OK = 8, + /* GPU ECC error (uncorrected, HWR) */ + ROGUE_CONTEXT_RESET_REASON_GPU_ECC_HWR = 9, + /* FW ECC error (corrected, OK) */ + ROGUE_CONTEXT_RESET_REASON_FW_ECC_OK = 10, + /* FW ECC error (uncorrected, ERR) */ + ROGUE_CONTEXT_RESET_REASON_FW_ECC_ERR = 11, /* FW Safety watchdog triggered */ ROGUE_CONTEXT_RESET_REASON_FW_WATCHDOG = 12, /* FW page fault (no HWR) */ @@ -249,7 +261,11 @@ enum rogue_context_reset_reason { }; struct rogue_context_reset_reason_data { - enum rogue_context_reset_reason reset_reason; + /* + * The valid values for reset_reason are the ones from + * enum rogue_context_reset_reason + */ + u32 reset_reason; u32 reset_ext_job_ref; }; diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig index acaf25089001..b2240998df4f 100644 --- a/drivers/gpu/drm/imx/ipuv3/Kconfig +++ b/drivers/gpu/drm/imx/ipuv3/Kconfig @@ -15,6 +15,7 @@ config DRM_IMX_PARALLEL_DISPLAY depends on DRM_IMX select DRM_BRIDGE select DRM_BRIDGE_CONNECTOR + select DRM_DISPLAY_HELPER select DRM_IMX_LEGACY_BRIDGE select DRM_PANEL_BRIDGE select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index 0ea70b8fd743..c1c7be4e26c6 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c @@ -890,7 +890,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, { struct ipu_plane *ipu_plane; const uint64_t *modifiers = ipu_format_modifiers; - unsigned int zpos = (type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1; + unsigned int primary_zpos = 1; unsigned int format_count; const uint32_t *formats; int ret; @@ -915,7 +915,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, type, NULL); if (IS_ERR(ipu_plane)) { DRM_ERROR("failed to allocate and initialize %s plane\n", - zpos ? "overlay" : "primary"); + (type == DRM_PLANE_TYPE_PRIMARY) ? "primary" : "overlay"); return ipu_plane; } @@ -923,17 +923,16 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ipu_plane->dma = dma; ipu_plane->dp_flow = dp; - if (type == DRM_PLANE_TYPE_PRIMARY) + if (type == DRM_PLANE_TYPE_PRIMARY) { drm_plane_helper_add(&ipu_plane->base, &ipu_primary_plane_helper_funcs); - else - drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); - - if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) - ret = drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0, - 1); - else ret = drm_plane_create_zpos_immutable_property(&ipu_plane->base, - 0); + primary_zpos); + } else { + drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); + ret = drm_plane_create_zpos_property(&ipu_plane->base, + primary_zpos + 1, 0, + primary_zpos + 1); + } if (ret) return ERR_PTR(ret); @@ -949,7 +948,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ret = ipu_plane_get_resources(dev, ipu_plane); if (ret) { DRM_ERROR("failed to get %s plane resources: %pe\n", - zpos ? "overlay" : "primary", &ret); + (type == DRM_PLANE_TYPE_PRIMARY) ? "primary" : "overlay", &ret); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c index 4ce772bc3cb3..a356f0b764cb 100644 --- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c +++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c @@ -110,8 +110,7 @@ imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, output_fmt = imxpd->bus_format ? : MEDIA_BUS_FMT_RGB888_1X24; /* Now make sure the requested output format is supported. */ - if ((imxpd->bus_format && imxpd->bus_format != output_fmt) || - !imx_pd_format_supported(output_fmt)) { + if (!imx_pd_format_supported(output_fmt)) { *num_input_fmts = 0; return NULL; } @@ -121,7 +120,17 @@ imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, if (!input_fmts) return NULL; - input_fmts[0] = output_fmt; + /* + * Prefer bus format set via legacy "interface-pix-fmt" DT property + * over panel bus format. This is necessary to retain support for + * DTs which configure the IPUv3 parallel output as 24bit, but + * connect 18bit DPI panels to it with hardware swizzling. + */ + if (imxpd->bus_format && imxpd->bus_format != output_fmt) + input_fmts[0] = imxpd->bus_format; + else + input_fmts[0] = output_fmt; + return input_fmts; } diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 9522a2e6ecd4..4068114adf8c 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -1401,7 +1401,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) goto err_devclk_disable; } - drm_atomic_private_obj_init(drm, &priv->private_obj, NULL, + drm_atomic_private_obj_init(drm, &priv->private_obj, &ingenic_drm_private_state_funcs); ret = drmm_add_action_or_reset(drm, ingenic_drm_atomic_private_obj_fini, diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c index 4fec37c63e7c..34545b9c8c33 100644 --- a/drivers/gpu/drm/ingenic/ingenic-ipu.c +++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c @@ -901,7 +901,7 @@ static int ingenic_ipu_bind(struct device *dev, struct device *master, void *d) return err; } - drm_atomic_private_obj_init(drm, &ipu->private_obj, NULL, + drm_atomic_private_obj_init(drm, &ipu->private_obj, &ingenic_ipu_private_state_funcs); return 0; diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index e0ac49b07d50..952d294642fb 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -14,7 +14,6 @@ mediatek-drm-y := mtk_crtc.o \ mtk_dsi.o \ mtk_dpi.o \ mtk_ethdr.o \ - mtk_gem.o \ mtk_mdp_rdma.o \ mtk_padding.o \ mtk_plane.o diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c index 351d58c50b84..fcb16f3f7b23 100644 --- a/drivers/gpu/drm/mediatek/mtk_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_crtc.c @@ -23,7 +23,6 @@ #include "mtk_crtc.h" #include "mtk_ddp_comp.h" #include "mtk_drm_drv.h" -#include "mtk_gem.h" #include "mtk_plane.h" /* diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c index e0236353d499..97a899e4bd99 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c @@ -671,6 +671,16 @@ static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = { .num_formats = ARRAY_SIZE(mt8173_formats), }; +static const struct mtk_disp_ovl_data mt8167_ovl_driver_data = { + .addr = DISP_REG_OVL_ADDR_MT8173, + .gmc_bits = 8, + .layer_nr = 4, + .fmt_rgb565_is_0 = true, + .smi_id_en = true, + .formats = mt8173_formats, + .num_formats = ARRAY_SIZE(mt8173_formats), +}; + static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = { .addr = DISP_REG_OVL_ADDR_MT8173, .gmc_bits = 8, @@ -742,6 +752,8 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = { static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = { { .compatible = "mediatek,mt2701-disp-ovl", .data = &mt2701_ovl_driver_data}, + { .compatible = "mediatek,mt8167-disp-ovl", + .data = &mt8167_ovl_driver_data}, { .compatible = "mediatek,mt8173-disp-ovl", .data = &mt8173_ovl_driver_data}, { .compatible = "mediatek,mt8183-disp-ovl", diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index 08c4d64b87b9..c52cc7c2e200 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2454,7 +2454,7 @@ mtk_dp_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_mode *mode) { struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge); - u32 bpp = info->color_formats & DRM_COLOR_FORMAT_YCBCR422 ? 16 : 24; + u32 bpp = info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) ? 16 : 24; u32 lane_count_min = mtk_dp->train_info.lane_count; u32 rate = drm_dp_bw_code_to_link_rate(mtk_dp->train_info.link_rate) * lane_count_min; @@ -2521,7 +2521,7 @@ static u32 *mtk_dp_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, */ if (((rate * 97 / 100) < (mode->clock * 24 / 8)) && ((rate * 97 / 100) > (mode->clock * 16 / 8)) && - (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) { + (display_info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))) { input_fmts = kcalloc(1, sizeof(*input_fmts), GFP_KERNEL); if (!input_fmts) return NULL; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index a94c51a83261..c86a3f54f35b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -4,6 +4,7 @@ * Author: YT SHEN <yt.shen@mediatek.com> */ +#include <linux/aperture.h> #include <linux/component.h> #include <linux/module.h> #include <linux/of.h> @@ -19,6 +20,7 @@ #include <drm/drm_fbdev_dma.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_ioctl.h> #include <drm/drm_of.h> @@ -29,7 +31,6 @@ #include "mtk_ddp_comp.h" #include "mtk_disp_drv.h" #include "mtk_drm_drv.h" -#include "mtk_gem.h" #define DRIVER_NAME "mediatek" #define DRIVER_DESC "Mediatek SoC DRM" @@ -565,8 +566,7 @@ static int mtk_drm_kms_init(struct drm_device *drm) goto err_component_unbind; } - for (i = 0; i < private->data->mmsys_dev_num; i++) - private->all_drm_private[i]->dma_dev = dma_dev; + drm_dev_set_dma_dev(drm, dma_dev); /* * Configure the DMA segment size to make sure we get contiguous IOVA @@ -600,26 +600,12 @@ static void mtk_drm_kms_deinit(struct drm_device *drm) DEFINE_DRM_GEM_FOPS(mtk_drm_fops); -/* - * We need to override this because the device used to import the memory is - * not dev->dev, as drm_gem_prime_import() expects. - */ -static struct drm_gem_object *mtk_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf) -{ - struct mtk_drm_private *private = dev->dev_private; - - return drm_gem_prime_import_dev(dev, dma_buf, private->dma_dev); -} - static const struct drm_driver mtk_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, - .dumb_create = mtk_gem_dumb_create, + DRM_GEM_DMA_DRIVER_OPS, DRM_FBDEV_DMA_DRIVER_OPS, - .gem_prime_import = mtk_gem_prime_import, - .gem_prime_import_sg_table = mtk_gem_prime_import_sg_table, .fops = &mtk_drm_fops, .name = DRIVER_NAME, @@ -670,6 +656,10 @@ static int mtk_drm_bind(struct device *dev) if (ret < 0) goto err_free; + ret = aperture_remove_all_conflicting_devices(DRIVER_NAME); + if (ret < 0) + dev_err(dev, "Error %d while removing conflicting aperture devices", ret); + ret = drm_dev_register(drm, 0); if (ret < 0) goto err_deinit; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index 675cdc90a440..1fc3df4b5485 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -54,7 +54,6 @@ struct mtk_mmsys_driver_data { struct mtk_drm_private { struct drm_device *drm; - struct device *dma_dev; bool mtk_drm_bound; bool drm_master; struct device *dev; diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 17c67f02016b..5aa71fcdcfab 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -673,6 +673,21 @@ static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) } } +static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +{ + if (!dsi->lanes_ready) { + dsi->lanes_ready = true; + mtk_dsi_rxtx_control(dsi); + usleep_range(30, 100); + mtk_dsi_reset_dphy(dsi); + mtk_dsi_clk_ulp_mode_leave(dsi); + mtk_dsi_lane0_ulp_mode_leave(dsi); + mtk_dsi_clk_hs_mode(dsi, 0); + usleep_range(1000, 3000); + /* The reaction time after pulling up the mipi signal for dsi_rx */ + } +} + static int mtk_dsi_poweron(struct mtk_dsi *dsi) { struct device *dev = dsi->host.dev; @@ -725,6 +740,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) mtk_dsi_set_vm_cmd(dsi); mtk_dsi_config_vdo_timing(dsi); mtk_dsi_set_interrupt_enable(dsi); + mtk_dsi_lane_ready(dsi); + mtk_dsi_clk_hs_mode(dsi, 1); return 0; err_disable_engine_clk: @@ -770,30 +787,12 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) dsi->lanes_ready = false; } -static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) -{ - if (!dsi->lanes_ready) { - dsi->lanes_ready = true; - mtk_dsi_rxtx_control(dsi); - usleep_range(30, 100); - mtk_dsi_reset_dphy(dsi); - mtk_dsi_clk_ulp_mode_leave(dsi); - mtk_dsi_lane0_ulp_mode_leave(dsi); - mtk_dsi_clk_hs_mode(dsi, 0); - usleep_range(1000, 3000); - /* The reaction time after pulling up the mipi signal for dsi_rx */ - } -} - static void mtk_output_dsi_enable(struct mtk_dsi *dsi) { if (dsi->enabled) return; - mtk_dsi_lane_ready(dsi); mtk_dsi_set_mode(dsi); - mtk_dsi_clk_hs_mode(dsi, 1); - mtk_dsi_start(dsi); dsi->enabled = true; @@ -1236,6 +1235,11 @@ static int mtk_dsi_probe(struct platform_device *pdev) dsi->host.ops = &mtk_dsi_ops; dsi->host.dev = dev; + + init_waitqueue_head(&dsi->irq_wait_queue); + + platform_set_drvdata(pdev, dsi); + ret = mipi_dsi_host_register(&dsi->host); if (ret < 0) return dev_err_probe(dev, ret, "Failed to register DSI host\n"); @@ -1247,10 +1251,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, ret, "Failed to request DSI irq\n"); } - init_waitqueue_head(&dsi->irq_wait_queue); - - platform_set_drvdata(pdev, dsi); - dsi->bridge.of_node = dev->of_node; dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; diff --git a/drivers/gpu/drm/mediatek/mtk_gem.c b/drivers/gpu/drm/mediatek/mtk_gem.c deleted file mode 100644 index f059a1452220..000000000000 --- a/drivers/gpu/drm/mediatek/mtk_gem.c +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015 MediaTek Inc. - * Copyright (c) 2025 Collabora Ltd. - * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> - */ - -#include <linux/dma-buf.h> -#include <linux/vmalloc.h> - -#include <drm/drm.h> -#include <drm/drm_device.h> -#include <drm/drm_gem.h> -#include <drm/drm_gem_dma_helper.h> -#include <drm/drm_prime.h> -#include <drm/drm_print.h> - -#include "mtk_drm_drv.h" -#include "mtk_gem.h" - -static int mtk_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); - -static void mtk_gem_free_object(struct drm_gem_object *obj) -{ - struct drm_gem_dma_object *dma_obj = to_drm_gem_dma_obj(obj); - struct mtk_drm_private *priv = obj->dev->dev_private; - - if (dma_obj->sgt) - drm_prime_gem_destroy(obj, dma_obj->sgt); - else - dma_free_wc(priv->dma_dev, dma_obj->base.size, - dma_obj->vaddr, dma_obj->dma_addr); - - /* release file pointer to gem object. */ - drm_gem_object_release(obj); - - kfree(dma_obj); -} - -/* - * Allocate a sg_table for this GEM object. - * Note: Both the table's contents, and the sg_table itself must be freed by - * the caller. - * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error. - */ -static struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj) -{ - struct drm_gem_dma_object *dma_obj = to_drm_gem_dma_obj(obj); - struct mtk_drm_private *priv = obj->dev->dev_private; - struct sg_table *sgt; - int ret; - - sgt = kzalloc_obj(*sgt); - if (!sgt) - return ERR_PTR(-ENOMEM); - - ret = dma_get_sgtable(priv->dma_dev, sgt, dma_obj->vaddr, - dma_obj->dma_addr, obj->size); - if (ret) { - DRM_ERROR("failed to allocate sgt, %d\n", ret); - kfree(sgt); - return ERR_PTR(ret); - } - - return sgt; -} - -static const struct drm_gem_object_funcs mtk_gem_object_funcs = { - .free = mtk_gem_free_object, - .print_info = drm_gem_dma_object_print_info, - .get_sg_table = mtk_gem_prime_get_sg_table, - .vmap = drm_gem_dma_object_vmap, - .mmap = mtk_gem_object_mmap, - .vm_ops = &drm_gem_dma_vm_ops, -}; - -static struct drm_gem_dma_object *mtk_gem_init(struct drm_device *dev, - unsigned long size, bool private) -{ - struct drm_gem_dma_object *dma_obj; - int ret; - - size = round_up(size, PAGE_SIZE); - - if (size == 0) - return ERR_PTR(-EINVAL); - - dma_obj = kzalloc_obj(*dma_obj); - if (!dma_obj) - return ERR_PTR(-ENOMEM); - - dma_obj->base.funcs = &mtk_gem_object_funcs; - - if (private) { - ret = 0; - drm_gem_private_object_init(dev, &dma_obj->base, size); - } else { - ret = drm_gem_object_init(dev, &dma_obj->base, size); - } - if (ret) { - DRM_ERROR("failed to initialize gem object\n"); - kfree(dma_obj); - return ERR_PTR(ret); - } - - return dma_obj; -} - -static struct drm_gem_dma_object *mtk_gem_create(struct drm_device *dev, size_t size) -{ - struct mtk_drm_private *priv = dev->dev_private; - struct drm_gem_dma_object *dma_obj; - struct drm_gem_object *obj; - int ret; - - dma_obj = mtk_gem_init(dev, size, false); - if (IS_ERR(dma_obj)) - return ERR_CAST(dma_obj); - - obj = &dma_obj->base; - - dma_obj->vaddr = dma_alloc_wc(priv->dma_dev, obj->size, - &dma_obj->dma_addr, - GFP_KERNEL | __GFP_NOWARN); - if (!dma_obj->vaddr) { - DRM_ERROR("failed to allocate %zx byte dma buffer", obj->size); - ret = -ENOMEM; - goto err_gem_free; - } - - DRM_DEBUG_DRIVER("vaddr = %p dma_addr = %pad size = %zu\n", - dma_obj->vaddr, &dma_obj->dma_addr, - size); - - return dma_obj; - -err_gem_free: - drm_gem_object_release(obj); - kfree(dma_obj); - return ERR_PTR(ret); -} - -int mtk_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, - struct drm_mode_create_dumb *args) -{ - struct drm_gem_dma_object *dma_obj; - int ret; - - args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - - /* - * Multiply 2 variables of different types, - * for example: args->size = args->spacing * args->height; - * may cause coverity issue with unintentional overflow. - */ - args->size = args->pitch; - args->size *= args->height; - - dma_obj = mtk_gem_create(dev, args->size); - if (IS_ERR(dma_obj)) - return PTR_ERR(dma_obj); - - /* - * allocate a id of idr table where the obj is registered - * and handle has the id what user can see. - */ - ret = drm_gem_handle_create(file_priv, &dma_obj->base, &args->handle); - if (ret) - goto err_handle_create; - - /* drop reference from allocate - handle holds it now. */ - drm_gem_object_put(&dma_obj->base); - - return 0; - -err_handle_create: - mtk_gem_free_object(&dma_obj->base); - return ret; -} - -static int mtk_gem_object_mmap(struct drm_gem_object *obj, - struct vm_area_struct *vma) - -{ - struct drm_gem_dma_object *dma_obj = to_drm_gem_dma_obj(obj); - struct mtk_drm_private *priv = obj->dev->dev_private; - int ret; - - /* - * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the - * whole buffer from the start. - */ - vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); - - /* - * dma_alloc_attrs() allocated a struct page table for mtk_gem, so clear - * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). - */ - vm_flags_mod(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP, VM_PFNMAP); - - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); - vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); - - ret = dma_mmap_wc(priv->dma_dev, vma, dma_obj->vaddr, - dma_obj->dma_addr, obj->size); - if (ret) - drm_gem_vm_close(vma); - - return ret; -} - -struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, struct sg_table *sgt) -{ - struct drm_gem_dma_object *dma_obj; - - /* check if the entries in the sg_table are contiguous */ - if (drm_prime_get_contiguous_size(sgt) < attach->dmabuf->size) { - DRM_ERROR("sg_table is not contiguous"); - return ERR_PTR(-EINVAL); - } - - dma_obj = mtk_gem_init(dev, attach->dmabuf->size, true); - if (IS_ERR(dma_obj)) - return ERR_CAST(dma_obj); - - dma_obj->dma_addr = sg_dma_address(sgt->sgl); - dma_obj->sgt = sgt; - - return &dma_obj->base; -} diff --git a/drivers/gpu/drm/mediatek/mtk_gem.h b/drivers/gpu/drm/mediatek/mtk_gem.h deleted file mode 100644 index afebc3a970a8..000000000000 --- a/drivers/gpu/drm/mediatek/mtk_gem.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#ifndef _MTK_GEM_H_ -#define _MTK_GEM_H_ - -#include <drm/drm_gem.h> -#include <drm/drm_gem_dma_helper.h> - -int mtk_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, - struct drm_mode_create_dumb *args); -struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, struct sg_table *sg); - -#endif diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c index 279ca896b0a2..b5c738380dc2 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c @@ -747,12 +747,12 @@ static void mtk_hdmi_v2_change_video_resolution(struct mtk_hdmi *hdmi, switch (conn_state->hdmi.output_format) { default: - case HDMI_COLORSPACE_RGB: - case HDMI_COLORSPACE_YUV444: + case DRM_OUTPUT_COLOR_FORMAT_RGB444: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: /* Disable YUV420 downsampling for RGB and YUV444 */ mtk_hdmi_yuv420_downsampling(hdmi, false); break; - case HDMI_COLORSPACE_YUV422: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: /* * YUV420 downsampling is special and needs a bit of setup * so we disable everything there before doing anything else. @@ -763,7 +763,7 @@ static void mtk_hdmi_v2_change_video_resolution(struct mtk_hdmi *hdmi, regmap_set_bits(hdmi->regs, VID_DOWNSAMPLE_CONFIG, C444_C422_CONFIG_ENABLE); break; - case HDMI_COLORSPACE_YUV420: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420: mtk_hdmi_yuv420_downsampling(hdmi, true); break; } diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c index 66c73c512b0e..4412bd678108 100644 --- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c @@ -119,8 +119,7 @@ static int dw_mipi_dsi_phy_init(void *priv_data) dpi_data_format = DPI_COLOR_18BIT_CFG_2; venc_data_width = VENC_IN_COLOR_18B; break; - case MIPI_DSI_FMT_RGB666_PACKED: - case MIPI_DSI_FMT_RGB565: + default: return -EINVAL; } @@ -232,8 +231,7 @@ static int meson_dw_mipi_dsi_host_attach(void *priv_data, break; case MIPI_DSI_FMT_RGB666: break; - case MIPI_DSI_FMT_RGB666_PACKED: - case MIPI_DSI_FMT_RGB565: + default: dev_err(mipi_dsi->dev, "invalid pixel format %d\n", device->format); return -EINVAL; } diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 8b94c5f1cb68..ba45e99be05b 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -25,6 +25,7 @@ adreno-y := \ adreno/a6xx_hfi.o \ adreno/a6xx_preempt.o \ adreno/a8xx_gpu.o \ + adreno/a8xx_preempt.o \ adreno-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \ diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpummu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpummu.c index d77b4774d414..e2225c5ba647 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx_gpummu.c +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpummu.c @@ -78,7 +78,7 @@ static void a2xx_gpummu_destroy(struct msm_mmu *mmu) { struct a2xx_gpummu *gpummu = to_a2xx_gpummu(mmu); - dma_free_attrs(mmu->dev, TABLE_SIZE, gpummu->table, gpummu->pt_base, + dma_free_attrs(mmu->dev, TABLE_SIZE + 32, gpummu->table, gpummu->pt_base, DMA_ATTR_FORCE_CONTIGUOUS); kfree(gpummu); diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 8464d89e37f3..e6ab731f8e9a 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -604,11 +604,9 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) { return 0; } -static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) +static u64 a4xx_get_timestamp(struct msm_gpu *gpu) { - *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO); - - return 0; + return gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO); } static u64 a4xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index ef9fd6171af7..79acae11154a 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -1435,11 +1435,9 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu) return 0; } -static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) +static u64 a5xx_get_timestamp(struct msm_gpu *gpu) { - *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO); - - return 0; + return gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO); } struct a5xx_crashdumper { @@ -1732,6 +1730,7 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) struct adreno_gpu *adreno_gpu; struct msm_gpu *gpu; unsigned int nr_rings; + u32 speedbin; int ret; a5xx_gpu = kzalloc_obj(*a5xx_gpu); @@ -1758,6 +1757,11 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) return ERR_PTR(ret); } + /* Set the speedbin value that is passed to userspace */ + if (adreno_read_speedbin(&pdev->dev, &speedbin) || !speedbin) + speedbin = 0xffff; + adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin); + msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu, a5xx_fault_handler); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 550a53a7865e..550ff3a9b82e 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -1759,7 +1759,45 @@ static const u32 x285_protect_regs[] = { A6XX_PROTECT_NORDWR(0x27c06, 0x0000), }; -DECLARE_ADRENO_PROTECT(x285_protect, 64); +DECLARE_ADRENO_PROTECT(x285_protect, 15); + +static const struct adreno_reglist_pipe x285_dyn_pwrup_reglist_regs[] = { + { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_GRAS_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_2, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_3, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_4, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_VIS_STREAM_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A7XX_RB_CCU_CNTL, 0, BIT(PIPE_BR) }, + { REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0, BIT(PIPE_BR)}, + { REG_A8XX_RB_CCU_NC_MODE_CNTL, 0, BIT(PIPE_BR) }, + { REG_A8XX_RB_CMP_NC_MODE_CNTL, 0, BIT(PIPE_BR) }, + { REG_A6XX_RB_RBP_CNTL, 0, BIT(PIPE_BR) }, + { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0, BIT(PIPE_BR) }, + { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0, BIT(PIPE_BR) }, + { REG_A7XX_VFD_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BV_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BR_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_LP_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_CP_HW_FAULT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) | + BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) | + BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) }, + { REG_A8XX_CP_INTERRUPT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) | + BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) | + BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) }, + { REG_A8XX_CP_PROTECT_CNTL_PIPE, 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC)}, + { REG_A8XX_CP_PROTECT_PIPE(15), 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC) }, + { REG_A8XX_RB_GC_GMEM_PROTECT, 0, BIT(PIPE_BR) }, + { REG_A8XX_RB_LPAC_GMEM_PROTECT, 0, BIT(PIPE_BR) }, + { REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, 0, BIT(PIPE_BR) }, +}; +DECLARE_ADRENO_REGLIST_PIPE_LIST(x285_dyn_pwrup_reglist); static const struct adreno_reglist_pipe a840_nonctxt_regs[] = { { REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) }, @@ -1891,6 +1929,185 @@ static const struct adreno_reglist a840_gbif[] = { { }, }; +static const uint32_t a840_pwrup_reglist_regs[] = { + REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, + REG_A7XX_SP_READ_SEL, + REG_A6XX_UCHE_MODE_CNTL, + REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, + REG_A8XX_UCHE_GBIF_GX_CONFIG, + REG_A8XX_UCHE_CCHE_MODE_CNTL, + REG_A8XX_UCHE_CCHE_CACHE_WAYS, + REG_A8XX_UCHE_CACHE_WAYS, + REG_A8XX_UCHE_CCHE_GC_GMEM_RANGE_MIN, + REG_A8XX_UCHE_CCHE_GC_GMEM_RANGE_MIN + 1, + REG_A8XX_UCHE_CCHE_LPAC_GMEM_RANGE_MIN, + REG_A8XX_UCHE_CCHE_LPAC_GMEM_RANGE_MIN + 1, + REG_A8XX_UCHE_CCHE_TRAP_BASE, + REG_A8XX_UCHE_CCHE_TRAP_BASE + 1, + REG_A8XX_UCHE_CCHE_WRITE_THRU_BASE, + REG_A8XX_UCHE_CCHE_WRITE_THRU_BASE + 1, + REG_A8XX_UCHE_HW_DBG_CNTL, + REG_A8XX_UCHE_WRITE_THRU_BASE, + REG_A8XX_UCHE_WRITE_THRU_BASE + 1, + REG_A8XX_UCHE_TRAP_BASE, + REG_A8XX_UCHE_TRAP_BASE + 1, + REG_A8XX_UCHE_CLIENT_PF, + REG_A8XX_RB_CMP_NC_MODE_CNTL, + REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN, + REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN + 1, + REG_A6XX_TPL1_NC_MODE_CNTL, + REG_A6XX_TPL1_DBG_ECO_CNTL, + REG_A6XX_TPL1_DBG_ECO_CNTL1, + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(0), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(1), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(2), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(3), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(4), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(5), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(6), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(7), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(8), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(9), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(10), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(11), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(12), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(13), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(14), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(15), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(16), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(17), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(18), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(19), +}; +DECLARE_ADRENO_REGLIST_LIST(a840_pwrup_reglist); + +static const u32 a840_ifpc_reglist_regs[] = { + REG_A8XX_RBBM_NC_MODE_CNTL, + REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, + REG_A6XX_SP_NC_MODE_CNTL, + REG_A6XX_SP_CHICKEN_BITS, + REG_A8XX_SP_SS_CHICKEN_BITS_0, + REG_A7XX_SP_CHICKEN_BITS_1, + REG_A7XX_SP_CHICKEN_BITS_2, + REG_A7XX_SP_CHICKEN_BITS_3, + REG_A8XX_SP_CHICKEN_BITS_4, + REG_A6XX_SP_PERFCTR_SHADER_MASK, + REG_A8XX_RBBM_SLICE_PERFCTR_CNTL, + REG_A8XX_RBBM_SLICE_INTERFACE_HANG_INT_CNTL, + REG_A7XX_SP_HLSQ_DBG_ECO_CNTL, + REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_1, + REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_2, + REG_A8XX_SP_HLSQ_DBG_ECO_CNTL_3, + REG_A8XX_SP_HLSQ_LPAC_GMEM_RANGE_MIN, + REG_A8XX_SP_HLSQ_LPAC_GMEM_RANGE_MIN + 1, + REG_A8XX_CP_INTERRUPT_STATUS_MASK_GLOBAL, + REG_A8XX_RBBM_PERFCTR_CNTL, + REG_A8XX_CP_PROTECT_GLOBAL(0), + REG_A8XX_CP_PROTECT_GLOBAL(1), + REG_A8XX_CP_PROTECT_GLOBAL(2), + REG_A8XX_CP_PROTECT_GLOBAL(3), + REG_A8XX_CP_PROTECT_GLOBAL(4), + REG_A8XX_CP_PROTECT_GLOBAL(5), + REG_A8XX_CP_PROTECT_GLOBAL(6), + REG_A8XX_CP_PROTECT_GLOBAL(7), + REG_A8XX_CP_PROTECT_GLOBAL(8), + REG_A8XX_CP_PROTECT_GLOBAL(9), + REG_A8XX_CP_PROTECT_GLOBAL(10), + REG_A8XX_CP_PROTECT_GLOBAL(11), + REG_A8XX_CP_PROTECT_GLOBAL(12), + REG_A8XX_CP_PROTECT_GLOBAL(13), + REG_A8XX_CP_PROTECT_GLOBAL(14), + REG_A8XX_CP_PROTECT_GLOBAL(15), + REG_A8XX_CP_PROTECT_GLOBAL(16), + REG_A8XX_CP_PROTECT_GLOBAL(17), + REG_A8XX_CP_PROTECT_GLOBAL(18), + REG_A8XX_CP_PROTECT_GLOBAL(19), + REG_A8XX_CP_PROTECT_GLOBAL(20), + REG_A8XX_CP_PROTECT_GLOBAL(21), + REG_A8XX_CP_PROTECT_GLOBAL(22), + REG_A8XX_CP_PROTECT_GLOBAL(23), + REG_A8XX_CP_PROTECT_GLOBAL(24), + REG_A8XX_CP_PROTECT_GLOBAL(25), + REG_A8XX_CP_PROTECT_GLOBAL(26), + REG_A8XX_CP_PROTECT_GLOBAL(27), + REG_A8XX_CP_PROTECT_GLOBAL(28), + REG_A8XX_CP_PROTECT_GLOBAL(29), + REG_A8XX_CP_PROTECT_GLOBAL(30), + REG_A8XX_CP_PROTECT_GLOBAL(31), + REG_A8XX_CP_PROTECT_GLOBAL(32), + REG_A8XX_CP_PROTECT_GLOBAL(33), + REG_A8XX_CP_PROTECT_GLOBAL(34), + REG_A8XX_CP_PROTECT_GLOBAL(35), + REG_A8XX_CP_PROTECT_GLOBAL(36), + REG_A8XX_CP_PROTECT_GLOBAL(37), + REG_A8XX_CP_PROTECT_GLOBAL(38), + REG_A8XX_CP_PROTECT_GLOBAL(39), + REG_A8XX_CP_PROTECT_GLOBAL(40), + REG_A8XX_CP_PROTECT_GLOBAL(41), + REG_A8XX_CP_PROTECT_GLOBAL(42), + REG_A8XX_CP_PROTECT_GLOBAL(43), + REG_A8XX_CP_PROTECT_GLOBAL(44), + REG_A8XX_CP_PROTECT_GLOBAL(45), + REG_A8XX_CP_PROTECT_GLOBAL(46), + REG_A8XX_CP_PROTECT_GLOBAL(47), + REG_A8XX_CP_PROTECT_GLOBAL(48), + REG_A8XX_CP_PROTECT_GLOBAL(49), + REG_A8XX_CP_PROTECT_GLOBAL(50), + REG_A8XX_CP_PROTECT_GLOBAL(51), + REG_A8XX_CP_PROTECT_GLOBAL(52), + REG_A8XX_CP_PROTECT_GLOBAL(53), + REG_A8XX_CP_PROTECT_GLOBAL(54), + REG_A8XX_CP_PROTECT_GLOBAL(55), + REG_A8XX_CP_PROTECT_GLOBAL(56), + REG_A8XX_CP_PROTECT_GLOBAL(57), + REG_A8XX_CP_PROTECT_GLOBAL(58), + REG_A8XX_CP_PROTECT_GLOBAL(59), + REG_A8XX_CP_PROTECT_GLOBAL(60), + REG_A8XX_CP_PROTECT_GLOBAL(61), + REG_A8XX_CP_PROTECT_GLOBAL(62), + REG_A8XX_CP_PROTECT_GLOBAL(63), +}; +DECLARE_ADRENO_REGLIST_LIST(a840_ifpc_reglist); + +static const struct adreno_reglist_pipe a840_dyn_pwrup_reglist_regs[] = { + { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_GRAS_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_2, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_3, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_4, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_VIS_STREAM_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A7XX_RB_CCU_CNTL, 0, BIT(PIPE_BR) }, + { REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0, BIT(PIPE_BR)}, + { REG_A8XX_RB_CCU_NC_MODE_CNTL, 0, BIT(PIPE_BR) }, + { REG_A8XX_RB_CMP_NC_MODE_CNTL, 0, BIT(PIPE_BR) }, + { REG_A6XX_RB_RBP_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0, BIT(PIPE_BR) }, + { REG_A6XX_RB_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0, BIT(PIPE_BR) }, + { REG_A7XX_VFD_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BV_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BR_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_LP_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_CP_HW_FAULT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) | + BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) | + BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) }, + { REG_A8XX_CP_INTERRUPT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) | + BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) | + BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) }, + { REG_A8XX_CP_PROTECT_CNTL_PIPE, 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC)}, + { REG_A8XX_CP_PROTECT_PIPE(15), 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC) }, + { REG_A8XX_RB_GC_GMEM_PROTECT, 0, BIT(PIPE_BR) }, + { REG_A8XX_RB_LPAC_GMEM_PROTECT, 0, BIT(PIPE_BR) }, + { REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, 0, BIT(PIPE_BR) }, +}; +DECLARE_ADRENO_REGLIST_PIPE_LIST(a840_dyn_pwrup_reglist); + static const struct adreno_info a8xx_gpus[] = { { .chip_ids = ADRENO_CHIP_IDS(0x44070001), @@ -1902,11 +2119,16 @@ static const struct adreno_info a8xx_gpus[] = { .gmem = 21 * SZ_1M, .inactive_period = DRM_MSM_INACTIVE_PERIOD, .quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT | - ADRENO_QUIRK_HAS_HW_APRIV, + ADRENO_QUIRK_HAS_HW_APRIV | + ADRENO_QUIRK_PREEMPTION | + ADRENO_QUIRK_SOFTFUSE, .funcs = &a8xx_gpu_funcs, .a6xx = &(const struct a6xx_info) { .protect = &x285_protect, .nonctxt_reglist = x285_nonctxt_regs, + .pwrup_reglist = &a840_pwrup_reglist, + .dyn_pwrup_reglist = &x285_dyn_pwrup_reglist, + .ifpc_reglist = &a840_ifpc_reglist, .gbif_cx = a840_gbif, .max_slices = 4, .gmu_chipid = 0x8010100, @@ -1922,6 +2144,12 @@ static const struct adreno_info a8xx_gpus[] = { { /* sentinel */ }, }, }, + .speedbins = ADRENO_SPEEDBINS( + { 0, 0 }, + { 388, 1 }, + { 357, 2 }, + { 284, 3 }, + ), }, { .chip_ids = ADRENO_CHIP_IDS(0x44050a01), .family = ADRENO_8XX_GEN2, @@ -1933,11 +2161,16 @@ static const struct adreno_info a8xx_gpus[] = { .gmem = 18 * SZ_1M, .inactive_period = DRM_MSM_INACTIVE_PERIOD, .quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT | - ADRENO_QUIRK_HAS_HW_APRIV, + ADRENO_QUIRK_HAS_HW_APRIV | + ADRENO_QUIRK_PREEMPTION | + ADRENO_QUIRK_IFPC, .funcs = &a8xx_gpu_funcs, .a6xx = &(const struct a6xx_info) { .protect = &a840_protect, .nonctxt_reglist = a840_nonctxt_regs, + .pwrup_reglist = &a840_pwrup_reglist, + .dyn_pwrup_reglist = &a840_dyn_pwrup_reglist, + .ifpc_reglist = &a840_ifpc_reglist, .gbif_cx = a840_gbif, .max_slices = 3, .gmu_chipid = 0x8020100, @@ -1954,6 +2187,12 @@ static const struct adreno_info a8xx_gpus[] = { }, }, .preempt_record_size = 19708 * SZ_1K, + .speedbins = ADRENO_SPEEDBINS( + { 0, 0 }, + { 273, 1 }, + { 252, 2 }, + { 221, 3 }, + ), } }; @@ -1966,5 +2205,4 @@ static inline __always_unused void __build_asserts(void) BUILD_BUG_ON(a660_protect.count > a660_protect.count_max); BUILD_BUG_ON(a690_protect.count > a690_protect.count_max); BUILD_BUG_ON(a730_protect.count > a730_protect.count_max); - BUILD_BUG_ON(a840_protect.count > a840_protect.count_max); } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 9662201cd2e9..1b44b9e21ad8 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -3,6 +3,7 @@ #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/firmware/qcom/qcom_scm.h> #include <linux/interconnect.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -91,10 +92,10 @@ bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu) } /* Check to see if the GX rail is still powered */ -bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu) +bool a6xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu) { - struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); - struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; u32 val; /* This can be called from gpu state code so make sure GMU is valid */ @@ -117,6 +118,40 @@ bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu) A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF)); } +bool a7xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu) +{ + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + u32 val; + + /* This can be called from gpu state code so make sure GMU is valid */ + if (!gmu->initialized) + return false; + + val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS); + + return !(val & + (A7XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF | + A7XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF)); +} + +bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu) +{ + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + u32 val; + + /* This can be called from gpu state code so make sure GMU is valid */ + if (!gmu->initialized) + return false; + + val = gmu_read(gmu, REG_A8XX_GMU_PWR_CLK_STATUS); + + return !(val & + (A8XX_GMU_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF | + A8XX_GMU_PWR_CLK_STATUS_GX_HM_CLK_OFF)); +} + void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp, bool suspended) { @@ -240,7 +275,7 @@ static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu) if (val == local) { if (gmu->idle_level != GMU_IDLE_STATE_IFPC || - !a6xx_gmu_gx_is_on(gmu)) + !adreno_gpu->funcs->gx_is_on(adreno_gpu)) return true; } @@ -1157,6 +1192,65 @@ static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu) dev_pm_opp_put(gpu_opp); } +static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu) +{ + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + struct msm_gpu *gpu = &adreno_gpu->base; + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + u32 fuse_val; + int ret; + + if (test_bit(GMU_STATUS_SECURE_INIT, &gmu->status)) + return 0; + + if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { + /* + * Assume that if qcom scm isn't available, that whatever + * replacement allows writing the fuse register ourselves. + * Users of alternative firmware need to make sure this + * register is writeable or indicate that it's not somehow. + * Print a warning because if you mess this up you're about to + * crash horribly. + */ + if (!qcom_scm_is_available()) { + dev_warn_once(gpu->dev->dev, + "SCM is not available, poking fuse register\n"); + a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE, + A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING | + A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND | + A7XX_CX_MISC_SW_FUSE_VALUE_LPAC); + adreno_gpu->has_ray_tracing = true; + goto done; + } + + ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ | + QCOM_SCM_GPU_TSENSE_EN_REQ); + if (ret) { + dev_warn_once(gpu->dev->dev, + "SCM call failed\n"); + return ret; + } + + /* + * On A7XX_GEN3 and newer, raytracing may be disabled by the + * firmware, find out whether that's the case. The scm call + * above sets the fuse register. + */ + fuse_val = a6xx_llc_read(a6xx_gpu, + REG_A7XX_CX_MISC_SW_FUSE_VALUE); + adreno_gpu->has_ray_tracing = + !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING); + } else if (adreno_is_a740(adreno_gpu)) { + /* Raytracing is always enabled on a740 */ + adreno_gpu->has_ray_tracing = true; + } + +done: + set_bit(GMU_STATUS_SECURE_INIT, &gmu->status); + return 0; +} + + int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) { struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; @@ -1185,11 +1279,12 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) clk_set_rate(gmu->hub_clk, adreno_is_a740_family(adreno_gpu) ? 200000000 : 150000000); ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks); - if (ret) { - pm_runtime_put(gmu->gxpd); - pm_runtime_put(gmu->dev); - return ret; - } + if (ret) + goto rpm_put; + + ret = a6xx_gmu_secure_init(a6xx_gpu); + if (ret) + goto disable_clk; /* Read the slice info on A8x GPUs */ a8xx_gpu_get_slice_info(gpu); @@ -1219,11 +1314,11 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) ret = a6xx_gmu_fw_start(gmu, status); if (ret) - goto out; + goto disable_irq; ret = a6xx_hfi_start(gmu, status); if (ret) - goto out; + goto disable_irq; /* * Turn on the GMU firmware fault interrupt after we know the boot @@ -1236,19 +1331,16 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) /* Set the GPU to the current freq */ a6xx_gmu_set_initial_freq(gpu, gmu); - if (refcount_read(&gpu->sysprof_active) > 1) { - ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET); - if (!ret) - set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status); - } -out: - /* On failure, shut down the GMU to leave it in a good state */ - if (ret) { - disable_irq(gmu->gmu_irq); - a6xx_rpmh_stop(gmu); - pm_runtime_put(gmu->gxpd); - pm_runtime_put(gmu->dev); - } + return 0; + +disable_irq: + disable_irq(gmu->gmu_irq); + a6xx_rpmh_stop(gmu); +disable_clk: + clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); +rpm_put: + pm_runtime_put(gmu->gxpd); + pm_runtime_put(gmu->dev); return ret; } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h index 2af074c8e8cf..3f96b10b5f61 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h @@ -10,6 +10,7 @@ #include <linux/notifier.h> #include <linux/soc/qcom/qcom_aoss.h> #include "msm_drv.h" +#include "adreno_gpu.h" #include "a6xx_hfi.h" struct a6xx_gmu_bo { @@ -110,7 +111,7 @@ struct a6xx_gmu { unsigned long freq; - struct a6xx_hfi_queue queues[2]; + struct a6xx_hfi_queue queues[HFI_MAX_QUEUES]; bool initialized; bool hung; @@ -129,6 +130,8 @@ struct a6xx_gmu { #define GMU_STATUS_PDC_SLEEP 1 /* To track Perfcounter OOB set status */ #define GMU_STATUS_OOB_PERF_SET 2 +/* To track whether secure world init was done */ +#define GMU_STATUS_SECURE_INIT 3 unsigned long status; }; @@ -231,7 +234,9 @@ void a6xx_hfi_stop(struct a6xx_gmu *gmu); int a6xx_hfi_send_prep_slumber(struct a6xx_gmu *gmu); int a6xx_hfi_set_freq(struct a6xx_gmu *gmu, u32 perf_index, u32 bw_index); -bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu); +bool a6xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu); +bool a7xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu); +bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu); bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu); void a6xx_sptprac_disable(struct a6xx_gmu *gmu); int a6xx_sptprac_enable(struct a6xx_gmu *gmu); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index d6dfe6337bc3..d5aba072f44c 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -10,14 +10,15 @@ #include <linux/bitfield.h> #include <linux/devfreq.h> -#include <linux/firmware/qcom/qcom_scm.h> #include <linux/pm_domain.h> #include <linux/soc/qcom/llcc-qcom.h> #define GPU_PAS_ID 13 -static u64 read_gmu_ao_counter(struct a6xx_gpu *a6xx_gpu) +static u64 a6xx_gmu_get_timestamp(struct msm_gpu *gpu) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); u64 count_hi, count_lo, temp; do { @@ -345,7 +346,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) * GPU registers so we need to add 0x1a800 to the register value on A630 * to get the right value from PM4. */ - get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER, + get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT, rbmemptr_stats(ring, index, alwayson_start)); /* Invalidate CCU depth and color */ @@ -386,7 +387,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) get_stats_counter(ring, REG_A6XX_RBBM_PERFCTR_CP(0), rbmemptr_stats(ring, index, cpcycles_end)); - get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER, + get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT, rbmemptr_stats(ring, index, alwayson_end)); /* Write the fence to the scratch register */ @@ -404,12 +405,12 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence))); OUT_RING(ring, submit->seqno); - trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu)); + trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu)); a6xx_flush(gpu, ring); } -static void a6xx_emit_set_pseudo_reg(struct msm_ringbuffer *ring, +void a6xx_emit_set_pseudo_reg(struct msm_ringbuffer *ring, struct a6xx_gpu *a6xx_gpu, struct msm_gpu_submitqueue *queue) { u64 preempt_postamble; @@ -455,7 +456,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); struct msm_ringbuffer *ring = submit->ring; - u32 rbbm_perfctr_cp0, cp_always_on_counter; + u32 rbbm_perfctr_cp0, cp_always_on_context; unsigned int i, ibs = 0; adreno_check_and_reenable_stall(adreno_gpu); @@ -478,14 +479,14 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) if (adreno_is_a8xx(adreno_gpu)) { rbbm_perfctr_cp0 = REG_A8XX_RBBM_PERFCTR_CP(0); - cp_always_on_counter = REG_A8XX_CP_ALWAYS_ON_COUNTER; + cp_always_on_context = REG_A8XX_CP_ALWAYS_ON_CONTEXT; } else { rbbm_perfctr_cp0 = REG_A7XX_RBBM_PERFCTR_CP(0); - cp_always_on_counter = REG_A6XX_CP_ALWAYS_ON_COUNTER; + cp_always_on_context = REG_A6XX_CP_ALWAYS_ON_CONTEXT; } get_stats_counter(ring, rbbm_perfctr_cp0, rbmemptr_stats(ring, index, cpcycles_start)); - get_stats_counter(ring, cp_always_on_counter, rbmemptr_stats(ring, index, alwayson_start)); + get_stats_counter(ring, cp_always_on_context, rbmemptr_stats(ring, index, alwayson_start)); OUT_PKT7(ring, CP_THREAD_CONTROL, 1); OUT_RING(ring, CP_SET_THREAD_BOTH); @@ -533,7 +534,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) } get_stats_counter(ring, rbbm_perfctr_cp0, rbmemptr_stats(ring, index, cpcycles_end)); - get_stats_counter(ring, cp_always_on_counter, rbmemptr_stats(ring, index, alwayson_end)); + get_stats_counter(ring, cp_always_on_context, rbmemptr_stats(ring, index, alwayson_end)); /* Write the fence to the scratch register */ if (adreno_is_a8xx(adreno_gpu)) { @@ -614,12 +615,15 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) } - trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu)); + trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu)); a6xx_flush(gpu, ring); /* Check to see if we need to start preemption */ - a6xx_preempt_trigger(gpu); + if (adreno_is_a8xx(adreno_gpu)) + a8xx_preempt_trigger(gpu); + else + a6xx_preempt_trigger(gpu); } static void a6xx_set_hwcg(struct msm_gpu *gpu, bool state) @@ -1603,6 +1607,12 @@ out: a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_BOOT_SLUMBER); } + if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) { + ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET); + if (!ret) + set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status); + } + return ret; } @@ -1635,7 +1645,7 @@ static void a6xx_recover(struct msm_gpu *gpu) adreno_dump_info(gpu); - if (a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) { + if (adreno_gpu->funcs->gx_is_on(adreno_gpu)) { /* Sometimes crashstate capture is skipped, so SQE should be halted here again */ gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3); @@ -2152,56 +2162,6 @@ static void a6xx_llc_slices_init(struct platform_device *pdev, a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL); } -static int a7xx_cx_mem_init(struct a6xx_gpu *a6xx_gpu) -{ - struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; - struct msm_gpu *gpu = &adreno_gpu->base; - u32 fuse_val; - int ret; - - if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { - /* - * Assume that if qcom scm isn't available, that whatever - * replacement allows writing the fuse register ourselves. - * Users of alternative firmware need to make sure this - * register is writeable or indicate that it's not somehow. - * Print a warning because if you mess this up you're about to - * crash horribly. - */ - if (!qcom_scm_is_available()) { - dev_warn_once(gpu->dev->dev, - "SCM is not available, poking fuse register\n"); - a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE, - A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING | - A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND | - A7XX_CX_MISC_SW_FUSE_VALUE_LPAC); - adreno_gpu->has_ray_tracing = true; - return 0; - } - - ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ | - QCOM_SCM_GPU_TSENSE_EN_REQ); - if (ret) - return ret; - - /* - * On A7XX_GEN3 and newer, raytracing may be disabled by the - * firmware, find out whether that's the case. The scm call - * above sets the fuse register. - */ - fuse_val = a6xx_llc_read(a6xx_gpu, - REG_A7XX_CX_MISC_SW_FUSE_VALUE); - adreno_gpu->has_ray_tracing = - !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING); - } else if (adreno_is_a740(adreno_gpu)) { - /* Raytracing is always enabled on a740 */ - adreno_gpu->has_ray_tracing = true; - } - - return 0; -} - - #define GBIF_CLIENT_HALT_MASK BIT(0) #define GBIF_ARB_HALT_MASK BIT(1) #define VBIF_XIN_HALT_CTRL0_MASK GENMASK(3, 0) @@ -2414,20 +2374,9 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu) return 0; } -static int a6xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value) -{ - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); - - *value = read_gmu_ao_counter(a6xx_gpu); - - return 0; -} - -static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) +static u64 a6xx_get_timestamp(struct msm_gpu *gpu) { - *value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER); - return 0; + return gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER); } static struct msm_ringbuffer *a6xx_active_ring(struct msm_gpu *gpu) @@ -2600,13 +2549,33 @@ static u32 fuse_to_supp_hw(const struct adreno_info *info, u32 fuse) return UINT_MAX; } -static int a6xx_set_supported_hw(struct device *dev, const struct adreno_info *info) +static int a6xx_read_speedbin(struct device *dev, struct a6xx_gpu *a6xx_gpu, + const struct adreno_info *info, u32 *speedbin) +{ + int ret; + + /* Use speedbin fuse if present. Otherwise, fallback to softfuse */ + ret = adreno_read_speedbin(dev, speedbin); + if (ret != -ENOENT) + return ret; + + if (info->quirks & ADRENO_QUIRK_SOFTFUSE) { + *speedbin = a6xx_llc_read(a6xx_gpu, REG_A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS); + *speedbin = A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS_FINALFREQLIMIT(*speedbin); + return 0; + } + + return -ENOENT; +} + +static int a6xx_set_supported_hw(struct device *dev, struct a6xx_gpu *a6xx_gpu, + const struct adreno_info *info) { u32 supp_hw; u32 speedbin; int ret; - ret = adreno_read_speedbin(dev, &speedbin); + ret = a6xx_read_speedbin(dev, a6xx_gpu, info, &speedbin); /* * -ENOENT means that the platform doesn't support speedbin which is * fine @@ -2635,16 +2604,29 @@ static int a6xx_set_supported_hw(struct device *dev, const struct adreno_info *i return 0; } +static bool a6xx_aqe_is_enabled(struct adreno_gpu *adreno_gpu) +{ + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + + /* + * AQE uses preemption context record as scratch pad, so check if + * preemption is enabled + */ + return (adreno_gpu->base.nr_rings > 1) && !!a6xx_gpu->aqe_bo; +} + static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; struct platform_device *pdev = priv->gpu_pdev; struct adreno_platform_config *config = pdev->dev.platform_data; + const struct adreno_info *info = config->info; struct device_node *node; struct a6xx_gpu *a6xx_gpu; struct adreno_gpu *adreno_gpu; struct msm_gpu *gpu; extern int enable_preemption; + u32 speedbin; bool is_a7xx; int ret, nr_rings = 1; @@ -2656,6 +2638,7 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) gpu = &adreno_gpu->base; mutex_init(&a6xx_gpu->gmu.lock); + spin_lock_init(&a6xx_gpu->aperture_lock); adreno_gpu->registers = NULL; @@ -2667,14 +2650,14 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) adreno_gpu->gmu_is_wrapper = of_device_is_compatible(node, "qcom,adreno-gmu-wrapper"); adreno_gpu->base.hw_apriv = - !!(config->info->quirks & ADRENO_QUIRK_HAS_HW_APRIV); + !!(info->quirks & ADRENO_QUIRK_HAS_HW_APRIV); /* gpu->info only gets assigned in adreno_gpu_init(). A8x is included intentionally */ - is_a7xx = config->info->family >= ADRENO_7XX_GEN1; + is_a7xx = info->family >= ADRENO_7XX_GEN1; a6xx_llc_slices_init(pdev, a6xx_gpu, is_a7xx); - ret = a6xx_set_supported_hw(&pdev->dev, config->info); + ret = a6xx_set_supported_hw(&pdev->dev, a6xx_gpu, info); if (ret) { a6xx_llc_slices_destroy(a6xx_gpu); kfree(a6xx_gpu); @@ -2682,15 +2665,20 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) } if ((enable_preemption == 1) || (enable_preemption == -1 && - (config->info->quirks & ADRENO_QUIRK_PREEMPTION))) + (info->quirks & ADRENO_QUIRK_PREEMPTION))) nr_rings = 4; - ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, nr_rings); + ret = adreno_gpu_init(dev, pdev, adreno_gpu, info->funcs, nr_rings); if (ret) { a6xx_destroy(&(a6xx_gpu->base.base)); return ERR_PTR(ret); } + /* Set the speedbin value that is passed to userspace */ + if (a6xx_read_speedbin(&pdev->dev, a6xx_gpu, info, &speedbin) || !speedbin) + speedbin = 0xffff; + adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin); + /* * For now only clamp to idle freq for devices where this is known not * to cause power supply issues: @@ -2708,14 +2696,6 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) return ERR_PTR(ret); } - if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { - ret = a7xx_cx_mem_init(a6xx_gpu); - if (ret) { - a6xx_destroy(&(a6xx_gpu->base.base)); - return ERR_PTR(ret); - } - } - adreno_gpu->uche_trap_base = 0x1fffffffff000ull; msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu, @@ -2765,6 +2745,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = { .get_timestamp = a6xx_gmu_get_timestamp, .bus_halt = a6xx_bus_clear_pending_transactions, .mmu_fault_handler = a6xx_fault_handler, + .gx_is_on = a6xx_gmu_gx_is_on, }; const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = { @@ -2797,6 +2778,7 @@ const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = { .get_timestamp = a6xx_get_timestamp, .bus_halt = a6xx_bus_clear_pending_transactions, .mmu_fault_handler = a6xx_fault_handler, + .gx_is_on = a6xx_gmu_gx_is_on, }; const struct adreno_gpu_funcs a7xx_gpu_funcs = { @@ -2831,6 +2813,8 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = { .get_timestamp = a6xx_gmu_get_timestamp, .bus_halt = a6xx_bus_clear_pending_transactions, .mmu_fault_handler = a6xx_fault_handler, + .gx_is_on = a7xx_gmu_gx_is_on, + .aqe_is_enabled = a6xx_aqe_is_enabled, }; const struct adreno_gpu_funcs a8xx_gpu_funcs = { @@ -2858,4 +2842,6 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = { .get_timestamp = a8xx_gmu_get_timestamp, .bus_halt = a8xx_bus_clear_pending_transactions, .mmu_fault_handler = a8xx_fault_handler, + .gx_is_on = a8xx_gmu_gx_is_on, + .aqe_is_enabled = a6xx_aqe_is_enabled, }; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index 4eaa04711246..eb431e5e00b1 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -278,6 +278,8 @@ void a6xx_preempt_hw_init(struct msm_gpu *gpu); void a6xx_preempt_trigger(struct msm_gpu *gpu); void a6xx_preempt_irq(struct msm_gpu *gpu); void a6xx_preempt_fini(struct msm_gpu *gpu); +void a6xx_emit_set_pseudo_reg(struct msm_ringbuffer *ring, + struct a6xx_gpu *a6xx_gpu, struct msm_gpu_submitqueue *queue); int a6xx_preempt_submitqueue_setup(struct msm_gpu *gpu, struct msm_gpu_submitqueue *queue); void a6xx_preempt_submitqueue_close(struct msm_gpu *gpu, @@ -320,13 +322,16 @@ int a6xx_zap_shader_init(struct msm_gpu *gpu); void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off); int a8xx_fault_handler(void *arg, unsigned long iova, int flags, void *data); void a8xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring); -int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value); +u64 a8xx_gmu_get_timestamp(struct msm_gpu *gpu); u64 a8xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate); int a8xx_gpu_feature_probe(struct msm_gpu *gpu); void a8xx_gpu_get_slice_info(struct msm_gpu *gpu); int a8xx_hw_init(struct msm_gpu *gpu); irqreturn_t a8xx_irq(struct msm_gpu *gpu); void a8xx_llc_activate(struct a6xx_gpu *a6xx_gpu); +void a8xx_preempt_hw_init(struct msm_gpu *gpu); +void a8xx_preempt_trigger(struct msm_gpu *gpu); +void a8xx_preempt_irq(struct msm_gpu *gpu); bool a8xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring); void a8xx_recover(struct msm_gpu *gpu); #endif /* __A6XX_GPU_H__ */ diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index 2d56fe0a65b7..166365359fa6 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -57,7 +57,7 @@ struct a6xx_gpu_state { struct msm_gpu_state_bo *gmu_hfi; struct msm_gpu_state_bo *gmu_debug; - s32 hfi_queue_history[2][HFI_HISTORY_SZ]; + s32 hfi_queue_history[HFI_MAX_QUEUES][HFI_HISTORY_SZ]; struct list_head objs; @@ -361,7 +361,7 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, sizeof(*a6xx_state->debugbus)); if (a6xx_state->debugbus) { - int i; + int i, j; for (i = 0; i < ARRAY_SIZE(a6xx_debugbus_blocks); i++) a6xx_get_debugbus_block(gpu, @@ -369,8 +369,6 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, &a6xx_debugbus_blocks[i], &a6xx_state->debugbus[i]); - a6xx_state->nr_debugbus = ARRAY_SIZE(a6xx_debugbus_blocks); - /* * GBIF has same debugbus as of other GPU blocks, fall back to * default path if GPU uses GBIF, also GBIF uses exactly same @@ -381,17 +379,19 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, &a6xx_gbif_debugbus_block, &a6xx_state->debugbus[i]); - a6xx_state->nr_debugbus += 1; + i++; } if (adreno_is_a650_family(to_adreno_gpu(gpu))) { - for (i = 0; i < ARRAY_SIZE(a650_debugbus_blocks); i++) + for (j = 0; j < ARRAY_SIZE(a650_debugbus_blocks); i++, j++) a6xx_get_debugbus_block(gpu, a6xx_state, - &a650_debugbus_blocks[i], + &a650_debugbus_blocks[j], &a6xx_state->debugbus[i]); } + + a6xx_state->nr_debugbus = i; } } @@ -1013,7 +1013,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; int i, regcount = 0; - in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); + in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); for (i = 0; i < regs->count; i += 2) { u32 count = RANGE(regs->registers, i); @@ -1251,7 +1251,7 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu, _a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gpucc_reg, &a6xx_state->gmu_registers[2], false); - if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) + if (!adreno_gpu->funcs->gx_is_on(adreno_gpu)) return; /* Set the fence to ALLOW mode so we can access the registers */ @@ -1607,7 +1607,7 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu) } /* If GX isn't on the rest of the data isn't going to be accessible */ - if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) + if (!adreno_gpu->funcs->gx_is_on(adreno_gpu)) return &a6xx_state->base; /* Halt SQE first */ diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c index 53cfdf4e6c34..487c2736f2b3 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c @@ -34,7 +34,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, struct a6xx_hfi_queue_header *header = queue->header; u32 i, hdr, index = header->read_index; - if (header->read_index == header->write_index) { + if (header->read_index == READ_ONCE(header->write_index)) { header->rx_request = 1; return 0; } @@ -62,7 +62,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, if (!gmu->legacy) index = ALIGN(index, 4) % header->size; - header->read_index = index; + /* Ensure all memory operations are complete before updating the read index */ + dma_mb(); + + WRITE_ONCE(header->read_index, index); return HFI_HEADER_SIZE(hdr); } @@ -74,7 +77,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, spin_lock(&queue->lock); - space = CIRC_SPACE(header->write_index, header->read_index, + space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), header->size); if (space < dwords) { header->dropped++; @@ -95,7 +98,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, queue->data[index] = 0xfafafafa; } - header->write_index = index; + /* Ensure all memory operations are complete before updating the write index */ + dma_mb(); + + WRITE_ONCE(header->write_index, index); spin_unlock(&queue->lock); gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); @@ -845,7 +851,6 @@ static int a6xx_hfi_feature_ctrl_msg(struct a6xx_gmu *gmu, u32 feature, u32 enab return a6xx_hfi_send_msg(gmu, HFI_H2F_FEATURE_CTRL, &msg, sizeof(msg), NULL, 0); } -#define HFI_FEATURE_IFPC 9 #define IFPC_LONG_HYST 0x1680 static int a6xx_hfi_enable_ifpc(struct a6xx_gmu *gmu) @@ -856,8 +861,6 @@ static int a6xx_hfi_enable_ifpc(struct a6xx_gmu *gmu) return a6xx_hfi_feature_ctrl_msg(gmu, HFI_FEATURE_IFPC, 1, IFPC_LONG_HYST); } -#define HFI_FEATURE_ACD 12 - static int a6xx_hfi_enable_acd(struct a6xx_gmu *gmu) { struct a6xx_hfi_acd_table *acd_table = &gmu->acd_table; @@ -1056,8 +1059,8 @@ void a6xx_hfi_init(struct a6xx_gmu *gmu) struct a6xx_gmu_bo *hfi = &gmu->hfi; struct a6xx_hfi_queue_table_header *table = hfi->virt; struct a6xx_hfi_queue_header *headers = hfi->virt + sizeof(*table); + int table_size, idx; u64 offset; - int table_size; /* * The table size is the size of the table header plus all of the queue @@ -1076,12 +1079,22 @@ void a6xx_hfi_init(struct a6xx_gmu *gmu) table->active_queues = ARRAY_SIZE(gmu->queues); /* Command queue */ + idx = 0; offset = SZ_4K; - a6xx_hfi_queue_init(&gmu->queues[0], &headers[0], hfi->virt + offset, + a6xx_hfi_queue_init(&gmu->queues[idx], &headers[idx], hfi->virt + offset, hfi->iova + offset, 0); /* GMU response queue */ + idx++; offset += SZ_4K; - a6xx_hfi_queue_init(&gmu->queues[1], &headers[1], hfi->virt + offset, + a6xx_hfi_queue_init(&gmu->queues[idx], &headers[idx], hfi->virt + offset, hfi->iova + offset, gmu->legacy ? 4 : 1); + + /* GMU Debug queue */ + idx++; + offset += SZ_4K; + a6xx_hfi_queue_init(&gmu->queues[idx], &headers[idx], hfi->virt + offset, + hfi->iova + offset, gmu->legacy ? 5 : 2); + + WARN_ON(idx >= HFI_MAX_QUEUES); } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h index 6f9f74a0bc85..e10d32ce93e0 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h @@ -4,6 +4,8 @@ #ifndef _A6XX_HFI_H_ #define _A6XX_HFI_H_ +#define HFI_MAX_QUEUES 3 + struct a6xx_hfi_queue_table_header { u32 version; u32 size; /* Size of the queue table in dwords */ @@ -11,7 +13,7 @@ struct a6xx_hfi_queue_table_header { u32 qhdr_size; /* Size of the queue headers */ u32 num_queues; /* Number of total queues */ u32 active_queues; /* Number of active queues */ -}; +} __packed; struct a6xx_hfi_queue_header { u32 status; @@ -26,7 +28,7 @@ struct a6xx_hfi_queue_header { u32 tx_request; u32 read_index; u32 write_index; -}; +} __packed; struct a6xx_hfi_queue { struct a6xx_hfi_queue_header *header; @@ -72,7 +74,7 @@ struct a6xx_hfi_msg_response { u32 ret_header; u32 error; u32 payload[HFI_RESPONSE_PAYLOAD_SIZE]; -}; +} __packed; #define HFI_F2H_MSG_ERROR 100 @@ -80,7 +82,7 @@ struct a6xx_hfi_msg_error { u32 header; u32 code; u32 payload[2]; -}; +} __packed; #define HFI_H2F_MSG_INIT 0 @@ -90,27 +92,27 @@ struct a6xx_hfi_msg_gmu_init_cmd { u32 dbg_buffer_addr; u32 dbg_buffer_size; u32 boot_state; -}; +} __packed; #define HFI_H2F_MSG_FW_VERSION 1 struct a6xx_hfi_msg_fw_version { u32 header; u32 supported_version; -}; +} __packed; #define HFI_H2F_MSG_PERF_TABLE 4 struct perf_level { u32 vote; u32 freq; -}; +} __packed; struct perf_gx_level { u32 vote; u32 acd; u32 freq; -}; +} __packed; struct a6xx_hfi_msg_perf_table_v1 { u32 header; @@ -119,7 +121,7 @@ struct a6xx_hfi_msg_perf_table_v1 { struct perf_level gx_votes[16]; struct perf_level cx_votes[4]; -}; +} __packed; struct a6xx_hfi_msg_perf_table { u32 header; @@ -128,7 +130,7 @@ struct a6xx_hfi_msg_perf_table { struct perf_gx_level gx_votes[16]; struct perf_level cx_votes[4]; -}; +} __packed; #define HFI_H2F_MSG_BW_TABLE 3 @@ -143,13 +145,13 @@ struct a6xx_hfi_msg_bw_table { u32 cnoc_cmds_data[2][6]; u32 ddr_cmds_addrs[8]; u32 ddr_cmds_data[16][8]; -}; +} __packed; #define HFI_H2F_MSG_TEST 5 struct a6xx_hfi_msg_test { u32 header; -}; +} __packed; #define HFI_H2F_MSG_ACD 7 #define MAX_ACD_STRIDE 2 @@ -161,29 +163,100 @@ struct a6xx_hfi_acd_table { u32 stride; u32 num_levels; u32 data[16 * MAX_ACD_STRIDE]; -}; +} __packed; + +#define CLX_DATA(irated, num_phases, clx_path, extd_intf) \ + ((extd_intf << 29) | \ + (clx_path << 28) | \ + (num_phases << 22) | \ + (irated << 16)) + +struct a6xx_hfi_clx_domain_v2 { + /** + * @data: BITS[0:15] Migration time + * BITS[16:21] Current rating + * BITS[22:27] Phases for domain + * BITS[28:28] Path notification + * BITS[29:31] Extra features + */ + u32 data; + /** @clxt: CLX time in microseconds */ + u32 clxt; + /** @clxh: CLH time in microseconds */ + u32 clxh; + /** @urg_mode: Urgent HW throttle mode of operation */ + u32 urg_mode; + /** @lkg_en: Enable leakage current estimate */ + u32 lkg_en; + /** curr_budget: Current Budget */ + u32 curr_budget; +} __packed; + +#define HFI_H2F_MSG_CLX_TBL 8 + +#define MAX_CLX_DOMAINS 2 +struct a6xx_hfi_clx_table_v2_cmd { + u32 hdr; + u32 version; + struct a6xx_hfi_clx_domain_v2 domain[MAX_CLX_DOMAINS]; +} __packed; #define HFI_H2F_MSG_START 10 struct a6xx_hfi_msg_start { u32 header; -}; +} __packed; #define HFI_H2F_FEATURE_CTRL 11 struct a6xx_hfi_msg_feature_ctrl { u32 header; u32 feature; +#define HFI_FEATURE_DCVS 0 +#define HFI_FEATURE_HWSCHED 1 +#define HFI_FEATURE_PREEMPTION 2 +#define HFI_FEATURE_CLOCKS_ON 3 +#define HFI_FEATURE_BUS_ON 4 +#define HFI_FEATURE_RAIL_ON 5 +#define HFI_FEATURE_HWCG 6 +#define HFI_FEATURE_LM 7 +#define HFI_FEATURE_THROTTLE 8 +#define HFI_FEATURE_IFPC 9 +#define HFI_FEATURE_NAP 10 +#define HFI_FEATURE_BCL 11 +#define HFI_FEATURE_ACD 12 +#define HFI_FEATURE_DIDT 13 +#define HFI_FEATURE_DEPRECATED 14 +#define HFI_FEATURE_CB 15 +#define HFI_FEATURE_KPROF 16 +#define HFI_FEATURE_BAIL_OUT_TIMER 17 +#define HFI_FEATURE_GMU_STATS 18 +#define HFI_FEATURE_DBQ 19 +#define HFI_FEATURE_MINBW 20 +#define HFI_FEATURE_CLX 21 +#define HFI_FEATURE_LSR 23 +#define HFI_FEATURE_LPAC 24 +#define HFI_FEATURE_HW_FENCE 25 +#define HFI_FEATURE_PERF_NORETAIN 26 +#define HFI_FEATURE_DMS 27 +#define HFI_FEATURE_THERMAL 28 +#define HFI_FEATURE_AQE 29 +#define HFI_FEATURE_TDCVS 30 +#define HFI_FEATURE_DCE 31 +#define HFI_FEATURE_IFF_PCLX 32 +#define HFI_FEATURE_SOFT_RESET 0x10000001 +#define HFI_FEATURE_DCVS_PROFILE 0x10000002 +#define HFI_FEATURE_FAST_CTX_DESTROY 0x10000003 u32 enable; u32 data; -}; +} __packed; #define HFI_H2F_MSG_CORE_FW_START 14 struct a6xx_hfi_msg_core_fw_start { u32 header; u32 handle; -}; +} __packed; #define HFI_H2F_MSG_TABLE 15 @@ -191,16 +264,25 @@ struct a6xx_hfi_table_entry { u32 count; u32 stride; u32 data[]; -}; +} __packed; struct a6xx_hfi_table { u32 header; u32 version; u32 type; -#define HFI_TABLE_BW_VOTE 0 -#define HFI_TABLE_GPU_PERF 1 +#define HFI_TABLE_BW_VOTE 0 +#define HFI_TABLE_GPU_PERF 1 +#define HFI_TABLE_DIDT 2 +#define HFI_TABLE_ACD 3 +#define HFI_TABLE_CLX_V1 4 /* Unused */ +#define HFI_TABLE_CLX_V2 5 +#define HFI_TABLE_THERM 6 +#define HFI_TABLE_DCVS 7 +#define HFI_TABLE_SYS_TIME 8 +#define HFI_TABLE_GMU_DCVS 9 +#define HFI_TABLE_LIMITS_MIT 10 struct a6xx_hfi_table_entry entry[]; -}; +} __packed; #define HFI_H2F_MSG_GX_BW_PERF_VOTE 30 @@ -209,7 +291,7 @@ struct a6xx_hfi_gx_bw_perf_vote_cmd { u32 ack_type; u32 freq; u32 bw; -}; +} __packed; #define AB_VOTE_MASK GENMASK(31, 16) #define MAX_AB_VOTE (FIELD_MAX(AB_VOTE_MASK) - 1) @@ -222,6 +304,35 @@ struct a6xx_hfi_prep_slumber_cmd { u32 header; u32 bw; u32 freq; -}; +} __packed; + +struct a6xx_hfi_limits_cfg { + u32 enable; + u32 msg_path; + u32 lkg_en; + /* + * BIT[0]: 0 = (static) throttle to fixed sid level + * 1 = (dynamic) throttle to sid level calculated by HW + * BIT[1]: 0 = Mx + * 1 = Bx + */ + u32 mode; + u32 sid; + /* Mitigation time in microseconds */ + u32 mit_time; + /* Max current in mA during mitigation */ + u32 curr_limit; +} __packed; + +struct a6xx_hfi_limits_tbl { + u8 feature_id; +#define GMU_MIT_IFF 0 +#define GMU_MIT_PCLX 1 + u8 domain; +#define GMU_GX_DOMAIN 0 +#define GMU_MX_DOMAIN 1 + u16 feature_rev; + struct a6xx_hfi_limits_cfg cfg; +} __packed; #endif diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c index 747a22afad9f..df4cbf42e9a4 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c @@ -6,85 +6,10 @@ #include "msm_gem.h" #include "a6xx_gpu.h" #include "a6xx_gmu.xml.h" +#include "a6xx_preempt.h" #include "msm_mmu.h" #include "msm_gpu_trace.h" -/* - * Try to transition the preemption state from old to new. Return - * true on success or false if the original state wasn't 'old' - */ -static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu, - enum a6xx_preempt_state old, enum a6xx_preempt_state new) -{ - enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state, - old, new); - - return (cur == old); -} - -/* - * Force the preemption state to the specified state. This is used in cases - * where the current state is known and won't change - */ -static inline void set_preempt_state(struct a6xx_gpu *gpu, - enum a6xx_preempt_state new) -{ - /* - * preempt_state may be read by other cores trying to trigger a - * preemption or in the interrupt handler so barriers are needed - * before... - */ - smp_mb__before_atomic(); - atomic_set(&gpu->preempt_state, new); - /* ... and after*/ - smp_mb__after_atomic(); -} - -/* Write the most recent wptr for the given ring into the hardware */ -static inline void update_wptr(struct a6xx_gpu *a6xx_gpu, struct msm_ringbuffer *ring) -{ - unsigned long flags; - uint32_t wptr; - - spin_lock_irqsave(&ring->preempt_lock, flags); - - if (ring->restore_wptr) { - wptr = get_wptr(ring); - - a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false); - - ring->restore_wptr = false; - } - - spin_unlock_irqrestore(&ring->preempt_lock, flags); -} - -/* Return the highest priority ringbuffer with something in it */ -static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) -{ - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); - - unsigned long flags; - int i; - - for (i = 0; i < gpu->nr_rings; i++) { - bool empty; - struct msm_ringbuffer *ring = gpu->rb[i]; - - spin_lock_irqsave(&ring->preempt_lock, flags); - empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring)); - if (!empty && ring == a6xx_gpu->cur_ring) - empty = ring->memptrs->fence == a6xx_gpu->last_seqno[i]; - spin_unlock_irqrestore(&ring->preempt_lock, flags); - - if (!empty) - return ring; - } - - return NULL; -} - static void a6xx_preempt_timer(struct timer_list *t) { struct a6xx_gpu *a6xx_gpu = timer_container_of(a6xx_gpu, t, diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.h b/drivers/gpu/drm/msm/adreno/a6xx_preempt.h new file mode 100644 index 000000000000..df36c945b836 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2023 Collabora, Ltd. */ +/* Copyright (c) 2024 Valve Corporation */ +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ + +/* + * Try to transition the preemption state from old to new. Return + * true on success or false if the original state wasn't 'old' + */ +static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu, + enum a6xx_preempt_state old, enum a6xx_preempt_state new) +{ + enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state, + old, new); + + return (cur == old); +} + +/* + * Force the preemption state to the specified state. This is used in cases + * where the current state is known and won't change + */ +static inline void set_preempt_state(struct a6xx_gpu *gpu, + enum a6xx_preempt_state new) +{ + /* + * preempt_state may be read by other cores trying to trigger a + * preemption or in the interrupt handler so barriers are needed + * before... + */ + smp_mb__before_atomic(); + atomic_set(&gpu->preempt_state, new); + /* ... and after */ + smp_mb__after_atomic(); +} + +/* Write the most recent wptr for the given ring into the hardware */ +static inline void update_wptr(struct a6xx_gpu *a6xx_gpu, struct msm_ringbuffer *ring) +{ + unsigned long flags; + uint32_t wptr; + + spin_lock_irqsave(&ring->preempt_lock, flags); + + if (ring->restore_wptr) { + wptr = get_wptr(ring); + + a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false); + + ring->restore_wptr = false; + } + + spin_unlock_irqrestore(&ring->preempt_lock, flags); +} + +/* Return the highest priority ringbuffer with something in it */ +static inline struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + + unsigned long flags; + int i; + + for (i = 0; i < gpu->nr_rings; i++) { + bool empty; + struct msm_ringbuffer *ring = gpu->rb[i]; + + spin_lock_irqsave(&ring->preempt_lock, flags); + empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring)); + if (!empty && ring == a6xx_gpu->cur_ring) + empty = ring->memptrs->fence == a6xx_gpu->last_seqno[i]; + spin_unlock_irqrestore(&ring->preempt_lock, flags); + + if (!empty) + return ring; + } + + return NULL; +} + diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c index 5a320f5bde41..ccfccc45133f 100644 --- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c @@ -87,6 +87,7 @@ void a8xx_gpu_get_slice_info(struct msm_gpu *gpu) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); const struct a6xx_info *info = adreno_gpu->info->a6xx; + struct device *dev = &gpu->pdev->dev; u32 slice_mask; if (adreno_gpu->info->family < ADRENO_8XX_GEN1) @@ -110,6 +111,15 @@ void a8xx_gpu_get_slice_info(struct msm_gpu *gpu) /* Chip ID depends on the number of slices available. So update it */ adreno_gpu->chip_id |= FIELD_PREP(GENMASK(7, 4), hweight32(slice_mask)); + + /* Update the gpu-name to reflect the slice config: */ + const char *name = devm_kasprintf(dev, GFP_KERNEL, + "%"ADRENO_CHIPID_FMT, + ADRENO_CHIPID_ARGS(adreno_gpu->chip_id)); + if (name) { + devm_kfree(dev, adreno_gpu->base.name); + adreno_gpu->base.name = name; + } } static u32 a8xx_get_first_slice(struct a6xx_gpu *a6xx_gpu) @@ -173,7 +183,7 @@ void a8xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) /* Update HW if this is the current ring and we are not in preempt*/ if (!a6xx_in_preempt(a6xx_gpu)) { if (a6xx_gpu->cur_ring == ring) - gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr); + a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false); else ring->restore_wptr = true; } else { @@ -310,11 +320,21 @@ static void a8xx_set_ubwc_config(struct msm_gpu *gpu) hbb = cfg->highest_bank_bit - 13; hbb_hi = hbb >> 2; hbb_lo = hbb & 3; - a8xx_write_pipe(gpu, PIPE_BV, REG_A8XX_GRAS_NC_MODE_CNTL, hbb << 5); - a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_GRAS_NC_MODE_CNTL, hbb << 5); + + a8xx_write_pipe(gpu, PIPE_BV, REG_A8XX_GRAS_NC_MODE_CNTL, + hbb << 5 | + level3_swizzling_dis << 4 | + level2_swizzling_dis << 3); + + a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_GRAS_NC_MODE_CNTL, + hbb << 5 | + level3_swizzling_dis << 4 | + level2_swizzling_dis << 3); a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_RB_CCU_NC_MODE_CNTL, yuvnotcomptofc << 6 | + level3_swizzling_dis << 5 | + level2_swizzling_dis << 4 | hbb_hi << 3 | hbb_lo << 1); @@ -376,8 +396,115 @@ static void a8xx_nonctxt_config(struct msm_gpu *gpu, u32 *gmem_protect) a8xx_aperture_clear(gpu); } +static void a8xx_patch_pwrup_reglist(struct msm_gpu *gpu) +{ + const struct adreno_reglist_pipe_list *dyn_pwrup_reglist; + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + const struct adreno_reglist_list *reglist; + void *ptr = a6xx_gpu->pwrup_reglist_ptr; + struct cpu_gpu_lock *lock = ptr; + u32 *dest = (u32 *)&lock->regs[0]; + u32 dyn_pwrup_reglist_count = 0; + int i; + + lock->gpu_req = lock->cpu_req = lock->turn = 0; + + reglist = adreno_gpu->info->a6xx->ifpc_reglist; + if (reglist) { + lock->ifpc_list_len = reglist->count; + + /* + * For each entry in each of the lists, write the offset and the current + * register value into the GPU buffer + */ + for (i = 0; i < reglist->count; i++) { + *dest++ = reglist->regs[i]; + *dest++ = gpu_read(gpu, reglist->regs[i]); + } + } + + reglist = adreno_gpu->info->a6xx->pwrup_reglist; + if (reglist) { + lock->preemption_list_len = reglist->count; + + for (i = 0; i < reglist->count; i++) { + *dest++ = reglist->regs[i]; + *dest++ = gpu_read(gpu, reglist->regs[i]); + } + } + + /* + * The overall register list is composed of + * 1. Static IFPC-only registers + * 2. Static IFPC + preemption registers + * 3. Dynamic IFPC + preemption registers (ex: perfcounter selects) + * + * The first two lists are static. Size of these lists are stored as + * number of pairs in ifpc_list_len and preemption_list_len + * respectively. With concurrent binning, Some of the perfcounter + * registers being virtualized, CP needs to know the pipe id to program + * the aperture inorder to restore the same. Thus, third list is a + * dynamic list with triplets as + * (<aperture, shifted 12 bits> <address> <data>), and the length is + * stored as number for triplets in dynamic_list_len. + */ + dyn_pwrup_reglist = adreno_gpu->info->a6xx->dyn_pwrup_reglist; + if (!dyn_pwrup_reglist) + goto done; + + for (u32 pipe_id = PIPE_BR; pipe_id <= PIPE_DDE_BV; pipe_id++) { + for (i = 0; i < dyn_pwrup_reglist->count; i++) { + if (!(dyn_pwrup_reglist->regs[i].pipe & BIT(pipe_id))) + continue; + *dest++ = A8XX_CP_APERTURE_CNTL_HOST_PIPEID(pipe_id); + *dest++ = dyn_pwrup_reglist->regs[i].offset; + *dest++ = a8xx_read_pipe_slice(gpu, + pipe_id, + a8xx_get_first_slice(a6xx_gpu), + dyn_pwrup_reglist->regs[i].offset); + dyn_pwrup_reglist_count++; + } + } + + lock->dynamic_list_len = dyn_pwrup_reglist_count; + +done: + a8xx_aperture_clear(gpu); +} + +static int a8xx_preempt_start(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring = gpu->rb[0]; + + if (gpu->nr_rings <= 1) + return 0; + + /* Turn CP protection off */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 0); + + a6xx_emit_set_pseudo_reg(ring, a6xx_gpu, NULL); + + /* Yield the floor on command completion */ + OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); + OUT_RING(ring, 0x00); + OUT_RING(ring, 0x00); + OUT_RING(ring, 0x00); + /* Generate interrupt on preemption completion */ + OUT_RING(ring, 0x00); + + a6xx_flush(gpu, ring); + + return a8xx_idle(gpu, ring) ? 0 : -EINVAL; +} + static int a8xx_cp_init(struct msm_gpu *gpu) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); struct msm_ringbuffer *ring = gpu->rb[0]; u32 mask; @@ -385,7 +512,7 @@ static int a8xx_cp_init(struct msm_gpu *gpu) OUT_PKT7(ring, CP_THREAD_CONTROL, 1); OUT_RING(ring, BIT(27)); - OUT_PKT7(ring, CP_ME_INIT, 4); + OUT_PKT7(ring, CP_ME_INIT, 7); /* Use multiple HW contexts */ mask = BIT(0); @@ -399,6 +526,9 @@ static int a8xx_cp_init(struct msm_gpu *gpu) /* Disable save/restore of performance counters across preemption */ mask |= BIT(6); + /* Enable the register init list with the spinlock */ + mask |= BIT(8); + OUT_RING(ring, mask); /* Enable multiple hardware contexts */ @@ -410,6 +540,14 @@ static int a8xx_cp_init(struct msm_gpu *gpu) /* Operation mode mask */ OUT_RING(ring, 0x00000002); + /* Lo address */ + OUT_RING(ring, lower_32_bits(a6xx_gpu->pwrup_reglist_iova)); + /* Hi address */ + OUT_RING(ring, upper_32_bits(a6xx_gpu->pwrup_reglist_iova)); + + /* Enable dyn pwrup list with triplets (offset, value, pipe) */ + OUT_RING(ring, BIT(31)); + a6xx_flush(gpu, ring); return a8xx_idle(gpu, ring) ? 0 : -EINVAL; } @@ -638,6 +776,8 @@ static int hw_init(struct msm_gpu *gpu) gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR, shadowptr(a6xx_gpu, gpu->rb[0])); gpu_write64(gpu, REG_A8XX_CP_RB_RPTR_ADDR_BV, rbmemptr(gpu->rb[0], bv_rptr)); + a8xx_preempt_hw_init(gpu); + for (i = 0; i < gpu->nr_rings; i++) a6xx_gpu->shadow[i] = 0; @@ -692,15 +832,29 @@ static int hw_init(struct msm_gpu *gpu) WARN_ON(!gmem_protect); a8xx_aperture_clear(gpu); + if (!a6xx_gpu->pwrup_reglist_emitted) { + a8xx_patch_pwrup_reglist(gpu); + a6xx_gpu->pwrup_reglist_emitted = true; + } + /* Enable hardware clockgating */ a8xx_set_hwcg(gpu, true); out: + /* Last step - yield the ringbuffer */ + a8xx_preempt_start(gpu); + /* * Tell the GMU that we are done touching the GPU and it can start power * management */ a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); + if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) { + ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET); + if (!ret) + set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status); + } + return ret; } @@ -1098,11 +1252,11 @@ irqreturn_t a8xx_irq(struct msm_gpu *gpu) if (status & A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) { msm_gpu_retire(gpu); - a6xx_preempt_trigger(gpu); + a8xx_preempt_trigger(gpu); } if (status & A6XX_RBBM_INT_0_MASK_CP_SW) - a6xx_preempt_irq(gpu); + a8xx_preempt_irq(gpu); return IRQ_HANDLED; } @@ -1164,23 +1318,19 @@ void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_ gpu_write(gpu, REG_A6XX_GBIF_HALT, 0x0); } -int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value) +u64 a8xx_gmu_get_timestamp(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + u64 count_hi, count_lo, temp; - mutex_lock(&a6xx_gpu->gmu.lock); - - /* Force the GPU power on so we can read this register */ - a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET); - - *value = gpu_read64(gpu, REG_A8XX_CP_ALWAYS_ON_COUNTER); - - a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET); - - mutex_unlock(&a6xx_gpu->gmu.lock); + do { + count_hi = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H); + count_lo = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_L); + temp = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H); + } while (unlikely(count_hi != temp)); - return 0; + return (count_hi << 32) | count_lo; } u64 a8xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate) diff --git a/drivers/gpu/drm/msm/adreno/a8xx_preempt.c b/drivers/gpu/drm/msm/adreno/a8xx_preempt.c new file mode 100644 index 000000000000..3d8c33ba722e --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a8xx_preempt.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ + +#include "msm_gem.h" +#include "a6xx_gpu.h" +#include "a6xx_gmu.xml.h" +#include "a6xx_preempt.h" +#include "msm_mmu.h" +#include "msm_gpu_trace.h" + +static void preempt_prepare_postamble(struct a6xx_gpu *a6xx_gpu) +{ + u32 *postamble = a6xx_gpu->preempt_postamble_ptr; + u32 count = 0; + + postamble[count++] = PKT7(CP_REG_RMW, 3); + postamble[count++] = REG_A8XX_RBBM_PERFCTR_SRAM_INIT_CMD; + postamble[count++] = 0; + postamble[count++] = 1; + + postamble[count++] = PKT7(CP_WAIT_REG_MEM, 6); + postamble[count++] = CP_WAIT_REG_MEM_0_FUNCTION(WRITE_EQ); + postamble[count++] = CP_WAIT_REG_MEM_POLL_ADDR_LO( + REG_A8XX_RBBM_PERFCTR_SRAM_INIT_STATUS); + postamble[count++] = CP_WAIT_REG_MEM_POLL_ADDR_HI(0); + postamble[count++] = CP_WAIT_REG_MEM_3_REF(0x1); + postamble[count++] = CP_WAIT_REG_MEM_4_MASK(0x1); + postamble[count++] = CP_WAIT_REG_MEM_5_DELAY_LOOP_CYCLES(0); + + a6xx_gpu->preempt_postamble_len = count; + + a6xx_gpu->postamble_enabled = true; +} + +static void preempt_disable_postamble(struct a6xx_gpu *a6xx_gpu) +{ + u32 *postamble = a6xx_gpu->preempt_postamble_ptr; + + /* + * Disable the postamble by replacing the first packet header with a NOP + * that covers the whole buffer. + */ + *postamble = PKT7(CP_NOP, (a6xx_gpu->preempt_postamble_len - 1)); + + a6xx_gpu->postamble_enabled = false; +} + +/* + * Set preemption keepalive vote. Please note that this vote is different from the one used in + * a8xx_irq() + */ +static void a8xx_preempt_keepalive_vote(struct msm_gpu *gpu, bool on) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + + gmu_write(&a6xx_gpu->gmu, REG_A8XX_GMU_PWR_COL_PREEMPT_KEEPALIVE, on); +} + +void a8xx_preempt_irq(struct msm_gpu *gpu) +{ + uint32_t status; + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct drm_device *dev = gpu->dev; + + if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING)) + return; + + /* Delete the preemption watchdog timer */ + timer_delete(&a6xx_gpu->preempt_timer); + + /* + * The hardware should be setting the stop bit of CP_CONTEXT_SWITCH_CNTL + * to zero before firing the interrupt, but there is a non zero chance + * of a hardware condition or a software race that could set it again + * before we have a chance to finish. If that happens, log and go for + * recovery + */ + status = gpu_read(gpu, REG_A8XX_CP_CONTEXT_SWITCH_CNTL); + if (unlikely(status & A8XX_CP_CONTEXT_SWITCH_CNTL_STOP)) { + DRM_DEV_ERROR(&gpu->pdev->dev, + "!!!!!!!!!!!!!!!! preemption faulted !!!!!!!!!!!!!! irq\n"); + set_preempt_state(a6xx_gpu, PREEMPT_FAULTED); + dev_err(dev->dev, "%s: Preemption failed to complete\n", + gpu->name); + kthread_queue_work(gpu->worker, &gpu->recover_work); + return; + } + + a6xx_gpu->cur_ring = a6xx_gpu->next_ring; + a6xx_gpu->next_ring = NULL; + + set_preempt_state(a6xx_gpu, PREEMPT_FINISH); + + update_wptr(a6xx_gpu, a6xx_gpu->cur_ring); + + set_preempt_state(a6xx_gpu, PREEMPT_NONE); + + a8xx_preempt_keepalive_vote(gpu, false); + + trace_msm_gpu_preemption_irq(a6xx_gpu->cur_ring->id); + + /* + * Retrigger preemption to avoid a deadlock that might occur when preemption + * is skipped due to it being already in flight when requested. + */ + a8xx_preempt_trigger(gpu); +} + +void a8xx_preempt_hw_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + int i; + + /* No preemption if we only have one ring */ + if (gpu->nr_rings == 1) + return; + + for (i = 0; i < gpu->nr_rings; i++) { + struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[i]; + + record_ptr->wptr = 0; + record_ptr->rptr = 0; + record_ptr->rptr_addr = shadowptr(a6xx_gpu, gpu->rb[i]); + record_ptr->info = 0; + record_ptr->data = 0; + record_ptr->rbase = gpu->rb[i]->iova; + } + + /* Write a 0 to signal that we aren't switching pagetables */ + gpu_write64(gpu, REG_A8XX_CP_CONTEXT_SWITCH_SMMU_INFO, 0); + + /* Enable the GMEM save/restore feature for preemption */ + gpu_write(gpu, REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, 0x1); + + /* Reset the preemption state */ + set_preempt_state(a6xx_gpu, PREEMPT_NONE); + + spin_lock_init(&a6xx_gpu->eval_lock); + + /* Always come up on rb 0 */ + a6xx_gpu->cur_ring = gpu->rb[0]; +} + +void a8xx_preempt_trigger(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + unsigned long flags; + struct msm_ringbuffer *ring; + unsigned int cntl; + bool sysprof; + + if (gpu->nr_rings == 1) + return; + + /* + * Lock to make sure another thread attempting preemption doesn't skip it + * while we are still evaluating the next ring. This makes sure the other + * thread does start preemption if we abort it and avoids a soft lock. + */ + spin_lock_irqsave(&a6xx_gpu->eval_lock, flags); + + /* + * Try to start preemption by moving from NONE to START. If + * unsuccessful, a preemption is already in flight + */ + if (!try_preempt_state(a6xx_gpu, PREEMPT_NONE, PREEMPT_START)) { + spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); + return; + } + + cntl = A8XX_CP_CONTEXT_SWITCH_CNTL_LEVEL(a6xx_gpu->preempt_level); + + if (a6xx_gpu->skip_save_restore) + cntl |= A8XX_CP_CONTEXT_SWITCH_CNTL_SKIP_SAVE_RESTORE; + + if (a6xx_gpu->uses_gmem) + cntl |= A8XX_CP_CONTEXT_SWITCH_CNTL_USES_GMEM; + + cntl |= A8XX_CP_CONTEXT_SWITCH_CNTL_STOP; + + /* Get the next ring to preempt to */ + ring = get_next_ring(gpu); + + /* + * If no ring is populated or the highest priority ring is the current + * one do nothing except to update the wptr to the latest and greatest + */ + if (!ring || (a6xx_gpu->cur_ring == ring)) { + set_preempt_state(a6xx_gpu, PREEMPT_FINISH); + update_wptr(a6xx_gpu, a6xx_gpu->cur_ring); + set_preempt_state(a6xx_gpu, PREEMPT_NONE); + spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); + return; + } + + spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); + + spin_lock_irqsave(&ring->preempt_lock, flags); + + struct a7xx_cp_smmu_info *smmu_info_ptr = + a6xx_gpu->preempt_smmu[ring->id]; + struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[ring->id]; + u64 ttbr0 = ring->memptrs->ttbr0; + u32 context_idr = ring->memptrs->context_idr; + + smmu_info_ptr->ttbr0 = ttbr0; + smmu_info_ptr->context_idr = context_idr; + record_ptr->wptr = get_wptr(ring); + + /* + * The GPU will write the wptr we set above when we preempt. Reset + * restore_wptr to make sure that we don't write WPTR to the same + * thing twice. It's still possible subsequent submissions will update + * wptr again, in which case they will set the flag to true. This has + * to be protected by the lock for setting the flag and updating wptr + * to be atomic. + */ + ring->restore_wptr = false; + + trace_msm_gpu_preemption_trigger(a6xx_gpu->cur_ring->id, ring->id); + + spin_unlock_irqrestore(&ring->preempt_lock, flags); + + /* Set the keepalive bit to keep the GPU ON until preemption is complete */ + a8xx_preempt_keepalive_vote(gpu, true); + + a6xx_fenced_write(a6xx_gpu, + REG_A8XX_CP_CONTEXT_SWITCH_SMMU_INFO, a6xx_gpu->preempt_smmu_iova[ring->id], + BIT(1), true); + + a6xx_fenced_write(a6xx_gpu, + REG_A8XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR, + a6xx_gpu->preempt_iova[ring->id], BIT(1), true); + + a6xx_gpu->next_ring = ring; + + /* Start a timer to catch a stuck preemption */ + mod_timer(&a6xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000)); + + /* Enable or disable postamble as needed */ + sysprof = refcount_read(&a6xx_gpu->base.base.sysprof_active) > 1; + + if (!sysprof && !a6xx_gpu->postamble_enabled) + preempt_prepare_postamble(a6xx_gpu); + + if (sysprof && a6xx_gpu->postamble_enabled) + preempt_disable_postamble(a6xx_gpu); + + /* Set the preemption state to triggered */ + set_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED); + + /* Trigger the preemption */ + a6xx_fenced_write(a6xx_gpu, REG_A8XX_CP_CONTEXT_SWITCH_CNTL, cntl, BIT(1), false); +} + diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 554d746f115b..4edfe80c5be7 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -302,6 +302,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "qcom,kgsl-3d0" }, {} }; +MODULE_DEVICE_TABLE(of, dt_match); static int adreno_runtime_resume(struct device *dev) { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index d5fe6f6f0dec..66f80f2d12f9 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -45,8 +45,8 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, return -EINVAL; } - np = of_get_child_by_name(dev->of_node, "zap-shader"); - if (!of_device_is_available(np)) { + np = of_get_available_child_by_name(dev->of_node, "zap-shader"); + if (!np) { zap_available = false; return -ENODEV; } @@ -391,13 +391,11 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx, return 0; case MSM_PARAM_TIMESTAMP: if (adreno_gpu->funcs->get_timestamp) { - int ret; - pm_runtime_get_sync(&gpu->pdev->dev); - ret = adreno_gpu->funcs->get_timestamp(gpu, value); + *value = adreno_gpu->funcs->get_timestamp(gpu); pm_runtime_put_autosuspend(&gpu->pdev->dev); - return ret; + return 0; } return -EINVAL; case MSM_PARAM_PRIORITIES: @@ -443,6 +441,10 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx, case MSM_PARAM_HAS_PRR: *value = adreno_smmu_has_prr(gpu); return 0; + case MSM_PARAM_AQE: + *value = !!(adreno_gpu->funcs->aqe_is_enabled && + adreno_gpu->funcs->aqe_is_enabled(adreno_gpu)); + return 0; default: return UERR(EINVAL, drm, "%s: invalid param: %u", gpu->name, param); } @@ -1184,7 +1186,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct msm_gpu_config adreno_gpu_config = { 0 }; struct msm_gpu *gpu = &adreno_gpu->base; const char *gpu_name; - u32 speedbin; int ret; adreno_gpu->funcs = funcs; @@ -1213,10 +1214,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, devm_pm_opp_set_clkname(dev, "core"); } - if (adreno_read_speedbin(dev, &speedbin) || !speedbin) - speedbin = 0xffff; - adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin); - gpu_name = devm_kasprintf(dev, GFP_KERNEL, "%"ADRENO_CHIPID_FMT, ADRENO_CHIPID_ARGS(config->chip_id)); if (!gpu_name) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 1d0145f8b3ec..ec643b84646b 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -63,25 +63,24 @@ enum adreno_family { #define ADRENO_QUIRK_PREEMPTION BIT(5) #define ADRENO_QUIRK_4GB_VA BIT(6) #define ADRENO_QUIRK_IFPC BIT(7) +#define ADRENO_QUIRK_SOFTFUSE BIT(8) /* Helper for formating the chip_id in the way that userspace tools like * crashdec expect. */ -#define ADRENO_CHIPID_FMT "u.%u.%u.%u" -#define ADRENO_CHIPID_ARGS(_c) \ - (((_c) >> 24) & 0xff), \ - (((_c) >> 16) & 0xff), \ - (((_c) >> 8) & 0xff), \ - ((_c) & 0xff) +#define ADRENO_CHIPID_FMT "08x" +#define ADRENO_CHIPID_ARGS(_c) (_c) struct adreno_gpu; struct adreno_gpu_funcs { struct msm_gpu_funcs base; struct msm_gpu *(*init)(struct drm_device *dev); - int (*get_timestamp)(struct msm_gpu *gpu, uint64_t *value); + u64 (*get_timestamp)(struct msm_gpu *gpu); void (*bus_halt)(struct adreno_gpu *adreno_gpu, bool gx_off); int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data); + bool (*gx_is_on)(struct adreno_gpu *adreno_gpu); + bool (*aqe_is_enabled)(struct adreno_gpu *adreno_gpu); }; struct adreno_reglist { diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h index 56d3c38c8778..2eef5f69832f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h @@ -322,7 +322,6 @@ static const struct dpu_wb_cfg sm8650_wb[] = { .format_list = wb2_formats_rgb_yuv, .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -378,7 +377,7 @@ static const struct dpu_intf_cfg sm8650_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -445,8 +444,7 @@ const struct dpu_mdss_cfg dpu_sm8650_cfg = { .cwb = sm8650_cwb, .intf_count = ARRAY_SIZE(sm8650_intf), .intf = sm8650_intf, - .vbif_count = ARRAY_SIZE(sm8650_vbif), - .vbif = sm8650_vbif, + .vbif = &sm8650_vbif, .perf = &sm8650_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_0_sm8750.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_0_sm8750.h index db8cc2d0112c..3889eb8a5428 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_0_sm8750.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_0_sm8750.h @@ -364,7 +364,6 @@ static const struct dpu_wb_cfg sm8750_wb[] = { .format_list = wb2_formats_rgb_yuv, .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -420,7 +419,7 @@ static const struct dpu_intf_cfg sm8750_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x4bc, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -486,8 +485,7 @@ const struct dpu_mdss_cfg dpu_sm8750_cfg = { .cwb = sm8650_cwb, .intf_count = ARRAY_SIZE(sm8750_intf), .intf = sm8750_intf, - .vbif_count = ARRAY_SIZE(sm8650_vbif), - .vbif = sm8650_vbif, + .vbif = &sm8650_vbif, .perf = &sm8750_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_2_glymur.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_2_glymur.h index 13bb43ba67d3..4eb4a0e9803e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_2_glymur.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_2_glymur.h @@ -371,7 +371,6 @@ static const struct dpu_wb_cfg glymur_wb[] = { .format_list = wb2_formats_rgb_yuv, .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -426,7 +425,7 @@ static const struct dpu_intf_cfg glymur_intf[] = { }, { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x400, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), @@ -458,7 +457,7 @@ static const struct dpu_intf_cfg glymur_intf[] = { }, { .name = "intf_7", .id = INTF_7, .base = 0x3b000, .len = 0x400, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_2, /* pair with intf_6 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 18), @@ -466,7 +465,7 @@ static const struct dpu_intf_cfg glymur_intf[] = { }, { .name = "intf_8", .id = INTF_8, .base = 0x3c000, .len = 0x400, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_1, /* pair with intf_4 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), @@ -533,8 +532,7 @@ const struct dpu_mdss_cfg dpu_glymur_cfg = { .cwb = sm8650_cwb, .intf_count = ARRAY_SIZE(glymur_intf), .intf = glymur_intf, - .vbif_count = ARRAY_SIZE(sm8650_vbif), - .vbif = sm8650_vbif, + .vbif = &sm8650_vbif, .perf = &glymur_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h new file mode 100644 index 000000000000..b93d32888972 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h @@ -0,0 +1,363 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _DPU_12_4_ELIZA_H +#define _DPU_12_4_ELIZA_H + +static const struct dpu_caps eliza_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 8192, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + +static const struct dpu_mdp_cfg eliza_mdp = { + .name = "top_0", + .base = 0, .len = 0x494, + .clk_ctrls = { + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, + }, +}; + +static const struct dpu_ctl_cfg eliza_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, +}; + +static const struct dpu_sspp_cfg eliza_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0x28000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_11", .id = SSPP_DMA3, + .base = 0x2a000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 13, + .type = SSPP_TYPE_DMA, + }, +}; + +static const struct dpu_lm_cfg eliza_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + .dspp = DSPP_1, + }, { + .name = "lm_2", .id = LM_2, + .base = 0x46000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_3, + .pingpong = PINGPONG_2, + .dspp = DSPP_2, + }, { + .name = "lm_3", .id = LM_3, + .base = 0x47000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_2, + .pingpong = PINGPONG_3, + }, +}; + +static const struct dpu_dspp_cfg eliza_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_1", .id = DSPP_1, + .base = 0x56000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_2", .id = DSPP_2, + .base = 0x58000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, +}; + +static const struct dpu_pingpong_cfg eliza_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x69000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x6a000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + }, { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x6b000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, { + .name = "pingpong_cwb_0", .id = PINGPONG_CWB_0, + .base = 0x66000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + }, { + .name = "pingpong_cwb_1", .id = PINGPONG_CWB_1, + .base = 0x66400, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + }, { + .name = "pingpong_cwb_2", .id = PINGPONG_CWB_2, + .base = 0x7e000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + }, { + .name = "pingpong_cwb_3", .id = PINGPONG_CWB_3, + .base = 0x7e400, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + }, +}; + +static const struct dpu_merge_3d_cfg eliza_merge_3d[] = { + { + .name = "merge_3d_0", .id = MERGE_3D_0, + .base = 0x4e000, .len = 0x1c, + }, { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x4f000, .len = 0x1c, + }, { + .name = "merge_3d_2", .id = MERGE_3D_2, + .base = 0x66700, .len = 0x1c, + }, { + .name = "merge_3d_3", .id = MERGE_3D_3, + .base = 0x7e700, .len = 0x1c, + }, +}; + +/* + * NOTE: Each display compression engine (DCE) contains dual hard + * slice DSC encoders so both share same base address but with + * its own different sub block address. + */ +static const struct dpu_dsc_cfg eliza_dsc[] = { + { + .name = "dce_0_0", .id = DSC_0, + .base = 0x80000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_0_1", .id = DSC_1, + .base = 0x80000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_1_0", .id = DSC_2, + .base = 0x81000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, +}; + +static const struct dpu_wb_cfg eliza_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SDM845_MASK, + .format_list = wb2_formats_rgb_yuv, + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), + .xin_id = 6, + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + +static const struct dpu_cwb_cfg eliza_cwb[] = { + { + .name = "cwb_0", .id = CWB_0, + .base = 0x66200, .len = 0x20, + }, + { + .name = "cwb_1", .id = CWB_1, + .base = 0x66600, .len = 0x20, + }, + { + .name = "cwb_2", .id = CWB_2, + .base = 0x7e200, .len = 0x20, + }, + { + .name = "cwb_3", .id = CWB_3, + .base = 0x7e600, .len = 0x20, + }, +}; + +static const struct dpu_intf_cfg eliza_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x34000, .len = 0x4bc, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), + }, { + .name = "intf_1", .id = INTF_1, + .base = 0x35000, .len = 0x4bc, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF1_TEAR_INTR, 2), + }, { + .name = "intf_2", .id = INTF_2, + .base = 0x36000, .len = 0x4bc, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 28), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 29), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF2_TEAR_INTR, 2), + }, { + .name = "intf_3", .id = INTF_3, + .base = 0x37000, .len = 0x4bc, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), + } +}; + +static const struct dpu_perf_cfg eliza_perf_data = { + .max_bw_low = 6800000, + .max_bw_high = 14200000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 1600000, + .min_prefill_lines = 35, + .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0}, + .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear + }, + {.nentry = ARRAY_SIZE(sc7180_qos_macrotile), + .entries = sc7180_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version eliza_mdss_ver = { + .core_major_ver = 12, + .core_minor_ver = 4, +}; + +const struct dpu_mdss_cfg dpu_eliza_cfg = { + .mdss_ver = &eliza_mdss_ver, + .caps = &eliza_dpu_caps, + .mdp = &eliza_mdp, + .cdm = &dpu_cdm_5_x, + .ctl_count = ARRAY_SIZE(eliza_ctl), + .ctl = eliza_ctl, + .sspp_count = ARRAY_SIZE(eliza_sspp), + .sspp = eliza_sspp, + .mixer_count = ARRAY_SIZE(eliza_lm), + .mixer = eliza_lm, + .dspp_count = ARRAY_SIZE(eliza_dspp), + .dspp = eliza_dspp, + .pingpong_count = ARRAY_SIZE(eliza_pp), + .pingpong = eliza_pp, + .dsc_count = ARRAY_SIZE(eliza_dsc), + .dsc = eliza_dsc, + .merge_3d_count = ARRAY_SIZE(eliza_merge_3d), + .merge_3d = eliza_merge_3d, + .wb_count = ARRAY_SIZE(eliza_wb), + .wb = eliza_wb, + .cwb_count = ARRAY_SIZE(eliza_cwb), + .cwb = eliza_cwb, + .intf_count = ARRAY_SIZE(eliza_intf), + .intf = eliza_intf, + .vbif = &sm8650_vbif, + .perf = &eliza_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h index 0b20401b04cf..b7b06e45b529 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h @@ -362,7 +362,6 @@ static const struct dpu_wb_cfg kaanapali_wb[] = { .format_list = wb2_formats_rgb_yuv, .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -418,7 +417,7 @@ static const struct dpu_intf_cfg kaanapali_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x190000, .len = 0x4bc, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -484,8 +483,7 @@ const struct dpu_mdss_cfg dpu_kaanapali_cfg = { .cwb = sm8650_cwb, .intf_count = ARRAY_SIZE(kaanapali_intf), .intf = kaanapali_intf, - .vbif_count = ARRAY_SIZE(sm8650_vbif), - .vbif = sm8650_vbif, + .vbif = &sm8650_vbif, .perf = &kaanapali_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_14_msm8937.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_14_msm8937.h index 29e0eba91930..4ff7b397f808 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_14_msm8937.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_14_msm8937.h @@ -197,8 +197,7 @@ const struct dpu_mdss_cfg dpu_msm8937_cfg = { .pingpong = msm8937_pp, .intf_count = ARRAY_SIZE(msm8937_intf), .intf = msm8937_intf, - .vbif_count = ARRAY_SIZE(msm8996_vbif), - .vbif = msm8996_vbif, + .vbif = &msm8996_vbif, .perf = &msm8937_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_15_msm8917.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_15_msm8917.h index cb1ee4b63f9f..1518c3d39ce8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_15_msm8917.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_15_msm8917.h @@ -176,8 +176,7 @@ const struct dpu_mdss_cfg dpu_msm8917_cfg = { .pingpong = msm8917_pp, .intf_count = ARRAY_SIZE(msm8917_intf), .intf = msm8917_intf, - .vbif_count = ARRAY_SIZE(msm8996_vbif), - .vbif = msm8996_vbif, + .vbif = &msm8996_vbif, .perf = &msm8917_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h index b44d02b48418..859a97e8c07e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h @@ -121,13 +121,6 @@ static const struct dpu_dspp_cfg msm8953_dspp[] = { static const struct dpu_intf_cfg msm8953_intf[] = { { - .name = "intf_0", .id = INTF_0, - .base = 0x6a000, .len = 0x268, - .type = INTF_NONE, - .prog_fetch_lines_worst_case = 14, - .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), - .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), - }, { .name = "intf_1", .id = INTF_1, .base = 0x6a800, .len = 0x268, .type = INTF_DSI, @@ -204,8 +197,7 @@ const struct dpu_mdss_cfg dpu_msm8953_cfg = { .pingpong = msm8953_pp, .intf_count = ARRAY_SIZE(msm8953_intf), .intf = msm8953_intf, - .vbif_count = ARRAY_SIZE(msm8996_vbif), - .vbif = msm8996_vbif, + .vbif = &msm8996_vbif, .perf = &msm8953_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_7_msm8996.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_7_msm8996.h index 8af63db315b4..67910a2f6880 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_7_msm8996.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_7_msm8996.h @@ -320,8 +320,7 @@ const struct dpu_mdss_cfg dpu_msm8996_cfg = { .dsc = msm8996_dsc, .intf_count = ARRAY_SIZE(msm8996_intf), .intf = msm8996_intf, - .vbif_count = ARRAY_SIZE(msm8996_vbif), - .vbif = msm8996_vbif, + .vbif = &msm8996_vbif, .perf = &msm8996_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h index b1b03d8b30fa..67c1463d3bd6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h @@ -305,8 +305,7 @@ const struct dpu_mdss_cfg dpu_msm8998_cfg = { .dsc = msm8998_dsc, .intf_count = ARRAY_SIZE(msm8998_intf), .intf = msm8998_intf, - .vbif_count = ARRAY_SIZE(msm8998_vbif), - .vbif = msm8998_vbif, + .vbif = &msm8998_vbif, .perf = &msm8998_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h index 64df4e80ea43..84344029819f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h @@ -269,8 +269,7 @@ const struct dpu_mdss_cfg dpu_sdm660_cfg = { .dsc = sdm660_dsc, .intf_count = ARRAY_SIZE(sdm660_intf), .intf = sdm660_intf, - .vbif_count = ARRAY_SIZE(msm8998_vbif), - .vbif = msm8998_vbif, + .vbif = &msm8998_vbif, .perf = &sdm660_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h index b409af899918..ef5777aee587 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h @@ -207,8 +207,7 @@ const struct dpu_mdss_cfg dpu_sdm630_cfg = { .pingpong = sdm630_pp, .intf_count = ARRAY_SIZE(sdm630_intf), .intf = sdm630_intf, - .vbif_count = ARRAY_SIZE(msm8998_vbif), - .vbif = msm8998_vbif, + .vbif = &msm8998_vbif, .perf = &sdm630_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h index 5cc9f55d542b..b608d2bb6d48 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h @@ -258,7 +258,7 @@ static const struct dpu_intf_cfg sdm845_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -325,8 +325,7 @@ const struct dpu_mdss_cfg dpu_sdm845_cfg = { .dsc = sdm845_dsc, .intf_count = ARRAY_SIZE(sdm845_intf), .intf = sdm845_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sdm845_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h index 0f5e9babdeea..54b4a83ee16e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h @@ -144,8 +144,7 @@ const struct dpu_mdss_cfg dpu_sdm670_cfg = { .dsc = sdm670_dsc, .intf_count = ARRAY_SIZE(sdm845_intf), .intf = sdm845_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sdm845_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h index ae1b2ed96e9f..9729a65d3e3a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h @@ -280,7 +280,6 @@ static const struct dpu_wb_cfg sm8150_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -317,7 +316,7 @@ static const struct dpu_intf_cfg sm8150_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -381,8 +380,7 @@ const struct dpu_mdss_cfg dpu_sm8150_cfg = { .wb = sm8150_wb, .intf_count = ARRAY_SIZE(sm8150_intf), .intf = sm8150_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm8150_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h index b572cfa7ed35..fb18de029e80 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h @@ -286,7 +286,6 @@ static const struct dpu_wb_cfg sc8180x_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -405,8 +404,7 @@ const struct dpu_mdss_cfg dpu_sc8180x_cfg = { .wb = sc8180x_wb, .intf_count = ARRAY_SIZE(sc8180x_intf), .intf = sc8180x_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sc8180x_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_2_sm7150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_2_sm7150.h index a56c288ac10c..92a614686cb6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_2_sm7150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_2_sm7150.h @@ -230,7 +230,7 @@ static const struct dpu_intf_cfg sm7150_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -246,7 +246,6 @@ static const struct dpu_wb_cfg sm7150_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -309,8 +308,7 @@ const struct dpu_mdss_cfg dpu_sm7150_cfg = { .intf = sm7150_intf, .wb_count = ARRAY_SIZE(sm7150_wb), .wb = sm7150_wb, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm7150_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h index 26883f6b66b3..87488d3ed95f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h @@ -158,7 +158,6 @@ static const struct dpu_wb_cfg sm6150_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 2160, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -186,7 +185,7 @@ static const struct dpu_intf_cfg sm6150_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -246,8 +245,7 @@ const struct dpu_mdss_cfg dpu_sm6150_cfg = { .wb = sm6150_wb, .intf_count = ARRAY_SIZE(sm6150_intf), .intf = sm6150_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm6150_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h index fbf50f279e66..64be51e30159 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h @@ -137,7 +137,6 @@ static const struct dpu_wb_cfg sm6125_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 2160, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -217,8 +216,7 @@ const struct dpu_mdss_cfg dpu_sm6125_cfg = { .wb = sm6125_wb, .intf_count = ARRAY_SIZE(sm6125_intf), .intf = sm6125_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm6125_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h index 7b8b7a1c2d76..0e311d54ef18 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h @@ -301,7 +301,7 @@ static const struct dpu_intf_cfg sm8250_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -317,7 +317,6 @@ static const struct dpu_wb_cfg sm8250_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -378,8 +377,7 @@ const struct dpu_mdss_cfg dpu_sm8250_cfg = { .merge_3d = sm8250_merge_3d, .intf_count = ARRAY_SIZE(sm8250_intf), .intf = sm8250_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .wb_count = ARRAY_SIZE(sm8250_wb), .wb = sm8250_wb, .perf = &sm8250_perf_data, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h index c990ba3b5db0..d6f7ee24ca93 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h @@ -153,7 +153,6 @@ static const struct dpu_wb_cfg sc7180_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -211,8 +210,7 @@ const struct dpu_mdss_cfg dpu_sc7180_cfg = { .intf = sc7180_intf, .wb_count = ARRAY_SIZE(sc7180_wb), .wb = sc7180_wb, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sc7180_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h index 343ff5482382..20a2e9ff5cc9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h @@ -144,8 +144,7 @@ const struct dpu_mdss_cfg dpu_sm6115_cfg = { .pingpong = sm6115_pp, .intf_count = ARRAY_SIZE(sm6115_intf), .intf = sm6115_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm6115_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h index 093d16bdc450..dd891703e35f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h @@ -147,7 +147,6 @@ static const struct dpu_wb_cfg sm6350_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 1920, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -229,8 +228,7 @@ const struct dpu_mdss_cfg dpu_sm6350_cfg = { .wb = sm6350_wb, .intf_count = ARRAY_SIZE(sm6350_intf), .intf = sm6350_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm6350_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h index 47053bf9b0a2..7ae7530aa3b0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h @@ -137,8 +137,7 @@ const struct dpu_mdss_cfg dpu_qcm2290_cfg = { .pingpong = qcm2290_pp, .intf_count = ARRAY_SIZE(qcm2290_intf), .intf = qcm2290_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &qcm2290_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h index 98190ee7ec7a..fc7ceac859be 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h @@ -155,8 +155,7 @@ const struct dpu_mdss_cfg dpu_sm6375_cfg = { .pingpong = sm6375_pp, .intf_count = ARRAY_SIZE(sm6375_intf), .intf = sm6375_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm6375_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h index 85aae40c210f..d06c14f05faf 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h @@ -290,7 +290,6 @@ static const struct dpu_wb_cfg sm8350_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -327,7 +326,7 @@ static const struct dpu_intf_cfg sm8350_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -392,8 +391,7 @@ const struct dpu_mdss_cfg dpu_sm8350_cfg = { .wb = sm8350_wb, .intf_count = ARRAY_SIZE(sm8350_intf), .intf = sm8350_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm8350_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h index 2f8688224f34..99b8a890fddc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h @@ -172,7 +172,6 @@ static const struct dpu_wb_cfg sc7280_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -263,8 +262,7 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = { .wb = sc7280_wb, .intf_count = ARRAY_SIZE(sc7280_intf), .intf = sc7280_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sc7280_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h index 303d33dc7783..0ba907711d36 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h @@ -133,7 +133,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { static const struct dpu_lm_cfg sc8280xp_lm[] = { { .name = "lm_0", .id = LM_0, - .base = 0x44000, .len = 0x320, + .base = 0x44000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_1, @@ -141,7 +141,7 @@ static const struct dpu_lm_cfg sc8280xp_lm[] = { .dspp = DSPP_0, }, { .name = "lm_1", .id = LM_1, - .base = 0x45000, .len = 0x320, + .base = 0x45000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_0, @@ -149,7 +149,7 @@ static const struct dpu_lm_cfg sc8280xp_lm[] = { .dspp = DSPP_1, }, { .name = "lm_2", .id = LM_2, - .base = 0x46000, .len = 0x320, + .base = 0x46000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_3, @@ -157,7 +157,7 @@ static const struct dpu_lm_cfg sc8280xp_lm[] = { .dspp = DSPP_2, }, { .name = "lm_3", .id = LM_3, - .base = 0x47000, .len = 0x320, + .base = 0x47000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_2, @@ -165,14 +165,14 @@ static const struct dpu_lm_cfg sc8280xp_lm[] = { .dspp = DSPP_3, }, { .name = "lm_4", .id = LM_4, - .base = 0x48000, .len = 0x320, + .base = 0x48000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_5, .pingpong = PINGPONG_4, }, { .name = "lm_5", .id = LM_5, - .base = 0x49000, .len = 0x320, + .base = 0x49000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_4, @@ -288,7 +288,6 @@ static const struct dpu_dsc_cfg sc8280xp_dsc[] = { }, }; -/* TODO: INTF 3, 8 and 7 are used for MST, marked as INTF_NONE for now */ static const struct dpu_intf_cfg sc8280xp_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -319,8 +318,8 @@ static const struct dpu_intf_cfg sc8280xp_intf[] = { }, { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, - .type = INTF_NONE, - .controller_id = MSM_DP_CONTROLLER_0, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -351,16 +350,16 @@ static const struct dpu_intf_cfg sc8280xp_intf[] = { }, { .name = "intf_7", .id = INTF_7, .base = 0x3b000, .len = 0x280, - .type = INTF_NONE, - .controller_id = MSM_DP_CONTROLLER_2, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_2, /* pair with intf_6 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 18), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 19), }, { .name = "intf_8", .id = INTF_8, .base = 0x3c000, .len = 0x280, - .type = INTF_NONE, - .controller_id = MSM_DP_CONTROLLER_1, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, /* pair with intf_8 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13), @@ -421,8 +420,7 @@ const struct dpu_mdss_cfg dpu_sc8280xp_cfg = { .merge_3d = sc8280xp_merge_3d, .intf_count = ARRAY_SIZE(sc8280xp_intf), .intf = sc8280xp_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sc8280xp_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index b09a6af4c474..170a709f987c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -134,7 +134,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { static const struct dpu_lm_cfg sm8450_lm[] = { { .name = "lm_0", .id = LM_0, - .base = 0x44000, .len = 0x320, + .base = 0x44000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_1, @@ -142,7 +142,7 @@ static const struct dpu_lm_cfg sm8450_lm[] = { .dspp = DSPP_0, }, { .name = "lm_1", .id = LM_1, - .base = 0x45000, .len = 0x320, + .base = 0x45000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_0, @@ -150,7 +150,7 @@ static const struct dpu_lm_cfg sm8450_lm[] = { .dspp = DSPP_1, }, { .name = "lm_2", .id = LM_2, - .base = 0x46000, .len = 0x320, + .base = 0x46000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_3, @@ -158,7 +158,7 @@ static const struct dpu_lm_cfg sm8450_lm[] = { .dspp = DSPP_2, }, { .name = "lm_3", .id = LM_3, - .base = 0x47000, .len = 0x320, + .base = 0x47000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_2, @@ -166,14 +166,14 @@ static const struct dpu_lm_cfg sm8450_lm[] = { .dspp = DSPP_3, }, { .name = "lm_4", .id = LM_4, - .base = 0x48000, .len = 0x320, + .base = 0x48000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_5, .pingpong = PINGPONG_4, }, { .name = "lm_5", .id = LM_5, - .base = 0x49000, .len = 0x320, + .base = 0x49000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_4, @@ -303,7 +303,6 @@ static const struct dpu_wb_cfg sm8450_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -340,7 +339,7 @@ static const struct dpu_intf_cfg sm8450_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -405,8 +404,7 @@ const struct dpu_mdss_cfg dpu_sm8450_cfg = { .wb = sm8450_wb, .intf_count = ARRAY_SIZE(sm8450_intf), .intf = sm8450_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sm8450_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h index 0f7b4a224e4c..9cc5e22e1228 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h @@ -310,13 +310,11 @@ static const struct dpu_wb_cfg sa8775p_wb[] = { .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, }; -/* TODO: INTF 3, 6, 7 and 8 are used for MST, marked as INTF_NONE for now */ static const struct dpu_intf_cfg sa8775p_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -347,7 +345,7 @@ static const struct dpu_intf_cfg sa8775p_intf[] = { }, { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), @@ -363,15 +361,15 @@ static const struct dpu_intf_cfg sa8775p_intf[] = { }, { .name = "intf_6", .id = INTF_6, .base = 0x3A000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, - .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 17), - .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 16), + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 16), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 17), }, { .name = "intf_7", .id = INTF_7, .base = 0x3b000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 18), @@ -379,7 +377,7 @@ static const struct dpu_intf_cfg sa8775p_intf[] = { }, { .name = "intf_8", .id = INTF_8, .base = 0x3c000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_1, /* pair with intf_4 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), @@ -445,8 +443,7 @@ const struct dpu_mdss_cfg dpu_sa8775p_cfg = { .wb = sa8775p_wb, .intf_count = ARRAY_SIZE(sa8775p_intf), .intf = sa8775p_intf, - .vbif_count = ARRAY_SIZE(sdm845_vbif), - .vbif = sdm845_vbif, + .vbif = &sdm845_vbif, .perf = &sa8775p_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h index 465b6460f875..b3d0f221807b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h @@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sm8550_sspp[] = { static const struct dpu_lm_cfg sm8550_lm[] = { { .name = "lm_0", .id = LM_0, - .base = 0x44000, .len = 0x320, + .base = 0x44000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_1, @@ -139,7 +139,7 @@ static const struct dpu_lm_cfg sm8550_lm[] = { .dspp = DSPP_0, }, { .name = "lm_1", .id = LM_1, - .base = 0x45000, .len = 0x320, + .base = 0x45000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_0, @@ -147,7 +147,7 @@ static const struct dpu_lm_cfg sm8550_lm[] = { .dspp = DSPP_1, }, { .name = "lm_2", .id = LM_2, - .base = 0x46000, .len = 0x320, + .base = 0x46000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_3, @@ -155,7 +155,7 @@ static const struct dpu_lm_cfg sm8550_lm[] = { .dspp = DSPP_2, }, { .name = "lm_3", .id = LM_3, - .base = 0x47000, .len = 0x320, + .base = 0x47000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_2, @@ -163,14 +163,14 @@ static const struct dpu_lm_cfg sm8550_lm[] = { .dspp = DSPP_3, }, { .name = "lm_4", .id = LM_4, - .base = 0x48000, .len = 0x320, + .base = 0x48000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_5, .pingpong = PINGPONG_4, }, { .name = "lm_5", .id = LM_5, - .base = 0x49000, .len = 0x320, + .base = 0x49000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_4, @@ -298,7 +298,6 @@ static const struct dpu_wb_cfg sm8550_wb[] = { .format_list = wb2_formats_rgb_yuv, .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -335,7 +334,7 @@ static const struct dpu_intf_cfg sm8550_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -400,8 +399,7 @@ const struct dpu_mdss_cfg dpu_sm8550_cfg = { .wb = sm8550_wb, .intf_count = ARRAY_SIZE(sm8550_intf), .intf = sm8550_intf, - .vbif_count = ARRAY_SIZE(sm8550_vbif), - .vbif = sm8550_vbif, + .vbif = &sm8550_vbif, .perf = &sm8550_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h index 6caa7d40f368..7effe7120a56 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h @@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sar2130p_sspp[] = { static const struct dpu_lm_cfg sar2130p_lm[] = { { .name = "lm_0", .id = LM_0, - .base = 0x44000, .len = 0x320, + .base = 0x44000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_1, @@ -139,7 +139,7 @@ static const struct dpu_lm_cfg sar2130p_lm[] = { .dspp = DSPP_0, }, { .name = "lm_1", .id = LM_1, - .base = 0x45000, .len = 0x320, + .base = 0x45000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_0, @@ -147,7 +147,7 @@ static const struct dpu_lm_cfg sar2130p_lm[] = { .dspp = DSPP_1, }, { .name = "lm_2", .id = LM_2, - .base = 0x46000, .len = 0x320, + .base = 0x46000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_3, @@ -155,7 +155,7 @@ static const struct dpu_lm_cfg sar2130p_lm[] = { .dspp = DSPP_2, }, { .name = "lm_3", .id = LM_3, - .base = 0x47000, .len = 0x320, + .base = 0x47000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_2, @@ -163,14 +163,14 @@ static const struct dpu_lm_cfg sar2130p_lm[] = { .dspp = DSPP_3, }, { .name = "lm_4", .id = LM_4, - .base = 0x48000, .len = 0x320, + .base = 0x48000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_5, .pingpong = PINGPONG_4, }, { .name = "lm_5", .id = LM_5, - .base = 0x49000, .len = 0x320, + .base = 0x49000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_4, @@ -298,7 +298,6 @@ static const struct dpu_wb_cfg sar2130p_wb[] = { .format_list = wb2_formats_rgb_yuv, .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, @@ -335,7 +334,7 @@ static const struct dpu_intf_cfg sar2130p_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), @@ -400,8 +399,7 @@ const struct dpu_mdss_cfg dpu_sar2130p_cfg = { .wb = sar2130p_wb, .intf_count = ARRAY_SIZE(sar2130p_intf), .intf = sar2130p_intf, - .vbif_count = ARRAY_SIZE(sm8550_vbif), - .vbif = sm8550_vbif, + .vbif = &sm8550_vbif, .perf = &sar2130p_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h index 7243eebb85f3..7b3febf8742d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h @@ -130,7 +130,7 @@ static const struct dpu_sspp_cfg x1e80100_sspp[] = { static const struct dpu_lm_cfg x1e80100_lm[] = { { .name = "lm_0", .id = LM_0, - .base = 0x44000, .len = 0x320, + .base = 0x44000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_1, @@ -138,7 +138,7 @@ static const struct dpu_lm_cfg x1e80100_lm[] = { .dspp = DSPP_0, }, { .name = "lm_1", .id = LM_1, - .base = 0x45000, .len = 0x320, + .base = 0x45000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_0, @@ -146,7 +146,7 @@ static const struct dpu_lm_cfg x1e80100_lm[] = { .dspp = DSPP_1, }, { .name = "lm_2", .id = LM_2, - .base = 0x46000, .len = 0x320, + .base = 0x46000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_3, @@ -154,7 +154,7 @@ static const struct dpu_lm_cfg x1e80100_lm[] = { .dspp = DSPP_2, }, { .name = "lm_3", .id = LM_3, - .base = 0x47000, .len = 0x320, + .base = 0x47000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_2, @@ -162,14 +162,14 @@ static const struct dpu_lm_cfg x1e80100_lm[] = { .dspp = DSPP_3, }, { .name = "lm_4", .id = LM_4, - .base = 0x48000, .len = 0x320, + .base = 0x48000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_5, .pingpong = PINGPONG_4, }, { .name = "lm_5", .id = LM_5, - .base = 0x49000, .len = 0x320, + .base = 0x49000, .len = 0x400, .features = MIXER_MSM8998_MASK, .sblk = &sdm845_lm_sblk, .lm_pair = LM_4, @@ -298,13 +298,11 @@ static const struct dpu_wb_cfg x1e80100_wb[] = { .format_list = wb2_formats_rgb_yuv, .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .xin_id = 6, - .vbif_idx = VBIF_RT, .maxlinewidth = 4096, .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), }, }; -/* TODO: INTF 3, 8 and 7 are used for MST, marked as INTF_NONE for now */ static const struct dpu_intf_cfg x1e80100_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -335,7 +333,7 @@ static const struct dpu_intf_cfg x1e80100_intf[] = { }, { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), @@ -367,7 +365,7 @@ static const struct dpu_intf_cfg x1e80100_intf[] = { }, { .name = "intf_7", .id = INTF_7, .base = 0x3b000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_2, /* pair with intf_6 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 18), @@ -375,7 +373,7 @@ static const struct dpu_intf_cfg x1e80100_intf[] = { }, { .name = "intf_8", .id = INTF_8, .base = 0x3c000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .controller_id = MSM_DP_CONTROLLER_1, /* pair with intf_4 for DP MST */ .prog_fetch_lines_worst_case = 24, .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), @@ -441,8 +439,7 @@ const struct dpu_mdss_cfg dpu_x1e80100_cfg = { .wb = x1e80100_wb, .intf_count = ARRAY_SIZE(x1e80100_intf), .intf = x1e80100_intf, - .vbif_count = ARRAY_SIZE(sm8550_vbif), - .vbif = sm8550_vbif, + .vbif = &sm8550_vbif, .perf = &x1e80100_perf_data, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 0f4921b1a892..411a6fa832b5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -326,43 +326,39 @@ static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer, { struct dpu_hw_mixer *lm = mixer->hw_lm; u32 blend_op; - u32 fg_alpha, bg_alpha, max_alpha; + u32 fg_alpha, bg_alpha; - if (mdss_ver->core_major_ver < 12) { - max_alpha = 0xff; - fg_alpha = pstate->base.alpha >> 8; - } else { - max_alpha = 0x3ff; - fg_alpha = pstate->base.alpha >> 6; - } - bg_alpha = max_alpha - fg_alpha; + fg_alpha = pstate->base.alpha; /* default to opaque blending */ if (pstate->base.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE || !format->alpha_enable) { blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | DPU_BLEND_BG_ALPHA_BG_CONST; + bg_alpha = DRM_BLEND_ALPHA_OPAQUE - fg_alpha; } else if (pstate->base.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) { blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | DPU_BLEND_BG_ALPHA_FG_PIXEL; - if (fg_alpha != max_alpha) { + if (fg_alpha != DRM_BLEND_ALPHA_OPAQUE) { bg_alpha = fg_alpha; blend_op |= DPU_BLEND_BG_MOD_ALPHA | DPU_BLEND_BG_INV_MOD_ALPHA; } else { + bg_alpha = 0; blend_op |= DPU_BLEND_BG_INV_ALPHA; } } else { /* coverage blending */ blend_op = DPU_BLEND_FG_ALPHA_FG_PIXEL | DPU_BLEND_BG_ALPHA_FG_PIXEL; - if (fg_alpha != max_alpha) { + if (fg_alpha != DRM_BLEND_ALPHA_OPAQUE) { bg_alpha = fg_alpha; blend_op |= DPU_BLEND_FG_MOD_ALPHA | DPU_BLEND_FG_INV_MOD_ALPHA | DPU_BLEND_BG_MOD_ALPHA | DPU_BLEND_BG_INV_MOD_ALPHA; } else { + bg_alpha = 0; blend_op |= DPU_BLEND_BG_INV_ALPHA; } } @@ -1325,7 +1321,7 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate) return false; } -static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) +static int dpu_crtc_assign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { int total_planes = crtc->dev->mode_config.num_total_plane; struct drm_atomic_state *state = crtc_state->state; @@ -1338,8 +1334,6 @@ static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state if (IS_ERR(global_state)) return PTR_ERR(global_state); - dpu_rm_release_all_sspp(global_state, crtc); - if (!crtc_state->enable) return 0; @@ -1366,6 +1360,19 @@ done: return ret; } +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) +{ + struct dpu_global_state *global_state; + + global_state = dpu_kms_get_global_state(crtc_state->state); + if (IS_ERR(global_state)) + return PTR_ERR(global_state); + + dpu_rm_release_all_sspp(global_state, crtc); + + return dpu_crtc_assign_planes(crtc, crtc_state); +} + #define MAX_CHANNELS_PER_CRTC PIPES_PER_PLANE #define MAX_HDISPLAY_SPLIT 1080 @@ -1410,7 +1417,8 @@ static struct msm_display_topology dpu_crtc_get_topology( topology.num_lm = 2; else if (topology.num_dsc == 2) topology.num_lm = 2; - else if (dpu_kms->catalog->caps->has_3d_merge) + else if (dpu_kms->catalog->caps->has_3d_merge && + topology.num_dsc == 0) topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; else topology.num_lm = 1; @@ -1534,9 +1542,11 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, return rc; } - if (dpu_use_virtual_planes && - (crtc_state->planes_changed || crtc_state->zpos_changed)) { - rc = dpu_crtc_reassign_planes(crtc, crtc_state); + if (crtc_state->planes_changed || crtc_state->zpos_changed) { + if (dpu_use_virtual_planes) + rc = dpu_crtc_reassign_planes(crtc, crtc_state); + else + rc = dpu_crtc_assign_planes(crtc, crtc_state); if (rc < 0) return rc; } @@ -1657,6 +1667,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) return 0; } +/** + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline + * @state: Pointer to drm crtc state object + */ +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state) +{ + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); + + return cstate->num_mixers; +} + #ifdef CONFIG_DEBUG_FS static int _dpu_debugfs_status_show(struct seq_file *s, void *data) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 94392b9b9245..6eaba5696e8e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type( void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state); + #endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index 93db1484f606..45079ee59cf6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -257,6 +257,12 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( if (!dpu_encoder_phys_cmd_is_master(phys_enc)) goto end; + /* IRQ not yet initialized */ + if (!phys_enc->irq[INTR_IDX_RDPTR]) { + ret = -EINVAL; + goto end; + } + /* protect against negative */ if (!enable && refcount == 0) { ret = -EINVAL; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 0ba777bda253..ba810f26ea30 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -10,6 +10,7 @@ #include "dpu_formats.h" #include "dpu_trace.h" #include "disp/msm_disp_snapshot.h" +#include "msm_dsc_helper.h" #include <drm/display/drm_dsc_helper.h> #include <drm/drm_managed.h> @@ -136,6 +137,7 @@ static void drm_mode_to_intf_timing_params( timing->width = timing->width * drm_dsc_get_bpp_int(dsc) / (dsc->bits_per_component * 3); timing->xres = timing->width; + timing->dce_bytes_per_line = msm_dsc_get_bytes_per_line(dsc); } } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c index 6d28f2281c76..22433bfbea1e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c @@ -70,7 +70,7 @@ static void dpu_encoder_phys_wb_set_ot_limit( ot_params.height = phys_enc->cached_mode.vdisplay; ot_params.is_wfd = !dpu_encoder_helper_get_cwb_mask(phys_enc); ot_params.frame_rate = drm_mode_vrefresh(&phys_enc->cached_mode); - ot_params.vbif_idx = hw_wb->caps->vbif_idx; + /* XXX: WB on MSM8996 should use VBIF_NRT */ ot_params.rd = false; if (!_dpu_encoder_phys_wb_clk_force_ctrl(hw_wb, phys_enc->dpu_kms->hw_mdp, @@ -108,14 +108,13 @@ static void dpu_encoder_phys_wb_set_qos_remap( hw_wb = phys_enc->hw_wb; memset(&qos_params, 0, sizeof(qos_params)); - qos_params.vbif_idx = hw_wb->caps->vbif_idx; + /* XXX: WB on MSM8996 should use VBIF_NRT */ qos_params.xin_id = hw_wb->caps->xin_id; qos_params.num = hw_wb->idx - WB_0; qos_params.is_rt = dpu_encoder_helper_get_cwb_mask(phys_enc); - DPU_DEBUG("[qos_remap] wb:%d vbif:%d xin:%d is_rt:%d\n", + DPU_DEBUG("[qos_remap] wb:%d xin:%d is_rt:%d\n", qos_params.num, - qos_params.vbif_idx, qos_params.xin_id, qos_params.is_rt); if (!_dpu_encoder_phys_wb_clk_force_ctrl(hw_wb, phys_enc->dpu_kms->hw_mdp, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index c4e1f6b7345d..bb4fd5fa4b22 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -513,10 +513,8 @@ static const struct dpu_vbif_dynamic_ot_cfg msm8998_ot_rdwr_cfg[] = { }, }; -static const struct dpu_vbif_cfg msm8996_vbif[] = { - { - .name = "vbif_rt", .id = VBIF_RT, - .base = 0, .len = 0x1040, +static const struct dpu_vbif_cfg msm8996_vbif = { + .len = 0x1040, .default_ot_rd_limit = 32, .default_ot_wr_limit = 16, .features = BIT(DPU_VBIF_QOS_REMAP) | BIT(DPU_VBIF_QOS_OTLIM), @@ -538,13 +536,10 @@ static const struct dpu_vbif_cfg msm8996_vbif[] = { .npriority_lvl = ARRAY_SIZE(msm8998_nrt_pri_lvl), .priority_lvl = msm8998_nrt_pri_lvl, }, - }, }; -static const struct dpu_vbif_cfg msm8998_vbif[] = { - { - .name = "vbif_rt", .id = VBIF_RT, - .base = 0, .len = 0x1040, +static const struct dpu_vbif_cfg msm8998_vbif = { + .len = 0x1040, .default_ot_rd_limit = 32, .default_ot_wr_limit = 32, .features = BIT(DPU_VBIF_QOS_REMAP) | BIT(DPU_VBIF_QOS_OTLIM), @@ -568,13 +563,10 @@ static const struct dpu_vbif_cfg msm8998_vbif[] = { }, .memtype_count = 14, .memtype = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, - }, }; -static const struct dpu_vbif_cfg sdm845_vbif[] = { - { - .name = "vbif_rt", .id = VBIF_RT, - .base = 0, .len = 0x1040, +static const struct dpu_vbif_cfg sdm845_vbif = { + .len = 0x1040, .features = BIT(DPU_VBIF_QOS_REMAP), .xin_halt_timeout = 0x4000, .qos_rp_remap_size = 0x40, @@ -588,13 +580,10 @@ static const struct dpu_vbif_cfg sdm845_vbif[] = { }, .memtype_count = 14, .memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, - }, }; -static const struct dpu_vbif_cfg sm8550_vbif[] = { - { - .name = "vbif_rt", .id = VBIF_RT, - .base = 0, .len = 0x1040, +static const struct dpu_vbif_cfg sm8550_vbif = { + .len = 0x1040, .features = BIT(DPU_VBIF_QOS_REMAP), .xin_halt_timeout = 0x4000, .qos_rp_remap_size = 0x40, @@ -608,13 +597,10 @@ static const struct dpu_vbif_cfg sm8550_vbif[] = { }, .memtype_count = 16, .memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, - }, }; -static const struct dpu_vbif_cfg sm8650_vbif[] = { - { - .name = "vbif_rt", .id = VBIF_RT, - .base = 0, .len = 0x1074, +static const struct dpu_vbif_cfg sm8650_vbif = { + .len = 0x1074, .features = BIT(DPU_VBIF_QOS_REMAP), .xin_halt_timeout = 0x4000, .qos_rp_remap_size = 0x40, @@ -628,7 +614,6 @@ static const struct dpu_vbif_cfg sm8650_vbif[] = { }, .memtype_count = 16, .memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, - }, }; /************************************************************* @@ -771,4 +756,5 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { #include "catalog/dpu_10_0_sm8650.h" #include "catalog/dpu_12_0_sm8750.h" #include "catalog/dpu_12_2_glymur.h" +#include "catalog/dpu_12_4_eliza.h" #include "catalog/dpu_13_0_kaanapali.h" diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 70d5ed4732f2..ba04ac24d5a9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -524,7 +524,6 @@ struct dpu_intf_cfg { /** * struct dpu_wb_cfg - information of writeback blocks * @DPU_HW_BLK_INFO: refer to the description above for DPU_HW_BLK_INFO - * @vbif_idx: vbif client index * @maxlinewidth: max line width supported by writeback block * @xin_id: bus client identifier * @intr_wb_done: interrupt index for WB_DONE @@ -535,7 +534,6 @@ struct dpu_intf_cfg { struct dpu_wb_cfg { DPU_HW_BLK_INFO; unsigned long features; - u8 vbif_idx; u32 maxlinewidth; u32 xin_id; unsigned int intr_wb_done; @@ -587,8 +585,7 @@ struct dpu_vbif_qos_tbl { /** * struct dpu_vbif_cfg - information of VBIF blocks - * @id enum identifying this block - * @base register offset of this block + * @len: length of hardware block * @features bit mask identifying sub-blocks/features * @ot_rd_limit default OT read limit * @ot_wr_limit default OT write limit @@ -602,7 +599,7 @@ struct dpu_vbif_qos_tbl { * @memtype array of xin memtype definitions */ struct dpu_vbif_cfg { - DPU_HW_BLK_INFO; + u32 len; unsigned long features; u32 default_ot_rd_limit; u32 default_ot_wr_limit; @@ -743,7 +740,6 @@ struct dpu_mdss_cfg { u32 intf_count; const struct dpu_intf_cfg *intf; - u32 vbif_count; const struct dpu_vbif_cfg *vbif; u32 wb_count; @@ -767,6 +763,7 @@ struct dpu_mdss_cfg { const struct dpu_format_extended *vig_formats; }; +extern const struct dpu_mdss_cfg dpu_eliza_cfg; extern const struct dpu_mdss_cfg dpu_glymur_cfg; extern const struct dpu_mdss_cfg dpu_kaanapali_cfg; extern const struct dpu_mdss_cfg dpu_msm8917_cfg; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c index 188ee0af2c90..23dcbe1ce1b8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c @@ -89,7 +89,7 @@ static void dpu_setup_dspp_gc(struct dpu_hw_dspp *ctx, base = ctx->cap->sblk->gc.base; if (!base) { - DRM_ERROR("invalid ctx %pK gc base\n", ctx); + DRM_ERROR("invalid ctx %p gc base\n", ctx); return; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c index 7e620f590984..ac82b69aedf6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -173,13 +173,29 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *intf, data_width = p->width; /* - * If widebus is enabled, data is valid for only half the active window - * since the data rate is doubled in this mode. But for the compression - * mode in DP case, the p->width is already adjusted in - * drm_mode_to_intf_timing_params() + * If widebus is disabled: + * For uncompressed stream, the data is valid for the entire active + * window period. + * For compressed stream, data is valid for a shorter time period + * inside the active window depending on the compression ratio. + * + * If widebus is enabled: + * For uncompressed stream, data is valid for only half the active + * window, since the data rate is doubled in this mode. + * For compressed stream, data validity window needs to be adjusted for + * compression ratio and then further halved. + * + * For the compression mode in DP case, the p->width is already + * adjusted in drm_mode_to_intf_timing_params(). */ - if (p->wide_bus_en && !dp_intf) + if (p->compression_en && !dp_intf) { + if (p->wide_bus_en) + data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 6); + else + data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3); + } else if (p->wide_bus_en && !dp_intf) { data_width = p->width >> 1; + } /* TODO: handle DSC+DP case, we only handle DSC+DSI case so far */ if (p->compression_en && !dp_intf && diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index f6ef2c21b66d..badd26305fc9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -35,6 +35,7 @@ struct dpu_hw_intf_timing_params { bool wide_bus_en; bool compression_en; + u32 dce_bytes_per_line; }; struct dpu_hw_intf_prog_fetch { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c index e8a76d5192c2..b7779726bf10 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -126,7 +126,9 @@ static int dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx, u32 *misr_value) } static void dpu_hw_lm_setup_blend_config_combined_alpha(struct dpu_hw_mixer *ctx, - u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) + u32 stage, + u16 fg_alpha, u16 bg_alpha, + u32 blend_op) { struct dpu_hw_blk_reg_map *c = &ctx->hw; int stage_off; @@ -139,15 +141,16 @@ static void dpu_hw_lm_setup_blend_config_combined_alpha(struct dpu_hw_mixer *ctx if (WARN_ON(stage_off < 0)) return; - const_alpha = (bg_alpha & 0xFF) | ((fg_alpha & 0xFF) << 16); + const_alpha = (bg_alpha >> 8) | ((fg_alpha >> 8) << 16); DPU_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, const_alpha); DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); } static void dpu_hw_lm_setup_blend_config_combined_alpha_v12(struct dpu_hw_mixer *ctx, - u32 stage, u32 fg_alpha, - u32 bg_alpha, u32 blend_op) + u32 stage, + u16 fg_alpha, u16 bg_alpha, + u32 blend_op) { struct dpu_hw_blk_reg_map *c = &ctx->hw; int stage_off; @@ -160,13 +163,15 @@ dpu_hw_lm_setup_blend_config_combined_alpha_v12(struct dpu_hw_mixer *ctx, if (WARN_ON(stage_off < 0)) return; - const_alpha = (bg_alpha & 0x3ff) | ((fg_alpha & 0x3ff) << 16); + const_alpha = (bg_alpha >> 6) | ((fg_alpha >> 6) << 16); DPU_REG_WRITE(c, LM_BLEND0_CONST_ALPHA_V12 + stage_off, const_alpha); DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); } static void dpu_hw_lm_setup_blend_config(struct dpu_hw_mixer *ctx, - u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) + u32 stage, + u16 fg_alpha, u16 bg_alpha, + u32 blend_op) { struct dpu_hw_blk_reg_map *c = &ctx->hw; int stage_off; @@ -178,8 +183,8 @@ static void dpu_hw_lm_setup_blend_config(struct dpu_hw_mixer *ctx, if (WARN_ON(stage_off < 0)) return; - DPU_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha); - DPU_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha); + DPU_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha >> 8); + DPU_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha >> 8); DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index ecbb77711d83..380ca673f6de 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -41,7 +41,7 @@ struct dpu_hw_lm_ops { * for the specified stage */ void (*setup_blend_config)(struct dpu_hw_mixer *ctx, uint32_t stage, - uint32_t fg_alpha, uint32_t bg_alpha, uint32_t blend_op); + u16 fg_alpha, u16 bg_alpha, uint32_t blend_op); /** * @setup_alpha_out: Alpha color component selection from either fg or bg diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index 046b683d4c66..0e65bf5ddc4a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -284,12 +284,6 @@ enum dpu_wd_timer { WD_TIMER_MAX }; -enum dpu_vbif { - VBIF_RT, - VBIF_NRT, - VBIF_MAX, -}; - /** * enum dpu_3d_blend_mode * Desribes how the 3d data is blended diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c index e65f1fc026fd..f8f96ad971d7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c @@ -156,11 +156,13 @@ static void dpu_hw_sspp_setup_pe_config_v13(struct dpu_hw_sspp *ctx, u8 color; u32 lr_pe[4], tb_pe[4]; const u32 bytemask = 0xff; - u32 offset = ctx->cap->sblk->sspp_rec0_blk.base; + u32 offset; if (!ctx || !pe_ext) return; + offset = ctx->cap->sblk->sspp_rec0_blk.base; + c = &ctx->hw; /* program SW pixel extension override for all pipes*/ for (color = 0; color < DPU_MAX_PLANES; color++) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c index af76ad8a8103..112df3f31e2b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c @@ -230,13 +230,12 @@ struct dpu_hw_vbif *dpu_hw_vbif_init(struct drm_device *dev, if (!c) return ERR_PTR(-ENOMEM); - c->hw.blk_addr = addr + cfg->base; + c->hw.blk_addr = addr; c->hw.log_mask = DPU_DBG_MASK_VBIF; /* * Assign ops */ - c->idx = cfg->id; c->cap = cfg; _setup_vbif_ops(&c->ops, c->cap->features); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h index 9ac49448e432..96ec4e35e549 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h @@ -98,7 +98,6 @@ struct dpu_hw_vbif { struct dpu_hw_blk_reg_map hw; /* vbif */ - enum dpu_vbif idx; const struct dpu_vbif_cfg *cap; /* ops */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 449552513997..35f7af4743d7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -52,7 +52,7 @@ #define DPU_DEBUGFS_DIR "msm_dpu" #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask" -bool dpu_use_virtual_planes; +bool dpu_use_virtual_planes = true; module_param(dpu_use_virtual_planes, bool, 0); static int dpu_kms_hw_init(struct msm_kms *kms); @@ -888,16 +888,12 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) { - int i; - dpu_kms->hw_intr = NULL; /* safe to call these more than once during shutdown */ _dpu_kms_mmu_destroy(dpu_kms); - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { - dpu_kms->hw_vbif[i] = NULL; - } + dpu_kms->hw_vbif = NULL; dpu_kms_global_obj_fini(dpu_kms); @@ -1061,13 +1057,11 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k dpu_kms->mmio + cat->cdm->base, "%s", cat->cdm->name); - for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { - const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; + const struct dpu_vbif_cfg *vbif = dpu_kms->catalog->vbif; - msm_disp_snapshot_add_block(disp_state, vbif->len, - dpu_kms->vbif[vbif->id] + vbif->base, - "%s", vbif->name); - } + msm_disp_snapshot_add_block(disp_state, vbif->len, + dpu_kms->vbif, + "vbif"); pm_runtime_put_sync(&dpu_kms->pdev->dev); } @@ -1145,7 +1139,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) { struct dpu_kms *dpu_kms; struct drm_device *dev; - int i, rc = -EINVAL; + int rc = -EINVAL; unsigned long max_core_clk_rate; u32 core_rev; @@ -1161,7 +1155,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dev->mode_config.cursor_height = 512; drm_atomic_private_obj_init(dpu_kms->dev, &dpu_kms->global_state, - NULL, &dpu_kms_global_state_funcs); atomic_set(&dpu_kms->bandwidth_ref, 0); @@ -1221,20 +1214,18 @@ static int dpu_kms_hw_init(struct msm_kms *kms) goto err_pm_put; } - for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { - struct dpu_hw_vbif *hw; - const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; - - hw = dpu_hw_vbif_init(dev, vbif, dpu_kms->vbif[vbif->id]); - if (IS_ERR(hw)) { - rc = PTR_ERR(hw); - DPU_ERROR("failed to init vbif %d: %d\n", vbif->id, rc); - goto err_pm_put; - } + struct dpu_hw_vbif *hw; + const struct dpu_vbif_cfg *vbif = dpu_kms->catalog->vbif; - dpu_kms->hw_vbif[vbif->id] = hw; + hw = dpu_hw_vbif_init(dev, vbif, dpu_kms->vbif); + if (IS_ERR(hw)) { + rc = PTR_ERR(hw); + DPU_ERROR("failed to init vbif: %d\n", rc); + goto err_pm_put; } + dpu_kms->hw_vbif = hw; + /* TODO: use the same max_freq as in dpu_kms_hw_init */ max_core_clk_rate = dpu_kms_get_clk_rate(dpu_kms, "core"); if (!max_core_clk_rate) { @@ -1349,24 +1340,14 @@ static int dpu_kms_mmap_mdp5(struct dpu_kms *dpu_kms) } DRM_DEBUG("mapped dpu address space @%p\n", dpu_kms->mmio); - dpu_kms->vbif[VBIF_RT] = msm_ioremap_mdss(mdss_dev, - dpu_kms->pdev, - "vbif_phys"); - if (IS_ERR(dpu_kms->vbif[VBIF_RT])) { - ret = PTR_ERR(dpu_kms->vbif[VBIF_RT]); + dpu_kms->vbif = msm_ioremap_mdss(mdss_dev, dpu_kms->pdev, "vbif_phys"); + if (IS_ERR(dpu_kms->vbif)) { + ret = PTR_ERR(dpu_kms->vbif); DPU_ERROR("vbif register memory map failed: %d\n", ret); - dpu_kms->vbif[VBIF_RT] = NULL; + dpu_kms->vbif = NULL; return ret; } - dpu_kms->vbif[VBIF_NRT] = msm_ioremap_mdss(mdss_dev, - dpu_kms->pdev, - "vbif_nrt_phys"); - if (IS_ERR(dpu_kms->vbif[VBIF_NRT])) { - dpu_kms->vbif[VBIF_NRT] = NULL; - DPU_DEBUG("VBIF NRT is not defined"); - } - return 0; } @@ -1384,20 +1365,14 @@ static int dpu_kms_mmap_dpu(struct dpu_kms *dpu_kms) } DRM_DEBUG("mapped dpu address space @%p\n", dpu_kms->mmio); - dpu_kms->vbif[VBIF_RT] = msm_ioremap(pdev, "vbif"); - if (IS_ERR(dpu_kms->vbif[VBIF_RT])) { - ret = PTR_ERR(dpu_kms->vbif[VBIF_RT]); + dpu_kms->vbif = msm_ioremap(pdev, "vbif"); + if (IS_ERR(dpu_kms->vbif)) { + ret = PTR_ERR(dpu_kms->vbif); DPU_ERROR("vbif register memory map failed: %d\n", ret); - dpu_kms->vbif[VBIF_RT] = NULL; + dpu_kms->vbif = NULL; return ret; } - dpu_kms->vbif[VBIF_NRT] = msm_ioremap_quiet(pdev, "vbif_nrt"); - if (IS_ERR(dpu_kms->vbif[VBIF_NRT])) { - dpu_kms->vbif[VBIF_NRT] = NULL; - DPU_DEBUG("VBIF NRT is not defined"); - } - return 0; } @@ -1463,8 +1438,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) struct msm_drm_private *priv = platform_get_drvdata(pdev); struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); - /* Drop the performance state vote */ - dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks); for (i = 0; i < dpu_kms->num_paths; i++) @@ -1507,6 +1480,7 @@ static const struct dev_pm_ops dpu_pm_ops = { }; static const struct of_device_id dpu_dt_match[] = { + { .compatible = "qcom,eliza-dpu", .data = &dpu_eliza_cfg, }, { .compatible = "qcom,glymur-dpu", .data = &dpu_glymur_cfg, }, { .compatible = "qcom,kaanapali-dpu", .data = &dpu_kaanapali_cfg, }, { .compatible = "qcom,msm8917-mdp5", .data = &dpu_msm8917_cfg, }, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 993cf512f8c5..bb3393bd102e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -63,7 +63,7 @@ struct dpu_kms { const struct qcom_ubwc_cfg_data *mdss; /* io/register spaces: */ - void __iomem *mmio, *vbif[VBIF_MAX]; + void __iomem *mmio, *vbif; struct regulator *vdd; struct regulator *mmagic; @@ -81,7 +81,7 @@ struct dpu_kms { struct dpu_rm rm; - struct dpu_hw_vbif *hw_vbif[VBIF_MAX]; + struct dpu_hw_vbif *hw_vbif; struct dpu_hw_mdp *hw_mdp; bool has_danger_ctrl; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 547d084f2944..3c315d5805b8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -374,7 +374,6 @@ static void _dpu_plane_set_ot_limit(struct drm_plane *plane, ot_params.height = drm_rect_height(&pipe_cfg->src_rect); ot_params.is_wfd = !pdpu->is_rt_pipe; ot_params.frame_rate = frame_rate; - ot_params.vbif_idx = VBIF_RT; ot_params.rd = true; if (!_dpu_plane_sspp_clk_force_ctrl(pipe->sspp, dpu_kms->hw_mdp, @@ -402,14 +401,12 @@ static void _dpu_plane_set_qos_remap(struct drm_plane *plane, bool forced_on = false; memset(&qos_params, 0, sizeof(qos_params)); - qos_params.vbif_idx = VBIF_RT; qos_params.xin_id = pipe->sspp->cap->xin_id; qos_params.num = pipe->sspp->idx - SSPP_VIG0; qos_params.is_rt = pdpu->is_rt_pipe; - DPU_DEBUG_PLANE(pdpu, "pipe:%d vbif:%d xin:%d rt:%d\n", + DPU_DEBUG_PLANE(pdpu, "pipe:%d xin:%d rt:%d\n", qos_params.num, - qos_params.vbif_idx, qos_params.xin_id, qos_params.is_rt); if (!_dpu_plane_sspp_clk_force_ctrl(pipe->sspp, dpu_kms->hw_mdp, @@ -821,13 +818,8 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, { int i, ret = 0, min_scale, max_scale; struct dpu_plane *pdpu = to_dpu_plane(plane); - struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); - u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate; struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); - struct dpu_sw_pipe_cfg *pipe_cfg; - struct dpu_sw_pipe_cfg *r_pipe_cfg; struct drm_rect fb_rect = { 0 }; - uint32_t max_linewidth; min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO); max_scale = MAX_DOWNSCALE_RATIO << 16; @@ -850,14 +842,6 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, return -EINVAL; } - /* move the assignment here, to ease handling to another pairs later */ - pipe_cfg = &pstate->pipe_cfg[0]; - r_pipe_cfg = &pstate->pipe_cfg[1]; - /* state->src is 16.16, src_rect is not */ - drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); - - pipe_cfg->dst_rect = new_plane_state->dst; - fb_rect.x2 = new_plane_state->fb->width; fb_rect.y2 = new_plane_state->fb->height; @@ -879,38 +863,125 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, if (pstate->layout.plane_pitch[i] > DPU_SSPP_MAX_PITCH_SIZE) return -E2BIG; + pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state); + + return 0; +} + +static int dpu_plane_split(struct drm_plane *plane, + struct drm_plane_state *new_plane_state, + const struct drm_crtc_state *crtc_state) +{ + struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); + u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate; + struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); + struct dpu_sw_pipe_cfg *pipe_cfg; + struct dpu_sw_pipe_cfg *r_pipe_cfg; + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; + uint32_t max_linewidth; + u32 num_lm; + int stage_id, num_stages; + max_linewidth = pdpu->catalog->caps->max_linewidth; - drm_rect_rotate(&pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, - new_plane_state->rotation); + /* In non-virtual plane case, one mixer pair is always needed. */ + num_lm = dpu_crtc_get_num_lm(crtc_state); + if (dpu_use_virtual_planes) + num_stages = (num_lm + 1) / 2; + else + num_stages = 1; - if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || - _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { - if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { - DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); - return -E2BIG; + /* + * For wide plane that exceeds SSPP rectangle constrain, it needed to + * be split and mapped to 2 rectangles with 1 config for 2:2:1. + * For 2 interfaces cases, such as dual DSI, 2:2:2 topology is needed. + * If the width or clock exceeds hardware limitation in every half of + * screen, 4:4:2 topology is needed and virtual plane feature should + * be enabled to map plane to more than 1 SSPP. 2 stage configs are + * needed to serve 2 mixer pairs in this 4:4:2 case. So both left/right + * half of plane splitting, and splitting within the half of screen is + * needed in quad-pipe case. Check dest rectangle left/right clipping + * and iterate mixer configs for this plane first, then check wide + * rectangle splitting in every half next. + */ + for (stage_id = 0; stage_id < num_stages; stage_id++) { + struct drm_rect mixer_rect = { + .x1 = stage_id * mode->hdisplay / num_stages, + .y1 = 0, + .x2 = (stage_id + 1) * mode->hdisplay / num_stages, + .y2 = mode->vdisplay + }; + int cfg_idx = stage_id * PIPES_PER_STAGE; + + pipe_cfg = &pstate->pipe_cfg[cfg_idx]; + r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1]; + + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); + + drm_rect_rotate(&pipe_cfg->src_rect, + new_plane_state->fb->width, new_plane_state->fb->height, + new_plane_state->rotation); + + pipe_cfg->dst_rect = new_plane_state->dst; + + DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT + " vs clip window " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), + DRM_RECT_ARG(&mixer_rect)); + + /* + * If this plane does not fall into mixer rect, check next + * mixer rect. + */ + if (!drm_rect_clip_scaled(&pipe_cfg->src_rect, + &pipe_cfg->dst_rect, + &mixer_rect)) { + memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg)); + + continue; } - *r_pipe_cfg = *pipe_cfg; - pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; - pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; - r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; - r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; - } else { - memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); - } + pipe_cfg->dst_rect.x1 -= mixer_rect.x1; + pipe_cfg->dst_rect.x2 -= mixer_rect.x1; + + DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect)); + + /* Split wide rect into 2 rect */ + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || + _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) { + + if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); + return -E2BIG; + } + + memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_pipe_cfg)); + pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; + pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; + r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; + r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; + DPU_DEBUG_PLANE(pdpu, "Split wide plane into:" + DRM_RECT_FMT " and " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), + DRM_RECT_ARG(&r_pipe_cfg->src_rect)); + } else { + memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg)); + } - drm_rect_rotate_inv(&pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, - new_plane_state->rotation); - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) - drm_rect_rotate_inv(&r_pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, + drm_rect_rotate_inv(&pipe_cfg->src_rect, + new_plane_state->fb->width, + new_plane_state->fb->height, new_plane_state->rotation); - pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state); + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) + drm_rect_rotate_inv(&r_pipe_cfg->src_rect, + new_plane_state->fb->width, + new_plane_state->fb->height, + new_plane_state->rotation); + } return 0; } @@ -985,20 +1056,18 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane, drm_atomic_get_new_plane_state(state, plane); struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); - struct dpu_sw_pipe *pipe = &pstate->pipe[0]; - struct dpu_sw_pipe *r_pipe = &pstate->pipe[1]; - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0]; - struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1]; - int ret = 0; - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, - &crtc_state->adjusted_mode, - new_plane_state); - if (ret) - return ret; + struct dpu_sw_pipe *pipe; + struct dpu_sw_pipe_cfg *pipe_cfg; + int ret = 0, i; - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) { - ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, + for (i = 0; i < PIPES_PER_PLANE; i++) { + pipe = &pstate->pipe[i]; + pipe_cfg = &pstate->pipe_cfg[i]; + if (!drm_rect_width(&pipe_cfg->src_rect)) + continue; + DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i); + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, &crtc_state->adjusted_mode, new_plane_state); if (ret) @@ -1103,60 +1172,12 @@ static int dpu_plane_try_multirect_shared(struct dpu_plane_state *pstate, static int dpu_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - int ret = 0; - struct dpu_plane *pdpu = to_dpu_plane(plane); - struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); - struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); - struct dpu_sw_pipe *pipe = &pstate->pipe[0]; - struct dpu_sw_pipe *r_pipe = &pstate->pipe[1]; - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0]; - struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1]; - const struct drm_crtc_state *crtc_state = NULL; - uint32_t max_linewidth = dpu_kms->catalog->caps->max_linewidth; - - if (new_plane_state->crtc) - crtc_state = drm_atomic_get_new_crtc_state(state, - new_plane_state->crtc); - - pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe); - - if (!pipe->sspp) - return -EINVAL; - - ret = dpu_plane_atomic_check_nosspp(plane, new_plane_state, crtc_state); - if (ret) - return ret; - - if (!new_plane_state->visible) - return 0; - - if (!dpu_plane_try_multirect_parallel(pipe, pipe_cfg, r_pipe, r_pipe_cfg, - pipe->sspp, - msm_framebuffer_format(new_plane_state->fb), - max_linewidth)) { - DPU_DEBUG_PLANE(pdpu, "invalid " DRM_RECT_FMT " /" DRM_RECT_FMT - " max_line:%u, can't use split source\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), - DRM_RECT_ARG(&r_pipe_cfg->src_rect), - max_linewidth); - return -E2BIG; - } - - return dpu_plane_atomic_check_sspp(plane, state, crtc_state); -} - -static int dpu_plane_virtual_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) -{ struct drm_plane_state *plane_state = drm_atomic_get_plane_state(state, plane); struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); - struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state); + int ret = 0; struct drm_crtc_state *crtc_state = NULL; - int ret, i; if (IS_ERR(plane_state)) return PTR_ERR(plane_state); @@ -1169,16 +1190,8 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane, if (ret) return ret; - if (!plane_state->visible) { - /* - * resources are freed by dpu_crtc_assign_plane_resources(), - * but clean them here. - */ - for (i = 0; i < PIPES_PER_PLANE; i++) - pstate->pipe[i].sspp = NULL; - + if (!plane_state->visible) return 0; - } /* * Force resource reallocation if the format of FB or src/dst have @@ -1193,7 +1206,6 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane, msm_framebuffer_format(old_plane_state->fb) != msm_framebuffer_format(plane_state->fb)) crtc_state->planes_changed = true; - return 0; } @@ -1240,9 +1252,9 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc, struct dpu_global_state *global_state, struct drm_atomic_state *state, struct drm_plane_state *plane_state, + const struct drm_crtc_state *crtc_state, struct drm_plane_state **prev_adjacent_plane_state) { - const struct drm_crtc_state *crtc_state = NULL; struct drm_plane *plane = plane_state->plane; struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); struct dpu_rm_sspp_requirements reqs; @@ -1252,10 +1264,6 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc, const struct msm_format *fmt; int i, ret; - if (plane_state->crtc) - crtc_state = drm_atomic_get_new_crtc_state(state, - plane_state->crtc); - pstate = to_dpu_plane_state(plane_state); for (i = 0; i < STAGES_PER_PLANE; i++) prev_adjacent_pstate[i] = prev_adjacent_plane_state[i] ? @@ -1267,6 +1275,10 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc, if (!plane_state->fb) return -EINVAL; + ret = dpu_plane_split(plane, plane_state, crtc_state); + if (ret) + return ret; + fmt = msm_framebuffer_format(plane_state->fb); reqs.yuv = MSM_FORMAT_IS_YUV(fmt); reqs.scale = (plane_state->src_w >> 16 != plane_state->crtc_w) || @@ -1297,14 +1309,55 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc, return dpu_plane_atomic_check_sspp(plane, state, crtc_state); } +static int dpu_plane_assign_resources(struct drm_crtc *crtc, + struct dpu_global_state *global_state, + struct drm_atomic_state *state, + struct drm_plane_state *plane_state, + const struct drm_crtc_state *crtc_state) +{ + struct drm_plane *plane = plane_state->plane; + struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); + struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state); + struct dpu_sw_pipe *pipe = &pstate->pipe[0]; + struct dpu_sw_pipe *r_pipe = &pstate->pipe[1]; + struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0]; + struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1]; + struct dpu_plane *pdpu = to_dpu_plane(plane); + int ret; + + pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe); + if (!pipe->sspp) + return -EINVAL; + + ret = dpu_plane_split(plane, plane_state, crtc_state); + if (ret) + return ret; + + if (!dpu_plane_try_multirect_parallel(pipe, pipe_cfg, r_pipe, r_pipe_cfg, + pipe->sspp, + msm_framebuffer_format(plane_state->fb), + dpu_kms->catalog->caps->max_linewidth)) { + DPU_DEBUG_PLANE(pdpu, "invalid " DRM_RECT_FMT " /" DRM_RECT_FMT + " max_line:%u, can't use split source\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), + DRM_RECT_ARG(&r_pipe_cfg->src_rect), + dpu_kms->catalog->caps->max_linewidth); + return -E2BIG; + } + + return dpu_plane_atomic_check_sspp(plane, state, crtc_state); +} + int dpu_assign_plane_resources(struct dpu_global_state *global_state, struct drm_atomic_state *state, struct drm_crtc *crtc, struct drm_plane_state **states, unsigned int num_planes) { - unsigned int i; struct drm_plane_state *prev_adjacent_plane_state[STAGES_PER_PLANE] = { NULL }; + const struct drm_crtc_state *crtc_state = NULL; + unsigned int i; + int ret; for (i = 0; i < num_planes; i++) { struct drm_plane_state *plane_state = states[i]; @@ -1313,8 +1366,18 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state, !plane_state->visible) continue; - int ret = dpu_plane_virtual_assign_resources(crtc, global_state, + if (plane_state->crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, + plane_state->crtc); + + if (!dpu_use_virtual_planes) + ret = dpu_plane_assign_resources(crtc, global_state, + state, plane_state, + crtc_state); + else + ret = dpu_plane_virtual_assign_resources(crtc, global_state, state, plane_state, + crtc_state, prev_adjacent_plane_state); if (ret) return ret; @@ -1751,7 +1814,7 @@ static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = { static const struct drm_plane_helper_funcs dpu_plane_virtual_helper_funcs = { .prepare_fb = dpu_plane_prepare_fb, .cleanup_fb = dpu_plane_cleanup_fb, - .atomic_check = dpu_plane_virtual_atomic_check, + .atomic_check = dpu_plane_atomic_check, .atomic_update = dpu_plane_atomic_update, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 451a4fcf3e65..7e77d88f8959 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -350,26 +350,28 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, return true; } -static bool dpu_rm_find_lms(struct dpu_rm *rm, - struct dpu_global_state *global_state, - uint32_t crtc_id, bool skip_dspp, - struct msm_display_topology *topology, - int *lm_idx, int *pp_idx, int *dspp_idx) +static int _dpu_rm_reserve_lms(struct dpu_rm *rm, + struct dpu_global_state *global_state, + uint32_t crtc_id, + struct msm_display_topology *topology) { + int lm_idx[MAX_BLOCKS]; + int pp_idx[MAX_BLOCKS]; + int dspp_idx[MAX_BLOCKS] = {0}; int i, lm_count = 0; + if (!topology->num_lm) { + DPU_ERROR("zero LMs in topology\n"); + return -EINVAL; + } + /* Find a primary mixer */ for (i = 0; i < ARRAY_SIZE(rm->mixer_blks) && lm_count < topology->num_lm; i++) { if (!rm->mixer_blks[i]) continue; - if (skip_dspp && to_dpu_hw_mixer(rm->mixer_blks[i])->cap->dspp) { - DPU_DEBUG("Skipping LM_%d, skipping LMs with DSPPs\n", i); - continue; - } - /* * Reset lm_count to an even index. This will drop the previous * primary mixer if failed to find its peer. @@ -408,38 +410,12 @@ static bool dpu_rm_find_lms(struct dpu_rm *rm, } } - return lm_count == topology->num_lm; -} - -static int _dpu_rm_reserve_lms(struct dpu_rm *rm, - struct dpu_global_state *global_state, - uint32_t crtc_id, - struct msm_display_topology *topology) - -{ - int lm_idx[MAX_BLOCKS]; - int pp_idx[MAX_BLOCKS]; - int dspp_idx[MAX_BLOCKS] = {0}; - int i; - bool found; - - if (!topology->num_lm) { - DPU_ERROR("zero LMs in topology\n"); - return -EINVAL; - } - - /* Try using non-DSPP LM blocks first */ - found = dpu_rm_find_lms(rm, global_state, crtc_id, !topology->num_dspp, - topology, lm_idx, pp_idx, dspp_idx); - if (!found && !topology->num_dspp) - found = dpu_rm_find_lms(rm, global_state, crtc_id, false, - topology, lm_idx, pp_idx, dspp_idx); - if (!found) { + if (lm_count != topology->num_lm) { DPU_DEBUG("unable to find appropriate mixers\n"); return -ENAVAIL; } - for (i = 0; i < topology->num_lm; i++) { + for (i = 0; i < lm_count; i++) { global_state->mixer_to_crtc_id[lm_idx[i]] = crtc_id; global_state->pingpong_to_crtc_id[pp_idx[i]] = crtc_id; global_state->dspp_to_crtc_id[dspp_idx[i]] = diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h index cb24ad2a6d8d..805d117493da 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h @@ -72,23 +72,20 @@ TRACE_EVENT(dpu_perf_set_danger_luts, ); TRACE_EVENT(dpu_perf_set_ot, - TP_PROTO(u32 pnum, u32 xin_id, u32 rd_lim, u32 vbif_idx), - TP_ARGS(pnum, xin_id, rd_lim, vbif_idx), + TP_PROTO(u32 pnum, u32 xin_id, u32 rd_lim), + TP_ARGS(pnum, xin_id, rd_lim), TP_STRUCT__entry( __field(u32, pnum) __field(u32, xin_id) __field(u32, rd_lim) - __field(u32, vbif_idx) ), TP_fast_assign( __entry->pnum = pnum; __entry->xin_id = xin_id; __entry->rd_lim = rd_lim; - __entry->vbif_idx = vbif_idx; ), - TP_printk("pnum:%d xin_id:%d ot:%d vbif:%d", - __entry->pnum, __entry->xin_id, __entry->rd_lim, - __entry->vbif_idx) + TP_printk("pnum:%d xin_id:%d ot:%d", + __entry->pnum, __entry->xin_id, __entry->rd_lim) ) TRACE_EVENT(dpu_cmd_release_bw, @@ -861,17 +858,15 @@ TRACE_EVENT(dpu_rm_reserve_lms, ); TRACE_EVENT(dpu_vbif_wait_xin_halt_fail, - TP_PROTO(enum dpu_vbif index, u32 xin_id), - TP_ARGS(index, xin_id), + TP_PROTO(u32 xin_id), + TP_ARGS(xin_id), TP_STRUCT__entry( - __field( enum dpu_vbif, index ) __field( u32, xin_id ) ), TP_fast_assign( - __entry->index = index; __entry->xin_id = xin_id; ), - TP_printk("index:%d xin_id:%u", __entry->index, __entry->xin_id) + TP_printk("xin_id:%u", __entry->xin_id) ); TRACE_EVENT(dpu_pp_connect_ext_te, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c index 2a551e455aa3..0c6fa9bb0cb6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c @@ -11,26 +11,6 @@ #include "dpu_hw_vbif.h" #include "dpu_trace.h" -static struct dpu_hw_vbif *dpu_get_vbif(struct dpu_kms *dpu_kms, enum dpu_vbif vbif_idx) -{ - if (vbif_idx < ARRAY_SIZE(dpu_kms->hw_vbif)) - return dpu_kms->hw_vbif[vbif_idx]; - - return NULL; -} - -static const char *dpu_vbif_name(enum dpu_vbif idx) -{ - switch (idx) { - case VBIF_RT: - return "VBIF_RT"; - case VBIF_NRT: - return "VBIF_NRT"; - default: - return "??"; - } -} - /** * _dpu_vbif_wait_for_xin_halt - wait for the xin to halt * @vbif: Pointer to hardware vbif driver @@ -62,12 +42,10 @@ static int _dpu_vbif_wait_for_xin_halt(struct dpu_hw_vbif *vbif, u32 xin_id) if (!status) { rc = -ETIMEDOUT; - DPU_ERROR("%s client %d not halting. TIMEDOUT.\n", - dpu_vbif_name(vbif->idx), xin_id); + DPU_ERROR("VBIF client %d not halting. TIMEDOUT.\n", xin_id); } else { rc = 0; - DRM_DEBUG_ATOMIC("%s client %d is halted\n", - dpu_vbif_name(vbif->idx), xin_id); + DRM_DEBUG_ATOMIC("VBIF client %d is halted\n", xin_id); } return rc; @@ -107,10 +85,10 @@ static void _dpu_vbif_apply_dynamic_ot_limit(struct dpu_hw_vbif *vbif, } } - DRM_DEBUG_ATOMIC("%s xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n", - dpu_vbif_name(vbif->idx), params->xin_id, - params->width, params->height, params->frame_rate, - pps, *ot_lim); + DRM_DEBUG_ATOMIC("VBIF xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n", + params->xin_id, + params->width, params->height, params->frame_rate, + pps, *ot_lim); } /** @@ -153,8 +131,7 @@ static u32 _dpu_vbif_get_ot_limit(struct dpu_hw_vbif *vbif, } exit: - DRM_DEBUG_ATOMIC("%s xin:%d ot_lim:%d\n", - dpu_vbif_name(vbif->idx), params->xin_id, ot_lim); + DRM_DEBUG_ATOMIC("VBIF xin:%d ot_lim:%d\n", params->xin_id, ot_lim); return ot_lim; } @@ -172,7 +149,7 @@ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, u32 ot_lim; int ret; - vbif = dpu_get_vbif(dpu_kms, params->vbif_idx); + vbif = dpu_kms->hw_vbif; if (!vbif) { DRM_DEBUG_ATOMIC("invalid arguments vbif %d\n", vbif != NULL); return; @@ -190,8 +167,7 @@ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, if (ot_lim == 0) return; - trace_dpu_perf_set_ot(params->num, params->xin_id, ot_lim, - params->vbif_idx); + trace_dpu_perf_set_ot(params->num, params->xin_id, ot_lim); vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim); @@ -199,7 +175,7 @@ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, ret = _dpu_vbif_wait_for_xin_halt(vbif, params->xin_id); if (ret) - trace_dpu_vbif_wait_xin_halt_fail(vbif->idx, params->xin_id); + trace_dpu_vbif_wait_xin_halt_fail(params->xin_id); vbif->ops.set_halt_ctrl(vbif, params->xin_id, false); } @@ -221,10 +197,10 @@ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, return; } - vbif = dpu_get_vbif(dpu_kms, params->vbif_idx); + vbif = dpu_kms->hw_vbif; if (!vbif || !vbif->cap) { - DPU_ERROR("invalid vbif %d\n", params->vbif_idx); + DPU_ERROR("invalid vbif\n"); return; } @@ -242,8 +218,8 @@ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, } for (i = 0; i < qos_tbl->npriority_lvl; i++) { - DRM_DEBUG_ATOMIC("%s xin:%d lvl:%d/%d\n", - dpu_vbif_name(params->vbif_idx), params->xin_id, i, + DRM_DEBUG_ATOMIC("VBIF xin:%d lvl:%d/%d\n", + params->xin_id, i, qos_tbl->priority_lvl[i]); vbif->ops.set_qos_remap(vbif, params->xin_id, i, qos_tbl->priority_lvl[i]); @@ -257,16 +233,13 @@ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms) { struct dpu_hw_vbif *vbif; - u32 i, pnd, src; - - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { - vbif = dpu_kms->hw_vbif[i]; - if (vbif && vbif->ops.clear_errors) { - vbif->ops.clear_errors(vbif, &pnd, &src); - if (pnd || src) { - DRM_DEBUG_KMS("%s: pnd 0x%X, src 0x%X\n", - dpu_vbif_name(vbif->idx), pnd, src); - } + u32 pnd, src; + + vbif = dpu_kms->hw_vbif; + if (vbif && vbif->ops.clear_errors) { + vbif->ops.clear_errors(vbif, &pnd, &src); + if (pnd || src) { + DRM_DEBUG_KMS("VBIF: pnd 0x%X, src 0x%X\n", pnd, src); } } } @@ -278,15 +251,12 @@ void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms) void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms) { struct dpu_hw_vbif *vbif; - int i, j; - - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { - vbif = dpu_kms->hw_vbif[i]; - if (vbif && vbif->cap && vbif->ops.set_mem_type) { - for (j = 0; j < vbif->cap->memtype_count; j++) - vbif->ops.set_mem_type( - vbif, j, vbif->cap->memtype[j]); - } + int j; + + vbif = dpu_kms->hw_vbif; + if (vbif && vbif->cap && vbif->ops.set_mem_type) { + for (j = 0; j < vbif->cap->memtype_count; j++) + vbif->ops.set_mem_type(vbif, j, vbif->cap->memtype[j]); } } @@ -294,58 +264,51 @@ void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms) void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root) { + const struct dpu_vbif_cfg *vbif = dpu_kms->catalog->vbif; char vbif_name[32]; - struct dentry *entry, *debugfs_vbif; - int i, j; - - entry = debugfs_create_dir("vbif", debugfs_root); - - for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { - const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; + struct dentry *debugfs_vbif; + int j; - snprintf(vbif_name, sizeof(vbif_name), "%d", vbif->id); + debugfs_vbif = debugfs_create_dir("vbif", debugfs_root); - debugfs_vbif = debugfs_create_dir(vbif_name, entry); + debugfs_create_u32("features", 0600, debugfs_vbif, + (u32 *)&vbif->features); - debugfs_create_u32("features", 0600, debugfs_vbif, - (u32 *)&vbif->features); + debugfs_create_u32("xin_halt_timeout", 0400, debugfs_vbif, + (u32 *)&vbif->xin_halt_timeout); - debugfs_create_u32("xin_halt_timeout", 0400, debugfs_vbif, - (u32 *)&vbif->xin_halt_timeout); + debugfs_create_u32("default_rd_ot_limit", 0400, debugfs_vbif, + (u32 *)&vbif->default_ot_rd_limit); - debugfs_create_u32("default_rd_ot_limit", 0400, debugfs_vbif, - (u32 *)&vbif->default_ot_rd_limit); + debugfs_create_u32("default_wr_ot_limit", 0400, debugfs_vbif, + (u32 *)&vbif->default_ot_wr_limit); - debugfs_create_u32("default_wr_ot_limit", 0400, debugfs_vbif, - (u32 *)&vbif->default_ot_wr_limit); + for (j = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) { + const struct dpu_vbif_dynamic_ot_cfg *cfg = + &vbif->dynamic_ot_rd_tbl.cfg[j]; - for (j = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) { - const struct dpu_vbif_dynamic_ot_cfg *cfg = - &vbif->dynamic_ot_rd_tbl.cfg[j]; - - snprintf(vbif_name, sizeof(vbif_name), - "dynamic_ot_rd_%d_pps", j); - debugfs_create_u64(vbif_name, 0400, debugfs_vbif, - (u64 *)&cfg->pps); - snprintf(vbif_name, sizeof(vbif_name), - "dynamic_ot_rd_%d_ot_limit", j); - debugfs_create_u32(vbif_name, 0400, debugfs_vbif, - (u32 *)&cfg->ot_limit); - } + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_rd_%d_pps", j); + debugfs_create_u64(vbif_name, 0400, debugfs_vbif, + (u64 *)&cfg->pps); + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_rd_%d_ot_limit", j); + debugfs_create_u32(vbif_name, 0400, debugfs_vbif, + (u32 *)&cfg->ot_limit); + } - for (j = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) { - const struct dpu_vbif_dynamic_ot_cfg *cfg = - &vbif->dynamic_ot_wr_tbl.cfg[j]; - - snprintf(vbif_name, sizeof(vbif_name), - "dynamic_ot_wr_%d_pps", j); - debugfs_create_u64(vbif_name, 0400, debugfs_vbif, - (u64 *)&cfg->pps); - snprintf(vbif_name, sizeof(vbif_name), - "dynamic_ot_wr_%d_ot_limit", j); - debugfs_create_u32(vbif_name, 0400, debugfs_vbif, - (u32 *)&cfg->ot_limit); - } + for (j = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) { + const struct dpu_vbif_dynamic_ot_cfg *cfg = + &vbif->dynamic_ot_wr_tbl.cfg[j]; + + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_wr_%d_pps", j); + debugfs_create_u64(vbif_name, 0400, debugfs_vbif, + (u64 *)&cfg->pps); + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_wr_%d_ot_limit", j); + debugfs_create_u32(vbif_name, 0400, debugfs_vbif, + (u32 *)&cfg->ot_limit); } } #endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h index 62e47ae1e3ee..f47a89cb34ea 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h @@ -15,24 +15,20 @@ struct dpu_vbif_set_ot_params { u32 frame_rate; bool rd; bool is_wfd; - u32 vbif_idx; }; struct dpu_vbif_set_memtype_params { u32 xin_id; - u32 vbif_idx; bool is_cacheable; }; /** * struct dpu_vbif_set_qos_params - QoS remapper parameter - * @vbif_idx: vbif identifier * @xin_id: client interface identifier * @num: pipe identifier (debug only) * @is_rt: true if pipe is used in real-time use case */ struct dpu_vbif_set_qos_params { - u32 vbif_idx; u32 xin_id; u32 num; bool is_rt; diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c index 69fef034d0df..7c91fc1915f3 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c @@ -14,95 +14,6 @@ struct mdp5_cfg_handler { /* mdp5_cfg must be exposed (used in mdp5.xml.h) */ const struct mdp5_cfg_hw *mdp5_cfg = NULL; -static const struct mdp5_cfg_hw msm8x74v1_config = { - .name = "msm8x74v1", - .mdp = { - .count = 1, - .caps = MDP_CAP_SMP | - 0, - }, - .smp = { - .mmb_count = 22, - .mmb_size = 4096, - .clients = { - [SSPP_VIG0] = 1, [SSPP_VIG1] = 4, [SSPP_VIG2] = 7, - [SSPP_DMA0] = 10, [SSPP_DMA1] = 13, - [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18, - }, - }, - .ctl = { - .count = 5, - .base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 }, - .flush_hw_mask = 0x0003ffff, - }, - .pipe_vig = { - .count = 3, - .base = { 0x01100, 0x01500, 0x01900 }, - .caps = MDP_PIPE_CAP_HFLIP | - MDP_PIPE_CAP_VFLIP | - MDP_PIPE_CAP_SCALE | - MDP_PIPE_CAP_CSC | - 0, - }, - .pipe_rgb = { - .count = 3, - .base = { 0x01d00, 0x02100, 0x02500 }, - .caps = MDP_PIPE_CAP_HFLIP | - MDP_PIPE_CAP_VFLIP | - MDP_PIPE_CAP_SCALE | - 0, - }, - .pipe_dma = { - .count = 2, - .base = { 0x02900, 0x02d00 }, - .caps = MDP_PIPE_CAP_HFLIP | - MDP_PIPE_CAP_VFLIP | - 0, - }, - .lm = { - .count = 5, - .base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 }, - .instances = { - { .id = 0, .pp = 0, .dspp = 0, - .caps = MDP_LM_CAP_DISPLAY, }, - { .id = 1, .pp = 1, .dspp = 1, - .caps = MDP_LM_CAP_DISPLAY, }, - { .id = 2, .pp = 2, .dspp = 2, - .caps = MDP_LM_CAP_DISPLAY, }, - { .id = 3, .pp = -1, .dspp = -1, - .caps = MDP_LM_CAP_WB }, - { .id = 4, .pp = -1, .dspp = -1, - .caps = MDP_LM_CAP_WB }, - }, - .nb_stages = 5, - .max_width = 2048, - .max_height = 0xFFFF, - }, - .dspp = { - .count = 3, - .base = { 0x04500, 0x04900, 0x04d00 }, - }, - .pp = { - .count = 3, - .base = { 0x21a00, 0x21b00, 0x21c00 }, - }, - .intf = { - .base = { 0x21000, 0x21200, 0x21400, 0x21600 }, - .connect = { - [0] = INTF_eDP, - [1] = INTF_DSI, - [2] = INTF_DSI, - [3] = INTF_HDMI, - }, - }, - .perf = { - .ab_inefficiency = 200, - .ib_inefficiency = 120, - .clk_inefficiency = 125 - }, - .max_clk = 200000000, -}; - static const struct mdp5_cfg_hw msm8x26_config = { .name = "msm8x26", .mdp = { @@ -184,7 +95,7 @@ static const struct mdp5_cfg_hw msm8x26_config = { .max_clk = 200000000, }; -static const struct mdp5_cfg_hw msm8x74v2_config = { +static const struct mdp5_cfg_hw msm8x74_config = { .name = "msm8x74", .mdp = { .count = 1, @@ -1098,9 +1009,8 @@ static const struct mdp5_cfg_hw msm8937_config = { }; static const struct mdp5_cfg_handler cfg_handlers_v1[] = { - { .revision = 0, .config = { .hw = &msm8x74v1_config } }, { .revision = 1, .config = { .hw = &msm8x26_config } }, - { .revision = 2, .config = { .hw = &msm8x74v2_config } }, + { .revision = 2, .config = { .hw = &msm8x74_config } }, { .revision = 3, .config = { .hw = &apq8084_config } }, { .revision = 6, .config = { .hw = &msm8x16_config } }, { .revision = 8, .config = { .hw = &msm8x36_config } }, diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c index fc183fe37f56..1eca140616c6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c @@ -17,9 +17,6 @@ * a specific data path ID - REG_MDP5_CTL_*(<id>, ...) * * Hardware capabilities determine the number of concurrent data paths - * - * In certain use cases (high-resolution dual pipe), one single CTL can be - * shared across multiple CRTCs. */ #define CTL_STAT_BUSY 0x1 @@ -46,11 +43,6 @@ struct mdp5_ctl { u32 pending_ctl_trigger; bool cursor_on; - - /* True if the current CTL has FLUSH bits pending for single FLUSH. */ - bool flush_pending; - - struct mdp5_ctl *pair; /* Paired CTL to be flushed together */ }; struct mdp5_ctl_manager { @@ -63,10 +55,6 @@ struct mdp5_ctl_manager { /* to filter out non-present bits in the current hardware config */ u32 flush_hw_mask; - /* status for single FLUSH */ - bool single_flush_supported; - u32 single_flush_pending_mask; - /* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */ spinlock_t pool_lock; struct mdp5_ctl ctls[MAX_CTL]; @@ -485,31 +473,6 @@ static u32 fix_sw_flush(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, return sw_mask; } -static void fix_for_single_flush(struct mdp5_ctl *ctl, u32 *flush_mask, - u32 *flush_id) -{ - struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; - - if (ctl->pair) { - DBG("CTL %d FLUSH pending mask %x", ctl->id, *flush_mask); - ctl->flush_pending = true; - ctl_mgr->single_flush_pending_mask |= (*flush_mask); - *flush_mask = 0; - - if (ctl->pair->flush_pending) { - *flush_id = min_t(u32, ctl->id, ctl->pair->id); - *flush_mask = ctl_mgr->single_flush_pending_mask; - - ctl->flush_pending = false; - ctl->pair->flush_pending = false; - ctl_mgr->single_flush_pending_mask = 0; - - DBG("Single FLUSH mask %x,ID %d", *flush_mask, - *flush_id); - } - } -} - /** * mdp5_ctl_commit() - Register Flush * @@ -555,8 +518,6 @@ u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, curr_ctl_flush_mask = flush_mask; - fix_for_single_flush(ctl, &flush_mask, &flush_id); - if (!start) { ctl->flush_mask |= flush_mask; return curr_ctl_flush_mask; @@ -589,40 +550,6 @@ int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl) } /* - * mdp5_ctl_pair() - Associate 2 booked CTLs for single FLUSH - */ -int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable) -{ - struct mdp5_ctl_manager *ctl_mgr = ctlx->ctlm; - struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr); - - /* do nothing silently if hw doesn't support */ - if (!ctl_mgr->single_flush_supported) - return 0; - - if (!enable) { - ctlx->pair = NULL; - ctly->pair = NULL; - mdp5_write(mdp5_kms, REG_MDP5_SPARE_0, 0); - return 0; - } else if ((ctlx->pair != NULL) || (ctly->pair != NULL)) { - DRM_DEV_ERROR(ctl_mgr->dev->dev, "CTLs already paired\n"); - return -EINVAL; - } else if (!(ctlx->status & ctly->status & CTL_STAT_BOOKED)) { - DRM_DEV_ERROR(ctl_mgr->dev->dev, "Only pair booked CTLs\n"); - return -EINVAL; - } - - ctlx->pair = ctly; - ctly->pair = ctlx; - - mdp5_write(mdp5_kms, REG_MDP5_SPARE_0, - MDP5_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN); - - return 0; -} - -/* * mdp5_ctl_request() - CTL allocation * * Try to return booked CTL for @intf_num is 1 or 2, unbooked for other INTFs. @@ -687,8 +614,6 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, { struct mdp5_ctl_manager *ctl_mgr; const struct mdp5_cfg_hw *hw_cfg = mdp5_cfg_get_hw_config(cfg_hnd); - int rev = mdp5_cfg_get_hw_rev(cfg_hnd); - unsigned dsi_cnt = 0; const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl; unsigned long flags; int c, ret; @@ -730,21 +655,6 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, spin_lock_init(&ctl->hw_lock); } - /* - * In bonded DSI case, CTL0 and CTL1 are always assigned to two DSI - * interfaces to support single FLUSH feature (Flush CTL0 and CTL1 when - * only write into CTL0's FLUSH register) to keep two DSI pipes in sync. - * Single FLUSH is supported from hw rev v3.0. - */ - for (c = 0; c < ARRAY_SIZE(hw_cfg->intf.connect); c++) - if (hw_cfg->intf.connect[c] == INTF_DSI) - dsi_cnt++; - if ((rev >= 3) && (dsi_cnt > 1)) { - ctl_mgr->single_flush_supported = true; - /* Reserve CTL0/1 for INTF1/2 */ - ctl_mgr->ctls[0].status |= CTL_STAT_BOOKED; - ctl_mgr->ctls[1].status |= CTL_STAT_BOOKED; - } spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags); DBG("Pool of %d CTLs created.", ctl_mgr->nctl); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h index 9020e8efc4e4..0c45f7874c24 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h @@ -35,7 +35,6 @@ int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, struct mdp5_pipeline *p, int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, int cursor_id, bool enable); -int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable); #define MAX_PIPE_STAGE 2 diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 1e3dc9bf9494..2d26b07b06f5 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -717,7 +717,6 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) mdp5_kms->dev = dev; drm_atomic_private_obj_init(mdp5_kms->dev, &mdp5_kms->glob_state, - NULL, &mdp5_global_state_funcs); /* we need to set a default rate before enabling. Set a safe diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index 500b7dc895d0..890d2f31510e 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c @@ -118,8 +118,6 @@ uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, u32 width, bool hdecim) { const struct drm_format_info *info = drm_format_info(format->pixel_format); - struct mdp5_kms *mdp5_kms = get_kms(smp); - int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg); int i, hsub, nplanes, nlines; uint32_t blkcfg = 0; @@ -133,7 +131,7 @@ uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, * U and V components (splits them from Y if necessary) and packs * them together, writes to SMP using a single client. */ - if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) { + if (format->chroma_sample > CHROMA_FULL) { nplanes = 2; /* if decimation is enabled, HW decimates less on the @@ -151,10 +149,6 @@ uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size); - /* for hw rev v1.00 */ - if (rev == 0) - n = roundup_pow_of_two(n); - blkcfg |= (n << (8 * i)); } diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index ef298c7d3e5e..cba8a71a2561 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1928,9 +1928,6 @@ void msm_dp_ctrl_phy_init(struct msm_dp_ctrl *msm_dp_ctrl) msm_dp_ctrl_phy_reset(ctrl); phy_init(phy); - - drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); } void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl) @@ -1943,8 +1940,6 @@ void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl) msm_dp_ctrl_phy_reset(ctrl); phy_exit(phy); - drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); } static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl) @@ -1996,8 +1991,6 @@ static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl) phy_exit(phy); phy_init(phy); - drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); return 0; } @@ -2588,9 +2581,6 @@ void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl) /* aux channel down, reinit phy */ phy_exit(phy); phy_init(phy); - - drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); } void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl) @@ -2606,13 +2596,7 @@ void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl) dev_pm_opp_set_rate(ctrl->dev, 0); msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); - DRM_DEBUG_DP("Before, phy=%p init_count=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); - phy_power_off(phy); - - DRM_DEBUG_DP("After, phy=%p init_count=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); } void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl) @@ -2638,8 +2622,6 @@ void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl) msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); phy_power_off(phy); - drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); } irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 476848bf8cd1..d2124d625485 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -210,6 +210,7 @@ static const struct of_device_id msm_dp_dt_match[] = { { .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 }, {} }; +MODULE_DEVICE_TABLE(of, msm_dp_dt_match); static struct msm_dp_display_private *dev_get_dp_display_private(struct device *dev) { diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index d8bb40ef820e..3c9f01ed6271 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -198,6 +198,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "qcom,dsi-ctrl-6g-qcm2290" }, {} }; +MODULE_DEVICE_TABLE(of, dt_match); static const struct dev_pm_ops dsi_pm_ops = { SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index bd3c51c350e7..da3fe6824495 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -317,10 +317,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, + &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, - {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, - &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index 5dc812028bd5..ccf06679608e 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -19,8 +19,8 @@ #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 +#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 -#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 #define MSM_DSI_6G_VER_MINOR_V2_3_1 0x20030001 diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index e0de545d4077..565d425f88b8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -569,6 +569,7 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) * dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case * @mode: The selected mode for the DSI output * @dsc: DRM DSC configuration for this DSI output + * @is_bonded_dsi: True if two DSI controllers are bonded * * Adjust the pclk rate by calculating a new hdisplay proportional to * the compression ratio such that: @@ -584,13 +585,30 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) * FIXME: Reconsider this if/when CMD mode handling is rewritten to use * transfer time and data overhead as a starting point of the calculations. */ -static unsigned long dsi_adjust_pclk_for_compression(const struct drm_display_mode *mode, - const struct drm_dsc_config *dsc) +static unsigned long +dsi_adjust_pclk_for_compression(const struct drm_display_mode *mode, + const struct drm_dsc_config *dsc, + bool is_bonded_dsi) { - int new_hdisplay = DIV_ROUND_UP(mode->hdisplay * drm_dsc_get_bpp_int(dsc), - dsc->bits_per_component * 3); + int hdisplay, new_hdisplay, new_htotal; - int new_htotal = mode->htotal - mode->hdisplay + new_hdisplay; + /* + * For bonded DSI, split hdisplay across two links and round up each + * half separately, passing the full hdisplay would only round up once. + * This also aligns with the hdisplay we program later in + * dsi_timing_setup() + */ + hdisplay = mode->hdisplay; + if (is_bonded_dsi) + hdisplay /= 2; + + new_hdisplay = DIV_ROUND_UP(hdisplay * drm_dsc_get_bpp_int(dsc), + dsc->bits_per_component * 3); + + if (is_bonded_dsi) + new_hdisplay *= 2; + + new_htotal = mode->htotal - mode->hdisplay + new_hdisplay; return mult_frac(mode->clock * 1000u, new_htotal, mode->htotal); } @@ -603,7 +621,7 @@ static unsigned long dsi_get_pclk_rate(const struct drm_display_mode *mode, pclk_rate = mode->clock * 1000u; if (dsc) - pclk_rate = dsi_adjust_pclk_for_compression(mode, dsc); + pclk_rate = dsi_adjust_pclk_for_compression(mode, dsc, is_bonded_dsi); /* * For bonded DSI mode, the current DRM mode has the complete width of the @@ -740,6 +758,7 @@ static inline enum dsi_vid_dst_format dsi_get_vid_fmt(const enum mipi_dsi_pixel_format mipi_fmt) { switch (mipi_fmt) { + case MIPI_DSI_FMT_RGB101010: return VID_DST_FORMAT_RGB101010; case MIPI_DSI_FMT_RGB888: return VID_DST_FORMAT_RGB888; case MIPI_DSI_FMT_RGB666: return VID_DST_FORMAT_RGB666_LOOSE; case MIPI_DSI_FMT_RGB666_PACKED: return VID_DST_FORMAT_RGB666; @@ -752,6 +771,7 @@ static inline enum dsi_cmd_dst_format dsi_get_cmd_fmt(const enum mipi_dsi_pixel_format mipi_fmt) { switch (mipi_fmt) { + case MIPI_DSI_FMT_RGB101010: return CMD_DST_FORMAT_RGB101010; case MIPI_DSI_FMT_RGB888: return CMD_DST_FORMAT_RGB888; case MIPI_DSI_FMT_RGB666_PACKED: case MIPI_DSI_FMT_RGB666: return CMD_DST_FORMAT_RGB666; @@ -765,13 +785,21 @@ static void dsi_ctrl_disable(struct msm_dsi_host *msm_host) dsi_write(msm_host, REG_DSI_CTRL, 0); } +static bool msm_dsi_host_version_geq(struct msm_dsi_host *msm_host, + u32 major, u32 minor) +{ + return msm_host->cfg_hnd->major > major || + (msm_host->cfg_hnd->major == major && + msm_host->cfg_hnd->minor >= minor); +} + bool msm_dsi_host_is_wide_bus_enabled(struct mipi_dsi_host *host) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); return msm_host->dsc && - (msm_host->cfg_hnd->major == MSM_DSI_VER_MAJOR_6G && - msm_host->cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V2_5_0); + msm_dsi_host_version_geq(msm_host, MSM_DSI_VER_MAJOR_6G, + MSM_DSI_6G_VER_MINOR_V2_5_0); } static void dsi_ctrl_enable(struct msm_dsi_host *msm_host, @@ -993,7 +1021,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) if (msm_host->dsc) { struct drm_dsc_config *dsc = msm_host->dsc; - u32 bytes_per_pclk; + u32 bits_per_pclk; /* update dsc params with timing params */ if (!dsc || !mode->hdisplay || !mode->vdisplay) { @@ -1015,7 +1043,10 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) /* * DPU sends 3 bytes per pclk cycle to DSI. If widebus is - * enabled, bus width is extended to 6 bytes. + * enabled, MDP always sends out 48-bit compressed data per + * pclk and on average, for video mode, DSI consumes only an + * amount of compressed data equivalent to the uncompressed + * pixel depth per pclk. * * Calculate the number of pclks needed to transmit one line of * the compressed data. @@ -1027,12 +1058,16 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) * unused anyway. */ h_total -= hdisplay; - if (wide_bus_enabled && !(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO)) - bytes_per_pclk = 6; - else - bytes_per_pclk = 3; + if (wide_bus_enabled) { + if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) + bits_per_pclk = dsc->bits_per_component * 3; + else + bits_per_pclk = 48; + } else { + bits_per_pclk = 24; + } - hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc), bytes_per_pclk); + hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc) * 8, bits_per_pclk); h_total += hdisplay; ha_end = ha_start + hdisplay; @@ -1686,6 +1721,26 @@ static int dsi_host_attach(struct mipi_dsi_host *host, if (dsi->dsc) msm_host->dsc = dsi->dsc; + if (msm_host->format == MIPI_DSI_FMT_RGB101010) { + if (!msm_dsi_host_version_geq(msm_host, MSM_DSI_VER_MAJOR_6G, + MSM_DSI_6G_VER_MINOR_V2_1_0)) { + DRM_DEV_ERROR(&msm_host->pdev->dev, + "RGB101010 not supported on this DSI controller\n"); + return -EINVAL; + } + + /* + * Downstream overrides RGB101010 back to RGB888 when DSC is enabled + * but widebus is not. Using RGB101010 in this case may require some + * extra changes. + */ + if (msm_host->dsc && + !msm_dsi_host_is_wide_bus_enabled(&msm_host->base)) { + dev_warn(&msm_host->pdev->dev, + "RGB101010 with DSC but without widebus, may need extra changes\n"); + } + } + ret = dsi_dev_attach(msm_host->pdev); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 7937266de1d2..c59375aaae19 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -582,6 +582,7 @@ static const struct of_device_id dsi_phy_dt_match[] = { #endif {} }; +MODULE_DEVICE_TABLE(of, dsi_phy_dt_match); /* * Currently, we only support one SoC for each PHY type. When we have multiple diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c index 8cb0db3a9880..8f4b03713f25 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -41,8 +41,8 @@ #define VCO_REF_CLK_RATE 19200000 #define FRAC_BITS 18 -/* Hardware is pre V4.1 */ -#define DSI_PHY_7NM_QUIRK_PRE_V4_1 BIT(0) +/* Hardware is V4.0 */ +#define DSI_PHY_7NM_QUIRK_V4_0 BIT(0) /* Hardware is V4.1 */ #define DSI_PHY_7NM_QUIRK_V4_1 BIT(1) /* Hardware is V4.2 */ @@ -51,8 +51,8 @@ #define DSI_PHY_7NM_QUIRK_V4_3 BIT(3) /* Hardware is V5.2 */ #define DSI_PHY_7NM_QUIRK_V5_2 BIT(4) -/* Hardware is V7.0 */ -#define DSI_PHY_7NM_QUIRK_V7_0 BIT(5) +/* Hardware is V7.2 */ +#define DSI_PHY_7NM_QUIRK_V7_2 BIT(5) struct dsi_pll_config { bool enable_ssc; @@ -141,9 +141,9 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config dec_multiple = div_u64(pll_freq * multiplier, divider); dec = div_u64_rem(dec_multiple, multiplier, &frac); - if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1) { + if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_0) { config->pll_clock_inverters = 0x28; - } else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) { + } else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) { if (pll_freq < 163000000ULL) config->pll_clock_inverters = 0xa0; else if (pll_freq < 175000000ULL) @@ -264,7 +264,7 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) void __iomem *base = pll->phy->pll_base; u8 analog_controls_five_1 = 0x01, vco_config_1 = 0x00; - if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)) + if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_0)) if (pll->vco_current_rate >= 3100000000ULL) analog_controls_five_1 = 0x03; @@ -284,7 +284,7 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) } if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) || - (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) { + (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) { if (pll->vco_current_rate < 1557000000ULL) vco_config_1 = 0x08; else @@ -313,10 +313,10 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) writel(0x29, base + REG_DSI_7nm_PHY_PLL_PFILT); writel(0x2f, base + REG_DSI_7nm_PHY_PLL_PFILT); writel(0x2a, base + REG_DSI_7nm_PHY_PLL_IFILT); - writel(!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1) ? 0x3f : 0x22, + writel(!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_0) ? 0x3f : 0x22, base + REG_DSI_7nm_PHY_PLL_IFILT); - if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)) { + if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_0)) { writel(0x22, base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE); if (pll->slave) writel(0x22, pll->slave->phy->pll_base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE); @@ -699,7 +699,7 @@ static int dsi_7nm_set_usecase(struct msm_dsi_phy *phy) case MSM_DSI_PHY_MASTER: pll_7nm->slave = pll_7nm_list[(pll_7nm->phy->id + 1) % DSI_MAX]; /* v7.0: Enable ATB_EN0 and alternate clock output to external phy */ - if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0) + if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2) writel(0x07, base + REG_DSI_7nm_PHY_CMN_CTRL_5); break; case MSM_DSI_PHY_SLAVE: @@ -928,7 +928,7 @@ static void dsi_phy_hw_v4_0_lane_settings(struct msm_dsi_phy *phy) const u8 *tx_dctrl = tx_dctrl_0; void __iomem *lane_base = phy->lane_base; - if (!(phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)) + if (!(phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_0)) tx_dctrl = tx_dctrl_1; /* Strength ctrl settings */ @@ -987,7 +987,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, /* Request for REFGEN READY */ if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) || (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) || - (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) { + (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) { writel(0x1, phy->base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10); udelay(500); } @@ -1021,7 +1021,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, lane_ctrl0 = 0x1f; } - if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) { + if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) { if (phy->cphy_mode) { /* TODO: different for second phy */ vreg_ctrl_0 = 0x57; @@ -1097,7 +1097,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, /* program CMN_CTRL_4 for minor_ver 2 chipsets*/ if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) || - (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0) || + (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2) || (readl(base + REG_DSI_7nm_PHY_CMN_REVISION_ID0) & (0xf0)) == 0x20) writel(0x04, base + REG_DSI_7nm_PHY_CMN_CTRL_4); @@ -1213,7 +1213,7 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy) /* Turn off REFGEN Vote */ if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) || (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) || - (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) { + (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) { writel(0x0, base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10); wmb(); /* Delay to ensure HW removes vote before PHY shut down */ @@ -1319,7 +1319,7 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = { .max_pll_rate = 3500000000UL, .io_start = { 0xae94400, 0xae96400 }, .num_dsi_phy = 2, - .quirks = DSI_PHY_7NM_QUIRK_PRE_V4_1, + .quirks = DSI_PHY_7NM_QUIRK_V4_0, }; const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs = { @@ -1502,7 +1502,7 @@ const struct msm_dsi_phy_cfg dsi_phy_3nm_8750_cfgs = { #endif .io_start = { 0xae95000, 0xae97000 }, .num_dsi_phy = 2, - .quirks = DSI_PHY_7NM_QUIRK_V7_0, + .quirks = DSI_PHY_7NM_QUIRK_V7_2, }; const struct msm_dsi_phy_cfg dsi_phy_3nm_kaanapali_cfgs = { @@ -1525,5 +1525,5 @@ const struct msm_dsi_phy_cfg dsi_phy_3nm_kaanapali_cfgs = { #endif .io_start = { 0x9ac1000, 0x9ac4000 }, .num_dsi_phy = 2, - .quirks = DSI_PHY_7NM_QUIRK_V7_0, + .quirks = DSI_PHY_7NM_QUIRK_V7_2, }; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 5afac09c0d33..852abb2466f0 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -20,7 +20,7 @@ void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on) { - uint32_t ctrl = 0; + u32 ctrl = 0; unsigned long flags; spin_lock_irqsave(&hdmi->reg_lock, flags); @@ -91,7 +91,7 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi) struct platform_device *phy_pdev; struct device_node *phy_node; - phy_node = of_parse_phandle(pdev->dev.of_node, "phys", 0); + phy_node = of_parse_phandle(dev_of_node(&pdev->dev), "phys", 0); if (!phy_node) { DRM_DEV_ERROR(&pdev->dev, "cannot find phy device\n"); return -ENXIO; @@ -278,7 +278,7 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) if (!config) return -EINVAL; - hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; @@ -287,7 +287,7 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) spin_lock_init(&hdmi->reg_lock); mutex_init(&hdmi->state_mutex); - ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge); + ret = drm_of_find_panel_or_bridge(dev_of_node(dev), 1, 0, NULL, &hdmi->next_bridge); if (ret && ret != -ENODEV) return ret; @@ -304,7 +304,7 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) hdmi->qfprom_mmio = msm_ioremap(pdev, "qfprom_physical"); if (IS_ERR(hdmi->qfprom_mmio)) { - DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n"); + DRM_DEV_INFO(dev, "can't find qfprom resource\n"); hdmi->qfprom_mmio = NULL; } @@ -312,8 +312,7 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) if (hdmi->irq < 0) return hdmi->irq; - hdmi->pwr_regs = devm_kcalloc(&pdev->dev, - config->pwr_reg_cnt, + hdmi->pwr_regs = devm_kcalloc(dev, config->pwr_reg_cnt, sizeof(hdmi->pwr_regs[0]), GFP_KERNEL); if (!hdmi->pwr_regs) @@ -322,12 +321,11 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) for (i = 0; i < config->pwr_reg_cnt; i++) hdmi->pwr_regs[i].supply = config->pwr_reg_names[i]; - ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs); + ret = devm_regulator_bulk_get(dev, config->pwr_reg_cnt, hdmi->pwr_regs); if (ret) return dev_err_probe(dev, ret, "failed to get pwr regulators\n"); - hdmi->pwr_clks = devm_kcalloc(&pdev->dev, - config->pwr_clk_cnt, + hdmi->pwr_clks = devm_kcalloc(dev, config->pwr_clk_cnt, sizeof(hdmi->pwr_clks[0]), GFP_KERNEL); if (!hdmi->pwr_clks) @@ -336,16 +334,16 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) for (i = 0; i < config->pwr_clk_cnt; i++) hdmi->pwr_clks[i].id = config->pwr_clk_names[i]; - ret = devm_clk_bulk_get(&pdev->dev, config->pwr_clk_cnt, hdmi->pwr_clks); + ret = devm_clk_bulk_get(dev, config->pwr_clk_cnt, hdmi->pwr_clks); if (ret) return ret; - hdmi->extp_clk = devm_clk_get_optional(&pdev->dev, "extp"); + hdmi->extp_clk = devm_clk_get_optional(dev, "extp"); if (IS_ERR(hdmi->extp_clk)) return dev_err_probe(dev, PTR_ERR(hdmi->extp_clk), "failed to get extp clock\n"); - hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); + hdmi->hpd_gpiod = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); /* This will catch e.g. -EPROBE_DEFER */ if (IS_ERR(hdmi->hpd_gpiod)) return dev_err_probe(dev, PTR_ERR(hdmi->hpd_gpiod), @@ -358,18 +356,16 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD"); ret = msm_hdmi_get_phy(hdmi); - if (ret) { - DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n"); + if (ret) return ret; - } - ret = devm_pm_runtime_enable(&pdev->dev); + ret = devm_pm_runtime_enable(dev); if (ret) goto err_put_phy; platform_set_drvdata(pdev, hdmi); - ret = component_add(&pdev->dev, &msm_hdmi_ops); + ret = component_add(dev, &msm_hdmi_ops); if (ret) goto err_put_phy; @@ -429,7 +425,7 @@ fail: return ret; } -DEFINE_RUNTIME_DEV_PM_OPS(msm_hdmi_pm_ops, msm_hdmi_runtime_suspend, msm_hdmi_runtime_resume, NULL); +static DEFINE_RUNTIME_DEV_PM_OPS(msm_hdmi_pm_ops, msm_hdmi_runtime_suspend, msm_hdmi_runtime_resume, NULL); static const struct of_device_id msm_hdmi_dt_match[] = { { .compatible = "qcom,hdmi-tx-8998", .data = &hdmi_tx_8974_config }, @@ -441,6 +437,7 @@ static const struct of_device_id msm_hdmi_dt_match[] = { { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8960_config }, {} }; +MODULE_DEVICE_TABLE(of, msm_hdmi_dt_match); static struct platform_driver msm_hdmi_driver = { .probe = msm_hdmi_dev_probe, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 02cfd46df594..49433f7727c3 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -43,7 +43,7 @@ struct hdmi { bool power_on; bool hpd_enabled; struct mutex state_mutex; /* protects two booleans */ - unsigned long int pixclock; + unsigned long pixclock; void __iomem *mmio; void __iomem *qfprom_mmio; @@ -132,7 +132,7 @@ enum hdmi_phy_type { struct hdmi_phy_cfg { enum hdmi_phy_type type; - void (*powerup)(struct hdmi_phy *phy, unsigned long int pixclock); + void (*powerup)(struct hdmi_phy *phy, unsigned long pixclock); void (*powerdown)(struct hdmi_phy *phy); const char * const *reg_names; int num_regs; @@ -167,7 +167,7 @@ static inline u32 hdmi_phy_read(struct hdmi_phy *phy, u32 reg) int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy); void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy); -void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long int pixclock); +void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long pixclock); void msm_hdmi_phy_powerdown(struct hdmi_phy *phy); void __init msm_hdmi_phy_driver_register(void); void __exit msm_hdmi_phy_driver_unregister(void); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c index d9a8dc9dae8f..249c167ab04d 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c @@ -17,8 +17,7 @@ int msm_hdmi_audio_update(struct hdmi *hdmi) { struct hdmi_audio *audio = &hdmi->audio; bool enabled = audio->enabled; - uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl; - uint32_t audio_config; + u32 acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl, audio_config; if (!hdmi->connector->display_info.is_hdmi) return -EINVAL; @@ -43,7 +42,7 @@ int msm_hdmi_audio_update(struct hdmi *hdmi) acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SELECT__MASK; if (enabled) { - uint32_t n, cts, multiplier; + u32 n, cts, multiplier; enum hdmi_acr_cts select; drm_hdmi_acr_get_n_cts(hdmi->pixclock, audio->rate, &n, &cts); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 98cd490e7ab0..a9eb6489c520 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -153,7 +153,7 @@ static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge, for (i = 0; i < ARRAY_SIZE(buf); i++) hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]); - val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); val |= HDMI_INFOFRAME_CTRL0_AVI_SEND | HDMI_INFOFRAME_CTRL0_AVI_CONT; hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); @@ -193,7 +193,7 @@ static int msm_hdmi_bridge_write_audio_infoframe(struct drm_bridge *bridge, buffer[9] << 16 | buffer[10] << 24); - val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND | HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT | HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE | @@ -356,7 +356,7 @@ static void msm_hdmi_set_timings(struct hdmi *hdmi, const struct drm_display_mode *mode) { int hstart, hend, vstart, vend; - uint32_t frame_ctrl; + u32 frame_ctrl; hstart = mode->htotal - mode->hsync_start; hend = mode->htotal - mode->hsync_start + mode->hdisplay; @@ -409,7 +409,7 @@ static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridg struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = hdmi_bridge->hdmi; const struct drm_edid *drm_edid; - uint32_t hdmi_ctrl; + u32 hdmi_ctrl; hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL); hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_hpd.c b/drivers/gpu/drm/msm/hdmi/hdmi_hpd.c index 114b0d507700..2cccd9062584 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_hpd.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_hpd.c @@ -65,7 +65,7 @@ void msm_hdmi_hpd_enable(struct drm_bridge *bridge) struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = hdmi_bridge->hdmi; struct device *dev = &hdmi->pdev->dev; - uint32_t hpd_ctrl; + u32 hpd_ctrl; int ret; unsigned long flags; @@ -125,7 +125,7 @@ void msm_hdmi_hpd_irq(struct drm_bridge *bridge) { struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = hdmi_bridge->hdmi; - uint32_t hpd_int_status, hpd_int_ctrl; + u32 hpd_int_status, hpd_int_ctrl; /* Process HPD: */ hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c index 6b9265159195..4a4a2cf90234 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c @@ -40,8 +40,8 @@ static int ddc_clear_irq(struct hdmi_i2c_adapter *hdmi_i2c) { struct hdmi *hdmi = hdmi_i2c->hdmi; struct drm_device *dev = hdmi->dev; - uint32_t retry = 0xffff; - uint32_t ddc_int_ctrl; + u32 retry = 0xffff; + u32 ddc_int_ctrl; do { --retry; @@ -71,7 +71,7 @@ static bool sw_done(struct hdmi_i2c_adapter *hdmi_i2c) struct hdmi *hdmi = hdmi_i2c->hdmi; if (!hdmi_i2c->sw_done) { - uint32_t ddc_int_ctrl; + u32 ddc_int_ctrl; ddc_int_ctrl = hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL); @@ -92,13 +92,13 @@ static int msm_hdmi_i2c_xfer(struct i2c_adapter *i2c, struct hdmi_i2c_adapter *hdmi_i2c = to_hdmi_i2c_adapter(i2c); struct hdmi *hdmi = hdmi_i2c->hdmi; struct drm_device *dev = hdmi->dev; - static const uint32_t nack[] = { + static const u32 nack[] = { HDMI_DDC_SW_STATUS_NACK0, HDMI_DDC_SW_STATUS_NACK1, HDMI_DDC_SW_STATUS_NACK2, HDMI_DDC_SW_STATUS_NACK3, }; int indices[MAX_TRANSACTIONS]; int ret, i, j, index = 0; - uint32_t ddc_status, ddc_data, i2c_trans; + u32 ddc_status, ddc_data, i2c_trans; num = min(num, MAX_TRANSACTIONS); @@ -119,7 +119,7 @@ static int msm_hdmi_i2c_xfer(struct i2c_adapter *i2c, for (i = 0; i < num; i++) { struct i2c_msg *p = &msgs[i]; - uint32_t raw_addr = p->addr << 1; + u32 raw_addr = p->addr << 1; if (p->flags & I2C_M_RD) raw_addr |= 1; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 667573f1db7c..eb1088755cb3 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -94,7 +94,7 @@ void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy) pm_runtime_put_sync(dev); } -void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long int pixclock) +void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long pixclock) { if (!phy || !phy->cfg->powerup) return; @@ -204,6 +204,7 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = { .data = &msm_hdmi_phy_8998_cfg }, {} }; +MODULE_DEVICE_TABLE(of, msm_hdmi_phy_dt_match); static struct platform_driver msm_hdmi_phy_platform_driver = { .probe = msm_hdmi_phy_probe, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c index cf90a0c1f822..cfa8fc494199 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c @@ -7,7 +7,7 @@ #include "hdmi.h" static void hdmi_phy_8960_powerup(struct hdmi_phy *phy, - unsigned long int pixclock) + unsigned long pixclock) { DBG("pixclock: %lu", pixclock); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c index 1d97640d8c24..10ee91818364 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c @@ -9,7 +9,7 @@ #include "hdmi.h" static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy, - unsigned long int pixclock) + unsigned long pixclock) { /* De-serializer delay D/C for non-lbk mode: */ hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG0, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c index a2a6940e195a..6f40820d9071 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c @@ -7,7 +7,7 @@ #include "hdmi.h" static void hdmi_phy_8x74_powerup(struct hdmi_phy *phy, - unsigned long int pixclock) + unsigned long pixclock) { hdmi_phy_write(phy, REG_HDMI_8x74_ANA_CFG0, 0x1b); hdmi_phy_write(phy, REG_HDMI_8x74_ANA_CFG1, 0xf2); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index e5ab1e28851d..195f40e331e5 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -536,6 +536,11 @@ static int msm_ioctl_gem_info_get_metadata(struct drm_gem_object *obj, len = msm_obj->metadata_size; buf = kmemdup(msm_obj->metadata, len, GFP_KERNEL); + if (!buf) { + msm_gem_unlock(obj); + return -ENOMEM; + } + msm_gem_unlock(obj); if (*metadata_size < len) { @@ -548,7 +553,7 @@ static int msm_ioctl_gem_info_get_metadata(struct drm_gem_object *obj, kfree(buf); - return 0; + return ret; } static int msm_ioctl_gem_info(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index b3fdb83202ab..9b681e144c07 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -219,7 +219,12 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, + mode_cmd->offsets[i]; if (bos[i]->size < min_size) { - ret = -EINVAL; + ret = UERR(EINVAL, dev, "plane %d too small", i); + goto fail; + } + + if (to_msm_bo(bos[i])->flags & MSM_BO_NO_SHARE) { + ret = UERR(EINVAL, dev, "Cannot map _NO_SHARE to kms vm"); goto fail; } diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index b27abaa13926..2cb3ab04f125 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -507,8 +507,11 @@ void msm_gem_unpin_locked(struct drm_gem_object *obj) */ void msm_gem_unpin_active(struct drm_gem_object *obj) { + struct msm_drm_private *priv = obj->dev->dev_private; struct msm_gem_object *msm_obj = to_msm_bo(obj); + GEM_WARN_ON(!mutex_is_locked(&priv->lru.lock)); + msm_obj->pin_count--; GEM_WARN_ON(msm_obj->pin_count < 0); update_lru_active(obj); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index cb32093fda47..762e546d25ef 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -452,6 +452,7 @@ struct msm_gem_submit { bool bos_pinned : 1; bool fault_dumped:1;/* Limit devcoredump dumping to one per submit */ bool in_rb : 1; /* "sudo" mode, copy cmds into RB */ + bool has_exec : 1; /* @exec is initialized. */ struct msm_ringbuffer *ring; unsigned int nr_cmds; unsigned int nr_bos; diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 1039e3c0a47b..31fa51a44f86 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -26,9 +26,8 @@ static bool can_swap(void) static bool can_block(struct shrink_control *sc) { - if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM)) - return false; - return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); + return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) || + (current_is_kswapd() && (sc->gfp_mask & __GFP_KSWAPD_RECLAIM)); } static unsigned long diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 75d9f3574370..26ea8a28be47 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -278,6 +278,7 @@ static int submit_lock_objects_vmbind(struct msm_gem_submit *submit) int ret = 0; drm_exec_init(&submit->exec, flags, submit->nr_bos); + submit->has_exec = true; drm_exec_until_all_locked (&submit->exec) { ret = drm_gpuvm_prepare_vm(submit->vm, exec, 1); @@ -304,6 +305,7 @@ static int submit_lock_objects(struct msm_gem_submit *submit) return submit_lock_objects_vmbind(submit); drm_exec_init(&submit->exec, flags, submit->nr_bos); + submit->has_exec = true; drm_exec_until_all_locked (&submit->exec) { ret = drm_exec_lock_obj(&submit->exec, @@ -523,7 +525,7 @@ static void submit_cleanup(struct msm_gem_submit *submit, bool error) if (error) submit_unpin_objects(submit); - if (submit->exec.objects) + if (submit->has_exec) drm_exec_fini(&submit->exec); /* if job wasn't enqueued to scheduler, early retirement: */ diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index adf88cf8f41a..1a952b171ed7 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -373,6 +373,12 @@ msm_gem_vma_new(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj, struct msm_gem_vma *vma; int ret; + /* _NO_SHARE objs cannot be mapped outside of their "host" vm: */ + if (obj && (to_msm_bo(obj)->flags & MSM_BO_NO_SHARE) && + GEM_WARN_ON(obj->resv != drm_gpuvm_resv(gpuvm))) { + return ERR_PTR(-EINVAL); + } + drm_gpuvm_resv_assert_held(&vm->base); vma = kzalloc_obj(*vma); @@ -696,6 +702,7 @@ static struct dma_fence * msm_vma_job_run(struct drm_sched_job *_job) { struct msm_vm_bind_job *job = to_msm_vm_bind_job(_job); + struct msm_drm_private *priv = job->vm->drm->dev_private; struct msm_gem_vm *vm = to_msm_vm(job->vm); struct drm_gem_object *obj; int ret = vm->unusable ? -EINVAL : 0; @@ -738,12 +745,14 @@ msm_vma_job_run(struct drm_sched_job *_job) if (ret) msm_gem_vm_unusable(job->vm); + mutex_lock(&priv->lru.lock); + job_foreach_bo (obj, job) { - msm_gem_lock(obj); - msm_gem_unpin_locked(obj); - msm_gem_unlock(obj); + msm_gem_unpin_active(obj); } + mutex_unlock(&priv->lru.lock); + /* VM_BIND ops are synchronous, so no fence to wait on: */ return NULL; } @@ -1242,7 +1251,7 @@ vm_bind_job_lock_objects(struct msm_vm_bind_job *job, struct drm_exec *exec) case MSM_VM_BIND_OP_UNMAP: ret = drm_gpuvm_sm_unmap_exec_lock(job->vm, exec, op->iova, - op->obj_offset); + op->range); break; case MSM_VM_BIND_OP_MAP: case MSM_VM_BIND_OP_MAP_NULL: { diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 84d6c7f50c8d..930e54d1b0a7 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -17,6 +17,7 @@ #include <linux/string_helpers.h> #include <linux/devcoredump.h> #include <linux/sched/task.h> +#include <linux/sched/mm.h> /* * Power Management: @@ -468,6 +469,7 @@ static void recover_worker(struct kthread_work *work) struct msm_gem_submit *submit; struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); char *comm = NULL, *cmd = NULL; + unsigned int noreclaim_flag; struct task_struct *task; int i; @@ -505,6 +507,8 @@ static void recover_worker(struct kthread_work *work) msm_gem_vm_unusable(submit->vm); } + noreclaim_flag = memalloc_noreclaim_save(); + get_comm_cmdline(submit, &comm, &cmd); if (comm && cmd) { @@ -523,6 +527,8 @@ static void recover_worker(struct kthread_work *work) pm_runtime_get_sync(&gpu->pdev->dev); msm_gpu_crashstate_capture(gpu, submit, NULL, comm, cmd); + memalloc_noreclaim_restore(noreclaim_flag); + kfree(cmd); kfree(comm); @@ -546,32 +552,30 @@ static void recover_worker(struct kthread_work *work) msm_update_fence(ring->fctx, fence); } - if (msm_gpu_active(gpu)) { - /* retire completed submits, plus the one that hung: */ - retire_submits(gpu); + /* retire completed submits, plus the one that hung: */ + retire_submits(gpu); - gpu->funcs->recover(gpu); + gpu->funcs->recover(gpu); - /* - * Replay all remaining submits starting with highest priority - * ring - */ - for (i = 0; i < gpu->nr_rings; i++) { - struct msm_ringbuffer *ring = gpu->rb[i]; - unsigned long flags; + /* + * Replay all remaining submits starting with highest priority + * ring + */ + for (i = 0; i < gpu->nr_rings; i++) { + struct msm_ringbuffer *ring = gpu->rb[i]; + unsigned long flags; - spin_lock_irqsave(&ring->submit_lock, flags); - list_for_each_entry(submit, &ring->submits, node) { - /* - * If the submit uses an unusable vm make sure - * we don't actually run it - */ - if (to_msm_vm(submit->vm)->unusable) - submit->nr_cmds = 0; - gpu->funcs->submit(gpu, submit); - } - spin_unlock_irqrestore(&ring->submit_lock, flags); + spin_lock_irqsave(&ring->submit_lock, flags); + list_for_each_entry(submit, &ring->submits, node) { + /* + * If the submit uses an unusable vm make sure + * we don't actually run it + */ + if (to_msm_vm(submit->vm)->unusable) + submit->nr_cmds = 0; + gpu->funcs->submit(gpu, submit); } + spin_unlock_irqrestore(&ring->submit_lock, flags); } pm_runtime_put(&gpu->pdev->dev); @@ -587,6 +591,7 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ struct msm_gem_submit *submit; struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); char *comm = NULL, *cmd = NULL; + unsigned int noreclaim_flag; mutex_lock(&gpu->lock); @@ -594,6 +599,8 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ if (submit && submit->fault_dumped) goto resume_smmu; + noreclaim_flag = memalloc_noreclaim_save(); + if (submit) { get_comm_cmdline(submit, &comm, &cmd); @@ -609,6 +616,8 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ msm_gpu_crashstate_capture(gpu, submit, fault_info, comm, cmd); pm_runtime_put_sync(&gpu->pdev->dev); + memalloc_noreclaim_restore(noreclaim_flag); + kfree(cmd); kfree(comm); diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 9047e8d9ee89..90c3fa0681a0 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -262,6 +262,14 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss) icc_set_bw(msm_mdss->reg_bus_path, 0, msm_mdss->reg_bus_bw); + /* + * TODO: + * Previous users (e.g. the bootloader) may have left this clock at a high rate, which + * would remain set, as prepare_enable() doesn't reprogram it. This theoretically poses a + * risk of brownout, but realistically this path is almost exclusively excercised after the + * correct OPP has been set in one of the MDPn or DPU drivers, or during initial probe, + * before the RPM(H)PD sync_state is done. + */ ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks); if (ret) { dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret); @@ -560,6 +568,7 @@ static const struct msm_mdss_data data_153k6 = { static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,mdss", .data = &data_153k6 }, + { .compatible = "qcom,eliza-mdss", .data = &data_57k }, { .compatible = "qcom,glymur-mdss", .data = &data_57k }, { .compatible = "qcom,kaanapali-mdss", .data = &data_57k }, { .compatible = "qcom,msm8998-mdss", .data = &data_76k8 }, diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml index 3941e7510754..2309870f5031 100644 --- a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml +++ b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml @@ -5016,6 +5016,10 @@ by a particular renderpass/blit. <bitfield pos="1" name="LPAC" type="boolean"/> <bitfield pos="2" name="RAYTRACING" type="boolean"/> </reg32> + <reg32 offset="0x0405" name="CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS" variants="A8XX-"> + <bitfield high="8" low="0" name="FINALFREQLIMIT"/> + <bitfield pos="24" name="SOFTSKUDISABLED" type="boolean"/> + </reg32> </domain> </database> diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml index c4e00b1263cd..33404eb18fd0 100644 --- a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml +++ b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml @@ -141,8 +141,10 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> <reg32 offset="0x1f9f0" name="GMU_BOOT_KMD_LM_HANDSHAKE"/> <reg32 offset="0x1f957" name="GMU_LLM_GLM_SLEEP_CTRL"/> <reg32 offset="0x1f958" name="GMU_LLM_GLM_SLEEP_STATUS"/> - <reg32 offset="0x1f888" name="GMU_ALWAYS_ON_COUNTER_L"/> - <reg32 offset="0x1f889" name="GMU_ALWAYS_ON_COUNTER_H"/> + <reg32 offset="0x1f888" name="GMU_ALWAYS_ON_COUNTER_L" variants="A6XX-A7XX"/> + <reg32 offset="0x1f840" name="GMU_ALWAYS_ON_COUNTER_L" variants="A8XX-"/> + <reg32 offset="0x1f889" name="GMU_ALWAYS_ON_COUNTER_H" variants="A6XX-A7XX"/> + <reg32 offset="0x1f841" name="GMU_ALWAYS_ON_COUNTER_H" variants="A8XX-"/> <reg32 offset="0x1f8c3" name="GMU_GMU_PWR_COL_KEEPALIVE" variants="A6XX-A7XX"/> <reg32 offset="0x1f7e4" name="GMU_GMU_PWR_COL_KEEPALIVE" variants="A8XX-"/> <reg32 offset="0x1f8c4" name="GMU_PWR_COL_PREEMPT_KEEPALIVE" variants="A6XX-A7XX"/> diff --git a/drivers/gpu/drm/msm/registers/display/dsi.xml b/drivers/gpu/drm/msm/registers/display/dsi.xml index c7a7b633d747..e40125f75175 100644 --- a/drivers/gpu/drm/msm/registers/display/dsi.xml +++ b/drivers/gpu/drm/msm/registers/display/dsi.xml @@ -15,6 +15,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> <value name="VID_DST_FORMAT_RGB666" value="1"/> <value name="VID_DST_FORMAT_RGB666_LOOSE" value="2"/> <value name="VID_DST_FORMAT_RGB888" value="3"/> + <value name="VID_DST_FORMAT_RGB101010" value="4"/> </enum> <enum name="dsi_rgb_swap"> <value name="SWAP_RGB" value="0"/> @@ -39,6 +40,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> <value name="CMD_DST_FORMAT_RGB565" value="6"/> <value name="CMD_DST_FORMAT_RGB666" value="7"/> <value name="CMD_DST_FORMAT_RGB888" value="8"/> + <value name="CMD_DST_FORMAT_RGB101010" value="9"/> </enum> <enum name="dsi_lane_swap"> <value name="LANE_SWAP_0123" value="0"/> @@ -142,7 +144,8 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> </reg32> <reg32 offset="0x0000c" name="VID_CFG0"> <bitfield name="VIRT_CHANNEL" low="0" high="1" type="uint"/> <!-- always zero? --> - <bitfield name="DST_FORMAT" low="4" high="5" type="dsi_vid_dst_format"/> + <!-- high was 5 before DSI 6G 2.1.0 --> + <bitfield name="DST_FORMAT" low="4" high="6" type="dsi_vid_dst_format"/> <bitfield name="TRAFFIC_MODE" low="8" high="9" type="dsi_traffic_mode"/> <bitfield name="BLLP_POWER_STOP" pos="12" type="boolean"/> <bitfield name="EOF_BLLP_POWER_STOP" pos="15" type="boolean"/> diff --git a/drivers/gpu/drm/nova/gem.rs b/drivers/gpu/drm/nova/gem.rs index 6ccfa5da5761..e073e174e257 100644 --- a/drivers/gpu/drm/nova/gem.rs +++ b/drivers/gpu/drm/nova/gem.rs @@ -19,8 +19,9 @@ pub(crate) struct NovaObject {} impl gem::DriverObject for NovaObject { type Driver = NovaDriver; + type Args = (); - fn new(_dev: &NovaDevice, _size: usize) -> impl PinInit<Self, Error> { + fn new(_dev: &NovaDevice, _size: usize, _args: Self::Args) -> impl PinInit<Self, Error> { try_pin_init!(NovaObject {}) } } @@ -33,7 +34,7 @@ impl NovaObject { } let aligned_size = page::page_align(size).ok_or(EINVAL)?; - gem::Object::new(dev, aligned_size) + gem::Object::new(dev, aligned_size, ()) } /// Look up a GEM object handle for a `File` and return an `ObjectRef` for it. diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index bf0bad8c8cf1..ae678696fbac 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -275,7 +275,22 @@ static void omap_global_destroy_state(struct drm_private_obj *obj, kfree(omap_state); } +static struct drm_private_state * +omap_global_atomic_create_state(struct drm_private_obj *obj) +{ + struct omap_global_state *state; + + state = kzalloc_obj(*state); + if (!state) + return ERR_PTR(-ENOMEM); + + __drm_atomic_helper_private_obj_create_state(obj, &state->base); + + return &state->base; +} + static const struct drm_private_state_funcs omap_global_state_funcs = { + .atomic_create_state = omap_global_atomic_create_state, .atomic_duplicate_state = omap_global_duplicate_state, .atomic_destroy_state = omap_global_destroy_state, }; @@ -283,13 +298,8 @@ static const struct drm_private_state_funcs omap_global_state_funcs = { static int omap_global_obj_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; - struct omap_global_state *state; - - state = kzalloc_obj(*state); - if (!state) - return -ENOMEM; - drm_atomic_private_obj_init(dev, &priv->glob_obj, &state->base, + drm_atomic_private_obj_init(dev, &priv->glob_obj, &omap_global_state_funcs); return 0; } diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index a99f2e2a49fe..d6863b28ddc5 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -203,6 +203,17 @@ config DRM_PANEL_HIMAX_HX83112B Say Y here if you want to enable support for Himax HX83112B-based display panels, such as the one found in the Fairphone 3 smartphone. +config DRM_PANEL_HIMAX_HX83121A + tristate "Himax HX83121A-based DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_KMS_HELPER + help + Say Y here if you want to enable support for Himax HX83121A-based + display panels, such as the one found in the HUAWEI Matebook E Go + series. + config DRM_PANEL_HIMAX_HX8394 tristate "HIMAX HX8394 MIPI-DSI LCD panels" depends on OF @@ -257,14 +268,30 @@ config DRM_PANEL_ILITEK_ILI9805 Say Y if you want to enable support for panels based on the Ilitek ILI9805 controller. -config DRM_PANEL_ILITEK_ILI9806E - tristate "Ilitek ILI9806E-based panels" +config DRM_PANEL_ILITEK_ILI9806E_CORE + tristate + +config DRM_PANEL_ILITEK_ILI9806E_DSI + tristate "Ilitek ILI9806E-based DSI panels" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE + select DRM_PANEL_ILITEK_ILI9806E_CORE + help + Say Y if you want to enable support for panels based on the + Ilitek ILI9806E controller using DSI. + +config DRM_PANEL_ILITEK_ILI9806E_SPI + tristate "Ilitek ILI9806E-based RGB SPI panel" + depends on OF + depends on SPI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_MIPI_DBI + select VIDEOMODE_HELPERS + select DRM_PANEL_ILITEK_ILI9806E_CORE help Say Y if you want to enable support for panels based on the - Ilitek ILI9806E controller. + Ilitek ILI9806E controller using SPI. config DRM_PANEL_ILITEK_ILI9881C tristate "Ilitek ILI9881C-based panels" @@ -939,6 +966,19 @@ config DRM_PANEL_SAMSUNG_S6E8AA5X01_AMS561RA01 ~5.6 inch AMOLED display, and the controller is driven by the MIPI DSI protocol with 4 lanes. +config DRM_PANEL_SAMSUNG_S6E8FC0 + tristate "Samsung S6E8FC0 DSI controller" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + select DRM_MIPI_DSI + help + Say Y or M here if you want to enable support for the Samsung + S6E8FC0 DSI controller and connected panel. + Currently supported panels: + + M1906F9 (M1906F9SH or M1906F9SI), 6.09 inch 720x1560, found + in the Xiaomi Mi A3 smartphone (xiaomi-laurel). + config DRM_PANEL_SAMSUNG_SOFEF00 tristate "Samsung SOFEF00 DSI panel controller" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 3336a2c0cd86..a4291dc3905b 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -21,12 +21,15 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX8279) += panel-himax-hx8279.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o +obj-$(CONFIG_DRM_PANEL_HIMAX_HX83121A) += panel-himax-hx83121a.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9805) += panel-ilitek-ili9805.o -obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9806E) += panel-ilitek-ili9806e.o +obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9806E_CORE) += panel-ilitek-ili9806e-core.o +obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9806E_DSI) += panel-ilitek-ili9806e-dsi.o +obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9806E_SPI) += panel-ilitek-ili9806e-spi.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9882T) += panel-ilitek-ili9882t.o obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o @@ -95,6 +98,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS427AP24) += panel-samsung-s6e88a0-ams4 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA5X01_AMS561RA01) += panel-samsung-s6e8aa5x01-ams561ra01.o +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8FC0) += panel-samsung-s6e8fc0-m1906f9.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF00) += panel-samsung-sofef00.o obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o obj-$(CONFIG_DRM_PANEL_SHARP_LQ079L1SX01) += panel-sharp-lq079l1sx01.o diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 0fce4452dbe7..497dcd48f57b 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -2025,6 +2025,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d45, &delay_200_500_e80, "NV116WHM-N4B"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d73, &delay_200_500_e80, "NE140WUM-N6S"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0db3, &delay_200_500_e80, "NV153WUM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ddf, &delay_200_500_e80, "NV116WHM-T01"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"), @@ -2061,6 +2062,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1565, &delay_200_500_e80, "N156HCA-EAB"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x156b, &delay_200_500_e80_d50, "N153JCA-ELK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x162b, &delay_200_500_e80_d50, "N160JCE-ELL"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x7402, &delay_200_500_e200_d50, "N116BCA-EAK"), @@ -2079,6 +2081,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'S', 'W', 0x146e, &delay_80_500_e50_d50, "MNE007QB3-1"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x147c, &delay_200_500_e50_d100, "MNE007QB3-1"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1519, &delay_200_500_e80_d50, "MNF601BS1-3"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x1529, &delay_200_500_e80_d50, "MNF307QS3-2"), EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"), diff --git a/drivers/gpu/drm/panel/panel-himax-hx83102.c b/drivers/gpu/drm/panel/panel-himax-hx83102.c index 1d3bb5dca559..8b2a68ee851e 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx83102.c +++ b/drivers/gpu/drm/panel/panel-himax-hx83102.c @@ -7,6 +7,7 @@ * Based on drivers/gpu/drm/panel/panel-himax-hx8394.c */ +#include <linux/backlight.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/module.h> @@ -76,6 +77,8 @@ struct hx83102_panel_desc { unsigned int height_mm; } size; + bool has_backlight; + int (*init)(struct hx83102 *ctx); }; @@ -701,6 +704,67 @@ static int starry_2082109qfh040022_50e_init(struct hx83102 *ctx) return dsi_ctx.accum_err; } +static int holitech_htf065h045_init(struct hx83102 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + msleep(50); + + hx83102_enable_extended_cmds(&dsi_ctx, true); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x22, 0x44, 0x27, 0x27, 0x32, + 0x52, 0x57, 0x39, 0x08, 0x08, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x00, 0x06, 0x40, 0x00, + 0x0e, 0xae, 0x38, 0x00, 0x00, 0x00, 0x00, 0xf4, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x01, 0x58, 0x01, 0x58, 0x01, + 0x58, 0x03, 0x58, 0x03, 0xff, 0x01, 0x20, 0x00, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPANEL, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x17, 0x00, 0x63, 0x37, 0x0e, 0x0e, 0x00, 0x00, + 0x32, 0x10, 0x08, 0x00, 0x08, 0x32, 0x16, 0x4e, 0x06, 0x4e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPWM, 0x04, 0x0c, 0xb2, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP1, 0x24, 0x25, 0x18, 0x18, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x06, 0x07, 0x04, 0x05, 0x18, 0x18, 0x18, + 0x18, 0x02, 0x03, 0x00, 0x01, 0x20, 0x21, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP2, 0x00, 0x09, 0x16, 0x1f, 0x28, + 0x4b, 0x65, 0x6d, 0x74, 0x70, 0x89, 0x8d, 0x91, 0xa0, 0x9e, + 0xa8, 0xb2, 0xc8, 0xc9, 0x65, 0x6d, 0x78, 0x7f, 0x00, 0x09, + 0x16, 0x1f, 0x28, 0x4b, 0x65, 0x6d, 0x74, 0x70, 0x89, 0x8d, + 0x91, 0xa0, 0x9e, 0xa8, 0xb2, 0xc8, 0xc9, 0x65, 0x6d, 0x78, + 0x7f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0xff, 0x14, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x70, 0x23, 0xa8, 0x93, 0xb2, + 0xc0, 0xc0, 0x01, 0x10, 0x00, 0x00, 0x00, 0x0d, 0x3d, 0x82, + 0x77, 0x04, 0x01, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x00, 0x53, 0x00, 0x02, 0x59); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xfc, 0x00, 0x04, 0x9e, 0xf6, + 0x00, 0x5d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x42, 0x00, 0x33, 0x00, 0x33, + 0x88, 0xb3, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPCTRL, 0x20, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x7f, 0x03, 0xf5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); + + return dsi_ctx.accum_err; +} + static const struct drm_display_mode starry_mode = { .clock = 162680, .hdisplay = 1200, @@ -833,6 +897,29 @@ static const struct hx83102_panel_desc starry_2082109qfh040022_50e_desc = { .init = starry_2082109qfh040022_50e_init, }; +static const struct drm_display_mode holitech_htf065h045_default_mode = { + .clock = 90720, + .hdisplay = 720, + .hsync_start = 720 + 40, + .hsync_end = 720 + 40 + 40, + .htotal = 720 + 40 + 40 + 40, + .vdisplay = 1600, + .vsync_start = 1600 + 186, + .vsync_end = 1600 + 186 + 2, + .vtotal = 1600 + 186 + 2 + 12, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static const struct hx83102_panel_desc holitech_htf065h045_desc = { + .modes = &holitech_htf065h045_default_mode, + .size = { + .width_mm = 68, + .height_mm = 151, + }, + .has_backlight = true, + .init = holitech_htf065h045_init, +}; + static int hx83102_enable(struct drm_panel *panel) { msleep(130); @@ -966,6 +1053,59 @@ static const struct drm_panel_funcs hx83102_drm_funcs = { .get_orientation = hx83102_get_orientation, }; +static int hx83102_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static int hx83102_bl_get_brightness(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness; + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return brightness; +} + +static const struct backlight_ops hx83102_bl_ops = { + .update_status = hx83102_bl_update_status, + .get_brightness = hx83102_bl_get_brightness, +}; + +static struct backlight_device * +hx83102_create_dcs_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 4095, + .max_brightness = 4095, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &hx83102_bl_ops, &props); +} + static int hx83102_panel_add(struct hx83102 *ctx) { struct device *dev = &ctx->dsi->dev; @@ -997,6 +1137,14 @@ static int hx83102_panel_add(struct hx83102 *ctx) if (err) return err; + /* Use DSI-based backlight as fallback if available */ + if (ctx->desc->has_backlight && !ctx->base.backlight) { + ctx->base.backlight = hx83102_create_dcs_backlight(ctx->dsi); + if (IS_ERR(ctx->base.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->base.backlight), + "Failed to create backlight\n"); + } + ctx->base.funcs = &hx83102_drm_funcs; ctx->base.dev = &ctx->dsi->dev; @@ -1069,6 +1217,9 @@ static const struct of_device_id hx83102_of_match[] = { { .compatible = "starry,himax83102-j02", .data = &starry_desc }, + { .compatible = "holitech,htf065h045", + .data = &holitech_htf065h045_desc + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, hx83102_of_match); diff --git a/drivers/gpu/drm/panel/panel-himax-hx83121a.c b/drivers/gpu/drm/panel/panel-himax-hx83121a.c new file mode 100644 index 000000000000..ebe643ba4184 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-himax-hx83121a.c @@ -0,0 +1,749 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Himax HX83121A DriverIC panels driver + * Copyright (c) 2024-2026 Pengyu Luo <mitltlatltl@gmail.com> + * + * Multiple panels handling based on panel-novatek-nt36523.c + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/regulator/consumer.h> + +#include <drm/display/drm_dsc.h> +#include <drm/display/drm_dsc_helper.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#include <video/mipi_display.h> + +static bool enable_dsc; +module_param(enable_dsc, bool, 0); +MODULE_PARM_DESC(enable_dsc, "enable DSC on the panel (default: false)"); + +struct himax { + struct drm_panel panel; + struct mipi_dsi_device *dsi[2]; + const struct panel_desc *desc; + struct drm_dsc_config dsc; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; + struct backlight_device *backlight; +}; + +struct panel_desc { + unsigned int width_mm; + unsigned int height_mm; + unsigned int bpc; + unsigned int lanes; + enum mipi_dsi_pixel_format format; + unsigned long mode_flags; + const struct drm_dsc_config *dsc_cfg; + const struct drm_display_mode *dsc_modes; + unsigned int num_dsc_modes; + + const struct drm_display_mode *modes; + unsigned int num_modes; + + int (*init_sequence_dsc)(struct mipi_dsi_multi_context *dsi_ctx); + int (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx); + + bool is_dual_dsi; + bool has_dcs_backlight; +}; + +static const struct regulator_bulk_data himax_supplies[] = { + { .supply = "vddi" }, + { .supply = "avdd" }, + { .supply = "avee" }, +}; + +static inline struct himax *to_himax(struct drm_panel *panel) +{ + return container_of(panel, struct himax, panel); +} + +static inline struct mipi_dsi_device *to_primary_dsi(struct himax *ctx) +{ + /* Sync on DSI1 for dual dsi */ + return ctx->desc->is_dual_dsi ? ctx->dsi[1] : ctx->dsi[0]; +} + +static void himax_reset(struct himax *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(4000, 4100); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); +} + +static int himax_prepare(struct drm_panel *panel) +{ + struct himax *ctx = to_himax(panel); + struct mipi_dsi_device *dsi = to_primary_dsi(ctx); + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + struct drm_dsc_picture_parameter_set pps; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(himax_supplies), + ctx->supplies); + if (ret < 0) + return ret; + + himax_reset(ctx); + + if (enable_dsc && ctx->desc->init_sequence_dsc) + ret = ctx->desc->init_sequence_dsc(&dsi_ctx); + else if (ctx->desc->init_sequence) + ret = ctx->desc->init_sequence(&dsi_ctx); + else + ret = -EOPNOTSUPP; + + if (ret < 0) { + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(himax_supplies), + ctx->supplies); + return ret; + } + + if (enable_dsc) { + drm_dsc_pps_payload_pack(&pps, &ctx->dsc); + mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps); + mipi_dsi_compression_mode_multi(&dsi_ctx, true); + } + + return backlight_enable(ctx->backlight); +} + +static int himax_off(struct mipi_dsi_multi_context *dsi_ctx) +{ + mipi_dsi_dcs_enter_sleep_mode_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 120); + + return dsi_ctx->accum_err; +} + +static int himax_unprepare(struct drm_panel *panel) +{ + struct himax *ctx = to_himax(panel); + struct mipi_dsi_device *dsi = to_primary_dsi(ctx); + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + struct device *dev = &dsi->dev; + int ret; + + ret = himax_off(&dsi_ctx); + if (ret < 0) + dev_err(dev, "panel failed to off: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(himax_supplies), ctx->supplies); + + return 0; +} + +static int himax_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct himax *ctx = to_himax(panel); + const struct panel_desc *desc = ctx->desc; + const struct drm_display_mode *modes; + int num_modes; + int i; + + modes = enable_dsc ? desc->dsc_modes : desc->modes; + num_modes = enable_dsc ? desc->num_dsc_modes : desc->num_modes; + + for (i = 0; i < num_modes; i++) { + const struct drm_display_mode *m = &modes[i]; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, m); + if (!mode) { + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", + m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); + return -ENOMEM; + } + + mode->type = DRM_MODE_TYPE_DRIVER; + if (i == 0) + mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + } + + connector->display_info.width_mm = desc->width_mm; + connector->display_info.height_mm = desc->height_mm; + connector->display_info.bpc = desc->bpc; + + return num_modes; +} + +static const struct drm_panel_funcs himax_panel_funcs = { + .prepare = himax_prepare, + .unprepare = himax_unprepare, + .get_modes = himax_get_modes, +}; + +static int himax_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + /* TODO: brightness to raw map table */ + return mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); +} + +static const struct backlight_ops himax_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = himax_bl_update_status, +}; + +static struct backlight_device * +himax_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 512, + .max_brightness = 4095, + .scale = BACKLIGHT_SCALE_NON_LINEAR, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &himax_bl_ops, &props); +} + +static int boe_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context *dsi_ctx) +{ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc7); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x98); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, + 0x01, 0x07, 0x01, 0x07, 0x01, 0x07, 0x06, 0x06, + 0x06, 0x16, 0x00, 0x16, 0x81, 0x02, 0x40, 0x00, + 0x1a, 0x4a, 0x05, 0x04, 0x03, 0x02, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x00, 0x30); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc9); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x04); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x42); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf5); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcd, + 0x81, 0x00, 0x80, 0x77, 0x00, 0x01, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, + 0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f, + 0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24, + 0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, + 0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4, + 0xff, 0xea, 0xff, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00); + + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 140); + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); + + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_msleep(dsi_ctx, 20); + + return dsi_ctx->accum_err; +} + +static int boe_ppc357db1_4_init_seq(struct mipi_dsi_multi_context *dsi_ctx) +{ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x20); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc7); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xa6); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, + 0x01, 0x07, 0x01, 0x07, 0x01, 0x07, 0x06, 0x06, + 0x06, 0x16, 0x00, 0x16, 0x81, 0x02, 0x40, 0x00, + 0x1a, 0x4a, 0x05, 0x04, 0x03, 0x02, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, + 0x02, 0x68, 0x02, 0x68, 0x02, 0x68, 0x02, 0x68, + 0x02, 0x6f, 0x03, 0x04, 0x2d, 0x09, 0x09, 0x00, + 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x10, 0x1c, 0x25, 0x3c, 0x00, 0x23, + 0x5d, 0x02, 0x02, 0x00, 0x00, 0x58, 0x01, 0xac, + 0x0f, 0xa9, 0x10, 0x00, 0x2d, 0x6f, 0x00, 0x70, + 0x00, 0x0a, 0xcb, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x09, 0x85); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc9); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x04); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf5); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, + 0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f, + 0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24, + 0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, + 0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4, + 0xff, 0xea, 0xff, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00); + + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 140); + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); + + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_msleep(dsi_ctx, 31); + + return dsi_ctx->accum_err; +} + +static int csot_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context *dsi_ctx) +{ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, + 0x1c, 0x6b, 0x6b, 0x27, 0xe7, 0x00, 0x1b, 0x25, + 0x21, 0x21, 0x2d, 0x2d, 0x17, 0x33, 0x31, 0x40, + 0xcd, 0xff, 0x1a, 0x05, 0x15, 0x98, 0x00, 0x88, + 0x7f, 0xff, 0xff, 0xcf, 0x1a, 0xcc, 0x02, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, + 0x00, 0x6a, 0x40, 0x00, 0x00, 0x14, 0x98, 0x60, + 0x3c, 0x02, 0x80, 0x21, 0x21, 0x00, 0x00, 0xf0, + 0x27); + /* + * NOTE: Register 0xE2 configuration (based on downstream reference): + * - 0x00: 120Hz with DSC enabled + * - 0x10: 60Hz with DSC enabled + * - 0x20: 60Hz with DSC disabled + * + * Both 0x00 and 0x10 are compatible with 60Hz/120Hz when DSC is active. + * We use a fixed DSC-on value to remain refresh-rate agnostic. + */ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc0, 0x23, 0x23, 0xcc, 0x22, 0x99, 0xd8); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb4, + 0x46, 0x06, 0x0c, 0xbe, 0x0c, 0xbe, 0x09, 0x46, + 0x0f, 0x57, 0x0f, 0x57, 0x03, 0x4a, 0x00, 0x00, + 0x04, 0x0c, 0x00, 0x18, 0x01, 0x06, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x10, 0x00, 0x02, + 0x14, 0x14, 0x14, 0x14); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x01, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xe2); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 0x49); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, + 0x00, 0xc0, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, + 0x16, 0x02, 0x07, 0x07, 0x07, 0x31, 0x13, 0x19, + 0x12, 0x12, 0x03, 0x03, 0x03, 0x32, 0x10, 0x18, + 0x00, 0x11, 0x32, 0x10, 0x03, 0x00, 0x03, 0x32, + 0x10, 0x03, 0x00, 0x03, 0x00, 0x00, 0xff, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, + 0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x0a, 0x00, + 0x03, 0x20, 0x00, 0x14, 0x03, 0x20, 0x03, 0x20, + 0x02, 0x00, 0x02, 0x91, 0x00, 0x20, 0x02, 0x47, + 0x00, 0x0b, 0x00, 0x0c, 0x05, 0x0e, 0x03, 0x68, + 0x18, 0x00, 0x10, 0xe0, 0x03, 0x0c, 0x20, 0x00, + 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38, + 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, + 0x7d, 0x7e, 0x01, 0x02, 0x01, 0x00, 0x09); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, + 0x17, 0x08, 0x08, 0x2c, 0x46, 0x1e, 0x02, 0x23, + 0x5d, 0x02, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x05, 0x02, 0x02, 0x07, 0x10, 0x10, 0x00, 0x1d, + 0xb9, 0x23, 0xb9, 0x00, 0x33, 0x02, 0x88); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, + 0x02, 0x00, 0xb2, 0x01, 0x56, 0x07, 0x56, 0x08, + 0x48, 0x14, 0xfd, 0x26); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, + 0x08, 0x08, 0x01, 0x03, 0x01, 0x03, 0x07, 0x02, + 0x02, 0x47, 0x00, 0x47, 0x81, 0x02, 0x40, 0x00, + 0x18, 0x4a, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbf, + 0xfd, 0x00, 0x80, 0x9c, 0x36, 0x00, 0x81, 0x0c); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcd, + 0x81, 0x00, 0x80, 0x77, 0x00, 0x01, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, + 0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f, + 0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24, + 0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, + 0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4, + 0xff, 0xea, 0xff, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00); + + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 140); + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); + + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_msleep(dsi_ctx, 20); + + return dsi_ctx->accum_err; +} + +static int csot_ppc357db1_4_init_seq(struct mipi_dsi_multi_context *dsi_ctx) +{ + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, + 0x1c, 0x6b, 0x6b, 0x27, 0xe7, 0x00, 0x1b, 0x11, + 0x21, 0x21, 0x2d, 0x2d, 0x17, 0x33, 0x31, 0x40, + 0xcd, 0xff, 0x1a, 0x05, 0x15, 0x98, 0x00, 0x88, + 0x7f, 0xff, 0xff, 0xcf, 0x1a, 0xcc, 0x02, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x20); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, + 0x00, 0x6a, 0x40, 0x00, 0x00, 0x14, 0x98, 0x60, + 0x3c, 0x02, 0x80, 0x21, 0x21, 0x00, 0x00, 0x10, + 0x27); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x00, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xe2); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 0x49); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, + 0x00, 0xc0, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, + 0x16, 0x02, 0x07, 0x07, 0x07, 0x31, 0x13, 0x16, + 0x12, 0x12, 0x03, 0x03, 0x03, 0x32, 0x10, 0x15, + 0x00, 0x11, 0x32, 0x10, 0x03, 0x00, 0x03, 0x32, + 0x10, 0x03, 0x00, 0x03, 0x00, 0x00, 0xff, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, + 0x80, 0x05, 0x1c, 0xbe, 0x09, 0x8d, 0x0f, 0x57, + 0x03, 0x87, 0x06, 0x10, 0x32, 0x06, 0x15, 0x00, + 0x00, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x10, 0x16, 0x28, 0x3c, 0x03, 0x23, + 0x5d, 0x02, 0x02, 0x00, 0x00, 0x48, 0x01, 0xac, + 0x0f, 0xab, 0x10, 0x00, 0x32, 0x87, 0x00, 0xa1, + 0x00, 0x0a, 0xcb, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, + 0x02, 0x00, 0xb2, 0x01, 0x56, 0x07, 0x56, 0x08, + 0x48, 0x14, 0x00, 0x26); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, + 0x05, 0x05, 0x01, 0x05, 0x01, 0x05, 0x04, 0x04, + 0x04, 0x24, 0x00, 0x24, 0x81, 0x02, 0x40, 0x00, + 0x32, 0x87, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf0); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbf, + 0xfd, 0x00, 0x80, 0x9c, 0x10, 0x00, 0x81, 0x0c); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, + 0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f, + 0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24, + 0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, + 0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4, + 0xff, 0xea, 0xff, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00); + + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 140); + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); + + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_msleep(dsi_ctx, 31); + + return dsi_ctx->accum_err; +} + +static struct drm_dsc_config ppc357db1_4_dsc_cfg = { + .dsc_version_major = 1, + .dsc_version_minor = 1, + .slice_height = 20, + .slice_width = 800, + .slice_count = 1, + .bits_per_component = 8, + .bits_per_pixel = 8 << 4, + .block_pred_enable = true, +}; + +static const struct drm_display_mode ppc357db1_4_dsc_modes[] = { + { + .clock = (800 + 60 + 40 + 40) * 2 * (2560 + 154 + 4 + 18) * 120 / 1000, + .hdisplay = 800 * 2, + .hsync_start = (800 + 60) * 2, + .hsync_end = (800 + 60 + 40) * 2, + .htotal = (800 + 60 + 40 + 40) * 2, + .vdisplay = 2560, + .vsync_start = 2560 + 154, + .vsync_end = 2560 + 154 + 4, + .vtotal = 2560 + 154 + 4 + 18, + }, + { + .clock = (800 + 60 + 40 + 40) * 2 * (2560 + 2890 + 4 + 18) * 60 / 1000, + .hdisplay = 800 * 2, + .hsync_start = (800 + 60) * 2, + .hsync_end = (800 + 60 + 40) * 2, + .htotal = (800 + 60 + 40 + 40) * 2, + .vdisplay = 2560, + .vsync_start = 2560 + 2890, + .vsync_end = 2560 + 2890 + 4, + .vtotal = 2560 + 2890 + 4 + 18, + }, +}; + +static const struct drm_display_mode ppc357db1_4_modes[] = { + { + .clock = (800 + 60 + 20 + 40) * 2 * (2560 + 154 + 4 + 18) * 60 / 1000, + .hdisplay = 800 * 2, + .hsync_start = (800 + 60) * 2, + .hsync_end = (800 + 60 + 20) * 2, + .htotal = (800 + 60 + 20 + 40) * 2, + .vdisplay = 2560, + .vsync_start = 2560 + 168, + .vsync_end = 2560 + 168 + 4, + .vtotal = 2560 + 168 + 4 + 18, + }, +}; + +static int himax_probe(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_device_info dsi_info = {"dsi-secondary", 0, NULL}; + struct mipi_dsi_host *dsi1_host; + struct device *dev = &dsi->dev; + const struct panel_desc *desc; + struct device_node *dsi1; + struct himax *ctx; + int num_dsi = 1; + int ret, i; + + ctx = devm_drm_panel_alloc(dev, struct himax, panel, &himax_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (!ctx) + return -ENOMEM; + + ret = devm_regulator_bulk_get_const(&dsi->dev, + ARRAY_SIZE(himax_supplies), + himax_supplies, &ctx->supplies); + if (ret < 0) + return ret; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + desc = of_device_get_match_data(dev); + if (!desc) + return -ENODEV; + ctx->desc = desc; + ctx->dsc = *desc->dsc_cfg; + + if (desc->is_dual_dsi) { + num_dsi = 2; + dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); + if (!dsi1) { + dev_err(dev, "cannot get secondary DSI node.\n"); + return -ENODEV; + } + + dsi1_host = of_find_mipi_dsi_host_by_node(dsi1); + of_node_put(dsi1); + if (!dsi1_host) + return dev_err_probe(dev, -EPROBE_DEFER, + "cannot get secondary DSI host\n"); + + ctx->dsi[1] = devm_mipi_dsi_device_register_full(dev, dsi1_host, + &dsi_info); + if (IS_ERR(ctx->dsi[1])) { + dev_err(dev, "cannot get secondary DSI device\n"); + return PTR_ERR(ctx->dsi[1]); + } + + mipi_dsi_set_drvdata(ctx->dsi[1], ctx); + } + + ctx->dsi[0] = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + ctx->panel.prepare_prev_first = true; + + if (desc->has_dcs_backlight) { + ctx->backlight = himax_create_backlight(to_primary_dsi(ctx)); + if (IS_ERR(ctx->backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->backlight), + "Failed to create backlight\n"); + } else { + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + } + + drm_panel_add(&ctx->panel); + + for (i = 0; i < num_dsi; i++) { + ctx->dsi[i]->lanes = desc->lanes; + ctx->dsi[i]->format = desc->format; + ctx->dsi[i]->mode_flags = desc->mode_flags; + ctx->dsi[i]->dsc = enable_dsc ? &ctx->dsc : NULL; + ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, + "Failed to attach to DSI host\n"); + } + } + + return 0; +} + +static void himax_remove(struct mipi_dsi_device *dsi) +{ + struct himax *ctx = mipi_dsi_get_drvdata(dsi); + + drm_panel_remove(&ctx->panel); +} + +/* Model name: BOE PPC357DB1-4 */ +static const struct panel_desc boe_ppc357db1_4_desc = { + .width_mm = 266, + .height_mm = 166, + .lanes = 4, + .format = MIPI_DSI_FMT_RGB888, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS | + MIPI_DSI_MODE_LPM, + .dsc_cfg = &ppc357db1_4_dsc_cfg, + .dsc_modes = ppc357db1_4_dsc_modes, + .num_dsc_modes = ARRAY_SIZE(ppc357db1_4_dsc_modes), + .modes = ppc357db1_4_modes, + .num_modes = ARRAY_SIZE(ppc357db1_4_modes), + .init_sequence_dsc = boe_ppc357db1_4_dsc_init_seq, + .init_sequence = boe_ppc357db1_4_init_seq, + .is_dual_dsi = true, + .has_dcs_backlight = true, +}; + +/* Model name: CSOT PPC357DB1-4 */ +static const struct panel_desc csot_ppc357db1_4_desc = { + .width_mm = 266, + .height_mm = 166, + .lanes = 4, + .format = MIPI_DSI_FMT_RGB888, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS | + MIPI_DSI_MODE_LPM, + .dsc_cfg = &ppc357db1_4_dsc_cfg, + .dsc_modes = ppc357db1_4_dsc_modes, + .num_dsc_modes = ARRAY_SIZE(ppc357db1_4_dsc_modes), + .modes = ppc357db1_4_modes, + .num_modes = ARRAY_SIZE(ppc357db1_4_modes), + .init_sequence_dsc = csot_ppc357db1_4_dsc_init_seq, + .init_sequence = csot_ppc357db1_4_init_seq, + .is_dual_dsi = true, + .has_dcs_backlight = true, +}; + +/* + * Known panels with HX83121A: + * CSOT PNC357DB1-4: on MI Book S 12.4 + * CSOT PPC357DB1-1: on SAMSUNG Galaxy Tab S7 FE + * BOE/CSOT PPC357DB1-4: on HUAWEI Matebook E Go + * CSOT PPC357DB1-5: on MI Pad 5 Pro 12.4 + */ + +static const struct of_device_id himax_of_match[] = { + { .compatible = "boe,ppc357db1-4", .data = &boe_ppc357db1_4_desc }, + { .compatible = "csot,ppc357db1-4", .data = &csot_ppc357db1_4_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, himax_of_match); + +static struct mipi_dsi_driver himax_driver = { + .probe = himax_probe, + .remove = himax_remove, + .driver = { + .name = "panel-himax-hx83121a", + .of_match_table = himax_of_match, + }, +}; +module_mipi_dsi_driver(himax_driver); + +MODULE_AUTHOR("Pengyu Luo <mitltlatltl0@gmail.com>"); +MODULE_DESCRIPTION("Himax HX83121A DriverIC panels driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.c new file mode 100644 index 000000000000..be2cf1440155 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Ilitek ILI9806E core driver. + * + * Copyright (c) 2026 Amarula Solutions, Dario Binacchi <dario.binacchi@amarulasolutions.com> + */ + +#include <drm/drm_panel.h> + +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> + +#include "panel-ilitek-ili9806e-core.h" + +struct ili9806e { + void *transport; + struct drm_panel panel; + + unsigned int num_supplies; + struct regulator_bulk_data supplies[2]; + struct gpio_desc *reset_gpio; +}; + +void *ili9806e_get_transport(struct drm_panel *panel) +{ + struct ili9806e *ctx = container_of(panel, struct ili9806e, panel); + + return ctx->transport; +} +EXPORT_SYMBOL_GPL(ili9806e_get_transport); + +int ili9806e_power_on(struct device *dev) +{ + struct ili9806e *ctx = dev_get_drvdata(dev); + int ret; + + gpiod_set_value(ctx->reset_gpio, 1); + + ret = regulator_bulk_enable(ctx->num_supplies, ctx->supplies); + if (ret) { + dev_err(dev, "regulator bulk enable failed: %d\n", ret); + return ret; + } + + usleep_range(10000, 20000); + gpiod_set_value(ctx->reset_gpio, 0); + usleep_range(10000, 20000); + + return 0; +} +EXPORT_SYMBOL_GPL(ili9806e_power_on); + +int ili9806e_power_off(struct device *dev) +{ + struct ili9806e *ctx = dev_get_drvdata(dev); + int ret; + + gpiod_set_value(ctx->reset_gpio, 1); + + ret = regulator_bulk_disable(ctx->num_supplies, ctx->supplies); + if (ret) + dev_err(dev, "regulator bulk disable failed: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(ili9806e_power_off); + +int ili9806e_probe(struct device *dev, void *transport, + const struct drm_panel_funcs *funcs, + int connector_type) +{ + struct ili9806e *ctx; + bool set_prepare_prev_first = false; + int ret; + + ctx = devm_kzalloc(dev, sizeof(struct ili9806e), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + dev_set_drvdata(dev, ctx); + ctx->transport = transport; + + ctx->supplies[ctx->num_supplies++].supply = "vdd"; + if (of_device_is_compatible(dev->of_node, + "densitron,dmt028vghmcmi-1d") || + of_device_is_compatible(dev->of_node, + "ortustech,com35h3p70ulc")) { + ctx->supplies[ctx->num_supplies++].supply = "vccio"; + set_prepare_prev_first = true; + } + + ret = devm_regulator_bulk_get(dev, ctx->num_supplies, ctx->supplies); + if (ret) + return dev_err_probe(dev, ret, "failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + drm_panel_init(&ctx->panel, dev, funcs, connector_type); + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + if (set_prepare_prev_first) + ctx->panel.prepare_prev_first = true; + + drm_panel_add(&ctx->panel); + + return 0; + +} +EXPORT_SYMBOL_GPL(ili9806e_probe); + +void ili9806e_remove(struct device *dev) +{ + struct ili9806e *ctx = dev_get_drvdata(dev); + + drm_panel_remove(&ctx->panel); +} +EXPORT_SYMBOL_GPL(ili9806e_remove); + +MODULE_AUTHOR("Dario Binacchi <dario.binacchi@amarulasolutions.com>"); +MODULE_AUTHOR("Gunnar Dibbern <gunnar.dibbern@lht.dlh.de>"); +MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>"); +MODULE_DESCRIPTION("Ilitek ILI9806E Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.h b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.h new file mode 100644 index 000000000000..dddece62cf42 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _PANEL_ILITEK_ILI9806E_CORE_H +#define _PANEL_ILITEK_ILI9806E_CORE_H + +void *ili9806e_get_transport(struct drm_panel *panel); +int ili9806e_power_off(struct device *dev); +int ili9806e_power_on(struct device *dev); + +int ili9806e_probe(struct device *dev, void *transport, + const struct drm_panel_funcs *funcs, + int connector_type); +void ili9806e_remove(struct device *dev); + +#endif /* _PANEL_ILITEK_ILI9806E_CORE_H */ diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c index 18aa6222b0c5..ecdbed8d4a3a 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c @@ -1,15 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/errno.h> -#include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> -#include <linux/regulator/consumer.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> @@ -18,7 +15,9 @@ #include <video/mipi_display.h> -struct panel_desc { +#include "panel-ilitek-ili9806e-core.h" + +struct ili9806e_dsi_panel_desc { const struct drm_display_mode *display_mode; unsigned long mode_flags; enum mipi_dsi_pixel_format format; @@ -26,60 +25,13 @@ struct panel_desc { void (*init_sequence)(struct mipi_dsi_multi_context *ctx); }; -struct ili9806e_panel { - struct drm_panel panel; +struct ili9806e_dsi_panel { struct mipi_dsi_device *dsi; - struct gpio_desc *reset_gpio; - struct regulator_bulk_data supplies[2]; - const struct panel_desc *desc; + const struct ili9806e_dsi_panel_desc *desc; enum drm_panel_orientation orientation; }; -static const char * const regulator_names[] = { - "vdd", - "vccio", -}; - -static inline struct ili9806e_panel *to_ili9806e_panel(struct drm_panel *panel) -{ - return container_of(panel, struct ili9806e_panel, panel); -} - -static int ili9806e_power_on(struct ili9806e_panel *ctx) -{ - struct mipi_dsi_device *dsi = ctx->dsi; - int ret; - - gpiod_set_value(ctx->reset_gpio, 1); - - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - if (ret < 0) { - dev_err(&dsi->dev, "regulator bulk enable failed: %d\n", ret); - return ret; - } - - usleep_range(10000, 20000); - gpiod_set_value(ctx->reset_gpio, 0); - usleep_range(10000, 20000); - - return 0; -} - -static int ili9806e_power_off(struct ili9806e_panel *ctx) -{ - struct mipi_dsi_device *dsi = ctx->dsi; - int ret; - - gpiod_set_value(ctx->reset_gpio, 1); - - ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - if (ret) - dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret); - - return ret; -} - -static int ili9806e_on(struct ili9806e_panel *ili9806e) +static int ili9806e_dsi_on(struct ili9806e_dsi_panel *ili9806e) { struct mipi_dsi_multi_context ctx = { .dsi = ili9806e->dsi }; @@ -93,7 +45,7 @@ static int ili9806e_on(struct ili9806e_panel *ili9806e) return ctx.accum_err; } -static int ili9806e_off(struct ili9806e_panel *panel) +static int ili9806e_dsi_off(struct ili9806e_dsi_panel *panel) { struct mipi_dsi_multi_context ctx = { .dsi = panel->dsi }; @@ -104,88 +56,75 @@ static int ili9806e_off(struct ili9806e_panel *panel) return ctx.accum_err; } -static int ili9806e_prepare(struct drm_panel *panel) +static int ili9806e_dsi_prepare(struct drm_panel *panel) { - struct ili9806e_panel *ctx = to_ili9806e_panel(panel); + struct ili9806e_dsi_panel *ctx = ili9806e_get_transport(panel); + struct device *dev = &ctx->dsi->dev; int ret; - ret = ili9806e_power_on(ctx); + ret = ili9806e_power_on(dev); if (ret < 0) return ret; - ret = ili9806e_on(ctx); + ret = ili9806e_dsi_on(ctx); if (ret < 0) { - ili9806e_power_off(ctx); + ili9806e_power_off(dev); return ret; } return 0; } -static int ili9806e_unprepare(struct drm_panel *panel) +static int ili9806e_dsi_unprepare(struct drm_panel *panel) { - struct ili9806e_panel *ctx = to_ili9806e_panel(panel); - struct mipi_dsi_device *dsi = ctx->dsi; + struct ili9806e_dsi_panel *ctx = ili9806e_get_transport(panel); + struct device *dev = &ctx->dsi->dev; int ret; - ili9806e_off(ctx); + ili9806e_dsi_off(ctx); - ret = ili9806e_power_off(ctx); + ret = ili9806e_power_off(dev); if (ret < 0) - dev_err(&dsi->dev, "power off failed: %d\n", ret); + dev_err(dev, "power off failed: %d\n", ret); return ret; } -static int ili9806e_get_modes(struct drm_panel *panel, +static int ili9806e_dsi_get_modes(struct drm_panel *panel, struct drm_connector *connector) { - struct ili9806e_panel *ctx = to_ili9806e_panel(panel); + struct ili9806e_dsi_panel *ctx = ili9806e_get_transport(panel); const struct drm_display_mode *mode = ctx->desc->display_mode; return drm_connector_helper_get_modes_fixed(connector, mode); } -static enum drm_panel_orientation ili9806e_get_orientation(struct drm_panel *panel) +static enum drm_panel_orientation ili9806e_dsi_get_orientation(struct drm_panel *panel) { - struct ili9806e_panel *ctx = to_ili9806e_panel(panel); + struct ili9806e_dsi_panel *ctx = ili9806e_get_transport(panel); return ctx->orientation; } -static const struct drm_panel_funcs ili9806e_funcs = { - .prepare = ili9806e_prepare, - .unprepare = ili9806e_unprepare, - .get_modes = ili9806e_get_modes, - .get_orientation = ili9806e_get_orientation, +static const struct drm_panel_funcs ili9806e_dsi_funcs = { + .prepare = ili9806e_dsi_prepare, + .unprepare = ili9806e_dsi_unprepare, + .get_modes = ili9806e_dsi_get_modes, + .get_orientation = ili9806e_dsi_get_orientation, }; static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi) { struct device *dev = &dsi->dev; - struct ili9806e_panel *ctx; - int i, ret; + struct ili9806e_dsi_panel *ctx; + int ret; - ctx = devm_drm_panel_alloc(dev, struct ili9806e_panel, panel, &ili9806e_funcs, - DRM_MODE_CONNECTOR_DSI); - if (IS_ERR(ctx)) - return PTR_ERR(ctx); + ctx = devm_kzalloc(dev, sizeof(struct ili9806e_dsi_panel), GFP_KERNEL); + if (!ctx) + return -ENOMEM; ctx->desc = device_get_match_data(dev); - for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) - ctx->supplies[i].supply = regulator_names[i]; - - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), - ctx->supplies); - if (ret < 0) - return ret; - - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) - return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), - "Failed to get reset-gpios\n"); - mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; @@ -197,17 +136,15 @@ static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi) if (ret) return dev_err_probe(dev, ret, "Failed to get orientation\n"); - ret = drm_panel_of_backlight(&ctx->panel); + ret = ili9806e_probe(dev, ctx, &ili9806e_dsi_funcs, + DRM_MODE_CONNECTOR_DSI); if (ret) - return dev_err_probe(dev, ret, "Failed to get backlight\n"); - - ctx->panel.prepare_prev_first = true; - drm_panel_add(&ctx->panel); + return ret; ret = mipi_dsi_attach(dsi); if (ret < 0) { dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); - drm_panel_remove(&ctx->panel); + ili9806e_remove(dev); return ret; } @@ -216,10 +153,8 @@ static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi) static void ili9806e_dsi_remove(struct mipi_dsi_device *dsi) { - struct ili9806e_panel *ctx = mipi_dsi_get_drvdata(dsi); - mipi_dsi_detach(dsi); - drm_panel_remove(&ctx->panel); + ili9806e_remove(&dsi->dev); } static void com35h3p70ulc_init(struct mipi_dsi_multi_context *ctx) @@ -369,7 +304,7 @@ static const struct drm_display_mode com35h3p70ulc_default_mode = { .height_mm = 71, }; -static const struct panel_desc com35h3p70ulc_desc = { +static const struct ili9806e_dsi_panel_desc com35h3p70ulc_desc = { .init_sequence = com35h3p70ulc_init, .display_mode = &com35h3p70ulc_default_mode, .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | @@ -533,7 +468,7 @@ static const struct drm_display_mode dmt028vghmcmi_1d_default_mode = { .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, }; -static const struct panel_desc dmt028vghmcmi_1d_desc = { +static const struct ili9806e_dsi_panel_desc dmt028vghmcmi_1d_desc = { .init_sequence = dmt028vghmcmi_1d_init, .display_mode = &dmt028vghmcmi_1d_default_mode, .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | @@ -542,17 +477,17 @@ static const struct panel_desc dmt028vghmcmi_1d_desc = { .lanes = 2, }; -static const struct of_device_id ili9806e_of_match[] = { +static const struct of_device_id ili9806e_dsi_of_match[] = { { .compatible = "densitron,dmt028vghmcmi-1d", .data = &dmt028vghmcmi_1d_desc }, { .compatible = "ortustech,com35h3p70ulc", .data = &com35h3p70ulc_desc }, { } }; -MODULE_DEVICE_TABLE(of, ili9806e_of_match); +MODULE_DEVICE_TABLE(of, ili9806e_dsi_of_match); static struct mipi_dsi_driver ili9806e_dsi_driver = { .driver = { .name = "ili9806e-dsi", - .of_match_table = ili9806e_of_match, + .of_match_table = ili9806e_dsi_of_match, }, .probe = ili9806e_dsi_probe, .remove = ili9806e_dsi_remove, @@ -561,5 +496,5 @@ module_mipi_dsi_driver(ili9806e_dsi_driver); MODULE_AUTHOR("Gunnar Dibbern <gunnar.dibbern@lht.dlh.de>"); MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>"); -MODULE_DESCRIPTION("Ilitek ILI9806E Controller Driver"); +MODULE_DESCRIPTION("Ilitek ILI9806E Controller DSI Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-spi.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-spi.c new file mode 100644 index 000000000000..9d10b0d28f52 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-spi.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SPI interface to the Ilitek ILI9806E panel. + * + * Copyright (c) 2026 Amarula Solutions, Dario Binacchi <dario.binacchi@amarulasolutions.com> + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/media-bus-format.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include <drm/drm_mipi_dbi.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +#include <video/mipi_display.h> + +#include "panel-ilitek-ili9806e-core.h" + +struct ili9806e_spi_panel { + struct spi_device *spi; + struct mipi_dbi dbi; + const struct ili9806e_spi_panel_desc *desc; +}; + +struct ili9806e_spi_panel_desc { + const struct drm_display_mode *display_mode; + u32 bus_format; + u32 bus_flags; + void (*init_sequence)(struct ili9806e_spi_panel *ctx); +}; + +static int ili9806e_spi_off(struct ili9806e_spi_panel *ctx) +{ + struct mipi_dbi *dbi = &ctx->dbi; + + mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF, 0x00); + mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE, 0x00); + + return 0; +} + +static int ili9806e_spi_unprepare(struct drm_panel *panel) +{ + struct ili9806e_spi_panel *ctx = ili9806e_get_transport(panel); + struct device *dev = &ctx->spi->dev; + int ret; + + ili9806e_spi_off(ctx); + + ret = ili9806e_power_off(dev); + if (ret) + dev_err(dev, "power off failed: %d\n", ret); + + return 0; +} + +static int ili9806e_spi_prepare(struct drm_panel *panel) +{ + struct ili9806e_spi_panel *ctx = ili9806e_get_transport(panel); + struct device *dev = &ctx->spi->dev; + int ret; + + ret = ili9806e_power_on(dev); + if (ret) + return ret; + + if (ctx->desc->init_sequence) + ctx->desc->init_sequence(ctx); + + return 0; +} + +static int ili9806e_spi_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct ili9806e_spi_panel *ctx = ili9806e_get_transport(panel); + const struct ili9806e_spi_panel_desc *desc = ctx->desc; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, desc->display_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + connector->display_info.bus_flags = desc->bus_flags; + drm_display_info_set_bus_formats(&connector->display_info, + &desc->bus_format, 1); + + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs ili9806e_spi_funcs = { + .unprepare = ili9806e_spi_unprepare, + .prepare = ili9806e_spi_prepare, + .get_modes = ili9806e_spi_get_modes, +}; + +static int ili9806e_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct ili9806e_spi_panel *ctx; + int err; + + ctx = devm_kzalloc(dev, sizeof(struct ili9806e_spi_panel), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->spi = spi; + ctx->desc = device_get_match_data(dev); + + err = mipi_dbi_spi_init(spi, &ctx->dbi, NULL); + if (err) + return dev_err_probe(dev, err, "MIPI DBI init failed\n"); + + return ili9806e_probe(dev, ctx, &ili9806e_spi_funcs, + DRM_MODE_CONNECTOR_DPI); +} + +static void ili9806e_spi_remove(struct spi_device *spi) +{ + ili9806e_remove(&spi->dev); +} + +static void rk050hr345_ct106a_init(struct ili9806e_spi_panel *ctx) +{ + struct mipi_dbi *dbi = &ctx->dbi; + + /* Switch to page 1 */ + mipi_dbi_command(dbi, 0xff, 0xff, 0x98, 0x06, 0x04, 0x01); + /* Interface Settings */ + mipi_dbi_command(dbi, 0x08, 0x10); + mipi_dbi_command(dbi, 0x21, 0x01); + /* Panel Settings */ + mipi_dbi_command(dbi, 0x30, 0x01); + mipi_dbi_command(dbi, 0x31, 0x00); + /* Power Control */ + mipi_dbi_command(dbi, 0x40, 0x15); + mipi_dbi_command(dbi, 0x41, 0x44); + mipi_dbi_command(dbi, 0x42, 0x03); + mipi_dbi_command(dbi, 0x43, 0x09); + mipi_dbi_command(dbi, 0x44, 0x09); + mipi_dbi_command(dbi, 0x50, 0x78); + mipi_dbi_command(dbi, 0x51, 0x78); + mipi_dbi_command(dbi, 0x52, 0x00); + mipi_dbi_command(dbi, 0x53, 0x3a); + mipi_dbi_command(dbi, 0x57, 0x50); + /* Timing Control */ + mipi_dbi_command(dbi, 0x60, 0x07); + mipi_dbi_command(dbi, 0x61, 0x00); + mipi_dbi_command(dbi, 0x62, 0x08); + mipi_dbi_command(dbi, 0x63, 0x00); + /* Gamma Settings */ + mipi_dbi_command(dbi, 0xa0, 0x00); + mipi_dbi_command(dbi, 0xa1, 0x03); + mipi_dbi_command(dbi, 0xa2, 0x0b); + mipi_dbi_command(dbi, 0xa3, 0x0f); + mipi_dbi_command(dbi, 0xa4, 0x0b); + mipi_dbi_command(dbi, 0xa5, 0x1b); + mipi_dbi_command(dbi, 0xa6, 0x0a); + mipi_dbi_command(dbi, 0xa7, 0x0a); + mipi_dbi_command(dbi, 0xa8, 0x02); + mipi_dbi_command(dbi, 0xa9, 0x07); + mipi_dbi_command(dbi, 0xaa, 0x05); + mipi_dbi_command(dbi, 0xab, 0x03); + mipi_dbi_command(dbi, 0xac, 0x0e); + mipi_dbi_command(dbi, 0xad, 0x32); + mipi_dbi_command(dbi, 0xae, 0x2d); + mipi_dbi_command(dbi, 0xaf, 0x00); + mipi_dbi_command(dbi, 0xc0, 0x00); + mipi_dbi_command(dbi, 0xc1, 0x03); + mipi_dbi_command(dbi, 0xc2, 0x0e); + mipi_dbi_command(dbi, 0xc3, 0x10); + mipi_dbi_command(dbi, 0xc4, 0x09); + mipi_dbi_command(dbi, 0xc5, 0x17); + mipi_dbi_command(dbi, 0xc6, 0x09); + mipi_dbi_command(dbi, 0xc7, 0x07); + mipi_dbi_command(dbi, 0xc8, 0x04); + mipi_dbi_command(dbi, 0xc9, 0x09); + mipi_dbi_command(dbi, 0xca, 0x06); + mipi_dbi_command(dbi, 0xcb, 0x06); + mipi_dbi_command(dbi, 0xcc, 0x0c); + mipi_dbi_command(dbi, 0xcd, 0x25); + mipi_dbi_command(dbi, 0xce, 0x20); + mipi_dbi_command(dbi, 0xcf, 0x00); + + /* Switch to page 6 */ + mipi_dbi_command(dbi, 0xff, 0xff, 0x98, 0x06, 0x04, 0x06); + /* GIP settings */ + mipi_dbi_command(dbi, 0x00, 0x21); + mipi_dbi_command(dbi, 0x01, 0x09); + mipi_dbi_command(dbi, 0x02, 0x00); + mipi_dbi_command(dbi, 0x03, 0x00); + mipi_dbi_command(dbi, 0x04, 0x01); + mipi_dbi_command(dbi, 0x05, 0x01); + mipi_dbi_command(dbi, 0x06, 0x80); + mipi_dbi_command(dbi, 0x07, 0x05); + mipi_dbi_command(dbi, 0x08, 0x02); + mipi_dbi_command(dbi, 0x09, 0x80); + mipi_dbi_command(dbi, 0x0a, 0x00); + mipi_dbi_command(dbi, 0x0b, 0x00); + mipi_dbi_command(dbi, 0x0c, 0x0a); + mipi_dbi_command(dbi, 0x0d, 0x0a); + mipi_dbi_command(dbi, 0x0e, 0x00); + mipi_dbi_command(dbi, 0x0f, 0x00); + mipi_dbi_command(dbi, 0x10, 0xe0); + mipi_dbi_command(dbi, 0x11, 0xe4); + mipi_dbi_command(dbi, 0x12, 0x04); + mipi_dbi_command(dbi, 0x13, 0x00); + mipi_dbi_command(dbi, 0x14, 0x00); + mipi_dbi_command(dbi, 0x15, 0xc0); + mipi_dbi_command(dbi, 0x16, 0x08); + mipi_dbi_command(dbi, 0x17, 0x00); + mipi_dbi_command(dbi, 0x18, 0x00); + mipi_dbi_command(dbi, 0x19, 0x00); + mipi_dbi_command(dbi, 0x1a, 0x00); + mipi_dbi_command(dbi, 0x1b, 0x00); + mipi_dbi_command(dbi, 0x1c, 0x00); + mipi_dbi_command(dbi, 0x1d, 0x00); + mipi_dbi_command(dbi, 0x20, 0x01); + mipi_dbi_command(dbi, 0x21, 0x23); + mipi_dbi_command(dbi, 0x22, 0x45); + mipi_dbi_command(dbi, 0x23, 0x67); + mipi_dbi_command(dbi, 0x24, 0x01); + mipi_dbi_command(dbi, 0x25, 0x23); + mipi_dbi_command(dbi, 0x26, 0x45); + mipi_dbi_command(dbi, 0x27, 0x67); + mipi_dbi_command(dbi, 0x30, 0x01); + mipi_dbi_command(dbi, 0x31, 0x11); + mipi_dbi_command(dbi, 0x32, 0x00); + mipi_dbi_command(dbi, 0x33, 0xee); + mipi_dbi_command(dbi, 0x34, 0xff); + mipi_dbi_command(dbi, 0x35, 0xbb); + mipi_dbi_command(dbi, 0x36, 0xca); + mipi_dbi_command(dbi, 0x37, 0xdd); + mipi_dbi_command(dbi, 0x38, 0xac); + mipi_dbi_command(dbi, 0x39, 0x76); + mipi_dbi_command(dbi, 0x3a, 0x67); + mipi_dbi_command(dbi, 0x3b, 0x22); + mipi_dbi_command(dbi, 0x3c, 0x22); + mipi_dbi_command(dbi, 0x3d, 0x22); + mipi_dbi_command(dbi, 0x3e, 0x22); + mipi_dbi_command(dbi, 0x3f, 0x22); + mipi_dbi_command(dbi, 0x40, 0x22); + mipi_dbi_command(dbi, 0x52, 0x10); + mipi_dbi_command(dbi, 0x53, 0x10); + + /* Switch to page 7 */ + mipi_dbi_command(dbi, 0xff, 0xff, 0x98, 0x06, 0x04, 0x07); + mipi_dbi_command(dbi, 0x17, 0x22); + mipi_dbi_command(dbi, 0x02, 0x77); + mipi_dbi_command(dbi, 0xe1, 0x79); + mipi_dbi_command(dbi, 0xb3, 0x10); + + /* Switch to page 0 */ + mipi_dbi_command(dbi, 0xff, 0xff, 0x98, 0x06, 0x04, 0x00); + mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, 0x00); // 0x36 + mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); // 0x11 + + msleep(120); + + mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); + + msleep(120); +} + +static const struct drm_display_mode rk050hr345_ct106a_mode = { + .width_mm = 62, + .height_mm = 110, + .clock = 27000, + .hdisplay = 480, + .hsync_start = 480 + 10, + .hsync_end = 480 + 10 + 10, + .htotal = 480 + 10 + 10 + 10, + .vdisplay = 854, + .vsync_start = 854 + 10, + .vsync_end = 854 + 10 + 10, + .vtotal = 854 + 10 + 10 + 10, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER, +}; + +static const struct ili9806e_spi_panel_desc rk050hr345_ct106a_desc = { + .init_sequence = rk050hr345_ct106a_init, + .display_mode = &rk050hr345_ct106a_mode, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, +}; + +static const struct of_device_id ili9806e_spi_of_match[] = { + { .compatible = "rocktech,rk050hr345-ct106a", .data = &rk050hr345_ct106a_desc }, + { } +}; +MODULE_DEVICE_TABLE(of, ili9806e_spi_of_match); + +static const struct spi_device_id ili9806e_spi_ids[] = { + { "rk050hr345-ct106a", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, ili9806e_spi_ids); + +static struct spi_driver ili9806e_spi_driver = { + .driver = { + .name = "ili9806e-spi", + .of_match_table = ili9806e_spi_of_match, + }, + .probe = ili9806e_spi_probe, + .remove = ili9806e_spi_remove, + .id_table = ili9806e_spi_ids, +}; +module_spi_driver(ili9806e_spi_driver); + +MODULE_AUTHOR("Dario Binacchi <dario.binacchi@amarulasolutions.com>"); +MODULE_DESCRIPTION("Ilitek ILI9806E LCD SPI Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c index 29e1f6aea480..7e8b5e059575 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c @@ -79,70 +79,57 @@ static inline struct nt36672a_panel *to_nt36672a_panel(struct drm_panel *panel) return container_of(panel, struct nt36672a_panel, base); } -static int nt36672a_send_cmds(struct drm_panel *panel, const struct nt36672a_panel_cmd *cmds, - int num) +static void nt36672a_send_cmds(struct mipi_dsi_multi_context *dsi_ctx, + const struct nt36672a_panel_cmd *cmds, int num) { - struct nt36672a_panel *pinfo = to_nt36672a_panel(panel); unsigned int i; - int err; for (i = 0; i < num; i++) { const struct nt36672a_panel_cmd *cmd = &cmds[i]; - err = mipi_dsi_dcs_write(pinfo->link, cmd->data[0], cmd->data + 1, 1); - - if (err < 0) - return err; + /* cmd->data[0] is the DCS command, cmd->data[1] is the parameter */ + mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd->data, sizeof(cmd->data)); } - - return 0; } -static int nt36672a_panel_power_off(struct drm_panel *panel) +static void nt36672a_panel_power_off(struct drm_panel *panel) { struct nt36672a_panel *pinfo = to_nt36672a_panel(panel); - int ret = 0; + int ret; gpiod_set_value(pinfo->reset_gpio, 1); ret = regulator_bulk_disable(ARRAY_SIZE(pinfo->supplies), pinfo->supplies); if (ret) dev_err(panel->dev, "regulator_bulk_disable failed %d\n", ret); - - return ret; } static int nt36672a_panel_unprepare(struct drm_panel *panel) { struct nt36672a_panel *pinfo = to_nt36672a_panel(panel); - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = pinfo->link }; /* send off cmds */ - ret = nt36672a_send_cmds(panel, pinfo->desc->off_cmds, - pinfo->desc->num_off_cmds); + nt36672a_send_cmds(&dsi_ctx, pinfo->desc->off_cmds, + pinfo->desc->num_off_cmds); - if (ret < 0) - dev_err(panel->dev, "failed to send DCS off cmds: %d\n", ret); - - ret = mipi_dsi_dcs_set_display_off(pinfo->link); - if (ret < 0) - dev_err(panel->dev, "set_display_off cmd failed ret = %d\n", ret); + /* Reset error to continue with display off even if send_cmds failed */ + dsi_ctx.accum_err = 0; + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + /* Reset error to continue power-down even if display off failed */ + dsi_ctx.accum_err = 0; /* 120ms delay required here as per DCS spec */ msleep(120); - ret = mipi_dsi_dcs_enter_sleep_mode(pinfo->link); - if (ret < 0) - dev_err(panel->dev, "enter_sleep cmd failed ret = %d\n", ret); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); /* 0x3C = 60ms delay */ msleep(60); - ret = nt36672a_panel_power_off(panel); - if (ret < 0) - dev_err(panel->dev, "power_off failed ret = %d\n", ret); + nt36672a_panel_power_off(panel); - return ret; + return 0; } static int nt36672a_panel_power_on(struct nt36672a_panel *pinfo) @@ -170,52 +157,31 @@ static int nt36672a_panel_power_on(struct nt36672a_panel *pinfo) static int nt36672a_panel_prepare(struct drm_panel *panel) { struct nt36672a_panel *pinfo = to_nt36672a_panel(panel); - int err; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = pinfo->link }; - err = nt36672a_panel_power_on(pinfo); - if (err < 0) - goto poweroff; + dsi_ctx.accum_err = nt36672a_panel_power_on(pinfo); /* send first part of init cmds */ - err = nt36672a_send_cmds(panel, pinfo->desc->on_cmds_1, - pinfo->desc->num_on_cmds_1); + nt36672a_send_cmds(&dsi_ctx, pinfo->desc->on_cmds_1, + pinfo->desc->num_on_cmds_1); - if (err < 0) { - dev_err(panel->dev, "failed to send DCS Init 1st Code: %d\n", err); - goto poweroff; - } - - err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link); - if (err < 0) { - dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); - goto poweroff; - } + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); /* 0x46 = 70 ms delay */ - msleep(70); + mipi_dsi_msleep(&dsi_ctx, 70); - err = mipi_dsi_dcs_set_display_on(pinfo->link); - if (err < 0) { - dev_err(panel->dev, "failed to Set Display ON: %d\n", err); - goto poweroff; - } + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); /* Send rest of the init cmds */ - err = nt36672a_send_cmds(panel, pinfo->desc->on_cmds_2, - pinfo->desc->num_on_cmds_2); + nt36672a_send_cmds(&dsi_ctx, pinfo->desc->on_cmds_2, + pinfo->desc->num_on_cmds_2); - if (err < 0) { - dev_err(panel->dev, "failed to send DCS Init 2nd Code: %d\n", err); - goto poweroff; - } + mipi_dsi_msleep(&dsi_ctx, 120); - msleep(120); + if (dsi_ctx.accum_err < 0) + gpiod_set_value(pinfo->reset_gpio, 0); - return 0; - -poweroff: - gpiod_set_value(pinfo->reset_gpio, 0); - return err; + return dsi_ctx.accum_err; } static int nt36672a_panel_get_modes(struct drm_panel *panel, diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8fc0-m1906f9.c b/drivers/gpu/drm/panel/panel-samsung-s6e8fc0-m1906f9.c new file mode 100644 index 000000000000..199ff99efd78 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8fc0-m1906f9.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) Kamil GoÅ‚da <kamil.golda@protonmail.com> +// Copyright (c) Yedaya Katsman <yedaya.ka@gmail.com> +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: +// Copyright (c) The Linux Foundation. All rights reserved. + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +struct s6e8fc0_ctx { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; +}; + +static const struct regulator_bulk_data s6e8fc0_supplies[] = { + { .supply = "vdd" }, + { .supply = "vci" }, +}; + +static inline +struct s6e8fc0_ctx *to_s6e8fc0_ctx(struct drm_panel *panel) +{ + return container_of_const(panel, struct s6e8fc0_ctx, panel); +} + +static void s6e8fc0_m1906f9_reset(struct s6e8fc0_ctx *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(12000, 13000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(2000, 3000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); +} + +#define s6e8fc0_test_key_on_lvl2(ctx) \ + mipi_dsi_dcs_write_seq_multi(ctx, 0xf0, 0x5a, 0x5a) +#define s6e8fc0_test_key_off_lvl2(ctx) \ + mipi_dsi_dcs_write_seq_multi(ctx, 0xf0, 0xa5, 0xa5) +#define s6e8fc0_test_key_on_lvl3(ctx) \ + mipi_dsi_dcs_write_seq_multi(ctx, 0xfc, 0x5a, 0x5a) +#define s6e8fc0_test_key_off_lvl3(ctx) \ + mipi_dsi_dcs_write_seq_multi(ctx, 0xfc, 0xa5, 0xa5) + +static int s6e8fc0_m1906f9_on(struct s6e8fc0_ctx *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + s6e8fc0_test_key_on_lvl3(&dsi_ctx); + + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + 0x20); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x04, 0xed); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xed, + 0xe4, 0x08, 0x96, 0xa4, 0x2a, 0x72, 0xe2, + 0xca, 0x00); + s6e8fc0_test_key_off_lvl3(&dsi_ctx); + s6e8fc0_test_key_on_lvl2(&dsi_ctx); + s6e8fc0_test_key_on_lvl3(&dsi_ctx); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x05, 0xf4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xed, 0x01, 0x81, 0x04); + s6e8fc0_test_key_off_lvl2(&dsi_ctx); + s6e8fc0_test_key_off_lvl3(&dsi_ctx); + + return dsi_ctx.accum_err; +} + +static int s6e8fc0_m1906f9_off(struct s6e8fc0_ctx *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 20); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + + return dsi_ctx.accum_err; +} + +static int s6e8fc0_m1906f9_prepare(struct drm_panel *panel) +{ + struct s6e8fc0_ctx *ctx = to_s6e8fc0_ctx(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(s6e8fc0_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + s6e8fc0_m1906f9_reset(ctx); + + ret = s6e8fc0_m1906f9_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(s6e8fc0_supplies), ctx->supplies); + return ret; + } + + return 0; +} + +static int s6e8fc0_m1906f9_unprepare(struct drm_panel *panel) +{ + struct s6e8fc0_ctx *ctx = to_s6e8fc0_ctx(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = s6e8fc0_m1906f9_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(s6e8fc0_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode s6e8fc0_m1906f9_samsungp_mode = { + .clock = (720 + 350 + 40 + 294) * (1560 + 17 + 2 + 5) * 60 / 1000, + .hdisplay = 720, + .hsync_start = 720 + 350, + .hsync_end = 720 + 350 + 40, + .htotal = 720 + 350 + 40 + 294, + .vdisplay = 1560, + .vsync_start = 1560 + 17, + .vsync_end = 1560 + 17 + 2, + .vtotal = 1560 + 17 + 2 + 5, + .width_mm = 65, + .height_mm = 140, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static int s6e8fc0_m1906f9_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &s6e8fc0_m1906f9_samsungp_mode); +} + +static const struct drm_panel_funcs s6e8fc0_m1906f9_panel_funcs = { + .prepare = s6e8fc0_m1906f9_prepare, + .unprepare = s6e8fc0_m1906f9_unprepare, + .get_modes = s6e8fc0_m1906f9_get_modes, +}; + +static int s6e8fc0_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static int s6e8fc0_bl_get_brightness(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness; + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return brightness; +} + +static const struct backlight_ops s6e8fc0_bl_ops = { + .update_status = s6e8fc0_bl_update_status, + .get_brightness = s6e8fc0_bl_get_brightness, +}; + +static struct backlight_device * +s6e8fc0_m1906f9_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 512, + .max_brightness = 1023, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &s6e8fc0_bl_ops, &props); +} + +static int s6e8fc0_m1906f9_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct s6e8fc0_ctx *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct s6e8fc0_ctx, panel, + &s6e8fc0_m1906f9_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(s6e8fc0_supplies), + s6e8fc0_supplies, + &ctx->supplies); + if (ret < 0) + return ret; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = s6e8fc0_m1906f9_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void s6e8fc0_remove(struct mipi_dsi_device *dsi) +{ + struct s6e8fc0_ctx *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id samsung_s6e8fc0_of_match[] = { + { .compatible = "samsung,s6e8fc0-m1906f9" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, samsung_s6e8fc0_of_match); + +static struct mipi_dsi_driver s6e8fc0_driver = { + .probe = s6e8fc0_m1906f9_probe, + .remove = s6e8fc0_remove, + .driver = { + .name = "panel-samsung-s6e8fc0-m1906f9", + .of_match_table = samsung_s6e8fc0_of_match, + }, +}; +module_mipi_dsi_driver(s6e8fc0_driver); + +MODULE_AUTHOR("Kamil GoÅ‚da <kamil.golda@protonmail.com>"); +MODULE_DESCRIPTION("DRM driver for Samsung s6e8fc0 DSI controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index 36abfa2e65e9..dd1eaba23ad3 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -201,6 +201,7 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev, &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); + sharp_nt->base.prepare_prev_first = true; ret = drm_panel_of_backlight(&sharp_nt->base); if (ret) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index e1d15434ea54..236bd56208cc 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1295,7 +1295,7 @@ static const struct panel_desc auo_g190ean01 = { .height = 301, }, .delay = { - .prepare = 50, + .prepare = 30, .enable = 200, .disable = 110, .unprepare = 1000, @@ -2947,6 +2947,35 @@ static const struct panel_desc innolux_zj070na_01p = { }, }; +static const struct display_timing jutouch_jt070tm041_timing = { + .pixelclock = { 40800000, 51200000, 67200000 }, + .hactive = { 1024, 1024, 1024 }, + .hfront_porch = { 16, 160, 216 }, + .hback_porch = { 160, 160, 160 }, + .hsync_len = { 1, 1, 140 }, + .vactive = { 600, 600, 600 }, + .vfront_porch = { 1, 12, 127 }, + .vback_porch = { 23, 23, 23 }, + .vsync_len = { 1, 1, 20 }, +}; + +static const struct panel_desc jutouch_jt070tm041 = { + .timings = &jutouch_jt070tm041_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 154, + .height = 86, + }, + .delay = { + .enable = 50, + .disable = 50, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing jutouch_jt101tm023_timing = { .pixelclock = { 66300000, 72400000, 78900000 }, .hactive = { 1280, 1280, 1280 }, @@ -5414,6 +5443,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "innolux,zj070na-01p", .data = &innolux_zj070na_01p, }, { + .compatible = "jutouch,jt070tm041", + .data = &jutouch_jt070tm041, + }, { .compatible = "jutouch,jt101tm023", .data = &jutouch_jt101tm023, }, { @@ -5609,6 +5641,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "tianma,p0700wxf1mbaa", .data = &tianma_p0700wxf1mbaa, }, { + .compatible = "tianma,tm050rdh03", + .data = &ontat_kd50g21_40nt_a1, + }, { .compatible = "tianma,tm070jdhg30", .data = &tianma_tm070jdhg30, }, { diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 1bcec6a2e3e0..87d27c3c1456 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -13,7 +13,9 @@ #include <linux/pagemap.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/sched/clock.h> #include <linux/time64.h> +#include <linux/time_namespace.h> #include <drm/drm_auth.h> #include <drm/drm_debugfs.h> @@ -761,22 +763,135 @@ static void panthor_submit_ctx_cleanup(struct panthor_submit_ctx *ctx, kvfree(ctx->jobs); } +#define VALID_TIMESTAMP_QUERY_FLAGS \ + (DRM_PANTHOR_TIMESTAMP_GPU | \ + DRM_PANTHOR_TIMESTAMP_CPU_TYPE_MASK | \ + DRM_PANTHOR_TIMESTAMP_GPU_OFFSET | \ + DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT | \ + DRM_PANTHOR_TIMESTAMP_FREQ | \ + DRM_PANTHOR_TIMESTAMP_DURATION) + static int panthor_query_timestamp_info(struct panthor_device *ptdev, struct drm_panthor_timestamp_info *arg) { int ret; + u32 flags; + unsigned long irq_flags; + struct timespec64 cpu_ts; + u64 query_start_time; + bool minimize_interruption; + u32 timestamp_types = 0; + + if (arg->flags != 0) { + flags = arg->flags; + } else { + /* + * If flags are 0, then ask for the same things that we asked + * for before flags were added. + */ + flags = DRM_PANTHOR_TIMESTAMP_GPU | + DRM_PANTHOR_TIMESTAMP_GPU_OFFSET | + DRM_PANTHOR_TIMESTAMP_FREQ; + } + + switch (flags & DRM_PANTHOR_TIMESTAMP_CPU_TYPE_MASK) { + case DRM_PANTHOR_TIMESTAMP_CPU_NONE: + break; + case DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC: + case DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC_RAW: + timestamp_types++; + break; + default: + return -EINVAL; + } + + if (flags & ~VALID_TIMESTAMP_QUERY_FLAGS) + return -EINVAL; + + if (flags & DRM_PANTHOR_TIMESTAMP_GPU) + timestamp_types++; + if (flags & DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT) + timestamp_types++; + + /* If user asked to obtain timestamps from more than one source, + * then it very likely means they want them to be as close as possible. + * If they asked for duration, then that likely means that they + * want to know how long obtaining timestamp takes, without random + * events, like process scheduling or interrupts. + */ + minimize_interruption = + (flags & DRM_PANTHOR_TIMESTAMP_DURATION) || + (timestamp_types >= 2); ret = panthor_device_resume_and_get(ptdev); if (ret) return ret; + if (flags & DRM_PANTHOR_TIMESTAMP_FREQ) { #ifdef CONFIG_ARM_ARCH_TIMER - arg->timestamp_frequency = arch_timer_get_cntfrq(); + arg->timestamp_frequency = arch_timer_get_cntfrq(); #else - arg->timestamp_frequency = 0; + arg->timestamp_frequency = 0; #endif - arg->current_timestamp = gpu_read64_counter(ptdev, GPU_TIMESTAMP); - arg->timestamp_offset = gpu_read64(ptdev, GPU_TIMESTAMP_OFFSET); + } else { + arg->timestamp_frequency = 0; + } + + if (flags & DRM_PANTHOR_TIMESTAMP_GPU_OFFSET) + arg->timestamp_offset = gpu_read64(ptdev, GPU_TIMESTAMP_OFFSET); + else + arg->timestamp_offset = 0; + + if (minimize_interruption) { + preempt_disable(); + local_irq_save(irq_flags); + } + + if (flags & DRM_PANTHOR_TIMESTAMP_DURATION) + query_start_time = local_clock(); + else + query_start_time = 0; + + if (flags & DRM_PANTHOR_TIMESTAMP_GPU) + arg->current_timestamp = gpu_read64_counter(ptdev, GPU_TIMESTAMP); + else + arg->current_timestamp = 0; + + switch (flags & DRM_PANTHOR_TIMESTAMP_CPU_TYPE_MASK) { + case DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC: + ktime_get_ts64(&cpu_ts); + break; + case DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC_RAW: + ktime_get_raw_ts64(&cpu_ts); + break; + default: + break; + } + + if (flags & DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT) + arg->cycle_count = gpu_read64_counter(ptdev, GPU_CYCLE_COUNT); + else + arg->cycle_count = 0; + + if (flags & DRM_PANTHOR_TIMESTAMP_DURATION) + arg->duration_nsec = local_clock() - query_start_time; + else + arg->duration_nsec = 0; + + if (minimize_interruption) { + local_irq_restore(irq_flags); + preempt_enable(); + } + + if (flags & DRM_PANTHOR_TIMESTAMP_CPU_TYPE_MASK) { + timens_add_monotonic(&cpu_ts); + + arg->cpu_timestamp_sec = cpu_ts.tv_sec; + arg->cpu_timestamp_nsec = cpu_ts.tv_nsec; + } else { + arg->cpu_timestamp_sec = 0; + arg->cpu_timestamp_nsec = 0; + } pm_runtime_put(ptdev->base.dev); return 0; @@ -851,8 +966,14 @@ static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct d return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->csif_info); case DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO: - ret = panthor_query_timestamp_info(ptdev, ×tamp_info); + ret = copy_struct_from_user(×tamp_info, + sizeof(timestamp_info), + u64_to_user_ptr(args->pointer), + args->size); + if (ret) + return ret; + ret = panthor_query_timestamp_info(ptdev, ×tamp_info); if (ret) return ret; @@ -1680,6 +1801,7 @@ static void panthor_debugfs_init(struct drm_minor *minor) * - adds DRM_IOCTL_PANTHOR_BO_SYNC ioctl * - adds DRM_IOCTL_PANTHOR_BO_QUERY_INFO ioctl * - adds drm_panthor_gpu_info::selected_coherency + * - 1.8 - extends DEV_QUERY_TIMESTAMP_INFO with flags */ static const struct drm_driver panthor_drm_driver = { .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | @@ -1693,7 +1815,7 @@ static const struct drm_driver panthor_drm_driver = { .name = "panthor", .desc = "Panthor DRM driver", .major = 1, - .minor = 7, + .minor = 8, .gem_create_object = panthor_gem_create_object, .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 5a904ca64525..8886002e1d31 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -581,7 +581,7 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev, if (hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_PROT) { drm_warn(&ptdev->base, - "Firmware protected mode entry not be supported, ignoring"); + "Firmware protected mode entry is not supported, ignoring"); return 0; } @@ -750,7 +750,7 @@ static int panthor_fw_load_entry(struct panthor_device *ptdev, if ((iter->offset % sizeof(u32)) || (CSF_FW_BINARY_ENTRY_SIZE(ehdr) % sizeof(u32))) { - drm_err(&ptdev->base, "Firmware entry isn't 32 bit aligned, offset=0x%x size=0x%x\n", + drm_err(&ptdev->base, "Firmware entry is not 32-bit aligned, offset=0x%x size=0x%x\n", (u32)(iter->offset - sizeof(u32)), CSF_FW_BINARY_ENTRY_SIZE(ehdr)); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index b4aa49b1ac63..4b10715f951c 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2915,9 +2915,11 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, if (rdev->family == CHIP_HAINAN) { if ((rdev->pdev->revision == 0x81) || (rdev->pdev->revision == 0xC3) || + (rdev->pdev->device == 0x6660) || (rdev->pdev->device == 0x6664) || (rdev->pdev->device == 0x6665) || - (rdev->pdev->device == 0x6667)) { + (rdev->pdev->device == 0x6667) || + (rdev->pdev->device == 0x666F)) { max_sclk = 75000; } if ((rdev->pdev->revision == 0xC3) || diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.c b/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.c index 93ba115d654f..5bced9d778e8 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.c @@ -59,7 +59,7 @@ static void rcar_cmm_lut_write(struct rcar_cmm *rcmm, /* * rcar_cmm_setup() - Configure the CMM unit - * @pdev: The platform device associated with the CMM instance + * @dev: The device associated with the CMM instance * @config: The CMM unit configuration * * Configure the CMM unit with the given configuration. Currently enabling, @@ -73,10 +73,10 @@ static void rcar_cmm_lut_write(struct rcar_cmm *rcmm, * TODO: Add support for LUT double buffer operations to avoid updating the * LUT table entries while a frame is being displayed. */ -int rcar_cmm_setup(struct platform_device *pdev, +int rcar_cmm_setup(struct device *dev, const struct rcar_cmm_config *config) { - struct rcar_cmm *rcmm = platform_get_drvdata(pdev); + struct rcar_cmm *rcmm = dev_get_drvdata(dev); /* Disable LUT if no table is provided. */ if (!config->lut.table) { @@ -102,7 +102,7 @@ EXPORT_SYMBOL_GPL(rcar_cmm_setup); /* * rcar_cmm_enable() - Enable the CMM unit - * @pdev: The platform device associated with the CMM instance + * @dev: The device associated with the CMM instance * * When the output of the corresponding DU channel is routed to the CMM unit, * the unit shall be enabled before the DU channel is started, and remain @@ -113,11 +113,11 @@ EXPORT_SYMBOL_GPL(rcar_cmm_setup); * It is an error to attempt to enable an already enabled CMM unit, or to * attempt to disable a disabled unit. */ -int rcar_cmm_enable(struct platform_device *pdev) +int rcar_cmm_enable(struct device *dev) { int ret; - ret = pm_runtime_resume_and_get(&pdev->dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; @@ -127,7 +127,7 @@ EXPORT_SYMBOL_GPL(rcar_cmm_enable); /* * rcar_cmm_disable() - Disable the CMM unit - * @pdev: The platform device associated with the CMM instance + * @dev: The device associated with the CMM instance * * See rcar_cmm_enable() for usage information. * @@ -135,27 +135,27 @@ EXPORT_SYMBOL_GPL(rcar_cmm_enable); * state shall thus be restored with rcar_cmm_setup() when re-enabling the CMM * unit after the next rcar_cmm_enable() call. */ -void rcar_cmm_disable(struct platform_device *pdev) +void rcar_cmm_disable(struct device *dev) { - struct rcar_cmm *rcmm = platform_get_drvdata(pdev); + struct rcar_cmm *rcmm = dev_get_drvdata(dev); rcar_cmm_write(rcmm, CM2_LUT_CTRL, 0); rcmm->lut.enabled = false; - pm_runtime_put(&pdev->dev); + pm_runtime_put(dev); } EXPORT_SYMBOL_GPL(rcar_cmm_disable); /* * rcar_cmm_init() - Initialize the CMM unit - * @pdev: The platform device associated with the CMM instance + * @dev: The device associated with the CMM instance * * Return: 0 on success, -EPROBE_DEFER if the CMM is not available yet, * -ENODEV if the DRM_RCAR_CMM config option is disabled */ -int rcar_cmm_init(struct platform_device *pdev) +int rcar_cmm_init(struct device *dev) { - struct rcar_cmm *rcmm = platform_get_drvdata(pdev); + struct rcar_cmm *rcmm = dev_get_drvdata(dev); if (!rcmm) return -EPROBE_DEFER; diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.h b/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.h index 628072acc98b..c420113430b9 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_cmm.h @@ -10,8 +10,8 @@ #define CM2_LUT_SIZE 256 +struct device; struct drm_color_lut; -struct platform_device; /** * struct rcar_cmm_config - CMM configuration @@ -26,29 +26,29 @@ struct rcar_cmm_config { }; #if IS_ENABLED(CONFIG_DRM_RCAR_CMM) -int rcar_cmm_init(struct platform_device *pdev); +int rcar_cmm_init(struct device *dev); -int rcar_cmm_enable(struct platform_device *pdev); -void rcar_cmm_disable(struct platform_device *pdev); +int rcar_cmm_enable(struct device *dev); +void rcar_cmm_disable(struct device *dev); -int rcar_cmm_setup(struct platform_device *pdev, +int rcar_cmm_setup(struct device *dev, const struct rcar_cmm_config *config); #else -static inline int rcar_cmm_init(struct platform_device *pdev) +static inline int rcar_cmm_init(struct device *dev) { return -ENODEV; } -static inline int rcar_cmm_enable(struct platform_device *pdev) +static inline int rcar_cmm_enable(struct device *dev) { return 0; } -static inline void rcar_cmm_disable(struct platform_device *pdev) +static inline void rcar_cmm_disable(struct device *dev) { } -static inline int rcar_cmm_setup(struct platform_device *pdev, +static inline int rcar_cmm_setup(struct device *dev, const struct rcar_cmm_config *config) { return 0; diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c index 28a5aa5a14d8..7c36c30a75b6 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c @@ -513,13 +513,13 @@ static void rcar_du_cmm_setup(struct drm_crtc *crtc) struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); struct rcar_cmm_config cmm_config = {}; - if (!rcrtc->cmm) + if (!rcrtc->cmm->dev) return; if (drm_lut) cmm_config.lut.table = (struct drm_color_lut *)drm_lut->data; - rcar_cmm_setup(rcrtc->cmm, &cmm_config); + rcar_cmm_setup(rcrtc->cmm->dev, &cmm_config); } /* ----------------------------------------------------------------------------- @@ -667,8 +667,8 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) rcar_du_vsp_disable(rcrtc); - if (rcrtc->cmm) - rcar_cmm_disable(rcrtc->cmm); + if (rcrtc->cmm->dev) + rcar_cmm_disable(rcrtc->cmm->dev); /* * Select switch sync mode. This stops display operation and configures @@ -726,8 +726,8 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(crtc->state); struct rcar_du_device *rcdu = rcrtc->dev; - if (rcrtc->cmm) - rcar_cmm_enable(rcrtc->cmm); + if (rcrtc->cmm->dev) + rcar_cmm_enable(rcrtc->cmm->dev); rcar_du_crtc_get(rcrtc); /* @@ -1300,8 +1300,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, return ret; /* CMM might be disabled for this CRTC. */ - if (rcdu->cmms[swindex]) { - rcrtc->cmm = rcdu->cmms[swindex]; + if (rcdu->cmms[swindex].dev) { + rcrtc->cmm = &rcdu->cmms[swindex]; rgrp->cmms_mask |= BIT(hwindex % 2); drm_mode_crtc_set_gamma_size(crtc, CM2_LUT_SIZE); diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.h index d0f38a8b3561..8857926e109a 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.h @@ -19,6 +19,7 @@ #include <media/vsp1.h> +struct rcar_du_cmm; struct rcar_du_group; struct rcar_du_vsp; @@ -65,7 +66,7 @@ struct rcar_du_crtc { unsigned int vblank_count; struct rcar_du_group *group; - struct platform_device *cmm; + struct rcar_du_cmm *cmm; struct rcar_du_vsp *vsp; unsigned int vsp_pipe; diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.h index 5cfa2bb7ad93..de9c6617a2d4 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.h @@ -22,6 +22,7 @@ struct clk; struct device; +struct device_link; struct drm_bridge; struct drm_property; struct rcar_du_device; @@ -88,6 +89,11 @@ struct rcar_du_device_info { unsigned int lvds_clk_mask; }; +struct rcar_du_cmm { + struct device *dev; + struct device_link *link; +}; + #define RCAR_DU_MAX_CRTCS 4 #define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2) #define RCAR_DU_MAX_VSPS 4 @@ -106,7 +112,7 @@ struct rcar_du_device { unsigned int num_crtcs; struct rcar_du_group groups[RCAR_DU_MAX_GROUPS]; - struct platform_device *cmms[RCAR_DU_MAX_CRTCS]; + struct rcar_du_cmm cmms[RCAR_DU_MAX_CRTCS]; struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS]; struct drm_bridge *lvds[RCAR_DU_MAX_LVDS]; struct drm_bridge *dsi[RCAR_DU_MAX_DSI]; diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c index 60e6f43b8ab2..b2d0e4651e35 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c @@ -19,6 +19,7 @@ #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/dma-buf.h> #include <linux/of.h> @@ -573,7 +574,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, enum rcar_du_output output, struct of_endpoint *ep) { - struct device_node *entity; + struct device_node *entity __free(device_node) = NULL; int ret; /* Locate the connected entity and initialize the encoder. */ @@ -588,7 +589,6 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, dev_dbg(rcdu->dev, "connected entity %pOF is disabled, skipping\n", entity); - of_node_put(entity); return -ENODEV; } @@ -598,15 +598,13 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, "failed to initialize encoder %pOF on output %s (%d), skipping\n", entity, rcar_du_output_name(output), ret); - of_node_put(entity); - return ret; } static int rcar_du_encoders_init(struct rcar_du_device *rcdu) { + struct device_node *ep_node __free(device_node) = NULL; struct device_node *np = rcdu->dev->of_node; - struct device_node *ep_node; unsigned int num_encoders = 0; /* @@ -620,10 +618,8 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu) int ret; ret = of_graph_parse_endpoint(ep_node, &ep); - if (ret < 0) { - of_node_put(ep_node); + if (ret < 0) return ret; - } /* Find the output route corresponding to the port number. */ for (i = 0; i < RCAR_DU_OUTPUT_MAX; ++i) { @@ -644,10 +640,8 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu) /* Process the output pipeline. */ ret = rcar_du_encoders_init_one(rcdu, output, &ep); if (ret < 0) { - if (ret == -EPROBE_DEFER) { - of_node_put(ep_node); + if (ret == -EPROBE_DEFER) return ret; - } continue; } @@ -775,51 +769,47 @@ static int rcar_du_cmm_init(struct rcar_du_device *rcdu) } for (i = 0; i < cells; ++i) { + struct device_node *cmm_node __free(device_node) = NULL; + struct rcar_du_cmm *cmm = &rcdu->cmms[i]; struct platform_device *pdev; - struct device_link *link; - struct device_node *cmm; int ret; - cmm = of_parse_phandle(np, "renesas,cmms", i); - if (!cmm) { + cmm_node = of_parse_phandle(np, "renesas,cmms", i); + if (!cmm_node) { dev_err(rcdu->dev, "Failed to parse 'renesas,cmms' property\n"); return -EINVAL; } - if (!of_device_is_available(cmm)) { + if (!of_device_is_available(cmm_node)) /* It's fine to have a phandle to a non-enabled CMM. */ - of_node_put(cmm); continue; - } - pdev = of_find_device_by_node(cmm); + pdev = of_find_device_by_node(cmm_node); if (!pdev) { dev_err(rcdu->dev, "No device found for CMM%u\n", i); - of_node_put(cmm); return -EINVAL; } - of_node_put(cmm); - /* * -ENODEV is used to report that the CMM config option is * disabled: return 0 and let the DU continue probing. */ - ret = rcar_cmm_init(pdev); + ret = rcar_cmm_init(&pdev->dev); if (ret) { platform_device_put(pdev); return ret == -ENODEV ? 0 : ret; } - rcdu->cmms[i] = pdev; + cmm->dev = &pdev->dev; /* * Enforce suspend/resume ordering by making the CMM a provider * of the DU: CMM is suspended after and resumed before the DU. */ - link = device_link_add(rcdu->dev, &pdev->dev, DL_FLAG_STATELESS); - if (!link) { + cmm->link = device_link_add(rcdu->dev, cmm->dev, + DL_FLAG_STATELESS); + if (!cmm->link) { dev_err(rcdu->dev, "Failed to create device link to CMM%u\n", i); return -EINVAL; @@ -834,8 +824,14 @@ static void rcar_du_modeset_cleanup(struct drm_device *dev, void *res) struct rcar_du_device *rcdu = to_rcar_du_device(dev); unsigned int i; - for (i = 0; i < ARRAY_SIZE(rcdu->cmms); ++i) - platform_device_put(rcdu->cmms[i]); + for (i = 0; i < ARRAY_SIZE(rcdu->cmms); ++i) { + struct rcar_du_cmm *cmm = &rcdu->cmms[i]; + + if (cmm->link) + device_link_del(cmm->link); + + put_device(cmm->dev); + } } int rcar_du_modeset_init(struct rcar_du_device *rcdu) diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.c index 94c22d2db197..a4a49dcd8233 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.c @@ -20,6 +20,7 @@ #include <drm/drm_vblank.h> #include <linux/bitops.h> +#include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -458,6 +459,9 @@ static void rcar_du_vsp_cleanup(struct drm_device *dev, void *res) kfree(vsp->planes); + if (vsp->link) + device_link_del(vsp->link); + put_device(vsp->vsp); } @@ -482,6 +486,18 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, if (ret < 0) return ret; + /* + * Enforce suspend/resume ordering between the DU (consumer) and the + * VSP (supplier). The DU will be suspended before and resume after the + * VSP. + */ + vsp->link = device_link_add(rcdu->dev, vsp->vsp, DL_FLAG_STATELESS); + if (!vsp->link) { + dev_err(rcdu->dev, "Failed to create device link to VSP %s\n", + dev_name(vsp->vsp)); + return -EINVAL; + } + ret = vsp1_du_init(vsp->vsp); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.h index 67630f0b6599..a6731249db34 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.h +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_vsp.h @@ -12,6 +12,7 @@ #include <drm/drm_plane.h> +struct device_link; struct drm_framebuffer; struct rcar_du_format_info; struct rcar_du_vsp; @@ -26,6 +27,7 @@ struct rcar_du_vsp_plane { struct rcar_du_vsp { unsigned int index; struct device *vsp; + struct device_link *link; struct rcar_du_device *dev; struct rcar_du_vsp_plane *planes; unsigned int num_planes; diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c index 29f2b7d24fe5..a87a301326c7 100644 --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c @@ -808,8 +808,7 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi, * commands payload not being saved to memory. */ dsisetr = rzg2l_mipi_dsi_link_read(dsi, DSISETR); - dsisetr &= ~DSISETR_MRPSZ; - dsisetr |= FIELD_PREP(DSISETR_MRPSZ, RZG2L_DCS_BUF_SIZE); + FIELD_MODIFY(DSISETR_MRPSZ, &dsisetr, RZG2L_DCS_BUF_SIZE); rzg2l_mipi_dsi_link_write(dsi, DSISETR, dsisetr); return 0; diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index fdab71d51e2a..96bd3dd239d2 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -171,12 +171,12 @@ static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, { struct drm_display_info *di = &connector->display_info; /* VOP couldn't output YUV video format for eDP rightly */ - u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422; + u32 mask = BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) | BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422); if ((di->color_formats & mask)) { DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); di->color_formats &= ~mask; - di->color_formats |= DRM_COLOR_FORMAT_RGB444; + di->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444); di->bpc = 8; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index a195f5c819a2..843c7ef979b2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1080,6 +1080,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } + if ((cstate->background_color << 16) && + (fb->format->has_alpha || pstate->alpha != 0xffff)) { + drm_dbg_kms(vop2->drm, + "Alpha-blending with background color is unsupported\n"); + return -EINVAL; + } + return 0; } @@ -1552,6 +1559,7 @@ static void vop2_post_config(struct drm_crtc *crtc) struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; struct drm_display_mode *mode = &crtc->state->adjusted_mode; + u64 bgcolor = crtc->state->background_color; u16 vtotal = mode->crtc_vtotal; u16 hdisplay = mode->crtc_hdisplay; u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; @@ -1597,7 +1605,15 @@ static void vop2_post_config(struct drm_crtc *crtc) vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val); } - vop2_vp_write(vp, RK3568_VP_DSP_BG, 0); + /* + * Background color is programmed with 10 bits of precision. + * Since performance is more important than accuracy here, + * make use of the DRM_ARGB64_GET*_BPCS() helpers. + */ + val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED, DRM_ARGB64_GETR_BPCS(bgcolor, 10)); + FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_GREEN, &val, DRM_ARGB64_GETG_BPCS(bgcolor, 10)); + FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_BLUE, &val, DRM_ARGB64_GETB_BPCS(bgcolor, 10)); + vop2_vp_write(vp, RK3568_VP_DSP_BG, val); } static int us_to_vertical_line(struct drm_display_mode *mode, int us) @@ -1983,6 +1999,10 @@ static int vop2_crtc_state_dump(struct drm_crtc *crtc, struct seq_file *s) drm_get_bus_format_name(vcstate->bus_format)); seq_printf(s, "\toutput_mode[%x]", vcstate->output_mode); seq_printf(s, " color_space[%d]\n", vcstate->color_space); + seq_printf(s, "\tbackground color (10bpc): r=0x%x g=0x%x b=0x%x\n", + DRM_ARGB64_GETR_BPCS(cstate->background_color, 10), + DRM_ARGB64_GETG_BPCS(cstate->background_color, 10), + DRM_ARGB64_GETB_BPCS(cstate->background_color, 10)); seq_printf(s, " Display mode: %dx%d%s%d\n", mode->hdisplay, mode->vdisplay, interlaced ? "i" : "p", drm_mode_vrefresh(mode)); @@ -2471,6 +2491,8 @@ static int vop2_create_crtcs(struct vop2 *vop2) return dev_err_probe(drm->dev, ret, "crtc init for video_port%d failed\n", i); + drm_crtc_attach_background_color_property(&vp->crtc); + drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs); if (vop2->lut_regs) { const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index 9124191899ba..37722652844a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -658,6 +658,10 @@ enum dst_factor_mode { #define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV GENMASK(3, 2) #define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV GENMASK(1, 0) +#define RK3568_VP_DSP_BG__DSP_BG_RED GENMASK(29, 20) +#define RK3568_VP_DSP_BG__DSP_BG_GREEN GENMASK(19, 10) +#define RK3568_VP_DSP_BG__DSP_BG_BLUE GENMASK(9, 0) + #define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN BIT(1) #define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN BIT(0) diff --git a/drivers/gpu/drm/sitronix/st7586.c b/drivers/gpu/drm/sitronix/st7586.c index b57ebf37a664..fa58b3d83564 100644 --- a/drivers/gpu/drm/sitronix/st7586.c +++ b/drivers/gpu/drm/sitronix/st7586.c @@ -13,6 +13,7 @@ #include <video/mipi_display.h> #include <drm/clients/drm_client_setup.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> @@ -48,6 +49,20 @@ #define ST7586_DISP_CTRL_MX BIT(6) #define ST7586_DISP_CTRL_MY BIT(7) +struct st7586_device { + struct mipi_dbi_dev dbidev; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct st7586_device *to_st7586_device(struct drm_device *dev) +{ + return container_of(drm_to_mipi_dbi_dev(dev), struct st7586_device, dbidev); +} + /* * The ST7586 controller has an unusual pixel format where 2bpp grayscale is * packed 3 pixels per byte with the first two pixels using 3 bits and the 3rd @@ -147,46 +162,59 @@ err_msg: dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret); } -static void st7586_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +static const u32 st7586_plane_formats[] = { + DRM_FORMAT_XRGB8888, +}; + +static const u64 st7586_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static void st7586_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) { - struct drm_plane_state *state = pipe->plane.state; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); - struct drm_framebuffer *fb = state->fb; + struct drm_plane_state *plane_state = plane->state; + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_rect rect; int idx; - if (!pipe->crtc.state->active) + if (!fb) return; - if (!drm_dev_enter(fb->dev, &idx)) + if (!drm_dev_enter(plane->dev, &idx)) return; - if (drm_atomic_helper_damage_merged(old_state, state, &rect)) + if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect)) st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect, &shadow_plane_state->fmtcnv_state); drm_dev_exit(idx); } -static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static const struct drm_plane_helper_funcs st7586_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = drm_mipi_dbi_plane_helper_atomic_check, + .atomic_update = st7586_plane_helper_atomic_update +}; + +static const struct drm_plane_funcs st7586_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void st7586_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); - struct drm_framebuffer *fb = plane_state->fb; + struct drm_device *drm = crtc->dev; + struct st7586_device *st7586 = to_st7586_device(drm); + struct mipi_dbi_dev *dbidev = &st7586->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; - struct drm_rect rect = { - .x1 = 0, - .x2 = fb->width, - .y1 = 0, - .y2 = fb->height, - }; int idx, ret; u8 addr_mode; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; DRM_DEBUG_KMS("\n"); @@ -242,17 +270,17 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, msleep(100); - st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect, - &shadow_plane_state->fmtcnv_state); - mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); out_exit: drm_dev_exit(idx); } -static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe) +static void st7586_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + struct drm_device *drm = crtc->dev; + struct st7586_device *st7586 = to_st7586_device(drm); + struct mipi_dbi_dev *dbidev = &st7586->dbidev; /* * This callback is not protected by drm_dev_enter/exit since we want to @@ -266,20 +294,37 @@ static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe) mipi_dbi_command(&dbidev->dbi, MIPI_DCS_SET_DISPLAY_OFF); } -static const u32 st7586_formats[] = { - DRM_FORMAT_XRGB8888, +static const struct drm_crtc_helper_funcs st7586_crtc_helper_funcs = { + .mode_valid = drm_mipi_dbi_crtc_helper_mode_valid, + .atomic_check = drm_mipi_dbi_crtc_helper_atomic_check, + .atomic_enable = st7586_crtc_helper_atomic_enable, + .atomic_disable = st7586_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs st7586_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs st7586_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs st7586_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, }; -static const struct drm_simple_display_pipe_funcs st7586_pipe_funcs = { - .mode_valid = mipi_dbi_pipe_mode_valid, - .enable = st7586_pipe_enable, - .disable = st7586_pipe_disable, - .update = st7586_pipe_update, - .begin_fb_access = mipi_dbi_pipe_begin_fb_access, - .end_fb_access = mipi_dbi_pipe_end_fb_access, - .reset_plane = mipi_dbi_pipe_reset_plane, - .duplicate_plane_state = mipi_dbi_pipe_duplicate_plane_state, - .destroy_plane_state = mipi_dbi_pipe_destroy_plane_state, +static const struct drm_connector_funcs st7586_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs st7586_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs st7586_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, }; static const struct drm_display_mode st7586_mode = { @@ -315,19 +360,23 @@ MODULE_DEVICE_TABLE(spi, st7586_id); static int st7586_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct st7586_device *st7586; struct mipi_dbi_dev *dbidev; struct drm_device *drm; struct mipi_dbi *dbi; struct gpio_desc *a0; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; u32 rotation = 0; size_t bufsize; int ret; - dbidev = devm_drm_dev_alloc(dev, &st7586_driver, - struct mipi_dbi_dev, drm); - if (IS_ERR(dbidev)) - return PTR_ERR(dbidev); - + st7586 = devm_drm_dev_alloc(dev, &st7586_driver, struct st7586_device, dbidev.drm); + if (IS_ERR(st7586)) + return PTR_ERR(st7586); + dbidev = &st7586->dbidev; dbi = &dbidev->dbi; drm = &dbidev->drm; @@ -347,23 +396,64 @@ static int st7586_probe(struct spi_device *spi) if (ret) return ret; + /* + * Override value set by mipi_dbi_spi_init(). This driver is a bit + * non-standard, so best to set it explicitly here. + */ + dbi->write_memory_bpw = 8; + /* Cannot read from this controller via SPI */ dbi->read_commands = NULL; - ret = mipi_dbi_dev_init_with_formats(dbidev, &st7586_pipe_funcs, - st7586_formats, ARRAY_SIZE(st7586_formats), - &st7586_mode, rotation, bufsize); + ret = drm_mipi_dbi_dev_init(dbidev, &st7586_mode, st7586_plane_formats[0], + rotation, bufsize); if (ret) return ret; - /* - * we are using 8-bit data, so we are not actually swapping anything, - * but setting mipi->swap_bytes makes mipi_dbi_typec3_command() do the - * right thing and not use 16-bit transfers (which results in swapped - * bytes on little-endian systems and causes out of order data to be - * sent to the display). - */ - dbi->swap_bytes = true; + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &st7586_mode_config_funcs; + drm->mode_config.preferred_depth = 24; + drm->mode_config.helper_private = &st7586_mode_config_helper_funcs; + + plane = &st7586->plane; + ret = drm_universal_plane_init(drm, plane, 0, &st7586_plane_funcs, + st7586_plane_formats, ARRAY_SIZE(st7586_plane_formats), + st7586_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &st7586_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &st7586->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &st7586_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &st7586_crtc_helper_funcs); + + encoder = &st7586->encoder; + ret = drm_encoder_init(drm, encoder, &st7586_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &st7586->connector; + ret = drm_connector_init(drm, connector, &st7586_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &st7586_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; drm_mode_config_reset(drm); diff --git a/drivers/gpu/drm/sitronix/st7735r.c b/drivers/gpu/drm/sitronix/st7735r.c index c1f8228495f6..5a75716ed5ff 100644 --- a/drivers/gpu/drm/sitronix/st7735r.c +++ b/drivers/gpu/drm/sitronix/st7735r.c @@ -52,23 +52,49 @@ struct st7735r_cfg { unsigned int rgb:1; /* RGB (vs. BGR) */ }; -struct st7735r_priv { +struct st7735r_device { struct mipi_dbi_dev dbidev; /* Must be first for .release() */ const struct st7735r_cfg *cfg; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; }; -static void st7735r_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static struct st7735r_device *to_st7735r_device(struct drm_device *drm) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); - struct st7735r_priv *priv = container_of(dbidev, struct st7735r_priv, - dbidev); + return container_of(drm_to_mipi_dbi_dev(drm), struct st7735r_device, dbidev); +} + +static const u32 st7735r_plane_formats[] = { + DRM_MIPI_DBI_PLANE_FORMATS, +}; + +static const u64 st7735r_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static const struct drm_plane_helper_funcs st7735r_plane_helper_funcs = { + DRM_MIPI_DBI_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs st7735r_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void st7735r_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct st7735r_device *st7735r = to_st7735r_device(drm); + struct mipi_dbi_dev *dbidev = &st7735r->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; int ret, idx; u8 addr_mode; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; DRM_DEBUG_KMS("\n"); @@ -109,7 +135,7 @@ static void st7735r_pipe_enable(struct drm_simple_display_pipe *pipe, break; } - if (priv->cfg->rgb) + if (st7735r->cfg->rgb) addr_mode |= ST7735R_RGB; mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); @@ -129,13 +155,40 @@ static void st7735r_pipe_enable(struct drm_simple_display_pipe *pipe, msleep(20); - mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); + backlight_enable(dbidev->backlight); out_exit: drm_dev_exit(idx); } -static const struct drm_simple_display_pipe_funcs st7735r_pipe_funcs = { - DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(st7735r_pipe_enable), +static const struct drm_crtc_helper_funcs st7735r_crtc_helper_funcs = { + DRM_MIPI_DBI_CRTC_HELPER_FUNCS, + .atomic_enable = st7735r_crtc_helper_atomic_enable, +}; + +static const struct drm_crtc_funcs st7735r_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs st7735r_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs st7735r_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs st7735r_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs st7735r_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs st7735r_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, }; static const struct st7735r_cfg jd_t18003_t01_cfg = { @@ -184,10 +237,14 @@ static int st7735r_probe(struct spi_device *spi) struct device *dev = &spi->dev; const struct st7735r_cfg *cfg; struct mipi_dbi_dev *dbidev; - struct st7735r_priv *priv; + struct st7735r_device *st7735r; struct drm_device *drm; struct mipi_dbi *dbi; struct gpio_desc *dc; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; u32 rotation = 0; int ret; @@ -195,13 +252,12 @@ static int st7735r_probe(struct spi_device *spi) if (!cfg) cfg = (void *)spi_get_device_id(spi)->driver_data; - priv = devm_drm_dev_alloc(dev, &st7735r_driver, - struct st7735r_priv, dbidev.drm); - if (IS_ERR(priv)) - return PTR_ERR(priv); + st7735r = devm_drm_dev_alloc(dev, &st7735r_driver, struct st7735r_device, dbidev.drm); + if (IS_ERR(st7735r)) + return PTR_ERR(st7735r); - dbidev = &priv->dbidev; - priv->cfg = cfg; + dbidev = &st7735r->dbidev; + st7735r->cfg = cfg; dbi = &dbidev->dbi; drm = &dbidev->drm; @@ -230,8 +286,52 @@ static int st7735r_probe(struct spi_device *spi) dbidev->left_offset = cfg->left_offset; dbidev->top_offset = cfg->top_offset; - ret = mipi_dbi_dev_init(dbidev, &st7735r_pipe_funcs, &cfg->mode, - rotation); + ret = drm_mipi_dbi_dev_init(dbidev, &cfg->mode, st7735r_plane_formats[0], rotation, 0); + if (ret) + return ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &st7735r_mode_config_funcs; + drm->mode_config.preferred_depth = 16; + drm->mode_config.helper_private = &st7735r_mode_config_helper_funcs; + + plane = &st7735r->plane; + ret = drm_universal_plane_init(drm, plane, 0, &st7735r_plane_funcs, + st7735r_plane_formats, ARRAY_SIZE(st7735r_plane_formats), + st7735r_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &st7735r_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &st7735r->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &st7735r_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &st7735r_crtc_helper_funcs); + + encoder = &st7735r->encoder; + ret = drm_encoder_init(drm, encoder, &st7735r_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &st7735r->connector; + ret = drm_connector_init(drm, connector, &st7735r_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &st7735r_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 6391bdc94a5c..bc35dad53b07 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -798,18 +798,21 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, dev_set_drvdata(dev, backend); spin_lock_init(&backend->frontend_lock); - if (of_property_present(dev->of_node, "interconnects")) { - /* - * This assume we have the same DMA constraints for all our the - * devices in our pipeline (all the backends, but also the - * frontends). This sounds bad, but it has always been the case - * for us, and DRM doesn't do per-device allocation either, so - * we would need to fix DRM first... - */ - ret = of_dma_configure(drm->dev, dev->of_node, true); - if (ret) - return ret; - } + /* + * This assume we have the same DMA constraints for all our the + * devices in our pipeline (all the backends, but also the + * frontends). This sounds bad, but it has always been the case + * for us, and DRM doesn't do per-device allocation either, so + * we would need to fix DRM first... + * + * Always use the first bound backend as the DMA device. While + * our device trees always have all backends enabled, some in + * the wild may actually have the first one disabled. If both + * are enabled, the order in which they are bound is guaranteed + * since the driver adds components in order. + */ + if (drm_dev_dma_dev(drm) == drm->dev) + drm_dev_set_dma_dev(drm, dev); backend->engine.node = dev->of_node; backend->engine.ops = &sun4i_backend_engine_ops; @@ -881,7 +884,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, &sun4i_backend_regmap_config); if (IS_ERR(backend->engine.regs)) { dev_err(dev, "Couldn't create the backend regmap\n"); - return PTR_ERR(backend->engine.regs); + ret = PTR_ERR(backend->engine.regs); + goto err_disable_ram_clk; } list_add_tail(&backend->engine.list, &drv->engine_list); diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index a50f260c73e4..dd2a78defdb4 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -661,7 +661,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master, &sun4i_hdmi_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA, hdmi->ddc_i2c, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); if (ret) { dev_err(dev, diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index 02acc7cbdb97..4071ab38b4ae 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -536,18 +536,21 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, mixer->engine.ops = &sun8i_engine_ops; mixer->engine.node = dev->of_node; - if (of_property_present(dev->of_node, "iommus")) { - /* - * This assume we have the same DMA constraints for - * all our the mixers in our pipeline. This sounds - * bad, but it has always been the case for us, and - * DRM doesn't do per-device allocation either, so we - * would need to fix DRM first... - */ - ret = of_dma_configure(drm->dev, dev->of_node, true); - if (ret) - return ret; - } + /* + * This assume we have the same DMA constraints for all our the + * devices in our pipeline (all the backends, but also the + * frontends). This sounds bad, but it has always been the case + * for us, and DRM doesn't do per-device allocation either, so + * we would need to fix DRM first... + * + * Always use the first bound backend as the DMA device. While + * our device trees always have all backends enabled, some in + * the wild may actually have the first one disabled. If both + * are enabled, the order in which they are bound is guaranteed + * since the driver adds components in order. + */ + if (drm_dev_dma_dev(drm) == drm->dev) + drm_dev_set_dma_dev(drm, dev); /* * While this function can fail, we shouldn't do anything diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index f08f6da55dd0..72c92203ae63 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -124,25 +124,13 @@ static void sun8i_ui_layer_update_buffer(struct sun8i_layer *layer, { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; - struct drm_gem_dma_object *gem; dma_addr_t dma_addr; u32 ch_base; - int bpp; ch_base = sun8i_channel_base(layer); - /* Get the physical address of the buffer in memory */ - gem = drm_fb_dma_get_gem_obj(fb, 0); - - DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr); - - /* Compute the start of the displayed memory */ - bpp = fb->format->cpp[0]; - dma_addr = gem->dma_addr + fb->offsets[0]; - - /* Fixup framebuffer address for src coordinates */ - dma_addr += (state->src.x1 >> 16) * bpp; - dma_addr += (state->src.y1 >> 16) * fb->pitches[0]; + /* Get the start of the displayed memory */ + dma_addr = drm_fb_dma_get_gem_addr(fb, state, 0); /* Set the line width */ DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]); diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index ca3ab59e108d..cd8d6c2da0c7 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -197,38 +197,15 @@ static void sun8i_vi_layer_update_buffer(struct sun8i_layer *layer, struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; - struct drm_gem_dma_object *gem; - u32 dx, dy, src_x, src_y; dma_addr_t dma_addr; u32 ch_base; int i; ch_base = sun8i_channel_base(layer); - /* Adjust x and y to be dividable by subsampling factor */ - src_x = (state->src.x1 >> 16) & ~(format->hsub - 1); - src_y = (state->src.y1 >> 16) & ~(format->vsub - 1); - for (i = 0; i < format->num_planes; i++) { - /* Get the physical address of the buffer in memory */ - gem = drm_fb_dma_get_gem_obj(fb, i); - - DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr); - - /* Compute the start of the displayed memory */ - dma_addr = gem->dma_addr + fb->offsets[i]; - - dx = src_x; - dy = src_y; - - if (i > 0) { - dx /= format->hsub; - dy /= format->vsub; - } - - /* Fixup framebuffer address for src coordinates */ - dma_addr += dx * format->cpp[i]; - dma_addr += dy * fb->pitches[i]; + /* Get the start of the displayed memory */ + dma_addr = drm_fb_dma_get_gem_addr(fb, state, i); /* Set the line width */ DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n", diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c index 1114359a1e62..a335c94a7bd7 100644 --- a/drivers/gpu/drm/sysfb/efidrm.c +++ b/drivers/gpu/drm/sysfb/efidrm.c @@ -157,7 +157,6 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv, struct drm_sysfb_device *sysfb; struct drm_device *dev; struct resource *mem = NULL; - void __iomem *screen_base = NULL; struct drm_plane *primary_plane; struct drm_crtc *crtc; struct drm_encoder *encoder; @@ -244,21 +243,38 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv, mem_flags = efidrm_get_mem_flags(dev, res->start, vsize); - if (mem_flags & EFI_MEMORY_WC) - screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); - else if (mem_flags & EFI_MEMORY_UC) - screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - else if (mem_flags & EFI_MEMORY_WT) - screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem), - MEMREMAP_WT); - else if (mem_flags & EFI_MEMORY_WB) - screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem), - MEMREMAP_WB); - else + if (mem_flags & EFI_MEMORY_WC) { + void __iomem *screen_base = devm_ioremap_wc(&pdev->dev, mem->start, + resource_size(mem)); + + if (!screen_base) + return ERR_PTR(-ENXIO); + iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); + } else if (mem_flags & EFI_MEMORY_UC) { + void __iomem *screen_base = devm_ioremap(&pdev->dev, mem->start, + resource_size(mem)); + + if (!screen_base) + return ERR_PTR(-ENXIO); + iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); + } else if (mem_flags & EFI_MEMORY_WT) { + void *screen_base = devm_memremap(&pdev->dev, mem->start, + resource_size(mem), MEMREMAP_WT); + + if (IS_ERR(screen_base)) + return ERR_CAST(screen_base); + iosys_map_set_vaddr(&sysfb->fb_addr, screen_base); + } else if (mem_flags & EFI_MEMORY_WB) { + void *screen_base = devm_memremap(&pdev->dev, mem->start, + resource_size(mem), MEMREMAP_WB); + + if (IS_ERR(screen_base)) + return ERR_CAST(screen_base); + iosys_map_set_vaddr(&sysfb->fb_addr, screen_base); + } else { drm_err(dev, "invalid mem_flags: 0x%llx\n", mem_flags); - if (!screen_base) - return ERR_PTR(-ENOMEM); - iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); + return ERR_PTR(-EINVAL); + } /* * Modesetting diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index a6fa196c2813..10d993b8d043 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -825,7 +825,22 @@ static void tegra_display_hub_destroy_state(struct drm_private_obj *obj, kfree(hub_state); } +static struct drm_private_state * +tegra_display_hub_create_state(struct drm_private_obj *obj) +{ + struct tegra_display_hub_state *hub_state; + + hub_state = kzalloc_obj(*hub_state); + if (!hub_state) + return ERR_PTR(-ENOMEM); + + __drm_atomic_helper_private_obj_create_state(obj, &hub_state->base); + + return &hub_state->base; +} + static const struct drm_private_state_funcs tegra_display_hub_state_funcs = { + .atomic_create_state = tegra_display_hub_create_state, .atomic_duplicate_state = tegra_display_hub_duplicate_state, .atomic_destroy_state = tegra_display_hub_destroy_state, }; @@ -941,13 +956,8 @@ static int tegra_display_hub_init(struct host1x_client *client) struct tegra_display_hub *hub = to_tegra_display_hub(client); struct drm_device *drm = dev_get_drvdata(client->host); struct tegra_drm *tegra = drm->dev_private; - struct tegra_display_hub_state *state; - - state = kzalloc_obj(*state); - if (!state) - return -ENOMEM; - drm_atomic_private_obj_init(drm, &hub->base, &state->base, + drm_atomic_private_obj_init(drm, &hub->base, &tegra_display_hub_state_funcs); tegra->hub = hub; diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c index 86860ad0861c..beb1d50a6646 100644 --- a/drivers/gpu/drm/tests/drm_connector_test.c +++ b/drivers/gpu/drm/tests/drm_connector_test.c @@ -675,7 +675,7 @@ static void drm_test_connector_hdmi_init_valid(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); } @@ -695,7 +695,7 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, NULL, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); } @@ -715,7 +715,7 @@ static void drm_test_connector_hdmi_init_null_vendor(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_LT(test, ret, 0); } @@ -735,7 +735,7 @@ static void drm_test_connector_hdmi_init_null_product(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_LT(test, ret, 0); } @@ -761,7 +761,7 @@ static void drm_test_connector_hdmi_init_product_valid(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); KUNIT_EXPECT_MEMEQ(test, @@ -794,7 +794,7 @@ static void drm_test_connector_hdmi_init_product_length_exact(struct kunit *test &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); KUNIT_EXPECT_MEMEQ(test, @@ -821,7 +821,7 @@ static void drm_test_connector_hdmi_init_product_length_too_long(struct kunit *t &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_LT(test, ret, 0); } @@ -847,7 +847,7 @@ static void drm_test_connector_hdmi_init_vendor_valid(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); KUNIT_EXPECT_MEMEQ(test, @@ -879,7 +879,7 @@ static void drm_test_connector_hdmi_init_vendor_length_exact(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); KUNIT_EXPECT_MEMEQ(test, @@ -906,7 +906,7 @@ static void drm_test_connector_hdmi_init_vendor_length_too_long(struct kunit *te &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_LT(test, ret, 0); } @@ -926,7 +926,7 @@ static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 9); KUNIT_EXPECT_LT(test, ret, 0); } @@ -946,7 +946,7 @@ static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 0); KUNIT_EXPECT_LT(test, ret, 0); } @@ -971,7 +971,7 @@ static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); @@ -1012,7 +1012,7 @@ static void drm_test_connector_hdmi_init_bpc_10(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 10); KUNIT_EXPECT_EQ(test, ret, 0); @@ -1053,7 +1053,7 @@ static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 12); KUNIT_EXPECT_EQ(test, ret, 0); @@ -1109,7 +1109,7 @@ static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test) &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_YUV422), + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422), 8); KUNIT_EXPECT_LT(test, ret, 0); } @@ -1122,17 +1122,17 @@ struct drm_connector_hdmi_init_formats_yuv420_allowed_test { #define YUV420_ALLOWED_TEST(_formats, _allowed, _result) \ { \ - .supported_formats = BIT(HDMI_COLORSPACE_RGB) | (_formats), \ + .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | (_formats), \ .yuv420_allowed = _allowed, \ .expected_result = _result, \ } static const struct drm_connector_hdmi_init_formats_yuv420_allowed_test drm_connector_hdmi_init_formats_yuv420_allowed_tests[] = { - YUV420_ALLOWED_TEST(BIT(HDMI_COLORSPACE_YUV420), true, 0), - YUV420_ALLOWED_TEST(BIT(HDMI_COLORSPACE_YUV420), false, -EINVAL), - YUV420_ALLOWED_TEST(BIT(HDMI_COLORSPACE_YUV422), true, -EINVAL), - YUV420_ALLOWED_TEST(BIT(HDMI_COLORSPACE_YUV422), false, 0), + YUV420_ALLOWED_TEST(BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420), true, 0), + YUV420_ALLOWED_TEST(BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420), false, -EINVAL), + YUV420_ALLOWED_TEST(BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422), true, -EINVAL), + YUV420_ALLOWED_TEST(BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422), false, 0), }; static void @@ -1188,7 +1188,7 @@ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test) &dummy_hdmi_funcs, connector_type, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); } @@ -1223,7 +1223,7 @@ static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test) &dummy_hdmi_funcs, connector_type, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_LT(test, ret, 0); } @@ -1432,10 +1432,10 @@ static void drm_test_drm_hdmi_connector_get_output_format_name(struct kunit *tes static const struct drm_hdmi_connector_get_output_format_name_test drm_hdmi_connector_get_output_format_name_valid_tests[] = { - OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_RGB, "RGB"), - OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV420, "YUV 4:2:0"), - OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV422, "YUV 4:2:2"), - OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV444, "YUV 4:4:4"), + OUTPUT_FORMAT_TEST(DRM_OUTPUT_COLOR_FORMAT_RGB444, "RGB"), + OUTPUT_FORMAT_TEST(DRM_OUTPUT_COLOR_FORMAT_YCBCR420, "YUV 4:2:0"), + OUTPUT_FORMAT_TEST(DRM_OUTPUT_COLOR_FORMAT_YCBCR422, "YUV 4:2:2"), + OUTPUT_FORMAT_TEST(DRM_OUTPUT_COLOR_FORMAT_YCBCR444, "YUV 4:4:4"), }; static void @@ -1500,7 +1500,7 @@ static void drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector( &dummy_hdmi_funcs, DRM_MODE_CONNECTOR_HDMIA, &priv->ddc, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_EXPECT_EQ(test, ret, 0); @@ -1540,7 +1540,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb(struct kunit *test) KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, mode->clock * 1000ULL, rate); } @@ -1561,7 +1561,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc(struct kunit *test) KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(mode, 10, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, mode->clock * 1250, rate); } @@ -1580,7 +1580,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1(struct kunit *t mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1); KUNIT_ASSERT_NOT_NULL(test, mode); - rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(mode, 10, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_EXPECT_EQ(test, rate, 0); } @@ -1600,7 +1600,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc(struct kunit *test) KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(mode, 12, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, mode->clock * 1500, rate); } @@ -1619,7 +1619,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1(struct kunit *t mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1); KUNIT_ASSERT_NOT_NULL(test, mode); - rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(mode, 12, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_EXPECT_EQ(test, rate, 0); } @@ -1639,7 +1639,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_double(struct kunit *test) KUNIT_ASSERT_TRUE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, (mode->clock * 1000ULL) * 2, rate); } @@ -1662,7 +1662,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv420_valid(struct kunit KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_YUV420); + rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_YCBCR420); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, (mode->clock * 1000ULL) / 2, rate); } @@ -1699,7 +1699,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc(struct kuni KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_YUV420); + rate = drm_hdmi_compute_mode_clock(mode, 10, DRM_OUTPUT_COLOR_FORMAT_YCBCR420); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, mode->clock * 625, rate); @@ -1724,7 +1724,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc(struct kuni KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_YUV420); + rate = drm_hdmi_compute_mode_clock(mode, 12, DRM_OUTPUT_COLOR_FORMAT_YCBCR420); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, mode->clock * 750, rate); @@ -1747,7 +1747,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc(struct kunit KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_YUV422); + rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_YCBCR422); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate); } @@ -1769,7 +1769,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc(struct kuni KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_YUV422); + rate = drm_hdmi_compute_mode_clock(mode, 10, DRM_OUTPUT_COLOR_FORMAT_YCBCR422); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate); } @@ -1791,7 +1791,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc(struct kuni KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_YUV422); + rate = drm_hdmi_compute_mode_clock(mode, 12, DRM_OUTPUT_COLOR_FORMAT_YCBCR422); KUNIT_ASSERT_GT(test, rate, 0); KUNIT_EXPECT_EQ(test, mode->clock * 1000, rate); } diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c index 4bdcea3c7435..a4357efaa983 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -239,7 +239,7 @@ __connector_hdmi_init(struct kunit *test, enc->possible_crtcs = drm_crtc_mask(priv->crtc); conn = &priv->connector; - conn->ycbcr_420_allowed = !!(formats & BIT(HDMI_COLORSPACE_YUV420)); + conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)); ret = drmm_connector_hdmi_init(drm, conn, "Vendor", "Product", @@ -300,7 +300,7 @@ static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -375,7 +375,7 @@ static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -450,7 +450,7 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -517,7 +517,7 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -584,7 +584,7 @@ static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -653,7 +653,7 @@ static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -722,7 +722,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -791,7 +791,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -863,8 +863,8 @@ static void drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit *test) broadcast_rgb = *(enum drm_hdmi_broadcast_rgb *)test->param_value; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV420), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420), 8, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz); @@ -918,7 +918,7 @@ retry_conn_state: KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); KUNIT_ASSERT_EQ(test, conn_state->hdmi.broadcast_rgb, broadcast_rgb); - KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV420); + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_YCBCR420); KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range); @@ -963,7 +963,7 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 10, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz); @@ -1045,7 +1045,7 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 10, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz); @@ -1122,9 +1122,9 @@ static void drm_test_check_output_bpc_dvi(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV422) | - BIT(HDMI_COLORSPACE_YUV444), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), 12, &dummy_connector_hdmi_funcs, test_edid_dvi_1080p); @@ -1157,7 +1157,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -1179,7 +1179,7 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_200mhz); @@ -1210,7 +1210,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 8); - KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1000); drm_modeset_drop_locks(&ctx); @@ -1234,7 +1234,7 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 10, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz); @@ -1265,7 +1265,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 10); - KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250); drm_modeset_drop_locks(&ctx); @@ -1289,7 +1289,7 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz); @@ -1320,7 +1320,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 12); - KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1500); drm_modeset_drop_locks(&ctx); @@ -1348,7 +1348,7 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -1416,7 +1416,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz); @@ -1433,10 +1433,10 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test) KUNIT_ASSERT_NOT_NULL(test, preferred); KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); - rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 10, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); drm_modeset_acquire_init(&ctx, 0); @@ -1457,7 +1457,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250); drm_modeset_drop_locks(&ctx); @@ -1490,8 +1490,8 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV420), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz); @@ -1509,10 +1509,10 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test) KUNIT_ASSERT_NOT_NULL(test, yuv420_only_mode); KUNIT_ASSERT_TRUE(test, drm_mode_is_420_only(info, yuv420_only_mode)); - rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 12, HDMI_COLORSPACE_YUV420); + rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 12, DRM_OUTPUT_COLOR_FORMAT_YCBCR420); KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); - rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 10, HDMI_COLORSPACE_YUV420); + rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 10, DRM_OUTPUT_COLOR_FORMAT_YCBCR420); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); drm_modeset_acquire_init(&ctx, 0); @@ -1531,7 +1531,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV420); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_YCBCR420); KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, yuv420_only_mode->clock * 625); drm_modeset_drop_locks(&ctx); @@ -1565,9 +1565,9 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV422) | - BIT(HDMI_COLORSPACE_YUV444), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz); @@ -1584,13 +1584,13 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit KUNIT_ASSERT_NOT_NULL(test, preferred); KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK); - rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 10, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_YCBCR422); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); drm_modeset_acquire_init(&ctx, 0); @@ -1611,7 +1611,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -1644,8 +1644,8 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV420), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz); @@ -1664,13 +1664,13 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK); KUNIT_ASSERT_TRUE(test, drm_mode_is_420_also(info, preferred)); - rate = drm_hdmi_compute_mode_clock(preferred, 8, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); - rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 10, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV420); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_YCBCR420); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); drm_modeset_acquire_init(&ctx, 0); @@ -1689,7 +1689,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -1715,7 +1715,7 @@ static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz); @@ -1750,7 +1750,7 @@ retry_conn_enable: conn_state = conn->state; KUNIT_ASSERT_NOT_NULL(test, conn_state); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); @@ -1800,9 +1800,9 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV422) | - BIT(HDMI_COLORSPACE_YUV444), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz); @@ -1847,7 +1847,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -1871,7 +1871,7 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz); @@ -1896,10 +1896,10 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test) * But since the driver only supports RGB, we should fallback to * a lower bpc with RGB. */ - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_YCBCR422); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); drm_modeset_acquire_init(&ctx, 0); @@ -1920,7 +1920,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -1944,9 +1944,9 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV422) | - BIT(HDMI_COLORSPACE_YUV444), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_200mhz); @@ -1971,10 +1971,10 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test * But since the display only supports RGB, we should fallback to * a lower bpc with RGB. */ - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000); - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_YCBCR422); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); drm_modeset_acquire_init(&ctx, 0); @@ -1995,7 +1995,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -2020,7 +2020,7 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz); @@ -2040,7 +2040,7 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test * We're making sure that we have headroom on the TMDS character * clock to actually use 12bpc. */ - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); drm_modeset_acquire_init(&ctx, 0); @@ -2061,7 +2061,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -2086,9 +2086,9 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV422) | - BIT(HDMI_COLORSPACE_YUV444), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), 12, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_340mhz); @@ -2108,7 +2108,7 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes * We're making sure that we have headroom on the TMDS character * clock to actually use 12bpc. */ - rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB); + rate = drm_hdmi_compute_mode_clock(preferred, 12, DRM_OUTPUT_COLOR_FORMAT_RGB444); KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000); drm_modeset_acquire_init(&ctx, 0); @@ -2129,7 +2129,7 @@ retry_conn_enable: KUNIT_ASSERT_NOT_NULL(test, conn_state); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); - KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); @@ -2150,7 +2150,7 @@ static void drm_test_check_disable_connector(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -2255,7 +2255,7 @@ static void drm_test_check_broadcast_rgb_value(struct kunit *test) struct drm_connector *conn; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -2277,7 +2277,7 @@ static void drm_test_check_bpc_8_value(struct kunit *test) struct drm_connector *conn; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -2301,7 +2301,7 @@ static void drm_test_check_bpc_10_value(struct kunit *test) struct drm_connector *conn; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 10); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -2325,7 +2325,7 @@ static void drm_test_check_bpc_12_value(struct kunit *test) struct drm_connector *conn; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 12); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -2347,9 +2347,9 @@ static void drm_test_check_format_value(struct kunit *test) struct drm_connector *conn; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV422) | - BIT(HDMI_COLORSPACE_YUV444), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -2369,9 +2369,9 @@ static void drm_test_check_tmds_char_value(struct kunit *test) struct drm_connector *conn; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV422) | - BIT(HDMI_COLORSPACE_YUV444), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), 12); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -2407,7 +2407,7 @@ static void drm_test_check_mode_valid(struct kunit *test) struct drm_display_mode *preferred; priv = drm_kunit_helper_connector_hdmi_init(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8); KUNIT_ASSERT_NOT_NULL(test, priv); @@ -2431,7 +2431,7 @@ static void drm_test_check_mode_valid_reject_rate(struct kunit *test) struct drm_display_mode *preferred; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &reject_100mhz_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_200mhz); @@ -2463,7 +2463,7 @@ static void drm_test_check_mode_valid_reject(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &reject_connector_hdmi_funcs, no_edid); @@ -2493,7 +2493,7 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test) struct drm_display_mode *preferred; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_100mhz); @@ -2540,7 +2540,7 @@ static void drm_test_check_infoframes(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &dummy_connector_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_200mhz); @@ -2643,7 +2643,7 @@ static void drm_test_check_reject_avi_infoframe(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &reject_avi_infoframe_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_200mhz); @@ -2747,7 +2747,7 @@ static void drm_test_check_reject_hdr_infoframe_bpc_8(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &reject_hdr_infoframe_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_200mhz_hdr); @@ -2861,7 +2861,7 @@ static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 10, &reject_hdr_infoframe_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_200mhz_hdr); @@ -2996,7 +2996,7 @@ static void drm_test_check_reject_audio_infoframe(struct kunit *test) int ret; priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, - BIT(HDMI_COLORSPACE_RGB), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), 8, &reject_audio_infoframe_hdmi_funcs, test_edid_hdmi_1080p_rgb_max_200mhz); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c deleted file mode 100644 index 1de3996501f7..000000000000 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ /dev/null @@ -1,408 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2012 Texas Instruments - * Author: Rob Clark <robdclark@gmail.com> - */ - -#include <linux/backlight.h> -#include <linux/gpio/consumer.h> -#include <linux/platform_device.h> - -#include <video/display_timing.h> -#include <video/of_display_timing.h> -#include <video/videomode.h> - -#include <drm/drm_atomic_state_helper.h> -#include <drm/drm_connector.h> -#include <drm/drm_modeset_helper_vtables.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> - -#include "tilcdc_drv.h" -#include "tilcdc_panel.h" - -struct panel_module { - struct tilcdc_module base; - struct tilcdc_panel_info *info; - struct display_timings *timings; - struct backlight_device *backlight; - struct gpio_desc *enable_gpio; -}; -#define to_panel_module(x) container_of(x, struct panel_module, base) - - -/* - * Encoder: - */ - -struct panel_encoder { - struct drm_encoder base; - struct panel_module *mod; -}; -#define to_panel_encoder(x) container_of(x, struct panel_encoder, base) - -static void panel_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct panel_encoder *panel_encoder = to_panel_encoder(encoder); - struct backlight_device *backlight = panel_encoder->mod->backlight; - struct gpio_desc *gpio = panel_encoder->mod->enable_gpio; - - if (backlight) { - backlight->props.power = mode == DRM_MODE_DPMS_ON ? - BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; - backlight_update_status(backlight); - } - - if (gpio) - gpiod_set_value_cansleep(gpio, - mode == DRM_MODE_DPMS_ON ? 1 : 0); -} - -static void panel_encoder_prepare(struct drm_encoder *encoder) -{ - panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); -} - -static void panel_encoder_commit(struct drm_encoder *encoder) -{ - panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON); -} - -static void panel_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - /* nothing needed */ -} - -static const struct drm_encoder_helper_funcs panel_encoder_helper_funcs = { - .dpms = panel_encoder_dpms, - .prepare = panel_encoder_prepare, - .commit = panel_encoder_commit, - .mode_set = panel_encoder_mode_set, -}; - -static struct drm_encoder *panel_encoder_create(struct drm_device *dev, - struct panel_module *mod) -{ - struct panel_encoder *panel_encoder; - struct drm_encoder *encoder; - int ret; - - panel_encoder = devm_kzalloc(dev->dev, sizeof(*panel_encoder), - GFP_KERNEL); - if (!panel_encoder) - return NULL; - - panel_encoder->mod = mod; - - encoder = &panel_encoder->base; - encoder->possible_crtcs = 1; - - ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); - if (ret < 0) - goto fail; - - drm_encoder_helper_add(encoder, &panel_encoder_helper_funcs); - - return encoder; - -fail: - drm_encoder_cleanup(encoder); - return NULL; -} - -/* - * Connector: - */ - -struct panel_connector { - struct drm_connector base; - - struct drm_encoder *encoder; /* our connected encoder */ - struct panel_module *mod; -}; -#define to_panel_connector(x) container_of(x, struct panel_connector, base) - - -static void panel_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static int panel_connector_get_modes(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - struct panel_connector *panel_connector = to_panel_connector(connector); - struct display_timings *timings = panel_connector->mod->timings; - int i; - - for (i = 0; i < timings->num_timings; i++) { - struct drm_display_mode *mode; - struct videomode vm; - - if (videomode_from_timings(timings, &vm, i)) - break; - - mode = drm_mode_create(dev); - if (!mode) - break; - - drm_display_mode_from_videomode(&vm, mode); - - mode->type = DRM_MODE_TYPE_DRIVER; - - if (timings->native_mode == i) - mode->type |= DRM_MODE_TYPE_PREFERRED; - - drm_mode_set_name(mode); - drm_mode_probed_add(connector, mode); - } - - return i; -} - -static struct drm_encoder *panel_connector_best_encoder( - struct drm_connector *connector) -{ - struct panel_connector *panel_connector = to_panel_connector(connector); - return panel_connector->encoder; -} - -static const struct drm_connector_funcs panel_connector_funcs = { - .destroy = panel_connector_destroy, - .fill_modes = drm_helper_probe_single_connector_modes, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const struct drm_connector_helper_funcs panel_connector_helper_funcs = { - .get_modes = panel_connector_get_modes, - .best_encoder = panel_connector_best_encoder, -}; - -static struct drm_connector *panel_connector_create(struct drm_device *dev, - struct panel_module *mod, struct drm_encoder *encoder) -{ - struct panel_connector *panel_connector; - struct drm_connector *connector; - int ret; - - panel_connector = devm_kzalloc(dev->dev, sizeof(*panel_connector), - GFP_KERNEL); - if (!panel_connector) - return NULL; - - panel_connector->encoder = encoder; - panel_connector->mod = mod; - - connector = &panel_connector->base; - - drm_connector_init(dev, connector, &panel_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); - drm_connector_helper_add(connector, &panel_connector_helper_funcs); - - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - goto fail; - - return connector; - -fail: - panel_connector_destroy(connector); - return NULL; -} - -/* - * Module: - */ - -static int panel_modeset_init(struct tilcdc_module *mod, struct drm_device *dev) -{ - struct panel_module *panel_mod = to_panel_module(mod); - struct tilcdc_drm_private *priv = dev->dev_private; - struct drm_encoder *encoder; - struct drm_connector *connector; - - encoder = panel_encoder_create(dev, panel_mod); - if (!encoder) - return -ENOMEM; - - connector = panel_connector_create(dev, panel_mod, encoder); - if (!connector) - return -ENOMEM; - - priv->encoders[priv->num_encoders++] = encoder; - priv->connectors[priv->num_connectors++] = connector; - - tilcdc_crtc_set_panel_info(priv->crtc, - to_panel_encoder(encoder)->mod->info); - - return 0; -} - -static const struct tilcdc_module_ops panel_module_ops = { - .modeset_init = panel_modeset_init, -}; - -/* - * Device: - */ - -/* maybe move this somewhere common if it is needed by other outputs? */ -static struct tilcdc_panel_info *of_get_panel_info(struct device_node *np) -{ - struct device_node *info_np; - struct tilcdc_panel_info *info; - int ret = 0; - - if (!np) { - pr_err("%s: no devicenode given\n", __func__); - return NULL; - } - - info_np = of_get_child_by_name(np, "panel-info"); - if (!info_np) { - pr_err("%s: could not find panel-info node\n", __func__); - return NULL; - } - - info = kzalloc_obj(*info); - if (!info) - goto put_node; - - ret |= of_property_read_u32(info_np, "ac-bias", &info->ac_bias); - ret |= of_property_read_u32(info_np, "ac-bias-intrpt", &info->ac_bias_intrpt); - ret |= of_property_read_u32(info_np, "dma-burst-sz", &info->dma_burst_sz); - ret |= of_property_read_u32(info_np, "bpp", &info->bpp); - ret |= of_property_read_u32(info_np, "fdd", &info->fdd); - ret |= of_property_read_u32(info_np, "sync-edge", &info->sync_edge); - ret |= of_property_read_u32(info_np, "sync-ctrl", &info->sync_ctrl); - ret |= of_property_read_u32(info_np, "raster-order", &info->raster_order); - ret |= of_property_read_u32(info_np, "fifo-th", &info->fifo_th); - - /* optional: */ - info->tft_alt_mode = of_property_read_bool(info_np, "tft-alt-mode"); - info->invert_pxl_clk = of_property_read_bool(info_np, "invert-pxl-clk"); - - if (ret) { - pr_err("%s: error reading panel-info properties\n", __func__); - kfree(info); - info = NULL; - } - -put_node: - of_node_put(info_np); - return info; -} - -static int panel_probe(struct platform_device *pdev) -{ - struct device_node *node = pdev->dev.of_node; - struct backlight_device *backlight; - struct panel_module *panel_mod; - struct tilcdc_module *mod; - int ret; - - /* bail out early if no DT data: */ - if (!node) { - dev_err(&pdev->dev, "device-tree data is missing\n"); - return -ENXIO; - } - - panel_mod = devm_kzalloc(&pdev->dev, sizeof(*panel_mod), GFP_KERNEL); - if (!panel_mod) - return -ENOMEM; - - backlight = devm_of_find_backlight(&pdev->dev); - if (IS_ERR(backlight)) - return PTR_ERR(backlight); - panel_mod->backlight = backlight; - - panel_mod->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", - GPIOD_OUT_LOW); - if (IS_ERR(panel_mod->enable_gpio)) { - ret = PTR_ERR(panel_mod->enable_gpio); - dev_err(&pdev->dev, "failed to request enable GPIO\n"); - goto fail_backlight; - } - - if (panel_mod->enable_gpio) - dev_info(&pdev->dev, "found enable GPIO\n"); - - mod = &panel_mod->base; - pdev->dev.platform_data = mod; - - tilcdc_module_init(mod, "panel", &panel_module_ops); - - panel_mod->timings = of_get_display_timings(node); - if (!panel_mod->timings) { - dev_err(&pdev->dev, "could not get panel timings\n"); - ret = -EINVAL; - goto fail_free; - } - - panel_mod->info = of_get_panel_info(node); - if (!panel_mod->info) { - dev_err(&pdev->dev, "could not get panel info\n"); - ret = -EINVAL; - goto fail_timings; - } - - return 0; - -fail_timings: - display_timings_release(panel_mod->timings); - -fail_free: - tilcdc_module_cleanup(mod); - -fail_backlight: - if (panel_mod->backlight) - put_device(&panel_mod->backlight->dev); - return ret; -} - -static void panel_remove(struct platform_device *pdev) -{ - struct tilcdc_module *mod = dev_get_platdata(&pdev->dev); - struct panel_module *panel_mod = to_panel_module(mod); - struct backlight_device *backlight = panel_mod->backlight; - - if (backlight) - put_device(&backlight->dev); - - display_timings_release(panel_mod->timings); - - tilcdc_module_cleanup(mod); - kfree(panel_mod->info); -} - -static const struct of_device_id panel_of_match[] = { - { .compatible = "ti,tilcdc,panel", }, - { }, -}; - -static struct platform_driver panel_driver = { - .probe = panel_probe, - .remove = panel_remove, - .driver = { - .name = "tilcdc-panel", - .of_match_table = panel_of_match, - }, -}; - -int __init tilcdc_panel_init(void) -{ - return platform_driver_register(&panel_driver); -} - -void __exit tilcdc_panel_fini(void) -{ - platform_driver_unregister(&panel_driver); -} diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c index 37a69b3cf04b..2e7b3e87fea1 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c @@ -105,14 +105,14 @@ static int __init tilcdc_panel_copy_props(struct device_node *old_panel, if (!invert_pxl_clk) { ret = tilcdc_panel_update_prop(&ocs, new_timing, "pixelclk-active", - &(u32){cpu_to_be32(1)}, sizeof(u32)); + &(__be32){cpu_to_be32(1)}, sizeof(__be32)); if (ret) goto destroy_ocs; } if (!sync_edge) { ret = tilcdc_panel_update_prop(&ocs, new_timing, "syncclk-active", - &(u32){cpu_to_be32(1)}, sizeof(u32)); + &(__be32){cpu_to_be32(1)}, sizeof(__be32)); if (ret) goto destroy_ocs; } diff --git a/drivers/gpu/drm/tiny/hx8357d.c b/drivers/gpu/drm/tiny/hx8357d.c index 9f26aaca0bfa..53b152fc6b04 100644 --- a/drivers/gpu/drm/tiny/hx8357d.c +++ b/drivers/gpu/drm/tiny/hx8357d.c @@ -46,16 +46,48 @@ #define HX8357D_MADCTL_BGR 0x08 #define HX8357D_MADCTL_MH 0x04 -static void yx240qv29_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +struct hx8357d_device { + struct mipi_dbi_dev dbidev; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct hx8357d_device *to_hx8357d_device(struct drm_device *dev) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + return container_of(drm_to_mipi_dbi_dev(dev), struct hx8357d_device, dbidev); +} + +static const u32 hx8357d_plane_formats[] = { + DRM_MIPI_DBI_PLANE_FORMATS, +}; + +static const u64 hx8357d_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static const struct drm_plane_helper_funcs hx8357d_plane_helper_funcs = { + DRM_MIPI_DBI_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs hx8357d_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void hx8357d_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct hx8357d_device *hx8357d = to_hx8357d_device(drm); + struct mipi_dbi_dev *dbidev = &hx8357d->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; u8 addr_mode; int ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; DRM_DEBUG_KMS("\n"); @@ -177,13 +209,41 @@ out_enable: break; } mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); - mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); + + backlight_enable(dbidev->backlight); out_exit: drm_dev_exit(idx); } -static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = { - DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(yx240qv29_enable), +static const struct drm_crtc_helper_funcs hx8357d_crtc_helper_funcs = { + DRM_MIPI_DBI_CRTC_HELPER_FUNCS, + .atomic_enable = hx8357d_crtc_helper_atomic_enable, +}; + +static const struct drm_crtc_funcs hx8357d_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs hx8357d_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs hx8357d_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs hx8357d_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs hx8357d_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs hx8357d_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, }; static const struct drm_display_mode yx350hv15_mode = { @@ -219,17 +279,21 @@ MODULE_DEVICE_TABLE(spi, hx8357d_id); static int hx8357d_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct hx8357d_device *hx8357d; struct mipi_dbi_dev *dbidev; struct drm_device *drm; struct gpio_desc *dc; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; u32 rotation = 0; int ret; - dbidev = devm_drm_dev_alloc(dev, &hx8357d_driver, - struct mipi_dbi_dev, drm); - if (IS_ERR(dbidev)) - return PTR_ERR(dbidev); - + hx8357d = devm_drm_dev_alloc(dev, &hx8357d_driver, struct hx8357d_device, dbidev.drm); + if (IS_ERR(hx8357d)) + return PTR_ERR(hx8357d); + dbidev = &hx8357d->dbidev; drm = &dbidev->drm; dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); @@ -246,7 +310,53 @@ static int hx8357d_probe(struct spi_device *spi) if (ret) return ret; - ret = mipi_dbi_dev_init(dbidev, &hx8357d_pipe_funcs, &yx350hv15_mode, rotation); + ret = drm_mipi_dbi_dev_init(dbidev, &yx350hv15_mode, hx8357d_plane_formats[0], + rotation, 0); + if (ret) + return ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &hx8357d_mode_config_funcs; + drm->mode_config.preferred_depth = 16; + drm->mode_config.helper_private = &hx8357d_mode_config_helper_funcs; + + plane = &hx8357d->plane; + ret = drm_universal_plane_init(drm, plane, 0, &hx8357d_plane_funcs, + hx8357d_plane_formats, ARRAY_SIZE(hx8357d_plane_formats), + hx8357d_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &hx8357d_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &hx8357d->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &hx8357d_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &hx8357d_crtc_helper_funcs); + + encoder = &hx8357d->encoder; + ret = drm_encoder_init(drm, encoder, &hx8357d_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &hx8357d->connector; + ret = drm_connector_init(drm, connector, &hx8357d_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &hx8357d_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/tiny/ili9163.c b/drivers/gpu/drm/tiny/ili9163.c index 7c154c008344..1e581576fc7e 100644 --- a/drivers/gpu/drm/tiny/ili9163.c +++ b/drivers/gpu/drm/tiny/ili9163.c @@ -35,16 +35,48 @@ #define ILI9163_MADCTL_MX BIT(6) #define ILI9163_MADCTL_MY BIT(7) -static void yx240qv29_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +struct ili9163_device { + struct mipi_dbi_dev dbidev; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct ili9163_device *to_ili9163_device(struct drm_device *dev) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + return container_of(drm_to_mipi_dbi_dev(dev), struct ili9163_device, dbidev); +} + +static const u32 ili9163_plane_formats[] = { + DRM_MIPI_DBI_PLANE_FORMATS, +}; + +static const u64 ili9163_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static const struct drm_plane_helper_funcs ili9163_plane_helper_funcs = { + DRM_MIPI_DBI_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs ili9163_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void ili9163_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct ili9163_device *ili9163 = to_ili9163_device(drm); + struct mipi_dbi_dev *dbidev = &ili9163->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; u8 addr_mode; int ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; DRM_DEBUG_KMS("\n"); @@ -96,13 +128,41 @@ out_enable: } addr_mode |= ILI9163_MADCTL_BGR; mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); - mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); + + backlight_enable(dbidev->backlight); out_exit: drm_dev_exit(idx); } -static const struct drm_simple_display_pipe_funcs ili9163_pipe_funcs = { - DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(yx240qv29_enable), +static const struct drm_crtc_helper_funcs ili9163_crtc_helper_funcs = { + DRM_MIPI_DBI_CRTC_HELPER_FUNCS, + .atomic_enable = ili9163_crtc_helper_atomic_enable, +}; + +static const struct drm_crtc_funcs ili9163_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs ili9163_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs ili9163_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs ili9163_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs ili9163_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs ili9163_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, }; static const struct drm_display_mode yx240qv29_mode = { @@ -138,18 +198,22 @@ MODULE_DEVICE_TABLE(spi, ili9163_id); static int ili9163_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct ili9163_device *ili9163; struct mipi_dbi_dev *dbidev; struct drm_device *drm; struct mipi_dbi *dbi; struct gpio_desc *dc; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; u32 rotation = 0; int ret; - dbidev = devm_drm_dev_alloc(dev, &ili9163_driver, - struct mipi_dbi_dev, drm); - if (IS_ERR(dbidev)) - return PTR_ERR(dbidev); - + ili9163 = devm_drm_dev_alloc(dev, &ili9163_driver, struct ili9163_device, dbidev.drm); + if (IS_ERR(ili9163)) + return PTR_ERR(ili9163); + dbidev = &ili9163->dbidev; dbi = &dbidev->dbi; drm = &dbidev->drm; @@ -177,7 +241,53 @@ static int ili9163_probe(struct spi_device *spi) if (ret) return ret; - ret = mipi_dbi_dev_init(dbidev, &ili9163_pipe_funcs, &yx240qv29_mode, rotation); + ret = drm_mipi_dbi_dev_init(dbidev, &yx240qv29_mode, ili9163_plane_formats[0], + rotation, 0); + if (ret) + return ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &ili9163_mode_config_funcs; + drm->mode_config.preferred_depth = 16; + drm->mode_config.helper_private = &ili9163_mode_config_helper_funcs; + + plane = &ili9163->plane; + ret = drm_universal_plane_init(drm, plane, 0, &ili9163_plane_funcs, + ili9163_plane_formats, ARRAY_SIZE(ili9163_plane_formats), + ili9163_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &ili9163_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &ili9163->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &ili9163_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &ili9163_crtc_helper_funcs); + + encoder = &ili9163->encoder; + ret = drm_encoder_init(drm, encoder, &ili9163_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &ili9163->connector; + ret = drm_connector_init(drm, connector, &ili9163_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &ili9163_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c index d32538b1eb09..0371527002f9 100644 --- a/drivers/gpu/drm/tiny/ili9225.c +++ b/drivers/gpu/drm/tiny/ili9225.c @@ -17,6 +17,7 @@ #include <video/mipi_display.h> #include <drm/clients/drm_client_setup.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> @@ -24,9 +25,7 @@ #include <drm/drm_fbdev_dma.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_dma_helper.h> -#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_print.h> @@ -72,6 +71,20 @@ #define ILI9225_GAMMA_CONTROL_9 0x58 #define ILI9225_GAMMA_CONTROL_10 0x59 +struct ili9225_device { + struct mipi_dbi_dev dbidev; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct ili9225_device *to_ili9225_device(struct drm_device *dev) +{ + return container_of(drm_to_mipi_dbi_dev(dev), struct ili9225_device, dbidev); +} + static inline int ili9225_command(struct mipi_dbi *dbi, u8 cmd, u16 data) { u8 par[2] = { data >> 8, data & 0xff }; @@ -157,47 +170,61 @@ err_msg: dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret); } -static void ili9225_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +static const u32 ili9225_plane_formats[] = { + DRM_MIPI_DBI_PLANE_FORMATS, +}; + +static const u64 ili9225_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static void ili9225_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) { - struct drm_plane_state *state = pipe->plane.state; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); - struct drm_framebuffer *fb = state->fb; + struct drm_device *drm = plane->dev; + struct drm_plane_state *plane_state = plane->state; + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_rect rect; int idx; - if (!pipe->crtc.state->active) + if (!plane_state->fb) return; - if (!drm_dev_enter(fb->dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; - if (drm_atomic_helper_damage_merged(old_state, state, &rect)) + if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect)) ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect, &shadow_plane_state->fmtcnv_state); drm_dev_exit(idx); } -static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static const struct drm_plane_helper_funcs ili9225_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = drm_mipi_dbi_plane_helper_atomic_check, + .atomic_update = ili9225_plane_helper_atomic_update, +}; + +static const struct drm_plane_funcs ili9225_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void ili9225_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); - struct drm_framebuffer *fb = plane_state->fb; - struct device *dev = pipe->crtc.dev->dev; + struct drm_device *drm = crtc->dev; + struct ili9225_device *ili9225 = to_ili9225_device(drm); + struct mipi_dbi_dev *dbidev = &ili9225->dbidev; + struct device *dev = drm->dev; struct mipi_dbi *dbi = &dbidev->dbi; - struct drm_rect rect = { - .x1 = 0, - .x2 = fb->width, - .y1 = 0, - .y2 = fb->height, - }; int ret, idx; u8 am_id; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; DRM_DEBUG_KMS("\n"); @@ -284,16 +311,16 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, ili9225_command(dbi, ILI9225_DISPLAY_CONTROL_1, 0x1017); - ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect, - &shadow_plane_state->fmtcnv_state); - out_exit: drm_dev_exit(idx); } -static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe) +static void ili9225_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + struct drm_device *drm = crtc->dev; + struct ili9225_device *ili9225 = to_ili9225_device(drm); + struct mipi_dbi_dev *dbidev = &ili9225->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; DRM_DEBUG_KMS("\n"); @@ -312,6 +339,39 @@ static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe) ili9225_command(dbi, ILI9225_POWER_CONTROL_1, 0x0a02); } +static const struct drm_crtc_helper_funcs ili9225_crtc_helper_funcs = { + .mode_valid = drm_mipi_dbi_crtc_helper_mode_valid, + .atomic_check = drm_mipi_dbi_crtc_helper_atomic_check, + .atomic_enable = ili9225_crtc_helper_atomic_enable, + .atomic_disable = ili9225_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs ili9225_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs ili9225_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs ili9225_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs ili9225_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs ili9225_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs ili9225_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, +}; + static int ili9225_dbi_command(struct mipi_dbi *dbi, u8 *cmd, u8 *par, size_t num) { @@ -340,18 +400,6 @@ static int ili9225_dbi_command(struct mipi_dbi *dbi, u8 *cmd, u8 *par, return ret; } -static const struct drm_simple_display_pipe_funcs ili9225_pipe_funcs = { - .mode_valid = mipi_dbi_pipe_mode_valid, - .enable = ili9225_pipe_enable, - .disable = ili9225_pipe_disable, - .update = ili9225_pipe_update, - .begin_fb_access = mipi_dbi_pipe_begin_fb_access, - .end_fb_access = mipi_dbi_pipe_end_fb_access, - .reset_plane = mipi_dbi_pipe_reset_plane, - .duplicate_plane_state = mipi_dbi_pipe_duplicate_plane_state, - .destroy_plane_state = mipi_dbi_pipe_destroy_plane_state, -}; - static const struct drm_display_mode ili9225_mode = { DRM_SIMPLE_MODE(176, 220, 35, 44), }; @@ -384,18 +432,22 @@ MODULE_DEVICE_TABLE(spi, ili9225_id); static int ili9225_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct ili9225_device *ili9225; struct mipi_dbi_dev *dbidev; struct drm_device *drm; struct mipi_dbi *dbi; struct gpio_desc *rs; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; u32 rotation = 0; int ret; - dbidev = devm_drm_dev_alloc(dev, &ili9225_driver, - struct mipi_dbi_dev, drm); - if (IS_ERR(dbidev)) - return PTR_ERR(dbidev); - + ili9225 = devm_drm_dev_alloc(dev, &ili9225_driver, struct ili9225_device, dbidev.drm); + if (IS_ERR(ili9225)) + return PTR_ERR(ili9225); + dbidev = &ili9225->dbidev; dbi = &dbidev->dbi; drm = &dbidev->drm; @@ -416,7 +468,53 @@ static int ili9225_probe(struct spi_device *spi) /* override the command function set in mipi_dbi_spi_init() */ dbi->command = ili9225_dbi_command; - ret = mipi_dbi_dev_init(dbidev, &ili9225_pipe_funcs, &ili9225_mode, rotation); + ret = drm_mipi_dbi_dev_init(dbidev, &ili9225_mode, ili9225_plane_formats[0], + rotation, 0); + if (ret) + return ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &ili9225_mode_config_funcs; + drm->mode_config.preferred_depth = 16; + drm->mode_config.helper_private = &ili9225_mode_config_helper_funcs; + + plane = &ili9225->plane; + ret = drm_universal_plane_init(drm, plane, 0, &ili9225_plane_funcs, + ili9225_plane_formats, ARRAY_SIZE(ili9225_plane_formats), + ili9225_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &ili9225_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &ili9225->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &ili9225_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &ili9225_crtc_helper_funcs); + + encoder = &ili9225->encoder; + ret = drm_encoder_init(drm, encoder, &ili9225_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &ili9225->connector; + ret = drm_connector_init(drm, connector, &ili9225_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &ili9225_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/tiny/ili9341.c b/drivers/gpu/drm/tiny/ili9341.c index 2ab750cba505..e623bd8a1827 100644 --- a/drivers/gpu/drm/tiny/ili9341.c +++ b/drivers/gpu/drm/tiny/ili9341.c @@ -52,16 +52,48 @@ #define ILI9341_MADCTL_MX BIT(6) #define ILI9341_MADCTL_MY BIT(7) -static void yx240qv29_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +struct ili9341_device { + struct mipi_dbi_dev dbidev; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct ili9341_device *to_ili9341_device(struct drm_device *dev) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + return container_of(drm_to_mipi_dbi_dev(dev), struct ili9341_device, dbidev); +} + +static const u32 ili9341_plane_formats[] = { + DRM_MIPI_DBI_PLANE_FORMATS, +}; + +static const u64 ili9341_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static const struct drm_plane_helper_funcs ili9341_plane_helper_funcs = { + DRM_MIPI_DBI_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs ili9341_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void ili9341_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct ili9341_device *ili9341 = to_ili9341_device(drm); + struct mipi_dbi_dev *dbidev = &ili9341->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; u8 addr_mode; int ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; DRM_DEBUG_KMS("\n"); @@ -133,13 +165,41 @@ out_enable: } addr_mode |= ILI9341_MADCTL_BGR; mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); - mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); + + backlight_enable(dbidev->backlight); out_exit: drm_dev_exit(idx); } -static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = { - DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(yx240qv29_enable), +static const struct drm_crtc_helper_funcs ili9341_crtc_helper_funcs = { + DRM_MIPI_DBI_CRTC_HELPER_FUNCS, + .atomic_enable = ili9341_crtc_helper_atomic_enable, +}; + +static const struct drm_crtc_funcs ili9341_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs ili9341_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs ili9341_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs ili9341_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs ili9341_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs ili9341_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, }; static const struct drm_display_mode yx240qv29_mode = { @@ -175,18 +235,22 @@ MODULE_DEVICE_TABLE(spi, ili9341_id); static int ili9341_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct ili9341_device *ili9341; struct mipi_dbi_dev *dbidev; struct drm_device *drm; struct mipi_dbi *dbi; struct gpio_desc *dc; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; u32 rotation = 0; int ret; - dbidev = devm_drm_dev_alloc(dev, &ili9341_driver, - struct mipi_dbi_dev, drm); - if (IS_ERR(dbidev)) - return PTR_ERR(dbidev); - + ili9341 = devm_drm_dev_alloc(dev, &ili9341_driver, struct ili9341_device, dbidev.drm); + if (IS_ERR(ili9341)) + return PTR_ERR(ili9341); + dbidev = &ili9341->dbidev; dbi = &dbidev->dbi; drm = &dbidev->drm; @@ -208,7 +272,53 @@ static int ili9341_probe(struct spi_device *spi) if (ret) return ret; - ret = mipi_dbi_dev_init(dbidev, &ili9341_pipe_funcs, &yx240qv29_mode, rotation); + ret = drm_mipi_dbi_dev_init(dbidev, &yx240qv29_mode, ili9341_plane_formats[0], + rotation, 0); + if (ret) + return ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &ili9341_mode_config_funcs; + drm->mode_config.preferred_depth = 16; + drm->mode_config.helper_private = &ili9341_mode_config_helper_funcs; + + plane = &ili9341->plane; + ret = drm_universal_plane_init(drm, plane, 0, &ili9341_plane_funcs, + ili9341_plane_formats, ARRAY_SIZE(ili9341_plane_formats), + ili9341_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &ili9341_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &ili9341->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &ili9341_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &ili9341_crtc_helper_funcs); + + encoder = &ili9341->encoder; + ret = drm_encoder_init(drm, encoder, &ili9341_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &ili9341->connector; + ret = drm_connector_init(drm, connector, &ili9341_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &ili9341_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c index 1e411a0f4567..030e87a8a3f0 100644 --- a/drivers/gpu/drm/tiny/ili9486.c +++ b/drivers/gpu/drm/tiny/ili9486.c @@ -36,6 +36,20 @@ #define ILI9486_MADCTL_MX BIT(6) #define ILI9486_MADCTL_MY BIT(7) +struct ili9486_device { + struct mipi_dbi_dev dbidev; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct ili9486_device *to_ili9486_device(struct drm_device *dev) +{ + return container_of(drm_to_mipi_dbi_dev(dev), struct ili9486_device, dbidev); +} + /* * The PiScreen/waveshare rpi-lcd-35 has a SPI to 16-bit parallel bus converter * in front of the display controller. This means that 8-bit values have to be @@ -94,16 +108,34 @@ static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par, return ret; } -static void waveshare_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static const u32 ili9486_plane_formats[] = { + DRM_MIPI_DBI_PLANE_FORMATS, +}; + +static const u64 ili9486_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static const struct drm_plane_helper_funcs ili9486_plane_helper_funcs = { + DRM_MIPI_DBI_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs ili9486_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void ili9486_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + struct drm_device *drm = crtc->dev; + struct ili9486_device *ili9486 = to_ili9486_device(drm); + struct mipi_dbi_dev *dbidev = &ili9486->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; u8 addr_mode; int ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; DRM_DEBUG_KMS("\n"); @@ -155,13 +187,41 @@ static void waveshare_enable(struct drm_simple_display_pipe *pipe, } addr_mode |= ILI9486_MADCTL_BGR; mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); - mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); + + backlight_enable(dbidev->backlight); out_exit: drm_dev_exit(idx); } -static const struct drm_simple_display_pipe_funcs waveshare_pipe_funcs = { - DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(waveshare_enable), +static const struct drm_crtc_helper_funcs ili9486_crtc_helper_funcs = { + DRM_MIPI_DBI_CRTC_HELPER_FUNCS, + .atomic_enable = ili9486_crtc_helper_atomic_enable, +}; + +static const struct drm_crtc_funcs ili9486_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs ili9486_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs ili9486_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs ili9486_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs ili9486_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs ili9486_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, }; static const struct drm_display_mode waveshare_mode = { @@ -200,18 +260,22 @@ MODULE_DEVICE_TABLE(spi, ili9486_id); static int ili9486_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct ili9486_device *ili9486; struct mipi_dbi_dev *dbidev; struct drm_device *drm; struct mipi_dbi *dbi; struct gpio_desc *dc; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; u32 rotation = 0; int ret; - dbidev = devm_drm_dev_alloc(dev, &ili9486_driver, - struct mipi_dbi_dev, drm); - if (IS_ERR(dbidev)) - return PTR_ERR(dbidev); - + ili9486 = devm_drm_dev_alloc(dev, &ili9486_driver, struct ili9486_device, dbidev.drm); + if (IS_ERR(ili9486)) + return PTR_ERR(ili9486); + dbidev = &ili9486->dbidev; dbi = &dbidev->dbi; drm = &dbidev->drm; @@ -236,8 +300,53 @@ static int ili9486_probe(struct spi_device *spi) dbi->command = waveshare_command; dbi->read_commands = NULL; - ret = mipi_dbi_dev_init(dbidev, &waveshare_pipe_funcs, - &waveshare_mode, rotation); + ret = drm_mipi_dbi_dev_init(dbidev, &waveshare_mode, ili9486_plane_formats[0], + rotation, 0); + if (ret) + return ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &ili9486_mode_config_funcs; + drm->mode_config.preferred_depth = 16; + drm->mode_config.helper_private = &ili9486_mode_config_helper_funcs; + + plane = &ili9486->plane; + ret = drm_universal_plane_init(drm, plane, 0, &ili9486_plane_funcs, + ili9486_plane_formats, ARRAY_SIZE(ili9486_plane_formats), + ili9486_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &ili9486_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &ili9486->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &ili9486_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &ili9486_crtc_helper_funcs); + + encoder = &ili9486->encoder; + ret = drm_encoder_init(drm, encoder, &ili9486_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &ili9486->connector; + ret = drm_connector_init(drm, connector, &ili9486_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &ili9486_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/tiny/mi0283qt.c b/drivers/gpu/drm/tiny/mi0283qt.c index a063eff77624..ee597d023390 100644 --- a/drivers/gpu/drm/tiny/mi0283qt.c +++ b/drivers/gpu/drm/tiny/mi0283qt.c @@ -50,16 +50,48 @@ #define ILI9341_MADCTL_MX BIT(6) #define ILI9341_MADCTL_MY BIT(7) -static void mi0283qt_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +struct mi0283qt_device { + struct mipi_dbi_dev dbidev; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct mi0283qt_device *to_mi0283qt_device(struct drm_device *dev) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + return container_of(drm_to_mipi_dbi_dev(dev), struct mi0283qt_device, dbidev); +} + +static const u32 mi0283qt_plane_formats[] = { + DRM_MIPI_DBI_PLANE_FORMATS, +}; + +static const u64 mi0283qt_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static const struct drm_plane_helper_funcs mi0283qt_plane_helper_funcs = { + DRM_MIPI_DBI_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mi0283qt_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void mi0283qt_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct mi0283qt_device *mi0283qt = to_mi0283qt_device(drm); + struct mipi_dbi_dev *dbidev = &mi0283qt->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; u8 addr_mode; int ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; DRM_DEBUG_KMS("\n"); @@ -137,13 +169,41 @@ out_enable: } addr_mode |= ILI9341_MADCTL_BGR; mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); - mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); + + backlight_enable(dbidev->backlight); out_exit: drm_dev_exit(idx); } -static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = { - DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(mi0283qt_enable), +static const struct drm_crtc_helper_funcs mi0283qt_crtc_helper_funcs = { + DRM_MIPI_DBI_CRTC_HELPER_FUNCS, + .atomic_enable = mi0283qt_crtc_helper_atomic_enable, +}; + +static const struct drm_crtc_funcs mi0283qt_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs mi0283qt_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs mi0283qt_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mi0283qt_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs mi0283qt_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs mi0283qt_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, }; static const struct drm_display_mode mi0283qt_mode = { @@ -179,18 +239,22 @@ MODULE_DEVICE_TABLE(spi, mi0283qt_id); static int mi0283qt_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct mi0283qt_device *mi0283qt; struct mipi_dbi_dev *dbidev; struct drm_device *drm; struct mipi_dbi *dbi; struct gpio_desc *dc; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; u32 rotation = 0; int ret; - dbidev = devm_drm_dev_alloc(dev, &mi0283qt_driver, - struct mipi_dbi_dev, drm); - if (IS_ERR(dbidev)) - return PTR_ERR(dbidev); - + mi0283qt = devm_drm_dev_alloc(dev, &mi0283qt_driver, struct mi0283qt_device, dbidev.drm); + if (IS_ERR(mi0283qt)) + return PTR_ERR(mi0283qt); + dbidev = &mi0283qt->dbidev; dbi = &dbidev->dbi; drm = &dbidev->drm; @@ -216,7 +280,53 @@ static int mi0283qt_probe(struct spi_device *spi) if (ret) return ret; - ret = mipi_dbi_dev_init(dbidev, &mi0283qt_pipe_funcs, &mi0283qt_mode, rotation); + ret = drm_mipi_dbi_dev_init(dbidev, &mi0283qt_mode, mi0283qt_plane_formats[0], + rotation, 0); + if (ret) + return ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &mi0283qt_mode_config_funcs; + drm->mode_config.preferred_depth = 16; + drm->mode_config.helper_private = &mi0283qt_mode_config_helper_funcs; + + plane = &mi0283qt->plane; + ret = drm_universal_plane_init(drm, plane, 0, &mi0283qt_plane_funcs, + mi0283qt_plane_formats, ARRAY_SIZE(mi0283qt_plane_formats), + mi0283qt_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &mi0283qt_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &mi0283qt->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &mi0283qt_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &mi0283qt_crtc_helper_funcs); + + encoder = &mi0283qt->encoder; + ret = drm_encoder_init(drm, encoder, &mi0283qt_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &mi0283qt->connector; + ret = drm_connector_init(drm, connector, &mi0283qt_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &mi0283qt_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/tiny/panel-mipi-dbi.c b/drivers/gpu/drm/tiny/panel-mipi-dbi.c index 82dfa169f762..581e14528608 100644 --- a/drivers/gpu/drm/tiny/panel-mipi-dbi.c +++ b/drivers/gpu/drm/tiny/panel-mipi-dbi.c @@ -233,18 +233,46 @@ static void panel_mipi_dbi_commands_execute(struct mipi_dbi *dbi, } } -static void panel_mipi_dbi_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +struct panel_mipi_dbi_device { + struct mipi_dbi_dev dbidev; + + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct panel_mipi_dbi_device *to_panel_mipi_dbi_device(struct drm_device *dev) +{ + return container_of(drm_to_mipi_dbi_dev(dev), struct panel_mipi_dbi_device, dbidev); +} + +static const u64 panel_mipi_dbi_plane_format_modifiers[] = { + DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, +}; + +static const struct drm_plane_helper_funcs panel_mipi_dbi_plane_helper_funcs = { + DRM_MIPI_DBI_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs panel_mipi_dbi_plane_funcs = { + DRM_MIPI_DBI_PLANE_FUNCS, + .destroy = drm_plane_cleanup, +}; + +static void panel_mipi_dbi_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) { - struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + struct drm_device *drm = crtc->dev; + struct panel_mipi_dbi_device *panel_mipi_dbi = to_panel_mipi_dbi_device(drm); + struct mipi_dbi_dev *dbidev = &panel_mipi_dbi->dbidev; struct mipi_dbi *dbi = &dbidev->dbi; int ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(drm, &idx)) return; - drm_dbg(pipe->crtc.dev, "\n"); + drm_dbg(drm, "\n"); ret = mipi_dbi_poweron_conditional_reset(dbidev); if (ret < 0) @@ -252,13 +280,40 @@ static void panel_mipi_dbi_enable(struct drm_simple_display_pipe *pipe, if (!ret) panel_mipi_dbi_commands_execute(dbi, dbidev->driver_private); - mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); + backlight_enable(dbidev->backlight); out_exit: drm_dev_exit(idx); } -static const struct drm_simple_display_pipe_funcs panel_mipi_dbi_pipe_funcs = { - DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(panel_mipi_dbi_enable), +static const struct drm_crtc_helper_funcs panel_mipi_dbi_crtc_helper_funcs = { + DRM_MIPI_DBI_CRTC_HELPER_FUNCS, + .atomic_enable = panel_mipi_dbi_crtc_helper_atomic_enable, +}; + +static const struct drm_crtc_funcs panel_mipi_dbi_crtc_funcs = { + DRM_MIPI_DBI_CRTC_FUNCS, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_encoder_funcs panel_mipi_dbi_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct drm_connector_helper_funcs panel_mipi_dbi_connector_helper_funcs = { + DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs panel_mipi_dbi_connector_funcs = { + DRM_MIPI_DBI_CONNECTOR_FUNCS, + .destroy = drm_connector_cleanup, +}; + +static const struct drm_mode_config_helper_funcs panel_mipi_dbi_mode_config_helper_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, +}; + +static const struct drm_mode_config_funcs panel_mipi_dbi_mode_config_funcs = { + DRM_MIPI_DBI_MODE_CONFIG_FUNCS, }; DEFINE_DRM_GEM_DMA_FOPS(panel_mipi_dbi_fops); @@ -317,20 +372,27 @@ static int panel_mipi_dbi_get_mode(struct mipi_dbi_dev *dbidev, struct drm_displ static int panel_mipi_dbi_spi_probe(struct spi_device *spi) { struct device *dev = &spi->dev; - struct drm_display_mode mode; + struct panel_mipi_dbi_device *panel_mipi_dbi; struct mipi_dbi_dev *dbidev; struct drm_device *drm; + struct drm_display_mode mode; struct mipi_dbi *dbi; struct gpio_desc *dc; unsigned int bpp; size_t buf_size; u32 formats[2]; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; int ret; - dbidev = devm_drm_dev_alloc(dev, &panel_mipi_dbi_driver, struct mipi_dbi_dev, drm); - if (IS_ERR(dbidev)) - return PTR_ERR(dbidev); - + panel_mipi_dbi = devm_drm_dev_alloc(dev, &panel_mipi_dbi_driver, + struct panel_mipi_dbi_device, + dbidev.drm); + if (IS_ERR(panel_mipi_dbi)) + return PTR_ERR(panel_mipi_dbi); + dbidev = &panel_mipi_dbi->dbidev; dbi = &dbidev->dbi; drm = &dbidev->drm; @@ -377,9 +439,54 @@ static int panel_mipi_dbi_spi_probe(struct spi_device *spi) return ret; buf_size = DIV_ROUND_UP(mode.hdisplay * mode.vdisplay * bpp, 8); - ret = mipi_dbi_dev_init_with_formats(dbidev, &panel_mipi_dbi_pipe_funcs, - formats, ARRAY_SIZE(formats), - &mode, 0, buf_size); + ret = drm_mipi_dbi_dev_init(dbidev, &mode, formats[0], 0, buf_size); + if (ret) + return ret; + + ret = drmm_mode_config_init(drm); + if (ret) + return ret; + + drm->mode_config.min_width = dbidev->mode.hdisplay; + drm->mode_config.max_width = dbidev->mode.hdisplay; + drm->mode_config.min_height = dbidev->mode.vdisplay; + drm->mode_config.max_height = dbidev->mode.vdisplay; + drm->mode_config.funcs = &panel_mipi_dbi_mode_config_funcs; + drm->mode_config.preferred_depth = bpp; + drm->mode_config.helper_private = &panel_mipi_dbi_mode_config_helper_funcs; + + plane = &panel_mipi_dbi->plane; + ret = drm_universal_plane_init(drm, plane, 0, &panel_mipi_dbi_plane_funcs, + formats, ARRAY_SIZE(formats), + panel_mipi_dbi_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &panel_mipi_dbi_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(plane); + + crtc = &panel_mipi_dbi->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &panel_mipi_dbi_crtc_funcs, + NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &panel_mipi_dbi_crtc_helper_funcs); + + encoder = &panel_mipi_dbi->encoder; + ret = drm_encoder_init(drm, encoder, &panel_mipi_dbi_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + connector = &panel_mipi_dbi->connector; + ret = drm_connector_init(drm, connector, &panel_mipi_dbi_connector_funcs, + DRM_MODE_CONNECTOR_SPI); + if (ret) + return ret; + drm_connector_helper_add(connector, &panel_mipi_dbi_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c index e32f3c8d7b84..2db221f6fc3a 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c +++ b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c @@ -759,6 +759,46 @@ static void ttm_bo_validate_move_fence_not_signaled(struct kunit *test) ttm_mock_manager_fini(priv->ttm_dev, snd_mem); } +static void ttm_bo_validate_swapout(struct kunit *test) +{ + u32 mem_type = TTM_PL_TT; + struct ttm_test_devices *priv = test->priv; + struct ttm_operation_ctx ctx_init = { }; + enum ttm_bo_type bo_type = ttm_bo_type_device; + struct ttm_resource_manager *man; + struct ttm_placement *placement; + struct ttm_buffer_object *bo; + struct ttm_place *place; + int err; + s64 swapped; + + ttm_mock_manager_init(priv->ttm_dev, mem_type, MANAGER_SIZE); + man = ttm_manager_type(priv->ttm_dev, mem_type); + KUNIT_ASSERT_NOT_NULL(test, man); + + place = ttm_place_kunit_init(test, mem_type, 0); + placement = ttm_placement_kunit_init(test, place, 1); + + bo = kunit_kzalloc(test, sizeof(*bo), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, bo); + + drm_gem_private_object_init(priv->drm, &bo->base, MANAGER_SIZE); + err = ttm_bo_init_reserved(priv->ttm_dev, bo, bo_type, placement, + PAGE_SIZE, &ctx_init, NULL, NULL, + &dummy_ttm_bo_destroy); + KUNIT_EXPECT_EQ(test, err, 0); + dma_resv_unlock(bo->base.resv); + + swapped = ttm_bo_swapout(priv->ttm_dev, &ctx_init, man, GFP_KERNEL, + MANAGER_SIZE / PAGE_SIZE); + KUNIT_EXPECT_EQ(test, swapped, MANAGER_SIZE / PAGE_SIZE); + KUNIT_EXPECT_EQ(test, bo->resource->mem_type, TTM_PL_SYSTEM); + KUNIT_EXPECT_TRUE(test, bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED); + + ttm_bo_fini(bo); + ttm_mock_manager_fini(priv->ttm_dev, mem_type); +} + static void ttm_bo_validate_happy_evict(struct kunit *test) { u32 mem_type = TTM_PL_VRAM, mem_multihop = TTM_PL_TT, @@ -1153,6 +1193,7 @@ static struct kunit_case ttm_bo_validate_test_cases[] = { KUNIT_CASE(ttm_bo_validate_move_fence_signaled), KUNIT_CASE_PARAM(ttm_bo_validate_move_fence_not_signaled, ttm_bo_validate_wait_gen_params), + KUNIT_CASE(ttm_bo_validate_swapout), KUNIT_CASE(ttm_bo_validate_happy_evict), KUNIT_CASE(ttm_bo_validate_all_pinned_evict), KUNIT_CASE(ttm_bo_validate_allowed_only_evict), diff --git a/drivers/gpu/drm/ttm/tests/ttm_device_test.c b/drivers/gpu/drm/ttm/tests/ttm_device_test.c index 2d55ad34fe48..db4b4a09a73f 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_device_test.c +++ b/drivers/gpu/drm/ttm/tests/ttm_device_test.c @@ -176,7 +176,7 @@ static void ttm_device_init_pools(struct kunit *test) if (ttm_pool_uses_dma_alloc(pool)) KUNIT_ASSERT_FALSE(test, - list_empty(&pt.pages)); + !list_lru_count(&pt.pages)); } } } diff --git a/drivers/gpu/drm/ttm/tests/ttm_pool_test.c b/drivers/gpu/drm/ttm/tests/ttm_pool_test.c index 11c92bd75779..01197014b83f 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_pool_test.c +++ b/drivers/gpu/drm/ttm/tests/ttm_pool_test.c @@ -248,7 +248,7 @@ static void ttm_pool_alloc_order_caching_match(struct kunit *test) pool = ttm_pool_pre_populated(test, size, caching); pt = &pool->caching[caching].orders[order]; - KUNIT_ASSERT_FALSE(test, list_empty(&pt->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt->pages)); tt = ttm_tt_kunit_init(test, 0, caching, size); KUNIT_ASSERT_NOT_NULL(test, tt); @@ -256,7 +256,7 @@ static void ttm_pool_alloc_order_caching_match(struct kunit *test) err = ttm_pool_alloc(pool, tt, &simple_ctx); KUNIT_ASSERT_EQ(test, err, 0); - KUNIT_ASSERT_TRUE(test, list_empty(&pt->pages)); + KUNIT_ASSERT_TRUE(test, !list_lru_count(&pt->pages)); ttm_pool_free(pool, tt); ttm_tt_fini(tt); @@ -282,8 +282,8 @@ static void ttm_pool_alloc_caching_mismatch(struct kunit *test) tt = ttm_tt_kunit_init(test, 0, tt_caching, size); KUNIT_ASSERT_NOT_NULL(test, tt); - KUNIT_ASSERT_FALSE(test, list_empty(&pt_pool->pages)); - KUNIT_ASSERT_TRUE(test, list_empty(&pt_tt->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt_pool->pages)); + KUNIT_ASSERT_TRUE(test, !list_lru_count(&pt_tt->pages)); err = ttm_pool_alloc(pool, tt, &simple_ctx); KUNIT_ASSERT_EQ(test, err, 0); @@ -291,8 +291,8 @@ static void ttm_pool_alloc_caching_mismatch(struct kunit *test) ttm_pool_free(pool, tt); ttm_tt_fini(tt); - KUNIT_ASSERT_FALSE(test, list_empty(&pt_pool->pages)); - KUNIT_ASSERT_FALSE(test, list_empty(&pt_tt->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt_pool->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt_tt->pages)); ttm_pool_fini(pool); } @@ -316,8 +316,8 @@ static void ttm_pool_alloc_order_mismatch(struct kunit *test) tt = ttm_tt_kunit_init(test, 0, caching, snd_size); KUNIT_ASSERT_NOT_NULL(test, tt); - KUNIT_ASSERT_FALSE(test, list_empty(&pt_pool->pages)); - KUNIT_ASSERT_TRUE(test, list_empty(&pt_tt->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt_pool->pages)); + KUNIT_ASSERT_TRUE(test, !list_lru_count(&pt_tt->pages)); err = ttm_pool_alloc(pool, tt, &simple_ctx); KUNIT_ASSERT_EQ(test, err, 0); @@ -325,8 +325,8 @@ static void ttm_pool_alloc_order_mismatch(struct kunit *test) ttm_pool_free(pool, tt); ttm_tt_fini(tt); - KUNIT_ASSERT_FALSE(test, list_empty(&pt_pool->pages)); - KUNIT_ASSERT_FALSE(test, list_empty(&pt_tt->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt_pool->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt_tt->pages)); ttm_pool_fini(pool); } @@ -352,12 +352,12 @@ static void ttm_pool_free_dma_alloc(struct kunit *test) ttm_pool_alloc(pool, tt, &simple_ctx); pt = &pool->caching[caching].orders[order]; - KUNIT_ASSERT_TRUE(test, list_empty(&pt->pages)); + KUNIT_ASSERT_TRUE(test, !list_lru_count(&pt->pages)); ttm_pool_free(pool, tt); ttm_tt_fini(tt); - KUNIT_ASSERT_FALSE(test, list_empty(&pt->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt->pages)); ttm_pool_fini(pool); } @@ -383,12 +383,12 @@ static void ttm_pool_free_no_dma_alloc(struct kunit *test) ttm_pool_alloc(pool, tt, &simple_ctx); pt = &pool->caching[caching].orders[order]; - KUNIT_ASSERT_TRUE(test, list_is_singular(&pt->pages)); + KUNIT_ASSERT_TRUE(test, list_lru_count(&pt->pages) == 1); ttm_pool_free(pool, tt); ttm_tt_fini(tt); - KUNIT_ASSERT_TRUE(test, list_is_singular(&pt->pages)); + KUNIT_ASSERT_TRUE(test, list_lru_count(&pt->pages) == 1); ttm_pool_fini(pool); } @@ -404,11 +404,11 @@ static void ttm_pool_fini_basic(struct kunit *test) pool = ttm_pool_pre_populated(test, size, caching); pt = &pool->caching[caching].orders[order]; - KUNIT_ASSERT_FALSE(test, list_empty(&pt->pages)); + KUNIT_ASSERT_FALSE(test, !list_lru_count(&pt->pages)); ttm_pool_fini(pool); - KUNIT_ASSERT_TRUE(test, list_empty(&pt->pages)); + KUNIT_ASSERT_TRUE(test, !list_lru_count(&pt->pages)); } static struct kunit_case ttm_pool_test_cases[] = { diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c index 6bd4c123d94c..81df4cb5606b 100644 --- a/drivers/gpu/drm/ttm/ttm_backup.c +++ b/drivers/gpu/drm/ttm/ttm_backup.c @@ -44,18 +44,20 @@ void ttm_backup_drop(struct file *backup, pgoff_t handle) * @dst: The struct page to copy into. * @handle: The handle returned when the page was backed up. * @intr: Try to perform waits interruptible or at least killable. + * @additional_gfp: GFP mask to add to the default GFP mask if any. * * Return: 0 on success, Negative error code on failure, notably * -EINTR if @intr was set to true and a signal is pending. */ int ttm_backup_copy_page(struct file *backup, struct page *dst, - pgoff_t handle, bool intr) + pgoff_t handle, bool intr, gfp_t additional_gfp) { struct address_space *mapping = backup->f_mapping; struct folio *from_folio; pgoff_t idx = ttm_backup_handle_to_shmem_idx(handle); - from_folio = shmem_read_folio(mapping, idx); + from_folio = shmem_read_folio_gfp(mapping, idx, mapping_gfp_mask(mapping) + | additional_gfp); if (IS_ERR(from_folio)) return PTR_ERR(from_folio); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 34ce53b4bdb9..d85f0a37ac35 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -32,6 +32,7 @@ #define pr_fmt(fmt) "[TTM] " fmt #include <drm/drm_print.h> +#include <drm/drm_util.h> #include <drm/ttm/ttm_allocation.h> #include <drm/ttm/ttm_bo.h> #include <drm/ttm/ttm_placement.h> @@ -1208,9 +1209,9 @@ const struct ttm_lru_walk_ops ttm_swap_ops = { * @man: The resource manager whose resources / buffer objects are * goint to be swapped out. * @gfp_flags: The gfp flags used for shmem page allocations. - * @target: The desired number of bytes to swap out. + * @target: The desired number of pages to swap out. * - * Return: The number of bytes actually swapped out, or negative error code + * Return: The number of pages actually swapped out, or negative error code * on error. */ s64 ttm_bo_swapout(struct ttm_device *bdev, struct ttm_operation_ctx *ctx, @@ -1230,6 +1231,7 @@ s64 ttm_bo_swapout(struct ttm_device *bdev, struct ttm_operation_ctx *ctx, return ttm_lru_walk_for_evict(&swapout_walk.walk, bdev, man, target); } +EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_bo_swapout); void ttm_bo_tt_destroy(struct ttm_buffer_object *bo) { diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c index c0d95559197c..26a3689e5fd9 100644 --- a/drivers/gpu/drm/ttm/ttm_pool.c +++ b/drivers/gpu/drm/ttm/ttm_pool.c @@ -116,10 +116,11 @@ struct ttm_pool_tt_restore { static unsigned long page_pool_size; -MODULE_PARM_DESC(page_pool_size, "Number of pages in the WC/UC/DMA pool"); +MODULE_PARM_DESC(page_pool_size, "Number of pages in the WC/UC/DMA pool per NUMA node"); module_param(page_pool_size, ulong, 0644); -static atomic_long_t allocated_pages; +static unsigned long pool_node_limit[MAX_NUMNODES]; +static atomic_long_t allocated_pages[MAX_NUMNODES]; static struct ttm_pool_type global_write_combined[NR_PAGE_ORDERS]; static struct ttm_pool_type global_uncached[NR_PAGE_ORDERS]; @@ -132,6 +133,16 @@ static struct list_head shrinker_list; static struct shrinker *mm_shrinker; static DECLARE_RWSEM(pool_shrink_rwsem); +static int ttm_pool_nid(struct ttm_pool *pool) +{ + int nid = NUMA_NO_NODE; + if (pool) + nid = pool->nid; + if (nid == NUMA_NO_NODE) + nid = numa_node_id(); + return nid; +} + /* Allocate pages of size 1 << order with the given gfp_flags */ static struct page *ttm_pool_alloc_page(struct ttm_pool *pool, gfp_t gfp_flags, unsigned int order) @@ -159,8 +170,10 @@ static struct page *ttm_pool_alloc_page(struct ttm_pool *pool, gfp_t gfp_flags, if (!ttm_pool_uses_dma_alloc(pool)) { p = alloc_pages_node(pool->nid, gfp_flags, order); - if (p) + if (p) { p->private = order; + mod_lruvec_page_state(p, NR_GPU_ACTIVE, 1 << order); + } return p; } @@ -195,7 +208,7 @@ error_free: /* Reset the caching and pages of size 1 << order */ static void ttm_pool_free_page(struct ttm_pool *pool, enum ttm_caching caching, - unsigned int order, struct page *p) + unsigned int order, struct page *p, bool reclaim) { unsigned long attr = DMA_ATTR_FORCE_CONTIGUOUS; struct ttm_pool_dma *dma; @@ -210,6 +223,8 @@ static void ttm_pool_free_page(struct ttm_pool *pool, enum ttm_caching caching, #endif if (!pool || !ttm_pool_uses_dma_alloc(pool)) { + mod_lruvec_page_state(p, reclaim ? NR_GPU_RECLAIM : NR_GPU_ACTIVE, + -(1 << order)); __free_pages(p, order); return; } @@ -285,6 +300,7 @@ static void ttm_pool_unmap(struct ttm_pool *pool, dma_addr_t dma_addr, static void ttm_pool_type_give(struct ttm_pool_type *pt, struct page *p) { unsigned int i, num_pages = 1 << pt->order; + int nid = page_to_nid(p); for (i = 0; i < num_pages; ++i) { if (PageHighMem(p)) @@ -293,25 +309,41 @@ static void ttm_pool_type_give(struct ttm_pool_type *pt, struct page *p) clear_page(page_address(p + i)); } - spin_lock(&pt->lock); - list_add(&p->lru, &pt->pages); - spin_unlock(&pt->lock); - atomic_long_add(1 << pt->order, &allocated_pages); + INIT_LIST_HEAD(&p->lru); + rcu_read_lock(); + list_lru_add(&pt->pages, &p->lru, nid, NULL); + rcu_read_unlock(); + + atomic_long_add(num_pages, &allocated_pages[nid]); + mod_lruvec_page_state(p, NR_GPU_ACTIVE, -num_pages); + mod_lruvec_page_state(p, NR_GPU_RECLAIM, num_pages); } -/* Take pages from a specific pool_type, return NULL when nothing available */ -static struct page *ttm_pool_type_take(struct ttm_pool_type *pt) +static enum lru_status take_one_from_lru(struct list_head *item, + struct list_lru_one *list, + void *cb_arg) { - struct page *p; + struct page **out_page = cb_arg; + struct page *p = container_of(item, struct page, lru); + list_lru_isolate(list, item); - spin_lock(&pt->lock); - p = list_first_entry_or_null(&pt->pages, typeof(*p), lru); - if (p) { - atomic_long_sub(1 << pt->order, &allocated_pages); - list_del(&p->lru); - } - spin_unlock(&pt->lock); + *out_page = p; + return LRU_REMOVED; +} +/* Take pages from a specific pool_type, return NULL when nothing available */ +static struct page *ttm_pool_type_take(struct ttm_pool_type *pt, int nid) +{ + int ret; + struct page *p = NULL; + unsigned long nr_to_walk = 1; + + ret = list_lru_walk_node(&pt->pages, nid, take_one_from_lru, (void *)&p, &nr_to_walk); + if (ret == 1 && p) { + atomic_long_sub(1 << pt->order, &allocated_pages[nid]); + mod_lruvec_page_state(p, NR_GPU_ACTIVE, (1 << pt->order)); + mod_lruvec_page_state(p, NR_GPU_RECLAIM, -(1 << pt->order)); + } return p; } @@ -322,25 +354,47 @@ static void ttm_pool_type_init(struct ttm_pool_type *pt, struct ttm_pool *pool, pt->pool = pool; pt->caching = caching; pt->order = order; - spin_lock_init(&pt->lock); - INIT_LIST_HEAD(&pt->pages); + list_lru_init(&pt->pages); spin_lock(&shrinker_lock); list_add_tail(&pt->shrinker_list, &shrinker_list); spin_unlock(&shrinker_lock); } +static enum lru_status pool_move_to_dispose_list(struct list_head *item, + struct list_lru_one *list, + void *cb_arg) +{ + struct list_head *dispose = cb_arg; + + list_lru_isolate_move(list, item, dispose); + + return LRU_REMOVED; +} + +static void ttm_pool_dispose_list(struct ttm_pool_type *pt, + struct list_head *dispose) +{ + while (!list_empty(dispose)) { + struct page *p; + p = list_first_entry(dispose, struct page, lru); + list_del_init(&p->lru); + atomic_long_sub(1 << pt->order, &allocated_pages[page_to_nid(p)]); + ttm_pool_free_page(pt->pool, pt->caching, pt->order, p, true); + } +} + /* Remove a pool_type from the global shrinker list and free all pages */ static void ttm_pool_type_fini(struct ttm_pool_type *pt) { - struct page *p; + LIST_HEAD(dispose); spin_lock(&shrinker_lock); list_del(&pt->shrinker_list); spin_unlock(&shrinker_lock); - while ((p = ttm_pool_type_take(pt))) - ttm_pool_free_page(pt->pool, pt->caching, pt->order, p); + list_lru_walk(&pt->pages, pool_move_to_dispose_list, &dispose, LONG_MAX); + ttm_pool_dispose_list(pt, &dispose); } /* Return the pool_type to use for the given caching and order */ @@ -354,17 +408,11 @@ static struct ttm_pool_type *ttm_pool_select_type(struct ttm_pool *pool, #ifdef CONFIG_X86 switch (caching) { case ttm_write_combined: - if (pool->nid != NUMA_NO_NODE) - return &pool->caching[caching].orders[order]; - if (ttm_pool_uses_dma32(pool)) return &global_dma32_write_combined[order]; return &global_write_combined[order]; case ttm_uncached: - if (pool->nid != NUMA_NO_NODE) - return &pool->caching[caching].orders[order]; - if (ttm_pool_uses_dma32(pool)) return &global_dma32_uncached[order]; @@ -377,12 +425,12 @@ static struct ttm_pool_type *ttm_pool_select_type(struct ttm_pool *pool, return NULL; } -/* Free pages using the global shrinker list */ -static unsigned int ttm_pool_shrink(void) +/* Free pages using the per-node shrinker list */ +static unsigned int ttm_pool_shrink(int nid, unsigned long num_to_free) { + LIST_HEAD(dispose); struct ttm_pool_type *pt; unsigned int num_pages; - struct page *p; down_read(&pool_shrink_rwsem); spin_lock(&shrinker_lock); @@ -390,13 +438,10 @@ static unsigned int ttm_pool_shrink(void) list_move_tail(&pt->shrinker_list, &shrinker_list); spin_unlock(&shrinker_lock); - p = ttm_pool_type_take(pt); - if (p) { - ttm_pool_free_page(pt->pool, pt->caching, pt->order, p); - num_pages = 1 << pt->order; - } else { - num_pages = 0; - } + num_pages = list_lru_walk_node(&pt->pages, nid, pool_move_to_dispose_list, &dispose, &num_to_free); + num_pages *= 1 << pt->order; + + ttm_pool_dispose_list(pt, &dispose); up_read(&pool_shrink_rwsem); return num_pages; @@ -484,7 +529,7 @@ static pgoff_t ttm_pool_unmap_and_free(struct ttm_pool *pool, struct page *page, if (pt) ttm_pool_type_give(pt, page); else - ttm_pool_free_page(pool, caching, order, page); + ttm_pool_free_page(pool, caching, order, page, false); return nr; } @@ -530,6 +575,8 @@ static int ttm_pool_restore_commit(struct ttm_pool_tt_restore *restore, p = first_page[i]; if (ttm_backup_page_ptr_is_handle(p)) { unsigned long handle = ttm_backup_page_ptr_to_handle(p); + gfp_t additional_gfp = ctx->gfp_retry_mayfail ? + __GFP_RETRY_MAYFAIL | __GFP_NOWARN : 0; if (IS_ENABLED(CONFIG_FAULT_INJECTION) && ctx->interruptible && should_fail(&backup_fault_inject, 1)) { @@ -543,7 +590,8 @@ static int ttm_pool_restore_commit(struct ttm_pool_tt_restore *restore, } ret = ttm_backup_copy_page(backup, restore->alloced_page + i, - handle, ctx->interruptible); + handle, ctx->interruptible, + additional_gfp); if (ret) break; @@ -726,7 +774,7 @@ static int __ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, gfp_flags |= __GFP_ZERO; if (ctx->gfp_retry_mayfail) - gfp_flags |= __GFP_RETRY_MAYFAIL; + gfp_flags |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN; if (ttm_pool_uses_dma32(pool)) gfp_flags |= GFP_DMA32; @@ -744,7 +792,8 @@ static int __ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, p = NULL; pt = ttm_pool_select_type(pool, page_caching, order); if (pt && allow_pools) - p = ttm_pool_type_take(pt); + p = ttm_pool_type_take(pt, ttm_pool_nid(pool)); + /* * If that fails or previously failed, allocate from system. * Note that this also disallows additional pool allocations using @@ -789,7 +838,7 @@ static int __ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, return 0; error_free_page: - ttm_pool_free_page(pool, page_caching, order, p); + ttm_pool_free_page(pool, page_caching, order, p, false); error_free_all: if (tt->restore) @@ -893,10 +942,14 @@ int ttm_pool_restore_and_alloc(struct ttm_pool *pool, struct ttm_tt *tt, */ void ttm_pool_free(struct ttm_pool *pool, struct ttm_tt *tt) { + int nid = ttm_pool_nid(pool); + ttm_pool_free_range(pool, tt, tt->caching, 0, tt->num_pages); - while (atomic_long_read(&allocated_pages) > page_pool_size) - ttm_pool_shrink(); + while (atomic_long_read(&allocated_pages[nid]) > pool_node_limit[nid]) { + unsigned long diff = atomic_long_read(&allocated_pages[nid]) - pool_node_limit[nid]; + ttm_pool_shrink(nid, diff); + } } EXPORT_SYMBOL(ttm_pool_free); @@ -1151,9 +1204,9 @@ static unsigned long ttm_pool_shrinker_scan(struct shrinker *shrink, unsigned long num_freed = 0; do - num_freed += ttm_pool_shrink(); + num_freed += ttm_pool_shrink(sc->nid, sc->nr_to_scan); while (num_freed < sc->nr_to_scan && - atomic_long_read(&allocated_pages)); + atomic_long_read(&allocated_pages[sc->nid])); sc->nr_scanned = num_freed; @@ -1164,7 +1217,7 @@ static unsigned long ttm_pool_shrinker_scan(struct shrinker *shrink, static unsigned long ttm_pool_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) { - unsigned long num_pages = atomic_long_read(&allocated_pages); + unsigned long num_pages = atomic_long_read(&allocated_pages[sc->nid]); return num_pages ? num_pages : SHRINK_EMPTY; } @@ -1173,16 +1226,7 @@ static unsigned long ttm_pool_shrinker_count(struct shrinker *shrink, /* Count the number of pages available in a pool_type */ static unsigned int ttm_pool_type_count(struct ttm_pool_type *pt) { - unsigned int count = 0; - struct page *p; - - spin_lock(&pt->lock); - /* Only used for debugfs, the overhead doesn't matter */ - list_for_each_entry(p, &pt->pages, lru) - ++count; - spin_unlock(&pt->lock); - - return count; + return list_lru_count(&pt->pages); } /* Print a nice header for the order */ @@ -1210,8 +1254,12 @@ static void ttm_pool_debugfs_orders(struct ttm_pool_type *pt, /* Dump the total amount of allocated pages */ static void ttm_pool_debugfs_footer(struct seq_file *m) { - seq_printf(m, "\ntotal\t: %8lu of %8lu\n", - atomic_long_read(&allocated_pages), page_pool_size); + int nid; + + for_each_node(nid) { + seq_printf(m, "\ntotal node%d\t: %8lu of %8lu\n", nid, + atomic_long_read(&allocated_pages[nid]), pool_node_limit[nid]); + } } /* Dump the information for the global pools */ @@ -1248,7 +1296,7 @@ int ttm_pool_debugfs(struct ttm_pool *pool, struct seq_file *m) { unsigned int i; - if (!ttm_pool_uses_dma_alloc(pool) && pool->nid == NUMA_NO_NODE) { + if (!ttm_pool_uses_dma_alloc(pool)) { seq_puts(m, "unused\n"); return 0; } @@ -1259,10 +1307,7 @@ int ttm_pool_debugfs(struct ttm_pool *pool, struct seq_file *m) for (i = 0; i < TTM_NUM_CACHING_TYPES; ++i) { if (!ttm_pool_select_type(pool, i, 0)) continue; - if (ttm_pool_uses_dma_alloc(pool)) - seq_puts(m, "DMA "); - else - seq_printf(m, "N%d ", pool->nid); + seq_puts(m, "DMA "); switch (i) { case ttm_cached: seq_puts(m, "\t:"); @@ -1291,11 +1336,15 @@ static int ttm_pool_debugfs_shrink_show(struct seq_file *m, void *data) .nr_to_scan = TTM_SHRINKER_BATCH, }; unsigned long count; + int nid; fs_reclaim_acquire(GFP_KERNEL); - count = ttm_pool_shrinker_count(mm_shrinker, &sc); - seq_printf(m, "%lu/%lu\n", count, - ttm_pool_shrinker_scan(mm_shrinker, &sc)); + for_each_node(nid) { + sc.nid = nid; + count = ttm_pool_shrinker_count(mm_shrinker, &sc); + seq_printf(m, "%d: %lu/%lu\n", nid, count, + ttm_pool_shrinker_scan(mm_shrinker, &sc)); + } fs_reclaim_release(GFP_KERNEL); return 0; @@ -1304,6 +1353,23 @@ DEFINE_SHOW_ATTRIBUTE(ttm_pool_debugfs_shrink); #endif +static inline u64 ttm_get_node_memory_size(int nid) +{ + /* + * This is directly using si_meminfo_node implementation as the + * function is not exported. + */ + int zone_type; + u64 managed_pages = 0; + + pg_data_t *pgdat = NODE_DATA(nid); + + for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) + managed_pages += + zone_managed_pages(&pgdat->node_zones[zone_type]); + return managed_pages * PAGE_SIZE; +} + /** * ttm_pool_mgr_init - Initialize globals * @@ -1315,8 +1381,15 @@ int ttm_pool_mgr_init(unsigned long num_pages) { unsigned int i; - if (!page_pool_size) - page_pool_size = num_pages; + int nid; + for_each_node(nid) { + if (!page_pool_size) { + u64 node_size = ttm_get_node_memory_size(nid); + pool_node_limit[nid] = (node_size >> PAGE_SHIFT) / 2; + } else { + pool_node_limit[nid] = page_pool_size; + } + } spin_lock_init(&shrinker_lock); INIT_LIST_HEAD(&shrinker_list); @@ -1343,7 +1416,7 @@ int ttm_pool_mgr_init(unsigned long num_pages) #endif #endif - mm_shrinker = shrinker_alloc(0, "drm-ttm_pool"); + mm_shrinker = shrinker_alloc(SHRINKER_NUMA_AWARE, "drm-ttm_pool"); if (!mm_shrinker) return -ENOMEM; diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index beeffe36b6cb..611434641580 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -1,44 +1,56 @@ // SPDX-License-Identifier: GPL-2.0 or MIT -use kernel::clk::Clk; -use kernel::clk::OptionalClk; -use kernel::device::Bound; -use kernel::device::Core; -use kernel::device::Device; -use kernel::devres::Devres; -use kernel::drm; -use kernel::drm::ioctl; -use kernel::io::poll; -use kernel::new_mutex; -use kernel::of; -use kernel::platform; -use kernel::prelude::*; -use kernel::regulator; -use kernel::regulator::Regulator; -use kernel::sizes::SZ_2M; -use kernel::sync::aref::ARef; -use kernel::sync::Arc; -use kernel::sync::Mutex; -use kernel::time; - -use crate::file::File; -use crate::gem::TyrObject; -use crate::gpu; -use crate::gpu::GpuInfo; -use crate::regs; +use kernel::{ + clk::{ + Clk, + OptionalClk, // + }, + device::{ + Bound, + Core, + Device, // + }, + devres::Devres, + drm, + drm::ioctl, + io::poll, + new_mutex, + of, + platform, + prelude::*, + regulator, + regulator::Regulator, + sizes::SZ_2M, + sync::{ + aref::ARef, + Arc, + Mutex, // + }, + time, // +}; + +use crate::{ + file::TyrDrmFileData, + gem::TyrObject, + gpu, + gpu::GpuInfo, + regs, // +}; pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>; +pub(crate) struct TyrDrmDriver; + /// Convenience type alias for the DRM device type for this driver. -pub(crate) type TyrDevice = drm::Device<TyrDriver>; +pub(crate) type TyrDrmDevice = drm::Device<TyrDrmDriver>; #[pin_data(PinnedDrop)] -pub(crate) struct TyrDriver { - _device: ARef<TyrDevice>, +pub(crate) struct TyrPlatformDriverData { + _device: ARef<TyrDrmDevice>, } #[pin_data(PinnedDrop)] -pub(crate) struct TyrData { +pub(crate) struct TyrDrmDeviceData { pub(crate) pdev: ARef<platform::Device>, #[pin] @@ -61,9 +73,9 @@ pub(crate) struct TyrData { // that it will be removed in a future patch. // // SAFETY: This will be removed in a future patch. -unsafe impl Send for TyrData {} +unsafe impl Send for TyrDrmDeviceData {} // SAFETY: This will be removed in a future patch. -unsafe impl Sync for TyrData {} +unsafe impl Sync for TyrDrmDeviceData {} fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result { regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?; @@ -82,14 +94,14 @@ fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - <TyrDriver as platform::Driver>::IdInfo, + <TyrPlatformDriverData as platform::Driver>::IdInfo, [ (of::DeviceId::new(c"rockchip,rk3588-mali"), ()), (of::DeviceId::new(c"arm,mali-valhall-csf"), ()) ] ); -impl platform::Driver for TyrDriver { +impl platform::Driver for TyrPlatformDriverData { type IdInfo = (); const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); @@ -119,7 +131,7 @@ impl platform::Driver for TyrDriver { let platform: ARef<platform::Device> = pdev.into(); - let data = try_pin_init!(TyrData { + let data = try_pin_init!(TyrDrmDeviceData { pdev: platform.clone(), clks <- new_mutex!(Clocks { core: core_clk, @@ -133,10 +145,10 @@ impl platform::Driver for TyrDriver { gpu_info, }); - let tdev: ARef<TyrDevice> = drm::Device::new(pdev.as_ref(), data)?; - drm::driver::Registration::new_foreign_owned(&tdev, pdev.as_ref(), 0)?; + let ddev: ARef<TyrDrmDevice> = drm::Device::new(pdev.as_ref(), data)?; + drm::driver::Registration::new_foreign_owned(&ddev, pdev.as_ref(), 0)?; - let driver = TyrDriver { _device: tdev }; + let driver = TyrPlatformDriverData { _device: ddev }; // We need this to be dev_info!() because dev_dbg!() does not work at // all in Rust for now, and we need to see whether probe succeeded. @@ -146,12 +158,12 @@ impl platform::Driver for TyrDriver { } #[pinned_drop] -impl PinnedDrop for TyrDriver { +impl PinnedDrop for TyrPlatformDriverData { fn drop(self: Pin<&mut Self>) {} } #[pinned_drop] -impl PinnedDrop for TyrData { +impl PinnedDrop for TyrDrmDeviceData { fn drop(self: Pin<&mut Self>) { // TODO: the type-state pattern for Clks will fix this. let clks = self.clks.lock(); @@ -172,15 +184,15 @@ const INFO: drm::DriverInfo = drm::DriverInfo { }; #[vtable] -impl drm::Driver for TyrDriver { - type Data = TyrData; - type File = File; +impl drm::Driver for TyrDrmDriver { + type Data = TyrDrmDeviceData; + type File = TyrDrmFileData; type Object = drm::gem::Object<TyrObject>; const INFO: drm::DriverInfo = INFO; kernel::declare_drm_ioctls! { - (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, File::dev_query), + (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query), } } diff --git a/drivers/gpu/drm/tyr/file.rs b/drivers/gpu/drm/tyr/file.rs index 0ef432947b73..31411da203c5 100644 --- a/drivers/gpu/drm/tyr/file.rs +++ b/drivers/gpu/drm/tyr/file.rs @@ -1,37 +1,41 @@ // SPDX-License-Identifier: GPL-2.0 or MIT -use kernel::drm; -use kernel::prelude::*; -use kernel::uaccess::UserSlice; -use kernel::uapi; - -use crate::driver::TyrDevice; -use crate::TyrDriver; +use kernel::{ + drm, + prelude::*, + uaccess::UserSlice, + uapi, // +}; + +use crate::driver::{ + TyrDrmDevice, + TyrDrmDriver, // +}; #[pin_data] -pub(crate) struct File {} +pub(crate) struct TyrDrmFileData {} /// Convenience type alias for our DRM `File` type -pub(crate) type DrmFile = drm::file::File<File>; +pub(crate) type TyrDrmFile = drm::file::File<TyrDrmFileData>; -impl drm::file::DriverFile for File { - type Driver = TyrDriver; +impl drm::file::DriverFile for TyrDrmFileData { + type Driver = TyrDrmDriver; fn open(_dev: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>> { KBox::try_pin_init(try_pin_init!(Self {}), GFP_KERNEL) } } -impl File { +impl TyrDrmFileData { pub(crate) fn dev_query( - tdev: &TyrDevice, + ddev: &TyrDrmDevice, devquery: &mut uapi::drm_panthor_dev_query, - _file: &DrmFile, + _file: &TyrDrmFile, ) -> Result<u32> { if devquery.pointer == 0 { match devquery.type_ { uapi::drm_panthor_dev_query_type_DRM_PANTHOR_DEV_QUERY_GPU_INFO => { - devquery.size = core::mem::size_of_val(&tdev.gpu_info) as u32; + devquery.size = core::mem::size_of_val(&ddev.gpu_info) as u32; Ok(0) } _ => Err(EINVAL), @@ -45,7 +49,7 @@ impl File { ) .writer(); - writer.write(&tdev.gpu_info)?; + writer.write(&ddev.gpu_info)?; Ok(0) } diff --git a/drivers/gpu/drm/tyr/gem.rs b/drivers/gpu/drm/tyr/gem.rs index 1273bf89dbd5..5cc6eb0b5d3f 100644 --- a/drivers/gpu/drm/tyr/gem.rs +++ b/drivers/gpu/drm/tyr/gem.rs @@ -1,18 +1,24 @@ // SPDX-License-Identifier: GPL-2.0 or MIT -use crate::driver::TyrDevice; -use crate::driver::TyrDriver; -use kernel::drm::gem; -use kernel::prelude::*; +use kernel::{ + drm::gem, + prelude::*, // +}; + +use crate::driver::{ + TyrDrmDevice, + TyrDrmDriver, // +}; /// GEM Object inner driver data #[pin_data] pub(crate) struct TyrObject {} impl gem::DriverObject for TyrObject { - type Driver = TyrDriver; + type Driver = TyrDrmDriver; + type Args = (); - fn new(_dev: &TyrDevice, _size: usize) -> impl PinInit<Self, Error> { + fn new(_dev: &TyrDrmDevice, _size: usize, _args: ()) -> impl PinInit<Self, Error> { try_pin_init!(TyrObject {}) } } diff --git a/drivers/gpu/drm/tyr/gpu.rs b/drivers/gpu/drm/tyr/gpu.rs index 64ca8311d4e8..a88775160f98 100644 --- a/drivers/gpu/drm/tyr/gpu.rs +++ b/drivers/gpu/drm/tyr/gpu.rs @@ -1,20 +1,28 @@ // SPDX-License-Identifier: GPL-2.0 or MIT -use core::ops::Deref; -use core::ops::DerefMut; -use kernel::bits::genmask_u32; -use kernel::device::Bound; -use kernel::device::Device; -use kernel::devres::Devres; -use kernel::io::poll; -use kernel::platform; -use kernel::prelude::*; -use kernel::time::Delta; -use kernel::transmute::AsBytes; -use kernel::uapi; - -use crate::driver::IoMem; -use crate::regs; +use core::ops::{ + Deref, + DerefMut, // +}; +use kernel::{ + bits::genmask_u32, + device::{ + Bound, + Device, // + }, + devres::Devres, + io::poll, + platform, + prelude::*, + time::Delta, + transmute::AsBytes, + uapi, // +}; + +use crate::{ + driver::IoMem, + regs, // +}; /// Struct containing information that can be queried by userspace. This is read from /// the GPU's registers. @@ -84,13 +92,11 @@ impl GpuInfo { } pub(crate) fn log(&self, pdev: &platform::Device) { - let major = (self.gpu_id >> 16) & 0xff; - let minor = (self.gpu_id >> 8) & 0xff; - let status = self.gpu_id & 0xff; + let gpu_id = GpuId::from(self.gpu_id); let model_name = if let Some(model) = GPU_MODELS .iter() - .find(|&f| f.major == major && f.minor == minor) + .find(|&f| f.arch_major == gpu_id.arch_major && f.prod_major == gpu_id.prod_major) { model.name } else { @@ -102,9 +108,9 @@ impl GpuInfo { "mali-{} id 0x{:x} major 0x{:x} minor 0x{:x} status 0x{:x}", model_name, self.gpu_id >> 16, - major, - minor, - status + gpu_id.ver_major, + gpu_id.ver_minor, + gpu_id.ver_status ); dev_info!( @@ -166,14 +172,14 @@ unsafe impl AsBytes for GpuInfo {} struct GpuModels { name: &'static str, - major: u32, - minor: u32, + arch_major: u32, + prod_major: u32, } const GPU_MODELS: [GpuModels; 1] = [GpuModels { name: "g610", - major: 10, - minor: 7, + arch_major: 10, + prod_major: 7, }]; #[allow(dead_code)] diff --git a/drivers/gpu/drm/tyr/regs.rs b/drivers/gpu/drm/tyr/regs.rs index d3a541cb37c6..611870c2e6af 100644 --- a/drivers/gpu/drm/tyr/regs.rs +++ b/drivers/gpu/drm/tyr/regs.rs @@ -7,12 +7,16 @@ // does. #![allow(dead_code)] -use kernel::bits::bit_u32; -use kernel::device::Bound; -use kernel::device::Device; -use kernel::devres::Devres; -use kernel::io::Io; -use kernel::prelude::*; +use kernel::{ + bits::bit_u32, + device::{ + Bound, + Device, // + }, + devres::Devres, + io::Io, + prelude::*, // +}; use crate::driver::IoMem; diff --git a/drivers/gpu/drm/tyr/tyr.rs b/drivers/gpu/drm/tyr/tyr.rs index 861d1db43072..9432ddd6b5b8 100644 --- a/drivers/gpu/drm/tyr/tyr.rs +++ b/drivers/gpu/drm/tyr/tyr.rs @@ -5,7 +5,7 @@ //! The name "Tyr" is inspired by Norse mythology, reflecting Arm's tradition of //! naming their GPUs after Nordic mythological figures and places. -use crate::driver::TyrDriver; +use crate::driver::TyrPlatformDriverData; mod driver; mod file; @@ -14,7 +14,7 @@ mod gpu; mod regs; kernel::module_platform_driver! { - type: TyrDriver, + type: TyrPlatformDriverData, name: "tyr", authors: ["The Tyr driver authors"], description: "Arm Mali Tyr DRM driver", diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index dd60acdf52c2..4b441afcb602 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -110,14 +110,12 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, args->value = !!drm_gem_get_huge_mnt(dev); return 0; case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER: - mutex_lock(&v3d->reset_lock); - args->value = v3d->reset_counter; - mutex_unlock(&v3d->reset_lock); + args->value = atomic_read(&v3d->reset_counter); return 0; case DRM_V3D_PARAM_CONTEXT_RESET_COUNTER: - mutex_lock(&v3d->reset_lock); - args->value = v3d_priv->reset_counter; - mutex_unlock(&v3d->reset_lock); + args->value = 0; + for (enum v3d_queue q = 0; q < V3D_MAX_QUEUES; q++) + args->value += atomic_read(&v3d_priv->stats[q]->reset_counter); return 0; default: drm_dbg(dev, "Unknown parameter %d\n", args->param); @@ -131,7 +129,7 @@ v3d_open(struct drm_device *dev, struct drm_file *file) struct v3d_dev *v3d = to_v3d_dev(dev); struct v3d_file_priv *v3d_priv; struct drm_gpu_scheduler *sched; - int i; + int i, ret; v3d_priv = kzalloc_obj(*v3d_priv); if (!v3d_priv) @@ -140,40 +138,45 @@ v3d_open(struct drm_device *dev, struct drm_file *file) v3d_priv->v3d = v3d; for (i = 0; i < V3D_MAX_QUEUES; i++) { - sched = &v3d->queue[i].sched; - drm_sched_entity_init(&v3d_priv->sched_entity[i], - DRM_SCHED_PRIORITY_NORMAL, &sched, - 1, NULL); + v3d_priv->stats[i] = v3d_stats_alloc(); + if (!v3d_priv->stats[i]) { + ret = -ENOMEM; + goto err_stats; + } - memset(&v3d_priv->stats[i], 0, sizeof(v3d_priv->stats[i])); - seqcount_init(&v3d_priv->stats[i].lock); + sched = &v3d->queue[i].sched; + ret = drm_sched_entity_init(&v3d_priv->sched_entity[i], + DRM_SCHED_PRIORITY_NORMAL, &sched, + 1, NULL); + if (ret) + goto err_sched; } v3d_perfmon_open_file(v3d_priv); file->driver_priv = v3d_priv; return 0; + +err_sched: + v3d_stats_put(v3d_priv->stats[i]); +err_stats: + for (i--; i >= 0; i--) { + drm_sched_entity_destroy(&v3d_priv->sched_entity[i]); + v3d_stats_put(v3d_priv->stats[i]); + } + kfree(v3d_priv); + return ret; } static void v3d_postclose(struct drm_device *dev, struct drm_file *file) { - struct v3d_dev *v3d = to_v3d_dev(dev); struct v3d_file_priv *v3d_priv = file->driver_priv; - unsigned long irqflags; enum v3d_queue q; for (q = 0; q < V3D_MAX_QUEUES; q++) { - struct v3d_queue_state *queue = &v3d->queue[q]; - struct v3d_job *job = queue->active_job; - drm_sched_entity_destroy(&v3d_priv->sched_entity[q]); - - if (job && job->base.entity == &v3d_priv->sched_entity[q]) { - spin_lock_irqsave(&queue->queue_lock, irqflags); - job->file_priv = NULL; - spin_unlock_irqrestore(&queue->queue_lock, irqflags); - } + v3d_stats_put(v3d_priv->stats[q]); } v3d_perfmon_close_file(v3d_priv); @@ -186,7 +189,7 @@ void v3d_get_stats(const struct v3d_stats *stats, u64 timestamp, unsigned int seq; do { - seq = read_seqcount_begin(&stats->lock); + seq = raw_read_seqcount_begin(&stats->lock); *active_runtime = stats->enabled_ns; if (stats->start_ns) *active_runtime += timestamp - stats->start_ns; @@ -201,7 +204,7 @@ static void v3d_show_fdinfo(struct drm_printer *p, struct drm_file *file) enum v3d_queue queue; for (queue = 0; queue < V3D_MAX_QUEUES; queue++) { - struct v3d_stats *stats = &file_priv->stats[queue]; + struct v3d_stats *stats = file_priv->stats[queue]; u64 active_runtime, jobs_completed; v3d_get_stats(stats, timestamp, &active_runtime, &jobs_completed); diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 314213c26710..6a3cad933439 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -38,6 +38,8 @@ static inline char *v3d_queue_to_string(enum v3d_queue queue) } struct v3d_stats { + struct kref refcount; + u64 start_ns; u64 enabled_ns; u64 jobs_completed; @@ -46,8 +48,15 @@ struct v3d_stats { * This seqcount is used to protect the access to the GPU stats * variables. It must be used as, while we are reading the stats, * IRQs can happen and the stats can be updated. + * + * However, we use the raw seqcount helpers to interact with this lock + * to avoid false positives from lockdep, which is unable to detect that + * our readers are never from irq or softirq context, and that, for CPU + * job queues, even the write side never is. */ seqcount_t lock; + + atomic_t reset_counter; }; struct v3d_queue_state { @@ -57,13 +66,11 @@ struct v3d_queue_state { u64 emit_seqno; /* Stores the GPU stats for this queue in the global context. */ - struct v3d_stats stats; + struct v3d_stats *stats; /* Currently active job for this queue */ struct v3d_job *active_job; spinlock_t queue_lock; - /* Protect dma fence for signalling job completion */ - spinlock_t fence_lock; }; /* Performance monitor object. The perform lifetime is controlled by userspace @@ -196,10 +203,8 @@ struct v3d_dev { */ struct v3d_perfmon *global_perfmon; - /* Global reset counter. The counter must be incremented when - * a GPU reset happens. It must be protected by @reset_lock. - */ - unsigned int reset_counter; + /* Global reset counter incremented on each GPU reset. */ + atomic_t reset_counter; }; static inline struct v3d_dev * @@ -225,13 +230,7 @@ struct v3d_file_priv { struct drm_sched_entity sched_entity[V3D_MAX_QUEUES]; /* Stores the GPU stats for a specific queue for this fd. */ - struct v3d_stats stats[V3D_MAX_QUEUES]; - - /* Per-fd reset counter, must be incremented when a job submitted - * by this fd causes a GPU reset. It must be protected by - * &struct v3d_dev->reset_lock. - */ - unsigned int reset_counter; + struct v3d_stats *stats[V3D_MAX_QUEUES]; }; struct v3d_bo { @@ -319,6 +318,10 @@ struct v3d_job { */ struct v3d_file_priv *file_priv; + /* Pointers to this job's per-fd and global queue stats. */ + struct v3d_stats *client_stats; + struct v3d_stats *global_stats; + /* Callback for the freeing of the job on refcount going to 0. */ void (*free)(struct kref *ref); }; @@ -598,10 +601,23 @@ void v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info, unsigned int count); void v3d_performance_query_info_free(struct v3d_performance_query_info *query_info, unsigned int count); -void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue q); +struct v3d_stats *v3d_stats_alloc(void); +void v3d_stats_release(struct kref *refcount); +void v3d_job_update_stats(struct v3d_job *job); int v3d_sched_init(struct v3d_dev *v3d); void v3d_sched_fini(struct v3d_dev *v3d); +static inline struct v3d_stats *v3d_stats_get(struct v3d_stats *stats) +{ + kref_get(&stats->refcount); + return stats; +} + +static inline void v3d_stats_put(struct v3d_stats *stats) +{ + kref_put(&stats->refcount, v3d_stats_release); +} + /* v3d_perfmon.c */ void v3d_perfmon_init(struct v3d_dev *v3d); void v3d_perfmon_get(struct v3d_perfmon *perfmon); diff --git a/drivers/gpu/drm/v3d/v3d_fence.c b/drivers/gpu/drm/v3d/v3d_fence.c index 3c999f60003c..c500136d0455 100644 --- a/drivers/gpu/drm/v3d/v3d_fence.c +++ b/drivers/gpu/drm/v3d/v3d_fence.c @@ -15,7 +15,7 @@ struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q) fence->dev = &v3d->drm; fence->queue = q; fence->seqno = ++queue->emit_seqno; - dma_fence_init(&fence->base, &v3d_fence_ops, &queue->fence_lock, + dma_fence_init(&fence->base, &v3d_fence_ops, &queue->queue_lock, queue->fence_context, fence->seqno); return &fence->base; diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 57965c0d6f6e..75d9eccd7966 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -287,27 +287,30 @@ v3d_gem_init(struct drm_device *dev) for (i = 0; i < V3D_MAX_QUEUES; i++) { struct v3d_queue_state *queue = &v3d->queue[i]; + queue->stats = v3d_stats_alloc(); + if (!queue->stats) { + ret = -ENOMEM; + goto err_stats; + } + queue->fence_context = dma_fence_context_alloc(1); - memset(&queue->stats, 0, sizeof(queue->stats)); - seqcount_init(&queue->stats.lock); spin_lock_init(&queue->queue_lock); - spin_lock_init(&queue->fence_lock); } spin_lock_init(&v3d->mm_lock); ret = drmm_mutex_init(dev, &v3d->bo_lock); if (ret) - return ret; + goto err_stats; ret = drmm_mutex_init(dev, &v3d->reset_lock); if (ret) - return ret; + goto err_stats; ret = drmm_mutex_init(dev, &v3d->sched_lock); if (ret) - return ret; + goto err_stats; ret = drmm_mutex_init(dev, &v3d->cache_clean_lock); if (ret) - return ret; + goto err_stats; /* Note: We don't allocate address 0. Various bits of HW * treat 0 as special, such as the occlusion query counters @@ -319,10 +322,10 @@ v3d_gem_init(struct drm_device *dev) &v3d->pt_paddr, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); if (!v3d->pt) { - drm_mm_takedown(&v3d->mm); dev_err(v3d->drm.dev, "Failed to allocate page tables. Please ensure you have DMA enabled.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_dma_alloc; } v3d_init_hw_state(v3d); @@ -331,14 +334,20 @@ v3d_gem_init(struct drm_device *dev) v3d_huge_mnt_init(v3d); ret = v3d_sched_init(v3d); - if (ret) { - drm_mm_takedown(&v3d->mm); - dma_free_coherent(v3d->drm.dev, pt_size, (void *)v3d->pt, - v3d->pt_paddr); - return ret; - } + if (ret) + goto err_sched; return 0; + +err_sched: + dma_free_coherent(v3d->drm.dev, pt_size, (void *)v3d->pt, v3d->pt_paddr); +err_dma_alloc: + drm_mm_takedown(&v3d->mm); +err_stats: + for (i--; i >= 0; i--) + v3d_stats_put(v3d->queue[i].stats); + + return ret; } void @@ -352,8 +361,10 @@ v3d_gem_destroy(struct drm_device *dev) /* Waiting for jobs to finish would need to be done before * unregistering V3D. */ - for (q = 0; q < V3D_MAX_QUEUES; q++) + for (q = 0; q < V3D_MAX_QUEUES; q++) { WARN_ON(v3d->queue[q].active_job); + v3d_stats_put(v3d->queue[q].stats); + } drm_mm_takedown(&v3d->mm); diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c index 1249f6e64b97..c28e74ab5442 100644 --- a/drivers/gpu/drm/v3d/v3d_irq.c +++ b/drivers/gpu/drm/v3d/v3d_irq.c @@ -92,7 +92,7 @@ v3d_irq_signal_fence(struct v3d_dev *v3d, enum v3d_queue q, struct v3d_queue_state *queue = &v3d->queue[q]; struct v3d_fence *fence = to_v3d_fence(queue->active_job->irq_fence); - v3d_job_update_stats(queue->active_job, q); + v3d_job_update_stats(queue->active_job); trace_irq(&v3d->drm, fence->seqno); queue->active_job = NULL; diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 6dc871fc9a62..1855ef5b3b5f 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -66,6 +66,27 @@ to_cpu_job(struct drm_sched_job *sched_job) return container_of(sched_job, struct v3d_cpu_job, base.base); } +void v3d_stats_release(struct kref *refcount) +{ + struct v3d_stats *stats = container_of(refcount, typeof(*stats), refcount); + + kfree(stats); +} + +struct v3d_stats *v3d_stats_alloc(void) +{ + struct v3d_stats *stats; + + stats = kzalloc_obj(*stats); + if (!stats) + return NULL; + + kref_init(&stats->refcount); + seqcount_init(&stats->lock); + + return stats; +} + static void v3d_sched_job_free(struct drm_sched_job *sched_job) { @@ -137,90 +158,43 @@ v3d_switch_perfmon(struct v3d_dev *v3d, struct v3d_job *job) } static void -v3d_job_start_stats(struct v3d_job *job, enum v3d_queue queue) +v3d_stats_start(struct v3d_stats *stats, u64 now) { - struct v3d_dev *v3d = job->v3d; - struct v3d_file_priv *file = job->file_priv; - struct v3d_stats *global_stats = &v3d->queue[queue].stats; - struct v3d_stats *local_stats = &file->stats[queue]; - u64 now = local_clock(); - unsigned long flags; - - /* - * We only need to disable local interrupts to appease lockdep who - * otherwise would think v3d_job_start_stats vs v3d_stats_update has an - * unsafe in-irq vs no-irq-off usage problem. This is a false positive - * because all the locks are per queue and stats type, and all jobs are - * completely one at a time serialised. More specifically: - * - * 1. Locks for GPU queues are updated from interrupt handlers under a - * spin lock and started here with preemption disabled. - * - * 2. Locks for CPU queues are updated from the worker with preemption - * disabled and equally started here with preemption disabled. - * - * Therefore both are consistent. - * - * 3. Because next job can only be queued after the previous one has - * been signaled, and locks are per queue, there is also no scope for - * the start part to race with the update part. - */ - if (IS_ENABLED(CONFIG_LOCKDEP)) - local_irq_save(flags); - else - preempt_disable(); - - write_seqcount_begin(&local_stats->lock); - local_stats->start_ns = now; - write_seqcount_end(&local_stats->lock); + raw_write_seqcount_begin(&stats->lock); + stats->start_ns = now; + raw_write_seqcount_end(&stats->lock); +} - write_seqcount_begin(&global_stats->lock); - global_stats->start_ns = now; - write_seqcount_end(&global_stats->lock); +static void +v3d_job_start_stats(struct v3d_job *job) +{ + u64 now = local_clock(); - if (IS_ENABLED(CONFIG_LOCKDEP)) - local_irq_restore(flags); - else - preempt_enable(); + preempt_disable(); + v3d_stats_start(job->client_stats, now); + v3d_stats_start(job->global_stats, now); + preempt_enable(); } static void v3d_stats_update(struct v3d_stats *stats, u64 now) { - write_seqcount_begin(&stats->lock); + raw_write_seqcount_begin(&stats->lock); stats->enabled_ns += now - stats->start_ns; stats->jobs_completed++; stats->start_ns = 0; - write_seqcount_end(&stats->lock); + raw_write_seqcount_end(&stats->lock); } void -v3d_job_update_stats(struct v3d_job *job, enum v3d_queue q) +v3d_job_update_stats(struct v3d_job *job) { - struct v3d_dev *v3d = job->v3d; - struct v3d_queue_state *queue = &v3d->queue[q]; - struct v3d_stats *global_stats = &queue->stats; u64 now = local_clock(); - unsigned long flags; - - /* See comment in v3d_job_start_stats() */ - if (IS_ENABLED(CONFIG_LOCKDEP)) - local_irq_save(flags); - else - preempt_disable(); - /* Don't update the local stats if the file context has already closed */ - spin_lock(&queue->queue_lock); - if (job->file_priv) - v3d_stats_update(&job->file_priv->stats[q], now); - spin_unlock(&queue->queue_lock); - - v3d_stats_update(global_stats, now); - - if (IS_ENABLED(CONFIG_LOCKDEP)) - local_irq_restore(flags); - else - preempt_enable(); + preempt_disable(); + v3d_stats_update(job->client_stats, now); + v3d_stats_update(job->global_stats, now); + preempt_enable(); } static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) @@ -263,7 +237,7 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno, job->start, job->end); - v3d_job_start_stats(&job->base, V3D_BIN); + v3d_job_start_stats(&job->base); v3d_switch_perfmon(v3d, &job->base); /* Set the current and end address of the control list. @@ -317,7 +291,7 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno, job->start, job->end); - v3d_job_start_stats(&job->base, V3D_RENDER); + v3d_job_start_stats(&job->base); v3d_switch_perfmon(v3d, &job->base); /* XXX: Set the QCFG */ @@ -356,7 +330,7 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); - v3d_job_start_stats(&job->base, V3D_TFU); + v3d_job_start_stats(&job->base); V3D_WRITE(V3D_TFU_IIA(v3d->ver), job->args.iia); V3D_WRITE(V3D_TFU_IIS(v3d->ver), job->args.iis); @@ -406,7 +380,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno); - v3d_job_start_stats(&job->base, V3D_CSD); + v3d_job_start_stats(&job->base); v3d_switch_perfmon(v3d, &job->base); csd_cfg0_reg = V3D_CSD_QUEUED_CFG0(v3d->ver); @@ -694,13 +668,13 @@ v3d_cpu_job_run(struct drm_sched_job *sched_job) return NULL; } - v3d_job_start_stats(&job->base, V3D_CPU); + v3d_job_start_stats(&job->base); trace_v3d_cpu_job_begin(&v3d->drm, job->job_type); cpu_job_function[job->job_type](job); trace_v3d_cpu_job_end(&v3d->drm, job->job_type); - v3d_job_update_stats(&job->base, V3D_CPU); + v3d_job_update_stats(&job->base); /* Synchronous operation, so no fence to wait on. */ return NULL; @@ -712,11 +686,11 @@ v3d_cache_clean_job_run(struct drm_sched_job *sched_job) struct v3d_job *job = to_v3d_job(sched_job); struct v3d_dev *v3d = job->v3d; - v3d_job_start_stats(job, V3D_CACHE_CLEAN); + v3d_job_start_stats(job); v3d_clean_caches(v3d); - v3d_job_update_stats(job, V3D_CACHE_CLEAN); + v3d_job_update_stats(job); /* Synchronous operation, so no fence to wait on. */ return NULL; @@ -727,8 +701,6 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job, enum v3d_queue q) { struct v3d_job *job = to_v3d_job(sched_job); - struct v3d_file_priv *v3d_priv = job->file_priv; - unsigned long irqflags; enum v3d_queue i; mutex_lock(&v3d->reset_lock); @@ -743,11 +715,8 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job, /* get the GPU back into the init state */ v3d_reset(v3d); - v3d->reset_counter++; - spin_lock_irqsave(&v3d->queue[q].queue_lock, irqflags); - if (v3d_priv) - v3d_priv->reset_counter++; - spin_unlock_irqrestore(&v3d->queue[q].queue_lock, irqflags); + atomic_inc(&v3d->reset_counter); + atomic_inc(&job->client_stats->reset_counter); for (i = 0; i < V3D_MAX_QUEUES; i++) drm_sched_resubmit_jobs(&v3d->queue[i].sched); diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 18f2bf1fe89f..8f061b6a05c6 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -103,6 +103,9 @@ v3d_job_free(struct kref *ref) if (job->perfmon) v3d_perfmon_put(job->perfmon); + v3d_stats_put(job->client_stats); + v3d_stats_put(job->global_stats); + kfree(job); } @@ -203,6 +206,9 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, kref_init(&job->refcount); + job->client_stats = v3d_stats_get(v3d_priv->stats[queue]); + job->global_stats = v3d_stats_get(v3d->queue[queue].stats); + return 0; fail_deps: diff --git a/drivers/gpu/drm/v3d/v3d_sysfs.c b/drivers/gpu/drm/v3d/v3d_sysfs.c index d610e355964f..b45a9b3db42d 100644 --- a/drivers/gpu/drm/v3d/v3d_sysfs.c +++ b/drivers/gpu/drm/v3d/v3d_sysfs.c @@ -20,7 +20,7 @@ gpu_stats_show(struct device *dev, struct device_attribute *attr, char *buf) len += sysfs_emit(buf, "queue\ttimestamp\tjobs\truntime\n"); for (queue = 0; queue < V3D_MAX_QUEUES; queue++) { - struct v3d_stats *stats = &v3d->queue[queue].stats; + struct v3d_stats *stats = v3d->queue[queue].stats; u64 active_runtime, jobs_completed; v3d_get_stats(stats, timestamp, &active_runtime, &jobs_completed); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 9898e5451a07..a99f53dadb28 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -133,7 +133,7 @@ static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi) static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode, unsigned int bpc, - enum hdmi_colorspace fmt) + enum drm_output_color_format fmt) { unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt); @@ -444,7 +444,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) const struct drm_display_mode *mode; list_for_each_entry(mode, &connector->probed_modes, head) { - if (vc4_hdmi_mode_needs_scrambling(mode, 8, HDMI_COLORSPACE_RGB)) { + if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) { drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz."); drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60."); } @@ -547,9 +547,9 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, &vc4_hdmi_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA, vc4_hdmi->ddc, - BIT(HDMI_COLORSPACE_RGB) | - BIT(HDMI_COLORSPACE_YUV422) | - BIT(HDMI_COLORSPACE_YUV444), + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), max_bpc); if (ret) return ret; @@ -1214,13 +1214,13 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); switch (state->hdmi.output_format) { - case HDMI_COLORSPACE_YUV444: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range); vc5_hdmi_set_csc_coeffs_swap(vc4_hdmi, csc); break; - case HDMI_COLORSPACE_YUV422: + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range); csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD, @@ -1237,7 +1237,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, vc5_hdmi_set_csc_coeffs(vc4_hdmi, csc); break; - case HDMI_COLORSPACE_RGB: + case DRM_OUTPUT_COLOR_FORMAT_RGB444: if_xbar = 0x354021; vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_rgb[lim_range]); @@ -1394,7 +1394,7 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, * YCC422 is always 36-bit and not considered deep colour so * doesn't signal in GCP. */ - if (state->hdmi.output_format == HDMI_COLORSPACE_YUV422) { + if (state->hdmi.output_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) { gcp = 0; } diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 8d069718df00..29d461d4ee49 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -210,7 +210,7 @@ struct vc4_hdmi { * @drm_connector_state.hdmi.output_format for use outside of * KMS hooks. Protected by @mutex. */ - enum hdmi_colorspace output_format; + enum drm_output_color_format output_format; /** * @hdmi_jack: Represents the connection state of the HDMI plug, for diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 0507f24adcdd..264b5e80c24d 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -116,7 +116,7 @@ static int vc4_ctm_obj_init(struct vc4_dev *vc4) { drm_modeset_lock_init(&vc4->ctm_state_lock); - drm_atomic_private_obj_init(&vc4->base, &vc4->ctm_manager, NULL, + drm_atomic_private_obj_init(&vc4->base, &vc4->ctm_manager, &vc4_ctm_state_funcs); return drmm_add_action_or_reset(&vc4->base, vc4_ctm_obj_fini, NULL); @@ -757,7 +757,6 @@ static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused) static int vc4_load_tracker_obj_init(struct vc4_dev *vc4) { drm_atomic_private_obj_init(&vc4->base, &vc4->load_tracker, - NULL, &vc4_load_tracker_state_funcs); return drmm_add_action_or_reset(&vc4->base, vc4_load_tracker_obj_fini, NULL); @@ -849,7 +848,6 @@ static void vc4_hvs_channels_obj_fini(struct drm_device *dev, void *unused) static int vc4_hvs_channels_obj_init(struct vc4_dev *vc4) { drm_atomic_private_obj_init(&vc4->base, &vc4->hvs_channels, - NULL, &vc4_hvs_state_funcs); return drmm_add_action_or_reset(&vc4->base, vc4_hvs_channels_obj_fini, NULL); diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c index 5f629d2d4bea..dad9967bc10b 100644 --- a/drivers/gpu/drm/verisilicon/vs_dc.c +++ b/drivers/gpu/drm/verisilicon/vs_dc.c @@ -190,7 +190,7 @@ static void vs_dc_shutdown(struct platform_device *pdev) vs_drm_shutdown_handler(dc); } -struct platform_driver vs_dc_platform_driver = { +static struct platform_driver vs_dc_platform_driver = { .probe = vs_dc_probe, .remove = vs_dc_remove, .shutdown = vs_dc_shutdown, diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index cd85de4ffd03..83d217085ad0 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -475,8 +475,14 @@ static void blend(struct vkms_writeback_job *wb, { struct vkms_plane_state **plane = crtc_state->active_planes; u32 n_active_planes = crtc_state->num_active_planes; - - const struct pixel_argb_u16 background_color = { .a = 0xffff }; + u64 bgcolor = crtc_state->base.background_color; + + const struct pixel_argb_u16 background_color = { + .a = 0xffff, + .r = DRM_ARGB64_GETR(bgcolor), + .g = DRM_ARGB64_GETG(bgcolor), + .b = DRM_ARGB64_GETB(bgcolor), + }; int crtc_y_limit = crtc_state->base.mode.vdisplay; int crtc_x_limit = crtc_state->base.mode.hdisplay; diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index ba2ff353e1a9..35ddc553a5e6 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -4,6 +4,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> #include <drm/drm_managed.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -227,6 +228,8 @@ struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *pri drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_LUT_SIZE); + drm_crtc_attach_background_color_property(crtc); + spin_lock_init(&vkms_out->lock); spin_lock_init(&vkms_out->composer_lock); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index f2abaf1bda6a..57465f69c687 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -96,12 +96,17 @@ struct vmwgfx_hash_item { struct vmw_res_func; +struct vmw_bo; +struct vmw_bo; +struct vmw_resource_dirty; + /** - * struct vmw-resource - base class for hardware resources + * struct vmw_resource - base class for hardware resources * * @kref: For refcounting. * @dev_priv: Pointer to the device private for this resource. Immutable. * @id: Device id. Protected by @dev_priv::resource_lock. + * @used_prio: Priority for this resource. * @guest_memory_size: Guest memory buffer size. Immutable. * @res_dirty: Resource contains data not yet in the guest memory buffer. * Protected by resource reserved. @@ -117,18 +122,16 @@ struct vmw_res_func; * pin-count greater than zero. It is not on the resource LRU lists and its * guest memory buffer is pinned. Hence it can't be evicted. * @func: Method vtable for this resource. Immutable. - * @mob_node; Node for the MOB guest memory rbtree. Protected by + * @mob_node: Node for the MOB guest memory rbtree. Protected by * @guest_memory_bo reserved. * @lru_head: List head for the LRU list. Protected by @dev_priv::resource_lock. * @binding_head: List head for the context binding list. Protected by * the @dev_priv::binding_mutex + * @dirty: resource's dirty tracker * @res_free: The resource destructor. * @hw_destroy: Callback to destroy the resource on the device, as part of * resource destruction. */ -struct vmw_bo; -struct vmw_bo; -struct vmw_resource_dirty; struct vmw_resource { struct kref kref; struct vmw_private *dev_priv; @@ -196,8 +199,8 @@ struct vmw_surface_offset; * @quality_level: Quality level. * @autogen_filter: Filter for automatically generated mipmaps. * @array_size: Number of array elements for a 1D/2D texture. For cubemap - texture number of faces * array_size. This should be 0 for pre - SM4 device. + * texture number of faces * array_size. This should be 0 for pre + * SM4 device. * @buffer_byte_stride: Buffer byte stride. * @num_sizes: Size of @sizes. For GB surface this should always be 1. * @base_size: Surface dimension. @@ -265,18 +268,24 @@ struct vmw_fifo_state { struct vmw_res_cache_entry { uint32_t handle; struct vmw_resource *res; + /* private: */ void *private; + /* public: */ unsigned short valid_handle; unsigned short valid; }; /** * enum vmw_dma_map_mode - indicate how to perform TTM page dma mappings. + * @vmw_dma_alloc_coherent: Use TTM coherent pages + * @vmw_dma_map_populate: Unmap from DMA just after unpopulate + * @vmw_dma_map_bind: Unmap from DMA just before unbind */ enum vmw_dma_map_mode { - vmw_dma_alloc_coherent, /* Use TTM coherent pages */ - vmw_dma_map_populate, /* Unmap from DMA just after unpopulate */ - vmw_dma_map_bind, /* Unmap from DMA just before unbind */ + vmw_dma_alloc_coherent, + vmw_dma_map_populate, + vmw_dma_map_bind, + /* private: */ vmw_dma_map_max }; @@ -284,8 +293,11 @@ enum vmw_dma_map_mode { * struct vmw_sg_table - Scatter/gather table for binding, with additional * device-specific information. * + * @mode: which page mapping mode to use + * @pages: Array of page pointers to the pages. + * @addrs: DMA addresses to the pages if coherent pages are used. * @sgt: Pointer to a struct sg_table with binding information - * @num_regions: Number of regions with device-address contiguous pages + * @num_pages: Number of @pages */ struct vmw_sg_table { enum vmw_dma_map_mode mode; @@ -353,6 +365,7 @@ struct vmw_ctx_validation_info; * than from user-space * @fp: If @kernel is false, points to the file of the client. Otherwise * NULL + * @filp: DRM state for this file * @cmd_bounce: Command bounce buffer used for command validation before * copying to fifo space * @cmd_bounce_size: Current command bounce buffer size @@ -729,7 +742,7 @@ extern void vmw_svga_disable(struct vmw_private *dev_priv); bool vmwgfx_supported(struct vmw_private *vmw); -/** +/* * GMR utilities - vmwgfx_gmr.c */ @@ -739,7 +752,7 @@ extern int vmw_gmr_bind(struct vmw_private *dev_priv, int gmr_id); extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id); -/** +/* * User handles */ struct vmw_user_object { @@ -759,7 +772,7 @@ void *vmw_user_object_map_size(struct vmw_user_object *uo, size_t size); void vmw_user_object_unmap(struct vmw_user_object *uo); bool vmw_user_object_is_mapped(struct vmw_user_object *uo); -/** +/* * Resource utilities - vmwgfx_resource.c */ struct vmw_user_resource_conv; @@ -819,7 +832,7 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res) return !RB_EMPTY_NODE(&res->mob_node); } -/** +/* * GEM related functionality - vmwgfx_gem.c */ struct vmw_bo_params; @@ -833,7 +846,7 @@ extern int vmw_gem_object_create_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); extern void vmw_debugfs_gem_init(struct vmw_private *vdev); -/** +/* * Misc Ioctl functionality - vmwgfx_ioctl.c */ @@ -846,7 +859,7 @@ extern int vmw_present_ioctl(struct drm_device *dev, void *data, extern int vmw_present_readback_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -/** +/* * Fifo utilities - vmwgfx_fifo.c */ @@ -880,9 +893,11 @@ extern int vmw_cmd_flush(struct vmw_private *dev_priv, /** - * vmw_fifo_caps - Returns the capabilities of the FIFO command + * vmw_fifo_caps - Get the capabilities of the FIFO command * queue or 0 if fifo memory isn't present. * @dev_priv: The device private context + * + * Returns: capabilities of the FIFO command or %0 if fifo memory not present */ static inline uint32_t vmw_fifo_caps(const struct vmw_private *dev_priv) { @@ -893,9 +908,11 @@ static inline uint32_t vmw_fifo_caps(const struct vmw_private *dev_priv) /** - * vmw_is_cursor_bypass3_enabled - Returns TRUE iff Cursor Bypass 3 - * is enabled in the FIFO. + * vmw_is_cursor_bypass3_enabled - check Cursor Bypass 3 enabled setting + * in the FIFO. * @dev_priv: The device private context + * + * Returns: %true iff Cursor Bypass 3 is enabled in the FIFO */ static inline bool vmw_is_cursor_bypass3_enabled(const struct vmw_private *dev_priv) @@ -903,7 +920,7 @@ vmw_is_cursor_bypass3_enabled(const struct vmw_private *dev_priv) return (vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_CURSOR_BYPASS_3) != 0; } -/** +/* * TTM buffer object driver - vmwgfx_ttm_buffer.c */ @@ -927,7 +944,7 @@ extern void vmw_piter_start(struct vmw_piter *viter, * * @viter: Pointer to the iterator to advance. * - * Returns false if past the list of pages, true otherwise. + * Returns: false if past the list of pages, true otherwise. */ static inline bool vmw_piter_next(struct vmw_piter *viter) { @@ -939,7 +956,7 @@ static inline bool vmw_piter_next(struct vmw_piter *viter) * * @viter: Pointer to the iterator * - * Returns the DMA address of the page pointed to by @viter. + * Returns: the DMA address of the page pointed to by @viter. */ static inline dma_addr_t vmw_piter_dma_addr(struct vmw_piter *viter) { @@ -951,14 +968,14 @@ static inline dma_addr_t vmw_piter_dma_addr(struct vmw_piter *viter) * * @viter: Pointer to the iterator * - * Returns the DMA address of the page pointed to by @viter. + * Returns: the DMA address of the page pointed to by @viter. */ static inline struct page *vmw_piter_page(struct vmw_piter *viter) { return viter->pages[viter->i]; } -/** +/* * Command submission - vmwgfx_execbuf.c */ @@ -993,7 +1010,7 @@ extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, int32_t out_fence_fd); bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd); -/** +/* * IRQs and wating - vmwgfx_irq.c */ @@ -1016,7 +1033,7 @@ bool vmw_generic_waiter_add(struct vmw_private *dev_priv, u32 flag, bool vmw_generic_waiter_remove(struct vmw_private *dev_priv, u32 flag, int *waiter_count); -/** +/* * Kernel modesetting - vmwgfx_kms.c */ @@ -1048,7 +1065,7 @@ extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible); extern void vmw_resource_unpin(struct vmw_resource *res); extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res); -/** +/* * Overlay control - vmwgfx_overlay.c */ @@ -1063,20 +1080,20 @@ int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id); int vmw_overlay_num_overlays(struct vmw_private *dev_priv); int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv); -/** +/* * GMR Id manager */ int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type); void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type); -/** +/* * System memory manager */ int vmw_sys_man_init(struct vmw_private *dev_priv); void vmw_sys_man_fini(struct vmw_private *dev_priv); -/** +/* * Prime - vmwgfx_prime.c */ @@ -1292,7 +1309,7 @@ extern void vmw_cmdbuf_irqthread(struct vmw_cmdbuf_man *man); * @line: The current line of the blit. * @line_offset: Offset of the current line segment. * @cpp: Bytes per pixel (granularity information). - * @memcpy: Which memcpy function to use. + * @do_cpy: Which memcpy function to use. */ struct vmw_diff_cpy { struct drm_rect rect; @@ -1380,13 +1397,14 @@ vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf); /** * VMW_DEBUG_KMS - Debug output for kernel mode-setting + * @fmt: format string for the args * * This macro is for debugging vmwgfx mode-setting code. */ #define VMW_DEBUG_KMS(fmt, ...) \ DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__) -/** +/* * Inline helper functions */ @@ -1417,11 +1435,13 @@ static inline void vmw_fifo_resource_dec(struct vmw_private *dev_priv) /** * vmw_fifo_mem_read - Perform a MMIO read from the fifo memory - * + * @vmw: The device private structure * @fifo_reg: The fifo register to read from * * This function is intended to be equivalent to ioread32() on * memremap'd memory, but without byteswapping. + * + * Returns: the value read */ static inline u32 vmw_fifo_mem_read(struct vmw_private *vmw, uint32 fifo_reg) { @@ -1431,8 +1451,9 @@ static inline u32 vmw_fifo_mem_read(struct vmw_private *vmw, uint32 fifo_reg) /** * vmw_fifo_mem_write - Perform a MMIO write to volatile memory - * - * @addr: The fifo register to write to + * @vmw: The device private structure + * @fifo_reg: The fifo register to write to + * @value: The value to write * * This function is intended to be equivalent to iowrite32 on * memremap'd memory, but without byteswapping. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 55730e29d3ae..e7bddf840a79 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -771,7 +771,8 @@ err_out: ret = vmw_bo_dirty_add(bo); if (!ret && surface && surface->res.func->dirty_alloc) { surface->res.coherent = true; - ret = surface->res.func->dirty_alloc(&surface->res); + if (surface->res.dirty == NULL) + ret = surface->res.func->dirty_alloc(&surface->res); } ttm_bo_unreserve(&bo->tbo); } diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index f9abaf687d46..9dacb0579a7d 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -253,6 +253,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_dbuf_bw.o \ i915-display/intel_ddi.o \ i915-display/intel_ddi_buf_trans.o \ + i915-display/intel_de.o \ i915-display/intel_display.o \ i915-display/intel_display_conversion.o \ i915-display/intel_display_device.o \ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h index 2cf13a572ab0..0eabe2866f5f 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/intel_step.h @@ -6,9 +6,8 @@ #ifndef __INTEL_STEP_H__ #define __INTEL_STEP_H__ -#include "xe_step.h" +#include "xe_step_types.h" #define intel_step xe_step -#define intel_step_name xe_step_name #endif /* __INTEL_STEP_H__ */ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h index a8cfd65119e0..08d7ab933672 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h @@ -98,37 +98,6 @@ static inline u32 intel_uncore_rmw(struct intel_uncore *uncore, return xe_mmio_rmw32(__compat_uncore_to_mmio(uncore), reg, clear, set); } -static inline int -__intel_wait_for_register(struct intel_uncore *uncore, i915_reg_t i915_reg, - u32 mask, u32 value, unsigned int fast_timeout_us, - unsigned int slow_timeout_ms, u32 *out_value) -{ - struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg)); - bool atomic; - - /* - * Replicate the behavior from i915 here, in which sleep is not - * performed if slow_timeout_ms == 0. This is necessary because - * of some paths in display code where waits are done in atomic - * context. - */ - atomic = !slow_timeout_ms && fast_timeout_us > 0; - - return xe_mmio_wait32(__compat_uncore_to_mmio(uncore), reg, mask, value, - fast_timeout_us + 1000 * slow_timeout_ms, - out_value, atomic); -} - -static inline int -__intel_wait_for_register_fw(struct intel_uncore *uncore, i915_reg_t i915_reg, - u32 mask, u32 value, unsigned int fast_timeout_us, - unsigned int slow_timeout_ms, u32 *out_value) -{ - return __intel_wait_for_register(uncore, i915_reg, mask, value, - fast_timeout_us, slow_timeout_ms, - out_value); -} - static inline u32 intel_uncore_read_fw(struct intel_uncore *uncore, i915_reg_t i915_reg) { diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 4d4d7a35e089..cbce1d0ffe48 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -1349,8 +1349,15 @@ void xe_device_declare_wedged(struct xe_device *xe) xe_gt_declare_wedged(gt); if (xe_device_wedged(xe)) { + /* + * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging + * hangs, so wedge the device with 'none' recovery method and have + * it available to the user for debugging. + */ + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE); /* If no wedge recovery method is set, use default */ - if (!xe->wedged.method) + else if (!xe->wedged.method) xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); diff --git a/drivers/gpu/nova-core/Kconfig b/drivers/gpu/nova-core/Kconfig index 527920f9c4d3..a4f2380654e2 100644 --- a/drivers/gpu/nova-core/Kconfig +++ b/drivers/gpu/nova-core/Kconfig @@ -3,8 +3,8 @@ config NOVA_CORE depends on 64BIT depends on PCI depends on RUST - select RUST_FW_LOADER_ABSTRACTIONS select AUXILIARY_BUS + select RUST_FW_LOADER_ABSTRACTIONS default n help Choose this if you want to build the Nova Core driver for Nvidia diff --git a/drivers/gpu/nova-core/dma.rs b/drivers/gpu/nova-core/dma.rs deleted file mode 100644 index 7215398969da..000000000000 --- a/drivers/gpu/nova-core/dma.rs +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Simple DMA object wrapper. - -use core::ops::{ - Deref, - DerefMut, // -}; - -use kernel::{ - device, - dma::CoherentAllocation, - page::PAGE_SIZE, - prelude::*, // -}; - -pub(crate) struct DmaObject { - dma: CoherentAllocation<u8>, -} - -impl DmaObject { - pub(crate) fn new(dev: &device::Device<device::Bound>, len: usize) -> Result<Self> { - let len = core::alloc::Layout::from_size_align(len, PAGE_SIZE) - .map_err(|_| EINVAL)? - .pad_to_align() - .size(); - let dma = CoherentAllocation::alloc_coherent(dev, len, GFP_KERNEL | __GFP_ZERO)?; - - Ok(Self { dma }) - } - - pub(crate) fn from_data(dev: &device::Device<device::Bound>, data: &[u8]) -> Result<Self> { - Self::new(dev, data.len()).and_then(|mut dma_obj| { - // SAFETY: We have just allocated the DMA memory, we are the only users and - // we haven't made the device aware of the handle yet. - unsafe { dma_obj.write(data, 0)? } - Ok(dma_obj) - }) - } -} - -impl Deref for DmaObject { - type Target = CoherentAllocation<u8>; - - fn deref(&self) -> &Self::Target { - &self.dma - } -} - -impl DerefMut for DmaObject { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.dma - } -} diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 5a4cc047bcfc..84b0e1703150 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -14,11 +14,20 @@ use kernel::{ }, prelude::*, sizes::SZ_16M, - sync::Arc, // + sync::{ + atomic::{ + Atomic, + Relaxed, // + }, + Arc, + }, }; use crate::gpu::Gpu; +/// Counter for generating unique auxiliary device IDs. +static AUXILIARY_ID_COUNTER: Atomic<u32> = Atomic::new(0); + #[pin_data] pub(crate) struct NovaCore { #[pin] @@ -70,7 +79,7 @@ impl pci::Driver for NovaCore { fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { pin_init::pin_init_scope(move || { - dev_dbg!(pdev.as_ref(), "Probe Nova Core GPU driver.\n"); + dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); pdev.enable_device_mem()?; pdev.set_master(); @@ -90,7 +99,9 @@ impl pci::Driver for NovaCore { _reg <- auxiliary::Registration::new( pdev.as_ref(), c"nova-drm", - 0, // TODO[XARR]: Once it lands, use XArray; for now we don't use the ID. + // TODO[XARR]: Use XArray or perhaps IDA for proper ID allocation/recycling. For + // now, use a simple atomic counter that never recycles IDs. + AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed), crate::MODULE_NAME ), })) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs index 37bfee1d0949..e0315fda576b 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -2,243 +2,135 @@ //! Falcon microprocessor base support -use core::ops::Deref; - use hal::FalconHal; use kernel::{ - device, + device::{ + self, + Device, // + }, dma::{ + Coherent, DmaAddress, DmaMask, // }, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::{ + RegisterBase, + WithBase, // + }, + Io, + }, prelude::*, sync::aref::ARef, - time::{ - Delta, // - }, + time::Delta, }; use crate::{ - dma::DmaObject, + bounded_enum, driver::Bar0, falcon::hal::LoadMethod, gpu::Chipset, num::{ - FromSafeCast, - IntoSafeCast, // + self, + FromSafeCast, // }, regs, - regs::macros::RegisterBase, // }; pub(crate) mod gsp; mod hal; pub(crate) mod sec2; -// TODO[FPRI]: Replace with `ToPrimitive`. -macro_rules! impl_from_enum_to_u8 { - ($enum_type:ty) => { - impl From<$enum_type> for u8 { - fn from(value: $enum_type) -> Self { - value as u8 - } - } - }; -} - -/// Revision number of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] -/// register. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum FalconCoreRev { - #[default] - Rev1 = 1, - Rev2 = 2, - Rev3 = 3, - Rev4 = 4, - Rev5 = 5, - Rev6 = 6, - Rev7 = 7, -} -impl_from_enum_to_u8!(FalconCoreRev); - -// TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom<u8> for FalconCoreRev { - type Error = Error; - - fn try_from(value: u8) -> Result<Self> { - use FalconCoreRev::*; - - let rev = match value { - 1 => Rev1, - 2 => Rev2, - 3 => Rev3, - 4 => Rev4, - 5 => Rev5, - 6 => Rev6, - 7 => Rev7, - _ => return Err(EINVAL), - }; - - Ok(rev) +/// Alignment (in bytes) of falcon memory blocks. +pub(crate) const MEM_BLOCK_ALIGNMENT: usize = 256; + +bounded_enum! { + /// Revision number of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] + /// register. + #[derive(Debug, Copy, Clone)] + pub(crate) enum FalconCoreRev with TryFrom<Bounded<u32, 4>> { + Rev1 = 1, + Rev2 = 2, + Rev3 = 3, + Rev4 = 4, + Rev5 = 5, + Rev6 = 6, + Rev7 = 7, } } -/// Revision subversion number of a falcon core, used in the -/// [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] register. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum FalconCoreRevSubversion { - #[default] - Subversion0 = 0, - Subversion1 = 1, - Subversion2 = 2, - Subversion3 = 3, -} -impl_from_enum_to_u8!(FalconCoreRevSubversion); - -// TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom<u8> for FalconCoreRevSubversion { - type Error = Error; - - fn try_from(value: u8) -> Result<Self> { - use FalconCoreRevSubversion::*; - - let sub_version = match value & 0b11 { - 0 => Subversion0, - 1 => Subversion1, - 2 => Subversion2, - 3 => Subversion3, - _ => return Err(EINVAL), - }; - - Ok(sub_version) +bounded_enum! { + /// Revision subversion number of a falcon core, used in the + /// [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] register. + #[derive(Debug, Copy, Clone)] + pub(crate) enum FalconCoreRevSubversion with From<Bounded<u32, 2>> { + Subversion0 = 0, + Subversion1 = 1, + Subversion2 = 2, + Subversion3 = 3, } } -/// Security model of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] -/// register. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone)] -/// Security mode of the Falcon microprocessor. -/// -/// See `falcon.rst` for more details. -pub(crate) enum FalconSecurityModel { - /// Non-Secure: runs unsigned code without privileges. - #[default] - None = 0, - /// Light-Secured (LS): Runs signed code with some privileges. - /// Entry into this mode is only possible from 'Heavy-secure' mode, which verifies the code's - /// signature. +bounded_enum! { + /// Security mode of the Falcon microprocessor. /// - /// Also known as Low-Secure, Privilege Level 2 or PL2. - Light = 2, - /// Heavy-Secured (HS): Runs signed code with full privileges. - /// The code's signature is verified by the Falcon Boot ROM (BROM). - /// - /// Also known as High-Secure, Privilege Level 3 or PL3. - Heavy = 3, -} -impl_from_enum_to_u8!(FalconSecurityModel); - -// TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom<u8> for FalconSecurityModel { - type Error = Error; - - fn try_from(value: u8) -> Result<Self> { - use FalconSecurityModel::*; - - let sec_model = match value { - 0 => None, - 2 => Light, - 3 => Heavy, - _ => return Err(EINVAL), - }; - - Ok(sec_model) - } -} - -/// Signing algorithm for a given firmware, used in the [`crate::regs::NV_PFALCON2_FALCON_MOD_SEL`] -/// register. It is passed to the Falcon Boot ROM (BROM) as a parameter. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] -pub(crate) enum FalconModSelAlgo { - /// AES. - #[expect(dead_code)] - Aes = 0, - /// RSA3K. - #[default] - Rsa3k = 1, -} -impl_from_enum_to_u8!(FalconModSelAlgo); - -// TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom<u8> for FalconModSelAlgo { - type Error = Error; - - fn try_from(value: u8) -> Result<Self> { - match value { - 1 => Ok(FalconModSelAlgo::Rsa3k), - _ => Err(EINVAL), - } + /// See `falcon.rst` for more details. + #[derive(Debug, Copy, Clone)] + pub(crate) enum FalconSecurityModel with TryFrom<Bounded<u32, 2>> { + /// Non-Secure: runs unsigned code without privileges. + None = 0, + /// Light-Secured (LS): Runs signed code with some privileges. + /// Entry into this mode is only possible from 'Heavy-secure' mode, which verifies the + /// code's signature. + /// + /// Also known as Low-Secure, Privilege Level 2 or PL2. + Light = 2, + /// Heavy-Secured (HS): Runs signed code with full privileges. + /// The code's signature is verified by the Falcon Boot ROM (BROM). + /// + /// Also known as High-Secure, Privilege Level 3 or PL3. + Heavy = 3, } } -/// Valid values for the `size` field of the [`crate::regs::NV_PFALCON_FALCON_DMATRFCMD`] register. -#[repr(u8)] -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] -pub(crate) enum DmaTrfCmdSize { - /// 256 bytes transfer. - #[default] - Size256B = 0x6, -} -impl_from_enum_to_u8!(DmaTrfCmdSize); - -// TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom<u8> for DmaTrfCmdSize { - type Error = Error; - - fn try_from(value: u8) -> Result<Self> { - match value { - 0x6 => Ok(Self::Size256B), - _ => Err(EINVAL), - } +bounded_enum! { + /// Signing algorithm for a given firmware, used in the + /// [`crate::regs::NV_PFALCON2_FALCON_MOD_SEL`] register. It is passed to the Falcon Boot ROM + /// (BROM) as a parameter. + #[derive(Debug, Copy, Clone)] + pub(crate) enum FalconModSelAlgo with TryFrom<Bounded<u32, 8>> { + /// AES. + Aes = 0, + /// RSA3K. + Rsa3k = 1, } } -/// Currently active core on a dual falcon/riscv (Peregrine) controller. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub(crate) enum PeregrineCoreSelect { - /// Falcon core is active. - #[default] - Falcon = 0, - /// RISC-V core is active. - Riscv = 1, -} - -impl From<bool> for PeregrineCoreSelect { - fn from(value: bool) -> Self { - match value { - false => PeregrineCoreSelect::Falcon, - true => PeregrineCoreSelect::Riscv, - } +bounded_enum! { + /// Valid values for the `size` field of the [`crate::regs::NV_PFALCON_FALCON_DMATRFCMD`] + /// register. + #[derive(Debug, Copy, Clone)] + pub(crate) enum DmaTrfCmdSize with TryFrom<Bounded<u32, 3>> { + /// 256 bytes transfer. + Size256B = 0x6, } } -impl From<PeregrineCoreSelect> for bool { - fn from(value: PeregrineCoreSelect) -> Self { - match value { - PeregrineCoreSelect::Falcon => false, - PeregrineCoreSelect::Riscv => true, - } +bounded_enum! { + /// Currently active core on a dual falcon/riscv (Peregrine) controller. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub(crate) enum PeregrineCoreSelect with From<Bounded<u32, 1>> { + /// Falcon core is active. + Falcon = 0, + /// RISC-V core is active. + Riscv = 1, } } /// Different types of memory present in a falcon core. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum FalconMem { /// Secure Instruction Memory. ImemSecure, @@ -249,64 +141,29 @@ pub(crate) enum FalconMem { Dmem, } -/// Defines the Framebuffer Interface (FBIF) aperture type. -/// This determines the memory type for external memory access during a DMA transfer, which is -/// performed by the Falcon's Framebuffer DMA (FBDMA) engine. See falcon.rst for more details. -#[derive(Debug, Clone, Default)] -pub(crate) enum FalconFbifTarget { - /// VRAM. - #[default] - /// Local Framebuffer (GPU's VRAM memory). - LocalFb = 0, - /// Coherent system memory (System DRAM). - CoherentSysmem = 1, - /// Non-coherent system memory (System DRAM). - NoncoherentSysmem = 2, -} -impl_from_enum_to_u8!(FalconFbifTarget); - -// TODO[FPRI]: replace with `FromPrimitive`. -impl TryFrom<u8> for FalconFbifTarget { - type Error = Error; - - fn try_from(value: u8) -> Result<Self> { - let res = match value { - 0 => Self::LocalFb, - 1 => Self::CoherentSysmem, - 2 => Self::NoncoherentSysmem, - _ => return Err(EINVAL), - }; - - Ok(res) - } -} - -/// Type of memory addresses to use. -#[derive(Debug, Clone, Default)] -pub(crate) enum FalconFbifMemType { - /// Virtual memory addresses. - #[default] - Virtual = 0, - /// Physical memory addresses. - Physical = 1, -} - -/// Conversion from a single-bit register field. -impl From<bool> for FalconFbifMemType { - fn from(value: bool) -> Self { - match value { - false => Self::Virtual, - true => Self::Physical, - } +bounded_enum! { + /// Defines the Framebuffer Interface (FBIF) aperture type. + /// This determines the memory type for external memory access during a DMA transfer, which is + /// performed by the Falcon's Framebuffer DMA (FBDMA) engine. See falcon.rst for more details. + #[derive(Debug, Copy, Clone)] + pub(crate) enum FalconFbifTarget with TryFrom<Bounded<u32, 2>> { + /// Local Framebuffer (GPU's VRAM memory). + LocalFb = 0, + /// Coherent system memory (System DRAM). + CoherentSysmem = 1, + /// Non-coherent system memory (System DRAM). + NoncoherentSysmem = 2, } } -impl From<FalconFbifMemType> for bool { - fn from(value: FalconFbifMemType) -> Self { - match value { - FalconFbifMemType::Virtual => false, - FalconFbifMemType::Physical => true, - } +bounded_enum! { + /// Type of memory addresses to use. + #[derive(Debug, Copy, Clone)] + pub(crate) enum FalconFbifMemType with From<Bounded<u32, 1>> { + /// Virtual memory addresses. + Virtual = 0, + /// Physical memory addresses. + Physical = 1, } } @@ -318,18 +175,16 @@ pub(crate) struct PFalcon2Base(()); /// Trait defining the parameters of a given Falcon engine. /// -/// Each engine provides one base for `PFALCON` and `PFALCON2` registers. The `ID` constant is used -/// to identify a given Falcon instance with register I/O methods. +/// Each engine provides one base for `PFALCON` and `PFALCON2` registers. pub(crate) trait FalconEngine: Send + Sync + RegisterBase<PFalconBase> + RegisterBase<PFalcon2Base> + Sized { - /// Singleton of the engine, used to identify it with register I/O methods. - const ID: Self; } -/// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM). +/// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM) +/// using DMA. #[derive(Debug, Clone)] -pub(crate) struct FalconLoadTarget { +pub(crate) struct FalconDmaLoadTarget { /// Offset from the start of the source object to copy from. pub(crate) src_start: u32, /// Offset from the start of the destination memory to copy into. @@ -349,32 +204,155 @@ pub(crate) struct FalconBromParams { pub(crate) ucode_id: u8, } -/// Trait for providing load parameters of falcon firmwares. -pub(crate) trait FalconLoadParams { +/// Trait implemented by falcon firmwares that can be loaded using DMA. +pub(crate) trait FalconDmaLoadable { + /// Returns the firmware data as a slice of bytes. + fn as_slice(&self) -> &[u8]; + /// Returns the load parameters for Secure `IMEM`. - fn imem_sec_load_params(&self) -> FalconLoadTarget; + fn imem_sec_load_params(&self) -> FalconDmaLoadTarget; /// Returns the load parameters for Non-Secure `IMEM`, /// used only on Turing and GA100. - fn imem_ns_load_params(&self) -> Option<FalconLoadTarget>; + fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget>; /// Returns the load parameters for `DMEM`. - fn dmem_load_params(&self) -> FalconLoadTarget; + fn dmem_load_params(&self) -> FalconDmaLoadTarget; - /// Returns the parameters to write into the BROM registers. - fn brom_params(&self) -> FalconBromParams; + /// Returns an adapter that provides the required parameter to load this firmware using PIO. + /// + /// This can only fail if some `u32` fields cannot be converted to `u16`, or if the indices in + /// the headers are invalid. + fn try_as_pio_loadable(&self) -> Result<FalconDmaFirmwarePioAdapter<'_, Self>> { + let new_pio_imem = |params: FalconDmaLoadTarget, secure| { + let start = usize::from_safe_cast(params.src_start); + let end = start + usize::from_safe_cast(params.len); + let data = self.as_slice().get(start..end).ok_or(EINVAL)?; + + let dst_start = u16::try_from(params.dst_start).map_err(|_| EINVAL)?; + + Ok::<_, Error>(FalconPioImemLoadTarget { + data, + dst_start, + secure, + start_tag: dst_start >> 8, + }) + }; - /// Returns the start address of the firmware. - fn boot_addr(&self) -> u32; + let imem_sec = new_pio_imem(self.imem_sec_load_params(), true)?; + + let imem_ns = if let Some(params) = self.imem_ns_load_params() { + Some(new_pio_imem(params, false)?) + } else { + None + }; + + let dmem = { + let params = self.dmem_load_params(); + let start = usize::from_safe_cast(params.src_start); + let end = start + usize::from_safe_cast(params.len); + let data = self.as_slice().get(start..end).ok_or(EINVAL)?; + + let dst_start = u16::try_from(params.dst_start).map_err(|_| EINVAL)?; + + FalconPioDmemLoadTarget { data, dst_start } + }; + + Ok(FalconDmaFirmwarePioAdapter { + fw: self, + imem_sec, + imem_ns, + dmem, + }) + } +} + +/// Represents a portion of the firmware to be loaded into IMEM using PIO. +#[derive(Clone)] +pub(crate) struct FalconPioImemLoadTarget<'a> { + pub(crate) data: &'a [u8], + pub(crate) dst_start: u16, + pub(crate) secure: bool, + pub(crate) start_tag: u16, +} + +/// Represents a portion of the firmware to be loaded into DMEM using PIO. +#[derive(Clone)] +pub(crate) struct FalconPioDmemLoadTarget<'a> { + pub(crate) data: &'a [u8], + pub(crate) dst_start: u16, +} + +/// Trait for providing PIO load parameters of falcon firmwares. +pub(crate) trait FalconPioLoadable { + /// Returns the load parameters for Secure `IMEM`, if any. + fn imem_sec_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>>; + + /// Returns the load parameters for Non-Secure `IMEM`, if any. + fn imem_ns_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>>; + + /// Returns the load parameters for `DMEM`. + fn dmem_load_params(&self) -> FalconPioDmemLoadTarget<'_>; +} + +/// Adapter type that makes any DMA-loadable firmware also loadable via PIO. +/// +/// Created using [`FalconDmaLoadable::try_as_pio_loadable`]. +pub(crate) struct FalconDmaFirmwarePioAdapter<'a, T: FalconDmaLoadable + ?Sized> { + /// Reference to the DMA firmware. + fw: &'a T, + /// Validated secure IMEM parameters. + imem_sec: FalconPioImemLoadTarget<'a>, + /// Validated non-secure IMEM parameters. + imem_ns: Option<FalconPioImemLoadTarget<'a>>, + /// Validated DMEM parameters. + dmem: FalconPioDmemLoadTarget<'a>, +} + +impl<'a, T> FalconPioLoadable for FalconDmaFirmwarePioAdapter<'a, T> +where + T: FalconDmaLoadable + ?Sized, +{ + fn imem_sec_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> { + Some(self.imem_sec.clone()) + } + + fn imem_ns_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> { + self.imem_ns.clone() + } + + fn dmem_load_params(&self) -> FalconPioDmemLoadTarget<'_> { + self.dmem.clone() + } +} + +impl<'a, T> FalconFirmware for FalconDmaFirmwarePioAdapter<'a, T> +where + T: FalconDmaLoadable + FalconFirmware + ?Sized, +{ + type Target = <T as FalconFirmware>::Target; + + fn brom_params(&self) -> FalconBromParams { + self.fw.brom_params() + } + + fn boot_addr(&self) -> u32 { + self.fw.boot_addr() + } } /// Trait for a falcon firmware. /// -/// A falcon firmware can be loaded on a given engine, and is presented in the form of a DMA -/// object. -pub(crate) trait FalconFirmware: FalconLoadParams + Deref<Target = DmaObject> { +/// A falcon firmware can be loaded on a given engine. +pub(crate) trait FalconFirmware { /// Engine on which this firmware is to be loaded. type Target: FalconEngine; + + /// Returns the parameters to write into the BROM registers. + fn brom_params(&self) -> FalconBromParams; + + /// Returns the start address of the firmware. + fn boot_addr(&self) -> u32; } /// Contains the base parameters common to all Falcon instances. @@ -394,8 +372,14 @@ impl<E: FalconEngine + 'static> Falcon<E> { /// Resets DMA-related registers. pub(crate) fn dma_reset(&self, bar: &Bar0) { - regs::NV_PFALCON_FBIF_CTL::update(bar, &E::ID, |v| v.set_allow_phys_no_ctx(true)); - regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID); + bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| { + v.with_allow_phys_no_ctx(true) + }); + + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_DMACTL::zeroed(), + ); } /// Reset the controller, select the falcon core, and wait for memory scrubbing to complete. @@ -404,9 +388,111 @@ impl<E: FalconEngine + 'static> Falcon<E> { self.hal.select_core(self, bar)?; self.hal.reset_wait_mem_scrubbing(bar)?; - regs::NV_PFALCON_FALCON_RM::default() - .set_value(regs::NV_PMC_BOOT_0::read(bar).into()) - .write(bar, &E::ID); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_RM::from(bar.read(regs::NV_PMC_BOOT_0).into_raw()), + ); + + Ok(()) + } + + /// Falcons supports up to four ports, but we only ever use one, so just hard-code it. + const PIO_PORT: usize = 0; + + /// Write a slice to Falcon IMEM memory using programmed I/O (PIO). + /// + /// Returns `EINVAL` if `img.len()` is not a multiple of 4. + fn pio_wr_imem_slice(&self, bar: &Bar0, load_offsets: FalconPioImemLoadTarget<'_>) -> Result { + // Rejecting misaligned images here allows us to avoid checking + // inside the loops. + if load_offsets.data.len() % 4 != 0 { + return Err(EINVAL); + } + + bar.write( + WithBase::of::<E>().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_IMEMC::zeroed() + .with_secure(load_offsets.secure) + .with_aincw(true) + .with_offs(load_offsets.dst_start), + ); + + for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).enumerate() { + let n = u16::try_from(n)?; + let tag: u16 = load_offsets.start_tag.checked_add(n).ok_or(ERANGE)?; + bar.write( + WithBase::of::<E>().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag), + ); + for word in block.chunks_exact(4) { + let w = [word[0], word[1], word[2], word[3]]; + bar.write( + WithBase::of::<E>().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32::from_le_bytes(w)), + ); + } + } + + Ok(()) + } + + /// Write a slice to Falcon DMEM memory using programmed I/O (PIO). + /// + /// Returns `EINVAL` if `img.len()` is not a multiple of 4. + fn pio_wr_dmem_slice(&self, bar: &Bar0, load_offsets: FalconPioDmemLoadTarget<'_>) -> Result { + // Rejecting misaligned images here allows us to avoid checking + // inside the loops. + if load_offsets.data.len() % 4 != 0 { + return Err(EINVAL); + } + + bar.write( + WithBase::of::<E>().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_DMEMC::zeroed() + .with_aincw(true) + .with_offs(load_offsets.dst_start), + ); + + for word in load_offsets.data.chunks_exact(4) { + let w = [word[0], word[1], word[2], word[3]]; + bar.write( + WithBase::of::<E>().at(Self::PIO_PORT), + regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::from_le_bytes(w)), + ); + } + + Ok(()) + } + + /// Perform a PIO copy into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it. + pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>( + &self, + bar: &Bar0, + fw: &F, + ) -> Result { + bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| { + v.with_allow_phys_no_ctx(true) + }); + + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_DMACTL::zeroed(), + ); + + if let Some(imem_ns) = fw.imem_ns_load_params() { + self.pio_wr_imem_slice(bar, imem_ns)?; + } + if let Some(imem_sec) = fw.imem_sec_load_params() { + self.pio_wr_imem_slice(bar, imem_sec)?; + } + self.pio_wr_dmem_slice(bar, fw.dmem_load_params())?; + + self.hal.program_brom(self, bar, &fw.brom_params())?; + + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()), + ); Ok(()) } @@ -415,14 +501,14 @@ impl<E: FalconEngine + 'static> Falcon<E> { /// `target_mem`. /// /// `sec` is set if the loaded firmware is expected to run in secure mode. - fn dma_wr<F: FalconFirmware<Target = E>>( + fn dma_wr( &self, bar: &Bar0, - fw: &F, + dma_obj: &Coherent<[u8]>, target_mem: FalconMem, - load_offsets: FalconLoadTarget, + load_offsets: FalconDmaLoadTarget, ) -> Result { - const DMA_LEN: u32 = 256; + const DMA_LEN: u32 = num::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>(); // For IMEM, we want to use the start offset as a virtual address tag for each page, since // code addresses in the firmware (and the boot vector) are virtual. @@ -430,11 +516,11 @@ impl<E: FalconEngine + 'static> Falcon<E> { // For DMEM we can fold the start offset into the DMA handle. let (src_start, dma_start) = match target_mem { FalconMem::ImemSecure | FalconMem::ImemNonSecure => { - (load_offsets.src_start, fw.dma_handle()) + (load_offsets.src_start, dma_obj.dma_handle()) } FalconMem::Dmem => ( 0, - fw.dma_handle_with_offset(load_offsets.src_start.into_safe_cast())?, + dma_obj.dma_handle() + DmaAddress::from(load_offsets.src_start), ), }; if dma_start % DmaAddress::from(DMA_LEN) > 0 { @@ -466,7 +552,7 @@ impl<E: FalconEngine + 'static> Falcon<E> { dev_err!(self.dev, "DMA transfer length overflow\n"); return Err(EOVERFLOW); } - Some(upper_bound) if usize::from_safe_cast(upper_bound) > fw.size() => { + Some(upper_bound) if usize::from_safe_cast(upper_bound) > dma_obj.size() => { dev_err!(self.dev, "DMA transfer goes beyond range of DMA object\n"); return Err(EINVAL); } @@ -475,36 +561,42 @@ impl<E: FalconEngine + 'static> Falcon<E> { // Set up the base source DMA address. - regs::NV_PFALCON_FALCON_DMATRFBASE::default() - // CAST: `as u32` is used on purpose since we do want to strip the upper bits, which - // will be written to `NV_PFALCON_FALCON_DMATRFBASE1`. - .set_base((dma_start >> 8) as u32) - .write(bar, &E::ID); - regs::NV_PFALCON_FALCON_DMATRFBASE1::default() - // CAST: `as u16` is used on purpose since the remaining bits are guaranteed to fit - // within a `u16`. - .set_base((dma_start >> 40) as u16) - .write(bar, &E::ID); - - let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::default() - .set_size(DmaTrfCmdSize::Size256B) + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base( + // CAST: `as u32` is used on purpose since we do want to strip the upper bits, + // which will be written to `NV_PFALCON_FALCON_DMATRFBASE1`. + (dma_start >> 8) as u32, + ), + ); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dma_start >> 40)?, + ); + + let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::zeroed() + .with_size(DmaTrfCmdSize::Size256B) .with_falcon_mem(target_mem); for pos in (0..num_transfers).map(|i| i * DMA_LEN) { // Perform a transfer of size `DMA_LEN`. - regs::NV_PFALCON_FALCON_DMATRFMOFFS::default() - .set_offs(load_offsets.dst_start + pos) - .write(bar, &E::ID); - regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() - .set_offs(src_start + pos) - .write(bar, &E::ID); - cmd.write(bar, &E::ID); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed() + .try_with_offs(load_offsets.dst_start + pos)?, + ); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos), + ); + + bar.write(WithBase::of::<E>(), cmd); // Wait for the transfer to complete. // TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories // should ever take that long. read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())), |r| r.idle(), Delta::ZERO, Delta::from_secs(2), @@ -515,29 +607,36 @@ impl<E: FalconEngine + 'static> Falcon<E> { } /// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it. - fn dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result { - // The Non-Secure section only exists on firmware used by Turing and GA100, and - // those platforms do not use DMA. - if fw.imem_ns_load_params().is_some() { - debug_assert!(false); - return Err(EINVAL); - } + fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>( + &self, + dev: &Device<device::Bound>, + bar: &Bar0, + fw: &F, + ) -> Result { + // Create DMA object with firmware content as the source of the DMA engine. + let dma_obj = Coherent::from_slice(dev, fw.as_slice(), GFP_KERNEL)?; self.dma_reset(bar); - regs::NV_PFALCON_FBIF_TRANSCFG::update(bar, &E::ID, 0, |v| { - v.set_target(FalconFbifTarget::CoherentSysmem) - .set_mem_type(FalconFbifMemType::Physical) + bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| { + v.with_target(FalconFbifTarget::CoherentSysmem) + .with_mem_type(FalconFbifMemType::Physical) }); - self.dma_wr(bar, fw, FalconMem::ImemSecure, fw.imem_sec_load_params())?; - self.dma_wr(bar, fw, FalconMem::Dmem, fw.dmem_load_params())?; + self.dma_wr( + bar, + &dma_obj, + FalconMem::ImemSecure, + fw.imem_sec_load_params(), + )?; + self.dma_wr(bar, &dma_obj, FalconMem::Dmem, fw.dmem_load_params())?; self.hal.program_brom(self, bar, &fw.brom_params())?; // Set `BootVec` to start of non-secure code. - regs::NV_PFALCON_FALCON_BOOTVEC::default() - .set_value(fw.boot_addr()) - .write(bar, &E::ID); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()), + ); Ok(()) } @@ -546,7 +645,7 @@ impl<E: FalconEngine + 'static> Falcon<E> { pub(crate) fn wait_till_halted(&self, bar: &Bar0) -> Result<()> { // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds. read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())), |r| r.halted(), Delta::ZERO, Delta::from_secs(2), @@ -557,13 +656,18 @@ impl<E: FalconEngine + 'static> Falcon<E> { /// Start the falcon CPU. pub(crate) fn start(&self, bar: &Bar0) -> Result<()> { - match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID).alias_en() { - true => regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default() - .set_startcpu(true) - .write(bar, &E::ID), - false => regs::NV_PFALCON_FALCON_CPUCTL::default() - .set_startcpu(true) - .write(bar, &E::ID), + match bar + .read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>()) + .alias_en() + { + true => bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startcpu(true), + ), + false => bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(true), + ), } Ok(()) @@ -572,26 +676,30 @@ impl<E: FalconEngine + 'static> Falcon<E> { /// Writes values to the mailbox registers if provided. pub(crate) fn write_mailboxes(&self, bar: &Bar0, mbox0: Option<u32>, mbox1: Option<u32>) { if let Some(mbox0) = mbox0 { - regs::NV_PFALCON_FALCON_MAILBOX0::default() - .set_value(mbox0) - .write(bar, &E::ID); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox0), + ); } if let Some(mbox1) = mbox1 { - regs::NV_PFALCON_FALCON_MAILBOX1::default() - .set_value(mbox1) - .write(bar, &E::ID); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox1), + ); } } /// Reads the value from `mbox0` register. pub(crate) fn read_mailbox0(&self, bar: &Bar0) -> u32 { - regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value() + bar.read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>()) + .value() } /// Reads the value from `mbox1` register. pub(crate) fn read_mailbox1(&self, bar: &Bar0) -> u32 { - regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, &E::ID).value() + bar.read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>()) + .value() } /// Reads values from both mailbox registers. @@ -640,18 +748,25 @@ impl<E: FalconEngine + 'static> Falcon<E> { self.hal.is_riscv_active(bar) } - // Load a firmware image into Falcon memory - pub(crate) fn load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result { + /// Load a firmware image into Falcon memory, using the preferred method for the current + /// chipset. + pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>( + &self, + dev: &Device<device::Bound>, + bar: &Bar0, + fw: &F, + ) -> Result { match self.hal.load_method() { - LoadMethod::Dma => self.dma_load(bar, fw), - LoadMethod::Pio => Err(ENOTSUPP), + LoadMethod::Dma => self.dma_load(dev, bar, fw), + LoadMethod::Pio => self.pio_load(bar, &fw.try_as_pio_loadable()?), } } /// Write the application version to the OS register. pub(crate) fn write_os_version(&self, bar: &Bar0, app_version: u32) { - regs::NV_PFALCON_FALCON_OS::default() - .set_value(app_version) - .write(bar, &E::ID); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version), + ); } } diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs index 67edef3636c1..df6d5a382c7a 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -1,7 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::{ + RegisterBase, + WithBase, // + }, + Io, + }, prelude::*, time::Delta, // }; @@ -14,10 +21,7 @@ use crate::{ PFalcon2Base, PFalconBase, // }, - regs::{ - self, - macros::RegisterBase, // - }, + regs, }; /// Type specifying the `Gsp` falcon engine. Cannot be instantiated. @@ -31,23 +35,22 @@ impl RegisterBase<PFalcon2Base> for Gsp { const BASE: usize = 0x00111000; } -impl FalconEngine for Gsp { - const ID: Self = Gsp(()); -} +impl FalconEngine for Gsp {} impl Falcon<Gsp> { /// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to /// allow GSP to signal CPU for processing new messages in message queue. pub(crate) fn clear_swgen0_intr(&self, bar: &Bar0) { - regs::NV_PFALCON_FALCON_IRQSCLR::default() - .set_swgen0(true) - .write(bar, &Gsp::ID); + bar.write( + WithBase::of::<Gsp>(), + regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true), + ); } /// Checks if GSP reload/resume has completed during the boot process. pub(crate) fn check_reload_completed(&self, bar: &Bar0, timeout: Delta) -> Result<bool> { read_poll_timeout( - || Ok(regs::NV_PGC6_BSI_SECURE_SCRATCH_14::read(bar)), + || Ok(bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)), |val| val.boot_stage_3_handoff(), Delta::ZERO, timeout, diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/falcon/hal.rs index 89babd5f9325..a7e5ea8d0272 100644 --- a/drivers/gpu/nova-core/falcon/hal.rs +++ b/drivers/gpu/nova-core/falcon/hal.rs @@ -58,7 +58,11 @@ pub(crate) trait FalconHal<E: FalconEngine>: Send + Sync { /// Reset the falcon engine. fn reset_eng(&self, bar: &Bar0) -> Result; - /// returns the method needed to load data into Falcon memory + /// Returns the method used to load data into the falcon's memory. + /// + /// The only chipsets supporting PIO are those < GA102, and PIO is the preferred method for + /// these. For anything above, the PIO registers appear to be masked to the CPU, so DMA is the + /// only usable method. fn load_method(&self) -> LoadMethod; } diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs index 8f62df10da0a..8368a61ddeef 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -4,7 +4,14 @@ use core::marker::PhantomData; use kernel::{ device, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::{ + Array, + WithBase, // + }, + Io, // + }, prelude::*, time::Delta, // }; @@ -25,15 +32,16 @@ use crate::{ use super::FalconHal; fn select_core_ga102<E: FalconEngine>(bar: &Bar0) -> Result { - let bcr_ctrl = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); + let bcr_ctrl = bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::<E>()); if bcr_ctrl.core_select() != PeregrineCoreSelect::Falcon { - regs::NV_PRISCV_RISCV_BCR_CTRL::default() - .set_core_select(PeregrineCoreSelect::Falcon) - .write(bar, &E::ID); + bar.write( + WithBase::of::<E>(), + regs::NV_PRISCV_RISCV_BCR_CTRL::zeroed().with_core_select(PeregrineCoreSelect::Falcon), + ); // TIMEOUT: falcon core should take less than 10ms to report being enabled. read_poll_timeout( - || Ok(regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::<E>())), |r| r.valid(), Delta::ZERO, Delta::from_millis(10), @@ -60,12 +68,15 @@ fn signature_reg_fuse_version_ga102( // `ucode_idx` is guaranteed to be in the range [0..15], making the `read` calls provable valid // at build-time. - let reg_fuse_version = if engine_id_mask & 0x0001 != 0 { - regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::read(bar, ucode_idx).data() + let reg_fuse_version: u16 = if engine_id_mask & 0x0001 != 0 { + bar.read(regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::at(ucode_idx)) + .data() } else if engine_id_mask & 0x0004 != 0 { - regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::read(bar, ucode_idx).data() + bar.read(regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::at(ucode_idx)) + .data() } else if engine_id_mask & 0x0400 != 0 { - regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::read(bar, ucode_idx).data() + bar.read(regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::at(ucode_idx)) + .data() } else { dev_err!(dev, "unexpected engine_id_mask {:#x}\n", engine_id_mask); return Err(EINVAL); @@ -76,18 +87,23 @@ fn signature_reg_fuse_version_ga102( } fn program_brom_ga102<E: FalconEngine>(bar: &Bar0, params: &FalconBromParams) -> Result { - regs::NV_PFALCON2_FALCON_BROM_PARAADDR::default() - .set_value(params.pkc_data_offset) - .write(bar, &E::ID, 0); - regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::default() - .set_value(u32::from(params.engine_id_mask)) - .write(bar, &E::ID); - regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::default() - .set_ucode_id(params.ucode_id) - .write(bar, &E::ID); - regs::NV_PFALCON2_FALCON_MOD_SEL::default() - .set_algo(FalconModSelAlgo::Rsa3k) - .write(bar, &E::ID); + bar.write( + WithBase::of::<E>().at(0), + regs::NV_PFALCON2_FALCON_BROM_PARAADDR::zeroed().with_value(params.pkc_data_offset), + ); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::zeroed() + .with_value(u32::from(params.engine_id_mask)), + ); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::zeroed().with_ucode_id(params.ucode_id), + ); + bar.write( + WithBase::of::<E>(), + regs::NV_PFALCON2_FALCON_MOD_SEL::zeroed().with_algo(FalconModSelAlgo::Rsa3k), + ); Ok(()) } @@ -120,14 +136,14 @@ impl<E: FalconEngine> FalconHal<E> for Ga102<E> { } fn is_riscv_active(&self, bar: &Bar0) -> bool { - let cpuctl = regs::NV_PRISCV_RISCV_CPUCTL::read(bar, &E::ID); - cpuctl.active_stat() + bar.read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>()) + .active_stat() } fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { // TIMEOUT: memory scrubbing should complete in less than 20ms. read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())), |r| r.mem_scrubbing_done(), Delta::ZERO, Delta::from_millis(20), @@ -136,12 +152,12 @@ impl<E: FalconEngine> FalconHal<E> for Ga102<E> { } fn reset_eng(&self, bar: &Bar0) -> Result { - let _ = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID); + let _ = bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>()); // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set // RESET_READY so a non-failing timeout is used. let _ = read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())), |r| r.reset_ready(), Delta::ZERO, Delta::from_micros(150), diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-core/falcon/hal/tu102.rs index 7de6f24cc0a0..c7a90266cb44 100644 --- a/drivers/gpu/nova-core/falcon/hal/tu102.rs +++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs @@ -3,7 +3,11 @@ use core::marker::PhantomData; use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + register::WithBase, + Io, // + }, prelude::*, time::Delta, // }; @@ -49,14 +53,14 @@ impl<E: FalconEngine> FalconHal<E> for Tu102<E> { } fn is_riscv_active(&self, bar: &Bar0) -> bool { - let cpuctl = regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::read(bar, &E::ID); - cpuctl.active_stat() + bar.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::<E>()) + .active_stat() } fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { // TIMEOUT: memory scrubbing should complete in less than 10ms. read_poll_timeout( - || Ok(regs::NV_PFALCON_FALCON_DMACTL::read(bar, &E::ID)), + || Ok(bar.read(regs::NV_PFALCON_FALCON_DMACTL::of::<E>())), |r| r.mem_scrubbing_done(), Delta::ZERO, Delta::from_millis(10), diff --git a/drivers/gpu/nova-core/falcon/sec2.rs b/drivers/gpu/nova-core/falcon/sec2.rs index b57d362e576a..91ec7d49c1f5 100644 --- a/drivers/gpu/nova-core/falcon/sec2.rs +++ b/drivers/gpu/nova-core/falcon/sec2.rs @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -use crate::{ - falcon::{ - FalconEngine, - PFalcon2Base, - PFalconBase, // - }, - regs::macros::RegisterBase, +use kernel::io::register::RegisterBase; + +use crate::falcon::{ + FalconEngine, + PFalcon2Base, + PFalconBase, // }; /// Type specifying the `Sec2` falcon engine. Cannot be instantiated. @@ -20,6 +19,4 @@ impl RegisterBase<PFalcon2Base> for Sec2 { const BASE: usize = 0x00841000; } -impl FalconEngine for Sec2 { - const ID: Self = Sec2(()); -} +impl FalconEngine for Sec2 {} diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index c62abcaed547..bdd5eed760e1 100644 --- a/drivers/gpu/nova-core/fb.rs +++ b/drivers/gpu/nova-core/fb.rs @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 -use core::ops::Range; +use core::ops::{ + Deref, + Range, // +}; use kernel::{ device, + dma::CoherentHandle, + fmt, + io::Io, prelude::*, ptr::{ Alignable, @@ -14,7 +20,6 @@ use kernel::{ }; use crate::{ - dma::DmaObject, driver::Bar0, firmware::gsp::GspFirmware, gpu::Chipset, @@ -48,7 +53,7 @@ pub(crate) struct SysmemFlush { chipset: Chipset, device: ARef<device::Device>, /// Keep the page alive as long as we need it. - page: DmaObject, + page: CoherentHandle, } impl SysmemFlush { @@ -58,7 +63,7 @@ impl SysmemFlush { bar: &Bar0, chipset: Chipset, ) -> Result<Self> { - let page = DmaObject::new(dev, kernel::page::PAGE_SIZE)?; + let page = CoherentHandle::alloc(dev, kernel::page::PAGE_SIZE, GFP_KERNEL)?; hal::fb_hal(chipset).write_sysmem_flush_page(bar, page.dma_handle())?; @@ -94,26 +99,77 @@ impl SysmemFlush { } } +pub(crate) struct FbRange(Range<u64>); + +impl FbRange { + pub(crate) fn len(&self) -> u64 { + self.0.end - self.0.start + } +} + +impl From<Range<u64>> for FbRange { + fn from(range: Range<u64>) -> Self { + Self(range) + } +} + +impl Deref for FbRange { + type Target = Range<u64>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl fmt::Debug for FbRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Use alternate format ({:#?}) to include size, compact format ({:?}) for just the range. + if f.alternate() { + let size = self.len(); + + if size < usize_as_u64(SZ_1M) { + let size_kib = size / usize_as_u64(SZ_1K); + f.write_fmt(fmt!( + "{:#x}..{:#x} ({} KiB)", + self.0.start, + self.0.end, + size_kib + )) + } else { + let size_mib = size / usize_as_u64(SZ_1M); + f.write_fmt(fmt!( + "{:#x}..{:#x} ({} MiB)", + self.0.start, + self.0.end, + size_mib + )) + } + } else { + f.write_fmt(fmt!("{:#x}..{:#x}", self.0.start, self.0.end)) + } + } +} + /// Layout of the GPU framebuffer memory. /// /// Contains ranges of GPU memory reserved for a given purpose during the GSP boot process. #[derive(Debug)] pub(crate) struct FbLayout { /// Range of the framebuffer. Starts at `0`. - pub(crate) fb: Range<u64>, + pub(crate) fb: FbRange, /// VGA workspace, small area of reserved memory at the end of the framebuffer. - pub(crate) vga_workspace: Range<u64>, + pub(crate) vga_workspace: FbRange, /// FRTS range. - pub(crate) frts: Range<u64>, + pub(crate) frts: FbRange, /// Memory area containing the GSP bootloader image. - pub(crate) boot: Range<u64>, + pub(crate) boot: FbRange, /// Memory area containing the GSP firmware image. - pub(crate) elf: Range<u64>, + pub(crate) elf: FbRange, /// WPR2 heap. - pub(crate) wpr2_heap: Range<u64>, + pub(crate) wpr2_heap: FbRange, /// WPR2 region range, starting with an instance of `GspFwWprMeta`. - pub(crate) wpr2: Range<u64>, - pub(crate) heap: Range<u64>, + pub(crate) wpr2: FbRange, + pub(crate) heap: FbRange, pub(crate) vf_partition_count: u8, } @@ -125,7 +181,7 @@ impl FbLayout { let fb = { let fb_size = hal.vidmem_size(bar); - 0..fb_size + FbRange(0..fb_size) }; let vga_workspace = { @@ -134,7 +190,10 @@ impl FbLayout { let base = fb.end - NV_PRAMIN_SIZE; if hal.supports_display(bar) { - match regs::NV_PDISP_VGA_WORKSPACE_BASE::read(bar).vga_workspace_addr() { + match bar + .read(regs::NV_PDISP_VGA_WORKSPACE_BASE) + .vga_workspace_addr() + { Some(addr) => { if addr < base { const VBIOS_WORKSPACE_SIZE: u64 = usize_as_u64(SZ_128K); @@ -152,7 +211,7 @@ impl FbLayout { } }; - vga_base..fb.end + FbRange(vga_base..fb.end) }; let frts = { @@ -160,7 +219,7 @@ impl FbLayout { const FRTS_SIZE: u64 = usize_as_u64(SZ_1M); let frts_base = vga_workspace.start.align_down(FRTS_DOWN_ALIGN) - FRTS_SIZE; - frts_base..frts_base + FRTS_SIZE + FbRange(frts_base..frts_base + FRTS_SIZE) }; let boot = { @@ -168,7 +227,7 @@ impl FbLayout { let bootloader_size = u64::from_safe_cast(gsp_fw.bootloader.ucode.size()); let bootloader_base = (frts.start - bootloader_size).align_down(BOOTLOADER_DOWN_ALIGN); - bootloader_base..bootloader_base + bootloader_size + FbRange(bootloader_base..bootloader_base + bootloader_size) }; let elf = { @@ -176,7 +235,7 @@ impl FbLayout { let elf_size = u64::from_safe_cast(gsp_fw.size); let elf_addr = (boot.start - elf_size).align_down(ELF_DOWN_ALIGN); - elf_addr..elf_addr + elf_size + FbRange(elf_addr..elf_addr + elf_size) }; let wpr2_heap = { @@ -185,7 +244,7 @@ impl FbLayout { gsp::LibosParams::from_chipset(chipset).wpr_heap_size(chipset, fb.end); let wpr2_heap_addr = (elf.start - wpr2_heap_size).align_down(WPR2_HEAP_DOWN_ALIGN); - wpr2_heap_addr..(elf.start).align_down(WPR2_HEAP_DOWN_ALIGN) + FbRange(wpr2_heap_addr..(elf.start).align_down(WPR2_HEAP_DOWN_ALIGN)) }; let wpr2 = { @@ -193,13 +252,13 @@ impl FbLayout { let wpr2_addr = (wpr2_heap.start - u64::from_safe_cast(size_of::<gsp::GspFwWprMeta>())) .align_down(WPR2_DOWN_ALIGN); - wpr2_addr..frts.end + FbRange(wpr2_addr..frts.end) }; let heap = { const HEAP_SIZE: u64 = usize_as_u64(SZ_1M); - wpr2.start - HEAP_SIZE..wpr2.start + FbRange(wpr2.start - HEAP_SIZE..wpr2.start) }; Ok(Self { diff --git a/drivers/gpu/nova-core/fb/hal/ga100.rs b/drivers/gpu/nova-core/fb/hal/ga100.rs index e0acc41aa7cd..1c03783cddef 100644 --- a/drivers/gpu/nova-core/fb/hal/ga100.rs +++ b/drivers/gpu/nova-core/fb/hal/ga100.rs @@ -1,6 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 -use kernel::prelude::*; +use kernel::{ + io::Io, + num::Bounded, + prelude::*, // +}; use crate::{ driver::Bar0, @@ -13,26 +17,31 @@ use super::tu102::FLUSH_SYSMEM_ADDR_SHIFT; struct Ga100; pub(super) fn read_sysmem_flush_page_ga100(bar: &Bar0) -> u64 { - u64::from(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::read(bar).adr_39_08()) << FLUSH_SYSMEM_ADDR_SHIFT - | u64::from(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::read(bar).adr_63_40()) + u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR).adr_39_08()) << FLUSH_SYSMEM_ADDR_SHIFT + | u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI).adr_63_40()) << FLUSH_SYSMEM_ADDR_SHIFT_HI } pub(super) fn write_sysmem_flush_page_ga100(bar: &Bar0, addr: u64) { - regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::default() - // CAST: `as u32` is used on purpose since the remaining bits are guaranteed to fit within - // a `u32`. - .set_adr_63_40((addr >> FLUSH_SYSMEM_ADDR_SHIFT_HI) as u32) - .write(bar); - regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() - // CAST: `as u32` is used on purpose since we want to strip the upper bits that have been - // written to `NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI`. - .set_adr_39_08((addr >> FLUSH_SYSMEM_ADDR_SHIFT) as u32) - .write(bar); + bar.write_reg( + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr_63_40( + Bounded::<u64, _>::from(addr) + .shr::<FLUSH_SYSMEM_ADDR_SHIFT_HI, _>() + .cast(), + ), + ); + + bar.write_reg( + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::zeroed() + // CAST: `as u32` is used on purpose since we want to strip the upper bits that have + // been written to `NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI`. + .with_adr_39_08((addr >> FLUSH_SYSMEM_ADDR_SHIFT) as u32), + ); } pub(super) fn display_enabled_ga100(bar: &Bar0) -> bool { - !regs::ga100::NV_FUSE_STATUS_OPT_DISPLAY::read(bar).display_disabled() + !bar.read(regs::ga100::NV_FUSE_STATUS_OPT_DISPLAY) + .display_disabled() } /// Shift applied to the sysmem address before it is written into diff --git a/drivers/gpu/nova-core/fb/hal/ga102.rs b/drivers/gpu/nova-core/fb/hal/ga102.rs index 734605905031..4b9f0f74d0e7 100644 --- a/drivers/gpu/nova-core/fb/hal/ga102.rs +++ b/drivers/gpu/nova-core/fb/hal/ga102.rs @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 -use kernel::prelude::*; +use kernel::{ + io::Io, + prelude::*, // +}; use crate::{ driver::Bar0, @@ -9,7 +12,7 @@ use crate::{ }; fn vidmem_size_ga102(bar: &Bar0) -> u64 { - regs::NV_USABLE_FB_SIZE_IN_MB::read(bar).usable_fb_size() + bar.read(regs::NV_USABLE_FB_SIZE_IN_MB).usable_fb_size() } struct Ga102; diff --git a/drivers/gpu/nova-core/fb/hal/tu102.rs b/drivers/gpu/nova-core/fb/hal/tu102.rs index eec984f4e816..281bb796e198 100644 --- a/drivers/gpu/nova-core/fb/hal/tu102.rs +++ b/drivers/gpu/nova-core/fb/hal/tu102.rs @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 -use kernel::prelude::*; +use kernel::{ + io::Io, + prelude::*, // +}; use crate::{ driver::Bar0, @@ -13,7 +16,7 @@ use crate::{ pub(super) const FLUSH_SYSMEM_ADDR_SHIFT: u32 = 8; pub(super) fn read_sysmem_flush_page_gm107(bar: &Bar0) -> u64 { - u64::from(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::read(bar).adr_39_08()) << FLUSH_SYSMEM_ADDR_SHIFT + u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR).adr_39_08()) << FLUSH_SYSMEM_ADDR_SHIFT } pub(super) fn write_sysmem_flush_page_gm107(bar: &Bar0, addr: u64) -> Result { @@ -21,18 +24,18 @@ pub(super) fn write_sysmem_flush_page_gm107(bar: &Bar0, addr: u64) -> Result { u32::try_from(addr >> FLUSH_SYSMEM_ADDR_SHIFT) .map_err(|_| EINVAL) .map(|addr| { - regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() - .set_adr_39_08(addr) - .write(bar) + bar.write_reg(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::zeroed().with_adr_39_08(addr)) }) } pub(super) fn display_enabled_gm107(bar: &Bar0) -> bool { - !regs::gm107::NV_FUSE_STATUS_OPT_DISPLAY::read(bar).display_disabled() + !bar.read(regs::gm107::NV_FUSE_STATUS_OPT_DISPLAY) + .display_disabled() } pub(super) fn vidmem_size_gp102(bar: &Bar0) -> u64 { - regs::NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE::read(bar).usable_fb_size() + bar.read(regs::NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE) + .usable_fb_size() } struct Tu102; diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs index 68779540aa28..6c2ab69cb605 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -15,10 +15,9 @@ use kernel::{ }; use crate::{ - dma::DmaObject, falcon::{ - FalconFirmware, - FalconLoadTarget, // + FalconDmaLoadTarget, + FalconFirmware, // }, gpu, num::{ @@ -64,7 +63,8 @@ pub(crate) struct FalconUCodeDescV2 { pub(crate) interface_offset: u32, /// Base address at which to load the code segment into 'IMEM'. pub(crate) imem_phys_base: u32, - /// Size in bytes of the code to copy into 'IMEM'. + /// Size in bytes of the code to copy into 'IMEM' (includes both secure and non-secure + /// segments). pub(crate) imem_load_size: u32, /// Virtual 'IMEM' address (i.e. 'tag') at which the code should start. pub(crate) imem_virt_base: u32, @@ -171,9 +171,9 @@ pub(crate) trait FalconUCodeDescriptor { ((hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast() } - fn imem_sec_load_params(&self) -> FalconLoadTarget; - fn imem_ns_load_params(&self) -> Option<FalconLoadTarget>; - fn dmem_load_params(&self) -> FalconLoadTarget; + fn imem_sec_load_params(&self) -> FalconDmaLoadTarget; + fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget>; + fn dmem_load_params(&self) -> FalconDmaLoadTarget; } impl FalconUCodeDescriptor for FalconUCodeDescV2 { @@ -205,24 +205,31 @@ impl FalconUCodeDescriptor for FalconUCodeDescV2 { 0 } - fn imem_sec_load_params(&self) -> FalconLoadTarget { - FalconLoadTarget { - src_start: 0, - dst_start: self.imem_sec_base, + fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { + // `imem_sec_base` is the *virtual* start address of the secure IMEM segment, so subtract + // `imem_virt_base` to get its physical offset. + let imem_sec_start = self.imem_sec_base.saturating_sub(self.imem_virt_base); + + FalconDmaLoadTarget { + src_start: imem_sec_start, + dst_start: self.imem_phys_base.saturating_add(imem_sec_start), len: self.imem_sec_size, } } - fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> { - Some(FalconLoadTarget { + fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> { + Some(FalconDmaLoadTarget { + // Non-secure code always starts at offset 0. src_start: 0, dst_start: self.imem_phys_base, - len: self.imem_load_size.checked_sub(self.imem_sec_size)?, + // `imem_load_size` includes the size of the secure segment, so subtract it to + // get the correct amount of data to copy. + len: self.imem_load_size.saturating_sub(self.imem_sec_size), }) } - fn dmem_load_params(&self) -> FalconLoadTarget { - FalconLoadTarget { + fn dmem_load_params(&self) -> FalconDmaLoadTarget { + FalconDmaLoadTarget { src_start: self.dmem_offset, dst_start: self.dmem_phys_base, len: self.dmem_load_size, @@ -259,21 +266,23 @@ impl FalconUCodeDescriptor for FalconUCodeDescV3 { self.signature_versions } - fn imem_sec_load_params(&self) -> FalconLoadTarget { - FalconLoadTarget { + fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { + FalconDmaLoadTarget { + // IMEM segment always starts at offset 0. src_start: 0, dst_start: self.imem_phys_base, len: self.imem_load_size, } } - fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> { + fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> { // Not used on V3 platforms None } - fn dmem_load_params(&self) -> FalconLoadTarget { - FalconLoadTarget { + fn dmem_load_params(&self) -> FalconDmaLoadTarget { + FalconDmaLoadTarget { + // DMEM segment starts right after the IMEM one. src_start: self.imem_load_size, dst_start: self.dmem_phys_base, len: self.dmem_load_size, @@ -292,7 +301,7 @@ impl SignedState for Unsigned {} struct Signed; impl SignedState for Signed {} -/// A [`DmaObject`] containing a specific microcode ready to be loaded into a falcon. +/// Microcode to be loaded into a specific falcon. /// /// This is module-local and meant for sub-modules to use internally. /// @@ -300,34 +309,35 @@ impl SignedState for Signed {} /// before it can be loaded (with an exception for development hardware). The /// [`Self::patch_signature`] and [`Self::no_patch_signature`] methods are used to transition the /// firmware to its [`Signed`] state. -struct FirmwareDmaObject<F: FalconFirmware, S: SignedState>(DmaObject, PhantomData<(F, S)>); +// TODO: Consider replacing this with a coherent memory object once `CoherentAllocation` supports +// temporary CPU-exclusive access to the object without unsafe methods. +struct FirmwareObject<F: FalconFirmware, S: SignedState>(KVVec<u8>, PhantomData<(F, S)>); /// Trait for signatures to be patched directly into a given firmware. /// /// This is module-local and meant for sub-modules to use internally. trait FirmwareSignature<F: FalconFirmware>: AsRef<[u8]> {} -impl<F: FalconFirmware> FirmwareDmaObject<F, Unsigned> { - /// Patches the firmware at offset `sig_base_img` with `signature`. +impl<F: FalconFirmware> FirmwareObject<F, Unsigned> { + /// Patches the firmware at offset `signature_start` with `signature`. fn patch_signature<S: FirmwareSignature<F>>( mut self, signature: &S, - sig_base_img: usize, - ) -> Result<FirmwareDmaObject<F, Signed>> { + signature_start: usize, + ) -> Result<FirmwareObject<F, Signed>> { let signature_bytes = signature.as_ref(); - if sig_base_img + signature_bytes.len() > self.0.size() { - return Err(EINVAL); - } + let signature_end = signature_start + .checked_add(signature_bytes.len()) + .ok_or(EOVERFLOW)?; + let dst = self + .0 + .get_mut(signature_start..signature_end) + .ok_or(EINVAL)?; - // SAFETY: We are the only user of this object, so there cannot be any race. - let dst = unsafe { self.0.start_ptr_mut().add(sig_base_img) }; - - // SAFETY: `signature` and `dst` are valid, properly aligned, and do not overlap. - unsafe { - core::ptr::copy_nonoverlapping(signature_bytes.as_ptr(), dst, signature_bytes.len()) - }; + // PANIC: `dst` and `signature_bytes` have the same length. + dst.copy_from_slice(signature_bytes); - Ok(FirmwareDmaObject(self.0, PhantomData)) + Ok(FirmwareObject(self.0, PhantomData)) } /// Mark the firmware as signed without patching it. @@ -335,8 +345,8 @@ impl<F: FalconFirmware> FirmwareDmaObject<F, Unsigned> { /// This method is used to explicitly confirm that we do not need to sign the firmware, while /// allowing us to continue as if it was. This is typically only needed for development /// hardware. - fn no_patch_signature(self) -> FirmwareDmaObject<F, Signed> { - FirmwareDmaObject(self.0, PhantomData) + fn no_patch_signature(self) -> FirmwareObject<F, Signed> { + FirmwareObject(self.0, PhantomData) } } @@ -394,8 +404,9 @@ impl<'a> BinFirmware<'a> { fn data(&self) -> Option<&[u8]> { let fw_start = usize::from_safe_cast(self.hdr.data_offset); let fw_size = usize::from_safe_cast(self.hdr.data_size); + let fw_end = fw_start.checked_add(fw_size)?; - self.fw.get(fw_start..fw_start + fw_size) + self.fw.get(fw_start..fw_end) } } @@ -416,24 +427,111 @@ impl<const N: usize> ModInfoBuilder<N> { ) } - const fn make_entry_chipset(self, chipset: &str) -> Self { - self.make_entry_file(chipset, "booter_load") - .make_entry_file(chipset, "booter_unload") - .make_entry_file(chipset, "bootloader") - .make_entry_file(chipset, "gsp") + const fn make_entry_chipset(self, chipset: gpu::Chipset) -> Self { + let name = chipset.name(); + + let this = self + .make_entry_file(name, "booter_load") + .make_entry_file(name, "booter_unload") + .make_entry_file(name, "bootloader") + .make_entry_file(name, "gsp"); + + if chipset.needs_fwsec_bootloader() { + this.make_entry_file(name, "gen_bootloader") + } else { + this + } } pub(crate) const fn create( - module_name: &'static kernel::str::CStr, + module_name: &'static core::ffi::CStr, ) -> firmware::ModInfoBuilder<N> { let mut this = Self(firmware::ModInfoBuilder::new(module_name)); let mut i = 0; while i < gpu::Chipset::ALL.len() { - this = this.make_entry_chipset(gpu::Chipset::ALL[i].name()); + this = this.make_entry_chipset(gpu::Chipset::ALL[i]); i += 1; } this.0 } } + +/// Ad-hoc and temporary module to extract sections from ELF images. +/// +/// Some firmware images are currently packaged as ELF files, where sections names are used as keys +/// to specific and related bits of data. Future firmware versions are scheduled to move away from +/// that scheme before nova-core becomes stable, which means this module will eventually be +/// removed. +mod elf { + use core::mem::size_of; + + use kernel::{ + bindings, + str::CStr, + transmute::FromBytes, // + }; + + /// Newtype to provide a [`FromBytes`] implementation. + #[repr(transparent)] + struct Elf64Hdr(bindings::elf64_hdr); + // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. + unsafe impl FromBytes for Elf64Hdr {} + + #[repr(transparent)] + struct Elf64SHdr(bindings::elf64_shdr); + // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. + unsafe impl FromBytes for Elf64SHdr {} + + /// Returns a NULL-terminated string from the ELF image at `offset`. + fn elf_str(elf: &[u8], offset: u64) -> Option<&str> { + let idx = usize::try_from(offset).ok()?; + let bytes = elf.get(idx..)?; + CStr::from_bytes_until_nul(bytes).ok()?.to_str().ok() + } + + /// Tries to extract section with name `name` from the ELF64 image `elf`, and returns it. + pub(super) fn elf64_section<'a, 'b>(elf: &'a [u8], name: &'b str) -> Option<&'a [u8]> { + let hdr = &elf + .get(0..size_of::<bindings::elf64_hdr>()) + .and_then(Elf64Hdr::from_bytes)? + .0; + + // Get all the section headers. + let mut shdr = { + let shdr_num = usize::from(hdr.e_shnum); + let shdr_start = usize::try_from(hdr.e_shoff).ok()?; + let shdr_end = shdr_num + .checked_mul(size_of::<Elf64SHdr>()) + .and_then(|v| v.checked_add(shdr_start))?; + + elf.get(shdr_start..shdr_end) + .map(|slice| slice.chunks_exact(size_of::<Elf64SHdr>()))? + }; + + // Get the strings table. + let strhdr = shdr + .clone() + .nth(usize::from(hdr.e_shstrndx)) + .and_then(Elf64SHdr::from_bytes)?; + + // Find the section which name matches `name` and return it. + shdr.find_map(|sh| { + let hdr = Elf64SHdr::from_bytes(sh)?; + let name_offset = strhdr.0.sh_offset.checked_add(u64::from(hdr.0.sh_name))?; + let section_name = elf_str(elf, name_offset)?; + + if section_name != name { + return None; + } + + let start = usize::try_from(hdr.0.sh_offset).ok()?; + let end = usize::try_from(hdr.0.sh_size) + .ok() + .and_then(|sh_size| start.checked_add(sh_size))?; + + elf.get(start..end) + }) + } +} diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs index 86556cee8e67..de2a4536b532 100644 --- a/drivers/gpu/nova-core/firmware/booter.rs +++ b/drivers/gpu/nova-core/firmware/booter.rs @@ -4,10 +4,7 @@ //! running on [`Sec2`], that is used on Turing/Ampere to load the GSP firmware into the GSP falcon //! (and optionally unload it through a separate firmware image). -use core::{ - marker::PhantomData, - ops::Deref, // -}; +use core::marker::PhantomData; use kernel::{ device, @@ -16,19 +13,18 @@ use kernel::{ }; use crate::{ - dma::DmaObject, driver::Bar0, falcon::{ sec2::Sec2, Falcon, FalconBromParams, - FalconFirmware, - FalconLoadParams, - FalconLoadTarget, // + FalconDmaLoadTarget, + FalconDmaLoadable, + FalconFirmware, // }, firmware::{ BinFirmware, - FirmwareDmaObject, + FirmwareObject, FirmwareSignature, Signed, Unsigned, // @@ -43,8 +39,9 @@ use crate::{ /// Local convenience function to return a copy of `S` by reinterpreting the bytes starting at /// `offset` in `slice`. fn frombytes_at<S: FromBytes + Sized>(slice: &[u8], offset: usize) -> Result<S> { + let end = offset.checked_add(size_of::<S>()).ok_or(EINVAL)?; slice - .get(offset..offset + size_of::<S>()) + .get(offset..end) .and_then(S::from_bytes_copy) .ok_or(EINVAL) } @@ -119,14 +116,21 @@ impl<'a> HsFirmwareV2<'a> { Some(sig_size) => { let patch_sig = frombytes_at::<u32>(self.fw, self.hdr.patch_sig_offset.into_safe_cast())?; - let signatures_start = usize::from_safe_cast(self.hdr.sig_prod_offset + patch_sig); + + let signatures_start = self + .hdr + .sig_prod_offset + .checked_add(patch_sig) + .map(usize::from_safe_cast) + .ok_or(EINVAL)?; + + let signatures_end = signatures_start + .checked_add(usize::from_safe_cast(self.hdr.sig_prod_size)) + .ok_or(EINVAL)?; self.fw // Get signatures range. - .get( - signatures_start - ..signatures_start + usize::from_safe_cast(self.hdr.sig_prod_size), - ) + .get(signatures_start..signatures_end) .ok_or(EINVAL)? .chunks_exact(sig_size.into_safe_cast()) } @@ -252,21 +256,24 @@ impl<'a> FirmwareSignature<BooterFirmware> for BooterSignature<'a> {} /// The `Booter` loader firmware, responsible for loading the GSP. pub(crate) struct BooterFirmware { // Load parameters for Secure `IMEM` falcon memory. - imem_sec_load_target: FalconLoadTarget, + imem_sec_load_target: FalconDmaLoadTarget, // Load parameters for Non-Secure `IMEM` falcon memory, // used only on Turing and GA100 - imem_ns_load_target: Option<FalconLoadTarget>, + imem_ns_load_target: Option<FalconDmaLoadTarget>, // Load parameters for `DMEM` falcon memory. - dmem_load_target: FalconLoadTarget, + dmem_load_target: FalconDmaLoadTarget, // BROM falcon parameters. brom_params: FalconBromParams, // Device-mapped firmware image. - ucode: FirmwareDmaObject<Self, Signed>, + ucode: FirmwareObject<Self, Signed>, } -impl FirmwareDmaObject<BooterFirmware, Unsigned> { - fn new_booter(dev: &device::Device<device::Bound>, data: &[u8]) -> Result<Self> { - DmaObject::from_data(dev, data).map(|ucode| Self(ucode, PhantomData)) +impl FirmwareObject<BooterFirmware, Unsigned> { + fn new_booter(data: &[u8]) -> Result<Self> { + let mut ucode = KVVec::new(); + ucode.extend_from_slice(data, GFP_KERNEL)?; + + Ok(Self(ucode, PhantomData)) } } @@ -320,7 +327,7 @@ impl BooterFirmware { let ucode = bin_fw .data() .ok_or(EINVAL) - .and_then(|data| FirmwareDmaObject::<Self, _>::new_booter(dev, data))?; + .and_then(FirmwareObject::<Self, _>::new_booter)?; let ucode_signed = { let mut signatures = hs_fw.signatures_iter()?.peekable(); @@ -363,7 +370,7 @@ impl BooterFirmware { let (imem_sec_dst_start, imem_ns_load_target) = if chipset <= Chipset::GA100 { ( app0.offset, - Some(FalconLoadTarget { + Some(FalconDmaLoadTarget { src_start: 0, dst_start: load_hdr.os_code_offset, len: load_hdr.os_code_size, @@ -374,13 +381,13 @@ impl BooterFirmware { }; Ok(Self { - imem_sec_load_target: FalconLoadTarget { + imem_sec_load_target: FalconDmaLoadTarget { src_start: app0.offset, dst_start: imem_sec_dst_start, len: app0.len, }, imem_ns_load_target, - dmem_load_target: FalconLoadTarget { + dmem_load_target: FalconDmaLoadTarget { src_start: load_hdr.os_data_offset, dst_start: 0, len: load_hdr.os_data_size, @@ -391,18 +398,26 @@ impl BooterFirmware { } } -impl FalconLoadParams for BooterFirmware { - fn imem_sec_load_params(&self) -> FalconLoadTarget { +impl FalconDmaLoadable for BooterFirmware { + fn as_slice(&self) -> &[u8] { + self.ucode.0.as_slice() + } + + fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { self.imem_sec_load_target.clone() } - fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> { + fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> { self.imem_ns_load_target.clone() } - fn dmem_load_params(&self) -> FalconLoadTarget { + fn dmem_load_params(&self) -> FalconDmaLoadTarget { self.dmem_load_target.clone() } +} + +impl FalconFirmware for BooterFirmware { + type Target = Sec2; fn brom_params(&self) -> FalconBromParams { self.brom_params.clone() @@ -416,15 +431,3 @@ impl FalconLoadParams for BooterFirmware { } } } - -impl Deref for BooterFirmware { - type Target = DmaObject; - - fn deref(&self) -> &Self::Target { - &self.ucode.0 - } -} - -impl FalconFirmware for BooterFirmware { - type Target = Sec2; -} diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs index bfb7b06b13d1..8810cb49db67 100644 --- a/drivers/gpu/nova-core/firmware/fwsec.rs +++ b/drivers/gpu/nova-core/firmware/fwsec.rs @@ -10,10 +10,9 @@ //! - The command to be run, as this firmware can perform several tasks ; //! - The ucode signature, so the GSP falcon can run FWSEC in HS mode. -use core::{ - marker::PhantomData, - ops::Deref, // -}; +pub(crate) mod bootloader; + +use core::marker::PhantomData; use kernel::{ device::{ @@ -28,27 +27,23 @@ use kernel::{ }; use crate::{ - dma::DmaObject, driver::Bar0, falcon::{ gsp::Gsp, Falcon, FalconBromParams, - FalconFirmware, - FalconLoadParams, - FalconLoadTarget, // + FalconDmaLoadTarget, + FalconDmaLoadable, + FalconFirmware, // }, firmware::{ FalconUCodeDesc, - FirmwareDmaObject, + FirmwareObject, FirmwareSignature, Signed, Unsigned, // }, - num::{ - FromSafeCast, - IntoSafeCast, // - }, + num::FromSafeCast, vbios::Vbios, }; @@ -177,63 +172,36 @@ impl AsRef<[u8]> for Bcrt30Rsa3kSignature { impl FirmwareSignature<FwsecFirmware> for Bcrt30Rsa3kSignature {} -/// Reinterpret the area starting from `offset` in `fw` as an instance of `T` (which must implement -/// [`FromBytes`]) and return a reference to it. -/// -/// # Safety -/// -/// * Callers must ensure that the device does not read/write to/from memory while the returned -/// reference is live. -/// * Callers must ensure that this call does not race with a write to the same region while -/// the returned reference is live. -unsafe fn transmute<T: Sized + FromBytes>(fw: &DmaObject, offset: usize) -> Result<&T> { - // SAFETY: The safety requirements of the function guarantee the device won't read - // or write to memory while the reference is alive and that this call won't race - // with writes to the same memory region. - T::from_bytes(unsafe { fw.as_slice(offset, size_of::<T>())? }).ok_or(EINVAL) -} - -/// Reinterpret the area starting from `offset` in `fw` as a mutable instance of `T` (which must -/// implement [`FromBytes`]) and return a reference to it. -/// -/// # Safety -/// -/// * Callers must ensure that the device does not read/write to/from memory while the returned -/// slice is live. -/// * Callers must ensure that this call does not race with a read or write to the same region -/// while the returned slice is live. -unsafe fn transmute_mut<T: Sized + FromBytes + AsBytes>( - fw: &mut DmaObject, - offset: usize, -) -> Result<&mut T> { - // SAFETY: The safety requirements of the function guarantee the device won't read - // or write to memory while the reference is alive and that this call won't race - // with writes or reads to the same memory region. - T::from_bytes_mut(unsafe { fw.as_slice_mut(offset, size_of::<T>())? }).ok_or(EINVAL) -} - /// The FWSEC microcode, extracted from the BIOS and to be run on the GSP falcon. /// /// It is responsible for e.g. carving out the WPR2 region as the first step of the GSP bootflow. pub(crate) struct FwsecFirmware { /// Descriptor of the firmware. desc: FalconUCodeDesc, - /// GPU-accessible DMA object containing the firmware. - ucode: FirmwareDmaObject<Self, Signed>, + /// Object containing the firmware binary. + ucode: FirmwareObject<Self, Signed>, } -impl FalconLoadParams for FwsecFirmware { - fn imem_sec_load_params(&self) -> FalconLoadTarget { +impl FalconDmaLoadable for FwsecFirmware { + fn as_slice(&self) -> &[u8] { + self.ucode.0.as_slice() + } + + fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { self.desc.imem_sec_load_params() } - fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> { + fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> { self.desc.imem_ns_load_params() } - fn dmem_load_params(&self) -> FalconLoadTarget { + fn dmem_load_params(&self) -> FalconDmaLoadTarget { self.desc.dmem_load_params() } +} + +impl FalconFirmware for FwsecFirmware { + type Target = Gsp; fn brom_params(&self) -> FalconBromParams { FalconBromParams { @@ -248,27 +216,23 @@ impl FalconLoadParams for FwsecFirmware { } } -impl Deref for FwsecFirmware { - type Target = DmaObject; - - fn deref(&self) -> &Self::Target { - &self.ucode.0 - } -} - -impl FalconFirmware for FwsecFirmware { - type Target = Gsp; -} - -impl FirmwareDmaObject<FwsecFirmware, Unsigned> { - fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Result<Self> { +impl FirmwareObject<FwsecFirmware, Unsigned> { + fn new_fwsec(bios: &Vbios, cmd: FwsecCommand) -> Result<Self> { let desc = bios.fwsec_image().header()?; - let ucode = bios.fwsec_image().ucode(&desc)?; - let mut dma_object = DmaObject::from_data(dev, ucode)?; + let mut ucode = KVVec::new(); + ucode.extend_from_slice(bios.fwsec_image().ucode(&desc)?, GFP_KERNEL)?; - let hdr_offset = usize::from_safe_cast(desc.imem_load_size() + desc.interface_offset()); - // SAFETY: we have exclusive access to `dma_object`. - let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?; + let hdr_offset = desc + .imem_load_size() + .checked_add(desc.interface_offset()) + .map(usize::from_safe_cast) + .ok_or(EINVAL)?; + + let hdr = ucode + .get(hdr_offset..) + .and_then(FalconAppifHdrV1::from_bytes_prefix) + .ok_or(EINVAL)? + .0; if hdr.version != 1 { return Err(EINVAL); @@ -276,26 +240,34 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> { // Find the DMEM mapper section in the firmware. for i in 0..usize::from(hdr.entry_count) { - // SAFETY: we have exclusive access to `dma_object`. - let app: &FalconAppifV1 = unsafe { - transmute( - &dma_object, - hdr_offset + usize::from(hdr.header_size) + i * usize::from(hdr.entry_size), - ) - }?; + // CALC: hdr_offset + header_size + i * entry_size. + let entry_offset = hdr_offset + .checked_add(usize::from(hdr.header_size)) + .and_then(|o| o.checked_add(i.checked_mul(usize::from(hdr.entry_size))?)) + .ok_or(EINVAL)?; + + let app = ucode + .get(entry_offset..) + .and_then(FalconAppifV1::from_bytes_prefix) + .ok_or(EINVAL)? + .0; if app.id != NVFW_FALCON_APPIF_ID_DMEMMAPPER { continue; } let dmem_base = app.dmem_base; - // SAFETY: we have exclusive access to `dma_object`. - let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe { - transmute_mut( - &mut dma_object, - (desc.imem_load_size() + dmem_base).into_safe_cast(), - ) - }?; + let dmem_mapper_offset = desc + .imem_load_size() + .checked_add(dmem_base) + .map(usize::from_safe_cast) + .ok_or(EINVAL)?; + + let dmem_mapper = ucode + .get_mut(dmem_mapper_offset..) + .and_then(FalconAppifDmemmapperV3::from_bytes_mut_prefix) + .ok_or(EINVAL)? + .0; dmem_mapper.init_cmd = match cmd { FwsecCommand::Frts { .. } => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS, @@ -303,13 +275,17 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> { }; let cmd_in_buffer_offset = dmem_mapper.cmd_in_buffer_offset; - // SAFETY: we have exclusive access to `dma_object`. - let frts_cmd: &mut FrtsCmd = unsafe { - transmute_mut( - &mut dma_object, - (desc.imem_load_size() + cmd_in_buffer_offset).into_safe_cast(), - ) - }?; + let frts_cmd_offset = desc + .imem_load_size() + .checked_add(cmd_in_buffer_offset) + .map(usize::from_safe_cast) + .ok_or(EINVAL)?; + + let frts_cmd = ucode + .get_mut(frts_cmd_offset..) + .and_then(FrtsCmd::from_bytes_mut_prefix) + .ok_or(EINVAL)? + .0; frts_cmd.read_vbios = ReadVbios { ver: 1, @@ -333,7 +309,7 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> { } // Return early as we found and patched the DMEMMAPPER region. - return Ok(Self(dma_object, PhantomData)); + return Ok(Self(ucode, PhantomData)); } Err(ENOTSUPP) @@ -350,13 +326,16 @@ impl FwsecFirmware { bios: &Vbios, cmd: FwsecCommand, ) -> Result<Self> { - let ucode_dma = FirmwareDmaObject::<Self, _>::new_fwsec(dev, bios, cmd)?; + let ucode_dma = FirmwareObject::<Self, _>::new_fwsec(bios, cmd)?; // Patch signature if needed. let desc = bios.fwsec_image().header()?; let ucode_signed = if desc.signature_count() != 0 { - let sig_base_img = - usize::from_safe_cast(desc.imem_load_size() + desc.pkc_data_offset()); + let sig_base_img = desc + .imem_load_size() + .checked_add(desc.pkc_data_offset()) + .map(usize::from_safe_cast) + .ok_or(EINVAL)?; let desc_sig_versions = u32::from(desc.signature_versions()); let reg_fuse_version = falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?; @@ -408,6 +387,10 @@ impl FwsecFirmware { } /// Loads the FWSEC firmware into `falcon` and execute it. + /// + /// This must only be called on chipsets that do not need the FWSEC bootloader (i.e., where + /// [`Chipset::needs_fwsec_bootloader()`](crate::gpu::Chipset::needs_fwsec_bootloader) returns + /// `false`). On chipsets that do, use [`bootloader::FwsecFirmwareWithBl`] instead. pub(crate) fn run( &self, dev: &Device<device::Bound>, @@ -419,7 +402,7 @@ impl FwsecFirmware { .reset(bar) .inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?; falcon - .load(bar, self) + .load(dev, bar, self) .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?; let (mbox0, _) = falcon .boot(bar, Some(0), None) diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs new file mode 100644 index 000000000000..bcb713a868e2 --- /dev/null +++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Bootloader support for the FWSEC firmware. +//! +//! On Turing, the FWSEC firmware is not loaded directly, but is instead loaded through a small +//! bootloader program that performs the required DMA operations. This bootloader itself needs to +//! be loaded using PIO. + +use kernel::{ + alloc::KVec, + device::{ + self, + Device, // + }, + dma::Coherent, + io::{ + register::WithBase, // + Io, + }, + prelude::*, + ptr::{ + Alignable, + Alignment, // + }, + sizes, + transmute::{ + AsBytes, + FromBytes, // + }, +}; + +use crate::{ + driver::Bar0, + falcon::{ + self, + gsp::Gsp, + Falcon, + FalconBromParams, + FalconDmaLoadable, + FalconFbifMemType, + FalconFbifTarget, + FalconFirmware, + FalconPioDmemLoadTarget, + FalconPioImemLoadTarget, + FalconPioLoadable, // + }, + firmware::{ + fwsec::FwsecFirmware, + request_firmware, + BinHdr, + FIRMWARE_VERSION, // + }, + gpu::Chipset, + num::FromSafeCast, + regs, +}; + +/// Descriptor used by RM to figure out the requirements of the boot loader. +/// +/// Most of its fields appear to be legacy and carry incorrect values, so they are left unused. +#[repr(C)] +#[derive(Debug, Clone)] +struct BootloaderDesc { + /// Starting tag of bootloader. + start_tag: u32, + /// DMEM load offset - unused here as we always load at offset `0`. + _dmem_load_off: u32, + /// Offset of code section in the image. Unused as there is only one section in the bootloader + /// binary. + _code_off: u32, + /// Size of code section in the image. + code_size: u32, + /// Offset of data section in the image. Unused as we build the data section ourselves. + _data_off: u32, + /// Size of data section in the image. Unused as we build the data section ourselves. + _data_size: u32, +} +// SAFETY: any byte sequence is valid for this struct. +unsafe impl FromBytes for BootloaderDesc {} + +/// Structure used by the boot-loader to load the rest of the code. +/// +/// This has to be filled by the GPU driver and copied into DMEM at offset +/// [`BootloaderDesc.dmem_load_off`]. +#[repr(C, packed)] +#[derive(Debug, Clone)] +struct BootloaderDmemDescV2 { + /// Reserved, should always be first element. + reserved: [u32; 4], + /// 16B signature for secure code, 0s if no secure code. + signature: [u32; 4], + /// DMA context used by the bootloader while loading code/data. + ctx_dma: u32, + /// 256B-aligned physical FB address where code is located. + code_dma_base: u64, + /// Offset from `code_dma_base` where the non-secure code is located. + /// + /// Also used as destination IMEM offset of non-secure code as the DMA firmware object is + /// expected to be a mirror image of its loaded state. + /// + /// Must be multiple of 256. + non_sec_code_off: u32, + /// Size of the non-secure code part. + non_sec_code_size: u32, + /// Offset from `code_dma_base` where the secure code is located (must be multiple of 256). + /// + /// Also used as destination IMEM offset of secure code as the DMA firmware object is expected + /// to be a mirror image of its loaded state. + /// + /// Must be multiple of 256. + sec_code_off: u32, + /// Size of the secure code part. + sec_code_size: u32, + /// Code entry point invoked by the bootloader after code is loaded. + code_entry_point: u32, + /// 256B-aligned physical FB address where data is located. + data_dma_base: u64, + /// Size of data block (should be multiple of 256B). + data_size: u32, + /// Number of arguments to be passed to the target firmware being loaded. + argc: u32, + /// Arguments to be passed to the target firmware being loaded. + argv: u32, +} +// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability. +unsafe impl AsBytes for BootloaderDmemDescV2 {} + +/// Wrapper for [`FwsecFirmware`] that includes the bootloader performing the actual load +/// operation. +pub(crate) struct FwsecFirmwareWithBl { + /// DMA object the bootloader will copy the firmware from. + _firmware_dma: Coherent<[u8]>, + /// Code of the bootloader to be loaded into non-secure IMEM. + ucode: KVec<u8>, + /// Descriptor to be loaded into DMEM for the bootloader to read. + dmem_desc: BootloaderDmemDescV2, + /// Range-validated start offset of the firmware code in IMEM. + imem_dst_start: u16, + /// BROM parameters of the loaded firmware. + brom_params: FalconBromParams, + /// Range-validated `desc.start_tag`. + start_tag: u16, +} + +impl FwsecFirmwareWithBl { + /// Loads the bootloader firmware for `dev` and `chipset`, and wrap `firmware` so it can be + /// loaded using it. + pub(crate) fn new( + firmware: FwsecFirmware, + dev: &Device<device::Bound>, + chipset: Chipset, + ) -> Result<Self> { + let fw = request_firmware(dev, chipset, "gen_bootloader", FIRMWARE_VERSION)?; + let hdr = fw + .data() + .get(0..size_of::<BinHdr>()) + .and_then(BinHdr::from_bytes_copy) + .ok_or(EINVAL)?; + + let desc = { + let desc_offset = usize::from_safe_cast(hdr.header_offset); + + fw.data() + .get(desc_offset..) + .and_then(BootloaderDesc::from_bytes_copy_prefix) + .ok_or(EINVAL)? + .0 + }; + + let ucode = { + let ucode_start = usize::from_safe_cast(hdr.data_offset); + let code_size = usize::from_safe_cast(desc.code_size); + // Align to falcon block size (256 bytes). + let aligned_code_size = code_size + .align_up(Alignment::new::<{ falcon::MEM_BLOCK_ALIGNMENT }>()) + .ok_or(EINVAL)?; + + let mut ucode = KVec::with_capacity(aligned_code_size, GFP_KERNEL)?; + ucode.extend_from_slice( + fw.data() + .get(ucode_start..ucode_start + code_size) + .ok_or(EINVAL)?, + GFP_KERNEL, + )?; + ucode.resize(aligned_code_size, 0, GFP_KERNEL)?; + + ucode + }; + + // `BootloaderDmemDescV2` expects the source to be a mirror image of the destination and + // uses the same offset parameter for both. + // + // Thus, the start of the source object needs to be padded with the difference between the + // destination and source offsets. + // + // In practice, this is expected to always be zero but is required for code correctness. + let (align_padding, firmware_dma) = { + let align_padding = { + let imem_sec = firmware.imem_sec_load_params(); + + imem_sec + .dst_start + .checked_sub(imem_sec.src_start) + .map(usize::from_safe_cast) + .ok_or(EOVERFLOW)? + }; + + let mut firmware_obj = KVVec::new(); + firmware_obj.extend_with(align_padding, 0u8, GFP_KERNEL)?; + firmware_obj.extend_from_slice(firmware.ucode.0.as_slice(), GFP_KERNEL)?; + + ( + align_padding, + Coherent::from_slice(dev, firmware_obj.as_slice(), GFP_KERNEL)?, + ) + }; + + let dmem_desc = { + // Bootloader payload is in non-coherent system memory. + const FALCON_DMAIDX_PHYS_SYS_NCOH: u32 = 4; + + let imem_sec = firmware.imem_sec_load_params(); + let imem_ns = firmware.imem_ns_load_params().ok_or(EINVAL)?; + let dmem = firmware.dmem_load_params(); + + // The bootloader does not have a data destination offset field and copies the data at + // the start of DMEM, so it can only be used if the destination offset of the firmware + // is 0. + if dmem.dst_start != 0 { + return Err(EINVAL); + } + + BootloaderDmemDescV2 { + reserved: [0; 4], + signature: [0; 4], + ctx_dma: FALCON_DMAIDX_PHYS_SYS_NCOH, + code_dma_base: firmware_dma.dma_handle(), + // `dst_start` is also valid as the source offset since the firmware DMA object is + // a mirror image of the target IMEM layout. + non_sec_code_off: imem_ns.dst_start, + non_sec_code_size: imem_ns.len, + // `dst_start` is also valid as the source offset since the firmware DMA object is + // a mirror image of the target IMEM layout. + sec_code_off: imem_sec.dst_start, + sec_code_size: imem_sec.len, + code_entry_point: 0, + // Start of data section is the added padding + the DMEM `src_start` field. + data_dma_base: firmware_dma + .dma_handle() + .checked_add(u64::from_safe_cast(align_padding)) + .and_then(|offset| offset.checked_add(dmem.src_start.into())) + .ok_or(EOVERFLOW)?, + data_size: dmem.len, + argc: 0, + argv: 0, + } + }; + + // The bootloader's code must be loaded in the area right below the first 64K of IMEM. + const BOOTLOADER_LOAD_CEILING: usize = sizes::SZ_64K; + let imem_dst_start = BOOTLOADER_LOAD_CEILING + .checked_sub(ucode.len()) + .ok_or(EOVERFLOW)?; + + Ok(Self { + _firmware_dma: firmware_dma, + ucode, + dmem_desc, + brom_params: firmware.brom_params(), + imem_dst_start: u16::try_from(imem_dst_start)?, + start_tag: u16::try_from(desc.start_tag)?, + }) + } + + /// Loads the bootloader into `falcon` and execute it. + /// + /// The bootloader will load the FWSEC firmware and then execute it. This function returns + /// after FWSEC has reached completion. + pub(crate) fn run( + &self, + dev: &Device<device::Bound>, + falcon: &Falcon<Gsp>, + bar: &Bar0, + ) -> Result<()> { + // Reset falcon, load the firmware, and run it. + falcon + .reset(bar) + .inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?; + falcon + .pio_load(bar, self) + .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?; + + // Configure DMA index for the bootloader to fetch the FWSEC firmware from system memory. + bar.update( + regs::NV_PFALCON_FBIF_TRANSCFG::of::<Gsp>() + .try_at(usize::from_safe_cast(self.dmem_desc.ctx_dma)) + .ok_or(EINVAL)?, + |v| { + v.with_target(FalconFbifTarget::CoherentSysmem) + .with_mem_type(FalconFbifMemType::Physical) + }, + ); + + let (mbox0, _) = falcon + .boot(bar, Some(0), None) + .inspect_err(|e| dev_err!(dev, "Failed to boot FWSEC firmware: {:?}\n", e))?; + if mbox0 != 0 { + dev_err!(dev, "FWSEC firmware returned error {}\n", mbox0); + Err(EIO) + } else { + Ok(()) + } + } +} + +impl FalconFirmware for FwsecFirmwareWithBl { + type Target = Gsp; + + fn brom_params(&self) -> FalconBromParams { + self.brom_params.clone() + } + + fn boot_addr(&self) -> u32 { + // On V2 platforms, the boot address is extracted from the generic bootloader, because the + // gbl is what actually copies FWSEC into memory, so that is what needs to be booted. + u32::from(self.start_tag) << 8 + } +} + +impl FalconPioLoadable for FwsecFirmwareWithBl { + fn imem_sec_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> { + None + } + + fn imem_ns_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> { + Some(FalconPioImemLoadTarget { + data: self.ucode.as_ref(), + dst_start: self.imem_dst_start, + secure: false, + start_tag: self.start_tag, + }) + } + + fn dmem_load_params(&self) -> FalconPioDmemLoadTarget<'_> { + FalconPioDmemLoadTarget { + data: self.dmem_desc.as_bytes(), + dst_start: 0, + } + } +} diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index 9488a626352f..2fcc255c3bc8 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -3,10 +3,11 @@ use kernel::{ device, dma::{ + Coherent, + CoherentBox, DataDirection, DmaAddress, // }, - kvec, prelude::*, scatterlist::{ Owned, @@ -15,8 +16,10 @@ use kernel::{ }; use crate::{ - dma::DmaObject, - firmware::riscv::RiscvFirmware, + firmware::{ + elf, + riscv::RiscvFirmware, // + }, gpu::{ Architecture, Chipset, // @@ -25,92 +28,6 @@ use crate::{ num::FromSafeCast, }; -/// Ad-hoc and temporary module to extract sections from ELF images. -/// -/// Some firmware images are currently packaged as ELF files, where sections names are used as keys -/// to specific and related bits of data. Future firmware versions are scheduled to move away from -/// that scheme before nova-core becomes stable, which means this module will eventually be -/// removed. -mod elf { - use kernel::{ - bindings, - prelude::*, - transmute::FromBytes, // - }; - - /// Newtype to provide a [`FromBytes`] implementation. - #[repr(transparent)] - struct Elf64Hdr(bindings::elf64_hdr); - // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. - unsafe impl FromBytes for Elf64Hdr {} - - #[repr(transparent)] - struct Elf64SHdr(bindings::elf64_shdr); - // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. - unsafe impl FromBytes for Elf64SHdr {} - - /// Tries to extract section with name `name` from the ELF64 image `elf`, and returns it. - pub(super) fn elf64_section<'a, 'b>(elf: &'a [u8], name: &'b str) -> Option<&'a [u8]> { - let hdr = &elf - .get(0..size_of::<bindings::elf64_hdr>()) - .and_then(Elf64Hdr::from_bytes)? - .0; - - // Get all the section headers. - let mut shdr = { - let shdr_num = usize::from(hdr.e_shnum); - let shdr_start = usize::try_from(hdr.e_shoff).ok()?; - let shdr_end = shdr_num - .checked_mul(size_of::<Elf64SHdr>()) - .and_then(|v| v.checked_add(shdr_start))?; - - elf.get(shdr_start..shdr_end) - .map(|slice| slice.chunks_exact(size_of::<Elf64SHdr>()))? - }; - - // Get the strings table. - let strhdr = shdr - .clone() - .nth(usize::from(hdr.e_shstrndx)) - .and_then(Elf64SHdr::from_bytes)?; - - // Find the section which name matches `name` and return it. - shdr.find(|&sh| { - let Some(hdr) = Elf64SHdr::from_bytes(sh) else { - return false; - }; - - let Some(name_idx) = strhdr - .0 - .sh_offset - .checked_add(u64::from(hdr.0.sh_name)) - .and_then(|idx| usize::try_from(idx).ok()) - else { - return false; - }; - - // Get the start of the name. - elf.get(name_idx..) - .and_then(|nstr| CStr::from_bytes_until_nul(nstr).ok()) - // Convert into str. - .and_then(|c_str| c_str.to_str().ok()) - // Check that the name matches. - .map(|str| str == name) - .unwrap_or(false) - }) - // Return the slice containing the section. - .and_then(|sh| { - let hdr = Elf64SHdr::from_bytes(sh)?; - let start = usize::try_from(hdr.0.sh_offset).ok()?; - let end = usize::try_from(hdr.0.sh_size) - .ok() - .and_then(|sh_size| start.checked_add(sh_size))?; - - elf.get(start..end) - }) - } -} - /// GSP firmware with 3-level radix page tables for the GSP bootloader. /// /// The bootloader expects firmware to be mapped starting at address 0 in GSP's virtual address @@ -136,11 +53,11 @@ pub(crate) struct GspFirmware { #[pin] level1: SGTable<Owned<VVec<u8>>>, /// Level 0 page table (single 4KB page) with one entry: DMA address of first level 1 page. - level0: DmaObject, + level0: Coherent<[u64]>, /// Size in bytes of the firmware contained in [`Self::fw`]. pub(crate) size: usize, /// Device-mapped GSP signatures matching the GPU's [`Chipset`]. - pub(crate) signatures: DmaObject, + pub(crate) signatures: Coherent<[u8]>, /// GSP bootloader, verifies the GSP firmware before loading and running it. pub(crate) bootloader: RiscvFirmware, } @@ -197,17 +114,20 @@ impl GspFirmware { // Allocate the level 0 page table as a device-visible DMA object, and map the // level 1 page table onto it. - // Level 0 page table data. - let mut level0_data = kvec![0u8; GSP_PAGE_SIZE]?; - // Fill level 1 page entry. let level1_entry = level1.iter().next().ok_or(EINVAL)?; let level1_entry_addr = level1_entry.dma_address(); - let dst = &mut level0_data[..size_of_val(&level1_entry_addr)]; - dst.copy_from_slice(&level1_entry_addr.to_le_bytes()); - // Turn the level0 page table into a [`DmaObject`]. - DmaObject::from_data(dev, &level0_data)? + // Create level 0 page table data and fill its first entry with the level 1 + // table. + let mut level0 = CoherentBox::<[u64]>::zeroed_slice( + dev, + GSP_PAGE_SIZE / size_of::<u64>(), + GFP_KERNEL + )?; + level0[0] = level1_entry_addr.to_le(); + + level0.into() }, size, signatures: { @@ -226,7 +146,7 @@ impl GspFirmware { elf::elf64_section(firmware.data(), sigs_section) .ok_or(EINVAL) - .and_then(|data| DmaObject::from_data(dev, data))? + .and_then(|data| Coherent::from_slice(dev, data, GFP_KERNEL))? }, bootloader: { let bl = super::request_firmware(dev, chipset, "bootloader", ver)?; diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs index 4bdd89bd0757..2afa7f36404e 100644 --- a/drivers/gpu/nova-core/firmware/riscv.rs +++ b/drivers/gpu/nova-core/firmware/riscv.rs @@ -5,13 +5,13 @@ use kernel::{ device, + dma::Coherent, firmware::Firmware, prelude::*, transmute::FromBytes, // }; use crate::{ - dma::DmaObject, firmware::BinFirmware, num::FromSafeCast, // }; @@ -45,10 +45,11 @@ impl RmRiscvUCodeDesc { /// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image. fn new(bin_fw: &BinFirmware<'_>) -> Result<Self> { let offset = usize::from_safe_cast(bin_fw.hdr.header_offset); + let end = offset.checked_add(size_of::<Self>()).ok_or(EINVAL)?; bin_fw .fw - .get(offset..offset + size_of::<Self>()) + .get(offset..end) .and_then(Self::from_bytes_copy) .ok_or(EINVAL) } @@ -65,7 +66,7 @@ pub(crate) struct RiscvFirmware { /// Application version. pub(crate) app_version: u32, /// Device-mapped firmware image. - pub(crate) ucode: DmaObject, + pub(crate) ucode: Coherent<[u8]>, } impl RiscvFirmware { @@ -78,8 +79,9 @@ impl RiscvFirmware { let ucode = { let start = usize::from_safe_cast(bin_fw.hdr.data_offset); let len = usize::from_safe_cast(bin_fw.hdr.data_size); + let end = start.checked_add(len).ok_or(EINVAL)?; - DmaObject::from_data(dev, fw.data().get(start..start + len).ok_or(EINVAL)?)? + Coherent::from_slice(dev, fw.data().get(start..end).ok_or(EINVAL)?, GFP_KERNEL)? }; Ok(Self { diff --git a/drivers/gpu/nova-core/gfw.rs b/drivers/gpu/nova-core/gfw.rs index 9121f400046d..fb75dd10a172 100644 --- a/drivers/gpu/nova-core/gfw.rs +++ b/drivers/gpu/nova-core/gfw.rs @@ -19,7 +19,10 @@ //! Note that the devinit sequence also needs to run during suspend/resume. use kernel::{ - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + Io, // + }, prelude::*, time::Delta, // }; @@ -58,9 +61,11 @@ pub(crate) fn wait_gfw_boot_completion(bar: &Bar0) -> Result { Ok( // Check that FWSEC has lowered its protection level before reading the GFW_BOOT // status. - regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK::read(bar) + bar.read(regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK) .read_protection_level0() - && regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT::read(bar).completed(), + && bar + .read(regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT) + .completed(), ) }, |&gfw_booted| gfw_booted, diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 9b042ef1a308..0f6fe9a1b955 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -4,12 +4,15 @@ use kernel::{ device, devres::Devres, fmt, + io::Io, + num::Bounded, pci, prelude::*, sync::Arc, // }; use crate::{ + bounded_enum, driver::Bar0, falcon::{ gsp::Gsp as GspFalcon, @@ -92,7 +95,7 @@ define_chipset!({ }); impl Chipset { - pub(crate) fn arch(&self) -> Architecture { + pub(crate) const fn arch(self) -> Architecture { match self { Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => { Architecture::Turing @@ -105,6 +108,13 @@ impl Chipset { } } } + + /// Returns `true` if this chipset requires the PIO-loaded bootloader in order to boot FWSEC. + /// + /// This includes all chipsets < GA102. + pub(crate) const fn needs_fwsec_bootloader(self) -> bool { + matches!(self.arch(), Architecture::Turing) || matches!(self, Self::GA100) + } } // TODO @@ -121,50 +131,26 @@ impl fmt::Display for Chipset { } } -/// Enum representation of the GPU generation. -/// -/// TODO: remove the `Default` trait implementation, and the `#[default]` -/// attribute, once the register!() macro (which creates Architecture items) no -/// longer requires it for read-only fields. -#[derive(fmt::Debug, Default, Copy, Clone)] -#[repr(u8)] -pub(crate) enum Architecture { - #[default] - Turing = 0x16, - Ampere = 0x17, - Ada = 0x19, -} - -impl TryFrom<u8> for Architecture { - type Error = Error; - - fn try_from(value: u8) -> Result<Self> { - match value { - 0x16 => Ok(Self::Turing), - 0x17 => Ok(Self::Ampere), - 0x19 => Ok(Self::Ada), - _ => Err(ENODEV), - } - } -} - -impl From<Architecture> for u8 { - fn from(value: Architecture) -> Self { - // CAST: `Architecture` is `repr(u8)`, so this cast is always lossless. - value as u8 +bounded_enum! { + /// Enum representation of the GPU generation. + #[derive(fmt::Debug, Copy, Clone)] + pub(crate) enum Architecture with TryFrom<Bounded<u32, 6>> { + Turing = 0x16, + Ampere = 0x17, + Ada = 0x19, } } pub(crate) struct Revision { - major: u8, - minor: u8, + major: Bounded<u8, 4>, + minor: Bounded<u8, 4>, } impl From<regs::NV_PMC_BOOT_42> for Revision { fn from(boot0: regs::NV_PMC_BOOT_42) -> Self { Self { - major: boot0.major_revision(), - minor: boot0.minor_revision(), + major: boot0.major_revision().cast(), + minor: boot0.minor_revision().cast(), } } } @@ -201,13 +187,13 @@ impl Spec { // from an earlier (pre-Fermi) era, and then using boot42 to precisely identify the GPU. // Somewhere in the Rubin timeframe, boot0 will no longer have space to add new GPU IDs. - let boot0 = regs::NV_PMC_BOOT_0::read(bar); + let boot0 = bar.read(regs::NV_PMC_BOOT_0); if boot0.is_older_than_fermi() { return Err(ENODEV); } - let boot42 = regs::NV_PMC_BOOT_42::read(bar); + let boot42 = bar.read(regs::NV_PMC_BOOT_42); Spec::try_from(boot42).inspect_err(|_| { dev_err!(dev, "Unsupported chipset: {}\n", boot42); }) @@ -262,13 +248,13 @@ impl Gpu { ) -> impl PinInit<Self, Error> + 'a { try_pin_init!(Self { spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| { - dev_info!(pdev.as_ref(),"NVIDIA ({})\n", spec); + dev_info!(pdev,"NVIDIA ({})\n", spec); })?, // We must wait for GFW_BOOT completion before doing any significant setup on the GPU. _: { gfw::wait_gfw_boot_completion(bar) - .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete\n"))?; + .inspect_err(|_| dev_err!(pdev, "GFW boot did not complete\n"))?; }, sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?, diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 174feaca0a6b..ba5b7f990031 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -3,15 +3,19 @@ mod boot; use kernel::{ + debugfs, device, dma::{ - CoherentAllocation, + Coherent, + CoherentBox, DmaAddress, // }, - dma_write, pci, prelude::*, - transmute::AsBytes, // + transmute::{ + AsBytes, + FromBytes, // + }, // }; pub(crate) mod cmdq; @@ -38,25 +42,25 @@ pub(crate) const GSP_PAGE_SIZE: usize = 1 << GSP_PAGE_SHIFT; /// Number of GSP pages to use in a RM log buffer. const RM_LOG_BUFFER_NUM_PAGES: usize = 0x10; +const LOG_BUFFER_SIZE: usize = RM_LOG_BUFFER_NUM_PAGES * GSP_PAGE_SIZE; /// Array of page table entries, as understood by the GSP bootloader. #[repr(C)] struct PteArray<const NUM_ENTRIES: usize>([u64; NUM_ENTRIES]); +/// SAFETY: arrays of `u64` implement `FromBytes` and we are but a wrapper around one. +unsafe impl<const NUM_ENTRIES: usize> FromBytes for PteArray<NUM_ENTRIES> {} + /// SAFETY: arrays of `u64` implement `AsBytes` and we are but a wrapper around one. unsafe impl<const NUM_ENTRIES: usize> AsBytes for PteArray<NUM_ENTRIES> {} impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> { - /// Creates a new page table array mapping `NUM_PAGES` GSP pages starting at address `start`. - fn new(start: DmaAddress) -> Result<Self> { - let mut ptes = [0u64; NUM_PAGES]; - for (i, pte) in ptes.iter_mut().enumerate() { - *pte = start - .checked_add(num::usize_as_u64(i) << GSP_PAGE_SHIFT) - .ok_or(EOVERFLOW)?; - } - - Ok(Self(ptes)) + /// Returns the page table entry for `index`, for a mapping starting at `start`. + // TODO: Replace with `IoView` projection once available. + fn entry(start: DmaAddress, index: usize) -> Result<u64> { + start + .checked_add(num::usize_as_u64(index) << GSP_PAGE_SHIFT) + .ok_or(EOVERFLOW) } } @@ -74,47 +78,53 @@ impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> { /// then pp points to index into the buffer where the next logging entry will /// be written. Therefore, the logging data is valid if: /// 1 <= pp < sizeof(buffer)/sizeof(u64) -struct LogBuffer(CoherentAllocation<u8>); +struct LogBuffer(Coherent<[u8; LOG_BUFFER_SIZE]>); impl LogBuffer { /// Creates a new `LogBuffer` mapped on `dev`. fn new(dev: &device::Device<device::Bound>) -> Result<Self> { - const NUM_PAGES: usize = RM_LOG_BUFFER_NUM_PAGES; + let obj = Self(Coherent::zeroed(dev, GFP_KERNEL)?); - let mut obj = Self(CoherentAllocation::<u8>::alloc_coherent( - dev, - NUM_PAGES * GSP_PAGE_SIZE, - GFP_KERNEL | __GFP_ZERO, - )?); - let ptes = PteArray::<NUM_PAGES>::new(obj.0.dma_handle())?; + let start_addr = obj.0.dma_handle(); // SAFETY: `obj` has just been created and we are its sole user. - unsafe { - // Copy the self-mapping PTE at the expected location. - obj.0 - .as_slice_mut(size_of::<u64>(), size_of_val(&ptes))? - .copy_from_slice(ptes.as_bytes()) + let pte_region = unsafe { + &mut obj.0.as_mut()[size_of::<u64>()..][..RM_LOG_BUFFER_NUM_PAGES * size_of::<u64>()] }; + // Write values one by one to avoid an on-stack instance of `PteArray`. + for (i, chunk) in pte_region.chunks_exact_mut(size_of::<u64>()).enumerate() { + let pte_value = PteArray::<0>::entry(start_addr, i)?; + + chunk.copy_from_slice(&pte_value.to_ne_bytes()); + } + Ok(obj) } } -/// GSP runtime data. -#[pin_data] -pub(crate) struct Gsp { - /// Libos arguments. - pub(crate) libos: CoherentAllocation<LibosMemoryRegionInitArgument>, +struct LogBuffers { /// Init log buffer. loginit: LogBuffer, /// Interrupts log buffer. logintr: LogBuffer, /// RM log buffer. logrm: LogBuffer, +} + +/// GSP runtime data. +#[pin_data] +pub(crate) struct Gsp { + /// Libos arguments. + pub(crate) libos: Coherent<[LibosMemoryRegionInitArgument]>, + /// Log buffers, optionally exposed via debugfs. + #[pin] + logs: debugfs::Scope<LogBuffers>, /// Command queue. + #[pin] pub(crate) cmdq: Cmdq, /// RM arguments. - rmargs: CoherentAllocation<GspArgumentsPadded>, + rmargs: Coherent<GspArgumentsPadded>, } impl Gsp { @@ -123,34 +133,52 @@ impl Gsp { pin_init::pin_init_scope(move || { let dev = pdev.as_ref(); + let loginit = LogBuffer::new(dev)?; + let logintr = LogBuffer::new(dev)?; + let logrm = LogBuffer::new(dev)?; + + // Initialise the logging structures. The OpenRM equivalents are in: + // _kgspInitLibosLoggingStructures (allocates memory for buffers) + // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array) Ok(try_pin_init!(Self { - libos: CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent( - dev, - GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(), - GFP_KERNEL | __GFP_ZERO, - )?, - loginit: LogBuffer::new(dev)?, - logintr: LogBuffer::new(dev)?, - logrm: LogBuffer::new(dev)?, - cmdq: Cmdq::new(dev)?, - rmargs: CoherentAllocation::<GspArgumentsPadded>::alloc_coherent( - dev, - 1, - GFP_KERNEL | __GFP_ZERO, - )?, - _: { - // Initialise the logging structures. The OpenRM equivalents are in: - // _kgspInitLibosLoggingStructures (allocates memory for buffers) - // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array) - dma_write!( - libos[0] = LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0) - )?; - dma_write!( - libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0) + cmdq <- Cmdq::new(dev), + rmargs: Coherent::init(dev, GFP_KERNEL, GspArgumentsPadded::new(&cmdq))?, + libos: { + let mut libos = CoherentBox::zeroed_slice( + dev, + GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(), + GFP_KERNEL, )?; - dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?; - dma_write!(rmargs[0].inner = fw::GspArgumentsCached::new(cmdq))?; - dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", rmargs))?; + + libos.init_at(0, LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0))?; + libos.init_at(1, LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0))?; + libos.init_at(2, LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?; + libos.init_at(3, LibosMemoryRegionInitArgument::new("RMARGS", rmargs))?; + + libos.into() + }, + logs <- { + let log_buffers = LogBuffers { + loginit, + logintr, + logrm, + }; + + #[allow(static_mut_refs)] + // SAFETY: `DEBUGFS_ROOT` is created before driver registration and cleared + // after driver unregistration, so no probe() can race with its modification. + // + // PANIC: `DEBUGFS_ROOT` cannot be `None` here. It is set before driver + // registration and cleared after driver unregistration, so it is always + // `Some` for the entire lifetime that probe() can be called. + let log_parent: &debugfs::Dir = unsafe { crate::DEBUGFS_ROOT.as_ref() } + .expect("DEBUGFS_ROOT not initialized"); + + log_parent.scope(log_buffers, dev.name(), |logs, dir| { + dir.read_binary_file(c"loginit", &logs.loginit.0); + dir.read_binary_file(c"logintr", &logs.logintr.0); + dir.read_binary_file(c"logrm", &logs.logrm.0); + }) }, })) }) diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index be427fe26a58..6f707b3d1a54 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -2,9 +2,9 @@ use kernel::{ device, - dma::CoherentAllocation, - dma_write, + dma::Coherent, io::poll::read_poll_timeout, + io::Io, pci, prelude::*, time::Delta, // @@ -24,6 +24,7 @@ use crate::{ BooterKind, // }, fwsec::{ + bootloader::FwsecFirmwareWithBl, FwsecCommand, FwsecFirmware, // }, @@ -48,6 +49,7 @@ impl super::Gsp { /// created the WPR2 region. fn run_fwsec_frts( dev: &device::Device<device::Bound>, + chipset: Chipset, falcon: &Falcon<Gsp>, bar: &Bar0, bios: &Vbios, @@ -55,7 +57,7 @@ impl super::Gsp { ) -> Result<()> { // Check that the WPR2 region does not already exists - if it does, we cannot run // FWSEC-FRTS until the GPU is reset. - if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 { + if bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI).higher_bound() != 0 { dev_err!( dev, "WPR2 region already exists - GPU needs to be reset to proceed\n" @@ -63,6 +65,7 @@ impl super::Gsp { return Err(EBUSY); } + // FWSEC-FRTS will create the WPR2 region. let fwsec_frts = FwsecFirmware::new( dev, falcon, @@ -70,15 +73,23 @@ impl super::Gsp { bios, FwsecCommand::Frts { frts_addr: fb_layout.frts.start, - frts_size: fb_layout.frts.end - fb_layout.frts.start, + frts_size: fb_layout.frts.len(), }, )?; - // Run FWSEC-FRTS to create the WPR2 region. - fwsec_frts.run(dev, falcon, bar)?; + if chipset.needs_fwsec_bootloader() { + let fwsec_frts_bl = FwsecFirmwareWithBl::new(fwsec_frts, dev, chipset)?; + // Load and run the bootloader, which will load FWSEC-FRTS and run it. + fwsec_frts_bl.run(dev, falcon, bar)?; + } else { + // Load and run FWSEC-FRTS directly. + fwsec_frts.run(dev, falcon, bar)?; + } // SCRATCH_E contains the error code for FWSEC-FRTS. - let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code(); + let frts_status = bar + .read(regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR) + .frts_err_code(); if frts_status != 0 { dev_err!( dev, @@ -91,8 +102,8 @@ impl super::Gsp { // Check that the WPR2 region has been created as we requested. let (wpr2_lo, wpr2_hi) = ( - regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(), - regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(), + bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO).lower_bound(), + bar.read(regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI).higher_bound(), ); match (wpr2_lo, wpr2_hi) { @@ -128,7 +139,7 @@ impl super::Gsp { /// /// Upon return, the GSP is up and running, and its runtime object given as return value. pub(crate) fn boot( - mut self: Pin<&mut Self>, + self: Pin<&mut Self>, pdev: &pci::Device<device::Bound>, bar: &Bar0, chipset: Chipset, @@ -144,7 +155,7 @@ impl super::Gsp { let fb_layout = FbLayout::new(chipset, bar, &gsp_fw)?; dev_dbg!(dev, "{:#x?}\n", fb_layout); - Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?; + Self::run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, &fb_layout)?; let booter_loader = BooterFirmware::new( dev, @@ -155,13 +166,12 @@ impl super::Gsp { bar, )?; - let wpr_meta = - CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?; - dma_write!(wpr_meta[0] = GspFwWprMeta::new(&gsp_fw, &fb_layout))?; + let wpr_meta = Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::new(&gsp_fw, &fb_layout))?; self.cmdq - .send_command(bar, commands::SetSystemInfo::new(pdev))?; - self.cmdq.send_command(bar, commands::SetRegistry::new())?; + .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev))?; + self.cmdq + .send_command_no_wait(bar, commands::SetRegistry::new())?; gsp_falcon.reset(bar)?; let libos_handle = self.libos.dma_handle(); @@ -170,39 +180,25 @@ impl super::Gsp { Some(libos_handle as u32), Some((libos_handle >> 32) as u32), )?; - dev_dbg!( - pdev.as_ref(), - "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", - mbox0, - mbox1 - ); + dev_dbg!(pdev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1); dev_dbg!( - pdev.as_ref(), + pdev, "Using SEC2 to load and run the booter_load firmware...\n" ); sec2_falcon.reset(bar)?; - sec2_falcon.load(bar, &booter_loader)?; + sec2_falcon.load(dev, bar, &booter_loader)?; let wpr_handle = wpr_meta.dma_handle(); let (mbox0, mbox1) = sec2_falcon.boot( bar, Some(wpr_handle as u32), Some((wpr_handle >> 32) as u32), )?; - dev_dbg!( - pdev.as_ref(), - "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", - mbox0, - mbox1 - ); + dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", mbox0, mbox1); if mbox0 != 0 { - dev_err!( - pdev.as_ref(), - "Booter-load failed with error {:#x}\n", - mbox0 - ); + dev_err!(pdev, "Booter-load failed with error {:#x}\n", mbox0); return Err(ENODEV); } @@ -216,11 +212,7 @@ impl super::Gsp { Delta::from_secs(5), )?; - dev_dbg!( - pdev.as_ref(), - "RISC-V active? {}\n", - gsp_falcon.is_riscv_active(bar), - ); + dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),); // Create and run the GSP sequencer. let seq_params = GspSequencerParams { @@ -231,16 +223,16 @@ impl super::Gsp { dev: pdev.as_ref().into(), bar, }; - GspSequencer::run(&mut self.cmdq, seq_params)?; + GspSequencer::run(&self.cmdq, seq_params)?; // Wait until GSP is fully initialized. - commands::wait_gsp_init_done(&mut self.cmdq)?; + commands::wait_gsp_init_done(&self.cmdq)?; // Obtain and display basic GPU information. - let info = commands::get_gsp_info(&mut self.cmdq, bar)?; + let info = commands::get_gsp_info(&self.cmdq, bar)?; match info.gpu_name() { - Ok(name) => dev_info!(pdev.as_ref(), "GPU name: {}\n", name), - Err(e) => dev_warn!(pdev.as_ref(), "GPU name unavailable: {:?}\n", e), + Ok(name) => dev_info!(pdev, "GPU name: {}\n", name), + Err(e) => dev_warn!(pdev, "GPU name unavailable: {:?}\n", e), } Ok(()) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs index 46819a82a51a..2224896ccc89 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -1,24 +1,26 @@ // SPDX-License-Identifier: GPL-2.0 -use core::{ - cmp, - mem, - sync::atomic::{ - fence, - Ordering, // - }, // -}; +mod continuation; + +use core::mem; use kernel::{ device, dma::{ - CoherentAllocation, + Coherent, DmaAddress, // }, dma_write, - io::poll::read_poll_timeout, + io::{ + poll::read_poll_timeout, + Io, // + }, + new_mutex, prelude::*, - sync::aref::ARef, + sync::{ + aref::ARef, + Mutex, // + }, time::Delta, transmute::{ AsBytes, @@ -26,6 +28,13 @@ use kernel::{ }, }; +use continuation::{ + ContinuationRecord, + SplitState, // +}; + +use pin_init::pin_init_scope; + use crate::{ driver::Bar0, gsp::{ @@ -33,7 +42,8 @@ use crate::{ GspMsgElement, MsgFunction, MsgqRxHeader, - MsgqTxHeader, // + MsgqTxHeader, + GSP_MSG_QUEUE_ELEMENT_SIZE_MAX, // }, PteArray, GSP_PAGE_SHIFT, @@ -44,10 +54,14 @@ use crate::{ sbuffer::SBufferIter, // }; +/// Marker type representing the absence of a reply for a command. Commands using this as their +/// reply type are sent using [`Cmdq::send_command_no_wait`]. +pub(crate) struct NoReply; + /// Trait implemented by types representing a command to send to the GSP. /// -/// The main purpose of this trait is to provide [`Cmdq::send_command`] with the information it -/// needs to send a given command. +/// The main purpose of this trait is to provide [`Cmdq`] with the information it needs to send +/// a given command. /// /// [`CommandToGsp::init`] in particular is responsible for initializing the command directly /// into the space reserved for it in the command queue buffer. @@ -62,6 +76,10 @@ pub(crate) trait CommandToGsp { /// Type generated by [`CommandToGsp::init`], to be written into the command queue buffer. type Command: FromBytes + AsBytes; + /// Type of the reply expected from the GSP, or [`NoReply`] for commands that don't + /// have a reply. + type Reply; + /// Error type returned by [`CommandToGsp::init`]. type InitError; @@ -94,6 +112,12 @@ pub(crate) trait CommandToGsp { ) -> Result { Ok(()) } + + /// Total size of the command (including its variable-length payload) without the + /// [`GspMsgElement`] header. + fn size(&self) -> usize { + size_of::<Self::Command>() + self.variable_payload_len() + } } /// Trait representing messages received from the GSP. @@ -146,30 +170,38 @@ static_assert!(align_of::<MsgqData>() == GSP_PAGE_SIZE); #[repr(C)] // There is no struct defined for this in the open-gpu-kernel-source headers. // Instead it is defined by code in `GspMsgQueuesInit()`. -struct Msgq { +// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module. +pub(super) struct Msgq { /// Header for sending messages, including the write pointer. - tx: MsgqTxHeader, + pub(super) tx: MsgqTxHeader, /// Header for receiving messages, including the read pointer. - rx: MsgqRxHeader, + pub(super) rx: MsgqRxHeader, /// The message queue proper. msgq: MsgqData, } /// Structure shared between the driver and the GSP and containing the command and message queues. #[repr(C)] -struct GspMem { +// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module. +pub(super) struct GspMem { /// Self-mapping page table entries. - ptes: PteArray<{ GSP_PAGE_SIZE / size_of::<u64>() }>, + ptes: PteArray<{ Self::PTE_ARRAY_SIZE }>, /// CPU queue: the driver writes commands here, and the GSP reads them. It also contains the - /// write and read pointers that the CPU updates. + /// write and read pointers that the CPU updates. This means that the read pointer here is an + /// index into the GSP queue. /// /// This member is read-only for the GSP. - cpuq: Msgq, + pub(super) cpuq: Msgq, /// GSP queue: the GSP writes messages here, and the driver reads them. It also contains the - /// write and read pointers that the GSP updates. + /// write and read pointers that the GSP updates. This means that the read pointer here is an + /// index into the CPU queue. /// /// This member is read-only for the driver. - gspq: Msgq, + pub(super) gspq: Msgq, +} + +impl GspMem { + const PTE_ARRAY_SIZE: usize = GSP_PAGE_SIZE / size_of::<u64>(); } // SAFETY: These structs don't meet the no-padding requirements of AsBytes but @@ -180,7 +212,7 @@ unsafe impl AsBytes for GspMem {} // that is not a problem because they are not used outside the kernel. unsafe impl FromBytes for GspMem {} -/// Wrapper around [`GspMem`] to share it with the GPU using a [`CoherentAllocation`]. +/// Wrapper around [`GspMem`] to share it with the GPU using a [`Coherent`]. /// /// This provides the low-level functionality to communicate with the GSP, including allocation of /// queue space to write messages to and management of read/write pointers. @@ -191,7 +223,7 @@ unsafe impl FromBytes for GspMem {} /// pointer and the GSP read pointer. This region is returned by [`Self::driver_write_area`]. /// * The driver owns (i.e. can read from) the part of the GSP message queue between the CPU read /// pointer and the GSP write pointer. This region is returned by [`Self::driver_read_area`]. -struct DmaGspMem(CoherentAllocation<GspMem>); +struct DmaGspMem(Coherent<GspMem>); impl DmaGspMem { /// Allocate a new instance and map it for `dev`. @@ -199,11 +231,20 @@ impl DmaGspMem { const MSGQ_SIZE: u32 = num::usize_into_u32::<{ size_of::<Msgq>() }>(); const RX_HDR_OFF: u32 = num::usize_into_u32::<{ mem::offset_of!(Msgq, rx) }>(); - let gsp_mem = - CoherentAllocation::<GspMem>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?; - dma_write!(gsp_mem[0].ptes = PteArray::new(gsp_mem.dma_handle())?)?; - dma_write!(gsp_mem[0].cpuq.tx = MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES))?; - dma_write!(gsp_mem[0].cpuq.rx = MsgqRxHeader::new())?; + let gsp_mem = Coherent::<GspMem>::zeroed(dev, GFP_KERNEL)?; + + let start = gsp_mem.dma_handle(); + // Write values one by one to avoid an on-stack instance of `PteArray`. + for i in 0..GspMem::PTE_ARRAY_SIZE { + dma_write!(gsp_mem, .ptes.0[i], PteArray::<0>::entry(start, i)?); + } + + dma_write!( + gsp_mem, + .cpuq.tx, + MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES) + ); + dma_write!(gsp_mem, .cpuq.rx, MsgqRxHeader::new()); Ok(Self(gsp_mem)) } @@ -218,31 +259,49 @@ impl DmaGspMem { let rx = self.gsp_read_ptr() as usize; // SAFETY: - // - The `CoherentAllocation` contains exactly one object. // - We will only access the driver-owned part of the shared memory. // - Per the safety statement of the function, no concurrent access will be performed. - let gsp_mem = &mut unsafe { self.0.as_slice_mut(0, 1) }.unwrap()[0]; - // PANIC: per the invariant of `cpu_write_ptr`, `tx` is `<= MSGQ_NUM_PAGES`. + let gsp_mem = unsafe { &mut *self.0.as_mut() }; + // PANIC: per the invariant of `cpu_write_ptr`, `tx` is `< MSGQ_NUM_PAGES`. let (before_tx, after_tx) = gsp_mem.cpuq.msgq.data.split_at_mut(tx); - if rx <= tx { - // The area from `tx` up to the end of the ring, and from the beginning of the ring up - // to `rx`, minus one unit, belongs to the driver. - if rx == 0 { - let last = after_tx.len() - 1; - (&mut after_tx[..last], &mut before_tx[0..0]) - } else { - (after_tx, &mut before_tx[..rx]) - } + // The area starting at `tx` and ending at `rx - 2` modulo MSGQ_NUM_PAGES, inclusive, + // belongs to the driver for writing. + + if rx == 0 { + // Since `rx` is zero, leave an empty slot at end of the buffer. + let last = after_tx.len() - 1; + (&mut after_tx[..last], &mut []) + } else if rx <= tx { + // The area is discontiguous and we leave an empty slot before `rx`. + // PANIC: + // - The index `rx - 1` is non-negative because `rx != 0` in this branch. + // - The index does not exceed `before_tx.len()` (which equals `tx`) because + // `rx <= tx` in this branch. + (after_tx, &mut before_tx[..(rx - 1)]) } else { - // The area from `tx` to `rx`, minus one unit, belongs to the driver. - // - // PANIC: per the invariants of `cpu_write_ptr` and `gsp_read_ptr`, `rx` and `tx` are - // `<= MSGQ_NUM_PAGES`, and the test above ensured that `rx > tx`. - (after_tx.split_at_mut(rx - tx).0, &mut before_tx[0..0]) + // The area is contiguous and we leave an empty slot before `rx`. + // PANIC: + // - The index `rx - tx - 1` is non-negative because `rx > tx` in this branch. + // - The index does not exceed `after_tx.len()` (which is `MSGQ_NUM_PAGES - tx`) + // because `rx < MSGQ_NUM_PAGES` by the `gsp_read_ptr` invariant. + (&mut after_tx[..(rx - tx - 1)], &mut []) } } + /// Returns the size of the region of the CPU message queue that the driver is currently allowed + /// to write to, in bytes. + fn driver_write_area_size(&self) -> usize { + let tx = self.cpu_write_ptr(); + let rx = self.gsp_read_ptr(); + + // `rx` and `tx` are both in `0..MSGQ_NUM_PAGES` per the invariants of `gsp_read_ptr` and + // `cpu_write_ptr`. The minimum value case is where `rx == 0` and `tx == MSGQ_NUM_PAGES - + // 1`, which gives `0 + MSGQ_NUM_PAGES - (MSGQ_NUM_PAGES - 1) - 1 == 0`. + let slots = (rx + MSGQ_NUM_PAGES - tx - 1) % MSGQ_NUM_PAGES; + num::u32_as_usize(slots) * GSP_PAGE_SIZE + } + /// Returns the region of the GSP message queue that the driver is currently allowed to read /// from. /// @@ -253,30 +312,46 @@ impl DmaGspMem { let rx = self.cpu_read_ptr() as usize; // SAFETY: - // - The `CoherentAllocation` contains exactly one object. // - We will only access the driver-owned part of the shared memory. // - Per the safety statement of the function, no concurrent access will be performed. - let gsp_mem = &unsafe { self.0.as_slice(0, 1) }.unwrap()[0]; - // PANIC: per the invariant of `cpu_read_ptr`, `xx` is `<= MSGQ_NUM_PAGES`. - let (before_rx, after_rx) = gsp_mem.gspq.msgq.data.split_at(rx); - - match tx.cmp(&rx) { - cmp::Ordering::Equal => (&after_rx[0..0], &after_rx[0..0]), - cmp::Ordering::Greater => (&after_rx[..tx], &before_rx[0..0]), - cmp::Ordering::Less => (after_rx, &before_rx[..tx]), + let gsp_mem = unsafe { &*self.0.as_ptr() }; + let data = &gsp_mem.gspq.msgq.data; + + // The area starting at `rx` and ending at `tx - 1` modulo MSGQ_NUM_PAGES, inclusive, + // belongs to the driver for reading. + // PANIC: + // - per the invariant of `cpu_read_ptr`, `rx < MSGQ_NUM_PAGES` + // - per the invariant of `gsp_write_ptr`, `tx < MSGQ_NUM_PAGES` + if rx <= tx { + // The area is contiguous. + (&data[rx..tx], &[]) + } else { + // The area is discontiguous. + (&data[rx..], &data[..tx]) } } /// Allocates a region on the command queue that is large enough to send a command of `size` - /// bytes. + /// bytes, waiting for space to become available based on the provided timeout. /// /// This returns a [`GspCommand`] ready to be written to by the caller. /// /// # Errors /// - /// - `EAGAIN` if the driver area is too small to hold the requested command. + /// - `EMSGSIZE` if the command is larger than [`GSP_MSG_QUEUE_ELEMENT_SIZE_MAX`]. + /// - `ETIMEDOUT` if space does not become available within the timeout. /// - `EIO` if the command header is not properly aligned. - fn allocate_command(&mut self, size: usize) -> Result<GspCommand<'_>> { + fn allocate_command(&mut self, size: usize, timeout: Delta) -> Result<GspCommand<'_>> { + if size_of::<GspMsgElement>() + size > GSP_MSG_QUEUE_ELEMENT_SIZE_MAX { + return Err(EMSGSIZE); + } + read_poll_timeout( + || Ok(self.driver_write_area_size()), + |available_bytes| *available_bytes >= size_of::<GspMsgElement>() + size, + Delta::from_micros(1), + timeout, + )?; + // Get the current writable area as an array of bytes. let (slice_1, slice_2) = { let (slice_1, slice_2) = self.driver_write_area(); @@ -285,13 +360,6 @@ impl DmaGspMem { (slice_1.as_flattened_mut(), slice_2.as_flattened_mut()) }; - // If the GSP is still processing previous messages the shared region - // may be full in which case we will have to retry once the GSP has - // processed the existing commands. - if size_of::<GspMsgElement>() + size > slice_1.len() + slice_2.len() { - return Err(EAGAIN); - } - // Extract area for the `GspMsgElement`. let (header, slice_1) = GspMsgElement::from_bytes_mut_prefix(slice_1).ok_or(EIO)?; @@ -315,85 +383,46 @@ impl DmaGspMem { // // # Invariants // - // - The returned value is between `0` and `MSGQ_NUM_PAGES`. + // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_write_ptr(&self) -> u32 { - let gsp_mem = self.0.start_ptr(); - - // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is valid. - (unsafe { (*gsp_mem).gspq.tx.write_ptr() } % MSGQ_NUM_PAGES) + super::fw::gsp_mem::gsp_write_ptr(&self.0) } // Returns the index of the memory page the GSP will read the next command from. // // # Invariants // - // - The returned value is between `0` and `MSGQ_NUM_PAGES`. + // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_read_ptr(&self) -> u32 { - let gsp_mem = self.0.start_ptr(); - - // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is valid. - (unsafe { (*gsp_mem).gspq.rx.read_ptr() } % MSGQ_NUM_PAGES) + super::fw::gsp_mem::gsp_read_ptr(&self.0) } // Returns the index of the memory page the CPU can read the next message from. // // # Invariants // - // - The returned value is between `0` and `MSGQ_NUM_PAGES`. + // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_read_ptr(&self) -> u32 { - let gsp_mem = self.0.start_ptr(); - - // SAFETY: - // - The ['CoherentAllocation'] contains at least one object. - // - By the invariants of CoherentAllocation the pointer is valid. - (unsafe { (*gsp_mem).cpuq.rx.read_ptr() } % MSGQ_NUM_PAGES) + super::fw::gsp_mem::cpu_read_ptr(&self.0) } // Informs the GSP that it can send `elem_count` new pages into the message queue. fn advance_cpu_read_ptr(&mut self, elem_count: u32) { - let rptr = self.cpu_read_ptr().wrapping_add(elem_count) % MSGQ_NUM_PAGES; - - // Ensure read pointer is properly ordered. - fence(Ordering::SeqCst); - - let gsp_mem = self.0.start_ptr_mut(); - - // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is valid. - unsafe { (*gsp_mem).cpuq.rx.set_read_ptr(rptr) }; + super::fw::gsp_mem::advance_cpu_read_ptr(&self.0, elem_count) } // Returns the index of the memory page the CPU can write the next command to. // // # Invariants // - // - The returned value is between `0` and `MSGQ_NUM_PAGES`. + // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_write_ptr(&self) -> u32 { - let gsp_mem = self.0.start_ptr(); - - // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is valid. - (unsafe { (*gsp_mem).cpuq.tx.write_ptr() } % MSGQ_NUM_PAGES) + super::fw::gsp_mem::cpu_write_ptr(&self.0) } // Informs the GSP that it can process `elem_count` new pages from the command queue. fn advance_cpu_write_ptr(&mut self, elem_count: u32) { - let wptr = self.cpu_write_ptr().wrapping_add(elem_count) & MSGQ_NUM_PAGES; - let gsp_mem = self.0.start_ptr_mut(); - - // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is valid. - unsafe { (*gsp_mem).cpuq.tx.set_write_ptr(wptr) }; - - // Ensure all command data is visible before triggering the GSP read. - fence(Ordering::SeqCst); + super::fw::gsp_mem::advance_cpu_write_ptr(&self.0, elem_count) } } @@ -423,13 +452,13 @@ struct GspMessage<'a> { /// /// Provides the ability to send commands and receive messages from the GSP using a shared memory /// area. +#[pin_data] pub(crate) struct Cmdq { - /// Device this command queue belongs to. - dev: ARef<device::Device>, - /// Current command sequence number. - seq: u32, - /// Memory area shared with the GSP for communicating commands and messages. - gsp_mem: DmaGspMem, + /// Inner mutex-protected state. + #[pin] + inner: Mutex<CmdqInner>, + /// DMA handle of the command queue's shared memory region. + pub(super) dma_handle: DmaAddress, } impl Cmdq { @@ -449,14 +478,22 @@ impl Cmdq { /// Number of page table entries for the GSP shared region. pub(crate) const NUM_PTES: usize = size_of::<GspMem>() >> GSP_PAGE_SHIFT; - /// Creates a new command queue for `dev`. - pub(crate) fn new(dev: &device::Device<device::Bound>) -> Result<Cmdq> { - let gsp_mem = DmaGspMem::new(dev)?; + /// Default timeout for receiving a message from the GSP. + pub(super) const RECEIVE_TIMEOUT: Delta = Delta::from_secs(5); - Ok(Cmdq { - dev: dev.into(), - seq: 0, - gsp_mem, + /// Creates a new command queue for `dev`. + pub(crate) fn new(dev: &device::Device<device::Bound>) -> impl PinInit<Self, Error> + '_ { + pin_init_scope(move || { + let gsp_mem = DmaGspMem::new(dev)?; + + Ok(try_pin_init!(Self { + dma_handle: gsp_mem.0.dma_handle(), + inner <- new_mutex!(CmdqInner { + dev: dev.into(), + gsp_mem, + seq: 0, + }), + })) }) } @@ -475,34 +512,115 @@ impl Cmdq { /// Notifies the GSP that we have updated the command queue pointers. fn notify_gsp(bar: &Bar0) { - regs::NV_PGSP_QUEUE_HEAD::default() - .set_address(0) - .write(bar); + bar.write_reg(regs::NV_PGSP_QUEUE_HEAD::zeroed().with_address(0u32)); } - /// Sends `command` to the GSP. + /// Sends `command` to the GSP and waits for the reply. + /// + /// Messages with non-matching function codes are silently consumed until the expected reply + /// arrives. + /// + /// The queue is locked for the entire send+receive cycle to ensure that no other command can + /// be interleaved. /// /// # Errors /// - /// - `EAGAIN` if there was not enough space in the command queue to send the command. + /// - `ETIMEDOUT` if space does not become available to send the command, or if the reply is + /// not received within the timeout. /// - `EIO` if the variable payload requested by the command has not been entirely /// written to by its [`CommandToGsp::init_variable_payload`] method. /// - /// Error codes returned by the command initializers are propagated as-is. - pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result + /// Error codes returned by the command and reply initializers are propagated as-is. + pub(crate) fn send_command<M>(&self, bar: &Bar0, command: M) -> Result<M::Reply> where M: CommandToGsp, + M::Reply: MessageFromGsp, + Error: From<M::InitError>, + Error: From<<M::Reply as MessageFromGsp>::InitError>, + { + let mut inner = self.inner.lock(); + inner.send_command(bar, command)?; + + loop { + match inner.receive_msg::<M::Reply>(Self::RECEIVE_TIMEOUT) { + Ok(reply) => break Ok(reply), + Err(ERANGE) => continue, + Err(e) => break Err(e), + } + } + } + + /// Sends `command` to the GSP without waiting for a reply. + /// + /// # Errors + /// + /// - `ETIMEDOUT` if space does not become available within the timeout. + /// - `EIO` if the variable payload requested by the command has not been entirely + /// written to by its [`CommandToGsp::init_variable_payload`] method. + /// + /// Error codes returned by the command initializers are propagated as-is. + pub(crate) fn send_command_no_wait<M>(&self, bar: &Bar0, command: M) -> Result + where + M: CommandToGsp<Reply = NoReply>, + Error: From<M::InitError>, + { + self.inner.lock().send_command(bar, command) + } + + /// Receive a message from the GSP. + /// + /// See [`CmdqInner::receive_msg`] for details. + pub(crate) fn receive_msg<M: MessageFromGsp>(&self, timeout: Delta) -> Result<M> + where // This allows all error types, including `Infallible`, to be used for `M::InitError`. Error: From<M::InitError>, { - let command_size = size_of::<M::Command>() + command.variable_payload_len(); - let dst = self.gsp_mem.allocate_command(command_size)?; + self.inner.lock().receive_msg(timeout) + } +} - // Extract area for the command itself. +/// Inner mutex protected state of [`Cmdq`]. +struct CmdqInner { + /// Device this command queue belongs to. + dev: ARef<device::Device>, + /// Current command sequence number. + seq: u32, + /// Memory area shared with the GSP for communicating commands and messages. + gsp_mem: DmaGspMem, +} + +impl CmdqInner { + /// Timeout for waiting for space on the command queue. + const ALLOCATE_TIMEOUT: Delta = Delta::from_secs(1); + + /// Sends `command` to the GSP, without splitting it. + /// + /// # Errors + /// + /// - `EMSGSIZE` if the command exceeds the maximum queue element size. + /// - `ETIMEDOUT` if space does not become available within the timeout. + /// - `EIO` if the variable payload requested by the command has not been entirely + /// written to by its [`CommandToGsp::init_variable_payload`] method. + /// + /// Error codes returned by the command initializers are propagated as-is. + fn send_single_command<M>(&mut self, bar: &Bar0, command: M) -> Result + where + M: CommandToGsp, + // This allows all error types, including `Infallible`, to be used for `M::InitError`. + Error: From<M::InitError>, + { + let size_in_bytes = command.size(); + let dst = self + .gsp_mem + .allocate_command(size_in_bytes, Self::ALLOCATE_TIMEOUT)?; + + // Extract area for the command itself. The GSP message header and the command header + // together are guaranteed to fit entirely into a single page, so it's ok to only look + // at `dst.contents.0` here. let (cmd, payload_1) = M::Command::from_bytes_mut_prefix(dst.contents.0).ok_or(EIO)?; // Fill the header and command in-place. - let msg_element = GspMsgElement::init(self.seq, command_size, M::FUNCTION); + let msg_element = GspMsgElement::init(self.seq, size_in_bytes, M::FUNCTION); // SAFETY: `msg_header` and `cmd` are valid references, and not touched if the initializer // fails. unsafe { @@ -510,16 +628,14 @@ impl Cmdq { command.init().__init(core::ptr::from_mut(cmd))?; } - // Fill the variable-length payload. - if command_size > size_of::<M::Command>() { - let mut sbuffer = - SBufferIter::new_writer([&mut payload_1[..], &mut dst.contents.1[..]]); - command.init_variable_payload(&mut sbuffer)?; + // Fill the variable-length payload, which may be empty. + let mut sbuffer = SBufferIter::new_writer([&mut payload_1[..], &mut dst.contents.1[..]]); + command.init_variable_payload(&mut sbuffer)?; - if !sbuffer.is_empty() { - return Err(EIO); - } + if !sbuffer.is_empty() { + return Err(EIO); } + drop(sbuffer); // Compute checksum now that the whole message is ready. dst.header @@ -531,7 +647,7 @@ impl Cmdq { dev_dbg!( &self.dev, - "GSP RPC: send: seq# {}, function={}, length=0x{:x}\n", + "GSP RPC: send: seq# {}, function={:?}, length=0x{:x}\n", self.seq, M::FUNCTION, dst.header.length(), @@ -546,6 +662,37 @@ impl Cmdq { Ok(()) } + /// Sends `command` to the GSP. + /// + /// The command may be split into multiple messages if it is large. + /// + /// # Errors + /// + /// - `ETIMEDOUT` if space does not become available within the timeout. + /// - `EIO` if the variable payload requested by the command has not been entirely + /// written to by its [`CommandToGsp::init_variable_payload`] method. + /// + /// Error codes returned by the command initializers are propagated as-is. + fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result + where + M: CommandToGsp, + Error: From<M::InitError>, + { + match SplitState::new(command)? { + SplitState::Single(command) => self.send_single_command(bar, command), + SplitState::Split(command, mut continuations) => { + self.send_single_command(bar, command)?; + + while let Some(continuation) = continuations.next() { + // Turbofish needed because the compiler cannot infer M here. + self.send_single_command::<ContinuationRecord<'_>>(bar, continuation)?; + } + + Ok(()) + } + } + } + /// Wait for a message to become available on the message queue. /// /// This works purely at the transport layer and does not interpret or validate the message @@ -581,7 +728,7 @@ impl Cmdq { let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?; dev_dbg!( - self.dev, + &self.dev, "GSP RPC: receive: seq# {}, function={:?}, length=0x{:x}\n", header.sequence(), header.function(), @@ -616,7 +763,7 @@ impl Cmdq { ])) != 0 { dev_err!( - self.dev, + &self.dev, "GSP RPC: receive: Call {} - bad checksum\n", header.sequence() ); @@ -631,23 +778,21 @@ impl Cmdq { /// Receive a message from the GSP. /// - /// `init` is a closure tasked with processing the message. It receives a reference to the - /// message in the message queue, and a [`SBufferIter`] pointing to its variable-length - /// payload, if any. - /// - /// The expected message is specified using the `M` generic parameter. If the pending message - /// is different, `EAGAIN` is returned and the unexpected message is dropped. + /// The expected message type is specified using the `M` generic parameter. If the pending + /// message has a different function code, `ERANGE` is returned and the message is consumed. /// - /// This design is by no means final, but it is simple and will let us go through GSP - /// initialization. + /// The read pointer is always advanced past the message, regardless of whether it matched. /// /// # Errors /// /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes available. /// - `EIO` if there was some inconsistency (e.g. message shorter than advertised) on the /// message queue. - /// - `EINVAL` if the function of the message was unrecognized. - pub(crate) fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M> + /// - `EINVAL` if the function code of the message was not recognized. + /// - `ERANGE` if the message had a recognized but non-matching function code. + /// + /// Error codes returned by [`MessageFromGsp::read`] are propagated as-is. + fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M> where // This allows all error types, including `Infallible`, to be used for `M::InitError`. Error: From<M::InitError>, @@ -661,7 +806,17 @@ impl Cmdq { let (cmd, contents_1) = M::Message::from_bytes_prefix(message.contents.0).ok_or(EIO)?; let mut sbuffer = SBufferIter::new_reader([contents_1, message.contents.1]); - M::read(cmd, &mut sbuffer).map_err(|e| e.into()) + M::read(cmd, &mut sbuffer) + .map_err(|e| e.into()) + .inspect(|_| { + if !sbuffer.is_empty() { + dev_warn!( + &self.dev, + "GSP message {:?} has unprocessed data\n", + function + ); + } + }) } else { Err(ERANGE) }; @@ -673,9 +828,4 @@ impl Cmdq { result } - - /// Returns the DMA handle of the command queue's shared memory region. - pub(crate) fn dma_handle(&self) -> DmaAddress { - self.gsp_mem.0.dma_handle() - } } diff --git a/drivers/gpu/nova-core/gsp/cmdq/continuation.rs b/drivers/gpu/nova-core/gsp/cmdq/continuation.rs new file mode 100644 index 000000000000..05e904f18097 --- /dev/null +++ b/drivers/gpu/nova-core/gsp/cmdq/continuation.rs @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Support for splitting large GSP commands across continuation records. + +use core::convert::Infallible; + +use kernel::prelude::*; + +use super::{ + CommandToGsp, + NoReply, // +}; + +use crate::{ + gsp::fw::{ + GspMsgElement, + MsgFunction, + GSP_MSG_QUEUE_ELEMENT_SIZE_MAX, // + }, + sbuffer::SBufferIter, +}; + +/// Maximum command size that fits in a single queue element. +const MAX_CMD_SIZE: usize = GSP_MSG_QUEUE_ELEMENT_SIZE_MAX - size_of::<GspMsgElement>(); + +/// Acts as an iterator over the continuation records for a split command. +pub(super) struct ContinuationRecords { + payload: KVVec<u8>, + offset: usize, +} + +impl ContinuationRecords { + /// Creates a new iterator over continuation records for the given payload. + fn new(payload: KVVec<u8>) -> Self { + Self { payload, offset: 0 } + } + + /// Returns the next continuation record, or [`None`] if there are no more. + pub(super) fn next(&mut self) -> Option<ContinuationRecord<'_>> { + let remaining = self.payload.len() - self.offset; + + if remaining > 0 { + let chunk_size = remaining.min(MAX_CMD_SIZE); + let record = + ContinuationRecord::new(&self.payload[self.offset..(self.offset + chunk_size)]); + self.offset += chunk_size; + Some(record) + } else { + None + } + } +} + +/// The [`ContinuationRecord`] command. +pub(super) struct ContinuationRecord<'a> { + data: &'a [u8], +} + +impl<'a> ContinuationRecord<'a> { + /// Creates a new [`ContinuationRecord`] command with the given data. + fn new(data: &'a [u8]) -> Self { + Self { data } + } +} + +impl<'a> CommandToGsp for ContinuationRecord<'a> { + const FUNCTION: MsgFunction = MsgFunction::ContinuationRecord; + type Command = (); + type Reply = NoReply; + type InitError = Infallible; + + fn init(&self) -> impl Init<Self::Command, Self::InitError> { + <()>::init_zeroed() + } + + fn variable_payload_len(&self) -> usize { + self.data.len() + } + + fn init_variable_payload( + &self, + dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>, + ) -> Result { + dst.write_all(self.data) + } +} + +/// Whether a command needs to be split across continuation records or not. +pub(super) enum SplitState<C: CommandToGsp> { + /// A command that fits in a single queue element. + Single(C), + /// A command split across continuation records. + Split(SplitCommand<C>, ContinuationRecords), +} + +impl<C: CommandToGsp> SplitState<C> { + /// Maximum variable payload size that fits in the first command alongside the command header. + const MAX_FIRST_PAYLOAD: usize = MAX_CMD_SIZE - size_of::<C::Command>(); + + /// Creates a new [`SplitState`] for the given command. + /// + /// If the command is too large, it will be split into a main command and some number of + /// continuation records. + pub(super) fn new(command: C) -> Result<Self> { + let payload_len = command.variable_payload_len(); + + if command.size() > MAX_CMD_SIZE { + let mut command_payload = + KVVec::<u8>::from_elem(0u8, payload_len.min(Self::MAX_FIRST_PAYLOAD), GFP_KERNEL)?; + let mut continuation_payload = + KVVec::<u8>::from_elem(0u8, payload_len - command_payload.len(), GFP_KERNEL)?; + let mut sbuffer = SBufferIter::new_writer([ + command_payload.as_mut_slice(), + continuation_payload.as_mut_slice(), + ]); + + command.init_variable_payload(&mut sbuffer)?; + if !sbuffer.is_empty() { + return Err(EIO); + } + drop(sbuffer); + + Ok(Self::Split( + SplitCommand::new(command, command_payload), + ContinuationRecords::new(continuation_payload), + )) + } else { + Ok(Self::Single(command)) + } + } +} + +/// A command that has been truncated to maximum accepted length of the command queue. +/// +/// The remainder of its payload is expected to be sent using [`ContinuationRecords`]. +pub(super) struct SplitCommand<C: CommandToGsp> { + command: C, + payload: KVVec<u8>, +} + +impl<C: CommandToGsp> SplitCommand<C> { + /// Creates a new [`SplitCommand`] wrapping `command` with the given truncated payload. + fn new(command: C, payload: KVVec<u8>) -> Self { + Self { command, payload } + } +} + +impl<C: CommandToGsp> CommandToGsp for SplitCommand<C> { + const FUNCTION: MsgFunction = C::FUNCTION; + type Command = C::Command; + type Reply = C::Reply; + type InitError = C::InitError; + + fn init(&self) -> impl Init<Self::Command, Self::InitError> { + self.command.init() + } + + fn variable_payload_len(&self) -> usize { + self.payload.len() + } + + fn init_variable_payload( + &self, + dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>, + ) -> Result { + dst.write_all(&self.payload) + } +} + +#[kunit_tests(nova_core_gsp_continuation)] +mod tests { + use super::*; + + use kernel::transmute::{ + AsBytes, + FromBytes, // + }; + + /// Non-zero-sized command header for testing. + #[repr(C)] + #[derive(Clone, Copy, Zeroable)] + struct TestHeader([u8; 64]); + + // SAFETY: `TestHeader` is a plain array of bytes for which all bit patterns are valid. + unsafe impl FromBytes for TestHeader {} + + // SAFETY: `TestHeader` is a plain array of bytes for which all bit patterns are valid. + unsafe impl AsBytes for TestHeader {} + + struct TestPayload { + data: KVVec<u8>, + } + + impl TestPayload { + fn generate_pattern(len: usize) -> Result<KVVec<u8>> { + let mut data = KVVec::with_capacity(len, GFP_KERNEL)?; + for i in 0..len { + // Mix in higher bits so the pattern does not repeat every 256 bytes. + data.push((i ^ (i >> 8)) as u8, GFP_KERNEL)?; + } + Ok(data) + } + + fn new(len: usize) -> Result<Self> { + Ok(Self { + data: Self::generate_pattern(len)?, + }) + } + } + + impl CommandToGsp for TestPayload { + const FUNCTION: MsgFunction = MsgFunction::Nop; + type Command = TestHeader; + type Reply = NoReply; + type InitError = Infallible; + + fn init(&self) -> impl Init<Self::Command, Self::InitError> { + TestHeader::init_zeroed() + } + + fn variable_payload_len(&self) -> usize { + self.data.len() + } + + fn init_variable_payload( + &self, + dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>, + ) -> Result { + dst.write_all(self.data.as_slice()) + } + } + + /// Maximum variable payload size that fits in the first command alongside the header. + const MAX_FIRST_PAYLOAD: usize = SplitState::<TestPayload>::MAX_FIRST_PAYLOAD; + + fn read_payload(cmd: impl CommandToGsp) -> Result<KVVec<u8>> { + let len = cmd.variable_payload_len(); + let mut buf = KVVec::from_elem(0u8, len, GFP_KERNEL)?; + let mut sbuf = SBufferIter::new_writer([buf.as_mut_slice(), &mut []]); + cmd.init_variable_payload(&mut sbuf)?; + drop(sbuf); + Ok(buf) + } + + struct SplitTest { + payload_size: usize, + num_continuations: usize, + } + + fn check_split(t: SplitTest) -> Result { + let payload = TestPayload::new(t.payload_size)?; + let mut num_continuations = 0; + + let buf = match SplitState::new(payload)? { + SplitState::Single(cmd) => read_payload(cmd)?, + SplitState::Split(cmd, mut continuations) => { + let mut buf = read_payload(cmd)?; + assert!(size_of::<TestHeader>() + buf.len() <= MAX_CMD_SIZE); + + while let Some(cont) = continuations.next() { + let payload = read_payload(cont)?; + assert!(payload.len() <= MAX_CMD_SIZE); + buf.extend_from_slice(&payload, GFP_KERNEL)?; + num_continuations += 1; + } + + buf + } + }; + + assert_eq!(num_continuations, t.num_continuations); + assert_eq!( + buf.as_slice(), + TestPayload::generate_pattern(t.payload_size)?.as_slice() + ); + Ok(()) + } + + #[test] + fn split_command() -> Result { + check_split(SplitTest { + payload_size: 0, + num_continuations: 0, + })?; + check_split(SplitTest { + payload_size: MAX_FIRST_PAYLOAD, + num_continuations: 0, + })?; + check_split(SplitTest { + payload_size: MAX_FIRST_PAYLOAD + 1, + num_continuations: 1, + })?; + check_split(SplitTest { + payload_size: MAX_FIRST_PAYLOAD + MAX_CMD_SIZE, + num_continuations: 1, + })?; + check_split(SplitTest { + payload_size: MAX_FIRST_PAYLOAD + MAX_CMD_SIZE + 1, + num_continuations: 2, + })?; + check_split(SplitTest { + payload_size: MAX_FIRST_PAYLOAD + MAX_CMD_SIZE * 3 + MAX_CMD_SIZE / 2, + num_continuations: 4, + })?; + Ok(()) + } +} diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs index 8f270eca33be..c89c7b57a751 100644 --- a/drivers/gpu/nova-core/gsp/commands.rs +++ b/drivers/gpu/nova-core/gsp/commands.rs @@ -11,7 +11,6 @@ use kernel::{ device, pci, prelude::*, - time::Delta, transmute::{ AsBytes, FromBytes, // @@ -24,7 +23,8 @@ use crate::{ cmdq::{ Cmdq, CommandToGsp, - MessageFromGsp, // + MessageFromGsp, + NoReply, // }, fw::{ commands::*, @@ -49,6 +49,7 @@ impl<'a> SetSystemInfo<'a> { impl<'a> CommandToGsp for SetSystemInfo<'a> { const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo; type Command = GspSetSystemInfo; + type Reply = NoReply; type InitError = Error; fn init(&self) -> impl Init<Self::Command, Self::InitError> { @@ -100,6 +101,7 @@ impl SetRegistry { impl CommandToGsp for SetRegistry { const FUNCTION: MsgFunction = MsgFunction::SetRegistry; type Command = PackedRegistryTable; + type Reply = NoReply; type InitError = Infallible; fn init(&self) -> impl Init<Self::Command, Self::InitError> { @@ -163,9 +165,9 @@ impl MessageFromGsp for GspInitDone { } /// Waits for GSP initialization to complete. -pub(crate) fn wait_gsp_init_done(cmdq: &mut Cmdq) -> Result { +pub(crate) fn wait_gsp_init_done(cmdq: &Cmdq) -> Result { loop { - match cmdq.receive_msg::<GspInitDone>(Delta::from_secs(10)) { + match cmdq.receive_msg::<GspInitDone>(Cmdq::RECEIVE_TIMEOUT) { Ok(_) => break Ok(()), Err(ERANGE) => continue, Err(e) => break Err(e), @@ -179,6 +181,7 @@ struct GetGspStaticInfo; impl CommandToGsp for GetGspStaticInfo { const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo; type Command = GspStaticConfigInfo; + type Reply = GetGspStaticInfoReply; type InitError = Infallible; fn init(&self) -> impl Init<Self::Command, Self::InitError> { @@ -231,14 +234,6 @@ impl GetGspStaticInfoReply { } /// Send the [`GetGspInfo`] command and awaits for its reply. -pub(crate) fn get_gsp_info(cmdq: &mut Cmdq, bar: &Bar0) -> Result<GetGspStaticInfoReply> { - cmdq.send_command(bar, GetGspStaticInfo)?; - - loop { - match cmdq.receive_msg::<GetGspStaticInfoReply>(Delta::from_secs(5)) { - Ok(info) => return Ok(info), - Err(ERANGE) => continue, - Err(e) => return Err(e), - } - } +pub(crate) fn get_gsp_info(cmdq: &Cmdq, bar: &Bar0) -> Result<GetGspStaticInfoReply> { + cmdq.send_command(bar, GetGspStaticInfo) } diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 83ff91614e36..0c8a74f0e8ac 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -9,12 +9,12 @@ use r570_144 as bindings; use core::ops::Range; use kernel::{ - dma::CoherentAllocation, - fmt, + dma::Coherent, prelude::*, ptr::{ Alignable, - Alignment, // + Alignment, + KnownSize, // }, sizes::{ SZ_128K, @@ -40,6 +40,63 @@ use crate::{ }, }; +// TODO: Replace with `IoView` projections once available. +pub(super) mod gsp_mem { + use core::sync::atomic::{ + fence, + Ordering, // + }; + + use kernel::{ + dma::Coherent, + dma_read, + dma_write, // + }; + + use crate::gsp::cmdq::{ + GspMem, + MSGQ_NUM_PAGES, // + }; + + pub(in crate::gsp) fn gsp_write_ptr(qs: &Coherent<GspMem>) -> u32 { + dma_read!(qs, .gspq.tx.0.writePtr) % MSGQ_NUM_PAGES + } + + pub(in crate::gsp) fn gsp_read_ptr(qs: &Coherent<GspMem>) -> u32 { + dma_read!(qs, .gspq.rx.0.readPtr) % MSGQ_NUM_PAGES + } + + pub(in crate::gsp) fn cpu_read_ptr(qs: &Coherent<GspMem>) -> u32 { + dma_read!(qs, .cpuq.rx.0.readPtr) % MSGQ_NUM_PAGES + } + + pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &Coherent<GspMem>, count: u32) { + let rptr = cpu_read_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES; + + // Ensure read pointer is properly ordered. + fence(Ordering::SeqCst); + + dma_write!(qs, .cpuq.rx.0.readPtr, rptr); + } + + pub(in crate::gsp) fn cpu_write_ptr(qs: &Coherent<GspMem>) -> u32 { + dma_read!(qs, .cpuq.tx.0.writePtr) % MSGQ_NUM_PAGES + } + + pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &Coherent<GspMem>, count: u32) { + let wptr = cpu_write_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES; + + dma_write!(qs, .cpuq.tx.0.writePtr, wptr); + + // Ensure all command data is visible before triggering the GSP read. + fence(Ordering::SeqCst); + } +} + +/// Maximum size of a single GSP message queue element in bytes. +pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize = + num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX); + /// Empty type to group methods related to heap parameters for running the GSP firmware. enum GspFwHeapParams {} @@ -132,7 +189,9 @@ impl LibosParams { /// Structure passed to the GSP bootloader, containing the framebuffer layout as well as the DMA /// addresses of the GSP bootloader and firmware. #[repr(transparent)] -pub(crate) struct GspFwWprMeta(bindings::GspFwWprMeta); +pub(crate) struct GspFwWprMeta { + inner: bindings::GspFwWprMeta, +} // SAFETY: Padding is explicit and does not contain uninitialized data. unsafe impl AsBytes for GspFwWprMeta {} @@ -145,10 +204,14 @@ type GspFwWprMetaBootResumeInfo = bindings::GspFwWprMeta__bindgen_ty_1; type GspFwWprMetaBootInfo = bindings::GspFwWprMeta__bindgen_ty_1__bindgen_ty_1; impl GspFwWprMeta { - /// Fill in and return a `GspFwWprMeta` suitable for booting `gsp_firmware` using the + /// Returns an initializer for a `GspFwWprMeta` suitable for booting `gsp_firmware` using the /// `fb_layout` layout. - pub(crate) fn new(gsp_firmware: &GspFirmware, fb_layout: &FbLayout) -> Self { - Self(bindings::GspFwWprMeta { + pub(crate) fn new<'a>( + gsp_firmware: &'a GspFirmware, + fb_layout: &'a FbLayout, + ) -> impl Init<Self> + 'a { + #[allow(non_snake_case)] + let init_inner = init!(bindings::GspFwWprMeta { // CAST: we want to store the bits of `GSP_FW_WPR_META_MAGIC` unmodified. magic: bindings::GSP_FW_WPR_META_MAGIC as u64, revision: u64::from(bindings::GSP_FW_WPR_META_REVISION), @@ -183,7 +246,11 @@ impl GspFwWprMeta { fbSize: fb_layout.fb.end - fb_layout.fb.start, vgaWorkspaceOffset: fb_layout.vga_workspace.start, vgaWorkspaceSize: fb_layout.vga_workspace.end - fb_layout.vga_workspace.start, - ..Default::default() + ..Zeroable::init_zeroed() + }); + + init!(GspFwWprMeta { + inner <- init_inner, }) } } @@ -192,111 +259,81 @@ impl GspFwWprMeta { #[repr(u32)] pub(crate) enum MsgFunction { // Common function codes - Nop = bindings::NV_VGPU_MSG_FUNCTION_NOP, - SetGuestSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO, - AllocRoot = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT, + AllocChannelDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA, + AllocCtxDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA, AllocDevice = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_DEVICE, AllocMemory = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_MEMORY, - AllocCtxDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA, - AllocChannelDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA, - MapMemory = bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY, - BindCtxDma = bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA, AllocObject = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_OBJECT, + AllocRoot = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT, + BindCtxDma = bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA, + ContinuationRecord = bindings::NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD, Free = bindings::NV_VGPU_MSG_FUNCTION_FREE, - Log = bindings::NV_VGPU_MSG_FUNCTION_LOG, GetGspStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO, - SetRegistry = bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY, - GspSetSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO, + GetStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO, GspInitPostObjGpu = bindings::NV_VGPU_MSG_FUNCTION_GSP_INIT_POST_OBJGPU, GspRmControl = bindings::NV_VGPU_MSG_FUNCTION_GSP_RM_CONTROL, - GetStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO, + GspSetSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO, + Log = bindings::NV_VGPU_MSG_FUNCTION_LOG, + MapMemory = bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY, + Nop = bindings::NV_VGPU_MSG_FUNCTION_NOP, + SetGuestSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO, + SetRegistry = bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY, // Event codes GspInitDone = bindings::NV_VGPU_MSG_EVENT_GSP_INIT_DONE, + GspLockdownNotice = bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE, + GspPostNoCat = bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD, GspRunCpuSequencer = bindings::NV_VGPU_MSG_EVENT_GSP_RUN_CPU_SEQUENCER, - PostEvent = bindings::NV_VGPU_MSG_EVENT_POST_EVENT, - RcTriggered = bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED, MmuFaultQueued = bindings::NV_VGPU_MSG_EVENT_MMU_FAULT_QUEUED, OsErrorLog = bindings::NV_VGPU_MSG_EVENT_OS_ERROR_LOG, - GspPostNoCat = bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD, - GspLockdownNotice = bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE, + PostEvent = bindings::NV_VGPU_MSG_EVENT_POST_EVENT, + RcTriggered = bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED, UcodeLibOsPrint = bindings::NV_VGPU_MSG_EVENT_UCODE_LIBOS_PRINT, } -impl fmt::Display for MsgFunction { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - // Common function codes - MsgFunction::Nop => write!(f, "NOP"), - MsgFunction::SetGuestSystemInfo => write!(f, "SET_GUEST_SYSTEM_INFO"), - MsgFunction::AllocRoot => write!(f, "ALLOC_ROOT"), - MsgFunction::AllocDevice => write!(f, "ALLOC_DEVICE"), - MsgFunction::AllocMemory => write!(f, "ALLOC_MEMORY"), - MsgFunction::AllocCtxDma => write!(f, "ALLOC_CTX_DMA"), - MsgFunction::AllocChannelDma => write!(f, "ALLOC_CHANNEL_DMA"), - MsgFunction::MapMemory => write!(f, "MAP_MEMORY"), - MsgFunction::BindCtxDma => write!(f, "BIND_CTX_DMA"), - MsgFunction::AllocObject => write!(f, "ALLOC_OBJECT"), - MsgFunction::Free => write!(f, "FREE"), - MsgFunction::Log => write!(f, "LOG"), - MsgFunction::GetGspStaticInfo => write!(f, "GET_GSP_STATIC_INFO"), - MsgFunction::SetRegistry => write!(f, "SET_REGISTRY"), - MsgFunction::GspSetSystemInfo => write!(f, "GSP_SET_SYSTEM_INFO"), - MsgFunction::GspInitPostObjGpu => write!(f, "GSP_INIT_POST_OBJGPU"), - MsgFunction::GspRmControl => write!(f, "GSP_RM_CONTROL"), - MsgFunction::GetStaticInfo => write!(f, "GET_STATIC_INFO"), - - // Event codes - MsgFunction::GspInitDone => write!(f, "INIT_DONE"), - MsgFunction::GspRunCpuSequencer => write!(f, "RUN_CPU_SEQUENCER"), - MsgFunction::PostEvent => write!(f, "POST_EVENT"), - MsgFunction::RcTriggered => write!(f, "RC_TRIGGERED"), - MsgFunction::MmuFaultQueued => write!(f, "MMU_FAULT_QUEUED"), - MsgFunction::OsErrorLog => write!(f, "OS_ERROR_LOG"), - MsgFunction::GspPostNoCat => write!(f, "NOCAT"), - MsgFunction::GspLockdownNotice => write!(f, "LOCKDOWN_NOTICE"), - MsgFunction::UcodeLibOsPrint => write!(f, "LIBOS_PRINT"), - } - } -} - impl TryFrom<u32> for MsgFunction { type Error = kernel::error::Error; fn try_from(value: u32) -> Result<MsgFunction> { match value { - bindings::NV_VGPU_MSG_FUNCTION_NOP => Ok(MsgFunction::Nop), - bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO => { - Ok(MsgFunction::SetGuestSystemInfo) - } - bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT => Ok(MsgFunction::AllocRoot), + // Common function codes + bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA => Ok(MsgFunction::AllocChannelDma), + bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA => Ok(MsgFunction::AllocCtxDma), bindings::NV_VGPU_MSG_FUNCTION_ALLOC_DEVICE => Ok(MsgFunction::AllocDevice), bindings::NV_VGPU_MSG_FUNCTION_ALLOC_MEMORY => Ok(MsgFunction::AllocMemory), - bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA => Ok(MsgFunction::AllocCtxDma), - bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA => Ok(MsgFunction::AllocChannelDma), - bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY => Ok(MsgFunction::MapMemory), - bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA => Ok(MsgFunction::BindCtxDma), bindings::NV_VGPU_MSG_FUNCTION_ALLOC_OBJECT => Ok(MsgFunction::AllocObject), + bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT => Ok(MsgFunction::AllocRoot), + bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA => Ok(MsgFunction::BindCtxDma), + bindings::NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD => { + Ok(MsgFunction::ContinuationRecord) + } bindings::NV_VGPU_MSG_FUNCTION_FREE => Ok(MsgFunction::Free), - bindings::NV_VGPU_MSG_FUNCTION_LOG => Ok(MsgFunction::Log), bindings::NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO => Ok(MsgFunction::GetGspStaticInfo), - bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY => Ok(MsgFunction::SetRegistry), - bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO => Ok(MsgFunction::GspSetSystemInfo), + bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO => Ok(MsgFunction::GetStaticInfo), bindings::NV_VGPU_MSG_FUNCTION_GSP_INIT_POST_OBJGPU => { Ok(MsgFunction::GspInitPostObjGpu) } bindings::NV_VGPU_MSG_FUNCTION_GSP_RM_CONTROL => Ok(MsgFunction::GspRmControl), - bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO => Ok(MsgFunction::GetStaticInfo), + bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO => Ok(MsgFunction::GspSetSystemInfo), + bindings::NV_VGPU_MSG_FUNCTION_LOG => Ok(MsgFunction::Log), + bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY => Ok(MsgFunction::MapMemory), + bindings::NV_VGPU_MSG_FUNCTION_NOP => Ok(MsgFunction::Nop), + bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO => { + Ok(MsgFunction::SetGuestSystemInfo) + } + bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY => Ok(MsgFunction::SetRegistry), + + // Event codes bindings::NV_VGPU_MSG_EVENT_GSP_INIT_DONE => Ok(MsgFunction::GspInitDone), + bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE => Ok(MsgFunction::GspLockdownNotice), + bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD => Ok(MsgFunction::GspPostNoCat), bindings::NV_VGPU_MSG_EVENT_GSP_RUN_CPU_SEQUENCER => { Ok(MsgFunction::GspRunCpuSequencer) } - bindings::NV_VGPU_MSG_EVENT_POST_EVENT => Ok(MsgFunction::PostEvent), - bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED => Ok(MsgFunction::RcTriggered), bindings::NV_VGPU_MSG_EVENT_MMU_FAULT_QUEUED => Ok(MsgFunction::MmuFaultQueued), bindings::NV_VGPU_MSG_EVENT_OS_ERROR_LOG => Ok(MsgFunction::OsErrorLog), - bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD => Ok(MsgFunction::GspPostNoCat), - bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE => Ok(MsgFunction::GspLockdownNotice), + bindings::NV_VGPU_MSG_EVENT_POST_EVENT => Ok(MsgFunction::PostEvent), + bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED => Ok(MsgFunction::RcTriggered), bindings::NV_VGPU_MSG_EVENT_UCODE_LIBOS_PRINT => Ok(MsgFunction::UcodeLibOsPrint), _ => Err(EINVAL), } @@ -330,22 +367,6 @@ pub(crate) enum SeqBufOpcode { RegWrite = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE, } -impl fmt::Display for SeqBufOpcode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SeqBufOpcode::CoreReset => write!(f, "CORE_RESET"), - SeqBufOpcode::CoreResume => write!(f, "CORE_RESUME"), - SeqBufOpcode::CoreStart => write!(f, "CORE_START"), - SeqBufOpcode::CoreWaitForHalt => write!(f, "CORE_WAIT_FOR_HALT"), - SeqBufOpcode::DelayUs => write!(f, "DELAY_US"), - SeqBufOpcode::RegModify => write!(f, "REG_MODIFY"), - SeqBufOpcode::RegPoll => write!(f, "REG_POLL"), - SeqBufOpcode::RegStore => write!(f, "REG_STORE"), - SeqBufOpcode::RegWrite => write!(f, "REG_WRITE"), - } - } -} - impl TryFrom<u32> for SeqBufOpcode { type Error = kernel::error::Error; @@ -384,7 +405,7 @@ impl From<SeqBufOpcode> for u32 { /// Wrapper for GSP sequencer register write payload. #[repr(transparent)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) struct RegWritePayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_WRITE); impl RegWritePayload { @@ -407,7 +428,7 @@ unsafe impl AsBytes for RegWritePayload {} /// Wrapper for GSP sequencer register modify payload. #[repr(transparent)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) struct RegModifyPayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY); impl RegModifyPayload { @@ -435,7 +456,7 @@ unsafe impl AsBytes for RegModifyPayload {} /// Wrapper for GSP sequencer register poll payload. #[repr(transparent)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) struct RegPollPayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_POLL); impl RegPollPayload { @@ -468,7 +489,7 @@ unsafe impl AsBytes for RegPollPayload {} /// Wrapper for GSP sequencer delay payload. #[repr(transparent)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) struct DelayUsPayload(bindings::GSP_SEQ_BUF_PAYLOAD_DELAY_US); impl DelayUsPayload { @@ -486,7 +507,7 @@ unsafe impl AsBytes for DelayUsPayload {} /// Wrapper for GSP sequencer register store payload. #[repr(transparent)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) struct RegStorePayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_STORE); impl RegStorePayload { @@ -526,13 +547,7 @@ impl SequencerBufferCmd { return Err(EINVAL); } // SAFETY: Opcode is verified to be `RegWrite`, so union contains valid `RegWritePayload`. - let payload_bytes = unsafe { - core::slice::from_raw_parts( - core::ptr::addr_of!(self.0.payload.regWrite).cast::<u8>(), - core::mem::size_of::<RegWritePayload>(), - ) - }; - Ok(*RegWritePayload::from_bytes(payload_bytes).ok_or(EINVAL)?) + Ok(RegWritePayload(unsafe { self.0.payload.regWrite })) } /// Returns the register modify payload by value. @@ -543,13 +558,7 @@ impl SequencerBufferCmd { return Err(EINVAL); } // SAFETY: Opcode is verified to be `RegModify`, so union contains valid `RegModifyPayload`. - let payload_bytes = unsafe { - core::slice::from_raw_parts( - core::ptr::addr_of!(self.0.payload.regModify).cast::<u8>(), - core::mem::size_of::<RegModifyPayload>(), - ) - }; - Ok(*RegModifyPayload::from_bytes(payload_bytes).ok_or(EINVAL)?) + Ok(RegModifyPayload(unsafe { self.0.payload.regModify })) } /// Returns the register poll payload by value. @@ -560,13 +569,7 @@ impl SequencerBufferCmd { return Err(EINVAL); } // SAFETY: Opcode is verified to be `RegPoll`, so union contains valid `RegPollPayload`. - let payload_bytes = unsafe { - core::slice::from_raw_parts( - core::ptr::addr_of!(self.0.payload.regPoll).cast::<u8>(), - core::mem::size_of::<RegPollPayload>(), - ) - }; - Ok(*RegPollPayload::from_bytes(payload_bytes).ok_or(EINVAL)?) + Ok(RegPollPayload(unsafe { self.0.payload.regPoll })) } /// Returns the delay payload by value. @@ -577,13 +580,7 @@ impl SequencerBufferCmd { return Err(EINVAL); } // SAFETY: Opcode is verified to be `DelayUs`, so union contains valid `DelayUsPayload`. - let payload_bytes = unsafe { - core::slice::from_raw_parts( - core::ptr::addr_of!(self.0.payload.delayUs).cast::<u8>(), - core::mem::size_of::<DelayUsPayload>(), - ) - }; - Ok(*DelayUsPayload::from_bytes(payload_bytes).ok_or(EINVAL)?) + Ok(DelayUsPayload(unsafe { self.0.payload.delayUs })) } /// Returns the register store payload by value. @@ -594,13 +591,7 @@ impl SequencerBufferCmd { return Err(EINVAL); } // SAFETY: Opcode is verified to be `RegStore`, so union contains valid `RegStorePayload`. - let payload_bytes = unsafe { - core::slice::from_raw_parts( - core::ptr::addr_of!(self.0.payload.regStore).cast::<u8>(), - core::mem::size_of::<RegStorePayload>(), - ) - }; - Ok(*RegStorePayload::from_bytes(payload_bytes).ok_or(EINVAL)?) + Ok(RegStorePayload(unsafe { self.0.payload.regStore })) } } @@ -642,7 +633,9 @@ unsafe impl AsBytes for RunCpuSequencer {} /// The memory allocated for the arguments must remain until the GSP sends the /// init_done RPC. #[repr(transparent)] -pub(crate) struct LibosMemoryRegionInitArgument(bindings::LibosMemoryRegionInitArgument); +pub(crate) struct LibosMemoryRegionInitArgument { + inner: bindings::LibosMemoryRegionInitArgument, +} // SAFETY: Padding is explicit and does not contain uninitialized data. unsafe impl AsBytes for LibosMemoryRegionInitArgument {} @@ -652,10 +645,10 @@ unsafe impl AsBytes for LibosMemoryRegionInitArgument {} unsafe impl FromBytes for LibosMemoryRegionInitArgument {} impl LibosMemoryRegionInitArgument { - pub(crate) fn new<A: AsBytes + FromBytes>( + pub(crate) fn new<'a, A: AsBytes + FromBytes + KnownSize + ?Sized>( name: &'static str, - obj: &CoherentAllocation<A>, - ) -> Self { + obj: &'a Coherent<A>, + ) -> impl Init<Self> + 'a { /// Generates the `ID8` identifier required for some GSP objects. fn id8(name: &str) -> u64 { let mut bytes = [0u8; core::mem::size_of::<u64>()]; @@ -667,7 +660,8 @@ impl LibosMemoryRegionInitArgument { u64::from_ne_bytes(bytes) } - Self(bindings::LibosMemoryRegionInitArgument { + #[allow(non_snake_case)] + let init_inner = init!(bindings::LibosMemoryRegionInitArgument { id8: id8(name), pa: obj.dma_handle(), size: num::usize_as_u64(obj.size()), @@ -677,7 +671,11 @@ impl LibosMemoryRegionInitArgument { loc: num::u32_into_u8::< { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM }, >(), - ..Default::default() + ..Zeroable::init_zeroed() + }); + + init!(LibosMemoryRegionInitArgument { + inner <- init_inner, }) } } @@ -708,22 +706,6 @@ impl MsgqTxHeader { entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(), }) } - - /// Returns the value of the write pointer for this queue. - pub(crate) fn write_ptr(&self) -> u32 { - let ptr = core::ptr::from_ref(&self.0.writePtr); - - // SAFETY: `ptr` is a valid pointer to a `u32`. - unsafe { ptr.read_volatile() } - } - - /// Sets the value of the write pointer for this queue. - pub(crate) fn set_write_ptr(&mut self, val: u32) { - let ptr = core::ptr::from_mut(&mut self.0.writePtr); - - // SAFETY: `ptr` is a valid pointer to a `u32`. - unsafe { ptr.write_volatile(val) } - } } // SAFETY: Padding is explicit and does not contain uninitialized data. @@ -739,22 +721,6 @@ impl MsgqRxHeader { pub(crate) fn new() -> Self { Self(Default::default()) } - - /// Returns the value of the read pointer for this queue. - pub(crate) fn read_ptr(&self) -> u32 { - let ptr = core::ptr::from_ref(&self.0.readPtr); - - // SAFETY: `ptr` is a valid pointer to a `u32`. - unsafe { ptr.read_volatile() } - } - - /// Sets the value of the read pointer for this queue. - pub(crate) fn set_read_ptr(&mut self, val: u32) { - let ptr = core::ptr::from_mut(&mut self.0.readPtr); - - // SAFETY: `ptr` is a valid pointer to a `u32`. - unsafe { ptr.write_volatile(val) } - } } // SAFETY: Padding is explicit and does not contain uninitialized data. @@ -888,15 +854,23 @@ unsafe impl FromBytes for GspMsgElement {} /// Arguments for GSP startup. #[repr(transparent)] -pub(crate) struct GspArgumentsCached(bindings::GSP_ARGUMENTS_CACHED); +#[derive(Zeroable)] +pub(crate) struct GspArgumentsCached { + inner: bindings::GSP_ARGUMENTS_CACHED, +} impl GspArgumentsCached { /// Creates the arguments for starting the GSP up using `cmdq` as its command queue. - pub(crate) fn new(cmdq: &Cmdq) -> Self { - Self(bindings::GSP_ARGUMENTS_CACHED { - messageQueueInitArguments: MessageQueueInitArguments::new(cmdq).0, + pub(crate) fn new(cmdq: &Cmdq) -> impl Init<Self> + '_ { + #[allow(non_snake_case)] + let init_inner = init!(bindings::GSP_ARGUMENTS_CACHED { + messageQueueInitArguments <- MessageQueueInitArguments::new(cmdq), bDmemStack: 1, - ..Default::default() + ..Zeroable::init_zeroed() + }); + + init!(GspArgumentsCached { + inner <- init_inner, }) } } @@ -908,11 +882,21 @@ unsafe impl AsBytes for GspArgumentsCached {} /// must all be a multiple of GSP_PAGE_SIZE in size, so add padding to force it /// to that size. #[repr(C)] +#[derive(Zeroable)] pub(crate) struct GspArgumentsPadded { pub(crate) inner: GspArgumentsCached, _padding: [u8; GSP_PAGE_SIZE - core::mem::size_of::<bindings::GSP_ARGUMENTS_CACHED>()], } +impl GspArgumentsPadded { + pub(crate) fn new(cmdq: &Cmdq) -> impl Init<Self> + '_ { + init!(GspArgumentsPadded { + inner <- GspArgumentsCached::new(cmdq), + ..Zeroable::init_zeroed() + }) + } +} + // SAFETY: Padding is explicit and will not contain uninitialized data. unsafe impl AsBytes for GspArgumentsPadded {} @@ -921,18 +905,18 @@ unsafe impl AsBytes for GspArgumentsPadded {} unsafe impl FromBytes for GspArgumentsPadded {} /// Init arguments for the message queue. -#[repr(transparent)] -struct MessageQueueInitArguments(bindings::MESSAGE_QUEUE_INIT_ARGUMENTS); +type MessageQueueInitArguments = bindings::MESSAGE_QUEUE_INIT_ARGUMENTS; impl MessageQueueInitArguments { /// Creates a new init arguments structure for `cmdq`. - fn new(cmdq: &Cmdq) -> Self { - Self(bindings::MESSAGE_QUEUE_INIT_ARGUMENTS { - sharedMemPhysAddr: cmdq.dma_handle(), + #[allow(non_snake_case)] + fn new(cmdq: &Cmdq) -> impl Init<Self> + '_ { + init!(MessageQueueInitArguments { + sharedMemPhysAddr: cmdq.dma_handle, pageTableEntryCount: num::usize_into_u32::<{ Cmdq::NUM_PTES }>(), cmdQueueOffset: num::usize_as_u64(Cmdq::CMDQ_OFFSET), statQueueOffset: num::usize_as_u64(Cmdq::STATQ_OFFSET), - ..Default::default() + ..Zeroable::init_zeroed() }) } } diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs index 21be44199693..db46276430be 100644 --- a/drivers/gpu/nova-core/gsp/fw/commands.rs +++ b/drivers/gpu/nova-core/gsp/fw/commands.rs @@ -1,8 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 -use kernel::prelude::*; -use kernel::transmute::{AsBytes, FromBytes}; -use kernel::{device, pci}; +use kernel::{ + device, + pci, + prelude::*, + transmute::{ + AsBytes, + FromBytes, // + }, // +}; use crate::gsp::GSP_PAGE_SIZE; @@ -107,6 +113,7 @@ unsafe impl FromBytes for PackedRegistryTable {} /// Payload of the `GetGspStaticInfo` command and message. #[repr(transparent)] +#[derive(Zeroable)] pub(crate) struct GspStaticConfigInfo(bindings::GspStaticConfigInfo_t); impl GspStaticConfigInfo { @@ -122,7 +129,3 @@ unsafe impl AsBytes for GspStaticConfigInfo {} // SAFETY: This struct only contains integer types for which all bit patterns // are valid. unsafe impl FromBytes for GspStaticConfigInfo {} - -// SAFETY: This struct only contains integer types and fixed-size arrays for which -// all bit patterns are valid. -unsafe impl Zeroable for GspStaticConfigInfo {} diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs index 6d25fe0bffa9..334e8be5fde8 100644 --- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs +++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs @@ -43,6 +43,7 @@ pub const GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB: u32 = 280; pub const GSP_FW_WPR_META_REVISION: u32 = 1; pub const GSP_FW_WPR_META_MAGIC: i64 = -2577556379034558285; pub const REGISTRY_TABLE_ENTRY_TYPE_DWORD: u32 = 1; +pub const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: u32 = 65536; pub type __u8 = ffi::c_uchar; pub type __u16 = ffi::c_ushort; pub type __u32 = ffi::c_uint; diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs index e415a2aa3203..474e4c8021db 100644 --- a/drivers/gpu/nova-core/gsp/sequencer.rs +++ b/drivers/gpu/nova-core/gsp/sequencer.rs @@ -67,6 +67,7 @@ const CMD_SIZE: usize = size_of::<fw::SequencerBufferCmd>(); /// GSP Sequencer Command types with payload data. /// Commands have an opcode and an opcode-dependent struct. #[allow(clippy::enum_variant_names)] +#[derive(Debug)] pub(crate) enum GspSeqCmd { RegWrite(fw::RegWritePayload), RegModify(fw::RegModifyPayload), @@ -144,12 +145,7 @@ pub(crate) struct GspSequencer<'a> { dev: ARef<device::Device>, } -/// Trait for running sequencer commands. -pub(crate) trait GspSeqCmdRunner { - fn run(&self, sequencer: &GspSequencer<'_>) -> Result; -} - -impl GspSeqCmdRunner for fw::RegWritePayload { +impl fw::RegWritePayload { fn run(&self, sequencer: &GspSequencer<'_>) -> Result { let addr = usize::from_safe_cast(self.addr()); @@ -157,7 +153,7 @@ impl GspSeqCmdRunner for fw::RegWritePayload { } } -impl GspSeqCmdRunner for fw::RegModifyPayload { +impl fw::RegModifyPayload { fn run(&self, sequencer: &GspSequencer<'_>) -> Result { let addr = usize::from_safe_cast(self.addr()); @@ -169,7 +165,7 @@ impl GspSeqCmdRunner for fw::RegModifyPayload { } } -impl GspSeqCmdRunner for fw::RegPollPayload { +impl fw::RegPollPayload { fn run(&self, sequencer: &GspSequencer<'_>) -> Result { let addr = usize::from_safe_cast(self.addr()); @@ -194,14 +190,14 @@ impl GspSeqCmdRunner for fw::RegPollPayload { } } -impl GspSeqCmdRunner for fw::DelayUsPayload { +impl fw::DelayUsPayload { fn run(&self, _sequencer: &GspSequencer<'_>) -> Result { fsleep(Delta::from_micros(i64::from(self.val()))); Ok(()) } } -impl GspSeqCmdRunner for fw::RegStorePayload { +impl fw::RegStorePayload { fn run(&self, sequencer: &GspSequencer<'_>) -> Result { let addr = usize::from_safe_cast(self.addr()); @@ -209,7 +205,7 @@ impl GspSeqCmdRunner for fw::RegStorePayload { } } -impl GspSeqCmdRunner for GspSeqCmd { +impl GspSeqCmd { fn run(&self, seq: &GspSequencer<'_>) -> Result { match self { GspSeqCmd::RegWrite(cmd) => cmd.run(seq), @@ -360,9 +356,9 @@ pub(crate) struct GspSequencerParams<'a> { } impl<'a> GspSequencer<'a> { - pub(crate) fn run(cmdq: &mut Cmdq, params: GspSequencerParams<'a>) -> Result { + pub(crate) fn run(cmdq: &Cmdq, params: GspSequencerParams<'a>) -> Result { let seq_info = loop { - match cmdq.receive_msg::<GspSequence>(Delta::from_secs(10)) { + match cmdq.receive_msg::<GspSequence>(Cmdq::RECEIVE_TIMEOUT) { Ok(seq_info) => break seq_info, Err(ERANGE) => continue, Err(e) => return Err(e), diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs index c1121e7c64c5..04a1fa6b25f8 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -2,10 +2,17 @@ //! Nova Core GPU Driver +use kernel::{ + debugfs, + driver::Registration, + pci, + prelude::*, + InPlaceModule, // +}; + #[macro_use] mod bitfield; -mod dma; mod driver; mod falcon; mod fb; @@ -13,15 +20,54 @@ mod firmware; mod gfw; mod gpu; mod gsp; +#[macro_use] mod num; mod regs; mod sbuffer; mod vbios; -pub(crate) const MODULE_NAME: &kernel::str::CStr = <LocalModule as kernel::ModuleMetadata>::NAME; +pub(crate) const MODULE_NAME: &core::ffi::CStr = <LocalModule as kernel::ModuleMetadata>::NAME; + +// TODO: Move this into per-module data once that exists. +static mut DEBUGFS_ROOT: Option<debugfs::Dir> = None; + +/// Guard that clears `DEBUGFS_ROOT` when dropped. +struct DebugfsRootGuard; + +impl Drop for DebugfsRootGuard { + fn drop(&mut self) { + // SAFETY: This guard is dropped after `_driver` (due to field order), + // so the driver is unregistered and no probe() can be running. + unsafe { DEBUGFS_ROOT = None }; + } +} + +#[pin_data] +struct NovaCoreModule { + // Fields are dropped in declaration order, so `_driver` is dropped first, + // then `_debugfs_guard` clears `DEBUGFS_ROOT`. + #[pin] + _driver: Registration<pci::Adapter<driver::NovaCore>>, + _debugfs_guard: DebugfsRootGuard, +} + +impl InPlaceModule for NovaCoreModule { + fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> { + let dir = debugfs::Dir::new(kernel::c_str!("nova_core")); + + // SAFETY: We are the only driver code running during init, so there + // cannot be any concurrent access to `DEBUGFS_ROOT`. + unsafe { DEBUGFS_ROOT = Some(dir) }; + + try_pin_init!(Self { + _driver <- Registration::new(MODULE_NAME, module), + _debugfs_guard: DebugfsRootGuard, + }) + } +} -kernel::module_pci_driver! { - type: driver::NovaCore, +module! { + type: NovaCoreModule, name: "NovaCore", authors: ["Danilo Krummrich"], description: "Nova Core GPU driver", diff --git a/drivers/gpu/nova-core/num.rs b/drivers/gpu/nova-core/num.rs index c952a834e662..6c824b8d7b97 100644 --- a/drivers/gpu/nova-core/num.rs +++ b/drivers/gpu/nova-core/num.rs @@ -215,3 +215,83 @@ impl_const_into!(usize => { u8, u16, u32 }); impl_const_into!(u64 => { u8, u16, u32 }); impl_const_into!(u32 => { u8, u16 }); impl_const_into!(u16 => { u8 }); + +/// Creates an enum type associated to a [`Bounded`](kernel::num::Bounded), with a [`From`] +/// conversion to the associated `Bounded` and either a [`TryFrom`] or `From` conversion from the +/// associated `Bounded`. +// TODO[FPRI]: This is a temporary solution to be replaced with the corresponding derive macros +// once they land. +#[macro_export] +macro_rules! bounded_enum { + ( + $(#[$enum_meta:meta])* + $vis:vis enum $enum_type:ident with $from_impl:ident<Bounded<$width:ty, $length:literal>> { + $( $(#[doc = $variant_doc:expr])* $variant:ident = $value:expr),* $(,)* + } + ) => { + $(#[$enum_meta])* + $vis enum $enum_type { + $( + $(#[doc = $variant_doc])* + $variant = $value + ),* + } + + impl core::convert::From<$enum_type> for kernel::num::Bounded<$width, $length> { + fn from(value: $enum_type) -> Self { + match value { + $($enum_type::$variant => + kernel::num::Bounded::<$width, _>::new::<{ $value }>()),* + } + } + } + + bounded_enum!(@impl_from $enum_type with $from_impl<Bounded<$width, $length>> { + $($variant = $value),* + }); + }; + + // `TryFrom` implementation from associated `Bounded` to enum type. + (@impl_from $enum_type:ident with TryFrom<Bounded<$width:ty, $length:literal>> { + $($variant:ident = $value:expr),* $(,)* + }) => { + impl core::convert::TryFrom<kernel::num::Bounded<$width, $length>> for $enum_type { + type Error = kernel::error::Error; + + fn try_from( + value: kernel::num::Bounded<$width, $length> + ) -> kernel::error::Result<Self> { + match value.get() { + $( + $value => Ok($enum_type::$variant), + )* + _ => Err(kernel::error::code::EINVAL), + } + } + } + }; + + // `From` implementation from associated `Bounded` to enum type. Triggers a build-time error if + // all possible values of the `Bounded` are not covered by the enum type. + (@impl_from $enum_type:ident with From<Bounded<$width:ty, $length:literal>> { + $($variant:ident = $value:expr),* $(,)* + }) => { + impl core::convert::From<kernel::num::Bounded<$width, $length>> for $enum_type { + fn from(value: kernel::num::Bounded<$width, $length>) -> Self { + const MAX: $width = 1 << $length; + + // Makes the compiler optimizer aware of the possible range of values. + let value = value.get() & ((1 << $length) - 1); + match value { + $( + $value => $enum_type::$variant, + )* + // PANIC: we cannot reach this arm as all possible variants are handled by the + // match arms above. It is here to make the compiler complain if `$enum_type` + // does not cover all values of the `0..MAX` range. + MAX.. => unreachable!(), + } + } + } + } +} diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index ea0d32f5396c..2f171a4ff9ba 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -1,13 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -// Required to retain the original register names used by OpenRM, which are all capital snake case -// but are mapped to types. -#![allow(non_camel_case_types)] - -#[macro_use] -pub(crate) mod macros; - use kernel::{ + io::{ + register, + register::WithBase, + Io, // + }, prelude::*, time, // }; @@ -37,18 +35,38 @@ use crate::{ // PMC -register!(NV_PMC_BOOT_0 @ 0x00000000, "Basic revision information about the GPU" { - 3:0 minor_revision as u8, "Minor revision of the chip"; - 7:4 major_revision as u8, "Major revision of the chip"; - 8:8 architecture_1 as u8, "MSB of the architecture"; - 23:20 implementation as u8, "Implementation version of the architecture"; - 28:24 architecture_0 as u8, "Lower bits of the architecture"; -}); +register! { + /// Basic revision information about the GPU. + pub(crate) NV_PMC_BOOT_0(u32) @ 0x00000000 { + /// Lower bits of the architecture. + 28:24 architecture_0; + /// Implementation version of the architecture. + 23:20 implementation; + /// MSB of the architecture. + 8:8 architecture_1; + /// Major revision of the chip. + 7:4 major_revision; + /// Minor revision of the chip. + 3:0 minor_revision; + } + + /// Extended architecture information. + pub(crate) NV_PMC_BOOT_42(u32) @ 0x00000a00 { + /// Architecture value. + 29:24 architecture ?=> Architecture; + /// Implementation version of the architecture. + 23:20 implementation; + /// Major revision of the chip. + 19:16 major_revision; + /// Minor revision of the chip. + 15:12 minor_revision; + } +} impl NV_PMC_BOOT_0 { pub(crate) fn is_older_than_fermi(self) -> bool { // From https://github.com/NVIDIA/open-gpu-doc/tree/master/manuals : - const NV_PMC_BOOT_0_ARCHITECTURE_GF100: u8 = 0xc; + const NV_PMC_BOOT_0_ARCHITECTURE_GF100: u32 = 0xc; // Older chips left arch1 zeroed out. That, combined with an arch0 value that is less than // GF100, means "older than Fermi". @@ -56,13 +74,6 @@ impl NV_PMC_BOOT_0 { } } -register!(NV_PMC_BOOT_42 @ 0x00000a00, "Extended architecture information" { - 15:12 minor_revision as u8, "Minor revision of the chip"; - 19:16 major_revision as u8, "Major revision of the chip"; - 23:20 implementation as u8, "Implementation version of the architecture"; - 29:24 architecture as u8 ?=> Architecture, "Architecture value"; -}); - impl NV_PMC_BOOT_42 { /// Combines `architecture` and `implementation` to obtain a code unique to the chipset. pub(crate) fn chipset(self) -> Result<Chipset> { @@ -76,8 +87,8 @@ impl NV_PMC_BOOT_42 { /// Returns the raw architecture value from the register. fn architecture_raw(self) -> u8 { - ((self.0 >> Self::ARCHITECTURE_RANGE.start()) & ((1 << Self::ARCHITECTURE_RANGE.len()) - 1)) - as u8 + ((self.into_raw() >> Self::ARCHITECTURE_RANGE.start()) + & ((1 << Self::ARCHITECTURE_RANGE.len()) - 1)) as u8 } } @@ -86,7 +97,7 @@ impl kernel::fmt::Display for NV_PMC_BOOT_42 { write!( f, "boot42 = 0x{:08x} (architecture 0x{:x}, implementation 0x{:x})", - self.0, + self.inner, self.architecture_raw(), self.implementation() ) @@ -95,35 +106,46 @@ impl kernel::fmt::Display for NV_PMC_BOOT_42 { // PBUS -register!(NV_PBUS_SW_SCRATCH @ 0x00001400[64] {}); +register! { + pub(crate) NV_PBUS_SW_SCRATCH(u32)[64] @ 0x00001400 {} -register!(NV_PBUS_SW_SCRATCH_0E_FRTS_ERR => NV_PBUS_SW_SCRATCH[0xe], - "scratch register 0xe used as FRTS firmware error code" { - 31:16 frts_err_code as u16; -}); + /// Scratch register 0xe used as FRTS firmware error code. + pub(crate) NV_PBUS_SW_SCRATCH_0E_FRTS_ERR(u32) => NV_PBUS_SW_SCRATCH[0xe] { + 31:16 frts_err_code; + } +} // PFB -// The following two registers together hold the physical system memory address that is used by the -// GPU to perform sysmembar operations (see `fb::SysmemFlush`). +register! { + /// Low bits of the physical system memory address used by the GPU to perform sysmembar + /// operations (see [`crate::fb::SysmemFlush`]). + pub(crate) NV_PFB_NISO_FLUSH_SYSMEM_ADDR(u32) @ 0x00100c10 { + 31:0 adr_39_08; + } -register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 { - 31:0 adr_39_08 as u32; -}); + /// High bits of the physical system memory address used by the GPU to perform sysmembar + /// operations (see [`crate::fb::SysmemFlush`]). + pub(crate) NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI(u32) @ 0x00100c40 { + 23:0 adr_63_40; + } -register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI @ 0x00100c40 { - 23:0 adr_63_40 as u32; -}); + pub(crate) NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE(u32) @ 0x00100ce0 { + 30:30 ecc_mode_enabled => bool; + 9:4 lower_mag; + 3:0 lower_scale; + } -register!(NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE @ 0x00100ce0 { - 3:0 lower_scale as u8; - 9:4 lower_mag as u8; - 30:30 ecc_mode_enabled as bool; -}); + pub(crate) NV_PFB_PRI_MMU_WPR2_ADDR_LO(u32) @ 0x001fa824 { + /// Bits 12..40 of the lower (inclusive) bound of the WPR2 region. + 31:4 lo_val; + } -register!(NV_PGSP_QUEUE_HEAD @ 0x00110c00 { - 31:0 address as u32; -}); + pub(crate) NV_PFB_PRI_MMU_WPR2_ADDR_HI(u32) @ 0x001fa828 { + /// Bits 12..40 of the higher (exclusive) bound of the WPR2 region. + 31:4 hi_val; + } +} impl NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE { /// Returns the usable framebuffer size, in bytes. @@ -140,10 +162,6 @@ impl NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE { } } -register!(NV_PFB_PRI_MMU_WPR2_ADDR_LO@0x001fa824 { - 31:4 lo_val as u32, "Bits 12..40 of the lower (inclusive) bound of the WPR2 region"; -}); - impl NV_PFB_PRI_MMU_WPR2_ADDR_LO { /// Returns the lower (inclusive) bound of the WPR2 region. pub(crate) fn lower_bound(self) -> u64 { @@ -151,10 +169,6 @@ impl NV_PFB_PRI_MMU_WPR2_ADDR_LO { } } -register!(NV_PFB_PRI_MMU_WPR2_ADDR_HI@0x001fa828 { - 31:4 hi_val as u32, "Bits 12..40 of the higher (exclusive) bound of the WPR2 region"; -}); - impl NV_PFB_PRI_MMU_WPR2_ADDR_HI { /// Returns the higher (exclusive) bound of the WPR2 region. /// @@ -164,6 +178,14 @@ impl NV_PFB_PRI_MMU_WPR2_ADDR_HI { } } +// PGSP + +register! { + pub(crate) NV_PGSP_QUEUE_HEAD(u32) @ 0x00110c00 { + 31:0 address; + } +} + // PGC6 register space. // // `GC6` is a GPU low-power state where VRAM is in self-refresh and the GPU is powered down (except @@ -173,29 +195,41 @@ impl NV_PFB_PRI_MMU_WPR2_ADDR_HI { // These scratch registers remain powered on even in a low-power state and have a designated group // number. -// Boot Sequence Interface (BSI) register used to determine -// if GSP reload/resume has completed during the boot process. -register!(NV_PGC6_BSI_SECURE_SCRATCH_14 @ 0x001180f8 { - 26:26 boot_stage_3_handoff as bool; -}); +register! { + /// Boot Sequence Interface (BSI) register used to determine + /// if GSP reload/resume has completed during the boot process. + pub(crate) NV_PGC6_BSI_SECURE_SCRATCH_14(u32) @ 0x001180f8 { + 26:26 boot_stage_3_handoff => bool; + } + + /// Privilege level mask register. It dictates whether the host CPU has privilege to access the + /// `PGC6_AON_SECURE_SCRATCH_GROUP_05` register (which it needs to read GFW_BOOT). + pub(crate) NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK(u32) @ 0x00118128 { + /// Set after FWSEC lowers its protection level. + 0:0 read_protection_level0 => bool; + } -// Privilege level mask register. It dictates whether the host CPU has privilege to access the -// `PGC6_AON_SECURE_SCRATCH_GROUP_05` register (which it needs to read GFW_BOOT). -register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128, - "Privilege level mask register" { - 0:0 read_protection_level0 as bool, "Set after FWSEC lowers its protection level"; -}); + /// OpenRM defines this as a register array, but doesn't specify its size and only uses its + /// first element. Be conservative until we know the actual size or need to use more registers. + pub(crate) NV_PGC6_AON_SECURE_SCRATCH_GROUP_05(u32)[1] @ 0x00118234 {} -// OpenRM defines this as a register array, but doesn't specify its size and only uses its first -// element. Be conservative until we know the actual size or need to use more registers. -register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05 @ 0x00118234[1] {}); + /// Scratch group 05 register 0 used as GFW boot progress indicator. + pub(crate) NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT(u32) + => NV_PGC6_AON_SECURE_SCRATCH_GROUP_05[0] { + /// Progress of GFW boot (0xff means completed). + 7:0 progress; + } + + pub(crate) NV_PGC6_AON_SECURE_SCRATCH_GROUP_42(u32) @ 0x001183a4 { + 31:0 value; + } -register!( - NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT => NV_PGC6_AON_SECURE_SCRATCH_GROUP_05[0], - "Scratch group 05 register 0 used as GFW boot progress indicator" { - 7:0 progress as u8, "Progress of GFW boot (0xff means completed)"; + /// Scratch group 42 register used as framebuffer size. + pub(crate) NV_USABLE_FB_SIZE_IN_MB(u32) => NV_PGC6_AON_SECURE_SCRATCH_GROUP_42 { + /// Usable framebuffer size, in megabytes. + 31:0 value; } -); +} impl NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT { /// Returns `true` if GFW boot is completed. @@ -204,17 +238,6 @@ impl NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT { } } -register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_42 @ 0x001183a4 { - 31:0 value as u32; -}); - -register!( - NV_USABLE_FB_SIZE_IN_MB => NV_PGC6_AON_SECURE_SCRATCH_GROUP_42, - "Scratch group 42 register used as framebuffer size" { - 31:0 value as u32, "Usable framebuffer size, in megabytes"; - } -); - impl NV_USABLE_FB_SIZE_IN_MB { /// Returns the usable framebuffer size, in bytes. pub(crate) fn usable_fb_size(self) -> u64 { @@ -224,10 +247,14 @@ impl NV_USABLE_FB_SIZE_IN_MB { // PDISP -register!(NV_PDISP_VGA_WORKSPACE_BASE @ 0x00625f04 { - 3:3 status_valid as bool, "Set if the `addr` field is valid"; - 31:8 addr as u32, "VGA workspace base address divided by 0x10000"; -}); +register! { + pub(crate) NV_PDISP_VGA_WORKSPACE_BASE(u32) @ 0x00625f04 { + /// VGA workspace base address divided by 0x10000. + 31:8 addr; + /// Set if the `addr` field is valid. + 3:3 status_valid => bool; + } +} impl NV_PDISP_VGA_WORKSPACE_BASE { /// Returns the base address of the VGA workspace, or `None` if none exists. @@ -244,73 +271,162 @@ impl NV_PDISP_VGA_WORKSPACE_BASE { pub(crate) const NV_FUSE_OPT_FPF_SIZE: usize = 16; -register!(NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION @ 0x00824100[NV_FUSE_OPT_FPF_SIZE] { - 15:0 data as u16; -}); +register! { + pub(crate) NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION(u32)[NV_FUSE_OPT_FPF_SIZE] @ 0x00824100 { + 15:0 data => u16; + } -register!(NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION @ 0x00824140[NV_FUSE_OPT_FPF_SIZE] { - 15:0 data as u16; -}); + pub(crate) NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION(u32)[NV_FUSE_OPT_FPF_SIZE] @ 0x00824140 { + 15:0 data => u16; + } -register!(NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION @ 0x008241c0[NV_FUSE_OPT_FPF_SIZE] { - 15:0 data as u16; -}); + pub(crate) NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION(u32)[NV_FUSE_OPT_FPF_SIZE] @ 0x008241c0 { + 15:0 data => u16; + } +} // PFALCON -register!(NV_PFALCON_FALCON_IRQSCLR @ PFalconBase[0x00000004] { - 4:4 halt as bool; - 6:6 swgen0 as bool; -}); +register! { + pub(crate) NV_PFALCON_FALCON_IRQSCLR(u32) @ PFalconBase + 0x00000004 { + 6:6 swgen0 => bool; + 4:4 halt => bool; + } + + pub(crate) NV_PFALCON_FALCON_MAILBOX0(u32) @ PFalconBase + 0x00000040 { + 31:0 value => u32; + } + + pub(crate) NV_PFALCON_FALCON_MAILBOX1(u32) @ PFalconBase + 0x00000044 { + 31:0 value => u32; + } -register!(NV_PFALCON_FALCON_MAILBOX0 @ PFalconBase[0x00000040] { - 31:0 value as u32; -}); + /// Used to store version information about the firmware running + /// on the Falcon processor. + pub(crate) NV_PFALCON_FALCON_OS(u32) @ PFalconBase + 0x00000080 { + 31:0 value => u32; + } -register!(NV_PFALCON_FALCON_MAILBOX1 @ PFalconBase[0x00000044] { - 31:0 value as u32; -}); + pub(crate) NV_PFALCON_FALCON_RM(u32) @ PFalconBase + 0x00000084 { + 31:0 value => u32; + } -// Used to store version information about the firmware running -// on the Falcon processor. -register!(NV_PFALCON_FALCON_OS @ PFalconBase[0x00000080] { - 31:0 value as u32; -}); + pub(crate) NV_PFALCON_FALCON_HWCFG2(u32) @ PFalconBase + 0x000000f4 { + /// Signal indicating that reset is completed (GA102+). + 31:31 reset_ready => bool; + /// Set to 0 after memory scrubbing is completed. + 12:12 mem_scrubbing => bool; + 10:10 riscv => bool; + } -register!(NV_PFALCON_FALCON_RM @ PFalconBase[0x00000084] { - 31:0 value as u32; -}); + pub(crate) NV_PFALCON_FALCON_CPUCTL(u32) @ PFalconBase + 0x00000100 { + 6:6 alias_en => bool; + 4:4 halted => bool; + 1:1 startcpu => bool; + } -register!(NV_PFALCON_FALCON_HWCFG2 @ PFalconBase[0x000000f4] { - 10:10 riscv as bool; - 12:12 mem_scrubbing as bool, "Set to 0 after memory scrubbing is completed"; - 31:31 reset_ready as bool, "Signal indicating that reset is completed (GA102+)"; -}); + pub(crate) NV_PFALCON_FALCON_BOOTVEC(u32) @ PFalconBase + 0x00000104 { + 31:0 value => u32; + } -impl NV_PFALCON_FALCON_HWCFG2 { - /// Returns `true` if memory scrubbing is completed. - pub(crate) fn mem_scrubbing_done(self) -> bool { - !self.mem_scrubbing() + pub(crate) NV_PFALCON_FALCON_DMACTL(u32) @ PFalconBase + 0x0000010c { + 7:7 secure_stat => bool; + 6:3 dmaq_num; + 2:2 imem_scrubbing => bool; + 1:1 dmem_scrubbing => bool; + 0:0 require_ctx => bool; } -} -register!(NV_PFALCON_FALCON_CPUCTL @ PFalconBase[0x00000100] { - 1:1 startcpu as bool; - 4:4 halted as bool; - 6:6 alias_en as bool; -}); + pub(crate) NV_PFALCON_FALCON_DMATRFBASE(u32) @ PFalconBase + 0x00000110 { + 31:0 base => u32; + } -register!(NV_PFALCON_FALCON_BOOTVEC @ PFalconBase[0x00000104] { - 31:0 value as u32; -}); + pub(crate) NV_PFALCON_FALCON_DMATRFMOFFS(u32) @ PFalconBase + 0x00000114 { + 23:0 offs; + } -register!(NV_PFALCON_FALCON_DMACTL @ PFalconBase[0x0000010c] { - 0:0 require_ctx as bool; - 1:1 dmem_scrubbing as bool; - 2:2 imem_scrubbing as bool; - 6:3 dmaq_num as u8; - 7:7 secure_stat as bool; -}); + pub(crate) NV_PFALCON_FALCON_DMATRFCMD(u32) @ PFalconBase + 0x00000118 { + 16:16 set_dmtag; + 14:12 ctxdma; + 10:8 size ?=> DmaTrfCmdSize; + 5:5 is_write => bool; + 4:4 imem => bool; + 3:2 sec; + 1:1 idle => bool; + 0:0 full => bool; + } + + pub(crate) NV_PFALCON_FALCON_DMATRFFBOFFS(u32) @ PFalconBase + 0x0000011c { + 31:0 offs => u32; + } + + pub(crate) NV_PFALCON_FALCON_DMATRFBASE1(u32) @ PFalconBase + 0x00000128 { + 8:0 base; + } + + pub(crate) NV_PFALCON_FALCON_HWCFG1(u32) @ PFalconBase + 0x0000012c { + /// Core revision subversion. + 7:6 core_rev_subversion => FalconCoreRevSubversion; + /// Security model. + 5:4 security_model ?=> FalconSecurityModel; + /// Core revision. + 3:0 core_rev ?=> FalconCoreRev; + } + + pub(crate) NV_PFALCON_FALCON_CPUCTL_ALIAS(u32) @ PFalconBase + 0x00000130 { + 1:1 startcpu => bool; + } + + /// IMEM access control register. Up to 4 ports are available for IMEM access. + pub(crate) NV_PFALCON_FALCON_IMEMC(u32)[4, stride = 16] @ PFalconBase + 0x00000180 { + /// Access secure IMEM. + 28:28 secure => bool; + /// Auto-increment on write. + 24:24 aincw => bool; + /// IMEM block and word offset. + 15:0 offs; + } + + /// IMEM data register. Reading/writing this register accesses IMEM at the address + /// specified by the corresponding IMEMC register. + pub(crate) NV_PFALCON_FALCON_IMEMD(u32)[4, stride = 16] @ PFalconBase + 0x00000184 { + 31:0 data; + } + + /// IMEM tag register. Used to set the tag for the current IMEM block. + pub(crate) NV_PFALCON_FALCON_IMEMT(u32)[4, stride = 16] @ PFalconBase + 0x00000188 { + 15:0 tag; + } + + /// DMEM access control register. Up to 8 ports are available for DMEM access. + pub(crate) NV_PFALCON_FALCON_DMEMC(u32)[8, stride = 8] @ PFalconBase + 0x000001c0 { + /// Auto-increment on write. + 24:24 aincw => bool; + /// DMEM block and word offset. + 15:0 offs; + } + + /// DMEM data register. Reading/writing this register accesses DMEM at the address + /// specified by the corresponding DMEMC register. + pub(crate) NV_PFALCON_FALCON_DMEMD(u32)[8, stride = 8] @ PFalconBase + 0x000001c4 { + 31:0 data; + } + + /// Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGINE` depending on the + /// falcon instance. + pub(crate) NV_PFALCON_FALCON_ENGINE(u32) @ PFalconBase + 0x000003c0 { + 0:0 reset => bool; + } + + pub(crate) NV_PFALCON_FBIF_TRANSCFG(u32)[8] @ PFalconBase + 0x00000600 { + 2:2 mem_type => FalconFbifMemType; + 1:0 target ?=> FalconFbifTarget; + } + + pub(crate) NV_PFALCON_FBIF_CTL(u32) @ PFalconBase + 0x00000624 { + 7:7 allow_phys_no_ctx => bool; + } +} impl NV_PFALCON_FALCON_DMACTL { /// Returns `true` if memory scrubbing is completed. @@ -319,133 +435,106 @@ impl NV_PFALCON_FALCON_DMACTL { } } -register!(NV_PFALCON_FALCON_DMATRFBASE @ PFalconBase[0x00000110] { - 31:0 base as u32; -}); - -register!(NV_PFALCON_FALCON_DMATRFMOFFS @ PFalconBase[0x00000114] { - 23:0 offs as u32; -}); - -register!(NV_PFALCON_FALCON_DMATRFCMD @ PFalconBase[0x00000118] { - 0:0 full as bool; - 1:1 idle as bool; - 3:2 sec as u8; - 4:4 imem as bool; - 5:5 is_write as bool; - 10:8 size as u8 ?=> DmaTrfCmdSize; - 14:12 ctxdma as u8; - 16:16 set_dmtag as u8; -}); - impl NV_PFALCON_FALCON_DMATRFCMD { /// Programs the `imem` and `sec` fields for the given FalconMem pub(crate) fn with_falcon_mem(self, mem: FalconMem) -> Self { - self.set_imem(mem != FalconMem::Dmem) - .set_sec(if mem == FalconMem::ImemSecure { 1 } else { 0 }) + let this = self.with_imem(mem != FalconMem::Dmem); + + match mem { + FalconMem::ImemSecure => this.with_const_sec::<1>(), + _ => this.with_const_sec::<0>(), + } } } -register!(NV_PFALCON_FALCON_DMATRFFBOFFS @ PFalconBase[0x0000011c] { - 31:0 offs as u32; -}); - -register!(NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase[0x00000128] { - 8:0 base as u16; -}); - -register!(NV_PFALCON_FALCON_HWCFG1 @ PFalconBase[0x0000012c] { - 3:0 core_rev as u8 ?=> FalconCoreRev, "Core revision"; - 5:4 security_model as u8 ?=> FalconSecurityModel, "Security model"; - 7:6 core_rev_subversion as u8 ?=> FalconCoreRevSubversion, "Core revision subversion"; -}); - -register!(NV_PFALCON_FALCON_CPUCTL_ALIAS @ PFalconBase[0x00000130] { - 1:1 startcpu as bool; -}); - -// Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGINE` depending on the falcon -// instance. -register!(NV_PFALCON_FALCON_ENGINE @ PFalconBase[0x000003c0] { - 0:0 reset as bool; -}); - impl NV_PFALCON_FALCON_ENGINE { /// Resets the falcon pub(crate) fn reset_engine<E: FalconEngine>(bar: &Bar0) { - Self::read(bar, &E::ID).set_reset(true).write(bar, &E::ID); + bar.update(Self::of::<E>(), |r| r.with_reset(true)); // TIMEOUT: falcon engine should not take more than 10us to reset. time::delay::fsleep(time::Delta::from_micros(10)); - Self::read(bar, &E::ID).set_reset(false).write(bar, &E::ID); + bar.update(Self::of::<E>(), |r| r.with_reset(false)); } } -register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600[8]] { - 1:0 target as u8 ?=> FalconFbifTarget; - 2:2 mem_type as bool => FalconFbifMemType; -}); - -register!(NV_PFALCON_FBIF_CTL @ PFalconBase[0x00000624] { - 7:7 allow_phys_no_ctx as bool; -}); +impl NV_PFALCON_FALCON_HWCFG2 { + /// Returns `true` if memory scrubbing is completed. + pub(crate) fn mem_scrubbing_done(self) -> bool { + !self.mem_scrubbing() + } +} /* PFALCON2 */ -register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base[0x00000180] { - 7:0 algo as u8 ?=> FalconModSelAlgo; -}); +register! { + pub(crate) NV_PFALCON2_FALCON_MOD_SEL(u32) @ PFalcon2Base + 0x00000180 { + 7:0 algo ?=> FalconModSelAlgo; + } -register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalcon2Base[0x00000198] { - 7:0 ucode_id as u8; -}); + pub(crate) NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID(u32) @ PFalcon2Base + 0x00000198 { + 7:0 ucode_id => u8; + } -register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalcon2Base[0x0000019c] { - 31:0 value as u32; -}); + pub(crate) NV_PFALCON2_FALCON_BROM_ENGIDMASK(u32) @ PFalcon2Base + 0x0000019c { + 31:0 value => u32; + } -// OpenRM defines this as a register array, but doesn't specify its size and only uses its first -// element. Be conservative until we know the actual size or need to use more registers. -register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210[1]] { - 31:0 value as u32; -}); + /// OpenRM defines this as a register array, but doesn't specify its size and only uses its + /// first element. Be conservative until we know the actual size or need to use more registers. + pub(crate) NV_PFALCON2_FALCON_BROM_PARAADDR(u32)[1] @ PFalcon2Base + 0x00000210 { + 31:0 value => u32; + } +} // PRISCV -// RISC-V status register for debug (Turing and GA100 only). -// Reflects current RISC-V core status. -register!(NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS @ PFalcon2Base[0x00000240] { - 0:0 active_stat as bool, "RISC-V core active/inactive status"; -}); +register! { + /// RISC-V status register for debug (Turing and GA100 only). + /// Reflects current RISC-V core status. + pub(crate) NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS(u32) @ PFalcon2Base + 0x00000240 { + /// RISC-V core active/inactive status. + 0:0 active_stat => bool; + } -// GA102 and later -register!(NV_PRISCV_RISCV_CPUCTL @ PFalcon2Base[0x00000388] { - 0:0 halted as bool; - 7:7 active_stat as bool; -}); + /// GA102 and later. + pub(crate) NV_PRISCV_RISCV_CPUCTL(u32) @ PFalcon2Base + 0x00000388 { + 7:7 active_stat => bool; + 0:0 halted => bool; + } -register!(NV_PRISCV_RISCV_BCR_CTRL @ PFalcon2Base[0x00000668] { - 0:0 valid as bool; - 4:4 core_select as bool => PeregrineCoreSelect; - 8:8 br_fetch as bool; -}); + /// GA102 and later. + pub(crate) NV_PRISCV_RISCV_BCR_CTRL(u32) @ PFalcon2Base + 0x00000668 { + 8:8 br_fetch => bool; + 4:4 core_select => PeregrineCoreSelect; + 0:0 valid => bool; + } +} // The modules below provide registers that are not identical on all supported chips. They should // only be used in HAL modules. pub(crate) mod gm107 { + use kernel::io::register; + // FUSE - register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00021c04 { - 0:0 display_disabled as bool; - }); + register! { + pub(crate) NV_FUSE_STATUS_OPT_DISPLAY(u32) @ 0x00021c04 { + 0:0 display_disabled => bool; + } + } } pub(crate) mod ga100 { + use kernel::io::register; + // FUSE - register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00820c04 { - 0:0 display_disabled as bool; - }); + register! { + pub(crate) NV_FUSE_STATUS_OPT_DISPLAY(u32) @ 0x00820c04 { + 0:0 display_disabled => bool; + } + } } diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs deleted file mode 100644 index ed624be1f39b..000000000000 --- a/drivers/gpu/nova-core/regs/macros.rs +++ /dev/null @@ -1,739 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! `register!` macro to define register layout and accessors. -//! -//! A single register typically includes several fields, which are accessed through a combination -//! of bit-shift and mask operations that introduce a class of potential mistakes, notably because -//! not all possible field values are necessarily valid. -//! -//! The `register!` macro in this module provides an intuitive and readable syntax for defining a -//! dedicated type for each register. Each such type comes with its own field accessors that can -//! return an error if a field's value is invalid. Please look at the [`bitfield`] macro for the -//! complete syntax of fields definitions. - -/// Trait providing a base address to be added to the offset of a relative register to obtain -/// its actual offset. -/// -/// The `T` generic argument is used to distinguish which base to use, in case a type provides -/// several bases. It is given to the `register!` macro to restrict the use of the register to -/// implementors of this particular variant. -pub(crate) trait RegisterBase<T> { - const BASE: usize; -} - -/// Defines a dedicated type for a register with an absolute offset, including getter and setter -/// methods for its fields and methods to read and write it from an `Io` region. -/// -/// Example: -/// -/// ```no_run -/// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" { -/// 3:0 minor_revision as u8, "Minor revision of the chip"; -/// 7:4 major_revision as u8, "Major revision of the chip"; -/// 28:20 chipset as u32 ?=> Chipset, "Chipset model"; -/// }); -/// ``` -/// -/// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io` -/// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 least -/// significant bits of the register. Each field can be accessed and modified using accessor -/// methods: -/// -/// ```no_run -/// // Read from the register's defined offset (0x100). -/// let boot0 = BOOT_0::read(&bar); -/// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision()); -/// -/// // `Chipset::try_from` is called with the value of the `chipset` field and returns an -/// // error if it is invalid. -/// let chipset = boot0.chipset()?; -/// -/// // Update some fields and write the value back. -/// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); -/// -/// // Or, just read and update the register in a single step: -/// BOOT_0::update(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); -/// ``` -/// -/// The documentation strings are optional. If present, they will be added to the type's -/// definition, or the field getter and setter methods they are attached to. -/// -/// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful -/// for cases where a register's interpretation depends on the context: -/// -/// ```no_run -/// register!(SCRATCH @ 0x00000200, "Scratch register" { -/// 31:0 value as u32, "Raw value"; -/// }); -/// -/// register!(SCRATCH_BOOT_STATUS => SCRATCH, "Boot status of the firmware" { -/// 0:0 completed as bool, "Whether the firmware has completed booting"; -/// }); -/// ``` -/// -/// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while also -/// providing its own `completed` field. -/// -/// ## Relative registers -/// -/// A register can be defined as being accessible from a fixed offset of a provided base. For -/// instance, imagine the following I/O space: -/// -/// ```text -/// +-----------------------------+ -/// | ... | -/// | | -/// 0x100--->+------------CPU0-------------+ -/// | | -/// 0x110--->+-----------------------------+ -/// | CPU_CTL | -/// +-----------------------------+ -/// | ... | -/// | | -/// | | -/// 0x200--->+------------CPU1-------------+ -/// | | -/// 0x210--->+-----------------------------+ -/// | CPU_CTL | -/// +-----------------------------+ -/// | ... | -/// +-----------------------------+ -/// ``` -/// -/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O -/// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define -/// them twice and would prefer a way to select which one to use from a single definition -/// -/// This can be done using the `Base[Offset]` syntax when specifying the register's address. -/// -/// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the -/// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for -/// this register needs to implement `RegisterBase<Base>`. Here is the above example translated -/// into code: -/// -/// ```no_run -/// // Type used to identify the base. -/// pub(crate) struct CpuCtlBase; -/// -/// // ZST describing `CPU0`. -/// struct Cpu0; -/// impl RegisterBase<CpuCtlBase> for Cpu0 { -/// const BASE: usize = 0x100; -/// } -/// // Singleton of `CPU0` used to identify it. -/// const CPU0: Cpu0 = Cpu0; -/// -/// // ZST describing `CPU1`. -/// struct Cpu1; -/// impl RegisterBase<CpuCtlBase> for Cpu1 { -/// const BASE: usize = 0x200; -/// } -/// // Singleton of `CPU1` used to identify it. -/// const CPU1: Cpu1 = Cpu1; -/// -/// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`. -/// register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" { -/// 0:0 start as bool, "Start the CPU core"; -/// }); -/// -/// // The `read`, `write` and `update` methods of relative registers take an extra `base` argument -/// // that is used to resolve its final address by adding its `BASE` to the offset of the -/// // register. -/// -/// // Start `CPU0`. -/// CPU_CTL::update(bar, &CPU0, |r| r.set_start(true)); -/// -/// // Start `CPU1`. -/// CPU_CTL::update(bar, &CPU1, |r| r.set_start(true)); -/// -/// // Aliases can also be defined for relative register. -/// register!(CPU_CTL_ALIAS => CpuCtlBase[CPU_CTL], "Alias to CPU core control" { -/// 1:1 alias_start as bool, "Start the aliased CPU core"; -/// }); -/// -/// // Start the aliased `CPU0`. -/// CPU_CTL_ALIAS::update(bar, &CPU0, |r| r.set_alias_start(true)); -/// ``` -/// -/// ## Arrays of registers -/// -/// Some I/O areas contain consecutive values that can be interpreted in the same way. These areas -/// can be defined as an array of identical registers, allowing them to be accessed by index with -/// compile-time or runtime bound checking. Simply define their address as `Address[Size]`, and add -/// an `idx` parameter to their `read`, `write` and `update` methods: -/// -/// ```no_run -/// # fn no_run() -> Result<(), Error> { -/// # fn get_scratch_idx() -> usize { -/// # 0x15 -/// # } -/// // Array of 64 consecutive registers with the same layout starting at offset `0x80`. -/// register!(SCRATCH @ 0x00000080[64], "Scratch registers" { -/// 31:0 value as u32; -/// }); -/// -/// // Read scratch register 0, i.e. I/O address `0x80`. -/// let scratch_0 = SCRATCH::read(bar, 0).value(); -/// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. -/// let scratch_15 = SCRATCH::read(bar, 15).value(); -/// -/// // This is out of bounds and won't build. -/// // let scratch_128 = SCRATCH::read(bar, 128).value(); -/// -/// // Runtime-obtained array index. -/// let scratch_idx = get_scratch_idx(); -/// // Access on a runtime index returns an error if it is out-of-bounds. -/// let some_scratch = SCRATCH::try_read(bar, scratch_idx)?.value(); -/// -/// // Alias to a particular register in an array. -/// // Here `SCRATCH[8]` is used to convey the firmware exit code. -/// register!(FIRMWARE_STATUS => SCRATCH[8], "Firmware exit status code" { -/// 7:0 status as u8; -/// }); -/// -/// let status = FIRMWARE_STATUS::read(bar).status(); -/// -/// // Non-contiguous register arrays can be defined by adding a stride parameter. -/// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the -/// // registers of the two declarations below are interleaved. -/// register!(SCRATCH_INTERLEAVED_0 @ 0x000000c0[16 ; 8], "Scratch registers bank 0" { -/// 31:0 value as u32; -/// }); -/// register!(SCRATCH_INTERLEAVED_1 @ 0x000000c4[16 ; 8], "Scratch registers bank 1" { -/// 31:0 value as u32; -/// }); -/// # Ok(()) -/// # } -/// ``` -/// -/// ## Relative arrays of registers -/// -/// Combining the two features described in the sections above, arrays of registers accessible from -/// a base can also be defined: -/// -/// ```no_run -/// # fn no_run() -> Result<(), Error> { -/// # fn get_scratch_idx() -> usize { -/// # 0x15 -/// # } -/// // Type used as parameter of `RegisterBase` to specify the base. -/// pub(crate) struct CpuCtlBase; -/// -/// // ZST describing `CPU0`. -/// struct Cpu0; -/// impl RegisterBase<CpuCtlBase> for Cpu0 { -/// const BASE: usize = 0x100; -/// } -/// // Singleton of `CPU0` used to identify it. -/// const CPU0: Cpu0 = Cpu0; -/// -/// // ZST describing `CPU1`. -/// struct Cpu1; -/// impl RegisterBase<CpuCtlBase> for Cpu1 { -/// const BASE: usize = 0x200; -/// } -/// // Singleton of `CPU1` used to identify it. -/// const CPU1: Cpu1 = Cpu1; -/// -/// // 64 per-cpu scratch registers, arranged as an contiguous array. -/// register!(CPU_SCRATCH @ CpuCtlBase[0x00000080[64]], "Per-CPU scratch registers" { -/// 31:0 value as u32; -/// }); -/// -/// let cpu0_scratch_0 = CPU_SCRATCH::read(bar, &Cpu0, 0).value(); -/// let cpu1_scratch_15 = CPU_SCRATCH::read(bar, &Cpu1, 15).value(); -/// -/// // This won't build. -/// // let cpu0_scratch_128 = CPU_SCRATCH::read(bar, &Cpu0, 128).value(); -/// -/// // Runtime-obtained array index. -/// let scratch_idx = get_scratch_idx(); -/// // Access on a runtime value returns an error if it is out-of-bounds. -/// let cpu0_some_scratch = CPU_SCRATCH::try_read(bar, &Cpu0, scratch_idx)?.value(); -/// -/// // `SCRATCH[8]` is used to convey the firmware exit code. -/// register!(CPU_FIRMWARE_STATUS => CpuCtlBase[CPU_SCRATCH[8]], -/// "Per-CPU firmware exit status code" { -/// 7:0 status as u8; -/// }); -/// -/// let cpu0_status = CPU_FIRMWARE_STATUS::read(bar, &Cpu0).status(); -/// -/// // Non-contiguous register arrays can be defined by adding a stride parameter. -/// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the -/// // registers of the two declarations below are interleaved. -/// register!(CPU_SCRATCH_INTERLEAVED_0 @ CpuCtlBase[0x00000d00[16 ; 8]], -/// "Scratch registers bank 0" { -/// 31:0 value as u32; -/// }); -/// register!(CPU_SCRATCH_INTERLEAVED_1 @ CpuCtlBase[0x00000d04[16 ; 8]], -/// "Scratch registers bank 1" { -/// 31:0 value as u32; -/// }); -/// # Ok(()) -/// # } -/// ``` -macro_rules! register { - // Creates a register at a fixed offset of the MMIO space. - ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); - register!(@io_fixed $name @ $offset); - }; - - // Creates an alias register of fixed offset register `alias` with its own fields. - ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); - register!(@io_fixed $name @ $alias::OFFSET); - }; - - // Creates a register at a relative offset from a base address provider. - ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => { - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); - register!(@io_relative $name @ $base [ $offset ]); - }; - - // Creates an alias register of relative offset register `alias` with its own fields. - ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => { - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); - register!(@io_relative $name @ $base [ $alias::OFFSET ]); - }; - - // Creates an array of registers at a fixed offset of the MMIO space. - ( - $name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $comment:literal)? { - $($fields:tt)* - } - ) => { - static_assert!(::core::mem::size_of::<u32>() <= $stride); - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); - register!(@io_array $name @ $offset [ $size ; $stride ]); - }; - - // Shortcut for contiguous array of registers (stride == size of element). - ( - $name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)? { - $($fields:tt)* - } - ) => { - register!($name @ $offset [ $size ; ::core::mem::size_of::<u32>() ] $(, $comment)? { - $($fields)* - } ); - }; - - // Creates an array of registers at a relative offset from a base address provider. - ( - $name:ident @ $base:ty [ $offset:literal [ $size:expr ; $stride:expr ] ] - $(, $comment:literal)? { $($fields:tt)* } - ) => { - static_assert!(::core::mem::size_of::<u32>() <= $stride); - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); - register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]); - }; - - // Shortcut for contiguous array of relative registers (stride == size of element). - ( - $name:ident @ $base:ty [ $offset:literal [ $size:expr ] ] $(, $comment:literal)? { - $($fields:tt)* - } - ) => { - register!($name @ $base [ $offset [ $size ; ::core::mem::size_of::<u32>() ] ] - $(, $comment)? { $($fields)* } ); - }; - - // Creates an alias of register `idx` of relative array of registers `alias` with its own - // fields. - ( - $name:ident => $base:ty [ $alias:ident [ $idx:expr ] ] $(, $comment:literal)? { - $($fields:tt)* - } - ) => { - static_assert!($idx < $alias::SIZE); - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); - register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] ); - }; - - // Creates an alias of register `idx` of array of registers `alias` with its own fields. - // This rule belongs to the (non-relative) register arrays set, but needs to be put last - // to avoid it being interpreted in place of the relative register array alias rule. - ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => { - static_assert!($idx < $alias::SIZE); - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); - register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE ); - }; - - // Generates the IO accessors for a fixed offset register. - (@io_fixed $name:ident @ $offset:expr) => { - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize = $offset; - - /// Read the register from its address in `io`. - #[inline(always)] - pub(crate) fn read<T, I>(io: &T) -> Self where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - { - Self(io.read32($offset)) - } - - /// Write the value contained in `self` to the register address in `io`. - #[inline(always)] - pub(crate) fn write<T, I>(self, io: &T) where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - { - io.write32(self.0, $offset) - } - - /// Read the register from its address in `io` and run `f` on its value to obtain a new - /// value to write back. - #[inline(always)] - pub(crate) fn update<T, I, F>( - io: &T, - f: F, - ) where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg = f(Self::read(io)); - reg.write(io); - } - } - }; - - // Generates the IO accessors for a relative offset register. - (@io_relative $name:ident @ $base:ty [ $offset:expr ]) => { - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize = $offset; - - /// Read the register from `io`, using the base address provided by `base` and adding - /// the register's offset to it. - #[inline(always)] - pub(crate) fn read<T, I, B>( - io: &T, - #[allow(unused_variables)] - base: &B, - ) -> Self where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - { - const OFFSET: usize = $name::OFFSET; - - let value = io.read32( - <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET - ); - - Self(value) - } - - /// Write the value contained in `self` to `io`, using the base address provided by - /// `base` and adding the register's offset to it. - #[inline(always)] - pub(crate) fn write<T, I, B>( - self, - io: &T, - #[allow(unused_variables)] - base: &B, - ) where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - { - const OFFSET: usize = $name::OFFSET; - - io.write32( - self.0, - <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET - ); - } - - /// Read the register from `io`, using the base address provided by `base` and adding - /// the register's offset to it, then run `f` on its value to obtain a new value to - /// write back. - #[inline(always)] - pub(crate) fn update<T, I, B, F>( - io: &T, - base: &B, - f: F, - ) where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg = f(Self::read(io, base)); - reg.write(io, base); - } - } - }; - - // Generates the IO accessors for an array of registers. - (@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]) => { - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize = $offset; - pub(crate) const SIZE: usize = $size; - pub(crate) const STRIDE: usize = $stride; - - /// Read the array register at index `idx` from its address in `io`. - #[inline(always)] - pub(crate) fn read<T, I>( - io: &T, - idx: usize, - ) -> Self where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - { - build_assert!(idx < Self::SIZE); - - let offset = Self::OFFSET + (idx * Self::STRIDE); - let value = io.read32(offset); - - Self(value) - } - - /// Write the value contained in `self` to the array register with index `idx` in `io`. - #[inline(always)] - pub(crate) fn write<T, I>( - self, - io: &T, - idx: usize - ) where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - { - build_assert!(idx < Self::SIZE); - - let offset = Self::OFFSET + (idx * Self::STRIDE); - - io.write32(self.0, offset); - } - - /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a - /// new value to write back. - #[inline(always)] - pub(crate) fn update<T, I, F>( - io: &T, - idx: usize, - f: F, - ) where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg = f(Self::read(io, idx)); - reg.write(io, idx); - } - - /// Read the array register at index `idx` from its address in `io`. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_read<T, I>( - io: &T, - idx: usize, - ) -> ::kernel::error::Result<Self> where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - { - if idx < Self::SIZE { - Ok(Self::read(io, idx)) - } else { - Err(EINVAL) - } - } - - /// Write the value contained in `self` to the array register with index `idx` in `io`. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_write<T, I>( - self, - io: &T, - idx: usize, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - { - if idx < Self::SIZE { - Ok(self.write(io, idx)) - } else { - Err(EINVAL) - } - } - - /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a - /// new value to write back. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_update<T, I, F>( - io: &T, - idx: usize, - f: F, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - F: ::core::ops::FnOnce(Self) -> Self, - { - if idx < Self::SIZE { - Ok(Self::update(io, idx, f)) - } else { - Err(EINVAL) - } - } - } - }; - - // Generates the IO accessors for an array of relative registers. - ( - @io_relative_array $name:ident @ $base:ty - [ $offset:literal [ $size:expr ; $stride:expr ] ] - ) => { - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize = $offset; - pub(crate) const SIZE: usize = $size; - pub(crate) const STRIDE: usize = $stride; - - /// Read the array register at index `idx` from `io`, using the base address provided - /// by `base` and adding the register's offset to it. - #[inline(always)] - pub(crate) fn read<T, I, B>( - io: &T, - #[allow(unused_variables)] - base: &B, - idx: usize, - ) -> Self where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - { - build_assert!(idx < Self::SIZE); - - let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE + - Self::OFFSET + (idx * Self::STRIDE); - let value = io.read32(offset); - - Self(value) - } - - /// Write the value contained in `self` to `io`, using the base address provided by - /// `base` and adding the offset of array register `idx` to it. - #[inline(always)] - pub(crate) fn write<T, I, B>( - self, - io: &T, - #[allow(unused_variables)] - base: &B, - idx: usize - ) where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - { - build_assert!(idx < Self::SIZE); - - let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE + - Self::OFFSET + (idx * Self::STRIDE); - - io.write32(self.0, offset); - } - - /// Read the array register at index `idx` from `io`, using the base address provided - /// by `base` and adding the register's offset to it, then run `f` on its value to - /// obtain a new value to write back. - #[inline(always)] - pub(crate) fn update<T, I, B, F>( - io: &T, - base: &B, - idx: usize, - f: F, - ) where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg = f(Self::read(io, base, idx)); - reg.write(io, base, idx); - } - - /// Read the array register at index `idx` from `io`, using the base address provided - /// by `base` and adding the register's offset to it. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_read<T, I, B>( - io: &T, - base: &B, - idx: usize, - ) -> ::kernel::error::Result<Self> where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - { - if idx < Self::SIZE { - Ok(Self::read(io, base, idx)) - } else { - Err(EINVAL) - } - } - - /// Write the value contained in `self` to `io`, using the base address provided by - /// `base` and adding the offset of array register `idx` to it. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_write<T, I, B>( - self, - io: &T, - base: &B, - idx: usize, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - { - if idx < Self::SIZE { - Ok(self.write(io, base, idx)) - } else { - Err(EINVAL) - } - } - - /// Read the array register at index `idx` from `io`, using the base address provided - /// by `base` and adding the register's offset to it, then run `f` on its value to - /// obtain a new value to write back. - /// - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the - /// access was out-of-bounds. - #[inline(always)] - pub(crate) fn try_update<T, I, B, F>( - io: &T, - base: &B, - idx: usize, - f: F, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref<Target = I>, - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, - B: crate::regs::macros::RegisterBase<$base>, - F: ::core::ops::FnOnce(Self) -> Self, - { - if idx < Self::SIZE { - Ok(Self::update(io, base, idx, f)) - } else { - Err(EINVAL) - } - } - } - }; -} |
