diff options
Diffstat (limited to 'drivers/gpu/drm')
578 files changed, 20522 insertions, 7811 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index ab9ef1c20349..48ca28a2e4ff 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -216,6 +216,13 @@ config DRM_EXEC help Execution context for command submissions +config DRM_GPUVM + tristate + depends on DRM + help + GPU-VM representation providing helpers to manage a GPUs virtual + address space + config DRM_BUDDY tristate depends on DRM diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 215e78e79125..8e1bde059170 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -45,7 +45,6 @@ drm-y := \ drm_vblank.o \ drm_vblank_work.o \ drm_vma_manager.o \ - drm_gpuva_mgr.o \ drm_writeback.o drm-$(CONFIG_DRM_LEGACY) += \ drm_agpsupport.o \ @@ -81,6 +80,7 @@ obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o # # obj-$(CONFIG_DRM_EXEC) += drm_exec.o +obj-$(CONFIG_DRM_GPUVM) += drm_gpuvm.o obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 058d9dc672bf..b6cddcad122f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -662,7 +662,7 @@ struct ip_hw_instance { u8 harvest; int num_base_addresses; - u32 base_addr[]; + u32 base_addr[] __counted_by(num_base_addresses); }; struct ip_hw_id { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index b1ce22a9b186..84beeaa4d21c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -962,6 +962,7 @@ static int amdgpu_debugfs_gem_info_show(struct seq_file *m, void *unused) list_for_each_entry(file, &dev->filelist, lhead) { struct task_struct *task; struct drm_gem_object *gobj; + struct pid *pid; int id; /* @@ -971,8 +972,9 @@ static int amdgpu_debugfs_gem_info_show(struct seq_file *m, void *unused) * Therefore, we need to protect this ->comm access using RCU. */ rcu_read_lock(); - task = pid_task(file->pid, PIDTYPE_TGID); - seq_printf(m, "pid %8d command %s:\n", pid_nr(file->pid), + pid = rcu_dereference(file->pid); + task = pid_task(pid, PIDTYPE_TGID); + seq_printf(m, "pid %8d command %s:\n", pid_nr(pid), task ? task->comm : "<unknown>"); rcu_read_unlock(); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index c6b4337eb20c..10df731998b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -81,7 +81,7 @@ int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, unsigned int size) { struct drm_suballoc *sa = drm_suballoc_new(&sa_manager->base, size, - GFP_KERNEL, true, 0); + GFP_KERNEL, false, 0); if (IS_ERR(sa)) { *sa_bo = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index c7085a747b03..18f58efc9dc7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -424,9 +424,9 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, const struct ttm_place *place, struct ttm_resource **res) { - u64 vis_usage = 0, max_bytes, cur_size, min_block_size; struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); struct amdgpu_device *adev = to_amdgpu_device(mgr); + u64 vis_usage = 0, max_bytes, min_block_size; struct amdgpu_vram_mgr_resource *vres; u64 size, remaining_size, lpfn, fpfn; struct drm_buddy *mm = &mgr->mm; @@ -474,6 +474,9 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, if (place->flags & TTM_PL_FLAG_TOPDOWN) vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) + vres->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION; + if (fpfn || lpfn != mgr->mm.size) /* Allocate blocks in desired range */ vres->flags |= DRM_BUDDY_RANGE_ALLOCATION; @@ -496,25 +499,6 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, !(size & (((u64)pages_per_block << PAGE_SHIFT) - 1))) min_block_size = (u64)pages_per_block << PAGE_SHIFT; - cur_size = size; - - if (fpfn + size != (u64)place->lpfn << PAGE_SHIFT) { - /* - * Except for actual range allocation, modify the size and - * min_block_size conforming to continuous flag enablement - */ - if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { - size = roundup_pow_of_two(size); - min_block_size = size; - /* - * Modify the size value if size is not - * aligned with min_block_size - */ - } else if (!IS_ALIGNED(size, min_block_size)) { - size = round_up(size, min_block_size); - } - } - r = drm_buddy_alloc_blocks(mm, fpfn, lpfn, size, @@ -531,40 +515,6 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, } mutex_unlock(&mgr->lock); - if (cur_size != size) { - struct drm_buddy_block *block; - struct list_head *trim_list; - u64 original_size; - LIST_HEAD(temp); - - trim_list = &vres->blocks; - original_size = (u64)vres->base.size; - - /* - * If size value is rounded up to min_block_size, trim the last - * block to the required size - */ - if (!list_is_singular(&vres->blocks)) { - block = list_last_entry(&vres->blocks, typeof(*block), link); - list_move_tail(&block->link, &temp); - trim_list = &temp; - /* - * Compute the original_size value by subtracting the - * last block size with (aligned size - original size) - */ - original_size = amdgpu_vram_mgr_block_size(block) - (size - cur_size); - } - - mutex_lock(&mgr->lock); - drm_buddy_block_trim(mm, - original_size, - trim_list); - mutex_unlock(&mgr->lock); - - if (!list_empty(&temp)) - list_splice_tail(trim_list, &vres->blocks); - } - vres->base.start = 0; list_for_each_entry(block, &vres->blocks, link) { unsigned long start; diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 5641cf05d856..e63abdf52b6c 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1574,17 +1574,8 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev) u16 bridge_cfg2, gpu_cfg2; u32 max_lw, current_lw, tmp; - pcie_capability_read_word(root, PCI_EXP_LNKCTL, - &bridge_cfg); - pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL, - &gpu_cfg); - - tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; - pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16); - - tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; - pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL, - tmp16); + pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); + pcie_capability_set_word(adev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); tmp = RREG32_PCIE(ixPCIE_LC_STATUS1); max_lw = (tmp & PCIE_LC_STATUS1__LC_DETECTED_LINK_WIDTH_MASK) >> @@ -1637,21 +1628,14 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev) msleep(100); /* linkctl */ - pcie_capability_read_word(root, PCI_EXP_LNKCTL, - &tmp16); - tmp16 &= ~PCI_EXP_LNKCTL_HAWD; - tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); - pcie_capability_write_word(root, PCI_EXP_LNKCTL, - tmp16); - - pcie_capability_read_word(adev->pdev, - PCI_EXP_LNKCTL, - &tmp16); - tmp16 &= ~PCI_EXP_LNKCTL_HAWD; - tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); - pcie_capability_write_word(adev->pdev, - PCI_EXP_LNKCTL, - tmp16); + pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_HAWD, + bridge_cfg & + PCI_EXP_LNKCTL_HAWD); + pcie_capability_clear_and_set_word(adev->pdev, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_HAWD, + gpu_cfg & + PCI_EXP_LNKCTL_HAWD); /* linkctl2 */ pcie_capability_read_word(root, PCI_EXP_LNKCTL2, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c index 355d25fd6169..9a8ec4d7e333 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c @@ -360,8 +360,10 @@ static int jpeg_v4_0_3_hw_fini(void *handle) cancel_delayed_work_sync(&adev->jpeg.idle_work); - if (adev->jpeg.cur_state != AMD_PG_STATE_GATE) - ret = jpeg_v4_0_3_set_powergating_state(adev, AMD_PG_STATE_GATE); + if (!amdgpu_sriov_vf(adev)) { + if (adev->jpeg.cur_state != AMD_PG_STATE_GATE) + ret = jpeg_v4_0_3_set_powergating_state(adev, AMD_PG_STATE_GATE); + } return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index f64b87b11b1b..4b81f29e5fd5 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -2276,17 +2276,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) u16 bridge_cfg2, gpu_cfg2; u32 max_lw, current_lw, tmp; - pcie_capability_read_word(root, PCI_EXP_LNKCTL, - &bridge_cfg); - pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL, - &gpu_cfg); - - tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; - pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16); - - tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; - pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL, - tmp16); + pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); + pcie_capability_set_word(adev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); tmp = RREG32_PCIE(PCIE_LC_STATUS1); max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT; @@ -2331,21 +2322,14 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) mdelay(100); - pcie_capability_read_word(root, PCI_EXP_LNKCTL, - &tmp16); - tmp16 &= ~PCI_EXP_LNKCTL_HAWD; - tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); - pcie_capability_write_word(root, PCI_EXP_LNKCTL, - tmp16); - - pcie_capability_read_word(adev->pdev, - PCI_EXP_LNKCTL, - &tmp16); - tmp16 &= ~PCI_EXP_LNKCTL_HAWD; - tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); - pcie_capability_write_word(adev->pdev, - PCI_EXP_LNKCTL, - tmp16); + pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_HAWD, + bridge_cfg & + PCI_EXP_LNKCTL_HAWD); + pcie_capability_clear_and_set_word(adev->pdev, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_HAWD, + gpu_cfg & + PCI_EXP_LNKCTL_HAWD); pcie_capability_read_word(root, PCI_EXP_LNKCTL2, &tmp16); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index bff5512ae952..f4038b33c404 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -2706,10 +2706,7 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr, return -EFAULT; } - *is_heap_stack = (vma->vm_start <= vma->vm_mm->brk && - vma->vm_end >= vma->vm_mm->start_brk) || - (vma->vm_start <= vma->vm_mm->start_stack && - vma->vm_end >= vma->vm_mm->start_stack); + *is_heap_stack = vma_is_initial_heap(vma) || vma_is_initial_stack(vma); start_limit = max(vma->vm_start >> PAGE_SHIFT, (unsigned long)ALIGN_DOWN(addr, 2UL << 8)); 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 801f87a12ccf..2ac940a38703 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -65,6 +65,7 @@ #include "amdgpu_dm_debugfs.h" #endif #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" #include "ivsrcid/ivsrcid_vislands30.h" @@ -4343,6 +4344,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) enum dc_connection_type new_connection_type = dc_connection_none; const struct dc_plane_cap *plane; bool psr_feature_enabled = false; + bool replay_feature_enabled = false; int max_overlay = dm->dc->caps.max_slave_planes; dm->display_indexes_num = dm->dc->caps.max_streams; @@ -4454,6 +4456,20 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } } + if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) { + switch (adev->ip_versions[DCE_HWIP][0]) { + case IP_VERSION(3, 1, 4): + case IP_VERSION(3, 1, 5): + case IP_VERSION(3, 1, 6): + case IP_VERSION(3, 2, 0): + case IP_VERSION(3, 2, 1): + replay_feature_enabled = true; + break; + default: + replay_feature_enabled = amdgpu_dc_feature_mask & DC_REPLAY_MASK; + break; + } + } /* loops over all connectors on the board */ for (i = 0; i < link_cnt; i++) { struct dc_link *link = NULL; @@ -4502,6 +4518,12 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) amdgpu_dm_update_connector_after_detect(aconnector); setup_backlight_device(dm, aconnector); + /* + * Disable psr if replay can be enabled + */ + if (replay_feature_enabled && amdgpu_dm_setup_replay(link, aconnector)) + psr_feature_enabled = false; + if (psr_feature_enabled) amdgpu_dm_set_psr_caps(link); @@ -6106,6 +6128,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, if (recalculate_timing) drm_mode_set_crtcinfo(&saved_mode, 0); + else if (!old_stream) + drm_mode_set_crtcinfo(&mode, 0); /* * If scaling is enabled and refresh rate didn't change 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 30d4c6fd95f5..97b7a0b8a1c2 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 @@ -29,6 +29,7 @@ #include "dc.h" #include "amdgpu.h" #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" #include "amdgpu_dm_crtc.h" #include "amdgpu_dm_plane.h" #include "amdgpu_dm_trace.h" @@ -123,7 +124,12 @@ static void vblank_control_worker(struct work_struct *work) * fill_dc_dirty_rects(). */ if (vblank_work->stream && vblank_work->stream->link) { - if (vblank_work->enable) { + /* + * Prioritize replay, instead of psr + */ + if (vblank_work->stream->link->replay_settings.replay_feature_enabled) + amdgpu_dm_replay_enable(vblank_work->stream, false); + else if (vblank_work->enable) { if (vblank_work->stream->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && vblank_work->stream->link->psr_settings.psr_allow_active) amdgpu_dm_psr_disable(vblank_work->stream); @@ -132,6 +138,7 @@ static void vblank_control_worker(struct work_struct *work) #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY !amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base) && #endif + vblank_work->stream->link->panel_config.psr.disallow_replay && vblank_work->acrtc->dm_irq_params.allow_psr_entry) { amdgpu_dm_psr_enable(vblank_work->stream); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 286474c04d43..9cd83b780102 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -204,37 +204,35 @@ void dm_helpers_dp_update_branch_info( {} static void dm_helpers_construct_old_payload( - struct dc_link *link, - int pbn_per_slot, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, struct drm_dp_mst_atomic_payload *new_payload, struct drm_dp_mst_atomic_payload *old_payload) { - struct link_mst_stream_allocation_table current_link_table = - link->mst_stream_alloc_table; - struct link_mst_stream_allocation *dc_alloc; - int i; + struct drm_dp_mst_atomic_payload *pos; + int pbn_per_slot = mst_state->pbn_div; + u8 next_payload_vc_start = mgr->next_start_slot; + u8 payload_vc_start = new_payload->vc_start_slot; + u8 allocated_time_slots; *old_payload = *new_payload; /* Set correct time_slots/PBN of old payload. * other fields (delete & dsc_enabled) in * struct drm_dp_mst_atomic_payload are don't care fields - * while calling drm_dp_remove_payload() + * while calling drm_dp_remove_payload_part2() */ - for (i = 0; i < current_link_table.stream_count; i++) { - dc_alloc = - ¤t_link_table.stream_allocations[i]; - - if (dc_alloc->vcp_id == new_payload->vcpi) { - old_payload->time_slots = dc_alloc->slot_count; - old_payload->pbn = dc_alloc->slot_count * pbn_per_slot; - break; - } + list_for_each_entry(pos, &mst_state->payloads, next) { + if (pos != new_payload && + pos->vc_start_slot > payload_vc_start && + pos->vc_start_slot < next_payload_vc_start) + next_payload_vc_start = pos->vc_start_slot; } - /* make sure there is an old payload*/ - ASSERT(i != current_link_table.stream_count); + allocated_time_slots = next_payload_vc_start - payload_vc_start; + old_payload->time_slots = allocated_time_slots; + old_payload->pbn = allocated_time_slots * pbn_per_slot; } /* @@ -263,21 +261,20 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( mst_mgr = &aconnector->mst_root->mst_mgr; mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); - - /* It's OK for this to fail */ new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); if (enable) { target_payload = new_payload; + /* It's OK for this to fail */ drm_dp_add_payload_part1(mst_mgr, mst_state, new_payload); } else { /* construct old payload by VCPI*/ - dm_helpers_construct_old_payload(stream->link, mst_state->pbn_div, - new_payload, &old_payload); + dm_helpers_construct_old_payload(mst_mgr, mst_state, + new_payload, &old_payload); target_payload = &old_payload; - drm_dp_remove_payload(mst_mgr, mst_state, &old_payload, new_payload); + drm_dp_remove_payload_part1(mst_mgr, mst_state, new_payload); } /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or @@ -344,7 +341,7 @@ bool dm_helpers_dp_mst_send_payload_allocation( struct amdgpu_dm_connector *aconnector; struct drm_dp_mst_topology_state *mst_state; struct drm_dp_mst_topology_mgr *mst_mgr; - struct drm_dp_mst_atomic_payload *payload; + struct drm_dp_mst_atomic_payload *new_payload, old_payload; enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD; enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD; int ret = 0; @@ -357,15 +354,20 @@ bool dm_helpers_dp_mst_send_payload_allocation( mst_mgr = &aconnector->mst_root->mst_mgr; mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); - payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); + new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); if (!enable) { set_flag = MST_CLEAR_ALLOCATED_PAYLOAD; clr_flag = MST_ALLOCATE_NEW_PAYLOAD; } - if (enable) - ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload); + if (enable) { + ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload); + } else { + dm_helpers_construct_old_payload(mst_mgr, mst_state, + new_payload, &old_payload); + drm_dp_remove_payload_part2(mst_mgr, mst_state, &old_payload, new_payload); + } if (ret) { amdgpu_dm_set_mst_status(&aconnector->mst_status, diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 98e60bc868dd..614aba75606f 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -244,6 +244,7 @@ enum DC_FEATURE_MASK { DC_DISABLE_LTTPR_DP2_0 = (1 << 6), //0x40, disabled by default DC_PSR_ALLOW_SMU_OPT = (1 << 7), //0x80, disabled by default DC_PSR_ALLOW_MULTI_DISP_OPT = (1 << 8), //0x100, disabled by default + DC_REPLAY_MASK = (1 << 9), //0x200, disabled by default for dcn < 3.1.4 }; enum DC_DEBUG_MASK { @@ -254,6 +255,7 @@ enum DC_DEBUG_MASK { DC_DISABLE_PSR = 0x10, DC_FORCE_SUBVP_MCLK_SWITCH = 0x20, DC_DISABLE_MPO = 0x40, + DC_DISABLE_REPLAY = 0x50, DC_ENABLE_DPIA_TRACE = 0x80, }; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h index 808e0ecbe1f0..42adc2a3dcbc 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h @@ -192,7 +192,7 @@ struct smu10_clock_voltage_dependency_record { struct smu10_voltage_dependency_table { uint32_t count; - struct smu10_clock_voltage_dependency_record entries[]; + struct smu10_clock_voltage_dependency_record entries[] __counted_by(count); }; struct smu10_clock_voltage_information { diff --git a/drivers/gpu/drm/arm/display/include/malidp_utils.h b/drivers/gpu/drm/arm/display/include/malidp_utils.h index 49a1d7f3539c..9f83baac6ed8 100644 --- a/drivers/gpu/drm/arm/display/include/malidp_utils.h +++ b/drivers/gpu/drm/arm/display/include/malidp_utils.h @@ -35,7 +35,7 @@ static inline void set_range(struct malidp_range *rg, u32 start, u32 end) rg->end = end; } -static inline bool in_range(struct malidp_range *rg, u32 v) +static inline bool malidp_in_range(struct malidp_range *rg, u32 v) { return (v >= rg->start) && (v <= rg->end); } 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 6c56f5662bc7..80973975bfdb 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c @@ -521,7 +521,7 @@ static struct komeda_format_caps d71_format_caps_table[] = { {__HW_ID(5, 1), DRM_FORMAT_YUYV, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */ {__HW_ID(5, 2), DRM_FORMAT_YUYV, RICH, Flip_H_V, 0, 0}, {__HW_ID(5, 3), DRM_FORMAT_UYVY, RICH, Flip_H_V, 0, 0}, - {__HW_ID(5, 6), DRM_FORMAT_NV12, RICH, Flip_H_V, 0, 0}, + {__HW_ID(5, 6), DRM_FORMAT_NV12, RICH_WB, Flip_H_V, 0, 0}, {__HW_ID(5, 6), DRM_FORMAT_YUV420_8BIT, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */ {__HW_ID(5, 7), DRM_FORMAT_YUV420, RICH, Flip_H_V, 0, 0}, /* YUV 10bit*/ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index cb2a2be24c5f..cc57ea4e13ae 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -45,6 +45,14 @@ static void komeda_platform_remove(struct platform_device *pdev) devm_kfree(dev, mdrv); } +static void komeda_platform_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct komeda_drv *mdrv = dev_get_drvdata(dev); + + komeda_kms_shutdown(mdrv->kms); +} + static int komeda_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -142,6 +150,7 @@ static const struct dev_pm_ops komeda_pm_ops = { static struct platform_driver komeda_platform_driver = { .probe = komeda_platform_probe, .remove_new = komeda_platform_remove, + .shutdown = komeda_platform_shutdown, .driver = { .name = "komeda", .of_match_table = komeda_of_match, diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 9299026701f3..fe46b0ebefea 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -340,3 +340,10 @@ void komeda_kms_detach(struct komeda_kms_dev *kms) komeda_kms_cleanup_private_objs(kms); drm->dev_private = NULL; } + +void komeda_kms_shutdown(struct komeda_kms_dev *kms) +{ + struct drm_device *drm = &kms->base; + + drm_atomic_helper_shutdown(drm); +} diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h index 6ef655326357..a4048724564d 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h @@ -190,5 +190,6 @@ void komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc, struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev); void komeda_kms_detach(struct komeda_kms_dev *kms); +void komeda_kms_shutdown(struct komeda_kms_dev *kms); #endif /*_KOMEDA_KMS_H_*/ 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 3276a3e82c62..f3e744172673 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -305,12 +305,12 @@ komeda_layer_check_cfg(struct komeda_layer *layer, if (komeda_fb_check_src_coords(kfb, src_x, src_y, src_w, src_h)) return -EINVAL; - if (!in_range(&layer->hsize_in, src_w)) { + if (!malidp_in_range(&layer->hsize_in, src_w)) { DRM_DEBUG_ATOMIC("invalidate src_w %d.\n", src_w); return -EINVAL; } - if (!in_range(&layer->vsize_in, src_h)) { + if (!malidp_in_range(&layer->vsize_in, src_h)) { DRM_DEBUG_ATOMIC("invalidate src_h %d.\n", src_h); return -EINVAL; } @@ -452,14 +452,14 @@ komeda_scaler_check_cfg(struct komeda_scaler *scaler, hsize_out = dflow->out_w; vsize_out = dflow->out_h; - if (!in_range(&scaler->hsize, hsize_in) || - !in_range(&scaler->hsize, hsize_out)) { + if (!malidp_in_range(&scaler->hsize, hsize_in) || + !malidp_in_range(&scaler->hsize, hsize_out)) { DRM_DEBUG_ATOMIC("Invalid horizontal sizes"); return -EINVAL; } - if (!in_range(&scaler->vsize, vsize_in) || - !in_range(&scaler->vsize, vsize_out)) { + if (!malidp_in_range(&scaler->vsize, vsize_in) || + !malidp_in_range(&scaler->vsize, vsize_out)) { DRM_DEBUG_ATOMIC("Invalid vertical sizes"); return -EINVAL; } @@ -574,13 +574,13 @@ komeda_splitter_validate(struct komeda_splitter *splitter, return -EINVAL; } - if (!in_range(&splitter->hsize, dflow->in_w)) { + if (!malidp_in_range(&splitter->hsize, dflow->in_w)) { DRM_DEBUG_ATOMIC("split in_w:%d is out of the acceptable range.\n", dflow->in_w); return -EINVAL; } - if (!in_range(&splitter->vsize, dflow->in_h)) { + if (!malidp_in_range(&splitter->vsize, dflow->in_h)) { DRM_DEBUG_ATOMIC("split in_h: %d exceeds the acceptable range.\n", dflow->in_h); return -EINVAL; @@ -624,13 +624,13 @@ komeda_merger_validate(struct komeda_merger *merger, return -EINVAL; } - if (!in_range(&merger->hsize_merged, output->out_w)) { + if (!malidp_in_range(&merger->hsize_merged, output->out_w)) { DRM_DEBUG_ATOMIC("merged_w: %d is out of the accepted range.\n", output->out_w); return -EINVAL; } - if (!in_range(&merger->vsize_merged, output->out_h)) { + if (!malidp_in_range(&merger->vsize_merged, output->out_h)) { DRM_DEBUG_ATOMIC("merged_h: %d is out of the accepted range.\n", output->out_h); return -EINVAL; @@ -866,8 +866,8 @@ void komeda_complete_data_flow_cfg(struct komeda_layer *layer, * input/output range. */ if (dflow->en_scaling && scaler) - dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) || - !in_range(&scaler->hsize, dflow->out_w); + dflow->en_split = !malidp_in_range(&scaler->hsize, dflow->in_w) || + !malidp_in_range(&scaler->hsize, dflow->out_w); } static bool merger_is_available(struct komeda_pipeline *pipe, @@ -1223,7 +1223,7 @@ int komeda_build_display_data_flow(struct komeda_crtc *kcrtc, return 0; } -static void +static int komeda_pipeline_unbound_components(struct komeda_pipeline *pipe, struct komeda_pipeline_state *new) { @@ -1243,8 +1243,12 @@ komeda_pipeline_unbound_components(struct komeda_pipeline *pipe, c = komeda_pipeline_get_component(pipe, id); c_st = komeda_component_get_state_and_set_user(c, drm_st, NULL, new->crtc); + if (PTR_ERR(c_st) == -EDEADLK) + return -EDEADLK; WARN_ON(IS_ERR(c_st)); } + + return 0; } /* release unclaimed pipeline resource */ @@ -1266,9 +1270,8 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe, if (WARN_ON(IS_ERR_OR_NULL(st))) return -EINVAL; - komeda_pipeline_unbound_components(pipe, st); + return komeda_pipeline_unbound_components(pipe, st); - return 0; } /* Since standalone disabled components must be disabled separately and in the diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index aa06f9838015..32be9e370049 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -372,6 +372,11 @@ static void hdlcd_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &hdlcd_master_ops); } +static void hdlcd_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct of_device_id hdlcd_of_match[] = { { .compatible = "arm,hdlcd" }, {}, @@ -399,6 +404,7 @@ static SIMPLE_DEV_PM_OPS(hdlcd_pm_ops, hdlcd_pm_suspend, hdlcd_pm_resume); static struct platform_driver hdlcd_platform_driver = { .probe = hdlcd_probe, .remove_new = hdlcd_remove, + .shutdown = hdlcd_shutdown, .driver = { .name = "hdlcd", .pm = &hdlcd_pm_ops, diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 62329d5dd992..6682131d2910 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -941,6 +941,11 @@ static void malidp_platform_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &malidp_master_ops); } +static void malidp_platform_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static int __maybe_unused malidp_pm_suspend(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); @@ -982,6 +987,7 @@ static const struct dev_pm_ops malidp_pm_ops = { static struct platform_driver malidp_platform_driver = { .probe = malidp_platform_probe, .remove_new = malidp_platform_remove, + .shutdown = malidp_platform_shutdown, .driver = { .name = "mali-dp", .pm = &malidp_pm_ops, diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index e8d2fe955909..fa1c67598706 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -148,6 +148,7 @@ static int armada_drm_bind(struct device *dev) err_kms: drm_mode_config_cleanup(&priv->drm); drm_mm_takedown(&priv->linear); + dev_set_drvdata(dev, NULL); return ret; } @@ -166,6 +167,7 @@ static void armada_drm_unbind(struct device *dev) drm_mode_config_cleanup(&priv->drm); drm_mm_takedown(&priv->linear); + dev_set_drvdata(dev, NULL); } static void armada_add_endpoints(struct device *dev, @@ -230,6 +232,11 @@ static int armada_drm_remove(struct platform_device *pdev) return 0; } +static void armada_drm_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct platform_device_id armada_drm_platform_ids[] = { { .name = "armada-drm", @@ -243,6 +250,7 @@ MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids); static struct platform_driver armada_drm_platform_driver = { .probe = armada_drm_probe, .remove = armada_drm_remove, + .shutdown = armada_drm_shutdown, .driver = { .name = "armada-drm", }, diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index d207b03f8357..78122b35a0cb 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -358,11 +358,18 @@ static void aspeed_gfx_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &aspeed_sysfs_attr_group); drm_dev_unregister(drm); aspeed_gfx_unload(drm); + drm_atomic_helper_shutdown(drm); +} + +static void aspeed_gfx_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); } static struct platform_driver aspeed_gfx_platform_driver = { .probe = aspeed_gfx_probe, .remove_new = aspeed_gfx_remove, + .shutdown = aspeed_gfx_shutdown, .driver = { .name = "aspeed_gfx", .of_match_table = aspeed_gfx_match, diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index e1224ef4ad83..cf5b754f044c 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -125,6 +125,11 @@ static void ast_pci_remove(struct pci_dev *pdev) drm_atomic_helper_shutdown(dev); } +static void ast_pci_shutdown(struct pci_dev *pdev) +{ + drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); +} + static int ast_drm_freeze(struct drm_device *dev) { int error; @@ -209,6 +214,7 @@ static struct pci_driver ast_pci_driver = { .id_table = ast_pciidlist, .probe = ast_pci_probe, .remove = ast_pci_remove, + .shutdown = ast_pci_shutdown, .driver.pm = &ast_pm_ops, }; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index fa0f9a93d50d..84c54e8622d1 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -782,6 +782,11 @@ static void atmel_hlcdc_dc_drm_remove(struct platform_device *pdev) drm_dev_put(ddev); } +static void atmel_hlcdc_dc_drm_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static int atmel_hlcdc_dc_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); @@ -825,6 +830,7 @@ static const struct of_device_id atmel_hlcdc_dc_of_match[] = { static struct platform_driver atmel_hlcdc_dc_platform_driver = { .probe = atmel_hlcdc_dc_drm_probe, .remove_new = atmel_hlcdc_dc_drm_remove, + .shutdown = atmel_hlcdc_dc_drm_shutdown, .driver = { .name = "atmel-hlcdc-display-controller", .pm = pm_sleep_ptr(&atmel_hlcdc_dc_drm_pm_ops), diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 44a660a4bdbf..ba82a1142adf 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -181,6 +181,7 @@ config DRM_NWL_MIPI_DSI select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY select GENERIC_PHY_MIPI_DPHY select MFD_SYSCON select MULTIPLEXER @@ -227,6 +228,7 @@ config DRM_SAMSUNG_DSIM select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY select GENERIC_PHY_MIPI_DPHY help The Samsung MIPI DSIM bridge controller driver. diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 2611afd2c1c1..d518de88b5c3 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -121,7 +121,7 @@ static const struct regmap_config adv7511_regmap_config = { .val_bits = 8, .max_register = 0xff, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults_raw = adv7511_register_defaults, .num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults), @@ -1068,7 +1068,7 @@ static const struct regmap_config adv7511_cec_regmap_config = { .val_bits = 8, .max_register = 0xff, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = adv7511_cec_register_volatile, }; diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index 800555aef97f..5748a8581af4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -1211,6 +1211,7 @@ static const u16 anx78xx_chipid_list[] = { 0x7808, 0x7812, 0x7814, + 0x7816, 0x7818, }; @@ -1231,9 +1232,7 @@ static int anx78xx_i2c_probe(struct i2c_client *client) mutex_init(&anx78xx->lock); -#if IS_ENABLED(CONFIG_OF) anx78xx->bridge.of_node = client->dev.of_node; -#endif anx78xx->client = client; i2c_set_clientdata(client, anx78xx); @@ -1367,16 +1366,11 @@ static void anx78xx_i2c_remove(struct i2c_client *client) kfree(anx78xx->edid); } -static const struct i2c_device_id anx78xx_id[] = { - { "anx7814", 0 }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(i2c, anx78xx_id); - static const struct of_device_id anx78xx_match_table[] = { { .compatible = "analogix,anx7808", .data = anx7808_i2c_addresses }, { .compatible = "analogix,anx7812", .data = anx781x_i2c_addresses }, { .compatible = "analogix,anx7814", .data = anx781x_i2c_addresses }, + { .compatible = "analogix,anx7816", .data = anx781x_i2c_addresses }, { .compatible = "analogix,anx7818", .data = anx781x_i2c_addresses }, { /* sentinel */ }, }; @@ -1389,7 +1383,6 @@ static struct i2c_driver anx78xx_driver = { }, .probe = anx78xx_i2c_probe, .remove = anx78xx_i2c_remove, - .id_table = anx78xx_id, }; module_i2c_driver(anx78xx_driver); diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 51abe42c639e..8f740154707d 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1464,6 +1464,9 @@ static int _anx7625_hpd_polling(struct anx7625_data *ctx, if (ctx->pdata.intp_irq) return 0; + /* Delay 200ms for FW HPD de-bounce */ + msleep(200); + ret = readx_poll_timeout(anx7625_read_hpd_status_p0, ctx, val, ((val & HPD_STATUS) || (val < 0)), diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig index ec35215a2003..cced81633ddc 100644 --- a/drivers/gpu/drm/bridge/cadence/Kconfig +++ b/drivers/gpu/drm/bridge/cadence/Kconfig @@ -4,6 +4,7 @@ config DRM_CDNS_DSI select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY select GENERIC_PHY_MIPI_DPHY depends on OF help diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index d205e755e524..82d23e4df09e 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -197,7 +197,7 @@ static const struct regmap_config chipone_regmap_config = { .val_bits = 8, .rd_table = &chipone_dsi_readable_table, .wr_table = &chipone_dsi_writeable_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = MIPI_ATE_STATUS(1), }; diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c index 466641c77fe9..1cf3fb1f13dc 100644 --- a/drivers/gpu/drm/bridge/ite-it66121.c +++ b/drivers/gpu/drm/bridge/ite-it66121.c @@ -884,14 +884,14 @@ static struct edid *it66121_bridge_get_edid(struct drm_bridge *bridge, mutex_lock(&ctx->lock); ret = it66121_preamble_ddc(ctx); if (ret) { - edid = ERR_PTR(ret); + edid = NULL; goto out_unlock; } ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG, IT66121_DDC_HEADER_EDID); if (ret) { - edid = ERR_PTR(ret); + edid = NULL; goto out_unlock; } @@ -1447,10 +1447,14 @@ static int it66121_audio_get_eld(struct device *dev, void *data, struct it66121_ctx *ctx = dev_get_drvdata(dev); mutex_lock(&ctx->lock); - - memcpy(buf, ctx->connector->eld, - min(sizeof(ctx->connector->eld), len)); - + if (!ctx->connector) { + /* Pass en empty ELD if connector not available */ + dev_dbg(dev, "No connector present, passing empty EDID data"); + memset(buf, 0, len); + } else { + memcpy(buf, ctx->connector->eld, + min(sizeof(ctx->connector->eld), len)); + } mutex_unlock(&ctx->lock); return 0; @@ -1501,7 +1505,6 @@ static const char * const it66121_supplies[] = { static int it66121_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 }; struct device_node *ep; int ret; @@ -1523,7 +1526,7 @@ static int it66121_probe(struct i2c_client *client) ctx->dev = dev; ctx->client = client; - ctx->info = (const struct it66121_chip_info *) id->driver_data; + ctx->info = i2c_get_match_data(client); of_property_read_u32(ep, "bus-width", &ctx->bus_width); of_node_put(ep); @@ -1609,13 +1612,6 @@ static void it66121_remove(struct i2c_client *client) mutex_destroy(&ctx->lock); } -static const struct of_device_id it66121_dt_match[] = { - { .compatible = "ite,it66121" }, - { .compatible = "ite,it6610" }, - { } -}; -MODULE_DEVICE_TABLE(of, it66121_dt_match); - static const struct it66121_chip_info it66121_chip_info = { .id = ID_IT66121, .vid = 0x4954, @@ -1628,6 +1624,13 @@ static const struct it66121_chip_info it6610_chip_info = { .pid = 0x0611, }; +static const struct of_device_id it66121_dt_match[] = { + { .compatible = "ite,it66121", &it66121_chip_info }, + { .compatible = "ite,it6610", &it6610_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, it66121_dt_match); + static const struct i2c_device_id it66121_id[] = { { "it66121", (kernel_ulong_t) &it66121_chip_info }, { "it6610", (kernel_ulong_t) &it6610_chip_info }, diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 4eaea67fb71c..03532efb893b 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -45,7 +45,6 @@ struct lt8912 { u8 data_lanes; bool is_power_on; - bool is_attached; }; static int lt8912_write_init_config(struct lt8912 *lt) @@ -559,6 +558,13 @@ static int lt8912_bridge_attach(struct drm_bridge *bridge, struct lt8912 *lt = bridge_to_lt8912(bridge); int ret; + ret = drm_bridge_attach(bridge->encoder, lt->hdmi_port, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) { + dev_err(lt->dev, "Failed to attach next bridge (%d)\n", ret); + return ret; + } + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { ret = lt8912_bridge_connector_init(bridge); if (ret) { @@ -575,8 +581,6 @@ static int lt8912_bridge_attach(struct drm_bridge *bridge, if (ret) goto error; - lt->is_attached = true; - return 0; error: @@ -588,15 +592,10 @@ static void lt8912_bridge_detach(struct drm_bridge *bridge) { struct lt8912 *lt = bridge_to_lt8912(bridge); - if (lt->is_attached) { - lt8912_hard_power_off(lt); - - if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) - drm_bridge_hpd_disable(lt->hdmi_port); + lt8912_hard_power_off(lt); - drm_connector_unregister(<->connector); - drm_connector_cleanup(<->connector); - } + if (lt->connector.dev && lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) + drm_bridge_hpd_disable(lt->hdmi_port); } static enum drm_connector_status @@ -750,7 +749,6 @@ static void lt8912_remove(struct i2c_client *client) { struct lt8912 *lt = i2c_get_clientdata(client); - lt8912_bridge_detach(<->bridge); drm_bridge_remove(<->bridge); lt8912_free_i2c(lt); lt8912_put_dt(lt); diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c b/drivers/gpu/drm/bridge/lontium-lt9211.c index 4d404f5ef87e..c8881796fba4 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9211.c +++ b/drivers/gpu/drm/bridge/lontium-lt9211.c @@ -89,7 +89,7 @@ static const struct regmap_config lt9211_regmap_config = { .volatile_table = <9211_rw_table, .ranges = <9211_range, .num_ranges = 1, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 0xda00, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 22c84d29c2bc..7835738a532e 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -296,7 +296,7 @@ static int lt9611uxc_connector_get_modes(struct drm_connector *connector) unsigned int count; struct edid *edid; - edid = lt9611uxc->bridge.funcs->get_edid(<9611uxc->bridge, connector); + edid = drm_bridge_get_edid(<9611uxc->bridge, connector); drm_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c index 8c5668dca0c4..991732c4b629 100644 --- a/drivers/gpu/drm/bridge/lvds-codec.c +++ b/drivers/gpu/drm/bridge/lvds-codec.c @@ -5,6 +5,7 @@ */ #include <linux/gpio/consumer.h> +#include <linux/media-bus-format.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> @@ -71,12 +72,6 @@ static void lvds_codec_disable(struct drm_bridge *bridge) "Failed to disable regulator \"vcc\": %d\n", ret); } -static const struct drm_bridge_funcs funcs = { - .attach = lvds_codec_attach, - .enable = lvds_codec_enable, - .disable = lvds_codec_disable, -}; - #define MAX_INPUT_SEL_FORMATS 1 static u32 * lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge, @@ -102,7 +97,7 @@ lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge, return input_fmts; } -static const struct drm_bridge_funcs funcs_decoder = { +static const struct drm_bridge_funcs funcs = { .attach = lvds_codec_attach, .enable = lvds_codec_enable, .disable = lvds_codec_disable, @@ -184,8 +179,9 @@ static int lvds_codec_probe(struct platform_device *pdev) return ret; } else { lvds_codec->bus_format = ret; - lvds_codec->bridge.funcs = &funcs_decoder; } + } else { + lvds_codec->bus_format = MEDIA_BUS_FMT_RGB888_1X24; } /* diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 9316384b4474..e48823a4f1ed 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -4,6 +4,8 @@ * Copyright (C) 2017 Broadcom */ +#include <linux/device.h> + #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_connector.h> @@ -19,6 +21,7 @@ struct panel_bridge { struct drm_bridge bridge; struct drm_connector connector; struct drm_panel *panel; + struct device_link *link; u32 connector_type; }; @@ -60,13 +63,24 @@ static int panel_bridge_attach(struct drm_bridge *bridge, { struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); struct drm_connector *connector = &panel_bridge->connector; + struct drm_panel *panel = panel_bridge->panel; + struct drm_device *drm_dev = bridge->dev; int ret; + panel_bridge->link = device_link_add(drm_dev->dev, panel->dev, + DL_FLAG_STATELESS); + if (!panel_bridge->link) { + DRM_ERROR("Failed to add device link between %s and %s\n", + dev_name(drm_dev->dev), dev_name(panel->dev)); + return -EINVAL; + } + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) return 0; if (!bridge->encoder) { DRM_ERROR("Missing encoder\n"); + device_link_del(panel_bridge->link); return -ENODEV; } @@ -78,6 +92,7 @@ static int panel_bridge_attach(struct drm_bridge *bridge, panel_bridge->connector_type); if (ret) { DRM_ERROR("Failed to initialize connector\n"); + device_link_del(panel_bridge->link); return ret; } @@ -100,6 +115,8 @@ static void panel_bridge_detach(struct drm_bridge *bridge) struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); struct drm_connector *connector = &panel_bridge->connector; + device_link_del(panel_bridge->link); + /* * Cleanup the connector if we know it was initialized. * @@ -302,9 +319,7 @@ struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, panel_bridge->panel = panel; panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs; -#ifdef CONFIG_OF panel_bridge->bridge.of_node = panel->dev->of_node; -#endif panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES; panel_bridge->bridge.type = connector_type; diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index c49091691ab1..be5914caa17d 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -385,7 +385,7 @@ static const unsigned int imx8mm_dsim_reg_values[] = { [RESET_TYPE] = DSIM_SWRST, [PLL_TIMER] = 500, [STOP_STATE_CNT] = 0xf, - [PHYCTRL_ULPS_EXIT] = 0, + [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0xaf), [PHYCTRL_VREG_LP] = 0, [PHYCTRL_SLEW_UP] = 0, [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x06), @@ -410,9 +410,12 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, + .has_broken_fifoctrl_emptyhdr = 1, }; static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { @@ -426,9 +429,12 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, + .has_broken_fifoctrl_emptyhdr = 1, }; static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { @@ -440,6 +446,8 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, @@ -455,6 +463,8 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .num_bits_resol = 12, .pll_p_offset = 13, .reg_values = exynos5433_reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, @@ -470,6 +480,8 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .num_bits_resol = 12, .pll_p_offset = 13, .reg_values = exynos5422_reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, @@ -489,6 +501,8 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { */ .pll_p_offset = 14, .reg_values = imx8mm_dsim_reg_values, + .pll_fin_min = 2, + .pll_fin_max = 30, .m_min = 64, .m_max = 1023, .min_freq = 1050, @@ -612,7 +626,23 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, u16 m; u32 reg; - fin = dsi->pll_clk_rate; + if (dsi->pll_clk) { + /* + * Ensure that the reference clock is generated with a power of + * two divider from its parent, but close to the PLLs upper + * limit. + */ + fin = clk_get_rate(clk_get_parent(dsi->pll_clk)); + while (fin > driver_data->pll_fin_max * MHZ) + fin /= 2; + clk_set_rate(dsi->pll_clk, fin); + + fin = clk_get_rate(dsi->pll_clk); + } else { + fin = dsi->pll_clk_rate; + } + dev_dbg(dsi->dev, "PLL ref clock freq %lu\n", fin); + fout = samsung_dsim_pll_find_pms(dsi, fin, freq, &p, &m, &s); if (!fout) { dev_err(dsi->dev, @@ -958,10 +988,12 @@ static void samsung_dsim_set_display_mode(struct samsung_dsim *dsi) u32 reg; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { - int byte_clk_khz = dsi->hs_clock / 1000 / 8; - int hfp = (m->hsync_start - m->hdisplay) * byte_clk_khz / m->clock; - int hbp = (m->htotal - m->hsync_end) * byte_clk_khz / m->clock; - int hsa = (m->hsync_end - m->hsync_start) * byte_clk_khz / m->clock; + u64 byte_clk = dsi->hs_clock / 8; + u64 pix_clk = m->clock * 1000; + + int hfp = DIV64_U64_ROUND_UP((m->hsync_start - m->hdisplay) * byte_clk, pix_clk); + int hbp = DIV64_U64_ROUND_UP((m->htotal - m->hsync_end) * byte_clk, pix_clk); + int hsa = DIV64_U64_ROUND_UP((m->hsync_end - m->hsync_start) * byte_clk, pix_clk); /* remove packet overhead when possible */ hfp = max(hfp - 6, 0); @@ -1010,8 +1042,20 @@ static int samsung_dsim_wait_for_hdr_fifo(struct samsung_dsim *dsi) do { u32 reg = samsung_dsim_read(dsi, DSIM_FIFOCTRL_REG); - if (reg & DSIM_SFR_HEADER_EMPTY) - return 0; + if (!dsi->driver_data->has_broken_fifoctrl_emptyhdr) { + if (reg & DSIM_SFR_HEADER_EMPTY) + return 0; + } else { + if (!(reg & DSIM_SFR_HEADER_FULL)) { + /* + * Wait a little bit, so the pending data can + * actually leave the FIFO to avoid overflow. + */ + if (!cond_resched()) + usleep_range(950, 1050); + return 0; + } + } if (!cond_resched()) usleep_range(950, 1050); @@ -1387,6 +1431,18 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi) disable_irq(dsi->irq); } +static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable) +{ + u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); + + if (enable) + reg |= DSIM_FORCE_STOP_STATE; + else + reg &= ~DSIM_FORCE_STOP_STATE; + + samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); +} + static int samsung_dsim_init(struct samsung_dsim *dsi) { const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; @@ -1446,15 +1502,12 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct samsung_dsim *dsi = bridge_to_dsi(bridge); - u32 reg; if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) { samsung_dsim_set_display_mode(dsi); samsung_dsim_set_display_enable(dsi, true); } else { - reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); - reg &= ~DSIM_FORCE_STOP_STATE; - samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); + samsung_dsim_set_stop_state(dsi, false); } dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; @@ -1464,16 +1517,12 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct samsung_dsim *dsi = bridge_to_dsi(bridge); - u32 reg; if (!(dsi->state & DSIM_STATE_ENABLED)) return; - if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) { - reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); - reg |= DSIM_FORCE_STOP_STATE; - samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); - } + if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) + samsung_dsim_set_stop_state(dsi, true); dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1707,7 +1756,10 @@ of_find_panel_or_bridge: return ret; } - DRM_DEV_INFO(dev, "Attached %s device\n", device->name); + DRM_DEV_INFO(dev, "Attached %s device (lanes:%d bpp:%d mode-flags:0x%lx)\n", + device->name, device->lanes, + mipi_dsi_pixel_format_to_bpp(device->format), + device->mode_flags); drm_bridge_add(&dsi->bridge); @@ -1776,6 +1828,8 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host, if (ret) return ret; + samsung_dsim_set_stop_state(dsi, false); + ret = mipi_dsi_create_packet(&xfer.packet, msg); if (ret < 0) return ret; @@ -1812,18 +1866,15 @@ static int samsung_dsim_parse_dt(struct samsung_dsim *dsi) u32 lane_polarities[5] = { 0 }; struct device_node *endpoint; int i, nr_lanes, ret; - struct clk *pll_clk; ret = samsung_dsim_of_read_u32(node, "samsung,pll-clock-frequency", &dsi->pll_clk_rate, 1); /* If it doesn't exist, read it from the clock instead of failing */ if (ret < 0) { dev_dbg(dev, "Using sclk_mipi for pll clock frequency\n"); - pll_clk = devm_clk_get(dev, "sclk_mipi"); - if (!IS_ERR(pll_clk)) - dsi->pll_clk_rate = clk_get_rate(pll_clk); - else - return PTR_ERR(pll_clk); + dsi->pll_clk = devm_clk_get(dev, "sclk_mipi"); + if (IS_ERR(dsi->pll_clk)) + return PTR_ERR(dsi->pll_clk); } /* If it doesn't exist, use pixel clock instead of failing */ @@ -1984,7 +2035,7 @@ err_disable_runtime: } EXPORT_SYMBOL_GPL(samsung_dsim_probe); -int samsung_dsim_remove(struct platform_device *pdev) +void samsung_dsim_remove(struct platform_device *pdev) { struct samsung_dsim *dsi = platform_get_drvdata(pdev); @@ -1992,8 +2043,6 @@ int samsung_dsim_remove(struct platform_device *pdev) if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->unregister_host) dsi->plat_data->host_ops->unregister_host(dsi); - - return 0; } EXPORT_SYMBOL_GPL(samsung_dsim_remove); @@ -2093,7 +2142,7 @@ MODULE_DEVICE_TABLE(of, samsung_dsim_of_match); static struct platform_driver samsung_dsim_driver = { .probe = samsung_dsim_probe, - .remove = samsung_dsim_remove, + .remove_new = samsung_dsim_remove, .driver = { .name = "samsung-dsim", .pm = &samsung_dsim_pm_ops, diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c index be21c11de1f2..673661160e54 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c @@ -145,6 +145,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) cec->tx_status = CEC_TX_STATUS_NACK; cec->tx_done = true; ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_ARBLOST) { + cec->tx_status = CEC_TX_STATUS_ARB_LOST; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; } if (stat & CEC_STAT_EOM) { @@ -209,7 +213,7 @@ static int dw_hdmi_cec_enable(struct cec_adapter *adap, bool enable) cec->ops->enable(cec->hdmi); irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM | - CEC_STAT_DONE; + CEC_STAT_ARBLOST | CEC_STAT_DONE; dw_hdmi_write(cec, irqs, HDMI_CEC_POLARITY); dw_hdmi_write(cec, ~irqs, HDMI_CEC_MASK); dw_hdmi_write(cec, ~irqs, HDMI_IH_MUTE_CEC_STAT0); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 6c1d79474505..52d91a0df85e 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -3541,9 +3541,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, | DRM_BRIDGE_OP_HPD; hdmi->bridge.interlace_allowed = true; hdmi->bridge.ddc = hdmi->ddc; -#ifdef CONFIG_OF hdmi->bridge.of_node = pdev->dev.of_node; -#endif memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.parent = dev; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 04d4a1a10698..a8dd2a2e7c7b 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -1182,9 +1182,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, dsi->bridge.driver_private = dsi; dsi->bridge.funcs = &dw_mipi_dsi_bridge_funcs; -#ifdef CONFIG_OF dsi->bridge.of_node = pdev->dev.of_node; -#endif return dsi; } diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index b45bffab7c81..ef2e373606ba 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2005,7 +2005,7 @@ static const struct regmap_config tc_regmap_config = { .val_bits = 32, .reg_stride = 4, .max_register = PLL_DBG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .readable_reg = tc_readable_reg, .volatile_table = &tc_volatile_table, .writeable_reg = tc_writeable_reg, diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index 819a4b6ec2a0..0e8813278a2f 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -9,12 +9,14 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/kernel.h> +#include <linux/math64.h> #include <linux/media-bus-format.h> #include <linux/minmax.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/units.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> @@ -156,6 +158,7 @@ struct tc358768_priv { u32 frs; /* PLL Freqency range for HSCK (post divider) */ u32 dsiclk; /* pll_clk / 2 */ + u32 pclk; /* incoming pclk rate */ }; static inline struct tc358768_priv *dsi_host_to_tc358768(struct mipi_dsi_host @@ -216,6 +219,10 @@ static void tc358768_update_bits(struct tc358768_priv *priv, u32 reg, u32 mask, u32 tmp, orig; tc358768_read(priv, reg, &orig); + + if (priv->error) + return; + tmp = orig & ~mask; tmp |= val & mask; if (tmp != orig) @@ -312,7 +319,7 @@ static int tc358768_calc_pll(struct tc358768_priv *priv, target_pll = tc358768_pclk_to_pll(priv, mode->clock * 1000); - /* pll_clk = RefClk * [(FBD + 1)/ (PRD + 1)] * [1 / (2^FRS)] */ + /* pll_clk = RefClk * FBD / PRD * (1 / (2^FRS)) */ for (i = 0; i < ARRAY_SIZE(frs_limits); i++) if (target_pll >= frs_limits[i]) @@ -332,19 +339,19 @@ static int tc358768_calc_pll(struct tc358768_priv *priv, best_prd = 0; best_fbd = 0; - for (prd = 0; prd < 16; ++prd) { - u32 divisor = (prd + 1) * (1 << frs); + for (prd = 1; prd <= 16; ++prd) { + u32 divisor = prd * (1 << frs); u32 fbd; - for (fbd = 0; fbd < 512; ++fbd) { + for (fbd = 1; fbd <= 512; ++fbd) { u32 pll, diff, pll_in; - pll = (u32)div_u64((u64)refclk * (fbd + 1), divisor); + pll = (u32)div_u64((u64)refclk * fbd, divisor); if (pll >= max_pll || pll < min_pll) continue; - pll_in = (u32)div_u64((u64)refclk, prd + 1); + pll_in = (u32)div_u64((u64)refclk, prd); if (pll_in < 4000000) continue; @@ -375,6 +382,7 @@ found: priv->prd = best_prd; priv->frs = frs; priv->dsiclk = best_pll / 2; + priv->pclk = mode->clock * 1000; return 0; } @@ -600,14 +608,14 @@ static int tc358768_setup_pll(struct tc358768_priv *priv, dev_dbg(priv->dev, "PLL: refclk %lu, fbd %u, prd %u, frs %u\n", clk_get_rate(priv->refclk), fbd, prd, frs); - dev_dbg(priv->dev, "PLL: pll_clk: %u, DSIClk %u, DSIByteClk %u\n", + dev_dbg(priv->dev, "PLL: pll_clk: %u, DSIClk %u, HSByteClk %u\n", priv->dsiclk * 2, priv->dsiclk, priv->dsiclk / 4); dev_dbg(priv->dev, "PLL: pclk %u (panel: %u)\n", tc358768_pll_to_pclk(priv, priv->dsiclk * 2), mode->clock * 1000); /* PRD[15:12] FBD[8:0] */ - tc358768_write(priv, TC358768_PLLCTL0, (prd << 12) | fbd); + tc358768_write(priv, TC358768_PLLCTL0, ((prd - 1) << 12) | (fbd - 1)); /* FRS[11:10] LBWS[9:8] CKEN[4] RESETB[1] EN[0] */ tc358768_write(priv, TC358768_PLLCTL1, @@ -623,15 +631,36 @@ static int tc358768_setup_pll(struct tc358768_priv *priv, return tc358768_clear_error(priv); } -#define TC358768_PRECISION 1000 -static u32 tc358768_ns_to_cnt(u32 ns, u32 period_nsk) +static u32 tc358768_ns_to_cnt(u32 ns, u32 period_ps) +{ + return DIV_ROUND_UP(ns * 1000, period_ps); +} + +static u32 tc358768_ps_to_ns(u32 ps) { - return (ns * TC358768_PRECISION + period_nsk) / period_nsk; + return ps / 1000; +} + +static u32 tc358768_dpi_to_ns(u32 val, u32 pclk) +{ + return (u32)div_u64((u64)val * NANO, pclk); +} + +/* Convert value in DPI pixel clock units to DSI byte count */ +static u32 tc358768_dpi_to_dsi_bytes(struct tc358768_priv *priv, u32 val) +{ + u64 m = (u64)val * priv->dsiclk / 4 * priv->dsi_lanes; + u64 n = priv->pclk; + + return (u32)div_u64(m + n - 1, n); } -static u32 tc358768_to_ns(u32 nsk) +static u32 tc358768_dsi_bytes_to_ns(struct tc358768_priv *priv, u32 val) { - return (nsk / TC358768_PRECISION); + u64 m = (u64)val * NANO; + u64 n = priv->dsiclk / 4 * priv->dsi_lanes; + + return (u32)div_u64(m, n); } static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) @@ -642,13 +671,23 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) u32 val, val2, lptxcnt, hact, data_type; s32 raw_val; const struct drm_display_mode *mode; - u32 dsibclk_nsk, dsiclk_nsk, ui_nsk; - u32 dsiclk, dsibclk, video_start; - const u32 internal_delay = 40; + u32 hsbyteclk_ps, dsiclk_ps, ui_ps; + u32 dsiclk, hsbyteclk; int ret, i; + struct videomode vm; + struct device *dev = priv->dev; + /* In pixelclock units */ + u32 dpi_htot, dpi_data_start; + /* In byte units */ + u32 dsi_dpi_htot, dsi_dpi_data_start; + u32 dsi_hsw, dsi_hbp, dsi_hact, dsi_hfp; + const u32 dsi_hss = 4; /* HSS is a short packet (4 bytes) */ + /* In hsbyteclk units */ + u32 dsi_vsdly; + const u32 internal_dly = 40; if (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) { - dev_warn_once(priv->dev, "Non-continuous mode unimplemented, falling back to continuous\n"); + dev_warn_once(dev, "Non-continuous mode unimplemented, falling back to continuous\n"); mode_flags &= ~MIPI_DSI_CLOCK_NON_CONTINUOUS; } @@ -656,7 +695,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) ret = tc358768_sw_reset(priv); if (ret) { - dev_err(priv->dev, "Software reset failed: %d\n", ret); + dev_err(dev, "Software reset failed: %d\n", ret); tc358768_hw_disable(priv); return; } @@ -664,53 +703,194 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) mode = &bridge->encoder->crtc->state->adjusted_mode; ret = tc358768_setup_pll(priv, mode); if (ret) { - dev_err(priv->dev, "PLL setup failed: %d\n", ret); + dev_err(dev, "PLL setup failed: %d\n", ret); tc358768_hw_disable(priv); return; } + drm_display_mode_to_videomode(mode, &vm); + dsiclk = priv->dsiclk; - dsibclk = dsiclk / 4; + hsbyteclk = dsiclk / 4; /* Data Format Control Register */ val = BIT(2) | BIT(1) | BIT(0); /* rdswap_en | dsitx_en | txdt_en */ switch (dsi_dev->format) { case MIPI_DSI_FMT_RGB888: val |= (0x3 << 4); - hact = mode->hdisplay * 3; - video_start = (mode->htotal - mode->hsync_start) * 3; + hact = vm.hactive * 3; data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; break; case MIPI_DSI_FMT_RGB666: val |= (0x4 << 4); - hact = mode->hdisplay * 3; - video_start = (mode->htotal - mode->hsync_start) * 3; + hact = vm.hactive * 3; data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; break; case MIPI_DSI_FMT_RGB666_PACKED: val |= (0x4 << 4) | BIT(3); - hact = mode->hdisplay * 18 / 8; - video_start = (mode->htotal - mode->hsync_start) * 18 / 8; + hact = vm.hactive * 18 / 8; data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; break; case MIPI_DSI_FMT_RGB565: val |= (0x5 << 4); - hact = mode->hdisplay * 2; - video_start = (mode->htotal - mode->hsync_start) * 2; + hact = vm.hactive * 2; data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; break; default: - dev_err(priv->dev, "Invalid data format (%u)\n", + dev_err(dev, "Invalid data format (%u)\n", dsi_dev->format); tc358768_hw_disable(priv); return; } + /* + * There are three important things to make TC358768 work correctly, + * which are not trivial to manage: + * + * 1. Keep the DPI line-time and the DSI line-time as close to each + * other as possible. + * 2. TC358768 goes to LP mode after each line's active area. The DSI + * HFP period has to be long enough for entering and exiting LP mode. + * But it is not clear how to calculate this. + * 3. VSDly (video start delay) has to be long enough to ensure that the + * DSI TX does not start transmitting until we have started receiving + * pixel data from the DPI input. It is not clear how to calculate + * this either. + */ + + dpi_htot = vm.hactive + vm.hfront_porch + vm.hsync_len + vm.hback_porch; + dpi_data_start = vm.hsync_len + vm.hback_porch; + + dev_dbg(dev, "dpi horiz timing (pclk): %u + %u + %u + %u = %u\n", + vm.hsync_len, vm.hback_porch, vm.hactive, vm.hfront_porch, + dpi_htot); + + dev_dbg(dev, "dpi horiz timing (ns): %u + %u + %u + %u = %u\n", + tc358768_dpi_to_ns(vm.hsync_len, vm.pixelclock), + tc358768_dpi_to_ns(vm.hback_porch, vm.pixelclock), + tc358768_dpi_to_ns(vm.hactive, vm.pixelclock), + tc358768_dpi_to_ns(vm.hfront_porch, vm.pixelclock), + tc358768_dpi_to_ns(dpi_htot, vm.pixelclock)); + + dev_dbg(dev, "dpi data start (ns): %u + %u = %u\n", + tc358768_dpi_to_ns(vm.hsync_len, vm.pixelclock), + tc358768_dpi_to_ns(vm.hback_porch, vm.pixelclock), + tc358768_dpi_to_ns(dpi_data_start, vm.pixelclock)); + + dsi_dpi_htot = tc358768_dpi_to_dsi_bytes(priv, dpi_htot); + dsi_dpi_data_start = tc358768_dpi_to_dsi_bytes(priv, dpi_data_start); + + if (dsi_dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { + dsi_hsw = tc358768_dpi_to_dsi_bytes(priv, vm.hsync_len); + dsi_hbp = tc358768_dpi_to_dsi_bytes(priv, vm.hback_porch); + } else { + /* HBP is included in HSW in event mode */ + dsi_hbp = 0; + dsi_hsw = tc358768_dpi_to_dsi_bytes(priv, + vm.hsync_len + + vm.hback_porch); + + /* + * The pixel packet includes the actual pixel data, and: + * DSI packet header = 4 bytes + * DCS code = 1 byte + * DSI packet footer = 2 bytes + */ + dsi_hact = hact + 4 + 1 + 2; + + dsi_hfp = dsi_dpi_htot - dsi_hact - dsi_hsw - dsi_hss; + + /* + * Here we should check if HFP is long enough for entering LP + * and exiting LP, but it's not clear how to calculate that. + * Instead, this is a naive algorithm that just adjusts the HFP + * and HSW so that HFP is (at least) roughly 2/3 of the total + * blanking time. + */ + if (dsi_hfp < (dsi_hfp + dsi_hsw + dsi_hss) * 2 / 3) { + u32 old_hfp = dsi_hfp; + u32 old_hsw = dsi_hsw; + u32 tot = dsi_hfp + dsi_hsw + dsi_hss; + + dsi_hsw = tot / 3; + + /* + * Seems like sometimes HSW has to be divisible by num-lanes, but + * not always... + */ + dsi_hsw = roundup(dsi_hsw, priv->dsi_lanes); + + dsi_hfp = dsi_dpi_htot - dsi_hact - dsi_hsw - dsi_hss; + + dev_dbg(dev, + "hfp too short, adjusting dsi hfp and dsi hsw from %u, %u to %u, %u\n", + old_hfp, old_hsw, dsi_hfp, dsi_hsw); + } + + dev_dbg(dev, + "dsi horiz timing (bytes): %u, %u + %u + %u + %u = %u\n", + dsi_hss, dsi_hsw, dsi_hbp, dsi_hact, dsi_hfp, + dsi_hss + dsi_hsw + dsi_hbp + dsi_hact + dsi_hfp); + + dev_dbg(dev, "dsi horiz timing (ns): %u + %u + %u + %u + %u = %u\n", + tc358768_dsi_bytes_to_ns(priv, dsi_hss), + tc358768_dsi_bytes_to_ns(priv, dsi_hsw), + tc358768_dsi_bytes_to_ns(priv, dsi_hbp), + tc358768_dsi_bytes_to_ns(priv, dsi_hact), + tc358768_dsi_bytes_to_ns(priv, dsi_hfp), + tc358768_dsi_bytes_to_ns(priv, dsi_hss + dsi_hsw + + dsi_hbp + dsi_hact + dsi_hfp)); + } + + /* VSDly calculation */ + + /* Start with the HW internal delay */ + dsi_vsdly = internal_dly; + + /* Convert to byte units as the other variables are in byte units */ + dsi_vsdly *= priv->dsi_lanes; + + /* Do we need more delay, in addition to the internal? */ + if (dsi_dpi_data_start > dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp) { + dsi_vsdly = dsi_dpi_data_start - dsi_hss - dsi_hsw - dsi_hbp; + dsi_vsdly = roundup(dsi_vsdly, priv->dsi_lanes); + } + + dev_dbg(dev, "dsi data start (bytes) %u + %u + %u + %u = %u\n", + dsi_vsdly, dsi_hss, dsi_hsw, dsi_hbp, + dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp); + + dev_dbg(dev, "dsi data start (ns) %u + %u + %u + %u = %u\n", + tc358768_dsi_bytes_to_ns(priv, dsi_vsdly), + tc358768_dsi_bytes_to_ns(priv, dsi_hss), + tc358768_dsi_bytes_to_ns(priv, dsi_hsw), + tc358768_dsi_bytes_to_ns(priv, dsi_hbp), + tc358768_dsi_bytes_to_ns(priv, dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp)); + + /* Convert back to hsbyteclk */ + dsi_vsdly /= priv->dsi_lanes; + + /* + * The docs say that there is an internal delay of 40 cycles. + * However, we get underflows if we follow that rule. If we + * instead ignore the internal delay, things work. So either + * the docs are wrong or the calculations are wrong. + * + * As a temporary fix, add the internal delay here, to counter + * the subtraction when writing the register. + */ + dsi_vsdly += internal_dly; + + /* Clamp to the register max */ + if (dsi_vsdly - internal_dly > 0x3ff) { + dev_warn(dev, "VSDly too high, underflows likely\n"); + dsi_vsdly = 0x3ff + internal_dly; + } + /* VSDly[9:0] */ - video_start = max(video_start, internal_delay + 1) - internal_delay; - tc358768_write(priv, TC358768_VSDLY, video_start); + tc358768_write(priv, TC358768_VSDLY, dsi_vsdly - internal_dly); tc358768_write(priv, TC358768_DATAFMT, val); tc358768_write(priv, TC358768_DSITX_DT, data_type); @@ -722,67 +902,67 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) tc358768_write(priv, TC358768_D0W_CNTRL + i * 4, 0x0000); /* DSI Timings */ - dsibclk_nsk = (u32)div_u64((u64)1000000000 * TC358768_PRECISION, - dsibclk); - dsiclk_nsk = (u32)div_u64((u64)1000000000 * TC358768_PRECISION, dsiclk); - ui_nsk = dsiclk_nsk / 2; - dev_dbg(priv->dev, "dsiclk_nsk: %u\n", dsiclk_nsk); - dev_dbg(priv->dev, "ui_nsk: %u\n", ui_nsk); - dev_dbg(priv->dev, "dsibclk_nsk: %u\n", dsibclk_nsk); + hsbyteclk_ps = (u32)div_u64(PICO, hsbyteclk); + dsiclk_ps = (u32)div_u64(PICO, dsiclk); + ui_ps = dsiclk_ps / 2; + dev_dbg(dev, "dsiclk: %u ps, ui %u ps, hsbyteclk %u ps\n", dsiclk_ps, + ui_ps, hsbyteclk_ps); /* LP11 > 100us for D-PHY Rx Init */ - val = tc358768_ns_to_cnt(100 * 1000, dsibclk_nsk) - 1; - dev_dbg(priv->dev, "LINEINITCNT: 0x%x\n", val); + val = tc358768_ns_to_cnt(100 * 1000, hsbyteclk_ps) - 1; + dev_dbg(dev, "LINEINITCNT: %u\n", val); tc358768_write(priv, TC358768_LINEINITCNT, val); /* LPTimeCnt > 50ns */ - val = tc358768_ns_to_cnt(50, dsibclk_nsk) - 1; + val = tc358768_ns_to_cnt(50, hsbyteclk_ps) - 1; lptxcnt = val; - dev_dbg(priv->dev, "LPTXTIMECNT: 0x%x\n", val); + dev_dbg(dev, "LPTXTIMECNT: %u\n", val); tc358768_write(priv, TC358768_LPTXTIMECNT, val); /* 38ns < TCLK_PREPARE < 95ns */ - val = tc358768_ns_to_cnt(65, dsibclk_nsk) - 1; + val = tc358768_ns_to_cnt(65, hsbyteclk_ps) - 1; + dev_dbg(dev, "TCLK_PREPARECNT %u\n", val); /* TCLK_PREPARE + TCLK_ZERO > 300ns */ - val2 = tc358768_ns_to_cnt(300 - tc358768_to_ns(2 * ui_nsk), - dsibclk_nsk) - 2; + val2 = tc358768_ns_to_cnt(300 - tc358768_ps_to_ns(2 * ui_ps), + hsbyteclk_ps) - 2; + dev_dbg(dev, "TCLK_ZEROCNT %u\n", val2); val |= val2 << 8; - dev_dbg(priv->dev, "TCLK_HEADERCNT: 0x%x\n", val); tc358768_write(priv, TC358768_TCLK_HEADERCNT, val); /* TCLK_TRAIL > 60ns AND TEOT <= 105 ns + 12*UI */ - raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(2 * ui_nsk), dsibclk_nsk) - 5; + raw_val = tc358768_ns_to_cnt(60 + tc358768_ps_to_ns(2 * ui_ps), hsbyteclk_ps) - 5; val = clamp(raw_val, 0, 127); - dev_dbg(priv->dev, "TCLK_TRAILCNT: 0x%x\n", val); + dev_dbg(dev, "TCLK_TRAILCNT: %u\n", val); tc358768_write(priv, TC358768_TCLK_TRAILCNT, val); /* 40ns + 4*UI < THS_PREPARE < 85ns + 6*UI */ - val = 50 + tc358768_to_ns(4 * ui_nsk); - val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 1; + val = 50 + tc358768_ps_to_ns(4 * ui_ps); + val = tc358768_ns_to_cnt(val, hsbyteclk_ps) - 1; + dev_dbg(dev, "THS_PREPARECNT %u\n", val); /* THS_PREPARE + THS_ZERO > 145ns + 10*UI */ - raw_val = tc358768_ns_to_cnt(145 - tc358768_to_ns(3 * ui_nsk), dsibclk_nsk) - 10; + raw_val = tc358768_ns_to_cnt(145 - tc358768_ps_to_ns(3 * ui_ps), hsbyteclk_ps) - 10; val2 = clamp(raw_val, 0, 127); + dev_dbg(dev, "THS_ZEROCNT %u\n", val2); val |= val2 << 8; - dev_dbg(priv->dev, "THS_HEADERCNT: 0x%x\n", val); tc358768_write(priv, TC358768_THS_HEADERCNT, val); /* TWAKEUP > 1ms in lptxcnt steps */ - val = tc358768_ns_to_cnt(1020000, dsibclk_nsk); + val = tc358768_ns_to_cnt(1020000, hsbyteclk_ps); val = val / (lptxcnt + 1) - 1; - dev_dbg(priv->dev, "TWAKEUP: 0x%x\n", val); + dev_dbg(dev, "TWAKEUP: %u\n", val); tc358768_write(priv, TC358768_TWAKEUP, val); /* TCLK_POSTCNT > 60ns + 52*UI */ - val = tc358768_ns_to_cnt(60 + tc358768_to_ns(52 * ui_nsk), - dsibclk_nsk) - 3; - dev_dbg(priv->dev, "TCLK_POSTCNT: 0x%x\n", val); + val = tc358768_ns_to_cnt(60 + tc358768_ps_to_ns(52 * ui_ps), + hsbyteclk_ps) - 3; + dev_dbg(dev, "TCLK_POSTCNT: %u\n", val); tc358768_write(priv, TC358768_TCLK_POSTCNT, val); /* max(60ns + 4*UI, 8*UI) < THS_TRAILCNT < 105ns + 12*UI */ - raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(18 * ui_nsk), - dsibclk_nsk) - 4; + raw_val = tc358768_ns_to_cnt(60 + tc358768_ps_to_ns(18 * ui_ps), + hsbyteclk_ps) - 4; val = clamp(raw_val, 0, 15); - dev_dbg(priv->dev, "THS_TRAILCNT: 0x%x\n", val); + dev_dbg(dev, "THS_TRAILCNT: %u\n", val); tc358768_write(priv, TC358768_THS_TRAILCNT, val); val = BIT(0); @@ -790,16 +970,17 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) val |= BIT(i + 1); tc358768_write(priv, TC358768_HSTXVREGEN, val); - if (!(mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) - tc358768_write(priv, TC358768_TXOPTIONCNTRL, 0x1); + tc358768_write(priv, TC358768_TXOPTIONCNTRL, + (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0 : BIT(0)); /* TXTAGOCNT[26:16] RXTASURECNT[10:0] */ - val = tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk * 4); - val = tc358768_ns_to_cnt(val, dsibclk_nsk) / 4 - 1; - val2 = tc358768_ns_to_cnt(tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk), - dsibclk_nsk) - 2; + val = tc358768_ps_to_ns((lptxcnt + 1) * hsbyteclk_ps * 4); + val = tc358768_ns_to_cnt(val, hsbyteclk_ps) / 4 - 1; + dev_dbg(dev, "TXTAGOCNT: %u\n", val); + val2 = tc358768_ns_to_cnt(tc358768_ps_to_ns((lptxcnt + 1) * hsbyteclk_ps), + hsbyteclk_ps) - 2; + dev_dbg(dev, "RXTASURECNT: %u\n", val2); val = val << 16 | val2; - dev_dbg(priv->dev, "BTACNTRL1: 0x%x\n", val); tc358768_write(priv, TC358768_BTACNTRL1, val); /* START[0] */ @@ -810,58 +991,44 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) tc358768_write(priv, TC358768_DSI_EVENT, 0); /* vact */ - tc358768_write(priv, TC358768_DSI_VACT, mode->vdisplay); + tc358768_write(priv, TC358768_DSI_VACT, vm.vactive); /* vsw */ - tc358768_write(priv, TC358768_DSI_VSW, - mode->vsync_end - mode->vsync_start); + tc358768_write(priv, TC358768_DSI_VSW, vm.vsync_len); + /* vbp */ - tc358768_write(priv, TC358768_DSI_VBPR, - mode->vtotal - mode->vsync_end); - - /* hsw * byteclk * ndl / pclk */ - val = (u32)div_u64((mode->hsync_end - mode->hsync_start) * - ((u64)priv->dsiclk / 4) * priv->dsi_lanes, - mode->clock * 1000); - tc358768_write(priv, TC358768_DSI_HSW, val); - - /* hbp * byteclk * ndl / pclk */ - val = (u32)div_u64((mode->htotal - mode->hsync_end) * - ((u64)priv->dsiclk / 4) * priv->dsi_lanes, - mode->clock * 1000); - tc358768_write(priv, TC358768_DSI_HBPR, val); + tc358768_write(priv, TC358768_DSI_VBPR, vm.vback_porch); } else { /* Set event mode */ tc358768_write(priv, TC358768_DSI_EVENT, 1); /* vact */ - tc358768_write(priv, TC358768_DSI_VACT, mode->vdisplay); + tc358768_write(priv, TC358768_DSI_VACT, vm.vactive); /* vsw (+ vbp) */ tc358768_write(priv, TC358768_DSI_VSW, - mode->vtotal - mode->vsync_start); + vm.vsync_len + vm.vback_porch); + /* vbp (not used in event mode) */ tc358768_write(priv, TC358768_DSI_VBPR, 0); + } - /* (hsw + hbp) * byteclk * ndl / pclk */ - val = (u32)div_u64((mode->htotal - mode->hsync_start) * - ((u64)priv->dsiclk / 4) * priv->dsi_lanes, - mode->clock * 1000); - tc358768_write(priv, TC358768_DSI_HSW, val); + /* hsw (bytes) */ + tc358768_write(priv, TC358768_DSI_HSW, dsi_hsw); - /* hbp (not used in event mode) */ - tc358768_write(priv, TC358768_DSI_HBPR, 0); - } + /* hbp (bytes) */ + tc358768_write(priv, TC358768_DSI_HBPR, dsi_hbp); /* hact (bytes) */ tc358768_write(priv, TC358768_DSI_HACT, hact); /* VSYNC polarity */ - if (!(mode->flags & DRM_MODE_FLAG_NVSYNC)) - tc358768_update_bits(priv, TC358768_CONFCTL, BIT(5), BIT(5)); + tc358768_update_bits(priv, TC358768_CONFCTL, BIT(5), + (mode->flags & DRM_MODE_FLAG_PVSYNC) ? BIT(5) : 0); + /* HSYNC polarity */ - if (mode->flags & DRM_MODE_FLAG_PHSYNC) - tc358768_update_bits(priv, TC358768_PP_MISC, BIT(0), BIT(0)); + tc358768_update_bits(priv, TC358768_PP_MISC, BIT(0), + (mode->flags & DRM_MODE_FLAG_PHSYNC) ? BIT(0) : 0); /* Start DSI Tx */ tc358768_write(priv, TC358768_DSI_START, 0x1); @@ -891,7 +1058,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) ret = tc358768_clear_error(priv); if (ret) { - dev_err(priv->dev, "Bridge pre_enable failed: %d\n", ret); + dev_err(dev, "Bridge pre_enable failed: %d\n", ret); tc358768_bridge_disable(bridge); tc358768_bridge_post_disable(bridge); } @@ -959,9 +1126,27 @@ tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge, return input_fmts; } +static bool tc358768_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* Default to positive sync */ + + if (!(adjusted_mode->flags & + (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC))) + adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC; + + if (!(adjusted_mode->flags & + (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))) + adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC; + + return true; +} + static const struct drm_bridge_funcs tc358768_bridge_funcs = { .attach = tc358768_bridge_attach, .mode_valid = tc358768_bridge_mode_valid, + .mode_fixup = tc358768_mode_fixup, .pre_enable = tc358768_bridge_pre_enable, .enable = tc358768_bridge_enable, .disable = tc358768_bridge_disable, diff --git a/drivers/gpu/drm/bridge/ti-dlpc3433.c b/drivers/gpu/drm/bridge/ti-dlpc3433.c index b65632ec7e7d..ca3348109bcd 100644 --- a/drivers/gpu/drm/bridge/ti-dlpc3433.c +++ b/drivers/gpu/drm/bridge/ti-dlpc3433.c @@ -100,7 +100,7 @@ static struct regmap_config dlpc_regmap_config = { .max_register = WR_DSI_PORT_EN, .writeable_noinc_reg = dlpc_writeable_noinc_reg, .volatile_table = &dlpc_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .name = "dlpc3433", }; diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 061e8bd5915d..4814b7b6d1fd 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -233,7 +233,7 @@ static const struct regmap_config sn65dsi83_regmap_config = { .rd_table = &sn65dsi83_readable_table, .wr_table = &sn65dsi83_writeable_table, .volatile_table = &sn65dsi83_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = REG_IRQ_STAT, }; diff --git a/drivers/gpu/drm/ci/arm.config b/drivers/gpu/drm/ci/arm.config new file mode 100644 index 000000000000..871f4de063ad --- /dev/null +++ b/drivers/gpu/drm/ci/arm.config @@ -0,0 +1,69 @@ +CONFIG_LOCALVERSION_AUTO=y +CONFIG_DEBUG_KERNEL=y + +CONFIG_CRYPTO_ZSTD=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC_STAT=y + +# abootimg with a 'dummy' rootfs fails with root=/dev/nfs +CONFIG_BLK_DEV_INITRD=n + +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y + +CONFIG_DRM=y +CONFIG_DRM_ETNAVIV=y +CONFIG_DRM_ROCKCHIP=y +CONFIG_DRM_PANFROST=y +CONFIG_DRM_LIMA=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_PWM_CROS_EC=y +CONFIG_BACKLIGHT_PWM=y + +CONFIG_ROCKCHIP_CDN_DP=n + +CONFIG_SPI_ROCKCHIP=y +CONFIG_PWM_ROCKCHIP=y +CONFIG_PHY_ROCKCHIP_DP=y +CONFIG_DWMAC_ROCKCHIP=y + +CONFIG_MFD_RK808=y +CONFIG_REGULATOR_RK808=y +CONFIG_RTC_DRV_RK808=y +CONFIG_COMMON_CLK_RK808=y + +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR=y + +CONFIG_REGULATOR_VCTRL=y + +CONFIG_KASAN=n +CONFIG_KASAN_INLINE=n +CONFIG_STACKTRACE=n + +CONFIG_TMPFS=y + +CONFIG_PROVE_LOCKING=n +CONFIG_DEBUG_LOCKDEP=n +CONFIG_SOFTLOCKUP_DETECTOR=n +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=n + +CONFIG_FW_LOADER_COMPRESS=y + +CONFIG_USB_USBNET=y +CONFIG_NETDEVICES=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_RTL8152=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_SMSC95XX=y + +# TK1 +CONFIG_ARM_TEGRA_DEVFREQ=y + +# 32-bit build failure +CONFIG_DRM_MSM=n diff --git a/drivers/gpu/drm/ci/arm64.config b/drivers/gpu/drm/ci/arm64.config new file mode 100644 index 000000000000..817e18ddfd4f --- /dev/null +++ b/drivers/gpu/drm/ci/arm64.config @@ -0,0 +1,199 @@ +CONFIG_LOCALVERSION_AUTO=y +CONFIG_DEBUG_KERNEL=y + +CONFIG_CRYPTO_ZSTD=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC_STAT=y + +# abootimg with a 'dummy' rootfs fails with root=/dev/nfs +CONFIG_BLK_DEV_INITRD=n + +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_PASSIVE=y + +CONFIG_DRM=y +CONFIG_DRM_ROCKCHIP=y +CONFIG_DRM_PANFROST=y +CONFIG_DRM_LIMA=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_DRM_PANEL_EDP=y +CONFIG_DRM_MSM=y +CONFIG_DRM_ETNAVIV=y +CONFIG_DRM_I2C_ADV7511=y +CONFIG_PWM_CROS_EC=y +CONFIG_BACKLIGHT_PWM=y + +CONFIG_ROCKCHIP_CDN_DP=n + +CONFIG_SPI_ROCKCHIP=y +CONFIG_PWM_ROCKCHIP=y +CONFIG_PHY_ROCKCHIP_DP=y +CONFIG_DWMAC_ROCKCHIP=y +CONFIG_STMMAC_ETH=y +CONFIG_TYPEC_FUSB302=y +CONFIG_TYPEC=y +CONFIG_TYPEC_TCPM=y + +# MSM platform bits + +# For CONFIG_QCOM_LMH +CONFIG_OF=y + +CONFIG_ARM_SMMU_QCOM=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_RPMHPD=y +CONFIG_QCOM_RPMPD=y +CONFIG_QCOM_OCMEM=y +CONFIG_SDM_GPUCC_845=y +CONFIG_SDM_VIDEOCC_845=y +CONFIG_SDM_DISPCC_845=y +CONFIG_SDM_LPASSCC_845=y +CONFIG_SDM_CAMCC_845=y +CONFIG_RESET_QCOM_PDC=y +CONFIG_DRM_TI_SN65DSI86=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_PHY_QCOM_QUSB2=y +CONFIG_PHY_QCOM_QMP=y +CONFIG_MSM_GCC_8996=y +CONFIG_QCOM_CLK_APCC_MSM8996=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_LMH=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_QCOM_WDT=y +CONFIG_POWER_RESET_QCOM_PON=y +CONFIG_RTC_DRV_PM8XXX=y +CONFIG_INTERCONNECT=y +CONFIG_INTERCONNECT_QCOM=y +CONFIG_INTERCONNECT_QCOM_MSM8996=y +CONFIG_INTERCONNECT_QCOM_SDM845=y +CONFIG_INTERCONNECT_QCOM_MSM8916=y +CONFIG_INTERCONNECT_QCOM_MSM8996=y +CONFIG_INTERCONNECT_QCOM_OSM_L3=y +CONFIG_INTERCONNECT_QCOM_SC7180=y +CONFIG_INTERCONNECT_QCOM_SM8350=y +CONFIG_CRYPTO_DEV_QCOM_RNG=y +CONFIG_SC_DISPCC_7180=y +CONFIG_SC_GPUCC_7180=y +CONFIG_SM_GPUCC_8350=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_DRM_PARADE_PS8640=y +CONFIG_DRM_LONTIUM_LT9611UXC=y +CONFIG_PHY_QCOM_USB_HS=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_USB_ONBOARD_HUB=y +CONFIG_NVMEM_QCOM_QFPROM=y +CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y + + +# db410c ethernet +CONFIG_USB_RTL8152=y +# db820c ethernet +CONFIG_ATL1C=y +# Chromebooks ethernet +CONFIG_USB_ONBOARD_HUB=y +# 888 HDK ethernet +CONFIG_USB_LAN78XX=y + +CONFIG_ARCH_ALPINE=n +CONFIG_ARCH_BCM2835=y +CONFIG_ARCH_BCM_IPROC=n +CONFIG_ARCH_BERLIN=n +CONFIG_ARCH_BRCMSTB=n +CONFIG_ARCH_EXYNOS=n +CONFIG_ARCH_K3=n +CONFIG_ARCH_LAYERSCAPE=n +CONFIG_ARCH_LG1K=n +CONFIG_ARCH_HISI=n +CONFIG_ARCH_MVEBU=n +CONFIG_ARCH_SEATTLE=n +CONFIG_ARCH_SYNQUACER=n +CONFIG_ARCH_RENESAS=n +CONFIG_ARCH_R8A774A1=n +CONFIG_ARCH_R8A774C0=n +CONFIG_ARCH_R8A7795=n +CONFIG_ARCH_R8A7796=n +CONFIG_ARCH_R8A77965=n +CONFIG_ARCH_R8A77970=n +CONFIG_ARCH_R8A77980=n +CONFIG_ARCH_R8A77990=n +CONFIG_ARCH_R8A77995=n +CONFIG_ARCH_STRATIX10=n +CONFIG_ARCH_TEGRA=n +CONFIG_ARCH_SPRD=n +CONFIG_ARCH_THUNDER=n +CONFIG_ARCH_THUNDER2=n +CONFIG_ARCH_UNIPHIER=n +CONFIG_ARCH_VEXPRESS=n +CONFIG_ARCH_XGENE=n +CONFIG_ARCH_ZX=n +CONFIG_ARCH_ZYNQMP=n + +# Strip out some stuff we don't need for graphics testing, to reduce +# the build. +CONFIG_CAN=n +CONFIG_WIRELESS=n +CONFIG_RFKILL=n +CONFIG_WLAN=n + +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR=y + +CONFIG_REGULATOR_VCTRL=y + +CONFIG_KASAN=n +CONFIG_KASAN_INLINE=n +CONFIG_STACKTRACE=n + +CONFIG_TMPFS=y + +CONFIG_PROVE_LOCKING=n +CONFIG_DEBUG_LOCKDEP=n +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y + +CONFIG_DETECT_HUNG_TASK=y + +CONFIG_FW_LOADER_COMPRESS=y +CONFIG_FW_LOADER_USER_HELPER=n + +CONFIG_USB_USBNET=y +CONFIG_NETDEVICES=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_RTL8152=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_SMSC95XX=y + +# For amlogic +CONFIG_MESON_GXL_PHY=y +CONFIG_MDIO_BUS_MUX_MESON_G12A=y +CONFIG_DRM_MESON=y + +# For Mediatek +CONFIG_DRM_MEDIATEK=y +CONFIG_PWM_MEDIATEK=y +CONFIG_DRM_MEDIATEK_HDMI=y +CONFIG_GNSS=y +CONFIG_GNSS_MTK_SERIAL=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MTK=y +CONFIG_MTK_DEVAPC=y +CONFIG_PWM_MTK_DISP=y +CONFIG_MTK_CMDQ=y + +# For nouveau. Note that DRM must be a module so that it's loaded after NFS is up to provide the firmware. +CONFIG_ARCH_TEGRA=y +CONFIG_DRM_NOUVEAU=m +CONFIG_DRM_TEGRA=m +CONFIG_R8169=y +CONFIG_STAGING=y +CONFIG_DRM_TEGRA_STAGING=y +CONFIG_TEGRA_HOST1X=y +CONFIG_ARM_TEGRA_DEVFREQ=y +CONFIG_TEGRA_SOCTHERM=y +CONFIG_DRM_TEGRA_DEBUG=y +CONFIG_PWM_TEGRA=y diff --git a/drivers/gpu/drm/ci/build-igt.sh b/drivers/gpu/drm/ci/build-igt.sh new file mode 100644 index 000000000000..500fa4f5c30a --- /dev/null +++ b/drivers/gpu/drm/ci/build-igt.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# SPDX-License-Identifier: MIT + +set -ex + +git clone https://gitlab.freedesktop.org/drm/igt-gpu-tools.git --single-branch --no-checkout +cd igt-gpu-tools +git checkout $IGT_VERSION + +if [[ "$KERNEL_ARCH" = "arm" ]]; then + . ../.gitlab-ci/container/create-cross-file.sh armhf + EXTRA_MESON_ARGS="--cross-file /cross_file-armhf.txt" +fi + +MESON_OPTIONS="-Doverlay=disabled \ + -Dchamelium=disabled \ + -Dvalgrind=disabled \ + -Dman=enabled \ + -Dtests=enabled \ + -Drunner=enabled \ + -Dlibunwind=enabled \ + -Dprefix=/igt" + +mkdir -p /igt +meson build $MESON_OPTIONS $EXTRA_MESON_ARGS +ninja -C build -j${FDO_CI_CONCURRENT:-4} || ninja -C build -j 1 +ninja -C build install + +mkdir -p artifacts/ +tar -cf artifacts/igt.tar /igt + +# Pass needed files to the test stage +S3_ARTIFACT_NAME="igt.tar.gz" +gzip -c artifacts/igt.tar > ${S3_ARTIFACT_NAME} +ci-fairy s3cp --token-file "${CI_JOB_JWT_FILE}" ${S3_ARTIFACT_NAME} https://${PIPELINE_ARTIFACTS_BASE}/${KERNEL_ARCH}/${S3_ARTIFACT_NAME} diff --git a/drivers/gpu/drm/ci/build.sh b/drivers/gpu/drm/ci/build.sh new file mode 100644 index 000000000000..7b014287a041 --- /dev/null +++ b/drivers/gpu/drm/ci/build.sh @@ -0,0 +1,157 @@ +#!/bin/bash +# SPDX-License-Identifier: MIT + +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 +apt-get update +apt-get install -y libssl-dev + +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/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" + DEVICE_TREES+=" arch/arm64/boot/dts/qcom/apq8016-sbc.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/qcom/apq8096-db820c.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper-sku16.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots-r5.dtb" +elif [[ "$KERNEL_ARCH" = "arm" ]]; then + GCC_ARCH="arm-linux-gnueabihf" + DEBIAN_ARCH="armhf" + DEVICE_TREES="arch/arm/boot/dts/rockchip/rk3288-veyron-jaq.dtb" + DEVICE_TREES+=" arch/arm/boot/dts/allwinner/sun8i-h3-libretech-all-h3-cc.dtb" + DEVICE_TREES+=" arch/arm/boot/dts/nxp/imx/imx6q-cubox-i.dtb" + apt-get install -y libssl-dev:armhf +else + GCC_ARCH="x86_64-linux-gnu" + DEBIAN_ARCH="x86_64" + DEVICE_TREES="" +fi + +export ARCH=${KERNEL_ARCH} +export CROSS_COMPILE="${GCC_ARCH}-" + +# The kernel doesn't like the gold linker (or the old lld in our debians). +# Sneak in some override symlinks during kernel build until we can update +# debian. +mkdir -p ld-links +for i in /usr/bin/*-ld /usr/bin/ld; do + i=$(basename $i) + ln -sf /usr/bin/$i.bfd ld-links/$i +done + +NEWPATH=$(pwd)/ld-links +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 + +# 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 +fi + +# Try to merge fixes from local repo if this isn't a merge request +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 + fi +fi + +for opt in $ENABLE_KCONFIGS; do + echo CONFIG_$opt=y >> drivers/gpu/drm/ci/${KERNEL_ARCH}.config +done +for opt in $DISABLE_KCONFIGS; do + echo CONFIG_$opt=n >> drivers/gpu/drm/ci/${KERNEL_ARCH}.config +done + +if [[ -n "${MERGE_FRAGMENT}" ]]; then + ./scripts/kconfig/merge_config.sh ${DEFCONFIG} drivers/gpu/drm/ci/${MERGE_FRAGMENT} +else + make `basename ${DEFCONFIG}` +fi + +make ${KERNEL_IMAGE_NAME} + +mkdir -p /lava-files/ +for image in ${KERNEL_IMAGE_NAME}; do + cp arch/${KERNEL_ARCH}/boot/${image} /lava-files/. +done + +if [[ -n ${DEVICE_TREES} ]]; then + make dtbs + cp ${DEVICE_TREES} /lava-files/. +fi + +make modules +mkdir -p install/modules/ +INSTALL_MOD_PATH=install/modules/ make modules_install + +if [[ ${DEBIAN_ARCH} = "arm64" ]]; then + make Image.lzma + mkimage \ + -f auto \ + -A arm \ + -O linux \ + -d arch/arm64/boot/Image.lzma \ + -C lzma\ + -b arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dtb \ + /lava-files/cheza-kernel + KERNEL_IMAGE_NAME+=" cheza-kernel" + + # Make a gzipped copy of the Image for db410c. + gzip -k /lava-files/Image + KERNEL_IMAGE_NAME+=" Image.gz" +fi + +# Pass needed files to the test stage +mkdir -p install +cp -rfv .gitlab-ci/* install/. +cp -rfv install/common install/ci-common +cp -rfv drivers/gpu/drm/ci/* install/. + +. .gitlab-ci/container/container_post_build.sh + +if [[ "$UPLOAD_TO_MINIO" = "1" ]]; then + xz -7 -c -T${FDO_CI_CONCURRENT:-4} vmlinux > /lava-files/vmlinux.xz + FILES_TO_UPLOAD="$KERNEL_IMAGE_NAME vmlinux.xz" + + if [[ -n $DEVICE_TREES ]]; then + FILES_TO_UPLOAD="$FILES_TO_UPLOAD $(basename -a $DEVICE_TREES)" + fi + + for f in $FILES_TO_UPLOAD; do + ci-fairy s3cp --token-file "${CI_JOB_JWT_FILE}" /lava-files/$f \ + https://${PIPELINE_ARTIFACTS_BASE}/${DEBIAN_ARCH}/$f + done + + S3_ARTIFACT_NAME="kernel-files.tar.zst" + tar --zstd -cf $S3_ARTIFACT_NAME install + ci-fairy s3cp --token-file "${CI_JOB_JWT_FILE}" ${S3_ARTIFACT_NAME} https://${PIPELINE_ARTIFACTS_BASE}/${DEBIAN_ARCH}/${S3_ARTIFACT_NAME} + + echo "Download vmlinux.xz from https://${PIPELINE_ARTIFACTS_BASE}/${DEBIAN_ARCH}/vmlinux.xz" +fi + +mkdir -p artifacts/install/lib +mv install/* artifacts/install/. +rm -rf artifacts/install/modules +ln -s common artifacts/install/ci-common + +for image in ${KERNEL_IMAGE_NAME}; do + cp /lava-files/$image artifacts/install/. +done + +tar -C artifacts -cf artifacts/install.tar install +rm -rf artifacts/install diff --git a/drivers/gpu/drm/ci/build.yml b/drivers/gpu/drm/ci/build.yml new file mode 100644 index 000000000000..e6503f1c5927 --- /dev/null +++ b/drivers/gpu/drm/ci/build.yml @@ -0,0 +1,110 @@ +.build: + extends: + - .build-rules + stage: build + artifacts: + paths: + - artifacts + script: + - FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash drivers/gpu/drm/ci/build.sh + +.build:arm32: + extends: + - .build + - .use-debian/arm64_build + tags: + - aarch64 + variables: + DEFCONFIG: "arch/arm/configs/multi_v7_defconfig" + KERNEL_IMAGE_NAME: "zImage" + KERNEL_ARCH: "arm" + +.build:arm64: + extends: + - .build + - .use-debian/arm64_build + tags: + - aarch64 + variables: + DEFCONFIG: "arch/arm64/configs/defconfig" + KERNEL_IMAGE_NAME: "Image" + KERNEL_ARCH: "arm64" + +.build:x86_64: + extends: + - .build + - .use-debian/x86_64_build + variables: + DEFCONFIG: "arch/x86/configs/x86_64_defconfig" + KERNEL_IMAGE_NAME: "bzImage" + KERNEL_ARCH: "x86_64" + + +# Build IGT for testing on devices + +igt:arm32: + extends: .build:arm32 + script: + - FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash drivers/gpu/drm/ci/build-igt.sh + +igt:arm64: + extends: .build:arm64 + script: + - FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash drivers/gpu/drm/ci/build-igt.sh + +igt:x86_64: + extends: .build:x86_64 + script: + - FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash drivers/gpu/drm/ci/build-igt.sh + +# Build kernels for testing on devices + +testing:arm32: + extends: .build:arm32 + variables: + # Would be good to have DEBUG_KMEMLEAK, but it doesn't work well with any of + # PROVE_LOCKING and KASAN as of 5.17. + # + # db410c and db820c don't boot with KASAN_INLINE, probably due to the kernel + # becoming too big for their bootloaders. + ENABLE_KCONFIGS: "PROVE_LOCKING DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT" + UPLOAD_TO_MINIO: 1 + MERGE_FRAGMENT: arm.config + +testing:arm64: + extends: .build:arm64 + variables: + # Would be good to have DEBUG_KMEMLEAK, but it doesn't work well with any of + # PROVE_LOCKING and KASAN as of 5.17. + # + # db410c and db820c don't boot with KASAN_INLINE, probably due to the kernel + # becoming too big for their bootloaders. + ENABLE_KCONFIGS: "PROVE_LOCKING DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT" + UPLOAD_TO_MINIO: 1 + MERGE_FRAGMENT: arm64.config + +testing:x86_64: + extends: .build:x86_64 + variables: + # Would be good to have DEBUG_KMEMLEAK, but it doesn't work well with any of + # PROVE_LOCKING and KASAN as of 5.17. + # + # db410c and db820c don't boot with KASAN_INLINE, probably due to the kernel + # becoming too big for their bootloaders. + ENABLE_KCONFIGS: "PROVE_LOCKING DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT" + UPLOAD_TO_MINIO: 1 + MERGE_FRAGMENT: x86_64.config + + +# Jobs for build-testing different configurations + +build:arm32: + extends: .build:arm32 + +build-nodebugfs:arm64: + extends: .build:arm64 + variables: + DISABLE_KCONFIGS: "DEBUG_FS" + +build:x86_64: + extends: .build:x86_64 diff --git a/drivers/gpu/drm/ci/check-patch.py b/drivers/gpu/drm/ci/check-patch.py new file mode 100755 index 000000000000..a5f399a20e25 --- /dev/null +++ b/drivers/gpu/drm/ci/check-patch.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# check-patch.py: run checkpatch.pl across all commits in a branch +# +# Based on qemu/.gitlab-ci.d/check-patch.py +# +# Copyright (C) 2020 Red Hat, Inc. +# Copyright (C) 2022 Collabora Ltd. + +import os +import os.path +import sys +import subprocess + +repourl = "https://gitlab.freedesktop.org/%s.git" % os.environ["CI_MERGE_REQUEST_PROJECT_PATH"] + +# GitLab CI environment does not give us any direct info about the +# base for the user's branch. We thus need to figure out a common +# ancestor between the user's branch and current git master. +os.environ["GIT_DEPTH"] = "1000" +subprocess.call(["git", "remote", "remove", "check-patch"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) +subprocess.check_call(["git", "remote", "add", "check-patch", repourl]) +subprocess.check_call(["git", "fetch", "check-patch", os.environ["CI_MERGE_REQUEST_TARGET_BRANCH_NAME"]], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + +ancestor = subprocess.check_output(["git", "merge-base", + "check-patch/%s" % os.environ["CI_MERGE_REQUEST_TARGET_BRANCH_NAME"], "HEAD"], + universal_newlines=True) + +ancestor = ancestor.strip() + +log = subprocess.check_output(["git", "log", "--format=%H %s", + ancestor + "..."], + universal_newlines=True) + +subprocess.check_call(["git", "remote", "rm", "check-patch"]) + +if log == "": + print("\nNo commits since %s, skipping checks\n" % ancestor) + sys.exit(0) + +errors = False + +print("\nChecking all commits since %s...\n" % ancestor, flush=True) + +ret = subprocess.run(["scripts/checkpatch.pl", + "--terse", + "--types", os.environ["CHECKPATCH_TYPES"], + "--git", ancestor + "..."]) + +if ret.returncode != 0: + print(" ❌ FAIL one or more commits failed scripts/checkpatch.pl") + sys.exit(1) + +sys.exit(0) diff --git a/drivers/gpu/drm/ci/container.yml b/drivers/gpu/drm/ci/container.yml new file mode 100644 index 000000000000..9764e7921a4f --- /dev/null +++ b/drivers/gpu/drm/ci/container.yml @@ -0,0 +1,65 @@ +.container: + variables: + CI_REPOSITORY_URL: ${DRM_CI_PROJECT_URL}.git # So ci-templates clones drm-ci instead of the repo to test + CI_COMMIT_SHA: ${DRM_CI_COMMIT_SHA} + +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" + +debian/x86_64_test-gl: + variables: + EXTRA_LOCAL_PACKAGES: "jq libasound2 libcairo2 libdw1 libglib2.0-0 libjson-c5 libkmod-dev libkmod2 libgles2 libproc2-dev" + +debian/arm64_build: + 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" + +.kernel+rootfs: + variables: + EXTRA_LOCAL_PACKAGES: "jq libasound2 libcairo2 libdw1 libglib2.0-0 libjson-c5" + +# Disable container jobs that we won't use +alpine/x86_64_build: + rules: + - when: never + +debian/x86_64_test-vk: + rules: + - when: never + +fedora/x86_64_build: + rules: + - when: never + +debian/android_build: + rules: + - when: never + +debian/x86_64_test-android: + rules: + - when: never + +windows_build_vs2019: + rules: + - when: never + +windows_test_vs2019: + rules: + - when: never + +.debian/x86_64_build-mingw: + rules: + - when: never + +rustfmt: + rules: + - when: never + +windows_vs2019: + rules: + - when: never + +clang-format: + rules: + - when: never
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/gitlab-ci.yml b/drivers/gpu/drm/ci/gitlab-ci.yml new file mode 100644 index 000000000000..2c4df53f5dfe --- /dev/null +++ b/drivers/gpu/drm/ci/gitlab-ci.yml @@ -0,0 +1,251 @@ +variables: + DRM_CI_PROJECT_PATH: &drm-ci-project-path mesa/mesa + DRM_CI_COMMIT_SHA: &drm-ci-commit-sha 0dc961645c4f0241f8512cb0ec3ad59635842072 + + UPSTREAM_REPO: git://anongit.freedesktop.org/drm/drm + TARGET_BRANCH: drm-next + + IGT_VERSION: 471bfababd070e1dac0ebb87470ac4f2ae85e663 + + DEQP_RUNNER_GIT_URL: https://gitlab.freedesktop.org/anholt/deqp-runner.git + DEQP_RUNNER_GIT_TAG: v0.15.0 + + FDO_UPSTREAM_REPO: helen.fornazier/linux # The repo where the git-archive daily runs + MESA_TEMPLATES_COMMIT: &ci-templates-commit d5aa3941aa03c2f716595116354fb81eb8012acb + DRM_CI_PROJECT_URL: https://gitlab.freedesktop.org/${DRM_CI_PROJECT_PATH} + CI_PRE_CLONE_SCRIPT: |- + set -o xtrace + curl -L --retry 4 -f --retry-all-errors --retry-delay 60 -s ${DRM_CI_PROJECT_URL}/-/raw/${DRM_CI_COMMIT_SHA}/.gitlab-ci/download-git-cache.sh -o download-git-cache.sh + bash download-git-cache.sh + rm download-git-cache.sh + set +o xtrace + S3_HOST: s3.freedesktop.org + # per-pipeline artifact storage on MinIO + PIPELINE_ARTIFACTS_BASE: ${S3_HOST}/artifacts/${CI_PROJECT_PATH}/${CI_PIPELINE_ID} + # per-job artifact storage on MinIO + JOB_ARTIFACTS_BASE: ${PIPELINE_ARTIFACTS_BASE}/${CI_JOB_ID} + + LAVA_JOB_PRIORITY: 30 + +default: + before_script: + - export SCRIPTS_DIR=$(mktemp -d) + - curl -L -s --retry 4 -f --retry-all-errors --retry-delay 60 -O --output-dir "${SCRIPTS_DIR}" "${DRM_CI_PROJECT_URL}/-/raw/${DRM_CI_COMMIT_SHA}/.gitlab-ci/setup-test-env.sh" + - source ${SCRIPTS_DIR}/setup-test-env.sh + - echo -e "\e[0Ksection_start:$(date +%s):unset_env_vars_section[collapsed=true]\r\e[0KUnsetting vulnerable environment variables" + - export CI_JOB_JWT_FILE="${CI_JOB_JWT_FILE:-$(mktemp)}" + - echo -n "${CI_JOB_JWT}" > "${CI_JOB_JWT_FILE}" + - unset CI_JOB_JWT + - echo -e "\e[0Ksection_end:$(date +%s):unset_env_vars_section\r\e[0K" + + - echo -e "\e[0Ksection_start:$(date +%s):drm_ci_download_section[collapsed=true]\r\e[0KDownloading mesa from $DRM_CI_PROJECT_URL/-/archive/$DRM_CI_COMMIT_SHA/mesa-$DRM_CI_COMMIT_SHA.tar.gz" + - cd $CI_PROJECT_DIR + - curl --output - $DRM_CI_PROJECT_URL/-/archive/$DRM_CI_COMMIT_SHA/mesa-$DRM_CI_COMMIT_SHA.tar.gz | tar -xz + - mv mesa-$DRM_CI_COMMIT_SHA/.gitlab-ci* . + - rm -rf mesa-$DRM_CI_COMMIT_SHA/ + - echo -e "\e[0Ksection_end:$(date +%s):drm_ci_download_section\r\e[0K" + + after_script: + - > + set +x + + test -e "${CI_JOB_JWT_FILE}" && + export CI_JOB_JWT="$(<${CI_JOB_JWT_FILE})" && + rm "${CI_JOB_JWT_FILE}" + + # Retry when job fails. + retry: + max: 1 + # Ignore runner_unsupported, stale_schedule, archived_failure, or + # unmet_prerequisites + when: + - api_failure + - runner_system_failure + - script_failure + - job_execution_timeout + - scheduler_failure + - data_integrity_failure + - unknown_failure + +include: + - project: 'freedesktop/ci-templates' + ref: 16bc29078de5e0a067ff84a1a199a3760d3b3811 + file: + - '/templates/ci-fairy.yml' + - project: 'freedesktop/ci-templates' + ref: *ci-templates-commit + file: + - '/templates/alpine.yml' + - '/templates/debian.yml' + - '/templates/fedora.yml' + - project: *drm-ci-project-path + ref: *drm-ci-commit-sha + file: + - '/.gitlab-ci/farm-rules.yml' + - '/.gitlab-ci/test-source-dep.yml' + - '/.gitlab-ci/container/gitlab-ci.yml' + - '/.gitlab-ci/test/gitlab-ci.yml' + - '/.gitlab-ci/lava/lava-gitlab-ci.yml' + - drivers/gpu/drm/ci/image-tags.yml + - drivers/gpu/drm/ci/container.yml + - drivers/gpu/drm/ci/static-checks.yml + - drivers/gpu/drm/ci/build.yml + - drivers/gpu/drm/ci/test.yml + - 'https://gitlab.freedesktop.org/gfx-ci/lab-status/-/raw/main/lab-status.yml' + + +stages: + - sanity + - container + - git-archive + - build + - amdgpu + - i915 + - mediatek + - meson + - msm + - rockchip + - virtio-gpu + - lint + +# YAML anchors for rule conditions +# -------------------------------- +.rules-anchors: + rules: + # Pipeline for forked project branch + - if: &is-forked-branch '$CI_COMMIT_BRANCH && $CI_PROJECT_NAMESPACE != "mesa"' + when: manual + # Forked project branch / pre-merge pipeline not for Marge bot + - if: &is-forked-branch-or-pre-merge-not-for-marge '$CI_PROJECT_NAMESPACE != "mesa" || ($GITLAB_USER_LOGIN != "marge-bot" && $CI_PIPELINE_SOURCE == "merge_request_event")' + when: manual + # Pipeline runs for the main branch of the upstream Mesa project + - if: &is-mesa-main '$CI_PROJECT_NAMESPACE == "mesa" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_COMMIT_BRANCH' + when: always + # Post-merge pipeline + - if: &is-post-merge '$CI_PROJECT_NAMESPACE == "mesa" && $CI_COMMIT_BRANCH' + when: on_success + # Post-merge pipeline, not for Marge Bot + - if: &is-post-merge-not-for-marge '$CI_PROJECT_NAMESPACE == "mesa" && $GITLAB_USER_LOGIN != "marge-bot" && $CI_COMMIT_BRANCH' + when: on_success + # Pre-merge pipeline + - if: &is-pre-merge '$CI_PIPELINE_SOURCE == "merge_request_event"' + when: on_success + # Pre-merge pipeline for Marge Bot + - if: &is-pre-merge-for-marge '$GITLAB_USER_LOGIN == "marge-bot" && $CI_PIPELINE_SOURCE == "merge_request_event"' + when: on_success + +# Rule to filter for only scheduled pipelines. +.scheduled_pipeline-rules: + rules: + - if: &is-scheduled-pipeline '$CI_PIPELINE_SOURCE == "schedule"' + when: on_success + +# Generic rule to not run the job during scheduled pipelines. Jobs that aren't +# something like a nightly run should include this rule. +.no_scheduled_pipelines-rules: + rules: + - if: *is-scheduled-pipeline + when: never + +# When to automatically run the CI for build jobs +.build-rules: + rules: + - !reference [.no_scheduled_pipelines-rules, rules] + # Run automatically once all dependency jobs have passed + - when: on_success + + +.ci-deqp-artifacts: + artifacts: + name: "mesa_${CI_JOB_NAME}" + when: always + untracked: false + paths: + # Watch out! Artifacts are relative to the build dir. + # https://gitlab.com/gitlab-org/gitlab-ce/commit/8788fb925706cad594adf6917a6c5f6587dd1521 + - artifacts + - _build/meson-logs/*.txt + - _build/meson-logs/strace + + +.container-rules: + rules: + - !reference [.no_scheduled_pipelines-rules, rules] + # Run pipeline by default in the main project if any CI pipeline + # configuration files were changed, to ensure docker images are up to date + - if: *is-post-merge + changes: + - drivers/gpu/drm/ci/**/* + when: on_success + # Run pipeline by default if it was triggered by Marge Bot, is for a + # merge request, and any files affecting the pipeline were changed + - if: *is-pre-merge-for-marge + when: on_success + # Run pipeline by default in the main project if it was not triggered by + # Marge Bot, and any files affecting the pipeline were changed + - if: *is-post-merge-not-for-marge + when: on_success + # Allow triggering jobs manually in other cases + - when: manual + + + +# Git archive + +make git archive: + extends: + - .fdo.ci-fairy + stage: git-archive + rules: + - !reference [.scheduled_pipeline-rules, rules] + # ensure we are running on packet + tags: + - packet.net + script: + # Remove drm-ci files we just added + - rm -rf .gitlab-ci.* + + # Compactify the .git directory + - git gc --aggressive + # compress the current folder + - tar -cvzf ../$CI_PROJECT_NAME.tar.gz . + + # login with the JWT token file + - ci-fairy s3cp --token-file "${CI_JOB_JWT_FILE}" ../$CI_PROJECT_NAME.tar.gz https://$S3_HOST/git-cache/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/$CI_PROJECT_NAME.tar.gz + + +# Sanity checks of MR settings and commit logs +sanity: + extends: + - .fdo.ci-fairy + stage: sanity + rules: + - if: *is-pre-merge + when: on_success + # Other cases default to never + variables: + GIT_STRATEGY: none + script: + # ci-fairy check-commits --junit-xml=check-commits.xml + - ci-fairy check-merge-request --require-allow-collaboration --junit-xml=check-merge-request.xml + artifacts: + when: on_failure + reports: + junit: check-*.xml + +# Rules for tests that should not block merging, but should be available to +# optionally run with the "play" button in the UI in pre-merge non-marge +# pipelines. This should appear in "extends:" after any includes of +# test-source-dep.yml rules, so that these rules replace those. +.test-manual-mr: + rules: + - !reference [.no_scheduled_pipelines-rules, rules] + - if: *is-forked-branch-or-pre-merge-not-for-marge + when: manual + variables: + JOB_TIMEOUT: 80 + + +# Jobs that need to pass before spending hardware resources on further testing +.required-for-hardware-jobs: + needs: []
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/igt_runner.sh b/drivers/gpu/drm/ci/igt_runner.sh new file mode 100755 index 000000000000..2bb759165063 --- /dev/null +++ b/drivers/gpu/drm/ci/igt_runner.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# SPDX-License-Identifier: MIT + +set -ex + +export IGT_FORCE_DRIVER=${DRIVER_NAME} +export PATH=$PATH:/igt/bin/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/igt/lib/aarch64-linux-gnu/:/igt/lib/x86_64-linux-gnu:/igt/lib:/igt/lib64 + +# Uncomment the below to debug problems with driver probing +: ' +ls -l /dev/dri/ +cat /sys/kernel/debug/devices_deferred +cat /sys/kernel/debug/device_component/* +' + +# Dump drm state to confirm that kernel was able to find a connected display: +# TODO this path might not exist for all drivers.. maybe run modetest instead? +set +e +cat /sys/kernel/debug/dri/*/state +set -e + +# Cannot use HWCI_KERNEL_MODULES as at that point we don't have the module in /lib +if [ "$IGT_FORCE_DRIVER" = "amdgpu" ]; then + mv /install/modules/lib/modules/* /lib/modules/. + modprobe amdgpu +fi + +if [ -e "/install/xfails/$DRIVER_NAME-$GPU_VERSION-skips.txt" ]; then + IGT_SKIPS="--skips /install/xfails/$DRIVER_NAME-$GPU_VERSION-skips.txt" +fi + +if [ -e "/install/xfails/$DRIVER_NAME-$GPU_VERSION-flakes.txt" ]; then + IGT_FLAKES="--flakes /install/xfails/$DRIVER_NAME-$GPU_VERSION-flakes.txt" +fi + +if [ -e "/install/xfails/$DRIVER_NAME-$GPU_VERSION-fails.txt" ]; then + IGT_FAILS="--baseline /install/xfails/$DRIVER_NAME-$GPU_VERSION-fails.txt" +fi + +if [ "`uname -m`" = "aarch64" ]; then + ARCH="arm64" +elif [ "`uname -m`" = "armv7l" ]; then + ARCH="arm" +else + ARCH="x86_64" +fi + +curl -L --retry 4 -f --retry-all-errors --retry-delay 60 -s ${FDO_HTTP_CACHE_URI:-}$PIPELINE_ARTIFACTS_BASE/$ARCH/igt.tar.gz | tar --zstd -v -x -C / + +set +e +igt-runner \ + run \ + --igt-folder /igt/libexec/igt-gpu-tools \ + --caselist /install/testlist.txt \ + --output /results \ + $IGT_SKIPS \ + $IGT_FLAKES \ + $IGT_FAILS \ + --fraction-start $CI_NODE_INDEX \ + --fraction $CI_NODE_TOTAL \ + --jobs 1 +ret=$? +set -e + +deqp-runner junit \ + --testsuite IGT \ + --results /results/failures.csv \ + --output /results/junit.xml \ + --limit 50 \ + --template "See https://$CI_PROJECT_ROOT_NAMESPACE.pages.freedesktop.org/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/results/{{testcase}}.xml" + +# Store the results also in the simpler format used by the runner in ChromeOS CI +#sed -r 's/(dmesg-warn|pass)/success/g' /results/results.txt > /results/results_simple.txt + +cd $oldpath +exit $ret diff --git a/drivers/gpu/drm/ci/image-tags.yml b/drivers/gpu/drm/ci/image-tags.yml new file mode 100644 index 000000000000..f051b6c547c5 --- /dev/null +++ b/drivers/gpu/drm/ci/image-tags.yml @@ -0,0 +1,15 @@ +variables: + CONTAINER_TAG: "2023-08-10-mesa-uprev" + DEBIAN_X86_64_BUILD_BASE_IMAGE: "debian/x86_64_build-base" + DEBIAN_BASE_TAG: "${CONTAINER_TAG}" + + DEBIAN_X86_64_BUILD_IMAGE_PATH: "debian/x86_64_build" + DEBIAN_BUILD_TAG: "${CONTAINER_TAG}" + + KERNEL_ROOTFS_TAG: "${CONTAINER_TAG}" + + DEBIAN_X86_64_TEST_BASE_IMAGE: "debian/x86_64_test-base" + DEBIAN_X86_64_TEST_IMAGE_GL_PATH: "debian/x86_64_test-gl" + DEBIAN_X86_64_TEST_GL_TAG: "${CONTAINER_TAG}" + + ALPINE_X86_64_LAVA_SSH_TAG: "${CONTAINER_TAG}"
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/lava-submit.sh b/drivers/gpu/drm/ci/lava-submit.sh new file mode 100755 index 000000000000..0c4456b21b0f --- /dev/null +++ b/drivers/gpu/drm/ci/lava-submit.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# SPDX-License-Identifier: MIT + +set -e +set -x + +# Try to use the kernel and rootfs built in mainline first, so we're more +# likely to hit cache +if curl -L --retry 4 -f --retry-all-errors --retry-delay 60 -s "https://${BASE_SYSTEM_MAINLINE_HOST_PATH}/done"; then + BASE_SYSTEM_HOST_PATH="${BASE_SYSTEM_MAINLINE_HOST_PATH}" +else + BASE_SYSTEM_HOST_PATH="${BASE_SYSTEM_FORK_HOST_PATH}" +fi + +rm -rf results +mkdir -p results/job-rootfs-overlay/ + +cp artifacts/ci-common/capture-devcoredump.sh results/job-rootfs-overlay/ +cp artifacts/ci-common/init-*.sh results/job-rootfs-overlay/ +cp artifacts/ci-common/intel-gpu-freq.sh results/job-rootfs-overlay/ +cp "$SCRIPTS_DIR"/setup-test-env.sh results/job-rootfs-overlay/ + +# Prepare env vars for upload. +section_start variables "Variables passed through:" +KERNEL_IMAGE_BASE_URL="https://${BASE_SYSTEM_HOST_PATH}" \ + artifacts/ci-common/generate-env.sh | tee results/job-rootfs-overlay/set-job-env-vars.sh +section_end variables + +tar zcf job-rootfs-overlay.tar.gz -C results/job-rootfs-overlay/ . +ci-fairy s3cp --token-file "${CI_JOB_JWT_FILE}" job-rootfs-overlay.tar.gz "https://${JOB_ROOTFS_OVERLAY_PATH}" + +touch results/lava.log +tail -f results/lava.log & + +PYTHONPATH=artifacts/ artifacts/lava/lava_job_submitter.py \ + submit \ + --dump-yaml \ + --pipeline-info "$CI_JOB_NAME: $CI_PIPELINE_URL on $CI_COMMIT_REF_NAME ${CI_NODE_INDEX}/${CI_NODE_TOTAL}" \ + --rootfs-url-prefix "https://${BASE_SYSTEM_HOST_PATH}" \ + --kernel-url-prefix "https://${PIPELINE_ARTIFACTS_BASE}/${ARCH}" \ + --build-url "${FDO_HTTP_CACHE_URI:-}https://${PIPELINE_ARTIFACTS_BASE}/${ARCH}/kernel-files.tar.zst" \ + --job-rootfs-overlay-url "${FDO_HTTP_CACHE_URI:-}https://${JOB_ROOTFS_OVERLAY_PATH}" \ + --job-timeout-min ${JOB_TIMEOUT:-80} \ + --first-stage-init artifacts/ci-common/init-stage1.sh \ + --ci-project-dir "${CI_PROJECT_DIR}" \ + --device-type "${DEVICE_TYPE}" \ + --dtb-filename "${DTB}" \ + --jwt-file "${CI_JOB_JWT_FILE}" \ + --kernel-image-name "${KERNEL_IMAGE_NAME}" \ + --kernel-image-type "${KERNEL_IMAGE_TYPE}" \ + --boot-method "${BOOT_METHOD}" \ + --visibility-group "${VISIBILITY_GROUP}" \ + --lava-tags "${LAVA_TAGS}" \ + --mesa-job-name "$CI_JOB_NAME" \ + --structured-log-file "results/lava_job_detail.json" \ + --ssh-client-image "${LAVA_SSH_CLIENT_IMAGE}" \ + >> results/lava.log diff --git a/drivers/gpu/drm/ci/static-checks.yml b/drivers/gpu/drm/ci/static-checks.yml new file mode 100644 index 000000000000..13ffa827b7fa --- /dev/null +++ b/drivers/gpu/drm/ci/static-checks.yml @@ -0,0 +1,12 @@ +check-patch: + extends: + - .build + - .use-debian/x86_64_build + script: + - drivers/gpu/drm/ci/check-patch.py + variables: + CHECKPATCH_TYPES: "BAD_SIGN_OFF,BAD_STABLE_ADDRESS_STYLE,COMMIT_COMMENT_SYMBOL,COMMIT_MESSAGE,EMAIL_SUBJECT,FROM_SIGN_OFF_MISMATCH,MISSING_SIGN_OFF,NO_AUTHOR_SIGN_OFF,DIFF_IN_COMMIT_MSG,GERRIT_CHANGE_ID,GIT_COMMIT_ID,UNKNOWN_COMMIT_ID,CODE_INDENT,BIT_MACRO,DOS_LINE_ENDINGS" + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + when: on_success + # Other cases default to never diff --git a/drivers/gpu/drm/ci/test.yml b/drivers/gpu/drm/ci/test.yml new file mode 100644 index 000000000000..6473cddaa7a9 --- /dev/null +++ b/drivers/gpu/drm/ci/test.yml @@ -0,0 +1,335 @@ +.test-rules: + rules: + - if: '$FD_FARM == "offline" && $RUNNER_TAG =~ /^google-freedreno-/' + when: never + - if: '$COLLABORA_FARM == "offline" && $RUNNER_TAG =~ /^mesa-ci-x86-64-lava-/' + when: never + - !reference [.no_scheduled_pipelines-rules, rules] + - when: on_success + +.lava-test: + extends: + - .test-rules + script: + # Note: Build dir (and thus install) may be dirty due to GIT_STRATEGY + - rm -rf install + - tar -xf artifacts/install.tar + - mv install/* artifacts/. + # Override it with our lava-submit.sh script + - ./artifacts/lava-submit.sh + +.lava-igt:arm32: + extends: + - .lava-test:arm32 + variables: + HWCI_TEST_SCRIPT: "/install/igt_runner.sh" + ARCH: "armhf" + dependencies: + - testing:arm32 + needs: + - alpine/x86_64_lava_ssh_client + - kernel+rootfs_arm32 + - debian/x86_64_build + - testing:arm32 + - igt:arm32 + +.lava-igt:arm64: + extends: + - .lava-test:arm64 + variables: + HWCI_TEST_SCRIPT: "/install/igt_runner.sh" + ARCH: "arm64" + dependencies: + - testing:arm64 + needs: + - alpine/x86_64_lava_ssh_client + - kernel+rootfs_arm64 + - debian/x86_64_build + - testing:arm64 + - igt:arm64 + +.lava-igt:x86_64: + extends: + - .lava-test:x86_64 + variables: + HWCI_TEST_SCRIPT: "/install/igt_runner.sh" + ARCH: "x86_64" + dependencies: + - testing:x86_64 + needs: + - alpine/x86_64_lava_ssh_client + - kernel+rootfs_x86_64 + - debian/x86_64_build + - testing:x86_64 + - igt:x86_64 + +.baremetal-igt-arm64: + extends: + - .baremetal-test-arm64 + - .use-debian/arm64_test + - .test-rules + 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" + needs: + - debian/arm64_test + - job: testing:arm64 + artifacts: false + - igt:arm64 + tags: + - $RUNNER_TAG + +msm:sc7180: + extends: + - .lava-igt:arm64 + stage: msm + parallel: 2 + variables: + DRIVER_NAME: msm + DEVICE_TYPE: sc7180-trogdor-lazor-limozeen + DTB: sc7180-trogdor-lazor-limozeen-nots-r5 + BOOT_METHOD: depthcharge + KERNEL_IMAGE_TYPE: "" + GPU_VERSION: sc7180 + RUNNER_TAG: mesa-ci-x86-64-lava-sc7180-trogdor-lazor-limozeen + +msm:apq8016: + extends: + - .baremetal-igt-arm64 + stage: msm + variables: + DRIVER_NAME: msm + BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/apq8016-sbc.dtb + GPU_VERSION: apq8016 + 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" + RUNNER_TAG: google-freedreno-db410c + script: + - ./install/bare-metal/fastboot.sh + rules: + # TODO: current issue: it is not fiding the NFS root. Fix and remove this rule. + - when: never + +msm:apq8096: + extends: + - .baremetal-igt-arm64 + stage: msm + variables: + DRIVER_NAME: msm + BM_KERNEL_EXTRA_ARGS: maxcpus=2 + BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/apq8096-db820c.dtb + GPU_VERSION: apq8096 + RUNNER_TAG: google-freedreno-db820c + script: + - ./install/bare-metal/fastboot.sh + +msm:sdm845: + extends: + - .baremetal-igt-arm64 + stage: msm + parallel: 6 + variables: + DRIVER_NAME: msm + BM_KERNEL: https://${PIPELINE_ARTIFACTS_BASE}/arm64/cheza-kernel + GPU_VERSION: sdm845 + RUNNER_TAG: google-freedreno-cheza + script: + - ./install/bare-metal/cros-servo.sh + +rockchip:rk3288: + extends: + - .lava-igt:arm32 + stage: rockchip + variables: + DRIVER_NAME: rockchip + DEVICE_TYPE: rk3288-veyron-jaq + DTB: ${DEVICE_TYPE} + BOOT_METHOD: depthcharge + KERNEL_IMAGE_TYPE: "zimage" + GPU_VERSION: rk3288 + RUNNER_TAG: mesa-ci-x86-64-lava-rk3288-veyron-jaq + +rockchip:rk3399: + extends: + - .lava-igt:arm64 + stage: rockchip + parallel: 3 + variables: + DRIVER_NAME: rockchip + DEVICE_TYPE: rk3399-gru-kevin + DTB: ${DEVICE_TYPE} + BOOT_METHOD: depthcharge + KERNEL_IMAGE_TYPE: "" + GPU_VERSION: rk3399 + RUNNER_TAG: mesa-ci-x86-64-lava-rk3399-gru-kevin + +.i915: + extends: + - .lava-igt:x86_64 + stage: i915 + variables: + DRIVER_NAME: i915 + DTB: "" + BOOT_METHOD: depthcharge + KERNEL_IMAGE_TYPE: "" + +i915:apl: + extends: + - .i915 + parallel: 12 + variables: + DEVICE_TYPE: asus-C523NA-A20057-coral + GPU_VERSION: apl + RUNNER_TAG: mesa-ci-x86-64-lava-asus-C523NA-A20057-coral + +i915:glk: + extends: + - .i915 + parallel: 5 + variables: + DEVICE_TYPE: hp-x360-12b-ca0010nr-n4020-octopus + GPU_VERSION: glk + RUNNER_TAG: mesa-ci-x86-64-lava-hp-x360-12b-ca0010nr-n4020-octopus + +i915:amly: + extends: + - .i915 + parallel: 8 + variables: + DEVICE_TYPE: asus-C433TA-AJ0005-rammus + GPU_VERSION: amly + RUNNER_TAG: mesa-ci-x86-64-lava-asus-C433TA-AJ0005-rammus + +i915:kbl: + extends: + - .i915 + parallel: 5 + variables: + DEVICE_TYPE: hp-x360-14-G1-sona + GPU_VERSION: kbl + RUNNER_TAG: mesa-ci-x86-64-lava-hp-x360-14-G1-sona + +i915:whl: + extends: + - .i915 + parallel: 8 + variables: + DEVICE_TYPE: dell-latitude-5400-8665U-sarien + GPU_VERSION: whl + RUNNER_TAG: mesa-ci-x86-64-lava-dell-latitude-5400-8665U-sarien + +i915:cml: + extends: + - .i915 + parallel: 6 + variables: + DEVICE_TYPE: asus-C436FA-Flip-hatch + GPU_VERSION: cml + RUNNER_TAG: mesa-ci-x86-64-lava-asus-C436FA-flip-hatch + +i915:tgl: + extends: + - .i915 + parallel: 6 + variables: + DEVICE_TYPE: asus-cx9400-volteer + GPU_VERSION: tgl + RUNNER_TAG: mesa-ci-x86-64-lava-asus-cx9400-volteer + +.amdgpu: + extends: + - .lava-igt:x86_64 + stage: amdgpu + variables: + DRIVER_NAME: amdgpu + DTB: "" + BOOT_METHOD: depthcharge + KERNEL_IMAGE_TYPE: "" + +amdgpu:stoney: + extends: + - .amdgpu + variables: + DEVICE_TYPE: hp-11A-G6-EE-grunt + GPU_VERSION: stoney + RUNNER_TAG: mesa-ci-x86-64-lava-hp-11A-G6-EE-grunt + +.mediatek: + extends: + - .lava-igt:arm64 + stage: mediatek + variables: + DRIVER_NAME: mediatek + DTB: ${DEVICE_TYPE} + BOOT_METHOD: depthcharge + KERNEL_IMAGE_TYPE: "" + +mediatek:mt8173: + extends: + - .mediatek + variables: + DEVICE_TYPE: mt8173-elm-hana + GPU_VERSION: mt8173 + RUNNER_TAG: mesa-ci-x86-64-lava-mt8173-elm-hana + rules: + # TODO: current issue: device is hanging. Fix and remove this rule. + - when: never + +mediatek:mt8183: + extends: + - .mediatek + variables: + DEVICE_TYPE: mt8183-kukui-jacuzzi-juniper-sku16 + GPU_VERSION: mt8183 + RUNNER_TAG: mesa-ci-x86-64-lava-mt8183-kukui-jacuzzi-juniper-sku16 + +# drm-mtk doesn't even probe yet in mainline for mt8192 +.mediatek:mt8192: + extends: + - .mediatek + variables: + DEVICE_TYPE: mt8192-asurada-spherion-r0 + GPU_VERSION: mt8192 + RUNNER_TAG: mesa-ci-x86-64-lava-mt8192-asurada-spherion-r0 + +.meson: + extends: + - .lava-igt:arm64 + stage: meson + variables: + DRIVER_NAME: meson + DTB: ${DEVICE_TYPE} + BOOT_METHOD: u-boot + KERNEL_IMAGE_TYPE: "image" + +meson:g12b: + extends: + - .meson + variables: + DEVICE_TYPE: meson-g12b-a311d-khadas-vim3 + GPU_VERSION: g12b + RUNNER_TAG: mesa-ci-x86-64-lava-meson-g12b-a311d-khadas-vim3 + +virtio_gpu:none: + stage: virtio-gpu + variables: + CROSVM_GALLIUM_DRIVER: llvmpipe + DRIVER_NAME: virtio_gpu + GPU_VERSION: none + extends: + - .test-gl + tags: + - kvm + script: + - ln -sf $CI_PROJECT_DIR/install /install + - mv install/bzImage /lava-files/bzImage + - install/crosvm-runner.sh install/igt_runner.sh + needs: + - debian/x86_64_test-gl + - testing:x86_64 + - igt:x86_64 + rules: + # TODO: current issue: malloc(): corrupted top size. Fix and remove this rule. + - when: never
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/testlist.txt b/drivers/gpu/drm/ci/testlist.txt new file mode 100644 index 000000000000..f82cd90372f4 --- /dev/null +++ b/drivers/gpu/drm/ci/testlist.txt @@ -0,0 +1,2912 @@ +core_auth@getclient-simple +core_auth@getclient-master-drop +core_auth@basic-auth +core_auth@many-magics +core_getclient +core_getstats +core_getversion +core_setmaster_vs_auth +drm_read@invalid-buffer +drm_read@fault-buffer +drm_read@empty-block +drm_read@empty-nonblock +drm_read@short-buffer-block +drm_read@short-buffer-nonblock +drm_read@short-buffer-wakeup +gem_eio@throttle +gem_eio@create +gem_eio@create-ext +gem_eio@context-create +gem_eio@execbuf +gem_eio@banned +gem_eio@suspend +gem_eio@hibernate +gem_eio@in-flight-external +gem_eio@in-flight-suspend +gem_eio@reset-stress +gem_eio@unwedge-stress +gem_eio@wait-immediate +gem_eio@wait-wedge-immediate +gem_eio@in-flight-immediate +gem_eio@in-flight-contexts-immediate +gem_eio@in-flight-internal-immediate +gem_eio@wait-1us +gem_eio@wait-wedge-1us +gem_eio@in-flight-1us +gem_eio@in-flight-contexts-1us +gem_eio@in-flight-internal-1us +gem_eio@wait-10ms +gem_eio@wait-wedge-10ms +gem_eio@in-flight-10ms +gem_eio@in-flight-contexts-10ms +gem_eio@in-flight-internal-10ms +gem_eio@kms +kms_3d +kms_addfb_basic@unused-handle +kms_addfb_basic@unused-pitches +kms_addfb_basic@unused-offsets +kms_addfb_basic@unused-modifier +kms_addfb_basic@clobberred-modifier +kms_addfb_basic@invalid-smem-bo-on-discrete +kms_addfb_basic@legacy-format +kms_addfb_basic@no-handle +kms_addfb_basic@basic +kms_addfb_basic@bad-pitch-0 +kms_addfb_basic@bad-pitch-32 +kms_addfb_basic@bad-pitch-63 +kms_addfb_basic@bad-pitch-128 +kms_addfb_basic@bad-pitch-256 +kms_addfb_basic@bad-pitch-1024 +kms_addfb_basic@bad-pitch-999 +kms_addfb_basic@bad-pitch-65536 +kms_addfb_basic@invalid-get-prop-any +kms_addfb_basic@invalid-get-prop +kms_addfb_basic@invalid-set-prop-any +kms_addfb_basic@invalid-set-prop +kms_addfb_basic@master-rmfb +kms_addfb_basic@addfb25-modifier-no-flag +kms_addfb_basic@addfb25-bad-modifier +kms_addfb_basic@addfb25-x-tiled-mismatch-legacy +kms_addfb_basic@addfb25-x-tiled-legacy +kms_addfb_basic@addfb25-framebuffer-vs-set-tiling +kms_addfb_basic@basic-x-tiled-legacy +kms_addfb_basic@framebuffer-vs-set-tiling +kms_addfb_basic@tile-pitch-mismatch +kms_addfb_basic@basic-y-tiled-legacy +kms_addfb_basic@size-max +kms_addfb_basic@too-wide +kms_addfb_basic@too-high +kms_addfb_basic@bo-too-small +kms_addfb_basic@small-bo +kms_addfb_basic@bo-too-small-due-to-tiling +kms_addfb_basic@addfb25-y-tiled-legacy +kms_addfb_basic@addfb25-yf-tiled-legacy +kms_addfb_basic@addfb25-y-tiled-small-legacy +kms_addfb_basic@addfb25-4-tiled +kms_async_flips@async-flip-with-page-flip-events +kms_async_flips@alternate-sync-async-flip +kms_async_flips@test-time-stamp +kms_async_flips@test-cursor +kms_async_flips@invalid-async-flip +kms_async_flips@crc +kms_atomic@plane-overlay-legacy +kms_atomic@plane-primary-legacy +kms_atomic@plane-primary-overlay-mutable-zpos +kms_atomic@plane-immutable-zpos +kms_atomic@test-only +kms_atomic@plane-cursor-legacy +kms_atomic@plane-invalid-params +kms_atomic@plane-invalid-params-fence +kms_atomic@crtc-invalid-params +kms_atomic@crtc-invalid-params-fence +kms_atomic@atomic-invalid-params +kms_atomic@atomic_plane_damage +kms_atomic_interruptible@legacy-setmode +kms_atomic_interruptible@atomic-setmode +kms_atomic_interruptible@legacy-dpms +kms_atomic_interruptible@legacy-pageflip +kms_atomic_interruptible@legacy-cursor +kms_atomic_interruptible@universal-setplane-primary +kms_atomic_interruptible@universal-setplane-cursor +kms_atomic_transition@plane-primary-toggle-with-vblank-wait +kms_atomic_transition@plane-all-transition +kms_atomic_transition@plane-all-transition-fencing +kms_atomic_transition@plane-all-transition-nonblocking +kms_atomic_transition@plane-all-transition-nonblocking-fencing +kms_atomic_transition@plane-use-after-nonblocking-unbind +kms_atomic_transition@plane-use-after-nonblocking-unbind-fencing +kms_atomic_transition@plane-all-modeset-transition +kms_atomic_transition@plane-all-modeset-transition-fencing +kms_atomic_transition@plane-all-modeset-transition-internal-panels +kms_atomic_transition@plane-all-modeset-transition-fencing-internal-panels +kms_atomic_transition@plane-toggle-modeset-transition +kms_atomic_transition@modeset-transition +kms_atomic_transition@modeset-transition-fencing +kms_atomic_transition@modeset-transition-nonblocking +kms_atomic_transition@modeset-transition-nonblocking-fencing +kms_big_fb@x-tiled-addfb-size-overflow +kms_big_fb@y-tiled-addfb-size-overflow +kms_big_fb@yf-tiled-addfb-size-overflow +kms_big_fb@4-tiled-addfb-size-overflow +kms_big_fb@x-tiled-addfb-size-offset-overflow +kms_big_fb@y-tiled-addfb-size-offset-overflow +kms_big_fb@yf-tiled-addfb-size-offset-overflow +kms_big_fb@4-tiled-addfb-size-offset-overflow +kms_big_fb@linear-addfb +kms_big_fb@x-tiled-addfb +kms_big_fb@y-tiled-addfb +kms_big_fb@yf-tiled-addfb +kms_big_fb@4-tiled-addfb +kms_big_fb@linear-8bpp-rotate-0 +kms_big_fb@linear-8bpp-rotate-90 +kms_big_fb@linear-8bpp-rotate-180 +kms_big_fb@linear-8bpp-rotate-270 +kms_big_fb@linear-16bpp-rotate-0 +kms_big_fb@linear-16bpp-rotate-90 +kms_big_fb@linear-16bpp-rotate-180 +kms_big_fb@linear-16bpp-rotate-270 +kms_big_fb@linear-32bpp-rotate-0 +kms_big_fb@linear-32bpp-rotate-90 +kms_big_fb@linear-32bpp-rotate-180 +kms_big_fb@linear-32bpp-rotate-270 +kms_big_fb@linear-64bpp-rotate-0 +kms_big_fb@linear-64bpp-rotate-90 +kms_big_fb@linear-64bpp-rotate-180 +kms_big_fb@linear-64bpp-rotate-270 +kms_big_fb@x-tiled-8bpp-rotate-0 +kms_big_fb@x-tiled-8bpp-rotate-90 +kms_big_fb@x-tiled-8bpp-rotate-180 +kms_big_fb@x-tiled-8bpp-rotate-270 +kms_big_fb@x-tiled-16bpp-rotate-0 +kms_big_fb@x-tiled-16bpp-rotate-90 +kms_big_fb@x-tiled-16bpp-rotate-180 +kms_big_fb@x-tiled-16bpp-rotate-270 +kms_big_fb@x-tiled-32bpp-rotate-0 +kms_big_fb@x-tiled-32bpp-rotate-90 +kms_big_fb@x-tiled-32bpp-rotate-180 +kms_big_fb@x-tiled-32bpp-rotate-270 +kms_big_fb@x-tiled-64bpp-rotate-0 +kms_big_fb@x-tiled-64bpp-rotate-90 +kms_big_fb@x-tiled-64bpp-rotate-180 +kms_big_fb@x-tiled-64bpp-rotate-270 +kms_big_fb@y-tiled-8bpp-rotate-0 +kms_big_fb@y-tiled-8bpp-rotate-90 +kms_big_fb@y-tiled-8bpp-rotate-180 +kms_big_fb@y-tiled-8bpp-rotate-270 +kms_big_fb@y-tiled-16bpp-rotate-0 +kms_big_fb@y-tiled-16bpp-rotate-90 +kms_big_fb@y-tiled-16bpp-rotate-180 +kms_big_fb@y-tiled-16bpp-rotate-270 +kms_big_fb@y-tiled-32bpp-rotate-0 +kms_big_fb@y-tiled-32bpp-rotate-90 +kms_big_fb@y-tiled-32bpp-rotate-180 +kms_big_fb@y-tiled-32bpp-rotate-270 +kms_big_fb@y-tiled-64bpp-rotate-0 +kms_big_fb@y-tiled-64bpp-rotate-90 +kms_big_fb@y-tiled-64bpp-rotate-180 +kms_big_fb@y-tiled-64bpp-rotate-270 +kms_big_fb@yf-tiled-8bpp-rotate-0 +kms_big_fb@yf-tiled-8bpp-rotate-90 +kms_big_fb@yf-tiled-8bpp-rotate-180 +kms_big_fb@yf-tiled-8bpp-rotate-270 +kms_big_fb@yf-tiled-16bpp-rotate-0 +kms_big_fb@yf-tiled-16bpp-rotate-90 +kms_big_fb@yf-tiled-16bpp-rotate-180 +kms_big_fb@yf-tiled-16bpp-rotate-270 +kms_big_fb@yf-tiled-32bpp-rotate-0 +kms_big_fb@yf-tiled-32bpp-rotate-90 +kms_big_fb@yf-tiled-32bpp-rotate-180 +kms_big_fb@yf-tiled-32bpp-rotate-270 +kms_big_fb@yf-tiled-64bpp-rotate-0 +kms_big_fb@yf-tiled-64bpp-rotate-90 +kms_big_fb@yf-tiled-64bpp-rotate-180 +kms_big_fb@yf-tiled-64bpp-rotate-270 +kms_big_fb@4-tiled-8bpp-rotate-0 +kms_big_fb@4-tiled-8bpp-rotate-90 +kms_big_fb@4-tiled-8bpp-rotate-180 +kms_big_fb@4-tiled-8bpp-rotate-270 +kms_big_fb@4-tiled-16bpp-rotate-0 +kms_big_fb@4-tiled-16bpp-rotate-90 +kms_big_fb@4-tiled-16bpp-rotate-180 +kms_big_fb@4-tiled-16bpp-rotate-270 +kms_big_fb@4-tiled-32bpp-rotate-0 +kms_big_fb@4-tiled-32bpp-rotate-90 +kms_big_fb@4-tiled-32bpp-rotate-180 +kms_big_fb@4-tiled-32bpp-rotate-270 +kms_big_fb@4-tiled-64bpp-rotate-0 +kms_big_fb@4-tiled-64bpp-rotate-90 +kms_big_fb@4-tiled-64bpp-rotate-180 +kms_big_fb@4-tiled-64bpp-rotate-270 +kms_big_fb@linear-max-hw-stride-32bpp-rotate-0 +kms_big_fb@linear-max-hw-stride-32bpp-rotate-180 +kms_big_fb@linear-max-hw-stride-64bpp-rotate-0 +kms_big_fb@linear-max-hw-stride-64bpp-rotate-180 +kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-0 +kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-0-async-flip +kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-180 +kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-180-async-flip +kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-0 +kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-0-async-flip +kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180 +kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-async-flip +kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-0-hflip +kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip +kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-180-hflip +kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-180-hflip-async-flip +kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-0-hflip +kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip +kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-hflip +kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip +kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-0 +kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-0-async-flip +kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-180 +kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-180-async-flip +kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-0 +kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-0-async-flip +kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180 +kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-async-flip +kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-0-hflip +kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip +kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-180-hflip +kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-180-hflip-async-flip +kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-0-hflip +kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip +kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip +kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip +kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-0 +kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-0-async-flip +kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-180 +kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-180-async-flip +kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-0 +kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-0-async-flip +kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180 +kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-async-flip +kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-0-hflip +kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip +kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-180-hflip +kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-180-hflip-async-flip +kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-0-hflip +kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip +kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-hflip +kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip +kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-0 +kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-0-async-flip +kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-180 +kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-180-async-flip +kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0 +kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0-async-flip +kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-180 +kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-180-async-flip +kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-0-hflip +kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip +kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-180-hflip +kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-180-hflip-async-flip +kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0-hflip +kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip +kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-180-hflip +kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip +kms_big_joiner@basic +kms_big_joiner@invalid-modeset +kms_big_joiner@2x-modeset +kms_busy@basic +kms_busy@basic-hang +kms_busy@extended-pageflip-modeset-hang-oldfb +kms_busy@extended-pageflip-hang-oldfb +kms_busy@extended-pageflip-hang-newfb +kms_busy@extended-modeset-hang-oldfb +kms_busy@extended-modeset-hang-newfb +kms_busy@extended-modeset-hang-oldfb-with-reset +kms_busy@extended-modeset-hang-newfb-with-reset +kms_bw@linear-tiling-1-displays-1920x1080p +kms_bw@linear-tiling-1-displays-2560x1440p +kms_bw@linear-tiling-1-displays-3840x2160p +kms_bw@linear-tiling-2-displays-1920x1080p +kms_bw@linear-tiling-2-displays-2560x1440p +kms_bw@linear-tiling-2-displays-3840x2160p +kms_bw@linear-tiling-3-displays-1920x1080p +kms_bw@linear-tiling-3-displays-2560x1440p +kms_bw@linear-tiling-3-displays-3840x2160p +kms_bw@linear-tiling-4-displays-1920x1080p +kms_bw@linear-tiling-4-displays-2560x1440p +kms_bw@linear-tiling-4-displays-3840x2160p +kms_bw@linear-tiling-5-displays-1920x1080p +kms_bw@linear-tiling-5-displays-2560x1440p +kms_bw@linear-tiling-5-displays-3840x2160p +kms_bw@linear-tiling-6-displays-1920x1080p +kms_bw@linear-tiling-6-displays-2560x1440p +kms_bw@linear-tiling-6-displays-3840x2160p +kms_bw@linear-tiling-7-displays-1920x1080p +kms_bw@linear-tiling-7-displays-2560x1440p +kms_bw@linear-tiling-7-displays-3840x2160p +kms_bw@linear-tiling-8-displays-1920x1080p +kms_bw@linear-tiling-8-displays-2560x1440p +kms_bw@linear-tiling-8-displays-3840x2160p +kms_ccs@pipe-A-bad-pixel-format-y_tiled_ccs +kms_ccs@pipe-A-bad-pixel-format-yf_tiled_ccs +kms_ccs@pipe-A-bad-pixel-format-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-bad-pixel-format-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-bad-pixel-format-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-bad-pixel-format-4_tiled_dg2_rc_ccs +kms_ccs@pipe-A-bad-pixel-format-4_tiled_dg2_mc_ccs +kms_ccs@pipe-A-bad-pixel-format-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-A-bad-pixel-format-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-bad-pixel-format-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-bad-pixel-format-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-A-bad-rotation-90-y_tiled_ccs +kms_ccs@pipe-A-bad-rotation-90-yf_tiled_ccs +kms_ccs@pipe-A-bad-rotation-90-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-bad-rotation-90-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-bad-rotation-90-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-bad-rotation-90-4_tiled_dg2_rc_ccs +kms_ccs@pipe-A-bad-rotation-90-4_tiled_dg2_mc_ccs +kms_ccs@pipe-A-bad-rotation-90-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-A-bad-rotation-90-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-bad-rotation-90-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-bad-rotation-90-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-A-crc-primary-basic-y_tiled_ccs +kms_ccs@pipe-A-crc-primary-basic-yf_tiled_ccs +kms_ccs@pipe-A-crc-primary-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-crc-primary-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-crc-primary-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-crc-primary-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-A-crc-primary-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-A-crc-primary-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-A-crc-primary-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-crc-primary-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-crc-primary-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-A-crc-primary-rotation-180-y_tiled_ccs +kms_ccs@pipe-A-crc-primary-rotation-180-yf_tiled_ccs +kms_ccs@pipe-A-crc-primary-rotation-180-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-crc-primary-rotation-180-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-crc-primary-rotation-180-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-crc-primary-rotation-180-4_tiled_dg2_rc_ccs +kms_ccs@pipe-A-crc-primary-rotation-180-4_tiled_dg2_mc_ccs +kms_ccs@pipe-A-crc-primary-rotation-180-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-A-crc-primary-rotation-180-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-crc-primary-rotation-180-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-crc-primary-rotation-180-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-A-random-ccs-data-y_tiled_ccs +kms_ccs@pipe-A-random-ccs-data-yf_tiled_ccs +kms_ccs@pipe-A-random-ccs-data-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-random-ccs-data-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-random-ccs-data-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-random-ccs-data-4_tiled_dg2_rc_ccs +kms_ccs@pipe-A-random-ccs-data-4_tiled_dg2_mc_ccs +kms_ccs@pipe-A-random-ccs-data-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-A-random-ccs-data-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-random-ccs-data-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-random-ccs-data-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-A-missing-ccs-buffer-y_tiled_ccs +kms_ccs@pipe-A-missing-ccs-buffer-yf_tiled_ccs +kms_ccs@pipe-A-missing-ccs-buffer-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-missing-ccs-buffer-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-missing-ccs-buffer-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-missing-ccs-buffer-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-missing-ccs-buffer-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-missing-ccs-buffer-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-A-ccs-on-another-bo-y_tiled_ccs +kms_ccs@pipe-A-ccs-on-another-bo-yf_tiled_ccs +kms_ccs@pipe-A-ccs-on-another-bo-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-ccs-on-another-bo-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-ccs-on-another-bo-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-ccs-on-another-bo-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-ccs-on-another-bo-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-A-bad-aux-stride-y_tiled_ccs +kms_ccs@pipe-A-bad-aux-stride-yf_tiled_ccs +kms_ccs@pipe-A-bad-aux-stride-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-bad-aux-stride-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-bad-aux-stride-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-bad-aux-stride-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-bad-aux-stride-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-bad-aux-stride-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-A-crc-sprite-planes-basic-y_tiled_ccs +kms_ccs@pipe-A-crc-sprite-planes-basic-yf_tiled_ccs +kms_ccs@pipe-A-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-A-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-A-crc-sprite-planes-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-A-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-A-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-A-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-A-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-A-crc-sprite-planes-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-A-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-bad-pixel-format-y_tiled_ccs +kms_ccs@pipe-B-bad-pixel-format-yf_tiled_ccs +kms_ccs@pipe-B-bad-pixel-format-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-bad-pixel-format-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-bad-pixel-format-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-bad-pixel-format-4_tiled_dg2_rc_ccs +kms_ccs@pipe-B-bad-pixel-format-4_tiled_dg2_mc_ccs +kms_ccs@pipe-B-bad-pixel-format-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-B-bad-pixel-format-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-bad-pixel-format-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-bad-pixel-format-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-bad-rotation-90-y_tiled_ccs +kms_ccs@pipe-B-bad-rotation-90-yf_tiled_ccs +kms_ccs@pipe-B-bad-rotation-90-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-bad-rotation-90-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-bad-rotation-90-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-bad-rotation-90-4_tiled_dg2_rc_ccs +kms_ccs@pipe-B-bad-rotation-90-4_tiled_dg2_mc_ccs +kms_ccs@pipe-B-bad-rotation-90-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-B-bad-rotation-90-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-bad-rotation-90-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-bad-rotation-90-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-crc-primary-basic-y_tiled_ccs +kms_ccs@pipe-B-crc-primary-basic-yf_tiled_ccs +kms_ccs@pipe-B-crc-primary-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-crc-primary-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-crc-primary-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-crc-primary-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-B-crc-primary-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-B-crc-primary-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-B-crc-primary-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-crc-primary-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-crc-primary-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-crc-primary-rotation-180-y_tiled_ccs +kms_ccs@pipe-B-crc-primary-rotation-180-yf_tiled_ccs +kms_ccs@pipe-B-crc-primary-rotation-180-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-crc-primary-rotation-180-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-crc-primary-rotation-180-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-crc-primary-rotation-180-4_tiled_dg2_rc_ccs +kms_ccs@pipe-B-crc-primary-rotation-180-4_tiled_dg2_mc_ccs +kms_ccs@pipe-B-crc-primary-rotation-180-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-B-crc-primary-rotation-180-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-crc-primary-rotation-180-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-crc-primary-rotation-180-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-random-ccs-data-y_tiled_ccs +kms_ccs@pipe-B-random-ccs-data-yf_tiled_ccs +kms_ccs@pipe-B-random-ccs-data-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-random-ccs-data-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-random-ccs-data-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-random-ccs-data-4_tiled_dg2_rc_ccs +kms_ccs@pipe-B-random-ccs-data-4_tiled_dg2_mc_ccs +kms_ccs@pipe-B-random-ccs-data-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-B-random-ccs-data-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-random-ccs-data-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-random-ccs-data-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-missing-ccs-buffer-y_tiled_ccs +kms_ccs@pipe-B-missing-ccs-buffer-yf_tiled_ccs +kms_ccs@pipe-B-missing-ccs-buffer-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-missing-ccs-buffer-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-missing-ccs-buffer-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-missing-ccs-buffer-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-missing-ccs-buffer-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-missing-ccs-buffer-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-ccs-on-another-bo-y_tiled_ccs +kms_ccs@pipe-B-ccs-on-another-bo-yf_tiled_ccs +kms_ccs@pipe-B-ccs-on-another-bo-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-ccs-on-another-bo-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-ccs-on-another-bo-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-ccs-on-another-bo-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-ccs-on-another-bo-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-bad-aux-stride-y_tiled_ccs +kms_ccs@pipe-B-bad-aux-stride-yf_tiled_ccs +kms_ccs@pipe-B-bad-aux-stride-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-bad-aux-stride-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-bad-aux-stride-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-bad-aux-stride-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-bad-aux-stride-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-bad-aux-stride-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-B-crc-sprite-planes-basic-y_tiled_ccs +kms_ccs@pipe-B-crc-sprite-planes-basic-yf_tiled_ccs +kms_ccs@pipe-B-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-B-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-B-crc-sprite-planes-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-B-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-B-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-B-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-B-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-B-crc-sprite-planes-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-B-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-bad-pixel-format-y_tiled_ccs +kms_ccs@pipe-C-bad-pixel-format-yf_tiled_ccs +kms_ccs@pipe-C-bad-pixel-format-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-bad-pixel-format-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-bad-pixel-format-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-bad-pixel-format-4_tiled_dg2_rc_ccs +kms_ccs@pipe-C-bad-pixel-format-4_tiled_dg2_mc_ccs +kms_ccs@pipe-C-bad-pixel-format-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-C-bad-pixel-format-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-bad-pixel-format-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-bad-pixel-format-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-bad-rotation-90-y_tiled_ccs +kms_ccs@pipe-C-bad-rotation-90-yf_tiled_ccs +kms_ccs@pipe-C-bad-rotation-90-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-bad-rotation-90-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-bad-rotation-90-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-bad-rotation-90-4_tiled_dg2_rc_ccs +kms_ccs@pipe-C-bad-rotation-90-4_tiled_dg2_mc_ccs +kms_ccs@pipe-C-bad-rotation-90-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-C-bad-rotation-90-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-bad-rotation-90-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-bad-rotation-90-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-crc-primary-basic-y_tiled_ccs +kms_ccs@pipe-C-crc-primary-basic-yf_tiled_ccs +kms_ccs@pipe-C-crc-primary-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-crc-primary-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-crc-primary-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-crc-primary-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-C-crc-primary-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-C-crc-primary-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-C-crc-primary-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-crc-primary-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-crc-primary-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-crc-primary-rotation-180-y_tiled_ccs +kms_ccs@pipe-C-crc-primary-rotation-180-yf_tiled_ccs +kms_ccs@pipe-C-crc-primary-rotation-180-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-crc-primary-rotation-180-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-crc-primary-rotation-180-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-crc-primary-rotation-180-4_tiled_dg2_rc_ccs +kms_ccs@pipe-C-crc-primary-rotation-180-4_tiled_dg2_mc_ccs +kms_ccs@pipe-C-crc-primary-rotation-180-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-C-crc-primary-rotation-180-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-crc-primary-rotation-180-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-crc-primary-rotation-180-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-random-ccs-data-y_tiled_ccs +kms_ccs@pipe-C-random-ccs-data-yf_tiled_ccs +kms_ccs@pipe-C-random-ccs-data-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-random-ccs-data-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-random-ccs-data-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-random-ccs-data-4_tiled_dg2_rc_ccs +kms_ccs@pipe-C-random-ccs-data-4_tiled_dg2_mc_ccs +kms_ccs@pipe-C-random-ccs-data-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-C-random-ccs-data-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-random-ccs-data-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-random-ccs-data-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-missing-ccs-buffer-y_tiled_ccs +kms_ccs@pipe-C-missing-ccs-buffer-yf_tiled_ccs +kms_ccs@pipe-C-missing-ccs-buffer-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-missing-ccs-buffer-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-missing-ccs-buffer-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-missing-ccs-buffer-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-missing-ccs-buffer-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-missing-ccs-buffer-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-ccs-on-another-bo-y_tiled_ccs +kms_ccs@pipe-C-ccs-on-another-bo-yf_tiled_ccs +kms_ccs@pipe-C-ccs-on-another-bo-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-ccs-on-another-bo-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-ccs-on-another-bo-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-ccs-on-another-bo-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-ccs-on-another-bo-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-bad-aux-stride-y_tiled_ccs +kms_ccs@pipe-C-bad-aux-stride-yf_tiled_ccs +kms_ccs@pipe-C-bad-aux-stride-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-bad-aux-stride-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-bad-aux-stride-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-bad-aux-stride-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-bad-aux-stride-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-bad-aux-stride-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-C-crc-sprite-planes-basic-y_tiled_ccs +kms_ccs@pipe-C-crc-sprite-planes-basic-yf_tiled_ccs +kms_ccs@pipe-C-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-C-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-C-crc-sprite-planes-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-C-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-C-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-C-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-C-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-C-crc-sprite-planes-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-C-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-bad-pixel-format-y_tiled_ccs +kms_ccs@pipe-D-bad-pixel-format-yf_tiled_ccs +kms_ccs@pipe-D-bad-pixel-format-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-bad-pixel-format-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-bad-pixel-format-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-bad-pixel-format-4_tiled_dg2_rc_ccs +kms_ccs@pipe-D-bad-pixel-format-4_tiled_dg2_mc_ccs +kms_ccs@pipe-D-bad-pixel-format-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-D-bad-pixel-format-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-bad-pixel-format-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-bad-pixel-format-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-bad-rotation-90-y_tiled_ccs +kms_ccs@pipe-D-bad-rotation-90-yf_tiled_ccs +kms_ccs@pipe-D-bad-rotation-90-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-bad-rotation-90-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-bad-rotation-90-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-bad-rotation-90-4_tiled_dg2_rc_ccs +kms_ccs@pipe-D-bad-rotation-90-4_tiled_dg2_mc_ccs +kms_ccs@pipe-D-bad-rotation-90-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-D-bad-rotation-90-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-bad-rotation-90-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-bad-rotation-90-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-crc-primary-basic-y_tiled_ccs +kms_ccs@pipe-D-crc-primary-basic-yf_tiled_ccs +kms_ccs@pipe-D-crc-primary-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-crc-primary-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-crc-primary-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-crc-primary-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-D-crc-primary-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-D-crc-primary-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-D-crc-primary-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-crc-primary-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-crc-primary-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-crc-primary-rotation-180-y_tiled_ccs +kms_ccs@pipe-D-crc-primary-rotation-180-yf_tiled_ccs +kms_ccs@pipe-D-crc-primary-rotation-180-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-crc-primary-rotation-180-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-crc-primary-rotation-180-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-crc-primary-rotation-180-4_tiled_dg2_rc_ccs +kms_ccs@pipe-D-crc-primary-rotation-180-4_tiled_dg2_mc_ccs +kms_ccs@pipe-D-crc-primary-rotation-180-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-D-crc-primary-rotation-180-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-crc-primary-rotation-180-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-crc-primary-rotation-180-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-random-ccs-data-y_tiled_ccs +kms_ccs@pipe-D-random-ccs-data-yf_tiled_ccs +kms_ccs@pipe-D-random-ccs-data-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-random-ccs-data-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-random-ccs-data-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-random-ccs-data-4_tiled_dg2_rc_ccs +kms_ccs@pipe-D-random-ccs-data-4_tiled_dg2_mc_ccs +kms_ccs@pipe-D-random-ccs-data-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-D-random-ccs-data-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-random-ccs-data-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-random-ccs-data-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-missing-ccs-buffer-y_tiled_ccs +kms_ccs@pipe-D-missing-ccs-buffer-yf_tiled_ccs +kms_ccs@pipe-D-missing-ccs-buffer-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-missing-ccs-buffer-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-missing-ccs-buffer-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-missing-ccs-buffer-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-missing-ccs-buffer-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-missing-ccs-buffer-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-ccs-on-another-bo-y_tiled_ccs +kms_ccs@pipe-D-ccs-on-another-bo-yf_tiled_ccs +kms_ccs@pipe-D-ccs-on-another-bo-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-ccs-on-another-bo-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-ccs-on-another-bo-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-ccs-on-another-bo-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-ccs-on-another-bo-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-bad-aux-stride-y_tiled_ccs +kms_ccs@pipe-D-bad-aux-stride-yf_tiled_ccs +kms_ccs@pipe-D-bad-aux-stride-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-bad-aux-stride-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-bad-aux-stride-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-bad-aux-stride-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-bad-aux-stride-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-bad-aux-stride-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-D-crc-sprite-planes-basic-y_tiled_ccs +kms_ccs@pipe-D-crc-sprite-planes-basic-yf_tiled_ccs +kms_ccs@pipe-D-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-D-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-D-crc-sprite-planes-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-D-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-D-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-D-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-D-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-D-crc-sprite-planes-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-D-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-bad-pixel-format-y_tiled_ccs +kms_ccs@pipe-E-bad-pixel-format-yf_tiled_ccs +kms_ccs@pipe-E-bad-pixel-format-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-bad-pixel-format-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-bad-pixel-format-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-bad-pixel-format-4_tiled_dg2_rc_ccs +kms_ccs@pipe-E-bad-pixel-format-4_tiled_dg2_mc_ccs +kms_ccs@pipe-E-bad-pixel-format-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-E-bad-pixel-format-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-bad-pixel-format-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-bad-pixel-format-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-bad-rotation-90-y_tiled_ccs +kms_ccs@pipe-E-bad-rotation-90-yf_tiled_ccs +kms_ccs@pipe-E-bad-rotation-90-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-bad-rotation-90-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-bad-rotation-90-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-bad-rotation-90-4_tiled_dg2_rc_ccs +kms_ccs@pipe-E-bad-rotation-90-4_tiled_dg2_mc_ccs +kms_ccs@pipe-E-bad-rotation-90-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-E-bad-rotation-90-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-bad-rotation-90-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-bad-rotation-90-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-crc-primary-basic-y_tiled_ccs +kms_ccs@pipe-E-crc-primary-basic-yf_tiled_ccs +kms_ccs@pipe-E-crc-primary-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-crc-primary-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-crc-primary-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-crc-primary-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-E-crc-primary-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-E-crc-primary-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-E-crc-primary-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-crc-primary-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-crc-primary-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-crc-primary-rotation-180-y_tiled_ccs +kms_ccs@pipe-E-crc-primary-rotation-180-yf_tiled_ccs +kms_ccs@pipe-E-crc-primary-rotation-180-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-crc-primary-rotation-180-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-crc-primary-rotation-180-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-crc-primary-rotation-180-4_tiled_dg2_rc_ccs +kms_ccs@pipe-E-crc-primary-rotation-180-4_tiled_dg2_mc_ccs +kms_ccs@pipe-E-crc-primary-rotation-180-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-E-crc-primary-rotation-180-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-crc-primary-rotation-180-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-crc-primary-rotation-180-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-random-ccs-data-y_tiled_ccs +kms_ccs@pipe-E-random-ccs-data-yf_tiled_ccs +kms_ccs@pipe-E-random-ccs-data-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-random-ccs-data-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-random-ccs-data-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-random-ccs-data-4_tiled_dg2_rc_ccs +kms_ccs@pipe-E-random-ccs-data-4_tiled_dg2_mc_ccs +kms_ccs@pipe-E-random-ccs-data-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-E-random-ccs-data-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-random-ccs-data-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-random-ccs-data-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-missing-ccs-buffer-y_tiled_ccs +kms_ccs@pipe-E-missing-ccs-buffer-yf_tiled_ccs +kms_ccs@pipe-E-missing-ccs-buffer-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-missing-ccs-buffer-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-missing-ccs-buffer-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-missing-ccs-buffer-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-missing-ccs-buffer-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-missing-ccs-buffer-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-ccs-on-another-bo-y_tiled_ccs +kms_ccs@pipe-E-ccs-on-another-bo-yf_tiled_ccs +kms_ccs@pipe-E-ccs-on-another-bo-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-ccs-on-another-bo-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-ccs-on-another-bo-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-ccs-on-another-bo-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-ccs-on-another-bo-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-bad-aux-stride-y_tiled_ccs +kms_ccs@pipe-E-bad-aux-stride-yf_tiled_ccs +kms_ccs@pipe-E-bad-aux-stride-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-bad-aux-stride-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-bad-aux-stride-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-bad-aux-stride-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-bad-aux-stride-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-bad-aux-stride-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-E-crc-sprite-planes-basic-y_tiled_ccs +kms_ccs@pipe-E-crc-sprite-planes-basic-yf_tiled_ccs +kms_ccs@pipe-E-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-E-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-E-crc-sprite-planes-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-E-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-E-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-E-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-E-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-E-crc-sprite-planes-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-E-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-bad-pixel-format-y_tiled_ccs +kms_ccs@pipe-F-bad-pixel-format-yf_tiled_ccs +kms_ccs@pipe-F-bad-pixel-format-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-bad-pixel-format-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-bad-pixel-format-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-bad-pixel-format-4_tiled_dg2_rc_ccs +kms_ccs@pipe-F-bad-pixel-format-4_tiled_dg2_mc_ccs +kms_ccs@pipe-F-bad-pixel-format-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-F-bad-pixel-format-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-bad-pixel-format-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-bad-pixel-format-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-bad-rotation-90-y_tiled_ccs +kms_ccs@pipe-F-bad-rotation-90-yf_tiled_ccs +kms_ccs@pipe-F-bad-rotation-90-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-bad-rotation-90-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-bad-rotation-90-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-bad-rotation-90-4_tiled_dg2_rc_ccs +kms_ccs@pipe-F-bad-rotation-90-4_tiled_dg2_mc_ccs +kms_ccs@pipe-F-bad-rotation-90-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-F-bad-rotation-90-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-bad-rotation-90-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-bad-rotation-90-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-crc-primary-basic-y_tiled_ccs +kms_ccs@pipe-F-crc-primary-basic-yf_tiled_ccs +kms_ccs@pipe-F-crc-primary-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-crc-primary-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-crc-primary-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-crc-primary-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-F-crc-primary-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-F-crc-primary-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-F-crc-primary-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-crc-primary-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-crc-primary-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-crc-primary-rotation-180-y_tiled_ccs +kms_ccs@pipe-F-crc-primary-rotation-180-yf_tiled_ccs +kms_ccs@pipe-F-crc-primary-rotation-180-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-crc-primary-rotation-180-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-crc-primary-rotation-180-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-crc-primary-rotation-180-4_tiled_dg2_rc_ccs +kms_ccs@pipe-F-crc-primary-rotation-180-4_tiled_dg2_mc_ccs +kms_ccs@pipe-F-crc-primary-rotation-180-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-F-crc-primary-rotation-180-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-crc-primary-rotation-180-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-crc-primary-rotation-180-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-random-ccs-data-y_tiled_ccs +kms_ccs@pipe-F-random-ccs-data-yf_tiled_ccs +kms_ccs@pipe-F-random-ccs-data-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-random-ccs-data-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-random-ccs-data-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-random-ccs-data-4_tiled_dg2_rc_ccs +kms_ccs@pipe-F-random-ccs-data-4_tiled_dg2_mc_ccs +kms_ccs@pipe-F-random-ccs-data-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-F-random-ccs-data-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-random-ccs-data-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-random-ccs-data-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-missing-ccs-buffer-y_tiled_ccs +kms_ccs@pipe-F-missing-ccs-buffer-yf_tiled_ccs +kms_ccs@pipe-F-missing-ccs-buffer-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-missing-ccs-buffer-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-missing-ccs-buffer-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-missing-ccs-buffer-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-missing-ccs-buffer-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-missing-ccs-buffer-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-ccs-on-another-bo-y_tiled_ccs +kms_ccs@pipe-F-ccs-on-another-bo-yf_tiled_ccs +kms_ccs@pipe-F-ccs-on-another-bo-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-ccs-on-another-bo-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-ccs-on-another-bo-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-ccs-on-another-bo-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-ccs-on-another-bo-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-bad-aux-stride-y_tiled_ccs +kms_ccs@pipe-F-bad-aux-stride-yf_tiled_ccs +kms_ccs@pipe-F-bad-aux-stride-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-bad-aux-stride-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-bad-aux-stride-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-bad-aux-stride-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-bad-aux-stride-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-bad-aux-stride-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-F-crc-sprite-planes-basic-y_tiled_ccs +kms_ccs@pipe-F-crc-sprite-planes-basic-yf_tiled_ccs +kms_ccs@pipe-F-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-F-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-F-crc-sprite-planes-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-F-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-F-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-F-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-F-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-F-crc-sprite-planes-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-F-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-bad-pixel-format-y_tiled_ccs +kms_ccs@pipe-G-bad-pixel-format-yf_tiled_ccs +kms_ccs@pipe-G-bad-pixel-format-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-bad-pixel-format-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-bad-pixel-format-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-bad-pixel-format-4_tiled_dg2_rc_ccs +kms_ccs@pipe-G-bad-pixel-format-4_tiled_dg2_mc_ccs +kms_ccs@pipe-G-bad-pixel-format-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-G-bad-pixel-format-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-bad-pixel-format-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-bad-pixel-format-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-bad-rotation-90-y_tiled_ccs +kms_ccs@pipe-G-bad-rotation-90-yf_tiled_ccs +kms_ccs@pipe-G-bad-rotation-90-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-bad-rotation-90-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-bad-rotation-90-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-bad-rotation-90-4_tiled_dg2_rc_ccs +kms_ccs@pipe-G-bad-rotation-90-4_tiled_dg2_mc_ccs +kms_ccs@pipe-G-bad-rotation-90-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-G-bad-rotation-90-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-bad-rotation-90-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-bad-rotation-90-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-crc-primary-basic-y_tiled_ccs +kms_ccs@pipe-G-crc-primary-basic-yf_tiled_ccs +kms_ccs@pipe-G-crc-primary-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-crc-primary-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-crc-primary-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-crc-primary-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-G-crc-primary-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-G-crc-primary-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-G-crc-primary-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-crc-primary-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-crc-primary-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-crc-primary-rotation-180-y_tiled_ccs +kms_ccs@pipe-G-crc-primary-rotation-180-yf_tiled_ccs +kms_ccs@pipe-G-crc-primary-rotation-180-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-crc-primary-rotation-180-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-crc-primary-rotation-180-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-crc-primary-rotation-180-4_tiled_dg2_rc_ccs +kms_ccs@pipe-G-crc-primary-rotation-180-4_tiled_dg2_mc_ccs +kms_ccs@pipe-G-crc-primary-rotation-180-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-G-crc-primary-rotation-180-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-crc-primary-rotation-180-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-crc-primary-rotation-180-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-random-ccs-data-y_tiled_ccs +kms_ccs@pipe-G-random-ccs-data-yf_tiled_ccs +kms_ccs@pipe-G-random-ccs-data-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-random-ccs-data-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-random-ccs-data-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-random-ccs-data-4_tiled_dg2_rc_ccs +kms_ccs@pipe-G-random-ccs-data-4_tiled_dg2_mc_ccs +kms_ccs@pipe-G-random-ccs-data-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-G-random-ccs-data-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-random-ccs-data-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-random-ccs-data-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-missing-ccs-buffer-y_tiled_ccs +kms_ccs@pipe-G-missing-ccs-buffer-yf_tiled_ccs +kms_ccs@pipe-G-missing-ccs-buffer-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-missing-ccs-buffer-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-missing-ccs-buffer-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-missing-ccs-buffer-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-missing-ccs-buffer-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-missing-ccs-buffer-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-ccs-on-another-bo-y_tiled_ccs +kms_ccs@pipe-G-ccs-on-another-bo-yf_tiled_ccs +kms_ccs@pipe-G-ccs-on-another-bo-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-ccs-on-another-bo-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-ccs-on-another-bo-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-ccs-on-another-bo-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-ccs-on-another-bo-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-bad-aux-stride-y_tiled_ccs +kms_ccs@pipe-G-bad-aux-stride-yf_tiled_ccs +kms_ccs@pipe-G-bad-aux-stride-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-bad-aux-stride-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-bad-aux-stride-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-bad-aux-stride-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-bad-aux-stride-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-bad-aux-stride-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-G-crc-sprite-planes-basic-y_tiled_ccs +kms_ccs@pipe-G-crc-sprite-planes-basic-yf_tiled_ccs +kms_ccs@pipe-G-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-G-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-G-crc-sprite-planes-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-G-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-G-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-G-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-G-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-G-crc-sprite-planes-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-G-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-bad-pixel-format-y_tiled_ccs +kms_ccs@pipe-H-bad-pixel-format-yf_tiled_ccs +kms_ccs@pipe-H-bad-pixel-format-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-bad-pixel-format-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-bad-pixel-format-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-bad-pixel-format-4_tiled_dg2_rc_ccs +kms_ccs@pipe-H-bad-pixel-format-4_tiled_dg2_mc_ccs +kms_ccs@pipe-H-bad-pixel-format-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-H-bad-pixel-format-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-bad-pixel-format-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-bad-pixel-format-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-bad-rotation-90-y_tiled_ccs +kms_ccs@pipe-H-bad-rotation-90-yf_tiled_ccs +kms_ccs@pipe-H-bad-rotation-90-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-bad-rotation-90-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-bad-rotation-90-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-bad-rotation-90-4_tiled_dg2_rc_ccs +kms_ccs@pipe-H-bad-rotation-90-4_tiled_dg2_mc_ccs +kms_ccs@pipe-H-bad-rotation-90-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-H-bad-rotation-90-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-bad-rotation-90-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-bad-rotation-90-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-crc-primary-basic-y_tiled_ccs +kms_ccs@pipe-H-crc-primary-basic-yf_tiled_ccs +kms_ccs@pipe-H-crc-primary-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-crc-primary-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-crc-primary-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-crc-primary-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-H-crc-primary-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-H-crc-primary-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-H-crc-primary-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-crc-primary-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-crc-primary-basic-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-crc-primary-rotation-180-y_tiled_ccs +kms_ccs@pipe-H-crc-primary-rotation-180-yf_tiled_ccs +kms_ccs@pipe-H-crc-primary-rotation-180-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-crc-primary-rotation-180-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-crc-primary-rotation-180-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-crc-primary-rotation-180-4_tiled_dg2_rc_ccs +kms_ccs@pipe-H-crc-primary-rotation-180-4_tiled_dg2_mc_ccs +kms_ccs@pipe-H-crc-primary-rotation-180-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-H-crc-primary-rotation-180-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-crc-primary-rotation-180-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-crc-primary-rotation-180-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-random-ccs-data-y_tiled_ccs +kms_ccs@pipe-H-random-ccs-data-yf_tiled_ccs +kms_ccs@pipe-H-random-ccs-data-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-random-ccs-data-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-random-ccs-data-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-random-ccs-data-4_tiled_dg2_rc_ccs +kms_ccs@pipe-H-random-ccs-data-4_tiled_dg2_mc_ccs +kms_ccs@pipe-H-random-ccs-data-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-H-random-ccs-data-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-random-ccs-data-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-random-ccs-data-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-missing-ccs-buffer-y_tiled_ccs +kms_ccs@pipe-H-missing-ccs-buffer-yf_tiled_ccs +kms_ccs@pipe-H-missing-ccs-buffer-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-missing-ccs-buffer-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-missing-ccs-buffer-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-missing-ccs-buffer-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-missing-ccs-buffer-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-missing-ccs-buffer-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-ccs-on-another-bo-y_tiled_ccs +kms_ccs@pipe-H-ccs-on-another-bo-yf_tiled_ccs +kms_ccs@pipe-H-ccs-on-another-bo-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-ccs-on-another-bo-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-ccs-on-another-bo-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-ccs-on-another-bo-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-ccs-on-another-bo-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-bad-aux-stride-y_tiled_ccs +kms_ccs@pipe-H-bad-aux-stride-yf_tiled_ccs +kms_ccs@pipe-H-bad-aux-stride-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-bad-aux-stride-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-bad-aux-stride-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-bad-aux-stride-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-bad-aux-stride-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-bad-aux-stride-4_tiled_mtl_rc_ccs_cc +kms_ccs@pipe-H-crc-sprite-planes-basic-y_tiled_ccs +kms_ccs@pipe-H-crc-sprite-planes-basic-yf_tiled_ccs +kms_ccs@pipe-H-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs +kms_ccs@pipe-H-crc-sprite-planes-basic-y_tiled_gen12_rc_ccs_cc +kms_ccs@pipe-H-crc-sprite-planes-basic-y_tiled_gen12_mc_ccs +kms_ccs@pipe-H-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs +kms_ccs@pipe-H-crc-sprite-planes-basic-4_tiled_dg2_mc_ccs +kms_ccs@pipe-H-crc-sprite-planes-basic-4_tiled_dg2_rc_ccs_cc +kms_ccs@pipe-H-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs +kms_ccs@pipe-H-crc-sprite-planes-basic-4_tiled_mtl_mc_ccs +kms_ccs@pipe-H-crc-sprite-planes-basic-4_tiled_mtl_rc_ccs_cc +kms_cdclk@plane-scaling +kms_cdclk@mode-transition +kms_cdclk@mode-transition-all-outputs +kms_color@degamma +kms_color@gamma +kms_color@legacy-gamma +kms_color@legacy-gamma-reset +kms_color@ctm-red-to-blue +kms_color@ctm-green-to-red +kms_color@ctm-blue-to-red +kms_color@ctm-max +kms_color@ctm-negative +kms_color@ctm-0-25 +kms_color@ctm-0-50 +kms_color@ctm-0-75 +kms_color@ctm-signed +kms_color@deep-color +kms_color@invalid-gamma-lut-sizes +kms_color@invalid-degamma-lut-sizes +kms_color@invalid-ctm-matrix-sizes +kms_concurrent@pipe-A +kms_concurrent@pipe-B +kms_concurrent@pipe-C +kms_concurrent@pipe-D +kms_concurrent@pipe-E +kms_concurrent@pipe-F +kms_concurrent@pipe-G +kms_concurrent@pipe-H +kms_content_protection@legacy +kms_content_protection@atomic +kms_content_protection@atomic-dpms +kms_content_protection@LIC +kms_content_protection@type1 +kms_content_protection@mei_interface +kms_content_protection@content_type_change +kms_content_protection@uevent +kms_content_protection@srm +kms_content_protection@dp-mst-type-0 +kms_content_protection@dp-mst-lic-type-0 +kms_content_protection@dp-mst-type-1 +kms_content_protection@dp-mst-lic-type-1 +kms_cursor_crc@cursor-size-change +kms_cursor_crc@cursor-alpha-opaque +kms_cursor_crc@cursor-alpha-transparent +kms_cursor_crc@cursor-dpms +kms_cursor_crc@cursor-suspend +kms_cursor_crc@cursor-onscreen-32x32 +kms_cursor_crc@cursor-offscreen-32x32 +kms_cursor_crc@cursor-sliding-32x32 +kms_cursor_crc@cursor-random-32x32 +kms_cursor_crc@cursor-rapid-movement-32x32 +kms_cursor_crc@cursor-onscreen-32x10 +kms_cursor_crc@cursor-offscreen-32x10 +kms_cursor_crc@cursor-sliding-32x10 +kms_cursor_crc@cursor-random-32x10 +kms_cursor_crc@cursor-rapid-movement-32x10 +kms_cursor_crc@cursor-onscreen-64x64 +kms_cursor_crc@cursor-offscreen-64x64 +kms_cursor_crc@cursor-sliding-64x64 +kms_cursor_crc@cursor-random-64x64 +kms_cursor_crc@cursor-rapid-movement-64x64 +kms_cursor_crc@cursor-onscreen-64x21 +kms_cursor_crc@cursor-offscreen-64x21 +kms_cursor_crc@cursor-sliding-64x21 +kms_cursor_crc@cursor-random-64x21 +kms_cursor_crc@cursor-rapid-movement-64x21 +kms_cursor_crc@cursor-onscreen-128x128 +kms_cursor_crc@cursor-offscreen-128x128 +kms_cursor_crc@cursor-sliding-128x128 +kms_cursor_crc@cursor-random-128x128 +kms_cursor_crc@cursor-rapid-movement-128x128 +kms_cursor_crc@cursor-onscreen-128x42 +kms_cursor_crc@cursor-offscreen-128x42 +kms_cursor_crc@cursor-sliding-128x42 +kms_cursor_crc@cursor-random-128x42 +kms_cursor_crc@cursor-rapid-movement-128x42 +kms_cursor_crc@cursor-onscreen-256x256 +kms_cursor_crc@cursor-offscreen-256x256 +kms_cursor_crc@cursor-sliding-256x256 +kms_cursor_crc@cursor-random-256x256 +kms_cursor_crc@cursor-rapid-movement-256x256 +kms_cursor_crc@cursor-onscreen-256x85 +kms_cursor_crc@cursor-offscreen-256x85 +kms_cursor_crc@cursor-sliding-256x85 +kms_cursor_crc@cursor-random-256x85 +kms_cursor_crc@cursor-rapid-movement-256x85 +kms_cursor_crc@cursor-onscreen-512x512 +kms_cursor_crc@cursor-offscreen-512x512 +kms_cursor_crc@cursor-sliding-512x512 +kms_cursor_crc@cursor-random-512x512 +kms_cursor_crc@cursor-rapid-movement-512x512 +kms_cursor_crc@cursor-onscreen-512x170 +kms_cursor_crc@cursor-offscreen-512x170 +kms_cursor_crc@cursor-sliding-512x170 +kms_cursor_crc@cursor-random-512x170 +kms_cursor_crc@cursor-rapid-movement-512x170 +kms_cursor_crc@cursor-onscreen-max-size +kms_cursor_crc@cursor-offscreen-max-size +kms_cursor_crc@cursor-sliding-max-size +kms_cursor_crc@cursor-random-max-size +kms_cursor_crc@cursor-rapid-movement-max-size +kms_cursor_legacy@single-bo +kms_cursor_legacy@single-move +kms_cursor_legacy@forked-bo +kms_cursor_legacy@forked-move +kms_cursor_legacy@torture-bo +kms_cursor_legacy@torture-move +kms_cursor_legacy@nonblocking-modeset-vs-cursor-atomic +kms_cursor_legacy@long-nonblocking-modeset-vs-cursor-atomic +kms_cursor_legacy@2x-flip-vs-cursor-legacy +kms_cursor_legacy@2x-flip-vs-cursor-atomic +kms_cursor_legacy@2x-long-flip-vs-cursor-legacy +kms_cursor_legacy@2x-long-flip-vs-cursor-atomic +kms_cursor_legacy@2x-nonblocking-modeset-vs-cursor-atomic +kms_cursor_legacy@2x-long-nonblocking-modeset-vs-cursor-atomic +kms_cursor_legacy@2x-cursor-vs-flip-legacy +kms_cursor_legacy@2x-long-cursor-vs-flip-legacy +kms_cursor_legacy@2x-cursor-vs-flip-atomic +kms_cursor_legacy@2x-long-cursor-vs-flip-atomic +kms_cursor_legacy@flip-vs-cursor-crc-legacy +kms_cursor_legacy@flip-vs-cursor-crc-atomic +kms_cursor_legacy@flip-vs-cursor-busy-crc-legacy +kms_cursor_legacy@flip-vs-cursor-busy-crc-atomic +kms_cursor_legacy@basic-flip-before-cursor-legacy +kms_cursor_legacy@basic-busy-flip-before-cursor-legacy +kms_cursor_legacy@basic-flip-after-cursor-legacy +kms_cursor_legacy@basic-flip-before-cursor-varying-size +kms_cursor_legacy@basic-busy-flip-before-cursor-varying-size +kms_cursor_legacy@basic-flip-after-cursor-varying-size +kms_cursor_legacy@short-flip-before-cursor-toggle +kms_cursor_legacy@short-busy-flip-before-cursor-toggle +kms_cursor_legacy@short-flip-after-cursor-toggle +kms_cursor_legacy@basic-flip-before-cursor-atomic +kms_cursor_legacy@basic-busy-flip-before-cursor-atomic +kms_cursor_legacy@basic-flip-after-cursor-atomic +kms_cursor_legacy@short-flip-before-cursor-atomic-transitions +kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions +kms_cursor_legacy@short-flip-after-cursor-atomic-transitions +kms_cursor_legacy@short-flip-before-cursor-atomic-transitions-varying-size +kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions-varying-size +kms_cursor_legacy@short-flip-after-cursor-atomic-transitions-varying-size +kms_cursor_legacy@cursor-vs-flip-legacy +kms_cursor_legacy@flip-vs-cursor-legacy +kms_cursor_legacy@cursorA-vs-flipA-legacy +kms_cursor_legacy@cursorA-vs-flipB-legacy +kms_cursor_legacy@cursorB-vs-flipA-legacy +kms_cursor_legacy@cursorB-vs-flipB-legacy +kms_cursor_legacy@cursor-vs-flip-varying-size +kms_cursor_legacy@flip-vs-cursor-varying-size +kms_cursor_legacy@cursorA-vs-flipA-varying-size +kms_cursor_legacy@cursorA-vs-flipB-varying-size +kms_cursor_legacy@cursorB-vs-flipA-varying-size +kms_cursor_legacy@cursorB-vs-flipB-varying-size +kms_cursor_legacy@cursor-vs-flip-toggle +kms_cursor_legacy@flip-vs-cursor-toggle +kms_cursor_legacy@cursorA-vs-flipA-toggle +kms_cursor_legacy@cursorA-vs-flipB-toggle +kms_cursor_legacy@cursorB-vs-flipA-toggle +kms_cursor_legacy@cursorB-vs-flipB-toggle +kms_cursor_legacy@cursor-vs-flip-atomic +kms_cursor_legacy@flip-vs-cursor-atomic +kms_cursor_legacy@cursorA-vs-flipA-atomic +kms_cursor_legacy@cursorA-vs-flipB-atomic +kms_cursor_legacy@cursorB-vs-flipA-atomic +kms_cursor_legacy@cursorB-vs-flipB-atomic +kms_cursor_legacy@cursor-vs-flip-atomic-transitions +kms_cursor_legacy@flip-vs-cursor-atomic-transitions +kms_cursor_legacy@cursorA-vs-flipA-atomic-transitions +kms_cursor_legacy@cursorA-vs-flipB-atomic-transitions +kms_cursor_legacy@cursorB-vs-flipA-atomic-transitions +kms_cursor_legacy@cursorB-vs-flipB-atomic-transitions +kms_cursor_legacy@cursor-vs-flip-atomic-transitions-varying-size +kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size +kms_cursor_legacy@cursorA-vs-flipA-atomic-transitions-varying-size +kms_cursor_legacy@cursorA-vs-flipB-atomic-transitions-varying-size +kms_cursor_legacy@cursorB-vs-flipA-atomic-transitions-varying-size +kms_cursor_legacy@cursorB-vs-flipB-atomic-transitions-varying-size +kms_dither@FB-8BPC-Vs-Panel-6BPC +kms_dither@FB-8BPC-Vs-Panel-8BPC +kms_dp_aux_dev +kms_tiled_display@basic-test-pattern +kms_tiled_display@basic-test-pattern-with-chamelium +kms_draw_crc@draw-method-mmap-cpu +kms_draw_crc@draw-method-mmap-gtt +kms_draw_crc@draw-method-mmap-wc +kms_draw_crc@draw-method-pwrite +kms_draw_crc@draw-method-blt +kms_draw_crc@draw-method-render +kms_draw_crc@fill-fb +kms_dsc@dsc-basic +kms_dsc@dsc-with-formats +kms_dsc@dsc-with-bpc +kms_dsc@dsc-with-bpc-formats +kms_dsc@dsc-with-output-formats +kms_fbcon_fbt@fbc +kms_fbcon_fbt@psr +kms_fbcon_fbt@fbc-suspend +kms_fbcon_fbt@psr-suspend +kms_fence_pin_leak +kms_flip@nonblocking-read +kms_flip@wf_vblank-ts-check +kms_flip@2x-wf_vblank-ts-check +kms_flip@blocking-wf_vblank +kms_flip@2x-blocking-wf_vblank +kms_flip@absolute-wf_vblank +kms_flip@2x-absolute-wf_vblank +kms_flip@blocking-absolute-wf_vblank +kms_flip@2x-blocking-absolute-wf_vblank +kms_flip@basic-plain-flip +kms_flip@2x-plain-flip +kms_flip@busy-flip +kms_flip@2x-busy-flip +kms_flip@flip-vs-fences +kms_flip@2x-flip-vs-fences +kms_flip@plain-flip-ts-check +kms_flip@2x-plain-flip-ts-check +kms_flip@plain-flip-fb-recreate +kms_flip@2x-plain-flip-fb-recreate +kms_flip@flip-vs-rmfb +kms_flip@2x-flip-vs-rmfb +kms_flip@basic-flip-vs-dpms +kms_flip@2x-flip-vs-dpms +kms_flip@flip-vs-panning +kms_flip@2x-flip-vs-panning +kms_flip@basic-flip-vs-modeset +kms_flip@2x-flip-vs-modeset +kms_flip@flip-vs-expired-vblank +kms_flip@2x-flip-vs-expired-vblank +kms_flip@flip-vs-absolute-wf_vblank +kms_flip@2x-flip-vs-absolute-wf_vblank +kms_flip@basic-flip-vs-wf_vblank +kms_flip@2x-flip-vs-wf_vblank +kms_flip@flip-vs-blocking-wf-vblank +kms_flip@2x-flip-vs-blocking-wf-vblank +kms_flip@flip-vs-modeset-vs-hang +kms_flip@2x-flip-vs-modeset-vs-hang +kms_flip@flip-vs-panning-vs-hang +kms_flip@2x-flip-vs-panning-vs-hang +kms_flip@flip-vs-dpms-off-vs-modeset +kms_flip@2x-flip-vs-dpms-off-vs-modeset +kms_flip@single-buffer-flip-vs-dpms-off-vs-modeset +kms_flip@2x-single-buffer-flip-vs-dpms-off-vs-modeset +kms_flip@dpms-off-confusion +kms_flip@nonexisting-fb +kms_flip@2x-nonexisting-fb +kms_flip@dpms-vs-vblank-race +kms_flip@2x-dpms-vs-vblank-race +kms_flip@modeset-vs-vblank-race +kms_flip@2x-modeset-vs-vblank-race +kms_flip@bo-too-big +kms_flip@flip-vs-suspend +kms_flip@2x-flip-vs-suspend +kms_flip@wf_vblank-ts-check-interruptible +kms_flip@2x-wf_vblank-ts-check-interruptible +kms_flip@absolute-wf_vblank-interruptible +kms_flip@2x-absolute-wf_vblank-interruptible +kms_flip@blocking-absolute-wf_vblank-interruptible +kms_flip@2x-blocking-absolute-wf_vblank-interruptible +kms_flip@plain-flip-interruptible +kms_flip@2x-plain-flip-interruptible +kms_flip@flip-vs-fences-interruptible +kms_flip@2x-flip-vs-fences-interruptible +kms_flip@plain-flip-ts-check-interruptible +kms_flip@2x-plain-flip-ts-check-interruptible +kms_flip@plain-flip-fb-recreate-interruptible +kms_flip@2x-plain-flip-fb-recreate-interruptible +kms_flip@flip-vs-rmfb-interruptible +kms_flip@2x-flip-vs-rmfb-interruptible +kms_flip@flip-vs-panning-interruptible +kms_flip@2x-flip-vs-panning-interruptible +kms_flip@flip-vs-expired-vblank-interruptible +kms_flip@2x-flip-vs-expired-vblank-interruptible +kms_flip@flip-vs-absolute-wf_vblank-interruptible +kms_flip@2x-flip-vs-absolute-wf_vblank-interruptible +kms_flip@flip-vs-wf_vblank-interruptible +kms_flip@2x-flip-vs-wf_vblank-interruptible +kms_flip@flip-vs-dpms-off-vs-modeset-interruptible +kms_flip@2x-flip-vs-dpms-off-vs-modeset-interruptible +kms_flip@single-buffer-flip-vs-dpms-off-vs-modeset-interruptible +kms_flip@2x-single-buffer-flip-vs-dpms-off-vs-modeset-interruptible +kms_flip@dpms-off-confusion-interruptible +kms_flip@nonexisting-fb-interruptible +kms_flip@2x-nonexisting-fb-interruptible +kms_flip@dpms-vs-vblank-race-interruptible +kms_flip@2x-dpms-vs-vblank-race-interruptible +kms_flip@modeset-vs-vblank-race-interruptible +kms_flip@2x-modeset-vs-vblank-race-interruptible +kms_flip@bo-too-big-interruptible +kms_flip@flip-vs-suspend-interruptible +kms_flip@2x-flip-vs-suspend-interruptible +kms_flip_event_leak@basic +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-yftile-to-64bpp-yftile-downscaling +kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-downscaling +kms_flip_scaled_crc@flip-32bpp-4tile-to-64bpp-4tile-downscaling +kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-downscaling +kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-downscaling +kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tile-downscaling +kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-yftile-to-16bpp-yftile-downscaling +kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-downscaling +kms_flip_scaled_crc@flip-64bpp-4tile-to-16bpp-4tile-downscaling +kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-downscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs-downscaling +kms_flip_scaled_crc@flip-32bpp-4tile-to-32bpp-4tiledg2rcccs-downscaling +kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytileccs-downscaling +kms_flip_scaled_crc@flip-32bpp-yftile-to-32bpp-yftileccs-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling +kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tiledg2rcccs-downscaling +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-32bpp-yftile-to-64bpp-yftile-upscaling +kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling +kms_flip_scaled_crc@flip-32bpp-4tile-to-64bpp-4tile-upscaling +kms_flip_scaled_crc@flip-32bpp-linear-to-64bpp-linear-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-upscaling +kms_flip_scaled_crc@flip-64bpp-xtile-to-32bpp-xtile-upscaling +kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tile-upscaling +kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-yftile-to-16bpp-yftile-upscaling +kms_flip_scaled_crc@flip-64bpp-xtile-to-16bpp-xtile-upscaling +kms_flip_scaled_crc@flip-64bpp-4tile-to-16bpp-4tile-upscaling +kms_flip_scaled_crc@flip-64bpp-linear-to-16bpp-linear-upscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-upscaling +kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling +kms_flip_scaled_crc@flip-32bpp-4tile-to-32bpp-4tiledg2rcccs-upscaling +kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytileccs-upscaling +kms_flip_scaled_crc@flip-32bpp-yftile-to-32bpp-yftileccs-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling +kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tiledg2rcccs-upscaling +kms_force_connector_basic@force-load-detect +kms_force_connector_basic@force-connector-state +kms_force_connector_basic@force-edid +kms_force_connector_basic@prune-stale-modes +kms_frontbuffer_tracking@fbc-1p-rte +kms_frontbuffer_tracking@fbc-2p-rte +kms_frontbuffer_tracking@psr-1p-rte +kms_frontbuffer_tracking@psr-2p-rte +kms_frontbuffer_tracking@fbcpsr-1p-rte +kms_frontbuffer_tracking@fbcpsr-2p-rte +kms_frontbuffer_tracking@drrs-1p-rte +kms_frontbuffer_tracking@drrs-2p-rte +kms_frontbuffer_tracking@fbcdrrs-1p-rte +kms_frontbuffer_tracking@fbcdrrs-2p-rte +kms_frontbuffer_tracking@psrdrrs-1p-rte +kms_frontbuffer_tracking@psrdrrs-2p-rte +kms_frontbuffer_tracking@fbcpsrdrrs-1p-rte +kms_frontbuffer_tracking@fbcpsrdrrs-2p-rte +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbc-1p-offscren-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-1p-offscren-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-1p-offscren-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-1p-offscren-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-1p-offscren-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbc-1p-offscren-pri-indfb-draw-render +kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbc-2p-scndscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-2p-scndscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-scndscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-2p-scndscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-2p-scndscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@psr-1p-offscren-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-1p-offscren-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-1p-offscren-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-1p-offscren-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-1p-offscren-pri-indfb-draw-blt +kms_frontbuffer_tracking@psr-1p-offscren-pri-indfb-draw-render +kms_frontbuffer_tracking@psr-1p-offscren-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-1p-offscren-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-1p-offscren-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-1p-offscren-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@psr-1p-offscren-pri-shrfb-draw-blt +kms_frontbuffer_tracking@psr-1p-offscren-pri-shrfb-draw-render +kms_frontbuffer_tracking@psr-2p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-2p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-2p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-2p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-2p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@psr-2p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@psr-2p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-2p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-2p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-2p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-2p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@psr-2p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@drrs-1p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-1p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-1p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-1p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-1p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@drrs-1p-offscren-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-1p-offscren-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-1p-offscren-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-1p-offscren-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-1p-offscren-pri-indfb-draw-blt +kms_frontbuffer_tracking@drrs-1p-offscren-pri-indfb-draw-render +kms_frontbuffer_tracking@drrs-1p-offscren-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-1p-offscren-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-1p-offscren-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-1p-offscren-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@drrs-1p-offscren-pri-shrfb-draw-blt +kms_frontbuffer_tracking@drrs-1p-offscren-pri-shrfb-draw-render +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@drrs-2p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-2p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-2p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-2p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-2p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@drrs-2p-scndscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-2p-scndscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-2p-scndscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-2p-scndscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-2p-scndscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-1p-offscren-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-shrfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-1p-offscren-pri-shrfb-draw-render +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-offscren-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-shrfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-shrfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-shrfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-shrfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-shrfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-pri-shrfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-cur-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-cur-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-cur-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-cur-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-cur-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-cur-indfb-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-draw-render +kms_frontbuffer_tracking@fbc-1p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbc-2p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbc-2p-scndscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@psr-1p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@psr-1p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@psr-1p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@psr-1p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@psr-1p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@psr-1p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@psr-2p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@psr-2p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@psr-2p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@psr-2p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@psr-2p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@psr-2p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-msflip-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-plflip-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@psr-2p-scndscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@drrs-1p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@drrs-2p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-indfb-msflip-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-indfb-plflip-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@drrs-2p-scndscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-indfb-msflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-indfb-plflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-indfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-indfb-msflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-indfb-plflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-shrfb-pgflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-shrfb-msflip-blt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-shrfb-plflip-blt +kms_frontbuffer_tracking@fbc-1p-indfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbc-1p-shrfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-indfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbc-2p-shrfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-1p-indfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-1p-shrfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-indfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-2p-shrfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-1p-indfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-1p-shrfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-indfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-2p-shrfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-indfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-1p-shrfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-indfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-2p-shrfb-fliptrack-mmap-gtt +kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbc-2p-scndscrn-cur-indfb-move +kms_frontbuffer_tracking@fbc-2p-scndscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-move +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-onoff +kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@psr-2p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@psr-2p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-move +kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-onoff +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-move +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-onoff +kms_frontbuffer_tracking@drrs-1p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@drrs-1p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@drrs-2p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@drrs-2p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@drrs-2p-scndscrn-cur-indfb-move +kms_frontbuffer_tracking@drrs-2p-scndscrn-cur-indfb-onoff +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-move +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-onoff +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-cur-indfb-move +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-cur-indfb-onoff +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-move +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-cur-indfb-move +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-cur-indfb-onoff +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-move +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-onoff +kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@drrs-2p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@psrdrrs-1p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@psrdrrs-2p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@psrdrrs-2p-scndscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcpsrdrrs-1p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcpsrdrrs-2p-primscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbcpsrdrrs-2p-scndscrn-spr-indfb-fullscreen +kms_frontbuffer_tracking@fbc-1p-pri-indfb-multidraw +kms_frontbuffer_tracking@fbc-2p-pri-indfb-multidraw +kms_frontbuffer_tracking@psr-1p-pri-indfb-multidraw +kms_frontbuffer_tracking@psr-2p-pri-indfb-multidraw +kms_frontbuffer_tracking@fbcpsr-1p-pri-indfb-multidraw +kms_frontbuffer_tracking@fbcpsr-2p-pri-indfb-multidraw +kms_frontbuffer_tracking@drrs-1p-pri-indfb-multidraw +kms_frontbuffer_tracking@drrs-2p-pri-indfb-multidraw +kms_frontbuffer_tracking@fbcdrrs-1p-pri-indfb-multidraw +kms_frontbuffer_tracking@fbcdrrs-2p-pri-indfb-multidraw +kms_frontbuffer_tracking@psrdrrs-1p-pri-indfb-multidraw +kms_frontbuffer_tracking@psrdrrs-2p-pri-indfb-multidraw +kms_frontbuffer_tracking@fbcpsrdrrs-1p-pri-indfb-multidraw +kms_frontbuffer_tracking@fbcpsrdrrs-2p-pri-indfb-multidraw +kms_frontbuffer_tracking@fbc-farfromfence-mmap-gtt +kms_frontbuffer_tracking@psr-farfromfence-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-farfromfence-mmap-gtt +kms_frontbuffer_tracking@drrs-farfromfence-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-farfromfence-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-farfromfence-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-farfromfence-mmap-gtt +kms_frontbuffer_tracking@fbc-rgb565-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-rgb101010-draw-mmap-cpu +kms_frontbuffer_tracking@fbc-rgb565-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-rgb101010-draw-mmap-gtt +kms_frontbuffer_tracking@fbc-rgb565-draw-mmap-wc +kms_frontbuffer_tracking@fbc-rgb101010-draw-mmap-wc +kms_frontbuffer_tracking@fbc-rgb565-draw-pwrite +kms_frontbuffer_tracking@fbc-rgb101010-draw-pwrite +kms_frontbuffer_tracking@fbc-rgb565-draw-blt +kms_frontbuffer_tracking@fbc-rgb101010-draw-blt +kms_frontbuffer_tracking@fbc-rgb565-draw-render +kms_frontbuffer_tracking@fbc-rgb101010-draw-render +kms_frontbuffer_tracking@psr-rgb565-draw-mmap-cpu +kms_frontbuffer_tracking@psr-rgb101010-draw-mmap-cpu +kms_frontbuffer_tracking@psr-rgb565-draw-mmap-gtt +kms_frontbuffer_tracking@psr-rgb101010-draw-mmap-gtt +kms_frontbuffer_tracking@psr-rgb565-draw-mmap-wc +kms_frontbuffer_tracking@psr-rgb101010-draw-mmap-wc +kms_frontbuffer_tracking@psr-rgb565-draw-pwrite +kms_frontbuffer_tracking@psr-rgb101010-draw-pwrite +kms_frontbuffer_tracking@psr-rgb565-draw-blt +kms_frontbuffer_tracking@psr-rgb101010-draw-blt +kms_frontbuffer_tracking@psr-rgb565-draw-render +kms_frontbuffer_tracking@psr-rgb101010-draw-render +kms_frontbuffer_tracking@fbcpsr-rgb565-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-rgb101010-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsr-rgb565-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-rgb101010-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsr-rgb565-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-rgb101010-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsr-rgb565-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-rgb101010-draw-pwrite +kms_frontbuffer_tracking@fbcpsr-rgb565-draw-blt +kms_frontbuffer_tracking@fbcpsr-rgb101010-draw-blt +kms_frontbuffer_tracking@fbcpsr-rgb565-draw-render +kms_frontbuffer_tracking@fbcpsr-rgb101010-draw-render +kms_frontbuffer_tracking@drrs-rgb565-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-rgb101010-draw-mmap-cpu +kms_frontbuffer_tracking@drrs-rgb565-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-rgb101010-draw-mmap-gtt +kms_frontbuffer_tracking@drrs-rgb565-draw-mmap-wc +kms_frontbuffer_tracking@drrs-rgb101010-draw-mmap-wc +kms_frontbuffer_tracking@drrs-rgb565-draw-pwrite +kms_frontbuffer_tracking@drrs-rgb101010-draw-pwrite +kms_frontbuffer_tracking@drrs-rgb565-draw-blt +kms_frontbuffer_tracking@drrs-rgb101010-draw-blt +kms_frontbuffer_tracking@drrs-rgb565-draw-render +kms_frontbuffer_tracking@drrs-rgb101010-draw-render +kms_frontbuffer_tracking@fbcdrrs-rgb565-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-rgb101010-draw-mmap-cpu +kms_frontbuffer_tracking@fbcdrrs-rgb565-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-rgb101010-draw-mmap-gtt +kms_frontbuffer_tracking@fbcdrrs-rgb565-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-rgb101010-draw-mmap-wc +kms_frontbuffer_tracking@fbcdrrs-rgb565-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-rgb101010-draw-pwrite +kms_frontbuffer_tracking@fbcdrrs-rgb565-draw-blt +kms_frontbuffer_tracking@fbcdrrs-rgb101010-draw-blt +kms_frontbuffer_tracking@fbcdrrs-rgb565-draw-render +kms_frontbuffer_tracking@fbcdrrs-rgb101010-draw-render +kms_frontbuffer_tracking@psrdrrs-rgb565-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-rgb101010-draw-mmap-cpu +kms_frontbuffer_tracking@psrdrrs-rgb565-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-rgb101010-draw-mmap-gtt +kms_frontbuffer_tracking@psrdrrs-rgb565-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-rgb101010-draw-mmap-wc +kms_frontbuffer_tracking@psrdrrs-rgb565-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-rgb101010-draw-pwrite +kms_frontbuffer_tracking@psrdrrs-rgb565-draw-blt +kms_frontbuffer_tracking@psrdrrs-rgb101010-draw-blt +kms_frontbuffer_tracking@psrdrrs-rgb565-draw-render +kms_frontbuffer_tracking@psrdrrs-rgb101010-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-rgb565-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-rgb101010-draw-mmap-cpu +kms_frontbuffer_tracking@fbcpsrdrrs-rgb565-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-rgb101010-draw-mmap-gtt +kms_frontbuffer_tracking@fbcpsrdrrs-rgb565-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-rgb101010-draw-mmap-wc +kms_frontbuffer_tracking@fbcpsrdrrs-rgb565-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-rgb101010-draw-pwrite +kms_frontbuffer_tracking@fbcpsrdrrs-rgb565-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-rgb101010-draw-blt +kms_frontbuffer_tracking@fbcpsrdrrs-rgb565-draw-render +kms_frontbuffer_tracking@fbcpsrdrrs-rgb101010-draw-render +kms_frontbuffer_tracking@fbc-indfb-scaledprimary +kms_frontbuffer_tracking@fbc-shrfb-scaledprimary +kms_frontbuffer_tracking@psr-indfb-scaledprimary +kms_frontbuffer_tracking@psr-shrfb-scaledprimary +kms_frontbuffer_tracking@fbcpsr-indfb-scaledprimary +kms_frontbuffer_tracking@fbcpsr-shrfb-scaledprimary +kms_frontbuffer_tracking@drrs-indfb-scaledprimary +kms_frontbuffer_tracking@drrs-shrfb-scaledprimary +kms_frontbuffer_tracking@fbcdrrs-indfb-scaledprimary +kms_frontbuffer_tracking@fbcdrrs-shrfb-scaledprimary +kms_frontbuffer_tracking@psrdrrs-indfb-scaledprimary +kms_frontbuffer_tracking@psrdrrs-shrfb-scaledprimary +kms_frontbuffer_tracking@fbcpsrdrrs-indfb-scaledprimary +kms_frontbuffer_tracking@fbcpsrdrrs-shrfb-scaledprimary +kms_frontbuffer_tracking@fbc-modesetfrombusy +kms_frontbuffer_tracking@fbc-badstride +kms_frontbuffer_tracking@fbc-stridechange +kms_frontbuffer_tracking@fbc-tiling-linear +kms_frontbuffer_tracking@fbc-tiling-y +kms_frontbuffer_tracking@fbc-tiling-4 +kms_frontbuffer_tracking@fbc-suspend +kms_frontbuffer_tracking@psr-modesetfrombusy +kms_frontbuffer_tracking@psr-slowdraw +kms_frontbuffer_tracking@psr-suspend +kms_frontbuffer_tracking@fbcpsr-modesetfrombusy +kms_frontbuffer_tracking@fbcpsr-badstride +kms_frontbuffer_tracking@fbcpsr-stridechange +kms_frontbuffer_tracking@fbcpsr-tiling-linear +kms_frontbuffer_tracking@fbcpsr-tiling-y +kms_frontbuffer_tracking@fbcpsr-tiling-4 +kms_frontbuffer_tracking@fbcpsr-slowdraw +kms_frontbuffer_tracking@fbcpsr-suspend +kms_frontbuffer_tracking@drrs-modesetfrombusy +kms_frontbuffer_tracking@drrs-slowdraw +kms_frontbuffer_tracking@drrs-suspend +kms_frontbuffer_tracking@fbcdrrs-modesetfrombusy +kms_frontbuffer_tracking@fbcdrrs-badstride +kms_frontbuffer_tracking@fbcdrrs-stridechange +kms_frontbuffer_tracking@fbcdrrs-tiling-linear +kms_frontbuffer_tracking@fbcdrrs-tiling-y +kms_frontbuffer_tracking@fbcdrrs-tiling-4 +kms_frontbuffer_tracking@fbcdrrs-slowdraw +kms_frontbuffer_tracking@fbcdrrs-suspend +kms_frontbuffer_tracking@psrdrrs-modesetfrombusy +kms_frontbuffer_tracking@psrdrrs-slowdraw +kms_frontbuffer_tracking@psrdrrs-suspend +kms_frontbuffer_tracking@fbcpsrdrrs-modesetfrombusy +kms_frontbuffer_tracking@fbcpsrdrrs-badstride +kms_frontbuffer_tracking@fbcpsrdrrs-stridechange +kms_frontbuffer_tracking@fbcpsrdrrs-tiling-linear +kms_frontbuffer_tracking@fbcpsrdrrs-tiling-y +kms_frontbuffer_tracking@fbcpsrdrrs-tiling-4 +kms_frontbuffer_tracking@fbcpsrdrrs-slowdraw +kms_frontbuffer_tracking@fbcpsrdrrs-suspend +kms_frontbuffer_tracking@basic +kms_getfb@getfb-handle-zero +kms_getfb@getfb-handle-valid +kms_getfb@getfb-handle-closed +kms_getfb@getfb-handle-not-fb +kms_getfb@getfb-addfb-different-handles +kms_getfb@getfb-repeated-different-handles +kms_getfb@getfb-reject-ccs +kms_getfb@getfb2-handle-zero +kms_getfb@getfb2-handle-closed +kms_getfb@getfb2-handle-not-fb +kms_getfb@getfb2-accept-ccs +kms_getfb@getfb2-into-addfb2 +kms_getfb@getfb-handle-protection +kms_getfb@getfb2-handle-protection +kms_hdmi_inject@inject-4k +kms_hdmi_inject@inject-audio +kms_hdr@bpc-switch +kms_hdr@bpc-switch-dpms +kms_hdr@bpc-switch-suspend +kms_hdr@static-toggle +kms_hdr@static-toggle-dpms +kms_hdr@static-toggle-suspend +kms_hdr@static-swap +kms_hdr@invalid-metadata-sizes +kms_hdr@invalid-hdr +kms_invalid_mode@clock-too-high +kms_invalid_mode@zero-clock +kms_invalid_mode@int-max-clock +kms_invalid_mode@uint-max-clock +kms_invalid_mode@zero-hdisplay +kms_invalid_mode@zero-vdisplay +kms_invalid_mode@bad-hsync-start +kms_invalid_mode@bad-vsync-start +kms_invalid_mode@bad-hsync-end +kms_invalid_mode@bad-vsync-end +kms_invalid_mode@bad-htotal +kms_invalid_mode@bad-vtotal +kms_legacy_colorkey@basic +kms_legacy_colorkey@invalid-plane +kms_multipipe_modeset@basic-max-pipe-crc-check +kms_panel_fitting@legacy +kms_panel_fitting@atomic-fastset +kms_pipe_b_c_ivb@pipe-B-dpms-off-modeset-pipe-C +kms_pipe_b_c_ivb@pipe-B-double-modeset-then-modeset-pipe-C +kms_pipe_b_c_ivb@disable-pipe-B-enable-pipe-C +kms_pipe_b_c_ivb@from-pipe-C-to-B-with-3-lanes +kms_pipe_b_c_ivb@enable-pipe-C-while-B-has-3-lanes +kms_pipe_crc_basic@bad-source +kms_pipe_crc_basic@read-crc +kms_pipe_crc_basic@read-crc-frame-sequence +kms_pipe_crc_basic@nonblocking-crc +kms_pipe_crc_basic@nonblocking-crc-frame-sequence +kms_pipe_crc_basic@suspend-read-crc +kms_pipe_crc_basic@hang-read-crc +kms_pipe_crc_basic@disable-crc-after-crtc +kms_pipe_crc_basic@compare-crc-sanitycheck-xr24 +kms_pipe_crc_basic@compare-crc-sanitycheck-nv12 +kms_plane@pixel-format +kms_plane@pixel-format-source-clamping +kms_plane@plane-position-covered +kms_plane@plane-position-hole +kms_plane@plane-position-hole-dpms +kms_plane@plane-panning-top-left +kms_plane@plane-panning-bottom-right +kms_plane@plane-panning-bottom-right-suspend +kms_plane@invalid-pixel-format-settings +kms_plane_alpha_blend@alpha-basic +kms_plane_alpha_blend@alpha-7efc +kms_plane_alpha_blend@coverage-7efc +kms_plane_alpha_blend@coverage-vs-premult-vs-constant +kms_plane_alpha_blend@alpha-transparent-fb +kms_plane_alpha_blend@alpha-opaque-fb +kms_plane_alpha_blend@constant-alpha-min +kms_plane_alpha_blend@constant-alpha-mid +kms_plane_alpha_blend@constant-alpha-max +kms_plane_cursor@primary +kms_plane_cursor@overlay +kms_plane_cursor@viewport +kms_plane_lowres@tiling-none +kms_plane_lowres@tiling-x +kms_plane_lowres@tiling-y +kms_plane_lowres@tiling-yf +kms_plane_lowres@tiling-4 +kms_plane_multiple@tiling-none +kms_plane_multiple@tiling-x +kms_plane_multiple@tiling-y +kms_plane_multiple@tiling-yf +kms_plane_multiple@tiling-4 +kms_plane_scaling@plane-upscale-with-pixel-format-20x20 +kms_plane_scaling@plane-upscale-with-pixel-format-factor-0-25 +kms_plane_scaling@plane-downscale-with-pixel-format-factor-0-25 +kms_plane_scaling@plane-downscale-with-pixel-format-factor-0-5 +kms_plane_scaling@plane-downscale-with-pixel-format-factor-0-75 +kms_plane_scaling@plane-scaler-with-pixel-format-unity-scaling +kms_plane_scaling@plane-upscale-with-rotation-20x20 +kms_plane_scaling@plane-upscale-with-rotation-factor-0-25 +kms_plane_scaling@plane-downscale-with-rotation-factor-0-25 +kms_plane_scaling@plane-downscale-with-rotation-factor-0-5 +kms_plane_scaling@plane-downscale-with-rotation-factor-0-75 +kms_plane_scaling@plane-scaler-with-rotation-unity-scaling +kms_plane_scaling@plane-upscale-with-modifiers-20x20 +kms_plane_scaling@plane-upscale-with-modifiers-factor-0-25 +kms_plane_scaling@plane-downscale-with-modifiers-factor-0-25 +kms_plane_scaling@plane-downscale-with-modifiers-factor-0-5 +kms_plane_scaling@plane-downscale-with-modifiers-factor-0-75 +kms_plane_scaling@plane-scaler-with-modifiers-unity-scaling +kms_plane_scaling@plane-scaler-with-clipping-clamping-pixel-formats +kms_plane_scaling@plane-scaler-with-clipping-clamping-rotation +kms_plane_scaling@plane-scaler-with-clipping-clamping-modifiers +kms_plane_scaling@planes-upscale-20x20 +kms_plane_scaling@planes-upscale-factor-0-25 +kms_plane_scaling@planes-scaler-unity-scaling +kms_plane_scaling@planes-downscale-factor-0-25 +kms_plane_scaling@planes-downscale-factor-0-5 +kms_plane_scaling@planes-downscale-factor-0-75 +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-25 +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-5 +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-75 +kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-25 +kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-5 +kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-75 +kms_plane_scaling@planes-unity-scaling-downscale-factor-0-25 +kms_plane_scaling@planes-unity-scaling-downscale-factor-0-5 +kms_plane_scaling@planes-unity-scaling-downscale-factor-0-75 +kms_plane_scaling@planes-downscale-factor-0-25-upscale-20x20 +kms_plane_scaling@planes-downscale-factor-0-25-upscale-factor-0-25 +kms_plane_scaling@planes-downscale-factor-0-25-unity-scaling +kms_plane_scaling@planes-downscale-factor-0-5-upscale-20x20 +kms_plane_scaling@planes-downscale-factor-0-5-upscale-factor-0-25 +kms_plane_scaling@planes-downscale-factor-0-5-unity-scaling +kms_plane_scaling@planes-downscale-factor-0-75-upscale-20x20 +kms_plane_scaling@planes-downscale-factor-0-75-upscale-factor-0-25 +kms_plane_scaling@planes-downscale-factor-0-75-unity-scaling +kms_plane_scaling@intel-max-src-size +kms_plane_scaling@invalid-num-scalers +kms_plane_scaling@invalid-parameters +kms_plane_scaling@2x-scaler-multi-pipe +kms_prime@basic-crc-hybrid +kms_prime@basic-modeset-hybrid +kms_prime@D3hot +kms_prime@basic-crc-vgem +kms_prop_blob@basic +kms_prop_blob@blob-prop-core +kms_prop_blob@blob-prop-validate +kms_prop_blob@blob-prop-lifetime +kms_prop_blob@blob-multiple +kms_prop_blob@invalid-get-prop-any +kms_prop_blob@invalid-get-prop +kms_prop_blob@invalid-set-prop-any +kms_prop_blob@invalid-set-prop +kms_properties@plane-properties-legacy +kms_properties@plane-properties-atomic +kms_properties@crtc-properties-legacy +kms_properties@crtc-properties-atomic +kms_properties@connector-properties-legacy +kms_properties@connector-properties-atomic +kms_properties@invalid-properties-legacy +kms_properties@invalid-properties-atomic +kms_properties@get_properties-sanity-atomic +kms_properties@get_properties-sanity-non-atomic +kms_psr@basic +kms_psr@no_drrs +kms_psr@primary_page_flip +kms_psr@primary_mmap_gtt +kms_psr@primary_mmap_cpu +kms_psr@primary_blt +kms_psr@primary_render +kms_psr@sprite_mmap_gtt +kms_psr@cursor_mmap_gtt +kms_psr@sprite_mmap_cpu +kms_psr@cursor_mmap_cpu +kms_psr@sprite_blt +kms_psr@cursor_blt +kms_psr@sprite_render +kms_psr@cursor_render +kms_psr@sprite_plane_move +kms_psr@cursor_plane_move +kms_psr@sprite_plane_onoff +kms_psr@cursor_plane_onoff +kms_psr@dpms +kms_psr@suspend +kms_psr@psr2_basic +kms_psr@psr2_no_drrs +kms_psr@psr2_primary_page_flip +kms_psr@psr2_primary_mmap_gtt +kms_psr@psr2_primary_mmap_cpu +kms_psr@psr2_primary_blt +kms_psr@psr2_primary_render +kms_psr@psr2_sprite_mmap_gtt +kms_psr@psr2_cursor_mmap_gtt +kms_psr@psr2_sprite_mmap_cpu +kms_psr@psr2_cursor_mmap_cpu +kms_psr@psr2_sprite_blt +kms_psr@psr2_cursor_blt +kms_psr@psr2_sprite_render +kms_psr@psr2_cursor_render +kms_psr@psr2_sprite_plane_move +kms_psr@psr2_cursor_plane_move +kms_psr@psr2_sprite_plane_onoff +kms_psr@psr2_cursor_plane_onoff +kms_psr@psr2_dpms +kms_psr@psr2_suspend +kms_psr2_sf@primary-plane-update-sf-dmg-area +kms_psr2_sf@primary-plane-update-sf-dmg-area-big-fb +kms_psr2_sf@overlay-plane-update-sf-dmg-area +kms_psr2_sf@cursor-plane-update-sf +kms_psr2_sf@cursor-plane-move-continuous-sf +kms_psr2_sf@cursor-plane-move-continuous-exceed-sf +kms_psr2_sf@cursor-plane-move-continuous-exceed-fully-sf +kms_psr2_sf@plane-move-sf-dmg-area +kms_psr2_sf@overlay-plane-move-continuous-sf +kms_psr2_sf@overlay-plane-move-continuous-exceed-sf +kms_psr2_sf@overlay-plane-move-continuous-exceed-fully-sf +kms_psr2_sf@overlay-primary-update-sf-dmg-area +kms_psr2_sf@overlay-plane-update-continuous-sf +kms_psr2_su@page_flip-XRGB8888 +kms_psr2_su@page_flip-NV12 +kms_psr2_su@page_flip-P010 +kms_psr2_su@frontbuffer-XRGB8888 +kms_pwrite_crc +kms_rmfb@rmfb-ioctl +kms_rmfb@close-fd +kms_rotation_crc@primary-rotation-90 +kms_rotation_crc@primary-rotation-180 +kms_rotation_crc@primary-rotation-270 +kms_rotation_crc@sprite-rotation-90 +kms_rotation_crc@sprite-rotation-180 +kms_rotation_crc@sprite-rotation-270 +kms_rotation_crc@cursor-rotation-180 +kms_rotation_crc@sprite-rotation-90-pos-100-0 +kms_rotation_crc@bad-pixel-format +kms_rotation_crc@bad-tiling +kms_rotation_crc@primary-x-tiled-reflect-x-0 +kms_rotation_crc@primary-x-tiled-reflect-x-180 +kms_rotation_crc@primary-y-tiled-reflect-x-0 +kms_rotation_crc@primary-y-tiled-reflect-x-90 +kms_rotation_crc@primary-y-tiled-reflect-x-180 +kms_rotation_crc@primary-y-tiled-reflect-x-270 +kms_rotation_crc@primary-yf-tiled-reflect-x-0 +kms_rotation_crc@primary-yf-tiled-reflect-x-90 +kms_rotation_crc@primary-yf-tiled-reflect-x-180 +kms_rotation_crc@primary-yf-tiled-reflect-x-270 +kms_rotation_crc@primary-4-tiled-reflect-x-0 +kms_rotation_crc@primary-4-tiled-reflect-x-180 +kms_rotation_crc@multiplane-rotation +kms_rotation_crc@multiplane-rotation-cropping-top +kms_rotation_crc@multiplane-rotation-cropping-bottom +kms_rotation_crc@exhaust-fences +kms_scaling_modes@scaling-mode-full +kms_scaling_modes@scaling-mode-center +kms_scaling_modes@scaling-mode-full-aspect +kms_scaling_modes@scaling-mode-none +kms_selftest@drm_cmdline +kms_selftest@drm_damage +kms_selftest@drm_dp_mst +kms_selftest@drm_format_helper +kms_selftest@drm_format +kms_selftest@framebuffer +kms_selftest@drm_plane +kms_setmode@basic +kms_setmode@basic-clone-single-crtc +kms_setmode@invalid-clone-single-crtc +kms_setmode@invalid-clone-exclusive-crtc +kms_setmode@clone-exclusive-crtc +kms_setmode@invalid-clone-single-crtc-stealing +kms_sysfs_edid_timing +kms_tv_load_detect@load-detect +kms_universal_plane@universal-plane-pipe-A-functional +kms_universal_plane@universal-plane-pipe-A-sanity +kms_universal_plane@disable-primary-vs-flip-pipe-A +kms_universal_plane@cursor-fb-leak-pipe-A +kms_universal_plane@universal-plane-pageflip-windowed-pipe-A +kms_universal_plane@universal-plane-pipe-B-functional +kms_universal_plane@universal-plane-pipe-B-sanity +kms_universal_plane@disable-primary-vs-flip-pipe-B +kms_universal_plane@cursor-fb-leak-pipe-B +kms_universal_plane@universal-plane-pageflip-windowed-pipe-B +kms_universal_plane@universal-plane-pipe-C-functional +kms_universal_plane@universal-plane-pipe-C-sanity +kms_universal_plane@disable-primary-vs-flip-pipe-C +kms_universal_plane@cursor-fb-leak-pipe-C +kms_universal_plane@universal-plane-pageflip-windowed-pipe-C +kms_universal_plane@universal-plane-pipe-D-functional +kms_universal_plane@universal-plane-pipe-D-sanity +kms_universal_plane@disable-primary-vs-flip-pipe-D +kms_universal_plane@cursor-fb-leak-pipe-D +kms_universal_plane@universal-plane-pageflip-windowed-pipe-D +kms_universal_plane@universal-plane-pipe-E-functional +kms_universal_plane@universal-plane-pipe-E-sanity +kms_universal_plane@disable-primary-vs-flip-pipe-E +kms_universal_plane@cursor-fb-leak-pipe-E +kms_universal_plane@universal-plane-pageflip-windowed-pipe-E +kms_universal_plane@universal-plane-pipe-F-functional +kms_universal_plane@universal-plane-pipe-F-sanity +kms_universal_plane@disable-primary-vs-flip-pipe-F +kms_universal_plane@cursor-fb-leak-pipe-F +kms_universal_plane@universal-plane-pageflip-windowed-pipe-F +kms_universal_plane@universal-plane-pipe-G-functional +kms_universal_plane@universal-plane-pipe-G-sanity +kms_universal_plane@disable-primary-vs-flip-pipe-G +kms_universal_plane@cursor-fb-leak-pipe-G +kms_universal_plane@universal-plane-pageflip-windowed-pipe-G +kms_universal_plane@universal-plane-pipe-H-functional +kms_universal_plane@universal-plane-pipe-H-sanity +kms_universal_plane@disable-primary-vs-flip-pipe-H +kms_universal_plane@cursor-fb-leak-pipe-H +kms_universal_plane@universal-plane-pageflip-windowed-pipe-H +kms_vblank@invalid +kms_vblank@crtc-id +kms_vblank@pipe-A-accuracy-idle +kms_vblank@pipe-A-query-idle +kms_vblank@pipe-A-query-idle-hang +kms_vblank@pipe-A-query-forked +kms_vblank@pipe-A-query-forked-hang +kms_vblank@pipe-A-query-busy +kms_vblank@pipe-A-query-busy-hang +kms_vblank@pipe-A-query-forked-busy +kms_vblank@pipe-A-query-forked-busy-hang +kms_vblank@pipe-A-wait-idle +kms_vblank@pipe-A-wait-idle-hang +kms_vblank@pipe-A-wait-forked +kms_vblank@pipe-A-wait-forked-hang +kms_vblank@pipe-A-wait-busy +kms_vblank@pipe-A-wait-busy-hang +kms_vblank@pipe-A-wait-forked-busy +kms_vblank@pipe-A-wait-forked-busy-hang +kms_vblank@pipe-A-ts-continuation-idle +kms_vblank@pipe-A-ts-continuation-idle-hang +kms_vblank@pipe-A-ts-continuation-dpms-rpm +kms_vblank@pipe-A-ts-continuation-dpms-suspend +kms_vblank@pipe-A-ts-continuation-suspend +kms_vblank@pipe-A-ts-continuation-modeset +kms_vblank@pipe-A-ts-continuation-modeset-hang +kms_vblank@pipe-A-ts-continuation-modeset-rpm +kms_vblank@pipe-B-accuracy-idle +kms_vblank@pipe-B-query-idle +kms_vblank@pipe-B-query-idle-hang +kms_vblank@pipe-B-query-forked +kms_vblank@pipe-B-query-forked-hang +kms_vblank@pipe-B-query-busy +kms_vblank@pipe-B-query-busy-hang +kms_vblank@pipe-B-query-forked-busy +kms_vblank@pipe-B-query-forked-busy-hang +kms_vblank@pipe-B-wait-idle +kms_vblank@pipe-B-wait-idle-hang +kms_vblank@pipe-B-wait-forked +kms_vblank@pipe-B-wait-forked-hang +kms_vblank@pipe-B-wait-busy +kms_vblank@pipe-B-wait-busy-hang +kms_vblank@pipe-B-wait-forked-busy +kms_vblank@pipe-B-wait-forked-busy-hang +kms_vblank@pipe-B-ts-continuation-idle +kms_vblank@pipe-B-ts-continuation-idle-hang +kms_vblank@pipe-B-ts-continuation-dpms-rpm +kms_vblank@pipe-B-ts-continuation-dpms-suspend +kms_vblank@pipe-B-ts-continuation-suspend +kms_vblank@pipe-B-ts-continuation-modeset +kms_vblank@pipe-B-ts-continuation-modeset-hang +kms_vblank@pipe-B-ts-continuation-modeset-rpm +kms_vblank@pipe-C-accuracy-idle +kms_vblank@pipe-C-query-idle +kms_vblank@pipe-C-query-idle-hang +kms_vblank@pipe-C-query-forked +kms_vblank@pipe-C-query-forked-hang +kms_vblank@pipe-C-query-busy +kms_vblank@pipe-C-query-busy-hang +kms_vblank@pipe-C-query-forked-busy +kms_vblank@pipe-C-query-forked-busy-hang +kms_vblank@pipe-C-wait-idle +kms_vblank@pipe-C-wait-idle-hang +kms_vblank@pipe-C-wait-forked +kms_vblank@pipe-C-wait-forked-hang +kms_vblank@pipe-C-wait-busy +kms_vblank@pipe-C-wait-busy-hang +kms_vblank@pipe-C-wait-forked-busy +kms_vblank@pipe-C-wait-forked-busy-hang +kms_vblank@pipe-C-ts-continuation-idle +kms_vblank@pipe-C-ts-continuation-idle-hang +kms_vblank@pipe-C-ts-continuation-dpms-rpm +kms_vblank@pipe-C-ts-continuation-dpms-suspend +kms_vblank@pipe-C-ts-continuation-suspend +kms_vblank@pipe-C-ts-continuation-modeset +kms_vblank@pipe-C-ts-continuation-modeset-hang +kms_vblank@pipe-C-ts-continuation-modeset-rpm +kms_vblank@pipe-D-accuracy-idle +kms_vblank@pipe-D-query-idle +kms_vblank@pipe-D-query-idle-hang +kms_vblank@pipe-D-query-forked +kms_vblank@pipe-D-query-forked-hang +kms_vblank@pipe-D-query-busy +kms_vblank@pipe-D-query-busy-hang +kms_vblank@pipe-D-query-forked-busy +kms_vblank@pipe-D-query-forked-busy-hang +kms_vblank@pipe-D-wait-idle +kms_vblank@pipe-D-wait-idle-hang +kms_vblank@pipe-D-wait-forked +kms_vblank@pipe-D-wait-forked-hang +kms_vblank@pipe-D-wait-busy +kms_vblank@pipe-D-wait-busy-hang +kms_vblank@pipe-D-wait-forked-busy +kms_vblank@pipe-D-wait-forked-busy-hang +kms_vblank@pipe-D-ts-continuation-idle +kms_vblank@pipe-D-ts-continuation-idle-hang +kms_vblank@pipe-D-ts-continuation-dpms-rpm +kms_vblank@pipe-D-ts-continuation-dpms-suspend +kms_vblank@pipe-D-ts-continuation-suspend +kms_vblank@pipe-D-ts-continuation-modeset +kms_vblank@pipe-D-ts-continuation-modeset-hang +kms_vblank@pipe-D-ts-continuation-modeset-rpm +kms_vblank@pipe-E-accuracy-idle +kms_vblank@pipe-E-query-idle +kms_vblank@pipe-E-query-idle-hang +kms_vblank@pipe-E-query-forked +kms_vblank@pipe-E-query-forked-hang +kms_vblank@pipe-E-query-busy +kms_vblank@pipe-E-query-busy-hang +kms_vblank@pipe-E-query-forked-busy +kms_vblank@pipe-E-query-forked-busy-hang +kms_vblank@pipe-E-wait-idle +kms_vblank@pipe-E-wait-idle-hang +kms_vblank@pipe-E-wait-forked +kms_vblank@pipe-E-wait-forked-hang +kms_vblank@pipe-E-wait-busy +kms_vblank@pipe-E-wait-busy-hang +kms_vblank@pipe-E-wait-forked-busy +kms_vblank@pipe-E-wait-forked-busy-hang +kms_vblank@pipe-E-ts-continuation-idle +kms_vblank@pipe-E-ts-continuation-idle-hang +kms_vblank@pipe-E-ts-continuation-dpms-rpm +kms_vblank@pipe-E-ts-continuation-dpms-suspend +kms_vblank@pipe-E-ts-continuation-suspend +kms_vblank@pipe-E-ts-continuation-modeset +kms_vblank@pipe-E-ts-continuation-modeset-hang +kms_vblank@pipe-E-ts-continuation-modeset-rpm +kms_vblank@pipe-F-accuracy-idle +kms_vblank@pipe-F-query-idle +kms_vblank@pipe-F-query-idle-hang +kms_vblank@pipe-F-query-forked +kms_vblank@pipe-F-query-forked-hang +kms_vblank@pipe-F-query-busy +kms_vblank@pipe-F-query-busy-hang +kms_vblank@pipe-F-query-forked-busy +kms_vblank@pipe-F-query-forked-busy-hang +kms_vblank@pipe-F-wait-idle +kms_vblank@pipe-F-wait-idle-hang +kms_vblank@pipe-F-wait-forked +kms_vblank@pipe-F-wait-forked-hang +kms_vblank@pipe-F-wait-busy +kms_vblank@pipe-F-wait-busy-hang +kms_vblank@pipe-F-wait-forked-busy +kms_vblank@pipe-F-wait-forked-busy-hang +kms_vblank@pipe-F-ts-continuation-idle +kms_vblank@pipe-F-ts-continuation-idle-hang +kms_vblank@pipe-F-ts-continuation-dpms-rpm +kms_vblank@pipe-F-ts-continuation-dpms-suspend +kms_vblank@pipe-F-ts-continuation-suspend +kms_vblank@pipe-F-ts-continuation-modeset +kms_vblank@pipe-F-ts-continuation-modeset-hang +kms_vblank@pipe-F-ts-continuation-modeset-rpm +kms_vblank@pipe-G-accuracy-idle +kms_vblank@pipe-G-query-idle +kms_vblank@pipe-G-query-idle-hang +kms_vblank@pipe-G-query-forked +kms_vblank@pipe-G-query-forked-hang +kms_vblank@pipe-G-query-busy +kms_vblank@pipe-G-query-busy-hang +kms_vblank@pipe-G-query-forked-busy +kms_vblank@pipe-G-query-forked-busy-hang +kms_vblank@pipe-G-wait-idle +kms_vblank@pipe-G-wait-idle-hang +kms_vblank@pipe-G-wait-forked +kms_vblank@pipe-G-wait-forked-hang +kms_vblank@pipe-G-wait-busy +kms_vblank@pipe-G-wait-busy-hang +kms_vblank@pipe-G-wait-forked-busy +kms_vblank@pipe-G-wait-forked-busy-hang +kms_vblank@pipe-G-ts-continuation-idle +kms_vblank@pipe-G-ts-continuation-idle-hang +kms_vblank@pipe-G-ts-continuation-dpms-rpm +kms_vblank@pipe-G-ts-continuation-dpms-suspend +kms_vblank@pipe-G-ts-continuation-suspend +kms_vblank@pipe-G-ts-continuation-modeset +kms_vblank@pipe-G-ts-continuation-modeset-hang +kms_vblank@pipe-G-ts-continuation-modeset-rpm +kms_vblank@pipe-H-accuracy-idle +kms_vblank@pipe-H-query-idle +kms_vblank@pipe-H-query-idle-hang +kms_vblank@pipe-H-query-forked +kms_vblank@pipe-H-query-forked-hang +kms_vblank@pipe-H-query-busy +kms_vblank@pipe-H-query-busy-hang +kms_vblank@pipe-H-query-forked-busy +kms_vblank@pipe-H-query-forked-busy-hang +kms_vblank@pipe-H-wait-idle +kms_vblank@pipe-H-wait-idle-hang +kms_vblank@pipe-H-wait-forked +kms_vblank@pipe-H-wait-forked-hang +kms_vblank@pipe-H-wait-busy +kms_vblank@pipe-H-wait-busy-hang +kms_vblank@pipe-H-wait-forked-busy +kms_vblank@pipe-H-wait-forked-busy-hang +kms_vblank@pipe-H-ts-continuation-idle +kms_vblank@pipe-H-ts-continuation-idle-hang +kms_vblank@pipe-H-ts-continuation-dpms-rpm +kms_vblank@pipe-H-ts-continuation-dpms-suspend +kms_vblank@pipe-H-ts-continuation-suspend +kms_vblank@pipe-H-ts-continuation-modeset +kms_vblank@pipe-H-ts-continuation-modeset-hang +kms_vblank@pipe-H-ts-continuation-modeset-rpm +kms_vrr@flip-basic +kms_vrr@flip-dpms +kms_vrr@flip-suspend +kms_vrr@flipline +kms_vrr@negative-basic +kms_writeback@writeback-pixel-formats +kms_writeback@writeback-invalid-parameters +kms_writeback@writeback-fb-id +kms_writeback@writeback-check-output +prime_mmap_kms@buffer-sharing diff --git a/drivers/gpu/drm/ci/x86_64.config b/drivers/gpu/drm/ci/x86_64.config new file mode 100644 index 000000000000..1cbd49a5b23a --- /dev/null +++ b/drivers/gpu/drm/ci/x86_64.config @@ -0,0 +1,111 @@ +CONFIG_LOCALVERSION_AUTO=y +CONFIG_DEBUG_KERNEL=y + +CONFIG_CRYPTO_ZSTD=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM=y +CONFIG_ZSMALLOC_STAT=y + +CONFIG_PWM=y +CONFIG_PM_DEVFREQ=y +CONFIG_OF=y +CONFIG_CROS_EC=y + +# abootimg with a 'dummy' rootfs fails with root=/dev/nfs +CONFIG_BLK_DEV_INITRD=n + +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_PASSIVE=y + +CONFIG_DRM=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_PWM_CROS_EC=y +CONFIG_BACKLIGHT_PWM=y + +# Strip out some stuff we don't need for graphics testing, to reduce +# the build. +CONFIG_CAN=n +CONFIG_WIRELESS=n +CONFIG_RFKILL=n +CONFIG_WLAN=n + +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR=y + +CONFIG_REGULATOR_VCTRL=y + +CONFIG_KASAN=n +CONFIG_KASAN_INLINE=n +CONFIG_STACKTRACE=n + +CONFIG_TMPFS=y + +CONFIG_PROVE_LOCKING=n +CONFIG_DEBUG_LOCKDEP=n +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y + +CONFIG_DETECT_HUNG_TASK=y + +CONFIG_USB_USBNET=y +CONFIG_NETDEVICES=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_RTL8152=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_GADGET=y +CONFIG_USB_ETH=y + +CONFIG_FW_LOADER_COMPRESS=y + +# options for AMD devices +CONFIG_X86_AMD_PLATFORM_DEVICE=y +CONFIG_ACPI_VIDEO=y +CONFIG_X86_AMD_FREQ_SENSITIVITY=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_AMD=y +CONFIG_DRM_AMDGPU=m +CONFIG_DRM_AMDGPU_SI=y +CONFIG_DRM_AMDGPU_USERPTR=y +CONFIG_DRM_AMD_ACP=n +CONFIG_ACPI_WMI=y +CONFIG_MXM_WMI=y +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_SERIAL=y +CONFIG_SERIAL_8250_DW=y +CONFIG_CHROME_PLATFORMS=y +CONFIG_KVM_AMD=m + +#options for Intel devices +CONFIG_MFD_INTEL_LPSS_PCI=y +CONFIG_KVM_INTEL=m + +#options for KVM guests +CONFIG_FUSE_FS=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_KVM=y +CONFIG_KVM_GUEST=y +CONFIG_VIRT_DRIVERS=y +CONFIG_VIRTIO_FS=y +CONFIG_DRM_VIRTIO_GPU=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_VIRTIO_NET=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_PARAVIRT=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTUALIZATION=y +CONFIG_VIRTIO=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_TUN=y +CONFIG_VSOCKETS=y +CONFIG_VIRTIO_VSOCKETS=y +CONFIG_VHOST_VSOCK=m diff --git a/drivers/gpu/drm/ci/xfails/amdgpu-stoney-fails.txt b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-fails.txt new file mode 100644 index 000000000000..bd9392536e7c --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-fails.txt @@ -0,0 +1,19 @@ +kms_addfb_basic@bad-pitch-65536,Fail +kms_addfb_basic@bo-too-small,Fail +kms_async_flips@invalid-async-flip,Fail +kms_atomic@plane-immutable-zpos,Fail +kms_atomic_transition@plane-toggle-modeset-transition,Fail +kms_bw@linear-tiling-1-displays-2560x1440p,Fail +kms_bw@linear-tiling-1-displays-3840x2160p,Fail +kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_bw@linear-tiling-3-displays-1920x1080p,Fail +kms_color@degamma,Fail +kms_cursor_crc@cursor-size-change,Fail +kms_cursor_crc@pipe-A-cursor-size-change,Fail +kms_cursor_crc@pipe-B-cursor-size-change,Fail +kms_cursor_legacy@forked-move,Fail +kms_hdr@bpc-switch,Fail +kms_hdr@bpc-switch-dpms,Fail +kms_plane_multiple@atomic-pipe-A-tiling-none,Fail +kms_rmfb@close-fd,Fail +kms_rotation_crc@primary-rotation-180,Fail diff --git a/drivers/gpu/drm/ci/xfails/amdgpu-stoney-flakes.txt b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-flakes.txt new file mode 100644 index 000000000000..f8defa0f9e67 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-flakes.txt @@ -0,0 +1,21 @@ +kms_addfb_basic@too-high +kms_async_flips@alternate-sync-async-flip +kms_async_flips@async-flip-with-page-flip-events +kms_async_flips@crc +kms_async_flips@test-cursor +kms_async_flips@test-time-stamp +kms_atomic_transition@plane-all-modeset-transition-internal-panels +kms_atomic_transition@plane-all-transition +kms_atomic_transition@plane-use-after-nonblocking-unbind +kms_bw@linear-tiling-1-displays-1920x1080p +kms_bw@linear-tiling-2-displays-1920x1080p +kms_bw@linear-tiling-2-displays-2560x1440p +kms_bw@linear-tiling-3-displays-2560x1440p +kms_bw@linear-tiling-3-displays-3840x2160p +kms_cursor_crc@pipe-A-cursor-alpha-opaque +kms_cursor_crc@pipe-B-cursor-alpha-opaque +kms_plane@pixel-format +kms_plane_multiple@atomic-pipe-B-tiling-none +kms_plane_scaling@downscale-with-rotation-factor-0-5 +kms_universal_plane@disable-primary-vs-flip-pipe-A +kms_universal_plane@disable-primary-vs-flip-pipe-B diff --git a/drivers/gpu/drm/ci/xfails/amdgpu-stoney-skips.txt b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-skips.txt new file mode 100644 index 000000000000..e2c538a0f954 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/amdgpu-stoney-skips.txt @@ -0,0 +1,2 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.*
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/i915-amly-fails.txt b/drivers/gpu/drm/ci/xfails/i915-amly-fails.txt new file mode 100644 index 000000000000..5f513c638beb --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-amly-fails.txt @@ -0,0 +1,17 @@ +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-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-32bpp-ytilegen12rcccs-upscaling,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 diff --git a/drivers/gpu/drm/ci/xfails/i915-amly-flakes.txt b/drivers/gpu/drm/ci/xfails/i915-amly-flakes.txt new file mode 100644 index 000000000000..d5000515a315 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-amly-flakes.txt @@ -0,0 +1,32 @@ +kms_bw@linear-tiling-2-displays-1920x1080p +kms_bw@linear-tiling-2-displays-2560x1440p +kms_bw@linear-tiling-2-displays-3840x2160p +kms_bw@linear-tiling-3-displays-1920x1080p +kms_bw@linear-tiling-3-displays-2560x1440p +kms_bw@linear-tiling-3-displays-3840x2160p +kms_bw@linear-tiling-4-displays-1920x1080p +kms_bw@linear-tiling-4-displays-2560x1440p +kms_bw@linear-tiling-4-displays-3840x2160p +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-upscaling +kms_plane_alpha_blend@pipe-A-alpha-basic +kms_plane_alpha_blend@pipe-A-alpha-opaque-fb +kms_plane_alpha_blend@pipe-A-alpha-transparent-fb +kms_plane_alpha_blend@pipe-A-constant-alpha-max +kms_plane_alpha_blend@pipe-B-alpha-basic +kms_plane_alpha_blend@pipe-B-alpha-opaque-fb +kms_plane_alpha_blend@pipe-B-alpha-transparent-fb +kms_plane_alpha_blend@pipe-B-constant-alpha-max +kms_plane_alpha_blend@pipe-C-alpha-basic +kms_plane_alpha_blend@pipe-C-alpha-opaque-fb +kms_plane_alpha_blend@pipe-C-alpha-transparent-fb +kms_plane_alpha_blend@pipe-C-constant-alpha-max +kms_sysfs_edid_timing diff --git a/drivers/gpu/drm/ci/xfails/i915-amly-skips.txt b/drivers/gpu/drm/ci/xfails/i915-amly-skips.txt new file mode 100644 index 000000000000..fe55540a3f9a --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-amly-skips.txt @@ -0,0 +1,4 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.* +# This is generating kernel oops with divide error +kms_plane_scaling@invalid-parameters
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/i915-apl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-apl-fails.txt new file mode 100644 index 000000000000..46397ce38d5a --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-apl-fails.txt @@ -0,0 +1,58 @@ +kms_3d,Timeout +kms_bw@linear-tiling-2-displays-1920x1080p,Fail +kms_bw@linear-tiling-2-displays-2560x1440p,Fail +kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_bw@linear-tiling-3-displays-1920x1080p,Fail +kms_bw@linear-tiling-3-displays-2560x1440p,Fail +kms_bw@linear-tiling-3-displays-3840x2160p,Fail +kms_bw@linear-tiling-4-displays-1920x1080p,Fail +kms_bw@linear-tiling-4-displays-2560x1440p,Fail +kms_bw@linear-tiling-4-displays-3840x2160p,Fail +kms_color@ctm-0-25,Fail +kms_color@ctm-0-50,Fail +kms_color@ctm-0-75,Fail +kms_color@ctm-max,Fail +kms_color@ctm-negative,Fail +kms_color@ctm-red-to-blue,Fail +kms_color@ctm-signed,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_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-upscaling,Fail +kms_hdmi_inject@inject-4k,Timeout +kms_plane@plane-position-hole,Timeout +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_alpha_blend@pipe-A-alpha-opaque-fb,Fail +kms_plane_alpha_blend@pipe-A-alpha-transparent-fb,Fail +kms_plane_alpha_blend@pipe-A-constant-alpha-max,Fail +kms_plane_alpha_blend@pipe-B-alpha-opaque-fb,Fail +kms_plane_alpha_blend@pipe-B-alpha-transparent-fb,Fail +kms_plane_alpha_blend@pipe-B-constant-alpha-max,Fail +kms_plane_alpha_blend@pipe-C-alpha-opaque-fb,Fail +kms_plane_alpha_blend@pipe-C-alpha-transparent-fb,Fail +kms_plane_alpha_blend@pipe-C-constant-alpha-max,Fail +kms_plane_multiple@tiling-y,Timeout +kms_pwrite_crc,Timeout +kms_sysfs_edid_timing,Fail diff --git a/drivers/gpu/drm/ci/xfails/i915-apl-flakes.txt b/drivers/gpu/drm/ci/xfails/i915-apl-flakes.txt new file mode 100644 index 000000000000..331c5841bb41 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-apl-flakes.txt @@ -0,0 +1 @@ +kms_frontbuffer_tracking@fbc-tiling-linear diff --git a/drivers/gpu/drm/ci/xfails/i915-apl-skips.txt b/drivers/gpu/drm/ci/xfails/i915-apl-skips.txt new file mode 100644 index 000000000000..3430b215c06e --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-apl-skips.txt @@ -0,0 +1,6 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.* +# This is generating kernel oops with divide error +kms_plane_scaling@invalid-parameters +# This is cascading issues +kms_3d
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/i915-cml-fails.txt b/drivers/gpu/drm/ci/xfails/i915-cml-fails.txt new file mode 100644 index 000000000000..6139b410e767 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-cml-fails.txt @@ -0,0 +1,18 @@ +kms_color@ctm-0-25,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-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-32bpp-ytilegen12rcccs-upscaling,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 diff --git a/drivers/gpu/drm/ci/xfails/i915-cml-flakes.txt b/drivers/gpu/drm/ci/xfails/i915-cml-flakes.txt new file mode 100644 index 000000000000..0514a7b3fdb0 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-cml-flakes.txt @@ -0,0 +1,38 @@ +kms_bw@linear-tiling-2-displays-1920x1080p +kms_bw@linear-tiling-2-displays-2560x1440p +kms_bw@linear-tiling-2-displays-3840x2160p +kms_bw@linear-tiling-3-displays-1920x1080p +kms_bw@linear-tiling-3-displays-2560x1440p +kms_bw@linear-tiling-3-displays-3840x2160p +kms_bw@linear-tiling-4-displays-1920x1080p +kms_bw@linear-tiling-4-displays-2560x1440p +kms_bw@linear-tiling-4-displays-3840x2160p +kms_draw_crc@draw-method-xrgb8888-render-xtiled +kms_flip@flip-vs-suspend +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-upscaling +kms_hdr@bpc-switch-suspend +kms_plane_alpha_blend@constant-alpha-min +kms_plane_alpha_blend@pipe-A-alpha-basic +kms_plane_alpha_blend@pipe-A-alpha-opaque-fb +kms_plane_alpha_blend@pipe-A-alpha-transparent-fb +kms_plane_alpha_blend@pipe-A-constant-alpha-max +kms_plane_alpha_blend@pipe-B-alpha-basic +kms_plane_alpha_blend@pipe-B-alpha-opaque-fb +kms_plane_alpha_blend@pipe-B-alpha-transparent-fb +kms_plane_alpha_blend@pipe-B-constant-alpha-max +kms_plane_alpha_blend@pipe-C-alpha-basic +kms_plane_alpha_blend@pipe-C-alpha-opaque-fb +kms_plane_alpha_blend@pipe-C-alpha-transparent-fb +kms_plane_alpha_blend@pipe-C-constant-alpha-max +kms_psr2_su@page_flip-NV12 +kms_psr2_su@page_flip-P010 +kms_setmode@basic diff --git a/drivers/gpu/drm/ci/xfails/i915-cml-skips.txt b/drivers/gpu/drm/ci/xfails/i915-cml-skips.txt new file mode 100644 index 000000000000..6d3d7ddc377f --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-cml-skips.txt @@ -0,0 +1,2 @@ +# This is generating kernel oops with divide error +kms_plane_scaling@invalid-parameters diff --git a/drivers/gpu/drm/ci/xfails/i915-glk-fails.txt b/drivers/gpu/drm/ci/xfails/i915-glk-fails.txt new file mode 100644 index 000000000000..5bd432e78129 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-glk-fails.txt @@ -0,0 +1,19 @@ +kms_fbcon_fbt@fbc,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-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-32bpp-ytilegen12rcccs-upscaling,Fail +kms_frontbuffer_tracking@fbcdrrs-tiling-linear,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 diff --git a/drivers/gpu/drm/ci/xfails/i915-glk-flakes.txt b/drivers/gpu/drm/ci/xfails/i915-glk-flakes.txt new file mode 100644 index 000000000000..fc41d13a2d56 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-glk-flakes.txt @@ -0,0 +1,41 @@ +kms_bw@linear-tiling-1-displays-3840x2160p +kms_bw@linear-tiling-2-displays-1920x1080p +kms_bw@linear-tiling-2-displays-2560x1440p +kms_bw@linear-tiling-2-displays-3840x2160p +kms_bw@linear-tiling-3-displays-1920x1080p +kms_bw@linear-tiling-3-displays-2560x1440p +kms_bw@linear-tiling-3-displays-3840x2160p +kms_bw@linear-tiling-4-displays-1920x1080p +kms_bw@linear-tiling-4-displays-2560x1440p +kms_bw@linear-tiling-4-displays-3840x2160p +kms_flip@blocking-wf_vblank +kms_flip@wf_vblank-ts-check +kms_flip@wf_vblank-ts-check-interruptible +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-upscaling +kms_frontbuffer_tracking@fbc-tiling-linear +kms_plane_alpha_blend@pipe-A-alpha-basic +kms_plane_alpha_blend@pipe-A-alpha-opaque-fb +kms_plane_alpha_blend@pipe-A-alpha-transparent-fb +kms_plane_alpha_blend@pipe-A-constant-alpha-max +kms_plane_alpha_blend@pipe-B-alpha-basic +kms_plane_alpha_blend@pipe-B-alpha-opaque-fb +kms_plane_alpha_blend@pipe-B-alpha-transparent-fb +kms_plane_alpha_blend@pipe-B-constant-alpha-max +kms_plane_alpha_blend@pipe-C-alpha-basic +kms_plane_alpha_blend@pipe-C-alpha-opaque-fb +kms_plane_alpha_blend@pipe-C-alpha-transparent-fb +kms_plane_alpha_blend@pipe-C-constant-alpha-max +kms_prop_blob@invalid-set-prop-any +kms_rotation_crc@multiplane-rotation +kms_rotation_crc@multiplane-rotation-cropping-bottom +kms_rotation_crc@multiplane-rotation-cropping-top +kms_setmode@basic diff --git a/drivers/gpu/drm/ci/xfails/i915-glk-skips.txt b/drivers/gpu/drm/ci/xfails/i915-glk-skips.txt new file mode 100644 index 000000000000..4c7d00ce14bc --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-glk-skips.txt @@ -0,0 +1,5 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.* + +# This is generating kernel oops with divide error +kms_plane_scaling@invalid-parameters
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/i915-kbl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-kbl-fails.txt new file mode 100644 index 000000000000..56ec021a7679 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-kbl-fails.txt @@ -0,0 +1,25 @@ +kms_bw@linear-tiling-2-displays-2560x1440p,Fail +kms_bw@linear-tiling-4-displays-2560x1440p,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-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-32bpp-ytile-downscaling,Fail +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling,Fail +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-upscaling,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_alpha_blend@pipe-A-constant-alpha-max,Fail +kms_plane_alpha_blend@pipe-B-alpha-opaque-fb,Fail +kms_plane_alpha_blend@pipe-C-constant-alpha-max,Fail diff --git a/drivers/gpu/drm/ci/xfails/i915-kbl-flakes.txt b/drivers/gpu/drm/ci/xfails/i915-kbl-flakes.txt new file mode 100644 index 000000000000..f3ba1c4c5d46 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-kbl-flakes.txt @@ -0,0 +1,26 @@ +kms_async_flips@crc +kms_bw@linear-tiling-2-displays-1920x1080p +kms_bw@linear-tiling-2-displays-3840x2160p +kms_bw@linear-tiling-3-displays-1920x1080p +kms_bw@linear-tiling-3-displays-2560x1440p +kms_bw@linear-tiling-3-displays-3840x2160p +kms_bw@linear-tiling-4-displays-1920x1080p +kms_bw@linear-tiling-4-displays-3840x2160p +kms_color@ctm-0-25 +kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling +kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-downscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling +kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling +kms_plane_alpha_blend@pipe-A-alpha-basic +kms_plane_alpha_blend@pipe-A-alpha-opaque-fb +kms_plane_alpha_blend@pipe-A-alpha-transparent-fb +kms_plane_alpha_blend@pipe-B-alpha-basic +kms_plane_alpha_blend@pipe-B-alpha-transparent-fb +kms_plane_alpha_blend@pipe-B-constant-alpha-max +kms_plane_alpha_blend@pipe-C-alpha-basic +kms_plane_alpha_blend@pipe-C-alpha-opaque-fb +kms_plane_alpha_blend@pipe-C-alpha-transparent-fb +kms_sysfs_edid_timing diff --git a/drivers/gpu/drm/ci/xfails/i915-kbl-skips.txt b/drivers/gpu/drm/ci/xfails/i915-kbl-skips.txt new file mode 100644 index 000000000000..4c7d00ce14bc --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-kbl-skips.txt @@ -0,0 +1,5 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.* + +# This is generating kernel oops with divide error +kms_plane_scaling@invalid-parameters
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/i915-tgl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-tgl-fails.txt new file mode 100644 index 000000000000..a6da5544e198 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-tgl-fails.txt @@ -0,0 +1,37 @@ +kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_bw@linear-tiling-3-displays-1920x1080p,Fail +kms_bw@linear-tiling-3-displays-2560x1440p,Fail +kms_bw@linear-tiling-3-displays-3840x2160p,Fail +kms_bw@linear-tiling-4-displays-1920x1080p,Fail +kms_bw@linear-tiling-4-displays-2560x1440p,Fail +kms_bw@linear-tiling-4-displays-3840x2160p,Fail +kms_bw@linear-tiling-5-displays-1920x1080p,Fail +kms_bw@linear-tiling-5-displays-2560x1440p,Fail +kms_bw@linear-tiling-5-displays-3840x2160p,Fail +kms_color@ctm-0-25,Fail +kms_flip@flip-vs-panning-vs-hang,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-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_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-upscaling,Fail +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 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..1cd910ee06df --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-tgl-flakes.txt @@ -0,0 +1,5 @@ +kms_draw_crc@.* +kms_flip@blocking-absolute-wf_vblank +kms_flip@bo-too-big-interruptible +kms_flip@busy-flip +kms_flip@flip-vs-rmfb-interruptible diff --git a/drivers/gpu/drm/ci/xfails/i915-tgl-skips.txt b/drivers/gpu/drm/ci/xfails/i915-tgl-skips.txt new file mode 100644 index 000000000000..1d0621750b14 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-tgl-skips.txt @@ -0,0 +1,11 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.* + +# GPU hangs, then the whole machine +gem_eio.* + +# Whole machine hangs +kms_flip@absolute-wf_vblank@a-edp1 + +# This is generating kernel oops with divide error +kms_plane_scaling@invalid-parameters
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/i915-whl-fails.txt b/drivers/gpu/drm/ci/xfails/i915-whl-fails.txt new file mode 100644 index 000000000000..967327ddc1ac --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-whl-fails.txt @@ -0,0 +1,48 @@ +kms_bw@linear-tiling-2-displays-1920x1080p,Fail +kms_bw@linear-tiling-2-displays-2560x1440p,Fail +kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_bw@linear-tiling-3-displays-1920x1080p,Fail +kms_bw@linear-tiling-3-displays-2560x1440p,Fail +kms_bw@linear-tiling-3-displays-3840x2160p,Fail +kms_bw@linear-tiling-4-displays-1920x1080p,Fail +kms_bw@linear-tiling-4-displays-2560x1440p,Fail +kms_bw@linear-tiling-4-displays-3840x2160p,Fail +kms_fbcon_fbt@fbc,Fail +kms_fbcon_fbt@fbc-suspend,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_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-upscaling,Fail +kms_frontbuffer_tracking@fbc-tiling-linear,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_alpha_blend@pipe-A-alpha-opaque-fb,Fail +kms_plane_alpha_blend@pipe-A-alpha-transparent-fb,Fail +kms_plane_alpha_blend@pipe-A-constant-alpha-max,Fail +kms_plane_alpha_blend@pipe-B-alpha-opaque-fb,Fail +kms_plane_alpha_blend@pipe-B-alpha-transparent-fb,Fail +kms_plane_alpha_blend@pipe-B-constant-alpha-max,Fail +kms_plane_alpha_blend@pipe-C-alpha-opaque-fb,Fail +kms_plane_alpha_blend@pipe-C-alpha-transparent-fb,Fail +kms_plane_alpha_blend@pipe-C-constant-alpha-max,Fail diff --git a/drivers/gpu/drm/ci/xfails/i915-whl-flakes.txt b/drivers/gpu/drm/ci/xfails/i915-whl-flakes.txt new file mode 100644 index 000000000000..c33202e7e2a1 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-whl-flakes.txt @@ -0,0 +1 @@ +kms_flip@flip-vs-suspend diff --git a/drivers/gpu/drm/ci/xfails/i915-whl-skips.txt b/drivers/gpu/drm/ci/xfails/i915-whl-skips.txt new file mode 100644 index 000000000000..f3be0888a214 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/i915-whl-skips.txt @@ -0,0 +1,2 @@ +# This is generating kernel oops with divide error +kms_plane_scaling@invalid-parameters
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt new file mode 100644 index 000000000000..671916067dba --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt @@ -0,0 +1,29 @@ +kms_3d,Fail +kms_addfb_basic@addfb25-bad-modifier,Fail +kms_bw@linear-tiling-1-displays-1920x1080p,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-2560x1440p,Fail +kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_bw@linear-tiling-3-displays-1920x1080p,Fail +kms_bw@linear-tiling-3-displays-2560x1440p,Fail +kms_bw@linear-tiling-3-displays-3840x2160p,Fail +kms_color@pipe-A-invalid-gamma-lut-sizes,Fail +kms_color@pipe-B-invalid-gamma-lut-sizes,Fail +kms_force_connector_basic@force-connector-state,Fail +kms_force_connector_basic@force-edid,Fail +kms_force_connector_basic@force-load-detect,Fail +kms_force_connector_basic@prune-stale-modes,Fail +kms_invalid_mode@int-max-clock,Fail +kms_plane_scaling@planes-upscale-20x20,Fail +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-25,Fail +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-5,Fail +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-75,Fail +kms_plane_scaling@upscale-with-modifier-20x20,Fail +kms_plane_scaling@upscale-with-pixel-format-20x20,Fail +kms_plane_scaling@upscale-with-rotation-20x20,Fail +kms_properties@get_properties-sanity-atomic,Fail +kms_properties@plane-properties-atomic,Fail +kms_properties@plane-properties-legacy,Fail +kms_rmfb@close-fd,Fail diff --git a/drivers/gpu/drm/ci/xfails/mediatek-mt8173-flakes.txt b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-flakes.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-flakes.txt diff --git a/drivers/gpu/drm/ci/xfails/mediatek-mt8183-fails.txt b/drivers/gpu/drm/ci/xfails/mediatek-mt8183-fails.txt new file mode 100644 index 000000000000..6ff81d00e84e --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/mediatek-mt8183-fails.txt @@ -0,0 +1,10 @@ +kms_addfb_basic@addfb25-bad-modifier,Fail +kms_bw@linear-tiling-1-displays-2560x1440p,Fail +kms_bw@linear-tiling-2-displays-1920x1080p,Fail +kms_bw@linear-tiling-2-displays-2560x1440p,Fail +kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_bw@linear-tiling-3-displays-2560x1440p,Fail +kms_bw@linear-tiling-3-displays-3840x2160p,Fail +kms_color@pipe-A-invalid-gamma-lut-sizes,Fail +kms_plane_scaling@upscale-with-rotation-20x20,Fail +kms_rmfb@close-fd,Fail
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/mediatek-mt8183-flakes.txt b/drivers/gpu/drm/ci/xfails/mediatek-mt8183-flakes.txt new file mode 100644 index 000000000000..208890b79eb0 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/mediatek-mt8183-flakes.txt @@ -0,0 +1,14 @@ +core_setmaster_vs_auth +kms_bw@linear-tiling-1-displays-1920x1080p +kms_bw@linear-tiling-1-displays-3840x2160p +kms_bw@linear-tiling-3-displays-1920x1080p +kms_cursor_legacy@cursor-vs-flip-atomic +kms_plane_scaling@invalid-num-scalers +kms_plane_scaling@planes-upscale-20x20 +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-5 +kms_plane_scaling@upscale-with-modifier-20x20 +kms_plane_scaling@upscale-with-pixel-format-20x20 +kms_prop_blob@invalid-set-prop-any +kms_properties@get_properties-sanity-atomic +kms_properties@plane-properties-atomic +kms_properties@plane-properties-legacy
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/meson-g12b-fails.txt b/drivers/gpu/drm/ci/xfails/meson-g12b-fails.txt new file mode 100644 index 000000000000..860e702091e2 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/meson-g12b-fails.txt @@ -0,0 +1,12 @@ +kms_3d,Fail +kms_properties@connector-properties-atomic,Fail +kms_properties@get_properties-sanity-atomic,Fail +kms_properties@get_properties-sanity-non-atomic,Fail +kms_properties@connector-properties-legacy,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_hdmi_inject@inject-4k,Fail
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/meson-g12b-flakes.txt b/drivers/gpu/drm/ci/xfails/meson-g12b-flakes.txt new file mode 100644 index 000000000000..b63329d06767 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/meson-g12b-flakes.txt @@ -0,0 +1,4 @@ +kms_force_connector_basic@force-connector-state +kms_force_connector_basic@force-edid +kms_force_connector_basic@force-load-detect +kms_force_connector_basic@prune-stale-modes
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt new file mode 100644 index 000000000000..9981682feab2 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt @@ -0,0 +1,15 @@ +kms_3d,Fail +kms_addfb_basic@addfb25-bad-modifier,Fail +kms_cursor_legacy@all-pipes-forked-bo,Fail +kms_cursor_legacy@all-pipes-forked-move,Fail +kms_cursor_legacy@all-pipes-single-bo,Fail +kms_cursor_legacy@all-pipes-single-move,Fail +kms_cursor_legacy@all-pipes-torture-bo,Fail +kms_cursor_legacy@all-pipes-torture-move,Fail +kms_cursor_legacy@pipe-A-forked-bo,Fail +kms_cursor_legacy@pipe-A-forked-move,Fail +kms_cursor_legacy@pipe-A-single-bo,Fail +kms_cursor_legacy@pipe-A-single-move,Fail +kms_cursor_legacy@pipe-A-torture-bo,Fail +kms_cursor_legacy@pipe-A-torture-move,Fail +kms_hdmi_inject@inject-4k,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8016-flakes.txt b/drivers/gpu/drm/ci/xfails/msm-apq8016-flakes.txt new file mode 100644 index 000000000000..0e3b60d3fade --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-apq8016-flakes.txt @@ -0,0 +1,4 @@ +kms_force_connector_basic@force-connector-state +kms_force_connector_basic@force-edid +kms_force_connector_basic@force-load-detect +kms_force_connector_basic@prune-stale-modes diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt b/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt new file mode 100644 index 000000000000..88a1fc0a3b0d --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt @@ -0,0 +1,2 @@ +kms_3d,Fail +kms_addfb_basic@addfb25-bad-modifier,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8096-flakes.txt b/drivers/gpu/drm/ci/xfails/msm-apq8096-flakes.txt new file mode 100644 index 000000000000..0e3b60d3fade --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-apq8096-flakes.txt @@ -0,0 +1,4 @@ +kms_force_connector_basic@force-connector-state +kms_force_connector_basic@force-edid +kms_force_connector_basic@force-load-detect +kms_force_connector_basic@prune-stale-modes diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8096-skips.txt b/drivers/gpu/drm/ci/xfails/msm-apq8096-skips.txt new file mode 100644 index 000000000000..cd49c8ce2059 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-apq8096-skips.txt @@ -0,0 +1,2 @@ +# Whole machine hangs +kms_cursor_legacy@all-pipes-torture-move
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-fails.txt new file mode 100644 index 000000000000..14adeba3b62d --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-sc7180-fails.txt @@ -0,0 +1,25 @@ +kms_cursor_legacy@cursor-vs-flip-toggle,Fail +kms_cursor_legacy@cursor-vs-flip-varying-size,Fail +kms_cursor_legacy@cursorA-vs-flipA-atomic-transitions,Crash +kms_pipe_crc_basic@compare-crc-sanitycheck-nv12,Fail +kms_plane@pixel-format,Fail +kms_plane@pixel-format-source-clamping,Fail +kms_plane@plane-position-covered,Fail +kms_plane@plane-position-hole,Fail +kms_plane@plane-position-hole-dpms,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_alpha_blend@pipe-A-alpha-7efc,Fail +kms_plane_alpha_blend@pipe-A-coverage-7efc,Fail +kms_plane_alpha_blend@pipe-A-coverage-vs-premult-vs-constant,Fail +kms_plane_alpha_blend@pipe-B-alpha-7efc,Fail +kms_plane_alpha_blend@pipe-B-alpha-basic,Fail +kms_plane_alpha_blend@pipe-B-alpha-opaque-fb,Fail +kms_plane_alpha_blend@pipe-B-constant-alpha-max,Fail +kms_plane_alpha_blend@pipe-B-constant-alpha-mid,Fail +kms_plane_alpha_blend@pipe-B-coverage-7efc,Fail +kms_plane_alpha_blend@pipe-B-coverage-vs-premult-vs-constant,Fail +kms_rmfb@close-fd,Fail +kms_universal_plane@disable-primary-vs-flip-pipe-b,Fail +kms_universal_plane@universal-plane-pipe-B-sanity,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-flakes.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-flakes.txt new file mode 100644 index 000000000000..636563d3e59a --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-sc7180-flakes.txt @@ -0,0 +1,7 @@ + +# Test ends up reading CRC from frame before cursor update +# bug +# sometimes.. tbd if this is a kernel CRC bug or a test +kms_cursor_crc@.* +kms_plane_multiple@atomic-pipe-A-tiling-none +kms_atomic_transition@modeset-transition-nonblocking-fencing,Fail
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-skips.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-skips.txt new file mode 100644 index 000000000000..410e0eeb3161 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-sc7180-skips.txt @@ -0,0 +1,23 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.* + +# Test incorrectly assumes that CTM support implies gamma/degamma +# LUT support. None of the subtests handle the case of only having +# CTM support +kms_color.* + +# 4k@60 is not supported on this hw, but driver doesn't handle it +# too gracefully.. https://gitlab.freedesktop.org/drm/msm/-/issues/15 +kms_bw@linear-tiling-.*-displays-3840x2160p + +# Until igt fix lands: https://patchwork.freedesktop.org/patch/493175/ +kms_bw@linear-tiling-2.* +kms_bw@linear-tiling-3.* +kms_bw@linear-tiling-4.* +kms_bw@linear-tiling-5.* +kms_bw@linear-tiling-6.* + +# igt fix posted: https://patchwork.freedesktop.org/patch/499926/ +# failure mode is flakey due to randomization but fails frequently +# enough to be detected as a Crash or occasionally UnexpectedPass. +kms_plane_multiple@atomic-pipe-A-tiling-none diff --git a/drivers/gpu/drm/ci/xfails/msm-sdm845-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sdm845-fails.txt new file mode 100644 index 000000000000..09c0c623cd75 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-sdm845-fails.txt @@ -0,0 +1,68 @@ +kms_color@ctm-0-25,Fail +kms_color@ctm-0-50,Fail +kms_color@ctm-0-75,Fail +kms_color@ctm-blue-to-red,Fail +kms_color@ctm-green-to-red,Fail +kms_color@ctm-negative,Fail +kms_color@ctm-red-to-blue,Fail +kms_color@ctm-signed,Fail +kms_color@pipe-A-ctm-0-25,Fail +kms_color@pipe-A-ctm-0-5,Fail +kms_color@pipe-A-ctm-0-75,Fail +kms_color@pipe-A-ctm-blue-to-red,Fail +kms_color@pipe-A-ctm-green-to-red,Fail +kms_color@pipe-A-ctm-max,Fail +kms_color@pipe-A-ctm-negative,Fail +kms_color@pipe-A-ctm-red-to-blue,Fail +kms_color@pipe-A-legacy-gamma,Fail +kms_cursor_legacy@basic-flip-after-cursor-atomic,Fail +kms_cursor_legacy@basic-flip-after-cursor-legacy,Fail +kms_cursor_legacy@basic-flip-after-cursor-varying-size,Fail +kms_cursor_legacy@basic-flip-before-cursor-atomic,Fail +kms_cursor_legacy@basic-flip-before-cursor-legacy,Fail +kms_cursor_legacy@basic-flip-before-cursor-varying-size,Fail +kms_cursor_legacy@cursor-vs-flip-atomic,Fail +kms_cursor_legacy@cursor-vs-flip-atomic-transitions,Fail +kms_cursor_legacy@cursor-vs-flip-atomic-transitions-varying-size,Fail +kms_cursor_legacy@cursor-vs-flip-legacy,Fail +kms_cursor_legacy@cursor-vs-flip-toggle,Fail +kms_cursor_legacy@cursor-vs-flip-varying-size,Fail +kms_cursor_legacy@cursorA-vs-flipA-toggle,Fail +kms_cursor_legacy@flip-vs-cursor-atomic,Fail +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@short-flip-after-cursor-atomic-transitions,Fail +kms_cursor_legacy@short-flip-after-cursor-atomic-transitions-varying-size,Fail +kms_cursor_legacy@short-flip-after-cursor-toggle,Fail +kms_cursor_legacy@short-flip-before-cursor-atomic-transitions,Fail +kms_cursor_legacy@short-flip-before-cursor-atomic-transitions-varying-size,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_alpha_blend@pipe-A-alpha-7efc,Fail +kms_plane_alpha_blend@pipe-A-coverage-7efc,Fail +kms_plane_alpha_blend@pipe-A-coverage-vs-premult-vs-constant,Fail +kms_plane_cursor@overlay,Fail +kms_plane_cursor@pipe-A-overlay-size-128,Fail +kms_plane_cursor@pipe-A-overlay-size-256,Fail +kms_plane_cursor@pipe-A-overlay-size-64,Fail +kms_plane_cursor@pipe-A-viewport-size-128,Fail +kms_plane_cursor@pipe-A-viewport-size-256,Fail +kms_plane_cursor@pipe-A-viewport-size-64,Fail +kms_plane_cursor@viewport,Fail +kms_plane_scaling@downscale-with-pixel-format-factor-0-25,Timeout +kms_plane_scaling@downscale-with-pixel-format-factor-0-5,Timeout +kms_plane_scaling@downscale-with-pixel-format-factor-0-75,Timeout +kms_plane_scaling@plane-downscale-with-pixel-format-factor-0-25,Timeout +kms_plane_scaling@plane-downscale-with-pixel-format-factor-0-5,Timeout +kms_plane_scaling@plane-downscale-with-pixel-format-factor-0-75,Timeout +kms_plane_scaling@plane-scaler-with-clipping-clamping-pixel-formats,Timeout +kms_plane_scaling@plane-scaler-with-pixel-format-unity-scaling,Timeout +kms_plane_scaling@planes-downscale-factor-0-25,Fail +kms_plane_scaling@scaler-with-clipping-clamping,Timeout +kms_plane_scaling@scaler-with-pixel-format-unity-scaling,Timeout +kms_rmfb@close-fd,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sdm845-flakes.txt b/drivers/gpu/drm/ci/xfails/msm-sdm845-flakes.txt new file mode 100644 index 000000000000..5b3aaab7ac3f --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-sdm845-flakes.txt @@ -0,0 +1,11 @@ + + +# Test ends up reading CRC from frame before cursor update +# bug +# sometimes.. tbd if this is a kernel CRC bug or a test +kms_cursor_crc@.* +kms_cursor_legacy@flip-vs-cursor-toggle +kms_cursor_legacy@pipe-A-forked-bo +kms_cursor_legacy@pipe-A-forked-move +kms_cursor_legacy@short-flip-before-cursor-toggle +kms_flip@dpms-vs-vblank-race-interruptible diff --git a/drivers/gpu/drm/ci/xfails/msm-sdm845-skips.txt b/drivers/gpu/drm/ci/xfails/msm-sdm845-skips.txt new file mode 100644 index 000000000000..42675f1c6d76 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-sdm845-skips.txt @@ -0,0 +1,2 @@ +# Hangs machine +kms_bw.*
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3288-fails.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-fails.txt new file mode 100644 index 000000000000..2a1baa948e12 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-fails.txt @@ -0,0 +1,48 @@ +kms_3d,Crash +kms_bw@linear-tiling-2-displays-1920x1080p,Fail +kms_bw@linear-tiling-2-displays-2560x1440p,Fail +kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_bw@linear-tiling-3-displays-1920x1080p,Fail +kms_bw@linear-tiling-3-displays-2560x1440p,Fail +kms_bw@linear-tiling-3-displays-3840x2160p,Fail +kms_force_connector_basic@force-load-detect,Fail +kms_invalid_mode@int-max-clock,Crash +kms_plane@pixel-format,Crash +kms_plane@pixel-format-source-clamping,Crash +kms_plane@plane-position-hole,Crash +kms_plane@plane-position-hole-dpms,Crash +kms_plane_cursor@overlay,Crash +kms_plane_cursor@pipe-A-overlay-size-128,Fail +kms_plane_cursor@pipe-A-overlay-size-256,Fail +kms_plane_cursor@pipe-A-overlay-size-64,Fail +kms_plane_cursor@pipe-A-primary-size-128,Fail +kms_plane_cursor@pipe-A-primary-size-256,Fail +kms_plane_cursor@pipe-A-primary-size-64,Fail +kms_plane_cursor@pipe-A-viewport-size-128,Fail +kms_plane_cursor@pipe-A-viewport-size-256,Fail +kms_plane_cursor@pipe-A-viewport-size-64,Fail +kms_plane_cursor@pipe-B-overlay-size-128,Fail +kms_plane_cursor@pipe-B-overlay-size-256,Fail +kms_plane_cursor@pipe-B-overlay-size-64,Fail +kms_plane_cursor@pipe-B-primary-size-128,Fail +kms_plane_cursor@pipe-B-primary-size-256,Fail +kms_plane_cursor@pipe-B-primary-size-64,Fail +kms_plane_cursor@pipe-B-viewport-size-128,Fail +kms_plane_cursor@pipe-B-viewport-size-256,Fail +kms_plane_cursor@pipe-B-viewport-size-64,Fail +kms_plane_cursor@primary,Crash +kms_plane_cursor@viewport,Crash +kms_plane_lowres@tiling-none,Fail +kms_plane_scaling@downscale-with-modifier-factor-0-25,Fail +kms_plane_scaling@downscale-with-rotation-factor-0-25,Fail +kms_plane_scaling@upscale-with-modifier-20x20,Fail +kms_plane_scaling@upscale-with-modifier-factor-0-25,Fail +kms_plane_scaling@upscale-with-pixel-format-20x20,Fail +kms_plane_scaling@upscale-with-pixel-format-factor-0-25,Fail +kms_plane_scaling@upscale-with-rotation-20x20,Fail +kms_prime@basic-crc,Fail +kms_properties@connector-properties-atomic,Crash +kms_properties@connector-properties-legacy,Crash +kms_properties@get_properties-sanity-atomic,Crash +kms_properties@get_properties-sanity-non-atomic,Crash +kms_setmode@invalid-clone-single-crtc,Crash diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3288-flakes.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-flakes.txt new file mode 100644 index 000000000000..45c54c75c899 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-flakes.txt @@ -0,0 +1,9 @@ +kms_addfb_basic@addfb25-bad-modifier +kms_cursor_crc@.* +kms_flip@basic-flip-vs-wf_vblank +kms_invalid_mode@int-max-clock,Crash +kms_pipe_crc_basic@.* +kms_properties@connector-properties-atomic,Crash +kms_properties@get_properties-sanity-atomic,Crash +kms_properties@get_properties-sanity-non-atomic,Crash +kms_rmfb@close-fd diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3288-skips.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-skips.txt new file mode 100644 index 000000000000..f20c3574b75a --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3288-skips.txt @@ -0,0 +1,52 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.* + +# Too unstable, machine ends up hanging after lots of Oopses +kms_cursor_legacy.* + +# Started hanging the machine on Linux 5.19-rc2: +# +# [IGT] kms_plane_lowres: executing +# [IGT] kms_plane_lowres: starting subtest pipe-F-tiling-y +# [IGT] kms_plane_lowres: exiting, ret=77 +# Console: switching to colour frame buffer device 170x48 +# rockchip-drm display-subsystem: [drm] *ERROR* flip_done timed out +# rockchip-drm display-subsystem: [drm] *ERROR* [CRTC:35:crtc-0] commit wait timed out +# BUG: spinlock bad magic on CPU#3, kms_plane_lowre/482 +# 8<--- cut here --- +# Unable to handle kernel paging request at virtual address 7812078e +# [7812078e] *pgd=00000000 +# Internal error: Oops: 5 [#1] SMP ARM +# Modules linked in: +# CPU: 3 PID: 482 Comm: kms_plane_lowre Tainted: G W 5.19.0-rc2-323596-g00535de92171 #1 +# Hardware name: Rockchip (Device Tree) +# Process kms_plane_lowre (pid: 482, stack limit = 0x1193ac2b) +# spin_dump from do_raw_spin_lock+0xa4/0xe8 +# do_raw_spin_lock from wait_for_completion_timeout+0x2c/0x120 +# wait_for_completion_timeout from drm_crtc_commit_wait+0x18/0x7c +# drm_crtc_commit_wait from drm_atomic_helper_wait_for_dependencies+0x44/0x168 +# drm_atomic_helper_wait_for_dependencies from commit_tail+0x34/0x180 +# commit_tail from drm_atomic_helper_commit+0x164/0x18c +# drm_atomic_helper_commit from drm_atomic_commit+0xac/0xe4 +# drm_atomic_commit from drm_client_modeset_commit_atomic+0x23c/0x284 +# drm_client_modeset_commit_atomic from drm_client_modeset_commit_locked+0x60/0x1c8 +# drm_client_modeset_commit_locked from drm_client_modeset_commit+0x24/0x40 +# drm_client_modeset_commit from drm_fbdev_client_restore+0x58/0x94 +# drm_fbdev_client_restore from drm_client_dev_restore+0x70/0xbc +# drm_client_dev_restore from drm_release+0xf4/0x114 +# drm_release from __fput+0x74/0x240 +# __fput from task_work_run+0x84/0xb4 +# task_work_run from do_exit+0x34c/0xa20 +# do_exit from do_group_exit+0x34/0x98 +# do_group_exit from __wake_up_parent+0x0/0x18 +# Code: e595c008 12843d19 03e00000 03093168 (15940508) +# ---[ end trace 0000000000000000 ]--- +# note: kms_plane_lowre[482] exited with preempt_count 1 +# Fixing recursive fault but reboot is needed! +kms_plane_lowres@pipe-F-tiling-y + +# Take too long, we have only two machines, and these are very flaky +kms_cursor_crc.* + +# Machine is hanging in this test, so skip it +kms_pipe_crc_basic@disable-crc-after-crtc
\ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3399-fails.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-fails.txt new file mode 100644 index 000000000000..6db08ba6b008 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-fails.txt @@ -0,0 +1,37 @@ +kms_color@legacy-gamma,Fail +kms_color@pipe-A-legacy-gamma,Fail +kms_color@pipe-B-legacy-gamma,Fail +kms_flip@basic-flip-vs-wf_vblank,Fail +kms_flip@blocking-wf_vblank,Fail +kms_flip@dpms-vs-vblank-race,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-panning,Fail +kms_flip@flip-vs-panning-interruptible,Fail +kms_flip@flip-vs-wf_vblank-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_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_cursor@pipe-B-overlay-size-128,Fail +kms_plane_cursor@pipe-B-overlay-size-256,Fail +kms_plane_cursor@pipe-B-overlay-size-64,Fail +kms_plane_cursor@pipe-B-primary-size-128,Fail +kms_plane_cursor@pipe-B-primary-size-256,Fail +kms_plane_cursor@pipe-B-primary-size-64,Fail +kms_plane_cursor@pipe-B-viewport-size-128,Fail +kms_plane_cursor@pipe-B-viewport-size-256,Fail +kms_plane_cursor@pipe-B-viewport-size-64,Fail +kms_plane_multiple@atomic-pipe-B-tiling-none,Fail +kms_plane_multiple@tiling-none,Fail +kms_prime@basic-crc,Fail +kms_rmfb@close-fd,Fail diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3399-flakes.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-flakes.txt new file mode 100644 index 000000000000..4c0539b4beaf --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-flakes.txt @@ -0,0 +1,23 @@ + +kms_cursor_crc@.* +kms_flip@dpms-vs-vblank-race-interruptible +kms_flip@flip-vs-expired-vblank +kms_flip@modeset-vs-vblank-race-interruptible +kms_pipe_crc_basic@.* +kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-A +kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-B +kms_plane@plane-position-hole +kms_plane_multiple@atomic-pipe-A-tiling-none +kms_plane_multiple@atomic-pipe-B-tiling-none +kms_sequence@get-forked +kms_sequence@get-forked-busy +kms_setmode@basic +kms_universal_plane@universal-plane-pipe-B-functional,UnexpectedPass +kms_vblank@pipe-A-accuracy-idle +kms_vblank@pipe-A-query-busy +kms_vblank@pipe-A-query-forked-busy +kms_vblank@pipe-A-wait-idle +kms_vblank@pipe-B-accuracy-idle +kms_vblank@pipe-B-query-busy +kms_vblank@pipe-B-query-forked-busy +kms_vblank@pipe-B-wait-idle diff --git a/drivers/gpu/drm/ci/xfails/rockchip-rk3399-skips.txt b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-skips.txt new file mode 100644 index 000000000000..10c3d81a919a --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/rockchip-rk3399-skips.txt @@ -0,0 +1,5 @@ +# Suspend to RAM seems to be broken on this machine +.*suspend.* + +# Too unstable, machine ends up hanging after lots of Oopses +kms_cursor_legacy.* diff --git a/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt new file mode 100644 index 000000000000..9586b2339f6f --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt @@ -0,0 +1,38 @@ +kms_addfb_basic@addfb25-bad-modifier,Fail +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@linear-tiling-1-displays-1920x1080p,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-2560x1440p,Fail +kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_invalid_mode@int-max-clock,Fail +kms_plane_scaling@downscale-with-modifier-factor-0-25,Fail +kms_plane_scaling@downscale-with-rotation-factor-0-25,Fail +kms_plane_scaling@planes-upscale-20x20,Fail +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-25,Fail +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-5,Fail +kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-75,Fail +kms_plane_scaling@upscale-with-modifier-20x20,Fail +kms_plane_scaling@upscale-with-modifier-factor-0-25,Fail +kms_plane_scaling@upscale-with-pixel-format-20x20,Fail +kms_plane_scaling@upscale-with-pixel-format-factor-0-25,Fail +kms_plane_scaling@upscale-with-rotation-20x20,Fail +kms_vblank@crtc-id,Fail +kms_vblank@invalid,Fail +kms_vblank@pipe-A-accuracy-idle,Fail +kms_vblank@pipe-A-query-busy,Fail +kms_vblank@pipe-A-query-forked,Fail +kms_vblank@pipe-A-query-forked-busy,Fail +kms_vblank@pipe-A-query-idle,Fail +kms_vblank@pipe-A-ts-continuation-idle,Fail +kms_vblank@pipe-A-ts-continuation-modeset,Fail +kms_vblank@pipe-A-ts-continuation-suspend,Fail +kms_vblank@pipe-A-wait-busy,Fail +kms_vblank@pipe-A-wait-forked,Fail +kms_vblank@pipe-A-wait-forked-busy,Fail +kms_vblank@pipe-A-wait-idle,Fail diff --git a/drivers/gpu/drm/ci/xfails/virtio_gpu-none-flakes.txt b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-flakes.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-flakes.txt diff --git a/drivers/gpu/drm/ci/xfails/virtio_gpu-none-skips.txt b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-skips.txt new file mode 100644 index 000000000000..78be18174012 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-skips.txt @@ -0,0 +1,6 @@ +# Hits a "refcount_t: underflow; use-after-free" in virtio_gpu_fence_event_process +# When run in a particular order with other tests +kms_cursor_legacy.* + +# Job just hangs without any output +kms_flip@flip-vs-suspend.*
\ No newline at end of file diff --git a/drivers/gpu/drm/display/drm_dp_cec.c b/drivers/gpu/drm/display/drm_dp_cec.c index ae39dc794190..007ceb281d00 100644 --- a/drivers/gpu/drm/display/drm_dp_cec.c +++ b/drivers/gpu/drm/display/drm_dp_cec.c @@ -14,6 +14,7 @@ #include <drm/display/drm_dp_helper.h> #include <drm/drm_connector.h> #include <drm/drm_device.h> +#include <drm/drm_edid.h> /* * Unfortunately it turns out that we have a chicken-and-egg situation @@ -297,7 +298,7 @@ static void drm_dp_cec_unregister_work(struct work_struct *work) * were unchanged and just update the CEC physical address. Otherwise * unregister the old CEC adapter and create a new one. */ -void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid) +void drm_dp_cec_attach(struct drm_dp_aux *aux, u16 source_physical_address) { struct drm_connector *connector = aux->cec.connector; u32 cec_caps = CEC_CAP_DEFAULTS | CEC_CAP_NEEDS_HPD | @@ -339,7 +340,7 @@ void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid) if (aux->cec.adap->capabilities == cec_caps && aux->cec.adap->available_log_addrs == num_las) { /* Unchanged, so just set the phys addr */ - cec_s_phys_addr_from_edid(aux->cec.adap, edid); + cec_s_phys_addr(aux->cec.adap, source_physical_address, false); goto unlock; } /* @@ -370,11 +371,27 @@ void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid) * from drm_dp_cec_register_connector() edid == NULL, so in * that case the phys addr is just invalidated. */ - cec_s_phys_addr_from_edid(aux->cec.adap, edid); + cec_s_phys_addr(aux->cec.adap, source_physical_address, false); } unlock: mutex_unlock(&aux->cec.lock); } +EXPORT_SYMBOL(drm_dp_cec_attach); + +/* + * Note: Prefer calling drm_dp_cec_attach() with + * connector->display_info.source_physical_address if possible. + */ +void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid) +{ + u16 pa = CEC_PHYS_ADDR_INVALID; + + if (edid && edid->extensions) + pa = cec_get_edid_phys_addr((const u8 *)edid, + EDID_LENGTH * (edid->extensions + 1), NULL); + + drm_dp_cec_attach(aux, pa); +} EXPORT_SYMBOL(drm_dp_cec_set_edid); /* diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index e6a78fd32380..f3680f4e6970 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -746,8 +746,11 @@ int drm_dp_dpcd_read_phy_link_status(struct drm_dp_aux *aux, } EXPORT_SYMBOL(drm_dp_dpcd_read_phy_link_status); -static bool is_edid_digital_input_dp(const struct edid *edid) +static bool is_edid_digital_input_dp(const struct drm_edid *drm_edid) { + /* FIXME: get rid of drm_edid_raw() */ + const struct edid *edid = drm_edid_raw(drm_edid); + return edid && edid->revision >= 4 && edid->input & DRM_EDID_INPUT_DIGITAL && (edid->input & DRM_EDID_DIGITAL_TYPE_MASK) == DRM_EDID_DIGITAL_TYPE_DP; @@ -779,13 +782,13 @@ EXPORT_SYMBOL(drm_dp_downstream_is_type); * drm_dp_downstream_is_tmds() - is the downstream facing port TMDS? * @dpcd: DisplayPort configuration data * @port_cap: port capabilities - * @edid: EDID + * @drm_edid: EDID * * Returns: whether the downstream facing port is TMDS (HDMI/DVI). */ bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid) + const struct drm_edid *drm_edid) { if (dpcd[DP_DPCD_REV] < 0x11) { switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) { @@ -798,7 +801,7 @@ bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE], switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { case DP_DS_PORT_TYPE_DP_DUALMODE: - if (is_edid_digital_input_dp(edid)) + if (is_edid_digital_input_dp(drm_edid)) return false; fallthrough; case DP_DS_PORT_TYPE_DVI: @@ -1036,14 +1039,14 @@ EXPORT_SYMBOL(drm_dp_downstream_max_dotclock); * drm_dp_downstream_max_tmds_clock() - extract downstream facing port max TMDS clock * @dpcd: DisplayPort configuration data * @port_cap: port capabilities - * @edid: EDID + * @drm_edid: EDID * * Returns: HDMI/DVI downstream facing port max TMDS clock in kHz on success, * or 0 if max TMDS clock not defined */ int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid) + const struct drm_edid *drm_edid) { if (!drm_dp_is_branch(dpcd)) return 0; @@ -1059,7 +1062,7 @@ int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { case DP_DS_PORT_TYPE_DP_DUALMODE: - if (is_edid_digital_input_dp(edid)) + if (is_edid_digital_input_dp(drm_edid)) return 0; /* * It's left up to the driver to check the @@ -1101,14 +1104,14 @@ EXPORT_SYMBOL(drm_dp_downstream_max_tmds_clock); * drm_dp_downstream_min_tmds_clock() - extract downstream facing port min TMDS clock * @dpcd: DisplayPort configuration data * @port_cap: port capabilities - * @edid: EDID + * @drm_edid: EDID * * Returns: HDMI/DVI downstream facing port min TMDS clock in kHz on success, * or 0 if max TMDS clock not defined */ int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid) + const struct drm_edid *drm_edid) { if (!drm_dp_is_branch(dpcd)) return 0; @@ -1124,7 +1127,7 @@ int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { case DP_DS_PORT_TYPE_DP_DUALMODE: - if (is_edid_digital_input_dp(edid)) + if (is_edid_digital_input_dp(drm_edid)) return 0; fallthrough; case DP_DS_PORT_TYPE_DVI: @@ -1145,13 +1148,13 @@ EXPORT_SYMBOL(drm_dp_downstream_min_tmds_clock); * bits per component * @dpcd: DisplayPort configuration data * @port_cap: downstream facing port capabilities - * @edid: EDID + * @drm_edid: EDID * * Returns: Max bpc on success or 0 if max bpc not defined */ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid) + const struct drm_edid *drm_edid) { if (!drm_dp_is_branch(dpcd)) return 0; @@ -1169,7 +1172,7 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], case DP_DS_PORT_TYPE_DP: return 0; case DP_DS_PORT_TYPE_DP_DUALMODE: - if (is_edid_digital_input_dp(edid)) + if (is_edid_digital_input_dp(drm_edid)) return 0; fallthrough; case DP_DS_PORT_TYPE_HDMI: @@ -1362,14 +1365,14 @@ EXPORT_SYMBOL(drm_dp_downstream_id); * @m: pointer for debugfs file * @dpcd: DisplayPort configuration data * @port_cap: port capabilities - * @edid: EDID + * @drm_edid: EDID * @aux: DisplayPort AUX channel * */ void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid, + const struct drm_edid *drm_edid, struct drm_dp_aux *aux) { bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] & @@ -1432,15 +1435,15 @@ void drm_dp_downstream_debug(struct seq_file *m, if (clk > 0) seq_printf(m, "\t\tMax dot clock: %d kHz\n", clk); - clk = drm_dp_downstream_max_tmds_clock(dpcd, port_cap, edid); + clk = drm_dp_downstream_max_tmds_clock(dpcd, port_cap, drm_edid); if (clk > 0) seq_printf(m, "\t\tMax TMDS clock: %d kHz\n", clk); - clk = drm_dp_downstream_min_tmds_clock(dpcd, port_cap, edid); + clk = drm_dp_downstream_min_tmds_clock(dpcd, port_cap, drm_edid); if (clk > 0) seq_printf(m, "\t\tMin TMDS clock: %d kHz\n", clk); - bpc = drm_dp_downstream_max_bpc(dpcd, port_cap, edid); + bpc = drm_dp_downstream_max_bpc(dpcd, port_cap, drm_edid); if (bpc > 0) seq_printf(m, "\t\tMax bpc: %d\n", bpc); @@ -2449,12 +2452,16 @@ int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_S int num_bpc = 0; u8 color_depth = dsc_dpcd[DP_DSC_DEC_COLOR_DEPTH_CAP - DP_DSC_SUPPORT]; + if (!drm_dp_sink_supports_dsc(dsc_dpcd)) + return 0; + if (color_depth & DP_DSC_12_BPC) dsc_bpc[num_bpc++] = 12; if (color_depth & DP_DSC_10_BPC) dsc_bpc[num_bpc++] = 10; - if (color_depth & DP_DSC_8_BPC) - dsc_bpc[num_bpc++] = 8; + + /* A DP DSC Sink device shall support 8 bpc. */ + dsc_bpc[num_bpc++] = 8; return num_bpc; } diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index ed96cfcfa304..c490e8befc2f 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3255,15 +3255,15 @@ out_get_port: } EXPORT_SYMBOL(drm_dp_send_query_stream_enc_status); -static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_atomic_payload *payload) +static int drm_dp_create_payload_at_dfp(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_atomic_payload *payload) { return drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, payload->time_slots); } -static int drm_dp_create_payload_step2(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_atomic_payload *payload) +static int drm_dp_create_payload_to_remote(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_atomic_payload *payload) { int ret; struct drm_dp_mst_port *port = drm_dp_mst_topology_get_port_validated(mgr, payload->port); @@ -3276,17 +3276,20 @@ static int drm_dp_create_payload_step2(struct drm_dp_mst_topology_mgr *mgr, return ret; } -static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_topology_state *mst_state, - struct drm_dp_mst_atomic_payload *payload) +static void drm_dp_destroy_payload_at_remote_and_dfp(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_atomic_payload *payload) { drm_dbg_kms(mgr->dev, "\n"); /* it's okay for these to fail */ - drm_dp_payload_send_msg(mgr, payload->port, payload->vcpi, 0); - drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, 0); + if (payload->payload_allocation_status == DRM_DP_MST_PAYLOAD_ALLOCATION_REMOTE) { + drm_dp_payload_send_msg(mgr, payload->port, payload->vcpi, 0); + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_DFP; + } - return 0; + if (payload->payload_allocation_status == DRM_DP_MST_PAYLOAD_ALLOCATION_DFP) + drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, 0); } /** @@ -3296,10 +3299,9 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr, * @payload: The payload to write * * Determines the starting time slot for the given payload, and programs the VCPI for this payload - * into hardware. After calling this, the driver should generate ACT and payload packets. + * into the DPCD of DPRX. After calling this, the driver should generate ACT and payload packets. * - * Returns: 0 on success, error code on failure. In the event that this fails, - * @payload.vc_start_slot will also be set to -1. + * Returns: 0 on success, error code on failure. */ int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_topology_state *mst_state, @@ -3308,69 +3310,93 @@ int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port; int ret; + /* Update mst mgr info */ + if (mgr->payload_count == 0) + mgr->next_start_slot = mst_state->start_slot; + + payload->vc_start_slot = mgr->next_start_slot; + + mgr->payload_count++; + mgr->next_start_slot += payload->time_slots; + + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_LOCAL; + + /* Allocate payload to immediate downstream facing port */ port = drm_dp_mst_topology_get_port_validated(mgr, payload->port); if (!port) { drm_dbg_kms(mgr->dev, - "VCPI %d for port %p not in topology, not creating a payload\n", + "VCPI %d for port %p not in topology, not creating a payload to remote\n", payload->vcpi, payload->port); - payload->vc_start_slot = -1; - return 0; + return -EIO; } - if (mgr->payload_count == 0) - mgr->next_start_slot = mst_state->start_slot; - - payload->vc_start_slot = mgr->next_start_slot; - - ret = drm_dp_create_payload_step1(mgr, payload); - drm_dp_mst_topology_put_port(port); + ret = drm_dp_create_payload_at_dfp(mgr, payload); if (ret < 0) { - drm_warn(mgr->dev, "Failed to create MST payload for port %p: %d\n", - payload->port, ret); - payload->vc_start_slot = -1; - return ret; + drm_dbg_kms(mgr->dev, "Failed to create MST payload for port %p: %d\n", + payload->port, ret); + goto put_port; } - mgr->payload_count++; - mgr->next_start_slot += payload->time_slots; + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_DFP; - return 0; +put_port: + drm_dp_mst_topology_put_port(port); + + return ret; } EXPORT_SYMBOL(drm_dp_add_payload_part1); /** - * drm_dp_remove_payload() - Remove an MST payload + * drm_dp_remove_payload_part1() - Remove an MST payload along the virtual channel * @mgr: Manager to use. * @mst_state: The MST atomic state - * @old_payload: The payload with its old state - * @new_payload: The payload to write + * @payload: The payload to remove * - * Removes a payload from an MST topology if it was successfully assigned a start slot. Also updates - * the starting time slots of all other payloads which would have been shifted towards the start of - * the VC table as a result. After calling this, the driver should generate ACT and payload packets. + * Removes a payload along the virtual channel if it was successfully allocated. + * After calling this, the driver should set HW to generate ACT and then switch to new + * payload allocation state. */ -void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_topology_state *mst_state, - const struct drm_dp_mst_atomic_payload *old_payload, - struct drm_dp_mst_atomic_payload *new_payload) +void drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_atomic_payload *payload) { - struct drm_dp_mst_atomic_payload *pos; + /* Remove remote payload allocation */ bool send_remove = false; - /* We failed to make the payload, so nothing to do */ - if (new_payload->vc_start_slot == -1) - return; - mutex_lock(&mgr->lock); - send_remove = drm_dp_mst_port_downstream_of_branch(new_payload->port, mgr->mst_primary); + send_remove = drm_dp_mst_port_downstream_of_branch(payload->port, mgr->mst_primary); mutex_unlock(&mgr->lock); if (send_remove) - drm_dp_destroy_payload_step1(mgr, mst_state, new_payload); + drm_dp_destroy_payload_at_remote_and_dfp(mgr, mst_state, payload); else drm_dbg_kms(mgr->dev, "Payload for VCPI %d not in topology, not sending remove\n", - new_payload->vcpi); + payload->vcpi); + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_LOCAL; +} +EXPORT_SYMBOL(drm_dp_remove_payload_part1); + +/** + * drm_dp_remove_payload_part2() - Remove an MST payload locally + * @mgr: Manager to use. + * @mst_state: The MST atomic state + * @old_payload: The payload with its old state + * @new_payload: The payload with its latest state + * + * Updates the starting time slots of all other payloads which would have been shifted towards + * the start of the payload ID table as a result of removing a payload. Driver should call this + * function whenever it removes a payload in its HW. It's independent to the result of payload + * allocation/deallocation at branch devices along the virtual channel. + */ +void drm_dp_remove_payload_part2(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + const struct drm_dp_mst_atomic_payload *old_payload, + struct drm_dp_mst_atomic_payload *new_payload) +{ + struct drm_dp_mst_atomic_payload *pos; + + /* Remove local payload allocation */ list_for_each_entry(pos, &mst_state->payloads, next) { if (pos != new_payload && pos->vc_start_slot > new_payload->vc_start_slot) pos->vc_start_slot -= old_payload->time_slots; @@ -3382,9 +3408,10 @@ void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr, if (new_payload->delete) drm_dp_mst_put_port_malloc(new_payload->port); -} -EXPORT_SYMBOL(drm_dp_remove_payload); + new_payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_NONE; +} +EXPORT_SYMBOL(drm_dp_remove_payload_part2); /** * drm_dp_add_payload_part2() - Execute payload update part 2 * @mgr: Manager to use. @@ -3403,21 +3430,19 @@ int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr, int ret = 0; /* Skip failed payloads */ - if (payload->vc_start_slot == -1) { - drm_dbg_kms(mgr->dev, "Part 1 of payload creation for %s failed, skipping part 2\n", + if (payload->payload_allocation_status != DRM_DP_MST_PAYLOAD_ALLOCATION_DFP) { + drm_dbg_kms(state->dev, "Part 1 of payload creation for %s failed, skipping part 2\n", payload->port->connector->name); return -EIO; } - ret = drm_dp_create_payload_step2(mgr, payload); - if (ret < 0) { - if (!payload->delete) - drm_err(mgr->dev, "Step 2 of creating MST payload for %p failed: %d\n", - payload->port, ret); - else - drm_dbg_kms(mgr->dev, "Step 2 of removing MST payload for %p failed: %d\n", - payload->port, ret); - } + /* Allocate payload to remote end */ + ret = drm_dp_create_payload_to_remote(mgr, payload); + if (ret < 0) + drm_err(mgr->dev, "Step 2 of creating MST payload for %p failed: %d\n", + payload->port, ret); + else + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_REMOTE; return ret; } @@ -4328,6 +4353,7 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, drm_dp_mst_get_port_malloc(port); payload->port = port; payload->vc_start_slot = -1; + payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_NONE; list_add(&payload->next, &topology_state->payloads); } payload->time_slots = req_slots; @@ -4497,7 +4523,7 @@ void drm_dp_mst_atomic_wait_for_dependencies(struct drm_atomic_state *state) } /* Now that previous state is committed, it's safe to copy over the start slot - * assignments + * and allocation status assignments */ list_for_each_entry(old_payload, &old_mst_state->payloads, next) { if (old_payload->delete) @@ -4506,6 +4532,8 @@ void drm_dp_mst_atomic_wait_for_dependencies(struct drm_atomic_state *state) new_payload = drm_atomic_get_mst_payload_state(new_mst_state, old_payload->port); new_payload->vc_start_slot = old_payload->vc_start_slot; + new_payload->payload_allocation_status = + old_payload->payload_allocation_status; } } } @@ -4822,6 +4850,13 @@ void drm_dp_mst_dump_topology(struct seq_file *m, struct drm_dp_mst_atomic_payload *payload; int i, ret; + static const char *const status[] = { + "None", + "Local", + "DFP", + "Remote", + }; + mutex_lock(&mgr->lock); if (mgr->mst_primary) drm_dp_mst_dump_mstb(m, mgr->mst_primary); @@ -4838,7 +4873,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, seq_printf(m, "payload_mask: %x, max_payloads: %d, start_slot: %u, pbn_div: %d\n", state->payload_mask, mgr->max_payloads, state->start_slot, state->pbn_div); - seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | sink name |\n"); + seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | status | sink name |\n"); for (i = 0; i < mgr->max_payloads; i++) { list_for_each_entry(payload, &state->payloads, next) { char name[14]; @@ -4847,7 +4882,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, continue; fetch_monitor_name(mgr, payload->port, name, sizeof(name)); - seq_printf(m, " %5d %6d %6d %02d - %02d %5d %5s %19s\n", + seq_printf(m, " %5d %6d %6d %02d - %02d %5d %5s %8s %19s\n", i, payload->port->port_num, payload->vcpi, @@ -4855,6 +4890,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, payload->vc_start_slot + payload->time_slots - 1, payload->pbn, payload->dsc_enabled ? "Y" : "N", + status[payload->payload_allocation_status], (*name != 0) ? name : "Unknown"); } } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c277b198fa3f..f1a503aafe5a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1841,9 +1841,9 @@ static const struct drm_debugfs_info drm_atomic_debugfs_list[] = { {"state", drm_state_info, 0}, }; -void drm_atomic_debugfs_init(struct drm_minor *minor) +void drm_atomic_debugfs_init(struct drm_device *dev) { - drm_debugfs_add_files(minor->dev, drm_atomic_debugfs_list, + drm_debugfs_add_files(dev, drm_atomic_debugfs_list, ARRAY_SIZE(drm_atomic_debugfs_list)); } #endif diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 292e38eb6218..71d399397107 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3339,6 +3339,9 @@ void drm_atomic_helper_shutdown(struct drm_device *dev) struct drm_modeset_acquire_ctx ctx; int ret; + if (dev == NULL) + return; + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); ret = drm_atomic_helper_disable_all(dev, &ctx); diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index cf92a9ae8034..2ed2585ded37 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -235,7 +235,8 @@ static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv) static int drm_master_check_perm(struct drm_device *dev, struct drm_file *file_priv) { - if (file_priv->pid == task_pid(current) && file_priv->was_master) + if (file_priv->was_master && + rcu_access_pointer(file_priv->pid) == task_pid(current)) return 0; if (!capable(CAP_SYS_ADMIN)) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 39e68e45bb12..30d66bee0ec6 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1384,9 +1384,9 @@ static const struct drm_debugfs_info drm_bridge_debugfs_list[] = { { "bridge_chains", drm_bridge_chains_info, 0 }, }; -void drm_bridge_debugfs_init(struct drm_minor *minor) +void drm_bridge_debugfs_init(struct drm_device *dev) { - drm_debugfs_add_files(minor->dev, drm_bridge_debugfs_list, + drm_debugfs_add_files(dev, drm_bridge_debugfs_list, ARRAY_SIZE(drm_bridge_debugfs_list)); } #endif diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 1da93d5a1f61..8239ad43aed5 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -5,6 +5,8 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/property.h> #include <linux/slab.h> #include <drm/drm_atomic_state_helper.h> @@ -107,27 +109,36 @@ static void drm_bridge_connector_hpd_notify(struct drm_connector *connector, } } -static void drm_bridge_connector_hpd_cb(void *cb_data, - enum drm_connector_status status) +static void drm_bridge_connector_handle_hpd(struct drm_bridge_connector *drm_bridge_connector, + enum drm_connector_status status) { - struct drm_bridge_connector *drm_bridge_connector = cb_data; struct drm_connector *connector = &drm_bridge_connector->base; struct drm_device *dev = connector->dev; - enum drm_connector_status old_status; mutex_lock(&dev->mode_config.mutex); - old_status = connector->status; connector->status = status; mutex_unlock(&dev->mode_config.mutex); - if (old_status == status) - return; - drm_bridge_connector_hpd_notify(connector, status); drm_kms_helper_connector_hotplug_event(connector); } +static void drm_bridge_connector_hpd_cb(void *cb_data, + enum drm_connector_status status) +{ + drm_bridge_connector_handle_hpd(cb_data, status); +} + +static void drm_bridge_connector_oob_hotplug_event(struct drm_connector *connector, + enum drm_connector_status status) +{ + struct drm_bridge_connector *bridge_connector = + to_drm_bridge_connector(connector); + + drm_bridge_connector_handle_hpd(bridge_connector, status); +} + static void drm_bridge_connector_enable_hpd(struct drm_connector *connector) { struct drm_bridge_connector *bridge_connector = @@ -196,6 +207,8 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector) drm_connector_unregister(connector); drm_connector_cleanup(connector); + fwnode_handle_put(connector->fwnode); + kfree(bridge_connector); } @@ -221,6 +234,7 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = { .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .debugfs_init = drm_bridge_connector_debugfs_init, + .oob_hotplug_event = drm_bridge_connector_oob_hotplug_event, }; /* ----------------------------------------------------------------------------- @@ -238,7 +252,7 @@ static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector, if (status != connector_status_connected) goto no_edid; - edid = bridge->funcs->get_edid(bridge, connector); + edid = drm_bridge_get_edid(bridge, connector); if (!drm_edid_is_valid(edid)) { kfree(edid); goto no_edid; @@ -357,6 +371,12 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, if (!drm_bridge_get_next_bridge(bridge)) connector_type = bridge->type; +#ifdef CONFIG_OF + if (!drm_bridge_get_next_bridge(bridge) && + bridge->of_node) + connector->fwnode = fwnode_handle_get(of_fwnode_handle(bridge->of_node)); +#endif + if (bridge->ddc) ddc = bridge->ddc; diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index e6f5ba5f4baf..f57e6d74fb0e 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -480,10 +480,12 @@ err_undo: static int __alloc_range(struct drm_buddy *mm, struct list_head *dfs, u64 start, u64 size, - struct list_head *blocks) + struct list_head *blocks, + u64 *total_allocated_on_err) { struct drm_buddy_block *block; struct drm_buddy_block *buddy; + u64 total_allocated = 0; LIST_HEAD(allocated); u64 end; int err; @@ -520,6 +522,7 @@ static int __alloc_range(struct drm_buddy *mm, } mark_allocated(block); + total_allocated += drm_buddy_block_size(mm, block); mm->avail -= drm_buddy_block_size(mm, block); list_add_tail(&block->link, &allocated); continue; @@ -551,13 +554,20 @@ err_undo: __drm_buddy_free(mm, block); err_free: - drm_buddy_free_list(mm, &allocated); + if (err == -ENOSPC && total_allocated_on_err) { + list_splice_tail(&allocated, blocks); + *total_allocated_on_err = total_allocated; + } else { + drm_buddy_free_list(mm, &allocated); + } + return err; } static int __drm_buddy_alloc_range(struct drm_buddy *mm, u64 start, u64 size, + u64 *total_allocated_on_err, struct list_head *blocks) { LIST_HEAD(dfs); @@ -566,7 +576,62 @@ static int __drm_buddy_alloc_range(struct drm_buddy *mm, for (i = 0; i < mm->n_roots; ++i) list_add_tail(&mm->roots[i]->tmp_link, &dfs); - return __alloc_range(mm, &dfs, start, size, blocks); + return __alloc_range(mm, &dfs, start, size, + blocks, total_allocated_on_err); +} + +static int __alloc_contig_try_harder(struct drm_buddy *mm, + u64 size, + u64 min_block_size, + struct list_head *blocks) +{ + u64 rhs_offset, lhs_offset, lhs_size, filled; + struct drm_buddy_block *block; + struct list_head *list; + LIST_HEAD(blocks_lhs); + unsigned long pages; + unsigned int order; + u64 modify_size; + int err; + + modify_size = rounddown_pow_of_two(size); + pages = modify_size >> ilog2(mm->chunk_size); + order = fls(pages) - 1; + if (order == 0) + return -ENOSPC; + + list = &mm->free_list[order]; + if (list_empty(list)) + return -ENOSPC; + + list_for_each_entry_reverse(block, list, link) { + /* Allocate blocks traversing RHS */ + rhs_offset = drm_buddy_block_offset(block); + err = __drm_buddy_alloc_range(mm, rhs_offset, size, + &filled, blocks); + if (!err || err != -ENOSPC) + return err; + + lhs_size = max((size - filled), min_block_size); + if (!IS_ALIGNED(lhs_size, min_block_size)) + lhs_size = round_up(lhs_size, min_block_size); + + /* Allocate blocks traversing LHS */ + lhs_offset = drm_buddy_block_offset(block) - lhs_size; + err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size, + NULL, &blocks_lhs); + if (!err) { + list_splice(&blocks_lhs, blocks); + return 0; + } else if (err != -ENOSPC) { + drm_buddy_free_list(mm, blocks); + return err; + } + /* Free blocks for the next iteration */ + drm_buddy_free_list(mm, blocks); + } + + return -ENOSPC; } /** @@ -626,7 +691,7 @@ int drm_buddy_block_trim(struct drm_buddy *mm, new_start = drm_buddy_block_offset(block); list_add(&block->tmp_link, &dfs); - err = __alloc_range(mm, &dfs, new_start, new_size, blocks); + err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL); if (err) { mark_allocated(block); mm->avail -= drm_buddy_block_size(mm, block); @@ -645,7 +710,7 @@ EXPORT_SYMBOL(drm_buddy_block_trim); * @start: start of the allowed range for this block * @end: end of the allowed range for this block * @size: size of the allocation - * @min_page_size: alignment of the allocation + * @min_block_size: alignment of the allocation * @blocks: output list head to add allocated blocks * @flags: DRM_BUDDY_*_ALLOCATION flags * @@ -660,23 +725,24 @@ EXPORT_SYMBOL(drm_buddy_block_trim); */ int drm_buddy_alloc_blocks(struct drm_buddy *mm, u64 start, u64 end, u64 size, - u64 min_page_size, + u64 min_block_size, struct list_head *blocks, unsigned long flags) { struct drm_buddy_block *block = NULL; + u64 original_size, original_min_size; unsigned int min_order, order; - unsigned long pages; LIST_HEAD(allocated); + unsigned long pages; int err; if (size < mm->chunk_size) return -EINVAL; - if (min_page_size < mm->chunk_size) + if (min_block_size < mm->chunk_size) return -EINVAL; - if (!is_power_of_2(min_page_size)) + if (!is_power_of_2(min_block_size)) return -EINVAL; if (!IS_ALIGNED(start | end | size, mm->chunk_size)) @@ -690,14 +756,23 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, /* Actual range allocation */ if (start + size == end) - return __drm_buddy_alloc_range(mm, start, size, blocks); - - if (!IS_ALIGNED(size, min_page_size)) - return -EINVAL; + return __drm_buddy_alloc_range(mm, start, size, NULL, blocks); + + original_size = size; + original_min_size = min_block_size; + + /* Roundup the size to power of 2 */ + if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION) { + size = roundup_pow_of_two(size); + min_block_size = size; + /* Align size value to min_block_size */ + } else if (!IS_ALIGNED(size, min_block_size)) { + size = round_up(size, min_block_size); + } pages = size >> ilog2(mm->chunk_size); order = fls(pages) - 1; - min_order = ilog2(min_page_size) - ilog2(mm->chunk_size); + min_order = ilog2(min_block_size) - ilog2(mm->chunk_size); do { order = min(order, (unsigned int)fls(pages) - 1); @@ -716,6 +791,16 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, break; if (order-- == min_order) { + if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION && + !(flags & DRM_BUDDY_RANGE_ALLOCATION)) + /* + * Try contiguous block allocation through + * try harder method + */ + return __alloc_contig_try_harder(mm, + original_size, + original_min_size, + blocks); err = -ENOSPC; goto err_free; } @@ -732,6 +817,31 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, break; } while (1); + /* Trim the allocated block to the required size */ + if (original_size != size) { + struct list_head *trim_list; + LIST_HEAD(temp); + u64 trim_size; + + trim_list = &allocated; + trim_size = original_size; + + if (!list_is_singular(&allocated)) { + block = list_last_entry(&allocated, typeof(*block), link); + list_move(&block->link, &temp); + trim_list = &temp; + trim_size = drm_buddy_block_size(mm, block) - + (size - original_size); + } + + drm_buddy_block_trim(mm, + trim_size, + trim_list); + + if (!list_empty(&temp)) + list_splice_tail(trim_list, &allocated); + } + list_splice_tail(&allocated, blocks); return 0; diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 037e36f2049c..2762572f286e 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -535,9 +535,9 @@ static const struct drm_debugfs_info drm_client_debugfs_list[] = { { "internal_clients", drm_client_debugfs_internal_clients, 0 }, }; -void drm_client_debugfs_init(struct drm_minor *minor) +void drm_client_debugfs_init(struct drm_device *dev) { - drm_debugfs_add_files(minor->dev, drm_client_debugfs_list, + drm_debugfs_add_files(dev, drm_client_debugfs_list, ARRAY_SIZE(drm_client_debugfs_list)); } #endif diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index bf8371dc2a61..c3725086f413 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -631,6 +631,10 @@ int drm_connector_register(struct drm_connector *connector) goto err_debugfs; } + ret = drm_sysfs_connector_add_late(connector); + if (ret) + goto err_late_register; + drm_mode_object_register(connector->dev, &connector->base); connector->registration_state = DRM_CONNECTOR_REGISTERED; @@ -647,6 +651,9 @@ int drm_connector_register(struct drm_connector *connector) mutex_unlock(&connector_list_lock); goto unlock; +err_late_register: + if (connector->funcs->early_unregister) + connector->funcs->early_unregister(connector); err_debugfs: drm_debugfs_connector_remove(connector); drm_sysfs_connector_remove(connector); @@ -681,11 +688,13 @@ void drm_connector_unregister(struct drm_connector *connector) connector->privacy_screen, &connector->privacy_screen_notifier); + drm_sysfs_connector_remove_early(connector); + if (connector->funcs->early_unregister) connector->funcs->early_unregister(connector); - drm_sysfs_connector_remove(connector); drm_debugfs_connector_remove(connector); + drm_sysfs_connector_remove(connector); connector->registration_state = DRM_CONNECTOR_UNREGISTERED; mutex_unlock(&connector->mutex); @@ -2203,6 +2212,7 @@ static int drm_mode_create_colorspace_property(struct drm_connector *connector, /** * drm_mode_create_hdmi_colorspace_property - create hdmi colorspace property * @connector: connector to create the Colorspace property on. + * @supported_colorspaces: bitmap of supported color spaces * * Called by a driver the first time it's needed, must be attached to desired * HDMI connectors. @@ -2227,6 +2237,7 @@ EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); /** * drm_mode_create_dp_colorspace_property - create dp colorspace property * @connector: connector to create the Colorspace property on. + * @supported_colorspaces: bitmap of supported color spaces * * Called by a driver the first time it's needed, must be attached to desired * DP connectors. @@ -3049,6 +3060,7 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode) /** * drm_connector_oob_hotplug_event - Report out-of-band hotplug event to connector * @connector_fwnode: fwnode_handle to report the event on + * @status: hot plug detect logical state * * On some hardware a hotplug event notification may come from outside the display * driver / device. An example of this is some USB Type-C setups where the hardware @@ -3058,7 +3070,8 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode) * This function can be used to report these out-of-band events after obtaining * a drm_connector reference through calling drm_connector_find_by_fwnode(). */ -void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode) +void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode, + enum drm_connector_status status) { struct drm_connector *connector; @@ -3067,7 +3080,7 @@ void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode) return; if (connector->funcs->oob_hotplug_event) - connector->funcs->oob_hotplug_event(connector); + connector->funcs->oob_hotplug_event(connector, status); drm_connector_put(connector); } diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 501a10edd0e1..8556c3b3ff88 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -232,7 +232,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, /* drm_atomic.c */ #ifdef CONFIG_DEBUG_FS struct drm_minor; -void drm_atomic_debugfs_init(struct drm_minor *minor); +void drm_atomic_debugfs_init(struct drm_device *dev); #endif int __drm_atomic_helper_disable_plane(struct drm_plane *plane, diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 2de43ff3ce0a..f291fb4b359f 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -40,7 +40,7 @@ #include <drm/drm_file.h> #include <drm/drm_gem.h> #include <drm/drm_managed.h> -#include <drm/drm_gpuva_mgr.h> +#include <drm/drm_gpuvm.h> #include "drm_crtc_internal.h" #include "drm_internal.h" @@ -92,15 +92,17 @@ static int drm_clients_info(struct seq_file *m, void *data) */ mutex_lock(&dev->filelist_mutex); list_for_each_entry_reverse(priv, &dev->filelist, lhead) { - struct task_struct *task; bool is_current_master = drm_is_current_master(priv); + struct task_struct *task; + struct pid *pid; - rcu_read_lock(); /* locks pid_task()->comm */ - task = pid_task(priv->pid, PIDTYPE_TGID); + rcu_read_lock(); /* Locks priv->pid and pid_task()->comm! */ + pid = rcu_dereference(priv->pid); + task = pid_task(pid, PIDTYPE_TGID); uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID; seq_printf(m, "%20s %5d %3d %c %c %5d %10u\n", task ? task->comm : "<unknown>", - pid_vnr(priv->pid), + pid_vnr(pid), priv->minor->index, is_current_master ? 'y' : 'n', priv->authenticated ? 'y' : 'n', @@ -150,6 +152,9 @@ static int drm_debugfs_open(struct inode *inode, struct file *file) { struct drm_info_node *node = inode->i_private; + if (!device_is_registered(node->minor->kdev)) + return -ENODEV; + return single_open(file, node->info_ent->show, node); } @@ -157,6 +162,10 @@ static int drm_debugfs_entry_open(struct inode *inode, struct file *file) { struct drm_debugfs_entry *entry = inode->i_private; struct drm_debugfs_info *node = &entry->file; + struct drm_minor *minor = entry->dev->primary ?: entry->dev->accel; + + if (!device_is_registered(minor->kdev)) + return -ENODEV; return single_open(file, node->show, entry); } @@ -180,31 +189,31 @@ static const struct file_operations drm_debugfs_fops = { /** * drm_debugfs_gpuva_info - dump the given DRM GPU VA space * @m: pointer to the &seq_file to write - * @mgr: the &drm_gpuva_manager representing the GPU VA space + * @gpuvm: the &drm_gpuvm representing the GPU VA space * * Dumps the GPU VA mappings of a given DRM GPU VA manager. * * For each DRM GPU VA space drivers should call this function from their * &drm_info_list's show callback. * - * Returns: 0 on success, -ENODEV if the &mgr is not initialized + * Returns: 0 on success, -ENODEV if the &gpuvm is not initialized */ int drm_debugfs_gpuva_info(struct seq_file *m, - struct drm_gpuva_manager *mgr) + struct drm_gpuvm *gpuvm) { - struct drm_gpuva *va, *kva = &mgr->kernel_alloc_node; + struct drm_gpuva *va, *kva = &gpuvm->kernel_alloc_node; - if (!mgr->name) + if (!gpuvm->name) return -ENODEV; seq_printf(m, "DRM GPU VA space (%s) [0x%016llx;0x%016llx]\n", - mgr->name, mgr->mm_start, mgr->mm_start + mgr->mm_range); + gpuvm->name, gpuvm->mm_start, gpuvm->mm_start + gpuvm->mm_range); seq_printf(m, "Kernel reserved node [0x%016llx;0x%016llx]\n", kva->va.addr, kva->va.addr + kva->va.range); seq_puts(m, "\n"); seq_puts(m, " VAs | start | range | end | object | object offset\n"); seq_puts(m, "-------------------------------------------------------------------------------------------------------------\n"); - drm_gpuva_for_each_va(va, mgr) { + drm_gpuvm_for_each_va(va, gpuvm) { if (unlikely(va == kva)) continue; @@ -227,7 +236,7 @@ EXPORT_SYMBOL(drm_debugfs_gpuva_info); * * Create a given set of debugfs files represented by an array of * &struct drm_info_list in the given root directory. These files will be removed - * automatically on drm_debugfs_cleanup(). + * automatically on drm_debugfs_dev_fini(). */ void drm_debugfs_create_files(const struct drm_info_list *files, int count, struct dentry *root, struct drm_minor *minor) @@ -242,7 +251,7 @@ void drm_debugfs_create_files(const struct drm_info_list *files, int count, if (features && !drm_core_check_all_features(dev, features)) continue; - tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); + tmp = drmm_kzalloc(dev, sizeof(*tmp), GFP_KERNEL); if (tmp == NULL) continue; @@ -251,111 +260,89 @@ void drm_debugfs_create_files(const struct drm_info_list *files, int count, 0444, root, tmp, &drm_debugfs_fops); tmp->info_ent = &files[i]; - - mutex_lock(&minor->debugfs_lock); - list_add(&tmp->list, &minor->debugfs_list); - mutex_unlock(&minor->debugfs_lock); } } EXPORT_SYMBOL(drm_debugfs_create_files); -int drm_debugfs_init(struct drm_minor *minor, int minor_id, - struct dentry *root) +int drm_debugfs_remove_files(const struct drm_info_list *files, int count, + struct dentry *root, struct drm_minor *minor) { - struct drm_device *dev = minor->dev; - struct drm_debugfs_entry *entry, *tmp; - char name[64]; - - INIT_LIST_HEAD(&minor->debugfs_list); - mutex_init(&minor->debugfs_lock); - sprintf(name, "%d", minor_id); - minor->debugfs_root = debugfs_create_dir(name, root); - - drm_debugfs_add_files(minor->dev, drm_debugfs_list, DRM_DEBUGFS_ENTRIES); - - if (drm_drv_uses_atomic_modeset(dev)) { - drm_atomic_debugfs_init(minor); - drm_bridge_debugfs_init(minor); - } - - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_framebuffer_debugfs_init(minor); + int i; - drm_client_debugfs_init(minor); - } + for (i = 0; i < count; i++) { + struct dentry *dent = debugfs_lookup(files[i].name, root); - if (dev->driver->debugfs_init) - dev->driver->debugfs_init(minor); + if (!dent) + continue; - list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) { - debugfs_create_file(entry->file.name, 0444, - minor->debugfs_root, entry, &drm_debugfs_entry_fops); - list_del(&entry->list); + drmm_kfree(minor->dev, d_inode(dent)->i_private); + debugfs_remove(dent); } - return 0; } +EXPORT_SYMBOL(drm_debugfs_remove_files); -void drm_debugfs_late_register(struct drm_device *dev) +/** + * drm_debugfs_dev_init - create debugfs directory for the device + * @dev: the device which we want to create the directory for + * @root: the parent directory depending on the device type + * + * Creates the debugfs directory for the device under the given root directory. + */ +void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root) { - struct drm_minor *minor = dev->primary; - struct drm_debugfs_entry *entry, *tmp; - - if (!minor) - return; - - list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) { - debugfs_create_file(entry->file.name, 0444, - minor->debugfs_root, entry, &drm_debugfs_entry_fops); - list_del(&entry->list); - } + dev->debugfs_root = debugfs_create_dir(dev->unique, root); } -int drm_debugfs_remove_files(const struct drm_info_list *files, int count, - struct drm_minor *minor) +/** + * drm_debugfs_dev_fini - cleanup debugfs directory + * @dev: the device to cleanup the debugfs stuff + * + * Remove the debugfs directory, might be called multiple times. + */ +void drm_debugfs_dev_fini(struct drm_device *dev) { - struct list_head *pos, *q; - struct drm_info_node *tmp; - int i; - - mutex_lock(&minor->debugfs_lock); - for (i = 0; i < count; i++) { - list_for_each_safe(pos, q, &minor->debugfs_list) { - tmp = list_entry(pos, struct drm_info_node, list); - if (tmp->info_ent == &files[i]) { - debugfs_remove(tmp->dent); - list_del(pos); - kfree(tmp); - } - } - } - mutex_unlock(&minor->debugfs_lock); - return 0; + debugfs_remove_recursive(dev->debugfs_root); + dev->debugfs_root = NULL; } -EXPORT_SYMBOL(drm_debugfs_remove_files); -static void drm_debugfs_remove_all_files(struct drm_minor *minor) +void drm_debugfs_dev_register(struct drm_device *dev) { - struct drm_info_node *node, *tmp; + drm_debugfs_add_files(dev, drm_debugfs_list, DRM_DEBUGFS_ENTRIES); - mutex_lock(&minor->debugfs_lock); - list_for_each_entry_safe(node, tmp, &minor->debugfs_list, list) { - debugfs_remove(node->dent); - list_del(&node->list); - kfree(node); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_framebuffer_debugfs_init(dev); + drm_client_debugfs_init(dev); + } + if (drm_drv_uses_atomic_modeset(dev)) { + drm_atomic_debugfs_init(dev); + drm_bridge_debugfs_init(dev); } - mutex_unlock(&minor->debugfs_lock); } -void drm_debugfs_cleanup(struct drm_minor *minor) +int drm_debugfs_register(struct drm_minor *minor, int minor_id, + struct dentry *root) { - if (!minor->debugfs_root) - return; + struct drm_device *dev = minor->dev; + char name[64]; + + sprintf(name, "%d", minor_id); + minor->debugfs_symlink = debugfs_create_symlink(name, root, + dev->unique); + + /* TODO: Only for compatibility with drivers */ + minor->debugfs_root = dev->debugfs_root; - drm_debugfs_remove_all_files(minor); + if (dev->driver->debugfs_init && dev->render != minor) + dev->driver->debugfs_init(minor); - debugfs_remove_recursive(minor->debugfs_root); - minor->debugfs_root = NULL; + return 0; +} + +void drm_debugfs_unregister(struct drm_minor *minor) +{ + debugfs_remove(minor->debugfs_symlink); + minor->debugfs_symlink = NULL; } /** @@ -381,9 +368,8 @@ void drm_debugfs_add_file(struct drm_device *dev, const char *name, entry->file.data = data; entry->dev = dev; - mutex_lock(&dev->debugfs_mutex); - list_add(&entry->list, &dev->debugfs_list); - mutex_unlock(&dev->debugfs_mutex); + debugfs_create_file(name, 0444, dev->debugfs_root, entry, + &drm_debugfs_entry_fops); } EXPORT_SYMBOL(drm_debugfs_add_file); @@ -540,13 +526,13 @@ static const struct file_operations drm_connector_fops = { void drm_debugfs_connector_add(struct drm_connector *connector) { - struct drm_minor *minor = connector->dev->primary; + struct drm_device *dev = connector->dev; struct dentry *root; - if (!minor->debugfs_root) + if (!dev->debugfs_root) return; - root = debugfs_create_dir(connector->name, minor->debugfs_root); + root = debugfs_create_dir(connector->name, dev->debugfs_root); connector->debugfs_entry = root; /* force */ @@ -581,7 +567,7 @@ void drm_debugfs_connector_remove(struct drm_connector *connector) void drm_debugfs_crtc_add(struct drm_crtc *crtc) { - struct drm_minor *minor = crtc->dev->primary; + struct drm_device *dev = crtc->dev; struct dentry *root; char *name; @@ -589,7 +575,7 @@ void drm_debugfs_crtc_add(struct drm_crtc *crtc) if (!name) return; - root = debugfs_create_dir(name, minor->debugfs_root); + root = debugfs_create_dir(name, dev->debugfs_root); kfree(name); crtc->debugfs_entry = root; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 3eda026ffac6..535f16e7882e 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -172,10 +172,9 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type) if (!minor) return 0; - if (minor->type == DRM_MINOR_ACCEL) { - accel_debugfs_init(minor, minor->index); - } else { - ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); + if (minor->type != DRM_MINOR_ACCEL) { + ret = drm_debugfs_register(minor, minor->index, + drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); goto err_debugfs; @@ -199,7 +198,7 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type) return 0; err_debugfs: - drm_debugfs_cleanup(minor); + drm_debugfs_unregister(minor); return ret; } @@ -223,7 +222,7 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ device_del(minor->kdev); dev_set_drvdata(minor->kdev, NULL); /* safety belt */ - drm_debugfs_cleanup(minor); + drm_debugfs_unregister(minor); } /* @@ -598,7 +597,6 @@ static void drm_dev_init_release(struct drm_device *dev, void *res) mutex_destroy(&dev->clientlist_mutex); mutex_destroy(&dev->filelist_mutex); mutex_destroy(&dev->struct_mutex); - mutex_destroy(&dev->debugfs_mutex); drm_legacy_destroy_members(dev); } @@ -639,14 +637,12 @@ static int drm_dev_init(struct drm_device *dev, INIT_LIST_HEAD(&dev->filelist_internal); INIT_LIST_HEAD(&dev->clientlist); INIT_LIST_HEAD(&dev->vblank_event_list); - INIT_LIST_HEAD(&dev->debugfs_list); spin_lock_init(&dev->event_lock); mutex_init(&dev->struct_mutex); mutex_init(&dev->filelist_mutex); mutex_init(&dev->clientlist_mutex); mutex_init(&dev->master_mutex); - mutex_init(&dev->debugfs_mutex); ret = drmm_add_action_or_reset(dev, drm_dev_init_release, NULL); if (ret) @@ -697,6 +693,11 @@ static int drm_dev_init(struct drm_device *dev, goto err; } + if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) + accel_debugfs_init(dev); + else + drm_debugfs_dev_init(dev, drm_debugfs_root); + return 0; err: @@ -786,6 +787,9 @@ static void drm_dev_release(struct kref *ref) { struct drm_device *dev = container_of(ref, struct drm_device, ref); + /* Just in case register/unregister was never called */ + drm_debugfs_dev_fini(dev); + if (dev->driver->release) dev->driver->release(dev); @@ -916,6 +920,11 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (drm_dev_needs_global_mutex(dev)) mutex_lock(&drm_global_mutex); + if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) + accel_debugfs_register(dev); + else + drm_debugfs_dev_register(dev); + ret = drm_minor_register(dev, DRM_MINOR_RENDER); if (ret) goto err_minors; @@ -1001,6 +1010,7 @@ void drm_dev_unregister(struct drm_device *dev) drm_minor_unregister(dev, DRM_MINOR_ACCEL); drm_minor_unregister(dev, DRM_MINOR_PRIMARY); drm_minor_unregister(dev, DRM_MINOR_RENDER); + drm_debugfs_dev_fini(dev); } EXPORT_SYMBOL(drm_dev_unregister); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 340da8257b51..ec1cb4890acb 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -29,6 +29,7 @@ */ #include <linux/bitfield.h> +#include <linux/cec.h> #include <linux/hdmi.h> #include <linux/i2c.h> #include <linux/kernel.h> @@ -3110,7 +3111,7 @@ drm_monitor_supports_rb(const struct drm_edid *drm_edid) return ret; } - return ((drm_edid->edid->input & DRM_EDID_INPUT_DIGITAL) != 0); + return drm_edid_is_digital(drm_edid); } static void @@ -3496,11 +3497,19 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto mode->vsync_end = mode->vsync_start + vsync_pulse_width; mode->vtotal = mode->vdisplay + vblank; - /* Some EDIDs have bogus h/vtotal values */ - if (mode->hsync_end > mode->htotal) - mode->htotal = mode->hsync_end + 1; - if (mode->vsync_end > mode->vtotal) - mode->vtotal = mode->vsync_end + 1; + /* Some EDIDs have bogus h/vsync_end values */ + if (mode->hsync_end > mode->htotal) { + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] reducing hsync_end %d->%d\n", + connector->base.id, connector->name, + mode->hsync_end, mode->htotal); + mode->hsync_end = mode->htotal; + } + if (mode->vsync_end > mode->vtotal) { + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] reducing vsync_end %d->%d\n", + connector->base.id, connector->name, + mode->vsync_end, mode->vtotal); + mode->vsync_end = mode->vtotal; + } drm_mode_do_interlace_quirk(mode, pt); @@ -6192,6 +6201,8 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db) info->is_hdmi = true; + info->source_physical_address = (db[4] << 8) | db[5]; + if (len >= 6) info->dvi_dual = db[6] & 1; if (len >= 7) @@ -6470,6 +6481,8 @@ static void drm_reset_display_info(struct drm_connector *connector) info->vics_len = 0; info->quirks = 0; + + info->source_physical_address = CEC_PHYS_ADDR_INVALID; } static void update_displayid_info(struct drm_connector *connector, @@ -6519,7 +6532,7 @@ static void update_display_info(struct drm_connector *connector, if (edid->revision < 3) goto out; - if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) + if (!drm_edid_is_digital(drm_edid)) goto out; info->color_formats |= DRM_COLOR_FORMAT_RGB444; @@ -7335,3 +7348,16 @@ static void _drm_update_tile_info(struct drm_connector *connector, connector->tile_group = NULL; } } + +/** + * drm_edid_is_digital - is digital? + * @drm_edid: The EDID + * + * Return true if input is digital. + */ +bool drm_edid_is_digital(const struct drm_edid *drm_edid) +{ + return drm_edid && drm_edid->edid && + drm_edid->edid->input & DRM_EDID_INPUT_DIGITAL; +} +EXPORT_SYMBOL(drm_edid_is_digital); diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index ff69cf0fb42a..5d2809de4517 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -56,7 +56,7 @@ static void drm_exec_unlock_all(struct drm_exec *exec) struct drm_gem_object *obj; unsigned long index; - drm_exec_for_each_locked_object(exec, index, obj) { + drm_exec_for_each_locked_object_reverse(exec, index, obj) { dma_resv_unlock(obj->resv); drm_gem_object_put(obj); } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 61a5d450cc20..d612133e2cf7 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -301,7 +301,7 @@ static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn); -static void drm_fb_helper_sysrq(int dummy1) +static void drm_fb_helper_sysrq(u8 dummy1) { schedule_work(&drm_fb_helper_restore_work); } diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 883d83bc0e3d..446458aca8e9 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -160,7 +160,7 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor) /* Get a unique identifier for fdinfo: */ file->client_id = atomic64_inc_return(&ident); - file->pid = get_pid(task_tgid(current)); + rcu_assign_pointer(file->pid, get_pid(task_tgid(current))); file->minor = minor; /* for compatibility root is always authenticated */ @@ -200,7 +200,7 @@ out_prime_destroy: drm_syncobj_release(file); if (drm_core_check_feature(dev, DRIVER_GEM)) drm_gem_release(dev, file); - put_pid(file->pid); + put_pid(rcu_access_pointer(file->pid)); kfree(file); return ERR_PTR(ret); @@ -291,7 +291,7 @@ void drm_file_free(struct drm_file *file) WARN_ON(!list_empty(&file->event_list)); - put_pid(file->pid); + put_pid(rcu_access_pointer(file->pid)); kfree(file); } @@ -505,6 +505,40 @@ int drm_release(struct inode *inode, struct file *filp) } EXPORT_SYMBOL(drm_release); +void drm_file_update_pid(struct drm_file *filp) +{ + struct drm_device *dev; + struct pid *pid, *old; + + /* + * Master nodes need to keep the original ownership in order for + * drm_master_check_perm to keep working correctly. (See comment in + * drm_auth.c.) + */ + if (filp->was_master) + return; + + pid = task_tgid(current); + + /* + * Quick unlocked check since the model is a single handover followed by + * exclusive repeated use. + */ + if (pid == rcu_access_pointer(filp->pid)) + return; + + dev = filp->minor->dev; + mutex_lock(&dev->filelist_mutex); + old = rcu_replace_pointer(filp->pid, pid, 1); + mutex_unlock(&dev->filelist_mutex); + + if (pid != old) { + get_pid(pid); + synchronize_rcu(); + put_pid(old); + } +} + /** * drm_release_noglobal - release method for DRM file * @inode: device inode @@ -930,6 +964,8 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) spin_lock(&file->table_lock); idr_for_each_entry (&file->object_idr, obj, id) { enum drm_gem_object_status s = 0; + size_t add_size = (obj->funcs && obj->funcs->rss) ? + obj->funcs->rss(obj) : obj->size; if (obj->funcs && obj->funcs->status) { s = obj->funcs->status(obj); @@ -944,7 +980,7 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) } if (s & DRM_GEM_OBJECT_RESIDENT) { - status.resident += obj->size; + status.resident += add_size; } else { /* If already purged or not yet backed by pages, don't * count it as purgeable: @@ -953,14 +989,14 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) } if (!dma_resv_test_signaled(obj->resv, dma_resv_usage_rw(true))) { - status.active += obj->size; + status.active += add_size; /* If still active, don't count as purgeable: */ s &= ~DRM_GEM_OBJECT_PURGEABLE; } if (s & DRM_GEM_OBJECT_PURGEABLE) - status.purgeable += obj->size; + status.purgeable += add_size; } spin_unlock(&file->table_lock); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index aff3746dedfb..d3ba0698b84b 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -151,24 +151,6 @@ int drm_mode_addfb_ioctl(struct drm_device *dev, return drm_mode_addfb(dev, data, file_priv); } -static int fb_plane_width(int width, - const struct drm_format_info *format, int plane) -{ - if (plane == 0) - return width; - - return DIV_ROUND_UP(width, format->hsub); -} - -static int fb_plane_height(int height, - const struct drm_format_info *format, int plane) -{ - if (plane == 0) - return height; - - return DIV_ROUND_UP(height, format->vsub); -} - static int framebuffer_check(struct drm_device *dev, const struct drm_mode_fb_cmd2 *r) { @@ -196,8 +178,8 @@ static int framebuffer_check(struct drm_device *dev, info = drm_get_format_info(dev, r); for (i = 0; i < info->num_planes; i++) { - unsigned int width = fb_plane_width(r->width, info, i); - unsigned int height = fb_plane_height(r->height, info, i); + unsigned int width = drm_format_info_plane_width(info, r->width, i); + unsigned int height = drm_format_info_plane_height(info, r->height, i); unsigned int block_size = info->char_per_block[i]; u64 min_pitch = drm_format_info_min_pitch(info, i, width); @@ -1136,44 +1118,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) } EXPORT_SYMBOL(drm_framebuffer_remove); -/** - * drm_framebuffer_plane_width - width of the plane given the first plane - * @width: width of the first plane - * @fb: the framebuffer - * @plane: plane index - * - * Returns: - * The width of @plane, given that the width of the first plane is @width. - */ -int drm_framebuffer_plane_width(int width, - const struct drm_framebuffer *fb, int plane) -{ - if (plane >= fb->format->num_planes) - return 0; - - return fb_plane_width(width, fb->format, plane); -} -EXPORT_SYMBOL(drm_framebuffer_plane_width); - -/** - * drm_framebuffer_plane_height - height of the plane given the first plane - * @height: height of the first plane - * @fb: the framebuffer - * @plane: plane index - * - * Returns: - * The height of @plane, given that the height of the first plane is @height. - */ -int drm_framebuffer_plane_height(int height, - const struct drm_framebuffer *fb, int plane) -{ - if (plane >= fb->format->num_planes) - return 0; - - return fb_plane_height(height, fb->format, plane); -} -EXPORT_SYMBOL(drm_framebuffer_plane_height); - void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, const struct drm_framebuffer *fb) { @@ -1189,8 +1133,8 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, for (i = 0; i < fb->format->num_planes; i++) { drm_printf_indent(p, indent + 1, "size[%u]=%dx%d\n", i, - drm_framebuffer_plane_width(fb->width, fb, i), - drm_framebuffer_plane_height(fb->height, fb, i)); + drm_format_info_plane_width(fb->format, fb->width, i), + drm_format_info_plane_height(fb->format, fb->height, i)); drm_printf_indent(p, indent + 1, "pitch[%u]=%u\n", i, fb->pitches[i]); drm_printf_indent(p, indent + 1, "offset[%u]=%u\n", i, fb->offsets[i]); drm_printf_indent(p, indent + 1, "obj[%u]:%s\n", i, @@ -1222,9 +1166,9 @@ static const struct drm_debugfs_info drm_framebuffer_debugfs_list[] = { { "framebuffer", drm_framebuffer_info, 0 }, }; -void drm_framebuffer_debugfs_init(struct drm_minor *minor) +void drm_framebuffer_debugfs_init(struct drm_device *dev) { - drm_debugfs_add_files(minor->dev, drm_framebuffer_debugfs_list, + drm_debugfs_add_files(dev, drm_framebuffer_debugfs_list, ARRAY_SIZE(drm_framebuffer_debugfs_list)); } #endif diff --git a/drivers/gpu/drm/drm_gpuva_mgr.c b/drivers/gpu/drm/drm_gpuvm.c index ad99c9cfedac..02ce6baacdad 100644 --- a/drivers/gpu/drm/drm_gpuva_mgr.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -25,7 +25,7 @@ * */ -#include <drm/drm_gpuva_mgr.h> +#include <drm/drm_gpuvm.h> #include <linux/interval_tree_generic.h> #include <linux/mm.h> @@ -33,8 +33,8 @@ /** * DOC: Overview * - * The DRM GPU VA Manager, represented by struct drm_gpuva_manager keeps track - * of a GPU's virtual address (VA) space and manages the corresponding virtual + * The DRM GPU VA Manager, represented by struct drm_gpuvm keeps track of a + * GPU's virtual address (VA) space and manages the corresponding virtual * mappings represented by &drm_gpuva objects. It also keeps track of the * mapping's backing &drm_gem_object buffers. * @@ -47,28 +47,28 @@ * The GPU VA manager internally uses a rb-tree to manage the * &drm_gpuva mappings within a GPU's virtual address space. * - * The &drm_gpuva_manager contains a special &drm_gpuva representing the + * The &drm_gpuvm structure contains a special &drm_gpuva representing the * portion of VA space reserved by the kernel. This node is initialized together * with the GPU VA manager instance and removed when the GPU VA manager is * destroyed. * - * In a typical application drivers would embed struct drm_gpuva_manager and + * In a typical application drivers would embed struct drm_gpuvm and * struct drm_gpuva within their own driver specific structures, there won't be * any memory allocations of its own nor memory allocations of &drm_gpuva * entries. * - * The data structures needed to store &drm_gpuvas within the &drm_gpuva_manager - * are contained within struct drm_gpuva already. Hence, for inserting - * &drm_gpuva entries from within dma-fence signalling critical sections it is - * enough to pre-allocate the &drm_gpuva structures. + * The data structures needed to store &drm_gpuvas within the &drm_gpuvm are + * contained within struct drm_gpuva already. Hence, for inserting &drm_gpuva + * entries from within dma-fence signalling critical sections it is enough to + * pre-allocate the &drm_gpuva structures. */ /** * DOC: Split and Merge * * Besides its capability to manage and represent a GPU VA space, the - * &drm_gpuva_manager also provides functions to let the &drm_gpuva_manager - * calculate a sequence of operations to satisfy a given map or unmap request. + * GPU VA manager also provides functions to let the &drm_gpuvm calculate a + * sequence of operations to satisfy a given map or unmap request. * * Therefore the DRM GPU VA manager provides an algorithm implementing splitting * and merging of existent GPU VA mappings with the ones that are requested to @@ -76,16 +76,16 @@ * implement Vulkan 'Sparse Memory Bindings' - drivers UAPIs often refer to this * as VM BIND. * - * Drivers can call drm_gpuva_sm_map() to receive a sequence of callbacks + * Drivers can call drm_gpuvm_sm_map() to receive a sequence of callbacks * containing map, unmap and remap operations for a given newly requested * mapping. The sequence of callbacks represents the set of operations to * execute in order to integrate the new mapping cleanly into the current state * of the GPU VA space. * * Depending on how the new GPU VA mapping intersects with the existent mappings - * of the GPU VA space the &drm_gpuva_fn_ops callbacks contain an arbitrary - * amount of unmap operations, a maximum of two remap operations and a single - * map operation. The caller might receive no callback at all if no operation is + * of the GPU VA space the &drm_gpuvm_ops callbacks contain an arbitrary amount + * of unmap operations, a maximum of two remap operations and a single map + * operation. The caller might receive no callback at all if no operation is * required, e.g. if the requested mapping already exists in the exact same way. * * The single map operation represents the original map operation requested by @@ -95,7 +95,7 @@ * &drm_gpuva to unmap is physically contiguous with the original mapping * request. Optionally, if 'keep' is set, drivers may keep the actual page table * entries for this &drm_gpuva, adding the missing page table entries only and - * update the &drm_gpuva_manager's view of things accordingly. + * update the &drm_gpuvm's view of things accordingly. * * Drivers may do the same optimization, namely delta page table updates, also * for remap operations. This is possible since &drm_gpuva_op_remap consists of @@ -106,34 +106,34 @@ * the beginning and one at the end of the new mapping, hence there is a * maximum of two remap operations. * - * Analogous to drm_gpuva_sm_map() drm_gpuva_sm_unmap() uses &drm_gpuva_fn_ops - * to call back into the driver in order to unmap a range of GPU VA space. The + * Analogous to drm_gpuvm_sm_map() drm_gpuvm_sm_unmap() uses &drm_gpuvm_ops to + * call back into the driver in order to unmap a range of GPU VA space. The * logic behind this function is way simpler though: For all existent mappings * enclosed by the given range unmap operations are created. For mappings which * are only partically located within the given range, remap operations are * created such that those mappings are split up and re-mapped partically. * - * As an alternative to drm_gpuva_sm_map() and drm_gpuva_sm_unmap(), - * drm_gpuva_sm_map_ops_create() and drm_gpuva_sm_unmap_ops_create() can be used + * As an alternative to drm_gpuvm_sm_map() and drm_gpuvm_sm_unmap(), + * drm_gpuvm_sm_map_ops_create() and drm_gpuvm_sm_unmap_ops_create() can be used * to directly obtain an instance of struct drm_gpuva_ops containing a list of * &drm_gpuva_op, which can be iterated with drm_gpuva_for_each_op(). This list * contains the &drm_gpuva_ops analogous to the callbacks one would receive when - * calling drm_gpuva_sm_map() or drm_gpuva_sm_unmap(). While this way requires + * calling drm_gpuvm_sm_map() or drm_gpuvm_sm_unmap(). While this way requires * more memory (to allocate the &drm_gpuva_ops), it provides drivers a way to * iterate the &drm_gpuva_op multiple times, e.g. once in a context where memory * allocations are possible (e.g. to allocate GPU page tables) and once in the * dma-fence signalling critical path. * - * To update the &drm_gpuva_manager's view of the GPU VA space - * drm_gpuva_insert() and drm_gpuva_remove() may be used. These functions can - * safely be used from &drm_gpuva_fn_ops callbacks originating from - * drm_gpuva_sm_map() or drm_gpuva_sm_unmap(). However, it might be more - * convenient to use the provided helper functions drm_gpuva_map(), - * drm_gpuva_remap() and drm_gpuva_unmap() instead. + * To update the &drm_gpuvm's view of the GPU VA space drm_gpuva_insert() and + * drm_gpuva_remove() may be used. These functions can safely be used from + * &drm_gpuvm_ops callbacks originating from drm_gpuvm_sm_map() or + * drm_gpuvm_sm_unmap(). However, it might be more convenient to use the + * provided helper functions drm_gpuva_map(), drm_gpuva_remap() and + * drm_gpuva_unmap() instead. * * The following diagram depicts the basic relationships of existent GPU VA * mappings, a newly requested mapping and the resulting mappings as implemented - * by drm_gpuva_sm_map() - it doesn't cover any arbitrary combinations of these. + * by drm_gpuvm_sm_map() - it doesn't cover any arbitrary combinations of these. * * 1) Requested mapping is identical. Replace it, but indicate the backing PTEs * could be kept. @@ -421,10 +421,10 @@ * // Allocates a new &drm_gpuva. * struct drm_gpuva * driver_gpuva_alloc(void); * - * // Typically drivers would embedd the &drm_gpuva_manager and &drm_gpuva + * // Typically drivers would embedd the &drm_gpuvm and &drm_gpuva * // structure in individual driver structures and lock the dma-resv with * // drm_exec or similar helpers. - * int driver_mapping_create(struct drm_gpuva_manager *mgr, + * int driver_mapping_create(struct drm_gpuvm *gpuvm, * u64 addr, u64 range, * struct drm_gem_object *obj, u64 offset) * { @@ -432,7 +432,7 @@ * struct drm_gpuva_op *op * * driver_lock_va_space(); - * ops = drm_gpuva_sm_map_ops_create(mgr, addr, range, + * ops = drm_gpuvm_sm_map_ops_create(gpuvm, addr, range, * obj, offset); * if (IS_ERR(ops)) * return PTR_ERR(ops); @@ -448,7 +448,7 @@ * // free memory and unlock * * driver_vm_map(); - * drm_gpuva_map(mgr, va, &op->map); + * drm_gpuva_map(gpuvm, va, &op->map); * drm_gpuva_link(va); * * break; @@ -504,23 +504,23 @@ * 2) Receive a callback for each &drm_gpuva_op to create a new mapping:: * * struct driver_context { - * struct drm_gpuva_manager *mgr; + * struct drm_gpuvm *gpuvm; * struct drm_gpuva *new_va; * struct drm_gpuva *prev_va; * struct drm_gpuva *next_va; * }; * - * // ops to pass to drm_gpuva_manager_init() - * static const struct drm_gpuva_fn_ops driver_gpuva_ops = { + * // ops to pass to drm_gpuvm_init() + * static const struct drm_gpuvm_ops driver_gpuvm_ops = { * .sm_step_map = driver_gpuva_map, * .sm_step_remap = driver_gpuva_remap, * .sm_step_unmap = driver_gpuva_unmap, * }; * - * // Typically drivers would embedd the &drm_gpuva_manager and &drm_gpuva + * // Typically drivers would embedd the &drm_gpuvm and &drm_gpuva * // structure in individual driver structures and lock the dma-resv with * // drm_exec or similar helpers. - * int driver_mapping_create(struct drm_gpuva_manager *mgr, + * int driver_mapping_create(struct drm_gpuvm *gpuvm, * u64 addr, u64 range, * struct drm_gem_object *obj, u64 offset) * { @@ -529,7 +529,7 @@ * struct drm_gpuva_op *op; * int ret = 0; * - * ctx.mgr = mgr; + * ctx.gpuvm = gpuvm; * * ctx.new_va = kzalloc(sizeof(*ctx.new_va), GFP_KERNEL); * ctx.prev_va = kzalloc(sizeof(*ctx.prev_va), GFP_KERNEL); @@ -540,7 +540,7 @@ * } * * driver_lock_va_space(); - * ret = drm_gpuva_sm_map(mgr, &ctx, addr, range, obj, offset); + * ret = drm_gpuvm_sm_map(gpuvm, &ctx, addr, range, obj, offset); * driver_unlock_va_space(); * * out: @@ -554,7 +554,7 @@ * { * struct driver_context *ctx = __ctx; * - * drm_gpuva_map(ctx->mgr, ctx->new_va, &op->map); + * drm_gpuva_map(ctx->vm, ctx->new_va, &op->map); * * drm_gpuva_link(ctx->new_va); * @@ -609,12 +609,12 @@ INTERVAL_TREE_DEFINE(struct drm_gpuva, rb.node, u64, rb.__subtree_last, GPUVA_START, GPUVA_LAST, static __maybe_unused, drm_gpuva_it) -static int __drm_gpuva_insert(struct drm_gpuva_manager *mgr, +static int __drm_gpuva_insert(struct drm_gpuvm *gpuvm, struct drm_gpuva *va); static void __drm_gpuva_remove(struct drm_gpuva *va); static bool -drm_gpuva_check_overflow(u64 addr, u64 range) +drm_gpuvm_check_overflow(u64 addr, u64 range) { u64 end; @@ -623,121 +623,121 @@ drm_gpuva_check_overflow(u64 addr, u64 range) } static bool -drm_gpuva_in_mm_range(struct drm_gpuva_manager *mgr, u64 addr, u64 range) +drm_gpuvm_in_mm_range(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { u64 end = addr + range; - u64 mm_start = mgr->mm_start; - u64 mm_end = mm_start + mgr->mm_range; + u64 mm_start = gpuvm->mm_start; + u64 mm_end = mm_start + gpuvm->mm_range; return addr >= mm_start && end <= mm_end; } static bool -drm_gpuva_in_kernel_node(struct drm_gpuva_manager *mgr, u64 addr, u64 range) +drm_gpuvm_in_kernel_node(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { u64 end = addr + range; - u64 kstart = mgr->kernel_alloc_node.va.addr; - u64 krange = mgr->kernel_alloc_node.va.range; + u64 kstart = gpuvm->kernel_alloc_node.va.addr; + u64 krange = gpuvm->kernel_alloc_node.va.range; u64 kend = kstart + krange; return krange && addr < kend && kstart < end; } static bool -drm_gpuva_range_valid(struct drm_gpuva_manager *mgr, +drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { - return !drm_gpuva_check_overflow(addr, range) && - drm_gpuva_in_mm_range(mgr, addr, range) && - !drm_gpuva_in_kernel_node(mgr, addr, range); + return !drm_gpuvm_check_overflow(addr, range) && + drm_gpuvm_in_mm_range(gpuvm, addr, range) && + !drm_gpuvm_in_kernel_node(gpuvm, addr, range); } /** - * drm_gpuva_manager_init() - initialize a &drm_gpuva_manager - * @mgr: pointer to the &drm_gpuva_manager to initialize + * drm_gpuvm_init() - initialize a &drm_gpuvm + * @gpuvm: pointer to the &drm_gpuvm to initialize * @name: the name of the GPU VA space * @start_offset: the start offset of the GPU VA space * @range: the size of the GPU VA space * @reserve_offset: the start of the kernel reserved GPU VA area * @reserve_range: the size of the kernel reserved GPU VA area - * @ops: &drm_gpuva_fn_ops called on &drm_gpuva_sm_map / &drm_gpuva_sm_unmap + * @ops: &drm_gpuvm_ops called on &drm_gpuvm_sm_map / &drm_gpuvm_sm_unmap * - * The &drm_gpuva_manager must be initialized with this function before use. + * The &drm_gpuvm must be initialized with this function before use. * - * Note that @mgr must be cleared to 0 before calling this function. The given + * Note that @gpuvm must be cleared to 0 before calling this function. The given * &name is expected to be managed by the surrounding driver structures. */ void -drm_gpuva_manager_init(struct drm_gpuva_manager *mgr, - const char *name, - u64 start_offset, u64 range, - u64 reserve_offset, u64 reserve_range, - const struct drm_gpuva_fn_ops *ops) +drm_gpuvm_init(struct drm_gpuvm *gpuvm, + const char *name, + u64 start_offset, u64 range, + u64 reserve_offset, u64 reserve_range, + const struct drm_gpuvm_ops *ops) { - mgr->rb.tree = RB_ROOT_CACHED; - INIT_LIST_HEAD(&mgr->rb.list); + gpuvm->rb.tree = RB_ROOT_CACHED; + INIT_LIST_HEAD(&gpuvm->rb.list); - drm_gpuva_check_overflow(start_offset, range); - mgr->mm_start = start_offset; - mgr->mm_range = range; + drm_gpuvm_check_overflow(start_offset, range); + gpuvm->mm_start = start_offset; + gpuvm->mm_range = range; - mgr->name = name ? name : "unknown"; - mgr->ops = ops; + gpuvm->name = name ? name : "unknown"; + gpuvm->ops = ops; - memset(&mgr->kernel_alloc_node, 0, sizeof(struct drm_gpuva)); + memset(&gpuvm->kernel_alloc_node, 0, sizeof(struct drm_gpuva)); if (reserve_range) { - mgr->kernel_alloc_node.va.addr = reserve_offset; - mgr->kernel_alloc_node.va.range = reserve_range; + gpuvm->kernel_alloc_node.va.addr = reserve_offset; + gpuvm->kernel_alloc_node.va.range = reserve_range; - if (likely(!drm_gpuva_check_overflow(reserve_offset, + if (likely(!drm_gpuvm_check_overflow(reserve_offset, reserve_range))) - __drm_gpuva_insert(mgr, &mgr->kernel_alloc_node); + __drm_gpuva_insert(gpuvm, &gpuvm->kernel_alloc_node); } } -EXPORT_SYMBOL_GPL(drm_gpuva_manager_init); +EXPORT_SYMBOL_GPL(drm_gpuvm_init); /** - * drm_gpuva_manager_destroy() - cleanup a &drm_gpuva_manager - * @mgr: pointer to the &drm_gpuva_manager to clean up + * drm_gpuvm_destroy() - cleanup a &drm_gpuvm + * @gpuvm: pointer to the &drm_gpuvm to clean up * * Note that it is a bug to call this function on a manager that still * holds GPU VA mappings. */ void -drm_gpuva_manager_destroy(struct drm_gpuva_manager *mgr) +drm_gpuvm_destroy(struct drm_gpuvm *gpuvm) { - mgr->name = NULL; + gpuvm->name = NULL; - if (mgr->kernel_alloc_node.va.range) - __drm_gpuva_remove(&mgr->kernel_alloc_node); + if (gpuvm->kernel_alloc_node.va.range) + __drm_gpuva_remove(&gpuvm->kernel_alloc_node); - WARN(!RB_EMPTY_ROOT(&mgr->rb.tree.rb_root), + WARN(!RB_EMPTY_ROOT(&gpuvm->rb.tree.rb_root), "GPUVA tree is not empty, potentially leaking memory."); } -EXPORT_SYMBOL_GPL(drm_gpuva_manager_destroy); +EXPORT_SYMBOL_GPL(drm_gpuvm_destroy); static int -__drm_gpuva_insert(struct drm_gpuva_manager *mgr, +__drm_gpuva_insert(struct drm_gpuvm *gpuvm, struct drm_gpuva *va) { struct rb_node *node; struct list_head *head; - if (drm_gpuva_it_iter_first(&mgr->rb.tree, + if (drm_gpuva_it_iter_first(&gpuvm->rb.tree, GPUVA_START(va), GPUVA_LAST(va))) return -EEXIST; - va->mgr = mgr; + va->vm = gpuvm; - drm_gpuva_it_insert(va, &mgr->rb.tree); + drm_gpuva_it_insert(va, &gpuvm->rb.tree); node = rb_prev(&va->rb.node); if (node) head = &(to_drm_gpuva(node))->rb.entry; else - head = &mgr->rb.list; + head = &gpuvm->rb.list; list_add(&va->rb.entry, head); @@ -746,36 +746,36 @@ __drm_gpuva_insert(struct drm_gpuva_manager *mgr, /** * drm_gpuva_insert() - insert a &drm_gpuva - * @mgr: the &drm_gpuva_manager to insert the &drm_gpuva in + * @gpuvm: the &drm_gpuvm to insert the &drm_gpuva in * @va: the &drm_gpuva to insert * * Insert a &drm_gpuva with a given address and range into a - * &drm_gpuva_manager. + * &drm_gpuvm. * * It is safe to use this function using the safe versions of iterating the GPU - * VA space, such as drm_gpuva_for_each_va_safe() and - * drm_gpuva_for_each_va_range_safe(). + * VA space, such as drm_gpuvm_for_each_va_safe() and + * drm_gpuvm_for_each_va_range_safe(). * * Returns: 0 on success, negative error code on failure. */ int -drm_gpuva_insert(struct drm_gpuva_manager *mgr, +drm_gpuva_insert(struct drm_gpuvm *gpuvm, struct drm_gpuva *va) { u64 addr = va->va.addr; u64 range = va->va.range; - if (unlikely(!drm_gpuva_range_valid(mgr, addr, range))) + if (unlikely(!drm_gpuvm_range_valid(gpuvm, addr, range))) return -EINVAL; - return __drm_gpuva_insert(mgr, va); + return __drm_gpuva_insert(gpuvm, va); } EXPORT_SYMBOL_GPL(drm_gpuva_insert); static void __drm_gpuva_remove(struct drm_gpuva *va) { - drm_gpuva_it_remove(va, &va->mgr->rb.tree); + drm_gpuva_it_remove(va, &va->vm->rb.tree); list_del_init(&va->rb.entry); } @@ -786,15 +786,15 @@ __drm_gpuva_remove(struct drm_gpuva *va) * This removes the given &va from the underlaying tree. * * It is safe to use this function using the safe versions of iterating the GPU - * VA space, such as drm_gpuva_for_each_va_safe() and - * drm_gpuva_for_each_va_range_safe(). + * VA space, such as drm_gpuvm_for_each_va_safe() and + * drm_gpuvm_for_each_va_range_safe(). */ void drm_gpuva_remove(struct drm_gpuva *va) { - struct drm_gpuva_manager *mgr = va->mgr; + struct drm_gpuvm *gpuvm = va->vm; - if (unlikely(va == &mgr->kernel_alloc_node)) { + if (unlikely(va == &gpuvm->kernel_alloc_node)) { WARN(1, "Can't destroy kernel reserved node.\n"); return; } @@ -853,37 +853,37 @@ EXPORT_SYMBOL_GPL(drm_gpuva_unlink); /** * drm_gpuva_find_first() - find the first &drm_gpuva in the given range - * @mgr: the &drm_gpuva_manager to search in + * @gpuvm: the &drm_gpuvm to search in * @addr: the &drm_gpuvas address * @range: the &drm_gpuvas range * * Returns: the first &drm_gpuva within the given range */ struct drm_gpuva * -drm_gpuva_find_first(struct drm_gpuva_manager *mgr, +drm_gpuva_find_first(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { u64 last = addr + range - 1; - return drm_gpuva_it_iter_first(&mgr->rb.tree, addr, last); + return drm_gpuva_it_iter_first(&gpuvm->rb.tree, addr, last); } EXPORT_SYMBOL_GPL(drm_gpuva_find_first); /** * drm_gpuva_find() - find a &drm_gpuva - * @mgr: the &drm_gpuva_manager to search in + * @gpuvm: the &drm_gpuvm to search in * @addr: the &drm_gpuvas address * @range: the &drm_gpuvas range * * Returns: the &drm_gpuva at a given &addr and with a given &range */ struct drm_gpuva * -drm_gpuva_find(struct drm_gpuva_manager *mgr, +drm_gpuva_find(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { struct drm_gpuva *va; - va = drm_gpuva_find_first(mgr, addr, range); + va = drm_gpuva_find_first(gpuvm, addr, range); if (!va) goto out; @@ -900,7 +900,7 @@ EXPORT_SYMBOL_GPL(drm_gpuva_find); /** * drm_gpuva_find_prev() - find the &drm_gpuva before the given address - * @mgr: the &drm_gpuva_manager to search in + * @gpuvm: the &drm_gpuvm to search in * @start: the given GPU VA's start address * * Find the adjacent &drm_gpuva before the GPU VA with given &start address. @@ -911,18 +911,18 @@ EXPORT_SYMBOL_GPL(drm_gpuva_find); * Returns: a pointer to the found &drm_gpuva or NULL if none was found */ struct drm_gpuva * -drm_gpuva_find_prev(struct drm_gpuva_manager *mgr, u64 start) +drm_gpuva_find_prev(struct drm_gpuvm *gpuvm, u64 start) { - if (!drm_gpuva_range_valid(mgr, start - 1, 1)) + if (!drm_gpuvm_range_valid(gpuvm, start - 1, 1)) return NULL; - return drm_gpuva_it_iter_first(&mgr->rb.tree, start - 1, start); + return drm_gpuva_it_iter_first(&gpuvm->rb.tree, start - 1, start); } EXPORT_SYMBOL_GPL(drm_gpuva_find_prev); /** * drm_gpuva_find_next() - find the &drm_gpuva after the given address - * @mgr: the &drm_gpuva_manager to search in + * @gpuvm: the &drm_gpuvm to search in * @end: the given GPU VA's end address * * Find the adjacent &drm_gpuva after the GPU VA with given &end address. @@ -933,47 +933,47 @@ EXPORT_SYMBOL_GPL(drm_gpuva_find_prev); * Returns: a pointer to the found &drm_gpuva or NULL if none was found */ struct drm_gpuva * -drm_gpuva_find_next(struct drm_gpuva_manager *mgr, u64 end) +drm_gpuva_find_next(struct drm_gpuvm *gpuvm, u64 end) { - if (!drm_gpuva_range_valid(mgr, end, 1)) + if (!drm_gpuvm_range_valid(gpuvm, end, 1)) return NULL; - return drm_gpuva_it_iter_first(&mgr->rb.tree, end, end + 1); + return drm_gpuva_it_iter_first(&gpuvm->rb.tree, end, end + 1); } EXPORT_SYMBOL_GPL(drm_gpuva_find_next); /** - * drm_gpuva_interval_empty() - indicate whether a given interval of the VA space + * drm_gpuvm_interval_empty() - indicate whether a given interval of the VA space * is empty - * @mgr: the &drm_gpuva_manager to check the range for + * @gpuvm: the &drm_gpuvm to check the range for * @addr: the start address of the range * @range: the range of the interval * * Returns: true if the interval is empty, false otherwise */ bool -drm_gpuva_interval_empty(struct drm_gpuva_manager *mgr, u64 addr, u64 range) +drm_gpuvm_interval_empty(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { - return !drm_gpuva_find_first(mgr, addr, range); + return !drm_gpuva_find_first(gpuvm, addr, range); } -EXPORT_SYMBOL_GPL(drm_gpuva_interval_empty); +EXPORT_SYMBOL_GPL(drm_gpuvm_interval_empty); /** * drm_gpuva_map() - helper to insert a &drm_gpuva according to a * &drm_gpuva_op_map - * @mgr: the &drm_gpuva_manager + * @gpuvm: the &drm_gpuvm * @va: the &drm_gpuva to insert * @op: the &drm_gpuva_op_map to initialize @va with * - * Initializes the @va from the @op and inserts it into the given @mgr. + * Initializes the @va from the @op and inserts it into the given @gpuvm. */ void -drm_gpuva_map(struct drm_gpuva_manager *mgr, +drm_gpuva_map(struct drm_gpuvm *gpuvm, struct drm_gpuva *va, struct drm_gpuva_op_map *op) { drm_gpuva_init_from_op(va, op); - drm_gpuva_insert(mgr, va); + drm_gpuva_insert(gpuvm, va); } EXPORT_SYMBOL_GPL(drm_gpuva_map); @@ -993,18 +993,18 @@ drm_gpuva_remap(struct drm_gpuva *prev, struct drm_gpuva_op_remap *op) { struct drm_gpuva *curr = op->unmap->va; - struct drm_gpuva_manager *mgr = curr->mgr; + struct drm_gpuvm *gpuvm = curr->vm; drm_gpuva_remove(curr); if (op->prev) { drm_gpuva_init_from_op(prev, op->prev); - drm_gpuva_insert(mgr, prev); + drm_gpuva_insert(gpuvm, prev); } if (op->next) { drm_gpuva_init_from_op(next, op->next); - drm_gpuva_insert(mgr, next); + drm_gpuva_insert(gpuvm, next); } } EXPORT_SYMBOL_GPL(drm_gpuva_remap); @@ -1024,7 +1024,7 @@ drm_gpuva_unmap(struct drm_gpuva_op_unmap *op) EXPORT_SYMBOL_GPL(drm_gpuva_unmap); static int -op_map_cb(const struct drm_gpuva_fn_ops *fn, void *priv, +op_map_cb(const struct drm_gpuvm_ops *fn, void *priv, u64 addr, u64 range, struct drm_gem_object *obj, u64 offset) { @@ -1040,7 +1040,7 @@ op_map_cb(const struct drm_gpuva_fn_ops *fn, void *priv, } static int -op_remap_cb(const struct drm_gpuva_fn_ops *fn, void *priv, +op_remap_cb(const struct drm_gpuvm_ops *fn, void *priv, struct drm_gpuva_op_map *prev, struct drm_gpuva_op_map *next, struct drm_gpuva_op_unmap *unmap) @@ -1058,7 +1058,7 @@ op_remap_cb(const struct drm_gpuva_fn_ops *fn, void *priv, } static int -op_unmap_cb(const struct drm_gpuva_fn_ops *fn, void *priv, +op_unmap_cb(const struct drm_gpuvm_ops *fn, void *priv, struct drm_gpuva *va, bool merge) { struct drm_gpuva_op op = {}; @@ -1071,8 +1071,8 @@ op_unmap_cb(const struct drm_gpuva_fn_ops *fn, void *priv, } static int -__drm_gpuva_sm_map(struct drm_gpuva_manager *mgr, - const struct drm_gpuva_fn_ops *ops, void *priv, +__drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, + const struct drm_gpuvm_ops *ops, void *priv, u64 req_addr, u64 req_range, struct drm_gem_object *req_obj, u64 req_offset) { @@ -1080,10 +1080,10 @@ __drm_gpuva_sm_map(struct drm_gpuva_manager *mgr, u64 req_end = req_addr + req_range; int ret; - if (unlikely(!drm_gpuva_range_valid(mgr, req_addr, req_range))) + if (unlikely(!drm_gpuvm_range_valid(gpuvm, req_addr, req_range))) return -EINVAL; - drm_gpuva_for_each_va_range_safe(va, next, mgr, req_addr, req_end) { + drm_gpuvm_for_each_va_range_safe(va, next, gpuvm, req_addr, req_end) { struct drm_gem_object *obj = va->gem.obj; u64 offset = va->gem.offset; u64 addr = va->va.addr; @@ -1213,18 +1213,18 @@ __drm_gpuva_sm_map(struct drm_gpuva_manager *mgr, } static int -__drm_gpuva_sm_unmap(struct drm_gpuva_manager *mgr, - const struct drm_gpuva_fn_ops *ops, void *priv, +__drm_gpuvm_sm_unmap(struct drm_gpuvm *gpuvm, + const struct drm_gpuvm_ops *ops, void *priv, u64 req_addr, u64 req_range) { struct drm_gpuva *va, *next; u64 req_end = req_addr + req_range; int ret; - if (unlikely(!drm_gpuva_range_valid(mgr, req_addr, req_range))) + if (unlikely(!drm_gpuvm_range_valid(gpuvm, req_addr, req_range))) return -EINVAL; - drm_gpuva_for_each_va_range_safe(va, next, mgr, req_addr, req_end) { + drm_gpuvm_for_each_va_range_safe(va, next, gpuvm, req_addr, req_end) { struct drm_gpuva_op_map prev = {}, next = {}; bool prev_split = false, next_split = false; struct drm_gem_object *obj = va->gem.obj; @@ -1271,8 +1271,8 @@ __drm_gpuva_sm_unmap(struct drm_gpuva_manager *mgr, } /** - * drm_gpuva_sm_map() - creates the &drm_gpuva_op split/merge steps - * @mgr: the &drm_gpuva_manager representing the GPU VA space + * drm_gpuvm_sm_map() - creates the &drm_gpuva_op split/merge steps + * @gpuvm: the &drm_gpuvm representing the GPU VA space * @req_addr: the start address of the new mapping * @req_range: the range of the new mapping * @req_obj: the &drm_gem_object to map @@ -1280,15 +1280,15 @@ __drm_gpuva_sm_unmap(struct drm_gpuva_manager *mgr, * @priv: pointer to a driver private data structure * * This function iterates the given range of the GPU VA space. It utilizes the - * &drm_gpuva_fn_ops to call back into the driver providing the split and merge + * &drm_gpuvm_ops to call back into the driver providing the split and merge * steps. * * Drivers may use these callbacks to update the GPU VA space right away within * the callback. In case the driver decides to copy and store the operations for - * later processing neither this function nor &drm_gpuva_sm_unmap is allowed to - * be called before the &drm_gpuva_manager's view of the GPU VA space was + * later processing neither this function nor &drm_gpuvm_sm_unmap is allowed to + * be called before the &drm_gpuvm's view of the GPU VA space was * updated with the previous set of operations. To update the - * &drm_gpuva_manager's view of the GPU VA space drm_gpuva_insert(), + * &drm_gpuvm's view of the GPU VA space drm_gpuva_insert(), * drm_gpuva_destroy_locked() and/or drm_gpuva_destroy_unlocked() should be * used. * @@ -1303,39 +1303,39 @@ __drm_gpuva_sm_unmap(struct drm_gpuva_manager *mgr, * Returns: 0 on success or a negative error code */ int -drm_gpuva_sm_map(struct drm_gpuva_manager *mgr, void *priv, +drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, void *priv, u64 req_addr, u64 req_range, struct drm_gem_object *req_obj, u64 req_offset) { - const struct drm_gpuva_fn_ops *ops = mgr->ops; + const struct drm_gpuvm_ops *ops = gpuvm->ops; if (unlikely(!(ops && ops->sm_step_map && ops->sm_step_remap && ops->sm_step_unmap))) return -EINVAL; - return __drm_gpuva_sm_map(mgr, ops, priv, + return __drm_gpuvm_sm_map(gpuvm, ops, priv, req_addr, req_range, req_obj, req_offset); } -EXPORT_SYMBOL_GPL(drm_gpuva_sm_map); +EXPORT_SYMBOL_GPL(drm_gpuvm_sm_map); /** - * drm_gpuva_sm_unmap() - creates the &drm_gpuva_ops to split on unmap - * @mgr: the &drm_gpuva_manager representing the GPU VA space + * drm_gpuvm_sm_unmap() - creates the &drm_gpuva_ops to split on unmap + * @gpuvm: the &drm_gpuvm representing the GPU VA space * @priv: pointer to a driver private data structure * @req_addr: the start address of the range to unmap * @req_range: the range of the mappings to unmap * * This function iterates the given range of the GPU VA space. It utilizes the - * &drm_gpuva_fn_ops to call back into the driver providing the operations to + * &drm_gpuvm_ops to call back into the driver providing the operations to * unmap and, if required, split existent mappings. * * Drivers may use these callbacks to update the GPU VA space right away within * the callback. In case the driver decides to copy and store the operations for - * later processing neither this function nor &drm_gpuva_sm_map is allowed to be - * called before the &drm_gpuva_manager's view of the GPU VA space was updated - * with the previous set of operations. To update the &drm_gpuva_manager's view + * later processing neither this function nor &drm_gpuvm_sm_map is allowed to be + * called before the &drm_gpuvm's view of the GPU VA space was updated + * with the previous set of operations. To update the &drm_gpuvm's view * of the GPU VA space drm_gpuva_insert(), drm_gpuva_destroy_locked() and/or * drm_gpuva_destroy_unlocked() should be used. * @@ -1348,24 +1348,24 @@ EXPORT_SYMBOL_GPL(drm_gpuva_sm_map); * Returns: 0 on success or a negative error code */ int -drm_gpuva_sm_unmap(struct drm_gpuva_manager *mgr, void *priv, +drm_gpuvm_sm_unmap(struct drm_gpuvm *gpuvm, void *priv, u64 req_addr, u64 req_range) { - const struct drm_gpuva_fn_ops *ops = mgr->ops; + const struct drm_gpuvm_ops *ops = gpuvm->ops; if (unlikely(!(ops && ops->sm_step_remap && ops->sm_step_unmap))) return -EINVAL; - return __drm_gpuva_sm_unmap(mgr, ops, priv, + return __drm_gpuvm_sm_unmap(gpuvm, ops, priv, req_addr, req_range); } -EXPORT_SYMBOL_GPL(drm_gpuva_sm_unmap); +EXPORT_SYMBOL_GPL(drm_gpuvm_sm_unmap); static struct drm_gpuva_op * -gpuva_op_alloc(struct drm_gpuva_manager *mgr) +gpuva_op_alloc(struct drm_gpuvm *gpuvm) { - const struct drm_gpuva_fn_ops *fn = mgr->ops; + const struct drm_gpuvm_ops *fn = gpuvm->ops; struct drm_gpuva_op *op; if (fn && fn->op_alloc) @@ -1380,10 +1380,10 @@ gpuva_op_alloc(struct drm_gpuva_manager *mgr) } static void -gpuva_op_free(struct drm_gpuva_manager *mgr, +gpuva_op_free(struct drm_gpuvm *gpuvm, struct drm_gpuva_op *op) { - const struct drm_gpuva_fn_ops *fn = mgr->ops; + const struct drm_gpuvm_ops *fn = gpuvm->ops; if (fn && fn->op_free) fn->op_free(op); @@ -1396,14 +1396,14 @@ drm_gpuva_sm_step(struct drm_gpuva_op *__op, void *priv) { struct { - struct drm_gpuva_manager *mgr; + struct drm_gpuvm *vm; struct drm_gpuva_ops *ops; } *args = priv; - struct drm_gpuva_manager *mgr = args->mgr; + struct drm_gpuvm *gpuvm = args->vm; struct drm_gpuva_ops *ops = args->ops; struct drm_gpuva_op *op; - op = gpuva_op_alloc(mgr); + op = gpuva_op_alloc(gpuvm); if (unlikely(!op)) goto err; @@ -1442,20 +1442,20 @@ err_free_unmap: err_free_prev: kfree(op->remap.prev); err_free_op: - gpuva_op_free(mgr, op); + gpuva_op_free(gpuvm, op); err: return -ENOMEM; } -static const struct drm_gpuva_fn_ops gpuva_list_ops = { +static const struct drm_gpuvm_ops gpuvm_list_ops = { .sm_step_map = drm_gpuva_sm_step, .sm_step_remap = drm_gpuva_sm_step, .sm_step_unmap = drm_gpuva_sm_step, }; /** - * drm_gpuva_sm_map_ops_create() - creates the &drm_gpuva_ops to split and merge - * @mgr: the &drm_gpuva_manager representing the GPU VA space + * drm_gpuvm_sm_map_ops_create() - creates the &drm_gpuva_ops to split and merge + * @gpuvm: the &drm_gpuvm representing the GPU VA space * @req_addr: the start address of the new mapping * @req_range: the range of the new mapping * @req_obj: the &drm_gem_object to map @@ -1474,9 +1474,9 @@ static const struct drm_gpuva_fn_ops gpuva_list_ops = { * map operation requested by the caller. * * Note that before calling this function again with another mapping request it - * is necessary to update the &drm_gpuva_manager's view of the GPU VA space. The + * is necessary to update the &drm_gpuvm's view of the GPU VA space. The * previously obtained operations must be either processed or abandoned. To - * update the &drm_gpuva_manager's view of the GPU VA space drm_gpuva_insert(), + * update the &drm_gpuvm's view of the GPU VA space drm_gpuva_insert(), * drm_gpuva_destroy_locked() and/or drm_gpuva_destroy_unlocked() should be * used. * @@ -1486,13 +1486,13 @@ static const struct drm_gpuva_fn_ops gpuva_list_ops = { * Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure */ struct drm_gpuva_ops * -drm_gpuva_sm_map_ops_create(struct drm_gpuva_manager *mgr, +drm_gpuvm_sm_map_ops_create(struct drm_gpuvm *gpuvm, u64 req_addr, u64 req_range, struct drm_gem_object *req_obj, u64 req_offset) { struct drm_gpuva_ops *ops; struct { - struct drm_gpuva_manager *mgr; + struct drm_gpuvm *vm; struct drm_gpuva_ops *ops; } args; int ret; @@ -1503,10 +1503,10 @@ drm_gpuva_sm_map_ops_create(struct drm_gpuva_manager *mgr, INIT_LIST_HEAD(&ops->list); - args.mgr = mgr; + args.vm = gpuvm; args.ops = ops; - ret = __drm_gpuva_sm_map(mgr, &gpuva_list_ops, &args, + ret = __drm_gpuvm_sm_map(gpuvm, &gpuvm_list_ops, &args, req_addr, req_range, req_obj, req_offset); if (ret) @@ -1515,15 +1515,15 @@ drm_gpuva_sm_map_ops_create(struct drm_gpuva_manager *mgr, return ops; err_free_ops: - drm_gpuva_ops_free(mgr, ops); + drm_gpuva_ops_free(gpuvm, ops); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_gpuva_sm_map_ops_create); +EXPORT_SYMBOL_GPL(drm_gpuvm_sm_map_ops_create); /** - * drm_gpuva_sm_unmap_ops_create() - creates the &drm_gpuva_ops to split on + * drm_gpuvm_sm_unmap_ops_create() - creates the &drm_gpuva_ops to split on * unmap - * @mgr: the &drm_gpuva_manager representing the GPU VA space + * @gpuvm: the &drm_gpuvm representing the GPU VA space * @req_addr: the start address of the range to unmap * @req_range: the range of the mappings to unmap * @@ -1538,9 +1538,9 @@ EXPORT_SYMBOL_GPL(drm_gpuva_sm_map_ops_create); * remap operations. * * Note that before calling this function again with another range to unmap it - * is necessary to update the &drm_gpuva_manager's view of the GPU VA space. The + * is necessary to update the &drm_gpuvm's view of the GPU VA space. The * previously obtained operations must be processed or abandoned. To update the - * &drm_gpuva_manager's view of the GPU VA space drm_gpuva_insert(), + * &drm_gpuvm's view of the GPU VA space drm_gpuva_insert(), * drm_gpuva_destroy_locked() and/or drm_gpuva_destroy_unlocked() should be * used. * @@ -1550,12 +1550,12 @@ EXPORT_SYMBOL_GPL(drm_gpuva_sm_map_ops_create); * Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure */ struct drm_gpuva_ops * -drm_gpuva_sm_unmap_ops_create(struct drm_gpuva_manager *mgr, +drm_gpuvm_sm_unmap_ops_create(struct drm_gpuvm *gpuvm, u64 req_addr, u64 req_range) { struct drm_gpuva_ops *ops; struct { - struct drm_gpuva_manager *mgr; + struct drm_gpuvm *vm; struct drm_gpuva_ops *ops; } args; int ret; @@ -1566,10 +1566,10 @@ drm_gpuva_sm_unmap_ops_create(struct drm_gpuva_manager *mgr, INIT_LIST_HEAD(&ops->list); - args.mgr = mgr; + args.vm = gpuvm; args.ops = ops; - ret = __drm_gpuva_sm_unmap(mgr, &gpuva_list_ops, &args, + ret = __drm_gpuvm_sm_unmap(gpuvm, &gpuvm_list_ops, &args, req_addr, req_range); if (ret) goto err_free_ops; @@ -1577,14 +1577,14 @@ drm_gpuva_sm_unmap_ops_create(struct drm_gpuva_manager *mgr, return ops; err_free_ops: - drm_gpuva_ops_free(mgr, ops); + drm_gpuva_ops_free(gpuvm, ops); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_gpuva_sm_unmap_ops_create); +EXPORT_SYMBOL_GPL(drm_gpuvm_sm_unmap_ops_create); /** - * drm_gpuva_prefetch_ops_create() - creates the &drm_gpuva_ops to prefetch - * @mgr: the &drm_gpuva_manager representing the GPU VA space + * drm_gpuvm_prefetch_ops_create() - creates the &drm_gpuva_ops to prefetch + * @gpuvm: the &drm_gpuvm representing the GPU VA space * @addr: the start address of the range to prefetch * @range: the range of the mappings to prefetch * @@ -1601,7 +1601,7 @@ EXPORT_SYMBOL_GPL(drm_gpuva_sm_unmap_ops_create); * Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure */ struct drm_gpuva_ops * -drm_gpuva_prefetch_ops_create(struct drm_gpuva_manager *mgr, +drm_gpuvm_prefetch_ops_create(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { struct drm_gpuva_ops *ops; @@ -1616,8 +1616,8 @@ drm_gpuva_prefetch_ops_create(struct drm_gpuva_manager *mgr, INIT_LIST_HEAD(&ops->list); - drm_gpuva_for_each_va_range(va, mgr, addr, end) { - op = gpuva_op_alloc(mgr); + drm_gpuvm_for_each_va_range(va, gpuvm, addr, end) { + op = gpuva_op_alloc(gpuvm); if (!op) { ret = -ENOMEM; goto err_free_ops; @@ -1631,14 +1631,14 @@ drm_gpuva_prefetch_ops_create(struct drm_gpuva_manager *mgr, return ops; err_free_ops: - drm_gpuva_ops_free(mgr, ops); + drm_gpuva_ops_free(gpuvm, ops); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_gpuva_prefetch_ops_create); +EXPORT_SYMBOL_GPL(drm_gpuvm_prefetch_ops_create); /** - * drm_gpuva_gem_unmap_ops_create() - creates the &drm_gpuva_ops to unmap a GEM - * @mgr: the &drm_gpuva_manager representing the GPU VA space + * drm_gpuvm_gem_unmap_ops_create() - creates the &drm_gpuva_ops to unmap a GEM + * @gpuvm: the &drm_gpuvm representing the GPU VA space * @obj: the &drm_gem_object to unmap * * This function creates a list of operations to perform unmapping for every @@ -1656,7 +1656,7 @@ EXPORT_SYMBOL_GPL(drm_gpuva_prefetch_ops_create); * Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure */ struct drm_gpuva_ops * -drm_gpuva_gem_unmap_ops_create(struct drm_gpuva_manager *mgr, +drm_gpuvm_gem_unmap_ops_create(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj) { struct drm_gpuva_ops *ops; @@ -1673,7 +1673,7 @@ drm_gpuva_gem_unmap_ops_create(struct drm_gpuva_manager *mgr, INIT_LIST_HEAD(&ops->list); drm_gem_for_each_gpuva(va, obj) { - op = gpuva_op_alloc(mgr); + op = gpuva_op_alloc(gpuvm); if (!op) { ret = -ENOMEM; goto err_free_ops; @@ -1687,21 +1687,21 @@ drm_gpuva_gem_unmap_ops_create(struct drm_gpuva_manager *mgr, return ops; err_free_ops: - drm_gpuva_ops_free(mgr, ops); + drm_gpuva_ops_free(gpuvm, ops); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_gpuva_gem_unmap_ops_create); +EXPORT_SYMBOL_GPL(drm_gpuvm_gem_unmap_ops_create); /** * drm_gpuva_ops_free() - free the given &drm_gpuva_ops - * @mgr: the &drm_gpuva_manager the ops were created for + * @gpuvm: the &drm_gpuvm the ops were created for * @ops: the &drm_gpuva_ops to free * * Frees the given &drm_gpuva_ops structure including all the ops associated * with it. */ void -drm_gpuva_ops_free(struct drm_gpuva_manager *mgr, +drm_gpuva_ops_free(struct drm_gpuvm *gpuvm, struct drm_gpuva_ops *ops) { struct drm_gpuva_op *op, *next; @@ -1715,9 +1715,12 @@ drm_gpuva_ops_free(struct drm_gpuva_manager *mgr, kfree(op->remap.unmap); } - gpuva_op_free(mgr, op); + gpuva_op_free(gpuvm, op); } kfree(ops); } EXPORT_SYMBOL_GPL(drm_gpuva_ops_free); + +MODULE_DESCRIPTION("DRM GPUVM"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index ba12acd55139..8462b657c375 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -153,6 +153,8 @@ int drm_sysfs_init(void); void drm_sysfs_destroy(void); struct device *drm_sysfs_minor_alloc(struct drm_minor *minor); int drm_sysfs_connector_add(struct drm_connector *connector); +int drm_sysfs_connector_add_late(struct drm_connector *connector); +void drm_sysfs_connector_remove_early(struct drm_connector *connector); void drm_sysfs_connector_remove(struct drm_connector *connector); void drm_sysfs_lease_event(struct drm_device *dev); @@ -180,27 +182,32 @@ void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map); /* drm_debugfs.c drm_debugfs_crc.c */ #if defined(CONFIG_DEBUG_FS) -int drm_debugfs_init(struct drm_minor *minor, int minor_id, - struct dentry *root); -void drm_debugfs_cleanup(struct drm_minor *minor); -void drm_debugfs_late_register(struct drm_device *dev); +void drm_debugfs_dev_fini(struct drm_device *dev); +void drm_debugfs_dev_register(struct drm_device *dev); +int drm_debugfs_register(struct drm_minor *minor, int minor_id, + struct dentry *root); +void drm_debugfs_unregister(struct drm_minor *minor); void drm_debugfs_connector_add(struct drm_connector *connector); void drm_debugfs_connector_remove(struct drm_connector *connector); void drm_debugfs_crtc_add(struct drm_crtc *crtc); void drm_debugfs_crtc_remove(struct drm_crtc *crtc); void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc); #else -static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id, - struct dentry *root) +static inline void drm_debugfs_dev_fini(struct drm_device *dev) { - return 0; } -static inline void drm_debugfs_cleanup(struct drm_minor *minor) +static inline void drm_debugfs_dev_register(struct drm_device *dev) { } -static inline void drm_debugfs_late_register(struct drm_device *dev) +static inline int drm_debugfs_register(struct drm_minor *minor, int minor_id, + struct dentry *root) +{ + return 0; +} + +static inline void drm_debugfs_unregister(struct drm_minor *minor) { } @@ -259,4 +266,4 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, /* drm_framebuffer.c */ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, const struct drm_framebuffer *fb); -void drm_framebuffer_debugfs_init(struct drm_minor *minor); +void drm_framebuffer_debugfs_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index f03ffbacfe9b..77590b0f38fa 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -776,6 +776,9 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, struct drm_device *dev = file_priv->minor->dev; int retcode; + /* Update drm_file owner if fd was passed along. */ + drm_file_update_pid(file_priv); + if (drm_dev_is_unplugged(dev)) return -ENODEV; diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 87eb591fe9b5..8525ef851540 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -54,8 +54,6 @@ int drm_modeset_register_all(struct drm_device *dev) if (ret) goto err_connector; - drm_debugfs_late_register(dev); - return 0; err_connector: diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index b169b3e44a92..a953f69a34b6 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -400,10 +400,6 @@ int drm_sysfs_connector_add(struct drm_connector *connector) drm_err(dev, "failed to add component to create link to typec connector\n"); } - if (connector->ddc) - return sysfs_create_link(&connector->kdev->kobj, - &connector->ddc->dev.kobj, "ddc"); - return 0; err_free: @@ -411,13 +407,25 @@ err_free: return r; } -void drm_sysfs_connector_remove(struct drm_connector *connector) +int drm_sysfs_connector_add_late(struct drm_connector *connector) { - if (!connector->kdev) - return; + if (connector->ddc) + return sysfs_create_link(&connector->kdev->kobj, + &connector->ddc->dev.kobj, "ddc"); + + return 0; +} +void drm_sysfs_connector_remove_early(struct drm_connector *connector) +{ if (connector->ddc) sysfs_remove_link(&connector->kdev->kobj, "ddc"); +} + +void drm_sysfs_connector_remove(struct drm_connector *connector) +{ + if (!connector->kdev) + return; if (dev_fwnode(connector->kdev)) component_del(connector->kdev, &typec_connector_ops); diff --git a/drivers/gpu/drm/drm_vblank_work.c b/drivers/gpu/drm/drm_vblank_work.c index bd481fdd6b87..43cd5c0f4f6f 100644 --- a/drivers/gpu/drm/drm_vblank_work.c +++ b/drivers/gpu/drm/drm_vblank_work.c @@ -73,6 +73,9 @@ void drm_vblank_cancel_pending_works(struct drm_vblank_crtc *vblank) assert_spin_locked(&vblank->dev->event_lock); + drm_WARN_ONCE(vblank->dev, !list_empty(&vblank->pending_work), + "Cancelling pending vblank works!\n"); + list_for_each_entry_safe(work, next, &vblank->pending_work, node) { list_del_init(&work->node); drm_vblank_put(vblank->dev, vblank->pipe); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 69ea33cae651..2fe0e5f3f638 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -181,7 +181,7 @@ MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); struct platform_driver dsi_driver = { .probe = samsung_dsim_probe, - .remove = samsung_dsim_remove, + .remove_new = samsung_dsim_remove, .driver = { .name = "exynos-dsi", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index a395f93449f3..ab6c0c6cd0e2 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -356,9 +356,17 @@ static void fsl_dcu_drm_remove(struct platform_device *pdev) clk_unregister(fsl_dev->pix_clk); } +static void fsl_dcu_drm_shutdown(struct platform_device *pdev) +{ + struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev); + + drm_atomic_helper_shutdown(fsl_dev->drm); +} + static struct platform_driver fsl_dcu_drm_platform_driver = { .probe = fsl_dcu_drm_probe, .remove_new = fsl_dcu_drm_remove, + .shutdown = fsl_dcu_drm_shutdown, .driver = { .name = "fsl-dcu", .pm = &fsl_dcu_drm_pm_ops, diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index c8b611a2f6c6..1188a8d61caf 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -81,7 +81,6 @@ extern void gma_encoder_destroy(struct drm_encoder *encoder); /* Common clock related functions */ extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk); -extern void gma_clock(int refclk, struct gma_clock_t *clock); extern bool gma_pll_is_valid(struct drm_crtc *crtc, const struct gma_limit_t *limit, struct gma_clock_t *clock); diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c index 06b5b2d70d48..939c53fd09e8 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c @@ -141,7 +141,7 @@ struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev) chan->drm_dev = dev; chan->reg = dev_priv->lpc_gpio_base; - strncpy(chan->base.name, "gma500 LPC", I2C_NAME_SIZE - 1); + strscpy(chan->base.name, "gma500 LPC", sizeof(chan->base.name)); chan->base.owner = THIS_MODULE; chan->base.algo_data = &chan->algo; chan->base.dev.parent = dev->dev; diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index f7f709df99b4..c5edfa4aa4cc 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -161,14 +161,6 @@ #define PSB_NUM_VBLANKS 2 - -#define PSB_2D_SIZE (256*1024*1024) -#define PSB_MAX_RELOC_PAGES 1024 - -#define PSB_LOW_REG_OFFS 0x0204 -#define PSB_HIGH_REG_OFFS 0x0600 - -#define PSB_NUM_VBLANKS 2 #define PSB_WATCHDOG_DELAY (HZ * 2) #define PSB_LID_DELAY (HZ / 10) @@ -424,6 +416,7 @@ struct drm_psb_private { uint32_t pipestat[PSB_NUM_PIPE]; spinlock_t irqmask_lock; + bool irq_enabled; /* Power */ bool pm_initialized; diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 0bb85494e3da..c111e933e1ed 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -186,19 +186,13 @@ extern bool psb_intel_ddc_probe(struct i2c_adapter *adapter); extern void psb_intel_crtc_init(struct drm_device *dev, int pipe, struct psb_intel_mode_device *mode_dev); -extern void psb_intel_crt_init(struct drm_device *dev); extern bool psb_intel_sdvo_init(struct drm_device *dev, int output_device); -extern void psb_intel_dvo_init(struct drm_device *dev); -extern void psb_intel_tv_init(struct drm_device *dev); extern void psb_intel_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); extern void psb_intel_lvds_set_brightness(struct drm_device *dev, int level); extern void oaktrail_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); -extern void oaktrail_wait_for_INTR_PKT_SENT(struct drm_device *dev); struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev); -extern void mid_dsi_init(struct drm_device *dev, - struct psb_intel_mode_device *mode_dev, int dsi_num); extern struct drm_encoder *gma_best_encoder(struct drm_connector *connector); extern void gma_connector_attach_encoder(struct gma_connector *connector, @@ -214,11 +208,6 @@ extern struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); -extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev, - int sdvoB); -extern int intelfb_probe(struct drm_device *dev); -extern int intelfb_remove(struct drm_device *dev, - struct drm_framebuffer *fb); extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); @@ -242,9 +231,6 @@ extern void cdv_intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern void psb_intel_attach_force_audio_property(struct drm_connector *connector); -extern void psb_intel_attach_broadcast_rgb_property(struct drm_connector *connector); - extern int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val); extern int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val); extern void cdv_sb_reset(struct drm_device *dev); diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index 343c51250207..7bbb79b0497d 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -327,6 +327,8 @@ int gma_irq_install(struct drm_device *dev) gma_irq_postinstall(dev); + dev_priv->irq_enabled = true; + return 0; } @@ -337,6 +339,9 @@ void gma_irq_uninstall(struct drm_device *dev) unsigned long irqflags; unsigned int i; + if (!dev_priv->irq_enabled) + return; + spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); if (dev_priv->ops->hotplug_enable) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 8a98fa276e8a..57c21ec452b7 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -357,6 +357,11 @@ static void hibmc_pci_remove(struct pci_dev *pdev) hibmc_unload(dev); } +static void hibmc_pci_shutdown(struct pci_dev *pdev) +{ + drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); +} + static const struct pci_device_id hibmc_pci_table[] = { { PCI_VDEVICE(HUAWEI, 0x1711) }, {0,} @@ -367,6 +372,7 @@ static struct pci_driver hibmc_pci_driver = { .id_table = hibmc_pci_table, .probe = hibmc_pci_probe, .remove = hibmc_pci_remove, + .shutdown = hibmc_pci_shutdown, .driver.pm = &hibmc_pm_ops, }; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index e8c77bcc6dae..75292a2f4644 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -206,6 +206,7 @@ err_mode_config_cleanup: static int kirin_drm_kms_cleanup(struct drm_device *dev) { drm_kms_helper_poll_fini(dev); + drm_atomic_helper_shutdown(dev); kirin_drm_private_cleanup(dev); drm_mode_config_cleanup(dev); @@ -244,6 +245,7 @@ err_kms_cleanup: kirin_drm_kms_cleanup(drm_dev); err_drm_dev_put: drm_dev_put(drm_dev); + dev_set_drvdata(dev, NULL); return ret; } @@ -255,6 +257,7 @@ static void kirin_drm_unbind(struct device *dev) drm_dev_unregister(drm_dev); kirin_drm_kms_cleanup(drm_dev); drm_dev_put(drm_dev); + dev_set_drvdata(dev, NULL); } static const struct component_master_ops kirin_drm_ops = { @@ -284,6 +287,11 @@ static void kirin_drm_platform_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &kirin_drm_ops); } +static void kirin_drm_platform_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct of_device_id kirin_drm_dt_ids[] = { { .compatible = "hisilicon,hi6220-ade", .data = &ade_driver_data, @@ -295,6 +303,7 @@ MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids); static struct platform_driver kirin_drm_platform_driver = { .probe = kirin_drm_platform_probe, .remove_new = kirin_drm_platform_remove, + .shutdown = kirin_drm_platform_shutdown, .driver = { .name = "kirin-drm", .of_match_table = kirin_drm_dt_ids, diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c index 8026118c6e03..58b0b46a21e6 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c @@ -178,6 +178,11 @@ static void hyperv_vmbus_remove(struct hv_device *hdev) vmbus_free_mmio(hv->mem->start, hv->fb_size); } +static void hyperv_vmbus_shutdown(struct hv_device *hdev) +{ + drm_atomic_helper_shutdown(hv_get_drvdata(hdev)); +} + static int hyperv_vmbus_suspend(struct hv_device *hdev) { struct drm_device *dev = hv_get_drvdata(hdev); @@ -220,6 +225,7 @@ static struct hv_driver hyperv_hv_driver = { .id_table = hyperv_vmbus_tbl, .probe = hyperv_vmbus_probe, .remove = hyperv_vmbus_remove, + .shutdown = hyperv_vmbus_shutdown, .suspend = hyperv_vmbus_suspend, .resume = hyperv_vmbus_resume, .driver = { diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 79f65eff6bb2..88b2bb005014 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -3,24 +3,34 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -# Add a set of useful warning flags and enable -Werror for CI to prevent -# trivial mistakes from creeping in. We have to do this piecemeal as we reject -# any patch that isn't warning clean, so turning on -Wall -Wextra (or W=1) we -# need to filter out dubious warnings. Still it is our interest -# to keep running locally with W=1 C=1 until we are completely clean. -# -# Note the danger in using -Wall -Wextra is that when CI updates gcc we -# will most likely get a sudden build breakage... Hopefully we will fix -# new warnings before CI updates! -subdir-ccflags-y := -Wall -Wextra -subdir-ccflags-y += -Wno-format-security -subdir-ccflags-y += -Wno-unused-parameter -subdir-ccflags-y += -Wno-type-limits +# Unconditionally enable W=1 warnings locally +# --- begin copy-paste W=1 warnings from scripts/Makefile.extrawarn +subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter +subdir-ccflags-y += -Wmissing-declarations +subdir-ccflags-y += $(call cc-option, -Wrestrict) +subdir-ccflags-y += -Wmissing-format-attribute +subdir-ccflags-y += -Wmissing-prototypes +subdir-ccflags-y += -Wold-style-definition +subdir-ccflags-y += -Wmissing-include-dirs +subdir-ccflags-y += $(call cc-option, -Wunused-but-set-variable) +subdir-ccflags-y += $(call cc-option, -Wunused-const-variable) +subdir-ccflags-y += $(call cc-option, -Wpacked-not-aligned) +subdir-ccflags-y += $(call cc-option, -Wformat-overflow) +subdir-ccflags-y += $(call cc-option, -Wformat-truncation) +subdir-ccflags-y += $(call cc-option, -Wstringop-overflow) +subdir-ccflags-y += $(call cc-option, -Wstringop-truncation) +# The following turn off the warnings enabled by -Wextra +ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),) subdir-ccflags-y += -Wno-missing-field-initializers -subdir-ccflags-y += -Wno-sign-compare +subdir-ccflags-y += -Wno-type-limits subdir-ccflags-y += -Wno-shift-negative-value -subdir-ccflags-y += $(call cc-option, -Wunused-but-set-variable) -subdir-ccflags-y += $(call cc-disable-warning, frame-address) +endif +ifeq ($(findstring 3, $(KBUILD_EXTRA_WARN)),) +subdir-ccflags-y += -Wno-sign-compare +endif +# --- end copy-paste + +# Enable -Werror in CI and development subdir-ccflags-$(CONFIG_DRM_I915_WERROR) += -Werror # Fine grained warnings disable @@ -28,6 +38,10 @@ CFLAGS_i915_pci.o = $(call cc-disable-warning, override-init) CFLAGS_display/intel_display_device.o = $(call cc-disable-warning, override-init) CFLAGS_display/intel_fbdev.o = $(call cc-disable-warning, override-init) +# Support compiling the display code separately for both i915 and xe +# drivers. Define I915 when building i915. +subdir-ccflags-y += -DI915 + subdir-ccflags-y += -I$(srctree)/$(src) # Please keep these build lists sorted! @@ -248,6 +262,7 @@ i915-y += \ display/intel_display_power_well.o \ display/intel_display_reset.o \ display/intel_display_rps.o \ + display/intel_display_wa.o \ display/intel_dmc.o \ display/intel_dpio_phy.o \ display/intel_dpll.o \ @@ -264,9 +279,11 @@ i915-y += \ display/intel_global_state.o \ display/intel_hdcp.o \ display/intel_hdcp_gsc.o \ + display/intel_hdcp_gsc_message.o \ display/intel_hotplug.o \ display/intel_hotplug_irq.o \ display/intel_hti.o \ + display/intel_link_bw.o \ display/intel_load_detect.o \ display/intel_lpe_audio.o \ display/intel_modeset_lock.o \ diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 4c7187f7913e..e8ee0a08947e 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -141,7 +141,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, intel_de_rmw(dev_priv, TRANS_DP_CTL(crtc->pipe), TRANS_DP_ENH_FRAMING, - drm_dp_enhanced_frame_cap(intel_dp->dpcd) ? + pipe_config->enhanced_framing ? TRANS_DP_ENH_FRAMING : 0); } else { if (IS_G4X(dev_priv) && pipe_config->limited_color_range) @@ -153,7 +153,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, intel_dp->DP |= DP_SYNC_VS_HIGH; intel_dp->DP |= DP_LINK_TRAIN_OFF; - if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + if (pipe_config->enhanced_framing) intel_dp->DP |= DP_ENHANCED_FRAMING; if (IS_CHERRYVIEW(dev_priv)) @@ -351,6 +351,9 @@ static void intel_dp_get_config(struct intel_encoder *encoder, u32 trans_dp = intel_de_read(dev_priv, TRANS_DP_CTL(crtc->pipe)); + if (trans_dp & TRANS_DP_ENH_FRAMING) + pipe_config->enhanced_framing = true; + if (trans_dp & TRANS_DP_HSYNC_ACTIVE_HIGH) flags |= DRM_MODE_FLAG_PHSYNC; else @@ -361,6 +364,9 @@ static void intel_dp_get_config(struct intel_encoder *encoder, else flags |= DRM_MODE_FLAG_NVSYNC; } else { + if (tmp & DP_ENHANCED_FRAMING) + pipe_config->enhanced_framing = true; + if (tmp & DP_SYNC_HS_HIGH) flags |= DRM_MODE_FLAG_PHSYNC; else diff --git a/drivers/gpu/drm/i915/display/g4x_dp.h b/drivers/gpu/drm/i915/display/g4x_dp.h index a38b3e1e01d3..a10638ab749c 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.h +++ b/drivers/gpu/drm/i915/display/g4x_dp.h @@ -17,6 +17,7 @@ struct intel_crtc_state; struct intel_dp; struct intel_encoder; +#ifdef I915 const struct dpll *vlv_get_dpll(struct drm_i915_private *i915); enum pipe vlv_active_pipe(struct intel_dp *intel_dp); void g4x_dp_set_clock(struct intel_encoder *encoder, @@ -26,5 +27,30 @@ bool g4x_dp_port_enabled(struct drm_i915_private *dev_priv, enum pipe *pipe); bool g4x_dp_init(struct drm_i915_private *dev_priv, i915_reg_t output_reg, enum port port); +#else +static inline const struct dpll *vlv_get_dpll(struct drm_i915_private *i915) +{ + return NULL; +} +static inline int vlv_active_pipe(struct intel_dp *intel_dp) +{ + return 0; +} +static inline void g4x_dp_set_clock(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) +{ +} +static inline bool g4x_dp_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t dp_reg, int port, + enum pipe *pipe) +{ + return false; +} +static inline bool g4x_dp_init(struct drm_i915_private *dev_priv, + i915_reg_t output_reg, int port) +{ + return false; +} +#endif #endif diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 634b14116d9d..45e044b4a88d 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -16,6 +16,7 @@ #include "intel_display_types.h" #include "intel_dp_aux.h" #include "intel_dpio_phy.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_hdmi.h" #include "intel_hotplug.h" @@ -133,8 +134,11 @@ static int g4x_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(encoder->base.dev); - if (HAS_PCH_SPLIT(i915)) + if (HAS_PCH_SPLIT(i915)) { crtc_state->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(crtc_state)) + return -EINVAL; + } if (IS_G4X(i915)) crtc_state->has_hdmi_sink = g4x_compute_has_hdmi_sink(state, crtc); diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.h b/drivers/gpu/drm/i915/display/g4x_hdmi.h index 1e3ea7f3c846..817f55c7a3a1 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.h +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.h @@ -15,9 +15,21 @@ struct drm_atomic_state; struct drm_connector; struct drm_i915_private; +#ifdef I915 void g4x_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg, enum port port); int g4x_hdmi_connector_atomic_check(struct drm_connector *connector, struct drm_atomic_state *state); +#else +static inline void g4x_hdmi_init(struct drm_i915_private *dev_priv, + i915_reg_t hdmi_reg, int port) +{ +} +static inline int g4x_hdmi_connector_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + return 0; +} +#endif #endif diff --git a/drivers/gpu/drm/i915/display/hsw_ips.c b/drivers/gpu/drm/i915/display/hsw_ips.c index 8eca0de065b6..7dc38ac02092 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.c +++ b/drivers/gpu/drm/i915/display/hsw_ips.c @@ -6,6 +6,7 @@ #include "hsw_ips.h" #include "i915_drv.h" #include "i915_reg.h" +#include "intel_color_regs.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_pcode.h" diff --git a/drivers/gpu/drm/i915/display/hsw_ips.h b/drivers/gpu/drm/i915/display/hsw_ips.h index 4eb83b350791..35364228e1c1 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.h +++ b/drivers/gpu/drm/i915/display/hsw_ips.h @@ -12,6 +12,7 @@ struct intel_atomic_state; struct intel_crtc; struct intel_crtc_state; +#ifdef I915 bool hsw_ips_disable(const struct intel_crtc_state *crtc_state); bool hsw_ips_pre_update(struct intel_atomic_state *state, struct intel_crtc *crtc); @@ -23,5 +24,39 @@ int hsw_ips_compute_config(struct intel_atomic_state *state, struct intel_crtc *crtc); void hsw_ips_get_config(struct intel_crtc_state *crtc_state); void hsw_ips_crtc_debugfs_add(struct intel_crtc *crtc); +#else +static inline bool hsw_ips_disable(const struct intel_crtc_state *crtc_state) +{ + return false; +} +static inline bool hsw_ips_pre_update(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + return false; +} +static inline void hsw_ips_post_update(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline bool hsw_crtc_supports_ips(struct intel_crtc *crtc) +{ + return false; +} +static inline bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state) +{ + return false; +} +static inline int hsw_ips_compute_config(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + return 0; +} +static inline void hsw_ips_get_config(struct intel_crtc_state *crtc_state) +{ +} +static inline void hsw_ips_crtc_debugfs_add(struct intel_crtc *crtc) +{ +} +#endif #endif /* __HSW_IPS_H__ */ diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index b10488324457..91f2bc405cba 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -17,6 +17,7 @@ #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fbc.h" +#include "intel_frontbuffer.h" #include "intel_sprite.h" /* Primary plane formats for gen <= 3 */ diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.h b/drivers/gpu/drm/i915/display/i9xx_plane.h index 027b66053984..b3d724a144cb 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.h +++ b/drivers/gpu/drm/i915/display/i9xx_plane.h @@ -15,6 +15,7 @@ struct intel_initial_plane_config; struct intel_plane; struct intel_plane_state; +#ifdef I915 unsigned int i965_plane_max_stride(struct intel_plane *plane, u32 pixel_format, u64 modifier, unsigned int rotation); @@ -25,4 +26,26 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe); void i9xx_get_initial_plane_config(struct intel_crtc *crtc, struct intel_initial_plane_config *plane_config); +#else +static inline unsigned int i965_plane_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + return 0; +} +static inline int i9xx_check_plane_surface(struct intel_plane_state *plane_state) +{ + return 0; +} +static inline struct intel_plane * +intel_primary_plane_create(struct drm_i915_private *dev_priv, int pipe) +{ + return NULL; +} +static inline void i9xx_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config) +{ +} +#endif + #endif diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.h b/drivers/gpu/drm/i915/display/i9xx_wm.h index b87ae369685a..de0920730ab2 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.h +++ b/drivers/gpu/drm/i915/display/i9xx_wm.h @@ -12,9 +12,26 @@ struct drm_i915_private; struct intel_crtc_state; struct intel_plane_state; +#ifdef I915 bool ilk_disable_lp_wm(struct drm_i915_private *i915); void ilk_wm_sanitize(struct drm_i915_private *i915); bool intel_set_memory_cxsr(struct drm_i915_private *i915, bool enable); void i9xx_wm_init(struct drm_i915_private *i915); +#else +static inline bool ilk_disable_lp_wm(struct drm_i915_private *i915) +{ + return false; +} +static inline void ilk_wm_sanitize(struct drm_i915_private *i915) +{ +} +static inline bool intel_set_memory_cxsr(struct drm_i915_private *i915, bool enable) +{ + return false; +} +static inline void i9xx_wm_init(struct drm_i915_private *i915) +{ +} +#endif #endif /* __I9XX_WM_H__ */ diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index ad6488e9c2b2..c4585e445198 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1822,7 +1822,7 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi) u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt; u32 ths_prepare_ns, tclk_trail_ns; u32 hs_zero_cnt; - u32 tclk_pre_cnt, tclk_post_cnt; + u32 tclk_pre_cnt; tlpx_ns = intel_dsi_tlpx_ns(intel_dsi); @@ -1869,15 +1869,6 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi) tclk_pre_cnt = ICL_TCLK_PRE_CNT_MAX; } - /* tclk post count in escape clocks */ - tclk_post_cnt = DIV_ROUND_UP(mipi_config->tclk_post, tlpx_ns); - if (tclk_post_cnt > ICL_TCLK_POST_CNT_MAX) { - drm_dbg_kms(&dev_priv->drm, - "tclk_post_cnt out of range (%d)\n", - tclk_post_cnt); - tclk_post_cnt = ICL_TCLK_POST_CNT_MAX; - } - /* hs zero cnt in escape clocks */ hs_zero_cnt = DIV_ROUND_UP(mipi_config->ths_prepare_hszero - ths_prepare_ns, tlpx_ns); @@ -1903,8 +1894,6 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi) CLK_ZERO(clk_zero_cnt) | CLK_PRE_OVERRIDE | CLK_PRE(tclk_pre_cnt) | - CLK_POST_OVERRIDE | - CLK_POST(tclk_post_cnt) | CLK_TRAIL_OVERRIDE | CLK_TRAIL(trail_cnt)); diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 7cf51dd8c056..5d18145da279 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -259,6 +259,8 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) drm_property_blob_get(crtc_state->post_csc_lut); crtc_state->update_pipe = false; + crtc_state->update_m_n = false; + crtc_state->update_lrr = false; crtc_state->disable_lp_wm = false; crtc_state->disable_cxsr = false; crtc_state->update_wm_pre = false; diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 60a492e186ab..b1074350616c 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -214,9 +214,6 @@ intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, int width, height; unsigned int rel_data_rate; - if (plane->id == PLANE_CURSOR) - return 0; - if (!plane_state->uapi.visible) return 0; @@ -244,6 +241,9 @@ intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, rel_data_rate = width * height * fb->format->cpp[color_plane]; + if (plane->id == PLANE_CURSOR) + return rel_data_rate; + return intel_adjusted_rate(&plane_state->uapi.src, &plane_state->uapi.dst, rel_data_rate); @@ -981,6 +981,14 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) if (fb->format->format == DRM_FORMAT_RGB565 && rotated) { hsub = 2; vsub = 2; + } else if (DISPLAY_VER(i915) >= 20 && + intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) { + /* + * This allows NV12 and P0xx formats to have odd size and/or odd + * source coordinates on DISPLAY_VER(i915) >= 20 + */ + hsub = 1; + vsub = 1; } else { hsub = fb->format->hsub; vsub = fb->format->vsub; diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 3d9c9b4f27f8..19605264a35c 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -759,10 +759,10 @@ static void ibx_audio_codec_enable(struct intel_encoder *encoder, mutex_unlock(&i915->display.audio.mutex); } -void intel_audio_sdp_split_update(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum transcoder trans = crtc_state->cpu_transcoder; if (HAS_DP20(i915)) diff --git a/drivers/gpu/drm/i915/display/intel_audio.h b/drivers/gpu/drm/i915/display/intel_audio.h index 07d034a981e9..9327954b801e 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.h +++ b/drivers/gpu/drm/i915/display/intel_audio.h @@ -29,7 +29,6 @@ void intel_audio_cdclk_change_pre(struct drm_i915_private *dev_priv); void intel_audio_cdclk_change_post(struct drm_i915_private *dev_priv); void intel_audio_init(struct drm_i915_private *dev_priv); void intel_audio_deinit(struct drm_i915_private *dev_priv); -void intel_audio_sdp_split_update(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); +void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state); #endif /* __INTEL_AUDIO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 858c959f7bab..4e8f1e91bb08 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -521,7 +521,8 @@ static void init_bdb_blocks(struct drm_i915_private *i915, } static void -fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, +fill_detail_timing_data(struct drm_i915_private *i915, + struct drm_display_mode *panel_fixed_mode, const struct lvds_dvo_timing *dvo_timing) { panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | @@ -561,11 +562,17 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, panel_fixed_mode->height_mm = (dvo_timing->vimage_hi << 8) | dvo_timing->vimage_lo; - /* Some VBTs have bogus h/vtotal values */ - if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) - panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; - if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) - panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; + /* Some VBTs have bogus h/vsync_end values */ + if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) { + drm_dbg_kms(&i915->drm, "reducing hsync_end %d->%d\n", + panel_fixed_mode->hsync_end, panel_fixed_mode->htotal); + panel_fixed_mode->hsync_end = panel_fixed_mode->htotal; + } + if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) { + drm_dbg_kms(&i915->drm, "reducing vsync_end %d->%d\n", + panel_fixed_mode->vsync_end, panel_fixed_mode->vtotal); + panel_fixed_mode->vsync_end = panel_fixed_mode->vtotal; + } drm_mode_set_name(panel_fixed_mode); } @@ -849,7 +856,7 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915, if (!panel_fixed_mode) return; - fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); + fill_detail_timing_data(i915, panel_fixed_mode, panel_dvo_timing); panel->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; @@ -1134,7 +1141,7 @@ parse_sdvo_panel_data(struct drm_i915_private *i915, if (!panel_fixed_mode) return; - fill_detail_timing_data(panel_fixed_mode, &dtds->dtds[index]); + fill_detail_timing_data(i915, panel_fixed_mode, &dtds->dtds[index]); panel->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; @@ -2194,7 +2201,8 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) const u8 *ddc_pin_map; int i, n_entries; - if (HAS_PCH_MTP(i915) || IS_ALDERLAKE_P(i915)) { + if (INTEL_PCH_TYPE(i915) >= PCH_LNL || HAS_PCH_MTP(i915) || + IS_ALDERLAKE_P(i915)) { ddc_pin_map = adlp_ddc_pin_map; n_entries = ARRAY_SIZE(adlp_ddc_pin_map); } else if (IS_ALDERLAKE_S(i915)) { @@ -3540,6 +3548,27 @@ enum aux_ch intel_bios_dp_aux_ch(const struct intel_bios_encoder_data *devdata) return map_aux_ch(devdata->i915, devdata->child.aux_channel); } +bool intel_bios_dp_has_shared_aux_ch(const struct intel_bios_encoder_data *devdata) +{ + struct drm_i915_private *i915; + u8 aux_channel; + int count = 0; + + if (!devdata || !devdata->child.aux_channel) + return false; + + i915 = devdata->i915; + aux_channel = devdata->child.aux_channel; + + list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) { + if (intel_bios_encoder_supports_dp(devdata) && + aux_channel == devdata->child.aux_channel) + count++; + } + + return count > 1; +} + int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata) { if (!devdata || devdata->i915->display.vbt.version < 196 || !devdata->child.iboost) diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h index 9680e3e92bb5..49e24b7cf675 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.h +++ b/drivers/gpu/drm/i915/display/intel_bios.h @@ -273,6 +273,7 @@ enum aux_ch intel_bios_dp_aux_ch(const struct intel_bios_encoder_data *devdata); int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata); int intel_bios_dp_max_lane_count(const struct intel_bios_encoder_data *devdata); int intel_bios_dp_max_link_rate(const struct intel_bios_encoder_data *devdata); +bool intel_bios_dp_has_shared_aux_ch(const struct intel_bios_encoder_data *devdata); int intel_bios_hdmi_boost_level(const struct intel_bios_encoder_data *devdata); int intel_bios_hdmi_ddc_pin(const struct intel_bios_encoder_data *devdata); int intel_bios_hdmi_level_shift(const struct intel_bios_encoder_data *devdata); diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 2fb030b1ff1d..6d7ba4d0f130 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -32,6 +32,7 @@ #include "intel_cdclk.h" #include "intel_crtc.h" #include "intel_de.h" +#include "intel_dp.h" #include "intel_display_types.h" #include "intel_mchbar_regs.h" #include "intel_pci_config.h" @@ -1381,6 +1382,31 @@ static const struct intel_cdclk_vals mtl_cdclk_table[] = { {} }; +static const struct intel_cdclk_vals lnl_cdclk_table[] = { + { .refclk = 38400, .cdclk = 153600, .divider = 2, .ratio = 16, .waveform = 0xaaaa }, + { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 211200, .divider = 2, .ratio = 16, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 230400, .divider = 2, .ratio = 16, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 249600, .divider = 2, .ratio = 16, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 268800, .divider = 2, .ratio = 16, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 288000, .divider = 2, .ratio = 16, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 330000, .divider = 2, .ratio = 25, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 360000, .divider = 2, .ratio = 25, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 390000, .divider = 2, .ratio = 25, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 420000, .divider = 2, .ratio = 25, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 450000, .divider = 2, .ratio = 25, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 487200, .divider = 2, .ratio = 29, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 522000, .divider = 2, .ratio = 29, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff }, + {} +}; + static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk) { const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table; @@ -1840,9 +1866,10 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91 static bool pll_enable_wa_needed(struct drm_i915_private *dev_priv) { - return ((IS_DG2(dev_priv) || IS_METEORLAKE(dev_priv)) && - dev_priv->display.cdclk.hw.vco > 0 && - HAS_CDCLK_SQUASH(dev_priv)); + return (DISPLAY_VER_FULL(dev_priv) == IP_VER(20, 0) || + DISPLAY_VER_FULL(dev_priv) == IP_VER(14, 0) || + IS_DG2(dev_priv)) && + dev_priv->display.cdclk.hw.vco > 0; } static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, @@ -1879,8 +1906,7 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, dg2_cdclk_squash_program(dev_priv, waveform); val = bxt_cdclk_cd2x_div_sel(dev_priv, clock, vco) | - bxt_cdclk_cd2x_pipe(dev_priv, pipe) | - skl_cdclk_decimal(cdclk); + bxt_cdclk_cd2x_pipe(dev_priv, pipe); /* * Disable SSA Precharge when CD clock frequency < 500 MHz, @@ -1889,6 +1915,12 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && cdclk >= 500000) val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; + + if (DISPLAY_VER(dev_priv) >= 20) + val |= MDCLK_SOURCE_SEL_CDCLK_PLL; + else + val |= skl_cdclk_decimal(cdclk); + intel_de_write(dev_priv, CDCLK_CTL, val); if (pipe != INVALID_PIPE) @@ -2533,6 +2565,48 @@ static int intel_planes_min_cdclk(const struct intel_crtc_state *crtc_state) return min_cdclk; } +static int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); + int min_cdclk = 0; + + /* + * When we decide to use only one VDSC engine, since + * each VDSC operates with 1 ppc throughput, pixel clock + * cannot be higher than the VDSC clock (cdclk) + * If there 2 VDSC engines, then pixel clock can't be higher than + * VDSC clock(cdclk) * 2 and so on. + */ + min_cdclk = max_t(int, min_cdclk, + DIV_ROUND_UP(crtc_state->pixel_rate, num_vdsc_instances)); + + if (crtc_state->bigjoiner_pipes) { + int pixel_clock = intel_dp_mode_to_fec_clock(crtc_state->hw.adjusted_mode.clock); + + /* + * According to Bigjoiner bw check: + * compressed_bpp <= PPC * CDCLK * Big joiner Interface bits / Pixel clock + * + * We have already computed compressed_bpp, so now compute the min CDCLK that + * is required to support this compressed_bpp. + * + * => CDCLK >= compressed_bpp * Pixel clock / (PPC * Bigjoiner Interface bits) + * + * Since PPC = 2 with bigjoiner + * => CDCLK >= compressed_bpp * Pixel clock / 2 * Bigjoiner Interface bits + */ + int bigjoiner_interface_bits = DISPLAY_VER(i915) > 13 ? 36 : 24; + int min_cdclk_bj = (crtc_state->dsc.compressed_bpp * pixel_clock) / + (2 * bigjoiner_interface_bits); + + min_cdclk = max(min_cdclk, min_cdclk_bj); + } + + return min_cdclk; +} + int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = @@ -2604,20 +2678,8 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) /* Account for additional needs from the planes */ min_cdclk = max(intel_planes_min_cdclk(crtc_state), min_cdclk); - /* - * When we decide to use only one VDSC engine, since - * each VDSC operates with 1 ppc throughput, pixel clock - * cannot be higher than the VDSC clock (cdclk) - * If there 2 VDSC engines, then pixel clock can't be higher than - * VDSC clock(cdclk) * 2 and so on. - */ - if (crtc_state->dsc.compression_enable) { - int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); - - min_cdclk = max_t(int, min_cdclk, - DIV_ROUND_UP(crtc_state->pixel_rate, - num_vdsc_instances)); - } + if (crtc_state->dsc.compression_enable) + min_cdclk = max(min_cdclk, intel_vdsc_min_cdclk(crtc_state)); /* * HACK. Currently for TGL/DG2 platforms we calculate @@ -3108,7 +3170,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) } else if (intel_cdclk_needs_modeset(&old_cdclk_state->actual, &new_cdclk_state->actual)) { /* All pipes must be switched off while we change the cdclk. */ - ret = intel_modeset_all_pipes(state, "CDCLK change"); + ret = intel_modeset_all_pipes_late(state, "CDCLK change"); if (ret) return ret; @@ -3559,7 +3621,10 @@ static const struct intel_cdclk_funcs i830_cdclk_funcs = { */ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) { - if (IS_METEORLAKE(dev_priv)) { + if (DISPLAY_VER(dev_priv) >= 20) { + dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs; + dev_priv->display.cdclk.table = lnl_cdclk_table; + } else if (DISPLAY_VER(dev_priv) >= 14) { dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs; dev_priv->display.cdclk.table = mtl_cdclk_table; } else if (IS_DG2(dev_priv)) { diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 454607b4a02a..2a2a163ea652 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -24,6 +24,7 @@ #include "i915_reg.h" #include "intel_color.h" +#include "intel_color_regs.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dsb.h" @@ -75,6 +76,10 @@ struct intel_color_funcs { * software state. Used by eg. the hardware state checker. */ void (*read_csc)(struct intel_crtc_state *crtc_state); + /* + * Read config other than LUTs and CSCs, before them. Optional. + */ + void (*get_config)(struct intel_crtc_state *crtc_state); }; #define CTM_COEFF_SIGN (1ULL << 63) @@ -1013,6 +1018,65 @@ static void hsw_color_commit_arm(const struct intel_crtc_state *crtc_state) crtc_state->csc_mode); } +static u32 hsw_read_gamma_mode(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + return intel_de_read(i915, GAMMA_MODE(crtc->pipe)); +} + +static u32 ilk_read_csc_mode(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + return intel_de_read(i915, PIPE_CSC_MODE(crtc->pipe)); +} + +static void i9xx_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + u32 tmp; + + tmp = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); + + if (tmp & DISP_PIPE_GAMMA_ENABLE) + crtc_state->gamma_enable = true; + + if (!HAS_GMCH(dev_priv) && tmp & DISP_PIPE_CSC_ENABLE) + crtc_state->csc_enable = true; +} + +static void hsw_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + crtc_state->gamma_mode = hsw_read_gamma_mode(crtc); + crtc_state->csc_mode = ilk_read_csc_mode(crtc); + + i9xx_get_config(crtc_state); +} + +static void skl_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + u32 tmp; + + crtc_state->gamma_mode = hsw_read_gamma_mode(crtc); + crtc_state->csc_mode = ilk_read_csc_mode(crtc); + + tmp = intel_de_read(i915, SKL_BOTTOM_COLOR(crtc->pipe)); + + if (tmp & SKL_BOTTOM_COLOR_GAMMA_ENABLE) + crtc_state->gamma_enable = true; + + if (tmp & SKL_BOTTOM_COLOR_CSC_ENABLE) + crtc_state->csc_enable = true; +} + static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -1265,9 +1329,20 @@ static void ilk_load_lut_8(const struct intel_crtc_state *crtc_state, lut = blob->data; + /* + * DSB fails to correctly load the legacy LUT + * unless we either write each entry twice, + * or use non-posted writes + */ + if (crtc_state->dsb) + intel_dsb_nonpost_start(crtc_state->dsb); + for (i = 0; i < 256; i++) ilk_lut_write(crtc_state, LGC_PALETTE(pipe, i), i9xx_lut_8(&lut[i])); + + if (crtc_state->dsb) + intel_dsb_nonpost_end(crtc_state->dsb); } static void ilk_load_lut_10(const struct intel_crtc_state *crtc_state, @@ -1677,12 +1752,6 @@ static void icl_load_luts(const struct intel_crtc_state *crtc_state) MISSING_CASE(crtc_state->gamma_mode); break; } - - if (crtc_state->dsb) { - intel_dsb_finish(crtc_state->dsb); - intel_dsb_commit(crtc_state->dsb, false); - intel_dsb_wait(crtc_state->dsb); - } } static void vlv_load_luts(const struct intel_crtc_state *crtc_state) @@ -1789,6 +1858,9 @@ void intel_color_load_luts(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + if (crtc_state->dsb) + return; + i915->display.funcs.color->load_luts(crtc_state); } @@ -1805,6 +1877,9 @@ void intel_color_commit_arm(const struct intel_crtc_state *crtc_state) struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); i915->display.funcs.color->color_commit_arm(crtc_state); + + if (crtc_state->dsb) + intel_dsb_commit(crtc_state->dsb, true); } void intel_color_post_update(const struct intel_crtc_state *crtc_state) @@ -1818,14 +1893,25 @@ void intel_color_post_update(const struct intel_crtc_state *crtc_state) void intel_color_prepare_commit(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); /* FIXME DSB has issues loading LUTs, disable it for now */ return; + if (!crtc_state->hw.active || + intel_crtc_needs_modeset(crtc_state)) + return; + if (!crtc_state->pre_csc_lut && !crtc_state->post_csc_lut) return; - crtc_state->dsb = intel_dsb_prepare(crtc, 1024); + crtc_state->dsb = intel_dsb_prepare(crtc_state, 1024); + if (!crtc_state->dsb) + return; + + i915->display.funcs.color->load_luts(crtc_state); + + intel_dsb_finish(crtc_state->dsb); } void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state) @@ -1837,6 +1923,17 @@ void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state) crtc_state->dsb = NULL; } +void intel_color_wait_commit(const struct intel_crtc_state *crtc_state) +{ + if (crtc_state->dsb) + intel_dsb_wait(crtc_state->dsb); +} + +bool intel_color_uses_dsb(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->dsb; +} + static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state) { struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); @@ -1891,6 +1988,9 @@ void intel_color_get_config(struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + if (i915->display.funcs.color->get_config) + i915->display.funcs.color->get_config(crtc_state); + i915->display.funcs.color->read_luts(crtc_state); if (i915->display.funcs.color->read_csc) @@ -2865,16 +2965,16 @@ static int icl_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state) return 16; } -static bool err_check(struct drm_color_lut *lut1, - struct drm_color_lut *lut2, u32 err) +static bool err_check(const struct drm_color_lut *lut1, + const struct drm_color_lut *lut2, u32 err) { return ((abs((long)lut2->red - lut1->red)) <= err) && ((abs((long)lut2->blue - lut1->blue)) <= err) && ((abs((long)lut2->green - lut1->green)) <= err); } -static bool intel_lut_entries_equal(struct drm_color_lut *lut1, - struct drm_color_lut *lut2, +static bool intel_lut_entries_equal(const struct drm_color_lut *lut1, + const struct drm_color_lut *lut2, int lut_size, u32 err) { int i; @@ -2891,7 +2991,7 @@ static bool intel_lut_equal(const struct drm_property_blob *blob1, const struct drm_property_blob *blob2, int check_size, int precision) { - struct drm_color_lut *lut1, *lut2; + const struct drm_color_lut *lut1, *lut2; int lut_size1, lut_size2; u32 err; @@ -3204,6 +3304,16 @@ static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc) return blob; } +static void chv_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + crtc_state->cgm_mode = intel_de_read(i915, CGM_PIPE_MODE(crtc->pipe)); + + i9xx_get_config(crtc_state); +} + static void chv_read_luts(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -3267,6 +3377,15 @@ static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc) return blob; } +static void ilk_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + crtc_state->csc_mode = ilk_read_csc_mode(crtc); + + i9xx_get_config(crtc_state); +} + static void ilk_read_luts(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -3573,6 +3692,7 @@ static const struct intel_color_funcs chv_color_funcs = { .read_luts = chv_read_luts, .lut_equal = chv_lut_equal, .read_csc = chv_read_csc, + .get_config = chv_get_config, }; static const struct intel_color_funcs vlv_color_funcs = { @@ -3582,6 +3702,7 @@ static const struct intel_color_funcs vlv_color_funcs = { .read_luts = i965_read_luts, .lut_equal = i965_lut_equal, .read_csc = vlv_read_csc, + .get_config = i9xx_get_config, }; static const struct intel_color_funcs i965_color_funcs = { @@ -3590,6 +3711,7 @@ static const struct intel_color_funcs i965_color_funcs = { .load_luts = i965_load_luts, .read_luts = i965_read_luts, .lut_equal = i965_lut_equal, + .get_config = i9xx_get_config, }; static const struct intel_color_funcs i9xx_color_funcs = { @@ -3598,6 +3720,7 @@ static const struct intel_color_funcs i9xx_color_funcs = { .load_luts = i9xx_load_luts, .read_luts = i9xx_read_luts, .lut_equal = i9xx_lut_equal, + .get_config = i9xx_get_config, }; static const struct intel_color_funcs tgl_color_funcs = { @@ -3608,6 +3731,7 @@ static const struct intel_color_funcs tgl_color_funcs = { .read_luts = icl_read_luts, .lut_equal = icl_lut_equal, .read_csc = icl_read_csc, + .get_config = skl_get_config, }; static const struct intel_color_funcs icl_color_funcs = { @@ -3619,6 +3743,7 @@ static const struct intel_color_funcs icl_color_funcs = { .read_luts = icl_read_luts, .lut_equal = icl_lut_equal, .read_csc = icl_read_csc, + .get_config = skl_get_config, }; static const struct intel_color_funcs glk_color_funcs = { @@ -3629,6 +3754,7 @@ static const struct intel_color_funcs glk_color_funcs = { .read_luts = glk_read_luts, .lut_equal = glk_lut_equal, .read_csc = skl_read_csc, + .get_config = skl_get_config, }; static const struct intel_color_funcs skl_color_funcs = { @@ -3639,6 +3765,7 @@ static const struct intel_color_funcs skl_color_funcs = { .read_luts = bdw_read_luts, .lut_equal = ivb_lut_equal, .read_csc = skl_read_csc, + .get_config = skl_get_config, }; static const struct intel_color_funcs bdw_color_funcs = { @@ -3649,6 +3776,7 @@ static const struct intel_color_funcs bdw_color_funcs = { .read_luts = bdw_read_luts, .lut_equal = ivb_lut_equal, .read_csc = ilk_read_csc, + .get_config = hsw_get_config, }; static const struct intel_color_funcs hsw_color_funcs = { @@ -3659,6 +3787,7 @@ static const struct intel_color_funcs hsw_color_funcs = { .read_luts = ivb_read_luts, .lut_equal = ivb_lut_equal, .read_csc = ilk_read_csc, + .get_config = hsw_get_config, }; static const struct intel_color_funcs ivb_color_funcs = { @@ -3669,6 +3798,7 @@ static const struct intel_color_funcs ivb_color_funcs = { .read_luts = ivb_read_luts, .lut_equal = ivb_lut_equal, .read_csc = ilk_read_csc, + .get_config = ilk_get_config, }; static const struct intel_color_funcs ilk_color_funcs = { @@ -3679,6 +3809,7 @@ static const struct intel_color_funcs ilk_color_funcs = { .read_luts = ilk_read_luts, .lut_equal = ilk_lut_equal, .read_csc = ilk_read_csc, + .get_config = ilk_get_config, }; void intel_color_crtc_init(struct intel_crtc *crtc) diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index 8002492be709..8ecd36149def 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -19,6 +19,8 @@ void intel_color_crtc_init(struct intel_crtc *crtc); int intel_color_check(struct intel_crtc_state *crtc_state); void intel_color_prepare_commit(struct intel_crtc_state *crtc_state); void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state); +bool intel_color_uses_dsb(const struct intel_crtc_state *crtc_state); +void intel_color_wait_commit(const struct intel_crtc_state *crtc_state); void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state); void intel_color_commit_arm(const struct intel_crtc_state *crtc_state); void intel_color_post_update(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_color_regs.h b/drivers/gpu/drm/i915/display/intel_color_regs.h new file mode 100644 index 000000000000..9f4ae58f3e7e --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_color_regs.h @@ -0,0 +1,286 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_COLOR_REGS_H__ +#define __INTEL_COLOR_REGS_H__ + +#include "intel_display_reg_defs.h" + +/* legacy palette */ +#define _LGC_PALETTE_A 0x4a000 +#define _LGC_PALETTE_B 0x4a800 +/* see PALETTE_* for the bits */ +#define LGC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4) + +/* ilk/snb precision palette */ +#define _PREC_PALETTE_A 0x4b000 +#define _PREC_PALETTE_B 0x4c000 +/* 10bit mode */ +#define PREC_PALETTE_10_RED_MASK REG_GENMASK(29, 20) +#define PREC_PALETTE_10_GREEN_MASK REG_GENMASK(19, 10) +#define PREC_PALETTE_10_BLUE_MASK REG_GENMASK(9, 0) +/* 12.4 interpolated mode ldw */ +#define PREC_PALETTE_12P4_RED_LDW_MASK REG_GENMASK(29, 24) +#define PREC_PALETTE_12P4_GREEN_LDW_MASK REG_GENMASK(19, 14) +#define PREC_PALETTE_12P4_BLUE_LDW_MASK REG_GENMASK(9, 4) +/* 12.4 interpolated mode udw */ +#define PREC_PALETTE_12P4_RED_UDW_MASK REG_GENMASK(29, 20) +#define PREC_PALETTE_12P4_GREEN_UDW_MASK REG_GENMASK(19, 10) +#define PREC_PALETTE_12P4_BLUE_UDW_MASK REG_GENMASK(9, 0) +#define PREC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _PREC_PALETTE_A, _PREC_PALETTE_B) + (i) * 4) + +#define _PREC_PIPEAGCMAX 0x4d000 +#define _PREC_PIPEBGCMAX 0x4d010 +#define PREC_PIPEGCMAX(pipe, i) _MMIO(_PIPE(pipe, _PIPEAGCMAX, _PIPEBGCMAX) + (i) * 4) /* u1.16 */ + +#define _GAMMA_MODE_A 0x4a480 +#define _GAMMA_MODE_B 0x4ac80 +#define GAMMA_MODE(pipe) _MMIO_PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) +#define PRE_CSC_GAMMA_ENABLE REG_BIT(31) /* icl+ */ +#define POST_CSC_GAMMA_ENABLE REG_BIT(30) /* icl+ */ +#define PALETTE_ANTICOL_DISABLE REG_BIT(15) /* skl+ */ +#define GAMMA_MODE_MODE_MASK REG_GENMASK(1, 0) +#define GAMMA_MODE_MODE_8BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 0) +#define GAMMA_MODE_MODE_10BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 1) +#define GAMMA_MODE_MODE_12BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 2) +#define GAMMA_MODE_MODE_SPLIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 3) /* ivb-bdw */ +#define GAMMA_MODE_MODE_12BIT_MULTI_SEG REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 3) /* icl-tgl */ + +/* pipe CSC */ +#define _PIPE_A_CSC_COEFF_RY_GY 0x49010 +#define _PIPE_A_CSC_COEFF_BY 0x49014 +#define _PIPE_A_CSC_COEFF_RU_GU 0x49018 +#define _PIPE_A_CSC_COEFF_BU 0x4901c +#define _PIPE_A_CSC_COEFF_RV_GV 0x49020 +#define _PIPE_A_CSC_COEFF_BV 0x49024 + +#define _PIPE_A_CSC_MODE 0x49028 +#define ICL_CSC_ENABLE (1 << 31) /* icl+ */ +#define ICL_OUTPUT_CSC_ENABLE (1 << 30) /* icl+ */ +#define CSC_BLACK_SCREEN_OFFSET (1 << 2) /* ilk/snb */ +#define CSC_POSITION_BEFORE_GAMMA (1 << 1) /* pre-glk */ +#define CSC_MODE_YUV_TO_RGB (1 << 0) /* ilk/snb */ + +#define _PIPE_A_CSC_PREOFF_HI 0x49030 +#define _PIPE_A_CSC_PREOFF_ME 0x49034 +#define _PIPE_A_CSC_PREOFF_LO 0x49038 +#define _PIPE_A_CSC_POSTOFF_HI 0x49040 +#define _PIPE_A_CSC_POSTOFF_ME 0x49044 +#define _PIPE_A_CSC_POSTOFF_LO 0x49048 + +#define _PIPE_B_CSC_COEFF_RY_GY 0x49110 +#define _PIPE_B_CSC_COEFF_BY 0x49114 +#define _PIPE_B_CSC_COEFF_RU_GU 0x49118 +#define _PIPE_B_CSC_COEFF_BU 0x4911c +#define _PIPE_B_CSC_COEFF_RV_GV 0x49120 +#define _PIPE_B_CSC_COEFF_BV 0x49124 +#define _PIPE_B_CSC_MODE 0x49128 +#define _PIPE_B_CSC_PREOFF_HI 0x49130 +#define _PIPE_B_CSC_PREOFF_ME 0x49134 +#define _PIPE_B_CSC_PREOFF_LO 0x49138 +#define _PIPE_B_CSC_POSTOFF_HI 0x49140 +#define _PIPE_B_CSC_POSTOFF_ME 0x49144 +#define _PIPE_B_CSC_POSTOFF_LO 0x49148 + +#define PIPE_CSC_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) +#define PIPE_CSC_COEFF_BY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) +#define PIPE_CSC_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) +#define PIPE_CSC_COEFF_BU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) +#define PIPE_CSC_COEFF_RV_GV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) +#define PIPE_CSC_COEFF_BV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) +#define PIPE_CSC_MODE(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) +#define PIPE_CSC_PREOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) +#define PIPE_CSC_PREOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) +#define PIPE_CSC_PREOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) +#define PIPE_CSC_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) +#define PIPE_CSC_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) +#define PIPE_CSC_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) + +/* Pipe Output CSC */ +#define _PIPE_A_OUTPUT_CSC_COEFF_RY_GY 0x49050 +#define _PIPE_A_OUTPUT_CSC_COEFF_BY 0x49054 +#define _PIPE_A_OUTPUT_CSC_COEFF_RU_GU 0x49058 +#define _PIPE_A_OUTPUT_CSC_COEFF_BU 0x4905c +#define _PIPE_A_OUTPUT_CSC_COEFF_RV_GV 0x49060 +#define _PIPE_A_OUTPUT_CSC_COEFF_BV 0x49064 +#define _PIPE_A_OUTPUT_CSC_PREOFF_HI 0x49068 +#define _PIPE_A_OUTPUT_CSC_PREOFF_ME 0x4906c +#define _PIPE_A_OUTPUT_CSC_PREOFF_LO 0x49070 +#define _PIPE_A_OUTPUT_CSC_POSTOFF_HI 0x49074 +#define _PIPE_A_OUTPUT_CSC_POSTOFF_ME 0x49078 +#define _PIPE_A_OUTPUT_CSC_POSTOFF_LO 0x4907c + +#define _PIPE_B_OUTPUT_CSC_COEFF_RY_GY 0x49150 +#define _PIPE_B_OUTPUT_CSC_COEFF_BY 0x49154 +#define _PIPE_B_OUTPUT_CSC_COEFF_RU_GU 0x49158 +#define _PIPE_B_OUTPUT_CSC_COEFF_BU 0x4915c +#define _PIPE_B_OUTPUT_CSC_COEFF_RV_GV 0x49160 +#define _PIPE_B_OUTPUT_CSC_COEFF_BV 0x49164 +#define _PIPE_B_OUTPUT_CSC_PREOFF_HI 0x49168 +#define _PIPE_B_OUTPUT_CSC_PREOFF_ME 0x4916c +#define _PIPE_B_OUTPUT_CSC_PREOFF_LO 0x49170 +#define _PIPE_B_OUTPUT_CSC_POSTOFF_HI 0x49174 +#define _PIPE_B_OUTPUT_CSC_POSTOFF_ME 0x49178 +#define _PIPE_B_OUTPUT_CSC_POSTOFF_LO 0x4917c + +#define PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe,\ + _PIPE_A_OUTPUT_CSC_COEFF_RY_GY,\ + _PIPE_B_OUTPUT_CSC_COEFF_RY_GY) +#define PIPE_CSC_OUTPUT_COEFF_BY(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_BY, \ + _PIPE_B_OUTPUT_CSC_COEFF_BY) +#define PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_RU_GU, \ + _PIPE_B_OUTPUT_CSC_COEFF_RU_GU) +#define PIPE_CSC_OUTPUT_COEFF_BU(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_BU, \ + _PIPE_B_OUTPUT_CSC_COEFF_BU) +#define PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_RV_GV, \ + _PIPE_B_OUTPUT_CSC_COEFF_RV_GV) +#define PIPE_CSC_OUTPUT_COEFF_BV(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_BV, \ + _PIPE_B_OUTPUT_CSC_COEFF_BV) +#define PIPE_CSC_OUTPUT_PREOFF_HI(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_PREOFF_HI, \ + _PIPE_B_OUTPUT_CSC_PREOFF_HI) +#define PIPE_CSC_OUTPUT_PREOFF_ME(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_PREOFF_ME, \ + _PIPE_B_OUTPUT_CSC_PREOFF_ME) +#define PIPE_CSC_OUTPUT_PREOFF_LO(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_PREOFF_LO, \ + _PIPE_B_OUTPUT_CSC_PREOFF_LO) +#define PIPE_CSC_OUTPUT_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_POSTOFF_HI, \ + _PIPE_B_OUTPUT_CSC_POSTOFF_HI) +#define PIPE_CSC_OUTPUT_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_POSTOFF_ME, \ + _PIPE_B_OUTPUT_CSC_POSTOFF_ME) +#define PIPE_CSC_OUTPUT_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_POSTOFF_LO, \ + _PIPE_B_OUTPUT_CSC_POSTOFF_LO) + +/* pipe degamma/gamma LUTs on IVB+ */ +#define _PAL_PREC_INDEX_A 0x4A400 +#define _PAL_PREC_INDEX_B 0x4AC00 +#define _PAL_PREC_INDEX_C 0x4B400 +#define PAL_PREC_SPLIT_MODE REG_BIT(31) +#define PAL_PREC_AUTO_INCREMENT REG_BIT(15) +#define PAL_PREC_INDEX_VALUE_MASK REG_GENMASK(9, 0) +#define PAL_PREC_INDEX_VALUE(x) REG_FIELD_PREP(PAL_PREC_INDEX_VALUE_MASK, (x)) +#define _PAL_PREC_DATA_A 0x4A404 +#define _PAL_PREC_DATA_B 0x4AC04 +#define _PAL_PREC_DATA_C 0x4B404 +/* see PREC_PALETTE_* for the bits */ +#define _PAL_PREC_GC_MAX_A 0x4A410 +#define _PAL_PREC_GC_MAX_B 0x4AC10 +#define _PAL_PREC_GC_MAX_C 0x4B410 +#define _PAL_PREC_EXT_GC_MAX_A 0x4A420 +#define _PAL_PREC_EXT_GC_MAX_B 0x4AC20 +#define _PAL_PREC_EXT_GC_MAX_C 0x4B420 +#define _PAL_PREC_EXT2_GC_MAX_A 0x4A430 +#define _PAL_PREC_EXT2_GC_MAX_B 0x4AC30 +#define _PAL_PREC_EXT2_GC_MAX_C 0x4B430 + +#define PREC_PAL_INDEX(pipe) _MMIO_PIPE(pipe, _PAL_PREC_INDEX_A, _PAL_PREC_INDEX_B) +#define PREC_PAL_DATA(pipe) _MMIO_PIPE(pipe, _PAL_PREC_DATA_A, _PAL_PREC_DATA_B) +#define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4) /* u1.16 */ +#define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (i) * 4) /* u3.16 */ +#define PREC_PAL_EXT2_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT2_GC_MAX_A, _PAL_PREC_EXT2_GC_MAX_B) + (i) * 4) /* glk+, u3.16 */ + +#define _PRE_CSC_GAMC_INDEX_A 0x4A484 +#define _PRE_CSC_GAMC_INDEX_B 0x4AC84 +#define _PRE_CSC_GAMC_INDEX_C 0x4B484 +#define PRE_CSC_GAMC_AUTO_INCREMENT REG_BIT(10) +#define PRE_CSC_GAMC_INDEX_VALUE_MASK REG_GENMASK(7, 0) +#define PRE_CSC_GAMC_INDEX_VALUE(x) REG_FIELD_PREP(PRE_CSC_GAMC_INDEX_VALUE_MASK, (x)) +#define _PRE_CSC_GAMC_DATA_A 0x4A488 +#define _PRE_CSC_GAMC_DATA_B 0x4AC88 +#define _PRE_CSC_GAMC_DATA_C 0x4B488 + +#define PRE_CSC_GAMC_INDEX(pipe) _MMIO_PIPE(pipe, _PRE_CSC_GAMC_INDEX_A, _PRE_CSC_GAMC_INDEX_B) +#define PRE_CSC_GAMC_DATA(pipe) _MMIO_PIPE(pipe, _PRE_CSC_GAMC_DATA_A, _PRE_CSC_GAMC_DATA_B) + +/* ICL Multi segmented gamma */ +#define _PAL_PREC_MULTI_SEG_INDEX_A 0x4A408 +#define _PAL_PREC_MULTI_SEG_INDEX_B 0x4AC08 +#define PAL_PREC_MULTI_SEG_AUTO_INCREMENT REG_BIT(15) +#define PAL_PREC_MULTI_SEG_INDEX_VALUE_MASK REG_GENMASK(4, 0) +#define PAL_PREC_MULTI_SEG_INDEX_VALUE(x) REG_FIELD_PREP(PAL_PREC_MULTI_SEG_INDEX_VALUE_MASK, (x)) + +#define _PAL_PREC_MULTI_SEG_DATA_A 0x4A40C +#define _PAL_PREC_MULTI_SEG_DATA_B 0x4AC0C +/* see PREC_PALETTE_12P4_* for the bits */ + +#define PREC_PAL_MULTI_SEG_INDEX(pipe) _MMIO_PIPE(pipe, \ + _PAL_PREC_MULTI_SEG_INDEX_A, \ + _PAL_PREC_MULTI_SEG_INDEX_B) +#define PREC_PAL_MULTI_SEG_DATA(pipe) _MMIO_PIPE(pipe, \ + _PAL_PREC_MULTI_SEG_DATA_A, \ + _PAL_PREC_MULTI_SEG_DATA_B) + +#define _PIPE_A_WGC_C01_C00 0x600B0 /* s2.10 */ +#define _PIPE_A_WGC_C02 0x600B4 /* s2.10 */ +#define _PIPE_A_WGC_C11_C10 0x600B8 /* s2.10 */ +#define _PIPE_A_WGC_C12 0x600BC /* s2.10 */ +#define _PIPE_A_WGC_C21_C20 0x600C0 /* s2.10 */ +#define _PIPE_A_WGC_C22 0x600C4 /* s2.10 */ + +#define PIPE_WGC_C01_C00(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C01_C00) +#define PIPE_WGC_C02(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C02) +#define PIPE_WGC_C11_C10(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C11_C10) +#define PIPE_WGC_C12(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C12) +#define PIPE_WGC_C21_C20(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C21_C20) +#define PIPE_WGC_C22(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C22) + +/* pipe CSC & degamma/gamma LUTs on CHV */ +#define _CGM_PIPE_A_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x67900) +#define _CGM_PIPE_A_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x67904) +#define _CGM_PIPE_A_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x67908) +#define _CGM_PIPE_A_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6790C) +#define _CGM_PIPE_A_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x67910) +#define _CGM_PIPE_A_DEGAMMA (VLV_DISPLAY_BASE + 0x66000) +/* cgm degamma ldw */ +#define CGM_PIPE_DEGAMMA_GREEN_LDW_MASK REG_GENMASK(29, 16) +#define CGM_PIPE_DEGAMMA_BLUE_LDW_MASK REG_GENMASK(13, 0) +/* cgm degamma udw */ +#define CGM_PIPE_DEGAMMA_RED_UDW_MASK REG_GENMASK(13, 0) +#define _CGM_PIPE_A_GAMMA (VLV_DISPLAY_BASE + 0x67000) +/* cgm gamma ldw */ +#define CGM_PIPE_GAMMA_GREEN_LDW_MASK REG_GENMASK(25, 16) +#define CGM_PIPE_GAMMA_BLUE_LDW_MASK REG_GENMASK(9, 0) +/* cgm gamma udw */ +#define CGM_PIPE_GAMMA_RED_UDW_MASK REG_GENMASK(9, 0) +#define _CGM_PIPE_A_MODE (VLV_DISPLAY_BASE + 0x67A00) +#define CGM_PIPE_MODE_GAMMA (1 << 2) +#define CGM_PIPE_MODE_CSC (1 << 1) +#define CGM_PIPE_MODE_DEGAMMA (1 << 0) + +#define _CGM_PIPE_B_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x69900) +#define _CGM_PIPE_B_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x69904) +#define _CGM_PIPE_B_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x69908) +#define _CGM_PIPE_B_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6990C) +#define _CGM_PIPE_B_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x69910) +#define _CGM_PIPE_B_DEGAMMA (VLV_DISPLAY_BASE + 0x68000) +#define _CGM_PIPE_B_GAMMA (VLV_DISPLAY_BASE + 0x69000) +#define _CGM_PIPE_B_MODE (VLV_DISPLAY_BASE + 0x69A00) + +#define CGM_PIPE_CSC_COEFF01(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF01, _CGM_PIPE_B_CSC_COEFF01) +#define CGM_PIPE_CSC_COEFF23(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF23, _CGM_PIPE_B_CSC_COEFF23) +#define CGM_PIPE_CSC_COEFF45(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF45, _CGM_PIPE_B_CSC_COEFF45) +#define CGM_PIPE_CSC_COEFF67(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF67, _CGM_PIPE_B_CSC_COEFF67) +#define CGM_PIPE_CSC_COEFF8(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF8, _CGM_PIPE_B_CSC_COEFF8) +#define CGM_PIPE_DEGAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_DEGAMMA, _CGM_PIPE_B_DEGAMMA) + (i) * 8 + (w) * 4) +#define CGM_PIPE_GAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_GAMMA, _CGM_PIPE_B_GAMMA) + (i) * 8 + (w) * 4) +#define CGM_PIPE_MODE(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_MODE, _CGM_PIPE_B_MODE) + +/* Skylake+ pipe bottom (background) color */ +#define _SKL_BOTTOM_COLOR_A 0x70034 +#define _SKL_BOTTOM_COLOR_B 0x71034 +#define SKL_BOTTOM_COLOR_GAMMA_ENABLE REG_BIT(31) +#define SKL_BOTTOM_COLOR_CSC_ENABLE REG_BIT(30) +#define SKL_BOTTOM_COLOR(pipe) _MMIO_PIPE(pipe, _SKL_BOTTOM_COLOR_A, _SKL_BOTTOM_COLOR_B) + +#endif /* __INTEL_COLOR_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c index e2a220cf2e57..143d66951631 100644 --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c @@ -114,10 +114,6 @@ static bool icl_verify_procmon_ref_values(struct drm_i915_private *dev_priv, procmon = icl_get_procmon_ref_values(dev_priv, phy); - drm_dbg_kms(&dev_priv->drm, - "Combo PHY %c Voltage/Process Info : %s\n", - phy_name(phy), procmon->name); - ret = check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW1(phy), (0xff << 16) | 0xff, procmon->dw1); ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW9(phy), @@ -312,14 +308,17 @@ static void icl_combo_phys_init(struct drm_i915_private *dev_priv) enum phy phy; for_each_combo_phy(dev_priv, phy) { + const struct icl_procmon *procmon; u32 val; - if (icl_combo_phy_verify_state(dev_priv, phy)) { - drm_dbg(&dev_priv->drm, - "Combo PHY %c already enabled, won't reprogram it.\n", - phy_name(phy)); + if (icl_combo_phy_verify_state(dev_priv, phy)) continue; - } + + procmon = icl_get_procmon_ref_values(dev_priv, phy); + + drm_dbg(&dev_priv->drm, + "Initializing combo PHY %c (Voltage/Process Info : %s)\n", + phy_name(phy), procmon->name); if (!has_phy_misc(dev_priv, phy)) goto skip_phy_misc; diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index ff3bcadebe59..c65887870ddc 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -192,17 +192,17 @@ int intel_connector_update_modes(struct drm_connector *connector, /** * intel_ddc_get_modes - get modelist from monitor * @connector: DRM connector device to use - * @adapter: i2c adapter + * @ddc: DDC bus i2c adapter * * Fetch the EDID information from @connector using the DDC bus. */ int intel_ddc_get_modes(struct drm_connector *connector, - struct i2c_adapter *adapter) + struct i2c_adapter *ddc) { const struct drm_edid *drm_edid; int ret; - drm_edid = drm_edid_read_ddc(connector, adapter); + drm_edid = drm_edid_read_ddc(connector, ddc); if (!drm_edid) return 0; diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h index aaf7281462dc..bafde3f11ff4 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.h +++ b/drivers/gpu/drm/i915/display/intel_connector.h @@ -26,7 +26,7 @@ bool intel_connector_get_hw_state(struct intel_connector *connector); enum pipe intel_connector_get_pipe(struct intel_connector *connector); int intel_connector_update_modes(struct drm_connector *connector, const struct drm_edid *drm_edid); -int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); +int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *ddc); void intel_attach_force_audio_property(struct drm_connector *connector); void intel_attach_broadcast_rgb_property(struct drm_connector *connector); void intel_attach_aspect_ratio_property(struct drm_connector *connector); diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 809074758687..913e5d230a4d 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -413,6 +413,9 @@ static int pch_crt_compute_config(struct intel_encoder *encoder, return -EINVAL; pipe_config->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(pipe_config)) + return -EINVAL; + pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; return 0; @@ -435,10 +438,14 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder, return -EINVAL; pipe_config->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(pipe_config)) + return -EINVAL; + pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; /* LPT FDI RX only supports 8bpc. */ if (HAS_PCH_LPT(dev_priv)) { + /* TODO: Check crtc_state->max_link_bpp_x16 instead of bw_constrained */ if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) { drm_dbg_kms(&dev_priv->drm, "LPT only supports 24bpp\n"); @@ -451,6 +458,8 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder, /* FDI must always be 2.7 GHz */ pipe_config->port_clock = 135000 * 2; + pipe_config->enhanced_framing = true; + adjusted_mode->crtc_clock = lpt_iclkip(pipe_config); return 0; @@ -610,18 +619,18 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) } static const struct drm_edid *intel_crt_get_edid(struct drm_connector *connector, - struct i2c_adapter *i2c) + struct i2c_adapter *ddc) { const struct drm_edid *drm_edid; - drm_edid = drm_edid_read_ddc(connector, i2c); + drm_edid = drm_edid_read_ddc(connector, ddc); - if (!drm_edid && !intel_gmbus_is_forced_bit(i2c)) { + if (!drm_edid && !intel_gmbus_is_forced_bit(ddc)) { drm_dbg_kms(connector->dev, "CRT GMBUS EDID read failed, retry using GPIO bit-banging\n"); - intel_gmbus_force_bit(i2c, true); - drm_edid = drm_edid_read_ddc(connector, i2c); - intel_gmbus_force_bit(i2c, false); + intel_gmbus_force_bit(ddc, true); + drm_edid = drm_edid_read_ddc(connector, ddc); + intel_gmbus_force_bit(ddc, false); } return drm_edid; @@ -629,12 +638,12 @@ static const struct drm_edid *intel_crt_get_edid(struct drm_connector *connector /* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */ static int intel_crt_ddc_get_modes(struct drm_connector *connector, - struct i2c_adapter *adapter) + struct i2c_adapter *ddc) { const struct drm_edid *drm_edid; int ret; - drm_edid = intel_crt_get_edid(connector, adapter); + drm_edid = intel_crt_get_edid(connector, ddc); if (!drm_edid) return 0; @@ -650,28 +659,23 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector)); struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev); const struct drm_edid *drm_edid; - struct i2c_adapter *i2c; bool ret = false; - i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->display.vbt.crt_ddc_pin); - drm_edid = intel_crt_get_edid(connector, i2c); + drm_edid = intel_crt_get_edid(connector, connector->ddc); if (drm_edid) { - const struct edid *edid = drm_edid_raw(drm_edid); - bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; - /* * This may be a DVI-I connector with a shared DDC * link between analog and digital outputs, so we * have to check the EDID input spec of the attached device. */ - if (!is_digital) { + if (drm_edid_is_digital(drm_edid)) { drm_dbg_kms(&dev_priv->drm, - "CRT detected via DDC:0x50 [EDID]\n"); - ret = true; + "CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); } else { drm_dbg_kms(&dev_priv->drm, - "CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); + "CRT detected via DDC:0x50 [EDID]\n"); + ret = true; } } else { drm_dbg_kms(&dev_priv->drm, @@ -834,7 +838,7 @@ intel_crt_detect(struct drm_connector *connector, connector->base.id, connector->name, force); - if (!INTEL_DISPLAY_ENABLED(dev_priv)) + if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; if (dev_priv->params.load_detect_test) { @@ -907,12 +911,6 @@ load_detect: out: intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref); - /* - * Make sure the refs for power wells enabled during detect are - * dropped to avoid a new detect cycle triggered by HPD polling. - */ - intel_display_power_flush_work(dev_priv); - return status; } @@ -923,20 +921,19 @@ static int intel_crt_get_modes(struct drm_connector *connector) struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector)); struct intel_encoder *intel_encoder = &crt->base; intel_wakeref_t wakeref; - struct i2c_adapter *i2c; + struct i2c_adapter *ddc; int ret; wakeref = intel_display_power_get(dev_priv, intel_encoder->power_domain); - i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->display.vbt.crt_ddc_pin); - ret = intel_crt_ddc_get_modes(connector, i2c); + ret = intel_crt_ddc_get_modes(connector, connector->ddc); if (ret || !IS_G4X(dev_priv)) goto out; /* Try to probe digital port for output in DVI-I -> VGA mode. */ - i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB); - ret = intel_crt_ddc_get_modes(connector, i2c); + ddc = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB); + ret = intel_crt_ddc_get_modes(connector, ddc); out: intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref); @@ -994,6 +991,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv) struct intel_crt *crt; struct intel_connector *intel_connector; i915_reg_t adpa_reg; + u8 ddc_pin; u32 adpa; if (HAS_PCH_SPLIT(dev_priv)) @@ -1030,10 +1028,14 @@ void intel_crt_init(struct drm_i915_private *dev_priv) return; } + ddc_pin = dev_priv->display.vbt.crt_ddc_pin; + connector = &intel_connector->base; crt->connector = intel_connector; - drm_connector_init(&dev_priv->drm, &intel_connector->base, - &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); + drm_connector_init_with_ddc(&dev_priv->drm, connector, + &intel_crt_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + intel_gmbus_get_adapter(dev_priv, ddc_pin)); drm_encoder_init(&dev_priv->drm, &crt->base.base, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC, "CRT"); diff --git a/drivers/gpu/drm/i915/display/intel_crt.h b/drivers/gpu/drm/i915/display/intel_crt.h index c6071efd93ce..fe7690c2b948 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.h +++ b/drivers/gpu/drm/i915/display/intel_crt.h @@ -12,9 +12,23 @@ enum pipe; struct drm_encoder; struct drm_i915_private; +#ifdef I915 bool intel_crt_port_enabled(struct drm_i915_private *dev_priv, i915_reg_t adpa_reg, enum pipe *pipe); void intel_crt_init(struct drm_i915_private *dev_priv); void intel_crt_reset(struct drm_encoder *encoder); +#else +static inline bool intel_crt_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t adpa_reg, enum pipe *pipe) +{ + return false; +} +static inline void intel_crt_init(struct drm_i915_private *dev_priv) +{ +} +static inline void intel_crt_reset(struct drm_encoder *encoder) +{ +} +#endif #endif /* __INTEL_CRT_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 182c6dd64f47..1fd068e6e26c 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -24,6 +24,7 @@ #include "intel_display_trace.h" #include "intel_display_types.h" #include "intel_drrs.h" +#include "intel_dsb.h" #include "intel_dsi.h" #include "intel_fifo_underrun.h" #include "intel_pipe_crc.h" @@ -175,6 +176,7 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state, crtc_state->hsw_workaround_pipe = INVALID_PIPE; crtc_state->scaler_state.scaler_id = -1; crtc_state->mst_master_transcoder = INVALID_TRANSCODER; + crtc_state->max_link_bpp_x16 = INT_MAX; } static struct intel_crtc *intel_crtc_alloc(void) @@ -394,7 +396,8 @@ static bool intel_crtc_needs_vblank_work(const struct intel_crtc_state *crtc_sta return crtc_state->hw.active && !intel_crtc_needs_modeset(crtc_state) && !crtc_state->preload_luts && - intel_crtc_needs_color_update(crtc_state); + intel_crtc_needs_color_update(crtc_state) && + !intel_color_uses_dsb(crtc_state); } static void intel_crtc_vblank_work(struct kthread_work *base) @@ -468,9 +471,64 @@ static int intel_mode_vblank_start(const struct drm_display_mode *mode) return vblank_start; } +static void intel_crtc_vblank_evade_scanlines(struct intel_atomic_state *state, + struct intel_crtc *crtc, + int *min, int *max, int *vblank_start) +{ + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + const struct intel_crtc_state *crtc_state; + const struct drm_display_mode *adjusted_mode; + + /* + * During fastsets/etc. the transcoder is still + * running with the old timings at this point. + * + * TODO: maybe just use the active timings here? + */ + if (intel_crtc_needs_modeset(new_crtc_state)) + crtc_state = new_crtc_state; + else + crtc_state = old_crtc_state; + + adjusted_mode = &crtc_state->hw.adjusted_mode; + + if (crtc->mode_flags & I915_MODE_FLAG_VRR) { + /* timing changes should happen with VRR disabled */ + drm_WARN_ON(state->base.dev, intel_crtc_needs_modeset(new_crtc_state) || + new_crtc_state->update_m_n || new_crtc_state->update_lrr); + + if (intel_vrr_is_push_sent(crtc_state)) + *vblank_start = intel_vrr_vmin_vblank_start(crtc_state); + else + *vblank_start = intel_vrr_vmax_vblank_start(crtc_state); + } else { + *vblank_start = intel_mode_vblank_start(adjusted_mode); + } + + /* FIXME needs to be calibrated sensibly */ + *min = *vblank_start - intel_usecs_to_scanlines(adjusted_mode, + VBLANK_EVASION_TIME_US); + *max = *vblank_start - 1; + + /* + * M/N and TRANS_VTOTAL are double buffered on the transcoder's + * undelayed vblank, so with seamless M/N and LRR we must evade + * both vblanks. + * + * DSB execution waits for the transcoder's undelayed vblank, + * hence we must kick off the commit before that. + */ + if (new_crtc_state->dsb || new_crtc_state->update_m_n || new_crtc_state->update_lrr) + *min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; +} + /** * intel_pipe_update_start() - start update of a set of display registers - * @new_crtc_state: the new crtc state + * @state: the atomic state + * @crtc: the crtc * * Mark the start of an update to pipe registers that should be updated * atomically regarding vblank. If the next vblank will happens within @@ -480,11 +538,12 @@ static int intel_mode_vblank_start(const struct drm_display_mode *mode) * until a subsequent call to intel_pipe_update_end(). That is done to * avoid random delays. */ -void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) +void intel_pipe_update_start(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - const struct drm_display_mode *adjusted_mode = &new_crtc_state->hw.adjusted_mode; + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); long timeout = msecs_to_jiffies_timeout(1); int scanline, min, max, vblank_start; wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); @@ -500,27 +559,7 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) if (intel_crtc_needs_vblank_work(new_crtc_state)) intel_crtc_vblank_work_init(new_crtc_state); - if (new_crtc_state->vrr.enable) { - if (intel_vrr_is_push_sent(new_crtc_state)) - vblank_start = intel_vrr_vmin_vblank_start(new_crtc_state); - else - vblank_start = intel_vrr_vmax_vblank_start(new_crtc_state); - } else { - vblank_start = intel_mode_vblank_start(adjusted_mode); - } - - /* FIXME needs to be calibrated sensibly */ - min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, - VBLANK_EVASION_TIME_US); - max = vblank_start - 1; - - /* - * M/N is double buffered on the transcoder's undelayed vblank, - * so with seamless M/N we must evade both vblanks. - */ - if (new_crtc_state->seamless_m_n && intel_crtc_needs_fastset(new_crtc_state)) - min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; - + intel_crtc_vblank_evade_scanlines(state, crtc, &min, &max, &vblank_start); if (min <= 0 || max <= 0) goto irq_disable; @@ -631,25 +670,26 @@ static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) {} /** * intel_pipe_update_end() - end update of a set of display registers - * @new_crtc_state: the new crtc state + * @state: the atomic state + * @crtc: the crtc * * Mark the end of an update started with intel_pipe_update_start(). This * re-enables interrupts and verifies the update was actually completed * before a vblank. */ -void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) +void intel_pipe_update_end(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); enum pipe pipe = crtc->pipe; int scanline_end = intel_get_crtc_scanline(crtc); u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); ktime_t end_vbl_time = ktime_get(); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - intel_psr_unlock(new_crtc_state); - if (new_crtc_state->do_async_flip) - return; + goto out; trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end); @@ -697,19 +737,10 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) */ intel_vrr_send_push(new_crtc_state); - /* - * Seamless M/N update may need to update frame timings. - * - * FIXME Should be synchronized with the start of vblank somehow... - */ - if (new_crtc_state->seamless_m_n && intel_crtc_needs_fastset(new_crtc_state)) - intel_crtc_update_active_timings(new_crtc_state, - new_crtc_state->vrr.enable); - local_irq_enable(); if (intel_vgpu_active(dev_priv)) - return; + goto out; if (crtc->debug.start_vbl_count && crtc->debug.start_vbl_count != end_vbl_count) { @@ -724,4 +755,7 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) } dbg_vblank_evade(crtc, end_vbl_time); + +out: + intel_psr_unlock(new_crtc_state); } diff --git a/drivers/gpu/drm/i915/display/intel_crtc.h b/drivers/gpu/drm/i915/display/intel_crtc.h index 51a4c8df9e65..22d7993d1f0b 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.h +++ b/drivers/gpu/drm/i915/display/intel_crtc.h @@ -36,8 +36,10 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state, u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc); void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state); void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state); -void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state); -void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state); +void intel_pipe_update_start(struct intel_atomic_state *state, + struct intel_crtc *crtc); +void intel_pipe_update_end(struct intel_atomic_state *state, + struct intel_crtc *crtc); void intel_wait_for_vblank_workers(struct intel_atomic_state *state); struct intel_crtc *intel_first_crtc(struct drm_i915_private *i915); struct intel_crtc *intel_crtc_for_pipe(struct drm_i915_private *i915, diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 8d4640d0fd34..66fe880af8f3 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -258,6 +258,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, intel_dump_m_n_config(pipe_config, "dp m2_n2", pipe_config->lane_count, &pipe_config->dp_m2_n2); + drm_dbg_kms(&i915->drm, "fec: %s, enhanced framing: %s\n", + str_enabled_disabled(pipe_config->fec_enable), + str_enabled_disabled(pipe_config->enhanced_framing)); } drm_dbg_kms(&i915->drm, "framestart delay: %d, MSA timing delay: %d\n", diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 1b00ef2c6185..6e6a1818071e 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -31,7 +31,7 @@ bool intel_is_c10phy(struct drm_i915_private *i915, enum phy phy) { - if (IS_METEORLAKE(i915) && (phy < PHY_C)) + if (DISPLAY_VER_FULL(i915) == IP_VER(14, 0) && phy < PHY_C) return true; return false; @@ -46,6 +46,22 @@ static int lane_mask_to_lane(u8 lane_mask) return ilog2(lane_mask); } +static u8 intel_cx0_get_owned_lane_mask(struct drm_i915_private *i915, + struct intel_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (!intel_tc_port_in_dp_alt_mode(dig_port)) + return INTEL_CX0_BOTH_LANES; + + /* + * In DP-alt with pin assignment D, only PHY lane 0 is owned + * by display and lane 1 is owned by USB. + */ + return intel_tc_port_max_lane_count(dig_port) > 2 + ? INTEL_CX0_BOTH_LANES : INTEL_CX0_LANE0; +} + static void assert_dc_off(struct drm_i915_private *i915) { @@ -55,19 +71,38 @@ assert_dc_off(struct drm_i915_private *i915) drm_WARN_ON(&i915->drm, !enabled); } +static void intel_cx0_program_msgbus_timer(struct intel_encoder *encoder) +{ + int lane; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + for_each_cx0_lane_in_mask(INTEL_CX0_BOTH_LANES, lane) + intel_de_rmw(i915, + XELPDP_PORT_MSGBUS_TIMER(encoder->port, lane), + XELPDP_PORT_MSGBUS_TIMER_VAL_MASK, + XELPDP_PORT_MSGBUS_TIMER_VAL); +} + /* * Prepare HW for CX0 phy transactions. * * It is required that PSR and DC5/6 are disabled before any CX0 message * bus transaction is executed. + * + * We also do the msgbus timer programming here to ensure that the timer + * is already programmed before any access to the msgbus. */ static intel_wakeref_t intel_cx0_phy_transaction_begin(struct intel_encoder *encoder) { + intel_wakeref_t wakeref; struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_psr_pause(intel_dp); - return intel_display_power_get(i915, POWER_DOMAIN_DC_OFF); + wakeref = intel_display_power_get(i915, POWER_DOMAIN_DC_OFF); + intel_cx0_program_msgbus_timer(encoder); + + return wakeref; } static void intel_cx0_phy_transaction_end(struct intel_encoder *encoder, intel_wakeref_t wakeref) @@ -116,6 +151,13 @@ static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port, XELPDP_MSGBUS_TIMEOUT_SLOW, val)) { drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for message ACK. Status: 0x%x\n", phy_name(phy), *val); + + if (!(intel_de_read(i915, XELPDP_PORT_MSGBUS_TIMER(port, lane)) & + XELPDP_PORT_MSGBUS_TIMER_TIMED_OUT)) + drm_dbg_kms(&i915->drm, + "PHY %c Hardware did not detect a timeout\n", + phy_name(phy)); + intel_cx0_bus_reset(i915, port, lane); return -ETIMEDOUT; } @@ -359,6 +401,7 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(i915, encoder->port); + u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); intel_wakeref_t wakeref; int n_entries, ln; @@ -371,13 +414,13 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, } if (intel_is_c10phy(i915, phy)) { - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CMN(3), + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_CMN(3), C10_CMN3_TXVBOOST_MASK, C10_CMN3_TXVBOOST(intel_c10_get_tx_vboost_lvl(crtc_state)), MB_WRITE_UNCOMMITTED); - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_TX(1), + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_TX(1), C10_TX1_TERMCTL_MASK, C10_TX1_TERMCTL(intel_c10_get_tx_term_ctl(crtc_state)), MB_WRITE_COMMITTED); @@ -385,32 +428,34 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, for (ln = 0; ln < crtc_state->lane_count; ln++) { int level = intel_ddi_level(encoder, crtc_state, ln); - int lane, tx; + int lane = ln / 2; + int tx = ln % 2; + u8 lane_mask = lane == 0 ? INTEL_CX0_LANE0 : INTEL_CX0_LANE1; - lane = ln / 2; - tx = ln % 2; + if (!(lane_mask & owned_lane_mask)) + continue; - intel_cx0_rmw(i915, encoder->port, BIT(lane), PHY_CX0_VDROVRD_CTL(lane, tx, 0), + intel_cx0_rmw(i915, encoder->port, lane_mask, PHY_CX0_VDROVRD_CTL(lane, tx, 0), C10_PHY_OVRD_LEVEL_MASK, C10_PHY_OVRD_LEVEL(trans->entries[level].snps.pre_cursor), MB_WRITE_COMMITTED); - intel_cx0_rmw(i915, encoder->port, BIT(lane), PHY_CX0_VDROVRD_CTL(lane, tx, 1), + intel_cx0_rmw(i915, encoder->port, lane_mask, PHY_CX0_VDROVRD_CTL(lane, tx, 1), C10_PHY_OVRD_LEVEL_MASK, C10_PHY_OVRD_LEVEL(trans->entries[level].snps.vswing), MB_WRITE_COMMITTED); - intel_cx0_rmw(i915, encoder->port, BIT(lane), PHY_CX0_VDROVRD_CTL(lane, tx, 2), + intel_cx0_rmw(i915, encoder->port, lane_mask, PHY_CX0_VDROVRD_CTL(lane, tx, 2), C10_PHY_OVRD_LEVEL_MASK, C10_PHY_OVRD_LEVEL(trans->entries[level].snps.post_cursor), MB_WRITE_COMMITTED); } /* Write Override enables in 0xD71 */ - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_OVRD, + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_OVRD, 0, PHY_C10_VDR_OVRD_TX1 | PHY_C10_VDR_OVRD_TX2, MB_WRITE_COMMITTED); if (intel_is_c10phy(i915, phy)) - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED); intel_cx0_phy_transaction_end(encoder, wakeref); @@ -2534,17 +2579,15 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915, { enum port port = encoder->port; enum phy phy = intel_port_to_phy(i915, port); - bool both_lanes = intel_tc_port_fia_max_lane_count(enc_to_dig_port(encoder)) > 2; - u8 lane_mask = lane_reversal ? INTEL_CX0_LANE1 : - INTEL_CX0_LANE0; - u32 lane_pipe_reset = both_lanes ? - XELPDP_LANE_PIPE_RESET(0) | - XELPDP_LANE_PIPE_RESET(1) : - XELPDP_LANE_PIPE_RESET(0); - u32 lane_phy_current_status = both_lanes ? - XELPDP_LANE_PHY_CURRENT_STATUS(0) | - XELPDP_LANE_PHY_CURRENT_STATUS(1) : - XELPDP_LANE_PHY_CURRENT_STATUS(0); + u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); + u8 lane_mask = lane_reversal ? INTEL_CX0_LANE1 : INTEL_CX0_LANE0; + u32 lane_pipe_reset = owned_lane_mask == INTEL_CX0_BOTH_LANES + ? XELPDP_LANE_PIPE_RESET(0) | XELPDP_LANE_PIPE_RESET(1) + : XELPDP_LANE_PIPE_RESET(0); + u32 lane_phy_current_status = owned_lane_mask == INTEL_CX0_BOTH_LANES + ? (XELPDP_LANE_PHY_CURRENT_STATUS(0) | + XELPDP_LANE_PHY_CURRENT_STATUS(1)) + : XELPDP_LANE_PHY_CURRENT_STATUS(0); if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL1(port), XELPDP_PORT_BUF_SOC_PHY_READY, @@ -2553,8 +2596,7 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915, drm_warn(&i915->drm, "PHY %c failed to bring out of SOC reset after %dus.\n", phy_name(phy), XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US); - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), - XELPDP_LANE_PIPE_RESET(0) | XELPDP_LANE_PIPE_RESET(1), + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), lane_pipe_reset, lane_pipe_reset); if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL2(port), @@ -2564,15 +2606,11 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915, phy_name(phy), XELPDP_PORT_RESET_START_TIMEOUT_US); intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(port), - intel_cx0_get_pclk_refclk_request(both_lanes ? - INTEL_CX0_BOTH_LANES : - INTEL_CX0_LANE0), + intel_cx0_get_pclk_refclk_request(owned_lane_mask), intel_cx0_get_pclk_refclk_request(lane_mask)); if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(port), - intel_cx0_get_pclk_refclk_ack(both_lanes ? - INTEL_CX0_BOTH_LANES : - INTEL_CX0_LANE0), + intel_cx0_get_pclk_refclk_ack(owned_lane_mask), intel_cx0_get_pclk_refclk_ack(lane_mask), XELPDP_REFCLK_ENABLE_TIMEOUT_US, 0, NULL)) drm_warn(&i915->drm, "PHY %c failed to request refclk after %dus.\n", @@ -2594,79 +2632,43 @@ static void intel_cx0_program_phy_lane(struct drm_i915_private *i915, struct intel_encoder *encoder, int lane_count, bool lane_reversal) { - u8 l0t1, l0t2, l1t1, l1t2; + int i; + u8 disables; bool dp_alt_mode = intel_tc_port_in_dp_alt_mode(enc_to_dig_port(encoder)); + u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); enum port port = encoder->port; if (intel_is_c10phy(i915, intel_port_to_phy(i915, port))) - intel_cx0_rmw(i915, port, INTEL_CX0_BOTH_LANES, + intel_cx0_rmw(i915, port, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); - /* TODO: DP-alt MFD case where only one PHY lane should be programmed. */ - l0t1 = intel_cx0_read(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(1, 2)); - l0t2 = intel_cx0_read(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(2, 2)); - l1t1 = intel_cx0_read(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(1, 2)); - l1t2 = intel_cx0_read(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(2, 2)); - - l0t1 |= CONTROL2_DISABLE_SINGLE_TX; - l0t2 |= CONTROL2_DISABLE_SINGLE_TX; - l1t1 |= CONTROL2_DISABLE_SINGLE_TX; - l1t2 |= CONTROL2_DISABLE_SINGLE_TX; - - if (lane_reversal) { - switch (lane_count) { - case 4: - l0t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 3: - l0t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 2: - l1t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 1: - l1t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - break; - default: - MISSING_CASE(lane_count); - } - } else { - switch (lane_count) { - case 4: - l1t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 3: - l1t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 2: - l0t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - l0t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - break; - case 1: - if (dp_alt_mode) - l0t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - else - l0t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - break; - default: - MISSING_CASE(lane_count); - } + if (lane_reversal) + disables = REG_GENMASK8(3, 0) >> lane_count; + else + disables = REG_GENMASK8(3, 0) << lane_count; + + if (dp_alt_mode && lane_count == 1) { + disables &= ~REG_GENMASK8(1, 0); + disables |= REG_FIELD_PREP8(REG_GENMASK8(1, 0), 0x1); } - /* disable MLs */ - intel_cx0_write(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(1, 2), - l0t1, MB_WRITE_COMMITTED); - intel_cx0_write(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(2, 2), - l0t2, MB_WRITE_COMMITTED); - intel_cx0_write(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(1, 2), - l1t1, MB_WRITE_COMMITTED); - intel_cx0_write(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(2, 2), - l1t2, MB_WRITE_COMMITTED); + for (i = 0; i < 4; i++) { + int tx = i % 2 + 1; + u8 lane_mask = i < 2 ? INTEL_CX0_LANE0 : INTEL_CX0_LANE1; + + if (!(owned_lane_mask & lane_mask)) + continue; + + intel_cx0_rmw(i915, port, lane_mask, PHY_CX0_TX_CONTROL(tx, 2), + CONTROL2_DISABLE_SINGLE_TX, + disables & BIT(i) ? CONTROL2_DISABLE_SINGLE_TX : 0, + MB_WRITE_COMMITTED); + } if (intel_is_c10phy(i915, intel_port_to_phy(i915, port))) - intel_cx0_rmw(i915, port, INTEL_CX0_BOTH_LANES, + intel_cx0_rmw(i915, port, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED); @@ -2721,39 +2723,45 @@ static void intel_cx0pll_enable(struct intel_encoder *encoder, intel_cx0_powerdown_change_sequence(i915, encoder->port, INTEL_CX0_BOTH_LANES, CX0_P2_STATE_READY); - /* 4. Program PHY internal PLL internal registers. */ + /* + * 4. Program PORT_MSGBUS_TIMER register's Message Bus Timer field to 0xA000. + * (This is done inside intel_cx0_phy_transaction_begin(), since we would need + * the right timer thresholds for readouts too.) + */ + + /* 5. Program PHY internal PLL internal registers. */ if (intel_is_c10phy(i915, phy)) intel_c10_pll_program(i915, crtc_state, encoder); else intel_c20_pll_program(i915, crtc_state, encoder); /* - * 5. Program the enabled and disabled owned PHY lane + * 6. Program the enabled and disabled owned PHY lane * transmitters over message bus */ intel_cx0_program_phy_lane(i915, encoder, crtc_state->lane_count, lane_reversal); /* - * 6. Follow the Display Voltage Frequency Switching - Sequence + * 7. Follow the Display Voltage Frequency Switching - Sequence * Before Frequency Change. We handle this step in bxt_set_cdclk(). */ /* - * 7. Program DDI_CLK_VALFREQ to match intended DDI + * 8. Program DDI_CLK_VALFREQ to match intended DDI * clock frequency. */ intel_de_write(i915, DDI_CLK_VALFREQ(encoder->port), crtc_state->port_clock); /* - * 8. Set PORT_CLOCK_CTL register PCLK PLL Request + * 9. Set PORT_CLOCK_CTL register PCLK PLL Request * LN<Lane for maxPCLK> to "1" to enable PLL. */ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES), intel_cx0_get_pclk_pll_request(maxpclk_lane)); - /* 9. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK> == "1". */ + /* 10. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK> == "1". */ if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES), intel_cx0_get_pclk_pll_ack(maxpclk_lane), @@ -2762,7 +2770,7 @@ static void intel_cx0pll_enable(struct intel_encoder *encoder, phy_name(phy), XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US); /* - * 10. Follow the Display Voltage Frequency Switching Sequence After + * 11. Follow the Display Voltage Frequency Switching Sequence After * Frequency Change. We handle this step in bxt_set_cdclk(). */ @@ -2996,12 +3004,13 @@ intel_mtl_port_pll_type(struct intel_encoder *encoder, } void intel_c10pll_state_verify(struct intel_atomic_state *state, - struct intel_crtc_state *new_crtc_state) + struct intel_crtc *crtc) { struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); struct intel_c10pll_state mpllb_hw_state = { 0 }; - struct intel_c10pll_state *mpllb_sw_state = &new_crtc_state->cx0pll_state.c10; - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + const struct intel_c10pll_state *mpllb_sw_state = &new_crtc_state->cx0pll_state.c10; struct intel_encoder *encoder; enum phy phy; int i; diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 4c4db5cdcbd0..0e0a38dac8cd 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -10,14 +10,16 @@ #include <linux/bitfield.h> #include <linux/bits.h> -#include "i915_drv.h" -#include "intel_display_types.h" - -struct drm_i915_private; -struct intel_encoder; -struct intel_crtc_state; enum icl_port_dpll_id; enum phy; +struct drm_i915_private; +struct intel_atomic_state; +struct intel_c10pll_state; +struct intel_c20pll_state; +struct intel_crtc; +struct intel_crtc_state; +struct intel_encoder; +struct intel_hdmi; bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy); void intel_mtl_pll_enable(struct intel_encoder *encoder, @@ -33,7 +35,7 @@ void intel_c10pll_dump_hw_state(struct drm_i915_private *dev_priv, int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, const struct intel_c10pll_state *pll_state); void intel_c10pll_state_verify(struct intel_atomic_state *state, - struct intel_crtc_state *new_crtc_state); + struct intel_crtc *crtc); void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, struct intel_c20pll_state *pll_state); void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, @@ -44,4 +46,5 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); int intel_cx0_phy_check_hdmi_link_rate(struct intel_hdmi *hdmi, int clock); int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder); + #endif /* __INTEL_CX0_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index cb5d1be2ba19..adf8f4ce0d49 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -110,6 +110,19 @@ #define CX0_P4PG_STATE_DISABLE 0xC #define CX0_P2_STATE_RESET 0x2 +#define _XELPDP_PORT_MSGBUS_TIMER_LN0_A 0x640d8 +#define _XELPDP_PORT_MSGBUS_TIMER_LN0_B 0x641d8 +#define _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC1 0x16f258 +#define _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC2 0x16f458 +#define XELPDP_PORT_MSGBUS_TIMER(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ + _XELPDP_PORT_MSGBUS_TIMER_LN0_A, \ + _XELPDP_PORT_MSGBUS_TIMER_LN0_B, \ + _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC1, \ + _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC2) + (lane) * 4) +#define XELPDP_PORT_MSGBUS_TIMER_TIMED_OUT REG_BIT(31) +#define XELPDP_PORT_MSGBUS_TIMER_VAL_MASK REG_GENMASK(23, 0) +#define XELPDP_PORT_MSGBUS_TIMER_VAL REG_FIELD_PREP(XELPDP_PORT_MSGBUS_TIMER_VAL_MASK, 0xa000) + #define _XELPDP_PORT_CLOCK_CTL_A 0x640E0 #define _XELPDP_PORT_CLOCK_CTL_B 0x641E0 #define _XELPDP_PORT_CLOCK_CTL_USBC1 0x16F260 diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 84bbf854337a..9151d5add960 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3248,7 +3248,7 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_ddi_enable_transcoder_func(encoder, crtc_state); /* Enable/Disable DP2.0 SDP split config before transcoder */ - intel_audio_sdp_split_update(encoder, crtc_state); + intel_audio_sdp_split_update(crtc_state); intel_enable_transcoder(crtc_state); @@ -3432,7 +3432,7 @@ static void mtl_ddi_prepare_link_retrain(struct intel_dp *intel_dp, dp_tp_ctl |= DP_TP_CTL_MODE_MST; } else { dp_tp_ctl |= DP_TP_CTL_MODE_SST; - if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + if (crtc_state->enhanced_framing) dp_tp_ctl |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; } intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl); @@ -3489,7 +3489,7 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp, dp_tp_ctl |= DP_TP_CTL_MODE_MST; } else { dp_tp_ctl |= DP_TP_CTL_MODE_SST; - if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + if (crtc_state->enhanced_framing) dp_tp_ctl |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; } intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl); @@ -3724,17 +3724,14 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, intel_cpu_transcoder_get_m2_n2(crtc, cpu_transcoder, &pipe_config->dp_m2_n2); - if (DISPLAY_VER(dev_priv) >= 11) { - i915_reg_t dp_tp_ctl = dp_tp_ctl_reg(encoder, pipe_config); + pipe_config->enhanced_framing = + intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, pipe_config)) & + DP_TP_CTL_ENHANCED_FRAME_ENABLE; + if (DISPLAY_VER(dev_priv) >= 11) pipe_config->fec_enable = - intel_de_read(dev_priv, dp_tp_ctl) & DP_TP_CTL_FEC_ENABLE; - - drm_dbg_kms(&dev_priv->drm, - "[ENCODER:%d:%s] Fec status: %u\n", - encoder->base.base.id, encoder->base.name, - pipe_config->fec_enable); - } + intel_de_read(dev_priv, + dp_tp_ctl_reg(encoder, pipe_config)) & DP_TP_CTL_FEC_ENABLE; if (dig_port->lspcon.active && intel_dp_has_hdmi_sink(&dig_port->dp)) pipe_config->infoframes.enable |= @@ -3747,6 +3744,9 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, if (!HAS_DP20(dev_priv)) { /* FDI */ pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG); + pipe_config->enhanced_framing = + intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, pipe_config)) & + DP_TP_CTL_ENHANCED_FRAME_ENABLE; break; } fallthrough; /* 128b/132b */ @@ -3762,6 +3762,11 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, intel_cpu_transcoder_get_m1_n1(crtc, cpu_transcoder, &pipe_config->dp_m_n); + if (DISPLAY_VER(dev_priv) >= 11) + pipe_config->fec_enable = + intel_de_read(dev_priv, + dp_tp_ctl_reg(encoder, pipe_config)) & DP_TP_CTL_FEC_ENABLE; + pipe_config->infoframes.enable |= intel_hdmi_infoframes_enabled(encoder, pipe_config); break; @@ -3857,11 +3862,9 @@ static void mtl_ddi_get_config(struct intel_encoder *encoder, crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); } else if (intel_is_c10phy(i915, phy)) { intel_c10pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10); - intel_c10pll_dump_hw_state(i915, &crtc_state->cx0pll_state.c10); crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10); } else { intel_c20pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c20); - intel_c20pll_dump_hw_state(i915, &crtc_state->cx0pll_state.c20); crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); } @@ -4173,7 +4176,7 @@ static int intel_ddi_compute_config_late(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; u8 port_sync_transcoders = 0; - drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] [CRTC:%d:%s]", + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] [CRTC:%d:%s]\n", encoder->base.base.id, encoder->base.name, crtc_state->uapi.crtc->base.id, crtc_state->uapi.crtc->name); @@ -4323,15 +4326,14 @@ static int intel_hdmi_reset_link(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_hdmi *hdmi = enc_to_intel_hdmi(encoder); struct intel_connector *connector = hdmi->attached_connector; - struct i2c_adapter *adapter = - intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); + struct i2c_adapter *ddc = connector->base.ddc; struct drm_connector_state *conn_state; struct intel_crtc_state *crtc_state; struct intel_crtc *crtc; u8 config; int ret; - if (!connector || connector->base.status != connector_status_connected) + if (connector->base.status != connector_status_connected) return 0; ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, @@ -4365,7 +4367,7 @@ static int intel_hdmi_reset_link(struct intel_encoder *encoder, !try_wait_for_completion(&conn_state->commit->hw_done)) return 0; - ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); + ret = drm_scdc_readb(ddc, SCDC_TMDS_CONFIG, &config); if (ret < 0) { drm_err(&dev_priv->drm, "[CONNECTOR:%d:%s] Failed to read TMDS config: %d\n", connector->base.base.id, connector->base.name, ret); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 763ab569d8f3..28d85e1e858e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -77,6 +77,7 @@ #include "intel_dpll_mgr.h" #include "intel_dpt.h" #include "intel_drrs.h" +#include "intel_dsb.h" #include "intel_dsi.h" #include "intel_dvo.h" #include "intel_fb.h" @@ -87,6 +88,7 @@ #include "intel_frontbuffer.h" #include "intel_hdmi.h" #include "intel_hotplug.h" +#include "intel_link_bw.h" #include "intel_lvds.h" #include "intel_lvds_regs.h" #include "intel_modeset_setup.h" @@ -726,7 +728,7 @@ static void icl_set_pipe_chicken(const struct intel_crtc_state *crtc_state) tmp |= UNDERRUN_RECOVERY_DISABLE_ADLP; /* Wa_14010547955:dg2 */ - if (IS_DG2_DISPLAY_STEP(dev_priv, STEP_B0, STEP_FOREVER)) + if (IS_DG2(dev_priv)) tmp |= DG2_RENDER_CCSTAG_4_3_EN; intel_de_write(dev_priv, PIPE_CHICKEN(pipe), tmp); @@ -913,16 +915,32 @@ static bool planes_disabling(const struct intel_crtc_state *old_crtc_state, return is_disabling(active_planes, old_crtc_state, new_crtc_state); } +static bool vrr_params_changed(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state) +{ + return old_crtc_state->vrr.flipline != new_crtc_state->vrr.flipline || + old_crtc_state->vrr.vmin != new_crtc_state->vrr.vmin || + old_crtc_state->vrr.vmax != new_crtc_state->vrr.vmax || + old_crtc_state->vrr.guardband != new_crtc_state->vrr.guardband || + old_crtc_state->vrr.pipeline_full != new_crtc_state->vrr.pipeline_full; +} + static bool vrr_enabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { - return is_enabling(vrr.enable, old_crtc_state, new_crtc_state); + return is_enabling(vrr.enable, old_crtc_state, new_crtc_state) || + (new_crtc_state->vrr.enable && + (new_crtc_state->update_m_n || new_crtc_state->update_lrr || + vrr_params_changed(old_crtc_state, new_crtc_state))); } static bool vrr_disabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { - return is_disabling(vrr.enable, old_crtc_state, new_crtc_state); + return is_disabling(vrr.enable, old_crtc_state, new_crtc_state) || + (old_crtc_state->vrr.enable && + (new_crtc_state->update_m_n || new_crtc_state->update_lrr || + vrr_params_changed(old_crtc_state, new_crtc_state))); } #undef is_disabling @@ -938,6 +956,8 @@ static void intel_post_plane_update(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); enum pipe pipe = crtc->pipe; + intel_psr_post_plane_update(state, crtc); + intel_frontbuffer_flip(dev_priv, new_crtc_state->fb_bits); if (new_crtc_state->update_wm_post && new_crtc_state->hw.active) @@ -1767,7 +1787,7 @@ bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy) if (IS_DG2(dev_priv)) /* DG2's "TC1" output uses a SNPS PHY */ return false; - else if (IS_ALDERLAKE_P(dev_priv) || IS_METEORLAKE(dev_priv)) + else if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER_FULL(dev_priv) == IP_VER(14, 0)) return phy >= PHY_F && phy <= PHY_I; else if (IS_TIGERLAKE(dev_priv)) return phy >= PHY_D && phy <= PHY_I; @@ -2570,6 +2590,37 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta VTOTAL(crtc_vtotal - 1)); } +static void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + u32 crtc_vdisplay, crtc_vtotal, crtc_vblank_start, crtc_vblank_end; + + crtc_vdisplay = adjusted_mode->crtc_vdisplay; + crtc_vtotal = adjusted_mode->crtc_vtotal; + crtc_vblank_start = adjusted_mode->crtc_vblank_start; + crtc_vblank_end = adjusted_mode->crtc_vblank_end; + + drm_WARN_ON(&dev_priv->drm, adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE); + + /* + * The hardware actually ignores TRANS_VBLANK.VBLANK_END in DP mode. + * But let's write it anyway to keep the state checker happy. + */ + intel_de_write(dev_priv, TRANS_VBLANK(cpu_transcoder), + VBLANK_START(crtc_vblank_start - 1) | + VBLANK_END(crtc_vblank_end - 1)); + /* + * The double buffer latch point for TRANS_VTOTAL + * is the transcoder's undelayed vblank. + */ + intel_de_write(dev_priv, TRANS_VTOTAL(cpu_transcoder), + VACTIVE(crtc_vdisplay - 1) | + VTOTAL(crtc_vtotal - 1)); +} + static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -2869,24 +2920,6 @@ bdw_get_pipe_misc_output_format(struct intel_crtc *crtc) } } -static void i9xx_get_pipe_color_config(struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct intel_plane *plane = to_intel_plane(crtc->base.primary); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - u32 tmp; - - tmp = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); - - if (tmp & DISP_PIPE_GAMMA_ENABLE) - crtc_state->gamma_enable = true; - - if (!HAS_GMCH(dev_priv) && - tmp & DISP_PIPE_CSC_ENABLE) - crtc_state->csc_enable = true; -} - static bool i9xx_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { @@ -2942,11 +2975,6 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, (tmp & TRANSCONF_WGC_ENABLE)) pipe_config->wgc_enable = true; - if (IS_CHERRYVIEW(dev_priv)) - pipe_config->cgm_mode = intel_de_read(dev_priv, - CGM_PIPE_MODE(crtc->pipe)); - - i9xx_get_pipe_color_config(pipe_config); intel_color_get_config(pipe_config); if (DISPLAY_VER(dev_priv) < 4) @@ -3344,10 +3372,6 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc, pipe_config->msa_timing_delay = REG_FIELD_GET(TRANSCONF_MSA_TIMING_DELAY_MASK, tmp); - pipe_config->csc_mode = intel_de_read(dev_priv, - PIPE_CSC_MODE(crtc->pipe)); - - i9xx_get_pipe_color_config(pipe_config); intel_color_get_config(pipe_config); pipe_config->pixel_multiplier = 1; @@ -3738,24 +3762,6 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, pipe_config->sink_format = pipe_config->output_format; - pipe_config->gamma_mode = intel_de_read(dev_priv, - GAMMA_MODE(crtc->pipe)); - - pipe_config->csc_mode = intel_de_read(dev_priv, - PIPE_CSC_MODE(crtc->pipe)); - - if (DISPLAY_VER(dev_priv) >= 9) { - tmp = intel_de_read(dev_priv, SKL_BOTTOM_COLOR(crtc->pipe)); - - if (tmp & SKL_BOTTOM_COLOR_GAMMA_ENABLE) - pipe_config->gamma_enable = true; - - if (tmp & SKL_BOTTOM_COLOR_CSC_ENABLE) - pipe_config->csc_enable = true; - } else { - i9xx_get_pipe_color_config(pipe_config); - } - intel_color_get_config(pipe_config); tmp = intel_de_read(dev_priv, WM_LINETIME(crtc->pipe)); @@ -3993,7 +3999,7 @@ intel_encoder_current_mode(struct intel_encoder *encoder) } if (!intel_crtc_get_pipe_config(crtc_state)) { - kfree(crtc_state); + intel_crtc_destroy_state(&crtc->base, &crtc_state->uapi); kfree(mode); return NULL; } @@ -4002,7 +4008,7 @@ intel_encoder_current_mode(struct intel_encoder *encoder) intel_mode_from_crtc_timings(mode, &crtc_state->hw.adjusted_mode); - kfree(crtc_state); + intel_crtc_destroy_state(&crtc->base, &crtc_state->uapi); return mode; } @@ -4641,7 +4647,8 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state, static int intel_modeset_pipe_config(struct intel_atomic_state *state, - struct intel_crtc *crtc) + struct intel_crtc *crtc, + const struct intel_link_bw_limits *limits) { struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_crtc_state *crtc_state = @@ -4650,7 +4657,6 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, struct drm_connector_state *connector_state; int pipe_src_w, pipe_src_h; int base_bpp, ret, i; - bool retry = true; crtc_state->cpu_transcoder = (enum transcoder) crtc->pipe; @@ -4673,6 +4679,16 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, if (ret) return ret; + crtc_state->max_link_bpp_x16 = limits->max_bpp_x16[crtc->pipe]; + + if (crtc_state->pipe_bpp > to_bpp_int(crtc_state->max_link_bpp_x16)) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s] Link bpp limited to " BPP_X16_FMT "\n", + crtc->base.base.id, crtc->base.name, + BPP_X16_ARGS(crtc_state->max_link_bpp_x16)); + crtc_state->bw_constrained = true; + } + base_bpp = crtc_state->pipe_bpp; /* @@ -4714,7 +4730,6 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, crtc_state->output_types |= BIT(encoder->type); } -encoder_retry: /* Ensure the port clock defaults are reset when retrying. */ crtc_state->port_clock = 0; crtc_state->pixel_multiplier = 1; @@ -4754,17 +4769,6 @@ encoder_retry: ret = intel_crtc_compute_config(state, crtc); if (ret == -EDEADLK) return ret; - if (ret == -EAGAIN) { - if (drm_WARN(&i915->drm, !retry, - "[CRTC:%d:%s] loop in pipe configuration computation\n", - crtc->base.base.id, crtc->base.name)) - return -EINVAL; - - drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] bw constrained, retrying\n", - crtc->base.base.id, crtc->base.name); - retry = false; - goto encoder_retry; - } if (ret < 0) { drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] config failure: %d\n", crtc->base.base.id, crtc->base.name, ret); @@ -4984,9 +4988,6 @@ pipe_config_mismatch(bool fastset, const struct intel_crtc *crtc, static bool fastboot_enabled(struct drm_i915_private *dev_priv) { - if (dev_priv->params.fastboot != -1) - return dev_priv->params.fastboot; - /* Enable fastboot by default on Skylake and newer */ if (DISPLAY_VER(dev_priv) >= 9) return true; @@ -5111,11 +5112,13 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(name.crtc_hsync_start); \ PIPE_CONF_CHECK_I(name.crtc_hsync_end); \ PIPE_CONF_CHECK_I(name.crtc_vdisplay); \ - PIPE_CONF_CHECK_I(name.crtc_vtotal); \ PIPE_CONF_CHECK_I(name.crtc_vblank_start); \ - PIPE_CONF_CHECK_I(name.crtc_vblank_end); \ PIPE_CONF_CHECK_I(name.crtc_vsync_start); \ PIPE_CONF_CHECK_I(name.crtc_vsync_end); \ + if (!fastset || !pipe_config->update_lrr) { \ + PIPE_CONF_CHECK_I(name.crtc_vtotal); \ + PIPE_CONF_CHECK_I(name.crtc_vblank_end); \ + } \ } while (0) #define PIPE_CONF_CHECK_RECT(name) do { \ @@ -5215,7 +5218,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_X(lane_lat_optim_mask); if (HAS_DOUBLE_BUFFERED_M_N(dev_priv)) { - if (!fastset || !pipe_config->seamless_m_n) + if (!fastset || !pipe_config->update_m_n) PIPE_CONF_CHECK_M_N(dp_m_n); } else { PIPE_CONF_CHECK_M_N(dp_m_n); @@ -5255,6 +5258,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_BOOL(hdmi_scrambling); PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio); PIPE_CONF_CHECK_BOOL(has_infoframe); + PIPE_CONF_CHECK_BOOL(enhanced_framing); PIPE_CONF_CHECK_BOOL(fec_enable); PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio); @@ -5352,7 +5356,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, if (IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) >= 5) PIPE_CONF_CHECK_I(pipe_bpp); - if (!fastset || !pipe_config->seamless_m_n) { + if (!fastset || !pipe_config->update_m_n) { PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_clock); PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_clock); } @@ -5377,6 +5381,37 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(master_transcoder); PIPE_CONF_CHECK_X(bigjoiner_pipes); + PIPE_CONF_CHECK_BOOL(dsc.config.block_pred_enable); + PIPE_CONF_CHECK_BOOL(dsc.config.convert_rgb); + PIPE_CONF_CHECK_BOOL(dsc.config.simple_422); + PIPE_CONF_CHECK_BOOL(dsc.config.native_422); + PIPE_CONF_CHECK_BOOL(dsc.config.native_420); + PIPE_CONF_CHECK_BOOL(dsc.config.vbr_enable); + PIPE_CONF_CHECK_I(dsc.config.line_buf_depth); + PIPE_CONF_CHECK_I(dsc.config.bits_per_component); + PIPE_CONF_CHECK_I(dsc.config.pic_width); + PIPE_CONF_CHECK_I(dsc.config.pic_height); + PIPE_CONF_CHECK_I(dsc.config.slice_width); + PIPE_CONF_CHECK_I(dsc.config.slice_height); + PIPE_CONF_CHECK_I(dsc.config.initial_dec_delay); + PIPE_CONF_CHECK_I(dsc.config.initial_xmit_delay); + PIPE_CONF_CHECK_I(dsc.config.scale_decrement_interval); + PIPE_CONF_CHECK_I(dsc.config.scale_increment_interval); + PIPE_CONF_CHECK_I(dsc.config.initial_scale_value); + PIPE_CONF_CHECK_I(dsc.config.first_line_bpg_offset); + PIPE_CONF_CHECK_I(dsc.config.flatness_min_qp); + PIPE_CONF_CHECK_I(dsc.config.flatness_max_qp); + PIPE_CONF_CHECK_I(dsc.config.slice_bpg_offset); + PIPE_CONF_CHECK_I(dsc.config.nfl_bpg_offset); + PIPE_CONF_CHECK_I(dsc.config.initial_offset); + PIPE_CONF_CHECK_I(dsc.config.final_offset); + PIPE_CONF_CHECK_I(dsc.config.rc_model_size); + PIPE_CONF_CHECK_I(dsc.config.rc_quant_incr_limit0); + PIPE_CONF_CHECK_I(dsc.config.rc_quant_incr_limit1); + PIPE_CONF_CHECK_I(dsc.config.slice_chunk_size); + PIPE_CONF_CHECK_I(dsc.config.second_line_bpg_offset); + PIPE_CONF_CHECK_I(dsc.config.nsl_bpg_offset); + PIPE_CONF_CHECK_I(dsc.compression_enable); PIPE_CONF_CHECK_I(dsc.dsc_split); PIPE_CONF_CHECK_I(dsc.compressed_bpp); @@ -5385,13 +5420,14 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(splitter.link_count); PIPE_CONF_CHECK_I(splitter.pixel_overlap); - if (!fastset) + if (!fastset) { PIPE_CONF_CHECK_BOOL(vrr.enable); - PIPE_CONF_CHECK_I(vrr.vmin); - PIPE_CONF_CHECK_I(vrr.vmax); - PIPE_CONF_CHECK_I(vrr.flipline); - PIPE_CONF_CHECK_I(vrr.pipeline_full); - PIPE_CONF_CHECK_I(vrr.guardband); + PIPE_CONF_CHECK_I(vrr.vmin); + PIPE_CONF_CHECK_I(vrr.vmax); + PIPE_CONF_CHECK_I(vrr.flipline); + PIPE_CONF_CHECK_I(vrr.pipeline_full); + PIPE_CONF_CHECK_I(vrr.guardband); + } #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I @@ -5420,17 +5456,54 @@ intel_verify_planes(struct intel_atomic_state *state) plane_state->uapi.visible); } -int intel_modeset_all_pipes(struct intel_atomic_state *state, - const char *reason) +static int intel_modeset_pipe(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state, + const char *reason) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + int ret; + + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] Full modeset due to %s\n", + crtc->base.base.id, crtc->base.name, reason); + + ret = drm_atomic_add_affected_connectors(&state->base, + &crtc->base); + if (ret) + return ret; + + ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc); + if (ret) + return ret; + + ret = intel_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + + crtc_state->uapi.mode_changed = true; + + return 0; +} + +/** + * intel_modeset_pipes_in_mask_early - force a full modeset on a set of pipes + * @state: intel atomic state + * @reason: the reason for the full modeset + * @mask: mask of pipes to modeset + * + * Add pipes in @mask to @state and force a full modeset on the enabled ones + * due to the description in @reason. + * This function can be called only before new plane states are computed. + * + * Returns 0 in case of success, negative error code otherwise. + */ +int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state, + const char *reason, u8 mask) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc *crtc; - /* - * Add all pipes to the state, and force - * a modeset on all the active ones. - */ - for_each_intel_crtc(&dev_priv->drm, crtc) { + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, mask) { struct intel_crtc_state *crtc_state; int ret; @@ -5438,29 +5511,54 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (!crtc_state->hw.active || + if (!crtc_state->hw.enable || intel_crtc_needs_modeset(crtc_state)) continue; - drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] Full modeset due to %s\n", - crtc->base.base.id, crtc->base.name, reason); - - crtc_state->uapi.mode_changed = true; - crtc_state->update_pipe = false; - - ret = drm_atomic_add_affected_connectors(&state->base, - &crtc->base); + ret = intel_modeset_pipe(state, crtc_state, reason); if (ret) return ret; + } - ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc); - if (ret) - return ret; + return 0; +} - ret = intel_atomic_add_affected_planes(state, crtc); +/** + * intel_modeset_all_pipes_late - force a full modeset on all pipes + * @state: intel atomic state + * @reason: the reason for the full modeset + * + * Add all pipes to @state and force a full modeset on the active ones due to + * the description in @reason. + * This function can be called only after new plane states are computed already. + * + * Returns 0 in case of success, negative error code otherwise. + */ +int intel_modeset_all_pipes_late(struct intel_atomic_state *state, + const char *reason) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_crtc *crtc; + + for_each_intel_crtc(&dev_priv->drm, crtc) { + struct intel_crtc_state *crtc_state; + int ret; + + crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->hw.active || + intel_crtc_needs_modeset(crtc_state)) + continue; + + ret = intel_modeset_pipe(state, crtc_state, reason); if (ret) return ret; + crtc_state->update_pipe = false; + crtc_state->update_m_n = false; + crtc_state->update_lrr = false; crtc_state->update_planes |= crtc_state->active_planes; crtc_state->async_flip_planes = 0; crtc_state->do_async_flip = false; @@ -5564,13 +5662,25 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta { struct drm_i915_private *i915 = to_i915(old_crtc_state->uapi.crtc->dev); - if (!intel_pipe_config_compare(old_crtc_state, new_crtc_state, true)) { + /* only allow LRR when the timings stay within the VRR range */ + if (old_crtc_state->vrr.in_range != new_crtc_state->vrr.in_range) + new_crtc_state->update_lrr = false; + + if (!intel_pipe_config_compare(old_crtc_state, new_crtc_state, true)) drm_dbg_kms(&i915->drm, "fastset requirement not met, forcing full modeset\n"); + else + new_crtc_state->uapi.mode_changed = false; - return; - } + if (intel_crtc_needs_modeset(new_crtc_state) || + intel_compare_link_m_n(&old_crtc_state->dp_m_n, + &new_crtc_state->dp_m_n)) + new_crtc_state->update_m_n = false; + + if (intel_crtc_needs_modeset(new_crtc_state) || + (old_crtc_state->hw.adjusted_mode.crtc_vtotal == new_crtc_state->hw.adjusted_mode.crtc_vtotal && + old_crtc_state->hw.adjusted_mode.crtc_vblank_end == new_crtc_state->hw.adjusted_mode.crtc_vblank_end)) + new_crtc_state->update_lrr = false; - new_crtc_state->uapi.mode_changed = false; if (!intel_crtc_needs_modeset(new_crtc_state)) new_crtc_state->update_pipe = true; } @@ -6171,6 +6281,101 @@ static int intel_bigjoiner_add_affected_crtcs(struct intel_atomic_state *state) return 0; } +static int intel_atomic_check_config(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits, + enum pipe *failed_pipe) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_crtc_state *new_crtc_state; + struct intel_crtc *crtc; + int ret; + int i; + + *failed_pipe = INVALID_PIPE; + + ret = intel_bigjoiner_add_affected_crtcs(state); + if (ret) + return ret; + + ret = intel_fdi_add_affected_crtcs(state); + if (ret) + return ret; + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + if (!intel_crtc_needs_modeset(new_crtc_state)) { + if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) + copy_bigjoiner_crtc_state_nomodeset(state, crtc); + else + intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc); + continue; + } + + if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) { + drm_WARN_ON(&i915->drm, new_crtc_state->uapi.enable); + continue; + } + + ret = intel_crtc_prepare_cleared_state(state, crtc); + if (ret) + break; + + if (!new_crtc_state->hw.enable) + continue; + + ret = intel_modeset_pipe_config(state, crtc, limits); + if (ret) + break; + + ret = intel_atomic_check_bigjoiner(state, crtc); + if (ret) + break; + } + + if (ret) + *failed_pipe = crtc->pipe; + + return ret; +} + +static int intel_atomic_check_config_and_link(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_link_bw_limits new_limits; + struct intel_link_bw_limits old_limits; + int ret; + + intel_link_bw_init_limits(i915, &new_limits); + old_limits = new_limits; + + while (true) { + enum pipe failed_pipe; + + ret = intel_atomic_check_config(state, &new_limits, + &failed_pipe); + if (ret) { + /* + * The bpp limit for a pipe is below the minimum it supports, set the + * limit to the minimum and recalculate the config. + */ + if (ret == -EINVAL && + intel_link_bw_set_bpp_limit_for_pipe(state, + &old_limits, + &new_limits, + failed_pipe)) + continue; + + break; + } + + old_limits = new_limits; + + ret = intel_link_bw_atomic_check(state, &new_limits); + if (ret != -EAGAIN) + break; + } + + return ret; +} /** * intel_atomic_check - validate state object * @dev: drm device @@ -6215,43 +6420,12 @@ int intel_atomic_check(struct drm_device *dev, return ret; } - ret = intel_bigjoiner_add_affected_crtcs(state); + ret = intel_atomic_check_config_and_link(state); if (ret) goto fail; for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - if (!intel_crtc_needs_modeset(new_crtc_state)) { - if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) - copy_bigjoiner_crtc_state_nomodeset(state, crtc); - else - intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc); - continue; - } - - if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) { - drm_WARN_ON(&dev_priv->drm, new_crtc_state->uapi.enable); - continue; - } - - ret = intel_crtc_prepare_cleared_state(state, crtc); - if (ret) - goto fail; - - if (!new_crtc_state->hw.enable) - continue; - - ret = intel_modeset_pipe_config(state, crtc); - if (ret) - goto fail; - - ret = intel_atomic_check_bigjoiner(state, crtc); - if (ret) - goto fail; - } - - for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, - new_crtc_state, i) { if (!intel_crtc_needs_modeset(new_crtc_state)) continue; @@ -6285,6 +6459,8 @@ int intel_atomic_check(struct drm_device *dev, if (intel_cpu_transcoders_need_modeset(state, BIT(master))) { new_crtc_state->uapi.mode_changed = true; new_crtc_state->update_pipe = false; + new_crtc_state->update_m_n = false; + new_crtc_state->update_lrr = false; } } @@ -6297,6 +6473,8 @@ int intel_atomic_check(struct drm_device *dev, if (intel_cpu_transcoders_need_modeset(state, trans)) { new_crtc_state->uapi.mode_changed = true; new_crtc_state->update_pipe = false; + new_crtc_state->update_m_n = false; + new_crtc_state->update_lrr = false; } } @@ -6304,6 +6482,8 @@ int intel_atomic_check(struct drm_device *dev, if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) { new_crtc_state->uapi.mode_changed = true; new_crtc_state->update_pipe = false; + new_crtc_state->update_m_n = false; + new_crtc_state->update_lrr = false; } } } @@ -6482,9 +6662,12 @@ static void intel_pipe_fastset(const struct intel_crtc_state *old_crtc_state, IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) hsw_set_linetime_wm(new_crtc_state); - if (new_crtc_state->seamless_m_n) + if (new_crtc_state->update_m_n) intel_cpu_transcoder_set_m1_n1(crtc, new_crtc_state->cpu_transcoder, &new_crtc_state->dp_m_n); + + if (new_crtc_state->update_lrr) + intel_set_transcoder_timings_lrr(new_crtc_state); } static void commit_pipe_pre_planes(struct intel_atomic_state *state, @@ -6521,6 +6704,8 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); const struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); @@ -6532,6 +6717,9 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) >= 9 && !intel_crtc_needs_modeset(new_crtc_state)) skl_detach_scalers(new_crtc_state); + + if (vrr_enabling(old_crtc_state, new_crtc_state)) + intel_vrr_enable(new_crtc_state); } static void intel_enable_crtc(struct intel_atomic_state *state, @@ -6572,12 +6760,6 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_dpt_configure(crtc); } - if (vrr_enabling(old_crtc_state, new_crtc_state)) { - intel_vrr_enable(new_crtc_state); - intel_crtc_update_active_timings(new_crtc_state, - new_crtc_state->vrr.enable); - } - if (!modeset) { if (new_crtc_state->preload_luts && intel_crtc_needs_color_update(new_crtc_state)) @@ -6591,6 +6773,9 @@ static void intel_update_crtc(struct intel_atomic_state *state, if (DISPLAY_VER(i915) >= 11 && intel_crtc_needs_fastset(new_crtc_state)) icl_set_pipe_chicken(new_crtc_state); + + if (vrr_params_changed(old_crtc_state, new_crtc_state)) + intel_vrr_set_transcoder_timings(new_crtc_state); } intel_fbc_update(state, crtc); @@ -6604,7 +6789,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_crtc_planes_update_noarm(state, crtc); /* Perform vblank evasion around commit operation */ - intel_pipe_update_start(new_crtc_state); + intel_pipe_update_start(state, crtc); commit_pipe_pre_planes(state, crtc); @@ -6612,7 +6797,17 @@ static void intel_update_crtc(struct intel_atomic_state *state, commit_pipe_post_planes(state, crtc); - intel_pipe_update_end(new_crtc_state); + intel_pipe_update_end(state, crtc); + + /* + * VRR/Seamless M/N update may need to update frame timings. + * + * FIXME Should be synchronized with the start of vblank somehow... + */ + if (vrr_enabling(old_crtc_state, new_crtc_state) || + new_crtc_state->update_m_n || new_crtc_state->update_lrr) + intel_crtc_update_active_timings(new_crtc_state, + new_crtc_state->vrr.enable); /* * We usually enable FIFO underrun interrupts as part of the @@ -7020,7 +7215,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_set_cdclk_pre_plane_update(state); - intel_modeset_verify_disabled(dev_priv, state); + intel_modeset_verify_disabled(state); } intel_sagv_pre_plane_update(state); @@ -7072,6 +7267,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (new_crtc_state->do_async_flip) intel_crtc_disable_flip_done(state, crtc); + + intel_color_wait_commit(new_crtc_state); } /* @@ -7098,14 +7295,13 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) } intel_dbuf_post_plane_update(state); - intel_psr_post_plane_update(state); for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { intel_post_plane_update(state, crtc); intel_modeset_put_crtc_power_domains(crtc, &put_domains[crtc->pipe]); - intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state); + intel_modeset_verify_crtc(state, crtc); /* Must be done after gamma readout due to HSW split gamma vs. IPS w/a */ hsw_ips_post_update(state, crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 49ac8473b988..0e5dffe8f018 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -190,8 +190,6 @@ enum aux_ch { AUX_CH_E_XELPD, }; -#define aux_ch_name(a) ((a) + 'A') - enum phy { PHY_NONE = -1, @@ -513,8 +511,10 @@ void intel_plane_fixup_bitmasks(struct intel_crtc_state *crtc_state); void intel_update_watermarks(struct drm_i915_private *i915); /* modesetting */ -int intel_modeset_all_pipes(struct intel_atomic_state *state, - const char *reason); +int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state, + const char *reason, u8 pipe_mask); +int intel_modeset_all_pipes_late(struct intel_atomic_state *state, + const char *reason); void intel_modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state, struct intel_power_domain_mask *old_domains); void intel_modeset_put_crtc_power_domains(struct intel_crtc *crtc, diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 53e5c33e08c3..ccfe27630fb6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -175,6 +175,9 @@ struct intel_hotplug { /* Whether or not to count short HPD IRQs in HPD storms */ u8 hpd_short_storm_enabled; + /* Last state reported by oob_hotplug_event for each encoder */ + unsigned long oob_hotplug_last_state; + /* * if we get a HPD irq from DP and a HPD irq from non-DP * the non-DP HPD could block the workqueue on a mode config diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 63c1fb9e479f..fbe75d47a165 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -43,12 +43,16 @@ static int i915_frontbuffer_tracking(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); + spin_lock(&dev_priv->display.fb_tracking.lock); + seq_printf(m, "FB tracking busy bits: 0x%08x\n", dev_priv->display.fb_tracking.busy_bits); seq_printf(m, "FB tracking flip bits: 0x%08x\n", dev_priv->display.fb_tracking.flip_bits); + spin_unlock(&dev_priv->display.fb_tracking.lock); + return 0; } @@ -233,14 +237,13 @@ static void intel_dp_info(struct seq_file *m, struct intel_connector *connector) { struct intel_encoder *intel_encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder); - const struct edid *edid = drm_edid_raw(connector->detect_edid); seq_printf(m, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]); seq_printf(m, "\taudio support: %s\n", str_yes_no(connector->base.display_info.has_audio)); drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports, - edid, &intel_dp->aux); + connector->detect_edid, &intel_dp->aux); } static void intel_dp_mst_info(struct seq_file *m, @@ -641,6 +644,7 @@ static int i915_display_info(struct seq_file *m, void *unused) static int i915_shared_dplls_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); + struct intel_shared_dpll *pll; int i; drm_modeset_lock_all(&dev_priv->drm); @@ -649,11 +653,9 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) dev_priv->display.dpll.ref_clks.nssc, dev_priv->display.dpll.ref_clks.ssc); - for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) { - struct intel_shared_dpll *pll = &dev_priv->display.dpll.shared_dplls[i]; - - seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->info->name, - pll->info->id); + for_each_shared_dpll(dev_priv, pll, i) { + seq_printf(m, "DPLL%i: %s, id: %i\n", pll->index, + pll->info->name, pll->info->id); seq_printf(m, " pipe_mask: 0x%x, active: 0x%x, on: %s\n", pll->state.pipe_mask, pll->active_mask, str_yes_no(pll->on)); diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index c39f8a15d8aa..2b1ec23ba9c3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -710,18 +710,61 @@ static const struct intel_display_device_info xe_hpd_display = { BIT(PORT_TC1), }; +#define XE_LPDP_FEATURES \ + .abox_mask = GENMASK(1, 0), \ + .color = { \ + .degamma_lut_size = 129, .gamma_lut_size = 1024, \ + .degamma_lut_tests = DRM_COLOR_LUT_NON_DECREASING | \ + DRM_COLOR_LUT_EQUAL_CHANNELS, \ + }, \ + .dbuf.size = 4096, \ + .dbuf.slice_mask = BIT(DBUF_S1) | BIT(DBUF_S2) | BIT(DBUF_S3) | \ + BIT(DBUF_S4), \ + .has_cdclk_crawl = 1, \ + .has_cdclk_squash = 1, \ + .has_ddi = 1, \ + .has_dp_mst = 1, \ + .has_dsb = 1, \ + .has_fpga_dbg = 1, \ + .has_hotplug = 1, \ + .has_ipc = 1, \ + .has_psr = 1, \ + .pipe_offsets = { \ + [TRANSCODER_A] = PIPE_A_OFFSET, \ + [TRANSCODER_B] = PIPE_B_OFFSET, \ + [TRANSCODER_C] = PIPE_C_OFFSET, \ + [TRANSCODER_D] = PIPE_D_OFFSET, \ + }, \ + .trans_offsets = { \ + [TRANSCODER_A] = TRANSCODER_A_OFFSET, \ + [TRANSCODER_B] = TRANSCODER_B_OFFSET, \ + [TRANSCODER_C] = TRANSCODER_C_OFFSET, \ + [TRANSCODER_D] = TRANSCODER_D_OFFSET, \ + }, \ + TGL_CURSOR_OFFSETS, \ + \ + .__runtime_defaults.cpu_transcoder_mask = \ + BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | \ + BIT(TRANSCODER_C) | BIT(TRANSCODER_D), \ + .__runtime_defaults.fbc_mask = BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B), \ + .__runtime_defaults.has_dmc = 1, \ + .__runtime_defaults.has_dsc = 1, \ + .__runtime_defaults.has_hdcp = 1, \ + .__runtime_defaults.pipe_mask = \ + BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D), \ + .__runtime_defaults.port_mask = BIT(PORT_A) | BIT(PORT_B) | \ + BIT(PORT_TC1) | BIT(PORT_TC2) | BIT(PORT_TC3) | BIT(PORT_TC4) + static const struct intel_display_device_info xe_lpdp_display = { - XE_LPD_FEATURES, - .has_cdclk_crawl = 1, - .has_cdclk_squash = 1, + XE_LPDP_FEATURES, +}; - .__runtime_defaults.ip.ver = 14, - .__runtime_defaults.fbc_mask = BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B), - .__runtime_defaults.cpu_transcoder_mask = - BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | - BIT(TRANSCODER_C) | BIT(TRANSCODER_D), - .__runtime_defaults.port_mask = BIT(PORT_A) | BIT(PORT_B) | - BIT(PORT_TC1) | BIT(PORT_TC2) | BIT(PORT_TC3) | BIT(PORT_TC4), +static const struct intel_display_device_info xe2_lpd_display = { + XE_LPDP_FEATURES, + + .__runtime_defaults.fbc_mask = + BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B) | + BIT(INTEL_FBC_C) | BIT(INTEL_FBC_D), }; /* @@ -803,6 +846,7 @@ static const struct { const struct intel_display_device_info *display; } gmdid_display_map[] = { { 14, 0, &xe_lpdp_display }, + { 20, 0, &xe2_lpd_display }, }; static const struct intel_display_device_info * @@ -850,16 +894,12 @@ probe_gmdid_display(struct drm_i915_private *i915, u16 *ver, u16 *rel, u16 *step return &no_display; } -const struct intel_display_device_info * -intel_display_device_probe(struct drm_i915_private *i915, bool has_gmdid, - u16 *gmdid_ver, u16 *gmdid_rel, u16 *gmdid_step) +static const struct intel_display_device_info * +probe_display(struct drm_i915_private *i915) { struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int i; - if (has_gmdid) - return probe_gmdid_display(i915, gmdid_ver, gmdid_rel, gmdid_step); - if (has_no_display(pdev)) { drm_dbg_kms(&i915->drm, "Device doesn't have display\n"); return &no_display; @@ -876,7 +916,30 @@ intel_display_device_probe(struct drm_i915_private *i915, bool has_gmdid, return &no_display; } -void intel_display_device_info_runtime_init(struct drm_i915_private *i915) +void intel_display_device_probe(struct drm_i915_private *i915) +{ + const struct intel_display_device_info *info; + u16 ver, rel, step; + + if (HAS_GMD_ID(i915)) + info = probe_gmdid_display(i915, &ver, &rel, &step); + else + info = probe_display(i915); + + DISPLAY_INFO(i915) = info; + + memcpy(DISPLAY_RUNTIME_INFO(i915), + &DISPLAY_INFO(i915)->__runtime_defaults, + sizeof(*DISPLAY_RUNTIME_INFO(i915))); + + if (HAS_GMD_ID(i915)) { + DISPLAY_RUNTIME_INFO(i915)->ip.ver = ver; + DISPLAY_RUNTIME_INFO(i915)->ip.rel = rel; + DISPLAY_RUNTIME_INFO(i915)->ip.step = step; + } +} + +static void __intel_display_device_info_runtime_init(struct drm_i915_private *i915) { struct intel_display_runtime_info *display_runtime = DISPLAY_RUNTIME_INFO(i915); enum pipe pipe; @@ -885,6 +948,13 @@ void intel_display_device_info_runtime_init(struct drm_i915_private *i915) BUILD_BUG_ON(BITS_PER_TYPE(display_runtime->cpu_transcoder_mask) < I915_MAX_TRANSCODERS); BUILD_BUG_ON(BITS_PER_TYPE(display_runtime->port_mask) < I915_MAX_PORTS); + /* This covers both ULT and ULX */ + if (IS_HASWELL_ULT(i915) || IS_BROADWELL_ULT(i915)) + display_runtime->port_mask &= ~BIT(PORT_D); + + if (IS_ICL_WITH_PORT_F(i915)) + display_runtime->port_mask |= BIT(PORT_F); + /* Wa_14011765242: adl-s A0,A1 */ if (IS_ALDERLAKE_S(i915) && IS_DISPLAY_STEP(i915, STEP_A0, STEP_A2)) for_each_pipe(i915, pipe) @@ -970,16 +1040,19 @@ void intel_display_device_info_runtime_init(struct drm_i915_private *i915) if (dfsm & SKL_DFSM_PIPE_B_DISABLE) { display_runtime->pipe_mask &= ~BIT(PIPE_B); display_runtime->cpu_transcoder_mask &= ~BIT(TRANSCODER_B); + display_runtime->fbc_mask &= ~BIT(INTEL_FBC_B); } if (dfsm & SKL_DFSM_PIPE_C_DISABLE) { display_runtime->pipe_mask &= ~BIT(PIPE_C); display_runtime->cpu_transcoder_mask &= ~BIT(TRANSCODER_C); + display_runtime->fbc_mask &= ~BIT(INTEL_FBC_C); } if (DISPLAY_VER(i915) >= 12 && (dfsm & TGL_DFSM_PIPE_D_DISABLE)) { display_runtime->pipe_mask &= ~BIT(PIPE_D); display_runtime->cpu_transcoder_mask &= ~BIT(TRANSCODER_D); + display_runtime->fbc_mask &= ~BIT(INTEL_FBC_D); } if (!display_runtime->pipe_mask) @@ -999,12 +1072,44 @@ void intel_display_device_info_runtime_init(struct drm_i915_private *i915) display_runtime->has_dsc = 0; } + if (DISPLAY_VER(i915) >= 20) { + u32 cap = intel_de_read(i915, XE2LPD_DE_CAP); + + if (REG_FIELD_GET(XE2LPD_DE_CAP_DSC_MASK, cap) == + XE2LPD_DE_CAP_DSC_REMOVED) + display_runtime->has_dsc = 0; + + if (REG_FIELD_GET(XE2LPD_DE_CAP_SCALER_MASK, cap) == + XE2LPD_DE_CAP_SCALER_SINGLE) { + for_each_pipe(i915, pipe) + if (display_runtime->num_scalers[pipe]) + display_runtime->num_scalers[pipe] = 1; + } + } + return; display_fused_off: memset(display_runtime, 0, sizeof(*display_runtime)); } +void intel_display_device_info_runtime_init(struct drm_i915_private *i915) +{ + if (HAS_DISPLAY(i915)) + __intel_display_device_info_runtime_init(i915); + + /* Display may have been disabled by runtime init */ + if (!HAS_DISPLAY(i915)) { + i915->drm.driver_features &= ~(DRIVER_MODESET | DRIVER_ATOMIC); + i915->display.info.__device_info = &no_display; + } + + /* Disable nuclear pageflip by default on pre-g4x */ + if (!i915->params.nuclear_pageflip && + DISPLAY_VER(i915) < 5 && !IS_G4X(i915)) + i915->drm.driver_features &= ~DRIVER_ATOMIC; +} + void intel_display_device_info_print(const struct intel_display_device_info *info, const struct intel_display_runtime_info *runtime, struct drm_printer *p) @@ -1025,3 +1130,20 @@ void intel_display_device_info_print(const struct intel_display_device_info *inf drm_printf(p, "has_dmc: %s\n", str_yes_no(runtime->has_dmc)); drm_printf(p, "has_dsc: %s\n", str_yes_no(runtime->has_dsc)); } + +/* + * Assuming the device has display hardware, should it be enabled? + * + * It's an error to call this function if the device does not have display + * hardware. + * + * Disabling display means taking over the display hardware, putting it to + * sleep, and preventing connectors from being connected via any means. + */ +bool intel_display_device_enabled(struct drm_i915_private *i915) +{ + /* Only valid when HAS_DISPLAY() is true */ + drm_WARN_ON(&i915->drm, !HAS_DISPLAY(i915)); + + return !i915->params.disable_display && !intel_opregion_headless_sku(i915); +} diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 215e682bd8b7..5b5c0e53307f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -32,6 +32,7 @@ struct drm_printer; func(overlay_needs_physical); \ func(supports_tv); +#define HAS_4TILE(i915) (IS_DG2(i915) || DISPLAY_VER(i915) >= 14) #define HAS_ASYNC_FLIPS(i915) (DISPLAY_VER(i915) >= 5) #define HAS_CDCLK_CRAWL(i915) (DISPLAY_INFO(i915)->has_cdclk_crawl) #define HAS_CDCLK_SQUASH(i915) (DISPLAY_INFO(i915)->has_cdclk_squash) @@ -55,6 +56,7 @@ struct drm_printer; #define HAS_HW_SAGV_WM(i915) (DISPLAY_VER(i915) >= 13 && !IS_DGFX(i915)) #define HAS_IPC(i915) (DISPLAY_INFO(i915)->has_ipc) #define HAS_IPS(i915) (IS_HASWELL_ULT(i915) || IS_BROADWELL(i915)) +#define HAS_LRR(i915) (DISPLAY_VER(i915) >= 12) #define HAS_LSPCON(i915) (IS_DISPLAY_VER(i915, 9, 10)) #define HAS_MBUS_JOINING(i915) (IS_ALDERLAKE_P(i915) || DISPLAY_VER(i915) >= 14) #define HAS_MSO(i915) (DISPLAY_VER(i915) >= 12) @@ -71,6 +73,40 @@ struct drm_printer; #define OVERLAY_NEEDS_PHYSICAL(i915) (DISPLAY_INFO(i915)->overlay_needs_physical) #define SUPPORTS_TV(i915) (DISPLAY_INFO(i915)->supports_tv) +/* Check that device has a display IP version within the specific range. */ +#define IS_DISPLAY_IP_RANGE(__i915, from, until) ( \ + BUILD_BUG_ON_ZERO((from) < IP_VER(2, 0)) + \ + (DISPLAY_VER_FULL(__i915) >= (from) && \ + DISPLAY_VER_FULL(__i915) <= (until))) + +/* + * Check if a device has a specific IP version as well as a stepping within the + * specified range [from, until). The lower bound is inclusive, the upper + * bound is exclusive. The most common use-case of this macro is for checking + * bounds for workarounds, which usually have a stepping ("from") at which the + * hardware issue is first present and another stepping ("until") at which a + * hardware fix is present and the software workaround is no longer necessary. + * E.g., + * + * IS_DISPLAY_IP_STEP(i915, IP_VER(14, 0), STEP_A0, STEP_B2) + * IS_DISPLAY_IP_STEP(i915, IP_VER(14, 0), STEP_C0, STEP_FOREVER) + * + * "STEP_FOREVER" can be passed as "until" for workarounds that have no upper + * stepping bound for the specified IP version. + */ +#define IS_DISPLAY_IP_STEP(__i915, ipver, from, until) \ + (IS_DISPLAY_IP_RANGE((__i915), (ipver), (ipver)) && \ + IS_DISPLAY_STEP((__i915), (from), (until))) + +#define DISPLAY_INFO(i915) ((i915)->display.info.__device_info) +#define DISPLAY_RUNTIME_INFO(i915) (&(i915)->display.info.__runtime_info) + +#define DISPLAY_VER(i915) (DISPLAY_RUNTIME_INFO(i915)->ip.ver) +#define DISPLAY_VER_FULL(i915) IP_VER(DISPLAY_RUNTIME_INFO(i915)->ip.ver, \ + DISPLAY_RUNTIME_INFO(i915)->ip.rel) +#define IS_DISPLAY_VER(i915, from, until) \ + (DISPLAY_VER(i915) >= (from) && DISPLAY_VER(i915) <= (until)) + struct intel_display_runtime_info { struct { u16 ver; @@ -123,9 +159,8 @@ struct intel_display_device_info { } color; }; -const struct intel_display_device_info * -intel_display_device_probe(struct drm_i915_private *i915, bool has_gmdid, - u16 *ver, u16 *rel, u16 *step); +bool intel_display_device_enabled(struct drm_i915_private *i915); +void intel_display_device_probe(struct drm_i915_private *i915); void intel_display_device_info_runtime_init(struct drm_i915_private *i915); void intel_display_device_info_print(const struct intel_display_device_info *info, diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 8f144d4d3c39..44b59ac301e6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -31,6 +31,7 @@ #include "intel_display_irq.h" #include "intel_display_power.h" #include "intel_display_types.h" +#include "intel_display_wa.h" #include "intel_dkl_phy.h" #include "intel_dmc.h" #include "intel_dp.h" @@ -88,6 +89,8 @@ void intel_display_driver_init_hw(struct drm_i915_private *i915) intel_update_cdclk(i915); intel_cdclk_dump_config(i915, &i915->display.cdclk.hw, "Current CDCLK"); cdclk_state->logical = cdclk_state->actual = i915->display.cdclk.hw; + + intel_display_wa_apply(i915); } static const struct drm_mode_config_funcs intel_mode_funcs = { @@ -377,6 +380,8 @@ int intel_display_driver_probe(struct drm_i915_private *i915) void intel_display_driver_register(struct drm_i915_private *i915) { + struct drm_printer p = drm_debug_printer("i915 display info:"); + if (!HAS_DISPLAY(i915)) return; @@ -404,6 +409,9 @@ void intel_display_driver_register(struct drm_i915_private *i915) * fbdev->async_cookie. */ drm_kms_helper_poll_init(&i915->drm); + + intel_display_device_info_print(DISPLAY_INFO(i915), + DISPLAY_RUNTIME_INFO(i915), &p); } /* part #1: call before irq uninstall */ diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 62ce55475554..bff4a76310c0 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -792,7 +792,9 @@ static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) { u32 mask; - if (DISPLAY_VER(dev_priv) >= 14) + if (DISPLAY_VER(dev_priv) >= 20) + return 0; + else if (DISPLAY_VER(dev_priv) >= 14) return TGL_DE_PORT_AUX_DDIA | TGL_DE_PORT_AUX_DDIB; else if (DISPLAY_VER(dev_priv) >= 13) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 9e01054c2430..e25785ae1c20 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -186,8 +186,6 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "GMBUS"; case POWER_DOMAIN_INIT: return "INIT"; - case POWER_DOMAIN_MODESET: - return "MODESET"; case POWER_DOMAIN_GT_IRQ: return "GT_IRQ"; case POWER_DOMAIN_DC_OFF: @@ -218,7 +216,7 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well; bool is_enabled; - if (dev_priv->runtime_pm.suspended) + if (pm_runtime_suspended(dev_priv->drm.dev)) return false; is_enabled = true; @@ -338,8 +336,6 @@ unlock: mutex_unlock(&power_domains->lock); } -#define POWER_DOMAIN_MASK (GENMASK_ULL(POWER_DOMAIN_NUM - 1, 0)) - static void __async_put_domains_mask(struct i915_power_domains *power_domains, struct intel_power_domain_mask *mask) { @@ -947,7 +943,9 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv, if (!HAS_DISPLAY(dev_priv)) return 0; - if (IS_DG2(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 20) + max_dc = 2; + else if (IS_DG2(dev_priv)) max_dc = 1; else if (IS_DG1(dev_priv)) max_dc = 3; diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index d3b5d04b7b07..d6c2a5846bdc 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -108,7 +108,6 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_TBT6, POWER_DOMAIN_GMBUS, - POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_TC_COLD_OFF, diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c index 5ad04cd42c15..10948b3964ee 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_map.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c @@ -332,7 +332,6 @@ I915_DECL_PW_DOMAINS(skl_pwdoms_pw_2, I915_DECL_PW_DOMAINS(skl_pwdoms_dc_off, SKL_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUX_A, - POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -437,7 +436,6 @@ I915_DECL_PW_DOMAINS(bxt_pwdoms_dc_off, BXT_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUX_A, POWER_DOMAIN_GMBUS, - POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -519,7 +517,6 @@ I915_DECL_PW_DOMAINS(glk_pwdoms_dc_off, GLK_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUX_A, POWER_DOMAIN_GMBUS, - POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -685,7 +682,6 @@ I915_DECL_PW_DOMAINS(icl_pwdoms_pw_2, I915_DECL_PW_DOMAINS(icl_pwdoms_dc_off, ICL_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUX_A, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -861,7 +857,6 @@ I915_DECL_PW_DOMAINS(tgl_pwdoms_dc_off, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, POWER_DOMAIN_AUX_C, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1058,7 +1053,6 @@ I915_DECL_PW_DOMAINS(rkl_pwdoms_dc_off, RKL_PW_3_POWER_DOMAINS, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1141,7 +1135,6 @@ I915_DECL_PW_DOMAINS(dg1_pwdoms_dc_off, POWER_DOMAIN_AUDIO_MMIO, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1311,7 +1304,6 @@ I915_DECL_PW_DOMAINS(xelpd_pwdoms_dc_off, POWER_DOMAIN_AUDIO_MMIO, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1426,7 +1418,6 @@ I915_DECL_PW_DOMAINS(xehpd_pwdoms_dc_off, POWER_DOMAIN_AUDIO_MMIO, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1545,6 +1536,56 @@ static const struct i915_power_well_desc_list xelpdp_power_wells[] = { I915_PW_DESCRIPTORS(xelpdp_power_wells_main), }; +I915_DECL_PW_DOMAINS(xe2lpd_pwdoms_pica_tc, + POWER_DOMAIN_PORT_DDI_LANES_TC1, + POWER_DOMAIN_PORT_DDI_LANES_TC2, + POWER_DOMAIN_PORT_DDI_LANES_TC3, + POWER_DOMAIN_PORT_DDI_LANES_TC4, + POWER_DOMAIN_AUX_USBC1, + POWER_DOMAIN_AUX_USBC2, + POWER_DOMAIN_AUX_USBC3, + POWER_DOMAIN_AUX_USBC4, + POWER_DOMAIN_AUX_TBT1, + POWER_DOMAIN_AUX_TBT2, + POWER_DOMAIN_AUX_TBT3, + POWER_DOMAIN_AUX_TBT4, + POWER_DOMAIN_INIT); + +static const struct i915_power_well_desc xe2lpd_power_wells_pica[] = { + { + .instances = &I915_PW_INSTANCES(I915_PW("PICA_TC", + &xe2lpd_pwdoms_pica_tc, + .id = DISP_PW_ID_NONE), + ), + .ops = &xe2lpd_pica_power_well_ops, + }, +}; + +I915_DECL_PW_DOMAINS(xe2lpd_pwdoms_dc_off, + POWER_DOMAIN_DC_OFF, + XELPD_PW_C_POWER_DOMAINS, + XELPD_PW_D_POWER_DOMAINS, + POWER_DOMAIN_AUDIO_MMIO, + POWER_DOMAIN_INIT); + +static const struct i915_power_well_desc xe2lpd_power_wells_dcoff[] = { + { + .instances = &I915_PW_INSTANCES( + I915_PW("DC_off", &xe2lpd_pwdoms_dc_off, + .id = SKL_DISP_DC_OFF), + ), + .ops = &gen9_dc_off_power_well_ops, + }, +}; + +static const struct i915_power_well_desc_list xe2lpd_power_wells[] = { + I915_PW_DESCRIPTORS(i9xx_power_wells_always_on), + I915_PW_DESCRIPTORS(icl_power_wells_pw_1), + I915_PW_DESCRIPTORS(xe2lpd_power_wells_dcoff), + I915_PW_DESCRIPTORS(xelpdp_power_wells_main), + I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), +}; + static void init_power_well_domains(const struct i915_power_well_instance *inst, struct i915_power_well *power_well) { @@ -1652,7 +1693,9 @@ int intel_display_power_map_init(struct i915_power_domains *power_domains) return 0; } - if (DISPLAY_VER(i915) >= 14) + if (DISPLAY_VER(i915) >= 20) + return set_power_wells(power_domains, xe2lpd_power_wells); + else if (DISPLAY_VER(i915) >= 14) return set_power_wells(power_domains, xelpdp_power_wells); else if (IS_DG2(i915)) return set_power_wells(power_domains, xehpd_power_wells); diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 916009894d89..07d650050099 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -1794,8 +1794,13 @@ static void xelpdp_aux_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { enum aux_ch aux_ch = i915_power_well_instance(power_well)->xelpdp.aux_ch; + enum phy phy = icl_aux_pw_to_phy(dev_priv, power_well); + + if (intel_phy_is_tc(dev_priv, phy)) + icl_tc_port_assert_ref_held(dev_priv, power_well, + aux_ch_to_digital_port(dev_priv, aux_ch)); - intel_de_rmw(dev_priv, XELPDP_DP_AUX_CH_CTL(aux_ch), + intel_de_rmw(dev_priv, XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch), XELPDP_DP_AUX_CH_CTL_POWER_REQUEST, XELPDP_DP_AUX_CH_CTL_POWER_REQUEST); @@ -1813,7 +1818,7 @@ static void xelpdp_aux_power_well_disable(struct drm_i915_private *dev_priv, { enum aux_ch aux_ch = i915_power_well_instance(power_well)->xelpdp.aux_ch; - intel_de_rmw(dev_priv, XELPDP_DP_AUX_CH_CTL(aux_ch), + intel_de_rmw(dev_priv, XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch), XELPDP_DP_AUX_CH_CTL_POWER_REQUEST, 0); usleep_range(10, 30); @@ -1824,10 +1829,44 @@ static bool xelpdp_aux_power_well_enabled(struct drm_i915_private *dev_priv, { enum aux_ch aux_ch = i915_power_well_instance(power_well)->xelpdp.aux_ch; - return intel_de_read(dev_priv, XELPDP_DP_AUX_CH_CTL(aux_ch)) & + return intel_de_read(dev_priv, XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch)) & XELPDP_DP_AUX_CH_CTL_POWER_STATUS; } +static void xe2lpd_pica_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + intel_de_write(dev_priv, XE2LPD_PICA_PW_CTL, + XE2LPD_PICA_CTL_POWER_REQUEST); + + if (intel_de_wait_for_set(dev_priv, XE2LPD_PICA_PW_CTL, + XE2LPD_PICA_CTL_POWER_STATUS, 1)) { + drm_dbg_kms(&dev_priv->drm, "pica power well enable timeout\n"); + + drm_WARN(&dev_priv->drm, 1, "Power well PICA timeout when enabled"); + } +} + +static void xe2lpd_pica_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + intel_de_write(dev_priv, XE2LPD_PICA_PW_CTL, 0); + + if (intel_de_wait_for_clear(dev_priv, XE2LPD_PICA_PW_CTL, + XE2LPD_PICA_CTL_POWER_STATUS, 1)) { + drm_dbg_kms(&dev_priv->drm, "pica power well disable timeout\n"); + + drm_WARN(&dev_priv->drm, 1, "Power well PICA timeout when disabled"); + } +} + +static bool xe2lpd_pica_power_well_enabled(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + return intel_de_read(dev_priv, XE2LPD_PICA_PW_CTL) & + XE2LPD_PICA_CTL_POWER_STATUS; +} + const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .sync_hw = i9xx_power_well_sync_hw_noop, .enable = i9xx_always_on_power_well_noop, @@ -1947,3 +1986,10 @@ const struct i915_power_well_ops xelpdp_aux_power_well_ops = { .disable = xelpdp_aux_power_well_disable, .is_enabled = xelpdp_aux_power_well_enabled, }; + +const struct i915_power_well_ops xe2lpd_pica_power_well_ops = { + .sync_hw = i9xx_power_well_sync_hw_noop, + .enable = xe2lpd_pica_power_well_enable, + .disable = xe2lpd_pica_power_well_disable, + .is_enabled = xe2lpd_pica_power_well_enabled, +}; diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.h b/drivers/gpu/drm/i915/display/intel_display_power_well.h index a8736588314d..9357a9a73c06 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.h +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.h @@ -176,5 +176,6 @@ extern const struct i915_power_well_ops icl_aux_power_well_ops; extern const struct i915_power_well_ops icl_ddi_power_well_ops; extern const struct i915_power_well_ops tgl_tc_cold_off_ops; extern const struct i915_power_well_ops xelpdp_aux_power_well_ops; +extern const struct i915_power_well_ops xe2lpd_pica_power_well_ops; #endif diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 731f2ec04d5c..8d8b2f8d37a9 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -500,15 +500,15 @@ struct intel_hdcp_shim { enum hdcp_wired_protocol protocol; /* Detects whether sink is HDCP2.2 capable */ - int (*hdcp_2_2_capable)(struct intel_digital_port *dig_port, + int (*hdcp_2_2_capable)(struct intel_connector *connector, bool *capable); /* Write HDCP2.2 messages */ - int (*write_2_2_msg)(struct intel_digital_port *dig_port, + int (*write_2_2_msg)(struct intel_connector *connector, void *buf, size_t size); /* Read HDCP2.2 messages */ - int (*read_2_2_msg)(struct intel_digital_port *dig_port, + int (*read_2_2_msg)(struct intel_connector *connector, u8 msg_id, void *buf, size_t size); /* @@ -516,7 +516,7 @@ struct intel_hdcp_shim { * type to Receivers. In DP HDCP2.2 Stream type is one of the input to * the HDCP2.2 Cipher for En/De-Cryption. Not applicable for HDMI. */ - int (*config_stream_type)(struct intel_digital_port *dig_port, + int (*config_stream_type)(struct intel_connector *connector, bool is_repeater, u8 type); /* Enable/Disable HDCP 2.2 stream encryption on DP MST Transport Link */ @@ -1083,6 +1083,8 @@ struct intel_crtc_state { unsigned fb_bits; /* framebuffers to flip */ bool update_pipe; /* can a fast modeset be performed? */ + bool update_m_n; /* update M/N seamlessly during fastset? */ + bool update_lrr; /* update TRANS_VTOTAL/etc. during fastset? */ bool disable_cxsr; bool update_wm_pre, update_wm_post; /* watermarks are updated */ bool fifo_changed; /* FIFO split is changed */ @@ -1189,13 +1191,13 @@ struct intel_crtc_state { u32 ctrl, div; } dsi_pll; - int pipe_bpp; + int max_link_bpp_x16; /* in 1/16 bpp units */ + int pipe_bpp; /* in 1 bpp units */ struct intel_link_m_n dp_m_n; /* m2_n2 for eDP downclock */ struct intel_link_m_n dp_m2_n2; bool has_drrs; - bool seamless_m_n; /* PSR is supported but might not be enabled due the lack of enabled planes */ bool has_psr; @@ -1362,7 +1364,14 @@ struct intel_crtc_state { u16 linetime; u16 ips_linetime; - /* Forward Error correction State */ + bool enhanced_framing; + + /* + * Forward Error Correction. + * + * Note: This will be false for 128b/132b, which will always have FEC + * enabled automatically. + */ bool fec_enable; bool sdp_split_enable; @@ -1383,7 +1392,7 @@ struct intel_crtc_state { /* Variable Refresh Rate state */ struct { - bool enable; + bool enable, in_range; u8 pipeline_full; u16 flipline, vmin, vmax, guardband; } vrr; @@ -1581,7 +1590,6 @@ struct intel_watermark_params { struct intel_hdmi { i915_reg_t hdmi_reg; - int ddc_bus; struct { enum drm_dp_dual_mode_type type; int max_tmds_clock; @@ -2108,4 +2116,27 @@ to_intel_frontbuffer(struct drm_framebuffer *fb) return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL; } +static inline int to_bpp_int(int bpp_x16) +{ + return bpp_x16 >> 4; +} + +static inline int to_bpp_frac(int bpp_x16) +{ + return bpp_x16 & 0xf; +} + +#define BPP_X16_FMT "%d.%04d" +#define BPP_X16_ARGS(bpp_x16) to_bpp_int(bpp_x16), (to_bpp_frac(bpp_x16) * 625) + +static inline int to_bpp_int_roundup(int bpp_x16) +{ + return (bpp_x16 + 0xf) >> 4; +} + +static inline int to_bpp_x16(int bpp) +{ + return bpp << 4; +} + #endif /* __INTEL_DISPLAY_TYPES_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.c b/drivers/gpu/drm/i915/display/intel_display_wa.c new file mode 100644 index 000000000000..ac136fd992ba --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_wa.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_drv.h" +#include "i915_reg.h" +#include "intel_de.h" +#include "intel_display_wa.h" + +static void gen11_display_wa_apply(struct drm_i915_private *i915) +{ + /* Wa_1409120013 */ + intel_de_write(i915, ILK_DPFC_CHICKEN(INTEL_FBC_A), + DPFC_CHICKEN_COMP_DUMMY_PIXEL); + + /* Wa_14010594013 */ + intel_de_rmw(i915, GEN8_CHICKEN_DCPR_1, 0, ICL_DELAY_PMRSP); +} + +static void xe_d_display_wa_apply(struct drm_i915_private *i915) +{ + /* Wa_1409120013 */ + intel_de_write(i915, ILK_DPFC_CHICKEN(INTEL_FBC_A), + DPFC_CHICKEN_COMP_DUMMY_PIXEL); + + /* Wa_14013723622 */ + intel_de_rmw(i915, CLKREQ_POLICY, CLKREQ_POLICY_MEM_UP_OVRD, 0); +} + +static void adlp_display_wa_apply(struct drm_i915_private *i915) +{ + /* Wa_22011091694:adlp */ + intel_de_rmw(i915, GEN9_CLKGATE_DIS_5, 0, DPCE_GATING_DIS); + + /* Bspec/49189 Initialize Sequence */ + intel_de_rmw(i915, GEN8_CHICKEN_DCPR_1, DDI_CLOCK_REG_ACCESS, 0); +} + +void intel_display_wa_apply(struct drm_i915_private *i915) +{ + if (IS_ALDERLAKE_P(i915)) + adlp_display_wa_apply(i915); + else if (DISPLAY_VER(i915) == 12) + xe_d_display_wa_apply(i915); + else if (DISPLAY_VER(i915) == 11) + gen11_display_wa_apply(i915); +} diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.h b/drivers/gpu/drm/i915/display/intel_display_wa.h new file mode 100644 index 000000000000..63201d09852c --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_wa.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DISPLAY_WA_H__ +#define __INTEL_DISPLAY_WA_H__ + +struct drm_i915_private; + +void intel_display_wa_apply(struct drm_i915_private *i915); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 5f479f3828bb..63e080e07023 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -309,7 +309,7 @@ static const struct stepping_info * intel_get_stepping_info(struct drm_i915_private *i915, struct stepping_info *si) { - const char *step_name = intel_step_name(RUNTIME_INFO(i915)->step.display_step); + const char *step_name = intel_display_step_name(i915); si->stepping = step_name[0]; si->substepping = step_name[1]; @@ -998,7 +998,7 @@ void intel_dmc_init(struct drm_i915_private *i915) INIT_WORK(&dmc->work, dmc_load_work_fn); - if (IS_METEORLAKE(i915)) { + if (DISPLAY_VER_FULL(i915) == IP_VER(14, 0)) { dmc->fw_path = MTL_DMC_PATH; dmc->max_fw_size = XELPDP_DMC_MAX_FW_SIZE; } else if (IS_DG2(i915)) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 12bd2f322e62..4f6835a7578e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -306,13 +306,13 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); int source_max = intel_dp_max_source_lane_count(dig_port); int sink_max = intel_dp->max_sink_lane_count; - int fia_max = intel_tc_port_fia_max_lane_count(dig_port); + int lane_max = intel_tc_port_max_lane_count(dig_port); int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps); if (lttpr_max) sink_max = min(sink_max, lttpr_max); - return min3(source_max, sink_max, fia_max); + return min3(source_max, sink_max, lane_max); } int intel_dp_max_lane_count(struct intel_dp *intel_dp) @@ -740,14 +740,41 @@ u32 intel_dp_dsc_nearest_valid_bpp(struct drm_i915_private *i915, u32 bpp, u32 p return bits_per_pixel; } -u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, - u32 link_clock, u32 lane_count, - u32 mode_clock, u32 mode_hdisplay, - bool bigjoiner, - u32 pipe_bpp, - u32 timeslots) +static +u32 get_max_compressed_bpp_with_joiner(struct drm_i915_private *i915, + u32 mode_clock, u32 mode_hdisplay, + bool bigjoiner) +{ + u32 max_bpp_small_joiner_ram; + + /* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */ + max_bpp_small_joiner_ram = small_joiner_ram_size_bits(i915) / mode_hdisplay; + + if (bigjoiner) { + int bigjoiner_interface_bits = DISPLAY_VER(i915) >= 14 ? 36 : 24; + /* With bigjoiner multiple dsc engines are used in parallel so PPC is 2 */ + int ppc = 2; + u32 max_bpp_bigjoiner = + i915->display.cdclk.max_cdclk_freq * ppc * bigjoiner_interface_bits / + intel_dp_mode_to_fec_clock(mode_clock); + + max_bpp_small_joiner_ram *= 2; + + return min(max_bpp_small_joiner_ram, max_bpp_bigjoiner); + } + + return max_bpp_small_joiner_ram; +} + +u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915, + u32 link_clock, u32 lane_count, + u32 mode_clock, u32 mode_hdisplay, + bool bigjoiner, + enum intel_output_format output_format, + u32 pipe_bpp, + u32 timeslots) { - u32 bits_per_pixel, max_bpp_small_joiner_ram; + u32 bits_per_pixel, joiner_max_bpp; /* * Available Link Bandwidth(Kbits/sec) = (NumberOfLanes)* @@ -768,40 +795,32 @@ u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, bits_per_pixel = ((link_clock * lane_count) * timeslots) / (intel_dp_mode_to_fec_clock(mode_clock) * 8); + /* Bandwidth required for 420 is half, that of 444 format */ + if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420) + bits_per_pixel *= 2; + + /* + * According to DSC 1.2a Section 4.1.1 Table 4.1 the maximum + * supported PPS value can be 63.9375 and with the further + * mention that for 420, 422 formats, bpp should be programmed double + * the target bpp restricting our target bpp to be 31.9375 at max. + */ + if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420) + bits_per_pixel = min_t(u32, bits_per_pixel, 31); + drm_dbg_kms(&i915->drm, "Max link bpp is %u for %u timeslots " "total bw %u pixel clock %u\n", bits_per_pixel, timeslots, (link_clock * lane_count * 8), intel_dp_mode_to_fec_clock(mode_clock)); - /* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */ - max_bpp_small_joiner_ram = small_joiner_ram_size_bits(i915) / - mode_hdisplay; - - if (bigjoiner) - max_bpp_small_joiner_ram *= 2; - - /* - * Greatest allowed DSC BPP = MIN (output BPP from available Link BW - * check, output bpp from small joiner RAM check) - */ - bits_per_pixel = min(bits_per_pixel, max_bpp_small_joiner_ram); - - if (bigjoiner) { - u32 max_bpp_bigjoiner = - i915->display.cdclk.max_cdclk_freq * 48 / - intel_dp_mode_to_fec_clock(mode_clock); - - bits_per_pixel = min(bits_per_pixel, max_bpp_bigjoiner); - } + joiner_max_bpp = get_max_compressed_bpp_with_joiner(i915, mode_clock, + mode_hdisplay, bigjoiner); + bits_per_pixel = min(bits_per_pixel, joiner_max_bpp); bits_per_pixel = intel_dp_dsc_nearest_valid_bpp(i915, bits_per_pixel, pipe_bpp); - /* - * Compressed BPP in U6.4 format so multiply by 16, for Gen 11, - * fractional part is 0 - */ - return bits_per_pixel << 4; + return bits_per_pixel; } u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, @@ -916,16 +935,42 @@ dfp_can_convert_from_ycbcr444(struct intel_dp *intel_dp, return false; } +static bool +dfp_can_convert(struct intel_dp *intel_dp, + enum intel_output_format output_format, + enum intel_output_format sink_format) +{ + switch (output_format) { + case INTEL_OUTPUT_FORMAT_RGB: + return dfp_can_convert_from_rgb(intel_dp, sink_format); + case INTEL_OUTPUT_FORMAT_YCBCR444: + return dfp_can_convert_from_ycbcr444(intel_dp, sink_format); + default: + MISSING_CASE(output_format); + return false; + } + + return false; +} + static enum intel_output_format intel_dp_output_format(struct intel_connector *connector, enum intel_output_format sink_format) { struct intel_dp *intel_dp = intel_attached_dp(connector); struct drm_i915_private *i915 = dp_to_i915(intel_dp); + enum intel_output_format force_dsc_output_format = + intel_dp->force_dsc_output_format; enum intel_output_format output_format; + if (force_dsc_output_format) { + if (source_can_output(intel_dp, force_dsc_output_format) && + (!drm_dp_is_branch(intel_dp->dpcd) || + sink_format != force_dsc_output_format || + dfp_can_convert(intel_dp, force_dsc_output_format, sink_format))) + return force_dsc_output_format; - if (intel_dp->force_dsc_output_format) - return intel_dp->force_dsc_output_format; + drm_dbg_kms(&i915->drm, "Cannot force DSC output format\n"); + } if (sink_format == INTEL_OUTPUT_FORMAT_RGB || dfp_can_convert_from_rgb(intel_dp, sink_format)) @@ -951,7 +996,7 @@ int intel_dp_min_bpp(enum intel_output_format output_format) return 8 * 3; } -static int intel_dp_output_bpp(enum intel_output_format output_format, int bpp) +int intel_dp_output_bpp(enum intel_output_format output_format, int bpp) { /* * bpp value was assumed to RGB format. And YCbCr 4:2:0 output @@ -1122,7 +1167,7 @@ intel_dp_mode_valid(struct drm_connector *_connector, int target_clock = mode->clock; int max_rate, mode_rate, max_lanes, max_link_clock; int max_dotclk = dev_priv->max_dotclk_freq; - u16 dsc_max_output_bpp = 0; + u16 dsc_max_compressed_bpp = 0; u8 dsc_slice_count = 0; enum drm_mode_status status; bool dsc = false, bigjoiner = false; @@ -1161,31 +1206,37 @@ intel_dp_mode_valid(struct drm_connector *_connector, if (HAS_DSC(dev_priv) && drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) { + enum intel_output_format sink_format, output_format; + int pipe_bpp; + + sink_format = intel_dp_sink_format(connector, mode); + output_format = intel_dp_output_format(connector, sink_format); /* * TBD pass the connector BPC, * for now U8_MAX so that max BPC on that platform would be picked */ - int pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, U8_MAX); + pipe_bpp = intel_dp_dsc_compute_max_bpp(intel_dp, U8_MAX); /* * Output bpp is stored in 6.4 format so right shift by 4 to get the * integer value since we support only integer values of bpp. */ if (intel_dp_is_edp(intel_dp)) { - dsc_max_output_bpp = + dsc_max_compressed_bpp = drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4; dsc_slice_count = drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, true); } else if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) { - dsc_max_output_bpp = - intel_dp_dsc_get_output_bpp(dev_priv, - max_link_clock, - max_lanes, - target_clock, - mode->hdisplay, - bigjoiner, - pipe_bpp, 64) >> 4; + dsc_max_compressed_bpp = + intel_dp_dsc_get_max_compressed_bpp(dev_priv, + max_link_clock, + max_lanes, + target_clock, + mode->hdisplay, + bigjoiner, + output_format, + pipe_bpp, 64); dsc_slice_count = intel_dp_dsc_get_slice_count(intel_dp, target_clock, @@ -1193,7 +1244,7 @@ intel_dp_mode_valid(struct drm_connector *_connector, bigjoiner); } - dsc = dsc_max_output_bpp && dsc_slice_count; + dsc = dsc_max_compressed_bpp && dsc_slice_count; } /* @@ -1306,13 +1357,13 @@ bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp) static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp, const struct intel_crtc_state *pipe_config) { + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - /* On TGL, FEC is supported on all Pipes */ if (DISPLAY_VER(dev_priv) >= 12) return true; - if (DISPLAY_VER(dev_priv) == 11 && pipe_config->cpu_transcoder != TRANSCODER_A) + if (DISPLAY_VER(dev_priv) == 11 && encoder->port != PORT_A) return true; return false; @@ -1419,7 +1470,7 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, if (intel_dp->compliance.test_data.bpc != 0) { int bpp = 3 * intel_dp->compliance.test_data.bpc; - limits->min_bpp = limits->max_bpp = bpp; + limits->pipe.min_bpp = limits->pipe.max_bpp = bpp; pipe_config->dither_force_disable = bpp == 6 * 3; drm_dbg_kms(&i915->drm, "Setting pipe_bpp to %d\n", bpp); @@ -1481,10 +1532,12 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, int bpp, i, lane_count, clock = intel_dp_mode_clock(pipe_config, conn_state); int mode_rate, link_rate, link_avail; - for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) { - int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp); + for (bpp = to_bpp_int(limits->link.max_bpp_x16); + bpp >= to_bpp_int(limits->link.min_bpp_x16); + bpp -= 2 * 3) { + int link_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp); - mode_rate = intel_dp_link_required(clock, output_bpp); + mode_rate = intel_dp_link_required(clock, link_bpp); for (i = 0; i < intel_dp->num_common_rates; i++) { link_rate = intel_dp_common_rate(intel_dp, i); @@ -1512,18 +1565,31 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, return -EINVAL; } -int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 max_req_bpc) +static +u8 intel_dp_dsc_max_src_input_bpc(struct drm_i915_private *i915) +{ + /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ + if (DISPLAY_VER(i915) >= 12) + return 12; + if (DISPLAY_VER(i915) == 11) + return 10; + + return 0; +} + +int intel_dp_dsc_compute_max_bpp(struct intel_dp *intel_dp, u8 max_req_bpc) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); int i, num_bpc; u8 dsc_bpc[3] = {0}; u8 dsc_max_bpc; - /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ - if (DISPLAY_VER(i915) >= 12) - dsc_max_bpc = min_t(u8, 12, max_req_bpc); - else - dsc_max_bpc = min_t(u8, 10, max_req_bpc); + dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(i915); + + if (!dsc_max_bpc) + return dsc_max_bpc; + + dsc_max_bpc = min_t(u8, dsc_max_bpc, max_req_bpc); num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd, dsc_bpc); @@ -1651,6 +1717,387 @@ static bool intel_dp_dsc_supports_format(struct intel_dp *intel_dp, return drm_dp_dsc_sink_supports_format(intel_dp->dsc_dpcd, sink_dsc_format); } +static bool is_bw_sufficient_for_dsc_config(u16 compressed_bpp, u32 link_clock, + u32 lane_count, u32 mode_clock, + enum intel_output_format output_format, + int timeslots) +{ + u32 available_bw, required_bw; + + available_bw = (link_clock * lane_count * timeslots) / 8; + required_bw = compressed_bpp * (intel_dp_mode_to_fec_clock(mode_clock)); + + return available_bw > required_bw; +} + +static int dsc_compute_link_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits, + u16 compressed_bpp, + int timeslots) +{ + const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; + int link_rate, lane_count; + int i; + + for (i = 0; i < intel_dp->num_common_rates; i++) { + link_rate = intel_dp_common_rate(intel_dp, i); + if (link_rate < limits->min_rate || link_rate > limits->max_rate) + continue; + + for (lane_count = limits->min_lane_count; + lane_count <= limits->max_lane_count; + lane_count <<= 1) { + if (!is_bw_sufficient_for_dsc_config(compressed_bpp, link_rate, lane_count, + adjusted_mode->clock, + pipe_config->output_format, + timeslots)) + continue; + + pipe_config->lane_count = lane_count; + pipe_config->port_clock = link_rate; + + return 0; + } + } + + return -EINVAL; +} + +static +u16 intel_dp_dsc_max_sink_compressed_bppx16(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + int bpc) +{ + u16 max_bppx16 = drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd); + + if (max_bppx16) + return max_bppx16; + /* + * If support not given in DPCD 67h, 68h use the Maximum Allowed bit rate + * values as given in spec Table 2-157 DP v2.0 + */ + switch (pipe_config->output_format) { + case INTEL_OUTPUT_FORMAT_RGB: + case INTEL_OUTPUT_FORMAT_YCBCR444: + return (3 * bpc) << 4; + case INTEL_OUTPUT_FORMAT_YCBCR420: + return (3 * (bpc / 2)) << 4; + default: + MISSING_CASE(pipe_config->output_format); + break; + } + + return 0; +} + +static int dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config) +{ + /* From Mandatory bit rate range Support Table 2-157 (DP v2.0) */ + switch (pipe_config->output_format) { + case INTEL_OUTPUT_FORMAT_RGB: + case INTEL_OUTPUT_FORMAT_YCBCR444: + return 8; + case INTEL_OUTPUT_FORMAT_YCBCR420: + return 6; + default: + MISSING_CASE(pipe_config->output_format); + break; + } + + return 0; +} + +static int dsc_sink_max_compressed_bpp(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + int bpc) +{ + return intel_dp_dsc_max_sink_compressed_bppx16(intel_dp, + pipe_config, bpc) >> 4; +} + +static int dsc_src_min_compressed_bpp(void) +{ + /* Min Compressed bpp supported by source is 8 */ + return 8; +} + +static int dsc_src_max_compressed_bpp(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + /* + * Max Compressed bpp for Gen 13+ is 27bpp. + * For earlier platform is 23bpp. (Bspec:49259). + */ + if (DISPLAY_VER(i915) <= 12) + return 23; + else + return 27; +} + +/* + * From a list of valid compressed bpps try different compressed bpp and find a + * suitable link configuration that can support it. + */ +static int +icl_dsc_compute_link_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits, + int dsc_max_bpp, + int dsc_min_bpp, + int pipe_bpp, + int timeslots) +{ + int i, ret; + + /* Compressed BPP should be less than the Input DSC bpp */ + dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); + + for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp); i++) { + if (valid_dsc_bpp[i] < dsc_min_bpp || + valid_dsc_bpp[i] > dsc_max_bpp) + break; + + ret = dsc_compute_link_config(intel_dp, + pipe_config, + limits, + valid_dsc_bpp[i], + timeslots); + if (ret == 0) { + pipe_config->dsc.compressed_bpp = valid_dsc_bpp[i]; + return 0; + } + } + + return -EINVAL; +} + +/* + * From XE_LPD onwards we supports compression bpps in steps of 1 up to + * uncompressed bpp-1. So we start from max compressed bpp and see if any + * link configuration is able to support that compressed bpp, if not we + * step down and check for lower compressed bpp. + */ +static int +xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits, + int dsc_max_bpp, + int dsc_min_bpp, + int pipe_bpp, + int timeslots) +{ + u16 compressed_bpp; + int ret; + + /* Compressed BPP should be less than the Input DSC bpp */ + dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); + + for (compressed_bpp = dsc_max_bpp; + compressed_bpp >= dsc_min_bpp; + compressed_bpp--) { + ret = dsc_compute_link_config(intel_dp, + pipe_config, + limits, + compressed_bpp, + timeslots); + if (ret == 0) { + pipe_config->dsc.compressed_bpp = compressed_bpp; + return 0; + } + } + return -EINVAL; +} + +static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits, + int pipe_bpp, + int timeslots) +{ + const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int dsc_src_min_bpp, dsc_sink_min_bpp, dsc_min_bpp; + int dsc_src_max_bpp, dsc_sink_max_bpp, dsc_max_bpp; + int dsc_joiner_max_bpp; + + dsc_src_min_bpp = dsc_src_min_compressed_bpp(); + dsc_sink_min_bpp = dsc_sink_min_compressed_bpp(pipe_config); + dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp); + dsc_min_bpp = max(dsc_min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); + + dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp); + dsc_sink_max_bpp = dsc_sink_max_compressed_bpp(intel_dp, pipe_config, pipe_bpp / 3); + dsc_max_bpp = dsc_sink_max_bpp ? min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; + + dsc_joiner_max_bpp = get_max_compressed_bpp_with_joiner(i915, adjusted_mode->clock, + adjusted_mode->hdisplay, + pipe_config->bigjoiner_pipes); + dsc_max_bpp = min(dsc_max_bpp, dsc_joiner_max_bpp); + dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16)); + + if (DISPLAY_VER(i915) >= 13) + return xelpd_dsc_compute_link_config(intel_dp, pipe_config, limits, + dsc_max_bpp, dsc_min_bpp, pipe_bpp, timeslots); + return icl_dsc_compute_link_config(intel_dp, pipe_config, limits, + dsc_max_bpp, dsc_min_bpp, pipe_bpp, timeslots); +} + +static +u8 intel_dp_dsc_min_src_input_bpc(struct drm_i915_private *i915) +{ + /* Min DSC Input BPC for ICL+ is 8 */ + return HAS_DSC(i915) ? 8 : 0; +} + +static +bool is_dsc_pipe_bpp_sufficient(struct drm_i915_private *i915, + struct drm_connector_state *conn_state, + struct link_config_limits *limits, + int pipe_bpp) +{ + u8 dsc_max_bpc, dsc_min_bpc, dsc_max_pipe_bpp, dsc_min_pipe_bpp; + + dsc_max_bpc = min(intel_dp_dsc_max_src_input_bpc(i915), conn_state->max_requested_bpc); + dsc_min_bpc = intel_dp_dsc_min_src_input_bpc(i915); + + dsc_max_pipe_bpp = min(dsc_max_bpc * 3, limits->pipe.max_bpp); + dsc_min_pipe_bpp = max(dsc_min_bpc * 3, limits->pipe.min_bpp); + + return pipe_bpp >= dsc_min_pipe_bpp && + pipe_bpp <= dsc_max_pipe_bpp; +} + +static +int intel_dp_force_dsc_pipe_bpp(struct intel_dp *intel_dp, + struct drm_connector_state *conn_state, + struct link_config_limits *limits) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int forced_bpp; + + if (!intel_dp->force_dsc_bpc) + return 0; + + forced_bpp = intel_dp->force_dsc_bpc * 3; + + if (is_dsc_pipe_bpp_sufficient(i915, conn_state, limits, forced_bpp)) { + drm_dbg_kms(&i915->drm, "Input DSC BPC forced to %d\n", intel_dp->force_dsc_bpc); + return forced_bpp; + } + + drm_dbg_kms(&i915->drm, "Cannot force DSC BPC:%d, due to DSC BPC limits\n", + intel_dp->force_dsc_bpc); + + return 0; +} + +static int intel_dp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + struct link_config_limits *limits, + int timeslots) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + u8 max_req_bpc = conn_state->max_requested_bpc; + u8 dsc_max_bpc, dsc_max_bpp; + u8 dsc_min_bpc, dsc_min_bpp; + u8 dsc_bpc[3] = {0}; + int forced_bpp, pipe_bpp; + int num_bpc, i, ret; + + forced_bpp = intel_dp_force_dsc_pipe_bpp(intel_dp, conn_state, limits); + + if (forced_bpp) { + ret = dsc_compute_compressed_bpp(intel_dp, pipe_config, + limits, forced_bpp, timeslots); + if (ret == 0) { + pipe_config->pipe_bpp = forced_bpp; + return 0; + } + } + + dsc_max_bpc = intel_dp_dsc_min_src_input_bpc(i915); + if (!dsc_max_bpc) + return -EINVAL; + + dsc_max_bpc = min_t(u8, dsc_max_bpc, max_req_bpc); + dsc_max_bpp = min(dsc_max_bpc * 3, limits->pipe.max_bpp); + + dsc_min_bpc = intel_dp_dsc_min_src_input_bpc(i915); + dsc_min_bpp = max(dsc_min_bpc * 3, limits->pipe.min_bpp); + + /* + * Get the maximum DSC bpc that will be supported by any valid + * link configuration and compressed bpp. + */ + num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd, dsc_bpc); + for (i = 0; i < num_bpc; i++) { + pipe_bpp = dsc_bpc[i] * 3; + if (pipe_bpp < dsc_min_bpp) + break; + if (pipe_bpp > dsc_max_bpp) + continue; + ret = dsc_compute_compressed_bpp(intel_dp, pipe_config, + limits, pipe_bpp, timeslots); + if (ret == 0) { + pipe_config->pipe_bpp = pipe_bpp; + return 0; + } + } + + return -EINVAL; +} + +static int intel_edp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + struct link_config_limits *limits) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int pipe_bpp, forced_bpp; + int dsc_src_min_bpp, dsc_sink_min_bpp, dsc_min_bpp; + int dsc_src_max_bpp, dsc_sink_max_bpp, dsc_max_bpp; + + forced_bpp = intel_dp_force_dsc_pipe_bpp(intel_dp, conn_state, limits); + + if (forced_bpp) { + pipe_bpp = forced_bpp; + } else { + int max_bpc = min(limits->pipe.max_bpp / 3, (int)conn_state->max_requested_bpc); + + /* For eDP use max bpp that can be supported with DSC. */ + pipe_bpp = intel_dp_dsc_compute_max_bpp(intel_dp, max_bpc); + if (!is_dsc_pipe_bpp_sufficient(i915, conn_state, limits, pipe_bpp)) { + drm_dbg_kms(&i915->drm, + "Computed BPC is not in DSC BPC limits\n"); + return -EINVAL; + } + } + pipe_config->port_clock = limits->max_rate; + pipe_config->lane_count = limits->max_lane_count; + + dsc_src_min_bpp = dsc_src_min_compressed_bpp(); + dsc_sink_min_bpp = dsc_sink_min_compressed_bpp(pipe_config); + dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp); + dsc_min_bpp = max(dsc_min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); + + dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp); + dsc_sink_max_bpp = dsc_sink_max_compressed_bpp(intel_dp, pipe_config, pipe_bpp / 3); + dsc_max_bpp = dsc_sink_max_bpp ? min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; + dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16)); + + /* Compressed BPP should be less than the Input DSC bpp */ + dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); + + pipe_config->dsc.compressed_bpp = max(dsc_min_bpp, dsc_max_bpp); + + pipe_config->pipe_bpp = pipe_bpp; + + return 0; +} + int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state, @@ -1662,7 +2109,6 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - int pipe_bpp; int ret; pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && @@ -1674,36 +2120,28 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, if (!intel_dp_dsc_supports_format(intel_dp, pipe_config->output_format)) return -EINVAL; - if (compute_pipe_bpp) - pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, conn_state->max_requested_bpc); - else - pipe_bpp = pipe_config->pipe_bpp; - - if (intel_dp->force_dsc_bpc) { - pipe_bpp = intel_dp->force_dsc_bpc * 3; - drm_dbg_kms(&dev_priv->drm, "Input DSC BPP forced to %d", pipe_bpp); - } - - /* Min Input BPC for ICL+ is 8 */ - if (pipe_bpp < 8 * 3) { - drm_dbg_kms(&dev_priv->drm, - "No DSC support for less than 8bpc\n"); - return -EINVAL; - } - /* - * For now enable DSC for max bpp, max link rate, max lane count. - * Optimize this later for the minimum possible link rate/lane count - * with DSC enabled for the requested mode. + * compute pipe bpp is set to false for DP MST DSC case + * and compressed_bpp is calculated same time once + * vpci timeslots are allocated, because overall bpp + * calculation procedure is bit different for MST case. */ - pipe_config->pipe_bpp = pipe_bpp; - pipe_config->port_clock = limits->max_rate; - pipe_config->lane_count = limits->max_lane_count; + if (compute_pipe_bpp) { + if (intel_dp_is_edp(intel_dp)) + ret = intel_edp_dsc_compute_pipe_bpp(intel_dp, pipe_config, + conn_state, limits); + else + ret = intel_dp_dsc_compute_pipe_bpp(intel_dp, pipe_config, + conn_state, limits, timeslots); + if (ret) { + drm_dbg_kms(&dev_priv->drm, + "No Valid pipe bpp for given mode ret = %d\n", ret); + return ret; + } + } + /* Calculate Slice count */ if (intel_dp_is_edp(intel_dp)) { - pipe_config->dsc.compressed_bpp = - min_t(u16, drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4, - pipe_config->pipe_bpp); pipe_config->dsc.slice_count = drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, true); @@ -1713,34 +2151,8 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return -EINVAL; } } else { - u16 dsc_max_output_bpp = 0; u8 dsc_dp_slice_count; - if (compute_pipe_bpp) { - dsc_max_output_bpp = - intel_dp_dsc_get_output_bpp(dev_priv, - pipe_config->port_clock, - pipe_config->lane_count, - adjusted_mode->crtc_clock, - adjusted_mode->crtc_hdisplay, - pipe_config->bigjoiner_pipes, - pipe_bpp, - timeslots); - /* - * According to DSC 1.2a Section 4.1.1 Table 4.1 the maximum - * supported PPS value can be 63.9375 and with the further - * mention that bpp should be programmed double the target bpp - * restricting our target bpp to be 31.9375 at max - */ - if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) - dsc_max_output_bpp = min_t(u16, dsc_max_output_bpp, 31 << 4); - - if (!dsc_max_output_bpp) { - drm_dbg_kms(&dev_priv->drm, - "Compressed BPP not supported\n"); - return -EINVAL; - } - } dsc_dp_slice_count = intel_dp_dsc_get_slice_count(intel_dp, adjusted_mode->crtc_clock, @@ -1752,21 +2164,7 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return -EINVAL; } - /* - * compute pipe bpp is set to false for DP MST DSC case - * and compressed_bpp is calculated same time once - * vpci timeslots are allocated, because overall bpp - * calculation procedure is bit different for MST case. - */ - if (compute_pipe_bpp) { - pipe_config->dsc.compressed_bpp = min_t(u16, - dsc_max_output_bpp >> 4, - pipe_config->pipe_bpp); - } pipe_config->dsc.slice_count = dsc_dp_slice_count; - drm_dbg_kms(&dev_priv->drm, "DSC: compressed bpp %d slice count %d\n", - pipe_config->dsc.compressed_bpp, - pipe_config->dsc.slice_count); } /* * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate @@ -1796,29 +2194,82 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return 0; } -static int -intel_dp_compute_link_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state, - bool respect_downstream_limits) +/** + * intel_dp_compute_config_link_bpp_limits - compute output link bpp limits + * @intel_dp: intel DP + * @crtc_state: crtc state + * @dsc: DSC compression mode + * @limits: link configuration limits + * + * Calculates the output link min, max bpp values in @limits based on the + * pipe bpp range, @crtc_state and @dsc mode. + * + * Returns %true in case of success. + */ +bool +intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + bool dsc, + struct link_config_limits *limits) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); const struct drm_display_mode *adjusted_mode = - &pipe_config->hw.adjusted_mode; - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct link_config_limits limits; - bool joiner_needs_dsc = false; - int ret; + &crtc_state->hw.adjusted_mode; + const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + const struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + int max_link_bpp_x16; + + max_link_bpp_x16 = min(crtc_state->max_link_bpp_x16, + to_bpp_x16(limits->pipe.max_bpp)); + + if (!dsc) { + max_link_bpp_x16 = rounddown(max_link_bpp_x16, to_bpp_x16(2 * 3)); + + if (max_link_bpp_x16 < to_bpp_x16(limits->pipe.min_bpp)) + return false; + + limits->link.min_bpp_x16 = to_bpp_x16(limits->pipe.min_bpp); + } else { + /* + * TODO: set the DSC link limits already here, atm these are + * initialized only later in intel_edp_dsc_compute_pipe_bpp() / + * intel_dp_dsc_compute_pipe_bpp() + */ + limits->link.min_bpp_x16 = 0; + } - limits.min_rate = intel_dp_common_rate(intel_dp, 0); - limits.max_rate = intel_dp_max_link_rate(intel_dp); + limits->link.max_bpp_x16 = max_link_bpp_x16; - limits.min_lane_count = 1; - limits.max_lane_count = intel_dp_max_lane_count(intel_dp); + drm_dbg_kms(&i915->drm, + "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max lanes %d max rate %d max pipe_bpp %d max link_bpp " BPP_X16_FMT "\n", + encoder->base.base.id, encoder->base.name, + crtc->base.base.id, crtc->base.name, + adjusted_mode->crtc_clock, + dsc ? "on" : "off", + limits->max_lane_count, + limits->max_rate, + limits->pipe.max_bpp, + BPP_X16_ARGS(limits->link.max_bpp_x16)); - limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format); - limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config, respect_downstream_limits); + return true; +} + +static bool +intel_dp_compute_config_limits(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state, + bool respect_downstream_limits, + bool dsc, + struct link_config_limits *limits) +{ + limits->min_rate = intel_dp_common_rate(intel_dp, 0); + limits->max_rate = intel_dp_max_link_rate(intel_dp); + + limits->min_lane_count = 1; + limits->max_lane_count = intel_dp_max_lane_count(intel_dp); + + limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format); + limits->pipe.max_bpp = intel_dp_max_bpp(intel_dp, crtc_state, + respect_downstream_limits); if (intel_dp->use_max_params) { /* @@ -1829,16 +2280,33 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, * configuration, and typically on older panels these * values correspond to the native resolution of the panel. */ - limits.min_lane_count = limits.max_lane_count; - limits.min_rate = limits.max_rate; + limits->min_lane_count = limits->max_lane_count; + limits->min_rate = limits->max_rate; } - intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits); + intel_dp_adjust_compliance_config(intel_dp, crtc_state, limits); - drm_dbg_kms(&i915->drm, "DP link computation with max lane count %i " - "max rate %d max bpp %d pixel clock %iKHz\n", - limits.max_lane_count, limits.max_rate, - limits.max_bpp, adjusted_mode->crtc_clock); + return intel_dp_compute_config_link_bpp_limits(intel_dp, + crtc_state, + dsc, + limits); +} + +static int +intel_dp_compute_link_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + bool respect_downstream_limits) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); + const struct drm_display_mode *adjusted_mode = + &pipe_config->hw.adjusted_mode; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct link_config_limits limits; + bool joiner_needs_dsc = false; + bool dsc_needed; + int ret = 0; if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_clock)) @@ -1851,16 +2319,34 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, */ joiner_needs_dsc = DISPLAY_VER(i915) < 13 && pipe_config->bigjoiner_pipes; - /* - * Optimize for slow and wide for everything, because there are some - * eDP 1.3 and 1.4 panels don't work well with fast and narrow. - */ - ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, conn_state, &limits); + dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en || + !intel_dp_compute_config_limits(intel_dp, pipe_config, + respect_downstream_limits, + false, + &limits); + + if (!dsc_needed) { + /* + * Optimize for slow and wide for everything, because there are some + * eDP 1.3 and 1.4 panels don't work well with fast and narrow. + */ + ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, + conn_state, &limits); + if (ret) + dsc_needed = true; + } - if (ret || joiner_needs_dsc || intel_dp->force_dsc_en) { + if (dsc_needed) { drm_dbg_kms(&i915->drm, "Try DSC (fallback=%s, joiner=%s, force=%s)\n", str_yes_no(ret), str_yes_no(joiner_needs_dsc), str_yes_no(intel_dp->force_dsc_en)); + + if (!intel_dp_compute_config_limits(intel_dp, pipe_config, + respect_downstream_limits, + true, + &limits)) + return -EINVAL; + ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, conn_state, &limits, 64, true); if (ret < 0) @@ -2136,7 +2622,7 @@ static bool can_enable_drrs(struct intel_connector *connector, static void intel_dp_drrs_compute_config(struct intel_connector *connector, struct intel_crtc_state *pipe_config, - int output_bpp) + int link_bpp) { struct drm_i915_private *i915 = to_i915(connector->base.dev); const struct drm_display_mode *downclock_mode = @@ -2144,7 +2630,7 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, int pixel_clock; if (has_seamless_m_n(connector)) - pipe_config->seamless_m_n = true; + pipe_config->update_m_n = true; if (!can_enable_drrs(connector, pipe_config, downclock_mode)) { if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder)) @@ -2161,7 +2647,7 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, if (pipe_config->splitter.enable) pixel_clock /= pipe_config->splitter.link_count; - intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock, + intel_link_compute_m_n(link_bpp, pipe_config->lane_count, pixel_clock, pipe_config->port_clock, &pipe_config->dp_m2_n2, pipe_config->fec_enable); @@ -2171,15 +2657,17 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, } static bool intel_dp_has_audio(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct intel_connector *connector = intel_dp->attached_connector; const struct intel_digital_connector_state *intel_conn_state = to_intel_digital_connector_state(conn_state); + struct intel_connector *connector = + to_intel_connector(conn_state->connector); - if (!intel_dp_port_has_audio(i915, encoder->port)) + if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) && + !intel_dp_port_has_audio(i915, encoder->port)) return false; if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) @@ -2232,7 +2720,7 @@ intel_dp_compute_output_format(struct intel_encoder *encoder, return ret; } -static void +void intel_dp_audio_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -2240,9 +2728,12 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; - pipe_config->sdp_split_enable = - intel_dp_has_audio(encoder, conn_state) && - intel_dp_is_uhbr(pipe_config); + pipe_config->has_audio = + intel_dp_has_audio(encoder, pipe_config, conn_state) && + intel_audio_compute_config(encoder, pipe_config, conn_state); + + pipe_config->sdp_split_enable = pipe_config->has_audio && + intel_dp_is_uhbr(pipe_config); drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] SDP split enable: %s\n", connector->base.id, connector->name, @@ -2259,15 +2750,11 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); const struct drm_display_mode *fixed_mode; struct intel_connector *connector = intel_dp->attached_connector; - int ret = 0, output_bpp; + int ret = 0, link_bpp; if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && encoder->port != PORT_A) pipe_config->has_pch_encoder = true; - pipe_config->has_audio = - intel_dp_has_audio(encoder, conn_state) && - intel_audio_compute_config(encoder, pipe_config, conn_state); - fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode); if (intel_dp_is_edp(intel_dp) && fixed_mode) { ret = intel_panel_compute_config(connector, adjusted_mode); @@ -2308,11 +2795,14 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->limited_color_range = intel_dp_limited_color_range(pipe_config, conn_state); + pipe_config->enhanced_framing = + drm_dp_enhanced_frame_cap(intel_dp->dpcd); + if (pipe_config->dsc.compression_enable) - output_bpp = pipe_config->dsc.compressed_bpp; + link_bpp = pipe_config->dsc.compressed_bpp; else - output_bpp = intel_dp_output_bpp(pipe_config->output_format, - pipe_config->pipe_bpp); + link_bpp = intel_dp_output_bpp(pipe_config->output_format, + pipe_config->pipe_bpp); if (intel_dp->mso_link_count) { int n = intel_dp->mso_link_count; @@ -2336,7 +2826,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_dp_audio_compute_config(encoder, pipe_config, conn_state); - intel_link_compute_m_n(output_bpp, + intel_link_compute_m_n(link_bpp, pipe_config->lane_count, adjusted_mode->crtc_clock, pipe_config->port_clock, @@ -2352,7 +2842,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_vrr_compute_config(pipe_config, conn_state); intel_psr_compute_config(intel_dp, pipe_config, conn_state); - intel_dp_drrs_compute_config(connector, pipe_config, output_bpp); + intel_dp_drrs_compute_config(connector, pipe_config, link_bpp); intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state); @@ -4717,14 +5207,10 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, { struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; - const struct edid *edid; - - /* FIXME: Get rid of drm_edid_raw() */ - edid = drm_edid_raw(drm_edid); intel_dp->dfp.max_bpc = drm_dp_downstream_max_bpc(intel_dp->dpcd, - intel_dp->downstream_ports, edid); + intel_dp->downstream_ports, drm_edid); intel_dp->dfp.max_dotclock = drm_dp_downstream_max_dotclock(intel_dp->dpcd, @@ -4733,11 +5219,11 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, intel_dp->dfp.min_tmds_clock = drm_dp_downstream_min_tmds_clock(intel_dp->dpcd, intel_dp->downstream_ports, - edid); + drm_edid); intel_dp->dfp.max_tmds_clock = drm_dp_downstream_max_tmds_clock(intel_dp->dpcd, intel_dp->downstream_ports, - edid); + drm_edid); intel_dp->dfp.pcon_max_frl_bw = drm_dp_get_pcon_max_frl_bw(intel_dp->dpcd, @@ -4808,7 +5294,6 @@ intel_dp_set_edid(struct intel_dp *intel_dp) struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; const struct drm_edid *drm_edid; - const struct edid *edid; bool vrr_capable; intel_dp_unset_edid(intel_dp); @@ -4826,10 +5311,8 @@ intel_dp_set_edid(struct intel_dp *intel_dp) intel_dp_update_dfp(intel_dp, drm_edid); intel_dp_update_420(intel_dp); - /* FIXME: Get rid of drm_edid_raw() */ - edid = drm_edid_raw(drm_edid); - - drm_dp_cec_set_edid(&intel_dp->aux, edid); + drm_dp_cec_attach(&intel_dp->aux, + connector->base.display_info.source_physical_address); } static void @@ -4871,7 +5354,7 @@ intel_dp_detect(struct drm_connector *connector, drm_WARN_ON(&dev_priv->drm, !drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex)); - if (!INTEL_DISPLAY_ENABLED(dev_priv)) + if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; /* Can't disconnect eDP */ @@ -4957,12 +5440,6 @@ out: if (status != connector_status_connected && !intel_dp->is_mst) intel_dp_unset_edid(intel_dp); - /* - * Make sure the refs for power wells enabled during detect are - * dropped to avoid a new detect cycle triggered by HPD polling. - */ - intel_display_power_flush_work(dev_priv); - if (!intel_dp_is_edp(intel_dp)) drm_dp_set_subconnector_property(connector, status, @@ -4978,9 +5455,6 @@ intel_dp_force(struct drm_connector *connector) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *intel_encoder = &dig_port->base; struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); - enum intel_display_power_domain aux_domain = - intel_aux_power_domain(dig_port); - intel_wakeref_t wakeref; drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -4989,11 +5463,7 @@ intel_dp_force(struct drm_connector *connector) if (connector->status != connector_status_connected) return; - wakeref = intel_display_power_get(dev_priv, aux_domain); - intel_dp_set_edid(intel_dp); - - intel_display_power_put(dev_priv, aux_domain, wakeref); } static int intel_dp_get_modes(struct drm_connector *connector) @@ -5253,15 +5723,26 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn, return intel_modeset_synced_crtcs(state, conn); } -static void intel_dp_oob_hotplug_event(struct drm_connector *connector) +static void intel_dp_oob_hotplug_event(struct drm_connector *connector, + enum drm_connector_status hpd_state) { struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); struct drm_i915_private *i915 = to_i915(connector->dev); + bool hpd_high = hpd_state == connector_status_connected; + unsigned int hpd_pin = encoder->hpd_pin; + bool need_work = false; spin_lock_irq(&i915->irq_lock); - i915->display.hotplug.event_bits |= BIT(encoder->hpd_pin); + if (hpd_high != test_bit(hpd_pin, &i915->display.hotplug.oob_hotplug_last_state)) { + i915->display.hotplug.event_bits |= BIT(hpd_pin); + + __assign_bit(hpd_pin, &i915->display.hotplug.oob_hotplug_last_state, hpd_high); + need_work = true; + } spin_unlock_irq(&i915->irq_lock); - queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0); + + if (need_work) + queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0); } static const struct drm_connector_funcs intel_dp_connector_funcs = { @@ -5512,8 +5993,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, /* * VBT and straps are liars. Also check HPD as that seems * to be the most reliable piece of information available. + * + * ... expect on devices that forgot to hook HPD up for eDP + * (eg. Acer Chromebook C710), so we'll check it only if multiple + * ports are attempting to use the same AUX CH, according to VBT. */ - if (!intel_digital_port_connected(encoder)) { + if (intel_bios_dp_has_shared_aux_ch(encoder->devdata) && + !intel_digital_port_connected(encoder)) { /* * If this fails, presume the DPCD answer came * from some other port using the same AUX CH. @@ -5528,7 +6014,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } mutex_lock(&dev_priv->drm.mode_config.mutex); - drm_edid = drm_edid_read_ddc(connector, &intel_dp->aux.ddc); + drm_edid = drm_edid_read_ddc(connector, connector->ddc); if (!drm_edid) { /* Fallback to EDID from ACPI OpRegion, if any */ drm_edid = intel_opregion_get_edid(intel_connector); @@ -5667,12 +6153,15 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) intel_dp->pps.active_pipe = vlv_active_pipe(intel_dp); + intel_dp_aux_init(intel_dp); + drm_dbg_kms(&dev_priv->drm, "Adding %s connector on [ENCODER:%d:%s]\n", type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP", intel_encoder->base.base.id, intel_encoder->base.name); - drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); + drm_connector_init_with_ddc(dev, connector, &intel_dp_connector_funcs, + type, &intel_dp->aux.ddc); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); if (!HAS_GMCH(dev_priv) && DISPLAY_VER(dev_priv) < 12) @@ -5680,8 +6169,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, intel_connector->polled = DRM_CONNECTOR_POLL_HPD; - intel_dp_aux_init(intel_dp); - intel_connector_attach_encoder(intel_connector, intel_encoder); if (HAS_DDI(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 22099de3ca45..2cf3681bac64 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -26,7 +26,14 @@ struct intel_encoder; struct link_config_limits { int min_rate, max_rate; int min_lane_count, max_lane_count; - int min_bpp, max_bpp; + struct { + /* Uncompressed DSC input or link output bpp in 1 bpp units */ + int min_bpp, max_bpp; + } pipe; + struct { + /* Compressed or uncompressed link output bpp in 1/16 bpp units */ + int min_bpp_x16, max_bpp_x16; + } link; }; void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp); @@ -65,6 +72,9 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, struct link_config_limits *limits, int timeslots, bool recompute_pipe_bpp); +void intel_dp_audio_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state); bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp); bool intel_dp_is_edp(struct intel_dp *intel_dp); bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state); @@ -106,13 +116,14 @@ void intel_read_dp_sdp(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, unsigned int type); bool intel_digital_port_connected(struct intel_encoder *encoder); -int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc); -u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, - u32 link_clock, u32 lane_count, - u32 mode_clock, u32 mode_hdisplay, - bool bigjoiner, - u32 pipe_bpp, - u32 timeslots); +int intel_dp_dsc_compute_max_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc); +u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915, + u32 link_clock, u32 lane_count, + u32 mode_clock, u32 mode_hdisplay, + bool bigjoiner, + enum intel_output_format output_format, + u32 pipe_bpp, + u32 timeslots); u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, int mode_clock, int mode_hdisplay, bool bigjoiner); @@ -143,5 +154,12 @@ void intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp, void intel_dp_phy_test(struct intel_encoder *encoder); void intel_dp_wait_source_oui(struct intel_dp *intel_dp); +int intel_dp_output_bpp(enum intel_output_format output_format, int bpp); + +bool +intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + bool dsc, + struct link_config_limits *limits); #endif /* __INTEL_DP_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 2d173bd495a3..4431b6290c4c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -14,6 +14,21 @@ #include "intel_pps.h" #include "intel_tc.h" +#define AUX_CH_NAME_BUFSIZE 6 + +static const char *aux_ch_name(struct drm_i915_private *i915, + char *buf, int size, enum aux_ch aux_ch) +{ + if (DISPLAY_VER(i915) >= 13 && aux_ch >= AUX_CH_D_XELPD) + snprintf(buf, size, "%c", 'A' + aux_ch - AUX_CH_D_XELPD + AUX_CH_D); + else if (DISPLAY_VER(i915) >= 12 && aux_ch >= AUX_CH_USBC1) + snprintf(buf, size, "USBC%c", '1' + aux_ch - AUX_CH_USBC1); + else + snprintf(buf, size, "%c", 'A' + aux_ch); + + return buf; +} + u32 intel_dp_aux_pack(const u8 *src, int src_bytes) { int i; @@ -687,10 +702,10 @@ static i915_reg_t xelpdp_aux_ctl_reg(struct intel_dp *intel_dp) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - return XELPDP_DP_AUX_CH_CTL(aux_ch); + return XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch); default: MISSING_CASE(aux_ch); - return XELPDP_DP_AUX_CH_CTL(AUX_CH_A); + return XELPDP_DP_AUX_CH_CTL(dev_priv, AUX_CH_A); } } @@ -707,10 +722,10 @@ static i915_reg_t xelpdp_aux_data_reg(struct intel_dp *intel_dp, int index) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - return XELPDP_DP_AUX_CH_DATA(aux_ch, index); + return XELPDP_DP_AUX_CH_DATA(dev_priv, aux_ch, index); default: MISSING_CASE(aux_ch); - return XELPDP_DP_AUX_CH_DATA(AUX_CH_A, index); + return XELPDP_DP_AUX_CH_DATA(dev_priv, AUX_CH_A, index); } } @@ -728,6 +743,7 @@ void intel_dp_aux_init(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; enum aux_ch aux_ch = dig_port->aux_ch; + char buf[AUX_CH_NAME_BUFSIZE]; if (DISPLAY_VER(dev_priv) >= 14) { intel_dp->aux_ch_ctl_reg = xelpdp_aux_ctl_reg; @@ -764,18 +780,9 @@ void intel_dp_aux_init(struct intel_dp *intel_dp) drm_dp_aux_init(&intel_dp->aux); /* Failure to allocate our preferred name is not critical */ - if (DISPLAY_VER(dev_priv) >= 13 && aux_ch >= AUX_CH_D_XELPD) - intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s", - aux_ch_name(aux_ch - AUX_CH_D_XELPD + AUX_CH_D), - encoder->base.name); - else if (DISPLAY_VER(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1) - intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s", - aux_ch - AUX_CH_USBC1 + '1', - encoder->base.name); - else - intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s", - aux_ch_name(aux_ch), - encoder->base.name); + intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %s/%s", + aux_ch_name(dev_priv, buf, sizeof(buf), aux_ch), + encoder->base.name); intel_dp->aux.transfer = intel_dp_aux_transfer; cpu_latency_qos_add_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE); @@ -819,6 +826,7 @@ enum aux_ch intel_dp_aux_ch(struct intel_encoder *encoder) struct intel_encoder *other; const char *source; enum aux_ch aux_ch; + char buf[AUX_CH_NAME_BUFSIZE]; aux_ch = intel_bios_dp_aux_ch(encoder->devdata); source = "VBT"; @@ -836,16 +844,17 @@ enum aux_ch intel_dp_aux_ch(struct intel_encoder *encoder) other = get_encoder_by_aux_ch(encoder, aux_ch); if (other) { drm_dbg_kms(&i915->drm, - "[ENCODER:%d:%s] AUX CH %c already claimed by [ENCODER:%d:%s]\n", - encoder->base.base.id, encoder->base.name, aux_ch_name(aux_ch), + "[ENCODER:%d:%s] AUX CH %s already claimed by [ENCODER:%d:%s]\n", + encoder->base.base.id, encoder->base.name, + aux_ch_name(i915, buf, sizeof(buf), aux_ch), other->base.base.id, other->base.name); return AUX_CH_NONE; } drm_dbg_kms(&i915->drm, - "[ENCODER:%d:%s] Using AUX CH %c (%s)\n", + "[ENCODER:%d:%s] Using AUX CH %s (%s)\n", encoder->base.base.id, encoder->base.name, - aux_ch_name(aux_ch), source); + aux_ch_name(i915, buf, sizeof(buf), aux_ch), source); return aux_ch; } diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h b/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h index 5185345277c7..34f6e0a48ed2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h @@ -13,48 +13,34 @@ * packet size supported is 20 bytes in each direction, hence the 5 fixed data * registers */ -#define _DPA_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64010) -#define _DPA_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64014) -#define _DPB_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64110) -#define _DPB_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64114) - -#define DP_AUX_CH_CTL(aux_ch) _MMIO_PORT(aux_ch, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL) -#define DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT(aux_ch, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ - -#define _XELPDP_USBC1_AUX_CH_CTL 0x16F210 -#define _XELPDP_USBC2_AUX_CH_CTL 0x16F410 -#define _XELPDP_USBC3_AUX_CH_CTL 0x16F610 -#define _XELPDP_USBC4_AUX_CH_CTL 0x16F810 - -#define XELPDP_DP_AUX_CH_CTL(aux_ch) _MMIO(_PICK(aux_ch, \ - _DPA_AUX_CH_CTL, \ - _DPB_AUX_CH_CTL, \ - 0, /* port/aux_ch C is non-existent */ \ - _XELPDP_USBC1_AUX_CH_CTL, \ - _XELPDP_USBC2_AUX_CH_CTL, \ - _XELPDP_USBC3_AUX_CH_CTL, \ - _XELPDP_USBC4_AUX_CH_CTL)) - -#define _XELPDP_USBC1_AUX_CH_DATA1 0x16F214 -#define _XELPDP_USBC2_AUX_CH_DATA1 0x16F414 -#define _XELPDP_USBC3_AUX_CH_DATA1 0x16F614 -#define _XELPDP_USBC4_AUX_CH_DATA1 0x16F814 - -#define XELPDP_DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PICK(aux_ch, \ - _DPA_AUX_CH_DATA1, \ - _DPB_AUX_CH_DATA1, \ - 0, /* port/aux_ch C is non-existent */ \ - _XELPDP_USBC1_AUX_CH_DATA1, \ - _XELPDP_USBC2_AUX_CH_DATA1, \ - _XELPDP_USBC3_AUX_CH_DATA1, \ - _XELPDP_USBC4_AUX_CH_DATA1) + (i) * 4) +/* + * Wrapper macro to convert from aux_ch to the index used in some of the + * registers. + */ +#define __xe2lpd_aux_ch_idx(aux_ch) \ + (aux_ch >= AUX_CH_USBC1 ? aux_ch : AUX_CH_USBC4 + 1 + (aux_ch) - AUX_CH_A) +/* TODO: Remove implicit dev_priv */ +#define _DPA_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64010) +#define _DPB_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64110) +#define _XELPDP_USBC1_AUX_CH_CTL 0x16f210 +#define _XELPDP_USBC2_AUX_CH_CTL 0x16f410 +#define DP_AUX_CH_CTL(aux_ch) _MMIO_PORT(aux_ch, _DPA_AUX_CH_CTL, \ + _DPB_AUX_CH_CTL) +#define _XELPDP_DP_AUX_CH_CTL(aux_ch) \ + _MMIO(_PICK_EVEN_2RANGES(aux_ch, AUX_CH_USBC1, \ + _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL, \ + _XELPDP_USBC1_AUX_CH_CTL, \ + _XELPDP_USBC2_AUX_CH_CTL)) +#define XELPDP_DP_AUX_CH_CTL(i915__, aux_ch) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_DP_AUX_CH_CTL(__xe2lpd_aux_ch_idx(aux_ch)) : \ + _XELPDP_DP_AUX_CH_CTL(aux_ch)) #define DP_AUX_CH_CTL_SEND_BUSY REG_BIT(31) #define DP_AUX_CH_CTL_DONE REG_BIT(30) #define DP_AUX_CH_CTL_INTERRUPT REG_BIT(29) #define DP_AUX_CH_CTL_TIME_OUT_ERROR REG_BIT(28) - #define DP_AUX_CH_CTL_TIME_OUT_MASK REG_GENMASK(27, 26) #define DP_AUX_CH_CTL_TIME_OUT_400us REG_FIELD_PREP(DP_AUX_CH_CTL_TIME_OUT_MASK, 0) #define DP_AUX_CH_CTL_TIME_OUT_600us REG_FIELD_PREP(DP_AUX_CH_CTL_TIME_OUT_MASK, 1) @@ -83,4 +69,26 @@ #define DP_AUX_CH_CTL_SYNC_PULSE_SKL_MASK REG_GENMASK(4, 0) /* skl+ */ #define DP_AUX_CH_CTL_SYNC_PULSE_SKL(c) REG_FIELD_PREP(DP_AUX_CH_CTL_SYNC_PULSE_SKL_MASK, (c) - 1) +/* TODO: Remove implicit dev_priv */ +#define _DPA_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64014) +#define _DPB_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64114) +#define _XELPDP_USBC1_AUX_CH_DATA1 0x16f214 +#define _XELPDP_USBC2_AUX_CH_DATA1 0x16f414 +#define DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT(aux_ch, _DPA_AUX_CH_DATA1, \ + _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ +#define _XELPDP_DP_AUX_CH_DATA(aux_ch, i) \ + _MMIO(_PICK_EVEN_2RANGES(aux_ch, AUX_CH_USBC1, \ + _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1, \ + _XELPDP_USBC1_AUX_CH_DATA1, \ + _XELPDP_USBC2_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ +#define XELPDP_DP_AUX_CH_DATA(i915__, aux_ch, i) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_DP_AUX_CH_DATA(__xe2lpd_aux_ch_idx(aux_ch), i) : \ + _XELPDP_DP_AUX_CH_DATA(aux_ch, i)) + +/* PICA Power Well Control */ +#define XE2LPD_PICA_PW_CTL _MMIO(0x16fe04) +#define XE2LPD_PICA_CTL_POWER_REQUEST REG_BIT(31) +#define XE2LPD_PICA_CTL_POWER_STATUS REG_BIT(30) + #endif /* __INTEL_DP_AUX_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c index e0c177161407..3a595cd433d4 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c @@ -330,14 +330,26 @@ static const struct hdcp2_dp_msg_data hdcp2_dp_msg_data[] = { 0, 0 }, }; +static struct drm_dp_aux * +intel_dp_hdcp_get_aux(struct intel_connector *connector) +{ + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); + + if (intel_encoder_is_mst(connector->encoder)) + return &connector->port->aux; + else + return &dig_port->dp.aux; +} + static int -intel_dp_hdcp2_read_rx_status(struct intel_digital_port *dig_port, +intel_dp_hdcp2_read_rx_status(struct intel_connector *connector, u8 *rx_status) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_dp_aux *aux = intel_dp_hdcp_get_aux(connector); ssize_t ret; - ret = drm_dp_dpcd_read(&dig_port->dp.aux, + ret = drm_dp_dpcd_read(aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, rx_status, HDCP_2_2_DP_RXSTATUS_LEN); if (ret != HDCP_2_2_DP_RXSTATUS_LEN) { @@ -350,14 +362,14 @@ intel_dp_hdcp2_read_rx_status(struct intel_digital_port *dig_port, } static -int hdcp2_detect_msg_availability(struct intel_digital_port *dig_port, +int hdcp2_detect_msg_availability(struct intel_connector *connector, u8 msg_id, bool *msg_ready) { u8 rx_status; int ret; *msg_ready = false; - ret = intel_dp_hdcp2_read_rx_status(dig_port, &rx_status); + ret = intel_dp_hdcp2_read_rx_status(connector, &rx_status); if (ret < 0) return ret; @@ -383,12 +395,11 @@ int hdcp2_detect_msg_availability(struct intel_digital_port *dig_port, } static ssize_t -intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *dig_port, +intel_dp_hdcp2_wait_for_msg(struct intel_connector *connector, const struct hdcp2_dp_msg_data *hdcp2_msg_data) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - struct intel_dp *dp = &dig_port->dp; - struct intel_hdcp *hdcp = &dp->attached_connector->hdcp; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_hdcp *hdcp = &connector->hdcp; u8 msg_id = hdcp2_msg_data->msg_id; int ret, timeout; bool msg_ready = false; @@ -411,8 +422,8 @@ intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *dig_port, * the timeout at wait for CP_IRQ. */ intel_dp_hdcp_wait_for_cp_irq(hdcp, timeout); - ret = hdcp2_detect_msg_availability(dig_port, - msg_id, &msg_ready); + ret = hdcp2_detect_msg_availability(connector, msg_id, + &msg_ready); if (!msg_ready) ret = -ETIMEDOUT; } @@ -437,13 +448,14 @@ static const struct hdcp2_dp_msg_data *get_hdcp2_dp_msg_data(u8 msg_id) } static -int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port, +int intel_dp_hdcp2_write_msg(struct intel_connector *connector, void *buf, size_t size) { unsigned int offset; u8 *byte = buf; ssize_t ret, bytes_to_write, len; const struct hdcp2_dp_msg_data *hdcp2_msg_data; + struct drm_dp_aux *aux; hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte); if (!hdcp2_msg_data) @@ -451,6 +463,8 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port, offset = hdcp2_msg_data->offset; + aux = intel_dp_hdcp_get_aux(connector); + /* No msg_id in DP HDCP2.2 msgs */ bytes_to_write = size - 1; byte++; @@ -459,7 +473,7 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port, len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ? DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write; - ret = drm_dp_dpcd_write(&dig_port->dp.aux, + ret = drm_dp_dpcd_write(aux, offset, (void *)byte, len); if (ret < 0) return ret; @@ -473,12 +487,14 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port, } static -ssize_t get_receiver_id_list_rx_info(struct intel_digital_port *dig_port, u32 *dev_cnt, u8 *byte) +ssize_t get_receiver_id_list_rx_info(struct intel_connector *connector, + u32 *dev_cnt, u8 *byte) { + struct drm_dp_aux *aux = intel_dp_hdcp_get_aux(connector); ssize_t ret; u8 *rx_info = byte; - ret = drm_dp_dpcd_read(&dig_port->dp.aux, + ret = drm_dp_dpcd_read(aux, DP_HDCP_2_2_REG_RXINFO_OFFSET, (void *)rx_info, HDCP_2_2_RXINFO_LEN); if (ret != HDCP_2_2_RXINFO_LEN) @@ -494,12 +510,13 @@ ssize_t get_receiver_id_list_rx_info(struct intel_digital_port *dig_port, u32 *d } static -int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, +int intel_dp_hdcp2_read_msg(struct intel_connector *connector, u8 msg_id, void *buf, size_t size) { + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - struct intel_dp *dp = &dig_port->dp; - struct intel_hdcp *hdcp = &dp->attached_connector->hdcp; + struct intel_hdcp *hdcp = &connector->hdcp; + struct drm_dp_aux *aux; unsigned int offset; u8 *byte = buf; ssize_t ret, bytes_to_recv, len; @@ -513,7 +530,9 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, return -EINVAL; offset = hdcp2_msg_data->offset; - ret = intel_dp_hdcp2_wait_for_msg(dig_port, hdcp2_msg_data); + aux = intel_dp_hdcp_get_aux(connector); + + ret = intel_dp_hdcp2_wait_for_msg(connector, hdcp2_msg_data); if (ret < 0) return ret; @@ -523,7 +542,7 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, byte++; if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) { - ret = get_receiver_id_list_rx_info(dig_port, &dev_cnt, byte); + ret = get_receiver_id_list_rx_info(connector, &dev_cnt, byte); if (ret < 0) return ret; @@ -541,11 +560,17 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_recv; /* Entire msg read timeout since initiate of msg read */ - if (bytes_to_recv == size - 1 && hdcp2_msg_data->msg_read_timeout > 0) - msg_end = ktime_add_ms(ktime_get_raw(), - hdcp2_msg_data->msg_read_timeout); + if (bytes_to_recv == size - 1 && hdcp2_msg_data->msg_read_timeout > 0) { + if (intel_encoder_is_mst(connector->encoder)) + msg_end = ktime_add_ms(ktime_get_raw(), + hdcp2_msg_data->msg_read_timeout * + connector->port->parent->num_ports); + else + msg_end = ktime_add_ms(ktime_get_raw(), + hdcp2_msg_data->msg_read_timeout); + } - ret = drm_dp_dpcd_read(&dig_port->dp.aux, offset, + ret = drm_dp_dpcd_read(aux, offset, (void *)byte, len); if (ret < 0) { drm_dbg_kms(&i915->drm, "msg_id %d, ret %zd\n", @@ -574,7 +599,7 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, } static -int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *dig_port, +int intel_dp_hdcp2_config_stream_type(struct intel_connector *connector, bool is_repeater, u8 content_type) { int ret; @@ -593,7 +618,7 @@ int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *dig_port, stream_type_msg.msg_id = HDCP_2_2_ERRATA_DP_STREAM_TYPE; stream_type_msg.stream_type = content_type; - ret = intel_dp_hdcp2_write_msg(dig_port, &stream_type_msg, + ret = intel_dp_hdcp2_write_msg(connector, &stream_type_msg, sizeof(stream_type_msg)); return ret < 0 ? ret : 0; @@ -607,7 +632,8 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port, u8 rx_status; int ret; - ret = intel_dp_hdcp2_read_rx_status(dig_port, &rx_status); + ret = intel_dp_hdcp2_read_rx_status(connector, + &rx_status); if (ret) return ret; @@ -622,14 +648,17 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port, } static -int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port, +int intel_dp_hdcp2_capable(struct intel_connector *connector, bool *capable) { + struct drm_dp_aux *aux; u8 rx_caps[3]; int ret; + aux = intel_dp_hdcp_get_aux(connector); + *capable = false; - ret = drm_dp_dpcd_read(&dig_port->dp.aux, + ret = drm_dp_dpcd_read(aux, DP_HDCP_2_2_REG_RX_CAPS_OFFSET, rx_caps, HDCP_2_2_RXCAPS_LEN); if (ret != HDCP_2_2_RXCAPS_LEN) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index a263773f4d68..dbc1b66c8ee4 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -655,7 +655,7 @@ intel_dp_update_link_bw_set(struct intel_dp *intel_dp, /* Write the link configuration data */ link_config[0] = link_bw; link_config[1] = crtc_state->lane_count; - if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + if (crtc_state->enhanced_framing) link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2); @@ -1390,11 +1390,13 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp, * Default value of bit 31 is '0' hence discarding the write * TODO: Corrective actions on SDP corruption yet to be defined */ - if (intel_dp_is_uhbr(crtc_state)) - /* DP v2.0 SCR on SDP CRC16 for 128b/132b Link Layer */ - drm_dp_dpcd_writeb(&intel_dp->aux, - DP_SDP_ERROR_DETECTION_CONFIGURATION, - DP_SDP_CRC16_128B132B_EN); + if (!intel_dp_is_uhbr(crtc_state)) + return; + + /* DP v2.0 SCR on SDP CRC16 for 128b/132b Link Layer */ + drm_dp_dpcd_writeb(&intel_dp->aux, + DP_SDP_ERROR_DETECTION_CONFIGURATION, + DP_SDP_CRC16_128B132B_EN); lt_dbg(intel_dp, DP_PHY_DPRX, "DP2.0 SDP CRC16 for 128b/132b enabled\n"); } diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index e3f176a093d2..73e397736463 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -94,12 +94,9 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, crtc_state->lane_count = limits->max_lane_count; crtc_state->port_clock = limits->max_rate; - // TODO: Handle pbn_div changes by adding a new MST helper - if (!mst_state->pbn_div) { - mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, - crtc_state->port_clock, - crtc_state->lane_count); - } + mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, + crtc_state->port_clock, + crtc_state->lane_count); for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) { drm_dbg_kms(&i915->drm, "Trying bpp %d\n", bpp); @@ -155,15 +152,24 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; int slots = -EINVAL; + int link_bpp; - slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, limits->max_bpp, - limits->min_bpp, limits, + /* + * FIXME: allocate the BW according to link_bpp, which in the case of + * YUV420 is only half of the pipe bpp value. + */ + slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, + to_bpp_int(limits->link.max_bpp_x16), + to_bpp_int(limits->link.min_bpp_x16), + limits, conn_state, 2 * 3, false); if (slots < 0) return slots; - intel_link_compute_m_n(crtc_state->pipe_bpp, + link_bpp = intel_dp_output_bpp(crtc_state->output_format, crtc_state->pipe_bpp); + + intel_link_compute_m_n(link_bpp, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, @@ -200,8 +206,8 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, else dsc_max_bpc = min_t(u8, 10, conn_state->max_requested_bpc); - max_bpp = min_t(u8, dsc_max_bpc * 3, limits->max_bpp); - min_bpp = limits->min_bpp; + max_bpp = min_t(u8, dsc_max_bpc * 3, limits->pipe.max_bpp); + min_bpp = limits->pipe.min_bpp; num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd, dsc_bpc); @@ -228,6 +234,9 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, if (max_bpp > sink_max_bpp) max_bpp = sink_max_bpp; + min_bpp = max(min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); + max_bpp = min(max_bpp, to_bpp_int(limits->link.max_bpp_x16)); + slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, max_bpp, min_bpp, limits, conn_state, 2 * 3, true); @@ -290,17 +299,39 @@ static int intel_dp_mst_update_slots(struct intel_encoder *encoder, return 0; } -static bool intel_dp_mst_has_audio(const struct drm_connector_state *conn_state) +static bool +intel_dp_mst_compute_config_limits(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state, + bool dsc, + struct link_config_limits *limits) { - const struct intel_digital_connector_state *intel_conn_state = - to_intel_digital_connector_state(conn_state); - struct intel_connector *connector = - to_intel_connector(conn_state->connector); + /* + * for MST we always configure max link bw - the spec doesn't + * seem to suggest we should do otherwise. + */ + limits->min_rate = limits->max_rate = + intel_dp_max_link_rate(intel_dp); - if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) - return connector->base.display_info.has_audio; - else - return intel_conn_state->force_audio == HDMI_AUDIO_ON; + limits->min_lane_count = limits->max_lane_count = + intel_dp_max_lane_count(intel_dp); + + limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format); + /* + * FIXME: If all the streams can't fit into the link with + * their current pipe_bpp we should reduce pipe_bpp across + * the board until things start to fit. Until then we + * limit to <= 8bpc since that's what was hardcoded for all + * MST streams previously. This hack should be removed once + * we have the proper retry logic in place. + */ + limits->pipe.max_bpp = min(crtc_state->pipe_bpp, 24); + + intel_dp_adjust_compliance_config(intel_dp, crtc_state, limits); + + return intel_dp_compute_config_link_bpp_limits(intel_dp, + crtc_state, + dsc, + limits); } static int intel_dp_mst_compute_config(struct intel_encoder *encoder, @@ -313,7 +344,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct link_config_limits limits; - int ret; + bool dsc_needed; + int ret = 0; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; @@ -322,42 +354,40 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->has_pch_encoder = false; - pipe_config->has_audio = - intel_dp_mst_has_audio(conn_state) && - intel_audio_compute_config(encoder, pipe_config, conn_state); - - /* - * for MST we always configure max link bw - the spec doesn't - * seem to suggest we should do otherwise. - */ - limits.min_rate = - limits.max_rate = intel_dp_max_link_rate(intel_dp); - - limits.min_lane_count = - limits.max_lane_count = intel_dp_max_lane_count(intel_dp); + dsc_needed = intel_dp->force_dsc_en || + !intel_dp_mst_compute_config_limits(intel_dp, + pipe_config, + false, + &limits); - limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format); - /* - * FIXME: If all the streams can't fit into the link with - * their current pipe_bpp we should reduce pipe_bpp across - * the board until things start to fit. Until then we - * limit to <= 8bpc since that's what was hardcoded for all - * MST streams previously. This hack should be removed once - * we have the proper retry logic in place. - */ - limits.max_bpp = min(pipe_config->pipe_bpp, 24); + if (!dsc_needed) { + ret = intel_dp_mst_compute_link_config(encoder, pipe_config, + conn_state, &limits); - intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits); - - ret = intel_dp_mst_compute_link_config(encoder, pipe_config, - conn_state, &limits); + if (ret == -EDEADLK) + return ret; - if (ret == -EDEADLK) - return ret; + if (ret) + dsc_needed = true; + } /* enable compression if the mode doesn't fit available BW */ - drm_dbg_kms(&dev_priv->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en); - if (ret || intel_dp->force_dsc_en) { + if (dsc_needed) { + drm_dbg_kms(&dev_priv->drm, "Try DSC (fallback=%s, force=%s)\n", + str_yes_no(ret), + str_yes_no(intel_dp->force_dsc_en)); + + if (!intel_dp_mst_compute_config_limits(intel_dp, + pipe_config, + true, + &limits)) + return -EINVAL; + + /* + * FIXME: As bpc is hardcoded to 8, as mentioned above, + * WARN and ignore the debug flag force_dsc_bpc for now. + */ + drm_WARN(&dev_priv->drm, intel_dp->force_dsc_bpc, "Cannot Force BPC for MST\n"); /* * Try to get at least some timeslots and then see, if * we can fit there with DSC. @@ -388,6 +418,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, pipe_config->lane_lat_optim_mask = bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); + intel_dp_audio_compute_config(encoder, pipe_config, conn_state); + intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); return 0; @@ -557,12 +589,8 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = &dig_port->dp; struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_dp_mst_topology_state *old_mst_state = - drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst_mgr); struct drm_dp_mst_topology_state *new_mst_state = drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); - const struct drm_dp_mst_atomic_payload *old_payload = - drm_atomic_get_mst_payload_state(old_mst_state, connector->port); struct drm_dp_mst_atomic_payload *new_payload = drm_atomic_get_mst_payload_state(new_mst_state, connector->port); struct drm_i915_private *i915 = to_i915(connector->base.dev); @@ -572,8 +600,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, intel_hdcp_disable(intel_mst->connector); - drm_dp_remove_payload(&intel_dp->mst_mgr, new_mst_state, - old_payload, new_payload); + drm_dp_remove_payload_part1(&intel_dp->mst_mgr, new_mst_state, new_payload); intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); } @@ -588,6 +615,14 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = &dig_port->dp; struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_dp_mst_topology_state *old_mst_state = + drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst_mgr); + struct drm_dp_mst_topology_state *new_mst_state = + drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); + const struct drm_dp_mst_atomic_payload *old_payload = + drm_atomic_get_mst_payload_state(old_mst_state, connector->port); + struct drm_dp_mst_atomic_payload *new_payload = + drm_atomic_get_mst_payload_state(new_mst_state, connector->port); struct drm_i915_private *dev_priv = to_i915(connector->base.dev); bool last_mst_stream; @@ -608,6 +643,9 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, wait_for_act_sent(encoder, old_crtc_state); + drm_dp_remove_payload_part2(&intel_dp->mst_mgr, new_mst_state, + old_payload, new_payload); + intel_ddi_disable_transcoder_func(old_crtc_state); if (DISPLAY_VER(dev_priv) >= 9) @@ -727,8 +765,8 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, ret = drm_dp_add_payload_part1(&intel_dp->mst_mgr, mst_state, drm_atomic_get_mst_payload_state(mst_state, connector->port)); if (ret < 0) - drm_err(&dev_priv->drm, "Failed to create MST payload for %s: %d\n", - connector->base.name, ret); + drm_dbg_kms(&dev_priv->drm, "Failed to create MST payload for %s: %d\n", + connector->base.name, ret); /* * Before Gen 12 this is not done as part of @@ -792,6 +830,8 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_de_rmw(dev_priv, CHICKEN_TRANS(trans), 0, FECSTALL_DIS_DPTSTREAM_DPTTG); + intel_audio_sdp_split_update(pipe_config); + intel_enable_transcoder(pipe_config); intel_crtc_vblank_on(pipe_config); @@ -912,7 +952,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, int max_rate, mode_rate, max_lanes, max_link_clock; int ret; bool dsc = false, bigjoiner = false; - u16 dsc_max_output_bpp = 0; + u16 dsc_max_compressed_bpp = 0; u8 dsc_slice_count = 0; int target_clock = mode->clock; @@ -963,17 +1003,18 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, * TBD pass the connector BPC, * for now U8_MAX so that max BPC on that platform would be picked */ - int pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, U8_MAX); + int pipe_bpp = intel_dp_dsc_compute_max_bpp(intel_dp, U8_MAX); if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) { - dsc_max_output_bpp = - intel_dp_dsc_get_output_bpp(dev_priv, - max_link_clock, - max_lanes, - target_clock, - mode->hdisplay, - bigjoiner, - pipe_bpp, 64) >> 4; + dsc_max_compressed_bpp = + intel_dp_dsc_get_max_compressed_bpp(dev_priv, + max_link_clock, + max_lanes, + target_clock, + mode->hdisplay, + bigjoiner, + INTEL_OUTPUT_FORMAT_RGB, + pipe_bpp, 64); dsc_slice_count = intel_dp_dsc_get_slice_count(intel_dp, target_clock, @@ -981,7 +1022,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, bigjoiner); } - dsc = dsc_max_output_bpp && dsc_slice_count; + dsc = dsc_max_compressed_bpp && dsc_slice_count; } /* @@ -1018,7 +1059,7 @@ intel_dp_mst_detect(struct drm_connector *connector, struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_dp *intel_dp = intel_connector->mst_port; - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; if (drm_connector_is_unregistered(connector)) diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h index 9c7725dacb47..4d43dbbdf81c 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h @@ -26,6 +26,7 @@ enum dpio_phy { DPIO_PHY2, }; +#ifdef I915 void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, enum dpio_phy *phy, enum dpio_channel *ch); void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, @@ -70,5 +71,100 @@ void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void vlv_phy_reset_lanes(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state); +#else +static inline void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, + enum dpio_phy *phy, enum dpio_channel *ch) +{ +} +static inline void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy) +{ +} +static inline void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy) +{ +} +static inline bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv, + enum dpio_phy phy) +{ + return false; +} +static inline bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv, + enum dpio_phy phy) +{ + return true; +} +static inline u8 bxt_ddi_phy_calc_lane_lat_optim_mask(u8 lane_count) +{ + return 0; +} +static inline void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder, + u8 lane_lat_optim_mask) +{ +} +static inline u8 bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder) +{ + return 0; +} +static inline enum dpio_channel vlv_dig_port_to_channel(struct intel_digital_port *dig_port) +{ + return DPIO_CH0; +} +static inline enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port) +{ + return DPIO_PHY0; +} +static inline enum dpio_channel vlv_pipe_to_channel(enum pipe pipe) +{ + return DPIO_CH0; +} +static inline void chv_set_phy_signal_level(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + u32 deemph_reg_value, u32 margin_reg_value, + bool uniq_trans_scale) +{ +} +static inline void chv_data_lane_soft_reset(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + bool reset) +{ +} +static inline void chv_phy_pre_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void chv_phy_release_cl2_override(struct intel_encoder *encoder) +{ +} +static inline void chv_phy_post_pll_disable(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state) +{ +} + +static inline void vlv_set_phy_signal_level(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + u32 demph_reg_value, u32 preemph_reg_value, + u32 uniqtranscale_reg_value, u32 tx3_demph) +{ +} +static inline void vlv_phy_pre_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void vlv_phy_reset_lanes(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state) +{ +} +#endif #endif /* __INTEL_DPIO_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 999badfe2906..d41c1dc9f66c 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -7,6 +7,7 @@ #include <linux/string_helpers.h> #include "i915_reg.h" +#include "intel_atomic.h" #include "intel_crtc.h" #include "intel_cx0_phy.h" #include "intel_de.h" @@ -314,10 +315,11 @@ int pnv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; - if (WARN_ON(clock->n == 0 || clock->p == 0)) - return 0; - clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + clock->vco = clock->n == 0 ? 0 : + DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = clock->p == 0 ? 0 : + DIV_ROUND_CLOSEST(clock->vco, clock->p); return clock->dot; } @@ -331,10 +333,11 @@ int i9xx_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; - if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) - return 0; - clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + clock->vco = clock->n + 2 == 0 ? 0 : + DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); + clock->dot = clock->p == 0 ? 0 : + DIV_ROUND_CLOSEST(clock->vco, clock->p); return clock->dot; } @@ -343,10 +346,11 @@ int vlv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2 * 5; - if (WARN_ON(clock->n == 0 || clock->p == 0)) - return 0; - clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + clock->vco = clock->n == 0 ? 0 : + DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = clock->p == 0 ? 0 : + DIV_ROUND_CLOSEST(clock->vco, clock->p); return clock->dot; } @@ -355,11 +359,11 @@ int chv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2 * 5; - if (WARN_ON(clock->n == 0 || clock->p == 0)) - return 0; - clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m), - clock->n << 22); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + clock->vco = clock->n == 0 ? 0 : + DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m), clock->n << 22); + clock->dot = clock->p == 0 ? 0 : + DIV_ROUND_CLOSEST(clock->vco, clock->p); return clock->dot; } @@ -1179,6 +1183,8 @@ static int ilk_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + i9xx_calc_dpll_params(refclk, &crtc_state->dpll); + ilk_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1253,6 +1259,8 @@ static int chv_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + chv_calc_dpll_params(refclk, &crtc_state->dpll); + chv_compute_dpll(crtc_state); /* FIXME this is a mess */ @@ -1275,9 +1283,10 @@ static int vlv_crtc_compute_clock(struct intel_atomic_state *state, if (!crtc_state->clock_set && !vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock, - refclk, NULL, &crtc_state->dpll)) { + refclk, NULL, &crtc_state->dpll)) return -EINVAL; - } + + vlv_calc_dpll_params(refclk, &crtc_state->dpll); vlv_compute_dpll(crtc_state); @@ -1327,6 +1336,8 @@ static int g4x_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + i9xx_calc_dpll_params(refclk, &crtc_state->dpll); + i9xx_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1365,6 +1376,8 @@ static int pnv_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + pnv_calc_dpll_params(refclk, &crtc_state->dpll); + i9xx_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1401,6 +1414,8 @@ static int i9xx_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + i9xx_calc_dpll_params(refclk, &crtc_state->dpll); + i9xx_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1441,6 +1456,8 @@ static int i8xx_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + i9xx_calc_dpll_params(refclk, &crtc_state->dpll); + i8xx_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1990,7 +2007,7 @@ int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, vlv_enable_pll(crtc_state); } - kfree(crtc_state); + intel_crtc_destroy_state(&crtc->base, &crtc_state->uapi); return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index a9b19e80bff7..399653a20f98 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -21,6 +21,7 @@ * DEALINGS IN THE SOFTWARE. */ +#include <linux/math.h> #include <linux/string_helpers.h> #include "i915_reg.h" @@ -106,22 +107,20 @@ struct intel_dpll_mgr { struct intel_crtc *crtc, struct intel_encoder *encoder); void (*update_ref_clks)(struct drm_i915_private *i915); - void (*dump_hw_state)(struct drm_i915_private *dev_priv, + void (*dump_hw_state)(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state); }; static void -intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, +intel_atomic_duplicate_dpll_state(struct drm_i915_private *i915, struct intel_shared_dpll_state *shared_dpll) { - enum intel_dpll_id i; + struct intel_shared_dpll *pll; + int i; /* Copy shared dpll state */ - for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) { - struct intel_shared_dpll *pll = &dev_priv->display.dpll.shared_dplls[i]; - - shared_dpll[i] = pll->state; - } + for_each_shared_dpll(i915, pll, i) + shared_dpll[pll->index] = pll->state; } static struct intel_shared_dpll_state * @@ -143,33 +142,42 @@ intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s) /** * intel_get_shared_dpll_by_id - get a DPLL given its id - * @dev_priv: i915 device instance + * @i915: i915 device instance * @id: pll id * * Returns: * A pointer to the DPLL with @id */ struct intel_shared_dpll * -intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv, +intel_get_shared_dpll_by_id(struct drm_i915_private *i915, enum intel_dpll_id id) { - return &dev_priv->display.dpll.shared_dplls[id]; + struct intel_shared_dpll *pll; + int i; + + for_each_shared_dpll(i915, pll, i) { + if (pll->info->id == id) + return pll; + } + + MISSING_CASE(id); + return NULL; } /* For ILK+ */ -void assert_shared_dpll(struct drm_i915_private *dev_priv, +void assert_shared_dpll(struct drm_i915_private *i915, struct intel_shared_dpll *pll, bool state) { bool cur_state; struct intel_dpll_hw_state hw_state; - if (drm_WARN(&dev_priv->drm, !pll, + if (drm_WARN(&i915->drm, !pll, "asserting DPLL %s with no DPLL\n", str_on_off(state))) return; - cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state); - I915_STATE_WARN(dev_priv, cur_state != state, + cur_state = intel_dpll_get_hw_state(i915, pll, &hw_state); + I915_STATE_WARN(i915, cur_state != state, "%s assertion failure (expected %s, current %s)\n", pll->info->name, str_on_off(state), str_on_off(cur_state)); @@ -220,41 +228,41 @@ intel_tc_pll_enable_reg(struct drm_i915_private *i915, void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; unsigned int pipe_mask = BIT(crtc->pipe); unsigned int old_mask; - if (drm_WARN_ON(&dev_priv->drm, pll == NULL)) + if (drm_WARN_ON(&i915->drm, pll == NULL)) return; - mutex_lock(&dev_priv->display.dpll.lock); + mutex_lock(&i915->display.dpll.lock); old_mask = pll->active_mask; - if (drm_WARN_ON(&dev_priv->drm, !(pll->state.pipe_mask & pipe_mask)) || - drm_WARN_ON(&dev_priv->drm, pll->active_mask & pipe_mask)) + if (drm_WARN_ON(&i915->drm, !(pll->state.pipe_mask & pipe_mask)) || + drm_WARN_ON(&i915->drm, pll->active_mask & pipe_mask)) goto out; pll->active_mask |= pipe_mask; - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "enable %s (active 0x%x, on? %d) for [CRTC:%d:%s]\n", pll->info->name, pll->active_mask, pll->on, crtc->base.base.id, crtc->base.name); if (old_mask) { - drm_WARN_ON(&dev_priv->drm, !pll->on); - assert_shared_dpll_enabled(dev_priv, pll); + drm_WARN_ON(&i915->drm, !pll->on); + assert_shared_dpll_enabled(i915, pll); goto out; } - drm_WARN_ON(&dev_priv->drm, pll->on); + drm_WARN_ON(&i915->drm, pll->on); - drm_dbg_kms(&dev_priv->drm, "enabling %s\n", pll->info->name); - pll->info->funcs->enable(dev_priv, pll); + drm_dbg_kms(&i915->drm, "enabling %s\n", pll->info->name); + pll->info->funcs->enable(i915, pll); pll->on = true; out: - mutex_unlock(&dev_priv->display.dpll.lock); + mutex_unlock(&i915->display.dpll.lock); } /** @@ -266,41 +274,57 @@ out: void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; unsigned int pipe_mask = BIT(crtc->pipe); /* PCH only available on ILK+ */ - if (DISPLAY_VER(dev_priv) < 5) + if (DISPLAY_VER(i915) < 5) return; if (pll == NULL) return; - mutex_lock(&dev_priv->display.dpll.lock); - if (drm_WARN(&dev_priv->drm, !(pll->active_mask & pipe_mask), + mutex_lock(&i915->display.dpll.lock); + if (drm_WARN(&i915->drm, !(pll->active_mask & pipe_mask), "%s not used by [CRTC:%d:%s]\n", pll->info->name, crtc->base.base.id, crtc->base.name)) goto out; - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "disable %s (active 0x%x, on? %d) for [CRTC:%d:%s]\n", pll->info->name, pll->active_mask, pll->on, crtc->base.base.id, crtc->base.name); - assert_shared_dpll_enabled(dev_priv, pll); - drm_WARN_ON(&dev_priv->drm, !pll->on); + assert_shared_dpll_enabled(i915, pll); + drm_WARN_ON(&i915->drm, !pll->on); pll->active_mask &= ~pipe_mask; if (pll->active_mask) goto out; - drm_dbg_kms(&dev_priv->drm, "disabling %s\n", pll->info->name); - pll->info->funcs->disable(dev_priv, pll); + drm_dbg_kms(&i915->drm, "disabling %s\n", pll->info->name); + pll->info->funcs->disable(i915, pll); pll->on = false; out: - mutex_unlock(&dev_priv->display.dpll.lock); + mutex_unlock(&i915->display.dpll.lock); +} + +static unsigned long +intel_dpll_mask_all(struct drm_i915_private *i915) +{ + struct intel_shared_dpll *pll; + unsigned long dpll_mask = 0; + int i; + + for_each_shared_dpll(i915, pll, i) { + drm_WARN_ON(&i915->drm, dpll_mask & BIT(pll->info->id)); + + dpll_mask |= BIT(pll->info->id); + } + + return dpll_mask; } static struct intel_shared_dpll * @@ -309,33 +333,38 @@ intel_find_shared_dpll(struct intel_atomic_state *state, const struct intel_dpll_hw_state *pll_state, unsigned long dpll_mask) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_shared_dpll *pll, *unused_pll = NULL; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + unsigned long dpll_mask_all = intel_dpll_mask_all(i915); struct intel_shared_dpll_state *shared_dpll; - enum intel_dpll_id i; + struct intel_shared_dpll *unused_pll = NULL; + enum intel_dpll_id id; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - drm_WARN_ON(&dev_priv->drm, dpll_mask & ~(BIT(I915_NUM_PLLS) - 1)); + drm_WARN_ON(&i915->drm, dpll_mask & ~dpll_mask_all); + + for_each_set_bit(id, &dpll_mask, fls(dpll_mask_all)) { + struct intel_shared_dpll *pll; - for_each_set_bit(i, &dpll_mask, I915_NUM_PLLS) { - pll = &dev_priv->display.dpll.shared_dplls[i]; + pll = intel_get_shared_dpll_by_id(i915, id); + if (!pll) + continue; /* Only want to check enabled timings first */ - if (shared_dpll[i].pipe_mask == 0) { + if (shared_dpll[pll->index].pipe_mask == 0) { if (!unused_pll) unused_pll = pll; continue; } if (memcmp(pll_state, - &shared_dpll[i].hw_state, + &shared_dpll[pll->index].hw_state, sizeof(*pll_state)) == 0) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] sharing existing %s (pipe mask 0x%x, active 0x%x)\n", crtc->base.base.id, crtc->base.name, pll->info->name, - shared_dpll[i].pipe_mask, + shared_dpll[pll->index].pipe_mask, pll->active_mask); return pll; } @@ -343,7 +372,7 @@ intel_find_shared_dpll(struct intel_atomic_state *state, /* Ok no matching timings, maybe there's a free one? */ if (unused_pll) { - drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] allocated %s\n", + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] allocated %s\n", crtc->base.base.id, crtc->base.name, unused_pll->info->name); return unused_pll; @@ -382,14 +411,13 @@ intel_reference_shared_dpll(struct intel_atomic_state *state, const struct intel_dpll_hw_state *pll_state) { struct intel_shared_dpll_state *shared_dpll; - const enum intel_dpll_id id = pll->info->id; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - if (shared_dpll[id].pipe_mask == 0) - shared_dpll[id].hw_state = *pll_state; + if (shared_dpll[pll->index].pipe_mask == 0) + shared_dpll[pll->index].hw_state = *pll_state; - intel_reference_shared_dpll_crtc(crtc, pll, &shared_dpll[id]); + intel_reference_shared_dpll_crtc(crtc, pll, &shared_dpll[pll->index]); } /** @@ -420,11 +448,10 @@ static void intel_unreference_shared_dpll(struct intel_atomic_state *state, const struct intel_shared_dpll *pll) { struct intel_shared_dpll_state *shared_dpll; - const enum intel_dpll_id id = pll->info->id; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - intel_unreference_shared_dpll_crtc(crtc, pll, &shared_dpll[id]); + intel_unreference_shared_dpll_crtc(crtc, pll, &shared_dpll[pll->index]); } static void intel_put_dpll(struct intel_atomic_state *state, @@ -456,22 +483,19 @@ static void intel_put_dpll(struct intel_atomic_state *state, */ void intel_shared_dpll_swap_state(struct intel_atomic_state *state) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_shared_dpll_state *shared_dpll = state->shared_dpll; - enum intel_dpll_id i; + struct intel_shared_dpll *pll; + int i; if (!state->dpll_set) return; - for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) { - struct intel_shared_dpll *pll = - &dev_priv->display.dpll.shared_dplls[i]; - - swap(pll->state, shared_dpll[i]); - } + for_each_shared_dpll(i915, pll, i) + swap(pll->state, shared_dpll[pll->index]); } -static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, +static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -479,48 +503,48 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, intel_wakeref_t wakeref; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, PCH_DPLL(id)); + val = intel_de_read(i915, PCH_DPLL(id)); hw_state->dpll = val; - hw_state->fp0 = intel_de_read(dev_priv, PCH_FP0(id)); - hw_state->fp1 = intel_de_read(dev_priv, PCH_FP1(id)); + hw_state->fp0 = intel_de_read(i915, PCH_FP0(id)); + hw_state->fp1 = intel_de_read(i915, PCH_FP1(id)); - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return val & DPLL_VCO_ENABLE; } -static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) +static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *i915) { u32 val; bool enabled; - val = intel_de_read(dev_priv, PCH_DREF_CONTROL); + val = intel_de_read(i915, PCH_DREF_CONTROL); enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK | DREF_SUPERSPREAD_SOURCE_MASK)); - I915_STATE_WARN(dev_priv, !enabled, + I915_STATE_WARN(i915, !enabled, "PCH refclk assertion failure, should be active but is disabled\n"); } -static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, +static void ibx_pch_dpll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; /* PCH refclock must be enabled first */ - ibx_assert_pch_refclk_enabled(dev_priv); + ibx_assert_pch_refclk_enabled(i915); - intel_de_write(dev_priv, PCH_FP0(id), pll->state.hw_state.fp0); - intel_de_write(dev_priv, PCH_FP1(id), pll->state.hw_state.fp1); + intel_de_write(i915, PCH_FP0(id), pll->state.hw_state.fp0); + intel_de_write(i915, PCH_FP1(id), pll->state.hw_state.fp1); - intel_de_write(dev_priv, PCH_DPLL(id), pll->state.hw_state.dpll); + intel_de_write(i915, PCH_DPLL(id), pll->state.hw_state.dpll); /* Wait for the clocks to stabilize. */ - intel_de_posting_read(dev_priv, PCH_DPLL(id)); + intel_de_posting_read(i915, PCH_DPLL(id)); udelay(150); /* The pixel multiplier can only be updated once the @@ -528,18 +552,18 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, * * So write it again. */ - intel_de_write(dev_priv, PCH_DPLL(id), pll->state.hw_state.dpll); - intel_de_posting_read(dev_priv, PCH_DPLL(id)); + intel_de_write(i915, PCH_DPLL(id), pll->state.hw_state.dpll); + intel_de_posting_read(i915, PCH_DPLL(id)); udelay(200); } -static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv, +static void ibx_pch_dpll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; - intel_de_write(dev_priv, PCH_DPLL(id), 0); - intel_de_posting_read(dev_priv, PCH_DPLL(id)); + intel_de_write(i915, PCH_DPLL(id), 0); + intel_de_posting_read(i915, PCH_DPLL(id)); udelay(200); } @@ -556,16 +580,16 @@ static int ibx_get_dpll(struct intel_atomic_state *state, { struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_shared_dpll *pll; - enum intel_dpll_id i; + enum intel_dpll_id id; - if (HAS_PCH_IBX(dev_priv)) { + if (HAS_PCH_IBX(i915)) { /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ - i = (enum intel_dpll_id) crtc->pipe; - pll = &dev_priv->display.dpll.shared_dplls[i]; + id = (enum intel_dpll_id) crtc->pipe; + pll = intel_get_shared_dpll_by_id(i915, id); - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] using pre-allocated %s\n", crtc->base.base.id, crtc->base.name, pll->info->name); @@ -588,10 +612,10 @@ static int ibx_get_dpll(struct intel_atomic_state *state, return 0; } -static void ibx_dump_hw_state(struct drm_i915_private *dev_priv, +static void ibx_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, " "fp0: 0x%x, fp1: 0x%x\n", hw_state->dpll, @@ -620,57 +644,57 @@ static const struct intel_dpll_mgr pch_pll_mgr = { .dump_hw_state = ibx_dump_hw_state, }; -static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv, +static void hsw_ddi_wrpll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; - intel_de_write(dev_priv, WRPLL_CTL(id), pll->state.hw_state.wrpll); - intel_de_posting_read(dev_priv, WRPLL_CTL(id)); + intel_de_write(i915, WRPLL_CTL(id), pll->state.hw_state.wrpll); + intel_de_posting_read(i915, WRPLL_CTL(id)); udelay(20); } -static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv, +static void hsw_ddi_spll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - intel_de_write(dev_priv, SPLL_CTL, pll->state.hw_state.spll); - intel_de_posting_read(dev_priv, SPLL_CTL); + intel_de_write(i915, SPLL_CTL, pll->state.hw_state.spll); + intel_de_posting_read(i915, SPLL_CTL); udelay(20); } -static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv, +static void hsw_ddi_wrpll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; - intel_de_rmw(dev_priv, WRPLL_CTL(id), WRPLL_PLL_ENABLE, 0); - intel_de_posting_read(dev_priv, WRPLL_CTL(id)); + intel_de_rmw(i915, WRPLL_CTL(id), WRPLL_PLL_ENABLE, 0); + intel_de_posting_read(i915, WRPLL_CTL(id)); /* * Try to set up the PCH reference clock once all DPLLs * that depend on it have been shut down. */ - if (dev_priv->display.dpll.pch_ssc_use & BIT(id)) - intel_init_pch_refclk(dev_priv); + if (i915->display.dpll.pch_ssc_use & BIT(id)) + intel_init_pch_refclk(i915); } -static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv, +static void hsw_ddi_spll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { enum intel_dpll_id id = pll->info->id; - intel_de_rmw(dev_priv, SPLL_CTL, SPLL_PLL_ENABLE, 0); - intel_de_posting_read(dev_priv, SPLL_CTL); + intel_de_rmw(i915, SPLL_CTL, SPLL_PLL_ENABLE, 0); + intel_de_posting_read(i915, SPLL_CTL); /* * Try to set up the PCH reference clock once all DPLLs * that depend on it have been shut down. */ - if (dev_priv->display.dpll.pch_ssc_use & BIT(id)) - intel_init_pch_refclk(dev_priv); + if (i915->display.dpll.pch_ssc_use & BIT(id)) + intel_init_pch_refclk(i915); } -static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv, +static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -678,35 +702,35 @@ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv, intel_wakeref_t wakeref; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, WRPLL_CTL(id)); + val = intel_de_read(i915, WRPLL_CTL(id)); hw_state->wrpll = val; - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return val & WRPLL_PLL_ENABLE; } -static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv, +static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { intel_wakeref_t wakeref; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, SPLL_CTL); + val = intel_de_read(i915, SPLL_CTL); hw_state->spll = val; - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return val & SPLL_PLL_ENABLE; } @@ -917,7 +941,7 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */, *r2_out = best.r2; } -static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv, +static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *i915, const struct intel_shared_dpll *pll, const struct intel_dpll_hw_state *pll_state) { @@ -928,8 +952,8 @@ static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv, switch (wrpll & WRPLL_REF_MASK) { case WRPLL_REF_SPECIAL_HSW: /* Muxed-SSC for BDW, non-SSC for non-ULT HSW. */ - if (IS_HASWELL(dev_priv) && !IS_HASWELL_ULT(dev_priv)) { - refclk = dev_priv->display.dpll.ref_clks.nssc; + if (IS_HASWELL(i915) && !IS_HASWELL_ULT(i915)) { + refclk = i915->display.dpll.ref_clks.nssc; break; } fallthrough; @@ -939,7 +963,7 @@ static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv, * code only cares about 5% accuracy, and spread is a max of * 0.5% downspread. */ - refclk = dev_priv->display.dpll.ref_clks.ssc; + refclk = i915->display.dpll.ref_clks.ssc; break; case WRPLL_REF_LCPLL: refclk = 2700000; @@ -995,7 +1019,7 @@ hsw_ddi_wrpll_get_dpll(struct intel_atomic_state *state, static int hsw_ddi_lcpll_compute_dpll(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); int clock = crtc_state->port_clock; switch (clock / 2) { @@ -1004,7 +1028,7 @@ hsw_ddi_lcpll_compute_dpll(struct intel_crtc_state *crtc_state) case 270000: return 0; default: - drm_dbg_kms(&dev_priv->drm, "Invalid clock for DP: %d\n", + drm_dbg_kms(&i915->drm, "Invalid clock for DP: %d\n", clock); return -EINVAL; } @@ -1013,7 +1037,7 @@ hsw_ddi_lcpll_compute_dpll(struct intel_crtc_state *crtc_state) static struct intel_shared_dpll * hsw_ddi_lcpll_get_dpll(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); struct intel_shared_dpll *pll; enum intel_dpll_id pll_id; int clock = crtc_state->port_clock; @@ -1033,7 +1057,7 @@ hsw_ddi_lcpll_get_dpll(struct intel_crtc_state *crtc_state) return NULL; } - pll = intel_get_shared_dpll_by_id(dev_priv, pll_id); + pll = intel_get_shared_dpll_by_id(i915, pll_id); if (!pll) return NULL; @@ -1169,10 +1193,10 @@ static void hsw_update_dpll_ref_clks(struct drm_i915_private *i915) i915->display.dpll.ref_clks.nssc = 135000; } -static void hsw_dump_hw_state(struct drm_i915_private *dev_priv, +static void hsw_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: wrpll: 0x%x spll: 0x%x\n", + drm_dbg_kms(&i915->drm, "dpll_hw_state: wrpll: 0x%x spll: 0x%x\n", hw_state->wrpll, hw_state->spll); } @@ -1190,17 +1214,17 @@ static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = { .get_freq = hsw_ddi_spll_get_freq, }; -static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv, +static void hsw_ddi_lcpll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { } -static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv, +static void hsw_ddi_lcpll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { } -static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv, +static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -1264,60 +1288,60 @@ static const struct skl_dpll_regs skl_dpll_regs[4] = { }, }; -static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv, +static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; - intel_de_rmw(dev_priv, DPLL_CTRL1, + intel_de_rmw(i915, DPLL_CTRL1, DPLL_CTRL1_HDMI_MODE(id) | DPLL_CTRL1_SSC(id) | DPLL_CTRL1_LINK_RATE_MASK(id), pll->state.hw_state.ctrl1 << (id * 6)); - intel_de_posting_read(dev_priv, DPLL_CTRL1); + intel_de_posting_read(i915, DPLL_CTRL1); } -static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, +static void skl_ddi_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const struct skl_dpll_regs *regs = skl_dpll_regs; const enum intel_dpll_id id = pll->info->id; - skl_ddi_pll_write_ctrl1(dev_priv, pll); + skl_ddi_pll_write_ctrl1(i915, pll); - intel_de_write(dev_priv, regs[id].cfgcr1, pll->state.hw_state.cfgcr1); - intel_de_write(dev_priv, regs[id].cfgcr2, pll->state.hw_state.cfgcr2); - intel_de_posting_read(dev_priv, regs[id].cfgcr1); - intel_de_posting_read(dev_priv, regs[id].cfgcr2); + intel_de_write(i915, regs[id].cfgcr1, pll->state.hw_state.cfgcr1); + intel_de_write(i915, regs[id].cfgcr2, pll->state.hw_state.cfgcr2); + intel_de_posting_read(i915, regs[id].cfgcr1); + intel_de_posting_read(i915, regs[id].cfgcr2); /* the enable bit is always bit 31 */ - intel_de_rmw(dev_priv, regs[id].ctl, 0, LCPLL_PLL_ENABLE); + intel_de_rmw(i915, regs[id].ctl, 0, LCPLL_PLL_ENABLE); - if (intel_de_wait_for_set(dev_priv, DPLL_STATUS, DPLL_LOCK(id), 5)) - drm_err(&dev_priv->drm, "DPLL %d not locked\n", id); + if (intel_de_wait_for_set(i915, DPLL_STATUS, DPLL_LOCK(id), 5)) + drm_err(&i915->drm, "DPLL %d not locked\n", id); } -static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv, +static void skl_ddi_dpll0_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - skl_ddi_pll_write_ctrl1(dev_priv, pll); + skl_ddi_pll_write_ctrl1(i915, pll); } -static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv, +static void skl_ddi_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const struct skl_dpll_regs *regs = skl_dpll_regs; const enum intel_dpll_id id = pll->info->id; /* the enable bit is always bit 31 */ - intel_de_rmw(dev_priv, regs[id].ctl, LCPLL_PLL_ENABLE, 0); - intel_de_posting_read(dev_priv, regs[id].ctl); + intel_de_rmw(i915, regs[id].ctl, LCPLL_PLL_ENABLE, 0); + intel_de_posting_read(i915, regs[id].ctl); } -static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv, +static void skl_ddi_dpll0_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { } -static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -1327,34 +1351,34 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, intel_wakeref_t wakeref; bool ret; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; ret = false; - val = intel_de_read(dev_priv, regs[id].ctl); + val = intel_de_read(i915, regs[id].ctl); if (!(val & LCPLL_PLL_ENABLE)) goto out; - val = intel_de_read(dev_priv, DPLL_CTRL1); + val = intel_de_read(i915, DPLL_CTRL1); hw_state->ctrl1 = (val >> (id * 6)) & 0x3f; /* avoid reading back stale values if HDMI mode is not enabled */ if (val & DPLL_CTRL1_HDMI_MODE(id)) { - hw_state->cfgcr1 = intel_de_read(dev_priv, regs[id].cfgcr1); - hw_state->cfgcr2 = intel_de_read(dev_priv, regs[id].cfgcr2); + hw_state->cfgcr1 = intel_de_read(i915, regs[id].cfgcr1); + hw_state->cfgcr2 = intel_de_read(i915, regs[id].cfgcr2); } ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } -static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv, +static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -1364,7 +1388,7 @@ static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv, u32 val; bool ret; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; @@ -1372,17 +1396,17 @@ static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv, ret = false; /* DPLL0 is always enabled since it drives CDCLK */ - val = intel_de_read(dev_priv, regs[id].ctl); - if (drm_WARN_ON(&dev_priv->drm, !(val & LCPLL_PLL_ENABLE))) + val = intel_de_read(i915, regs[id].ctl); + if (drm_WARN_ON(&i915->drm, !(val & LCPLL_PLL_ENABLE))) goto out; - val = intel_de_read(dev_priv, DPLL_CTRL1); + val = intel_de_read(i915, DPLL_CTRL1); hw_state->ctrl1 = (val >> (id * 6)) & 0x3f; ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } @@ -1872,10 +1896,10 @@ static void skl_update_dpll_ref_clks(struct drm_i915_private *i915) i915->display.dpll.ref_clks.nssc = i915->display.cdclk.hw.ref; } -static void skl_dump_hw_state(struct drm_i915_private *dev_priv, +static void skl_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: " + drm_dbg_kms(&i915->drm, "dpll_hw_state: " "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n", hw_state->ctrl1, hw_state->cfgcr1, @@ -1913,129 +1937,129 @@ static const struct intel_dpll_mgr skl_pll_mgr = { .dump_hw_state = skl_dump_hw_state, }; -static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll) +static void bxt_ddi_pll_enable(struct drm_i915_private *i915, + struct intel_shared_dpll *pll) { u32 temp; enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ enum dpio_phy phy; enum dpio_channel ch; - bxt_port_to_phy_channel(dev_priv, port, &phy, &ch); + bxt_port_to_phy_channel(i915, port, &phy, &ch); /* Non-SSC reference */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_REF_SEL); + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_REF_SEL); - if (IS_GEMINILAKE(dev_priv)) { - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), + if (IS_GEMINILAKE(i915)) { + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_POWER_ENABLE); - if (wait_for_us((intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) & + if (wait_for_us((intel_de_read(i915, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_POWER_STATE), 200)) - drm_err(&dev_priv->drm, + drm_err(&i915->drm, "Power state not set for PLL:%d\n", port); } /* Disable 10 bit clock */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch), + intel_de_rmw(i915, BXT_PORT_PLL_EBB_4(phy, ch), PORT_PLL_10BIT_CLK_ENABLE, 0); /* Write P1 & P2 */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_EBB_0(phy, ch), + intel_de_rmw(i915, BXT_PORT_PLL_EBB_0(phy, ch), PORT_PLL_P1_MASK | PORT_PLL_P2_MASK, pll->state.hw_state.ebb0); /* Write M2 integer */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 0), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 0), PORT_PLL_M2_INT_MASK, pll->state.hw_state.pll0); /* Write N */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 1), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 1), PORT_PLL_N_MASK, pll->state.hw_state.pll1); /* Write M2 fraction */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 2), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 2), PORT_PLL_M2_FRAC_MASK, pll->state.hw_state.pll2); /* Write M2 fraction enable */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 3), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 3), PORT_PLL_M2_FRAC_ENABLE, pll->state.hw_state.pll3); /* Write coeff */ - temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 6)); + temp = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 6)); temp &= ~PORT_PLL_PROP_COEFF_MASK; temp &= ~PORT_PLL_INT_COEFF_MASK; temp &= ~PORT_PLL_GAIN_CTL_MASK; temp |= pll->state.hw_state.pll6; - intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 6), temp); + intel_de_write(i915, BXT_PORT_PLL(phy, ch, 6), temp); /* Write calibration val */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 8), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 8), PORT_PLL_TARGET_CNT_MASK, pll->state.hw_state.pll8); - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 9), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 9), PORT_PLL_LOCK_THRESHOLD_MASK, pll->state.hw_state.pll9); - temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 10)); + temp = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 10)); temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H; temp &= ~PORT_PLL_DCO_AMP_MASK; temp |= pll->state.hw_state.pll10; - intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 10), temp); + intel_de_write(i915, BXT_PORT_PLL(phy, ch, 10), temp); /* Recalibrate with new settings */ - temp = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch)); + temp = intel_de_read(i915, BXT_PORT_PLL_EBB_4(phy, ch)); temp |= PORT_PLL_RECALIBRATE; - intel_de_write(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch), temp); + intel_de_write(i915, BXT_PORT_PLL_EBB_4(phy, ch), temp); temp &= ~PORT_PLL_10BIT_CLK_ENABLE; temp |= pll->state.hw_state.ebb4; - intel_de_write(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch), temp); + intel_de_write(i915, BXT_PORT_PLL_EBB_4(phy, ch), temp); /* Enable PLL */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_ENABLE); - intel_de_posting_read(dev_priv, BXT_PORT_PLL_ENABLE(port)); + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_ENABLE); + intel_de_posting_read(i915, BXT_PORT_PLL_ENABLE(port)); - if (wait_for_us((intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK), + if (wait_for_us((intel_de_read(i915, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK), 200)) - drm_err(&dev_priv->drm, "PLL %d not locked\n", port); + drm_err(&i915->drm, "PLL %d not locked\n", port); - if (IS_GEMINILAKE(dev_priv)) { - temp = intel_de_read(dev_priv, BXT_PORT_TX_DW5_LN0(phy, ch)); + if (IS_GEMINILAKE(i915)) { + temp = intel_de_read(i915, BXT_PORT_TX_DW5_LN0(phy, ch)); temp |= DCC_DELAY_RANGE_2; - intel_de_write(dev_priv, BXT_PORT_TX_DW5_GRP(phy, ch), temp); + intel_de_write(i915, BXT_PORT_TX_DW5_GRP(phy, ch), temp); } /* * While we write to the group register to program all lanes at once we * can read only lane registers and we pick lanes 0/1 for that. */ - temp = intel_de_read(dev_priv, BXT_PORT_PCS_DW12_LN01(phy, ch)); + temp = intel_de_read(i915, BXT_PORT_PCS_DW12_LN01(phy, ch)); temp &= ~LANE_STAGGER_MASK; temp &= ~LANESTAGGER_STRAP_OVRD; temp |= pll->state.hw_state.pcsdw12; - intel_de_write(dev_priv, BXT_PORT_PCS_DW12_GRP(phy, ch), temp); + intel_de_write(i915, BXT_PORT_PCS_DW12_GRP(phy, ch), temp); } -static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll) +static void bxt_ddi_pll_disable(struct drm_i915_private *i915, + struct intel_shared_dpll *pll) { enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), PORT_PLL_ENABLE, 0); - intel_de_posting_read(dev_priv, BXT_PORT_PLL_ENABLE(port)); + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), PORT_PLL_ENABLE, 0); + intel_de_posting_read(i915, BXT_PORT_PLL_ENABLE(port)); - if (IS_GEMINILAKE(dev_priv)) { - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), + if (IS_GEMINILAKE(i915)) { + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), PORT_PLL_POWER_ENABLE, 0); - if (wait_for_us(!(intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) & + if (wait_for_us(!(intel_de_read(i915, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_POWER_STATE), 200)) - drm_err(&dev_priv->drm, + drm_err(&i915->drm, "Power state not reset for PLL:%d\n", port); } } -static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll, - struct intel_dpll_hw_state *hw_state) +static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *i915, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state) { enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ intel_wakeref_t wakeref; @@ -2044,49 +2068,49 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, u32 val; bool ret; - bxt_port_to_phy_channel(dev_priv, port, &phy, &ch); + bxt_port_to_phy_channel(i915, port, &phy, &ch); - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; ret = false; - val = intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)); + val = intel_de_read(i915, BXT_PORT_PLL_ENABLE(port)); if (!(val & PORT_PLL_ENABLE)) goto out; - hw_state->ebb0 = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_0(phy, ch)); + hw_state->ebb0 = intel_de_read(i915, BXT_PORT_PLL_EBB_0(phy, ch)); hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK; - hw_state->ebb4 = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch)); + hw_state->ebb4 = intel_de_read(i915, BXT_PORT_PLL_EBB_4(phy, ch)); hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE; - hw_state->pll0 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0)); + hw_state->pll0 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 0)); hw_state->pll0 &= PORT_PLL_M2_INT_MASK; - hw_state->pll1 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 1)); + hw_state->pll1 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 1)); hw_state->pll1 &= PORT_PLL_N_MASK; - hw_state->pll2 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 2)); + hw_state->pll2 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 2)); hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK; - hw_state->pll3 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 3)); + hw_state->pll3 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 3)); hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE; - hw_state->pll6 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 6)); + hw_state->pll6 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 6)); hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK | PORT_PLL_INT_COEFF_MASK | PORT_PLL_GAIN_CTL_MASK; - hw_state->pll8 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 8)); + hw_state->pll8 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 8)); hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK; - hw_state->pll9 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 9)); + hw_state->pll9 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 9)); hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK; - hw_state->pll10 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 10)); + hw_state->pll10 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 10)); hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H | PORT_PLL_DCO_AMP_MASK; @@ -2095,20 +2119,20 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, * can read only lane registers. We configure all lanes the same way, so * here just read out lanes 0/1 and output a note if lanes 2/3 differ. */ - hw_state->pcsdw12 = intel_de_read(dev_priv, + hw_state->pcsdw12 = intel_de_read(i915, BXT_PORT_PCS_DW12_LN01(phy, ch)); - if (intel_de_read(dev_priv, BXT_PORT_PCS_DW12_LN23(phy, ch)) != hw_state->pcsdw12) - drm_dbg(&dev_priv->drm, + if (intel_de_read(i915, BXT_PORT_PCS_DW12_LN23(phy, ch)) != hw_state->pcsdw12) + drm_dbg(&i915->drm, "lane stagger config different for lane 01 (%08x) and 23 (%08x)\n", hw_state->pcsdw12, - intel_de_read(dev_priv, + intel_de_read(i915, BXT_PORT_PCS_DW12_LN23(phy, ch))); hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD; ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } @@ -2299,15 +2323,15 @@ static int bxt_get_dpll(struct intel_atomic_state *state, { struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_shared_dpll *pll; enum intel_dpll_id id; /* 1:1 mapping between ports and PLLs */ id = (enum intel_dpll_id) encoder->port; - pll = intel_get_shared_dpll_by_id(dev_priv, id); + pll = intel_get_shared_dpll_by_id(i915, id); - drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] using pre-allocated %s\n", + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] using pre-allocated %s\n", crtc->base.base.id, crtc->base.name, pll->info->name); intel_reference_shared_dpll(state, crtc, @@ -2325,10 +2349,10 @@ static void bxt_update_dpll_ref_clks(struct drm_i915_private *i915) /* DSI non-SSC ref 19.2MHz */ } -static void bxt_dump_hw_state(struct drm_i915_private *dev_priv, +static void bxt_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x," + drm_dbg_kms(&i915->drm, "dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x," "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, " "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n", hw_state->ebb0, @@ -2556,9 +2580,9 @@ static const struct skl_wrpll_params tgl_tbt_pll_24MHz_values = { static int icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state, struct skl_wrpll_params *pll_params) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); const struct icl_combo_pll_params *params = - dev_priv->display.dpll.ref_clks.nssc == 24000 ? + i915->display.dpll.ref_clks.nssc == 24000 ? icl_dp_combo_pll_24MHz_values : icl_dp_combo_pll_19_2MHz_values; int clock = crtc_state->port_clock; @@ -2578,12 +2602,12 @@ static int icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state, static int icl_calc_tbt_pll(struct intel_crtc_state *crtc_state, struct skl_wrpll_params *pll_params) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - if (DISPLAY_VER(dev_priv) >= 12) { - switch (dev_priv->display.dpll.ref_clks.nssc) { + if (DISPLAY_VER(i915) >= 12) { + switch (i915->display.dpll.ref_clks.nssc) { default: - MISSING_CASE(dev_priv->display.dpll.ref_clks.nssc); + MISSING_CASE(i915->display.dpll.ref_clks.nssc); fallthrough; case 19200: case 38400: @@ -2594,9 +2618,9 @@ static int icl_calc_tbt_pll(struct intel_crtc_state *crtc_state, break; } } else { - switch (dev_priv->display.dpll.ref_clks.nssc) { + switch (i915->display.dpll.ref_clks.nssc) { default: - MISSING_CASE(dev_priv->display.dpll.ref_clks.nssc); + MISSING_CASE(i915->display.dpll.ref_clks.nssc); fallthrough; case 19200: case 38400: @@ -2852,8 +2876,8 @@ static int icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc, static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, struct intel_dpll_hw_state *pll_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - int refclk_khz = dev_priv->display.dpll.ref_clks.nssc; + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + int refclk_khz = i915->display.dpll.ref_clks.nssc; int clock = crtc_state->port_clock; u32 dco_khz, m1div, m2div_int, m2div_rem, m2div_frac; u32 iref_ndiv, iref_trim, iref_pulse_w; @@ -2863,7 +2887,7 @@ static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, u64 tmp; bool use_ssc = false; bool is_dp = !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI); - bool is_dkl = DISPLAY_VER(dev_priv) >= 12; + bool is_dkl = DISPLAY_VER(i915) >= 12; int ret; ret = icl_mg_pll_find_divisors(clock, is_dp, use_ssc, &dco_khz, @@ -2961,8 +2985,8 @@ static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, DKL_PLL_DIV0_PROP_COEFF(prop_coeff) | DKL_PLL_DIV0_FBPREDIV(m1div) | DKL_PLL_DIV0_FBDIV_INT(m2div_int); - if (dev_priv->display.vbt.override_afc_startup) { - u8 val = dev_priv->display.vbt.override_afc_startup_val; + if (i915->display.vbt.override_afc_startup) { + u8 val = i915->display.vbt.override_afc_startup_val; pll_state->mg_pll_div0 |= DKL_PLL_DIV0_AFC_STARTUP(val); } @@ -3052,16 +3076,16 @@ static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, return 0; } -static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *dev_priv, +static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *i915, const struct intel_shared_dpll *pll, const struct intel_dpll_hw_state *pll_state) { u32 m1, m2_int, m2_frac, div1, div2, ref_clock; u64 tmp; - ref_clock = dev_priv->display.dpll.ref_clks.nssc; + ref_clock = i915->display.dpll.ref_clks.nssc; - if (DISPLAY_VER(dev_priv) >= 12) { + if (DISPLAY_VER(i915) >= 12) { m1 = pll_state->mg_pll_div0 & DKL_PLL_DIV0_FBPREDIV_MASK; m1 = m1 >> DKL_PLL_DIV0_FBPREDIV_SHIFT; m2_int = pll_state->mg_pll_div0 & DKL_PLL_DIV0_FBDIV_INT_MASK; @@ -3166,7 +3190,7 @@ static void icl_update_active_dpll(struct intel_atomic_state *state, static int icl_compute_combo_phy_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = @@ -3183,12 +3207,12 @@ static int icl_compute_combo_phy_dpll(struct intel_atomic_state *state, if (ret) return ret; - icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state); + icl_calc_dpll_state(i915, &pll_params, &port_dpll->hw_state); /* this is mainly for the fastset check */ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT); - crtc_state->port_clock = icl_ddi_combo_pll_get_freq(dev_priv, NULL, + crtc_state->port_clock = icl_ddi_combo_pll_get_freq(i915, NULL, &port_dpll->hw_state); return 0; @@ -3198,7 +3222,7 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = @@ -3206,13 +3230,13 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, enum port port = encoder->port; unsigned long dpll_mask; - if (IS_ALDERLAKE_S(dev_priv)) { + if (IS_ALDERLAKE_S(i915)) { dpll_mask = BIT(DPLL_ID_DG1_DPLL3) | BIT(DPLL_ID_DG1_DPLL2) | BIT(DPLL_ID_ICL_DPLL1) | BIT(DPLL_ID_ICL_DPLL0); - } else if (IS_DG1(dev_priv)) { + } else if (IS_DG1(i915)) { if (port == PORT_D || port == PORT_E) { dpll_mask = BIT(DPLL_ID_DG1_DPLL2) | @@ -3222,13 +3246,13 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, BIT(DPLL_ID_DG1_DPLL0) | BIT(DPLL_ID_DG1_DPLL1); } - } else if (IS_ROCKETLAKE(dev_priv)) { + } else if (IS_ROCKETLAKE(i915)) { dpll_mask = BIT(DPLL_ID_EHL_DPLL4) | BIT(DPLL_ID_ICL_DPLL1) | BIT(DPLL_ID_ICL_DPLL0); - } else if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && - port != PORT_A) { + } else if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && + port != PORT_A) { dpll_mask = BIT(DPLL_ID_EHL_DPLL4) | BIT(DPLL_ID_ICL_DPLL1) | @@ -3238,7 +3262,7 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, } /* Eliminate DPLLs from consideration if reserved by HTI */ - dpll_mask &= ~intel_hti_dpll_mask(dev_priv); + dpll_mask &= ~intel_hti_dpll_mask(i915); port_dpll->pll = intel_find_shared_dpll(state, crtc, &port_dpll->hw_state, @@ -3257,7 +3281,7 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = @@ -3270,7 +3294,7 @@ static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state, if (ret) return ret; - icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state); + icl_calc_dpll_state(i915, &pll_params, &port_dpll->hw_state); port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY]; ret = icl_calc_mg_pll_state(crtc_state, &port_dpll->hw_state); @@ -3280,7 +3304,7 @@ static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state, /* this is mainly for the fastset check */ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_MG_PHY); - crtc_state->port_clock = icl_ddi_mg_pll_get_freq(dev_priv, NULL, + crtc_state->port_clock = icl_ddi_mg_pll_get_freq(i915, NULL, &port_dpll->hw_state); return 0; @@ -3290,7 +3314,7 @@ static int icl_get_tc_phy_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = @@ -3309,7 +3333,7 @@ static int icl_get_tc_phy_dplls(struct intel_atomic_state *state, port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY]; - dpll_id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv, + dpll_id = icl_tc_port_to_pll_id(intel_port_to_tc(i915, encoder->port)); port_dpll->pll = intel_find_shared_dpll(state, crtc, &port_dpll->hw_state, @@ -3336,12 +3360,12 @@ static int icl_compute_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + struct drm_i915_private *i915 = to_i915(state->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); - if (intel_phy_is_combo(dev_priv, phy)) + if (intel_phy_is_combo(i915, phy)) return icl_compute_combo_phy_dpll(state, crtc); - else if (intel_phy_is_tc(dev_priv, phy)) + else if (intel_phy_is_tc(i915, phy)) return icl_compute_tc_phy_dplls(state, crtc); MISSING_CASE(phy); @@ -3353,12 +3377,12 @@ static int icl_get_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + struct drm_i915_private *i915 = to_i915(state->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); - if (intel_phy_is_combo(dev_priv, phy)) + if (intel_phy_is_combo(i915, phy)) return icl_get_combo_phy_dpll(state, crtc, encoder); - else if (intel_phy_is_tc(dev_priv, phy)) + else if (intel_phy_is_tc(i915, phy)) return icl_get_tc_phy_dplls(state, crtc, encoder); MISSING_CASE(phy); @@ -3392,7 +3416,7 @@ static void icl_put_dplls(struct intel_atomic_state *state, } } -static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool mg_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -3402,46 +3426,46 @@ static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv, bool ret = false; u32 val; - i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_tc_pll_enable_reg(i915, pll); - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, enable_reg); + val = intel_de_read(i915, enable_reg); if (!(val & PLL_ENABLE)) goto out; - hw_state->mg_refclkin_ctl = intel_de_read(dev_priv, + hw_state->mg_refclkin_ctl = intel_de_read(i915, MG_REFCLKIN_CTL(tc_port)); hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK; hw_state->mg_clktop2_coreclkctl1 = - intel_de_read(dev_priv, MG_CLKTOP2_CORECLKCTL1(tc_port)); + intel_de_read(i915, MG_CLKTOP2_CORECLKCTL1(tc_port)); hw_state->mg_clktop2_coreclkctl1 &= MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; hw_state->mg_clktop2_hsclkctl = - intel_de_read(dev_priv, MG_CLKTOP2_HSCLKCTL(tc_port)); + intel_de_read(i915, MG_CLKTOP2_HSCLKCTL(tc_port)); hw_state->mg_clktop2_hsclkctl &= MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK; - hw_state->mg_pll_div0 = intel_de_read(dev_priv, MG_PLL_DIV0(tc_port)); - hw_state->mg_pll_div1 = intel_de_read(dev_priv, MG_PLL_DIV1(tc_port)); - hw_state->mg_pll_lf = intel_de_read(dev_priv, MG_PLL_LF(tc_port)); - hw_state->mg_pll_frac_lock = intel_de_read(dev_priv, + hw_state->mg_pll_div0 = intel_de_read(i915, MG_PLL_DIV0(tc_port)); + hw_state->mg_pll_div1 = intel_de_read(i915, MG_PLL_DIV1(tc_port)); + hw_state->mg_pll_lf = intel_de_read(i915, MG_PLL_LF(tc_port)); + hw_state->mg_pll_frac_lock = intel_de_read(i915, MG_PLL_FRAC_LOCK(tc_port)); - hw_state->mg_pll_ssc = intel_de_read(dev_priv, MG_PLL_SSC(tc_port)); + hw_state->mg_pll_ssc = intel_de_read(i915, MG_PLL_SSC(tc_port)); - hw_state->mg_pll_bias = intel_de_read(dev_priv, MG_PLL_BIAS(tc_port)); + hw_state->mg_pll_bias = intel_de_read(i915, MG_PLL_BIAS(tc_port)); hw_state->mg_pll_tdc_coldst_bias = - intel_de_read(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port)); + intel_de_read(i915, MG_PLL_TDC_COLDST_BIAS(tc_port)); - if (dev_priv->display.dpll.ref_clks.nssc == 38400) { + if (i915->display.dpll.ref_clks.nssc == 38400) { hw_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART; hw_state->mg_pll_bias_mask = 0; } else { @@ -3454,11 +3478,11 @@ static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv, ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } -static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool dkl_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -3468,12 +3492,12 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, bool ret = false; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, intel_tc_pll_enable_reg(dev_priv, pll)); + val = intel_de_read(i915, intel_tc_pll_enable_reg(i915, pll)); if (!(val & PLL_ENABLE)) goto out; @@ -3481,12 +3505,12 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, * All registers read here have the same HIP_INDEX_REG even though * they are on different building blocks */ - hw_state->mg_refclkin_ctl = intel_dkl_phy_read(dev_priv, + hw_state->mg_refclkin_ctl = intel_dkl_phy_read(i915, DKL_REFCLKIN_CTL(tc_port)); hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK; hw_state->mg_clktop2_hsclkctl = - intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port)); + intel_dkl_phy_read(i915, DKL_CLKTOP2_HSCLKCTL(tc_port)); hw_state->mg_clktop2_hsclkctl &= MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | @@ -3494,42 +3518,42 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK; hw_state->mg_clktop2_coreclkctl1 = - intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port)); + intel_dkl_phy_read(i915, DKL_CLKTOP2_CORECLKCTL1(tc_port)); hw_state->mg_clktop2_coreclkctl1 &= MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; - hw_state->mg_pll_div0 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV0(tc_port)); + hw_state->mg_pll_div0 = intel_dkl_phy_read(i915, DKL_PLL_DIV0(tc_port)); val = DKL_PLL_DIV0_MASK; - if (dev_priv->display.vbt.override_afc_startup) + if (i915->display.vbt.override_afc_startup) val |= DKL_PLL_DIV0_AFC_STARTUP_MASK; hw_state->mg_pll_div0 &= val; - hw_state->mg_pll_div1 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port)); + hw_state->mg_pll_div1 = intel_dkl_phy_read(i915, DKL_PLL_DIV1(tc_port)); hw_state->mg_pll_div1 &= (DKL_PLL_DIV1_IREF_TRIM_MASK | DKL_PLL_DIV1_TDC_TARGET_CNT_MASK); - hw_state->mg_pll_ssc = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port)); + hw_state->mg_pll_ssc = intel_dkl_phy_read(i915, DKL_PLL_SSC(tc_port)); hw_state->mg_pll_ssc &= (DKL_PLL_SSC_IREF_NDIV_RATIO_MASK | DKL_PLL_SSC_STEP_LEN_MASK | DKL_PLL_SSC_STEP_NUM_MASK | DKL_PLL_SSC_EN); - hw_state->mg_pll_bias = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port)); + hw_state->mg_pll_bias = intel_dkl_phy_read(i915, DKL_PLL_BIAS(tc_port)); hw_state->mg_pll_bias &= (DKL_PLL_BIAS_FRAC_EN_H | DKL_PLL_BIAS_FBDIV_FRAC_MASK); hw_state->mg_pll_tdc_coldst_bias = - intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + intel_dkl_phy_read(i915, DKL_PLL_TDC_COLDST_BIAS(tc_port)); hw_state->mg_pll_tdc_coldst_bias &= (DKL_PLL_TDC_SSC_STEP_SIZE_MASK | DKL_PLL_TDC_FEED_FWD_GAIN_MASK); ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } -static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool icl_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state, i915_reg_t enable_reg) @@ -3539,94 +3563,94 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, bool ret = false; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, enable_reg); + val = intel_de_read(i915, enable_reg); if (!(val & PLL_ENABLE)) goto out; - if (IS_ALDERLAKE_S(dev_priv)) { - hw_state->cfgcr0 = intel_de_read(dev_priv, ADLS_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, ADLS_DPLL_CFGCR1(id)); - } else if (IS_DG1(dev_priv)) { - hw_state->cfgcr0 = intel_de_read(dev_priv, DG1_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, DG1_DPLL_CFGCR1(id)); - } else if (IS_ROCKETLAKE(dev_priv)) { - hw_state->cfgcr0 = intel_de_read(dev_priv, + if (IS_ALDERLAKE_S(i915)) { + hw_state->cfgcr0 = intel_de_read(i915, ADLS_DPLL_CFGCR0(id)); + hw_state->cfgcr1 = intel_de_read(i915, ADLS_DPLL_CFGCR1(id)); + } else if (IS_DG1(i915)) { + hw_state->cfgcr0 = intel_de_read(i915, DG1_DPLL_CFGCR0(id)); + hw_state->cfgcr1 = intel_de_read(i915, DG1_DPLL_CFGCR1(id)); + } else if (IS_ROCKETLAKE(i915)) { + hw_state->cfgcr0 = intel_de_read(i915, RKL_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, + hw_state->cfgcr1 = intel_de_read(i915, RKL_DPLL_CFGCR1(id)); - } else if (DISPLAY_VER(dev_priv) >= 12) { - hw_state->cfgcr0 = intel_de_read(dev_priv, + } else if (DISPLAY_VER(i915) >= 12) { + hw_state->cfgcr0 = intel_de_read(i915, TGL_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, + hw_state->cfgcr1 = intel_de_read(i915, TGL_DPLL_CFGCR1(id)); - if (dev_priv->display.vbt.override_afc_startup) { - hw_state->div0 = intel_de_read(dev_priv, TGL_DPLL0_DIV0(id)); + if (i915->display.vbt.override_afc_startup) { + hw_state->div0 = intel_de_read(i915, TGL_DPLL0_DIV0(id)); hw_state->div0 &= TGL_DPLL0_DIV0_AFC_STARTUP_MASK; } } else { - if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && + if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && id == DPLL_ID_EHL_DPLL4) { - hw_state->cfgcr0 = intel_de_read(dev_priv, + hw_state->cfgcr0 = intel_de_read(i915, ICL_DPLL_CFGCR0(4)); - hw_state->cfgcr1 = intel_de_read(dev_priv, + hw_state->cfgcr1 = intel_de_read(i915, ICL_DPLL_CFGCR1(4)); } else { - hw_state->cfgcr0 = intel_de_read(dev_priv, + hw_state->cfgcr0 = intel_de_read(i915, ICL_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, + hw_state->cfgcr1 = intel_de_read(i915, ICL_DPLL_CFGCR1(id)); } } ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } -static bool combo_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool combo_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { - i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - return icl_pll_get_hw_state(dev_priv, pll, hw_state, enable_reg); + return icl_pll_get_hw_state(i915, pll, hw_state, enable_reg); } -static bool tbt_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool tbt_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { - return icl_pll_get_hw_state(dev_priv, pll, hw_state, TBT_PLL_ENABLE); + return icl_pll_get_hw_state(i915, pll, hw_state, TBT_PLL_ENABLE); } -static void icl_dpll_write(struct drm_i915_private *dev_priv, +static void icl_dpll_write(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { struct intel_dpll_hw_state *hw_state = &pll->state.hw_state; const enum intel_dpll_id id = pll->info->id; i915_reg_t cfgcr0_reg, cfgcr1_reg, div0_reg = INVALID_MMIO_REG; - if (IS_ALDERLAKE_S(dev_priv)) { + if (IS_ALDERLAKE_S(i915)) { cfgcr0_reg = ADLS_DPLL_CFGCR0(id); cfgcr1_reg = ADLS_DPLL_CFGCR1(id); - } else if (IS_DG1(dev_priv)) { + } else if (IS_DG1(i915)) { cfgcr0_reg = DG1_DPLL_CFGCR0(id); cfgcr1_reg = DG1_DPLL_CFGCR1(id); - } else if (IS_ROCKETLAKE(dev_priv)) { + } else if (IS_ROCKETLAKE(i915)) { cfgcr0_reg = RKL_DPLL_CFGCR0(id); cfgcr1_reg = RKL_DPLL_CFGCR1(id); - } else if (DISPLAY_VER(dev_priv) >= 12) { + } else if (DISPLAY_VER(i915) >= 12) { cfgcr0_reg = TGL_DPLL_CFGCR0(id); cfgcr1_reg = TGL_DPLL_CFGCR1(id); div0_reg = TGL_DPLL0_DIV0(id); } else { - if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && + if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && id == DPLL_ID_EHL_DPLL4) { cfgcr0_reg = ICL_DPLL_CFGCR0(4); cfgcr1_reg = ICL_DPLL_CFGCR1(4); @@ -3636,18 +3660,18 @@ static void icl_dpll_write(struct drm_i915_private *dev_priv, } } - intel_de_write(dev_priv, cfgcr0_reg, hw_state->cfgcr0); - intel_de_write(dev_priv, cfgcr1_reg, hw_state->cfgcr1); - drm_WARN_ON_ONCE(&dev_priv->drm, dev_priv->display.vbt.override_afc_startup && + intel_de_write(i915, cfgcr0_reg, hw_state->cfgcr0); + intel_de_write(i915, cfgcr1_reg, hw_state->cfgcr1); + drm_WARN_ON_ONCE(&i915->drm, i915->display.vbt.override_afc_startup && !i915_mmio_reg_valid(div0_reg)); - if (dev_priv->display.vbt.override_afc_startup && + if (i915->display.vbt.override_afc_startup && i915_mmio_reg_valid(div0_reg)) - intel_de_rmw(dev_priv, div0_reg, + intel_de_rmw(i915, div0_reg, TGL_DPLL0_DIV0_AFC_STARTUP_MASK, hw_state->div0); - intel_de_posting_read(dev_priv, cfgcr1_reg); + intel_de_posting_read(i915, cfgcr1_reg); } -static void icl_mg_pll_write(struct drm_i915_private *dev_priv, +static void icl_mg_pll_write(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { struct intel_dpll_hw_state *hw_state = &pll->state.hw_state; @@ -3659,38 +3683,38 @@ static void icl_mg_pll_write(struct drm_i915_private *dev_priv, * during the calc/readout phase if the mask depends on some other HW * state like refclk, see icl_calc_mg_pll_state(). */ - intel_de_rmw(dev_priv, MG_REFCLKIN_CTL(tc_port), + intel_de_rmw(i915, MG_REFCLKIN_CTL(tc_port), MG_REFCLKIN_CTL_OD_2_MUX_MASK, hw_state->mg_refclkin_ctl); - intel_de_rmw(dev_priv, MG_CLKTOP2_CORECLKCTL1(tc_port), + intel_de_rmw(i915, MG_CLKTOP2_CORECLKCTL1(tc_port), MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK, hw_state->mg_clktop2_coreclkctl1); - intel_de_rmw(dev_priv, MG_CLKTOP2_HSCLKCTL(tc_port), + intel_de_rmw(i915, MG_CLKTOP2_HSCLKCTL(tc_port), MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK, hw_state->mg_clktop2_hsclkctl); - intel_de_write(dev_priv, MG_PLL_DIV0(tc_port), hw_state->mg_pll_div0); - intel_de_write(dev_priv, MG_PLL_DIV1(tc_port), hw_state->mg_pll_div1); - intel_de_write(dev_priv, MG_PLL_LF(tc_port), hw_state->mg_pll_lf); - intel_de_write(dev_priv, MG_PLL_FRAC_LOCK(tc_port), + intel_de_write(i915, MG_PLL_DIV0(tc_port), hw_state->mg_pll_div0); + intel_de_write(i915, MG_PLL_DIV1(tc_port), hw_state->mg_pll_div1); + intel_de_write(i915, MG_PLL_LF(tc_port), hw_state->mg_pll_lf); + intel_de_write(i915, MG_PLL_FRAC_LOCK(tc_port), hw_state->mg_pll_frac_lock); - intel_de_write(dev_priv, MG_PLL_SSC(tc_port), hw_state->mg_pll_ssc); + intel_de_write(i915, MG_PLL_SSC(tc_port), hw_state->mg_pll_ssc); - intel_de_rmw(dev_priv, MG_PLL_BIAS(tc_port), + intel_de_rmw(i915, MG_PLL_BIAS(tc_port), hw_state->mg_pll_bias_mask, hw_state->mg_pll_bias); - intel_de_rmw(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port), + intel_de_rmw(i915, MG_PLL_TDC_COLDST_BIAS(tc_port), hw_state->mg_pll_tdc_coldst_bias_mask, hw_state->mg_pll_tdc_coldst_bias); - intel_de_posting_read(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port)); + intel_de_posting_read(i915, MG_PLL_TDC_COLDST_BIAS(tc_port)); } -static void dkl_pll_write(struct drm_i915_private *dev_priv, +static void dkl_pll_write(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { struct intel_dpll_hw_state *hw_state = &pll->state.hw_state; @@ -3702,83 +3726,83 @@ static void dkl_pll_write(struct drm_i915_private *dev_priv, * though on different building block */ /* All the registers are RMW */ - val = intel_dkl_phy_read(dev_priv, DKL_REFCLKIN_CTL(tc_port)); + val = intel_dkl_phy_read(i915, DKL_REFCLKIN_CTL(tc_port)); val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK; val |= hw_state->mg_refclkin_ctl; - intel_dkl_phy_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), val); + intel_dkl_phy_write(i915, DKL_REFCLKIN_CTL(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port)); + val = intel_dkl_phy_read(i915, DKL_CLKTOP2_CORECLKCTL1(tc_port)); val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; val |= hw_state->mg_clktop2_coreclkctl1; - intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), val); + intel_dkl_phy_write(i915, DKL_CLKTOP2_CORECLKCTL1(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port)); + val = intel_dkl_phy_read(i915, DKL_CLKTOP2_HSCLKCTL(tc_port)); val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK); val |= hw_state->mg_clktop2_hsclkctl; - intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), val); + intel_dkl_phy_write(i915, DKL_CLKTOP2_HSCLKCTL(tc_port), val); val = DKL_PLL_DIV0_MASK; - if (dev_priv->display.vbt.override_afc_startup) + if (i915->display.vbt.override_afc_startup) val |= DKL_PLL_DIV0_AFC_STARTUP_MASK; - intel_dkl_phy_rmw(dev_priv, DKL_PLL_DIV0(tc_port), val, + intel_dkl_phy_rmw(i915, DKL_PLL_DIV0(tc_port), val, hw_state->mg_pll_div0); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port)); + val = intel_dkl_phy_read(i915, DKL_PLL_DIV1(tc_port)); val &= ~(DKL_PLL_DIV1_IREF_TRIM_MASK | DKL_PLL_DIV1_TDC_TARGET_CNT_MASK); val |= hw_state->mg_pll_div1; - intel_dkl_phy_write(dev_priv, DKL_PLL_DIV1(tc_port), val); + intel_dkl_phy_write(i915, DKL_PLL_DIV1(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port)); + val = intel_dkl_phy_read(i915, DKL_PLL_SSC(tc_port)); val &= ~(DKL_PLL_SSC_IREF_NDIV_RATIO_MASK | DKL_PLL_SSC_STEP_LEN_MASK | DKL_PLL_SSC_STEP_NUM_MASK | DKL_PLL_SSC_EN); val |= hw_state->mg_pll_ssc; - intel_dkl_phy_write(dev_priv, DKL_PLL_SSC(tc_port), val); + intel_dkl_phy_write(i915, DKL_PLL_SSC(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port)); + val = intel_dkl_phy_read(i915, DKL_PLL_BIAS(tc_port)); val &= ~(DKL_PLL_BIAS_FRAC_EN_H | DKL_PLL_BIAS_FBDIV_FRAC_MASK); val |= hw_state->mg_pll_bias; - intel_dkl_phy_write(dev_priv, DKL_PLL_BIAS(tc_port), val); + intel_dkl_phy_write(i915, DKL_PLL_BIAS(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + val = intel_dkl_phy_read(i915, DKL_PLL_TDC_COLDST_BIAS(tc_port)); val &= ~(DKL_PLL_TDC_SSC_STEP_SIZE_MASK | DKL_PLL_TDC_FEED_FWD_GAIN_MASK); val |= hw_state->mg_pll_tdc_coldst_bias; - intel_dkl_phy_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), val); + intel_dkl_phy_write(i915, DKL_PLL_TDC_COLDST_BIAS(tc_port), val); - intel_dkl_phy_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + intel_dkl_phy_posting_read(i915, DKL_PLL_TDC_COLDST_BIAS(tc_port)); } -static void icl_pll_power_enable(struct drm_i915_private *dev_priv, +static void icl_pll_power_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll, i915_reg_t enable_reg) { - intel_de_rmw(dev_priv, enable_reg, 0, PLL_POWER_ENABLE); + intel_de_rmw(i915, enable_reg, 0, PLL_POWER_ENABLE); /* * The spec says we need to "wait" but it also says it should be * immediate. */ - if (intel_de_wait_for_set(dev_priv, enable_reg, PLL_POWER_STATE, 1)) - drm_err(&dev_priv->drm, "PLL %d Power not enabled\n", + if (intel_de_wait_for_set(i915, enable_reg, PLL_POWER_STATE, 1)) + drm_err(&i915->drm, "PLL %d Power not enabled\n", pll->info->id); } -static void icl_pll_enable(struct drm_i915_private *dev_priv, +static void icl_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll, i915_reg_t enable_reg) { - intel_de_rmw(dev_priv, enable_reg, 0, PLL_ENABLE); + intel_de_rmw(i915, enable_reg, 0, PLL_ENABLE); /* Timeout is actually 600us. */ - if (intel_de_wait_for_set(dev_priv, enable_reg, PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "PLL %d not locked\n", pll->info->id); + if (intel_de_wait_for_set(i915, enable_reg, PLL_LOCK, 1)) + drm_err(&i915->drm, "PLL %d not locked\n", pll->info->id); } static void adlp_cmtg_clock_gating_wa(struct drm_i915_private *i915, struct intel_shared_dpll *pll) @@ -3805,12 +3829,12 @@ static void adlp_cmtg_clock_gating_wa(struct drm_i915_private *i915, struct inte drm_dbg_kms(&i915->drm, "Unexpected flags in TRANS_CMTG_CHICKEN: %08x\n", val); } -static void combo_pll_enable(struct drm_i915_private *dev_priv, +static void combo_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && + if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && pll->info->id == DPLL_ID_EHL_DPLL4) { /* @@ -3818,13 +3842,13 @@ static void combo_pll_enable(struct drm_i915_private *dev_priv, * This can be done by taking a reference on DPLL4 power * domain. */ - pll->wakeref = intel_display_power_get(dev_priv, + pll->wakeref = intel_display_power_get(i915, POWER_DOMAIN_DC_OFF); } - icl_pll_power_enable(dev_priv, pll, enable_reg); + icl_pll_power_enable(i915, pll, enable_reg); - icl_dpll_write(dev_priv, pll); + icl_dpll_write(i915, pll); /* * DVFS pre sequence would be here, but in our driver the cdclk code @@ -3832,19 +3856,19 @@ static void combo_pll_enable(struct drm_i915_private *dev_priv, * nothing here. */ - icl_pll_enable(dev_priv, pll, enable_reg); + icl_pll_enable(i915, pll, enable_reg); - adlp_cmtg_clock_gating_wa(dev_priv, pll); + adlp_cmtg_clock_gating_wa(i915, pll); /* DVFS post sequence would be here. See the comment above. */ } -static void tbt_pll_enable(struct drm_i915_private *dev_priv, +static void tbt_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - icl_pll_power_enable(dev_priv, pll, TBT_PLL_ENABLE); + icl_pll_power_enable(i915, pll, TBT_PLL_ENABLE); - icl_dpll_write(dev_priv, pll); + icl_dpll_write(i915, pll); /* * DVFS pre sequence would be here, but in our driver the cdclk code @@ -3852,22 +3876,22 @@ static void tbt_pll_enable(struct drm_i915_private *dev_priv, * nothing here. */ - icl_pll_enable(dev_priv, pll, TBT_PLL_ENABLE); + icl_pll_enable(i915, pll, TBT_PLL_ENABLE); /* DVFS post sequence would be here. See the comment above. */ } -static void mg_pll_enable(struct drm_i915_private *dev_priv, +static void mg_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_tc_pll_enable_reg(i915, pll); - icl_pll_power_enable(dev_priv, pll, enable_reg); + icl_pll_power_enable(i915, pll, enable_reg); - if (DISPLAY_VER(dev_priv) >= 12) - dkl_pll_write(dev_priv, pll); + if (DISPLAY_VER(i915) >= 12) + dkl_pll_write(i915, pll); else - icl_mg_pll_write(dev_priv, pll); + icl_mg_pll_write(i915, pll); /* * DVFS pre sequence would be here, but in our driver the cdclk code @@ -3875,12 +3899,12 @@ static void mg_pll_enable(struct drm_i915_private *dev_priv, * nothing here. */ - icl_pll_enable(dev_priv, pll, enable_reg); + icl_pll_enable(i915, pll, enable_reg); /* DVFS post sequence would be here. See the comment above. */ } -static void icl_pll_disable(struct drm_i915_private *dev_priv, +static void icl_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll, i915_reg_t enable_reg) { @@ -3892,50 +3916,50 @@ static void icl_pll_disable(struct drm_i915_private *dev_priv, * nothing here. */ - intel_de_rmw(dev_priv, enable_reg, PLL_ENABLE, 0); + intel_de_rmw(i915, enable_reg, PLL_ENABLE, 0); /* Timeout is actually 1us. */ - if (intel_de_wait_for_clear(dev_priv, enable_reg, PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "PLL %d locked\n", pll->info->id); + if (intel_de_wait_for_clear(i915, enable_reg, PLL_LOCK, 1)) + drm_err(&i915->drm, "PLL %d locked\n", pll->info->id); /* DVFS post sequence would be here. See the comment above. */ - intel_de_rmw(dev_priv, enable_reg, PLL_POWER_ENABLE, 0); + intel_de_rmw(i915, enable_reg, PLL_POWER_ENABLE, 0); /* * The spec says we need to "wait" but it also says it should be * immediate. */ - if (intel_de_wait_for_clear(dev_priv, enable_reg, PLL_POWER_STATE, 1)) - drm_err(&dev_priv->drm, "PLL %d Power not disabled\n", + if (intel_de_wait_for_clear(i915, enable_reg, PLL_POWER_STATE, 1)) + drm_err(&i915->drm, "PLL %d Power not disabled\n", pll->info->id); } -static void combo_pll_disable(struct drm_i915_private *dev_priv, +static void combo_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - icl_pll_disable(dev_priv, pll, enable_reg); + icl_pll_disable(i915, pll, enable_reg); - if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && + if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && pll->info->id == DPLL_ID_EHL_DPLL4) - intel_display_power_put(dev_priv, POWER_DOMAIN_DC_OFF, + intel_display_power_put(i915, POWER_DOMAIN_DC_OFF, pll->wakeref); } -static void tbt_pll_disable(struct drm_i915_private *dev_priv, +static void tbt_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - icl_pll_disable(dev_priv, pll, TBT_PLL_ENABLE); + icl_pll_disable(i915, pll, TBT_PLL_ENABLE); } -static void mg_pll_disable(struct drm_i915_private *dev_priv, +static void mg_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_tc_pll_enable_reg(i915, pll); - icl_pll_disable(dev_priv, pll, enable_reg); + icl_pll_disable(i915, pll, enable_reg); } static void icl_update_dpll_ref_clks(struct drm_i915_private *i915) @@ -3944,10 +3968,10 @@ static void icl_update_dpll_ref_clks(struct drm_i915_private *i915) i915->display.dpll.ref_clks.nssc = i915->display.cdclk.hw.ref; } -static void icl_dump_hw_state(struct drm_i915_private *dev_priv, +static void icl_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "dpll_hw_state: cfgcr0: 0x%x, cfgcr1: 0x%x, div0: 0x%x, " "mg_refclkin_ctl: 0x%x, hg_clktop2_coreclkctl1: 0x%x, " "mg_clktop2_hsclkctl: 0x%x, mg_pll_div0: 0x%x, " @@ -4129,62 +4153,64 @@ static const struct intel_dpll_mgr adlp_pll_mgr = { /** * intel_shared_dpll_init - Initialize shared DPLLs - * @dev_priv: i915 device + * @i915: i915 device * - * Initialize shared DPLLs for @dev_priv. + * Initialize shared DPLLs for @i915. */ -void intel_shared_dpll_init(struct drm_i915_private *dev_priv) +void intel_shared_dpll_init(struct drm_i915_private *i915) { const struct intel_dpll_mgr *dpll_mgr = NULL; const struct dpll_info *dpll_info; int i; - mutex_init(&dev_priv->display.dpll.lock); + mutex_init(&i915->display.dpll.lock); - if (DISPLAY_VER(dev_priv) >= 14 || IS_DG2(dev_priv)) + if (DISPLAY_VER(i915) >= 14 || IS_DG2(i915)) /* No shared DPLLs on DG2; port PLLs are part of the PHY */ dpll_mgr = NULL; - else if (IS_ALDERLAKE_P(dev_priv)) + else if (IS_ALDERLAKE_P(i915)) dpll_mgr = &adlp_pll_mgr; - else if (IS_ALDERLAKE_S(dev_priv)) + else if (IS_ALDERLAKE_S(i915)) dpll_mgr = &adls_pll_mgr; - else if (IS_DG1(dev_priv)) + else if (IS_DG1(i915)) dpll_mgr = &dg1_pll_mgr; - else if (IS_ROCKETLAKE(dev_priv)) + else if (IS_ROCKETLAKE(i915)) dpll_mgr = &rkl_pll_mgr; - else if (DISPLAY_VER(dev_priv) >= 12) + else if (DISPLAY_VER(i915) >= 12) dpll_mgr = &tgl_pll_mgr; - else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) + else if (IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) dpll_mgr = &ehl_pll_mgr; - else if (DISPLAY_VER(dev_priv) >= 11) + else if (DISPLAY_VER(i915) >= 11) dpll_mgr = &icl_pll_mgr; - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) dpll_mgr = &bxt_pll_mgr; - else if (DISPLAY_VER(dev_priv) == 9) + else if (DISPLAY_VER(i915) == 9) dpll_mgr = &skl_pll_mgr; - else if (HAS_DDI(dev_priv)) + else if (HAS_DDI(i915)) dpll_mgr = &hsw_pll_mgr; - else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) + else if (HAS_PCH_IBX(i915) || HAS_PCH_CPT(i915)) dpll_mgr = &pch_pll_mgr; - if (!dpll_mgr) { - dev_priv->display.dpll.num_shared_dpll = 0; + if (!dpll_mgr) return; - } dpll_info = dpll_mgr->dpll_info; for (i = 0; dpll_info[i].name; i++) { - if (drm_WARN_ON(&dev_priv->drm, - i >= ARRAY_SIZE(dev_priv->display.dpll.shared_dplls))) + if (drm_WARN_ON(&i915->drm, + i >= ARRAY_SIZE(i915->display.dpll.shared_dplls))) + break; + + /* must fit into unsigned long bitmask on 32bit */ + if (drm_WARN_ON(&i915->drm, dpll_info[i].id >= 32)) break; - drm_WARN_ON(&dev_priv->drm, i != dpll_info[i].id); - dev_priv->display.dpll.shared_dplls[i].info = &dpll_info[i]; + i915->display.dpll.shared_dplls[i].info = &dpll_info[i]; + i915->display.dpll.shared_dplls[i].index = i; } - dev_priv->display.dpll.mgr = dpll_mgr; - dev_priv->display.dpll.num_shared_dpll = i; + i915->display.dpll.mgr = dpll_mgr; + i915->display.dpll.num_shared_dpll = i; } /** @@ -4205,10 +4231,10 @@ int intel_compute_shared_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr; + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dpll_mgr *dpll_mgr = i915->display.dpll.mgr; - if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr)) + if (drm_WARN_ON(&i915->drm, !dpll_mgr)) return -EINVAL; return dpll_mgr->compute_dplls(state, crtc, encoder); @@ -4238,10 +4264,10 @@ int intel_reserve_shared_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr; + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dpll_mgr *dpll_mgr = i915->display.dpll.mgr; - if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr)) + if (drm_WARN_ON(&i915->drm, !dpll_mgr)) return -EINVAL; return dpll_mgr->get_dplls(state, crtc, encoder); @@ -4261,8 +4287,8 @@ int intel_reserve_shared_dplls(struct intel_atomic_state *state, void intel_release_shared_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr; + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dpll_mgr *dpll_mgr = i915->display.dpll.mgr; /* * FIXME: this function is called for every platform having a @@ -4290,10 +4316,10 @@ void intel_update_active_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_dpll_mgr *dpll_mgr = i915->display.dpll.mgr; - if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr)) + if (drm_WARN_ON(&i915->drm, !dpll_mgr)) return; dpll_mgr->update_active_dpll(state, crtc, encoder); @@ -4369,10 +4395,11 @@ void intel_dpll_update_ref_clks(struct drm_i915_private *i915) void intel_dpll_readout_hw_state(struct drm_i915_private *i915) { + struct intel_shared_dpll *pll; int i; - for (i = 0; i < i915->display.dpll.num_shared_dpll; i++) - readout_dpll_hw_state(i915, &i915->display.dpll.shared_dplls[i]); + for_each_shared_dpll(i915, pll, i) + readout_dpll_hw_state(i915, pll); } static void sanitize_dpll_state(struct drm_i915_private *i915, @@ -4396,29 +4423,30 @@ static void sanitize_dpll_state(struct drm_i915_private *i915, void intel_dpll_sanitize_state(struct drm_i915_private *i915) { + struct intel_shared_dpll *pll; int i; - for (i = 0; i < i915->display.dpll.num_shared_dpll; i++) - sanitize_dpll_state(i915, &i915->display.dpll.shared_dplls[i]); + for_each_shared_dpll(i915, pll, i) + sanitize_dpll_state(i915, pll); } /** * intel_dpll_dump_hw_state - write hw_state to dmesg - * @dev_priv: i915 drm device + * @i915: i915 drm device * @hw_state: hw state to be written to the log * * Write the relevant values in @hw_state to dmesg using drm_dbg_kms. */ -void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, +void intel_dpll_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - if (dev_priv->display.dpll.mgr) { - dev_priv->display.dpll.mgr->dump_hw_state(dev_priv, hw_state); + if (i915->display.dpll.mgr) { + i915->display.dpll.mgr->dump_hw_state(i915, hw_state); } else { /* fallback for platforms that don't use the shared dpll * infrastructure */ - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, " "fp0: 0x%x, fp1: 0x%x\n", hw_state->dpll, @@ -4429,10 +4457,10 @@ void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, } static void -verify_single_dpll_state(struct drm_i915_private *dev_priv, +verify_single_dpll_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state) + const struct intel_crtc_state *new_crtc_state) { struct intel_dpll_hw_state dpll_hw_state; u8 pipe_mask; @@ -4440,22 +4468,22 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); - drm_dbg_kms(&dev_priv->drm, "%s\n", pll->info->name); + drm_dbg_kms(&i915->drm, "%s\n", pll->info->name); - active = intel_dpll_get_hw_state(dev_priv, pll, &dpll_hw_state); + active = intel_dpll_get_hw_state(i915, pll, &dpll_hw_state); if (!(pll->info->flags & INTEL_DPLL_ALWAYS_ON)) { - I915_STATE_WARN(dev_priv, !pll->on && pll->active_mask, + I915_STATE_WARN(i915, !pll->on && pll->active_mask, "pll in active use but not on in sw tracking\n"); - I915_STATE_WARN(dev_priv, pll->on && !pll->active_mask, + I915_STATE_WARN(i915, pll->on && !pll->active_mask, "pll is on but not used by any active pipe\n"); - I915_STATE_WARN(dev_priv, pll->on != active, + I915_STATE_WARN(i915, pll->on != active, "pll on state mismatch (expected %i, found %i)\n", pll->on, active); } if (!crtc) { - I915_STATE_WARN(dev_priv, + I915_STATE_WARN(i915, pll->active_mask & ~pll->state.pipe_mask, "more active pll users than references: 0x%x vs 0x%x\n", pll->active_mask, pll->state.pipe_mask); @@ -4466,32 +4494,35 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, pipe_mask = BIT(crtc->pipe); if (new_crtc_state->hw.active) - I915_STATE_WARN(dev_priv, !(pll->active_mask & pipe_mask), + I915_STATE_WARN(i915, !(pll->active_mask & pipe_mask), "pll active mismatch (expected pipe %c in active mask 0x%x)\n", pipe_name(crtc->pipe), pll->active_mask); else - I915_STATE_WARN(dev_priv, pll->active_mask & pipe_mask, + I915_STATE_WARN(i915, pll->active_mask & pipe_mask, "pll active mismatch (didn't expect pipe %c in active mask 0x%x)\n", pipe_name(crtc->pipe), pll->active_mask); - I915_STATE_WARN(dev_priv, !(pll->state.pipe_mask & pipe_mask), + I915_STATE_WARN(i915, !(pll->state.pipe_mask & pipe_mask), "pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n", pipe_mask, pll->state.pipe_mask); - I915_STATE_WARN(dev_priv, + I915_STATE_WARN(i915, pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state, sizeof(dpll_hw_state)), "pll hw state mismatch\n"); } -void intel_shared_dpll_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state) +void intel_shared_dpll_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); if (new_crtc_state->shared_dpll) - verify_single_dpll_state(dev_priv, new_crtc_state->shared_dpll, + verify_single_dpll_state(i915, new_crtc_state->shared_dpll, crtc, new_crtc_state); if (old_crtc_state->shared_dpll && @@ -4499,20 +4530,21 @@ void intel_shared_dpll_state_verify(struct intel_crtc *crtc, u8 pipe_mask = BIT(crtc->pipe); struct intel_shared_dpll *pll = old_crtc_state->shared_dpll; - I915_STATE_WARN(dev_priv, pll->active_mask & pipe_mask, + I915_STATE_WARN(i915, pll->active_mask & pipe_mask, "pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n", pipe_name(crtc->pipe), pll->active_mask); - I915_STATE_WARN(dev_priv, pll->state.pipe_mask & pipe_mask, + I915_STATE_WARN(i915, pll->state.pipe_mask & pipe_mask, "pll enabled crtcs mismatch (found %x in enabled mask (0x%x))\n", pipe_name(crtc->pipe), pll->state.pipe_mask); } } -void intel_shared_dpll_verify_disabled(struct drm_i915_private *i915) +void intel_shared_dpll_verify_disabled(struct intel_atomic_state *state) { + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_shared_dpll *pll; int i; - for (i = 0; i < i915->display.dpll.num_shared_dpll; i++) - verify_single_dpll_state(i915, &i915->display.dpll.shared_dplls[i], - NULL, NULL); + for_each_shared_dpll(i915, pll, i) + verify_single_dpll_state(i915, pll, NULL, NULL); } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index ba62eb5d7c51..dd4796a61751 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -29,12 +29,9 @@ #include "intel_wakeref.h" -/*FIXME: Move this to a more appropriate place. */ -#define abs_diff(a, b) ({ \ - typeof(a) __a = (a); \ - typeof(b) __b = (b); \ - (void) (&__a == &__b); \ - __a > __b ? (__a - __b) : (__b - __a); }) +#define for_each_shared_dpll(__i915, __pll, __i) \ + for ((__i) = 0; (__i) < (__i915)->display.dpll.num_shared_dpll && \ + ((__pll) = &(__i915)->display.dpll.shared_dplls[(__i)]) ; (__i)++) enum tc_port; struct drm_i915_private; @@ -269,8 +266,7 @@ struct dpll_info { const struct intel_shared_dpll_funcs *funcs; /** - * @id: unique indentifier for this DPLL; should match the index in the - * dev_priv->shared_dplls array + * @id: unique indentifier for this DPLL */ enum intel_dpll_id id; @@ -298,6 +294,11 @@ struct intel_shared_dpll { struct intel_shared_dpll_state state; /** + * @index: index for atomic state + */ + u8 index; + + /** * @active_mask: mask of active pipes (i.e. DPMS on) using this DPLL */ u8 active_mask; @@ -326,9 +327,9 @@ struct intel_shared_dpll { /* shared dpll functions */ struct intel_shared_dpll * -intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv, +intel_get_shared_dpll_by_id(struct drm_i915_private *i915, enum intel_dpll_id id); -void assert_shared_dpll(struct drm_i915_private *dev_priv, +void assert_shared_dpll(struct drm_i915_private *i915, struct intel_shared_dpll *pll, bool state); #define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true) @@ -358,19 +359,18 @@ bool intel_dpll_get_hw_state(struct drm_i915_private *i915, void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state); void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state); void intel_shared_dpll_swap_state(struct intel_atomic_state *state); -void intel_shared_dpll_init(struct drm_i915_private *dev_priv); -void intel_dpll_update_ref_clks(struct drm_i915_private *dev_priv); -void intel_dpll_readout_hw_state(struct drm_i915_private *dev_priv); -void intel_dpll_sanitize_state(struct drm_i915_private *dev_priv); +void intel_shared_dpll_init(struct drm_i915_private *i915); +void intel_dpll_update_ref_clks(struct drm_i915_private *i915); +void intel_dpll_readout_hw_state(struct drm_i915_private *i915); +void intel_dpll_sanitize_state(struct drm_i915_private *i915); -void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, +void intel_dpll_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state); enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port); bool intel_dpll_is_combophy(enum intel_dpll_id id); -void intel_shared_dpll_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state); -void intel_shared_dpll_verify_disabled(struct drm_i915_private *i915); +void intel_shared_dpll_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc); +void intel_shared_dpll_verify_disabled(struct intel_atomic_state *state); #endif /* _INTEL_DPLL_MGR_H_ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index fbfd8f959f17..48582b31b7f7 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -29,7 +29,7 @@ static inline struct i915_dpt * i915_vm_to_dpt(struct i915_address_space *vm) { BUILD_BUG_ON(offsetof(struct i915_dpt, vm)); - GEM_BUG_ON(!i915_is_dpt(vm)); + drm_WARN_ON(&vm->i915->drm, !i915_is_dpt(vm)); return container_of(vm, struct i915_dpt, vm); } diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index 0d35b6be5b6a..6282ec0fc9b4 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -9,6 +9,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_drrs.h" +#include "intel_frontbuffer.h" #include "intel_panel.h" /** diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index bed058d2c3ac..3e32aa49b8eb 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -7,11 +7,16 @@ #include "gem/i915_gem_internal.h" #include "i915_drv.h" +#include "i915_irq.h" #include "i915_reg.h" +#include "intel_crtc.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dsb.h" #include "intel_dsb_regs.h" +#include "intel_vblank.h" +#include "intel_vrr.h" +#include "skl_watermark.h" struct i915_vma; @@ -47,6 +52,8 @@ struct intel_dsb { * register. */ unsigned int ins_start_offset; + + int dewake_scanline; }; /** @@ -70,17 +77,21 @@ struct intel_dsb { #define DSB_OPCODE_SHIFT 24 #define DSB_OPCODE_NOOP 0x0 #define DSB_OPCODE_MMIO_WRITE 0x1 +#define DSB_BYTE_EN 0xf +#define DSB_BYTE_EN_SHIFT 20 +#define DSB_REG_VALUE_MASK 0xfffff #define DSB_OPCODE_WAIT_USEC 0x2 -#define DSB_OPCODE_WAIT_LINES 0x3 +#define DSB_OPCODE_WAIT_SCANLINE 0x3 #define DSB_OPCODE_WAIT_VBLANKS 0x4 #define DSB_OPCODE_WAIT_DSL_IN 0x5 #define DSB_OPCODE_WAIT_DSL_OUT 0x6 +#define DSB_SCANLINE_UPPER_SHIFT 20 +#define DSB_SCANLINE_LOWER_SHIFT 0 #define DSB_OPCODE_INTERRUPT 0x7 #define DSB_OPCODE_INDEXED_WRITE 0x9 +/* see DSB_REG_VALUE_MASK */ #define DSB_OPCODE_POLL 0xA -#define DSB_BYTE_EN 0xF -#define DSB_BYTE_EN_SHIFT 20 -#define DSB_REG_VALUE_MASK 0xfffff +/* see DSB_REG_VALUE_MASK */ static bool assert_dsb_has_room(struct intel_dsb *dsb) { @@ -93,10 +104,26 @@ static bool assert_dsb_has_room(struct intel_dsb *dsb) crtc->base.base.id, crtc->base.name, dsb->id); } +static void intel_dsb_dump(struct intel_dsb *dsb) +{ + struct intel_crtc *crtc = dsb->crtc; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + const u32 *buf = dsb->cmd_buf; + int i; + + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] DSB %d commands {\n", + crtc->base.base.id, crtc->base.name, dsb->id); + for (i = 0; i < ALIGN(dsb->free_pos, 64 / 4); i += 4) + drm_dbg_kms(&i915->drm, + " 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", + i * 4, buf[i], buf[i+1], buf[i+2], buf[i+3]); + drm_dbg_kms(&i915->drm, "}\n"); +} + static bool is_dsb_busy(struct drm_i915_private *i915, enum pipe pipe, enum dsb_id id) { - return intel_de_read(i915, DSB_CTRL(pipe, id)) & DSB_STATUS_BUSY; + return intel_de_read_fw(i915, DSB_CTRL(pipe, id)) & DSB_STATUS_BUSY; } static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw) @@ -121,7 +148,15 @@ static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb, const u32 *buf = dsb->cmd_buf; u32 prev_opcode, prev_reg; - prev_opcode = buf[dsb->ins_start_offset + 1] >> DSB_OPCODE_SHIFT; + /* + * Nothing emitted yet? Must check before looking + * at the actual data since i915_gem_object_create_internal() + * does *not* give you zeroed memory! + */ + if (dsb->free_pos == 0) + return false; + + prev_opcode = buf[dsb->ins_start_offset + 1] & ~DSB_REG_VALUE_MASK; prev_reg = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK; return prev_opcode == opcode && prev_reg == i915_mmio_reg_offset(reg); @@ -129,12 +164,18 @@ static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb, static bool intel_dsb_prev_ins_is_mmio_write(struct intel_dsb *dsb, i915_reg_t reg) { - return intel_dsb_prev_ins_is_write(dsb, DSB_OPCODE_MMIO_WRITE, reg); + /* only full byte-enables can be converted to indexed writes */ + return intel_dsb_prev_ins_is_write(dsb, + DSB_OPCODE_MMIO_WRITE << DSB_OPCODE_SHIFT | + DSB_BYTE_EN << DSB_BYTE_EN_SHIFT, + reg); } static bool intel_dsb_prev_ins_is_indexed_write(struct intel_dsb *dsb, i915_reg_t reg) { - return intel_dsb_prev_ins_is_write(dsb, DSB_OPCODE_INDEXED_WRITE, reg); + return intel_dsb_prev_ins_is_write(dsb, + DSB_OPCODE_INDEXED_WRITE << DSB_OPCODE_SHIFT, + reg); } /** @@ -200,6 +241,53 @@ void intel_dsb_reg_write(struct intel_dsb *dsb, } } +static u32 intel_dsb_mask_to_byte_en(u32 mask) +{ + return (!!(mask & 0xff000000) << 3 | + !!(mask & 0x00ff0000) << 2 | + !!(mask & 0x0000ff00) << 1 | + !!(mask & 0x000000ff) << 0); +} + +/* Note: mask implemented via byte enables! */ +void intel_dsb_reg_write_masked(struct intel_dsb *dsb, + i915_reg_t reg, u32 mask, u32 val) +{ + intel_dsb_emit(dsb, val, + (DSB_OPCODE_MMIO_WRITE << DSB_OPCODE_SHIFT) | + (intel_dsb_mask_to_byte_en(mask) << DSB_BYTE_EN_SHIFT) | + i915_mmio_reg_offset(reg)); +} + +void intel_dsb_noop(struct intel_dsb *dsb, int count) +{ + int i; + + for (i = 0; i < count; i++) + intel_dsb_emit(dsb, 0, + DSB_OPCODE_NOOP << DSB_OPCODE_SHIFT); +} + +void intel_dsb_nonpost_start(struct intel_dsb *dsb) +{ + struct intel_crtc *crtc = dsb->crtc; + enum pipe pipe = crtc->pipe; + + intel_dsb_reg_write_masked(dsb, DSB_CTRL(pipe, dsb->id), + DSB_NON_POSTED, DSB_NON_POSTED); + intel_dsb_noop(dsb, 4); +} + +void intel_dsb_nonpost_end(struct intel_dsb *dsb) +{ + struct intel_crtc *crtc = dsb->crtc; + enum pipe pipe = crtc->pipe; + + intel_dsb_reg_write_masked(dsb, DSB_CTRL(pipe, dsb->id), + DSB_NON_POSTED, 0); + intel_dsb_noop(dsb, 4); +} + static void intel_dsb_align_tail(struct intel_dsb *dsb) { u32 aligned_tail, tail; @@ -216,17 +304,40 @@ static void intel_dsb_align_tail(struct intel_dsb *dsb) void intel_dsb_finish(struct intel_dsb *dsb) { + struct intel_crtc *crtc = dsb->crtc; + + /* + * DSB_FORCE_DEWAKE remains active even after DSB is + * disabled, so make sure to clear it (if set during + * intel_dsb_commit()). + */ + intel_dsb_reg_write_masked(dsb, DSB_PMCTRL_2(crtc->pipe, dsb->id), + DSB_FORCE_DEWAKE, 0); + intel_dsb_align_tail(dsb); } -/** - * intel_dsb_commit() - Trigger workload execution of DSB. - * @dsb: DSB context - * @wait_for_vblank: wait for vblank before executing - * - * This function is used to do actual write to hardware using DSB. - */ -void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank) +static int intel_dsb_dewake_scanline(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + unsigned int latency = skl_watermark_max_latency(i915); + int vblank_start; + + if (crtc_state->vrr.enable) { + vblank_start = intel_vrr_vmin_vblank_start(crtc_state); + } else { + vblank_start = adjusted_mode->crtc_vblank_start; + + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + vblank_start = DIV_ROUND_UP(vblank_start, 2); + } + + return max(0, vblank_start - intel_usecs_to_scanlines(adjusted_mode, latency)); +} + +static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl, + unsigned int dewake_scanline) { struct intel_crtc *crtc = dsb->crtc; struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -243,13 +354,48 @@ void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank) return; } - intel_de_write(dev_priv, DSB_CTRL(pipe, dsb->id), - (wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0) | - DSB_ENABLE); - intel_de_write(dev_priv, DSB_HEAD(pipe, dsb->id), - i915_ggtt_offset(dsb->vma)); - intel_de_write(dev_priv, DSB_TAIL(pipe, dsb->id), - i915_ggtt_offset(dsb->vma) + tail); + intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id), + ctrl | DSB_ENABLE); + + intel_de_write_fw(dev_priv, DSB_HEAD(pipe, dsb->id), + i915_ggtt_offset(dsb->vma)); + + if (dewake_scanline >= 0) { + int diff, hw_dewake_scanline; + + hw_dewake_scanline = intel_crtc_scanline_to_hw(crtc, dewake_scanline); + + intel_de_write_fw(dev_priv, DSB_PMCTRL(pipe, dsb->id), + DSB_ENABLE_DEWAKE | + DSB_SCANLINE_FOR_DEWAKE(hw_dewake_scanline)); + + /* + * Force DEwake immediately if we're already past + * or close to racing past the target scanline. + */ + diff = dewake_scanline - intel_get_crtc_scanline(crtc); + intel_de_write_fw(dev_priv, DSB_PMCTRL_2(pipe, dsb->id), + (diff >= 0 && diff < 5 ? DSB_FORCE_DEWAKE : 0) | + DSB_BLOCK_DEWAKE_EXTENSION); + } + + intel_de_write_fw(dev_priv, DSB_TAIL(pipe, dsb->id), + i915_ggtt_offset(dsb->vma) + tail); +} + +/** + * intel_dsb_commit() - Trigger workload execution of DSB. + * @dsb: DSB context + * @wait_for_vblank: wait for vblank before executing + * + * This function is used to do actual write to hardware using DSB. + */ +void intel_dsb_commit(struct intel_dsb *dsb, + bool wait_for_vblank) +{ + _intel_dsb_commit(dsb, + wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0, + wait_for_vblank ? dsb->dewake_scanline : -1); } void intel_dsb_wait(struct intel_dsb *dsb) @@ -258,20 +404,31 @@ void intel_dsb_wait(struct intel_dsb *dsb) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; - if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) + if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) { + u32 offset = i915_ggtt_offset(dsb->vma); + + intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id), + DSB_ENABLE | DSB_HALT); + drm_err(&dev_priv->drm, - "[CRTC:%d:%s] DSB %d timed out waiting for idle\n", - crtc->base.base.id, crtc->base.name, dsb->id); + "[CRTC:%d:%s] DSB %d timed out waiting for idle (current head=0x%x, head=0x%x, tail=0x%x)\n", + crtc->base.base.id, crtc->base.name, dsb->id, + intel_de_read_fw(dev_priv, DSB_CURRENT_HEAD(pipe, dsb->id)) - offset, + intel_de_read_fw(dev_priv, DSB_HEAD(pipe, dsb->id)) - offset, + intel_de_read_fw(dev_priv, DSB_TAIL(pipe, dsb->id)) - offset); + + intel_dsb_dump(dsb); + } /* Attempt to reset it */ dsb->free_pos = 0; dsb->ins_start_offset = 0; - intel_de_write(dev_priv, DSB_CTRL(pipe, dsb->id), 0); + intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id), 0); } /** * intel_dsb_prepare() - Allocate, pin and map the DSB command buffer. - * @crtc: the CRTC + * @crtc_state: the CRTC state * @max_cmds: number of commands we need to fit into command buffer * * This function prepare the command buffer which is used to store dsb @@ -280,9 +437,10 @@ void intel_dsb_wait(struct intel_dsb *dsb) * Returns: * DSB context, NULL on failure */ -struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc, +struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, unsigned int max_cmds) { + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct drm_i915_gem_object *obj; intel_wakeref_t wakeref; @@ -328,6 +486,7 @@ struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc, dsb->size = size / 4; /* in dwords */ dsb->free_pos = 0; dsb->ins_start_offset = 0; + dsb->dewake_scanline = intel_dsb_dewake_scanline(crtc_state); return dsb; diff --git a/drivers/gpu/drm/i915/display/intel_dsb.h b/drivers/gpu/drm/i915/display/intel_dsb.h index b8148b47022d..16d80f434356 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.h +++ b/drivers/gpu/drm/i915/display/intel_dsb.h @@ -11,14 +11,21 @@ #include "i915_reg_defs.h" struct intel_crtc; +struct intel_crtc_state; struct intel_dsb; -struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc, +struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, unsigned int max_cmds); void intel_dsb_finish(struct intel_dsb *dsb); void intel_dsb_cleanup(struct intel_dsb *dsb); void intel_dsb_reg_write(struct intel_dsb *dsb, i915_reg_t reg, u32 val); +void intel_dsb_reg_write_masked(struct intel_dsb *dsb, + i915_reg_t reg, u32 mask, u32 val); +void intel_dsb_noop(struct intel_dsb *dsb, int count); +void intel_dsb_nonpost_start(struct intel_dsb *dsb); +void intel_dsb_nonpost_end(struct intel_dsb *dsb); + void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank); void intel_dsb_wait(struct intel_dsb *dsb); diff --git a/drivers/gpu/drm/i915/display/intel_dsb_regs.h b/drivers/gpu/drm/i915/display/intel_dsb_regs.h index 12535d478775..210e2665441d 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dsb_regs.h @@ -37,6 +37,19 @@ #define DSB_DEBUG(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x14) #define DSB_POLLMASK(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x1c) #define DSB_STATUS(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x24) +#define DSB_HP_IDLE_STATUS REG_BIT(31) +#define DSB_DEWAKE_STATUS REG_BIT(30) +#define DSB_REQARB_SM_STATE_MASK REG_GENMASK(29, 27) +#define DSB_SAFE_WINDOW_LIVE REG_BIT(26) +#define DSB_VTDFAULT_ARB_SM_STATE_MASK REG_GENMASK(25, 23) +#define DSB_TLBTRANS_SM_STATE_MASK REG_GENMASK(21, 20) +#define DSB_SAFE_WINDOW REG_BIT(19) +#define DSB_POINTERS_SM_STATE_MASK REG_GENMASK(18, 17) +#define DSB_BUSY_ON_DELAYED_VBLANK REG_BIT(16) +#define DSB_MMIO_ARB_SM_STATE_MASK REG_GENMASK(15, 13) +#define DSB_MMIO_INST_SM_STATE_MASK REG_GENMASK(11, 7) +#define DSB_RESET_SM_STATE_MASK REG_GENMASK(5, 4) +#define DSB_RUN_SM_STATE_MASK REG_GENMASK(2, 0) #define DSB_INTERRUPT(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x28) #define DSB_ATS_FAULT_INT_EN REG_BIT(20) #define DSB_GTT_FAULT_INT_EN REG_BIT(19) @@ -58,10 +71,28 @@ #define DSB_RM_READY_TIMEOUT_VALUE(x) REG_FIELD_PREP(DSB_RM_READY_TIMEOUT_VALUE, (x)) /* usec */ #define DSB_RMTIMEOUTREG_CAPTURE(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x34) #define DSB_PMCTRL(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x38) +#define DSB_ENABLE_DEWAKE REG_BIT(31) +#define DSB_SCANLINE_FOR_DEWAKE_MASK REG_GENMASK(30, 0) +#define DSB_SCANLINE_FOR_DEWAKE(x) REG_FIELD_PREP(DSB_SCANLINE_FOR_DEWAKE_MASK, (x)) #define DSB_PMCTRL_2(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x3c) +#define DSB_MMIOGEN_DEWAKE_DIS REG_BIT(31) +#define DSB_FORCE_DEWAKE REG_BIT(23) +#define DSB_BLOCK_DEWAKE_EXTENSION REG_BIT(15) +#define DSB_OVERRIDE_DC5_DC6_OK REG_BIT(7) #define DSB_PF_LN_LOWER(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x40) #define DSB_PF_LN_UPPER(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x44) #define DSB_BUFRPT_CNT(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x48) #define DSB_CHICKEN(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0xf0) +#define DSB_FORCE_DMA_SYNC_RESET REG_BIT(31) +#define DSB_FORCE_VTD_ENGIE_RESET REG_BIT(30) +#define DSB_DISABLE_IPC_DEMOTE REG_BIT(29) +#define DSB_SKIP_WAITS_EN REG_BIT(23) +#define DSB_EXTEND_HP_IDLE REG_BIT(16) +#define DSB_CTRL_WAIT_SAFE_WINDOW REG_BIT(15) +#define DSB_CTRL_NO_WAIT_VBLANK REG_BIT(14) +#define DSB_INST_WAIT_SAFE_WINDOW REG_BIT(7) +#define DSB_INST_NO_WAIT_VBLANK REG_BIT(6) +#define DSB_MMIOGEN_DEWAKE_DIS_CHICKEN REG_BIT(2) +#define DSB_DISABLE_MMIO_COUNT_FOR_INDEXED REG_BIT(0) #endif /* __INTEL_DSB_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index e56ec3f2d84a..24b2cbcfc1ef 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -565,6 +565,9 @@ static const u8 *mipi_exec_i2c(struct intel_dsi *intel_dsi, const u8 *data) u8 payload_size = *(data + 6); u8 *payload_data; + drm_dbg_kms(&i915->drm, "bus %d client-addr 0x%02x reg 0x%02x data %*ph\n", + vbt_i2c_bus_num, slave_addr, reg_offset, payload_size, data + 7); + if (intel_dsi->i2c_bus_num < 0) { intel_dsi->i2c_bus_num = vbt_i2c_bus_num; i2c_acpi_find_adapter(intel_dsi, slave_addr); diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index b386894c3a6d..55d6743374bd 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -319,7 +319,7 @@ intel_dvo_detect(struct drm_connector *_connector, bool force) drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n", connector->base.base.id, connector->base.name); - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); @@ -328,7 +328,6 @@ intel_dvo_detect(struct drm_connector *_connector, bool force) static int intel_dvo_get_modes(struct drm_connector *_connector) { struct intel_connector *connector = to_intel_connector(_connector); - struct drm_i915_private *i915 = to_i915(connector->base.dev); int num_modes; /* @@ -337,8 +336,7 @@ static int intel_dvo_get_modes(struct drm_connector *_connector) * (TV-out, for example), but for now with just TMDS and LVDS, * that's not the case. */ - num_modes = intel_ddc_get_modes(&connector->base, - intel_gmbus_get_adapter(i915, GMBUS_PIN_DPC)); + num_modes = intel_ddc_get_modes(&connector->base, connector->base.ddc); if (num_modes) return num_modes; @@ -533,9 +531,10 @@ void intel_dvo_init(struct drm_i915_private *i915) connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - drm_connector_init(&i915->drm, &connector->base, - &intel_dvo_connector_funcs, - intel_dvo_connector_type(&intel_dvo->dev)); + drm_connector_init_with_ddc(&i915->drm, &connector->base, + &intel_dvo_connector_funcs, + intel_dvo_connector_type(&intel_dvo->dev), + intel_gmbus_get_adapter(i915, GMBUS_PIN_DPC)); drm_connector_helper_add(&connector->base, &intel_dvo_connector_helper_funcs); diff --git a/drivers/gpu/drm/i915/display/intel_dvo.h b/drivers/gpu/drm/i915/display/intel_dvo.h index 3ed0fdf8efff..bf7a356422ab 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.h +++ b/drivers/gpu/drm/i915/display/intel_dvo.h @@ -8,6 +8,12 @@ struct drm_i915_private; +#ifdef I915 void intel_dvo_init(struct drm_i915_private *dev_priv); +#else +static inline void intel_dvo_init(struct drm_i915_private *dev_priv) +{ +} +#endif #endif /* __INTEL_DVO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 446bbf7986b6..19b35ece31f1 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -7,11 +7,15 @@ #include <drm/drm_framebuffer.h> #include <drm/drm_modeset_helper.h> +#include <linux/dma-fence.h> +#include <linux/dma-resv.h> + #include "i915_drv.h" #include "intel_display.h" #include "intel_display_types.h" #include "intel_dpt.h" #include "intel_fb.h" +#include "intel_frontbuffer.h" #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a)) @@ -1113,7 +1117,7 @@ static int intel_fb_offset_to_xy(int *x, int *y, return -EINVAL; } - height = drm_framebuffer_plane_height(fb->height, fb, color_plane); + height = drm_format_info_plane_height(fb->format, fb->height, color_plane); height = ALIGN(height, intel_tile_height(fb, color_plane)); /* Catch potential overflows early */ @@ -1896,6 +1900,21 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, return drm_gem_handle_create(file, &obj->base, handle); } +struct frontbuffer_fence_cb { + struct dma_fence_cb base; + struct intel_frontbuffer *front; +}; + +static void intel_user_framebuffer_fence_wake(struct dma_fence *dma, + struct dma_fence_cb *data) +{ + struct frontbuffer_fence_cb *cb = container_of(data, typeof(*cb), base); + + intel_frontbuffer_queue_flush(cb->front); + kfree(cb); + dma_fence_put(dma); +} + static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_file *file, unsigned int flags, unsigned int color, @@ -1903,11 +1922,47 @@ static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, unsigned int num_clips) { struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_frontbuffer *front = to_intel_frontbuffer(fb); + struct dma_fence *fence; + struct frontbuffer_fence_cb *cb; + int ret = 0; - i915_gem_object_flush_if_display(obj); - intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB); + if (!atomic_read(&front->bits)) + return 0; - return 0; + if (dma_resv_test_signaled(obj->base.resv, dma_resv_usage_rw(false))) + goto flush; + + ret = dma_resv_get_singleton(obj->base.resv, dma_resv_usage_rw(false), + &fence); + if (ret || !fence) + goto flush; + + cb = kmalloc(sizeof(*cb), GFP_KERNEL); + if (!cb) { + dma_fence_put(fence); + ret = -ENOMEM; + goto flush; + } + + cb->front = front; + + intel_frontbuffer_invalidate(front, ORIGIN_DIRTYFB); + + ret = dma_fence_add_callback(fence, &cb->base, + intel_user_framebuffer_fence_wake); + if (ret) { + intel_user_framebuffer_fence_wake(fence, &cb->base); + if (ret == -ENOENT) + ret = 0; + } + + return ret; + +flush: + i915_gem_object_flush_if_display(obj); + intel_frontbuffer_flush(front, ORIGIN_DIRTYFB); + return ret; } static const struct drm_framebuffer_funcs intel_fb_funcs = { diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c index fffd568070d4..7b42aef37d2f 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.c +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c @@ -35,7 +35,8 @@ intel_pin_fb_obj_dpt(struct drm_framebuffer *fb, * We are not syncing against the binding (and potential migrations) * below, so this vm must never be async. */ - GEM_WARN_ON(vm->bind_async_flags); + if (drm_WARN_ON(&dev_priv->drm, vm->bind_async_flags)) + return ERR_PTR(-EINVAL); if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) return ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 25382022cd27..4820d21cc942 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -50,6 +50,7 @@ #include "i915_vma.h" #include "intel_cdclk.h" #include "intel_de.h" +#include "intel_display_device.h" #include "intel_display_trace.h" #include "intel_display_types.h" #include "intel_fbc.h" @@ -332,12 +333,14 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc) { struct drm_i915_private *i915 = fbc->i915; - GEM_BUG_ON(range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), - i915_gem_stolen_node_offset(&fbc->compressed_fb), - U32_MAX)); - GEM_BUG_ON(range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), - i915_gem_stolen_node_offset(&fbc->compressed_llb), - U32_MAX)); + drm_WARN_ON(&i915->drm, + range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), + i915_gem_stolen_node_offset(&fbc->compressed_fb), + U32_MAX)); + drm_WARN_ON(&i915->drm, + range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), + i915_gem_stolen_node_offset(&fbc->compressed_llb), + U32_MAX)); intel_de_write(i915, FBC_CFB_BASE, i915_gem_stolen_node_address(i915, &fbc->compressed_fb)); intel_de_write(i915, FBC_LL_BASE, @@ -590,6 +593,9 @@ static u32 ivb_dpfc_ctl(struct intel_fbc *fbc) if (IS_IVYBRIDGE(i915)) dpfc_ctl |= DPFC_CTL_PLANE_IVB(fbc_state->plane->i9xx_plane); + if (DISPLAY_VER(i915) >= 20) + dpfc_ctl |= DPFC_CTL_PLANE_BINDING(fbc_state->plane->id); + if (fbc_state->fence_id >= 0) dpfc_ctl |= DPFC_CTL_FENCE_EN_IVB; @@ -847,39 +853,64 @@ void intel_fbc_cleanup(struct drm_i915_private *i915) } } -static bool stride_is_valid(const struct intel_plane_state *plane_state) +static bool i8xx_fbc_stride_is_valid(const struct intel_plane_state *plane_state) { - struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; unsigned int stride = intel_fbc_plane_stride(plane_state) * fb->format->cpp[0]; - /* This should have been caught earlier. */ - if (drm_WARN_ON_ONCE(&i915->drm, (stride & (64 - 1)) != 0)) - return false; + return stride == 4096 || stride == 8192; +} - /* Below are the additional FBC restrictions. */ - if (stride < 512) - return false; +static bool i965_fbc_stride_is_valid(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int stride = intel_fbc_plane_stride(plane_state) * + fb->format->cpp[0]; - if (DISPLAY_VER(i915) == 2 || DISPLAY_VER(i915) == 3) - return stride == 4096 || stride == 8192; + return stride >= 2048 && stride <= 16384; +} - if (DISPLAY_VER(i915) == 4 && !IS_G4X(i915) && stride < 2048) - return false; +static bool g4x_fbc_stride_is_valid(const struct intel_plane_state *plane_state) +{ + return true; +} + +static bool skl_fbc_stride_is_valid(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int stride = intel_fbc_plane_stride(plane_state) * + fb->format->cpp[0]; /* Display WA #1105: skl,bxt,kbl,cfl,glk */ - if ((DISPLAY_VER(i915) == 9 || IS_GEMINILAKE(i915)) && - fb->modifier == DRM_FORMAT_MOD_LINEAR && stride & 511) + if (fb->modifier == DRM_FORMAT_MOD_LINEAR && stride & 511) return false; - if (stride > 16384) - return false; + return true; +} +static bool icl_fbc_stride_is_valid(const struct intel_plane_state *plane_state) +{ return true; } -static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) +static bool stride_is_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + + if (DISPLAY_VER(i915) >= 11) + return icl_fbc_stride_is_valid(plane_state); + else if (DISPLAY_VER(i915) >= 9) + return skl_fbc_stride_is_valid(plane_state); + else if (DISPLAY_VER(i915) >= 5 || IS_G4X(i915)) + return g4x_fbc_stride_is_valid(plane_state); + else if (DISPLAY_VER(i915) == 4) + return i965_fbc_stride_is_valid(plane_state); + else + return i8xx_fbc_stride_is_valid(plane_state); +} + +static bool i8xx_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state) { struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -893,6 +924,22 @@ static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) /* 16bpp not supported on gen2 */ if (DISPLAY_VER(i915) == 2) return false; + return true; + default: + return false; + } +} + +static bool g4x_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + + switch (fb->format->format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + return true; + case DRM_FORMAT_RGB565: /* WaFbcOnly1to1Ratio:ctg */ if (IS_G4X(i915)) return false; @@ -902,22 +949,68 @@ static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) } } -static bool rotation_is_valid(const struct intel_plane_state *plane_state) +static bool lnl_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + + switch (fb->format->format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGB565: + return true; + default: + return false; + } +} + +static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) { struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + + if (DISPLAY_VER(i915) >= 20) + return lnl_fbc_pixel_format_is_valid(plane_state); + else if (DISPLAY_VER(i915) >= 5 || IS_G4X(i915)) + return g4x_fbc_pixel_format_is_valid(plane_state); + else + return i8xx_fbc_pixel_format_is_valid(plane_state); +} + +static bool i8xx_fbc_rotation_is_valid(const struct intel_plane_state *plane_state) +{ + return plane_state->hw.rotation == DRM_MODE_ROTATE_0; +} + +static bool g4x_fbc_rotation_is_valid(const struct intel_plane_state *plane_state) +{ + return true; +} + +static bool skl_fbc_rotation_is_valid(const struct intel_plane_state *plane_state) +{ const struct drm_framebuffer *fb = plane_state->hw.fb; unsigned int rotation = plane_state->hw.rotation; - if (DISPLAY_VER(i915) >= 9 && fb->format->format == DRM_FORMAT_RGB565 && + if (fb->format->format == DRM_FORMAT_RGB565 && drm_rotation_90_or_270(rotation)) return false; - else if (DISPLAY_VER(i915) <= 4 && !IS_G4X(i915) && - rotation != DRM_MODE_ROTATE_0) - return false; return true; } +static bool rotation_is_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + + if (DISPLAY_VER(i915) >= 9) + return skl_fbc_rotation_is_valid(plane_state); + else if (DISPLAY_VER(i915) >= 5 || IS_G4X(i915)) + return g4x_fbc_rotation_is_valid(plane_state); + else + return i8xx_fbc_rotation_is_valid(plane_state); +} + /* * For some reason, the hardware tracking starts looking at whatever we * programmed as the display plane base address register. It does not look at @@ -951,16 +1044,21 @@ static bool intel_fbc_hw_tracking_covers_screen(const struct intel_plane_state * return effective_w <= max_w && effective_h <= max_h; } -static bool tiling_is_valid(const struct intel_plane_state *plane_state) +static bool i8xx_fbc_tiling_valid(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + + return fb->modifier == I915_FORMAT_MOD_X_TILED; +} + +static bool skl_fbc_tiling_valid(const struct intel_plane_state *plane_state) { - struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; switch (fb->modifier) { case DRM_FORMAT_MOD_LINEAR: case I915_FORMAT_MOD_Y_TILED: case I915_FORMAT_MOD_Yf_TILED: - return DISPLAY_VER(i915) >= 9; case I915_FORMAT_MOD_4_TILED: case I915_FORMAT_MOD_X_TILED: return true; @@ -969,6 +1067,16 @@ static bool tiling_is_valid(const struct intel_plane_state *plane_state) } } +static bool tiling_is_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + + if (DISPLAY_VER(i915) >= 9) + return skl_fbc_tiling_valid(plane_state); + else + return i8xx_fbc_tiling_valid(plane_state); +} + static void intel_fbc_update_state(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_plane *plane) @@ -1100,7 +1208,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, /* Wa_14016291713 */ if ((IS_DISPLAY_VER(i915, 12, 13) || - IS_MTL_DISPLAY_STEP(i915, STEP_A0, STEP_C0)) && + IS_DISPLAY_IP_STEP(i915, IP_VER(14, 0), STEP_A0, STEP_C0)) && crtc_state->has_psr) { plane_state->no_fbc_reason = "PSR1 enabled (Wa_14016291713)"; return 0; @@ -1126,7 +1234,8 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, return 0; } - if (plane_state->hw.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE && + if (DISPLAY_VER(i915) < 20 && + plane_state->hw.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE && fb->format->has_alpha) { plane_state->no_fbc_reason = "per-pixel alpha not supported"; return 0; @@ -1306,11 +1415,9 @@ static void __intel_fbc_post_update(struct intel_fbc *fbc) lockdep_assert_held(&fbc->lock); fbc->flip_pending = false; + fbc->busy_bits = 0; - if (!fbc->busy_bits) - intel_fbc_activate(fbc); - else - intel_fbc_deactivate(fbc, "frontbuffer write"); + intel_fbc_activate(fbc); } void intel_fbc_post_update(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_fbc.h b/drivers/gpu/drm/i915/display/intel_fbc.h index 4adb98afe6ff..6720ec8ee8a2 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.h +++ b/drivers/gpu/drm/i915/display/intel_fbc.h @@ -20,6 +20,8 @@ struct intel_plane_state; enum intel_fbc_id { INTEL_FBC_A, INTEL_FBC_B, + INTEL_FBC_C, + INTEL_FBC_D, I915_MAX_FBCS, }; diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index e12b46a84fa1..e6429dfebe15 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -13,6 +13,7 @@ #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" +#include "intel_link_bw.h" struct intel_fdi_funcs { void (*fdi_link_train)(struct intel_crtc *crtc, @@ -119,6 +120,53 @@ void intel_fdi_link_train(struct intel_crtc *crtc, dev_priv->display.funcs.fdi->fdi_link_train(crtc, crtc_state); } +/** + * intel_fdi_add_affected_crtcs - add CRTCs on FDI affected by other modeset CRTCs + * @state: intel atomic state + * + * Add a CRTC using FDI to @state if changing another CRTC's FDI BW usage is + * known to affect the available FDI BW for the former CRTC. In practice this + * means adding CRTC B on IVYBRIDGE if its use of FDI lanes is limited (by + * CRTC C) and CRTC C is getting disabled. + * + * Returns 0 in case of success, or a negative error code otherwise. + */ +int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *old_crtc_state; + const struct intel_crtc_state *new_crtc_state; + struct intel_crtc *crtc; + + if (!IS_IVYBRIDGE(i915) || INTEL_NUM_PIPES(i915) != 3) + return 0; + + crtc = intel_crtc_for_pipe(i915, PIPE_C); + new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); + if (!new_crtc_state) + return 0; + + if (!intel_crtc_needs_modeset(new_crtc_state)) + return 0; + + old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); + if (!old_crtc_state->fdi_lanes) + return 0; + + crtc = intel_crtc_for_pipe(i915, PIPE_B); + new_crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); + if (IS_ERR(new_crtc_state)) + return PTR_ERR(new_crtc_state); + + old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); + if (!old_crtc_state->fdi_lanes) + return 0; + + return intel_modeset_pipes_in_mask_early(state, + "FDI link BW decrease on pipe C", + BIT(PIPE_B)); +} + /* units of 100MHz */ static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state) { @@ -129,13 +177,16 @@ static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state) } static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, - struct intel_crtc_state *pipe_config) + struct intel_crtc_state *pipe_config, + enum pipe *pipe_to_reduce) { struct drm_i915_private *dev_priv = to_i915(dev); struct drm_atomic_state *state = pipe_config->uapi.state; struct intel_crtc *other_crtc; struct intel_crtc_state *other_crtc_state; + *pipe_to_reduce = pipe; + drm_dbg_kms(&dev_priv->drm, "checking fdi config on pipe %c, lanes %i\n", pipe_name(pipe), pipe_config->fdi_lanes); @@ -198,6 +249,9 @@ static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, if (pipe_required_fdi_lanes(other_crtc_state) > 2) { drm_dbg_kms(&dev_priv->drm, "fdi link B uses too many lanes to enable link C\n"); + + *pipe_to_reduce = PIPE_B; + return -EINVAL; } return 0; @@ -232,16 +286,42 @@ int intel_fdi_link_freq(struct drm_i915_private *i915, return i915->display.fdi.pll_freq; } +/** + * intel_fdi_compute_pipe_bpp - compute pipe bpp limited by max link bpp + * @crtc_state: the crtc state + * + * Compute the pipe bpp limited by the CRTC's maximum link bpp. Encoders can + * call this function during state computation in the simple case where the + * link bpp will always match the pipe bpp. This is the case for all non-DP + * encoders, while DP encoders will use a link bpp lower than pipe bpp in case + * of DSC compression. + * + * Returns %true in case of success, %false if pipe bpp would need to be + * reduced below its valid range. + */ +bool intel_fdi_compute_pipe_bpp(struct intel_crtc_state *crtc_state) +{ + int pipe_bpp = min(crtc_state->pipe_bpp, + to_bpp_int(crtc_state->max_link_bpp_x16)); + + pipe_bpp = rounddown(pipe_bpp, 2 * 3); + + if (pipe_bpp < 6 * 3) + return false; + + crtc_state->pipe_bpp = pipe_bpp; + + return true; +} + int ilk_fdi_compute_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *i915 = to_i915(dev); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - int lane, link_bw, fdi_dotclock, ret; - bool needs_recompute = false; + int lane, link_bw, fdi_dotclock; -retry: /* FDI is a binary signal running at ~2.7GHz, encoding * each output octet as 10 bits. The actual frequency * is stored as a divider into a 100MHz clock, and the @@ -261,25 +341,69 @@ retry: intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, link_bw, &pipe_config->fdi_m_n, false); - ret = ilk_check_fdi_lanes(dev, crtc->pipe, pipe_config); - if (ret == -EDEADLK) + return 0; +} + +static int intel_fdi_atomic_check_bw(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config, + struct intel_link_bw_limits *limits) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + enum pipe pipe_to_reduce; + int ret; + + ret = ilk_check_fdi_lanes(&i915->drm, crtc->pipe, pipe_config, + &pipe_to_reduce); + if (ret != -EINVAL) return ret; - if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) { - pipe_config->pipe_bpp -= 2*3; - drm_dbg_kms(&i915->drm, - "fdi link bw constraint, reducing pipe bpp to %i\n", - pipe_config->pipe_bpp); - needs_recompute = true; - pipe_config->bw_constrained = true; + ret = intel_link_bw_reduce_bpp(state, limits, + BIT(pipe_to_reduce), + "FDI link BW"); - goto retry; - } + return ret ? : -EAGAIN; +} + +/** + * intel_fdi_atomic_check_link - check all modeset FDI link configuration + * @state: intel atomic state + * @limits: link BW limits + * + * Check the link configuration for all modeset FDI outputs. If the + * configuration is invalid @limits will be updated if possible to + * reduce the total BW, after which the configuration for all CRTCs in + * @state must be recomputed with the updated @limits. + * + * Returns: + * - 0 if the confugration is valid + * - %-EAGAIN, if the configuration is invalid and @limits got updated + * with fallback values with which the configuration of all CRTCs + * in @state must be recomputed + * - Other negative error, if the configuration is invalid without a + * fallback possibility, or the check failed for another reason + */ +int intel_fdi_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits) +{ + struct intel_crtc *crtc; + struct intel_crtc_state *crtc_state; + int i; + + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { + int ret; + + if (!crtc_state->has_pch_encoder || + !intel_crtc_needs_modeset(crtc_state) || + !crtc_state->hw.enable) + continue; - if (needs_recompute) - return -EAGAIN; + ret = intel_fdi_atomic_check_bw(state, crtc, crtc_state, limits); + if (ret) + return ret; + } - return ret; + return 0; } static void cpt_set_fdi_bc_bifurcation(struct drm_i915_private *dev_priv, bool enable) @@ -766,7 +890,10 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, * WaFDIAutoLinkSetTimingOverrride:hsw */ intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), - FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + FDI_RX_PWRDN_LANE1_VAL(2) | + FDI_RX_PWRDN_LANE0_VAL(2) | + FDI_RX_TP1_TO_TP2_48 | + FDI_RX_FDI_DELAY_90); /* Enable the PCH Receiver FDI PLL */ rx_ctl_val = dev_priv->display.fdi.rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | @@ -799,7 +926,9 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, * achieved on the PCH side in FDI_RX_CTL, so no need to set the * port reversal bit */ intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), - DDI_BUF_CTL_ENABLE | ((crtc_state->fdi_lanes - 1) << 1) | DDI_BUF_TRANS_SELECT(i / 2)); + DDI_BUF_CTL_ENABLE | + ((crtc_state->fdi_lanes - 1) << 1) | + DDI_BUF_TRANS_SELECT(i / 2)); intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); udelay(600); diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h index 1cdb86172702..477ff0136934 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.h +++ b/drivers/gpu/drm/i915/display/intel_fdi.h @@ -6,16 +6,24 @@ #ifndef _INTEL_FDI_H_ #define _INTEL_FDI_H_ +#include <linux/types.h> + enum pipe; struct drm_i915_private; +struct intel_atomic_state; struct intel_crtc; struct intel_crtc_state; struct intel_encoder; +struct intel_link_bw_limits; +int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state); int intel_fdi_link_freq(struct drm_i915_private *i915, const struct intel_crtc_state *pipe_config); +bool intel_fdi_compute_pipe_bpp(struct intel_crtc_state *crtc_state); int ilk_fdi_compute_config(struct intel_crtc *intel_crtc, struct intel_crtc_state *pipe_config); +int intel_fdi_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits); void intel_fdi_normal_train(struct intel_crtc *crtc); void ilk_fdi_disable(struct intel_crtc *crtc); void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc); diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index 22392f94b626..ec46716b2f49 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -55,6 +55,8 @@ * cancelled as soon as busyness is detected. */ +#include "gem/i915_gem_object_frontbuffer.h" +#include "i915_active.h" #include "i915_drv.h" #include "intel_display_trace.h" #include "intel_display_types.h" @@ -202,6 +204,33 @@ void __intel_fb_flush(struct intel_frontbuffer *front, frontbuffer_flush(i915, frontbuffer_bits, origin); } +static void intel_frontbuffer_flush_work(struct work_struct *work) +{ + struct intel_frontbuffer *front = + container_of(work, struct intel_frontbuffer, flush_work); + + i915_gem_object_flush_if_display(front->obj); + intel_frontbuffer_flush(front, ORIGIN_DIRTYFB); + intel_frontbuffer_put(front); +} + +/** + * intel_frontbuffer_queue_flush - queue flushing frontbuffer object + * @front: GEM object to flush + * + * This function is targeted for our dirty callback for queueing flush when + * dma fence is signales + */ +void intel_frontbuffer_queue_flush(struct intel_frontbuffer *front) +{ + if (!front) + return; + + kref_get(&front->ref); + if (!schedule_work(&front->flush_work)) + intel_frontbuffer_put(front); +} + static int frontbuffer_active(struct i915_active *ref) { struct intel_frontbuffer *front = @@ -223,7 +252,7 @@ static void frontbuffer_retire(struct i915_active *ref) static void frontbuffer_release(struct kref *ref) __releases(&intel_bo_to_i915(front->obj)->display.fb_tracking.lock) { - struct intel_frontbuffer *front = + struct intel_frontbuffer *ret, *front = container_of(ref, typeof(*front), ref); struct drm_i915_gem_object *obj = front->obj; @@ -231,7 +260,8 @@ static void frontbuffer_release(struct kref *ref) i915_ggtt_clear_scanout(obj); - i915_gem_object_set_frontbuffer(obj, NULL); + ret = i915_gem_object_set_frontbuffer(obj, NULL); + drm_WARN_ON(&intel_bo_to_i915(obj)->drm, ret); spin_unlock(&intel_bo_to_i915(obj)->display.fb_tracking.lock); i915_active_fini(&front->write); @@ -261,6 +291,7 @@ intel_frontbuffer_get(struct drm_i915_gem_object *obj) frontbuffer_active, frontbuffer_retire, I915_ACTIVE_RETIRE_SLEEPS); + INIT_WORK(&front->flush_work, intel_frontbuffer_flush_work); spin_lock(&i915->display.fb_tracking.lock); cur = i915_gem_object_set_frontbuffer(obj, front); diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.h b/drivers/gpu/drm/i915/display/intel_frontbuffer.h index 72d89be3284b..abb51e8bb920 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.h +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.h @@ -46,6 +46,8 @@ struct intel_frontbuffer { struct i915_active write; struct drm_i915_gem_object *obj; struct rcu_head rcu; + + struct work_struct flush_work; }; /* @@ -135,6 +137,8 @@ static inline void intel_frontbuffer_flush(struct intel_frontbuffer *front, __intel_fb_flush(front, origin, frontbuffer_bits); } +void intel_frontbuffer_queue_flush(struct intel_frontbuffer *front); + void intel_frontbuffer_track(struct intel_frontbuffer *old, struct intel_frontbuffer *new, unsigned int frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index e95ddb580ef6..801fabbccf7e 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -155,7 +155,10 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915, const struct gmbus_pin *pins; size_t size; - if (INTEL_PCH_TYPE(i915) >= PCH_DG2) { + if (INTEL_PCH_TYPE(i915) >= PCH_LNL) { + pins = gmbus_pins_mtp; + size = ARRAY_SIZE(gmbus_pins_mtp); + } else if (INTEL_PCH_TYPE(i915) >= PCH_DG2) { pins = gmbus_pins_dg2; size = ARRAY_SIZE(gmbus_pins_dg2); } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) { diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index a42549fa9691..c89da3568ebd 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -163,7 +163,6 @@ bool intel_hdcp_capable(struct intel_connector *connector) /* Is HDCP2.2 capable on Platform and Sink */ bool intel_hdcp2_capable(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; bool capable = false; @@ -174,14 +173,8 @@ bool intel_hdcp2_capable(struct intel_connector *connector) /* If MTL+ make sure gsc is loaded and proxy is setup */ if (intel_hdcp_gsc_cs_required(i915)) { - struct intel_gt *gt = i915->media_gt; - struct intel_gsc_uc *gsc = gt ? >->uc.gsc : NULL; - - if (!gsc || !intel_uc_fw_is_running(&gsc->fw)) { - drm_dbg_kms(&i915->drm, - "GSC components required for HDCP2.2 are not ready\n"); + if (!intel_hdcp_gsc_check_status(i915)) return false; - } } /* MEI/GSC interface is solid depending on which is used */ @@ -193,7 +186,7 @@ bool intel_hdcp2_capable(struct intel_connector *connector) mutex_unlock(&i915->display.hdcp.hdcp_mutex); /* Sink's capability for HDCP2.2 */ - hdcp->shim->hdcp_2_2_capable(dig_port, &capable); + hdcp->shim->hdcp_2_2_capable(connector, &capable); return capable; } @@ -1415,7 +1408,6 @@ static int hdcp2_deauthenticate_port(struct intel_connector *connector) /* Authentication flow starts from here */ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; union { @@ -1437,12 +1429,12 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) if (ret < 0) return ret; - ret = shim->write_2_2_msg(dig_port, &msgs.ake_init, + ret = shim->write_2_2_msg(connector, &msgs.ake_init, sizeof(msgs.ake_init)); if (ret < 0) return ret; - ret = shim->read_2_2_msg(dig_port, HDCP_2_2_AKE_SEND_CERT, + ret = shim->read_2_2_msg(connector, HDCP_2_2_AKE_SEND_CERT, &msgs.send_cert, sizeof(msgs.send_cert)); if (ret < 0) return ret; @@ -1471,11 +1463,11 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) if (ret < 0) return ret; - ret = shim->write_2_2_msg(dig_port, &msgs.no_stored_km, size); + ret = shim->write_2_2_msg(connector, &msgs.no_stored_km, size); if (ret < 0) return ret; - ret = shim->read_2_2_msg(dig_port, HDCP_2_2_AKE_SEND_HPRIME, + ret = shim->read_2_2_msg(connector, HDCP_2_2_AKE_SEND_HPRIME, &msgs.send_hprime, sizeof(msgs.send_hprime)); if (ret < 0) return ret; @@ -1486,7 +1478,7 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) if (!hdcp->is_paired) { /* Pairing is required */ - ret = shim->read_2_2_msg(dig_port, + ret = shim->read_2_2_msg(connector, HDCP_2_2_AKE_SEND_PAIRING_INFO, &msgs.pairing_info, sizeof(msgs.pairing_info)); @@ -1504,7 +1496,6 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) static int hdcp2_locality_check(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct intel_hdcp *hdcp = &connector->hdcp; union { struct hdcp2_lc_init lc_init; @@ -1518,12 +1509,12 @@ static int hdcp2_locality_check(struct intel_connector *connector) if (ret < 0) continue; - ret = shim->write_2_2_msg(dig_port, &msgs.lc_init, + ret = shim->write_2_2_msg(connector, &msgs.lc_init, sizeof(msgs.lc_init)); if (ret < 0) continue; - ret = shim->read_2_2_msg(dig_port, + ret = shim->read_2_2_msg(connector, HDCP_2_2_LC_SEND_LPRIME, &msgs.send_lprime, sizeof(msgs.send_lprime)); @@ -1540,7 +1531,6 @@ static int hdcp2_locality_check(struct intel_connector *connector) static int hdcp2_session_key_exchange(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct intel_hdcp *hdcp = &connector->hdcp; struct hdcp2_ske_send_eks send_eks; int ret; @@ -1549,7 +1539,7 @@ static int hdcp2_session_key_exchange(struct intel_connector *connector) if (ret < 0) return ret; - ret = hdcp->shim->write_2_2_msg(dig_port, &send_eks, + ret = hdcp->shim->write_2_2_msg(connector, &send_eks, sizeof(send_eks)); if (ret < 0) return ret; @@ -1587,12 +1577,12 @@ int _hdcp2_propagate_stream_management_info(struct intel_connector *connector) streams_size_delta = (HDCP_2_2_MAX_CONTENT_STREAMS_CNT - data->k) * sizeof(struct hdcp2_streamid_type); /* Send it to Repeater */ - ret = shim->write_2_2_msg(dig_port, &msgs.stream_manage, + ret = shim->write_2_2_msg(connector, &msgs.stream_manage, sizeof(msgs.stream_manage) - streams_size_delta); if (ret < 0) goto out; - ret = shim->read_2_2_msg(dig_port, HDCP_2_2_REP_STREAM_READY, + ret = shim->read_2_2_msg(connector, HDCP_2_2_REP_STREAM_READY, &msgs.stream_ready, sizeof(msgs.stream_ready)); if (ret < 0) goto out; @@ -1622,7 +1612,7 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) u8 *rx_info; int ret; - ret = shim->read_2_2_msg(dig_port, HDCP_2_2_REP_SEND_RECVID_LIST, + ret = shim->read_2_2_msg(connector, HDCP_2_2_REP_SEND_RECVID_LIST, &msgs.recvid_list, sizeof(msgs.recvid_list)); if (ret < 0) return ret; @@ -1675,7 +1665,7 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) return ret; hdcp->seq_num_v = seq_num_v; - ret = shim->write_2_2_msg(dig_port, &msgs.rep_ack, + ret = shim->write_2_2_msg(connector, &msgs.rep_ack, sizeof(msgs.rep_ack)); if (ret < 0) return ret; @@ -1685,7 +1675,6 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) static int hdcp2_authenticate_sink(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; const struct intel_hdcp_shim *shim = hdcp->shim; @@ -1711,7 +1700,7 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector) } if (shim->config_stream_type) { - ret = shim->config_stream_type(dig_port, + ret = shim->config_stream_type(connector, hdcp->is_repeater, hdcp->content_type); if (ret < 0) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c index d753db3eef15..18117b789b16 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c @@ -11,610 +11,27 @@ #include "i915_drv.h" #include "i915_utils.h" #include "intel_hdcp_gsc.h" +#include "intel_hdcp_gsc_message.h" bool intel_hdcp_gsc_cs_required(struct drm_i915_private *i915) { return DISPLAY_VER(i915) >= 14; } -static int -gsc_hdcp_initiate_session(struct device *dev, struct hdcp_port_data *data, - struct hdcp2_ake_init *ake_data) +bool intel_hdcp_gsc_check_status(struct drm_i915_private *i915) { - struct wired_cmd_initiate_hdcp2_session_in session_init_in = { { 0 } }; - struct wired_cmd_initiate_hdcp2_session_out - session_init_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !ake_data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - session_init_in.header.api_version = HDCP_API_VERSION; - session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION; - session_init_in.header.status = FW_HDCP_STATUS_SUCCESS; - session_init_in.header.buffer_len = - WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN; - - session_init_in.port.integrated_port_type = data->port_type; - session_init_in.port.physical_port = (u8)data->hdcp_ddi; - session_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - session_init_in.protocol = data->protocol; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_init_in, - sizeof(session_init_in), - (u8 *)&session_init_out, - sizeof(session_init_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (session_init_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", - WIRED_INITIATE_HDCP2_SESSION, - session_init_out.header.status); - return -EIO; - } - - ake_data->msg_id = HDCP_2_2_AKE_INIT; - ake_data->tx_caps = session_init_out.tx_caps; - memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN); - - return 0; -} - -static int -gsc_hdcp_verify_receiver_cert_prepare_km(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_ake_send_cert *rx_cert, - bool *km_stored, - struct hdcp2_ake_no_stored_km - *ek_pub_km, - size_t *msg_sz) -{ - struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = { { 0 } }; - struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - verify_rxcert_in.header.api_version = HDCP_API_VERSION; - verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT; - verify_rxcert_in.header.status = FW_HDCP_STATUS_SUCCESS; - verify_rxcert_in.header.buffer_len = - WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN; - - verify_rxcert_in.port.integrated_port_type = data->port_type; - verify_rxcert_in.port.physical_port = (u8)data->hdcp_ddi; - verify_rxcert_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - verify_rxcert_in.cert_rx = rx_cert->cert_rx; - memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN); - memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_rxcert_in, - sizeof(verify_rxcert_in), - (u8 *)&verify_rxcert_out, - sizeof(verify_rxcert_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed: %zd\n", byte); - return byte; - } - - if (verify_rxcert_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", - WIRED_VERIFY_RECEIVER_CERT, - verify_rxcert_out.header.status); - return -EIO; - } - - *km_stored = !!verify_rxcert_out.km_stored; - if (verify_rxcert_out.km_stored) { - ek_pub_km->msg_id = HDCP_2_2_AKE_STORED_KM; - *msg_sz = sizeof(struct hdcp2_ake_stored_km); - } else { - ek_pub_km->msg_id = HDCP_2_2_AKE_NO_STORED_KM; - *msg_sz = sizeof(struct hdcp2_ake_no_stored_km); - } - - memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff, - sizeof(verify_rxcert_out.ekm_buff)); - - return 0; -} - -static int -gsc_hdcp_verify_hprime(struct device *dev, struct hdcp_port_data *data, - struct hdcp2_ake_send_hprime *rx_hprime) -{ - struct wired_cmd_ake_send_hprime_in send_hprime_in = { { 0 } }; - struct wired_cmd_ake_send_hprime_out send_hprime_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !rx_hprime) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - send_hprime_in.header.api_version = HDCP_API_VERSION; - send_hprime_in.header.command_id = WIRED_AKE_SEND_HPRIME; - send_hprime_in.header.status = FW_HDCP_STATUS_SUCCESS; - send_hprime_in.header.buffer_len = WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN; - - send_hprime_in.port.integrated_port_type = data->port_type; - send_hprime_in.port.physical_port = (u8)data->hdcp_ddi; - send_hprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(send_hprime_in.h_prime, rx_hprime->h_prime, - HDCP_2_2_H_PRIME_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&send_hprime_in, - sizeof(send_hprime_in), - (u8 *)&send_hprime_out, - sizeof(send_hprime_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (send_hprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", - WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status); - return -EIO; - } - - return 0; -} - -static int -gsc_hdcp_store_pairing_info(struct device *dev, struct hdcp_port_data *data, - struct hdcp2_ake_send_pairing_info *pairing_info) -{ - struct wired_cmd_ake_send_pairing_info_in pairing_info_in = { { 0 } }; - struct wired_cmd_ake_send_pairing_info_out pairing_info_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !pairing_info) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - pairing_info_in.header.api_version = HDCP_API_VERSION; - pairing_info_in.header.command_id = WIRED_AKE_SEND_PAIRING_INFO; - pairing_info_in.header.status = FW_HDCP_STATUS_SUCCESS; - pairing_info_in.header.buffer_len = - WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN; - - pairing_info_in.port.integrated_port_type = data->port_type; - pairing_info_in.port.physical_port = (u8)data->hdcp_ddi; - pairing_info_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km, - HDCP_2_2_E_KH_KM_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&pairing_info_in, - sizeof(pairing_info_in), - (u8 *)&pairing_info_out, - sizeof(pairing_info_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (pairing_info_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. Status: 0x%X\n", - WIRED_AKE_SEND_PAIRING_INFO, - pairing_info_out.header.status); - return -EIO; - } - - return 0; -} - -static int -gsc_hdcp_initiate_locality_check(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_lc_init *lc_init_data) -{ - struct wired_cmd_init_locality_check_in lc_init_in = { { 0 } }; - struct wired_cmd_init_locality_check_out lc_init_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !lc_init_data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - lc_init_in.header.api_version = HDCP_API_VERSION; - lc_init_in.header.command_id = WIRED_INIT_LOCALITY_CHECK; - lc_init_in.header.status = FW_HDCP_STATUS_SUCCESS; - lc_init_in.header.buffer_len = WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN; - - lc_init_in.port.integrated_port_type = data->port_type; - lc_init_in.port.physical_port = (u8)data->hdcp_ddi; - lc_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&lc_init_in, sizeof(lc_init_in), - (u8 *)&lc_init_out, sizeof(lc_init_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (lc_init_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. status: 0x%X\n", - WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status); - return -EIO; - } - - lc_init_data->msg_id = HDCP_2_2_LC_INIT; - memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN); - - return 0; -} - -static int -gsc_hdcp_verify_lprime(struct device *dev, struct hdcp_port_data *data, - struct hdcp2_lc_send_lprime *rx_lprime) -{ - struct wired_cmd_validate_locality_in verify_lprime_in = { { 0 } }; - struct wired_cmd_validate_locality_out verify_lprime_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !rx_lprime) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - verify_lprime_in.header.api_version = HDCP_API_VERSION; - verify_lprime_in.header.command_id = WIRED_VALIDATE_LOCALITY; - verify_lprime_in.header.status = FW_HDCP_STATUS_SUCCESS; - verify_lprime_in.header.buffer_len = - WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN; - - verify_lprime_in.port.integrated_port_type = data->port_type; - verify_lprime_in.port.physical_port = (u8)data->hdcp_ddi; - verify_lprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime, - HDCP_2_2_L_PRIME_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_lprime_in, - sizeof(verify_lprime_in), - (u8 *)&verify_lprime_out, - sizeof(verify_lprime_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (verify_lprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_VALIDATE_LOCALITY, - verify_lprime_out.header.status); - return -EIO; - } - - return 0; -} - -static int gsc_hdcp_get_session_key(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_ske_send_eks *ske_data) -{ - struct wired_cmd_get_session_key_in get_skey_in = { { 0 } }; - struct wired_cmd_get_session_key_out get_skey_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !ske_data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - get_skey_in.header.api_version = HDCP_API_VERSION; - get_skey_in.header.command_id = WIRED_GET_SESSION_KEY; - get_skey_in.header.status = FW_HDCP_STATUS_SUCCESS; - get_skey_in.header.buffer_len = WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN; - - get_skey_in.port.integrated_port_type = data->port_type; - get_skey_in.port.physical_port = (u8)data->hdcp_ddi; - get_skey_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&get_skey_in, sizeof(get_skey_in), - (u8 *)&get_skey_out, sizeof(get_skey_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (get_skey_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_GET_SESSION_KEY, get_skey_out.header.status); - return -EIO; - } - - ske_data->msg_id = HDCP_2_2_SKE_SEND_EKS; - memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks, - HDCP_2_2_E_DKEY_KS_LEN); - memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN); - - return 0; -} - -static int -gsc_hdcp_repeater_check_flow_prepare_ack(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_rep_send_receiverid_list - *rep_topology, - struct hdcp2_rep_send_ack - *rep_send_ack) -{ - struct wired_cmd_verify_repeater_in verify_repeater_in = { { 0 } }; - struct wired_cmd_verify_repeater_out verify_repeater_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !rep_topology || !rep_send_ack || !data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - verify_repeater_in.header.api_version = HDCP_API_VERSION; - verify_repeater_in.header.command_id = WIRED_VERIFY_REPEATER; - verify_repeater_in.header.status = FW_HDCP_STATUS_SUCCESS; - verify_repeater_in.header.buffer_len = - WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN; - - verify_repeater_in.port.integrated_port_type = data->port_type; - verify_repeater_in.port.physical_port = (u8)data->hdcp_ddi; - verify_repeater_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(verify_repeater_in.rx_info, rep_topology->rx_info, - HDCP_2_2_RXINFO_LEN); - memcpy(verify_repeater_in.seq_num_v, rep_topology->seq_num_v, - HDCP_2_2_SEQ_NUM_LEN); - memcpy(verify_repeater_in.v_prime, rep_topology->v_prime, - HDCP_2_2_V_PRIME_HALF_LEN); - memcpy(verify_repeater_in.receiver_ids, rep_topology->receiver_ids, - HDCP_2_2_RECEIVER_IDS_MAX_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_repeater_in, - sizeof(verify_repeater_in), - (u8 *)&verify_repeater_out, - sizeof(verify_repeater_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (verify_repeater_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_VERIFY_REPEATER, - verify_repeater_out.header.status); - return -EIO; - } - - memcpy(rep_send_ack->v, verify_repeater_out.v, - HDCP_2_2_V_PRIME_HALF_LEN); - rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK; - - return 0; -} - -static int gsc_hdcp_verify_mprime(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_rep_stream_ready *stream_ready) -{ - struct wired_cmd_repeater_auth_stream_req_in *verify_mprime_in; - struct wired_cmd_repeater_auth_stream_req_out - verify_mprime_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - size_t cmd_size; - - if (!dev || !stream_ready || !data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - cmd_size = struct_size(verify_mprime_in, streams, data->k); - if (cmd_size == SIZE_MAX) - return -EINVAL; - - verify_mprime_in = kzalloc(cmd_size, GFP_KERNEL); - if (!verify_mprime_in) - return -ENOMEM; - - verify_mprime_in->header.api_version = HDCP_API_VERSION; - verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ; - verify_mprime_in->header.status = FW_HDCP_STATUS_SUCCESS; - verify_mprime_in->header.buffer_len = cmd_size - sizeof(verify_mprime_in->header); - - verify_mprime_in->port.integrated_port_type = data->port_type; - verify_mprime_in->port.physical_port = (u8)data->hdcp_ddi; - verify_mprime_in->port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(verify_mprime_in->m_prime, stream_ready->m_prime, HDCP_2_2_MPRIME_LEN); - drm_hdcp_cpu_to_be24(verify_mprime_in->seq_num_m, data->seq_num_m); - - memcpy(verify_mprime_in->streams, data->streams, - array_size(data->k, sizeof(*data->streams))); - - verify_mprime_in->k = cpu_to_be16(data->k); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)verify_mprime_in, cmd_size, - (u8 *)&verify_mprime_out, - sizeof(verify_mprime_out)); - kfree(verify_mprime_in); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (verify_mprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_REPEATER_AUTH_STREAM_REQ, - verify_mprime_out.header.status); - return -EIO; - } - - return 0; -} - -static int gsc_hdcp_enable_authentication(struct device *dev, - struct hdcp_port_data *data) -{ - struct wired_cmd_enable_auth_in enable_auth_in = { { 0 } }; - struct wired_cmd_enable_auth_out enable_auth_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - enable_auth_in.header.api_version = HDCP_API_VERSION; - enable_auth_in.header.command_id = WIRED_ENABLE_AUTH; - enable_auth_in.header.status = FW_HDCP_STATUS_SUCCESS; - enable_auth_in.header.buffer_len = WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN; - - enable_auth_in.port.integrated_port_type = data->port_type; - enable_auth_in.port.physical_port = (u8)data->hdcp_ddi; - enable_auth_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - enable_auth_in.stream_type = data->streams[0].stream_type; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&enable_auth_in, - sizeof(enable_auth_in), - (u8 *)&enable_auth_out, - sizeof(enable_auth_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (enable_auth_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_ENABLE_AUTH, enable_auth_out.header.status); - return -EIO; - } - - return 0; -} - -static int -gsc_hdcp_close_session(struct device *dev, struct hdcp_port_data *data) -{ - struct wired_cmd_close_session_in session_close_in = { { 0 } }; - struct wired_cmd_close_session_out session_close_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - session_close_in.header.api_version = HDCP_API_VERSION; - session_close_in.header.command_id = WIRED_CLOSE_SESSION; - session_close_in.header.status = FW_HDCP_STATUS_SUCCESS; - session_close_in.header.buffer_len = - WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN; - - session_close_in.port.integrated_port_type = data->port_type; - session_close_in.port.physical_port = (u8)data->hdcp_ddi; - session_close_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_close_in, - sizeof(session_close_in), - (u8 *)&session_close_out, - sizeof(session_close_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } + struct intel_gt *gt = i915->media_gt; + struct intel_gsc_uc *gsc = gt ? >->uc.gsc : NULL; - if (session_close_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "Session Close Failed. status: 0x%X\n", - session_close_out.header.status); - return -EIO; + if (!gsc || !intel_uc_fw_is_running(&gsc->fw)) { + drm_dbg_kms(&i915->drm, + "GSC components required for HDCP2.2 are not ready\n"); + return false; } - return 0; + return true; } -static const struct i915_hdcp_ops gsc_hdcp_ops = { - .initiate_hdcp2_session = gsc_hdcp_initiate_session, - .verify_receiver_cert_prepare_km = - gsc_hdcp_verify_receiver_cert_prepare_km, - .verify_hprime = gsc_hdcp_verify_hprime, - .store_pairing_info = gsc_hdcp_store_pairing_info, - .initiate_locality_check = gsc_hdcp_initiate_locality_check, - .verify_lprime = gsc_hdcp_verify_lprime, - .get_session_key = gsc_hdcp_get_session_key, - .repeater_check_flow_prepare_ack = - gsc_hdcp_repeater_check_flow_prepare_ack, - .verify_mprime = gsc_hdcp_verify_mprime, - .enable_hdcp_authentication = gsc_hdcp_enable_authentication, - .close_hdcp_session = gsc_hdcp_close_session, -}; - /*This function helps allocate memory for the command that we will send to gsc cs */ static int intel_hdcp_gsc_initialize_message(struct drm_i915_private *i915, struct intel_hdcp_gsc_message *hdcp_message) @@ -667,6 +84,22 @@ out_unpin: return err; } +static const struct i915_hdcp_ops gsc_hdcp_ops = { + .initiate_hdcp2_session = intel_hdcp_gsc_initiate_session, + .verify_receiver_cert_prepare_km = + intel_hdcp_gsc_verify_receiver_cert_prepare_km, + .verify_hprime = intel_hdcp_gsc_verify_hprime, + .store_pairing_info = intel_hdcp_gsc_store_pairing_info, + .initiate_locality_check = intel_hdcp_gsc_initiate_locality_check, + .verify_lprime = intel_hdcp_gsc_verify_lprime, + .get_session_key = intel_hdcp_gsc_get_session_key, + .repeater_check_flow_prepare_ack = + intel_hdcp_gsc_repeater_check_flow_prepare_ack, + .verify_mprime = intel_hdcp_gsc_verify_mprime, + .enable_hdcp_authentication = intel_hdcp_gsc_enable_authentication, + .close_hdcp_session = intel_hdcp_gsc_close_session, +}; + static int intel_hdcp_gsc_hdcp2_init(struct drm_i915_private *i915) { struct intel_hdcp_gsc_message *hdcp_message; diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h index cbf96551e534..eba2057c5a9e 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h @@ -23,5 +23,6 @@ ssize_t intel_hdcp_gsc_msg_send(struct drm_i915_private *i915, u8 *msg_in, size_t msg_out_len); int intel_hdcp_gsc_init(struct drm_i915_private *i915); void intel_hdcp_gsc_fini(struct drm_i915_private *i915); +bool intel_hdcp_gsc_check_status(struct drm_i915_private *i915); #endif /* __INTEL_HDCP_GCS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c new file mode 100644 index 000000000000..caa9f0b25729 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c @@ -0,0 +1,592 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2023, Intel Corporation. + */ + +#include <linux/err.h> +#include <drm/i915_hdcp_interface.h> + +#include "i915_drv.h" +#include "intel_hdcp_gsc_message.h" + +int +intel_hdcp_gsc_initiate_session(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_init *ake_data) +{ + struct wired_cmd_initiate_hdcp2_session_in session_init_in = { { 0 } }; + struct wired_cmd_initiate_hdcp2_session_out + session_init_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !ake_data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + session_init_in.header.api_version = HDCP_API_VERSION; + session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION; + session_init_in.header.status = FW_HDCP_STATUS_SUCCESS; + session_init_in.header.buffer_len = + WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN; + + session_init_in.port.integrated_port_type = data->port_type; + session_init_in.port.physical_port = (u8)data->hdcp_ddi; + session_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + session_init_in.protocol = data->protocol; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_init_in, + sizeof(session_init_in), + (u8 *)&session_init_out, + sizeof(session_init_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (session_init_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_INITIATE_HDCP2_SESSION, + session_init_out.header.status); + return -EIO; + } + + ake_data->msg_id = HDCP_2_2_AKE_INIT; + ake_data->tx_caps = session_init_out.tx_caps; + memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN); + + return 0; +} + +int +intel_hdcp_gsc_verify_receiver_cert_prepare_km(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_ake_send_cert *rx_cert, + bool *km_stored, + struct hdcp2_ake_no_stored_km + *ek_pub_km, + size_t *msg_sz) +{ + struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = { { 0 } }; + struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + verify_rxcert_in.header.api_version = HDCP_API_VERSION; + verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT; + verify_rxcert_in.header.status = FW_HDCP_STATUS_SUCCESS; + verify_rxcert_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN; + + verify_rxcert_in.port.integrated_port_type = data->port_type; + verify_rxcert_in.port.physical_port = (u8)data->hdcp_ddi; + verify_rxcert_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + verify_rxcert_in.cert_rx = rx_cert->cert_rx; + memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN); + memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_rxcert_in, + sizeof(verify_rxcert_in), + (u8 *)&verify_rxcert_out, + sizeof(verify_rxcert_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed: %zd\n", byte); + return byte; + } + + if (verify_rxcert_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_VERIFY_RECEIVER_CERT, + verify_rxcert_out.header.status); + return -EIO; + } + + *km_stored = !!verify_rxcert_out.km_stored; + if (verify_rxcert_out.km_stored) { + ek_pub_km->msg_id = HDCP_2_2_AKE_STORED_KM; + *msg_sz = sizeof(struct hdcp2_ake_stored_km); + } else { + ek_pub_km->msg_id = HDCP_2_2_AKE_NO_STORED_KM; + *msg_sz = sizeof(struct hdcp2_ake_no_stored_km); + } + + memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff, + sizeof(verify_rxcert_out.ekm_buff)); + + return 0; +} + +int +intel_hdcp_gsc_verify_hprime(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_send_hprime *rx_hprime) +{ + struct wired_cmd_ake_send_hprime_in send_hprime_in = { { 0 } }; + struct wired_cmd_ake_send_hprime_out send_hprime_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !rx_hprime) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + send_hprime_in.header.api_version = HDCP_API_VERSION; + send_hprime_in.header.command_id = WIRED_AKE_SEND_HPRIME; + send_hprime_in.header.status = FW_HDCP_STATUS_SUCCESS; + send_hprime_in.header.buffer_len = WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN; + + send_hprime_in.port.integrated_port_type = data->port_type; + send_hprime_in.port.physical_port = (u8)data->hdcp_ddi; + send_hprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(send_hprime_in.h_prime, rx_hprime->h_prime, + HDCP_2_2_H_PRIME_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&send_hprime_in, + sizeof(send_hprime_in), + (u8 *)&send_hprime_out, + sizeof(send_hprime_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (send_hprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status); + return -EIO; + } + + return 0; +} + +int +intel_hdcp_gsc_store_pairing_info(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_send_pairing_info *pairing_info) +{ + struct wired_cmd_ake_send_pairing_info_in pairing_info_in = { { 0 } }; + struct wired_cmd_ake_send_pairing_info_out pairing_info_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !pairing_info) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + pairing_info_in.header.api_version = HDCP_API_VERSION; + pairing_info_in.header.command_id = WIRED_AKE_SEND_PAIRING_INFO; + pairing_info_in.header.status = FW_HDCP_STATUS_SUCCESS; + pairing_info_in.header.buffer_len = + WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN; + + pairing_info_in.port.integrated_port_type = data->port_type; + pairing_info_in.port.physical_port = (u8)data->hdcp_ddi; + pairing_info_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km, + HDCP_2_2_E_KH_KM_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&pairing_info_in, + sizeof(pairing_info_in), + (u8 *)&pairing_info_out, + sizeof(pairing_info_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (pairing_info_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. Status: 0x%X\n", + WIRED_AKE_SEND_PAIRING_INFO, + pairing_info_out.header.status); + return -EIO; + } + + return 0; +} + +int +intel_hdcp_gsc_initiate_locality_check(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_lc_init *lc_init_data) +{ + struct wired_cmd_init_locality_check_in lc_init_in = { { 0 } }; + struct wired_cmd_init_locality_check_out lc_init_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !lc_init_data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + lc_init_in.header.api_version = HDCP_API_VERSION; + lc_init_in.header.command_id = WIRED_INIT_LOCALITY_CHECK; + lc_init_in.header.status = FW_HDCP_STATUS_SUCCESS; + lc_init_in.header.buffer_len = WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN; + + lc_init_in.port.integrated_port_type = data->port_type; + lc_init_in.port.physical_port = (u8)data->hdcp_ddi; + lc_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&lc_init_in, sizeof(lc_init_in), + (u8 *)&lc_init_out, sizeof(lc_init_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (lc_init_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. status: 0x%X\n", + WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status); + return -EIO; + } + + lc_init_data->msg_id = HDCP_2_2_LC_INIT; + memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN); + + return 0; +} + +int +intel_hdcp_gsc_verify_lprime(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_lc_send_lprime *rx_lprime) +{ + struct wired_cmd_validate_locality_in verify_lprime_in = { { 0 } }; + struct wired_cmd_validate_locality_out verify_lprime_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !rx_lprime) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + verify_lprime_in.header.api_version = HDCP_API_VERSION; + verify_lprime_in.header.command_id = WIRED_VALIDATE_LOCALITY; + verify_lprime_in.header.status = FW_HDCP_STATUS_SUCCESS; + verify_lprime_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN; + + verify_lprime_in.port.integrated_port_type = data->port_type; + verify_lprime_in.port.physical_port = (u8)data->hdcp_ddi; + verify_lprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime, + HDCP_2_2_L_PRIME_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_lprime_in, + sizeof(verify_lprime_in), + (u8 *)&verify_lprime_out, + sizeof(verify_lprime_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (verify_lprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_VALIDATE_LOCALITY, + verify_lprime_out.header.status); + return -EIO; + } + + return 0; +} + +int intel_hdcp_gsc_get_session_key(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_ske_send_eks *ske_data) +{ + struct wired_cmd_get_session_key_in get_skey_in = { { 0 } }; + struct wired_cmd_get_session_key_out get_skey_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !ske_data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + get_skey_in.header.api_version = HDCP_API_VERSION; + get_skey_in.header.command_id = WIRED_GET_SESSION_KEY; + get_skey_in.header.status = FW_HDCP_STATUS_SUCCESS; + get_skey_in.header.buffer_len = WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN; + + get_skey_in.port.integrated_port_type = data->port_type; + get_skey_in.port.physical_port = (u8)data->hdcp_ddi; + get_skey_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&get_skey_in, sizeof(get_skey_in), + (u8 *)&get_skey_out, sizeof(get_skey_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (get_skey_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_GET_SESSION_KEY, get_skey_out.header.status); + return -EIO; + } + + ske_data->msg_id = HDCP_2_2_SKE_SEND_EKS; + memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks, + HDCP_2_2_E_DKEY_KS_LEN); + memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN); + + return 0; +} + +int +intel_hdcp_gsc_repeater_check_flow_prepare_ack(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_rep_send_receiverid_list + *rep_topology, + struct hdcp2_rep_send_ack + *rep_send_ack) +{ + struct wired_cmd_verify_repeater_in verify_repeater_in = { { 0 } }; + struct wired_cmd_verify_repeater_out verify_repeater_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !rep_topology || !rep_send_ack || !data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + verify_repeater_in.header.api_version = HDCP_API_VERSION; + verify_repeater_in.header.command_id = WIRED_VERIFY_REPEATER; + verify_repeater_in.header.status = FW_HDCP_STATUS_SUCCESS; + verify_repeater_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN; + + verify_repeater_in.port.integrated_port_type = data->port_type; + verify_repeater_in.port.physical_port = (u8)data->hdcp_ddi; + verify_repeater_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(verify_repeater_in.rx_info, rep_topology->rx_info, + HDCP_2_2_RXINFO_LEN); + memcpy(verify_repeater_in.seq_num_v, rep_topology->seq_num_v, + HDCP_2_2_SEQ_NUM_LEN); + memcpy(verify_repeater_in.v_prime, rep_topology->v_prime, + HDCP_2_2_V_PRIME_HALF_LEN); + memcpy(verify_repeater_in.receiver_ids, rep_topology->receiver_ids, + HDCP_2_2_RECEIVER_IDS_MAX_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_repeater_in, + sizeof(verify_repeater_in), + (u8 *)&verify_repeater_out, + sizeof(verify_repeater_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (verify_repeater_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_VERIFY_REPEATER, + verify_repeater_out.header.status); + return -EIO; + } + + memcpy(rep_send_ack->v, verify_repeater_out.v, + HDCP_2_2_V_PRIME_HALF_LEN); + rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK; + + return 0; +} + +int intel_hdcp_gsc_verify_mprime(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_rep_stream_ready *stream_ready) +{ + struct wired_cmd_repeater_auth_stream_req_in *verify_mprime_in; + struct wired_cmd_repeater_auth_stream_req_out + verify_mprime_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + size_t cmd_size; + + if (!dev || !stream_ready || !data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + cmd_size = struct_size(verify_mprime_in, streams, data->k); + if (cmd_size == SIZE_MAX) + return -EINVAL; + + verify_mprime_in = kzalloc(cmd_size, GFP_KERNEL); + if (!verify_mprime_in) + return -ENOMEM; + + verify_mprime_in->header.api_version = HDCP_API_VERSION; + verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ; + verify_mprime_in->header.status = FW_HDCP_STATUS_SUCCESS; + verify_mprime_in->header.buffer_len = cmd_size - sizeof(verify_mprime_in->header); + + verify_mprime_in->port.integrated_port_type = data->port_type; + verify_mprime_in->port.physical_port = (u8)data->hdcp_ddi; + verify_mprime_in->port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(verify_mprime_in->m_prime, stream_ready->m_prime, HDCP_2_2_MPRIME_LEN); + drm_hdcp_cpu_to_be24(verify_mprime_in->seq_num_m, data->seq_num_m); + + memcpy(verify_mprime_in->streams, data->streams, + array_size(data->k, sizeof(*data->streams))); + + verify_mprime_in->k = cpu_to_be16(data->k); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)verify_mprime_in, cmd_size, + (u8 *)&verify_mprime_out, + sizeof(verify_mprime_out)); + kfree(verify_mprime_in); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (verify_mprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_REPEATER_AUTH_STREAM_REQ, + verify_mprime_out.header.status); + return -EIO; + } + + return 0; +} + +int intel_hdcp_gsc_enable_authentication(struct device *dev, + struct hdcp_port_data *data) +{ + struct wired_cmd_enable_auth_in enable_auth_in = { { 0 } }; + struct wired_cmd_enable_auth_out enable_auth_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + enable_auth_in.header.api_version = HDCP_API_VERSION; + enable_auth_in.header.command_id = WIRED_ENABLE_AUTH; + enable_auth_in.header.status = FW_HDCP_STATUS_SUCCESS; + enable_auth_in.header.buffer_len = WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN; + + enable_auth_in.port.integrated_port_type = data->port_type; + enable_auth_in.port.physical_port = (u8)data->hdcp_ddi; + enable_auth_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + enable_auth_in.stream_type = data->streams[0].stream_type; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&enable_auth_in, + sizeof(enable_auth_in), + (u8 *)&enable_auth_out, + sizeof(enable_auth_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (enable_auth_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_ENABLE_AUTH, enable_auth_out.header.status); + return -EIO; + } + + return 0; +} + +int +intel_hdcp_gsc_close_session(struct device *dev, struct hdcp_port_data *data) +{ + struct wired_cmd_close_session_in session_close_in = { { 0 } }; + struct wired_cmd_close_session_out session_close_out = { { 0 } }; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + session_close_in.header.api_version = HDCP_API_VERSION; + session_close_in.header.command_id = WIRED_CLOSE_SESSION; + session_close_in.header.status = FW_HDCP_STATUS_SUCCESS; + session_close_in.header.buffer_len = + WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN; + + session_close_in.port.integrated_port_type = data->port_type; + session_close_in.port.physical_port = (u8)data->hdcp_ddi; + session_close_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_close_in, + sizeof(session_close_in), + (u8 *)&session_close_out, + sizeof(session_close_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (session_close_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "Session Close Failed. status: 0x%X\n", + session_close_out.header.status); + return -EIO; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.h b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.h new file mode 100644 index 000000000000..ce199d6f6232 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_HDCP_GSC_MESSAGE_H__ +#define __INTEL_HDCP_GSC_MESSAGE_H__ + +#include <linux/types.h> + +struct device; +struct drm_i915_private; +struct hdcp_port_data; +struct hdcp2_ake_init; +struct hdcp2_ake_send_cert; +struct hdcp2_ake_no_stored_km; +struct hdcp2_ake_send_hprime; +struct hdcp2_ake_send_pairing_info; +struct hdcp2_lc_init; +struct hdcp2_lc_send_lprime; +struct hdcp2_ske_send_eks; +struct hdcp2_rep_send_receiverid_list; +struct hdcp2_rep_send_ack; +struct hdcp2_rep_stream_ready; + +ssize_t intel_hdcp_gsc_msg_send(struct drm_i915_private *i915, u8 *msg_in, + size_t msg_in_len, u8 *msg_out, + size_t msg_out_len); +bool intel_hdcp_gsc_check_status(struct drm_i915_private *i915); +int +intel_hdcp_gsc_initiate_session(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_init *ake_data); +int +intel_hdcp_gsc_verify_receiver_cert_prepare_km(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_ake_send_cert *rx_cert, + bool *km_stored, + struct hdcp2_ake_no_stored_km + *ek_pub_km, + size_t *msg_sz); +int +intel_hdcp_gsc_verify_hprime(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_send_hprime *rx_hprime); +int +intel_hdcp_gsc_store_pairing_info(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_send_pairing_info *pairing_info); +int +intel_hdcp_gsc_initiate_locality_check(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_lc_init *lc_init_data); +int +intel_hdcp_gsc_verify_lprime(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_lc_send_lprime *rx_lprime); +int intel_hdcp_gsc_get_session_key(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_ske_send_eks *ske_data); +int +intel_hdcp_gsc_repeater_check_flow_prepare_ack(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_rep_send_receiverid_list + *rep_topology, + struct hdcp2_rep_send_ack + *rep_send_ack); +int intel_hdcp_gsc_verify_mprime(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_rep_stream_ready *stream_ready); +int intel_hdcp_gsc_enable_authentication(struct device *dev, + struct hdcp_port_data *data); +int +intel_hdcp_gsc_close_session(struct device *dev, struct hdcp_port_data *data); + +#endif /* __INTEL_HDCP_GSC_MESSAGE_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 94a7e1537f42..ac315f8e7820 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -1240,26 +1240,23 @@ static void hsw_set_infoframes(struct intel_encoder *encoder, void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable) { struct drm_i915_private *dev_priv = intel_hdmi_to_i915(hdmi); - struct i2c_adapter *adapter; + struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI) return; - adapter = intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); - drm_dbg_kms(&dev_priv->drm, "%s DP dual mode adaptor TMDS output\n", enable ? "Enabling" : "Disabling"); - drm_dp_dual_mode_set_tmds_output(&dev_priv->drm, hdmi->dp_dual_mode.type, adapter, enable); + drm_dp_dual_mode_set_tmds_output(&dev_priv->drm, + hdmi->dp_dual_mode.type, ddc, enable); } static int intel_hdmi_hdcp_read(struct intel_digital_port *dig_port, unsigned int offset, void *buffer, size_t size) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_hdmi *hdmi = &dig_port->hdmi; - struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915, - hdmi->ddc_bus); + struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; int ret; u8 start = offset & 0xff; struct i2c_msg msgs[] = { @@ -1276,7 +1273,7 @@ static int intel_hdmi_hdcp_read(struct intel_digital_port *dig_port, .buf = buffer } }; - ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); + ret = i2c_transfer(ddc, msgs, ARRAY_SIZE(msgs)); if (ret == ARRAY_SIZE(msgs)) return 0; return ret >= 0 ? -EIO : ret; @@ -1285,10 +1282,8 @@ static int intel_hdmi_hdcp_read(struct intel_digital_port *dig_port, static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port, unsigned int offset, void *buffer, size_t size) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_hdmi *hdmi = &dig_port->hdmi; - struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915, - hdmi->ddc_bus); + struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; int ret; u8 *write_buf; struct i2c_msg msg; @@ -1305,7 +1300,7 @@ static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port, msg.len = size + 1, msg.buf = write_buf; - ret = i2c_transfer(adapter, &msg, 1); + ret = i2c_transfer(ddc, &msg, 1); if (ret == 1) ret = 0; else if (ret >= 0) @@ -1321,8 +1316,7 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port, { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_hdmi *hdmi = &dig_port->hdmi; - struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915, - hdmi->ddc_bus); + struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; int ret; ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an, @@ -1333,7 +1327,7 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port, return ret; } - ret = intel_gmbus_output_aksv(adapter); + ret = intel_gmbus_output_aksv(ddc); if (ret < 0) { drm_dbg_kms(&i915->drm, "Failed to output aksv (%d)\n", ret); return ret; @@ -1665,9 +1659,10 @@ intel_hdmi_hdcp2_wait_for_msg(struct intel_digital_port *dig_port, } static -int intel_hdmi_hdcp2_write_msg(struct intel_digital_port *dig_port, +int intel_hdmi_hdcp2_write_msg(struct intel_connector *connector, void *buf, size_t size) { + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); unsigned int offset; offset = HDCP_2_2_HDMI_REG_WR_MSG_OFFSET; @@ -1675,9 +1670,10 @@ int intel_hdmi_hdcp2_write_msg(struct intel_digital_port *dig_port, } static -int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *dig_port, +int intel_hdmi_hdcp2_read_msg(struct intel_connector *connector, u8 msg_id, void *buf, size_t size) { + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_hdmi *hdmi = &dig_port->hdmi; struct intel_hdcp *hdcp = &hdmi->attached_connector->hdcp; @@ -1733,9 +1729,10 @@ int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port, } static -int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port, +int intel_hdmi_hdcp2_capable(struct intel_connector *connector, bool *capable) { + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); u8 hdcp2_version; int ret; @@ -2400,9 +2397,10 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base; - struct i2c_adapter *adapter = - intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); - enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(&dev_priv->drm, adapter); + struct i2c_adapter *ddc = connector->ddc; + enum drm_dp_dual_mode_type type; + + type = drm_dp_dual_mode_detect(&dev_priv->drm, ddc); /* * Type 1 DVI adaptors are not required to implement any @@ -2429,7 +2427,7 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) hdmi->dp_dual_mode.type = type; hdmi->dp_dual_mode.max_tmds_clock = - drm_dp_dual_mode_max_tmds_clock(&dev_priv->drm, type, adapter); + drm_dp_dual_mode_max_tmds_clock(&dev_priv->drm, type, ddc); drm_dbg_kms(&dev_priv->drm, "DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n", @@ -2450,24 +2448,21 @@ intel_hdmi_set_edid(struct drm_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *intel_hdmi = intel_attached_hdmi(to_intel_connector(connector)); + struct i2c_adapter *ddc = connector->ddc; intel_wakeref_t wakeref; const struct drm_edid *drm_edid; - const struct edid *edid; bool connected = false; - struct i2c_adapter *i2c; wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); - i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); + drm_edid = drm_edid_read_ddc(connector, ddc); - drm_edid = drm_edid_read_ddc(connector, i2c); - - if (!drm_edid && !intel_gmbus_is_forced_bit(i2c)) { + if (!drm_edid && !intel_gmbus_is_forced_bit(ddc)) { drm_dbg_kms(&dev_priv->drm, "HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n"); - intel_gmbus_force_bit(i2c, true); - drm_edid = drm_edid_read_ddc(connector, i2c); - intel_gmbus_force_bit(i2c, false); + intel_gmbus_force_bit(ddc, true); + drm_edid = drm_edid_read_ddc(connector, ddc); + intel_gmbus_force_bit(ddc, false); } /* Below we depend on display info having been updated */ @@ -2475,9 +2470,7 @@ intel_hdmi_set_edid(struct drm_connector *connector) to_intel_connector(connector)->detect_edid = drm_edid; - /* FIXME: Get rid of drm_edid_raw() */ - edid = drm_edid_raw(drm_edid); - if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { + if (drm_edid_is_digital(drm_edid)) { intel_hdmi_dp_dual_mode_detect(connector); connected = true; @@ -2485,7 +2478,8 @@ intel_hdmi_set_edid(struct drm_connector *connector) intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref); - cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid); + cec_notifier_set_phys_addr(intel_hdmi->cec_notifier, + connector->display_info.source_physical_address); return connected; } @@ -2502,7 +2496,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); - if (!INTEL_DISPLAY_ENABLED(dev_priv)) + if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); @@ -2522,12 +2516,6 @@ out: if (status != connector_status_connected) cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier); - /* - * Make sure the refs for power wells enabled during detect are - * dropped to avoid a new detect cycle triggered by HPD polling. - */ - intel_display_power_flush_work(dev_priv); - return status; } @@ -2553,37 +2541,6 @@ static int intel_hdmi_get_modes(struct drm_connector *connector) return drm_edid_connector_add_modes(connector); } -static struct i2c_adapter * -intel_hdmi_get_i2c_adapter(struct drm_connector *connector) -{ - struct drm_i915_private *dev_priv = to_i915(connector->dev); - struct intel_hdmi *intel_hdmi = intel_attached_hdmi(to_intel_connector(connector)); - - return intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); -} - -static void intel_hdmi_create_i2c_symlink(struct drm_connector *connector) -{ - struct drm_i915_private *i915 = to_i915(connector->dev); - struct i2c_adapter *adapter = intel_hdmi_get_i2c_adapter(connector); - struct kobject *i2c_kobj = &adapter->dev.kobj; - struct kobject *connector_kobj = &connector->kdev->kobj; - int ret; - - ret = sysfs_create_link(connector_kobj, i2c_kobj, i2c_kobj->name); - if (ret) - drm_err(&i915->drm, "Failed to create i2c symlink (%d)\n", ret); -} - -static void intel_hdmi_remove_i2c_symlink(struct drm_connector *connector) -{ - struct i2c_adapter *adapter = intel_hdmi_get_i2c_adapter(connector); - struct kobject *i2c_kobj = &adapter->dev.kobj; - struct kobject *connector_kobj = &connector->kdev->kobj; - - sysfs_remove_link(connector_kobj, i2c_kobj->name); -} - static int intel_hdmi_connector_register(struct drm_connector *connector) { @@ -2593,8 +2550,6 @@ intel_hdmi_connector_register(struct drm_connector *connector) if (ret) return ret; - intel_hdmi_create_i2c_symlink(connector); - return ret; } @@ -2604,7 +2559,6 @@ static void intel_hdmi_connector_unregister(struct drm_connector *connector) cec_notifier_conn_unregister(n); - intel_hdmi_remove_i2c_symlink(connector); intel_connector_unregister(connector); } @@ -2918,13 +2872,17 @@ get_encoder_by_ddc_pin(struct intel_encoder *encoder, u8 ddc_pin) struct intel_encoder *other; for_each_intel_encoder(&i915->drm, other) { + struct intel_connector *connector; + if (other == encoder) continue; if (!intel_encoder_is_dig_port(other)) continue; - if (enc_to_dig_port(other)->hdmi.ddc_bus == ddc_pin) + connector = enc_to_dig_port(other)->hdmi.attached_connector; + + if (connector && connector->base.ddc == intel_gmbus_get_adapter(i915, ddc_pin)) return other; } @@ -3016,9 +2974,9 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, struct intel_encoder *intel_encoder = &dig_port->base; struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct i2c_adapter *ddc; enum port port = intel_encoder->port; struct cec_connector_info conn_info; + u8 ddc_pin; drm_dbg_kms(&dev_priv->drm, "Adding HDMI connector on [ENCODER:%d:%s]\n", @@ -3033,16 +2991,15 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, intel_encoder->base.name)) return; - intel_hdmi->ddc_bus = intel_hdmi_ddc_pin(intel_encoder); - if (!intel_hdmi->ddc_bus) + ddc_pin = intel_hdmi_ddc_pin(intel_encoder); + if (!ddc_pin) return; - ddc = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); - drm_connector_init_with_ddc(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA, - ddc); + intel_gmbus_get_adapter(dev_priv, ddc_pin)); + drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); if (DISPLAY_VER(dev_priv) < 12) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 69a83dcc1996..0c0700c6ec66 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -25,6 +25,7 @@ #include "i915_drv.h" #include "i915_irq.h" +#include "intel_display_power.h" #include "intel_display_types.h" #include "intel_hotplug.h" #include "intel_hotplug_irq.h" @@ -259,21 +260,22 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); } -enum intel_hotplug_state -intel_encoder_hotplug(struct intel_encoder *encoder, - struct intel_connector *connector) +static enum intel_hotplug_state +intel_hotplug_detect_connector(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; enum drm_connector_status old_status; u64 old_epoch_counter; + int status; bool ret = false; drm_WARN_ON(dev, !mutex_is_locked(&dev->mode_config.mutex)); old_status = connector->base.status; old_epoch_counter = connector->base.epoch_counter; - connector->base.status = - drm_helper_probe_detect(&connector->base, NULL, false); + status = drm_helper_probe_detect(&connector->base, NULL, false); + if (!connector->base.force) + connector->base.status = status; if (old_epoch_counter != connector->base.epoch_counter) ret = true; @@ -291,6 +293,13 @@ intel_encoder_hotplug(struct intel_encoder *encoder, return INTEL_HOTPLUG_UNCHANGED; } +enum intel_hotplug_state +intel_encoder_hotplug(struct intel_encoder *encoder, + struct intel_connector *connector) +{ + return intel_hotplug_detect_connector(connector); +} + static bool intel_encoder_has_hpd_pulse(struct intel_encoder *encoder) { return intel_encoder_is_dig_port(encoder) && @@ -631,6 +640,49 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } +static void i915_hpd_poll_detect_connectors(struct drm_i915_private *i915) +{ + struct drm_connector_list_iter conn_iter; + struct intel_connector *connector; + struct intel_connector *first_changed_connector = NULL; + int changed = 0; + + mutex_lock(&i915->drm.mode_config.mutex); + + if (!i915->drm.mode_config.poll_enabled) + goto out; + + drm_connector_list_iter_begin(&i915->drm, &conn_iter); + for_each_intel_connector_iter(connector, &conn_iter) { + if (!(connector->base.polled & DRM_CONNECTOR_POLL_HPD)) + continue; + + if (intel_hotplug_detect_connector(connector) != INTEL_HOTPLUG_CHANGED) + continue; + + changed++; + + if (changed == 1) { + drm_connector_get(&connector->base); + first_changed_connector = connector; + } + } + drm_connector_list_iter_end(&conn_iter); + +out: + mutex_unlock(&i915->drm.mode_config.mutex); + + if (!changed) + return; + + if (changed == 1) + drm_kms_helper_connector_hotplug_event(&first_changed_connector->base); + else + drm_kms_helper_hotplug_event(&i915->drm); + + drm_connector_put(&first_changed_connector->base); +} + static void i915_hpd_poll_init_work(struct work_struct *work) { struct drm_i915_private *dev_priv = @@ -638,11 +690,25 @@ static void i915_hpd_poll_init_work(struct work_struct *work) display.hotplug.poll_init_work); struct drm_connector_list_iter conn_iter; struct intel_connector *connector; + intel_wakeref_t wakeref; bool enabled; mutex_lock(&dev_priv->drm.mode_config.mutex); enabled = READ_ONCE(dev_priv->display.hotplug.poll_enabled); + /* + * Prevent taking a power reference from this sequence of + * i915_hpd_poll_init_work() -> drm_helper_hpd_irq_event() -> + * connector detect which would requeue i915_hpd_poll_init_work() + * and so risk an endless loop of this same sequence. + */ + if (!enabled) { + wakeref = intel_display_power_get(dev_priv, + POWER_DOMAIN_DISPLAY_CORE); + drm_WARN_ON(&dev_priv->drm, + READ_ONCE(dev_priv->display.hotplug.poll_enabled)); + cancel_work(&dev_priv->display.hotplug.poll_init_work); + } drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { @@ -669,8 +735,13 @@ static void i915_hpd_poll_init_work(struct work_struct *work) * We might have missed any hotplugs that happened while we were * in the middle of disabling polling */ - if (!enabled) - drm_helper_hpd_irq_event(&dev_priv->drm); + if (!enabled) { + i915_hpd_poll_detect_connectors(dev_priv); + + intel_display_power_put(dev_priv, + POWER_DOMAIN_DISPLAY_CORE, + wakeref); + } } /** @@ -692,7 +763,7 @@ static void i915_hpd_poll_init_work(struct work_struct *work) void intel_hpd_poll_enable(struct drm_i915_private *dev_priv) { if (!HAS_DISPLAY(dev_priv) || - !INTEL_DISPLAY_ENABLED(dev_priv)) + !intel_display_device_enabled(dev_priv)) return; WRITE_ONCE(dev_priv->display.hotplug.poll_enabled, true); diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index 95a7ea94f417..f07047e9cb30 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -163,7 +163,9 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))) return; - if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) + if (INTEL_PCH_TYPE(dev_priv) >= PCH_LNL) + hpd->pch_hpd = hpd_mtp; + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) hpd->pch_hpd = hpd_sde_dg1; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP) hpd->pch_hpd = hpd_mtp; @@ -514,6 +516,9 @@ void xelpdp_pica_irq_handler(struct drm_i915_private *i915, u32 iir) u32 trigger_aux = iir & XELPDP_AUX_TC_MASK; u32 pin_mask = 0, long_mask = 0; + if (DISPLAY_VER(i915) >= 20) + trigger_aux |= iir & XE2LPD_AUX_DDI_MASK; + for (pin = HPD_PORT_TC1; pin <= HPD_PORT_TC4; pin++) { u32 val; @@ -1060,6 +1065,19 @@ static void mtp_hpd_irq_setup(struct drm_i915_private *i915) mtp_tc_hpd_detection_setup(i915); } +static void xe2lpd_sde_hpd_irq_setup(struct drm_i915_private *i915) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(i915, i915->display.hotplug.pch_hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(i915, i915->display.hotplug.pch_hpd); + + ibx_display_interrupt_update(i915, hotplug_irqs, enabled_irqs); + + mtp_ddi_hpd_detection_setup(i915); + mtp_tc_hpd_detection_setup(i915); +} + static bool is_xelpdp_pica_hpd_pin(enum hpd_pin hpd_pin) { return hpd_pin >= HPD_PORT_TC1 && hpd_pin <= HPD_PORT_TC4; @@ -1119,7 +1137,9 @@ static void xelpdp_hpd_irq_setup(struct drm_i915_private *i915) xelpdp_pica_hpd_detection_setup(i915); - if (INTEL_PCH_TYPE(i915) >= PCH_MTP) + if (INTEL_PCH_TYPE(i915) >= PCH_LNL) + xe2lpd_sde_hpd_irq_setup(i915); + else if (INTEL_PCH_TYPE(i915) >= PCH_MTP) mtp_hpd_irq_setup(i915); } diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c new file mode 100644 index 000000000000..c5eb5f242536 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_drv.h" + +#include "intel_atomic.h" +#include "intel_display_types.h" +#include "intel_fdi.h" +#include "intel_link_bw.h" + +/** + * intel_link_bw_init_limits - initialize BW limits + * @i915: device instance + * @limits: link BW limits + * + * Initialize @limits. + */ +void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_bw_limits *limits) +{ + enum pipe pipe; + + limits->bpp_limit_reached_pipes = 0; + for_each_pipe(i915, pipe) + limits->max_bpp_x16[pipe] = INT_MAX; +} + +/** + * intel_link_bw_reduce_bpp - reduce maximum link bpp for a selected pipe + * @state: atomic state + * @limits: link BW limits + * @pipe_mask: mask of pipes to select from + * @reason: explanation of why bpp reduction is needed + * + * Select the pipe from @pipe_mask with the biggest link bpp value and set the + * maximum of link bpp in @limits below this value. Modeset the selected pipe, + * so that its state will get recomputed. + * + * This function can be called to resolve a link's BW overallocation by reducing + * the link bpp of one pipe on the link and hence reducing the total link BW. + * + * Returns + * - 0 in case of success + * - %-ENOSPC if no pipe can further reduce its link bpp + * - Other negative error, if modesetting the selected pipe failed + */ +int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits, + u8 pipe_mask, + const char *reason) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + enum pipe max_bpp_pipe = INVALID_PIPE; + struct intel_crtc *crtc; + int max_bpp = 0; + + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) { + struct intel_crtc_state *crtc_state; + int link_bpp; + + if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe)) + continue; + + crtc_state = intel_atomic_get_crtc_state(&state->base, + crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (crtc_state->dsc.compression_enable) + link_bpp = crtc_state->dsc.compressed_bpp; + else + /* + * TODO: for YUV420 the actual link bpp is only half + * of the pipe bpp value. The MST encoder's BW allocation + * is based on the pipe bpp value, set the actual link bpp + * limit here once the MST BW allocation is fixed. + */ + link_bpp = crtc_state->pipe_bpp; + + if (link_bpp > max_bpp) { + max_bpp = link_bpp; + max_bpp_pipe = crtc->pipe; + } + } + + if (max_bpp_pipe == INVALID_PIPE) + return -ENOSPC; + + limits->max_bpp_x16[max_bpp_pipe] = to_bpp_x16(max_bpp) - 1; + + return intel_modeset_pipes_in_mask_early(state, reason, + BIT(max_bpp_pipe)); +} + +/** + * intel_link_bw_set_bpp_limit_for_pipe - set link bpp limit for a pipe to its minimum + * @state: atomic state + * @old_limits: link BW limits + * @new_limits: link BW limits + * @pipe: pipe + * + * Set the link bpp limit for @pipe in @new_limits to its value in + * @old_limits and mark this limit as the minimum. This function must be + * called after a pipe's compute config function failed, @old_limits + * containing the bpp limit with which compute config previously passed. + * + * The function will fail if setting a minimum is not possible, either + * because the old and new limits match (and so would lead to a pipe compute + * config failure) or the limit is already at the minimum. + * + * Returns %true in case of success. + */ +bool +intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state, + const struct intel_link_bw_limits *old_limits, + struct intel_link_bw_limits *new_limits, + enum pipe pipe) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + + if (pipe == INVALID_PIPE) + return false; + + if (new_limits->max_bpp_x16[pipe] == + old_limits->max_bpp_x16[pipe]) + return false; + + if (drm_WARN_ON(&i915->drm, + new_limits->bpp_limit_reached_pipes & BIT(pipe))) + return false; + + new_limits->max_bpp_x16[pipe] = + old_limits->max_bpp_x16[pipe]; + new_limits->bpp_limit_reached_pipes |= BIT(pipe); + + return true; +} + +static int check_all_link_config(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits) +{ + /* TODO: Check additional shared display link configurations like MST */ + int ret; + + ret = intel_fdi_atomic_check_link(state, limits); + if (ret) + return ret; + + return 0; +} + +static bool +assert_link_limit_change_valid(struct drm_i915_private *i915, + const struct intel_link_bw_limits *old_limits, + const struct intel_link_bw_limits *new_limits) +{ + bool bpps_changed = false; + enum pipe pipe; + + for_each_pipe(i915, pipe) { + /* The bpp limit can only decrease. */ + if (drm_WARN_ON(&i915->drm, + new_limits->max_bpp_x16[pipe] > + old_limits->max_bpp_x16[pipe])) + return false; + + if (new_limits->max_bpp_x16[pipe] < + old_limits->max_bpp_x16[pipe]) + bpps_changed = true; + } + + /* At least one limit must change. */ + if (drm_WARN_ON(&i915->drm, + !bpps_changed)) + return false; + + return true; +} + +/** + * intel_link_bw_atomic_check - check display link states and set a fallback config if needed + * @state: atomic state + * @new_limits: link BW limits + * + * Check the configuration of all shared display links in @state and set new BW + * limits in @new_limits if there is a BW limitation. + * + * Returns: + * - 0 if the confugration is valid + * - %-EAGAIN, if the configuration is invalid and @new_limits got updated + * with fallback values with which the configuration of all CRTCs + * in @state must be recomputed + * - Other negative error, if the configuration is invalid without a + * fallback possibility, or the check failed for another reason + */ +int intel_link_bw_atomic_check(struct intel_atomic_state *state, + struct intel_link_bw_limits *new_limits) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_link_bw_limits old_limits = *new_limits; + int ret; + + ret = check_all_link_config(state, new_limits); + if (ret != -EAGAIN) + return ret; + + if (!assert_link_limit_change_valid(i915, &old_limits, new_limits)) + return -EINVAL; + + return -EAGAIN; +} diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.h b/drivers/gpu/drm/i915/display/intel_link_bw.h new file mode 100644 index 000000000000..e07df22a779a --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_link_bw.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_LINK_BW_H__ +#define __INTEL_LINK_BW_H__ + +#include <linux/types.h> + +#include "intel_display_limits.h" + +struct drm_i915_private; + +struct intel_atomic_state; +struct intel_crtc_state; + +struct intel_link_bw_limits { + u8 bpp_limit_reached_pipes; + /* in 1/16 bpp units */ + int max_bpp_x16[I915_MAX_PIPES]; +}; + +void intel_link_bw_init_limits(struct drm_i915_private *i915, + struct intel_link_bw_limits *limits); +int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits, + u8 pipe_mask, + const char *reason); +bool intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state, + const struct intel_link_bw_limits *old_limits, + struct intel_link_bw_limits *new_limits, + enum pipe pipe); +int intel_link_bw_atomic_check(struct intel_atomic_state *state, + struct intel_link_bw_limits *new_limits); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.h b/drivers/gpu/drm/i915/display/intel_lpe_audio.h index 0beecac267ae..2c5fcb6e1fd0 100644 --- a/drivers/gpu/drm/i915/display/intel_lpe_audio.h +++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.h @@ -12,11 +12,29 @@ enum port; enum transcoder; struct drm_i915_private; +#ifdef I915 int intel_lpe_audio_init(struct drm_i915_private *dev_priv); void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv); void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv); void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder, enum port port, const void *eld, int ls_clock, bool dp_output); +#else +static inline int intel_lpe_audio_init(struct drm_i915_private *dev_priv) +{ + return -ENODEV; +} +static inline void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv) +{ +} +static inline void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv) +{ +} +static inline void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder, enum port port, + const void *eld, int ls_clock, bool dp_output) +{ +} +#endif #endif /* __INTEL_LPE_AUDIO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c index bb3b5355a0d9..1d048fa98561 100644 --- a/drivers/gpu/drm/i915/display/intel_lspcon.c +++ b/drivers/gpu/drm/i915/display/intel_lspcon.c @@ -144,15 +144,27 @@ static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon) struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); struct drm_i915_private *i915 = dp_to_i915(intel_dp); enum drm_lspcon_mode current_mode; - struct i2c_adapter *adapter = &intel_dp->aux.ddc; + struct i2c_adapter *ddc = &intel_dp->aux.ddc; - if (drm_lspcon_get_mode(intel_dp->aux.drm_dev, adapter, ¤t_mode)) { + if (drm_lspcon_get_mode(intel_dp->aux.drm_dev, ddc, ¤t_mode)) { drm_dbg_kms(&i915->drm, "Error reading LSPCON mode\n"); return DRM_LSPCON_MODE_INVALID; } return current_mode; } +static int lspcon_get_mode_settle_timeout(struct intel_lspcon *lspcon) +{ + /* + * On some CometLake-based device designs the Parade PS175 takes more + * than 400ms to settle in PCON mode. 100 reboot trials on one device + * resulted in a median settle time of 440ms and a maximum of 444ms. + * Even after increasing the timeout to 500ms, 2% of devices still had + * this error. So this sets the timeout to 800ms. + */ + return lspcon->vendor == LSPCON_VENDOR_PARADE ? 800 : 400; +} + static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon, enum drm_lspcon_mode mode) { @@ -167,7 +179,8 @@ static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon, drm_dbg_kms(&i915->drm, "Waiting for LSPCON mode %s to settle\n", lspcon_mode_name(mode)); - wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, 400); + wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, + lspcon_get_mode_settle_timeout(lspcon)); if (current_mode != mode) drm_err(&i915->drm, "LSPCON mode hasn't settled\n"); @@ -185,9 +198,9 @@ static int lspcon_change_mode(struct intel_lspcon *lspcon, struct drm_i915_private *i915 = dp_to_i915(intel_dp); int err; enum drm_lspcon_mode current_mode; - struct i2c_adapter *adapter = &intel_dp->aux.ddc; + struct i2c_adapter *ddc = &intel_dp->aux.ddc; - err = drm_lspcon_get_mode(intel_dp->aux.drm_dev, adapter, ¤t_mode); + err = drm_lspcon_get_mode(intel_dp->aux.drm_dev, ddc, ¤t_mode); if (err) { drm_err(&i915->drm, "Error reading LSPCON mode\n"); return err; @@ -198,7 +211,7 @@ static int lspcon_change_mode(struct intel_lspcon *lspcon, return 0; } - err = drm_lspcon_set_mode(intel_dp->aux.drm_dev, adapter, mode); + err = drm_lspcon_set_mode(intel_dp->aux.drm_dev, ddc, mode); if (err < 0) { drm_err(&i915->drm, "LSPCON mode change failed\n"); return err; @@ -233,7 +246,7 @@ static bool lspcon_probe(struct intel_lspcon *lspcon) enum drm_dp_dual_mode_type adaptor_type; struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); struct drm_i915_private *i915 = dp_to_i915(intel_dp); - struct i2c_adapter *adapter = &intel_dp->aux.ddc; + struct i2c_adapter *ddc = &intel_dp->aux.ddc; enum drm_lspcon_mode expected_mode; expected_mode = lspcon_wake_native_aux_ch(lspcon) ? @@ -244,7 +257,7 @@ static bool lspcon_probe(struct intel_lspcon *lspcon) if (retry) usleep_range(500, 1000); - adaptor_type = drm_dp_dual_mode_detect(intel_dp->aux.drm_dev, adapter); + adaptor_type = drm_dp_dual_mode_detect(intel_dp->aux.drm_dev, ddc); if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON) break; } diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 3ace56979b70..2a4ca7e65775 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -425,11 +425,18 @@ static int intel_lvds_compute_config(struct intel_encoder *encoder, return -EINVAL; } + if (HAS_PCH_SPLIT(i915)) { + crtc_state->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(crtc_state)) + return -EINVAL; + } + if (lvds_encoder->a3_power == LVDS_A3_POWER_UP) lvds_bpp = 8*3; else lvds_bpp = 6*3; + /* TODO: Check crtc_state->max_link_bpp_x16 instead of bw_constrained */ if (lvds_bpp != crtc_state->pipe_bpp && !crtc_state->bw_constrained) { drm_dbg_kms(&i915->drm, "forcing display bpp (was %d) to LVDS (%d)\n", @@ -453,9 +460,6 @@ static int intel_lvds_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; - if (HAS_PCH_SPLIT(i915)) - crtc_state->has_pch_encoder = true; - ret = intel_panel_fitting(crtc_state, conn_state); if (ret) return ret; @@ -837,7 +841,7 @@ void intel_lvds_init(struct drm_i915_private *i915) struct intel_encoder *encoder; i915_reg_t lvds_reg; u32 lvds; - u8 pin; + u8 ddc_pin; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) { @@ -864,8 +868,8 @@ void intel_lvds_init(struct drm_i915_private *i915) return; } - pin = GMBUS_PIN_PANEL; - if (!intel_bios_is_lvds_present(i915, &pin)) { + ddc_pin = GMBUS_PIN_PANEL; + if (!intel_bios_is_lvds_present(i915, &ddc_pin)) { if ((lvds & LVDS_PORT_EN) == 0) { drm_dbg_kms(&i915->drm, "LVDS is not present in VBT\n"); @@ -888,8 +892,10 @@ void intel_lvds_init(struct drm_i915_private *i915) lvds_encoder->attached_connector = connector; encoder = &lvds_encoder->base; - drm_connector_init(&i915->drm, &connector->base, &intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + drm_connector_init_with_ddc(&i915->drm, &connector->base, + &intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS, + intel_gmbus_get_adapter(i915, ddc_pin)); drm_encoder_init(&i915->drm, &encoder->base, &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS, "LVDS"); @@ -943,13 +949,10 @@ void intel_lvds_init(struct drm_i915_private *i915) * preferred mode is the right one. */ mutex_lock(&i915->drm.mode_config.mutex); - if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) { - drm_edid = drm_edid_read_switcheroo(&connector->base, - intel_gmbus_get_adapter(i915, pin)); - } else { - drm_edid = drm_edid_read_ddc(&connector->base, - intel_gmbus_get_adapter(i915, pin)); - } + if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) + drm_edid = drm_edid_read_switcheroo(&connector->base, connector->base.ddc); + else + drm_edid = drm_edid_read_ddc(&connector->base, connector->base.ddc); if (drm_edid) { if (drm_edid_connector_update(&connector->base, drm_edid) || !drm_edid_connector_add_modes(&connector->base)) { diff --git a/drivers/gpu/drm/i915/display/intel_lvds.h b/drivers/gpu/drm/i915/display/intel_lvds.h index 9d3372dc503f..7ad5fa9c0434 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.h +++ b/drivers/gpu/drm/i915/display/intel_lvds.h @@ -13,10 +13,29 @@ enum pipe; struct drm_i915_private; +#ifdef I915 bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv, i915_reg_t lvds_reg, enum pipe *pipe); void intel_lvds_init(struct drm_i915_private *dev_priv); struct intel_encoder *intel_get_lvds_encoder(struct drm_i915_private *dev_priv); bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv); +#else +static inline bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t lvds_reg, enum pipe *pipe) +{ + return false; +} +static inline void intel_lvds_init(struct drm_i915_private *dev_priv) +{ +} +static inline struct intel_encoder *intel_get_lvds_encoder(struct drm_i915_private *dev_priv) +{ + return NULL; +} +static inline bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv) +{ + return false; +} +#endif #endif /* __INTEL_LVDS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 138144a65a45..5e1c2c780412 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -23,8 +23,8 @@ * Cross check the actual hw state with our own modeset state tracking (and its * internal consistency). */ -static void intel_connector_verify_state(struct intel_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +static void intel_connector_verify_state(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) { struct intel_connector *connector = to_intel_connector(conn_state->connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); @@ -66,12 +66,12 @@ verify_connector_state(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_connector *connector; - struct drm_connector_state *new_conn_state; + const struct drm_connector_state *new_conn_state; int i; for_each_new_connector_in_state(&state->base, connector, new_conn_state, i) { struct drm_encoder *encoder = connector->encoder; - struct intel_crtc_state *crtc_state = NULL; + const struct intel_crtc_state *crtc_state = NULL; if (new_conn_state->crtc != &crtc->base) continue; @@ -86,38 +86,40 @@ verify_connector_state(struct intel_atomic_state *state, } } -static void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv, - const struct intel_crtc_state *pipe_config) +static void intel_pipe_config_sanity_check(const struct intel_crtc_state *crtc_state) { - if (pipe_config->has_pch_encoder) { - int fdi_dotclock = intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config), - &pipe_config->fdi_m_n); - int dotclock = pipe_config->hw.adjusted_mode.crtc_clock; + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + + if (crtc_state->has_pch_encoder) { + int fdi_dotclock = intel_dotclock_calculate(intel_fdi_link_freq(i915, crtc_state), + &crtc_state->fdi_m_n); + int dotclock = crtc_state->hw.adjusted_mode.crtc_clock; /* * FDI already provided one idea for the dotclock. * Yell if the encoder disagrees. Allow for slight * rounding differences. */ - drm_WARN(&dev_priv->drm, abs(fdi_dotclock - dotclock) > 1, + drm_WARN(&i915->drm, abs(fdi_dotclock - dotclock) > 1, "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n", fdi_dotclock, dotclock); } } static void -verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_state *state) +verify_encoder_state(struct intel_atomic_state *state) { + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_encoder *encoder; struct drm_connector *connector; - struct drm_connector_state *old_conn_state, *new_conn_state; + const struct drm_connector_state *old_conn_state, *new_conn_state; int i; - for_each_intel_encoder(&dev_priv->drm, encoder) { + for_each_intel_encoder(&i915->drm, encoder) { bool enabled = false, found = false; enum pipe pipe; - drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s]\n", + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s]\n", encoder->base.base.id, encoder->base.name); @@ -132,7 +134,7 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat found = true; enabled = true; - I915_STATE_WARN(dev_priv, + I915_STATE_WARN(i915, new_conn_state->crtc != encoder->base.crtc, "connector's crtc doesn't match encoder crtc\n"); } @@ -140,7 +142,7 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat if (!found) continue; - I915_STATE_WARN(dev_priv, !!encoder->base.crtc != enabled, + I915_STATE_WARN(i915, !!encoder->base.crtc != enabled, "encoder's enabled state mismatch (expected %i, found %i)\n", !!encoder->base.crtc, enabled); @@ -148,7 +150,7 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat bool active; active = encoder->get_hw_state(encoder, &pipe); - I915_STATE_WARN(dev_priv, active, + I915_STATE_WARN(i915, active, "encoder detached but still enabled on pipe %c.\n", pipe_name(pipe)); } @@ -156,96 +158,98 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat } static void -verify_crtc_state(struct intel_crtc *crtc, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state) +verify_crtc_state(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_encoder *encoder; - struct intel_crtc_state *pipe_config = old_crtc_state; - struct drm_atomic_state *state = old_crtc_state->uapi.state; + struct drm_i915_private *i915 = to_i915(dev); + const struct intel_crtc_state *sw_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct intel_crtc_state *hw_crtc_state; struct intel_crtc *master_crtc; + struct intel_encoder *encoder; - __drm_atomic_helper_crtc_destroy_state(&old_crtc_state->uapi); - intel_crtc_free_hw_state(old_crtc_state); - intel_crtc_state_reset(old_crtc_state, crtc); - old_crtc_state->uapi.state = state; + hw_crtc_state = intel_crtc_state_alloc(crtc); + if (!hw_crtc_state) + return; - drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s]\n", crtc->base.base.id, + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s]\n", crtc->base.base.id, crtc->base.name); - pipe_config->hw.enable = new_crtc_state->hw.enable; + hw_crtc_state->hw.enable = sw_crtc_state->hw.enable; - intel_crtc_get_pipe_config(pipe_config); + intel_crtc_get_pipe_config(hw_crtc_state); /* we keep both pipes enabled on 830 */ - if (IS_I830(dev_priv) && pipe_config->hw.active) - pipe_config->hw.active = new_crtc_state->hw.active; + if (IS_I830(i915) && hw_crtc_state->hw.active) + hw_crtc_state->hw.active = sw_crtc_state->hw.active; - I915_STATE_WARN(dev_priv, - new_crtc_state->hw.active != pipe_config->hw.active, + I915_STATE_WARN(i915, + sw_crtc_state->hw.active != hw_crtc_state->hw.active, "crtc active state doesn't match with hw state (expected %i, found %i)\n", - new_crtc_state->hw.active, pipe_config->hw.active); + sw_crtc_state->hw.active, hw_crtc_state->hw.active); - I915_STATE_WARN(dev_priv, crtc->active != new_crtc_state->hw.active, + I915_STATE_WARN(i915, crtc->active != sw_crtc_state->hw.active, "transitional active state does not match atomic hw state (expected %i, found %i)\n", - new_crtc_state->hw.active, crtc->active); + sw_crtc_state->hw.active, crtc->active); - master_crtc = intel_master_crtc(new_crtc_state); + master_crtc = intel_master_crtc(sw_crtc_state); for_each_encoder_on_crtc(dev, &master_crtc->base, encoder) { enum pipe pipe; bool active; active = encoder->get_hw_state(encoder, &pipe); - I915_STATE_WARN(dev_priv, active != new_crtc_state->hw.active, + I915_STATE_WARN(i915, active != sw_crtc_state->hw.active, "[ENCODER:%i] active %i with crtc active %i\n", encoder->base.base.id, active, - new_crtc_state->hw.active); + sw_crtc_state->hw.active); - I915_STATE_WARN(dev_priv, active && master_crtc->pipe != pipe, + I915_STATE_WARN(i915, active && master_crtc->pipe != pipe, "Encoder connected to wrong pipe %c\n", pipe_name(pipe)); if (active) - intel_encoder_get_config(encoder, pipe_config); + intel_encoder_get_config(encoder, hw_crtc_state); } - if (!new_crtc_state->hw.active) - return; + if (!sw_crtc_state->hw.active) + goto destroy_state; - intel_pipe_config_sanity_check(dev_priv, pipe_config); + intel_pipe_config_sanity_check(hw_crtc_state); - if (!intel_pipe_config_compare(new_crtc_state, - pipe_config, false)) { - I915_STATE_WARN(dev_priv, 1, "pipe state doesn't match!\n"); - intel_crtc_state_dump(pipe_config, NULL, "hw state"); - intel_crtc_state_dump(new_crtc_state, NULL, "sw state"); + if (!intel_pipe_config_compare(sw_crtc_state, + hw_crtc_state, false)) { + I915_STATE_WARN(i915, 1, "pipe state doesn't match!\n"); + intel_crtc_state_dump(hw_crtc_state, NULL, "hw state"); + intel_crtc_state_dump(sw_crtc_state, NULL, "sw state"); } + +destroy_state: + intel_crtc_destroy_state(&crtc->base, &hw_crtc_state->uapi); } -void intel_modeset_verify_crtc(struct intel_crtc *crtc, - struct intel_atomic_state *state, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state) +void intel_modeset_verify_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) { + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + if (!intel_crtc_needs_modeset(new_crtc_state) && !intel_crtc_needs_fastset(new_crtc_state)) return; - intel_wm_state_verify(crtc, new_crtc_state); + intel_wm_state_verify(state, crtc); verify_connector_state(state, crtc); - verify_crtc_state(crtc, old_crtc_state, new_crtc_state); - intel_shared_dpll_state_verify(crtc, old_crtc_state, new_crtc_state); - intel_mpllb_state_verify(state, new_crtc_state); - intel_c10pll_state_verify(state, new_crtc_state); + verify_crtc_state(state, crtc); + intel_shared_dpll_state_verify(state, crtc); + intel_mpllb_state_verify(state, crtc); + intel_c10pll_state_verify(state, crtc); } -void intel_modeset_verify_disabled(struct drm_i915_private *dev_priv, - struct intel_atomic_state *state) +void intel_modeset_verify_disabled(struct intel_atomic_state *state) { - verify_encoder_state(dev_priv, state); + verify_encoder_state(state); verify_connector_state(state, NULL); - intel_shared_dpll_verify_disabled(dev_priv); + intel_shared_dpll_verify_disabled(state); } diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.h b/drivers/gpu/drm/i915/display/intel_modeset_verify.h index 2d6fbe4f7846..3bef8735cb4b 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.h +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.h @@ -6,16 +6,11 @@ #ifndef __INTEL_MODESET_VERIFY_H__ #define __INTEL_MODESET_VERIFY_H__ -struct drm_i915_private; struct intel_atomic_state; struct intel_crtc; -struct intel_crtc_state; -void intel_modeset_verify_crtc(struct intel_crtc *crtc, - struct intel_atomic_state *state, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state); -void intel_modeset_verify_disabled(struct drm_i915_private *dev_priv, - struct intel_atomic_state *state); +void intel_modeset_verify_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc); +void intel_modeset_verify_disabled(struct intel_atomic_state *state); #endif /* __INTEL_MODESET_VERIFY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index 09c1aa1427ad..2b1392d5a902 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -29,12 +29,14 @@ #include <drm/drm_fourcc.h> #include "gem/i915_gem_internal.h" +#include "gem/i915_gem_object_frontbuffer.h" #include "gem/i915_gem_pm.h" #include "gt/intel_gpu_commands.h" #include "gt/intel_ring.h" #include "i915_drv.h" #include "i915_reg.h" +#include "intel_color_regs.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_frontbuffer.h" diff --git a/drivers/gpu/drm/i915/display/intel_overlay.h b/drivers/gpu/drm/i915/display/intel_overlay.h index a167c28acd27..c3f68fce6f08 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.h +++ b/drivers/gpu/drm/i915/display/intel_overlay.h @@ -13,6 +13,7 @@ struct drm_i915_private; struct intel_overlay; struct intel_overlay_error_state; +#ifdef I915 void intel_overlay_setup(struct drm_i915_private *dev_priv); void intel_overlay_cleanup(struct drm_i915_private *dev_priv); int intel_overlay_switch_off(struct intel_overlay *overlay); @@ -25,5 +26,39 @@ struct intel_overlay_error_state * intel_overlay_capture_error_state(struct drm_i915_private *dev_priv); void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e, struct intel_overlay_error_state *error); +#else +static inline void intel_overlay_setup(struct drm_i915_private *dev_priv) +{ +} +static inline void intel_overlay_cleanup(struct drm_i915_private *dev_priv) +{ +} +static inline int intel_overlay_switch_off(struct intel_overlay *overlay) +{ + return 0; +} +static inline int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} +static inline int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} +static inline void intel_overlay_reset(struct drm_i915_private *dev_priv) +{ +} +static inline struct intel_overlay_error_state * +intel_overlay_capture_error_state(struct drm_i915_private *dev_priv) +{ + return NULL; +} +static inline void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e, + struct intel_overlay_error_state *error) +{ +} +#endif #endif /* __INTEL_OVERLAY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 9232a305b1e6..483beedac5b8 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -59,15 +59,6 @@ intel_panel_preferred_fixed_mode(struct intel_connector *connector) struct drm_display_mode, head); } -static bool is_in_vrr_range(struct intel_connector *connector, int vrefresh) -{ - const struct drm_display_info *info = &connector->base.display_info; - - return intel_vrr_is_capable(connector) && - vrefresh >= info->monitor_range.min_vfreq && - vrefresh <= info->monitor_range.max_vfreq; -} - static bool is_best_fixed_mode(struct intel_connector *connector, int vrefresh, int fixed_mode_vrefresh, const struct drm_display_mode *best_mode) @@ -81,8 +72,8 @@ static bool is_best_fixed_mode(struct intel_connector *connector, * vrefresh, which we can then reduce to match the requested * vrefresh by extending the vblank length. */ - if (is_in_vrr_range(connector, vrefresh) && - is_in_vrr_range(connector, fixed_mode_vrefresh) && + if (intel_vrr_is_in_range(connector, vrefresh) && + intel_vrr_is_in_range(connector, fixed_mode_vrefresh) && fixed_mode_vrefresh < vrefresh) return false; @@ -224,8 +215,8 @@ int intel_panel_compute_config(struct intel_connector *connector, * Assume that we shouldn't muck about with the * timings if they don't land in the VRR range. */ - is_vrr = is_in_vrr_range(connector, vrefresh) && - is_in_vrr_range(connector, fixed_mode_vrefresh); + is_vrr = intel_vrr_is_in_range(connector, vrefresh) && + intel_vrr_is_in_range(connector, fixed_mode_vrefresh); if (!is_vrr) { /* @@ -689,7 +680,7 @@ intel_panel_detect(struct drm_connector *connector, bool force) { struct drm_i915_private *i915 = to_i915(connector->dev); - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; return connector_status_connected; diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.h b/drivers/gpu/drm/i915/display/intel_pch_display.h index 41a63413cb3d..35f8288af3d1 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_display.h +++ b/drivers/gpu/drm/i915/display/intel_pch_display.h @@ -15,6 +15,7 @@ struct intel_crtc; struct intel_crtc_state; struct intel_link_m_n; +#ifdef I915 bool intel_has_pch_trancoder(struct drm_i915_private *i915, enum pipe pch_transcoder); enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc); @@ -41,5 +42,57 @@ void intel_pch_transcoder_get_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n); void intel_pch_sanitize(struct drm_i915_private *i915); +#else +static inline bool intel_has_pch_trancoder(struct drm_i915_private *i915, + enum pipe pch_transcoder) +{ + return false; +} +static inline int intel_crtc_pch_transcoder(struct intel_crtc *crtc) +{ + return 0; +} +static inline void ilk_pch_pre_enable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void ilk_pch_enable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void ilk_pch_disable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void ilk_pch_post_disable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void ilk_pch_get_config(struct intel_crtc_state *crtc_state) +{ +} +static inline void lpt_pch_enable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void lpt_pch_disable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void lpt_pch_get_config(struct intel_crtc_state *crtc_state) +{ +} +static inline void intel_pch_transcoder_get_m1_n1(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ +} +static inline void intel_pch_transcoder_get_m2_n2(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ +} +static inline void intel_pch_sanitize(struct drm_i915_private *i915) +{ +} +#endif #endif diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.c b/drivers/gpu/drm/i915/display/intel_pch_refclk.c index 9583e86b602a..713cfba71475 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_refclk.c +++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.c @@ -492,6 +492,7 @@ static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv) static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv) { struct intel_encoder *encoder; + struct intel_shared_dpll *pll; int i; u32 val, final; bool has_lvds = false; @@ -527,8 +528,10 @@ static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv) } /* Check if any DPLLs are using the SSC source */ - for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) { - u32 temp = intel_de_read(dev_priv, PCH_DPLL(i)); + for_each_shared_dpll(dev_priv, pll, i) { + u32 temp; + + temp = intel_de_read(dev_priv, PCH_DPLL(pll->info->id)); if (!(temp & DPLL_VCO_ENABLE)) continue; diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.h b/drivers/gpu/drm/i915/display/intel_pch_refclk.h index 9bcf56629f24..ae3403c0ced8 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_refclk.h +++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.h @@ -11,6 +11,7 @@ struct drm_i915_private; struct intel_crtc_state; +#ifdef I915 void lpt_program_iclkip(const struct intel_crtc_state *crtc_state); void lpt_disable_iclkip(struct drm_i915_private *dev_priv); int lpt_get_iclkip(struct drm_i915_private *dev_priv); @@ -18,5 +19,27 @@ int lpt_iclkip(const struct intel_crtc_state *crtc_state); void intel_init_pch_refclk(struct drm_i915_private *dev_priv); void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv); +#else +static inline void lpt_program_iclkip(const struct intel_crtc_state *crtc_state) +{ +} +static inline void lpt_disable_iclkip(struct drm_i915_private *dev_priv) +{ +} +static inline int lpt_get_iclkip(struct drm_i915_private *dev_priv) +{ + return 0; +} +static inline int lpt_iclkip(const struct intel_crtc_state *crtc_state) +{ + return 0; +} +static inline void intel_init_pch_refclk(struct drm_i915_private *dev_priv) +{ +} +static inline void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv) +{ +} +#endif #endif diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index 736072a8b2b0..451a642e106e 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -9,6 +9,7 @@ #include "intel_display.h" #include "intel_display_types.h" #include "intel_fb.h" +#include "intel_frontbuffer.h" #include "intel_plane_initial.h" static bool diff --git a/drivers/gpu/drm/i915/display/intel_pmdemand.c b/drivers/gpu/drm/i915/display/intel_pmdemand.c index f7608d363634..744e332fa2af 100644 --- a/drivers/gpu/drm/i915/display/intel_pmdemand.c +++ b/drivers/gpu/drm/i915/display/intel_pmdemand.c @@ -92,7 +92,7 @@ int intel_pmdemand_init(struct drm_i915_private *i915) &pmdemand_state->base, &intel_pmdemand_funcs); - if (IS_MTL_DISPLAY_STEP(i915, STEP_A0, STEP_C0)) + if (IS_DISPLAY_IP_STEP(i915, IP_VER(14, 0), STEP_A0, STEP_C0)) /* Wa_14016740474 */ intel_de_rmw(i915, XELPD_CHICKEN_DCPR_3, 0, DMD_RSP_TIMEOUT_DISABLE); diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 97d5eef10130..bb65881e87cc 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -23,6 +23,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> +#include <drm/drm_debugfs.h> #include "i915_drv.h" #include "i915_reg.h" @@ -32,6 +33,7 @@ #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_aux.h" +#include "intel_frontbuffer.h" #include "intel_hdmi.h" #include "intel_psr.h" #include "intel_psr_regs.h" @@ -1360,8 +1362,7 @@ static void wm_optimization_wa(struct intel_dp *intel_dp, bool set_wa_bit = false; /* Wa_14015648006 */ - if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) || - IS_DISPLAY_VER(dev_priv, 11, 13)) + if (IS_DISPLAY_VER(dev_priv, 11, 14)) set_wa_bit |= crtc_state->wm_level_disabled; /* Wa_16013835468 */ @@ -1447,7 +1448,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, * All supported adlp panels have 1-based X granularity, this may * cause issues if non-supported panels are used. */ - if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) + if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(cpu_transcoder), 0, ADLP_1_BASED_X_GRANULARITY); else if (IS_ALDERLAKE_P(dev_priv)) @@ -1455,7 +1456,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, ADLP_1_BASED_X_GRANULARITY); /* Wa_16012604467:adlp,mtl[a0,b0] */ - if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) + if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) intel_de_rmw(dev_priv, MTL_CLKGATE_DIS_TRANS(cpu_transcoder), 0, MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS); @@ -1613,7 +1614,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) if (intel_dp->psr.psr2_enabled) { /* Wa_16012604467:adlp,mtl[a0,b0] */ - if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) + if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) intel_de_rmw(dev_priv, MTL_CLKGATE_DIS_TRANS(cpu_transcoder), MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS, 0); @@ -2087,7 +2088,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, goto skip_sel_fetch_set_loop; /* Wa_14014971492 */ - if ((IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) || + if ((IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0) || IS_ALDERLAKE_P(dev_priv) || IS_TIGERLAKE(dev_priv)) && crtc_state->splitter.enable) pipe_clip.y1 = 0; @@ -2194,10 +2195,12 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state, } } -static void _intel_psr_post_plane_update(const struct intel_atomic_state *state, - const struct intel_crtc_state *crtc_state) +void intel_psr_post_plane_update(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); + const struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); struct intel_encoder *encoder; if (!crtc_state->has_psr) @@ -2230,24 +2233,16 @@ static void _intel_psr_post_plane_update(const struct intel_atomic_state *state, if (crtc_state->crc_enabled && psr->enabled) psr_force_hw_tracking_exit(intel_dp); + /* + * Clear possible busy bits in case we have + * invalidate -> flip -> flush sequence. + */ + intel_dp->psr.busy_frontbuffer_bits = 0; + mutex_unlock(&psr->lock); } } -void intel_psr_post_plane_update(const struct intel_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - struct intel_crtc_state *crtc_state; - struct intel_crtc *crtc; - int i; - - if (!HAS_PSR(dev_priv)) - return; - - for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) - _intel_psr_post_plane_update(state, crtc_state); -} - static int _psr2_ready_for_pipe_update_locked(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -3153,7 +3148,7 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) }; const char *str; int ret; - u8 val; + u8 status, error_status; if (!CAN_PSR(intel_dp)) { seq_puts(m, "PSR Unsupported\n"); @@ -3163,19 +3158,34 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) if (connector->base.status != connector_status_connected) return -ENODEV; - ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val); - if (ret != 1) - return ret < 0 ? ret : -EIO; + ret = psr_get_status_and_error_status(intel_dp, &status, &error_status); + if (ret) + return ret; - val &= DP_PSR_SINK_STATE_MASK; - if (val < ARRAY_SIZE(sink_status)) - str = sink_status[val]; + status &= DP_PSR_SINK_STATE_MASK; + if (status < ARRAY_SIZE(sink_status)) + str = sink_status[status]; else str = "unknown"; - seq_printf(m, "Sink PSR status: 0x%x [%s]\n", val, str); + seq_printf(m, "Sink PSR status: 0x%x [%s]\n", status, str); - return 0; + seq_printf(m, "Sink PSR error status: 0x%x", error_status); + + if (error_status & (DP_PSR_RFB_STORAGE_ERROR | + DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR | + DP_PSR_LINK_CRC_ERROR)) + seq_puts(m, ":\n"); + else + seq_puts(m, "\n"); + if (error_status & DP_PSR_RFB_STORAGE_ERROR) + seq_puts(m, "\tPSR RFB storage error\n"); + if (error_status & DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR) + seq_puts(m, "\tPSR VSC SDP uncorrectable error\n"); + if (error_status & DP_PSR_LINK_CRC_ERROR) + seq_puts(m, "\tPSR Link CRC error\n"); + + return ret; } DEFINE_SHOW_ATTRIBUTE(i915_psr_sink_status); diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 0b95e8aa615f..bf35f42df6bc 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -24,7 +24,8 @@ struct intel_plane_state; void intel_psr_init_dpcd(struct intel_dp *intel_dp); void intel_psr_pre_plane_update(struct intel_atomic_state *state, struct intel_crtc *crtc); -void intel_psr_post_plane_update(const struct intel_atomic_state *state); +void intel_psr_post_plane_update(struct intel_atomic_state *state, + struct intel_crtc *crtc); void intel_psr_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state); int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value); diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 7d25a64698e2..35137e978591 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -44,6 +44,7 @@ #include "intel_crtc.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_gmbus.h" #include "intel_hdmi.h" @@ -57,15 +58,16 @@ #define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1) #define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0) -#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\ - SDVO_TV_MASK) +#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK | SDVO_TV_MASK) -#define IS_TV(c) (c->output_flag & SDVO_TV_MASK) -#define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK) -#define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) -#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) -#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK)) +#define IS_TV(c) ((c)->output_flag & SDVO_TV_MASK) +#define IS_TMDS(c) ((c)->output_flag & SDVO_TMDS_MASK) +#define IS_LVDS(c) ((c)->output_flag & SDVO_LVDS_MASK) +#define IS_TV_OR_LVDS(c) ((c)->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) +#define IS_DIGITAL(c) ((c)->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK)) +#define HAS_DDC(c) ((c)->output_flag & (SDVO_RGB_MASK | SDVO_TMDS_MASK | \ + SDVO_LVDS_MASK)) static const char * const tv_format_names[] = { "NTSC_M" , "NTSC_J" , "NTSC_443", @@ -79,20 +81,25 @@ static const char * const tv_format_names[] = { #define TV_FORMAT_NUM ARRAY_SIZE(tv_format_names) +struct intel_sdvo; + +struct intel_sdvo_ddc { + struct i2c_adapter ddc; + struct intel_sdvo *sdvo; + u8 ddc_bus; +}; + struct intel_sdvo { struct intel_encoder base; struct i2c_adapter *i2c; u8 slave_addr; - struct i2c_adapter ddc; + struct intel_sdvo_ddc ddc[3]; /* Register for the SDVO device: SDVOB or SDVOC */ i915_reg_t sdvo_reg; - /* Active outputs controlled by this SDVO output */ - u16 controlled_output; - /* * Capabilities of the SDVO device returned by * intel_sdvo_get_capabilities() @@ -105,21 +112,10 @@ struct intel_sdvo { int pixel_clock_min, pixel_clock_max; /* - * For multiple function SDVO device, - * this is for current attached outputs. - */ - u16 attached_output; - - /* * Hotplug activation bits for this device */ u16 hotplug_active; - enum port port; - - /* DDC bus used by this SDVO encoder */ - u8 ddc_bus; - /* * the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd */ @@ -233,7 +229,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) return; } - if (intel_sdvo->port == PORT_B) + if (intel_sdvo->base.port == PORT_B) cval = intel_de_read(dev_priv, GEN3_SDVOC); else bval = intel_de_read(dev_priv, GEN3_SDVOB); @@ -410,7 +406,7 @@ static const char *sdvo_cmd_name(u8 cmd) return NULL; } -#define SDVO_NAME(svdo) ((svdo)->port == PORT_B ? "SDVOB" : "SDVOC") +#define SDVO_NAME(svdo) ((svdo)->base.port == PORT_B ? "SDVOB" : "SDVOC") static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, const void *args, int args_len) @@ -1224,12 +1220,13 @@ static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, const struct drm_display_mode *mode) { struct intel_sdvo_dtd output_dtd; if (!intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output)) + intel_sdvo_connector->output_flag)) return false; intel_sdvo_get_dtd_from_mode(&output_dtd, mode); @@ -1270,10 +1267,10 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, return true; } -static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) +static int i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) { struct drm_i915_private *dev_priv = to_i915(pipe_config->uapi.crtc->dev); - unsigned dotclock = pipe_config->port_clock; + unsigned int dotclock = pipe_config->hw.adjusted_mode.crtc_clock; struct dpll *clock = &pipe_config->dpll; /* @@ -1293,11 +1290,14 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) clock->m1 = 12; clock->m2 = 8; } else { - drm_WARN(&dev_priv->drm, 1, - "SDVO TV clock out of range: %i\n", dotclock); + drm_dbg_kms(&dev_priv->drm, + "SDVO TV clock out of range: %i\n", dotclock); + return -EINVAL; } pipe_config->clock_set = true; + + return 0; } static bool intel_has_hdmi_sink(struct intel_sdvo_connector *intel_sdvo_connector, @@ -1352,14 +1352,18 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct drm_display_mode *mode = &pipe_config->hw.mode; + if (HAS_PCH_SPLIT(to_i915(encoder->base.dev))) { + pipe_config->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(pipe_config)) + return -EINVAL; + } + DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n"); + /* FIXME: Don't increase pipe_bpp */ pipe_config->pipe_bpp = 8*3; pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - if (HAS_PCH_SPLIT(to_i915(encoder->base.dev))) - pipe_config->has_pch_encoder = true; - /* * We need to construct preferred input timings based on our * output timings. To do that, we have to set the output @@ -1367,7 +1371,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, * the sequence to do it. Oh well. */ if (IS_TV(intel_sdvo_connector)) { - if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, + intel_sdvo_connector, + mode)) return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, @@ -1385,7 +1391,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, if (ret) return ret; - if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, fixed_mode)) + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, + intel_sdvo_connector, + fixed_mode)) return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, @@ -1415,8 +1423,13 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, conn_state); /* Clock computation needs to happen after pixel multiplier. */ - if (IS_TV(intel_sdvo_connector)) - i9xx_adjust_sdvo_tv_clock(pipe_config); + if (IS_TV(intel_sdvo_connector)) { + int ret; + + ret = i9xx_adjust_sdvo_tv_clock(pipe_config); + if (ret) + return ret; + } if (conn_state->picture_aspect_ratio) adjusted_mode->picture_aspect_ratio = @@ -1521,7 +1534,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, * channel on the motherboard. In a two-input device, the first input * will be SDVOB and the second SDVOC. */ - in_out.in0 = intel_sdvo->attached_output; + in_out.in0 = intel_sdvo_connector->output_flag; in_out.in1 = 0; intel_sdvo_set_value(intel_sdvo, @@ -1530,7 +1543,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, /* Set the output timings to the screen */ if (!intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output)) + intel_sdvo_connector->output_flag)) return; /* lvds has a special fixed output timing. */ @@ -1598,7 +1611,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, sdvox |= SDVO_BORDER_ENABLE; } else { sdvox = intel_de_read(dev_priv, intel_sdvo->sdvo_reg); - if (intel_sdvo->port == PORT_B) + if (intel_sdvo->base.port == PORT_B) sdvox &= SDVOB_PRESERVE_MASK; else sdvox &= SDVOC_PRESERVE_MASK; @@ -1867,6 +1880,8 @@ static void intel_enable_sdvo(struct intel_atomic_state *state, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(conn_state->connector); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); u32 temp; bool input1, input2; @@ -1896,7 +1911,7 @@ static void intel_enable_sdvo(struct intel_atomic_state *state, if (0) intel_sdvo_set_encoder_power_state(intel_sdvo, DRM_MODE_DPMS_ON); - intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); + intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo_connector->output_flag); if (pipe_config->has_audio) intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state); @@ -1956,7 +1971,7 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in " device_rev_id: %d\n" " sdvo_version_major: %d\n" " sdvo_version_minor: %d\n" - " sdvo_inputs_mask: %d\n" + " sdvo_num_inputs: %d\n" " smooth_scaling: %d\n" " sharp_scaling: %d\n" " up_scaling: %d\n" @@ -1968,7 +1983,7 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in caps->device_rev_id, caps->sdvo_version_major, caps->sdvo_version_minor, - caps->sdvo_inputs_mask, + caps->sdvo_num_inputs, caps->smooth_scaling, caps->sharp_scaling, caps->up_scaling, @@ -2029,18 +2044,15 @@ intel_sdvo_hotplug(struct intel_encoder *encoder, return intel_encoder_hotplug(encoder, connector); } -static bool -intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) -{ - /* Is there more than one type of output? */ - return hweight16(intel_sdvo->caps.output_flags) > 1; -} - static const struct drm_edid * intel_sdvo_get_edid(struct drm_connector *connector) { - struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector)); - return drm_edid_read_ddc(connector, &sdvo->ddc); + struct i2c_adapter *ddc = connector->ddc; + + if (!ddc) + return NULL; + + return drm_edid_read_ddc(connector, ddc); } /* Mac mini hack -- use the same DDC as the analog connector */ @@ -2048,43 +2060,23 @@ static const struct drm_edid * intel_sdvo_get_analog_edid(struct drm_connector *connector) { struct drm_i915_private *i915 = to_i915(connector->dev); - struct i2c_adapter *i2c; + struct i2c_adapter *ddc; - i2c = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin); + ddc = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin); + if (!ddc) + return NULL; - return drm_edid_read_ddc(connector, i2c); + return drm_edid_read_ddc(connector, ddc); } static enum drm_connector_status intel_sdvo_tmds_sink_detect(struct drm_connector *connector) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); enum drm_connector_status status; const struct drm_edid *drm_edid; drm_edid = intel_sdvo_get_edid(connector); - if (!drm_edid && intel_sdvo_multifunc_encoder(intel_sdvo)) { - u8 ddc, saved_ddc = intel_sdvo->ddc_bus; - - /* - * Don't use the 1 as the argument of DDC bus switch to get - * the EDID. It is used for SDVO SPD ROM. - */ - for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { - intel_sdvo->ddc_bus = ddc; - drm_edid = intel_sdvo_get_edid(connector); - if (drm_edid) - break; - } - /* - * If we found the EDID on the other bus, - * assume that is the correct DDC bus. - */ - if (!drm_edid) - intel_sdvo->ddc_bus = saved_ddc; - } - /* * When there is no edid and no monitor is connected with VGA * port, try to use the CRT ddc to read the EDID for DVI-connector. @@ -2094,10 +2086,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) status = connector_status_unknown; if (drm_edid) { - const struct edid *edid = drm_edid_raw(drm_edid); - /* DDC bus is shared, match EDID to connector type */ - if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) + if (drm_edid_is_digital(drm_edid)) status = connector_status_connected; else status = connector_status_disconnected; @@ -2111,8 +2101,7 @@ static bool intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo, const struct drm_edid *drm_edid) { - const struct edid *edid = drm_edid_raw(drm_edid); - bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); + bool monitor_is_digital = drm_edid_is_digital(drm_edid); bool connector_is_digital = !!IS_DIGITAL(sdvo); DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n", @@ -2132,9 +2121,13 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo_connector->output_flag)) + return connector_status_unknown; + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ATTACHED_DISPLAYS, &response, 2)) @@ -2147,8 +2140,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if (response == 0) return connector_status_disconnected; - intel_sdvo->attached_output = response; - if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; else if (IS_TMDS(intel_sdvo_connector)) @@ -2276,6 +2267,8 @@ static const struct drm_display_mode sdvo_tv_modes[] = { static int intel_sdvo_get_tv_modes(struct drm_connector *connector) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(connector); const struct drm_connector_state *conn_state = connector->state; struct intel_sdvo_sdtv_resolution_request tv_res; u32 reply = 0, format_map = 0; @@ -2293,7 +2286,7 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector) memcpy(&tv_res, &format_map, min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); - if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output)) + if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo_connector->output_flag)) return 0; BUILD_BUG_ON(sizeof(tv_res) != 3); @@ -2458,31 +2451,6 @@ intel_sdvo_connector_atomic_set_property(struct drm_connector *connector, return 0; } -static int -intel_sdvo_connector_register(struct drm_connector *connector) -{ - struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector)); - int ret; - - ret = intel_connector_register(connector); - if (ret) - return ret; - - return sysfs_create_link(&connector->kdev->kobj, - &sdvo->ddc.dev.kobj, - sdvo->ddc.dev.kobj.name); -} - -static void -intel_sdvo_connector_unregister(struct drm_connector *connector) -{ - struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector)); - - sysfs_remove_link(&connector->kdev->kobj, - sdvo->ddc.dev.kobj.name); - intel_connector_unregister(connector); -} - static struct drm_connector_state * intel_sdvo_connector_duplicate_state(struct drm_connector *connector) { @@ -2501,8 +2469,8 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .atomic_get_property = intel_sdvo_connector_atomic_get_property, .atomic_set_property = intel_sdvo_connector_atomic_set_property, - .late_register = intel_sdvo_connector_register, - .early_unregister = intel_sdvo_connector_unregister, + .late_register = intel_connector_register, + .early_unregister = intel_connector_unregister, .destroy = intel_connector_destroy, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = intel_sdvo_connector_duplicate_state, @@ -2539,29 +2507,37 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs .atomic_check = intel_sdvo_atomic_check, }; -static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) +static void intel_sdvo_encoder_destroy(struct drm_encoder *_encoder) { - struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder)); + struct intel_encoder *encoder = to_intel_encoder(_encoder); + struct intel_sdvo *sdvo = to_sdvo(encoder); + int i; - i2c_del_adapter(&intel_sdvo->ddc); - intel_encoder_destroy(encoder); -} + for (i = 0; i < ARRAY_SIZE(sdvo->ddc); i++) { + if (sdvo->ddc[i].ddc_bus) + i2c_del_adapter(&sdvo->ddc[i].ddc); + } + + drm_encoder_cleanup(&encoder->base); + kfree(sdvo); +}; static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { - .destroy = intel_sdvo_enc_destroy, + .destroy = intel_sdvo_encoder_destroy, }; -static void -intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) +static int +intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo, + struct intel_sdvo_connector *connector) { u16 mask = 0; - unsigned int num_bits; + int num_bits; /* * Make a mask of outputs less than or equal to our own priority in the * list. */ - switch (sdvo->controlled_output) { + switch (connector->output_flag) { case SDVO_OUTPUT_LVDS1: mask |= SDVO_OUTPUT_LVDS1; fallthrough; @@ -2590,7 +2566,7 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) num_bits = 3; /* Corresponds to SDVO_CONTROL_BUS_DDCx */ - sdvo->ddc_bus = 1 << num_bits; + return num_bits; } /* @@ -2600,31 +2576,38 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) * DDC bus number assignment is in a priority order of RGB outputs, then TMDS * outputs, then LVDS outputs. */ -static void -intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +static struct intel_sdvo_ddc * +intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo, + struct intel_sdvo_connector *connector) { - struct sdvo_device_mapping *mapping; + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); + const struct sdvo_device_mapping *mapping; + int ddc_bus; - if (sdvo->port == PORT_B) + if (sdvo->base.port == PORT_B) mapping = &dev_priv->display.vbt.sdvo_mappings[0]; else mapping = &dev_priv->display.vbt.sdvo_mappings[1]; if (mapping->initialized) - sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4); + ddc_bus = (mapping->ddc_pin & 0xf0) >> 4; else - intel_sdvo_guess_ddc_bus(sdvo); + ddc_bus = intel_sdvo_guess_ddc_bus(sdvo, connector); + + if (ddc_bus < 1 || ddc_bus > 3) + return NULL; + + return &sdvo->ddc[ddc_bus - 1]; } static void -intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo) { - struct sdvo_device_mapping *mapping; + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); + const struct sdvo_device_mapping *mapping; u8 pin; - if (sdvo->port == PORT_B) + if (sdvo->base.port == PORT_B) mapping = &dev_priv->display.vbt.sdvo_mappings[0]; else mapping = &dev_priv->display.vbt.sdvo_mappings[1]; @@ -2635,6 +2618,10 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, else pin = GMBUS_PIN_DPB; + drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] I2C pin %d, slave addr 0x%x\n", + sdvo->base.base.base.id, sdvo->base.base.name, + pin, sdvo->slave_addr); + sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); /* @@ -2659,12 +2646,12 @@ intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo) } static u8 -intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +intel_sdvo_get_slave_addr(struct intel_sdvo *sdvo) { - struct sdvo_device_mapping *my_mapping, *other_mapping; + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); + const struct sdvo_device_mapping *my_mapping, *other_mapping; - if (sdvo->port == PORT_B) { + if (sdvo->base.port == PORT_B) { my_mapping = &dev_priv->display.vbt.sdvo_mappings[0]; other_mapping = &dev_priv->display.vbt.sdvo_mappings[1]; } else { @@ -2691,28 +2678,36 @@ intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv, * No SDVO device info is found for another DVO port, * so use mapping assumption we had before BIOS parsing. */ - if (sdvo->port == PORT_B) + if (sdvo->base.port == PORT_B) return 0x70; else return 0x72; } static int +intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc, + struct intel_sdvo *sdvo, int bit); + +static int intel_sdvo_connector_init(struct intel_sdvo_connector *connector, struct intel_sdvo *encoder) { - struct drm_connector *drm_connector; + struct drm_i915_private *i915 = to_i915(encoder->base.base.dev); + struct intel_sdvo_ddc *ddc = NULL; int ret; - drm_connector = &connector->base.base; - ret = drm_connector_init(encoder->base.base.dev, - drm_connector, - &intel_sdvo_connector_funcs, - connector->base.base.connector_type); + if (HAS_DDC(connector)) + ddc = intel_sdvo_select_ddc_bus(encoder, connector); + + ret = drm_connector_init_with_ddc(encoder->base.base.dev, + &connector->base.base, + &intel_sdvo_connector_funcs, + connector->base.base.connector_type, + ddc ? &ddc->ddc : NULL); if (ret < 0) return ret; - drm_connector_helper_add(drm_connector, + drm_connector_helper_add(&connector->base.base, &intel_sdvo_connector_helper_funcs); connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; @@ -2721,6 +2716,11 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, intel_connector_attach_encoder(&connector->base, &encoder->base); + if (ddc) + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s\n", + connector->base.base.base.id, connector->base.base.name, + ddc->ddc.name); + return 0; } @@ -2918,7 +2918,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type) if (!intel_panel_preferred_fixed_mode(intel_connector)) { mutex_lock(&i915->drm.mode_config.mutex); - intel_ddc_get_modes(connector, &intel_sdvo->ddc); + intel_ddc_get_modes(connector, connector->ddc); intel_panel_add_edid_fixed_modes(intel_connector, false); mutex_unlock(&i915->drm.mode_config.mutex); @@ -2982,7 +2982,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) SDVO_OUTPUT_LVDS0, SDVO_OUTPUT_LVDS1, }; - struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev); u16 flags; int i; @@ -2994,10 +2993,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) return false; } - intel_sdvo->controlled_output = flags; - - intel_sdvo_select_ddc_bus(i915, intel_sdvo); - for (i = 0; i < ARRAY_SIZE(probe_order); i++) { u16 type = flags & probe_order[i]; @@ -3250,9 +3245,10 @@ static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; - if (!__intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus)) + if (!__intel_sdvo_set_control_bus_switch(sdvo, 1 << ddc->ddc_bus)) return -EIO; return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num); @@ -3260,7 +3256,9 @@ static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + return sdvo->i2c->algo->functionality(sdvo->i2c); } @@ -3272,21 +3270,27 @@ static const struct i2c_algorithm intel_sdvo_ddc_proxy = { static void proxy_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + sdvo->i2c->lock_ops->lock_bus(sdvo->i2c, flags); } static int proxy_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + return sdvo->i2c->lock_ops->trylock_bus(sdvo->i2c, flags); } static void proxy_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + sdvo->i2c->lock_ops->unlock_bus(sdvo->i2c, flags); } @@ -3296,21 +3300,26 @@ static const struct i2c_lock_operations proxy_lock_ops = { .unlock_bus = proxy_unlock_bus, }; -static bool -intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, - struct drm_i915_private *dev_priv) +static int +intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc, + struct intel_sdvo *sdvo, int ddc_bus) { + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - sdvo->ddc.owner = THIS_MODULE; - sdvo->ddc.class = I2C_CLASS_DDC; - snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); - sdvo->ddc.dev.parent = &pdev->dev; - sdvo->ddc.algo_data = sdvo; - sdvo->ddc.algo = &intel_sdvo_ddc_proxy; - sdvo->ddc.lock_ops = &proxy_lock_ops; + ddc->sdvo = sdvo; + ddc->ddc_bus = ddc_bus; - return i2c_add_adapter(&sdvo->ddc) == 0; + ddc->ddc.owner = THIS_MODULE; + ddc->ddc.class = I2C_CLASS_DDC; + snprintf(ddc->ddc.name, I2C_NAME_SIZE, "SDVO %c DDC%d", + port_name(sdvo->base.port), ddc_bus); + ddc->ddc.dev.parent = &pdev->dev; + ddc->ddc.algo_data = ddc; + ddc->ddc.algo = &intel_sdvo_ddc_proxy; + ddc->ddc.lock_ops = &proxy_lock_ops; + + return i2c_add_adapter(&ddc->ddc); } static bool is_sdvo_port_valid(struct drm_i915_private *dev_priv, enum port port) @@ -3345,23 +3354,21 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, if (!intel_sdvo) return false; - intel_sdvo->sdvo_reg = sdvo_reg; - intel_sdvo->port = port; - intel_sdvo->slave_addr = - intel_sdvo_get_slave_addr(dev_priv, intel_sdvo) >> 1; - intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo); - if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev_priv)) - goto err_i2c_bus; - /* encoder type will be decided later */ intel_encoder = &intel_sdvo->base; intel_encoder->type = INTEL_OUTPUT_SDVO; intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER; intel_encoder->port = port; + drm_encoder_init(&dev_priv->drm, &intel_encoder->base, &intel_sdvo_enc_funcs, 0, "SDVO %c", port_name(port)); + intel_sdvo->sdvo_reg = sdvo_reg; + intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(intel_sdvo) >> 1; + + intel_sdvo_select_i2c_bus(intel_sdvo); + /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { u8 byte; @@ -3393,6 +3400,15 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, intel_sdvo->colorimetry_cap = intel_sdvo_get_colorimetry_cap(intel_sdvo); + for (i = 0; i < ARRAY_SIZE(intel_sdvo->ddc); i++) { + int ret; + + ret = intel_sdvo_init_ddc_proxy(&intel_sdvo->ddc[i], + intel_sdvo, i + 1); + if (ret) + goto err; + } + if (!intel_sdvo_output_setup(intel_sdvo)) { drm_dbg_kms(&dev_priv->drm, "SDVO output failed to setup on %s\n", @@ -3406,7 +3422,7 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, * hotplug lines. */ if (intel_sdvo->hotplug_active) { - if (intel_sdvo->port == PORT_B) + if (intel_sdvo->base.port == PORT_B) intel_encoder->hpd_pin = HPD_SDVO_B; else intel_encoder->hpd_pin = HPD_SDVO_C; @@ -3433,15 +3449,14 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, drm_dbg_kms(&dev_priv->drm, "%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " - "input 1: %c, input 2: %c, " + "num inputs: %d, " "output 1: %c, output 2: %c\n", SDVO_NAME(intel_sdvo), intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id, intel_sdvo->caps.device_rev_id, intel_sdvo->pixel_clock_min / 1000, intel_sdvo->pixel_clock_max / 1000, - (intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', - (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + intel_sdvo->caps.sdvo_num_inputs, /* check currently supported outputs */ intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 | @@ -3454,13 +3469,9 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, err_output: intel_sdvo_output_cleanup(intel_sdvo); - err: - drm_encoder_cleanup(&intel_encoder->base); - i2c_del_adapter(&intel_sdvo->ddc); -err_i2c_bus: intel_sdvo_unselect_i2c_bus(intel_sdvo); - kfree(intel_sdvo); + intel_sdvo_encoder_destroy(&intel_encoder->base); return false; } diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.h b/drivers/gpu/drm/i915/display/intel_sdvo.h index 2868852c85f2..d1815b4103d4 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.h +++ b/drivers/gpu/drm/i915/display/intel_sdvo.h @@ -14,9 +14,22 @@ struct drm_i915_private; enum pipe; enum port; +#ifdef I915 bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv, i915_reg_t sdvo_reg, enum pipe *pipe); bool intel_sdvo_init(struct drm_i915_private *dev_priv, i915_reg_t reg, enum port port); +#else +static inline bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t sdvo_reg, enum pipe *pipe) +{ + return false; +} +static inline bool intel_sdvo_init(struct drm_i915_private *dev_priv, + i915_reg_t reg, enum port port) +{ + return false; +} +#endif #endif /* __INTEL_SDVO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_sdvo_regs.h b/drivers/gpu/drm/i915/display/intel_sdvo_regs.h index 74dc6c042b6e..54f099abefeb 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/display/intel_sdvo_regs.h @@ -57,7 +57,7 @@ struct intel_sdvo_caps { u8 device_rev_id; u8 sdvo_version_major; u8 sdvo_version_minor; - unsigned int sdvo_inputs_mask:2; + unsigned int sdvo_num_inputs:2; unsigned int smooth_scaling:1; unsigned int sharp_scaling:1; unsigned int up_scaling:1; diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index 88ef56b6e0fd..c0285365efae 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -1993,12 +1993,13 @@ int intel_snps_phy_check_hdmi_link_rate(int clock) } void intel_mpllb_state_verify(struct intel_atomic_state *state, - struct intel_crtc_state *new_crtc_state) + struct intel_crtc *crtc) { struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); struct intel_mpllb_state mpllb_hw_state = { 0 }; - struct intel_mpllb_state *mpllb_sw_state = &new_crtc_state->mpllb_state; - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + const struct intel_mpllb_state *mpllb_sw_state = &new_crtc_state->mpllb_state; struct intel_encoder *encoder; if (!IS_DG2(i915)) diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.h b/drivers/gpu/drm/i915/display/intel_snps_phy.h index 557ef820bc0b..515abf7c5902 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.h +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.h @@ -10,6 +10,7 @@ struct drm_i915_private; struct intel_atomic_state; +struct intel_crtc; struct intel_crtc_state; struct intel_encoder; struct intel_mpllb_state; @@ -33,6 +34,6 @@ int intel_snps_phy_check_hdmi_link_rate(int clock); void intel_snps_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_mpllb_state_verify(struct intel_atomic_state *state, - struct intel_crtc_state *new_crtc_state); + struct intel_crtc *crtc); #endif /* __INTEL_SNPS_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 25034bbf1445..1fb16510f750 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -45,6 +45,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_fb.h" +#include "intel_frontbuffer.h" #include "intel_sprite.h" static void i9xx_plane_linear_gamma(u16 gamma[8]) diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h index 91c6dca342b2..044a032e41b9 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.h +++ b/drivers/gpu/drm/i915/display/intel_sprite.h @@ -16,6 +16,7 @@ struct intel_crtc_state; struct intel_plane_state; enum pipe; +#ifdef I915 struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe, int plane); int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, @@ -29,5 +30,12 @@ int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); +#else +static inline struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv, + int pipe, int plane) +{ + return NULL; +} +#endif #endif /* __INTEL_SPRITE_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 3ebf41859043..37b0f8529b4f 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -260,7 +260,7 @@ assert_tc_port_power_enabled(struct intel_tc_port *tc) !intel_display_power_is_enabled(i915, tc_port_power_domain(tc))); } -u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) +static u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_tc_port *tc = to_tc_port(dig_port); @@ -290,7 +290,32 @@ u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port) DP_PIN_ASSIGNMENT_SHIFT(tc->phy_fia_idx); } -static int mtl_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port) +static int lnl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port); + intel_wakeref_t wakeref; + u32 val, pin_assignment; + + with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref) + val = intel_de_read(i915, TCSS_DDI_STATUS(tc_port)); + + pin_assignment = + REG_FIELD_GET(TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK, val); + + switch (pin_assignment) { + default: + MISSING_CASE(pin_assignment); + fallthrough; + case DP_PIN_ASSIGNMENT_D: + return 2; + case DP_PIN_ASSIGNMENT_C: + case DP_PIN_ASSIGNMENT_E: + return 4; + } +} + +static int mtl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); intel_wakeref_t wakeref; @@ -311,23 +336,12 @@ static int mtl_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_po } } -int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) +static int intel_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - struct intel_tc_port *tc = to_tc_port(dig_port); - enum phy phy = intel_port_to_phy(i915, dig_port->base.port); intel_wakeref_t wakeref; - u32 lane_mask; - - if (!intel_phy_is_tc(i915, phy) || tc->mode != TC_PORT_DP_ALT) - return 4; - - assert_tc_cold_blocked(tc); - - if (DISPLAY_VER(i915) >= 14) - return mtl_tc_port_get_pin_assignment_mask(dig_port); + u32 lane_mask = 0; - lane_mask = 0; with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref) lane_mask = intel_tc_port_get_lane_mask(dig_port); @@ -348,6 +362,26 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) } } +int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + struct intel_tc_port *tc = to_tc_port(dig_port); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); + + if (!intel_phy_is_tc(i915, phy) || tc->mode != TC_PORT_DP_ALT) + return 4; + + assert_tc_cold_blocked(tc); + + if (DISPLAY_VER(i915) >= 20) + return lnl_tc_port_get_max_lane_count(dig_port); + + if (DISPLAY_VER(i915) >= 14) + return mtl_tc_port_get_max_lane_count(dig_port); + + return intel_tc_port_get_max_lane_count(dig_port); +} + void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes) { @@ -583,7 +617,7 @@ static bool tc_phy_verify_legacy_or_dp_alt_mode(struct intel_tc_port *tc, struct intel_digital_port *dig_port = tc->dig_port; int max_lanes; - max_lanes = intel_tc_port_fia_max_lane_count(dig_port); + max_lanes = intel_tc_port_max_lane_count(dig_port); if (tc->mode == TC_PORT_LEGACY) { drm_WARN_ON(&i915->drm, max_lanes != 4); return true; diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 3b16491925fa..80a61e52850e 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -19,9 +19,8 @@ bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_encoder *encoder); bool intel_tc_port_connected_locked(struct intel_encoder *encoder); -u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port); u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port); -int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); +int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port); void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes); diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 36b479b46b60..31a79fdfc812 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1720,7 +1720,7 @@ intel_tv_detect(struct drm_connector *connector, drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] force=%d\n", connector->base.id, connector->name, force); - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; if (force) { diff --git a/drivers/gpu/drm/i915/display/intel_tv.h b/drivers/gpu/drm/i915/display/intel_tv.h index 44518575ec5c..f08827b8bf2b 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.h +++ b/drivers/gpu/drm/i915/display/intel_tv.h @@ -8,6 +8,12 @@ struct drm_i915_private; +#ifdef I915 void intel_tv_init(struct drm_i915_private *dev_priv); +#else +static inline void intel_tv_init(struct drm_i915_private *dev_priv) +{ +} +#endif #endif /* __INTEL_TV_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index f5659ebd08eb..2cec2abf9746 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -251,6 +251,20 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) return (position + crtc->scanline_offset) % vtotal; } +int intel_crtc_scanline_to_hw(struct intel_crtc *crtc, int scanline) +{ + const struct drm_vblank_crtc *vblank = + &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)]; + const struct drm_display_mode *mode = &vblank->hwmode; + int vtotal; + + vtotal = mode->crtc_vtotal; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vtotal /= 2; + + return (scanline + vtotal - crtc->scanline_offset) % vtotal; +} + static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, bool in_vblank_irq, int *vpos, int *hpos, diff --git a/drivers/gpu/drm/i915/display/intel_vblank.h b/drivers/gpu/drm/i915/display/intel_vblank.h index 08e706b29149..17636f140c71 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.h +++ b/drivers/gpu/drm/i915/display/intel_vblank.h @@ -22,5 +22,6 @@ void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc); void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc); void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state, bool vrr_enable); +int intel_crtc_scanline_to_hw(struct intel_crtc *crtc, int scanline); #endif /* __INTEL_VBLANK_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 9d76c2756784..6757dbae9ee5 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -80,13 +80,19 @@ calculate_rc_params(struct drm_dsc_config *vdsc_cfg) int bpc = vdsc_cfg->bits_per_component; int bpp = vdsc_cfg->bits_per_pixel >> 4; int qp_bpc_modifier = (bpc - 8) * 2; + int uncompressed_bpg_rate; + int first_line_bpg_offset; u32 res, buf_i, bpp_i; if (vdsc_cfg->slice_height >= 8) - vdsc_cfg->first_line_bpg_offset = - 12 + DIV_ROUND_UP((9 * min(34, vdsc_cfg->slice_height - 8)), 100); + first_line_bpg_offset = + 12 + (9 * min(34, vdsc_cfg->slice_height - 8)) / 100; else - vdsc_cfg->first_line_bpg_offset = 2 * (vdsc_cfg->slice_height - 1); + first_line_bpg_offset = 2 * (vdsc_cfg->slice_height - 1); + + uncompressed_bpg_rate = (3 * bpc + (vdsc_cfg->convert_rgb ? 0 : 2)) * 3; + vdsc_cfg->first_line_bpg_offset = clamp(first_line_bpg_offset, 0, + uncompressed_bpg_rate - 3 * bpp); /* * According to DSC 1.2 spec in Section 4.1 if native_420 is set: @@ -350,9 +356,14 @@ intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder) return POWER_DOMAIN_TRANSCODER_VDSC_PW2; } +static int intel_dsc_get_vdsc_per_pipe(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->dsc.dsc_split ? 2 : 1; +} + int intel_dsc_get_num_vdsc_instances(const struct intel_crtc_state *crtc_state) { - int num_vdsc_instances = (crtc_state->dsc.dsc_split) ? 2 : 1; + int num_vdsc_instances = intel_dsc_get_vdsc_per_pipe(crtc_state); if (crtc_state->bigjoiner_pipes) num_vdsc_instances *= 2; @@ -360,6 +371,43 @@ int intel_dsc_get_num_vdsc_instances(const struct intel_crtc_state *crtc_state) return num_vdsc_instances; } +static void intel_dsc_get_pps_reg(const struct intel_crtc_state *crtc_state, int pps, + i915_reg_t *dsc_reg, int dsc_reg_num) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + enum pipe pipe = crtc->pipe; + bool pipe_dsc; + + pipe_dsc = is_pipe_dsc(crtc, cpu_transcoder); + + if (dsc_reg_num >= 3) + MISSING_CASE(dsc_reg_num); + if (dsc_reg_num >= 2) + dsc_reg[1] = pipe_dsc ? ICL_DSC1_PPS(pipe, pps) : DSCC_PPS(pps); + if (dsc_reg_num >= 1) + dsc_reg[0] = pipe_dsc ? ICL_DSC0_PPS(pipe, pps) : DSCA_PPS(pps); +} + +static void intel_dsc_pps_write(const struct intel_crtc_state *crtc_state, + int pps, u32 pps_val) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + i915_reg_t dsc_reg[2]; + int i, vdsc_per_pipe, dsc_reg_num; + + vdsc_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); + dsc_reg_num = min_t(int, ARRAY_SIZE(dsc_reg), vdsc_per_pipe); + + drm_WARN_ON_ONCE(&i915->drm, dsc_reg_num < vdsc_per_pipe); + + intel_dsc_get_pps_reg(crtc_state, pps, dsc_reg, dsc_reg_num); + + for (i = 0; i < dsc_reg_num; i++) + intel_de_write(i915, dsc_reg[i], pps_val); +} + static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -367,359 +415,119 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum pipe pipe = crtc->pipe; - u32 pps_val = 0; + u32 pps_val; u32 rc_buf_thresh_dword[4]; u32 rc_range_params_dword[8]; int i = 0; int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); + int vdsc_instances_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); - /* Populate PICTURE_PARAMETER_SET_0 registers */ - pps_val = DSC_VER_MAJ | vdsc_cfg->dsc_version_minor << - DSC_VER_MIN_SHIFT | - vdsc_cfg->bits_per_component << DSC_BPC_SHIFT | - vdsc_cfg->line_buf_depth << DSC_LINE_BUF_DEPTH_SHIFT; + /* PPS 0 */ + pps_val = DSC_PPS0_VER_MAJOR(1) | + DSC_PPS0_VER_MINOR(vdsc_cfg->dsc_version_minor) | + DSC_PPS0_BPC(vdsc_cfg->bits_per_component) | + DSC_PPS0_LINE_BUF_DEPTH(vdsc_cfg->line_buf_depth); if (vdsc_cfg->dsc_version_minor == 2) { - pps_val |= DSC_ALT_ICH_SEL; + pps_val |= DSC_PPS0_ALT_ICH_SEL; if (vdsc_cfg->native_420) - pps_val |= DSC_NATIVE_420_ENABLE; + pps_val |= DSC_PPS0_NATIVE_420_ENABLE; if (vdsc_cfg->native_422) - pps_val |= DSC_NATIVE_422_ENABLE; + pps_val |= DSC_PPS0_NATIVE_422_ENABLE; } if (vdsc_cfg->block_pred_enable) - pps_val |= DSC_BLOCK_PREDICTION; + pps_val |= DSC_PPS0_BLOCK_PREDICTION; if (vdsc_cfg->convert_rgb) - pps_val |= DSC_COLOR_SPACE_CONVERSION; + pps_val |= DSC_PPS0_COLOR_SPACE_CONVERSION; if (vdsc_cfg->simple_422) - pps_val |= DSC_422_ENABLE; + pps_val |= DSC_PPS0_422_ENABLE; if (vdsc_cfg->vbr_enable) - pps_val |= DSC_VBR_ENABLE; + pps_val |= DSC_PPS0_VBR_ENABLE; drm_dbg_kms(&dev_priv->drm, "PPS0 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_0, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_0, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_0(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_0(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 0, pps_val); - /* Populate PICTURE_PARAMETER_SET_1 registers */ - pps_val = 0; - pps_val |= DSC_BPP(vdsc_cfg->bits_per_pixel); + /* PPS 1 */ + pps_val = DSC_PPS1_BPP(vdsc_cfg->bits_per_pixel); drm_dbg_kms(&dev_priv->drm, "PPS1 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_1, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_1, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_1(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 1, pps_val); - /* Populate PICTURE_PARAMETER_SET_2 registers */ - pps_val = 0; - pps_val |= DSC_PIC_HEIGHT(vdsc_cfg->pic_height) | - DSC_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances); + /* PPS 2 */ + pps_val = DSC_PPS2_PIC_HEIGHT(vdsc_cfg->pic_height) | + DSC_PPS2_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances); drm_dbg_kms(&dev_priv->drm, "PPS2 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_2, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_2, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_2(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_2(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 2, pps_val); - /* Populate PICTURE_PARAMETER_SET_3 registers */ - pps_val = 0; - pps_val |= DSC_SLICE_HEIGHT(vdsc_cfg->slice_height) | - DSC_SLICE_WIDTH(vdsc_cfg->slice_width); + /* PPS 3 */ + pps_val = DSC_PPS3_SLICE_HEIGHT(vdsc_cfg->slice_height) | + DSC_PPS3_SLICE_WIDTH(vdsc_cfg->slice_width); drm_dbg_kms(&dev_priv->drm, "PPS3 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_3, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_3, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_3(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_3(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 3, pps_val); - /* Populate PICTURE_PARAMETER_SET_4 registers */ - pps_val = 0; - pps_val |= DSC_INITIAL_XMIT_DELAY(vdsc_cfg->initial_xmit_delay) | - DSC_INITIAL_DEC_DELAY(vdsc_cfg->initial_dec_delay); + /* PPS 4 */ + pps_val = DSC_PPS4_INITIAL_XMIT_DELAY(vdsc_cfg->initial_xmit_delay) | + DSC_PPS4_INITIAL_DEC_DELAY(vdsc_cfg->initial_dec_delay); drm_dbg_kms(&dev_priv->drm, "PPS4 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_4, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_4, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_4(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_4(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 4, pps_val); - /* Populate PICTURE_PARAMETER_SET_5 registers */ - pps_val = 0; - pps_val |= DSC_SCALE_INC_INT(vdsc_cfg->scale_increment_interval) | - DSC_SCALE_DEC_INT(vdsc_cfg->scale_decrement_interval); + /* PPS 5 */ + pps_val = DSC_PPS5_SCALE_INC_INT(vdsc_cfg->scale_increment_interval) | + DSC_PPS5_SCALE_DEC_INT(vdsc_cfg->scale_decrement_interval); drm_dbg_kms(&dev_priv->drm, "PPS5 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_5, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_5, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_5(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 5, pps_val); - /* Populate PICTURE_PARAMETER_SET_6 registers */ - pps_val = 0; - pps_val |= DSC_INITIAL_SCALE_VALUE(vdsc_cfg->initial_scale_value) | - DSC_FIRST_LINE_BPG_OFFSET(vdsc_cfg->first_line_bpg_offset) | - DSC_FLATNESS_MIN_QP(vdsc_cfg->flatness_min_qp) | - DSC_FLATNESS_MAX_QP(vdsc_cfg->flatness_max_qp); + /* PPS 6 */ + pps_val = DSC_PPS6_INITIAL_SCALE_VALUE(vdsc_cfg->initial_scale_value) | + DSC_PPS6_FIRST_LINE_BPG_OFFSET(vdsc_cfg->first_line_bpg_offset) | + DSC_PPS6_FLATNESS_MIN_QP(vdsc_cfg->flatness_min_qp) | + DSC_PPS6_FLATNESS_MAX_QP(vdsc_cfg->flatness_max_qp); drm_dbg_kms(&dev_priv->drm, "PPS6 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_6, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_6, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_6(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 6, pps_val); - /* Populate PICTURE_PARAMETER_SET_7 registers */ - pps_val = 0; - pps_val |= DSC_SLICE_BPG_OFFSET(vdsc_cfg->slice_bpg_offset) | - DSC_NFL_BPG_OFFSET(vdsc_cfg->nfl_bpg_offset); + /* PPS 7 */ + pps_val = DSC_PPS7_SLICE_BPG_OFFSET(vdsc_cfg->slice_bpg_offset) | + DSC_PPS7_NFL_BPG_OFFSET(vdsc_cfg->nfl_bpg_offset); drm_dbg_kms(&dev_priv->drm, "PPS7 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_7, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_7, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_7(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_7(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 7, pps_val); - /* Populate PICTURE_PARAMETER_SET_8 registers */ - pps_val = 0; - pps_val |= DSC_FINAL_OFFSET(vdsc_cfg->final_offset) | - DSC_INITIAL_OFFSET(vdsc_cfg->initial_offset); + /* PPS 8 */ + pps_val = DSC_PPS8_FINAL_OFFSET(vdsc_cfg->final_offset) | + DSC_PPS8_INITIAL_OFFSET(vdsc_cfg->initial_offset); drm_dbg_kms(&dev_priv->drm, "PPS8 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_8, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_8, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_8(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_8(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 8, pps_val); - /* Populate PICTURE_PARAMETER_SET_9 registers */ - pps_val = 0; - pps_val |= DSC_RC_MODEL_SIZE(vdsc_cfg->rc_model_size) | - DSC_RC_EDGE_FACTOR(DSC_RC_EDGE_FACTOR_CONST); + /* PPS 9 */ + pps_val = DSC_PPS9_RC_MODEL_SIZE(vdsc_cfg->rc_model_size) | + DSC_PPS9_RC_EDGE_FACTOR(DSC_RC_EDGE_FACTOR_CONST); drm_dbg_kms(&dev_priv->drm, "PPS9 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_9, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_9, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_9(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_9(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 9, pps_val); - /* Populate PICTURE_PARAMETER_SET_10 registers */ - pps_val = 0; - pps_val |= DSC_RC_QUANT_INC_LIMIT0(vdsc_cfg->rc_quant_incr_limit0) | - DSC_RC_QUANT_INC_LIMIT1(vdsc_cfg->rc_quant_incr_limit1) | - DSC_RC_TARGET_OFF_HIGH(DSC_RC_TGT_OFFSET_HI_CONST) | - DSC_RC_TARGET_OFF_LOW(DSC_RC_TGT_OFFSET_LO_CONST); + /* PPS 10 */ + pps_val = DSC_PPS10_RC_QUANT_INC_LIMIT0(vdsc_cfg->rc_quant_incr_limit0) | + DSC_PPS10_RC_QUANT_INC_LIMIT1(vdsc_cfg->rc_quant_incr_limit1) | + DSC_PPS10_RC_TARGET_OFF_HIGH(DSC_RC_TGT_OFFSET_HI_CONST) | + DSC_PPS10_RC_TARGET_OFF_LOW(DSC_RC_TGT_OFFSET_LO_CONST); drm_dbg_kms(&dev_priv->drm, "PPS10 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_10, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - DSCC_PICTURE_PARAMETER_SET_10, pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_10(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_10(pipe), - pps_val); - } - - /* Populate Picture parameter set 16 */ - pps_val = 0; - pps_val |= DSC_SLICE_CHUNK_SIZE(vdsc_cfg->slice_chunk_size) | - DSC_SLICE_PER_LINE((vdsc_cfg->pic_width / num_vdsc_instances) / - vdsc_cfg->slice_width) | - DSC_SLICE_ROW_PER_FRAME(vdsc_cfg->pic_height / - vdsc_cfg->slice_height); + intel_dsc_pps_write(crtc_state, 10, pps_val); + + /* PPS 16 */ + pps_val = DSC_PPS16_SLICE_CHUNK_SIZE(vdsc_cfg->slice_chunk_size) | + DSC_PPS16_SLICE_PER_LINE((vdsc_cfg->pic_width / num_vdsc_instances) / + vdsc_cfg->slice_width) | + DSC_PPS16_SLICE_ROW_PER_FRAME(vdsc_cfg->pic_height / + vdsc_cfg->slice_height); drm_dbg_kms(&dev_priv->drm, "PPS16 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_16, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - DSCC_PICTURE_PARAMETER_SET_16, pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_16(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 16, pps_val); if (DISPLAY_VER(dev_priv) >= 14) { - /* Populate PICTURE_PARAMETER_SET_17 registers */ - pps_val = 0; - pps_val |= DSC_SL_BPG_OFFSET(vdsc_cfg->second_line_bpg_offset); + /* PPS 17 */ + pps_val = DSC_PPS17_SL_BPG_OFFSET(vdsc_cfg->second_line_bpg_offset); drm_dbg_kms(&dev_priv->drm, "PPS17 = 0x%08x\n", pps_val); - intel_de_write(dev_priv, - MTL_DSC0_PICTURE_PARAMETER_SET_17(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - MTL_DSC1_PICTURE_PARAMETER_SET_17(pipe), - pps_val); + intel_dsc_pps_write(crtc_state, 17, pps_val); - /* Populate PICTURE_PARAMETER_SET_18 registers */ - pps_val = 0; - pps_val |= DSC_NSL_BPG_OFFSET(vdsc_cfg->nsl_bpg_offset) | - DSC_SL_OFFSET_ADJ(vdsc_cfg->second_line_offset_adj); + /* PPS 18 */ + pps_val = DSC_PPS18_NSL_BPG_OFFSET(vdsc_cfg->nsl_bpg_offset) | + DSC_PPS18_SL_OFFSET_ADJ(vdsc_cfg->second_line_offset_adj); drm_dbg_kms(&dev_priv->drm, "PPS18 = 0x%08x\n", pps_val); - intel_de_write(dev_priv, - MTL_DSC0_PICTURE_PARAMETER_SET_18(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - MTL_DSC1_PICTURE_PARAMETER_SET_18(pipe), - pps_val); + intel_dsc_pps_write(crtc_state, 18, pps_val); } /* Populate the RC_BUF_THRESH registers */ @@ -740,7 +548,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) rc_buf_thresh_dword[2]); intel_de_write(dev_priv, DSCA_RC_BUF_THRESH_1_UDW, rc_buf_thresh_dword[3]); - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { intel_de_write(dev_priv, DSCC_RC_BUF_THRESH_0, rc_buf_thresh_dword[0]); intel_de_write(dev_priv, DSCC_RC_BUF_THRESH_0_UDW, @@ -759,7 +567,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) rc_buf_thresh_dword[2]); intel_de_write(dev_priv, ICL_DSC0_RC_BUF_THRESH_1_UDW(pipe), rc_buf_thresh_dword[3]); - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { intel_de_write(dev_priv, ICL_DSC1_RC_BUF_THRESH_0(pipe), rc_buf_thresh_dword[0]); @@ -805,7 +613,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) rc_range_params_dword[6]); intel_de_write(dev_priv, DSCA_RC_RANGE_PARAMETERS_3_UDW, rc_range_params_dword[7]); - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { intel_de_write(dev_priv, DSCC_RC_RANGE_PARAMETERS_0, rc_range_params_dword[0]); intel_de_write(dev_priv, @@ -848,7 +656,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) intel_de_write(dev_priv, ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe), rc_range_params_dword[7]); - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { intel_de_write(dev_priv, ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe), rc_range_params_dword[0]); @@ -954,6 +762,7 @@ void intel_dsc_enable(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 dss_ctl1_val = 0; u32 dss_ctl2_val = 0; + int vdsc_instances_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); if (!crtc_state->dsc.compression_enable) return; @@ -961,7 +770,7 @@ void intel_dsc_enable(const struct intel_crtc_state *crtc_state) intel_dsc_pps_configure(crtc_state); dss_ctl2_val |= LEFT_BRANCH_VDSC_ENABLE; - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE; dss_ctl1_val |= JOINER_ENABLE; } @@ -987,16 +796,168 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state) } } +static u32 intel_dsc_pps_read(struct intel_crtc_state *crtc_state, int pps, + bool *check_equal) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + i915_reg_t dsc_reg[2]; + int i, vdsc_per_pipe, dsc_reg_num; + u32 val = 0; + + vdsc_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); + dsc_reg_num = min_t(int, ARRAY_SIZE(dsc_reg), vdsc_per_pipe); + + drm_WARN_ON_ONCE(&i915->drm, dsc_reg_num < vdsc_per_pipe); + + intel_dsc_get_pps_reg(crtc_state, pps, dsc_reg, dsc_reg_num); + + if (check_equal) + *check_equal = true; + + for (i = 0; i < dsc_reg_num; i++) { + u32 tmp; + + tmp = intel_de_read(i915, dsc_reg[i]); + + if (i == 0) { + val = tmp; + } else if (check_equal && tmp != val) { + *check_equal = false; + break; + } else if (!check_equal) { + break; + } + } + + return val; +} + +static u32 intel_dsc_pps_read_and_verify(struct intel_crtc_state *crtc_state, int pps) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + u32 val; + bool all_equal; + + val = intel_dsc_pps_read(crtc_state, pps, &all_equal); + drm_WARN_ON(&i915->drm, !all_equal); + + return val; +} + +static void intel_dsc_get_pps_config(struct intel_crtc_state *crtc_state) +{ + struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); + u32 pps_temp; + + /* PPS 0 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 0); + + vdsc_cfg->bits_per_component = REG_FIELD_GET(DSC_PPS0_BPC_MASK, pps_temp); + vdsc_cfg->line_buf_depth = REG_FIELD_GET(DSC_PPS0_LINE_BUF_DEPTH_MASK, pps_temp); + vdsc_cfg->block_pred_enable = pps_temp & DSC_PPS0_BLOCK_PREDICTION; + vdsc_cfg->convert_rgb = pps_temp & DSC_PPS0_COLOR_SPACE_CONVERSION; + vdsc_cfg->simple_422 = pps_temp & DSC_PPS0_422_ENABLE; + vdsc_cfg->native_422 = pps_temp & DSC_PPS0_NATIVE_422_ENABLE; + vdsc_cfg->native_420 = pps_temp & DSC_PPS0_NATIVE_420_ENABLE; + vdsc_cfg->vbr_enable = pps_temp & DSC_PPS0_VBR_ENABLE; + + /* PPS 1 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 1); + + vdsc_cfg->bits_per_pixel = REG_FIELD_GET(DSC_PPS1_BPP_MASK, pps_temp); + + if (vdsc_cfg->native_420) + vdsc_cfg->bits_per_pixel >>= 1; + + crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4; + + /* PPS 2 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 2); + + vdsc_cfg->pic_width = REG_FIELD_GET(DSC_PPS2_PIC_WIDTH_MASK, pps_temp) * num_vdsc_instances; + vdsc_cfg->pic_height = REG_FIELD_GET(DSC_PPS2_PIC_HEIGHT_MASK, pps_temp); + + /* PPS 3 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 3); + + vdsc_cfg->slice_width = REG_FIELD_GET(DSC_PPS3_SLICE_WIDTH_MASK, pps_temp); + vdsc_cfg->slice_height = REG_FIELD_GET(DSC_PPS3_SLICE_HEIGHT_MASK, pps_temp); + + /* PPS 4 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 4); + + vdsc_cfg->initial_dec_delay = REG_FIELD_GET(DSC_PPS4_INITIAL_DEC_DELAY_MASK, pps_temp); + vdsc_cfg->initial_xmit_delay = REG_FIELD_GET(DSC_PPS4_INITIAL_XMIT_DELAY_MASK, pps_temp); + + /* PPS 5 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 5); + + vdsc_cfg->scale_decrement_interval = REG_FIELD_GET(DSC_PPS5_SCALE_DEC_INT_MASK, pps_temp); + vdsc_cfg->scale_increment_interval = REG_FIELD_GET(DSC_PPS5_SCALE_INC_INT_MASK, pps_temp); + + /* PPS 6 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 6); + + vdsc_cfg->initial_scale_value = REG_FIELD_GET(DSC_PPS6_INITIAL_SCALE_VALUE_MASK, pps_temp); + vdsc_cfg->first_line_bpg_offset = REG_FIELD_GET(DSC_PPS6_FIRST_LINE_BPG_OFFSET_MASK, pps_temp); + vdsc_cfg->flatness_min_qp = REG_FIELD_GET(DSC_PPS6_FLATNESS_MIN_QP_MASK, pps_temp); + vdsc_cfg->flatness_max_qp = REG_FIELD_GET(DSC_PPS6_FLATNESS_MAX_QP_MASK, pps_temp); + + /* PPS 7 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 7); + + vdsc_cfg->nfl_bpg_offset = REG_FIELD_GET(DSC_PPS7_NFL_BPG_OFFSET_MASK, pps_temp); + vdsc_cfg->slice_bpg_offset = REG_FIELD_GET(DSC_PPS7_SLICE_BPG_OFFSET_MASK, pps_temp); + + /* PPS 8 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 8); + + vdsc_cfg->initial_offset = REG_FIELD_GET(DSC_PPS8_INITIAL_OFFSET_MASK, pps_temp); + vdsc_cfg->final_offset = REG_FIELD_GET(DSC_PPS8_FINAL_OFFSET_MASK, pps_temp); + + /* PPS 9 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 9); + + vdsc_cfg->rc_model_size = REG_FIELD_GET(DSC_PPS9_RC_MODEL_SIZE_MASK, pps_temp); + + /* PPS 10 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 10); + + vdsc_cfg->rc_quant_incr_limit0 = REG_FIELD_GET(DSC_PPS10_RC_QUANT_INC_LIMIT0_MASK, pps_temp); + vdsc_cfg->rc_quant_incr_limit1 = REG_FIELD_GET(DSC_PPS10_RC_QUANT_INC_LIMIT1_MASK, pps_temp); + + /* PPS 16 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 16); + + vdsc_cfg->slice_chunk_size = REG_FIELD_GET(DSC_PPS16_SLICE_CHUNK_SIZE_MASK, pps_temp); + + if (DISPLAY_VER(i915) >= 14) { + /* PPS 17 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 17); + + vdsc_cfg->second_line_bpg_offset = REG_FIELD_GET(DSC_PPS17_SL_BPG_OFFSET_MASK, pps_temp); + + /* PPS 18 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 18); + + vdsc_cfg->nsl_bpg_offset = REG_FIELD_GET(DSC_PPS18_NSL_BPG_OFFSET_MASK, pps_temp); + vdsc_cfg->second_line_offset_adj = REG_FIELD_GET(DSC_PPS18_SL_OFFSET_ADJ_MASK, pps_temp); + } +} + void intel_dsc_get_config(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - enum pipe pipe = crtc->pipe; enum intel_display_power_domain power_domain; intel_wakeref_t wakeref; - u32 dss_ctl1, dss_ctl2, pps0 = 0, pps1 = 0; + u32 dss_ctl1, dss_ctl2; if (!intel_dsc_source_support(crtc_state)) return; @@ -1017,24 +978,7 @@ void intel_dsc_get_config(struct intel_crtc_state *crtc_state) crtc_state->dsc.dsc_split = (dss_ctl2 & RIGHT_BRANCH_VDSC_ENABLE) && (dss_ctl1 & JOINER_ENABLE); - /* FIXME: add more state readout as needed */ - - /* PPS0 & PPS1 */ - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - pps1 = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1); - } else { - pps0 = intel_de_read(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_0(pipe)); - pps1 = intel_de_read(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe)); - } - - vdsc_cfg->bits_per_pixel = pps1; - - if (pps0 & DSC_NATIVE_420_ENABLE) - vdsc_cfg->bits_per_pixel >>= 1; - - crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4; + intel_dsc_get_pps_config(crtc_state); out: intel_display_power_put(dev_priv, power_domain, wakeref); } diff --git a/drivers/gpu/drm/i915/display/intel_vdsc_regs.h b/drivers/gpu/drm/i915/display/intel_vdsc_regs.h index b71f00b5c761..64f440fdc22b 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc_regs.h +++ b/drivers/gpu/drm/i915/display/intel_vdsc_regs.h @@ -46,35 +46,13 @@ _ICL_PIPE_DSS_CTL2_PB, \ _ICL_PIPE_DSS_CTL2_PC) -/* MTL Display Stream Compression registers */ -#define _MTL_DSC0_PICTURE_PARAMETER_SET_17_PB 0x782B4 -#define _MTL_DSC1_PICTURE_PARAMETER_SET_17_PB 0x783B4 -#define _MTL_DSC0_PICTURE_PARAMETER_SET_17_PC 0x784B4 -#define _MTL_DSC1_PICTURE_PARAMETER_SET_17_PC 0x785B4 -#define MTL_DSC0_PICTURE_PARAMETER_SET_17(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _MTL_DSC0_PICTURE_PARAMETER_SET_17_PB, \ - _MTL_DSC0_PICTURE_PARAMETER_SET_17_PC) -#define MTL_DSC1_PICTURE_PARAMETER_SET_17(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _MTL_DSC1_PICTURE_PARAMETER_SET_17_PB, \ - _MTL_DSC1_PICTURE_PARAMETER_SET_17_PC) -#define DSC_SL_BPG_OFFSET(offset) ((offset) << 27) - -#define _MTL_DSC0_PICTURE_PARAMETER_SET_18_PB 0x782B8 -#define _MTL_DSC1_PICTURE_PARAMETER_SET_18_PB 0x783B8 -#define _MTL_DSC0_PICTURE_PARAMETER_SET_18_PC 0x784B8 -#define _MTL_DSC1_PICTURE_PARAMETER_SET_18_PC 0x785B8 -#define MTL_DSC0_PICTURE_PARAMETER_SET_18(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _MTL_DSC0_PICTURE_PARAMETER_SET_18_PB, \ - _MTL_DSC0_PICTURE_PARAMETER_SET_18_PC) -#define MTL_DSC1_PICTURE_PARAMETER_SET_18(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _MTL_DSC1_PICTURE_PARAMETER_SET_18_PB, \ - _MTL_DSC1_PICTURE_PARAMETER_SET_18_PC) -#define DSC_NSL_BPG_OFFSET(offset) ((offset) << 16) -#define DSC_SL_OFFSET_ADJ(offset) ((offset) << 0) - /* Icelake Display Stream Compression Registers */ #define DSCA_PICTURE_PARAMETER_SET_0 _MMIO(0x6B200) #define DSCC_PICTURE_PARAMETER_SET_0 _MMIO(0x6BA00) +#define _DSCA_PPS_0 0x6B200 +#define _DSCC_PPS_0 0x6BA00 +#define DSCA_PPS(pps) _MMIO(_DSCA_PPS_0 + (pps) * 4) +#define DSCC_PPS(pps) _MMIO(_DSCC_PPS_0 + (pps) * 4) #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB 0x78270 #define _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB 0x78370 #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC 0x78470 @@ -85,251 +63,128 @@ #define ICL_DSC1_PICTURE_PARAMETER_SET_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_0_PC) -#define DSC_NATIVE_422_ENABLE BIT(23) -#define DSC_NATIVE_420_ENABLE BIT(22) -#define DSC_ALT_ICH_SEL (1 << 20) -#define DSC_VBR_ENABLE (1 << 19) -#define DSC_422_ENABLE (1 << 18) -#define DSC_COLOR_SPACE_CONVERSION (1 << 17) -#define DSC_BLOCK_PREDICTION (1 << 16) -#define DSC_LINE_BUF_DEPTH_SHIFT 12 -#define DSC_BPC_SHIFT 8 -#define DSC_VER_MIN_SHIFT 4 -#define DSC_VER_MAJ (0x1 << 0) - -#define DSCA_PICTURE_PARAMETER_SET_1 _MMIO(0x6B204) -#define DSCC_PICTURE_PARAMETER_SET_1 _MMIO(0x6BA04) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_1_PB 0x78274 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_1_PB 0x78374 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_1_PC 0x78474 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_1_PC 0x78574 -#define ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_1_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_1_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_1_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_1_PC) -#define DSC_BPP(bpp) ((bpp) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_2 _MMIO(0x6B208) -#define DSCC_PICTURE_PARAMETER_SET_2 _MMIO(0x6BA08) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_2_PB 0x78278 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_2_PB 0x78378 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_2_PC 0x78478 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_2_PC 0x78578 -#define ICL_DSC0_PICTURE_PARAMETER_SET_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_2_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_2_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_2_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_2_PC) -#define DSC_PIC_WIDTH(pic_width) ((pic_width) << 16) -#define DSC_PIC_HEIGHT(pic_height) ((pic_height) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_3 _MMIO(0x6B20C) -#define DSCC_PICTURE_PARAMETER_SET_3 _MMIO(0x6BA0C) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_3_PB 0x7827C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_3_PB 0x7837C -#define _ICL_DSC0_PICTURE_PARAMETER_SET_3_PC 0x7847C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_3_PC 0x7857C -#define ICL_DSC0_PICTURE_PARAMETER_SET_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_3_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_3_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_3_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_3_PC) -#define DSC_SLICE_WIDTH(slice_width) ((slice_width) << 16) -#define DSC_SLICE_HEIGHT(slice_height) ((slice_height) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_4 _MMIO(0x6B210) -#define DSCC_PICTURE_PARAMETER_SET_4 _MMIO(0x6BA10) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_4_PB 0x78280 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_4_PB 0x78380 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_4_PC 0x78480 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_4_PC 0x78580 -#define ICL_DSC0_PICTURE_PARAMETER_SET_4(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_4_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_4_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_4(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_4_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_4_PC) -#define DSC_INITIAL_DEC_DELAY(dec_delay) ((dec_delay) << 16) -#define DSC_INITIAL_XMIT_DELAY(xmit_delay) ((xmit_delay) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_5 _MMIO(0x6B214) -#define DSCC_PICTURE_PARAMETER_SET_5 _MMIO(0x6BA14) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_5_PB 0x78284 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_5_PB 0x78384 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_5_PC 0x78484 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_5_PC 0x78584 -#define ICL_DSC0_PICTURE_PARAMETER_SET_5(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_5_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_5_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_5_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_5_PC) -#define DSC_SCALE_DEC_INT(scale_dec) ((scale_dec) << 16) -#define DSC_SCALE_INC_INT(scale_inc) ((scale_inc) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_6 _MMIO(0x6B218) -#define DSCC_PICTURE_PARAMETER_SET_6 _MMIO(0x6BA18) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_6_PB 0x78288 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_6_PB 0x78388 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_6_PC 0x78488 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_6_PC 0x78588 -#define ICL_DSC0_PICTURE_PARAMETER_SET_6(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_6_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_6_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_6_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_6_PC) -#define DSC_FLATNESS_MAX_QP(max_qp) ((max_qp) << 24) -#define DSC_FLATNESS_MIN_QP(min_qp) ((min_qp) << 16) -#define DSC_FIRST_LINE_BPG_OFFSET(offset) ((offset) << 8) -#define DSC_INITIAL_SCALE_VALUE(value) ((value) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_7 _MMIO(0x6B21C) -#define DSCC_PICTURE_PARAMETER_SET_7 _MMIO(0x6BA1C) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_7_PB 0x7828C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_7_PB 0x7838C -#define _ICL_DSC0_PICTURE_PARAMETER_SET_7_PC 0x7848C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_7_PC 0x7858C -#define ICL_DSC0_PICTURE_PARAMETER_SET_7(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_7_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_7_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_7(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_7_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_7_PC) -#define DSC_NFL_BPG_OFFSET(bpg_offset) ((bpg_offset) << 16) -#define DSC_SLICE_BPG_OFFSET(bpg_offset) ((bpg_offset) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_8 _MMIO(0x6B220) -#define DSCC_PICTURE_PARAMETER_SET_8 _MMIO(0x6BA20) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_8_PB 0x78290 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_8_PB 0x78390 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_8_PC 0x78490 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_8_PC 0x78590 -#define ICL_DSC0_PICTURE_PARAMETER_SET_8(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_8_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_8_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_8(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_8_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_8_PC) -#define DSC_INITIAL_OFFSET(initial_offset) ((initial_offset) << 16) -#define DSC_FINAL_OFFSET(final_offset) ((final_offset) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_9 _MMIO(0x6B224) -#define DSCC_PICTURE_PARAMETER_SET_9 _MMIO(0x6BA24) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_9_PB 0x78294 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_9_PB 0x78394 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_9_PC 0x78494 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_9_PC 0x78594 -#define ICL_DSC0_PICTURE_PARAMETER_SET_9(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_9_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_9_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_9(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_9_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_9_PC) -#define DSC_RC_EDGE_FACTOR(rc_edge_fact) ((rc_edge_fact) << 16) -#define DSC_RC_MODEL_SIZE(rc_model_size) ((rc_model_size) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_10 _MMIO(0x6B228) -#define DSCC_PICTURE_PARAMETER_SET_10 _MMIO(0x6BA28) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_10_PB 0x78298 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_10_PB 0x78398 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_10_PC 0x78498 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_10_PC 0x78598 -#define ICL_DSC0_PICTURE_PARAMETER_SET_10(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_10_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_10_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_10(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_10_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_10_PC) -#define DSC_RC_TARGET_OFF_LOW(rc_tgt_off_low) ((rc_tgt_off_low) << 20) -#define DSC_RC_TARGET_OFF_HIGH(rc_tgt_off_high) ((rc_tgt_off_high) << 16) -#define DSC_RC_QUANT_INC_LIMIT1(lim) ((lim) << 8) -#define DSC_RC_QUANT_INC_LIMIT0(lim) ((lim) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_11 _MMIO(0x6B22C) -#define DSCC_PICTURE_PARAMETER_SET_11 _MMIO(0x6BA2C) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_11_PB 0x7829C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_11_PB 0x7839C -#define _ICL_DSC0_PICTURE_PARAMETER_SET_11_PC 0x7849C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_11_PC 0x7859C -#define ICL_DSC0_PICTURE_PARAMETER_SET_11(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_11_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_11_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_11(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_11_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_11_PC) - -#define DSCA_PICTURE_PARAMETER_SET_12 _MMIO(0x6B260) -#define DSCC_PICTURE_PARAMETER_SET_12 _MMIO(0x6BA60) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_12_PB 0x782A0 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_12_PB 0x783A0 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_12_PC 0x784A0 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_12_PC 0x785A0 -#define ICL_DSC0_PICTURE_PARAMETER_SET_12(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_12_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_12_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_12(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_12_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_12_PC) - -#define DSCA_PICTURE_PARAMETER_SET_13 _MMIO(0x6B264) -#define DSCC_PICTURE_PARAMETER_SET_13 _MMIO(0x6BA64) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_13_PB 0x782A4 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_13_PB 0x783A4 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_13_PC 0x784A4 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_13_PC 0x785A4 -#define ICL_DSC0_PICTURE_PARAMETER_SET_13(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_13_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_13_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_13(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_13_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_13_PC) - -#define DSCA_PICTURE_PARAMETER_SET_14 _MMIO(0x6B268) -#define DSCC_PICTURE_PARAMETER_SET_14 _MMIO(0x6BA68) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_14_PB 0x782A8 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_14_PB 0x783A8 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_14_PC 0x784A8 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_14_PC 0x785A8 -#define ICL_DSC0_PICTURE_PARAMETER_SET_14(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_14_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_14_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_14(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_14_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_14_PC) - -#define DSCA_PICTURE_PARAMETER_SET_15 _MMIO(0x6B26C) -#define DSCC_PICTURE_PARAMETER_SET_15 _MMIO(0x6BA6C) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_15_PB 0x782AC -#define _ICL_DSC1_PICTURE_PARAMETER_SET_15_PB 0x783AC -#define _ICL_DSC0_PICTURE_PARAMETER_SET_15_PC 0x784AC -#define _ICL_DSC1_PICTURE_PARAMETER_SET_15_PC 0x785AC -#define ICL_DSC0_PICTURE_PARAMETER_SET_15(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_15_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_15_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_15(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_15_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_15_PC) - -#define DSCA_PICTURE_PARAMETER_SET_16 _MMIO(0x6B270) -#define DSCC_PICTURE_PARAMETER_SET_16 _MMIO(0x6BA70) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_16_PB 0x782B0 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB 0x783B0 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_16_PC 0x784B0 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_16_PC 0x785B0 -#define ICL_DSC0_PICTURE_PARAMETER_SET_16(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_16_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_16_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_16_PC) -#define DSC_SLICE_ROW_PER_FRAME(slice_row_per_frame) ((slice_row_per_frame) << 20) -#define DSC_SLICE_PER_LINE(slice_per_line) ((slice_per_line) << 16) -#define DSC_SLICE_CHUNK_SIZE(slice_chunk_size) ((slice_chunk_size) << 0) +#define _ICL_DSC0_PPS_0(pipe) _PICK_EVEN((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC) +#define _ICL_DSC1_PPS_0(pipe) _PICK_EVEN((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_0_PC) +#define ICL_DSC0_PPS(pipe, pps) _MMIO(_ICL_DSC0_PPS_0(pipe) + ((pps) * 4)) +#define ICL_DSC1_PPS(pipe, pps) _MMIO(_ICL_DSC1_PPS_0(pipe) + ((pps) * 4)) + +/* PPS 0 */ +#define DSC_PPS0_NATIVE_422_ENABLE REG_BIT(23) +#define DSC_PPS0_NATIVE_420_ENABLE REG_BIT(22) +#define DSC_PPS0_ALT_ICH_SEL REG_BIT(20) +#define DSC_PPS0_VBR_ENABLE REG_BIT(19) +#define DSC_PPS0_422_ENABLE REG_BIT(18) +#define DSC_PPS0_COLOR_SPACE_CONVERSION REG_BIT(17) +#define DSC_PPS0_BLOCK_PREDICTION REG_BIT(16) +#define DSC_PPS0_LINE_BUF_DEPTH_MASK REG_GENMASK(15, 12) +#define DSC_PPS0_LINE_BUF_DEPTH(depth) REG_FIELD_PREP(DSC_PPS0_LINE_BUF_DEPTH_MASK, depth) +#define DSC_PPS0_BPC_MASK REG_GENMASK(11, 8) +#define DSC_PPS0_BPC(bpc) REG_FIELD_PREP(DSC_PPS0_BPC_MASK, bpc) +#define DSC_PPS0_VER_MINOR_MASK REG_GENMASK(7, 4) +#define DSC_PPS0_VER_MINOR(minor) REG_FIELD_PREP(DSC_PPS0_VER_MINOR_MASK, minor) +#define DSC_PPS0_VER_MAJOR_MASK REG_GENMASK(3, 0) +#define DSC_PPS0_VER_MAJOR(major) REG_FIELD_PREP(DSC_PPS0_VER_MAJOR_MASK, major) + +/* PPS 1 */ +#define DSC_PPS1_BPP_MASK REG_GENMASK(9, 0) +#define DSC_PPS1_BPP(bpp) REG_FIELD_PREP(DSC_PPS1_BPP_MASK, bpp) + +/* PPS 2 */ +#define DSC_PPS2_PIC_WIDTH_MASK REG_GENMASK(31, 16) +#define DSC_PPS2_PIC_HEIGHT_MASK REG_GENMASK(15, 0) +#define DSC_PPS2_PIC_WIDTH(pic_width) REG_FIELD_PREP(DSC_PPS2_PIC_WIDTH_MASK, pic_width) +#define DSC_PPS2_PIC_HEIGHT(pic_height) REG_FIELD_PREP(DSC_PPS2_PIC_HEIGHT_MASK, pic_height) + +/* PPS 3 */ +#define DSC_PPS3_SLICE_WIDTH_MASK REG_GENMASK(31, 16) +#define DSC_PPS3_SLICE_HEIGHT_MASK REG_GENMASK(15, 0) +#define DSC_PPS3_SLICE_WIDTH(slice_width) REG_FIELD_PREP(DSC_PPS3_SLICE_WIDTH_MASK, slice_width) +#define DSC_PPS3_SLICE_HEIGHT(slice_height) REG_FIELD_PREP(DSC_PPS3_SLICE_HEIGHT_MASK, slice_height) + +/* PPS 4 */ +#define DSC_PPS4_INITIAL_DEC_DELAY_MASK REG_GENMASK(31, 16) +#define DSC_PPS4_INITIAL_XMIT_DELAY_MASK REG_GENMASK(9, 0) +#define DSC_PPS4_INITIAL_DEC_DELAY(dec_delay) REG_FIELD_PREP(DSC_PPS4_INITIAL_DEC_DELAY_MASK, \ + dec_delay) +#define DSC_PPS4_INITIAL_XMIT_DELAY(xmit_delay) REG_FIELD_PREP(DSC_PPS4_INITIAL_XMIT_DELAY_MASK, \ + xmit_delay) + +/* PPS 5 */ +#define DSC_PPS5_SCALE_DEC_INT_MASK REG_GENMASK(27, 16) +#define DSC_PPS5_SCALE_INC_INT_MASK REG_GENMASK(15, 0) +#define DSC_PPS5_SCALE_DEC_INT(scale_dec) REG_FIELD_PREP(DSC_PPS5_SCALE_DEC_INT_MASK, scale_dec) +#define DSC_PPS5_SCALE_INC_INT(scale_inc) REG_FIELD_PREP(DSC_PPS5_SCALE_INC_INT_MASK, scale_inc) + +/* PPS 6 */ +#define DSC_PPS6_FLATNESS_MAX_QP_MASK REG_GENMASK(28, 24) +#define DSC_PPS6_FLATNESS_MIN_QP_MASK REG_GENMASK(20, 16) +#define DSC_PPS6_FIRST_LINE_BPG_OFFSET_MASK REG_GENMASK(12, 8) +#define DSC_PPS6_INITIAL_SCALE_VALUE_MASK REG_GENMASK(5, 0) +#define DSC_PPS6_FLATNESS_MAX_QP(max_qp) REG_FIELD_PREP(DSC_PPS6_FLATNESS_MAX_QP_MASK, max_qp) +#define DSC_PPS6_FLATNESS_MIN_QP(min_qp) REG_FIELD_PREP(DSC_PPS6_FLATNESS_MIN_QP_MASK, min_qp) +#define DSC_PPS6_FIRST_LINE_BPG_OFFSET(offset) REG_FIELD_PREP(DSC_PPS6_FIRST_LINE_BPG_OFFSET_MASK, \ + offset) +#define DSC_PPS6_INITIAL_SCALE_VALUE(value) REG_FIELD_PREP(DSC_PPS6_INITIAL_SCALE_VALUE_MASK, \ + value) + +/* PPS 7 */ +#define DSC_PPS7_NFL_BPG_OFFSET_MASK REG_GENMASK(31, 16) +#define DSC_PPS7_SLICE_BPG_OFFSET_MASK REG_GENMASK(15, 0) +#define DSC_PPS7_NFL_BPG_OFFSET(bpg_offset) REG_FIELD_PREP(DSC_PPS7_NFL_BPG_OFFSET_MASK, bpg_offset) +#define DSC_PPS7_SLICE_BPG_OFFSET(bpg_offset) REG_FIELD_PREP(DSC_PPS7_SLICE_BPG_OFFSET_MASK, \ + bpg_offset) +/* PPS 8 */ +#define DSC_PPS8_INITIAL_OFFSET_MASK REG_GENMASK(31, 16) +#define DSC_PPS8_FINAL_OFFSET_MASK REG_GENMASK(15, 0) +#define DSC_PPS8_INITIAL_OFFSET(initial_offset) REG_FIELD_PREP(DSC_PPS8_INITIAL_OFFSET_MASK, \ + initial_offset) +#define DSC_PPS8_FINAL_OFFSET(final_offset) REG_FIELD_PREP(DSC_PPS8_FINAL_OFFSET_MASK, \ + final_offset) + +/* PPS 9 */ +#define DSC_PPS9_RC_EDGE_FACTOR_MASK REG_GENMASK(19, 16) +#define DSC_PPS9_RC_MODEL_SIZE_MASK REG_GENMASK(15, 0) +#define DSC_PPS9_RC_EDGE_FACTOR(rc_edge_fact) REG_FIELD_PREP(DSC_PPS9_RC_EDGE_FACTOR_MASK, \ + rc_edge_fact) +#define DSC_PPS9_RC_MODEL_SIZE(rc_model_size) REG_FIELD_PREP(DSC_PPS9_RC_MODEL_SIZE_MASK, \ + rc_model_size) + +/* PPS 10 */ +#define DSC_PPS10_RC_TGT_OFF_LOW_MASK REG_GENMASK(23, 20) +#define DSC_PPS10_RC_TGT_OFF_HIGH_MASK REG_GENMASK(19, 16) +#define DSC_PPS10_RC_QUANT_INC_LIMIT1_MASK REG_GENMASK(12, 8) +#define DSC_PPS10_RC_QUANT_INC_LIMIT0_MASK REG_GENMASK(4, 0) +#define DSC_PPS10_RC_TARGET_OFF_LOW(rc_tgt_off_low) REG_FIELD_PREP(DSC_PPS10_RC_TGT_OFF_LOW_MASK, \ + rc_tgt_off_low) +#define DSC_PPS10_RC_TARGET_OFF_HIGH(rc_tgt_off_high) REG_FIELD_PREP(DSC_PPS10_RC_TGT_OFF_HIGH_MASK, \ + rc_tgt_off_high) +#define DSC_PPS10_RC_QUANT_INC_LIMIT1(lim) REG_FIELD_PREP(DSC_PPS10_RC_QUANT_INC_LIMIT1_MASK, lim) +#define DSC_PPS10_RC_QUANT_INC_LIMIT0(lim) REG_FIELD_PREP(DSC_PPS10_RC_QUANT_INC_LIMIT0_MASK, lim) + +/* PPS 16 */ +#define DSC_PPS16_SLICE_ROW_PR_FRME_MASK REG_GENMASK(31, 20) +#define DSC_PPS16_SLICE_PER_LINE_MASK REG_GENMASK(18, 16) +#define DSC_PPS16_SLICE_CHUNK_SIZE_MASK REG_GENMASK(15, 0) +#define DSC_PPS16_SLICE_ROW_PER_FRAME(slice_row_per_frame) REG_FIELD_PREP(DSC_PPS16_SLICE_ROW_PR_FRME_MASK, \ + slice_row_per_frame) +#define DSC_PPS16_SLICE_PER_LINE(slice_per_line) REG_FIELD_PREP(DSC_PPS16_SLICE_PER_LINE_MASK, \ + slice_per_line) +#define DSC_PPS16_SLICE_CHUNK_SIZE(slice_chunk_size) REG_FIELD_PREP(DSC_PPS16_SLICE_CHUNK_SIZE_MASK, \ + slice_chunk_size) + +/* PPS 17 (MTL+) */ +#define DSC_PPS17_SL_BPG_OFFSET_MASK REG_GENMASK(31, 27) +#define DSC_PPS17_SL_BPG_OFFSET(offset) REG_FIELD_PREP(DSC_PPS17_SL_BPG_OFFSET_MASK, offset) + +/* PPS 18 (MTL+) */ +#define DSC_PPS18_NSL_BPG_OFFSET_MASK REG_GENMASK(31, 16) +#define DSC_PPS18_SL_OFFSET_ADJ_MASK REG_GENMASK(15, 0) +#define DSC_PPS18_NSL_BPG_OFFSET(offset) REG_FIELD_PREP(DSC_PPS18_NSL_BPG_OFFSET_MASK, offset) +#define DSC_PPS18_SL_OFFSET_ADJ(offset) REG_FIELD_PREP(DSC_PPS18_SL_OFFSET_ADJ_MASK, offset) /* Icelake Rate Control Buffer Threshold Registers */ #define DSCA_RC_BUF_THRESH_0 _MMIO(0x6B230) diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index 286a0bdd28c6..4b98833bfa8c 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -3,11 +3,9 @@ * Copyright © 2019 Intel Corporation */ -#include <linux/pci.h> #include <linux/vgaarb.h> #include <video/vga.h> - #include "soc/intel_gmch.h" #include "i915_drv.h" @@ -99,20 +97,6 @@ void intel_vga_reset_io_mem(struct drm_i915_private *i915) vga_put(pdev, VGA_RSRC_LEGACY_IO); } -static unsigned int -intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode) -{ - struct drm_i915_private *i915 = pdev_to_i915(pdev); - - intel_gmch_vga_set_state(i915, enable_decode); - - if (enable_decode) - return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; - else - return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; -} - int intel_vga_register(struct drm_i915_private *i915) { @@ -127,7 +111,7 @@ int intel_vga_register(struct drm_i915_private *i915) * then we do not take part in VGA arbitration and the * vga_client_register() fails with -ENODEV. */ - ret = vga_client_register(pdev, intel_vga_set_decode); + ret = vga_client_register(pdev, intel_gmch_vga_set_decode); if (ret && ret != -ENODEV) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 88e4759b538b..5d905f932cb4 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -42,6 +42,15 @@ bool intel_vrr_is_capable(struct intel_connector *connector) info->monitor_range.max_vfreq - info->monitor_range.min_vfreq > 10; } +bool intel_vrr_is_in_range(struct intel_connector *connector, int vrefresh) +{ + const struct drm_display_info *info = &connector->base.display_info; + + return intel_vrr_is_capable(connector) && + vrefresh >= info->monitor_range.min_vfreq && + vrefresh <= info->monitor_range.max_vfreq; +} + void intel_vrr_check_modeset(struct intel_atomic_state *state) { @@ -108,12 +117,17 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, const struct drm_display_info *info = &connector->base.display_info; int vmin, vmax; - if (!intel_vrr_is_capable(connector)) + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) return; - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + crtc_state->vrr.in_range = + intel_vrr_is_in_range(connector, drm_mode_vrefresh(adjusted_mode)); + if (!crtc_state->vrr.in_range) return; + if (HAS_LRR(i915)) + crtc_state->update_lrr = true; + vmin = DIV_ROUND_UP(adjusted_mode->crtc_clock * 1000, adjusted_mode->crtc_htotal * info->monitor_range.max_vfreq); vmax = adjusted_mode->crtc_clock * 1000 / diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h index de16960c4929..89937858200d 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.h +++ b/drivers/gpu/drm/i915/display/intel_vrr.h @@ -14,6 +14,7 @@ struct intel_connector; struct intel_crtc_state; bool intel_vrr_is_capable(struct intel_connector *connector); +bool intel_vrr_is_in_range(struct intel_connector *connector, int vrefresh); void intel_vrr_check_modeset(struct intel_atomic_state *state); void intel_vrr_compute_config(struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state); diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index ffc15d278a39..245a64332cc7 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -16,10 +16,12 @@ #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fbc.h" +#include "intel_frontbuffer.h" #include "intel_psr.h" #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_watermark.h" +#include "gt/intel_gt.h" #include "pxp/intel_pxp.h" static const u32 skl_plane_formats[] = { @@ -1245,7 +1247,7 @@ icl_plane_update_noarm(struct intel_plane *plane, } /* FLAT CCS doesn't need to program AUX_DIST */ - if (!HAS_FLAT_CCS(dev_priv)) + if (!HAS_FLAT_CCS(dev_priv) && DISPLAY_VER(dev_priv) < 20) intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), skl_plane_aux_dist(plane_state, color_plane)); @@ -1941,13 +1943,16 @@ static enum intel_fbc_id skl_fbc_id_for_pipe(enum pipe pipe) return pipe - PIPE_A + INTEL_FBC_A; } -static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv, +static bool skl_plane_has_fbc(struct drm_i915_private *i915, enum intel_fbc_id fbc_id, enum plane_id plane_id) { - if ((DISPLAY_RUNTIME_INFO(dev_priv)->fbc_mask & BIT(fbc_id)) == 0) + if ((DISPLAY_RUNTIME_INFO(i915)->fbc_mask & BIT(fbc_id)) == 0) return false; - return plane_id == PLANE_PRIMARY; + if (DISPLAY_VER(i915) >= 20) + return icl_is_hdr_plane(i915, plane_id); + else + return plane_id == PLANE_PRIMARY; } static struct intel_fbc *skl_plane_fbc(struct drm_i915_private *dev_priv, @@ -2168,11 +2173,6 @@ skl_plane_disable_flip_done(struct intel_plane *plane) static bool skl_plane_has_rc_ccs(struct drm_i915_private *i915, enum pipe pipe, enum plane_id plane_id) { - /* Wa_14017240301 */ - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) - return false; - /* Wa_22011186057 */ if (IS_ALDERLAKE_P(i915) && IS_DISPLAY_STEP(i915, STEP_A0, STEP_B0)) return false; @@ -2203,10 +2203,6 @@ static bool gen12_plane_has_mc_ccs(struct drm_i915_private *i915, if (IS_ALDERLAKE_P(i915) && IS_DISPLAY_STEP(i915, STEP_A0, STEP_B0)) return false; - /* Wa_14013215631 */ - if (IS_DG2_DISPLAY_STEP(i915, STEP_A0, STEP_C0)) - return false; - return plane_id < PLANE_SPRITE4; } diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 063929a42a42..99b8ccdc3dfa 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1367,7 +1367,7 @@ skl_total_relative_data_rate(const struct intel_crtc_state *crtc_state) u64 data_rate = 0; for_each_plane_id_on_crtc(crtc, plane_id) { - if (plane_id == PLANE_CURSOR) + if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) continue; data_rate += crtc_state->rel_data_rate[plane_id]; @@ -1514,10 +1514,12 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, return 0; /* Allocate fixed number of blocks for cursor. */ - cursor_size = skl_cursor_allocation(crtc_state, num_active); - iter.size -= cursor_size; - skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR], - alloc->end - cursor_size, alloc->end); + if (DISPLAY_VER(i915) < 20) { + cursor_size = skl_cursor_allocation(crtc_state, num_active); + iter.size -= cursor_size; + skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR], + alloc->end - cursor_size, alloc->end); + } iter.data_rate = skl_total_relative_data_rate(crtc_state); @@ -1531,7 +1533,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (plane_id == PLANE_CURSOR) { + if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) { const struct skl_ddb_entry *ddb = &crtc_state->wm.skl.plane_ddb[plane_id]; @@ -1579,7 +1581,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (plane_id == PLANE_CURSOR) + if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) continue; if (DISPLAY_VER(i915) < 11 && @@ -2616,7 +2618,7 @@ skl_compute_ddb(struct intel_atomic_state *state) if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) { /* TODO: Implement vblank synchronized MBUS joining changes */ - ret = intel_modeset_all_pipes(state, "MBUS joining change"); + ret = intel_modeset_all_pipes_late(state, "MBUS joining change"); if (ret) return ret; } @@ -3132,10 +3134,12 @@ static void skl_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915) skl_wm_sanitize(i915); } -void intel_wm_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state) +void intel_wm_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); struct skl_hw_state { struct skl_ddb_entry ddb[I915_MAX_PLANES]; struct skl_ddb_entry ddb_y[I915_MAX_PLANES]; @@ -3719,3 +3723,17 @@ void skl_watermark_debugfs_register(struct drm_i915_private *i915) debugfs_create_file("i915_sagv_status", 0444, minor->debugfs_root, i915, &intel_sagv_status_fops); } + +unsigned int skl_watermark_max_latency(struct drm_i915_private *i915) +{ + int level; + + for (level = i915->display.wm.num_levels - 1; level >= 0; level--) { + unsigned int latency = skl_wm_latency(i915, level, NULL); + + if (latency) + return latency; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h index f91a3d4ddc07..fb0da36fd3ec 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.h +++ b/drivers/gpu/drm/i915/display/skl_watermark.h @@ -38,14 +38,16 @@ bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb, const struct skl_ddb_entry *entries, int num_entries, int ignore_idx); -void intel_wm_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state); +void intel_wm_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc); void skl_watermark_ipc_init(struct drm_i915_private *i915); void skl_watermark_ipc_update(struct drm_i915_private *i915); bool skl_watermark_ipc_enabled(struct drm_i915_private *i915); void skl_watermark_debugfs_register(struct drm_i915_private *i915); +unsigned int skl_watermark_max_latency(struct drm_i915_private *i915); + void skl_wm_init(struct drm_i915_private *i915); struct intel_dbuf_state { diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index a96e7d028c5c..55da627a8b8d 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -23,6 +23,7 @@ * Author: Jani Nikula <jani.nikula@intel.com> */ +#include <linux/dmi.h> #include <linux/slab.h> #include <drm/drm_atomic_helper.h> @@ -1744,6 +1745,126 @@ static void vlv_dphy_param_init(struct intel_dsi *intel_dsi) intel_dsi_log_params(intel_dsi); } +typedef void (*vlv_dsi_dmi_quirk_func)(struct intel_dsi *intel_dsi); + +/* + * Vtotal is wrong on the Asus TF103C leading to the last line of the display + * being shown as the first line. The factory installed Android has a hardcoded + * modeline, causing it to not suffer from this BIOS bug. + * + * Original mode: "1280x800": 60 67700 1280 1312 1328 1376 800 808 812 820 0x8 0xa + * Fixed mode: "1280x800": 60 67700 1280 1312 1328 1376 800 808 812 816 0x8 0xa + * + * https://gitlab.freedesktop.org/drm/intel/-/issues/9381 + */ +static void vlv_dsi_asus_tf103c_mode_fixup(struct intel_dsi *intel_dsi) +{ + /* Cast away the const as we want to fixup the mode */ + struct drm_display_mode *fixed_mode = (struct drm_display_mode *) + intel_panel_preferred_fixed_mode(intel_dsi->attached_connector); + + if (fixed_mode->vtotal == 820) + fixed_mode->vtotal -= 4; +} + +/* + * On the Lenovo Yoga Tablet 2 830 / 1050 there are 2 problems: + * 1. The I2C MIPI sequence elements reference bus 3. ACPI has I2C1 - I2C7 + * which under Linux become bus 0 - 6. And the MIPI sequence reference + * to bus 3 is indented for I2C3 which is bus 2 under Linux. + * + * Note mipi_exec_i2c() cannot just subtract 1 from the bus + * given in the I2C MIPI sequence element. Since on other + * devices the I2C bus-numbers used in the MIPI sequences do + * actually start at 0. + * + * 2. width_/height_mm contain a bogus 192mm x 120mm size. This is + * especially a problem on the 8" 830 version which uses a 10:16 + * portrait screen where as the bogus size is 16:10. + * + * https://gitlab.freedesktop.org/drm/intel/-/issues/9379 + */ +static void vlv_dsi_lenovo_yoga_tab2_size_fixup(struct intel_dsi *intel_dsi) +{ + const struct drm_display_mode *fixed_mode = + intel_panel_preferred_fixed_mode(intel_dsi->attached_connector); + struct drm_display_info *info = &intel_dsi->attached_connector->base.display_info; + + intel_dsi->i2c_bus_num = 2; + + /* + * The 10" 1050 uses a 1920x1200 landscape screen, where as the 8" 830 + * uses a 1200x1920 portrait screen. + */ + if (fixed_mode->hdisplay == 1920) { + info->width_mm = 216; + info->height_mm = 135; + } else { + info->width_mm = 107; + info->height_mm = 171; + } +} + +/* + * On the Lenovo Yoga Tab 3 Pro YT3-X90F there are 2 problems: + * 1. i2c_acpi_find_adapter() picks the wrong adapter causing mipi_exec_i2c() + * to not work. Fix this by setting i2c_bus_num. + * 2. There is no backlight off MIPI sequence, causing the backlight to stay on. + * Add a backlight off sequence mirroring the existing backlight on sequence. + * + * https://gitlab.freedesktop.org/drm/intel/-/issues/9380 + */ +static void vlv_dsi_lenovo_yoga_tab3_backlight_fixup(struct intel_dsi *intel_dsi) +{ + static const u8 backlight_off_sequence[16] = { + /* Header Seq-id 7, length after header 11 bytes */ + 0x07, 0x0b, 0x00, 0x00, 0x00, + /* MIPI_SEQ_ELEM_I2C bus 0 addr 0x2c reg 0x00 data-len 1 data 0x00 */ + 0x04, 0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x01, 0x00, + /* MIPI_SEQ_ELEM_END */ + 0x00 + }; + struct intel_connector *connector = intel_dsi->attached_connector; + + intel_dsi->i2c_bus_num = 0; + connector->panel.vbt.dsi.sequence[MIPI_SEQ_BACKLIGHT_OFF] = backlight_off_sequence; +} + +static const struct dmi_system_id vlv_dsi_dmi_quirk_table[] = { + { + /* Asus Transformer Pad TF103C */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), + }, + .driver_data = (void *)vlv_dsi_asus_tf103c_mode_fixup, + }, + { + /* + * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10" + * Lenovo Yoga Tablet 2 use the same mainboard) + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), + DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"), + /* Partial match on beginning of BIOS version */ + DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"), + }, + .driver_data = (void *)vlv_dsi_lenovo_yoga_tab2_size_fixup, + }, + { + /* Lenovo Yoga Tab 3 Pro YT3-X90F */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), + }, + .driver_data = (void *)vlv_dsi_lenovo_yoga_tab3_backlight_fixup, + }, + { } +}; + void vlv_dsi_init(struct drm_i915_private *dev_priv) { struct intel_dsi *intel_dsi; @@ -1752,6 +1873,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) struct intel_connector *intel_connector; struct drm_connector *connector; struct drm_display_mode *current_mode; + const struct dmi_system_id *dmi_id; enum port port; enum pipe pipe; @@ -1883,6 +2005,14 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) goto err_cleanup_connector; } + dmi_id = dmi_first_match(vlv_dsi_dmi_quirk_table); + if (dmi_id) { + vlv_dsi_dmi_quirk_func quirk_func = + (vlv_dsi_dmi_quirk_func)dmi_id->driver_data; + + quirk_func(intel_dsi); + } + intel_panel_init(intel_connector, NULL); intel_backlight_setup(intel_connector, INVALID_PIPE); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.h b/drivers/gpu/drm/i915/display/vlv_dsi.h index 0c2b279df9d4..cf9d7b82f288 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.h +++ b/drivers/gpu/drm/i915/display/vlv_dsi.h @@ -12,8 +12,21 @@ enum port; struct drm_i915_private; struct intel_dsi; +#ifdef I915 void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port); enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt); void vlv_dsi_init(struct drm_i915_private *dev_priv); +#else +static inline void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port) +{ +} +static inline enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt) +{ + return 0; +} +static inline void vlv_dsi_init(struct drm_i915_private *dev_priv) +{ +} +#endif #endif /* __VLV_DSI_H__ */ diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.h b/drivers/gpu/drm/i915/display/vlv_dsi_pll.h index ab9291ad1e79..fbe5113dbeb9 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.h +++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.h @@ -32,7 +32,16 @@ u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, struct intel_crtc_state *config); void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port); +#ifdef I915 void assert_dsi_pll_enabled(struct drm_i915_private *i915); void assert_dsi_pll_disabled(struct drm_i915_private *i915); +#else +static inline void assert_dsi_pll_enabled(struct drm_i915_private *i915) +{ +} +static inline void assert_dsi_pll_disabled(struct drm_i915_private *i915) +{ +} +#endif #endif /* __VLV_DSI_PLL_H__ */ diff --git a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c index 385ffc575b48..7d97ea2a653e 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c @@ -6,11 +6,10 @@ #include <drm/drm_cache.h> -#include "display/intel_frontbuffer.h" - #include "i915_config.h" #include "i915_drv.h" #include "i915_gem_clflush.h" +#include "i915_gem_object_frontbuffer.h" #include "i915_sw_fence_work.h" #include "i915_trace.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c index d24c0ce8805c..19156ba4b9ef 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c @@ -405,8 +405,8 @@ static int ext_set_pat(struct i915_user_extension __user *base, void *data) BUILD_BUG_ON(sizeof(struct drm_i915_gem_create_ext_set_pat) != offsetofend(struct drm_i915_gem_create_ext_set_pat, rsvd)); - /* Limiting the extension only to Meteor Lake */ - if (!IS_METEORLAKE(i915)) + /* Limiting the extension only to Xe_LPG and beyond */ + if (GRAPHICS_VER_FULL(i915) < IP_VER(12, 70)) return -ENODEV; if (copy_from_user(&ext, base, sizeof(ext))) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_domain.c b/drivers/gpu/drm/i915/gem/i915_gem_domain.c index ffddec1d2a76..3770828f2eaf 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_domain.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_domain.c @@ -5,7 +5,6 @@ */ #include "display/intel_display.h" -#include "display/intel_frontbuffer.h" #include "gt/intel_gt.h" #include "i915_drv.h" @@ -16,6 +15,7 @@ #include "i915_gem_lmem.h" #include "i915_gem_mman.h" #include "i915_gem_object.h" +#include "i915_gem_object_frontbuffer.h" #include "i915_vma.h" #define VTD_GUARD (168u * I915_GTT_PAGE_SIZE) /* 168 or tile-row PTE padding */ diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 5a687a3686bd..683fd8d3151c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -321,7 +321,7 @@ static int eb_pin_engine(struct i915_execbuffer *eb, bool throttle); static void eb_unpin_engine(struct i915_execbuffer *eb); static void eb_capture_release(struct i915_execbuffer *eb); -static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb) +static bool eb_use_cmdparser(const struct i915_execbuffer *eb) { return intel_engine_requires_cmd_parser(eb->context->engine) || (intel_engine_using_cmd_parser(eb->context->engine) && @@ -433,7 +433,7 @@ static u64 eb_pin_flags(const struct drm_i915_gem_exec_object2 *entry, return pin_flags; } -static inline int +static int eb_pin_vma(struct i915_execbuffer *eb, const struct drm_i915_gem_exec_object2 *entry, struct eb_vma *ev) @@ -486,7 +486,7 @@ eb_pin_vma(struct i915_execbuffer *eb, return 0; } -static inline void +static void eb_unreserve_vma(struct eb_vma *ev) { if (unlikely(ev->flags & __EXEC_OBJECT_HAS_FENCE)) @@ -548,7 +548,7 @@ eb_validate_vma(struct i915_execbuffer *eb, return 0; } -static inline bool +static bool is_batch_buffer(struct i915_execbuffer *eb, unsigned int buffer_idx) { return eb->args->flags & I915_EXEC_BATCH_FIRST ? @@ -628,8 +628,8 @@ eb_add_vma(struct i915_execbuffer *eb, return 0; } -static inline int use_cpu_reloc(const struct reloc_cache *cache, - const struct drm_i915_gem_object *obj) +static int use_cpu_reloc(const struct reloc_cache *cache, + const struct drm_i915_gem_object *obj) { if (!i915_gem_object_has_struct_page(obj)) return false; @@ -1107,7 +1107,7 @@ static void eb_destroy(const struct i915_execbuffer *eb) kfree(eb->buckets); } -static inline u64 +static u64 relocation_target(const struct drm_i915_gem_relocation_entry *reloc, const struct i915_vma *target) { @@ -1128,19 +1128,19 @@ static void reloc_cache_init(struct reloc_cache *cache, cache->node.flags = 0; } -static inline void *unmask_page(unsigned long p) +static void *unmask_page(unsigned long p) { return (void *)(uintptr_t)(p & PAGE_MASK); } -static inline unsigned int unmask_flags(unsigned long p) +static unsigned int unmask_flags(unsigned long p) { return p & ~PAGE_MASK; } #define KMAP 0x4 /* after CLFLUSH_FLAGS */ -static inline struct i915_ggtt *cache_to_ggtt(struct reloc_cache *cache) +static struct i915_ggtt *cache_to_ggtt(struct reloc_cache *cache) { struct drm_i915_private *i915 = container_of(cache, struct i915_execbuffer, reloc_cache)->i915; @@ -1436,7 +1436,7 @@ eb_relocate_entry(struct i915_execbuffer *eb, if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) { drm_dbg(&i915->drm, "reloc with multiple write domains: " "target %d offset %d " - "read %08x write %08x", + "read %08x write %08x\n", reloc->target_handle, (int) reloc->offset, reloc->read_domains, @@ -1447,7 +1447,7 @@ eb_relocate_entry(struct i915_execbuffer *eb, & ~I915_GEM_GPU_DOMAINS)) { drm_dbg(&i915->drm, "reloc with read/write non-GPU domains: " "target %d offset %d " - "read %08x write %08x", + "read %08x write %08x\n", reloc->target_handle, (int) reloc->offset, reloc->read_domains, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index ef9346ed6d0f..c26d87555825 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -37,6 +37,7 @@ #include "i915_gem_dmabuf.h" #include "i915_gem_mman.h" #include "i915_gem_object.h" +#include "i915_gem_object_frontbuffer.h" #include "i915_gem_ttm.h" #include "i915_memcpy.h" #include "i915_trace.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index f607b87890dd..3560a062d287 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -11,7 +11,6 @@ #include <drm/drm_file.h> #include <drm/drm_device.h> -#include "display/intel_frontbuffer.h" #include "intel_memory_region.h" #include "i915_gem_object_types.h" #include "i915_gem_gtt.h" @@ -806,27 +805,6 @@ int i915_gem_object_wait_priority(struct drm_i915_gem_object *obj, unsigned int flags, const struct i915_sched_attr *attr); -void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj, - enum fb_op_origin origin); -void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj, - enum fb_op_origin origin); - -static inline void -i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj, - enum fb_op_origin origin) -{ - if (unlikely(rcu_access_pointer(obj->frontbuffer))) - __i915_gem_object_flush_frontbuffer(obj, origin); -} - -static inline void -i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj, - enum fb_op_origin origin) -{ - if (unlikely(rcu_access_pointer(obj->frontbuffer))) - __i915_gem_object_invalidate_frontbuffer(obj, origin); -} - int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset, void *dst, int size); bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj); @@ -887,71 +865,4 @@ static inline int i915_gem_object_userptr_validate(struct drm_i915_gem_object *o #endif -/** - * i915_gem_object_get_frontbuffer - Get the object's frontbuffer - * @obj: The object whose frontbuffer to get. - * - * Get pointer to object's frontbuffer if such exists. Please note that RCU - * mechanism is used to handle e.g. ongoing removal of frontbuffer pointer. - * - * Return: pointer to object's frontbuffer is such exists or NULL - */ -static inline struct intel_frontbuffer * -i915_gem_object_get_frontbuffer(const struct drm_i915_gem_object *obj) -{ - struct intel_frontbuffer *front; - - if (likely(!rcu_access_pointer(obj->frontbuffer))) - return NULL; - - rcu_read_lock(); - do { - front = rcu_dereference(obj->frontbuffer); - if (!front) - break; - - if (unlikely(!kref_get_unless_zero(&front->ref))) - continue; - - if (likely(front == rcu_access_pointer(obj->frontbuffer))) - break; - - intel_frontbuffer_put(front); - } while (1); - rcu_read_unlock(); - - return front; -} - -/** - * i915_gem_object_set_frontbuffer - Set the object's frontbuffer - * @obj: The object whose frontbuffer to set. - * @front: The frontbuffer to set - * - * Set object's frontbuffer pointer. If frontbuffer is already set for the - * object keep it and return it's pointer to the caller. Please note that RCU - * mechanism is used to handle e.g. ongoing removal of frontbuffer pointer. This - * function is protected by i915->display.fb_tracking.lock - * - * Return: pointer to frontbuffer which was set. - */ -static inline struct intel_frontbuffer * -i915_gem_object_set_frontbuffer(struct drm_i915_gem_object *obj, - struct intel_frontbuffer *front) -{ - struct intel_frontbuffer *cur = front; - - if (!front) { - RCU_INIT_POINTER(obj->frontbuffer, NULL); - } else if (rcu_access_pointer(obj->frontbuffer)) { - cur = rcu_dereference_protected(obj->frontbuffer, true); - kref_get(&cur->ref); - } else { - drm_gem_object_get(intel_bo_to_drm_bo(obj)); - rcu_assign_pointer(obj->frontbuffer, front); - } - - return cur; -} - #endif diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h new file mode 100644 index 000000000000..e5e870b6f186 --- /dev/null +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __I915_GEM_OBJECT_FRONTBUFFER_H__ +#define __I915_GEM_OBJECT_FRONTBUFFER_H__ + +#include <linux/kref.h> +#include <linux/rcupdate.h> + +#include "display/intel_frontbuffer.h" +#include "i915_gem_object_types.h" + +void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj, + enum fb_op_origin origin); +void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj, + enum fb_op_origin origin); + +static inline void +i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj, + enum fb_op_origin origin) +{ + if (unlikely(rcu_access_pointer(obj->frontbuffer))) + __i915_gem_object_flush_frontbuffer(obj, origin); +} + +static inline void +i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj, + enum fb_op_origin origin) +{ + if (unlikely(rcu_access_pointer(obj->frontbuffer))) + __i915_gem_object_invalidate_frontbuffer(obj, origin); +} + +/** + * i915_gem_object_get_frontbuffer - Get the object's frontbuffer + * @obj: The object whose frontbuffer to get. + * + * Get pointer to object's frontbuffer if such exists. Please note that RCU + * mechanism is used to handle e.g. ongoing removal of frontbuffer pointer. + * + * Return: pointer to object's frontbuffer is such exists or NULL + */ +static inline struct intel_frontbuffer * +i915_gem_object_get_frontbuffer(const struct drm_i915_gem_object *obj) +{ + struct intel_frontbuffer *front; + + if (likely(!rcu_access_pointer(obj->frontbuffer))) + return NULL; + + rcu_read_lock(); + do { + front = rcu_dereference(obj->frontbuffer); + if (!front) + break; + + if (unlikely(!kref_get_unless_zero(&front->ref))) + continue; + + if (likely(front == rcu_access_pointer(obj->frontbuffer))) + break; + + intel_frontbuffer_put(front); + } while (1); + rcu_read_unlock(); + + return front; +} + +/** + * i915_gem_object_set_frontbuffer - Set the object's frontbuffer + * @obj: The object whose frontbuffer to set. + * @front: The frontbuffer to set + * + * Set object's frontbuffer pointer. If frontbuffer is already set for the + * object keep it and return it's pointer to the caller. Please note that RCU + * mechanism is used to handle e.g. ongoing removal of frontbuffer pointer. This + * function is protected by i915->display.fb_tracking.lock + * + * Return: pointer to frontbuffer which was set. + */ +static inline struct intel_frontbuffer * +i915_gem_object_set_frontbuffer(struct drm_i915_gem_object *obj, + struct intel_frontbuffer *front) +{ + struct intel_frontbuffer *cur = front; + + if (!front) { + RCU_INIT_POINTER(obj->frontbuffer, NULL); + } else if (rcu_access_pointer(obj->frontbuffer)) { + cur = rcu_dereference_protected(obj->frontbuffer, true); + kref_get(&cur->ref); + } else { + drm_gem_object_get(intel_bo_to_drm_bo(obj)); + rcu_assign_pointer(obj->frontbuffer, front); + } + + return cur; +} + +#endif diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index 6b6d22c19411..0ba955611dfb 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -198,7 +198,7 @@ static void flush_tlb_invalidate(struct drm_i915_gem_object *obj) for_each_gt(gt, i915, id) { if (!obj->mm.tlb[id]) - return; + continue; intel_gt_invalidate_tlb_full(gt, obj->mm.tlb[id]); obj->mm.tlb[id] = 0; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/i915_gem_phys.c index 76efe98eaa14..5df128e2f4dc 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c @@ -13,6 +13,7 @@ #include "gt/intel_gt.h" #include "i915_drv.h" #include "i915_gem_object.h" +#include "i915_gem_object_frontbuffer.h" #include "i915_gem_region.h" #include "i915_gem_tiling.h" #include "i915_scatterlist.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 8f1633c3fb93..73a4a4eb29e0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -100,6 +100,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st, st->nents = 0; for (i = 0; i < page_count; i++) { struct folio *folio; + unsigned long nr_pages; const unsigned int shrink[] = { I915_SHRINK_BOUND | I915_SHRINK_UNBOUND, 0, @@ -150,6 +151,8 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st, } } while (1); + nr_pages = min_t(unsigned long, + folio_nr_pages(folio), page_count - i); if (!i || sg->length >= max_segment || folio_pfn(folio) != next_pfn) { @@ -157,13 +160,13 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st, sg = sg_next(sg); st->nents++; - sg_set_folio(sg, folio, folio_size(folio), 0); + sg_set_folio(sg, folio, nr_pages * PAGE_SIZE, 0); } else { /* XXX: could overflow? */ - sg->length += folio_size(folio); + sg->length += nr_pages * PAGE_SIZE; } - next_pfn = folio_pfn(folio) + folio_nr_pages(folio); - i += folio_nr_pages(folio) - 1; + next_pfn = folio_pfn(folio) + nr_pages; + i += nr_pages - 1; /* Check that the i965g/gm workaround works. */ GEM_BUG_ON(gfp & __GFP_DMA32 && next_pfn >= 0x00100000UL); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c index 214763942aa2..9cb7bbfb4278 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c @@ -14,6 +14,7 @@ #include <linux/vmalloc.h> #include "gt/intel_gt_requests.h" +#include "gt/intel_gt.h" #include "i915_trace.h" @@ -119,7 +120,8 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww, intel_wakeref_t wakeref = 0; unsigned long count = 0; unsigned long scanned = 0; - int err = 0; + int err = 0, i = 0; + struct intel_gt *gt; /* CHV + VTD workaround use stop_machine(); need to trylock vm->mutex */ bool trylock_vm = !ww && intel_vm_no_concurrent_access_wa(i915); @@ -147,9 +149,11 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww, * what we can do is give them a kick so that we do not keep idle * contexts around longer than is necessary. */ - if (shrink & I915_SHRINK_ACTIVE) - /* Retire requests to unpin all idle contexts */ - intel_gt_retire_requests(to_gt(i915)); + if (shrink & I915_SHRINK_ACTIVE) { + for_each_gt(gt, i915, i) + /* Retire requests to unpin all idle contexts */ + intel_gt_retire_requests(gt); + } /* * As we may completely rewrite the (un)bound list whilst unbinding @@ -389,6 +393,8 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr struct i915_vma *vma, *next; unsigned long freed_pages = 0; intel_wakeref_t wakeref; + struct intel_gt *gt; + int i; with_intel_runtime_pm(&i915->runtime_pm, wakeref) freed_pages += i915_gem_shrink(NULL, i915, -1UL, NULL, @@ -397,24 +403,26 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr I915_SHRINK_VMAPS); /* We also want to clear any cached iomaps as they wrap vmap */ - mutex_lock(&to_gt(i915)->ggtt->vm.mutex); - list_for_each_entry_safe(vma, next, - &to_gt(i915)->ggtt->vm.bound_list, vm_link) { - unsigned long count = i915_vma_size(vma) >> PAGE_SHIFT; - struct drm_i915_gem_object *obj = vma->obj; - - if (!vma->iomap || i915_vma_is_active(vma)) - continue; + for_each_gt(gt, i915, i) { + mutex_lock(>->ggtt->vm.mutex); + list_for_each_entry_safe(vma, next, + >->ggtt->vm.bound_list, vm_link) { + unsigned long count = i915_vma_size(vma) >> PAGE_SHIFT; + struct drm_i915_gem_object *obj = vma->obj; + + if (!vma->iomap || i915_vma_is_active(vma)) + continue; - if (!i915_gem_object_trylock(obj, NULL)) - continue; + if (!i915_gem_object_trylock(obj, NULL)) + continue; - if (__i915_vma_unbind(vma) == 0) - freed_pages += count; + if (__i915_vma_unbind(vma) == 0) + freed_pages += count; - i915_gem_object_unlock(obj); + i915_gem_object_unlock(obj); + } + mutex_unlock(>->ggtt->vm.mutex); } - mutex_unlock(&to_gt(i915)->ggtt->vm.mutex); *(unsigned long *)ptr += freed_pages; return NOTIFY_DONE; diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c index ff81af4c8202..10a7847f1b04 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c @@ -83,8 +83,7 @@ static int linear_x_y_to_ftiled_pos(int x, int y, u32 stride, int bpp) enum client_tiling { CLIENT_TILING_LINEAR, CLIENT_TILING_X, - CLIENT_TILING_Y, - CLIENT_TILING_4, + CLIENT_TILING_Y, /* Y-major, either Tile4 (Xe_HP and beyond) or legacy TileY */ CLIENT_NUM_TILING_TYPES }; @@ -165,11 +164,10 @@ static int prepare_blit(const struct tiled_blits *t, BLIT_CCTL_DST_MOCS(gt->mocs.uc_index)); src_pitch = t->width; /* in dwords */ - if (src->tiling == CLIENT_TILING_4) { - src_tiles = XY_FAST_COPY_BLT_D0_SRC_TILE_MODE(YMAJOR); - src_4t = XY_FAST_COPY_BLT_D1_SRC_TILE4; - } else if (src->tiling == CLIENT_TILING_Y) { + if (src->tiling == CLIENT_TILING_Y) { src_tiles = XY_FAST_COPY_BLT_D0_SRC_TILE_MODE(YMAJOR); + if (GRAPHICS_VER_FULL(to_i915(batch->base.dev)) >= IP_VER(12, 50)) + src_4t = XY_FAST_COPY_BLT_D1_SRC_TILE4; } else if (src->tiling == CLIENT_TILING_X) { src_tiles = XY_FAST_COPY_BLT_D0_SRC_TILE_MODE(TILE_X); } else { @@ -177,11 +175,10 @@ static int prepare_blit(const struct tiled_blits *t, } dst_pitch = t->width; /* in dwords */ - if (dst->tiling == CLIENT_TILING_4) { - dst_tiles = XY_FAST_COPY_BLT_D0_DST_TILE_MODE(YMAJOR); - dst_4t = XY_FAST_COPY_BLT_D1_DST_TILE4; - } else if (dst->tiling == CLIENT_TILING_Y) { + if (dst->tiling == CLIENT_TILING_Y) { dst_tiles = XY_FAST_COPY_BLT_D0_DST_TILE_MODE(YMAJOR); + if (GRAPHICS_VER_FULL(to_i915(batch->base.dev)) >= IP_VER(12, 50)) + dst_4t = XY_FAST_COPY_BLT_D1_DST_TILE4; } else if (dst->tiling == CLIENT_TILING_X) { dst_tiles = XY_FAST_COPY_BLT_D0_DST_TILE_MODE(TILE_X); } else { @@ -326,12 +323,6 @@ static int tiled_blits_create_buffers(struct tiled_blits *t, t->buffers[i].vma = vma; t->buffers[i].tiling = i915_prandom_u32_max_state(CLIENT_NUM_TILING_TYPES, prng); - - /* Platforms support either TileY or Tile4, not both */ - if (HAS_4TILE(i915) && t->buffers[i].tiling == CLIENT_TILING_Y) - t->buffers[i].tiling = CLIENT_TILING_4; - else if (!HAS_4TILE(i915) && t->buffers[i].tiling == CLIENT_TILING_4) - t->buffers[i].tiling = CLIENT_TILING_Y; } return 0; @@ -367,18 +358,19 @@ static u64 tiled_offset(const struct intel_gt *gt, y = div64_u64_rem(v, stride, &x); - if (tiling == CLIENT_TILING_4) { - v = linear_x_y_to_ftiled_pos(x_pos, y_pos, stride, 32); - - /* no swizzling for f-tiling */ - swizzle = I915_BIT_6_SWIZZLE_NONE; - } else if (tiling == CLIENT_TILING_X) { + if (tiling == CLIENT_TILING_X) { v = div64_u64_rem(y, 8, &y) * stride * 8; v += y * 512; v += div64_u64_rem(x, 512, &x) << 12; v += x; swizzle = gt->ggtt->bit_6_swizzle_x; + } else if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50)) { + /* Y-major tiling layout is Tile4 for Xe_HP and beyond */ + v = linear_x_y_to_ftiled_pos(x_pos, y_pos, stride, 32); + + /* no swizzling for f-tiling */ + swizzle = I915_BIT_6_SWIZZLE_NONE; } else { const unsigned int ytile_span = 16; const unsigned int ytile_height = 512; @@ -414,8 +406,7 @@ static const char *repr_tiling(enum client_tiling tiling) switch (tiling) { case CLIENT_TILING_LINEAR: return "linear"; case CLIENT_TILING_X: return "X"; - case CLIENT_TILING_Y: return "Y"; - case CLIENT_TILING_4: return "F"; + case CLIENT_TILING_Y: return "Y / 4"; default: return "unknown"; } } diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c index 8ac6726ec16b..e199d7dbb876 100644 --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c @@ -36,7 +36,7 @@ mock_context(struct drm_i915_private *i915, if (name) { struct i915_ppgtt *ppgtt; - strncpy(ctx->name, name, sizeof(ctx->name) - 1); + strscpy(ctx->name, name, sizeof(ctx->name)); ppgtt = mock_ppgtt(i915, name); if (!ppgtt) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index a4ff55aa5e55..ba4c2422b340 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -4,9 +4,9 @@ */ #include "gen8_engine_cs.h" -#include "i915_drv.h" #include "intel_engine_regs.h" #include "intel_gpu_commands.h" +#include "intel_gt.h" #include "intel_lrc.h" #include "intel_ring.h" @@ -226,8 +226,8 @@ u32 *gen12_emit_aux_table_inv(struct intel_engine_cs *engine, u32 *cs) static int mtl_dummy_pipe_control(struct i915_request *rq) { /* Wa_14016712196 */ - if (IS_MTL_GRAPHICS_STEP(rq->i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(rq->i915, P, STEP_A0, STEP_B0)) { + if (IS_GFX_GT_IP_RANGE(rq->engine->gt, IP_VER(12, 70), IP_VER(12, 71)) || + IS_DG2(rq->i915)) { u32 *cs; /* dummy PIPE_CONTROL + depth flush */ @@ -271,8 +271,17 @@ int gen12_emit_flush_rcs(struct i915_request *rq, u32 mode) if (GRAPHICS_VER_FULL(rq->i915) >= IP_VER(12, 70)) bit_group_0 |= PIPE_CONTROL_CCS_FLUSH; + /* + * L3 fabric flush is needed for AUX CCS invalidation + * which happens as part of pipe-control so we can + * ignore PIPE_CONTROL_FLUSH_L3. Also PIPE_CONTROL_FLUSH_L3 + * deals with Protected Memory which is not needed for + * AUX CCS invalidation and lead to unwanted side effects. + */ + if (mode & EMIT_FLUSH) + bit_group_1 |= PIPE_CONTROL_FLUSH_L3; + bit_group_1 |= PIPE_CONTROL_TILE_CACHE_FLUSH; - bit_group_1 |= PIPE_CONTROL_FLUSH_L3; bit_group_1 |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; bit_group_1 |= PIPE_CONTROL_DEPTH_CACHE_FLUSH; /* Wa_1409600907:tgl,adl-p */ @@ -799,6 +808,7 @@ u32 *gen12_emit_fini_breadcrumb_xcs(struct i915_request *rq, u32 *cs) u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) { struct drm_i915_private *i915 = rq->i915; + struct intel_gt *gt = rq->engine->gt; u32 flags = (PIPE_CONTROL_CS_STALL | PIPE_CONTROL_TLB_INVALIDATE | PIPE_CONTROL_TILE_CACHE_FLUSH | @@ -809,8 +819,7 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) PIPE_CONTROL_FLUSH_ENABLE); /* Wa_14016712196 */ - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)) || IS_DG2(i915)) /* dummy PIPE_CONTROL + depth flush */ cs = gen12_emit_pipe_control(cs, 0, PIPE_CONTROL_DEPTH_CACHE_FLUSH, 0); diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index c8568e5d1147..9895e18df043 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -242,9 +242,9 @@ static u64 __gen8_ppgtt_clear(struct i915_address_space * const vm, GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT); len = gen8_pd_range(start, end, lvl--, &idx); - DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n", - __func__, vm, lvl + 1, start, end, - idx, len, atomic_read(px_used(pd))); + GTT_TRACE("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n", + __func__, vm, lvl + 1, start, end, + idx, len, atomic_read(px_used(pd))); GEM_BUG_ON(!len || len >= atomic_read(px_used(pd))); do { @@ -252,8 +252,8 @@ static u64 __gen8_ppgtt_clear(struct i915_address_space * const vm, if (atomic_fetch_inc(&pt->used) >> gen8_pd_shift(1) && gen8_pd_contains(start, end, lvl)) { - DBG("%s(%p):{ lvl:%d, idx:%d, start:%llx, end:%llx } removing pd\n", - __func__, vm, lvl + 1, idx, start, end); + GTT_TRACE("%s(%p):{ lvl:%d, idx:%d, start:%llx, end:%llx } removing pd\n", + __func__, vm, lvl + 1, idx, start, end); clear_pd_entry(pd, idx, scratch); __gen8_ppgtt_cleanup(vm, as_pd(pt), I915_PDES, lvl); start += (u64)I915_PDES << gen8_pd_shift(lvl); @@ -270,10 +270,10 @@ static u64 __gen8_ppgtt_clear(struct i915_address_space * const vm, u64 *vaddr; count = gen8_pt_count(start, end); - DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } removing pte\n", - __func__, vm, lvl, start, end, - gen8_pd_index(start, 0), count, - atomic_read(&pt->used)); + GTT_TRACE("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } removing pte\n", + __func__, vm, lvl, start, end, + gen8_pd_index(start, 0), count, + atomic_read(&pt->used)); GEM_BUG_ON(!count || count >= atomic_read(&pt->used)); num_ptes = count; @@ -325,9 +325,9 @@ static void __gen8_ppgtt_alloc(struct i915_address_space * const vm, GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT); len = gen8_pd_range(*start, end, lvl--, &idx); - DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n", - __func__, vm, lvl + 1, *start, end, - idx, len, atomic_read(px_used(pd))); + GTT_TRACE("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n", + __func__, vm, lvl + 1, *start, end, + idx, len, atomic_read(px_used(pd))); GEM_BUG_ON(!len || (idx + len - 1) >> gen8_pd_shift(1)); spin_lock(&pd->lock); @@ -338,8 +338,8 @@ static void __gen8_ppgtt_alloc(struct i915_address_space * const vm, if (!pt) { spin_unlock(&pd->lock); - DBG("%s(%p):{ lvl:%d, idx:%d } allocating new tree\n", - __func__, vm, lvl + 1, idx); + GTT_TRACE("%s(%p):{ lvl:%d, idx:%d } allocating new tree\n", + __func__, vm, lvl + 1, idx); pt = stash->pt[!!lvl]; __i915_gem_object_pin_pages(pt->base); @@ -369,10 +369,10 @@ static void __gen8_ppgtt_alloc(struct i915_address_space * const vm, } else { unsigned int count = gen8_pt_count(*start, end); - DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } inserting pte\n", - __func__, vm, lvl, *start, end, - gen8_pd_index(*start, 0), count, - atomic_read(&pt->used)); + GTT_TRACE("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } inserting pte\n", + __func__, vm, lvl, *start, end, + gen8_pd_index(*start, 0), count, + atomic_read(&pt->used)); atomic_add(count, &pt->used); /* All other pdes may be simultaneously removed */ diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index b58c30ac8ef0..40269e4c1e31 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -170,6 +170,8 @@ intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value) #define I915_GEM_HWS_SEQNO 0x40 #define I915_GEM_HWS_SEQNO_ADDR (I915_GEM_HWS_SEQNO * sizeof(u32)) #define I915_GEM_HWS_MIGRATE (0x42 * sizeof(u32)) +#define I915_GEM_HWS_GGTT_BIND 0x46 +#define I915_GEM_HWS_GGTT_BIND_ADDR (I915_GEM_HWS_GGTT_BIND * sizeof(u32)) #define I915_GEM_HWS_PXP 0x60 #define I915_GEM_HWS_PXP_ADDR (I915_GEM_HWS_PXP * sizeof(u32)) #define I915_GEM_HWS_GSC 0x62 diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index ee15486fed0d..179d9546865b 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -316,10 +316,9 @@ u32 intel_engine_context_size(struct intel_gt *gt, u8 class) * out in the wash. */ cxt_size = intel_uncore_read(uncore, CXT_SIZE) + 1; - drm_dbg(>->i915->drm, - "graphics_ver = %d CXT_SIZE = %d bytes [0x%08x]\n", - GRAPHICS_VER(gt->i915), cxt_size * 64, - cxt_size - 1); + gt_dbg(gt, "graphics_ver = %d CXT_SIZE = %d bytes [0x%08x]\n", + GRAPHICS_VER(gt->i915), cxt_size * 64, + cxt_size - 1); return round_up(cxt_size * 64, PAGE_SIZE); case 3: case 2: @@ -558,7 +557,6 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, DRIVER_CAPS(i915)->has_logical_contexts = true; ewma__engine_latency_init(&engine->latency); - seqcount_init(&engine->stats.execlists.lock); ATOMIC_INIT_NOTIFIER_HEAD(&engine->context_status_notifier); @@ -789,7 +787,7 @@ static void engine_mask_apply_media_fuses(struct intel_gt *gt) if (!(BIT(i) & vdbox_mask)) { gt->info.engine_mask &= ~BIT(_VCS(i)); - drm_dbg(&i915->drm, "vcs%u fused off\n", i); + gt_dbg(gt, "vcs%u fused off\n", i); continue; } @@ -797,8 +795,7 @@ static void engine_mask_apply_media_fuses(struct intel_gt *gt) gt->info.vdbox_sfc_access |= BIT(i); logical_vdbox++; } - drm_dbg(&i915->drm, "vdbox enable: %04x, instances: %04lx\n", - vdbox_mask, VDBOX_MASK(gt)); + gt_dbg(gt, "vdbox enable: %04x, instances: %04lx\n", vdbox_mask, VDBOX_MASK(gt)); GEM_BUG_ON(vdbox_mask != VDBOX_MASK(gt)); for (i = 0; i < I915_MAX_VECS; i++) { @@ -809,11 +806,10 @@ static void engine_mask_apply_media_fuses(struct intel_gt *gt) if (!(BIT(i) & vebox_mask)) { gt->info.engine_mask &= ~BIT(_VECS(i)); - drm_dbg(&i915->drm, "vecs%u fused off\n", i); + gt_dbg(gt, "vecs%u fused off\n", i); } } - drm_dbg(&i915->drm, "vebox enable: %04x, instances: %04lx\n", - vebox_mask, VEBOX_MASK(gt)); + gt_dbg(gt, "vebox enable: %04x, instances: %04lx\n", vebox_mask, VEBOX_MASK(gt)); GEM_BUG_ON(vebox_mask != VEBOX_MASK(gt)); } @@ -839,7 +835,7 @@ static void engine_mask_apply_compute_fuses(struct intel_gt *gt) */ for_each_clear_bit(i, &ccs_mask, I915_MAX_CCS) { info->engine_mask &= ~BIT(_CCS(i)); - drm_dbg(&i915->drm, "ccs%u fused off\n", i); + gt_dbg(gt, "ccs%u fused off\n", i); } } @@ -867,8 +863,8 @@ static void engine_mask_apply_copy_fuses(struct intel_gt *gt) _BCS(instance)); if (mask & info->engine_mask) { - drm_dbg(&i915->drm, "bcs%u fused off\n", instance); - drm_dbg(&i915->drm, "bcs%u fused off\n", instance + 1); + gt_dbg(gt, "bcs%u fused off\n", instance); + gt_dbg(gt, "bcs%u fused off\n", instance + 1); info->engine_mask &= ~mask; } @@ -908,8 +904,7 @@ static intel_engine_mask_t init_engine_mask(struct intel_gt *gt) * submission, which will wake up the GSC power well. */ if (__HAS_ENGINE(info->engine_mask, GSC0) && !intel_uc_wants_gsc_uc(>->uc)) { - drm_notice(>->i915->drm, - "No GSC FW selected, disabling GSC CS and media C6\n"); + gt_notice(gt, "No GSC FW selected, disabling GSC CS and media C6\n"); info->engine_mask &= ~BIT(GSC0); } @@ -1098,8 +1093,7 @@ static int init_status_page(struct intel_engine_cs *engine) */ obj = i915_gem_object_create_internal(engine->i915, PAGE_SIZE); if (IS_ERR(obj)) { - drm_err(&engine->i915->drm, - "Failed to allocate status page\n"); + gt_err(engine->gt, "Failed to allocate status page\n"); return PTR_ERR(obj); } @@ -1420,6 +1414,20 @@ void intel_engine_destroy_pinned_context(struct intel_context *ce) } static struct intel_context * +create_ggtt_bind_context(struct intel_engine_cs *engine) +{ + static struct lock_class_key kernel; + + /* + * MI_UPDATE_GTT can insert up to 511 PTE entries and there could be multiple + * bind requets at a time so get a bigger ring. + */ + return intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_512K, + I915_GEM_HWS_GGTT_BIND_ADDR, + &kernel, "ggtt_bind_context"); +} + +static struct intel_context * create_kernel_context(struct intel_engine_cs *engine) { static struct lock_class_key kernel; @@ -1442,7 +1450,7 @@ create_kernel_context(struct intel_engine_cs *engine) */ static int engine_init_common(struct intel_engine_cs *engine) { - struct intel_context *ce; + struct intel_context *ce, *bce = NULL; int ret; engine->set_default_submission(engine); @@ -1458,17 +1466,33 @@ static int engine_init_common(struct intel_engine_cs *engine) ce = create_kernel_context(engine); if (IS_ERR(ce)) return PTR_ERR(ce); + /* + * Create a separate pinned context for GGTT update with blitter engine + * if a platform require such service. MI_UPDATE_GTT works on other + * engines as well but BCS should be less busy engine so pick that for + * GGTT updates. + */ + if (i915_ggtt_require_binder(engine->i915) && engine->id == BCS0) { + bce = create_ggtt_bind_context(engine); + if (IS_ERR(bce)) { + ret = PTR_ERR(bce); + goto err_ce_context; + } + } ret = measure_breadcrumb_dw(ce); if (ret < 0) - goto err_context; + goto err_bce_context; engine->emit_fini_breadcrumb_dw = ret; engine->kernel_context = ce; + engine->bind_context = bce; return 0; -err_context: +err_bce_context: + intel_engine_destroy_pinned_context(bce); +err_ce_context: intel_engine_destroy_pinned_context(ce); return ret; } @@ -1538,6 +1562,10 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine) if (engine->kernel_context) intel_engine_destroy_pinned_context(engine->kernel_context); + if (engine->bind_context) + intel_engine_destroy_pinned_context(engine->bind_context); + + GEM_BUG_ON(!llist_empty(&engine->barrier_tasks)); cleanup_status_page(engine); @@ -1617,9 +1645,7 @@ static int __intel_engine_stop_cs(struct intel_engine_cs *engine, * Wa_22011802037: Prior to doing a reset, ensure CS is * stopped, set ring stop bit and prefetch disable bit to halt CS */ - if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) || - (GRAPHICS_VER(engine->i915) >= 11 && - GRAPHICS_VER_FULL(engine->i915) < IP_VER(12, 70))) + if (intel_engine_reset_needs_wa_22011802037(engine->gt)) intel_uncore_write_fw(uncore, RING_MODE_GEN7(engine->mmio_base), _MASKED_BIT_ENABLE(GEN12_GFX_PREFETCH_DISABLE)); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c index b538b5c04948..e91fc881dbf1 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -21,7 +21,7 @@ static void intel_gsc_idle_msg_enable(struct intel_engine_cs *engine) { struct drm_i915_private *i915 = engine->i915; - if (IS_METEORLAKE(i915) && engine->id == GSC0) { + if (MEDIA_VER(i915) >= 13 && engine->id == GSC0) { intel_uncore_write(engine->gt->uncore, RC_PSMI_CTRL_GSCCS, _MASKED_BIT_DISABLE(IDLE_MSG_DISABLE)); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_regs.h b/drivers/gpu/drm/i915/gt/intel_engine_regs.h index 6b9d9f837669..fdd4ddd3a978 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_regs.h @@ -177,6 +177,7 @@ #define CTX_CTRL_RS_CTX_ENABLE REG_BIT(1) #define CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT REG_BIT(2) #define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH REG_BIT(3) +#define GEN12_CTX_CTRL_RUNALONE_MODE REG_BIT(7) #define GEN12_CTX_CTRL_OAR_CONTEXT_ENABLE REG_BIT(8) #define RING_CTX_SR_CTL(base) _MMIO((base) + 0x244) #define RING_SEMA_WAIT_POLL(base) _MMIO((base) + 0x24c) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h index e99a6fa03d45..8769760257fd 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -58,6 +58,7 @@ struct i915_perf_group; typedef u32 intel_engine_mask_t; #define ALL_ENGINES ((intel_engine_mask_t)~0ul) +#define VIRTUAL_ENGINES BIT(BITS_PER_TYPE(intel_engine_mask_t) - 1) struct intel_hw_status_page { struct list_head timelines; @@ -401,7 +402,15 @@ struct intel_engine_cs { unsigned long context_tag; - struct rb_node uabi_node; + /* + * The type evolves during initialization, see related comment for + * struct drm_i915_private's uabi_engines member. + */ + union { + struct llist_node uabi_llist; + struct list_head uabi_list; + struct rb_node uabi_node; + }; struct intel_sseu sseu; @@ -415,6 +424,9 @@ struct intel_engine_cs { struct llist_head barrier_tasks; struct intel_context *kernel_context; /* pinned */ + struct intel_context *bind_context; /* pinned, only for BCS0 */ + /* mark the bind context's availability status */ + bool bind_context_ready; /** * pinned_contexts_list: List of pinned contexts. This list is only diff --git a/drivers/gpu/drm/i915/gt/intel_engine_user.c b/drivers/gpu/drm/i915/gt/intel_engine_user.c index dcedff41a825..118164ddbb2e 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_user.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_user.c @@ -38,8 +38,7 @@ intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance) void intel_engine_add_user(struct intel_engine_cs *engine) { - llist_add((struct llist_node *)&engine->uabi_node, - (struct llist_head *)&engine->i915->uabi_engines); + llist_add(&engine->uabi_llist, &engine->i915->uabi_engines_llist); } static const u8 uabi_classes[] = { @@ -54,9 +53,9 @@ static int engine_cmp(void *priv, const struct list_head *A, const struct list_head *B) { const struct intel_engine_cs *a = - container_of((struct rb_node *)A, typeof(*a), uabi_node); + container_of(A, typeof(*a), uabi_list); const struct intel_engine_cs *b = - container_of((struct rb_node *)B, typeof(*b), uabi_node); + container_of(B, typeof(*b), uabi_list); if (uabi_classes[a->class] < uabi_classes[b->class]) return -1; @@ -73,7 +72,7 @@ static int engine_cmp(void *priv, const struct list_head *A, static struct llist_node *get_engines(struct drm_i915_private *i915) { - return llist_del_all((struct llist_head *)&i915->uabi_engines); + return llist_del_all(&i915->uabi_engines_llist); } static void sort_engines(struct drm_i915_private *i915, @@ -83,9 +82,8 @@ static void sort_engines(struct drm_i915_private *i915, llist_for_each_safe(pos, next, get_engines(i915)) { struct intel_engine_cs *engine = - container_of((struct rb_node *)pos, typeof(*engine), - uabi_node); - list_add((struct list_head *)&engine->uabi_node, engines); + container_of(pos, typeof(*engine), uabi_llist); + list_add(&engine->uabi_list, engines); } list_sort(NULL, engines, engine_cmp); } @@ -213,8 +211,7 @@ void intel_engines_driver_register(struct drm_i915_private *i915) p = &i915->uabi_engines.rb_node; list_for_each_safe(it, next, &engines) { struct intel_engine_cs *engine = - container_of((struct rb_node *)it, typeof(*engine), - uabi_node); + container_of(it, typeof(*engine), uabi_list); if (intel_gt_has_unrecoverable_error(engine->gt)) continue; /* ignore incomplete engines */ diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 8a641bcf777c..e8f42ec6b1b4 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -3001,9 +3001,7 @@ static void execlists_reset_prepare(struct intel_engine_cs *engine) * Wa_22011802037: In addition to stopping the cs, we need * to wait for any pending mi force wakeups */ - if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) || - (GRAPHICS_VER(engine->i915) >= 11 && - GRAPHICS_VER_FULL(engine->i915) < IP_VER(12, 70))) + if (intel_engine_reset_needs_wa_22011802037(engine->gt)) intel_engine_wait_for_pending_mi_fw(engine); engine->execlists.reset_ccid = active_ccid(engine); @@ -3550,6 +3548,8 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine) logical_ring_default_vfuncs(engine); logical_ring_default_irqs(engine); + seqcount_init(&engine->stats.execlists.lock); + if (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE) rcs_submission_override(engine); diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index dd0ed941441a..4d7d88b92632 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -15,18 +15,23 @@ #include "display/intel_display.h" #include "gem/i915_gem_lmem.h" +#include "intel_context.h" #include "intel_ggtt_gmch.h" +#include "intel_gpu_commands.h" #include "intel_gt.h" #include "intel_gt_regs.h" #include "intel_pci_config.h" +#include "intel_ring.h" #include "i915_drv.h" #include "i915_pci.h" +#include "i915_request.h" #include "i915_scatterlist.h" #include "i915_utils.h" #include "i915_vgpu.h" #include "intel_gtt.h" #include "gen8_ppgtt.h" +#include "intel_engine_pm.h" static void i915_ggtt_color_adjust(const struct drm_mm_node *node, unsigned long color, @@ -252,6 +257,145 @@ u64 gen8_ggtt_pte_encode(dma_addr_t addr, return pte; } +static bool should_update_ggtt_with_bind(struct i915_ggtt *ggtt) +{ + struct intel_gt *gt = ggtt->vm.gt; + + return intel_gt_is_bind_context_ready(gt); +} + +static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt) +{ + struct intel_context *ce; + struct intel_gt *gt = ggtt->vm.gt; + + if (intel_gt_is_wedged(gt)) + return NULL; + + ce = gt->engine[BCS0]->bind_context; + GEM_BUG_ON(!ce); + + /* + * If the GT is not awake already at this stage then fallback + * to pci based GGTT update otherwise __intel_wakeref_get_first() + * would conflict with fs_reclaim trying to allocate memory while + * doing rpm_resume(). + */ + if (!intel_gt_pm_get_if_awake(gt)) + return NULL; + + intel_engine_pm_get(ce->engine); + + return ce; +} + +static void gen8_ggtt_bind_put_ce(struct intel_context *ce) +{ + intel_engine_pm_put(ce->engine); + intel_gt_pm_put(ce->engine->gt); +} + +static bool gen8_ggtt_bind_ptes(struct i915_ggtt *ggtt, u32 offset, + struct sg_table *pages, u32 num_entries, + const gen8_pte_t pte) +{ + struct i915_sched_attr attr = {}; + struct intel_gt *gt = ggtt->vm.gt; + const gen8_pte_t scratch_pte = ggtt->vm.scratch[0]->encode; + struct sgt_iter iter; + struct i915_request *rq; + struct intel_context *ce; + u32 *cs; + + if (!num_entries) + return true; + + ce = gen8_ggtt_bind_get_ce(ggtt); + if (!ce) + return false; + + if (pages) + iter = __sgt_iter(pages->sgl, true); + + while (num_entries) { + int count = 0; + dma_addr_t addr; + /* + * MI_UPDATE_GTT can update 512 entries in a single command but + * that end up with engine reset, 511 works. + */ + u32 n_ptes = min_t(u32, 511, num_entries); + + if (mutex_lock_interruptible(&ce->timeline->mutex)) + goto put_ce; + + intel_context_enter(ce); + rq = __i915_request_create(ce, GFP_NOWAIT | GFP_ATOMIC); + intel_context_exit(ce); + if (IS_ERR(rq)) { + GT_TRACE(gt, "Failed to get bind request\n"); + mutex_unlock(&ce->timeline->mutex); + goto put_ce; + } + + cs = intel_ring_begin(rq, 2 * n_ptes + 2); + if (IS_ERR(cs)) { + GT_TRACE(gt, "Failed to ring space for GGTT bind\n"); + i915_request_set_error_once(rq, PTR_ERR(cs)); + /* once a request is created, it must be queued */ + goto queue_err_rq; + } + + *cs++ = MI_UPDATE_GTT | (2 * n_ptes); + *cs++ = offset << 12; + + if (pages) { + for_each_sgt_daddr_next(addr, iter) { + if (count == n_ptes) + break; + *cs++ = lower_32_bits(pte | addr); + *cs++ = upper_32_bits(pte | addr); + count++; + } + /* fill remaining with scratch pte, if any */ + if (count < n_ptes) { + memset64((u64 *)cs, scratch_pte, + n_ptes - count); + cs += (n_ptes - count) * 2; + } + } else { + memset64((u64 *)cs, pte, n_ptes); + cs += n_ptes * 2; + } + + intel_ring_advance(rq, cs); +queue_err_rq: + i915_request_get(rq); + __i915_request_commit(rq); + __i915_request_queue(rq, &attr); + + mutex_unlock(&ce->timeline->mutex); + /* This will break if the request is complete or after engine reset */ + i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT); + if (rq->fence.error) + goto err_rq; + + i915_request_put(rq); + + num_entries -= n_ptes; + offset += n_ptes; + } + + gen8_ggtt_bind_put_ce(ce); + return true; + +err_rq: + i915_request_put(rq); +put_ce: + gen8_ggtt_bind_put_ce(ce); + return false; +} + static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) { writeq(pte, addr); @@ -272,6 +416,21 @@ static void gen8_ggtt_insert_page(struct i915_address_space *vm, ggtt->invalidate(ggtt); } +static void gen8_ggtt_insert_page_bind(struct i915_address_space *vm, + dma_addr_t addr, u64 offset, + unsigned int pat_index, u32 flags) +{ + struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); + gen8_pte_t pte; + + pte = ggtt->vm.pte_encode(addr, pat_index, flags); + if (should_update_ggtt_with_bind(i915_vm_to_ggtt(vm)) && + gen8_ggtt_bind_ptes(ggtt, offset, NULL, 1, pte)) + return ggtt->invalidate(ggtt); + + gen8_ggtt_insert_page(vm, addr, offset, pat_index, flags); +} + static void gen8_ggtt_insert_entries(struct i915_address_space *vm, struct i915_vma_resource *vma_res, unsigned int pat_index, @@ -311,6 +470,50 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, ggtt->invalidate(ggtt); } +static bool __gen8_ggtt_insert_entries_bind(struct i915_address_space *vm, + struct i915_vma_resource *vma_res, + unsigned int pat_index, u32 flags) +{ + struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); + gen8_pte_t scratch_pte = vm->scratch[0]->encode; + gen8_pte_t pte_encode; + u64 start, end; + + pte_encode = ggtt->vm.pte_encode(0, pat_index, flags); + start = (vma_res->start - vma_res->guard) / I915_GTT_PAGE_SIZE; + end = start + vma_res->guard / I915_GTT_PAGE_SIZE; + if (!gen8_ggtt_bind_ptes(ggtt, start, NULL, end - start, scratch_pte)) + goto err; + + start = end; + end += (vma_res->node_size + vma_res->guard) / I915_GTT_PAGE_SIZE; + if (!gen8_ggtt_bind_ptes(ggtt, start, vma_res->bi.pages, + vma_res->node_size / I915_GTT_PAGE_SIZE, pte_encode)) + goto err; + + start += vma_res->node_size / I915_GTT_PAGE_SIZE; + if (!gen8_ggtt_bind_ptes(ggtt, start, NULL, end - start, scratch_pte)) + goto err; + + return true; + +err: + return false; +} + +static void gen8_ggtt_insert_entries_bind(struct i915_address_space *vm, + struct i915_vma_resource *vma_res, + unsigned int pat_index, u32 flags) +{ + struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); + + if (should_update_ggtt_with_bind(i915_vm_to_ggtt(vm)) && + __gen8_ggtt_insert_entries_bind(vm, vma_res, pat_index, flags)) + return ggtt->invalidate(ggtt); + + gen8_ggtt_insert_entries(vm, vma_res, pat_index, flags); +} + static void gen8_ggtt_clear_range(struct i915_address_space *vm, u64 start, u64 length) { @@ -332,6 +535,27 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm, gen8_set_pte(>t_base[i], scratch_pte); } +static void gen8_ggtt_scratch_range_bind(struct i915_address_space *vm, + u64 start, u64 length) +{ + struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); + unsigned int first_entry = start / I915_GTT_PAGE_SIZE; + unsigned int num_entries = length / I915_GTT_PAGE_SIZE; + const gen8_pte_t scratch_pte = vm->scratch[0]->encode; + const int max_entries = ggtt_total_entries(ggtt) - first_entry; + + if (WARN(num_entries > max_entries, + "First entry = %d; Num entries = %d (max=%d)\n", + first_entry, num_entries, max_entries)) + num_entries = max_entries; + + if (should_update_ggtt_with_bind(ggtt) && gen8_ggtt_bind_ptes(ggtt, first_entry, + NULL, num_entries, scratch_pte)) + return ggtt->invalidate(ggtt); + + gen8_ggtt_clear_range(vm, start, length); +} + static void gen6_ggtt_insert_page(struct i915_address_space *vm, dma_addr_t addr, u64 offset, @@ -511,20 +735,31 @@ void intel_ggtt_unbind_vma(struct i915_address_space *vm, vm->clear_range(vm, vma_res->start, vma_res->vma_size); } +/* + * Reserve the top of the GuC address space for firmware images. Addresses + * beyond GUC_GGTT_TOP in the GuC address space are inaccessible by GuC, + * which makes for a suitable range to hold GuC/HuC firmware images if the + * size of the GGTT is 4G. However, on a 32-bit platform the size of the GGTT + * is limited to 2G, which is less than GUC_GGTT_TOP, but we reserve a chunk + * of the same size anyway, which is far more than needed, to keep the logic + * in uc_fw_ggtt_offset() simple. + */ +#define GUC_TOP_RESERVE_SIZE (SZ_4G - GUC_GGTT_TOP) + static int ggtt_reserve_guc_top(struct i915_ggtt *ggtt) { - u64 size; + u64 offset; int ret; if (!intel_uc_uses_guc(&ggtt->vm.gt->uc)) return 0; - GEM_BUG_ON(ggtt->vm.total <= GUC_GGTT_TOP); - size = ggtt->vm.total - GUC_GGTT_TOP; + GEM_BUG_ON(ggtt->vm.total <= GUC_TOP_RESERVE_SIZE); + offset = ggtt->vm.total - GUC_TOP_RESERVE_SIZE; - ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &ggtt->uc_fw, size, - GUC_GGTT_TOP, I915_COLOR_UNEVICTABLE, - PIN_NOEVICT); + ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &ggtt->uc_fw, + GUC_TOP_RESERVE_SIZE, offset, + I915_COLOR_UNEVICTABLE, PIN_NOEVICT); if (ret) drm_dbg(&ggtt->vm.i915->drm, "Failed to reserve top of GGTT for GuC\n"); @@ -997,6 +1232,17 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND; } + if (i915_ggtt_require_binder(i915)) { + ggtt->vm.scratch_range = gen8_ggtt_scratch_range_bind; + ggtt->vm.insert_page = gen8_ggtt_insert_page_bind; + ggtt->vm.insert_entries = gen8_ggtt_insert_entries_bind; + /* + * On GPU is hung, we might bind VMAs for error capture. + * Fallback to CPU GGTT updates in that case. + */ + ggtt->vm.raw_insert_page = gen8_ggtt_insert_page; + } + if (intel_uc_wants_guc(&ggtt->vm.gt->uc)) ggtt->invalidate = guc_ggtt_invalidate; else diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.c b/drivers/gpu/drm/i915/gt/intel_gsc.c index bcc3605158db..6d440de8ba01 100644 --- a/drivers/gpu/drm/i915/gt/intel_gsc.c +++ b/drivers/gpu/drm/i915/gt/intel_gsc.c @@ -11,6 +11,7 @@ #include "gem/i915_gem_region.h" #include "gt/intel_gsc.h" #include "gt/intel_gt.h" +#include "gt/intel_gt_print.h" #define GSC_BAR_LENGTH 0x00000FFC @@ -49,13 +50,13 @@ gsc_ext_om_alloc(struct intel_gsc *gsc, struct intel_gsc_intf *intf, size_t size I915_BO_ALLOC_CONTIGUOUS | I915_BO_ALLOC_CPU_CLEAR); if (IS_ERR(obj)) { - drm_err(>->i915->drm, "Failed to allocate gsc memory\n"); + gt_err(gt, "Failed to allocate gsc memory\n"); return PTR_ERR(obj); } err = i915_gem_object_pin_pages_unlocked(obj); if (err) { - drm_err(>->i915->drm, "Failed to pin pages for gsc memory\n"); + gt_err(gt, "Failed to pin pages for gsc memory\n"); goto out_put; } @@ -286,12 +287,12 @@ static void gsc_irq_handler(struct intel_gt *gt, unsigned int intf_id) int ret; if (intf_id >= INTEL_GSC_NUM_INTERFACES) { - drm_warn_once(>->i915->drm, "GSC irq: intf_id %d is out of range", intf_id); + gt_warn_once(gt, "GSC irq: intf_id %d is out of range", intf_id); return; } if (!HAS_HECI_GSC(gt->i915)) { - drm_warn_once(>->i915->drm, "GSC irq: not supported"); + gt_warn_once(gt, "GSC irq: not supported"); return; } @@ -300,7 +301,7 @@ static void gsc_irq_handler(struct intel_gt *gt, unsigned int intf_id) ret = generic_handle_irq(gt->gsc.intf[intf_id].irq); if (ret) - drm_err_ratelimited(>->i915->drm, "error handling GSC irq: %d\n", ret); + gt_err_ratelimited(gt, "error handling GSC irq: %d\n", ret); } void intel_gsc_irq_handler(struct intel_gt *gt, u32 iir) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 449f0b7fc843..ed32bf5b1546 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -62,7 +62,13 @@ void intel_gt_common_init_early(struct intel_gt *gt) /* Preliminary initialization of Tile 0 */ int intel_root_gt_init_early(struct drm_i915_private *i915) { - struct intel_gt *gt = to_gt(i915); + struct intel_gt *gt; + + gt = drmm_kzalloc(&i915->drm, sizeof(*gt), GFP_KERNEL); + if (!gt) + return -ENOMEM; + + i915->gt[0] = gt; gt->i915 = i915; gt->uncore = &i915->uncore; @@ -262,10 +268,21 @@ intel_gt_clear_error_registers(struct intel_gt *gt, I915_MASTER_ERROR_INTERRUPT); } - if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + /* + * For the media GT, this ring fault register is not replicated, + * so don't do multicast/replicated register read/write operation on it. + */ + if (MEDIA_VER(i915) >= 13 && gt->type == GT_MEDIA) { + intel_uncore_rmw(uncore, XELPMP_RING_FAULT_REG, + RING_FAULT_VALID, 0); + intel_uncore_posting_read(uncore, + XELPMP_RING_FAULT_REG); + + } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { intel_gt_mcr_multicast_rmw(gt, XEHP_RING_FAULT_REG, RING_FAULT_VALID, 0); intel_gt_mcr_read_any(gt, XEHP_RING_FAULT_REG); + } else if (GRAPHICS_VER(i915) >= 12) { intel_uncore_rmw(uncore, GEN12_RING_FAULT_REG, RING_FAULT_VALID, 0); intel_uncore_posting_read(uncore, GEN12_RING_FAULT_REG); @@ -911,8 +928,6 @@ int intel_gt_probe_all(struct drm_i915_private *i915) if (ret) return ret; - i915->gt[0] = gt; - if (!HAS_EXTRA_GT_LIST(i915)) return 0; @@ -1019,3 +1034,57 @@ enum i915_map_type intel_gt_coherent_map_type(struct intel_gt *gt, else return I915_MAP_WC; } + +bool intel_gt_needs_wa_22016122933(struct intel_gt *gt) +{ + return MEDIA_VER_FULL(gt->i915) == IP_VER(13, 0) && gt->type == GT_MEDIA; +} + +static void __intel_gt_bind_context_set_ready(struct intel_gt *gt, bool ready) +{ + struct intel_engine_cs *engine = gt->engine[BCS0]; + + if (engine && engine->bind_context) + engine->bind_context_ready = ready; +} + +/** + * intel_gt_bind_context_set_ready - Set the context binding as ready + * + * @gt: GT structure + * + * This function marks the binder context as ready. + */ +void intel_gt_bind_context_set_ready(struct intel_gt *gt) +{ + __intel_gt_bind_context_set_ready(gt, true); +} + +/** + * intel_gt_bind_context_set_unready - Set the context binding as ready + * @gt: GT structure + * + * This function marks the binder context as not ready. + */ + +void intel_gt_bind_context_set_unready(struct intel_gt *gt) +{ + __intel_gt_bind_context_set_ready(gt, false); +} + +/** + * intel_gt_is_bind_context_ready - Check if context binding is ready + * + * @gt: GT structure + * + * This function returns binder context's ready status. + */ +bool intel_gt_is_bind_context_ready(struct intel_gt *gt) +{ + struct intel_engine_cs *engine = gt->engine[BCS0]; + + if (engine) + return engine->bind_context_ready; + + return false; +} diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h index 6c34547b58b5..970bedf6b78a 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.h +++ b/drivers/gpu/drm/i915/gt/intel_gt.h @@ -6,7 +6,6 @@ #ifndef __INTEL_GT__ #define __INTEL_GT__ -#include "i915_drv.h" #include "intel_engine_types.h" #include "intel_gt_types.h" #include "intel_reset.h" @@ -14,6 +13,69 @@ struct drm_i915_private; struct drm_printer; +/* + * Check that the GT is a graphics GT and has an IP version within the + * specified range (inclusive). + */ +#define IS_GFX_GT_IP_RANGE(gt, from, until) ( \ + BUILD_BUG_ON_ZERO((from) < IP_VER(2, 0)) + \ + BUILD_BUG_ON_ZERO((until) < (from)) + \ + ((gt)->type != GT_MEDIA && \ + GRAPHICS_VER_FULL((gt)->i915) >= (from) && \ + GRAPHICS_VER_FULL((gt)->i915) <= (until))) + +/* + * Check that the GT is a media GT and has an IP version within the + * specified range (inclusive). + * + * Only usable on platforms with a standalone media design (i.e., IP version 13 + * and higher). + */ +#define IS_MEDIA_GT_IP_RANGE(gt, from, until) ( \ + BUILD_BUG_ON_ZERO((from) < IP_VER(13, 0)) + \ + BUILD_BUG_ON_ZERO((until) < (from)) + \ + ((gt) && (gt)->type == GT_MEDIA && \ + MEDIA_VER_FULL((gt)->i915) >= (from) && \ + MEDIA_VER_FULL((gt)->i915) <= (until))) + +/* + * Check that the GT is a graphics GT with a specific IP version and has + * a stepping in the range [from, until). The lower stepping bound is + * inclusive, the upper bound is exclusive. The most common use-case of this + * macro is for checking bounds for workarounds, which usually have a stepping + * ("from") at which the hardware issue is first present and another stepping + * ("until") at which a hardware fix is present and the software workaround is + * no longer necessary. E.g., + * + * IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) + * IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B1, STEP_FOREVER) + * + * "STEP_FOREVER" can be passed as "until" for workarounds that have no upper + * stepping bound for the specified IP version. + */ +#define IS_GFX_GT_IP_STEP(gt, ipver, from, until) ( \ + BUILD_BUG_ON_ZERO((until) <= (from)) + \ + (IS_GFX_GT_IP_RANGE((gt), (ipver), (ipver)) && \ + IS_GRAPHICS_STEP((gt)->i915, (from), (until)))) + +/* + * Check that the GT is a media GT with a specific IP version and has + * a stepping in the range [from, until). The lower stepping bound is + * inclusive, the upper bound is exclusive. The most common use-case of this + * macro is for checking bounds for workarounds, which usually have a stepping + * ("from") at which the hardware issue is first present and another stepping + * ("until") at which a hardware fix is present and the software workaround is + * no longer necessary. "STEP_FOREVER" can be passed as "until" for + * workarounds that have no upper stepping bound for the specified IP version. + * + * This macro may only be used to match on platforms that have a standalone + * media design (i.e., media version 13 or higher). + */ +#define IS_MEDIA_GT_IP_STEP(gt, ipver, from, until) ( \ + BUILD_BUG_ON_ZERO((until) <= (from)) + \ + (IS_MEDIA_GT_IP_RANGE((gt), (ipver), (ipver)) && \ + IS_MEDIA_STEP((gt)->i915, (from), (until)))) + #define GT_TRACE(gt, fmt, ...) do { \ const struct intel_gt *gt__ __maybe_unused = (gt); \ GEM_TRACE("%s " fmt, dev_name(gt__->i915->drm.dev), \ @@ -25,10 +87,7 @@ static inline bool gt_is_root(struct intel_gt *gt) return !gt->info.id; } -static inline bool intel_gt_needs_wa_22016122933(struct intel_gt *gt) -{ - return MEDIA_VER_FULL(gt->i915) == IP_VER(13, 0) && gt->type == GT_MEDIA; -} +bool intel_gt_needs_wa_22016122933(struct intel_gt *gt); static inline struct intel_gt *uc_to_gt(struct intel_uc *uc) { @@ -117,4 +176,7 @@ enum i915_map_type intel_gt_coherent_map_type(struct intel_gt *gt, struct drm_i915_gem_object *obj, bool always_coherent); +void intel_gt_bind_context_set_ready(struct intel_gt *gt); +void intel_gt_bind_context_set_unready(struct intel_gt *gt); +bool intel_gt_is_bind_context_ready(struct intel_gt *gt); #endif /* __INTEL_GT_H__ */ diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 0b414eae1683..326c2ed1d99b 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -4,7 +4,7 @@ */ #include "i915_drv.h" - +#include "intel_gt.h" #include "intel_gt_mcr.h" #include "intel_gt_print.h" #include "intel_gt_regs.h" @@ -166,8 +166,8 @@ void intel_gt_mcr_init(struct intel_gt *gt) gt->steering_table[OADDRM] = xelpmp_oaddrm_steering_table; } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) { /* Wa_14016747170 */ - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) fuse = REG_FIELD_GET(MTL_GT_L3_EXC_MASK, intel_uncore_read(gt->uncore, MTL_GT_ACTIVITY_FACTOR)); @@ -420,6 +420,28 @@ void intel_gt_mcr_unlock(struct intel_gt *gt, unsigned long flags) } /** + * intel_gt_mcr_lock_sanitize - Sanitize MCR steering lock + * @gt: GT structure + * + * This will be used to sanitize the initial status of the hardware lock + * during driver load and resume since there won't be any concurrent access + * from other agents at those times, but it's possible that boot firmware + * may have left the lock in a bad state. + * + */ +void intel_gt_mcr_lock_sanitize(struct intel_gt *gt) +{ + /* + * This gets called at load/resume time, so we shouldn't be + * racing with other driver threads grabbing the mcr lock. + */ + lockdep_assert_not_held(>->mcr_lock); + + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) + intel_uncore_write_fw(gt->uncore, MTL_STEER_SEMAPHORE, 0x1); +} + +/** * intel_gt_mcr_read - read a specific instance of an MCR register * @gt: GT structure * @reg: the MCR register to read diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h index 41684495b7da..01ac565a56a4 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h @@ -11,6 +11,7 @@ void intel_gt_mcr_init(struct intel_gt *gt); void intel_gt_mcr_lock(struct intel_gt *gt, unsigned long *flags); void intel_gt_mcr_unlock(struct intel_gt *gt, unsigned long flags); +void intel_gt_mcr_lock_sanitize(struct intel_gt *gt); u32 intel_gt_mcr_read(struct intel_gt *gt, i915_mcr_reg_t reg, diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c index 5a942af0a14e..f5899d503e23 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -13,6 +13,7 @@ #include "intel_engine_pm.h" #include "intel_gt.h" #include "intel_gt_clock_utils.h" +#include "intel_gt_mcr.h" #include "intel_gt_pm.h" #include "intel_gt_print.h" #include "intel_gt_requests.h" @@ -216,6 +217,21 @@ void intel_gt_pm_fini(struct intel_gt *gt) intel_rc6_fini(>->rc6); } +void intel_gt_resume_early(struct intel_gt *gt) +{ + /* + * Sanitize steer semaphores during driver resume. This is necessary + * to address observed cases of steer semaphores being + * held after a suspend operation. Confirmation from the hardware team + * assures the safety of this operation, as no lock acquisitions + * by other agents occur during driver load/resume process. + */ + intel_gt_mcr_lock_sanitize(gt); + + intel_uncore_resume_early(gt->uncore); + intel_gt_check_and_clear_faults(gt); +} + int intel_gt_resume(struct intel_gt *gt) { struct intel_engine_cs *engine; @@ -280,6 +296,7 @@ int intel_gt_resume(struct intel_gt *gt) out_fw: intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); intel_gt_pm_put(gt); + intel_gt_bind_context_set_ready(gt); return err; err_wedged: @@ -306,6 +323,7 @@ static void wait_for_suspend(struct intel_gt *gt) void intel_gt_suspend_prepare(struct intel_gt *gt) { + intel_gt_bind_context_set_unready(gt); user_forcewake(gt, true); wait_for_suspend(gt); } @@ -359,6 +377,7 @@ void intel_gt_suspend_late(struct intel_gt *gt) void intel_gt_runtime_suspend(struct intel_gt *gt) { + intel_gt_bind_context_set_unready(gt); intel_uc_runtime_suspend(>->uc); GT_TRACE(gt, "\n"); @@ -376,6 +395,7 @@ int intel_gt_runtime_resume(struct intel_gt *gt) if (ret) return ret; + intel_gt_bind_context_set_ready(gt); return 0; } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h b/drivers/gpu/drm/i915/gt/intel_gt_pm.h index 6c9a46452364..b1eeb5b33918 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h @@ -78,6 +78,7 @@ void intel_gt_pm_fini(struct intel_gt *gt); void intel_gt_suspend_prepare(struct intel_gt *gt); void intel_gt_suspend_late(struct intel_gt *gt); int intel_gt_resume(struct intel_gt *gt); +void intel_gt_resume_early(struct intel_gt *gt); void intel_gt_runtime_suspend(struct intel_gt *gt); int intel_gt_runtime_resume(struct intel_gt *gt); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 357e2f865727..f900cc68d6d9 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -290,7 +290,6 @@ static int mtl_drpc(struct seq_file *m) seq_puts(m, "RC6\n"); break; default: - MISSING_CASE(REG_FIELD_GET(MTL_CC_MASK, gt_core_status)); seq_puts(m, "Unknown\n"); break; } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_print.h b/drivers/gpu/drm/i915/gt/intel_gt_print.h index 55a336a9ff06..7fdc78c79273 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_print.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_print.h @@ -16,6 +16,9 @@ #define gt_warn(_gt, _fmt, ...) \ drm_warn(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__) +#define gt_warn_once(_gt, _fmt, ...) \ + drm_warn_once(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__) + #define gt_notice(_gt, _fmt, ...) \ drm_notice(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 2cdfb2f713d0..eecd0a87a647 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -26,7 +26,7 @@ #define MTL_CAGF_MASK REG_GENMASK(8, 0) #define MTL_CC0 0x0 #define MTL_CC6 0x3 -#define MTL_CC_MASK REG_GENMASK(12, 9) +#define MTL_CC_MASK REG_GENMASK(10, 9) /* RPM unit config (Gen8+) */ #define RPM_CONFIG0 _MMIO(0xd00) @@ -164,6 +164,8 @@ #define GEN9_CSFE_CHICKEN1_RCS _MMIO(0x20d4) #define GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE (1 << 2) #define GEN11_ENABLE_32_PLANE_MODE (1 << 7) +#define GEN12_CS_DEBUG_MODE2 _MMIO(0x20d8) +#define INSTRUCTION_STATE_CACHE_INVALIDATE REG_BIT(6) #define GEN7_FF_SLICE_CS_CHICKEN1 _MMIO(0x20e0) #define GEN9_FFSC_PERCTX_PREEMPT_CTRL (1 << 14) @@ -412,9 +414,6 @@ #define XEHP_CULLBIT1 MCR_REG(0x6100) -#define CHICKEN_RASTER_1 MCR_REG(0x6204) -#define DIS_SF_ROUND_NEAREST_EVEN REG_BIT(8) - #define CHICKEN_RASTER_2 MCR_REG(0x6208) #define TBIMR_FAST_CLIP REG_BIT(5) @@ -1085,6 +1084,7 @@ #define GEN12_RING_FAULT_REG _MMIO(0xcec4) #define XEHP_RING_FAULT_REG MCR_REG(0xcec4) +#define XELPMP_RING_FAULT_REG _MMIO(0xcec4) #define GEN8_RING_FAULT_ENGINE_ID(x) (((x) >> 12) & 0x7) #define RING_FAULT_GTTSEL_MASK (1 << 11) #define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff) @@ -1221,6 +1221,8 @@ #define XEHP_HDC_CHICKEN0 MCR_REG(0xe5f0) #define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11) +#define DIS_ATOMIC_CHAINING_TYPED_WRITES REG_BIT(3) + #define ICL_HDC_MODE MCR_REG(0xe5f4) #define EU_PERF_CNTL2 PERF_REG(0xe658) @@ -1231,6 +1233,7 @@ #define DISABLE_D8_D16_COASLESCE REG_BIT(30) #define FORCE_1_SUB_MESSAGE_PER_FRAGMENT REG_BIT(15) #define LSC_CHICKEN_BIT_0_UDW MCR_REG(0xe7c8 + 4) +#define UGM_FRAGMENT_THRESHOLD_TO_3 REG_BIT(58 - 32) #define DIS_CHAIN_2XSIMD8 REG_BIT(55 - 32) #define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32) #define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32) diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index 13944a14ea2d..4fbed27ef0ec 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -21,6 +21,11 @@ #include "intel_gt_regs.h" #include "intel_gtt.h" +bool i915_ggtt_require_binder(struct drm_i915_private *i915) +{ + /* Wa_13010847436 & Wa_14019519902 */ + return MEDIA_VER_FULL(i915) == IP_VER(13, 0); +} static bool intel_ggtt_update_needs_vtd_wa(struct drm_i915_private *i915) { diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index 4d6296cdbcfd..b471edac2699 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -35,9 +35,9 @@ #define I915_GFP_ALLOW_FAIL (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN) #if IS_ENABLED(CONFIG_DRM_I915_TRACE_GTT) -#define DBG(...) trace_printk(__VA_ARGS__) +#define GTT_TRACE(...) trace_printk(__VA_ARGS__) #else -#define DBG(...) +#define GTT_TRACE(...) #endif #define NALLOC 3 /* 1 normal, 1 for concurrent threads, 1 for preallocation */ @@ -171,6 +171,9 @@ struct intel_gt; #define for_each_sgt_daddr(__dp, __iter, __sgt) \ __for_each_sgt_daddr(__dp, __iter, __sgt, I915_GTT_PAGE_SIZE) +#define for_each_sgt_daddr_next(__dp, __iter) \ + __for_each_daddr_next(__dp, __iter, I915_GTT_PAGE_SIZE) + struct i915_page_table { struct drm_i915_gem_object *base; union { @@ -688,4 +691,6 @@ static inline struct sgt_dma { return (struct sgt_dma){ sg, addr, addr + sg_dma_len(sg) }; } +bool i915_ggtt_require_binder(struct drm_i915_private *i915); + #endif diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 957d0aeb0c02..eaf66d903166 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -845,6 +845,27 @@ lrc_setup_indirect_ctx(u32 *regs, lrc_ring_indirect_offset_default(engine) << 6; } +static bool ctx_needs_runalone(const struct intel_context *ce) +{ + struct i915_gem_context *gem_ctx; + bool ctx_is_protected = false; + + /* + * On MTL and newer platforms, protected contexts require setting + * the LRC run-alone bit or else the encryption will not happen. + */ + if (GRAPHICS_VER_FULL(ce->engine->i915) >= IP_VER(12, 70) && + (ce->engine->class == COMPUTE_CLASS || ce->engine->class == RENDER_CLASS)) { + rcu_read_lock(); + gem_ctx = rcu_dereference(ce->gem_context); + if (gem_ctx) + ctx_is_protected = gem_ctx->uses_protected_content; + rcu_read_unlock(); + } + + return ctx_is_protected; +} + static void init_common_regs(u32 * const regs, const struct intel_context *ce, const struct intel_engine_cs *engine, @@ -860,6 +881,8 @@ static void init_common_regs(u32 * const regs, if (GRAPHICS_VER(engine->i915) < 11) ctl |= _MASKED_BIT_DISABLE(CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT | CTX_CTRL_RS_CTX_ENABLE); + if (ctx_needs_runalone(ce)) + ctl |= _MASKED_BIT_ENABLE(GEN12_CTX_CTRL_RUNALONE_MODE); regs[CTX_CONTEXT_CONTROL] = ctl; regs[CTX_TIMESTAMP] = ce->stats.runtime.last; @@ -1094,6 +1117,9 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) I915_BO_ALLOC_PM_VOLATILE); if (IS_ERR(obj)) { obj = i915_gem_object_create_shmem(engine->i915, context_size); + if (IS_ERR(obj)) + return ERR_CAST(obj); + /* * Wa_22016122933: For Media version 13.0, all Media GT shared * memory needs to be mapped as WC on CPU side and UC (PAT @@ -1102,8 +1128,6 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) if (intel_gt_needs_wa_22016122933(engine->gt)) i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); } - if (IS_ERR(obj)) - return ERR_CAST(obj); vma = i915_vma_instance(obj, &engine->gt->ggtt->vm, NULL); if (IS_ERR(vma)) { @@ -1316,29 +1340,6 @@ gen12_emit_cmd_buf_wa(const struct intel_context *ce, u32 *cs) } /* - * On DG2 during context restore of a preempted context in GPGPU mode, - * RCS restore hang is detected. This is extremely timing dependent. - * To address this below sw wabb is implemented for DG2 A steppings. - */ -static u32 * -dg2_emit_rcs_hang_wabb(const struct intel_context *ce, u32 *cs) -{ - *cs++ = MI_LOAD_REGISTER_IMM(1); - *cs++ = i915_mmio_reg_offset(GEN12_STATE_ACK_DEBUG(ce->engine->mmio_base)); - *cs++ = 0x21; - - *cs++ = MI_LOAD_REGISTER_REG; - *cs++ = i915_mmio_reg_offset(RING_NOPID(ce->engine->mmio_base)); - *cs++ = i915_mmio_reg_offset(XEHP_CULLBIT1); - - *cs++ = MI_LOAD_REGISTER_REG; - *cs++ = i915_mmio_reg_offset(RING_NOPID(ce->engine->mmio_base)); - *cs++ = i915_mmio_reg_offset(XEHP_CULLBIT2); - - return cs; -} - -/* * The bspec's tuning guide asks us to program a vertical watermark value of * 0x3FF. However this register is not saved/restored properly by the * hardware, so we're required to apply the desired value via INDIRECT_CTX @@ -1356,27 +1357,34 @@ dg2_emit_draw_watermark_setting(u32 *cs) } static u32 * +gen12_invalidate_state_cache(u32 *cs) +{ + *cs++ = MI_LOAD_REGISTER_IMM(1); + *cs++ = i915_mmio_reg_offset(GEN12_CS_DEBUG_MODE2); + *cs++ = _MASKED_BIT_ENABLE(INSTRUCTION_STATE_CACHE_INVALIDATE); + return cs; +} + +static u32 * gen12_emit_indirect_ctx_rcs(const struct intel_context *ce, u32 *cs) { cs = gen12_emit_timestamp_wa(ce, cs); cs = gen12_emit_cmd_buf_wa(ce, cs); cs = gen12_emit_restore_scratch(ce, cs); - /* Wa_22011450934:dg2 */ - if (IS_DG2_GRAPHICS_STEP(ce->engine->i915, G10, STEP_A0, STEP_B0) || - IS_DG2_GRAPHICS_STEP(ce->engine->i915, G11, STEP_A0, STEP_B0)) - cs = dg2_emit_rcs_hang_wabb(ce, cs); - /* Wa_16013000631:dg2 */ - if (IS_DG2_GRAPHICS_STEP(ce->engine->i915, G10, STEP_B0, STEP_C0) || - IS_DG2_G11(ce->engine->i915)) + if (IS_DG2_G11(ce->engine->i915)) cs = gen8_emit_pipe_control(cs, PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE, 0); cs = gen12_emit_aux_table_inv(ce->engine, cs); + /* Wa_18022495364 */ + if (IS_GFX_GT_IP_RANGE(ce->engine->gt, IP_VER(12, 0), IP_VER(12, 10))) + cs = gen12_invalidate_state_cache(cs); + /* Wa_16014892111 */ - if (IS_MTL_GRAPHICS_STEP(ce->engine->i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(ce->engine->i915, P, STEP_A0, STEP_B0) || + if (IS_GFX_GT_IP_STEP(ce->engine->gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(ce->engine->gt, IP_VER(12, 71), STEP_A0, STEP_B0) || IS_DG2(ce->engine->i915)) cs = dg2_emit_draw_watermark_setting(cs); @@ -1390,8 +1398,7 @@ gen12_emit_indirect_ctx_xcs(const struct intel_context *ce, u32 *cs) cs = gen12_emit_restore_scratch(ce, cs); /* Wa_16013000631:dg2 */ - if (IS_DG2_GRAPHICS_STEP(ce->engine->i915, G10, STEP_B0, STEP_C0) || - IS_DG2_G11(ce->engine->i915)) + if (IS_DG2_G11(ce->engine->i915)) if (ce->engine->class == COMPUTE_CLASS) cs = gen8_emit_pipe_control(cs, PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE, diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c index 2c014407225c..353f93baaca0 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.c +++ b/drivers/gpu/drm/i915/gt/intel_mocs.c @@ -404,18 +404,6 @@ static const struct drm_i915_mocs_entry dg2_mocs_table[] = { MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)), }; -static const struct drm_i915_mocs_entry dg2_mocs_table_g10_ax[] = { - /* Wa_14011441408: Set Go to Memory for MOCS#0 */ - MOCS_ENTRY(0, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)), - /* UC - Coherent; GO:Memory */ - MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)), - /* UC - Non-Coherent; GO:Memory */ - MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)), - - /* WB - LC */ - MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)), -}; - static const struct drm_i915_mocs_entry pvc_mocs_table[] = { /* Error */ MOCS_ENTRY(0, 0, L3_3_WB), @@ -499,7 +487,7 @@ static bool has_mocs(const struct drm_i915_private *i915) return !IS_DGFX(i915); } -static unsigned int get_mocs_settings(const struct drm_i915_private *i915, +static unsigned int get_mocs_settings(struct drm_i915_private *i915, struct drm_i915_mocs_table *table) { unsigned int flags; @@ -507,7 +495,7 @@ static unsigned int get_mocs_settings(const struct drm_i915_private *i915, memset(table, 0, sizeof(struct drm_i915_mocs_table)); table->unused_entries_index = I915_MOCS_PTE; - if (IS_METEORLAKE(i915)) { + if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 71))) { table->size = ARRAY_SIZE(mtl_mocs_table); table->table = mtl_mocs_table; table->n_entries = MTL_NUM_MOCS_ENTRIES; @@ -521,13 +509,8 @@ static unsigned int get_mocs_settings(const struct drm_i915_private *i915, table->wb_index = 2; table->unused_entries_index = 2; } else if (IS_DG2(i915)) { - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) { - table->size = ARRAY_SIZE(dg2_mocs_table_g10_ax); - table->table = dg2_mocs_table_g10_ax; - } else { - table->size = ARRAY_SIZE(dg2_mocs_table); - table->table = dg2_mocs_table; - } + table->size = ARRAY_SIZE(dg2_mocs_table); + table->table = dg2_mocs_table; table->uc_index = 1; table->n_entries = GEN9_NUM_MOCS_ENTRIES; table->unused_entries_index = 3; diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index 58bb1c55294c..8b67abd720be 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -118,14 +118,12 @@ static void gen11_rc6_enable(struct intel_rc6 *rc6) GEN6_RC_CTL_EI_MODE(1); /* - * Wa_16011777198 and BSpec 52698 - Render powergating must be off. + * BSpec 52698 - Render powergating must be off. * FIXME BSpec is outdated, disabling powergating for MTL is just * temporary wa and should be removed after fixing real cause * of forcewake timeouts. */ - if (IS_METEORLAKE(gt->i915) || - IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || - IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0)) + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) pg_enable = GEN9_MEDIA_PG_ENABLE | GEN11_MEDIA_SAMPLER_PG_ENABLE; @@ -526,8 +524,7 @@ static bool rc6_supported(struct intel_rc6 *rc6) return false; } - if (IS_MTL_MEDIA_STEP(gt->i915, STEP_A0, STEP_B0) && - gt->type == GT_MEDIA) { + if (IS_MEDIA_GT_IP_STEP(gt, IP_VER(13, 0), STEP_A0, STEP_B0)) { drm_notice(&i915->drm, "Media RC6 disabled on A step\n"); return false; diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index cc6bd21a3e51..d5ed904f355d 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -26,6 +26,7 @@ #include "intel_engine_regs.h" #include "intel_gt.h" #include "intel_gt_pm.h" +#include "intel_gt_print.h" #include "intel_gt_requests.h" #include "intel_mchbar_regs.h" #include "intel_pci_config.h" @@ -161,16 +162,16 @@ static int i915_do_reset(struct intel_gt *gt, struct pci_dev *pdev = to_pci_dev(gt->i915->drm.dev); int err; - /* Assert reset for at least 20 usec, and wait for acknowledgement. */ + /* Assert reset for at least 50 usec, and wait for acknowledgement. */ pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE); udelay(50); - err = wait_for_atomic(i915_in_reset(pdev), 50); + err = _wait_for_atomic(i915_in_reset(pdev), 50000, 0); /* Clear the reset request. */ pci_write_config_byte(pdev, I915_GDRST, 0); udelay(50); if (!err) - err = wait_for_atomic(!i915_in_reset(pdev), 50); + err = _wait_for_atomic(!i915_in_reset(pdev), 50000, 0); return err; } @@ -190,7 +191,7 @@ static int g33_do_reset(struct intel_gt *gt, struct pci_dev *pdev = to_pci_dev(gt->i915->drm.dev); pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE); - return wait_for_atomic(g4x_reset_complete(pdev), 50); + return _wait_for_atomic(g4x_reset_complete(pdev), 50000, 0); } static int g4x_do_reset(struct intel_gt *gt, @@ -207,7 +208,7 @@ static int g4x_do_reset(struct intel_gt *gt, pci_write_config_byte(pdev, I915_GDRST, GRDOM_MEDIA | GRDOM_RESET_ENABLE); - ret = wait_for_atomic(g4x_reset_complete(pdev), 50); + ret = _wait_for_atomic(g4x_reset_complete(pdev), 50000, 0); if (ret) { GT_TRACE(gt, "Wait for media reset failed\n"); goto out; @@ -215,7 +216,7 @@ static int g4x_do_reset(struct intel_gt *gt, pci_write_config_byte(pdev, I915_GDRST, GRDOM_RENDER | GRDOM_RESET_ENABLE); - ret = wait_for_atomic(g4x_reset_complete(pdev), 50); + ret = _wait_for_atomic(g4x_reset_complete(pdev), 50000, 0); if (ret) { GT_TRACE(gt, "Wait for render reset failed\n"); goto out; @@ -592,10 +593,10 @@ static int gen8_engine_reset_prepare(struct intel_engine_cs *engine) ret = __intel_wait_for_register_fw(uncore, reg, mask, ack, 700, 0, NULL); if (ret) - drm_err(&engine->i915->drm, - "%s reset request timed out: {request: %08x, RESET_CTL: %08x}\n", - engine->name, request, - intel_uncore_read_fw(uncore, reg)); + gt_err(engine->gt, + "%s reset request timed out: {request: %08x, RESET_CTL: %08x}\n", + engine->name, request, + intel_uncore_read_fw(uncore, reg)); return ret; } @@ -705,7 +706,7 @@ static int __reset_guc(struct intel_gt *gt) static bool needs_wa_14015076503(struct intel_gt *gt, intel_engine_mask_t engine_mask) { - if (!IS_METEORLAKE(gt->i915) || !HAS_ENGINE(gt, GSC0)) + if (MEDIA_VER_FULL(gt->i915) != IP_VER(13, 0) || !HAS_ENGINE(gt, GSC0)) return false; if (!__HAS_ENGINE(engine_mask, GSC0)) @@ -785,9 +786,7 @@ int __intel_gt_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask) reset_mask = wa_14015076503_start(gt, engine_mask, !retry); GT_TRACE(gt, "engine_mask=%x\n", reset_mask); - preempt_disable(); ret = reset(gt, reset_mask, retry); - preempt_enable(); wa_14015076503_end(gt, reset_mask); } @@ -1201,17 +1200,16 @@ void intel_gt_reset(struct intel_gt *gt, goto unlock; if (reason) - drm_notice(>->i915->drm, - "Resetting chip for %s\n", reason); + gt_notice(gt, "Resetting chip for %s\n", reason); atomic_inc(>->i915->gpu_error.reset_count); awake = reset_prepare(gt); if (!intel_has_gpu_reset(gt)) { if (gt->i915->params.reset) - drm_err(>->i915->drm, "GPU reset not supported\n"); + gt_err(gt, "GPU reset not supported\n"); else - drm_dbg(>->i915->drm, "GPU reset disabled\n"); + gt_dbg(gt, "GPU reset disabled\n"); goto error; } @@ -1219,7 +1217,7 @@ void intel_gt_reset(struct intel_gt *gt, intel_runtime_pm_disable_interrupts(gt->i915); if (do_reset(gt, stalled_mask)) { - drm_err(>->i915->drm, "Failed to reset chip\n"); + gt_err(gt, "Failed to reset chip\n"); goto taint; } @@ -1238,9 +1236,7 @@ void intel_gt_reset(struct intel_gt *gt, */ ret = intel_gt_init_hw(gt); if (ret) { - drm_err(>->i915->drm, - "Failed to initialise HW following reset (%d)\n", - ret); + gt_err(gt, "Failed to initialise HW following reset (%d)\n", ret); goto taint; } @@ -1607,9 +1603,7 @@ static void intel_wedge_me(struct work_struct *work) { struct intel_wedge_me *w = container_of(work, typeof(*w), work.work); - drm_err(&w->gt->i915->drm, - "%s timed out, cancelling all in-flight rendering.\n", - w->name); + gt_err(w->gt, "%s timed out, cancelling all in-flight rendering.\n", w->name); intel_gt_set_wedged(w->gt); } @@ -1632,6 +1626,24 @@ void __intel_fini_wedge(struct intel_wedge_me *w) w->gt = NULL; } +/* + * Wa_22011802037 requires that we (or the GuC) ensure that no command + * streamers are executing MI_FORCE_WAKE while an engine reset is initiated. + */ +bool intel_engine_reset_needs_wa_22011802037(struct intel_gt *gt) +{ + if (GRAPHICS_VER(gt->i915) < 11) + return false; + + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0)) + return true; + + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) + return false; + + return true; +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftest_reset.c" #include "selftest_hangcheck.c" diff --git a/drivers/gpu/drm/i915/gt/intel_reset.h b/drivers/gpu/drm/i915/gt/intel_reset.h index 25c975b6e8fc..f615b30b81c5 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.h +++ b/drivers/gpu/drm/i915/gt/intel_reset.h @@ -78,4 +78,6 @@ void __intel_fini_wedge(struct intel_wedge_me *w); bool intel_has_gpu_reset(const struct intel_gt *gt); bool intel_has_reset_engine(const struct intel_gt *gt); +bool intel_engine_reset_needs_wa_22011802037(struct intel_gt *gt); + #endif /* I915_RESET_H */ diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 092542f53aad..4feef874e6d6 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1161,7 +1161,7 @@ void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *c { struct drm_i915_private *i915 = rps_to_i915(rps); - if (IS_METEORLAKE(i915)) + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) return mtl_get_freq_caps(rps, caps); else return __gen6_rps_get_freq_caps(rps, caps); diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 3ae0dbd39eaa..192ac0e59afa 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -11,6 +11,7 @@ #include "intel_gpu_commands.h" #include "intel_gt.h" #include "intel_gt_mcr.h" +#include "intel_gt_print.h" #include "intel_gt_regs.h" #include "intel_ring.h" #include "intel_workarounds.h" @@ -119,8 +120,8 @@ static void wa_init_finish(struct i915_wa_list *wal) if (!wal->count) return; - drm_dbg(&wal->gt->i915->drm, "Initialized %u %s workarounds on %s\n", - wal->wa_count, wal->name, wal->engine_name); + gt_dbg(wal->gt, "Initialized %u %s workarounds on %s\n", + wal->wa_count, wal->name, wal->engine_name); } static enum forcewake_domains @@ -764,68 +765,41 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine, { dg2_ctx_gt_tuning_init(engine, wal); - /* Wa_16011186671:dg2_g11 */ - if (IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) { - wa_mcr_masked_dis(wal, VFLSKPD, DIS_MULT_MISS_RD_SQUASH); - wa_mcr_masked_en(wal, VFLSKPD, DIS_OVER_FETCH_CACHE); - } - - if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) { - /* Wa_14010469329:dg2_g10 */ - wa_mcr_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, - XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE); - - /* - * Wa_22010465075:dg2_g10 - * Wa_22010613112:dg2_g10 - * Wa_14010698770:dg2_g10 - */ - wa_mcr_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, - GEN12_DISABLE_CPS_AWARE_COLOR_PIPE); - } - /* Wa_16013271637:dg2 */ wa_mcr_masked_en(wal, XEHP_SLICE_COMMON_ECO_CHICKEN1, MSC_MSAA_REODER_BUF_BYPASS_DISABLE); /* Wa_14014947963:dg2 */ - if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_B0, STEP_FOREVER) || - IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915)) - wa_masked_field_set(wal, VF_PREEMPTION, PREEMPTION_VERTEX_COUNT, 0x4000); + wa_masked_field_set(wal, VF_PREEMPTION, PREEMPTION_VERTEX_COUNT, 0x4000); /* Wa_18018764978:dg2 */ - if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_C0, STEP_FOREVER) || - IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915)) - wa_mcr_masked_en(wal, XEHP_PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL); - - /* Wa_15010599737:dg2 */ - wa_mcr_masked_en(wal, CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN); + wa_mcr_masked_en(wal, XEHP_PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL); /* Wa_18019271663:dg2 */ wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE); } -static void mtl_ctx_gt_tuning_init(struct intel_engine_cs *engine, - struct i915_wa_list *wal) +static void xelpg_ctx_gt_tuning_init(struct intel_engine_cs *engine, + struct i915_wa_list *wal) { - struct drm_i915_private *i915 = engine->i915; + struct intel_gt *gt = engine->gt; dg2_ctx_gt_tuning_init(engine, wal); - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_B0, STEP_FOREVER) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_B0, STEP_FOREVER)) + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER)) wa_add(wal, DRAW_WATERMARK, VERT_WM_VAL, 0x3FF, 0, false); } -static void mtl_ctx_workarounds_init(struct intel_engine_cs *engine, - struct i915_wa_list *wal) +static void xelpg_ctx_workarounds_init(struct intel_engine_cs *engine, + struct i915_wa_list *wal) { - struct drm_i915_private *i915 = engine->i915; + struct intel_gt *gt = engine->gt; - mtl_ctx_gt_tuning_init(engine, wal); + xelpg_ctx_gt_tuning_init(engine, wal); - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) { + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) { /* Wa_14014947963 */ wa_masked_field_set(wal, VF_PREEMPTION, PREEMPTION_VERTEX_COUNT, 0x4000); @@ -931,8 +905,8 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine, if (engine->class != RENDER_CLASS) goto done; - if (IS_METEORLAKE(i915)) - mtl_ctx_workarounds_init(engine, wal); + if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 71))) + xelpg_ctx_workarounds_init(engine, wal); else if (IS_PONTEVECCHIO(i915)) ; /* noop; none at this time */ else if (IS_DG2(i915)) @@ -1606,31 +1580,11 @@ xehpsdv_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) static void dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - struct intel_engine_cs *engine; - int id; - xehp_init_mcr(gt, wal); /* Wa_14011060649:dg2 */ wa_14011060649(gt, wal); - /* - * Although there are per-engine instances of these registers, - * they technically exist outside the engine itself and are not - * impacted by engine resets. Furthermore, they're part of the - * GuC blacklist so trying to treat them as engine workarounds - * will result in GuC initialization failure and a wedged GPU. - */ - for_each_engine(engine, gt, id) { - if (engine->class != VIDEO_DECODE_CLASS) - continue; - - /* Wa_16010515920:dg2_g10 */ - if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) - wa_write_or(wal, VDBOX_CGCTL3F18(engine->mmio_base), - ALNUNIT_CLKGATE_DIS); - } - if (IS_DG2_G10(gt->i915)) { /* Wa_22010523718:dg2 */ wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE, @@ -1641,70 +1595,15 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) DSS_ROUTER_CLKGATE_DIS); } - if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0) || - IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0)) { - /* Wa_14012362059:dg2 */ - wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB); - } - - if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) { - /* Wa_14010948348:dg2_g10 */ - wa_write_or(wal, UNSLCGCTL9430, MSQDUNIT_CLKGATE_DIS); - - /* Wa_14011037102:dg2_g10 */ - wa_write_or(wal, UNSLCGCTL9444, LTCDD_CLKGATE_DIS); - - /* Wa_14011371254:dg2_g10 */ - wa_mcr_write_or(wal, XEHP_SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS); - - /* Wa_14011431319:dg2_g10 */ - wa_write_or(wal, UNSLCGCTL9440, GAMTLBOACS_CLKGATE_DIS | - GAMTLBVDBOX7_CLKGATE_DIS | - GAMTLBVDBOX6_CLKGATE_DIS | - GAMTLBVDBOX5_CLKGATE_DIS | - GAMTLBVDBOX4_CLKGATE_DIS | - GAMTLBVDBOX3_CLKGATE_DIS | - GAMTLBVDBOX2_CLKGATE_DIS | - GAMTLBVDBOX1_CLKGATE_DIS | - GAMTLBVDBOX0_CLKGATE_DIS | - GAMTLBKCR_CLKGATE_DIS | - GAMTLBGUC_CLKGATE_DIS | - GAMTLBBLT_CLKGATE_DIS); - wa_write_or(wal, UNSLCGCTL9444, GAMTLBGFXA0_CLKGATE_DIS | - GAMTLBGFXA1_CLKGATE_DIS | - GAMTLBCOMPA0_CLKGATE_DIS | - GAMTLBCOMPA1_CLKGATE_DIS | - GAMTLBCOMPB0_CLKGATE_DIS | - GAMTLBCOMPB1_CLKGATE_DIS | - GAMTLBCOMPC0_CLKGATE_DIS | - GAMTLBCOMPC1_CLKGATE_DIS | - GAMTLBCOMPD0_CLKGATE_DIS | - GAMTLBCOMPD1_CLKGATE_DIS | - GAMTLBMERT_CLKGATE_DIS | - GAMTLBVEBOX3_CLKGATE_DIS | - GAMTLBVEBOX2_CLKGATE_DIS | - GAMTLBVEBOX1_CLKGATE_DIS | - GAMTLBVEBOX0_CLKGATE_DIS); - - /* Wa_14010569222:dg2_g10 */ - wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE, - GAMEDIA_CLKGATE_DIS); - - /* Wa_14011028019:dg2_g10 */ - wa_mcr_write_or(wal, SSMCGCTL9530, RTFUNIT_CLKGATE_DIS); - - /* Wa_14010680813:dg2_g10 */ - wa_mcr_write_or(wal, XEHP_GAMSTLB_CTRL, - CONTROL_BLOCK_CLKGATE_DIS | - EGRESS_BLOCK_CLKGATE_DIS | - TAG_BLOCK_CLKGATE_DIS); - } - /* Wa_14014830051:dg2 */ wa_mcr_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN); - /* Wa_14015795083 */ - wa_write_clr(wal, GEN7_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); + /* + * Wa_14015795083 + * Skip verification for possibly locked register. + */ + wa_add(wal, GEN7_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE, + 0, 0, false); /* Wa_18018781329 */ wa_mcr_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB); @@ -1747,8 +1646,8 @@ xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) /* Wa_22016670082 */ wa_write_or(wal, GEN12_SQCNT1, GEN12_STRICT_RAR_ENABLE); - if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(gt->i915, P, STEP_A0, STEP_B0)) { + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) { /* Wa_14014830051 */ wa_mcr_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN); @@ -1791,10 +1690,8 @@ xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) */ static void gt_tuning_settings(struct intel_gt *gt, struct i915_wa_list *wal) { - if (IS_METEORLAKE(gt->i915)) { - if (gt->type != GT_MEDIA) - wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS); - + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) { + wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS); wa_mcr_write_or(wal, XEHP_SQCM, EN_32B_ACCESS); } @@ -1818,15 +1715,15 @@ gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal) gt_tuning_settings(gt, wal); if (gt->type == GT_MEDIA) { - if (MEDIA_VER(i915) >= 13) + if (MEDIA_VER_FULL(i915) == IP_VER(13, 0)) xelpmp_gt_workarounds_init(gt, wal); else - MISSING_CASE(MEDIA_VER(i915)); + MISSING_CASE(MEDIA_VER_FULL(i915)); return; } - if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) xelpg_gt_workarounds_init(gt, wal); else if (IS_PONTEVECCHIO(i915)) pvc_gt_workarounds_init(gt, wal); @@ -1884,10 +1781,10 @@ wa_verify(struct intel_gt *gt, const struct i915_wa *wa, u32 cur, const char *name, const char *from) { if ((cur ^ wa->set) & wa->read) { - drm_err(>->i915->drm, - "%s workaround lost on %s! (reg[%x]=0x%x, relevant bits were 0x%x vs expected 0x%x)\n", - name, from, i915_mmio_reg_offset(wa->reg), - cur, cur & wa->read, wa->set & wa->read); + gt_err(gt, + "%s workaround lost on %s! (reg[%x]=0x%x, relevant bits were 0x%x vs expected 0x%x)\n", + name, from, i915_mmio_reg_offset(wa->reg), + cur, cur & wa->read, wa->set & wa->read); return false; } @@ -2242,29 +2139,10 @@ static void dg2_whitelist_build(struct intel_engine_cs *engine) switch (engine->class) { case RENDER_CLASS: - /* - * Wa_1507100340:dg2_g10 - * - * This covers 4 registers which are next to one another : - * - PS_INVOCATION_COUNT - * - PS_INVOCATION_COUNT_UDW - * - PS_DEPTH_COUNT - * - PS_DEPTH_COUNT_UDW - */ - if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) - whitelist_reg_ext(w, PS_INVOCATION_COUNT, - RING_FORCE_TO_NONPRIV_ACCESS_RD | - RING_FORCE_TO_NONPRIV_RANGE_4); - /* Required by recommended tuning setting (not a workaround) */ whitelist_mcr_reg(w, XEHP_COMMON_SLICE_CHICKEN3); break; - case COMPUTE_CLASS: - /* Wa_16011157294:dg2_g10 */ - if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) - whitelist_reg(w, GEN9_CTX_PREEMPT_REG); - break; default: break; } @@ -2294,7 +2172,7 @@ static void pvc_whitelist_build(struct intel_engine_cs *engine) blacklist_trtt(engine); } -static void mtl_whitelist_build(struct intel_engine_cs *engine) +static void xelpg_whitelist_build(struct intel_engine_cs *engine) { struct i915_wa_list *w = &engine->whitelist; @@ -2316,8 +2194,10 @@ void intel_engine_init_whitelist(struct intel_engine_cs *engine) wa_init_start(w, engine->gt, "whitelist", engine->name); - if (IS_METEORLAKE(i915)) - mtl_whitelist_build(engine); + if (engine->gt->type == GT_MEDIA) + ; /* none yet */ + else if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 71))) + xelpg_whitelist_build(engine); else if (IS_PONTEVECCHIO(i915)) pvc_whitelist_build(engine); else if (IS_DG2(i915)) @@ -2415,62 +2295,35 @@ engine_fake_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) } } -static bool needs_wa_1308578152(struct intel_engine_cs *engine) -{ - return intel_sseu_find_first_xehp_dss(&engine->gt->info.sseu, 0, 0) >= - GEN_DSS_PER_GSLICE; -} - static void rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { struct drm_i915_private *i915 = engine->i915; + struct intel_gt *gt = engine->gt; - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) { + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) { /* Wa_22014600077 */ wa_mcr_masked_en(wal, GEN10_CACHE_MODE_SS, ENABLE_EU_COUNT_FOR_TDL_FLUSH); } - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) || - IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || - IS_DG2_G11(i915) || IS_DG2_G12(i915)) { + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0) || + IS_DG2(i915)) { /* Wa_1509727124 */ wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE, SC_DISABLE_POWER_OPTIMIZATION_EBB); } - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || - IS_DG2_G11(i915) || IS_DG2_G12(i915) || - IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0)) { + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_DG2(i915)) { /* Wa_22012856258 */ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_DISABLE_READ_SUPPRESSION); } - if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) { - /* Wa_14013392000:dg2_g11 */ - wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE); - } - - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0) || - IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) { - /* Wa_14012419201:dg2 */ - wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, - GEN12_DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX); - } - - /* Wa_1308578152:dg2_g10 when first gslice is fused off */ - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) && - needs_wa_1308578152(engine)) { - wa_masked_dis(wal, GEN12_CS_DEBUG_MODE1_CCCSUNIT_BE_COMMON, - GEN12_REPLAY_MODE_GRANULARITY); - } - - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || - IS_DG2_G11(i915) || IS_DG2_G12(i915)) { + if (IS_DG2(i915)) { /* * Wa_22010960976:dg2 * Wa_14013347512:dg2 @@ -2479,34 +2332,15 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK); } - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) { - /* - * Wa_1608949956:dg2_g10 - * Wa_14010198302:dg2_g10 - */ - wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, - MDQ_ARBITRATION_MODE | UGM_BACKUP_MODE); + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)) || + IS_DG2(i915)) { + /* Wa_14015150844 */ + wa_mcr_add(wal, XEHP_HDC_CHICKEN0, 0, + _MASKED_BIT_ENABLE(DIS_ATOMIC_CHAINING_TYPED_WRITES), + 0, true); } - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) - /* Wa_22010430635:dg2 */ - wa_mcr_masked_en(wal, - GEN9_ROW_CHICKEN4, - GEN12_DISABLE_GRF_CLEAR); - - /* Wa_14013202645:dg2 */ - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) || - IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) - wa_mcr_write_or(wal, RT_CTRL, DIS_NULL_QUERY); - - /* Wa_22012532006:dg2 */ - if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_C0) || - IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) - wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7, - DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA); - - if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_B0, STEP_FOREVER) || - IS_DG2_G10(i915)) { + if (IS_DG2_G11(i915) || IS_DG2_G10(i915)) { /* Wa_22014600077:dg2 */ wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, _MASKED_BIT_ENABLE(ENABLE_EU_COUNT_FOR_TDL_FLUSH), @@ -2514,6 +2348,19 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) true); } + if (IS_DG2(i915) || IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || + IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { + /* + * Wa_1606700617:tgl,dg1,adl-p + * Wa_22010271021:tgl,rkl,dg1,adl-s,adl-p + * Wa_14010826681:tgl,dg1,rkl,adl-p + * Wa_18019627453:dg2 + */ + wa_masked_en(wal, + GEN9_CS_DEBUG_MODE1, + FF_DOP_CLOCK_GATE_DISABLE); + } + if (IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { /* Wa_1606931601:tgl,rkl,dg1,adl-s,adl-p */ @@ -2527,19 +2374,11 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) */ wa_write_or(wal, GEN7_FF_THREAD_MODE, GEN12_FF_TESSELATION_DOP_GATE_DISABLE); - } - if (IS_ALDERLAKE_P(i915) || IS_DG2(i915) || IS_ALDERLAKE_S(i915) || - IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { - /* - * Wa_1606700617:tgl,dg1,adl-p - * Wa_22010271021:tgl,rkl,dg1,adl-s,adl-p - * Wa_14010826681:tgl,dg1,rkl,adl-p - * Wa_18019627453:dg2 - */ - wa_masked_en(wal, - GEN9_CS_DEBUG_MODE1, - FF_DOP_CLOCK_GATE_DISABLE); + /* Wa_1406941453:tgl,rkl,dg1,adl-s,adl-p */ + wa_mcr_masked_en(wal, + GEN10_SAMPLER_MODE, + ENABLE_SMALLPL); } if (IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || @@ -2566,14 +2405,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN8_RC_SEMA_IDLE_MSG_DISABLE); } - if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) || - IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) { - /* Wa_1406941453:tgl,rkl,dg1,adl-s,adl-p */ - wa_mcr_masked_en(wal, - GEN10_SAMPLER_MODE, - ENABLE_SMALLPL); - } - if (GRAPHICS_VER(i915) == 11) { /* This is not an Wa. Enable for better image quality */ wa_masked_en(wal, @@ -2975,10 +2806,12 @@ ccs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) * function invoked by __intel_engine_init_ctx_wa(). */ static void -add_render_compute_tuning_settings(struct drm_i915_private *i915, +add_render_compute_tuning_settings(struct intel_gt *gt, struct i915_wa_list *wal) { - if (IS_METEORLAKE(i915) || IS_DG2(i915)) + struct drm_i915_private *i915 = gt->i915; + + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)) || IS_DG2(i915)) wa_mcr_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512); /* @@ -3007,8 +2840,9 @@ static void general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { struct drm_i915_private *i915 = engine->i915; + struct intel_gt *gt = engine->gt; - add_render_compute_tuning_settings(i915, wal); + add_render_compute_tuning_settings(gt, wal); if (GRAPHICS_VER(i915) >= 11) { /* This is not a Wa (although referred to as @@ -3029,13 +2863,13 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li GEN11_INDIRECT_STATE_BASE_ADDR_OVERRIDE); } - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_B0, STEP_FOREVER) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_B0, STEP_FOREVER)) + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER)) /* Wa_14017856879 */ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN3, MTL_DISABLE_FIX_FOR_EOT_FLUSH); - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) /* * Wa_14017066071 * Wa_14017654203 @@ -3043,37 +2877,47 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE, MTL_DISABLE_SAMPLER_SC_OOO); - if (IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) /* Wa_22015279794 */ wa_mcr_masked_en(wal, GEN10_CACHE_MODE_SS, DISABLE_PREFETCH_INTO_IC); - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) || - IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || - IS_DG2_G11(i915) || IS_DG2_G12(i915)) { + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0) || + IS_DG2(i915)) { /* Wa_22013037850 */ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DISABLE_128B_EVICTION_COMMAND_UDW); + + /* Wa_18017747507 */ + wa_masked_en(wal, VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE); } - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) || + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0) || IS_PONTEVECCHIO(i915) || IS_DG2(i915)) { /* Wa_22014226127 */ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, DISABLE_D8_D16_COASLESCE); } - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) || - IS_DG2(i915)) { - /* Wa_18017747507 */ - wa_masked_en(wal, VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE); + if (IS_PONTEVECCHIO(i915) || IS_DG2(i915)) { + /* Wa_14015227452:dg2,pvc */ + wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE); + + /* Wa_16015675438:dg2,pvc */ + wa_masked_en(wal, FF_SLICE_CS_CHICKEN2, GEN12_PERF_FIX_BALANCING_CFE_DISABLE); } - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) || - IS_DG2_G11(i915)) { + if (IS_DG2(i915)) { + /* + * Wa_16011620976:dg2_g11 + * Wa_22015475538:dg2 + */ + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); + } + + if (IS_DG2_G11(i915)) { /* * Wa_22012826095:dg2 * Wa_22013059131:dg2 @@ -3085,18 +2929,23 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li /* Wa_22013059131:dg2 */ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, FORCE_1_SUB_MESSAGE_PER_FRAGMENT); - } - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) { /* - * Wa_14010918519:dg2_g10 + * Wa_22012654132 * - * LSC_CHICKEN_BIT_0 always reads back as 0 is this stepping, - * so ignoring verification. + * Note that register 0xE420 is write-only and cannot be read + * back for verification on DG2 (due to Wa_14012342262), so + * we need to explicitly skip the readback. */ - wa_mcr_add(wal, LSC_CHICKEN_BIT_0_UDW, 0, - FORCE_SLM_FENCE_SCOPE_TO_TILE | FORCE_UGM_FENCE_SCOPE_TO_TILE, - 0, false); + wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, + _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC), + 0 /* write-only, so skip validation */, + true); + } + + if (IS_DG2_G10(i915) || IS_DG2_G12(i915)) { + /* Wa_18028616096 */ + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, UGM_FRAGMENT_THRESHOLD_TO_3); } if (IS_XEHPSDV(i915)) { @@ -3114,35 +2963,6 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE); } - - if (IS_DG2(i915) || IS_PONTEVECCHIO(i915)) { - /* Wa_14015227452:dg2,pvc */ - wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE); - - /* Wa_16015675438:dg2,pvc */ - wa_masked_en(wal, FF_SLICE_CS_CHICKEN2, GEN12_PERF_FIX_BALANCING_CFE_DISABLE); - } - - if (IS_DG2(i915)) { - /* - * Wa_16011620976:dg2_g11 - * Wa_22015475538:dg2 - */ - wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); - } - - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_C0) || IS_DG2_G11(i915)) - /* - * Wa_22012654132 - * - * Note that register 0xE420 is write-only and cannot be read - * back for verification on DG2 (due to Wa_14012342262), so - * we need to explicitly skip the readback. - */ - wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, - _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC), - 0 /* write-only, so skip validation */, - true); } static void diff --git a/drivers/gpu/drm/i915/gt/selftest_migrate.c b/drivers/gpu/drm/i915/gt/selftest_migrate.c index 3def5ca72dec..1a34cbe04fb6 100644 --- a/drivers/gpu/drm/i915/gt/selftest_migrate.c +++ b/drivers/gpu/drm/i915/gt/selftest_migrate.c @@ -710,7 +710,7 @@ static int threaded_migrate(struct intel_migrate *migrate, thread[i].tsk = tsk; } - msleep(10); /* start all threads before we kthread_stop() */ + msleep(10 * n_cpus); /* start all threads before we kthread_stop() */ for (i = 0; i < n_cpus; ++i) { struct task_struct *tsk = thread[i].tsk; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c index 0d3b22a74365..453d855dd1de 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c @@ -68,8 +68,7 @@ static void gsc_work(struct work_struct *work) * A proxy failure right after firmware load means the proxy-init * step has failed so mark GSC as not usable after this */ - drm_err(>->i915->drm, - "GSC proxy handler failed to init\n"); + gt_err(gt, "GSC proxy handler failed to init\n"); intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL); } goto out_put; @@ -83,11 +82,10 @@ static void gsc_work(struct work_struct *work) * status register to check if the proxy init was actually successful */ if (intel_gsc_uc_fw_proxy_init_done(gsc, false)) { - drm_dbg(>->i915->drm, "GSC Proxy initialized\n"); + gt_dbg(gt, "GSC Proxy initialized\n"); intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_RUNNING); } else { - drm_err(>->i915->drm, - "GSC status reports proxy init not complete\n"); + gt_err(gt, "GSC status reports proxy init not complete\n"); intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL); } } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c index 89ed5ee9cded..2fde5c360cff 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c @@ -81,8 +81,17 @@ out_rq: i915_request_add(rq); - if (!err && i915_request_wait(rq, 0, msecs_to_jiffies(500)) < 0) - err = -ETIME; + if (!err) { + /* + * Start timeout for i915_request_wait only after considering one possible + * pending GSC-HECI submission cycle on the other (non-privileged) path. + */ + if (wait_for(i915_request_started(rq), GSC_HECI_REPLY_LATENCY_MS)) + drm_dbg(&gsc_uc_to_gt(gsc)->i915->drm, + "Delay in gsc-heci-priv submission to gsccs-hw"); + if (i915_request_wait(rq, 0, msecs_to_jiffies(GSC_HECI_REPLY_LATENCY_MS)) < 0) + err = -ETIME; + } i915_request_put(rq); @@ -186,6 +195,13 @@ out_rq: i915_request_add(rq); if (!err) { + /* + * Start timeout for i915_request_wait only after considering one possible + * pending GSC-HECI submission cycle on the other (privileged) path. + */ + if (wait_for(i915_request_started(rq), GSC_HECI_REPLY_LATENCY_MS)) + drm_dbg(&gsc_uc_to_gt(gsc)->i915->drm, + "Delay in gsc-heci-non-priv submission to gsccs-hw"); if (i915_request_wait(rq, I915_WAIT_INTERRUPTIBLE, msecs_to_jiffies(timeout_ms)) < 0) err = -ETIME; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.h b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.h index 09d3fbdad05a..c4308291c003 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.h @@ -12,6 +12,12 @@ struct i915_vma; struct intel_context; struct intel_gsc_uc; +#define GSC_HECI_REPLY_LATENCY_MS 500 +/* + * Max FW response time is 500ms, but this should be counted from the time the + * command has hit the GSC-CS hardware, not the preceding handoff to GuC CTB. + */ + struct intel_gsc_mtl_header { u32 validity_marker; #define GSC_HECI_VALIDITY_MARKER 0xA578875A diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index 569b5fe94c41..3f3df1166b86 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -159,6 +159,21 @@ static void gen11_disable_guc_interrupts(struct intel_guc *guc) gen11_reset_guc_interrupts(guc); } +static void guc_dead_worker_func(struct work_struct *w) +{ + struct intel_guc *guc = container_of(w, struct intel_guc, dead_guc_worker); + struct intel_gt *gt = guc_to_gt(guc); + unsigned long last = guc->last_dead_guc_jiffies; + unsigned long delta = jiffies_to_msecs(jiffies - last); + + if (delta < 500) { + intel_gt_set_wedged(gt); + } else { + intel_gt_handle_error(gt, ALL_ENGINES, I915_ERROR_CAPTURE, "dead GuC"); + guc->last_dead_guc_jiffies = jiffies; + } +} + void intel_guc_init_early(struct intel_guc *guc) { struct intel_gt *gt = guc_to_gt(guc); @@ -171,6 +186,8 @@ void intel_guc_init_early(struct intel_guc *guc) intel_guc_slpc_init_early(&guc->slpc); intel_guc_rc_init_early(guc); + INIT_WORK(&guc->dead_guc_worker, guc_dead_worker_func); + mutex_init(&guc->send_mutex); spin_lock_init(&guc->irq_lock); if (GRAPHICS_VER(i915) >= 11) { @@ -272,18 +289,14 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc) GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 50)) flags |= GUC_WA_POLLCS; - /* Wa_16011759253:dg2_g10:a0 */ - if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) - flags |= GUC_WA_GAM_CREDITS; - /* Wa_14014475959 */ - if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) || + if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || IS_DG2(gt->i915)) flags |= GUC_WA_HOLD_CCS_SWITCHOUT; /* - * Wa_14012197797:dg2_g10:a0,dg2_g11:a0 - * Wa_22011391025:dg2_g10,dg2_g11,dg2_g12 + * Wa_14012197797 + * Wa_22011391025 * * The same WA bit is used for both and 22011391025 is applicable to * all DG2. @@ -292,28 +305,26 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc) flags |= GUC_WA_DUAL_QUEUE; /* Wa_22011802037: graphics version 11/12 */ - if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) || - (GRAPHICS_VER(gt->i915) >= 11 && - GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 70))) + if (intel_engine_reset_needs_wa_22011802037(gt)) flags |= GUC_WA_PRE_PARSER; - /* Wa_16011777198:dg2 */ - if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || - IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0)) - flags |= GUC_WA_RCS_RESET_BEFORE_RC6; - /* - * Wa_22012727170:dg2_g10[a0-c0), dg2_g11[a0..) - * Wa_22012727685:dg2_g11[a0..) + * Wa_22012727170 + * Wa_22012727685 */ - if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || - IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_FOREVER)) + if (IS_DG2_G11(gt->i915)) flags |= GUC_WA_CONTEXT_ISOLATION; /* Wa_16015675438 */ if (!RCS_MASK(gt)) flags |= GUC_WA_RCS_REGS_IN_CCS_REGS_LIST; + /* Wa_14018913170 */ + if (GUC_FIRMWARE_VER(guc) >= MAKE_GUC_VER(70, 7, 0)) { + if (IS_DG2(gt->i915) || IS_METEORLAKE(gt->i915) || IS_PONTEVECCHIO(gt->i915)) + flags |= GUC_WA_ENABLE_TSC_CHECK_ON_RC6; + } + return flags; } @@ -461,6 +472,8 @@ void intel_guc_fini(struct intel_guc *guc) if (!intel_uc_fw_is_loadable(&guc->fw)) return; + flush_work(&guc->dead_guc_worker); + if (intel_guc_slpc_is_used(guc)) intel_guc_slpc_fini(&guc->slpc); @@ -585,6 +598,20 @@ out: return ret; } +int intel_guc_crash_process_msg(struct intel_guc *guc, u32 action) +{ + if (action == INTEL_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED) + guc_err(guc, "Crash dump notification\n"); + else if (action == INTEL_GUC_ACTION_NOTIFY_EXCEPTION) + guc_err(guc, "Exception notification\n"); + else + guc_err(guc, "Unknown crash notification: 0x%04X\n", action); + + queue_work(system_unbound_wq, &guc->dead_guc_worker); + + return 0; +} + int intel_guc_to_host_process_recv_msg(struct intel_guc *guc, const u32 *payload, u32 len) { @@ -601,6 +628,9 @@ int intel_guc_to_host_process_recv_msg(struct intel_guc *guc, if (msg & INTEL_GUC_RECV_MSG_EXCEPTION) guc_err(guc, "Received early exception notification!\n"); + if (msg & (INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED | INTEL_GUC_RECV_MSG_EXCEPTION)) + queue_work(system_unbound_wq, &guc->dead_guc_worker); + return 0; } @@ -640,6 +670,8 @@ int intel_guc_suspend(struct intel_guc *guc) return 0; if (intel_guc_submission_is_used(guc)) { + flush_work(&guc->dead_guc_worker); + /* * This H2G MMIO command tears down the GuC in two steps. First it will * generate a G2H CTB for every active context indicating a reset. In diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 8dc291ff0093..818c8c146fd4 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -266,6 +266,20 @@ struct intel_guc { unsigned long last_stat_jiffies; } timestamp; + /** + * @dead_guc_worker: Asynchronous worker thread for forcing a GuC reset. + * Specifically used when the G2H handler wants to issue a reset. Resets + * require flushing the G2H queue. So, the G2H processing itself must not + * trigger a reset directly. Instead, go via this worker. + */ + struct work_struct dead_guc_worker; + /** + * @last_dead_guc_jiffies: timestamp of previous 'dead guc' occurrance + * used to prevent a fundamentally broken system from continuously + * reloading the GuC. + */ + unsigned long last_dead_guc_jiffies; + #ifdef CONFIG_DRM_I915_SELFTEST /** * @number_guc_id_stolen: The number of guc_ids that have been stolen @@ -281,6 +295,7 @@ struct intel_guc { #define MAKE_GUC_VER(maj, min, pat) (((maj) << 16) | ((min) << 8) | (pat)) #define MAKE_GUC_VER_STRUCT(ver) MAKE_GUC_VER((ver).major, (ver).minor, (ver).patch) #define GUC_SUBMIT_VER(guc) MAKE_GUC_VER_STRUCT((guc)->submission_version) +#define GUC_FIRMWARE_VER(guc) MAKE_GUC_VER_STRUCT((guc)->fw.file_selected.ver) static inline struct intel_guc *log_to_guc(struct intel_guc_log *log) { @@ -476,6 +491,7 @@ int intel_guc_engine_failure_process_msg(struct intel_guc *guc, const u32 *msg, u32 len); int intel_guc_error_capture_process_msg(struct intel_guc *guc, const u32 *msg, u32 len); +int intel_guc_crash_process_msg(struct intel_guc *guc, u32 action); struct intel_engine_cs * intel_guc_lookup_engine(struct intel_guc *guc, u8 guc_class, u8 instance); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index 97eadd08181d..c33210ead1ef 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -96,7 +96,7 @@ struct ct_request { struct ct_incoming_msg { struct list_head link; u32 size; - u32 msg[]; + u32 msg[] __counted_by(size); }; enum { CTB_SEND = 0, CTB_RECV = 1 }; @@ -1112,12 +1112,8 @@ static int ct_process_request(struct intel_guc_ct *ct, struct ct_incoming_msg *r ret = 0; break; case INTEL_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED: - CT_ERROR(ct, "Received GuC crash dump notification!\n"); - ret = 0; - break; case INTEL_GUC_ACTION_NOTIFY_EXCEPTION: - CT_ERROR(ct, "Received GuC exception notification!\n"); - ret = 0; + ret = intel_guc_crash_process_msg(guc, action); break; default: ret = -EOPNOTSUPP; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index b4d56eccfb1f..123ad75d2eb2 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -100,6 +100,7 @@ #define GUC_WA_HOLD_CCS_SWITCHOUT BIT(17) #define GUC_WA_POLLCS BIT(18) #define GUC_WA_RCS_REGS_IN_CCS_REGS_LIST BIT(21) +#define GUC_WA_ENABLE_TSC_CHECK_ON_RC6 BIT(22) #define GUC_CTL_FEATURE 2 #define GUC_CTL_ENABLE_SLPC BIT(2) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c index 477df260ae3a..2dfb07cc4b33 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c @@ -138,17 +138,6 @@ static int guc_action_slpc_set_param(struct intel_guc *guc, u8 id, u32 value) return ret > 0 ? -EPROTO : ret; } -static int guc_action_slpc_unset_param(struct intel_guc *guc, u8 id) -{ - u32 request[] = { - GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST, - SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1), - id, - }; - - return intel_guc_send(guc, request, ARRAY_SIZE(request)); -} - static bool slpc_is_running(struct intel_guc_slpc *slpc) { return slpc_get_state(slpc) == SLPC_GLOBAL_STATE_RUNNING; @@ -199,15 +188,6 @@ static int slpc_set_param(struct intel_guc_slpc *slpc, u8 id, u32 value) return ret; } -static int slpc_unset_param(struct intel_guc_slpc *slpc, u8 id) -{ - struct intel_guc *guc = slpc_to_guc(slpc); - - GEM_BUG_ON(id >= SLPC_MAX_PARAM); - - return guc_action_slpc_unset_param(guc, id); -} - static int slpc_force_min_freq(struct intel_guc_slpc *slpc, u32 freq) { struct intel_guc *guc = slpc_to_guc(slpc); @@ -672,49 +652,6 @@ static void slpc_get_rp_values(struct intel_guc_slpc *slpc) slpc->boost_freq = slpc->rp0_freq; } -/** - * intel_guc_slpc_override_gucrc_mode() - override GUCRC mode - * @slpc: pointer to intel_guc_slpc. - * @mode: new value of the mode. - * - * This function will override the GUCRC mode. - * - * Return: 0 on success, non-zero error code on failure. - */ -int intel_guc_slpc_override_gucrc_mode(struct intel_guc_slpc *slpc, u32 mode) -{ - int ret; - struct drm_i915_private *i915 = slpc_to_i915(slpc); - intel_wakeref_t wakeref; - - if (mode >= SLPC_GUCRC_MODE_MAX) - return -EINVAL; - - with_intel_runtime_pm(&i915->runtime_pm, wakeref) { - ret = slpc_set_param(slpc, SLPC_PARAM_PWRGATE_RC_MODE, mode); - if (ret) - guc_err(slpc_to_guc(slpc), "Override RC mode %d failed: %pe\n", - mode, ERR_PTR(ret)); - } - - return ret; -} - -int intel_guc_slpc_unset_gucrc_mode(struct intel_guc_slpc *slpc) -{ - struct drm_i915_private *i915 = slpc_to_i915(slpc); - intel_wakeref_t wakeref; - int ret = 0; - - with_intel_runtime_pm(&i915->runtime_pm, wakeref) { - ret = slpc_unset_param(slpc, SLPC_PARAM_PWRGATE_RC_MODE); - if (ret) - guc_err(slpc_to_guc(slpc), "Unsetting RC mode failed: %pe\n", ERR_PTR(ret)); - } - - return ret; -} - /* * intel_guc_slpc_enable() - Start SLPC * @slpc: pointer to intel_guc_slpc. diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h index 597eb5413ddf..6ac6503c39d4 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h @@ -44,8 +44,6 @@ int intel_guc_slpc_set_media_ratio_mode(struct intel_guc_slpc *slpc, u32 val); void intel_guc_pm_intrmsk_enable(struct intel_gt *gt); void intel_guc_slpc_boost(struct intel_guc_slpc *slpc); void intel_guc_slpc_dec_waiters(struct intel_guc_slpc *slpc); -int intel_guc_slpc_unset_gucrc_mode(struct intel_guc_slpc *slpc); -int intel_guc_slpc_override_gucrc_mode(struct intel_guc_slpc *slpc, u32 mode); int intel_guc_slpc_set_ignore_eff_freq(struct intel_guc_slpc *slpc, bool val); #endif diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index a0e3ef1c65d2..2cce5ec1ff00 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1433,6 +1433,36 @@ static void guc_timestamp_ping(struct work_struct *wrk) int srcu, ret; /* + * Ideally the busyness worker should take a gt pm wakeref because the + * worker only needs to be active while gt is awake. However, the + * gt_park path cancels the worker synchronously and this complicates + * the flow if the worker is also running at the same time. The cancel + * waits for the worker and when the worker releases the wakeref, that + * would call gt_park and would lead to a deadlock. + * + * The resolution is to take the global pm wakeref if runtime pm is + * already active. If not, we don't need to update the busyness stats as + * the stats would already be updated when the gt was parked. + * + * Note: + * - We do not requeue the worker if we cannot take a reference to runtime + * pm since intel_guc_busyness_unpark would requeue the worker in the + * resume path. + * + * - If the gt was parked longer than time taken for GT timestamp to roll + * over, we ignore those rollovers since we don't care about tracking + * the exact GT time. We only care about roll overs when the gt is + * active and running workloads. + * + * - There is a window of time between gt_park and runtime suspend, + * where the worker may run. This is acceptable since the worker will + * not find any new data to update busyness. + */ + wakeref = intel_runtime_pm_get_if_active(>->i915->runtime_pm); + if (!wakeref) + return; + + /* * Synchronize with gt reset to make sure the worker does not * corrupt the engine/guc stats. NB: can't actually block waiting * for a reset to complete as the reset requires flushing out @@ -1440,10 +1470,9 @@ static void guc_timestamp_ping(struct work_struct *wrk) */ ret = intel_gt_reset_trylock(gt, &srcu); if (ret) - return; + goto err_trylock; - with_intel_runtime_pm(>->i915->runtime_pm, wakeref) - __update_guc_busyness_stats(guc); + __update_guc_busyness_stats(guc); /* adjust context stats for overflow */ xa_for_each(&guc->context_lookup, index, ce) @@ -1452,6 +1481,9 @@ static void guc_timestamp_ping(struct work_struct *wrk) intel_gt_reset_unlock(gt, srcu); guc_enable_busyness_worker(guc); + +err_trylock: + intel_runtime_pm_put(>->i915->runtime_pm, wakeref); } static int guc_action_enable_usage_stats(struct intel_guc *guc) @@ -1658,9 +1690,7 @@ static void guc_engine_reset_prepare(struct intel_engine_cs *engine) * Wa_22011802037: In addition to stopping the cs, we need * to wait for any pending mi force wakeups */ - if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) || - (GRAPHICS_VER(engine->i915) >= 11 && - GRAPHICS_VER_FULL(engine->i915) < IP_VER(12, 70))) { + if (intel_engine_reset_needs_wa_22011802037(engine->gt)) { intel_engine_stop_cs(engine); intel_engine_wait_for_pending_mi_fw(engine); } @@ -4267,7 +4297,7 @@ static void guc_default_vfuncs(struct intel_engine_cs *engine) /* Wa_14014475959:dg2 */ if (engine->class == COMPUTE_CLASS) - if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) || + if (IS_GFX_GT_IP_STEP(engine->gt, IP_VER(12, 70), STEP_A0, STEP_B0) || IS_DG2(engine->i915)) engine->flags |= I915_ENGINE_USES_WA_HOLD_CCS_SWITCHOUT; @@ -4772,19 +4802,19 @@ static void guc_context_replay(struct intel_context *ce) static void guc_handle_context_reset(struct intel_guc *guc, struct intel_context *ce) { + bool capture = intel_context_is_schedulable(ce); + trace_intel_context_reset(ce); - guc_dbg(guc, "Got context reset notification: 0x%04X on %s, exiting = %s, banned = %s\n", + guc_dbg(guc, "%s context reset notification: 0x%04X on %s, exiting = %s, banned = %s\n", + capture ? "Got" : "Ignoring", ce->guc_id.id, ce->engine->name, str_yes_no(intel_context_is_exiting(ce)), str_yes_no(intel_context_is_banned(ce))); - if (likely(intel_context_is_schedulable(ce))) { + if (capture) { capture_error_state(guc, ce); guc_context_replay(ce); - } else { - guc_info(guc, "Ignoring context reset notification of exiting context 0x%04X on %s", - ce->guc_id.id, ce->engine->name); } } @@ -5470,6 +5500,9 @@ guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count, ve->base.flags = I915_ENGINE_IS_VIRTUAL; + BUILD_BUG_ON(ilog2(VIRTUAL_ENGINES) < I915_NUM_ENGINES); + ve->base.mask = VIRTUAL_ENGINES; + intel_context_init(&ve->context, &ve->base); for (n = 0; n < count; n++) { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 8be005de1d28..362639162ed6 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -88,12 +88,12 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, * security fixes, etc. to be enabled. */ #define INTEL_GUC_FIRMWARE_DEFS(fw_def, guc_maj, guc_mmp) \ - fw_def(METEORLAKE, 0, guc_maj(mtl, 70, 6, 6)) \ - fw_def(DG2, 0, guc_maj(dg2, 70, 5, 1)) \ - fw_def(ALDERLAKE_P, 0, guc_maj(adlp, 70, 5, 1)) \ + fw_def(METEORLAKE, 0, guc_maj(mtl, 70, 12, 1)) \ + fw_def(DG2, 0, guc_maj(dg2, 70, 12, 1)) \ + fw_def(ALDERLAKE_P, 0, guc_maj(adlp, 70, 12, 1)) \ fw_def(ALDERLAKE_P, 0, guc_mmp(adlp, 70, 1, 1)) \ fw_def(ALDERLAKE_P, 0, guc_mmp(adlp, 69, 0, 3)) \ - fw_def(ALDERLAKE_S, 0, guc_maj(tgl, 70, 5, 1)) \ + fw_def(ALDERLAKE_S, 0, guc_maj(tgl, 70, 12, 1)) \ fw_def(ALDERLAKE_S, 0, guc_mmp(tgl, 70, 1, 1)) \ fw_def(ALDERLAKE_S, 0, guc_mmp(tgl, 69, 0, 3)) \ fw_def(DG1, 0, guc_maj(dg1, 70, 5, 1)) \ @@ -132,6 +132,17 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, fw_def(SKYLAKE, 0, huc_mmp(skl, 2, 0, 0)) /* + * The GSC FW has multiple version (see intel_gsc_uc.h for details); since what + * we care about is the interface, we use the compatibility version in the + * binary names. + * Same as with the GuC, a major version bump indicate a + * backward-incompatible change, while a minor version bump indicates a + * backward-compatible one, so we use only the former in the file name. + */ +#define INTEL_GSC_FIRMWARE_DEFS(fw_def, gsc_def) \ + fw_def(METEORLAKE, 0, gsc_def(mtl, 1, 0)) + +/* * Set of macros for producing a list of filenames from the above table. */ #define __MAKE_UC_FW_PATH_BLANK(prefix_, name_) \ @@ -166,6 +177,9 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, #define MAKE_HUC_FW_PATH_MMP(prefix_, major_, minor_, patch_) \ __MAKE_UC_FW_PATH_MMP(prefix_, "huc", major_, minor_, patch_) +#define MAKE_GSC_FW_PATH(prefix_, major_, minor_) \ + __MAKE_UC_FW_PATH_MAJOR(prefix_, "gsc", major_) + /* * All blobs need to be declared via MODULE_FIRMWARE(). * This first expansion of the table macros is solely to provide @@ -176,6 +190,7 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, INTEL_GUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH_MAJOR, MAKE_GUC_FW_PATH_MMP) INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH_BLANK, MAKE_HUC_FW_PATH_MMP, MAKE_HUC_FW_PATH_GSC) +INTEL_GSC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GSC_FW_PATH) /* * The next expansion of the table macros (in __uc_fw_auto_select below) provides @@ -225,6 +240,10 @@ struct __packed uc_fw_blob { #define HUC_FW_BLOB_GSC(prefix_) \ UC_FW_BLOB_NEW(0, 0, 0, true, MAKE_HUC_FW_PATH_GSC(prefix_)) +#define GSC_FW_BLOB(prefix_, major_, minor_) \ + UC_FW_BLOB_NEW(major_, minor_, 0, true, \ + MAKE_GSC_FW_PATH(prefix_, major_, minor_)) + struct __packed uc_fw_platform_requirement { enum intel_platform p; u8 rev; /* first platform rev using this FW */ @@ -251,9 +270,14 @@ static const struct uc_fw_platform_requirement blobs_huc[] = { INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB, HUC_FW_BLOB_MMP, HUC_FW_BLOB_GSC) }; +static const struct uc_fw_platform_requirement blobs_gsc[] = { + INTEL_GSC_FIRMWARE_DEFS(MAKE_FW_LIST, GSC_FW_BLOB) +}; + static const struct fw_blobs_by_type blobs_all[INTEL_UC_FW_NUM_TYPES] = { [INTEL_UC_FW_TYPE_GUC] = { blobs_guc, ARRAY_SIZE(blobs_guc) }, [INTEL_UC_FW_TYPE_HUC] = { blobs_huc, ARRAY_SIZE(blobs_huc) }, + [INTEL_UC_FW_TYPE_GSC] = { blobs_gsc, ARRAY_SIZE(blobs_gsc) }, }; static void @@ -267,14 +291,6 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw) bool found; /* - * GSC FW support is still not fully in place, so we're not defining - * the FW blob yet because we don't want the driver to attempt to load - * it until we're ready for it. - */ - if (uc_fw->type == INTEL_UC_FW_TYPE_GSC) - return; - - /* * The only difference between the ADL GuC FWs is the HWConfig support. * ADL-N does not support HWConfig, so we should use the same binary as * ADL-S, otherwise the GuC might attempt to fetch a config table that diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 4ec85308379a..094fca9b0e73 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -49,22 +49,6 @@ static bool enable_out_of_sync = false; static int preallocated_oos_pages = 8192; -static bool intel_gvt_is_valid_gfn(struct intel_vgpu *vgpu, unsigned long gfn) -{ - struct kvm *kvm = vgpu->vfio_device.kvm; - int idx; - bool ret; - - if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) - return false; - - idx = srcu_read_lock(&kvm->srcu); - ret = kvm_is_visible_gfn(kvm, gfn); - srcu_read_unlock(&kvm->srcu, idx); - - return ret; -} - /* * validate a gm address and related range size, * translate it to host gm address @@ -1161,31 +1145,6 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se, ops->set_pfn(se, s->shadow_page.mfn); } -/* - * Check if can do 2M page - * @vgpu: target vgpu - * @entry: target pfn's gtt entry - * - * Return 1 if 2MB huge gtt shadowing is possible, 0 if miscondition, - * negative if found err. - */ -static int is_2MB_gtt_possible(struct intel_vgpu *vgpu, - struct intel_gvt_gtt_entry *entry) -{ - const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; - kvm_pfn_t pfn; - - if (!HAS_PAGE_SIZES(vgpu->gvt->gt->i915, I915_GTT_PAGE_SIZE_2M)) - return 0; - - if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) - return -EINVAL; - pfn = gfn_to_pfn(vgpu->vfio_device.kvm, ops->get_pfn(entry)); - if (is_error_noslot_pfn(pfn)) - return -EINVAL; - return PageTransHuge(pfn_to_page(pfn)); -} - static int split_2MB_gtt_entry(struct intel_vgpu *vgpu, struct intel_vgpu_ppgtt_spt *spt, unsigned long index, struct intel_gvt_gtt_entry *se) @@ -1279,7 +1238,7 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, { const struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops; struct intel_gvt_gtt_entry se = *ge; - unsigned long gfn, page_size = PAGE_SIZE; + unsigned long gfn; dma_addr_t dma_addr; int ret; @@ -1291,6 +1250,9 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, switch (ge->type) { case GTT_TYPE_PPGTT_PTE_4K_ENTRY: gvt_vdbg_mm("shadow 4K gtt entry\n"); + ret = intel_gvt_dma_map_guest_page(vgpu, gfn, PAGE_SIZE, &dma_addr); + if (ret) + return -ENXIO; break; case GTT_TYPE_PPGTT_PTE_64K_ENTRY: gvt_vdbg_mm("shadow 64K gtt entry\n"); @@ -1302,25 +1264,20 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, return split_64KB_gtt_entry(vgpu, spt, index, &se); case GTT_TYPE_PPGTT_PTE_2M_ENTRY: gvt_vdbg_mm("shadow 2M gtt entry\n"); - ret = is_2MB_gtt_possible(vgpu, ge); - if (ret == 0) + if (!HAS_PAGE_SIZES(vgpu->gvt->gt->i915, I915_GTT_PAGE_SIZE_2M) || + intel_gvt_dma_map_guest_page(vgpu, gfn, + I915_GTT_PAGE_SIZE_2M, &dma_addr)) return split_2MB_gtt_entry(vgpu, spt, index, &se); - else if (ret < 0) - return ret; - page_size = I915_GTT_PAGE_SIZE_2M; break; case GTT_TYPE_PPGTT_PTE_1G_ENTRY: gvt_vgpu_err("GVT doesn't support 1GB entry\n"); return -EINVAL; default: GEM_BUG_ON(1); + return -EINVAL; } - /* direct shadow */ - ret = intel_gvt_dma_map_guest_page(vgpu, gfn, page_size, &dma_addr); - if (ret) - return -ENXIO; - + /* Successfully shadowed a 4K or 2M page (without splitting). */ pte_ops->set_pfn(&se, dma_addr >> PAGE_SHIFT); ppgtt_set_shadow_entry(spt, &se, index); return 0; @@ -1329,11 +1286,9 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, static int ppgtt_populate_spt(struct intel_vgpu_ppgtt_spt *spt) { struct intel_vgpu *vgpu = spt->vgpu; - struct intel_gvt *gvt = vgpu->gvt; - const struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops; struct intel_vgpu_ppgtt_spt *s; struct intel_gvt_gtt_entry se, ge; - unsigned long gfn, i; + unsigned long i; int ret; trace_spt_change(spt->vgpu->id, "born", spt, @@ -1350,13 +1305,6 @@ static int ppgtt_populate_spt(struct intel_vgpu_ppgtt_spt *spt) ppgtt_generate_shadow_entry(&se, s, &ge); ppgtt_set_shadow_entry(spt, &se, i); } else { - gfn = ops->get_pfn(&ge); - if (!intel_gvt_is_valid_gfn(vgpu, gfn)) { - ops->set_pfn(&se, gvt->gtt.scratch_mfn); - ppgtt_set_shadow_entry(spt, &se, i); - continue; - } - ret = ppgtt_populate_shadow_entry(vgpu, spt, i, &ge); if (ret) goto fail; @@ -1845,6 +1793,9 @@ static int shadow_ppgtt_mm(struct intel_vgpu_mm *mm) if (mm->ppgtt_mm.shadowed) return 0; + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) + return -EINVAL; + mm->ppgtt_mm.shadowed = true; for (index = 0; index < ARRAY_SIZE(mm->ppgtt_mm.guest_pdps); index++) { @@ -2331,14 +2282,6 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off, m.val64 = e.val64; m.type = e.type; - /* one PTE update may be issued in multiple writes and the - * first write may not construct a valid gfn - */ - if (!intel_gvt_is_valid_gfn(vgpu, gfn)) { - ops->set_pfn(&m, gvt->gtt.scratch_mfn); - goto out; - } - ret = intel_gvt_dma_map_guest_page(vgpu, gfn, PAGE_SIZE, &dma_addr); if (ret) { @@ -2355,7 +2298,6 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off, ops->clear_present(&m); } -out: ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index); ggtt_get_host_entry(ggtt_mm, &e, g_gtt_index); @@ -2876,24 +2818,6 @@ void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu, bool invalidate_old) } /** - * intel_vgpu_reset_gtt - reset the all GTT related status - * @vgpu: a vGPU - * - * This function is called from vfio core to reset reset all - * GTT related status, including GGTT, PPGTT, scratch page. - * - */ -void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu) -{ - /* Shadow pages are only created when there is no page - * table tracking data, so remove page tracking data after - * removing the shadow pages. - */ - intel_vgpu_destroy_all_ppgtt_mm(vgpu); - intel_vgpu_reset_ggtt(vgpu, true); -} - -/** * intel_gvt_restore_ggtt - restore all vGPU's ggtt entries * @gvt: intel gvt device * diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h index a3b0f59ec8bd..4cb183e06e95 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.h +++ b/drivers/gpu/drm/i915/gvt/gtt.h @@ -224,7 +224,6 @@ void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu, bool invalidate_old); void intel_vgpu_invalidate_ppgtt(struct intel_vgpu *vgpu); int intel_gvt_init_gtt(struct intel_gvt *gvt); -void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu); void intel_gvt_clean_gtt(struct intel_gvt *gvt); struct intel_vgpu_mm *intel_gvt_find_ppgtt_mm(struct intel_vgpu *vgpu, diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 2d65800d8e93..c57aba09091f 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -34,11 +34,12 @@ #define _GVT_H_ #include <uapi/linux/pci_regs.h> -#include <linux/kvm_host.h> #include <linux/vfio.h> #include <linux/mdev.h> -#include "i915_drv.h" +#include <asm/kvm_page_track.h> + +#include "gt/intel_gt.h" #include "intel_gvt.h" #include "debug.h" @@ -59,6 +60,8 @@ #define GVT_MAX_VGPU 8 +struct engine_mmio; + /* Describe per-platform limitations. */ struct intel_gvt_device_info { u32 max_support_vgpus; @@ -367,11 +370,6 @@ struct intel_gvt { struct dentry *debugfs_root; }; -static inline struct intel_gvt *to_gvt(struct drm_i915_private *i915) -{ - return i915->gvt; -} - enum { /* Scheduling trigger by timer */ INTEL_GVT_REQUEST_SCHED = 0, diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c index 68eca023bbc6..de3f5903d1a7 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.c +++ b/drivers/gpu/drm/i915/gvt/interrupt.c @@ -36,6 +36,23 @@ #include "gvt.h" #include "trace.h" +struct intel_gvt_irq_info { + char *name; + i915_reg_t reg_base; + enum intel_gvt_event_type bit_to_event[INTEL_GVT_IRQ_BITWIDTH]; + unsigned long warned; + int group; + DECLARE_BITMAP(downstream_irq_bitmap, INTEL_GVT_IRQ_BITWIDTH); + bool has_upstream_irq; +}; + +struct intel_gvt_irq_map { + int up_irq_group; + int up_irq_bit; + int down_irq_group; + u32 down_irq_bitmask; +}; + /* common offset among interrupt control registers */ #define regbase_to_isr(base) (base) #define regbase_to_imr(base) (base + 0x4) diff --git a/drivers/gpu/drm/i915/gvt/interrupt.h b/drivers/gpu/drm/i915/gvt/interrupt.h index b62f04ab47cb..e60ad476fe60 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.h +++ b/drivers/gpu/drm/i915/gvt/interrupt.h @@ -32,10 +32,13 @@ #ifndef _GVT_INTERRUPT_H_ #define _GVT_INTERRUPT_H_ -#include <linux/hrtimer.h> -#include <linux/kernel.h> +#include <linux/bitops.h> -#include "i915_reg_defs.h" +struct intel_gvt; +struct intel_gvt_irq; +struct intel_gvt_irq_info; +struct intel_gvt_irq_map; +struct intel_vgpu; enum intel_gvt_event_type { RCS_MI_USER_INTERRUPT = 0, @@ -138,10 +141,6 @@ enum intel_gvt_event_type { INTEL_GVT_EVENT_MAX, }; -struct intel_gvt_irq; -struct intel_gvt; -struct intel_vgpu; - typedef void (*gvt_event_virt_handler_t)(struct intel_gvt_irq *irq, enum intel_gvt_event_type event, struct intel_vgpu *vgpu); @@ -175,17 +174,6 @@ enum intel_gvt_irq_type { #define INTEL_GVT_IRQ_BITWIDTH 32 -/* device specific interrupt bit definitions */ -struct intel_gvt_irq_info { - char *name; - i915_reg_t reg_base; - enum intel_gvt_event_type bit_to_event[INTEL_GVT_IRQ_BITWIDTH]; - unsigned long warned; - int group; - DECLARE_BITMAP(downstream_irq_bitmap, INTEL_GVT_IRQ_BITWIDTH); - bool has_upstream_irq; -}; - /* per-event information */ struct intel_gvt_event_info { int bit; /* map to register bit */ @@ -194,13 +182,6 @@ struct intel_gvt_event_info { gvt_event_virt_handler_t v_handler; /* for v_event */ }; -struct intel_gvt_irq_map { - int up_irq_group; - int up_irq_bit; - int down_irq_group; - u32 down_irq_bitmask; -}; - /* structure containing device specific IRQ state */ struct intel_gvt_irq { const struct intel_gvt_irq_ops *ops; diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index de675d799c7d..42ce20e72db7 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -106,12 +106,10 @@ struct gvt_dma { #define vfio_dev_to_vgpu(vfio_dev) \ container_of((vfio_dev), struct intel_vgpu, vfio_device) -static void kvmgt_page_track_write(struct kvm_vcpu *vcpu, gpa_t gpa, - const u8 *val, int len, - struct kvm_page_track_notifier_node *node); -static void kvmgt_page_track_flush_slot(struct kvm *kvm, - struct kvm_memory_slot *slot, - struct kvm_page_track_notifier_node *node); +static void kvmgt_page_track_write(gpa_t gpa, const u8 *val, int len, + struct kvm_page_track_notifier_node *node); +static void kvmgt_page_track_remove_region(gfn_t gfn, unsigned long nr_pages, + struct kvm_page_track_notifier_node *node); static ssize_t intel_vgpu_show_description(struct mdev_type *mtype, char *buf) { @@ -161,8 +159,7 @@ static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, if (npage == 0) base_page = cur_page; - else if (base_page + npage != cur_page) { - gvt_vgpu_err("The pages are not continuous\n"); + else if (page_to_pfn(base_page) + npage != page_to_pfn(cur_page)) { ret = -EINVAL; npage++; goto err; @@ -172,7 +169,8 @@ static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, *page = base_page; return 0; err: - gvt_unpin_guest_page(vgpu, gfn, npage * PAGE_SIZE); + if (npage) + gvt_unpin_guest_page(vgpu, gfn, npage * PAGE_SIZE); return ret; } @@ -352,6 +350,8 @@ __kvmgt_protect_table_find(struct intel_vgpu *info, gfn_t gfn) { struct kvmgt_pgfn *p, *res = NULL; + lockdep_assert_held(&info->vgpu_lock); + hash_for_each_possible(info->ptable, p, hnode, gfn) { if (gfn == p->gfn) { res = p; @@ -654,21 +654,19 @@ out: static int intel_vgpu_open_device(struct vfio_device *vfio_dev) { struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev); - - if (!vgpu->vfio_device.kvm || - vgpu->vfio_device.kvm->mm != current->mm) { - gvt_vgpu_err("KVM is required to use Intel vGPU\n"); - return -ESRCH; - } + int ret; if (__kvmgt_vgpu_exist(vgpu)) return -EEXIST; vgpu->track_node.track_write = kvmgt_page_track_write; - vgpu->track_node.track_flush_slot = kvmgt_page_track_flush_slot; - kvm_get_kvm(vgpu->vfio_device.kvm); - kvm_page_track_register_notifier(vgpu->vfio_device.kvm, - &vgpu->track_node); + vgpu->track_node.track_remove_region = kvmgt_page_track_remove_region; + ret = kvm_page_track_register_notifier(vgpu->vfio_device.kvm, + &vgpu->track_node); + if (ret) { + gvt_vgpu_err("KVM is required to use Intel vGPU\n"); + return ret; + } set_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status); @@ -703,7 +701,6 @@ static void intel_vgpu_close_device(struct vfio_device *vfio_dev) kvm_page_track_unregister_notifier(vgpu->vfio_device.kvm, &vgpu->track_node); - kvm_put_kvm(vgpu->vfio_device.kvm); kvmgt_protect_table_destroy(vgpu); gvt_cache_destroy(vgpu); @@ -1474,6 +1471,7 @@ static const struct vfio_device_ops intel_vgpu_dev_ops = { .bind_iommufd = vfio_iommufd_emulated_bind, .unbind_iommufd = vfio_iommufd_emulated_unbind, .attach_ioas = vfio_iommufd_emulated_attach_ioas, + .detach_ioas = vfio_iommufd_emulated_detach_ioas, }; static int intel_vgpu_probe(struct mdev_device *mdev) @@ -1546,95 +1544,70 @@ static struct mdev_driver intel_vgpu_mdev_driver = { int intel_gvt_page_track_add(struct intel_vgpu *info, u64 gfn) { - struct kvm *kvm = info->vfio_device.kvm; - struct kvm_memory_slot *slot; - int idx; + int r; if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, info->status)) return -ESRCH; - idx = srcu_read_lock(&kvm->srcu); - slot = gfn_to_memslot(kvm, gfn); - if (!slot) { - srcu_read_unlock(&kvm->srcu, idx); - return -EINVAL; - } - - write_lock(&kvm->mmu_lock); - if (kvmgt_gfn_is_write_protected(info, gfn)) - goto out; + return 0; - kvm_slot_page_track_add_page(kvm, slot, gfn, KVM_PAGE_TRACK_WRITE); - kvmgt_protect_table_add(info, gfn); + r = kvm_write_track_add_gfn(info->vfio_device.kvm, gfn); + if (r) + return r; -out: - write_unlock(&kvm->mmu_lock); - srcu_read_unlock(&kvm->srcu, idx); + kvmgt_protect_table_add(info, gfn); return 0; } int intel_gvt_page_track_remove(struct intel_vgpu *info, u64 gfn) { - struct kvm *kvm = info->vfio_device.kvm; - struct kvm_memory_slot *slot; - int idx; + int r; if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, info->status)) return -ESRCH; - idx = srcu_read_lock(&kvm->srcu); - slot = gfn_to_memslot(kvm, gfn); - if (!slot) { - srcu_read_unlock(&kvm->srcu, idx); - return -EINVAL; - } - - write_lock(&kvm->mmu_lock); - if (!kvmgt_gfn_is_write_protected(info, gfn)) - goto out; + return 0; - kvm_slot_page_track_remove_page(kvm, slot, gfn, KVM_PAGE_TRACK_WRITE); - kvmgt_protect_table_del(info, gfn); + r = kvm_write_track_remove_gfn(info->vfio_device.kvm, gfn); + if (r) + return r; -out: - write_unlock(&kvm->mmu_lock); - srcu_read_unlock(&kvm->srcu, idx); + kvmgt_protect_table_del(info, gfn); return 0; } -static void kvmgt_page_track_write(struct kvm_vcpu *vcpu, gpa_t gpa, - const u8 *val, int len, - struct kvm_page_track_notifier_node *node) +static void kvmgt_page_track_write(gpa_t gpa, const u8 *val, int len, + struct kvm_page_track_notifier_node *node) { struct intel_vgpu *info = container_of(node, struct intel_vgpu, track_node); - if (kvmgt_gfn_is_write_protected(info, gpa_to_gfn(gpa))) + mutex_lock(&info->vgpu_lock); + + if (kvmgt_gfn_is_write_protected(info, gpa >> PAGE_SHIFT)) intel_vgpu_page_track_handler(info, gpa, (void *)val, len); + + mutex_unlock(&info->vgpu_lock); } -static void kvmgt_page_track_flush_slot(struct kvm *kvm, - struct kvm_memory_slot *slot, - struct kvm_page_track_notifier_node *node) +static void kvmgt_page_track_remove_region(gfn_t gfn, unsigned long nr_pages, + struct kvm_page_track_notifier_node *node) { - int i; - gfn_t gfn; + unsigned long i; struct intel_vgpu *info = container_of(node, struct intel_vgpu, track_node); - write_lock(&kvm->mmu_lock); - for (i = 0; i < slot->npages; i++) { - gfn = slot->base_gfn + i; - if (kvmgt_gfn_is_write_protected(info, gfn)) { - kvm_slot_page_track_remove_page(kvm, slot, gfn, - KVM_PAGE_TRACK_WRITE); - kvmgt_protect_table_del(info, gfn); - } + mutex_lock(&info->vgpu_lock); + + for (i = 0; i < nr_pages; i++) { + if (kvmgt_gfn_is_write_protected(info, gfn + i)) + kvmgt_protect_table_del(info, gfn + i); } - write_unlock(&kvm->mmu_lock); + + mutex_unlock(&info->vgpu_lock); } void intel_vgpu_detach_regions(struct intel_vgpu *vgpu) diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index 490e8ae51228..273db14fd5fc 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -45,6 +45,14 @@ #define GEN9_MOCS_SIZE 64 +struct engine_mmio { + enum intel_engine_id id; + i915_reg_t reg; + u32 mask; + bool in_context; + u32 value; +}; + /* Raw offset is appened to each line for convenience. */ static struct engine_mmio gen8_engine_mmio_list[] __cacheline_aligned = { {RCS0, RING_MODE_GEN7(RENDER_RING_BASE), 0xffff, false}, /* 0x229c */ diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.h b/drivers/gpu/drm/i915/gvt/mmio_context.h index 9540813b88e5..a821edf574dd 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.h +++ b/drivers/gpu/drm/i915/gvt/mmio_context.h @@ -39,8 +39,6 @@ #include <linux/types.h> #include "gt/intel_engine_regs.h" -#include "gt/intel_engine_types.h" -#include "gt/intel_lrc_reg.h" struct i915_request; struct intel_context; @@ -48,14 +46,6 @@ struct intel_engine_cs; struct intel_gvt; struct intel_vgpu; -struct engine_mmio { - enum intel_engine_id id; - i915_reg_t reg; - u32 mask; - bool in_context; - u32 value; -}; - void intel_gvt_switch_mmio(struct intel_vgpu *pre, struct intel_vgpu *next, const struct intel_engine_cs *engine); diff --git a/drivers/gpu/drm/i915/gvt/page_track.c b/drivers/gpu/drm/i915/gvt/page_track.c index df34e73cba41..60a65435556d 100644 --- a/drivers/gpu/drm/i915/gvt/page_track.c +++ b/drivers/gpu/drm/i915/gvt/page_track.c @@ -162,13 +162,9 @@ int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa, struct intel_vgpu_page_track *page_track; int ret = 0; - mutex_lock(&vgpu->vgpu_lock); - page_track = intel_vgpu_find_page_track(vgpu, gpa >> PAGE_SHIFT); - if (!page_track) { - ret = -ENXIO; - goto out; - } + if (!page_track) + return -ENXIO; if (unlikely(vgpu->failsafe)) { /* Remove write protection to prevent furture traps. */ @@ -179,7 +175,5 @@ int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa, gvt_err("guest page write error, gpa %llx\n", gpa); } -out: - mutex_unlock(&vgpu->vgpu_lock); return ret; } diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4de44cf1026d..e9b79c2c37d8 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -144,7 +144,7 @@ static const char *i915_cache_level_str(struct drm_i915_gem_object *obj) { struct drm_i915_private *i915 = obj_to_i915(obj); - if (IS_METEORLAKE(i915)) { + if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 71))) { switch (obj->pat_index) { case 0: return " WB"; case 1: return " WT"; @@ -740,15 +740,19 @@ static int i915_drop_caches_set(void *data, u64 val) { struct drm_i915_private *i915 = data; + struct intel_gt *gt; unsigned int flags; + unsigned int i; int ret; drm_dbg(&i915->drm, "Dropping caches: 0x%08llx [0x%08llx]\n", val, val & DROP_ALL); - ret = gt_drop_caches(to_gt(i915), val); - if (ret) - return ret; + for_each_gt(gt, i915, i) { + ret = gt_drop_caches(gt, val); + if (ret) + return ret; + } fs_reclaim_acquire(GFP_KERNEL); flags = memalloc_noreclaim_save(); diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index b870c0df081a..8a0e2c745e1f 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -71,6 +71,7 @@ #include "gem/i915_gem_pm.h" #include "gt/intel_gt.h" #include "gt/intel_gt_pm.h" +#include "gt/intel_gt_print.h" #include "gt/intel_rc6.h" #include "pxp/intel_pxp.h" @@ -183,6 +184,9 @@ static void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv) pre |= IS_ICELAKE(dev_priv) && INTEL_REVID(dev_priv) < 0x7; pre |= IS_TIGERLAKE(dev_priv) && INTEL_REVID(dev_priv) < 0x1; pre |= IS_DG1(dev_priv) && INTEL_REVID(dev_priv) < 0x1; + pre |= IS_DG2_G10(dev_priv) && INTEL_REVID(dev_priv) < 0x8; + pre |= IS_DG2_G11(dev_priv) && INTEL_REVID(dev_priv) < 0x5; + pre |= IS_DG2_G12(dev_priv) && INTEL_REVID(dev_priv) < 0x1; if (pre) { drm_err(&dev_priv->drm, "This is a pre-production stepping. " @@ -335,6 +339,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv) /* Try to make sure MCHBAR is enabled before poking at it */ intel_gmch_bar_setup(dev_priv); intel_device_info_runtime_init(dev_priv); + intel_display_device_info_runtime_init(dev_priv); for_each_gt(gt, dev_priv, i) { ret = intel_gt_init_mmio(gt); @@ -425,7 +430,7 @@ static int i915_pcode_init(struct drm_i915_private *i915) for_each_gt(gt, i915, id) { ret = intel_pcode_init(gt->uncore); if (ret) { - drm_err(>->i915->drm, "gt%d: intel_pcode_init failed %d\n", id, ret); + gt_err(gt, "intel_pcode_init failed %d\n", ret); return ret; } } @@ -443,7 +448,6 @@ static int i915_pcode_init(struct drm_i915_private *i915) static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) { struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - struct pci_dev *root_pdev; int ret; if (i915_inject_probe_failure(dev_priv)) @@ -557,15 +561,6 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) intel_bw_init_hw(dev_priv); - /* - * FIXME: Temporary hammer to avoid freezing the machine on our DGFX - * This should be totally removed when we handle the pci states properly - * on runtime PM and on s2idle cases. - */ - root_pdev = pcie_find_root_port(pdev); - if (root_pdev) - pci_d3cold_disable(root_pdev); - return 0; err_opregion: @@ -591,7 +586,6 @@ err_perf: static void i915_driver_hw_remove(struct drm_i915_private *dev_priv) { struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - struct pci_dev *root_pdev; i915_perf_fini(dev_priv); @@ -599,10 +593,6 @@ static void i915_driver_hw_remove(struct drm_i915_private *dev_priv) if (pdev->msi_enabled) pci_disable_msi(pdev); - - root_pdev = pcie_find_root_port(pdev); - if (root_pdev) - pci_d3cold_enable(root_pdev); } /** @@ -711,8 +701,6 @@ static void i915_welcome_messages(struct drm_i915_private *dev_priv) intel_device_info_print(INTEL_INFO(dev_priv), RUNTIME_INFO(dev_priv), &p); - intel_display_device_info_print(DISPLAY_INFO(dev_priv), - DISPLAY_RUNTIME_INFO(dev_priv), &p); i915_print_iommu_status(dev_priv, &p); for_each_gt(gt, dev_priv, i) intel_gt_info_print(>->info, &p); @@ -747,6 +735,8 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) /* Set up device info and initial runtime info. */ intel_device_info_driver_create(i915, pdev->device, match_info); + intel_display_device_probe(i915); + return i915; } @@ -1339,10 +1329,8 @@ static int i915_drm_resume_early(struct drm_device *dev) drm_err(&dev_priv->drm, "Resume prepare failed: %d, continuing anyway\n", ret); - for_each_gt(gt, dev_priv, i) { - intel_uncore_resume_early(gt->uncore); - intel_gt_check_and_clear_faults(gt); - } + for_each_gt(gt, dev_priv, i) + intel_gt_resume_early(gt); intel_display_power_resume_early(dev_priv); @@ -1519,6 +1507,8 @@ static int intel_runtime_suspend(struct device *kdev) { struct drm_i915_private *dev_priv = kdev_to_i915(kdev); struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *root_pdev; struct intel_gt *gt; int ret, i; @@ -1570,7 +1560,14 @@ static int intel_runtime_suspend(struct device *kdev) drm_err(&dev_priv->drm, "Unclaimed access detected prior to suspending\n"); - rpm->suspended = true; + /* + * FIXME: Temporary hammer to avoid freezing the machine on our DGFX + * This should be totally removed when we handle the pci states properly + * on runtime PM. + */ + root_pdev = pcie_find_root_port(pdev); + if (root_pdev) + pci_d3cold_disable(root_pdev); /* * FIXME: We really should find a document that references the arguments @@ -1608,6 +1605,8 @@ static int intel_runtime_resume(struct device *kdev) { struct drm_i915_private *dev_priv = kdev_to_i915(kdev); struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *root_pdev; struct intel_gt *gt; int ret, i; @@ -1620,7 +1619,11 @@ static int intel_runtime_resume(struct device *kdev) disable_rpm_wakeref_asserts(rpm); intel_opregion_notify_adapter(dev_priv, PCI_D0); - rpm->suspended = false; + + root_pdev = pcie_find_root_port(pdev); + if (root_pdev) + pci_d3cold_enable(root_pdev); + if (intel_uncore_unclaimed_mmio(&dev_priv->uncore)) drm_dbg(&dev_priv->drm, "Unclaimed access during suspend, bios?\n"); diff --git a/drivers/gpu/drm/i915/i915_driver.h b/drivers/gpu/drm/i915/i915_driver.h index 44ec543d92cb..94a70d8ec5d5 100644 --- a/drivers/gpu/drm/i915/i915_driver.h +++ b/drivers/gpu/drm/i915/i915_driver.h @@ -15,8 +15,8 @@ struct drm_printer; #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20201103" -#define DRIVER_TIMESTAMP 1604406085 +#define DRIVER_DATE "20230929" +#define DRIVER_TIMESTAMP 1695980603 extern const struct dev_pm_ops i915_pm_ops; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7a8ce7239bc9..cb60fc9cf873 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -222,7 +222,22 @@ struct drm_i915_private { bool mchbar_need_disable; } gmch; - struct rb_root uabi_engines; + /* + * Chaining user engines happens in multiple stages, starting with a + * simple lock-less linked list created by intel_engine_add_user(), + * which later gets sorted and converted to an intermediate regular + * list, just to be converted once again to its final rb tree structure + * in intel_engines_driver_register(). + * + * Make sure to use the right iterator helper, depending on if the code + * in question runs before or after intel_engines_driver_register() -- + * for_each_uabi_engine() can only be used afterwards! + */ + union { + struct llist_head uabi_engines_llist; + struct list_head uabi_engines_list; + struct rb_root uabi_engines; + }; unsigned int engine_uabi_class_count[I915_LAST_UABI_ENGINE_CLASS + 1]; /* protects the irq masks */ @@ -317,12 +332,6 @@ struct drm_i915_private { struct i915_hwmon *hwmon; - /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ - struct intel_gt gt0; - - /* - * i915->gt[0] == &i915->gt0 - */ struct intel_gt *gt[I915_MAX_GT]; struct kobject *sysfs_gt; @@ -382,9 +391,9 @@ static inline struct drm_i915_private *pdev_to_i915(struct pci_dev *pdev) return pci_get_drvdata(pdev); } -static inline struct intel_gt *to_gt(struct drm_i915_private *i915) +static inline struct intel_gt *to_gt(const struct drm_i915_private *i915) { - return &i915->gt0; + return i915->gt[0]; } /* Simple iterator over all initialised engines */ @@ -416,8 +425,6 @@ static inline struct intel_gt *to_gt(struct drm_i915_private *i915) #define INTEL_INFO(i915) ((i915)->__info) #define RUNTIME_INFO(i915) (&(i915)->__runtime) -#define DISPLAY_INFO(i915) ((i915)->display.info.__device_info) -#define DISPLAY_RUNTIME_INFO(i915) (&(i915)->display.info.__runtime_info) #define DRIVER_CAPS(i915) (&(i915)->caps) #define INTEL_DEVID(i915) (RUNTIME_INFO(i915)->device_id) @@ -436,10 +443,6 @@ static inline struct intel_gt *to_gt(struct drm_i915_private *i915) #define IS_MEDIA_VER(i915, from, until) \ (MEDIA_VER(i915) >= (from) && MEDIA_VER(i915) <= (until)) -#define DISPLAY_VER(i915) (DISPLAY_RUNTIME_INFO(i915)->ip.ver) -#define IS_DISPLAY_VER(i915, from, until) \ - (DISPLAY_VER(i915) >= (from) && DISPLAY_VER(i915) <= (until)) - #define INTEL_REVID(i915) (to_pci_dev((i915)->drm.dev)->revision) #define INTEL_DISPLAY_STEP(__i915) (RUNTIME_INFO(__i915)->step.display_step) @@ -573,10 +576,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_PONTEVECCHIO(i915) IS_PLATFORM(i915, INTEL_PONTEVECCHIO) #define IS_METEORLAKE(i915) IS_PLATFORM(i915, INTEL_METEORLAKE) -#define IS_METEORLAKE_M(i915) \ - IS_SUBPLATFORM(i915, INTEL_METEORLAKE, INTEL_SUBPLATFORM_M) -#define IS_METEORLAKE_P(i915) \ - IS_SUBPLATFORM(i915, INTEL_METEORLAKE, INTEL_SUBPLATFORM_P) #define IS_DG2_G10(i915) \ IS_SUBPLATFORM(i915, INTEL_DG2, INTEL_SUBPLATFORM_G10) #define IS_DG2_G11(i915) \ @@ -648,51 +647,9 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_TIGERLAKE_UY(i915) \ IS_SUBPLATFORM(i915, INTEL_TIGERLAKE, INTEL_SUBPLATFORM_UY) - - - - - - - #define IS_XEHPSDV_GRAPHICS_STEP(__i915, since, until) \ (IS_XEHPSDV(__i915) && IS_GRAPHICS_STEP(__i915, since, until)) -#define IS_MTL_GRAPHICS_STEP(__i915, variant, since, until) \ - (IS_SUBPLATFORM(__i915, INTEL_METEORLAKE, INTEL_SUBPLATFORM_##variant) && \ - IS_GRAPHICS_STEP(__i915, since, until)) - -#define IS_MTL_DISPLAY_STEP(__i915, since, until) \ - (IS_METEORLAKE(__i915) && \ - IS_DISPLAY_STEP(__i915, since, until)) - -#define IS_MTL_MEDIA_STEP(__i915, since, until) \ - (IS_METEORLAKE(__i915) && \ - IS_MEDIA_STEP(__i915, since, until)) - -/* - * DG2 hardware steppings are a bit unusual. The hardware design was forked to - * create three variants (G10, G11, and G12) which each have distinct - * workaround sets. The G11 and G12 forks of the DG2 design reset the GT - * stepping back to "A0" for their first iterations, even though they're more - * similar to a G10 B0 stepping and G10 C0 stepping respectively in terms of - * functionality and workarounds. However the display stepping does not reset - * in the same manner --- a specific stepping like "B0" has a consistent - * meaning regardless of whether it belongs to a G10, G11, or G12 DG2. - * - * TLDR: All GT workarounds and stepping-specific logic must be applied in - * relation to a specific subplatform (G10/G11/G12), whereas display workarounds - * and stepping-specific logic will be applied with a general DG2-wide stepping - * number. - */ -#define IS_DG2_GRAPHICS_STEP(__i915, variant, since, until) \ - (IS_SUBPLATFORM(__i915, INTEL_DG2, INTEL_SUBPLATFORM_##variant) && \ - IS_GRAPHICS_STEP(__i915, since, until)) - -#define IS_DG2_DISPLAY_STEP(__i915, since, until) \ - (IS_DG2(__i915) && \ - IS_DISPLAY_STEP(__i915, since, until)) - #define IS_PVC_BD_STEP(__i915, since, until) \ (IS_PONTEVECCHIO(__i915) && \ IS_BASEDIE_STEP(__i915, since, until)) @@ -737,7 +694,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define CMDPARSER_USES_GGTT(i915) (GRAPHICS_VER(i915) == 7) #define HAS_LLC(i915) (INTEL_INFO(i915)->has_llc) -#define HAS_4TILE(i915) (INTEL_INFO(i915)->has_4tile) #define HAS_SNOOP(i915) (INTEL_INFO(i915)->has_snoop) #define HAS_EDRAM(i915) ((i915)->edram_size_mb) #define HAS_SECURE_BATCHES(i915) (GRAPHICS_VER(i915) < 6) @@ -835,12 +791,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define NUM_L3_SLICES(i915) (IS_HASWELL_GT3(i915) ? \ 2 : HAS_L3_DPF(i915)) -/* Only valid when HAS_DISPLAY() is true */ -#define INTEL_DISPLAY_ENABLED(i915) \ - (drm_WARN_ON(&(i915)->drm, !HAS_DISPLAY(i915)), \ - !(i915)->params.disable_display && \ - !intel_opregion_headless_sku(i915)) - #define HAS_GUC_DEPRIVILEGE(i915) \ (INTEL_INFO(i915)->has_guc_deprivilege) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1f65bb33dd21..c166ad5e187a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -40,12 +40,12 @@ #include <drm/drm_vma_manager.h> #include "display/intel_display.h" -#include "display/intel_frontbuffer.h" #include "gem/i915_gem_clflush.h" #include "gem/i915_gem_context.h" #include "gem/i915_gem_ioctls.h" #include "gem/i915_gem_mman.h" +#include "gem/i915_gem_object_frontbuffer.h" #include "gem/i915_gem_pm.h" #include "gem/i915_gem_region.h" #include "gem/i915_gem_userptr.h" @@ -1199,6 +1199,13 @@ int i915_gem_init(struct drm_i915_private *dev_priv) goto err_unlock; } + /* + * Register engines early to ensure the engine list is in its final + * rb-tree form, lowering the amount of code that has to deal with + * the intermediate llist state. + */ + intel_engines_driver_register(dev_priv); + return 0; /* @@ -1246,8 +1253,6 @@ err_unlock: void i915_gem_driver_register(struct drm_i915_private *i915) { i915_gem_driver_register__shrinker(i915); - - intel_engines_driver_register(i915); } void i915_gem_driver_unregister(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/i915_getparam.c b/drivers/gpu/drm/i915/i915_getparam.c index 890f2b382bee..5c3fec63cb4c 100644 --- a/drivers/gpu/drm/i915/i915_getparam.c +++ b/drivers/gpu/drm/i915/i915_getparam.c @@ -109,7 +109,7 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data, return value; break; case I915_PARAM_PXP_STATUS: - value = intel_pxp_get_readiness_status(i915->pxp); + value = intel_pxp_get_readiness_status(i915->pxp, 0); if (value < 0) return value; break; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 4008bb09fdb5..b4e31e59c799 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1234,7 +1234,16 @@ static void engine_record_registers(struct intel_engine_coredump *ee) if (GRAPHICS_VER(i915) >= 6) { ee->rc_psmi = ENGINE_READ(engine, RING_PSMI_CTL); - if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) + /* + * For the media GT, this ring fault register is not replicated, + * so don't do multicast/replicated register read/write + * operation on it. + */ + if (MEDIA_VER(i915) >= 13 && engine->gt->type == GT_MEDIA) + ee->fault_reg = intel_uncore_read(engine->uncore, + XELPMP_RING_FAULT_REG); + + else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) ee->fault_reg = intel_gt_mcr_read_any(engine->gt, XEHP_RING_FAULT_REG); else if (GRAPHICS_VER(i915) >= 12) @@ -1757,7 +1766,7 @@ static void gt_record_display_regs(struct intel_gt_coredump *gt) struct intel_uncore *uncore = gt->_gt->uncore; struct drm_i915_private *i915 = uncore->i915; - if (GRAPHICS_VER(i915) >= 6) + if (DISPLAY_VER(i915) >= 6 && DISPLAY_VER(i915) < 20) gt->derrmr = intel_uncore_read(uncore, DERRMR); if (GRAPHICS_VER(i915) >= 8) @@ -1972,7 +1981,7 @@ static void capture_gen(struct i915_gpu_coredump *error) struct drm_i915_private *i915 = error->i915; error->wakelock = atomic_read(&i915->runtime_pm.wakeref_count); - error->suspended = i915->runtime_pm.suspended; + error->suspended = pm_runtime_suspended(i915->drm.dev); error->iommu = i915_vtd_active(i915); error->reset_count = i915_reset_count(&i915->gpu_error); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1bfcfbe6e30b..8130f043693b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -751,6 +751,8 @@ static void dg1_irq_reset(struct drm_i915_private *dev_priv) GEN3_IRQ_RESET(uncore, GEN11_GU_MISC_); GEN3_IRQ_RESET(uncore, GEN8_PCU_); + + intel_uncore_write(uncore, GEN11_GFX_MSTR_IRQ, ~0); } static void cherryview_irq_reset(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 0a171b57fd8f..036c4c3ed6ed 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -137,11 +137,6 @@ i915_param_named_unsafe(enable_ips, int, 0400, "Enable IPS (default: true)"); i915_param_named_unsafe(enable_dpt, bool, 0400, "Enable display page table (DPT) (default: true)"); -i915_param_named(fastboot, int, 0400, - "Try to skip unnecessary mode sets at boot time " - "(0=disabled, 1=enabled) " - "Default: -1 (use per-chip default)"); - i915_param_named_unsafe(load_detect_test, bool, 0400, "Force-enable the VGA load detect code for testing (default:false). " "For developers only."); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 68abf0ad6c00..d5194b039aab 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -72,7 +72,6 @@ struct drm_printer; param(int, edp_vswing, 0, 0400) \ param(unsigned int, reset, 3, 0600) \ param(unsigned int, inject_probe_failure, 0, 0) \ - param(int, fastboot, -1, 0600) \ param(int, enable_dpcd_backlight, -1, 0600) \ param(char *, force_probe, CONFIG_DRM_I915_FORCE_PROBE, 0400) \ param(unsigned int, request_timeout_ms, CONFIG_DRM_I915_REQUEST_TIMEOUT, CONFIG_DRM_I915_REQUEST_TIMEOUT ? 0600 : 0) \ diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index fcacdc21643c..df7c261410f7 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -713,7 +713,6 @@ static const struct intel_device_info adl_p_info = { .has_3d_pipeline = 1, \ .has_64bit_reloc = 1, \ .has_flat_ccs = 1, \ - .has_4tile = 1, \ .has_global_mocs = 1, \ .has_gt_uc = 1, \ .has_llc = 1, \ diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 04bc1f4a1115..8f7ab64feec0 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -206,6 +206,7 @@ #include "gt/intel_gt.h" #include "gt/intel_gt_clock_utils.h" #include "gt/intel_gt_mcr.h" +#include "gt/intel_gt_print.h" #include "gt/intel_gt_regs.h" #include "gt/intel_lrc.h" #include "gt/intel_lrc_reg.h" @@ -543,10 +544,9 @@ static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream) { u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma); int report_size = stream->oa_buffer.format->size; - u32 head, tail, read_tail; + u32 tail, hw_tail; unsigned long flags; bool pollin; - u32 hw_tail; u32 partial_report_size; /* We have to consider the (unlikely) possibility that read() errors @@ -556,6 +556,7 @@ static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream) spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags); hw_tail = stream->perf->ops.oa_hw_tail_read(stream); + hw_tail -= gtt_offset; /* The tail pointer increases in 64 byte increments, not in report_size * steps. Also the report size may not be a power of 2. Compute @@ -567,13 +568,6 @@ static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream) /* Subtract partial amount off the tail */ hw_tail = OA_TAKEN(hw_tail, partial_report_size); - /* NB: The head we observe here might effectively be a little - * out of date. If a read() is in progress, the head could be - * anywhere between this head and stream->oa_buffer.tail. - */ - head = stream->oa_buffer.head - gtt_offset; - read_tail = stream->oa_buffer.tail - gtt_offset; - tail = hw_tail; /* Walk the stream backward until we find a report with report @@ -587,7 +581,7 @@ static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream) * memory in the order they were written to. * If not : (╯°□°)╯︵ ┻━┻ */ - while (OA_TAKEN(tail, read_tail) >= report_size) { + while (OA_TAKEN(tail, stream->oa_buffer.tail) >= report_size) { void *report = stream->oa_buffer.vaddr + tail; if (oa_report_id(stream, report) || @@ -601,9 +595,9 @@ static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream) __ratelimit(&stream->perf->tail_pointer_race)) drm_notice(&stream->uncore->i915->drm, "unlanded report(s) head=0x%x tail=0x%x hw_tail=0x%x\n", - head, tail, hw_tail); + stream->oa_buffer.head, tail, hw_tail); - stream->oa_buffer.tail = gtt_offset + tail; + stream->oa_buffer.tail = tail; pollin = OA_TAKEN(stream->oa_buffer.tail, stream->oa_buffer.head) >= report_size; @@ -754,13 +748,6 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags); /* - * NB: oa_buffer.head/tail include the gtt_offset which we don't want - * while indexing relative to oa_buf_base. - */ - head -= gtt_offset; - tail -= gtt_offset; - - /* * An out of bounds or misaligned head or tail pointer implies a driver * bug since we validate + align the tail pointers we read from the * hardware and we are in full control of the head pointer which should @@ -895,9 +882,8 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, * We removed the gtt_offset for the copy loop above, indexing * relative to oa_buf_base so put back here... */ - head += gtt_offset; intel_uncore_write(uncore, oaheadptr, - head & GEN12_OAG_OAHEADPTR_MASK); + (head + gtt_offset) & GEN12_OAG_OAHEADPTR_MASK); stream->oa_buffer.head = head; spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags); @@ -1042,12 +1028,6 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream, spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags); - /* NB: oa_buffer.head/tail include the gtt_offset which we don't want - * while indexing relative to oa_buf_base. - */ - head -= gtt_offset; - tail -= gtt_offset; - /* An out of bounds or misaligned head or tail pointer implies a driver * bug since we validate + align the tail pointers we read from the * hardware and we are in full control of the head pointer which should @@ -1110,13 +1090,8 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream, if (start_offset != *offset) { spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags); - /* We removed the gtt_offset for the copy loop above, indexing - * relative to oa_buf_base so put back here... - */ - head += gtt_offset; - intel_uncore_write(uncore, GEN7_OASTATUS2, - (head & GEN7_OASTATUS2_HEAD_MASK) | + ((head + gtt_offset) & GEN7_OASTATUS2_HEAD_MASK) | GEN7_OASTATUS2_MEM_SELECT_GGTT); stream->oa_buffer.head = head; @@ -1675,13 +1650,6 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) free_oa_buffer(stream); - /* - * Wa_16011777198:dg2: Unset the override of GUCRC mode to enable rc6. - */ - if (stream->override_gucrc) - drm_WARN_ON(>->i915->drm, - intel_guc_slpc_unset_gucrc_mode(>->uc.guc.slpc)); - intel_uncore_forcewake_put(stream->uncore, FORCEWAKE_ALL); intel_engine_pm_put(stream->engine); @@ -1692,9 +1660,8 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) free_noa_wait(stream); if (perf->spurious_report_rs.missed) { - drm_notice(>->i915->drm, - "%d spurious OA report notices suppressed due to ratelimiting\n", - perf->spurious_report_rs.missed); + gt_notice(gt, "%d spurious OA report notices suppressed due to ratelimiting\n", + perf->spurious_report_rs.missed); } } @@ -1711,7 +1678,7 @@ static void gen7_init_oa_buffer(struct i915_perf_stream *stream) */ intel_uncore_write(uncore, GEN7_OASTATUS2, /* head */ gtt_offset | GEN7_OASTATUS2_MEM_SELECT_GGTT); - stream->oa_buffer.head = gtt_offset; + stream->oa_buffer.head = 0; intel_uncore_write(uncore, GEN7_OABUFFER, gtt_offset); @@ -1719,7 +1686,7 @@ static void gen7_init_oa_buffer(struct i915_perf_stream *stream) gtt_offset | OABUFFER_SIZE_16M); /* Mark that we need updated tail pointers to read from... */ - stream->oa_buffer.tail = gtt_offset; + stream->oa_buffer.tail = 0; spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags); @@ -1753,7 +1720,7 @@ static void gen8_init_oa_buffer(struct i915_perf_stream *stream) intel_uncore_write(uncore, GEN8_OASTATUS, 0); intel_uncore_write(uncore, GEN8_OAHEADPTR, gtt_offset); - stream->oa_buffer.head = gtt_offset; + stream->oa_buffer.head = 0; intel_uncore_write(uncore, GEN8_OABUFFER_UDW, 0); @@ -1770,7 +1737,7 @@ static void gen8_init_oa_buffer(struct i915_perf_stream *stream) intel_uncore_write(uncore, GEN8_OATAILPTR, gtt_offset & GEN8_OATAILPTR_MASK); /* Mark that we need updated tail pointers to read from... */ - stream->oa_buffer.tail = gtt_offset; + stream->oa_buffer.tail = 0; /* * Reset state used to recognise context switches, affecting which @@ -1807,7 +1774,7 @@ static void gen12_init_oa_buffer(struct i915_perf_stream *stream) intel_uncore_write(uncore, __oa_regs(stream)->oa_status, 0); intel_uncore_write(uncore, __oa_regs(stream)->oa_head_ptr, gtt_offset & GEN12_OAG_OAHEADPTR_MASK); - stream->oa_buffer.head = gtt_offset; + stream->oa_buffer.head = 0; /* * PRM says: @@ -1823,7 +1790,7 @@ static void gen12_init_oa_buffer(struct i915_perf_stream *stream) gtt_offset & GEN12_OAG_OATAILPTR_MASK); /* Mark that we need updated tail pointers to read from... */ - stream->oa_buffer.tail = gtt_offset; + stream->oa_buffer.tail = 0; /* * Reset state used to recognise context switches, affecting which @@ -1885,7 +1852,7 @@ static int alloc_oa_buffer(struct i915_perf_stream *stream) */ ret = i915_vma_pin(vma, 0, SZ_16M, PIN_GLOBAL | PIN_HIGH); if (ret) { - drm_err(>->i915->drm, "Failed to pin OA buffer %d\n", ret); + gt_err(gt, "Failed to pin OA buffer %d\n", ret); goto err_unref; } @@ -3227,11 +3194,10 @@ get_sseu_config(struct intel_sseu *out_sseu, */ u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915) { - /* - * Wa_18013179988:dg2 - * Wa_14015846243:mtl - */ - if (IS_DG2(i915) || IS_METEORLAKE(i915)) { + struct intel_gt *gt = to_gt(i915); + + /* Wa_18013179988 */ + if (IS_DG2(i915) || IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) { intel_wakeref_t wakeref; u32 reg, shift; @@ -3272,7 +3238,6 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, struct drm_i915_private *i915 = stream->perf->i915; struct i915_perf *perf = stream->perf; struct i915_perf_group *g; - struct intel_gt *gt; int ret; if (!props->engine) { @@ -3280,7 +3245,6 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, "OA engine not specified\n"); return -EINVAL; } - gt = props->engine->gt; g = props->engine->oa_group; /* @@ -3381,25 +3345,6 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, intel_engine_pm_get(stream->engine); intel_uncore_forcewake_get(stream->uncore, FORCEWAKE_ALL); - /* - * Wa_16011777198:dg2: GuC resets render as part of the Wa. This causes - * OA to lose the configuration state. Prevent this by overriding GUCRC - * mode. - */ - if (intel_uc_uses_guc_rc(>->uc) && - (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || - IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0))) { - ret = intel_guc_slpc_override_gucrc_mode(>->uc.guc.slpc, - SLPC_GUCRC_MODE_GUCRC_NO_RC6); - if (ret) { - drm_dbg(&stream->perf->i915->drm, - "Unable to override gucrc mode\n"); - goto err_gucrc; - } - - stream->override_gucrc = true; - } - ret = alloc_oa_buffer(stream); if (ret) goto err_oa_buf_alloc; @@ -3436,10 +3381,6 @@ err_enable: free_oa_buffer(stream); err_oa_buf_alloc: - if (stream->override_gucrc) - intel_guc_slpc_unset_gucrc_mode(>->uc.guc.slpc); - -err_gucrc: intel_uncore_forcewake_put(stream->uncore, FORCEWAKE_ALL); intel_engine_pm_put(stream->engine); @@ -4223,7 +4164,7 @@ static int read_properties_unlocked(struct i915_perf *perf, * C6 disable in BIOS. Fail if Media C6 is enabled on steppings where OAM * does not work as expected. */ - if (IS_MTL_MEDIA_STEP(props->engine->i915, STEP_A0, STEP_C0) && + if (IS_MEDIA_GT_IP_STEP(props->engine->gt, IP_VER(13, 0), STEP_A0, STEP_C0) && props->engine->oa_group->type == TYPE_OAM && intel_check_bios_c6_setup(&props->engine->gt->rc6)) { drm_dbg(&perf->i915->drm, @@ -4539,7 +4480,7 @@ static bool xehp_is_valid_b_counter_addr(struct i915_perf *perf, u32 addr) static bool gen12_is_valid_mux_addr(struct i915_perf *perf, u32 addr) { - if (IS_METEORLAKE(perf->i915)) + if (GRAPHICS_VER_FULL(perf->i915) >= IP_VER(12, 70)) return reg_in_range_table(addr, mtl_oa_mux_regs); else return reg_in_range_table(addr, gen12_oa_mux_regs); @@ -5332,16 +5273,9 @@ int i915_perf_ioctl_version(struct drm_i915_private *i915) * C6 disable in BIOS. If Media C6 is enabled in BIOS, return version 6 * to indicate that OA media is not supported. */ - if (IS_MTL_MEDIA_STEP(i915, STEP_A0, STEP_C0)) { - struct intel_gt *gt; - int i; - - for_each_gt(gt, i915, i) { - if (gt->type == GT_MEDIA && - intel_check_bios_c6_setup(>->rc6)) - return 6; - } - } + if (IS_MEDIA_GT_IP_STEP(i915->media_gt, IP_VER(13, 0), STEP_A0, STEP_C0) && + intel_check_bios_c6_setup(&i915->media_gt->rc6)) + return 6; return 7; } diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index fe3a5dae8c22..13b1ae9b96c7 100644 --- a/drivers/gpu/drm/i915/i915_perf_types.h +++ b/drivers/gpu/drm/i915/i915_perf_types.h @@ -338,12 +338,6 @@ struct i915_perf_stream { * buffer should be checked for available data. */ u64 poll_oa_period; - - /** - * @override_gucrc: GuC RC has been overridden for the perf stream, - * and we need to restore the default configuration on release. - */ - bool override_gucrc; }; /** diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index d35973b41186..108b675088ba 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -696,12 +696,11 @@ static void i915_pmu_event_read(struct perf_event *event) event->hw.state = PERF_HES_STOPPED; return; } -again: - prev = local64_read(&hwc->prev_count); - new = __i915_pmu_event_read(event); - if (local64_cmpxchg(&hwc->prev_count, prev, new) != prev) - goto again; + prev = local64_read(&hwc->prev_count); + do { + new = __i915_pmu_event_read(event); + } while (!local64_try_cmpxchg(&hwc->prev_count, &prev, new)); local64_add(new - prev, &event->count); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aefad14ab27a..135e8d8dbdf0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1327,6 +1327,8 @@ #define DPFC_CTL_PLANE_IVB(i9xx_plane) REG_FIELD_PREP(DPFC_CTL_PLANE_MASK_IVB, (i9xx_plane)) #define DPFC_CTL_FENCE_EN_IVB REG_BIT(28) /* ivb+ */ #define DPFC_CTL_PERSISTENT_MODE REG_BIT(25) /* g4x-snb */ +#define DPFC_CTL_PLANE_BINDING_MASK REG_GENMASK(12, 11) /* lnl+ */ +#define DPFC_CTL_PLANE_BINDING(plane_id) REG_FIELD_PREP(DPFC_CTL_PLANE_BINDING_MASK, (plane_id)) #define DPFC_CTL_FALSE_COLOR REG_BIT(10) /* ivb+ */ #define DPFC_CTL_SR_EN REG_BIT(10) /* g4x only */ #define DPFC_CTL_SR_EXIT_DIS REG_BIT(9) /* g4x only */ @@ -2693,13 +2695,6 @@ #define PIPE_MISC2_FLIP_INFO_PLANE_SEL(plane_id) REG_FIELD_PREP(PIPE_MISC2_FLIP_INFO_PLANE_SEL_MASK, (plane_id)) #define PIPE_MISC2(pipe) _MMIO_PIPE(pipe, _PIPE_MISC2_A, _PIPE_MISC2_B) -/* Skylake+ pipe bottom (background) color */ -#define _SKL_BOTTOM_COLOR_A 0x70034 -#define _SKL_BOTTOM_COLOR_B 0x71034 -#define SKL_BOTTOM_COLOR_GAMMA_ENABLE REG_BIT(31) -#define SKL_BOTTOM_COLOR_CSC_ENABLE REG_BIT(30) -#define SKL_BOTTOM_COLOR(pipe) _MMIO_PIPE(pipe, _SKL_BOTTOM_COLOR_A, _SKL_BOTTOM_COLOR_B) - #define _ICL_PIPE_A_STATUS 0x70058 #define ICL_PIPESTATUS(pipe) _MMIO_PIPE2(pipe, _ICL_PIPE_A_STATUS) #define PIPE_STATUS_UNDERRUN REG_BIT(31) @@ -4213,45 +4208,6 @@ #define GLK_PS_COEF_DATA_SET(pipe, id, set) _MMIO_PIPE(pipe, \ _ID(id, _PS_COEF_SET0_DATA_1A, _PS_COEF_SET0_DATA_2A) + (set) * 8, \ _ID(id, _PS_COEF_SET0_DATA_1B, _PS_COEF_SET0_DATA_2B) + (set) * 8) -/* legacy palette */ -#define _LGC_PALETTE_A 0x4a000 -#define _LGC_PALETTE_B 0x4a800 -/* see PALETTE_* for the bits */ -#define LGC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4) - -/* ilk/snb precision palette */ -#define _PREC_PALETTE_A 0x4b000 -#define _PREC_PALETTE_B 0x4c000 -/* 10bit mode */ -#define PREC_PALETTE_10_RED_MASK REG_GENMASK(29, 20) -#define PREC_PALETTE_10_GREEN_MASK REG_GENMASK(19, 10) -#define PREC_PALETTE_10_BLUE_MASK REG_GENMASK(9, 0) -/* 12.4 interpolated mode ldw */ -#define PREC_PALETTE_12P4_RED_LDW_MASK REG_GENMASK(29, 24) -#define PREC_PALETTE_12P4_GREEN_LDW_MASK REG_GENMASK(19, 14) -#define PREC_PALETTE_12P4_BLUE_LDW_MASK REG_GENMASK(9, 4) -/* 12.4 interpolated mode udw */ -#define PREC_PALETTE_12P4_RED_UDW_MASK REG_GENMASK(29, 20) -#define PREC_PALETTE_12P4_GREEN_UDW_MASK REG_GENMASK(19, 10) -#define PREC_PALETTE_12P4_BLUE_UDW_MASK REG_GENMASK(9, 0) -#define PREC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _PREC_PALETTE_A, _PREC_PALETTE_B) + (i) * 4) - -#define _PREC_PIPEAGCMAX 0x4d000 -#define _PREC_PIPEBGCMAX 0x4d010 -#define PREC_PIPEGCMAX(pipe, i) _MMIO(_PIPE(pipe, _PIPEAGCMAX, _PIPEBGCMAX) + (i) * 4) /* u1.16 */ - -#define _GAMMA_MODE_A 0x4a480 -#define _GAMMA_MODE_B 0x4ac80 -#define GAMMA_MODE(pipe) _MMIO_PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) -#define PRE_CSC_GAMMA_ENABLE REG_BIT(31) /* icl+ */ -#define POST_CSC_GAMMA_ENABLE REG_BIT(30) /* icl+ */ -#define PALETTE_ANTICOL_DISABLE REG_BIT(15) /* skl+ */ -#define GAMMA_MODE_MODE_MASK REG_GENMASK(1, 0) -#define GAMMA_MODE_MODE_8BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 0) -#define GAMMA_MODE_MODE_10BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 1) -#define GAMMA_MODE_MODE_12BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 2) -#define GAMMA_MODE_MODE_SPLIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 3) /* ivb-bdw */ -#define GAMMA_MODE_MODE_12BIT_MULTI_SEG REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 3) /* icl-tgl */ /* Display Internal Timeout Register */ #define RM_TIMEOUT _MMIO(0x42060) @@ -4513,13 +4469,12 @@ #define PICAINTERRUPT_IMR _MMIO(0x16FE54) #define PICAINTERRUPT_IIR _MMIO(0x16FE58) #define PICAINTERRUPT_IER _MMIO(0x16FE5C) - #define XELPDP_DP_ALT_HOTPLUG(hpd_pin) REG_BIT(16 + _HPD_PIN_TC(hpd_pin)) #define XELPDP_DP_ALT_HOTPLUG_MASK REG_GENMASK(19, 16) - #define XELPDP_AUX_TC(hpd_pin) REG_BIT(8 + _HPD_PIN_TC(hpd_pin)) #define XELPDP_AUX_TC_MASK REG_GENMASK(11, 8) - +#define XE2LPD_AUX_DDI(hpd_pin) REG_BIT(6 + _HPD_PIN_DDI(hpd_pin)) +#define XE2LPD_AUX_DDI_MASK REG_GENMASK(7, 6) #define XELPDP_TBT_HOTPLUG(hpd_pin) REG_BIT(_HPD_PIN_TC(hpd_pin)) #define XELPDP_TBT_HOTPLUG_MASK REG_GENMASK(3, 0) @@ -4725,6 +4680,13 @@ #define TGL_DFSM_PIPE_D_DISABLE (1 << 22) #define GLK_DFSM_DISPLAY_DSC_DISABLE (1 << 7) +#define XE2LPD_DE_CAP _MMIO(0x41100) +#define XE2LPD_DE_CAP_3DLUT_MASK REG_GENMASK(31, 30) +#define XE2LPD_DE_CAP_DSC_MASK REG_GENMASK(29, 28) +#define XE2LPD_DE_CAP_DSC_REMOVED 1 +#define XE2LPD_DE_CAP_SCALER_MASK REG_GENMASK(27, 26) +#define XE2LPD_DE_CAP_SCALER_SINGLE 1 + #define SKL_DSSM _MMIO(0x51004) #define ICL_DSSM_CDCLK_PLL_REFCLK_MASK (7 << 29) #define ICL_DSSM_CDCLK_PLL_REFCLK_24MHz (0 << 29) @@ -5929,6 +5891,7 @@ enum skl_power_gate { #define CDCLK_FREQ_540 REG_FIELD_PREP(CDCLK_FREQ_SEL_MASK, 1) #define CDCLK_FREQ_337_308 REG_FIELD_PREP(CDCLK_FREQ_SEL_MASK, 2) #define CDCLK_FREQ_675_617 REG_FIELD_PREP(CDCLK_FREQ_SEL_MASK, 3) +#define MDCLK_SOURCE_SEL_CDCLK_PLL REG_BIT(25) #define BXT_CDCLK_CD2X_DIV_SEL_MASK REG_GENMASK(23, 22) #define BXT_CDCLK_CD2X_DIV_SEL_1 REG_FIELD_PREP(BXT_CDCLK_CD2X_DIV_SEL_MASK, 0) #define BXT_CDCLK_CD2X_DIV_SEL_1_5 REG_FIELD_PREP(BXT_CDCLK_CD2X_DIV_SEL_MASK, 1) @@ -6269,179 +6232,6 @@ enum skl_power_gate { #define WM_DBG_DISALLOW_MAXFIFO (1 << 1) #define WM_DBG_DISALLOW_SPRITE (1 << 2) -/* pipe CSC */ -#define _PIPE_A_CSC_COEFF_RY_GY 0x49010 -#define _PIPE_A_CSC_COEFF_BY 0x49014 -#define _PIPE_A_CSC_COEFF_RU_GU 0x49018 -#define _PIPE_A_CSC_COEFF_BU 0x4901c -#define _PIPE_A_CSC_COEFF_RV_GV 0x49020 -#define _PIPE_A_CSC_COEFF_BV 0x49024 - -#define _PIPE_A_CSC_MODE 0x49028 -#define ICL_CSC_ENABLE (1 << 31) /* icl+ */ -#define ICL_OUTPUT_CSC_ENABLE (1 << 30) /* icl+ */ -#define CSC_BLACK_SCREEN_OFFSET (1 << 2) /* ilk/snb */ -#define CSC_POSITION_BEFORE_GAMMA (1 << 1) /* pre-glk */ -#define CSC_MODE_YUV_TO_RGB (1 << 0) /* ilk/snb */ - -#define _PIPE_A_CSC_PREOFF_HI 0x49030 -#define _PIPE_A_CSC_PREOFF_ME 0x49034 -#define _PIPE_A_CSC_PREOFF_LO 0x49038 -#define _PIPE_A_CSC_POSTOFF_HI 0x49040 -#define _PIPE_A_CSC_POSTOFF_ME 0x49044 -#define _PIPE_A_CSC_POSTOFF_LO 0x49048 - -#define _PIPE_B_CSC_COEFF_RY_GY 0x49110 -#define _PIPE_B_CSC_COEFF_BY 0x49114 -#define _PIPE_B_CSC_COEFF_RU_GU 0x49118 -#define _PIPE_B_CSC_COEFF_BU 0x4911c -#define _PIPE_B_CSC_COEFF_RV_GV 0x49120 -#define _PIPE_B_CSC_COEFF_BV 0x49124 -#define _PIPE_B_CSC_MODE 0x49128 -#define _PIPE_B_CSC_PREOFF_HI 0x49130 -#define _PIPE_B_CSC_PREOFF_ME 0x49134 -#define _PIPE_B_CSC_PREOFF_LO 0x49138 -#define _PIPE_B_CSC_POSTOFF_HI 0x49140 -#define _PIPE_B_CSC_POSTOFF_ME 0x49144 -#define _PIPE_B_CSC_POSTOFF_LO 0x49148 - -#define PIPE_CSC_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) -#define PIPE_CSC_COEFF_BY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) -#define PIPE_CSC_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) -#define PIPE_CSC_COEFF_BU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) -#define PIPE_CSC_COEFF_RV_GV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) -#define PIPE_CSC_COEFF_BV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) -#define PIPE_CSC_MODE(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) -#define PIPE_CSC_PREOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) -#define PIPE_CSC_PREOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) -#define PIPE_CSC_PREOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) -#define PIPE_CSC_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) -#define PIPE_CSC_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) -#define PIPE_CSC_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) - -/* Pipe Output CSC */ -#define _PIPE_A_OUTPUT_CSC_COEFF_RY_GY 0x49050 -#define _PIPE_A_OUTPUT_CSC_COEFF_BY 0x49054 -#define _PIPE_A_OUTPUT_CSC_COEFF_RU_GU 0x49058 -#define _PIPE_A_OUTPUT_CSC_COEFF_BU 0x4905c -#define _PIPE_A_OUTPUT_CSC_COEFF_RV_GV 0x49060 -#define _PIPE_A_OUTPUT_CSC_COEFF_BV 0x49064 -#define _PIPE_A_OUTPUT_CSC_PREOFF_HI 0x49068 -#define _PIPE_A_OUTPUT_CSC_PREOFF_ME 0x4906c -#define _PIPE_A_OUTPUT_CSC_PREOFF_LO 0x49070 -#define _PIPE_A_OUTPUT_CSC_POSTOFF_HI 0x49074 -#define _PIPE_A_OUTPUT_CSC_POSTOFF_ME 0x49078 -#define _PIPE_A_OUTPUT_CSC_POSTOFF_LO 0x4907c - -#define _PIPE_B_OUTPUT_CSC_COEFF_RY_GY 0x49150 -#define _PIPE_B_OUTPUT_CSC_COEFF_BY 0x49154 -#define _PIPE_B_OUTPUT_CSC_COEFF_RU_GU 0x49158 -#define _PIPE_B_OUTPUT_CSC_COEFF_BU 0x4915c -#define _PIPE_B_OUTPUT_CSC_COEFF_RV_GV 0x49160 -#define _PIPE_B_OUTPUT_CSC_COEFF_BV 0x49164 -#define _PIPE_B_OUTPUT_CSC_PREOFF_HI 0x49168 -#define _PIPE_B_OUTPUT_CSC_PREOFF_ME 0x4916c -#define _PIPE_B_OUTPUT_CSC_PREOFF_LO 0x49170 -#define _PIPE_B_OUTPUT_CSC_POSTOFF_HI 0x49174 -#define _PIPE_B_OUTPUT_CSC_POSTOFF_ME 0x49178 -#define _PIPE_B_OUTPUT_CSC_POSTOFF_LO 0x4917c - -#define PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe,\ - _PIPE_A_OUTPUT_CSC_COEFF_RY_GY,\ - _PIPE_B_OUTPUT_CSC_COEFF_RY_GY) -#define PIPE_CSC_OUTPUT_COEFF_BY(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_COEFF_BY, \ - _PIPE_B_OUTPUT_CSC_COEFF_BY) -#define PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_COEFF_RU_GU, \ - _PIPE_B_OUTPUT_CSC_COEFF_RU_GU) -#define PIPE_CSC_OUTPUT_COEFF_BU(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_COEFF_BU, \ - _PIPE_B_OUTPUT_CSC_COEFF_BU) -#define PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_COEFF_RV_GV, \ - _PIPE_B_OUTPUT_CSC_COEFF_RV_GV) -#define PIPE_CSC_OUTPUT_COEFF_BV(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_COEFF_BV, \ - _PIPE_B_OUTPUT_CSC_COEFF_BV) -#define PIPE_CSC_OUTPUT_PREOFF_HI(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_PREOFF_HI, \ - _PIPE_B_OUTPUT_CSC_PREOFF_HI) -#define PIPE_CSC_OUTPUT_PREOFF_ME(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_PREOFF_ME, \ - _PIPE_B_OUTPUT_CSC_PREOFF_ME) -#define PIPE_CSC_OUTPUT_PREOFF_LO(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_PREOFF_LO, \ - _PIPE_B_OUTPUT_CSC_PREOFF_LO) -#define PIPE_CSC_OUTPUT_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_POSTOFF_HI, \ - _PIPE_B_OUTPUT_CSC_POSTOFF_HI) -#define PIPE_CSC_OUTPUT_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_POSTOFF_ME, \ - _PIPE_B_OUTPUT_CSC_POSTOFF_ME) -#define PIPE_CSC_OUTPUT_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, \ - _PIPE_A_OUTPUT_CSC_POSTOFF_LO, \ - _PIPE_B_OUTPUT_CSC_POSTOFF_LO) - -/* pipe degamma/gamma LUTs on IVB+ */ -#define _PAL_PREC_INDEX_A 0x4A400 -#define _PAL_PREC_INDEX_B 0x4AC00 -#define _PAL_PREC_INDEX_C 0x4B400 -#define PAL_PREC_SPLIT_MODE REG_BIT(31) -#define PAL_PREC_AUTO_INCREMENT REG_BIT(15) -#define PAL_PREC_INDEX_VALUE_MASK REG_GENMASK(9, 0) -#define PAL_PREC_INDEX_VALUE(x) REG_FIELD_PREP(PAL_PREC_INDEX_VALUE_MASK, (x)) -#define _PAL_PREC_DATA_A 0x4A404 -#define _PAL_PREC_DATA_B 0x4AC04 -#define _PAL_PREC_DATA_C 0x4B404 -/* see PREC_PALETTE_* for the bits */ -#define _PAL_PREC_GC_MAX_A 0x4A410 -#define _PAL_PREC_GC_MAX_B 0x4AC10 -#define _PAL_PREC_GC_MAX_C 0x4B410 -#define _PAL_PREC_EXT_GC_MAX_A 0x4A420 -#define _PAL_PREC_EXT_GC_MAX_B 0x4AC20 -#define _PAL_PREC_EXT_GC_MAX_C 0x4B420 -#define _PAL_PREC_EXT2_GC_MAX_A 0x4A430 -#define _PAL_PREC_EXT2_GC_MAX_B 0x4AC30 -#define _PAL_PREC_EXT2_GC_MAX_C 0x4B430 - -#define PREC_PAL_INDEX(pipe) _MMIO_PIPE(pipe, _PAL_PREC_INDEX_A, _PAL_PREC_INDEX_B) -#define PREC_PAL_DATA(pipe) _MMIO_PIPE(pipe, _PAL_PREC_DATA_A, _PAL_PREC_DATA_B) -#define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4) /* u1.16 */ -#define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (i) * 4) /* u3.16 */ -#define PREC_PAL_EXT2_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT2_GC_MAX_A, _PAL_PREC_EXT2_GC_MAX_B) + (i) * 4) /* glk+, u3.16 */ - -#define _PRE_CSC_GAMC_INDEX_A 0x4A484 -#define _PRE_CSC_GAMC_INDEX_B 0x4AC84 -#define _PRE_CSC_GAMC_INDEX_C 0x4B484 -#define PRE_CSC_GAMC_AUTO_INCREMENT REG_BIT(10) -#define PRE_CSC_GAMC_INDEX_VALUE_MASK REG_GENMASK(7, 0) -#define PRE_CSC_GAMC_INDEX_VALUE(x) REG_FIELD_PREP(PRE_CSC_GAMC_INDEX_VALUE_MASK, (x)) -#define _PRE_CSC_GAMC_DATA_A 0x4A488 -#define _PRE_CSC_GAMC_DATA_B 0x4AC88 -#define _PRE_CSC_GAMC_DATA_C 0x4B488 - -#define PRE_CSC_GAMC_INDEX(pipe) _MMIO_PIPE(pipe, _PRE_CSC_GAMC_INDEX_A, _PRE_CSC_GAMC_INDEX_B) -#define PRE_CSC_GAMC_DATA(pipe) _MMIO_PIPE(pipe, _PRE_CSC_GAMC_DATA_A, _PRE_CSC_GAMC_DATA_B) - -/* ICL Multi segmented gamma */ -#define _PAL_PREC_MULTI_SEG_INDEX_A 0x4A408 -#define _PAL_PREC_MULTI_SEG_INDEX_B 0x4AC08 -#define PAL_PREC_MULTI_SEG_AUTO_INCREMENT REG_BIT(15) -#define PAL_PREC_MULTI_SEG_INDEX_VALUE_MASK REG_GENMASK(4, 0) -#define PAL_PREC_MULTI_SEG_INDEX_VALUE(x) REG_FIELD_PREP(PAL_PREC_MULTI_SEG_INDEX_VALUE_MASK, (x)) - -#define _PAL_PREC_MULTI_SEG_DATA_A 0x4A40C -#define _PAL_PREC_MULTI_SEG_DATA_B 0x4AC0C -/* see PREC_PALETTE_12P4_* for the bits */ - -#define PREC_PAL_MULTI_SEG_INDEX(pipe) _MMIO_PIPE(pipe, \ - _PAL_PREC_MULTI_SEG_INDEX_A, \ - _PAL_PREC_MULTI_SEG_INDEX_B) -#define PREC_PAL_MULTI_SEG_DATA(pipe) _MMIO_PIPE(pipe, \ - _PAL_PREC_MULTI_SEG_DATA_A, \ - _PAL_PREC_MULTI_SEG_DATA_B) - #define _MMIO_PLANE_GAMC(plane, i, a, b) _MMIO(_PIPE(plane, a, b) + (i) * 4) /* Plane CSC Registers */ @@ -6487,61 +6277,6 @@ enum skl_power_gate { (index) * 4, _PLANE_CSC_POSTOFF_HI_2(pipe) + \ (index) * 4) -#define _PIPE_A_WGC_C01_C00 0x600B0 /* s2.10 */ -#define _PIPE_A_WGC_C02 0x600B4 /* s2.10 */ -#define _PIPE_A_WGC_C11_C10 0x600B8 /* s2.10 */ -#define _PIPE_A_WGC_C12 0x600BC /* s2.10 */ -#define _PIPE_A_WGC_C21_C20 0x600C0 /* s2.10 */ -#define _PIPE_A_WGC_C22 0x600C4 /* s2.10 */ - -#define PIPE_WGC_C01_C00(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C01_C00) -#define PIPE_WGC_C02(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C02) -#define PIPE_WGC_C11_C10(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C11_C10) -#define PIPE_WGC_C12(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C12) -#define PIPE_WGC_C21_C20(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C21_C20) -#define PIPE_WGC_C22(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C22) - -/* pipe CSC & degamma/gamma LUTs on CHV */ -#define _CGM_PIPE_A_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x67900) -#define _CGM_PIPE_A_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x67904) -#define _CGM_PIPE_A_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x67908) -#define _CGM_PIPE_A_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6790C) -#define _CGM_PIPE_A_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x67910) -#define _CGM_PIPE_A_DEGAMMA (VLV_DISPLAY_BASE + 0x66000) -/* cgm degamma ldw */ -#define CGM_PIPE_DEGAMMA_GREEN_LDW_MASK REG_GENMASK(29, 16) -#define CGM_PIPE_DEGAMMA_BLUE_LDW_MASK REG_GENMASK(13, 0) -/* cgm degamma udw */ -#define CGM_PIPE_DEGAMMA_RED_UDW_MASK REG_GENMASK(13, 0) -#define _CGM_PIPE_A_GAMMA (VLV_DISPLAY_BASE + 0x67000) -/* cgm gamma ldw */ -#define CGM_PIPE_GAMMA_GREEN_LDW_MASK REG_GENMASK(25, 16) -#define CGM_PIPE_GAMMA_BLUE_LDW_MASK REG_GENMASK(9, 0) -/* cgm gamma udw */ -#define CGM_PIPE_GAMMA_RED_UDW_MASK REG_GENMASK(9, 0) -#define _CGM_PIPE_A_MODE (VLV_DISPLAY_BASE + 0x67A00) -#define CGM_PIPE_MODE_GAMMA (1 << 2) -#define CGM_PIPE_MODE_CSC (1 << 1) -#define CGM_PIPE_MODE_DEGAMMA (1 << 0) - -#define _CGM_PIPE_B_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x69900) -#define _CGM_PIPE_B_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x69904) -#define _CGM_PIPE_B_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x69908) -#define _CGM_PIPE_B_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6990C) -#define _CGM_PIPE_B_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x69910) -#define _CGM_PIPE_B_DEGAMMA (VLV_DISPLAY_BASE + 0x68000) -#define _CGM_PIPE_B_GAMMA (VLV_DISPLAY_BASE + 0x69000) -#define _CGM_PIPE_B_MODE (VLV_DISPLAY_BASE + 0x69A00) - -#define CGM_PIPE_CSC_COEFF01(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF01, _CGM_PIPE_B_CSC_COEFF01) -#define CGM_PIPE_CSC_COEFF23(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF23, _CGM_PIPE_B_CSC_COEFF23) -#define CGM_PIPE_CSC_COEFF45(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF45, _CGM_PIPE_B_CSC_COEFF45) -#define CGM_PIPE_CSC_COEFF67(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF67, _CGM_PIPE_B_CSC_COEFF67) -#define CGM_PIPE_CSC_COEFF8(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF8, _CGM_PIPE_B_CSC_COEFF8) -#define CGM_PIPE_DEGAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_DEGAMMA, _CGM_PIPE_B_DEGAMMA) + (i) * 8 + (w) * 4) -#define CGM_PIPE_GAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_GAMMA, _CGM_PIPE_B_GAMMA) + (i) * 8 + (w) * 4) -#define CGM_PIPE_MODE(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_MODE, _CGM_PIPE_B_MODE) - /* Gen4+ Timestamp and Pipe Frame time stamp registers */ #define GEN4_TIMESTAMP _MMIO(0x2358) #define ILK_TIMESTAMP_HI _MMIO(0x70070) @@ -6624,6 +6359,7 @@ enum skl_power_gate { #define TCSS_DDI_STATUS(tc) _MMIO(_PICK_EVEN(tc, \ _TCSS_DDI_STATUS_1, \ _TCSS_DDI_STATUS_2)) +#define TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK REG_GENMASK(28, 25) #define TCSS_DDI_STATUS_READY REG_BIT(2) #define TCSS_DDI_STATUS_HPD_LIVE_STATUS_TBT REG_BIT(1) #define TCSS_DDI_STATUS_HPD_LIVE_STATUS_ALT REG_BIT(0) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 7c7da284990d..f59081066a19 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -134,9 +134,7 @@ static void i915_fence_release(struct dma_fence *fence) i915_sw_fence_fini(&rq->semaphore); /* - * Keep one request on each engine for reserved use under mempressure - * do not use with virtual engines as this really is only needed for - * kernel contexts. + * Keep one request on each engine for reserved use under mempressure. * * We do not hold a reference to the engine here and so have to be * very careful in what rq->engine we poke. The virtual engine is @@ -166,8 +164,7 @@ static void i915_fence_release(struct dma_fence *fence) * know that if the rq->execution_mask is a single bit, rq->engine * can be a physical engine with the exact corresponding mask. */ - if (!intel_engine_is_virtual(rq->engine) && - is_power_of_2(rq->execution_mask) && + if (is_power_of_2(rq->execution_mask) && !cmpxchg(&rq->engine->request_pool, NULL, rq)) return; diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h index 5a10c1a31183..6cf8a298849f 100644 --- a/drivers/gpu/drm/i915/i915_scatterlist.h +++ b/drivers/gpu/drm/i915/i915_scatterlist.h @@ -91,6 +91,16 @@ static inline struct scatterlist *__sg_next(struct scatterlist *sg) ((__dp) = (__iter).dma + (__iter).curr), (__iter).sgp; \ (((__iter).curr += (__step)) >= (__iter).max) ? \ (__iter) = __sgt_iter(__sg_next((__iter).sgp), true), 0 : 0) +/** + * __for_each_daddr_next - iterates over the device addresses with pre-initialized iterator. + * @__dp: Device address (output) + * @__iter: 'struct sgt_iter' (iterator state, external) + * @__step: step size + */ +#define __for_each_daddr_next(__dp, __iter, __step) \ + for (; ((__dp) = (__iter).dma + (__iter).curr), (__iter).sgp; \ + (((__iter).curr += (__step)) >= (__iter).max) ? \ + (__iter) = __sgt_iter(__sg_next((__iter).sgp), true), 0 : 0) /** * for_each_sgt_page - iterate over the pages of the given sg_table diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c index a1bc804cfa15..0d735d5c2b35 100644 --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c @@ -59,6 +59,9 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, if (place->flags & TTM_PL_FLAG_TOPDOWN) bman_res->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) + bman_res->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION; + if (place->fpfn || lpfn != man->size) bman_res->flags |= DRM_BUDDY_RANGE_ALLOCATION; @@ -72,18 +75,6 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, GEM_BUG_ON(min_page_size < mm->chunk_size); GEM_BUG_ON(!IS_ALIGNED(size, min_page_size)); - if (place->fpfn + PFN_UP(bman_res->base.size) != place->lpfn && - place->flags & TTM_PL_FLAG_CONTIGUOUS) { - unsigned long pages; - - size = roundup_pow_of_two(size); - min_page_size = size; - - pages = size >> ilog2(mm->chunk_size); - if (pages > lpfn) - lpfn = pages; - } - if (size > lpfn << PAGE_SHIFT) { err = -E2BIG; goto err_free_res; @@ -107,14 +98,6 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, if (unlikely(err)) goto err_free_blocks; - if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { - u64 original_size = (u64)bman_res->base.size; - - drm_buddy_block_trim(mm, - original_size, - &bman_res->blocks); - } - if (lpfn <= bman->visible_size) { bman_res->used_visible_size = PFN_UP(bman_res->base.size); } else { diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 6f180ee13853..d09aad34ba37 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -29,6 +29,7 @@ #include "display/intel_display.h" #include "display/intel_frontbuffer.h" #include "gem/i915_gem_lmem.h" +#include "gem/i915_gem_object_frontbuffer.h" #include "gem/i915_gem_tiling.h" #include "gt/intel_engine.h" #include "gt/intel_engine_heartbeat.h" diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c b/drivers/gpu/drm/i915/i915_vma_resource.c index 6ba7a7feceba..53d619ef0c3d 100644 --- a/drivers/gpu/drm/i915/i915_vma_resource.c +++ b/drivers/gpu/drm/i915/i915_vma_resource.c @@ -94,7 +94,7 @@ static void unbind_fence_release(struct dma_fence *fence) call_rcu(&fence->rcu, unbind_fence_free_rcu); } -static struct dma_fence_ops unbind_fence_ops = { +static const struct dma_fence_ops unbind_fence_ops = { .get_driver_name = get_driver_name, .get_timeline_name = get_timeline_name, .release = unbind_fence_release, diff --git a/drivers/gpu/drm/i915/intel_clock_gating.c b/drivers/gpu/drm/i915/intel_clock_gating.c index 81a4d32734e9..9c21ce69bd98 100644 --- a/drivers/gpu/drm/i915/intel_clock_gating.c +++ b/drivers/gpu/drm/i915/intel_clock_gating.c @@ -349,41 +349,6 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *i915, intel_uncore_write(&i915->uncore, GEN7_MISCCPCTL, misccpctl); } -static void icl_init_clock_gating(struct drm_i915_private *i915) -{ - /* Wa_1409120013:icl,ehl */ - intel_uncore_write(&i915->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), - DPFC_CHICKEN_COMP_DUMMY_PIXEL); - - /*Wa_14010594013:icl, ehl */ - intel_uncore_rmw(&i915->uncore, GEN8_CHICKEN_DCPR_1, - 0, ICL_DELAY_PMRSP); -} - -static void gen12lp_init_clock_gating(struct drm_i915_private *i915) -{ - /* Wa_1409120013 */ - if (DISPLAY_VER(i915) == 12) - intel_uncore_write(&i915->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), - DPFC_CHICKEN_COMP_DUMMY_PIXEL); - - /* Wa_14013723622:tgl,rkl,dg1,adl-s */ - if (DISPLAY_VER(i915) == 12) - intel_uncore_rmw(&i915->uncore, CLKREQ_POLICY, - CLKREQ_POLICY_MEM_UP_OVRD, 0); -} - -static void adlp_init_clock_gating(struct drm_i915_private *i915) -{ - gen12lp_init_clock_gating(i915); - - /* Wa_22011091694:adlp */ - intel_de_rmw(i915, GEN9_CLKGATE_DIS_5, 0, DPCE_GATING_DIS); - - /* Bspec/49189 Initialize Sequence */ - intel_de_rmw(i915, GEN8_CHICKEN_DCPR_1, DDI_CLOCK_REG_ACCESS, 0); -} - static void xehpsdv_init_clock_gating(struct drm_i915_private *i915) { /* Wa_22010146351:xehpsdv */ @@ -396,14 +361,6 @@ static void dg2_init_clock_gating(struct drm_i915_private *i915) /* Wa_22010954014:dg2 */ intel_uncore_rmw(&i915->uncore, XEHP_CLOCK_GATE_DIS, 0, SGSI_SIDECLK_DIS); - - /* - * Wa_14010733611:dg2_g10 - * Wa_22010146351:dg2_g10 - */ - if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) - intel_uncore_rmw(&i915->uncore, XEHP_CLOCK_GATE_DIS, 0, - SGR_DIS | SGGI_DIS); } static void pvc_init_clock_gating(struct drm_i915_private *i915) @@ -808,9 +765,6 @@ static const struct drm_i915_clock_gating_funcs platform##_clock_gating_funcs = CG_FUNCS(pvc); CG_FUNCS(dg2); CG_FUNCS(xehpsdv); -CG_FUNCS(adlp); -CG_FUNCS(gen12lp); -CG_FUNCS(icl); CG_FUNCS(cfl); CG_FUNCS(skl); CG_FUNCS(kbl); @@ -843,20 +797,12 @@ CG_FUNCS(nop); */ void intel_clock_gating_hooks_init(struct drm_i915_private *i915) { - if (IS_METEORLAKE(i915)) - i915->clock_gating_funcs = &nop_clock_gating_funcs; - else if (IS_PONTEVECCHIO(i915)) + if (IS_PONTEVECCHIO(i915)) i915->clock_gating_funcs = &pvc_clock_gating_funcs; else if (IS_DG2(i915)) i915->clock_gating_funcs = &dg2_clock_gating_funcs; else if (IS_XEHPSDV(i915)) i915->clock_gating_funcs = &xehpsdv_clock_gating_funcs; - else if (IS_ALDERLAKE_P(i915)) - i915->clock_gating_funcs = &adlp_clock_gating_funcs; - else if (GRAPHICS_VER(i915) == 12) - i915->clock_gating_funcs = &gen12lp_clock_gating_funcs; - else if (GRAPHICS_VER(i915) == 11) - i915->clock_gating_funcs = &icl_clock_gating_funcs; else if (IS_COFFEELAKE(i915) || IS_COMETLAKE(i915)) i915->clock_gating_funcs = &cfl_clock_gating_funcs; else if (IS_SKYLAKE(i915)) @@ -893,8 +839,6 @@ void intel_clock_gating_hooks_init(struct drm_i915_private *i915) i915->clock_gating_funcs = &i85x_clock_gating_funcs; else if (GRAPHICS_VER(i915) == 2) i915->clock_gating_funcs = &i830_clock_gating_funcs; - else { - MISSING_CASE(INTEL_DEVID(i915)); + else i915->clock_gating_funcs = &nop_clock_gating_funcs; - } } diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index ea0ec6174ce5..59bea1398c91 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -27,7 +27,6 @@ #include <drm/drm_print.h> #include <drm/i915_pciids.h> -#include "display/intel_display_device.h" #include "gt/intel_gt_regs.h" #include "i915_drv.h" #include "i915_reg.h" @@ -206,14 +205,6 @@ static const u16 subplatform_g12_ids[] = { INTEL_DG2_G12_IDS(0), }; -static const u16 subplatform_m_ids[] = { - INTEL_MTL_M_IDS(0), -}; - -static const u16 subplatform_p_ids[] = { - INTEL_MTL_P_IDS(0), -}; - static bool find_devid(u16 id, const u16 *p, unsigned int num) { for (; num; num--, p++) { @@ -240,19 +231,15 @@ static void intel_device_info_subplatform_init(struct drm_i915_private *i915) if (find_devid(devid, subplatform_ult_ids, ARRAY_SIZE(subplatform_ult_ids))) { mask = BIT(INTEL_SUBPLATFORM_ULT); - if (IS_HASWELL(i915) || IS_BROADWELL(i915)) - DISPLAY_RUNTIME_INFO(i915)->port_mask &= ~BIT(PORT_D); } else if (find_devid(devid, subplatform_ulx_ids, ARRAY_SIZE(subplatform_ulx_ids))) { mask = BIT(INTEL_SUBPLATFORM_ULX); if (IS_HASWELL(i915) || IS_BROADWELL(i915)) { /* ULX machines are also considered ULT. */ mask |= BIT(INTEL_SUBPLATFORM_ULT); - DISPLAY_RUNTIME_INFO(i915)->port_mask &= ~BIT(PORT_D); } } else if (find_devid(devid, subplatform_portf_ids, ARRAY_SIZE(subplatform_portf_ids))) { - DISPLAY_RUNTIME_INFO(i915)->port_mask |= BIT(PORT_F); mask = BIT(INTEL_SUBPLATFORM_PORTF); } else if (find_devid(devid, subplatform_uy_ids, ARRAY_SIZE(subplatform_uy_ids))) { @@ -275,12 +262,6 @@ static void intel_device_info_subplatform_init(struct drm_i915_private *i915) } else if (find_devid(devid, subplatform_g12_ids, ARRAY_SIZE(subplatform_g12_ids))) { mask = BIT(INTEL_SUBPLATFORM_G12); - } else if (find_devid(devid, subplatform_m_ids, - ARRAY_SIZE(subplatform_m_ids))) { - mask = BIT(INTEL_SUBPLATFORM_M); - } else if (find_devid(devid, subplatform_p_ids, - ARRAY_SIZE(subplatform_p_ids))) { - mask = BIT(INTEL_SUBPLATFORM_P); } GEM_BUG_ON(mask & ~INTEL_SUBPLATFORM_MASK); @@ -364,8 +345,6 @@ void intel_device_info_runtime_init_early(struct drm_i915_private *i915) intel_device_info_subplatform_init(i915); } -static const struct intel_display_device_info no_display = {}; - /** * intel_device_info_runtime_init - initialize runtime info * @dev_priv: the i915 device @@ -386,21 +365,6 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) { struct intel_runtime_info *runtime = RUNTIME_INFO(dev_priv); - if (HAS_DISPLAY(dev_priv)) - intel_display_device_info_runtime_init(dev_priv); - - /* Display may have been disabled by runtime init */ - if (!HAS_DISPLAY(dev_priv)) { - dev_priv->drm.driver_features &= ~(DRIVER_MODESET | - DRIVER_ATOMIC); - dev_priv->display.info.__device_info = &no_display; - } - - /* Disable nuclear pageflip by default on pre-g4x */ - if (!dev_priv->params.nuclear_pageflip && - DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) - dev_priv->drm.driver_features &= ~DRIVER_ATOMIC; - BUILD_BUG_ON(BITS_PER_TYPE(intel_engine_mask_t) < I915_NUM_ENGINES); if (GRAPHICS_VER(dev_priv) == 6 && i915_vtd_active(dev_priv)) { @@ -424,7 +388,6 @@ void intel_device_info_driver_create(struct drm_i915_private *i915, const struct intel_device_info *match_info) { struct intel_runtime_info *runtime; - u16 ver, rel, step; /* Setup INTEL_INFO() */ i915->__info = match_info; @@ -433,19 +396,6 @@ void intel_device_info_driver_create(struct drm_i915_private *i915, runtime = RUNTIME_INFO(i915); memcpy(runtime, &INTEL_INFO(i915)->__runtime, sizeof(*runtime)); - /* Probe display support */ - i915->display.info.__device_info = intel_display_device_probe(i915, HAS_GMD_ID(i915), - &ver, &rel, &step); - memcpy(DISPLAY_RUNTIME_INFO(i915), - &DISPLAY_INFO(i915)->__runtime_defaults, - sizeof(*DISPLAY_RUNTIME_INFO(i915))); - - if (HAS_GMD_ID(i915)) { - DISPLAY_RUNTIME_INFO(i915)->ip.ver = ver; - DISPLAY_RUNTIME_INFO(i915)->ip.rel = rel; - DISPLAY_RUNTIME_INFO(i915)->ip.step = step; - } - runtime->device_id = device_id; } diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index dbfe6443457b..39817490b13f 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -129,10 +129,6 @@ enum intel_platform { #define INTEL_SUBPLATFORM_N 1 #define INTEL_SUBPLATFORM_RPLU 2 -/* MTL */ -#define INTEL_SUBPLATFORM_M 0 -#define INTEL_SUBPLATFORM_P 1 - enum intel_ppgtt_type { INTEL_PPGTT_NONE = I915_GEM_PPGTT_NONE, INTEL_PPGTT_ALIASING = I915_GEM_PPGTT_ALIASING, @@ -150,7 +146,6 @@ enum intel_ppgtt_type { func(gpu_reset_clobbers_display); \ func(has_reset_engine); \ func(has_3d_pipeline); \ - func(has_4tile); \ func(has_flat_ccs); \ func(has_global_mocs); \ func(has_gmd_id); \ diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c index 5d08774029cc..87ecc5104fd9 100644 --- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c +++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c @@ -5,6 +5,7 @@ #include "display/intel_audio_regs.h" #include "display/intel_backlight_regs.h" +#include "display/intel_color_regs.h" #include "display/intel_display_types.h" #include "display/intel_dmc_regs.h" #include "display/intel_dp_aux_regs.h" @@ -14,8 +15,9 @@ #include "display/intel_psr_regs.h" #include "display/skl_watermark_regs.h" #include "display/vlv_dsi_pll_regs.h" +#include "gt/intel_engine_regs.h" #include "gt/intel_gt_regs.h" -#include "gvt/gvt.h" +#include "gvt/reg.h" #include "i915_drv.h" #include "i915_pvinfo.h" diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 6d8e5e5c0cba..8743153fad87 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -652,7 +652,6 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) rpm->kdev = kdev; rpm->available = HAS_RUNTIME_PM(i915); - rpm->suspended = false; atomic_set(&rpm->wakeref_count, 0); init_intel_runtime_pm_wakeref(rpm); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h index 764b183ae452..f79cda7a2503 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -6,6 +6,7 @@ #ifndef __INTEL_RUNTIME_PM_H__ #define __INTEL_RUNTIME_PM_H__ +#include <linux/pm_runtime.h> #include <linux/types.h> #include "intel_wakeref.h" @@ -43,7 +44,6 @@ struct intel_runtime_pm { atomic_t wakeref_count; struct device *kdev; /* points to i915->drm.dev */ bool available; - bool suspended; bool irqs_enabled; bool no_wakeref_tracking; @@ -110,7 +110,7 @@ intel_rpm_wakelock_count(int wakeref_count) static inline void assert_rpm_device_not_suspended(struct intel_runtime_pm *rpm) { - WARN_ONCE(rpm->suspended, + WARN_ONCE(pm_runtime_suspended(rpm->kdev), "Device suspended during HW access\n"); } diff --git a/drivers/gpu/drm/i915/intel_step.c b/drivers/gpu/drm/i915/intel_step.c index c02a6f156a00..b4162f1be765 100644 --- a/drivers/gpu/drm/i915/intel_step.c +++ b/drivers/gpu/drm/i915/intel_step.c @@ -124,6 +124,7 @@ static const struct intel_step_info dg2_g11_revid_step_tbl[] = { static const struct intel_step_info dg2_g12_revid_step_tbl[] = { [0x0] = { COMMON_GT_MEDIA_STEP(A0), .display_step = STEP_C0 }, + [0x1] = { COMMON_GT_MEDIA_STEP(A1), .display_step = STEP_C0 }, }; static const struct intel_step_info adls_rpls_revids[] = { @@ -352,3 +353,8 @@ const char *intel_step_name(enum intel_step step) return "**"; } } + +const char *intel_display_step_name(struct drm_i915_private *i915) +{ + return intel_step_name(RUNTIME_INFO(i915)->step.display_step); +} diff --git a/drivers/gpu/drm/i915/intel_step.h b/drivers/gpu/drm/i915/intel_step.h index 96dfca4cba73..b6f43b624774 100644 --- a/drivers/gpu/drm/i915/intel_step.h +++ b/drivers/gpu/drm/i915/intel_step.h @@ -78,5 +78,6 @@ enum intel_step { void intel_step_init(struct drm_i915_private *i915); const char *intel_step_name(enum intel_step step); +const char *intel_display_step_name(struct drm_i915_private *i915); #endif /* __INTEL_STEP_H__ */ diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c index 718f2f1b6174..623a69089386 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -10,21 +10,12 @@ #include "intel_wakeref.h" #include "i915_drv.h" -static void rpm_get(struct intel_wakeref *wf) -{ - wf->wakeref = intel_runtime_pm_get(&wf->i915->runtime_pm); -} - -static void rpm_put(struct intel_wakeref *wf) -{ - intel_wakeref_t wakeref = fetch_and_zero(&wf->wakeref); - - intel_runtime_pm_put(&wf->i915->runtime_pm, wakeref); - INTEL_WAKEREF_BUG_ON(!wakeref); -} - int __intel_wakeref_get_first(struct intel_wakeref *wf) { + intel_wakeref_t wakeref; + int ret = 0; + + wakeref = intel_runtime_pm_get(&wf->i915->runtime_pm); /* * Treat get/put as different subclasses, as we may need to run * the put callback from under the shrinker and do not want to @@ -32,41 +23,52 @@ int __intel_wakeref_get_first(struct intel_wakeref *wf) * upon acquiring the wakeref. */ mutex_lock_nested(&wf->mutex, SINGLE_DEPTH_NESTING); - if (!atomic_read(&wf->count)) { - int err; - - rpm_get(wf); - err = wf->ops->get(wf); - if (unlikely(err)) { - rpm_put(wf); - mutex_unlock(&wf->mutex); - return err; + if (!atomic_read(&wf->count)) { + INTEL_WAKEREF_BUG_ON(wf->wakeref); + wf->wakeref = wakeref; + wakeref = 0; + + ret = wf->ops->get(wf); + if (ret) { + wakeref = xchg(&wf->wakeref, 0); + wake_up_var(&wf->wakeref); + goto unlock; } smp_mb__before_atomic(); /* release wf->count */ } + atomic_inc(&wf->count); + INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0); + +unlock: mutex_unlock(&wf->mutex); + if (unlikely(wakeref)) + intel_runtime_pm_put(&wf->i915->runtime_pm, wakeref); - INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0); - return 0; + return ret; } static void ____intel_wakeref_put_last(struct intel_wakeref *wf) { + intel_wakeref_t wakeref = 0; + INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0); if (unlikely(!atomic_dec_and_test(&wf->count))) goto unlock; /* ops->put() must reschedule its own release on error/deferral */ if (likely(!wf->ops->put(wf))) { - rpm_put(wf); + INTEL_WAKEREF_BUG_ON(!wf->wakeref); + wakeref = xchg(&wf->wakeref, 0); wake_up_var(&wf->wakeref); } unlock: mutex_unlock(&wf->mutex); + if (wakeref) + intel_runtime_pm_put(&wf->i915->runtime_pm, wakeref); } void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index 38ec754d0ec8..dc327cf40b5a 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -359,22 +359,46 @@ void intel_pxp_end(struct intel_pxp *pxp) intel_runtime_pm_put(&i915->runtime_pm, wakeref); } +static bool pxp_required_fw_failed(struct intel_pxp *pxp) +{ + if (__intel_uc_fw_status(&pxp->ctrl_gt->uc.huc.fw) == INTEL_UC_FIRMWARE_LOAD_FAIL) + return true; + if (HAS_ENGINE(pxp->ctrl_gt, GSC0) && + __intel_uc_fw_status(&pxp->ctrl_gt->uc.gsc.fw) == INTEL_UC_FIRMWARE_LOAD_FAIL) + return true; + + return false; +} + +static bool pxp_fw_dependencies_completed(struct intel_pxp *pxp) +{ + if (HAS_ENGINE(pxp->ctrl_gt, GSC0)) + return intel_pxp_gsccs_is_ready_for_sessions(pxp); + + return pxp_component_bound(pxp); +} + /* * this helper is used by both intel_pxp_start and by * the GET_PARAM IOCTL that user space calls. Thus, the * return values here should match the UAPI spec. */ -int intel_pxp_get_readiness_status(struct intel_pxp *pxp) +int intel_pxp_get_readiness_status(struct intel_pxp *pxp, int timeout_ms) { if (!intel_pxp_is_enabled(pxp)) return -ENODEV; - if (HAS_ENGINE(pxp->ctrl_gt, GSC0)) { - if (wait_for(intel_pxp_gsccs_is_ready_for_sessions(pxp), 250)) - return 2; - } else { - if (wait_for(pxp_component_bound(pxp), 250)) + if (pxp_required_fw_failed(pxp)) + return -ENODEV; + + if (pxp->platform_cfg_is_bad) + return -ENODEV; + + if (timeout_ms) { + if (wait_for(pxp_fw_dependencies_completed(pxp), timeout_ms)) return 2; + } else if (!pxp_fw_dependencies_completed(pxp)) { + return 2; } return 1; } @@ -383,11 +407,13 @@ int intel_pxp_get_readiness_status(struct intel_pxp *pxp) * the arb session is restarted from the irq work when we receive the * termination completion interrupt */ +#define PXP_READINESS_TIMEOUT 250 + int intel_pxp_start(struct intel_pxp *pxp) { int ret = 0; - ret = intel_pxp_get_readiness_status(pxp); + ret = intel_pxp_get_readiness_status(pxp, PXP_READINESS_TIMEOUT); if (ret < 0) return ret; else if (ret > 1) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index 17254c3f1267..d9372f6f7797 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -26,7 +26,7 @@ void intel_pxp_fini_hw(struct intel_pxp *pxp); void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp); void intel_pxp_tee_end_arb_fw_session(struct intel_pxp *pxp, u32 arb_session_id); -int intel_pxp_get_readiness_status(struct intel_pxp *pxp); +int intel_pxp_get_readiness_status(struct intel_pxp *pxp, int timeout_ms); int intel_pxp_get_backend_timeout_ms(struct intel_pxp *pxp); int intel_pxp_start(struct intel_pxp *pxp); void intel_pxp_end(struct intel_pxp *pxp); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h index 0165d38fbead..329b4fcdc040 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h @@ -14,8 +14,8 @@ #define PXP43_CMDID_NEW_HUC_AUTH 0x0000003F /* MTL+ */ #define PXP43_CMDID_INIT_SESSION 0x00000036 -/* PXP-Packet sizes for MTL's GSCCS-HECI instruction */ -#define PXP43_MAX_HECI_INOUT_SIZE (SZ_32K) +/* PXP-Packet sizes for MTL's GSCCS-HECI instruction is spec'd at 65K before page alignment*/ +#define PXP43_MAX_HECI_INOUT_SIZE (PAGE_ALIGN(SZ_64K + SZ_1K)) /* PXP-Packet size for MTL's NEW_HUC_AUTH instruction */ #define PXP43_HUC_AUTH_INOUT_SIZE (SZ_4K) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.c b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.c index 2a600184a077..27402ecf0457 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.c @@ -18,12 +18,13 @@ #include "intel_pxp_types.h" static bool -is_fw_err_platform_config(u32 type) +is_fw_err_platform_config(struct intel_pxp *pxp, u32 type) { switch (type) { case PXP_STATUS_ERROR_API_VERSION: case PXP_STATUS_PLATFCONFIG_KF1_NOVERIF: case PXP_STATUS_PLATFCONFIG_KF1_BAD: + pxp->platform_cfg_is_bad = true; return true; default: break; @@ -111,7 +112,7 @@ gsccs_send_message(struct intel_pxp *pxp, ret = intel_gsc_uc_heci_cmd_submit_nonpriv(>->uc.gsc, exec_res->ce, &pkt, exec_res->bb_vaddr, - GSC_REPLY_LATENCY_MS); + GSC_HECI_REPLY_LATENCY_MS); if (ret) { drm_err(&i915->drm, "failed to send gsc PXP msg (%d)\n", ret); goto unlock; @@ -226,7 +227,7 @@ int intel_pxp_gsccs_create_session(struct intel_pxp *pxp, if (ret) { drm_err(&i915->drm, "Failed to init session %d, ret=[%d]\n", arb_session_id, ret); } else if (msg_out.header.status != 0) { - if (is_fw_err_platform_config(msg_out.header.status)) { + if (is_fw_err_platform_config(pxp, msg_out.header.status)) { drm_info_once(&i915->drm, "PXP init-session-%d failed due to BIOS/SOC:0x%08x:%s\n", arb_session_id, msg_out.header.status, @@ -269,7 +270,7 @@ void intel_pxp_gsccs_end_arb_fw_session(struct intel_pxp *pxp, u32 session_id) drm_err(&i915->drm, "Failed to inv-stream-key-%u, ret=[%d]\n", session_id, ret); } else if (msg_out.header.status != 0) { - if (is_fw_err_platform_config(msg_out.header.status)) { + if (is_fw_err_platform_config(pxp, msg_out.header.status)) { drm_info_once(&i915->drm, "PXP inv-stream-key-%u failed due to BIOS/SOC :0x%08x:%s\n", session_id, msg_out.header.status, diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h index 298ad38e6c7d..9aae779c4da3 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h @@ -8,16 +8,14 @@ #include <linux/types.h> +#include "gt/uc/intel_gsc_uc_heci_cmd_submit.h" + struct intel_pxp; -#define GSC_REPLY_LATENCY_MS 210 -/* - * Max FW response time is 200ms, to which we add 10ms to account for overhead - * such as request preparation, GuC submission to hw and pipeline completion times. - */ #define GSC_PENDING_RETRY_MAXCOUNT 40 #define GSC_PENDING_RETRY_PAUSE_MS 50 -#define GSCFW_MAX_ROUND_TRIP_LATENCY_MS (GSC_PENDING_RETRY_MAXCOUNT * GSC_PENDING_RETRY_PAUSE_MS) +#define GSCFW_MAX_ROUND_TRIP_LATENCY_MS (GSC_HECI_REPLY_LATENCY_MS + \ + (GSC_PENDING_RETRY_MAXCOUNT * GSC_PENDING_RETRY_PAUSE_MS)) #ifdef CONFIG_DRM_I915_PXP void intel_pxp_gsccs_fini(struct intel_pxp *pxp); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c index 1a04067f61fc..6dfd24918953 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c @@ -34,8 +34,10 @@ void intel_pxp_suspend(struct intel_pxp *pxp) } } -void intel_pxp_resume_complete(struct intel_pxp *pxp) +static void _pxp_resume(struct intel_pxp *pxp, bool take_wakeref) { + intel_wakeref_t wakeref; + if (!intel_pxp_is_enabled(pxp)) return; @@ -48,7 +50,21 @@ void intel_pxp_resume_complete(struct intel_pxp *pxp) if (!HAS_ENGINE(pxp->ctrl_gt, GSC0) && !pxp->pxp_component) return; + if (take_wakeref) + wakeref = intel_runtime_pm_get(&pxp->ctrl_gt->i915->runtime_pm); intel_pxp_init_hw(pxp); + if (take_wakeref) + intel_runtime_pm_put(&pxp->ctrl_gt->i915->runtime_pm, wakeref); +} + +void intel_pxp_resume_complete(struct intel_pxp *pxp) +{ + _pxp_resume(pxp, true); +} + +void intel_pxp_runtime_resume(struct intel_pxp *pxp) +{ + _pxp_resume(pxp, false); } void intel_pxp_runtime_suspend(struct intel_pxp *pxp) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.h b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.h index 06b46f535b42..8695889b8380 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.h @@ -13,6 +13,7 @@ void intel_pxp_suspend_prepare(struct intel_pxp *pxp); void intel_pxp_suspend(struct intel_pxp *pxp); void intel_pxp_resume_complete(struct intel_pxp *pxp); void intel_pxp_runtime_suspend(struct intel_pxp *pxp); +void intel_pxp_runtime_resume(struct intel_pxp *pxp); #else static inline void intel_pxp_suspend_prepare(struct intel_pxp *pxp) { @@ -29,9 +30,9 @@ static inline void intel_pxp_resume_complete(struct intel_pxp *pxp) static inline void intel_pxp_runtime_suspend(struct intel_pxp *pxp) { } -#endif + static inline void intel_pxp_runtime_resume(struct intel_pxp *pxp) { - intel_pxp_resume_complete(pxp); } +#endif #endif /* __INTEL_PXP_PM_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index 80bb00189865..bb58fa9579b8 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -9,6 +9,7 @@ #include <drm/i915_component.h> #include "gem/i915_gem_lmem.h" +#include "gt/intel_gt_print.h" #include "i915_drv.h" #include "gt/intel_gt.h" @@ -21,12 +22,13 @@ #include "intel_pxp_types.h" static bool -is_fw_err_platform_config(u32 type) +is_fw_err_platform_config(struct intel_pxp *pxp, u32 type) { switch (type) { case PXP_STATUS_ERROR_API_VERSION: case PXP_STATUS_PLATFCONFIG_KF1_NOVERIF: case PXP_STATUS_PLATFCONFIG_KF1_BAD: + pxp->platform_cfg_is_bad = true; return true; default: break; @@ -155,7 +157,8 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, { struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); struct intel_pxp *pxp = i915->pxp; - struct intel_uc *uc = &pxp->ctrl_gt->uc; + struct intel_gt *gt = pxp->ctrl_gt; + struct intel_uc *uc = >->uc; intel_wakeref_t wakeref; int ret = 0; @@ -175,7 +178,7 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, /* load huc via pxp */ ret = intel_huc_fw_load_and_auth_via_gsc(&uc->huc); if (ret < 0) - drm_err(&i915->drm, "failed to load huc via gsc %d\n", ret); + gt_probe_error(gt, "failed to load huc via gsc %d\n", ret); } } @@ -342,7 +345,7 @@ int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp, if (ret) { drm_err(&i915->drm, "Failed to send tee msg init arb session, ret=[%d]\n", ret); } else if (msg_out.header.status != 0) { - if (is_fw_err_platform_config(msg_out.header.status)) { + if (is_fw_err_platform_config(pxp, msg_out.header.status)) { drm_info_once(&i915->drm, "PXP init-arb-session-%d failed due to BIOS/SOC:0x%08x:%s\n", arb_session_id, msg_out.header.status, @@ -390,7 +393,7 @@ try_again: drm_err(&i915->drm, "Failed to send tee msg for inv-stream-key-%u, ret=[%d]\n", session_id, ret); } else if (msg_out.header.status != 0) { - if (is_fw_err_platform_config(msg_out.header.status)) { + if (is_fw_err_platform_config(pxp, msg_out.header.status)) { drm_info_once(&i915->drm, "PXP inv-stream-key-%u failed due to BIOS/SOC :0x%08x:%s\n", session_id, msg_out.header.status, diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index 1a8765866b8b..7e11fa8034b2 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -27,6 +27,15 @@ struct intel_pxp { struct intel_gt *ctrl_gt; /** + * @platform_cfg_is_bad: used to track if any prior arb session creation resulted + * in a failure that was caused by a platform configuration issue, meaning that + * failure will not get resolved without a change to the platform (not kernel) + * such as BIOS configuration, firwmware update, etc. This bool gets reflected when + * GET_PARAM:I915_PARAM_PXP_STATUS is called. + */ + bool platform_cfg_is_bad; + + /** * @kcr_base: base mmio offset for the KCR engine which is different on legacy platforms * vs newer platforms where the KCR is inside the media-tile. */ diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index a9b79888c193..acae30a04a94 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -1924,7 +1924,7 @@ struct perf_stats { struct perf_series { struct drm_i915_private *i915; unsigned int nengines; - struct intel_context *ce[]; + struct intel_context *ce[] __counted_by(nengines); }; static int cmp_u32(const void *A, const void *B) diff --git a/drivers/gpu/drm/i915/selftests/igt_spinner.c b/drivers/gpu/drm/i915/selftests/igt_spinner.c index 0f064930ef11..8c3e1f20e5a1 100644 --- a/drivers/gpu/drm/i915/selftests/igt_spinner.c +++ b/drivers/gpu/drm/i915/selftests/igt_spinner.c @@ -179,6 +179,9 @@ igt_spinner_create_request(struct igt_spinner *spin, *batch++ = arbitration_command; + memset32(batch, MI_NOOP, 128); + batch += 128; + if (GRAPHICS_VER(rq->i915) >= 8) *batch++ = MI_BATCH_BUFFER_START | BIT(8) | 1; else if (IS_HASWELL(rq->i915)) diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index da0b269606c5..af349fd9abc2 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -114,7 +114,6 @@ static struct dev_pm_domain pm_domain = { static void mock_gt_probe(struct drm_i915_private *i915) { - i915->gt[0] = to_gt(i915); i915->gt[0]->name = "Mock GT"; } @@ -181,6 +180,8 @@ struct drm_i915_private *mock_gem_device(void) /* Set up device info and initial runtime info. */ intel_device_info_driver_create(i915, pdev->device, &mock_info); + intel_display_device_probe(i915); + dev_pm_domain_set(&pdev->dev, &pm_domain); pm_runtime_enable(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.c b/drivers/gpu/drm/i915/soc/intel_gmch.c index 49c7fb16e934..f32e9f78770a 100644 --- a/drivers/gpu/drm/i915/soc/intel_gmch.c +++ b/drivers/gpu/drm/i915/soc/intel_gmch.c @@ -5,6 +5,7 @@ #include <linux/pci.h> #include <linux/pnp.h> +#include <linux/vgaarb.h> #include <drm/drm_managed.h> #include <drm/i915_drm.h> @@ -167,3 +168,16 @@ int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode) return 0; } + +unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode) +{ + struct drm_i915_private *i915 = pdev_to_i915(pdev); + + intel_gmch_vga_set_state(i915, enable_decode); + + if (enable_decode) + return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | + VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; + else + return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; +} diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.h b/drivers/gpu/drm/i915/soc/intel_gmch.h index d0133eedc720..23be2d113afd 100644 --- a/drivers/gpu/drm/i915/soc/intel_gmch.h +++ b/drivers/gpu/drm/i915/soc/intel_gmch.h @@ -8,11 +8,13 @@ #include <linux/types.h> +struct pci_dev; struct drm_i915_private; int intel_gmch_bridge_setup(struct drm_i915_private *i915); void intel_gmch_bar_setup(struct drm_i915_private *i915); void intel_gmch_bar_teardown(struct drm_i915_private *i915); int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode); +unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode); #endif /* __INTEL_GMCH_H__ */ diff --git a/drivers/gpu/drm/i915/soc/intel_pch.c b/drivers/gpu/drm/i915/soc/intel_pch.c index 19a8f27c404e..240beafb38ed 100644 --- a/drivers/gpu/drm/i915/soc/intel_pch.c +++ b/drivers/gpu/drm/i915/soc/intel_pch.c @@ -218,13 +218,19 @@ void intel_detect_pch(struct drm_i915_private *dev_priv) unsigned short id; enum intel_pch pch_type; - /* DG1 has south engine display on the same PCI device */ - if (IS_DG1(dev_priv)) { - dev_priv->pch_type = PCH_DG1; + /* + * South display engine on the same PCI device: just assign the fake + * PCH. + */ + if (DISPLAY_VER(dev_priv) >= 20) { + dev_priv->pch_type = PCH_LNL; return; } else if (IS_DG2(dev_priv)) { dev_priv->pch_type = PCH_DG2; return; + } else if (IS_DG1(dev_priv)) { + dev_priv->pch_type = PCH_DG1; + return; } /* diff --git a/drivers/gpu/drm/i915/soc/intel_pch.h b/drivers/gpu/drm/i915/soc/intel_pch.h index 32aff5a70d04..1b03ea60a7a8 100644 --- a/drivers/gpu/drm/i915/soc/intel_pch.h +++ b/drivers/gpu/drm/i915/soc/intel_pch.h @@ -30,6 +30,7 @@ enum intel_pch { /* Fake PCHs, functionality handled on the same PCI dev */ PCH_DG1 = 1024, PCH_DG2, + PCH_LNL, }; #define INTEL_PCH_DEVICE_ID_MASK 0xff80 @@ -66,6 +67,7 @@ enum intel_pch { #define INTEL_PCH_TYPE(dev_priv) ((dev_priv)->pch_type) #define INTEL_PCH_ID(dev_priv) ((dev_priv)->pch_id) +#define HAS_PCH_LNL(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_LNL) #define HAS_PCH_MTP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_MTP) #define HAS_PCH_DG2(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_DG2) #define HAS_PCH_ADP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_ADP) diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c index c68b0d93ae9e..b61cec0cc79d 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-drv.c +++ b/drivers/gpu/drm/imx/dcss/dcss-drv.c @@ -92,6 +92,13 @@ static int dcss_drv_platform_remove(struct platform_device *pdev) return 0; } +static void dcss_drv_platform_shutdown(struct platform_device *pdev) +{ + struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev); + + dcss_kms_shutdown(mdrv->kms); +} + static struct dcss_type_data dcss_types[] = { [DCSS_IMX8MQ] = { .name = "DCSS_IMX8MQ", @@ -114,6 +121,7 @@ MODULE_DEVICE_TABLE(of, dcss_of_match); static struct platform_driver dcss_platform_driver = { .probe = dcss_drv_platform_probe, .remove = dcss_drv_platform_remove, + .shutdown = dcss_drv_platform_shutdown, .driver = { .name = "imx-dcss", .of_match_table = dcss_of_match, diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c index 896de946f8df..d0ea4e97cded 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-kms.c +++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c @@ -172,3 +172,10 @@ void dcss_kms_detach(struct dcss_kms_dev *kms) dcss_crtc_deinit(&kms->crtc, drm); drm->dev_private = NULL; } + +void dcss_kms_shutdown(struct dcss_kms_dev *kms) +{ + struct drm_device *drm = &kms->base; + + drm_atomic_helper_shutdown(drm); +} diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.h b/drivers/gpu/drm/imx/dcss/dcss-kms.h index dfe5dd99eea3..62521c1fd6d2 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-kms.h +++ b/drivers/gpu/drm/imx/dcss/dcss-kms.h @@ -34,6 +34,7 @@ struct dcss_kms_dev { struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss); void dcss_kms_detach(struct dcss_kms_dev *kms); +void dcss_kms_shutdown(struct dcss_kms_dev *kms); int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm); void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm); struct dcss_plane *dcss_plane_init(struct drm_device *drm, diff --git a/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c b/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c index a2277a0d6d06..0006ea52b83c 100644 --- a/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c @@ -255,19 +255,17 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev) return ret; } -static int dw_hdmi_imx_remove(struct platform_device *pdev) +static void dw_hdmi_imx_remove(struct platform_device *pdev) { struct imx_hdmi *hdmi = platform_get_drvdata(pdev); component_del(&pdev->dev, &dw_hdmi_imx_ops); dw_hdmi_remove(hdmi->hdmi); - - return 0; } static struct platform_driver dw_hdmi_imx_platform_driver = { .probe = dw_hdmi_imx_probe, - .remove = dw_hdmi_imx_remove, + .remove_new = dw_hdmi_imx_remove, .driver = { .name = "dwhdmi-imx", .of_match_table = dw_hdmi_imx_dt_ids, diff --git a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c index 4a866ac60fff..4cfabcf7375a 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c @@ -257,6 +257,7 @@ err_poll_fini: drm_kms_helper_poll_fini(drm); component_unbind_all(drm->dev, drm); err_kms: + dev_set_drvdata(dev, NULL); drm_dev_put(drm); return ret; @@ -269,6 +270,7 @@ static void imx_drm_unbind(struct device *dev) drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); + drm_atomic_helper_shutdown(drm); component_unbind_all(drm->dev, drm); @@ -292,10 +294,14 @@ static int imx_drm_platform_probe(struct platform_device *pdev) return ret; } -static int imx_drm_platform_remove(struct platform_device *pdev) +static void imx_drm_platform_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &imx_drm_ops); - return 0; +} + +static void imx_drm_platform_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); } #ifdef CONFIG_PM_SLEEP @@ -324,7 +330,8 @@ MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); static struct platform_driver imx_drm_pdrv = { .probe = imx_drm_platform_probe, - .remove = imx_drm_platform_remove, + .remove_new = imx_drm_platform_remove, + .shutdown = imx_drm_platform_shutdown, .driver = { .name = "imx-drm", .pm = &imx_drm_pm_ops, diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c index c45fc8f4744d..989eca32d325 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c @@ -737,7 +737,7 @@ free_child: return ret; } -static int imx_ldb_remove(struct platform_device *pdev) +static void imx_ldb_remove(struct platform_device *pdev) { struct imx_ldb *imx_ldb = platform_get_drvdata(pdev); int i; @@ -750,12 +750,11 @@ static int imx_ldb_remove(struct platform_device *pdev) } component_del(&pdev->dev, &imx_ldb_ops); - return 0; } static struct platform_driver imx_ldb_driver = { .probe = imx_ldb_probe, - .remove = imx_ldb_remove, + .remove_new = imx_ldb_remove, .driver = { .of_match_table = imx_ldb_dt_ids, .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/imx/ipuv3/imx-tve.c b/drivers/gpu/drm/imx/ipuv3/imx-tve.c index d6832f506322..b49bddb85535 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-tve.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-tve.c @@ -645,10 +645,9 @@ static int imx_tve_probe(struct platform_device *pdev) return component_add(dev, &imx_tve_ops); } -static int imx_tve_remove(struct platform_device *pdev) +static void imx_tve_remove(struct platform_device *pdev) { component_del(&pdev->dev, &imx_tve_ops); - return 0; } static const struct of_device_id imx_tve_dt_ids[] = { @@ -659,7 +658,7 @@ MODULE_DEVICE_TABLE(of, imx_tve_dt_ids); static struct platform_driver imx_tve_driver = { .probe = imx_tve_probe, - .remove = imx_tve_remove, + .remove_new = imx_tve_remove, .driver = { .of_match_table = imx_tve_dt_ids, .name = "imx-tve", diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c index 89585b31b985..ef29c9a61a46 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c @@ -441,10 +441,9 @@ static int ipu_drm_probe(struct platform_device *pdev) return component_add(dev, &ipu_crtc_ops); } -static int ipu_drm_remove(struct platform_device *pdev) +static void ipu_drm_remove(struct platform_device *pdev) { component_del(&pdev->dev, &ipu_crtc_ops); - return 0; } struct platform_driver ipu_drm_driver = { @@ -452,5 +451,5 @@ struct platform_driver ipu_drm_driver = { .name = "imx-ipuv3-crtc", }, .probe = ipu_drm_probe, - .remove = ipu_drm_remove, + .remove_new = ipu_drm_remove, }; diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c index 0fa0b590830b..70349739dd89 100644 --- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c +++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c @@ -353,11 +353,9 @@ static int imx_pd_probe(struct platform_device *pdev) return component_add(dev, &imx_pd_ops); } -static int imx_pd_remove(struct platform_device *pdev) +static void imx_pd_remove(struct platform_device *pdev) { component_del(&pdev->dev, &imx_pd_ops); - - return 0; } static const struct of_device_id imx_pd_dt_ids[] = { @@ -368,7 +366,7 @@ MODULE_DEVICE_TABLE(of, imx_pd_dt_ids); static struct platform_driver imx_pd_driver = { .probe = imx_pd_probe, - .remove = imx_pd_remove, + .remove_new = imx_pd_remove, .driver = { .of_match_table = imx_pd_dt_ids, .name = "imx-parallel-display", diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 8dbd4847d3a6..0751235007a7 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -1130,7 +1130,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ret = drmm_mode_config_init(drm); if (ret) - return ret; + goto err_drvdata; drm->mode_config.min_width = 0; drm->mode_config.min_height = 0; @@ -1142,7 +1142,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) { dev_err(dev, "Failed to get memory resource\n"); - return PTR_ERR(base); + ret = PTR_ERR(base); + goto err_drvdata; } regmap_config = ingenic_drm_regmap_config; @@ -1151,33 +1152,40 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ®map_config); if (IS_ERR(priv->map)) { dev_err(dev, "Failed to create regmap\n"); - return PTR_ERR(priv->map); + ret = PTR_ERR(priv->map); + goto err_drvdata; } irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto err_drvdata; + } if (soc_info->needs_dev_clk) { priv->lcd_clk = devm_clk_get(dev, "lcd"); if (IS_ERR(priv->lcd_clk)) { dev_err(dev, "Failed to get lcd clock\n"); - return PTR_ERR(priv->lcd_clk); + ret = PTR_ERR(priv->lcd_clk); + goto err_drvdata; } } priv->pix_clk = devm_clk_get(dev, "lcd_pclk"); if (IS_ERR(priv->pix_clk)) { dev_err(dev, "Failed to get pixel clock\n"); - return PTR_ERR(priv->pix_clk); + ret = PTR_ERR(priv->pix_clk); + goto err_drvdata; } priv->dma_hwdescs = dmam_alloc_coherent(dev, sizeof(*priv->dma_hwdescs), &priv->dma_hwdescs_phys, GFP_KERNEL); - if (!priv->dma_hwdescs) - return -ENOMEM; + if (!priv->dma_hwdescs) { + ret = -ENOMEM; + goto err_drvdata; + } /* Configure DMA hwdesc for foreground0 plane */ ingenic_drm_configure_hwdesc_plane(priv, 0); @@ -1199,7 +1207,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) NULL, DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) { dev_err(dev, "Failed to register plane: %i\n", ret); - return ret; + goto err_drvdata; } if (soc_info->map_noncoherent) @@ -1211,7 +1219,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) NULL, &ingenic_drm_crtc_funcs, NULL); if (ret) { dev_err(dev, "Failed to init CRTC: %i\n", ret); - return ret; + goto err_drvdata; } drm_crtc_enable_color_mgmt(&priv->crtc, 0, false, @@ -1230,7 +1238,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) if (ret) { dev_err(dev, "Failed to register overlay plane: %i\n", ret); - return ret; + goto err_drvdata; } if (soc_info->map_noncoherent) @@ -1241,17 +1249,18 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to bind components: %i\n", ret); - return ret; + goto err_drvdata; } ret = devm_add_action_or_reset(dev, ingenic_drm_unbind_all, priv); if (ret) - return ret; + goto err_drvdata; priv->ipu_plane = drm_plane_from_index(drm, 2); if (!priv->ipu_plane) { dev_err(dev, "Failed to retrieve IPU plane\n"); - return -EINVAL; + ret = -EINVAL; + goto err_drvdata; } } } @@ -1263,7 +1272,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) break; /* we're done */ if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get bridge handle\n"); - return ret; + goto err_drvdata; } if (panel) @@ -1275,7 +1284,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) if (IS_ERR(ib)) { ret = PTR_ERR(ib); dev_err(dev, "Failed to init encoder: %d\n", ret); - return ret; + goto err_drvdata; } encoder = &ib->encoder; @@ -1290,13 +1299,14 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) { dev_err(dev, "Unable to attach bridge\n"); - return ret; + goto err_drvdata; } connector = drm_bridge_connector_init(drm, encoder); if (IS_ERR(connector)) { dev_err(dev, "Unable to init connector\n"); - return PTR_ERR(connector); + ret = PTR_ERR(connector); + goto err_drvdata; } drm_connector_attach_encoder(connector, encoder); @@ -1313,13 +1323,13 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ret = devm_request_irq(dev, irq, ingenic_drm_irq_handler, 0, drm->driver->name, drm); if (ret) { dev_err(dev, "Unable to install IRQ handler\n"); - return ret; + goto err_drvdata; } ret = drm_vblank_init(drm, 1); if (ret) { dev_err(dev, "Failed calling drm_vblank_init()\n"); - return ret; + goto err_drvdata; } drm_mode_config_reset(drm); @@ -1327,7 +1337,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ret = clk_prepare_enable(priv->pix_clk); if (ret) { dev_err(dev, "Unable to start pixel clock\n"); - return ret; + goto err_drvdata; } if (priv->lcd_clk) { @@ -1402,6 +1412,8 @@ err_devclk_disable: clk_disable_unprepare(priv->lcd_clk); err_pixclk_disable: clk_disable_unprepare(priv->pix_clk); +err_drvdata: + platform_set_drvdata(pdev, NULL); return ret; } @@ -1422,6 +1434,7 @@ static void ingenic_drm_unbind(struct device *dev) drm_dev_unregister(&priv->drm); drm_atomic_helper_shutdown(&priv->drm); + dev_set_drvdata(dev, NULL); } static const struct component_master_ops ingenic_master_ops = { @@ -1449,7 +1462,7 @@ static int ingenic_drm_probe(struct platform_device *pdev) return component_master_add_with_match(dev, &ingenic_master_ops, match); } -static int ingenic_drm_remove(struct platform_device *pdev) +static void ingenic_drm_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1457,8 +1470,14 @@ static int ingenic_drm_remove(struct platform_device *pdev) ingenic_drm_unbind(dev); else component_master_del(dev, &ingenic_master_ops); +} - return 0; +static void ingenic_drm_shutdown(struct platform_device *pdev) +{ + struct ingenic_drm *priv = platform_get_drvdata(pdev); + + if (priv) + drm_atomic_helper_shutdown(&priv->drm); } static int ingenic_drm_suspend(struct device *dev) @@ -1611,7 +1630,8 @@ static struct platform_driver ingenic_drm_driver = { .of_match_table = of_match_ptr(ingenic_drm_of_match), }, .probe = ingenic_drm_probe, - .remove = ingenic_drm_remove, + .remove_new = ingenic_drm_remove, + .shutdown = ingenic_drm_shutdown, }; static int ingenic_drm_init(void) diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c index 6d236547f611..5bd9072352b5 100644 --- a/drivers/gpu/drm/ingenic/ingenic-ipu.c +++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c @@ -922,10 +922,9 @@ static int ingenic_ipu_probe(struct platform_device *pdev) return component_add(&pdev->dev, &ingenic_ipu_ops); } -static int ingenic_ipu_remove(struct platform_device *pdev) +static void ingenic_ipu_remove(struct platform_device *pdev) { component_del(&pdev->dev, &ingenic_ipu_ops); - return 0; } static const u32 jz4725b_ipu_formats[] = { @@ -992,7 +991,7 @@ static struct platform_driver ingenic_ipu_driver = { .of_match_table = ingenic_ipu_of_match, }, .probe = ingenic_ipu_probe, - .remove = ingenic_ipu_remove, + .remove_new = ingenic_ipu_remove, }; struct platform_driver *ingenic_ipu_driver_ptr = &ingenic_ipu_driver; diff --git a/drivers/gpu/drm/logicvc/logicvc_drm.c b/drivers/gpu/drm/logicvc/logicvc_drm.c index 749debd3d6a5..01a37e28c080 100644 --- a/drivers/gpu/drm/logicvc/logicvc_drm.c +++ b/drivers/gpu/drm/logicvc/logicvc_drm.c @@ -482,6 +482,14 @@ static void logicvc_drm_remove(struct platform_device *pdev) of_reserved_mem_device_release(dev); } +static void logicvc_drm_shutdown(struct platform_device *pdev) +{ + struct logicvc_drm *logicvc = platform_get_drvdata(pdev); + struct drm_device *drm_dev = &logicvc->drm_dev; + + drm_atomic_helper_shutdown(drm_dev); +} + static const struct of_device_id logicvc_drm_of_table[] = { { .compatible = "xylon,logicvc-3.02.a-display" }, { .compatible = "xylon,logicvc-4.01.a-display" }, @@ -492,6 +500,7 @@ MODULE_DEVICE_TABLE(of, logicvc_drm_of_table); static struct platform_driver logicvc_drm_platform_driver = { .probe = logicvc_drm_probe, .remove_new = logicvc_drm_remove, + .shutdown = logicvc_drm_shutdown, .driver = { .name = "logicvc-drm", .of_match_table = logicvc_drm_of_table, diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c index 188ec82afcfb..89ccc0c43169 100644 --- a/drivers/gpu/drm/loongson/lsdc_drv.c +++ b/drivers/gpu/drm/loongson/lsdc_drv.c @@ -327,6 +327,11 @@ static void lsdc_pci_remove(struct pci_dev *pdev) drm_atomic_helper_shutdown(ddev); } +static void lsdc_pci_shutdown(struct pci_dev *pdev) +{ + drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); +} + static int lsdc_drm_freeze(struct drm_device *ddev) { struct lsdc_device *ldev = to_lsdc(ddev); @@ -447,6 +452,7 @@ struct pci_driver lsdc_pci_driver = { .id_table = lsdc_pciid_list, .probe = lsdc_pci_probe, .remove = lsdc_pci_remove, + .shutdown = lsdc_pci_shutdown, .driver.pm = &lsdc_pm_ops, }; diff --git a/drivers/gpu/drm/loongson/lsdc_pixpll.c b/drivers/gpu/drm/loongson/lsdc_pixpll.c index 04c15b4697e2..2609a2256da4 100644 --- a/drivers/gpu/drm/loongson/lsdc_pixpll.c +++ b/drivers/gpu/drm/loongson/lsdc_pixpll.c @@ -120,12 +120,14 @@ static int lsdc_pixel_pll_setup(struct lsdc_pixpll * const this) struct lsdc_pixpll_parms *pparms; this->mmio = ioremap(this->reg_base, this->reg_size); - if (IS_ERR_OR_NULL(this->mmio)) + if (!this->mmio) return -ENOMEM; pparms = kzalloc(sizeof(*pparms), GFP_KERNEL); - if (IS_ERR_OR_NULL(pparms)) + if (!pparms) { + iounmap(this->mmio); return -ENOMEM; + } pparms->ref_clock = LSDC_PLL_REF_CLK_KHZ; diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index a2572fb311f0..10c06440c7e7 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -459,6 +459,14 @@ static void mcde_remove(struct platform_device *pdev) regulator_disable(mcde->epod); } +static void mcde_shutdown(struct platform_device *pdev) +{ + struct drm_device *drm = platform_get_drvdata(pdev); + + if (drm->registered) + drm_atomic_helper_shutdown(drm); +} + static const struct of_device_id mcde_of_match[] = { { .compatible = "ste,mcde", @@ -473,6 +481,7 @@ static struct platform_driver mcde_driver = { }, .probe = mcde_probe, .remove_new = mcde_remove, + .shutdown = mcde_shutdown, }; static struct platform_driver *const component_drivers[] = { diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index abddf37f0ea1..2fb18b782b05 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -10,6 +10,7 @@ #include <linux/pci.h> #include <drm/drm_aperture.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fbdev_generic.h> #include <drm/drm_file.h> @@ -278,6 +279,12 @@ static void mgag200_pci_remove(struct pci_dev *pdev) struct drm_device *dev = pci_get_drvdata(pdev); drm_dev_unregister(dev); + drm_atomic_helper_shutdown(dev); +} + +static void mgag200_pci_shutdown(struct pci_dev *pdev) +{ + drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); } static struct pci_driver mgag200_pci_driver = { @@ -285,6 +292,7 @@ static struct pci_driver mgag200_pci_driver = { .id_table = mgag200_pciidlist, .probe = mgag200_pci_probe, .remove = mgag200_pci_remove, + .shutdown = mgag200_pci_shutdown, }; drm_module_pci_driver_if_modeset(mgag200_pci_driver, mgag200_modeset); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index cd73ee0cbf23..7923129363b0 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -678,12 +678,6 @@ struct block_header { u32 data[]; }; -/* this should be a general kernel helper */ -static int in_range(u32 addr, u32 start, u32 size) -{ - return addr >= start && addr < start + size; -} - static bool fw_block_mem(struct a6xx_gmu_bo *bo, const struct block_header *blk) { if (!in_range(blk->addr, bo->iova, bo->size)) diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 575e7c56219f..fa527935ffd4 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -751,10 +751,9 @@ static int adreno_probe(struct platform_device *pdev) return 0; } -static int adreno_remove(struct platform_device *pdev) +static void adreno_remove(struct platform_device *pdev) { component_del(&pdev->dev, &a3xx_ops); - return 0; } static void adreno_shutdown(struct platform_device *pdev) @@ -869,7 +868,7 @@ static const struct dev_pm_ops adreno_pm_ops = { static struct platform_driver adreno_driver = { .probe = adreno_probe, - .remove = adreno_remove, + .remove_new = adreno_remove, .shutdown = adreno_shutdown, .driver = { .name = "adreno", diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h index dab761e54863..50cf9523d367 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -61,7 +61,7 @@ struct dpu_hw_intr { void (*cb)(void *arg, int irq_idx); void *arg; atomic_t count; - } irq_tbl[]; + } irq_tbl[] __counted_by(total_irqs); }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index aa6ba2cf4b84..82381d12414d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1302,11 +1302,9 @@ static int dpu_dev_probe(struct platform_device *pdev) return msm_drv_probe(&pdev->dev, dpu_kms_init); } -static int dpu_dev_remove(struct platform_device *pdev) +static void dpu_dev_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &msm_drm_ops); - - return 0; } static int __maybe_unused dpu_runtime_suspend(struct device *dev) @@ -1382,7 +1380,7 @@ MODULE_DEVICE_TABLE(of, dpu_dt_match); static struct platform_driver dpu_driver = { .probe = dpu_dev_probe, - .remove = dpu_dev_remove, + .remove_new = dpu_dev_remove, .shutdown = msm_drv_shutdown, .driver = { .name = "msm_dpu", diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 700df4040e9a..e5012fa6771f 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -560,11 +560,9 @@ static int mdp4_probe(struct platform_device *pdev) return msm_drv_probe(&pdev->dev, mdp4_kms_init); } -static int mdp4_remove(struct platform_device *pdev) +static void mdp4_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &msm_drm_ops); - - return 0; } static const struct of_device_id mdp4_dt_match[] = { @@ -575,7 +573,7 @@ MODULE_DEVICE_TABLE(of, mdp4_dt_match); static struct platform_driver mdp4_platform_driver = { .probe = mdp4_probe, - .remove = mdp4_remove, + .remove_new = mdp4_remove, .shutdown = msm_drv_shutdown, .driver = { .name = "mdp4", diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 92bf9d949d09..8a7b44376bc6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -942,11 +942,10 @@ static int mdp5_dev_probe(struct platform_device *pdev) return msm_drv_probe(&pdev->dev, mdp5_kms_init); } -static int mdp5_dev_remove(struct platform_device *pdev) +static void mdp5_dev_remove(struct platform_device *pdev) { DBG(""); component_master_del(&pdev->dev, &msm_drm_ops); - return 0; } static __maybe_unused int mdp5_runtime_suspend(struct device *dev) @@ -987,7 +986,7 @@ MODULE_DEVICE_TABLE(of, mdp5_dt_match); static struct platform_driver mdp5_driver = { .probe = mdp5_dev_probe, - .remove = mdp5_dev_remove, + .remove_new = mdp5_dev_remove, .shutdown = msm_drv_shutdown, .driver = { .name = "msm_mdp", diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 76f13954015b..01784e9e7127 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1296,7 +1296,7 @@ static int dp_display_probe(struct platform_device *pdev) return rc; } -static int dp_display_remove(struct platform_device *pdev) +static void dp_display_remove(struct platform_device *pdev) { struct dp_display_private *dp = dev_get_dp_display_private(&pdev->dev); @@ -1304,8 +1304,6 @@ static int dp_display_remove(struct platform_device *pdev) dp_display_deinit_sub_modules(dp); platform_set_drvdata(pdev, NULL); - - return 0; } static int dp_pm_resume(struct device *dev) @@ -1415,7 +1413,7 @@ static const struct dev_pm_ops dp_pm_ops = { static struct platform_driver dp_display_driver = { .probe = dp_display_probe, - .remove = dp_display_remove, + .remove_new = dp_display_remove, .driver = { .name = "msm-dp-display", .of_match_table = dp_dt_match, diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index baab79ab6e74..7a8208cd6649 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -161,14 +161,12 @@ static int dsi_dev_probe(struct platform_device *pdev) return 0; } -static int dsi_dev_remove(struct platform_device *pdev) +static void dsi_dev_remove(struct platform_device *pdev) { struct msm_dsi *msm_dsi = platform_get_drvdata(pdev); DBG(""); dsi_destroy(msm_dsi); - - return 0; } static const struct of_device_id dt_match[] = { @@ -187,7 +185,7 @@ static const struct dev_pm_ops dsi_pm_ops = { static struct platform_driver dsi_driver = { .probe = dsi_dev_probe, - .remove = dsi_dev_remove, + .remove_new = dsi_dev_remove, .driver = { .name = "msm_dsi", .of_match_table = dt_match, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 60509fb39710..b6bcb9f675fe 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -551,15 +551,13 @@ err_put_phy: return ret; } -static int msm_hdmi_dev_remove(struct platform_device *pdev) +static void msm_hdmi_dev_remove(struct platform_device *pdev) { struct hdmi *hdmi = dev_get_drvdata(&pdev->dev); component_del(&pdev->dev, &msm_hdmi_ops); msm_hdmi_put_phy(hdmi); - - return 0; } static const struct of_device_id msm_hdmi_dt_match[] = { @@ -574,7 +572,7 @@ static const struct of_device_id msm_hdmi_dt_match[] = { static struct platform_driver msm_hdmi_driver = { .probe = msm_hdmi_dev_probe, - .remove = msm_hdmi_dev_remove, + .remove_new = msm_hdmi_dev_remove, .driver = { .name = "hdmi_msm", .of_match_table = msm_hdmi_dt_match, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 3e00fb8190b2..88a3423b7f24 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -177,11 +177,9 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev) return 0; } -static int msm_hdmi_phy_remove(struct platform_device *pdev) +static void msm_hdmi_phy_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id msm_hdmi_phy_dt_match[] = { @@ -200,7 +198,7 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = { static struct platform_driver msm_hdmi_phy_platform_driver = { .probe = msm_hdmi_phy_probe, - .remove = msm_hdmi_phy_remove, + .remove_new = msm_hdmi_phy_remove, .driver = { .name = "msm_hdmi_phy", .of_match_table = msm_hdmi_phy_dt_match, diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 4bd028fa7500..a428951ee539 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1278,11 +1278,9 @@ static int msm_pdev_probe(struct platform_device *pdev) return msm_drv_probe(&pdev->dev, NULL); } -static int msm_pdev_remove(struct platform_device *pdev) +static void msm_pdev_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &msm_drm_ops); - - return 0; } void msm_drv_shutdown(struct platform_device *pdev) @@ -1303,7 +1301,7 @@ void msm_drv_shutdown(struct platform_device *pdev) static struct platform_driver msm_platform_driver = { .probe = msm_pdev_probe, - .remove = msm_pdev_remove, + .remove_new = msm_pdev_remove, .shutdown = msm_drv_shutdown, .driver = { .name = "msm", diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 2e87dd6cb17b..a429b704059e 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -497,15 +497,13 @@ static int mdss_probe(struct platform_device *pdev) return 0; } -static int mdss_remove(struct platform_device *pdev) +static void mdss_remove(struct platform_device *pdev) { struct msm_mdss *mdss = platform_get_drvdata(pdev); of_platform_depopulate(&pdev->dev); msm_mdss_destroy(mdss); - - return 0; } static const struct msm_mdss_data msm8998_data = { @@ -629,7 +627,7 @@ MODULE_DEVICE_TABLE(of, mdss_dt_match); static struct platform_driver mdss_platform_driver = { .probe = mdss_probe, - .remove = mdss_remove, + .remove_new = mdss_remove, .driver = { .name = "msm-mdss", .of_match_table = mdss_dt_match, diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index c52e8096cca4..1e6aaf95ff7c 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -11,6 +11,7 @@ config DRM_NOUVEAU select DRM_TTM select DRM_TTM_HELPER select DRM_EXEC + select DRM_GPUVM select DRM_SCHED select I2C select I2C_ALGOBIT diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index a34924523133..a34917b048f9 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -1122,18 +1122,11 @@ nv04_page_flip_emit(struct nouveau_channel *chan, PUSH_NVSQ(push, NV_SW, NV_SW_PAGE_FLIP, 0x00000000); PUSH_KICK(push); - ret = nouveau_fence_new(pfence); + ret = nouveau_fence_new(pfence, chan); if (ret) goto fail; - ret = nouveau_fence_emit(*pfence, chan); - if (ret) - goto fail_fence_unref; - return 0; - -fail_fence_unref: - nouveau_fence_unref(pfence); fail: spin_lock_irqsave(&dev->event_lock, flags); list_del(&s->head); diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index e9ac3fb27ff7..13705c5f1497 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -256,7 +256,7 @@ nv04_display_create(struct drm_device *dev) for (i = 0; i < dcb->entries; i++) { struct dcb_output *dcbent = &dcb->entry[i]; - connector = nouveau_connector_create(dev, dcbent); + connector = nouveau_connector_create(dev, dcbent->connector); if (IS_ERR(connector)) continue; diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 4e7c9c353c51..a0ac8c258d9f 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -66,8 +66,6 @@ #include "nouveau_fence.h" #include "nv50_display.h" -#include <subdev/bios/dp.h> - /****************************************************************************** * EVO channel *****************************************************************************/ @@ -477,7 +475,6 @@ nv50_dac_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL); nv_encoder->crtc = NULL; - nvif_outp_release(&nv_encoder->outp); } static void @@ -502,7 +499,8 @@ nv50_dac_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, PROTOCOL, RGB_CRT); - nvif_outp_acquire_rgb_crt(&nv_encoder->outp); + if (!nvif_outp_acquired(&nv_encoder->outp)) + nvif_outp_acquire_dac(&nv_encoder->outp); core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh); asyh->or.depth = 0; @@ -553,34 +551,27 @@ nv50_dac_func = { }; static int -nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) +nv50_dac_create(struct nouveau_encoder *nv_encoder) { + struct drm_connector *connector = &nv_encoder->conn->base; struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nv50_disp *disp = nv50_disp(connector->dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device); struct nvkm_i2c_bus *bus; - struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; + struct dcb_output *dcbe = nv_encoder->dcb; int type = DRM_MODE_ENCODER_DAC; - nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); - if (!nv_encoder) - return -ENOMEM; - nv_encoder->dcb = dcbe; - bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index); if (bus) nv_encoder->i2c = &bus->i2c; encoder = to_drm_encoder(nv_encoder); - encoder->possible_crtcs = dcbe->heads; - encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type, "dac-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_dac_help); drm_connector_attach_encoder(connector, encoder); - return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp); + return 0; } /* @@ -617,7 +608,7 @@ nv50_audio_component_get_eld(struct device *kdev, int port, int dev_id, continue; /* TODO */ nv_encoder = nouveau_encoder(encoder); - nv_connector = nouveau_connector(nv_encoder->audio.connector); + nv_connector = nv_encoder->conn; nv_crtc = nouveau_crtc(nv_encoder->crtc); if (!nv_crtc || nv_encoder->outp.or.id != port || nv_crtc->index != dev_id) @@ -713,6 +704,18 @@ nv50_audio_supported(struct drm_encoder *encoder) disp->disp->object.oclass == GT206_DISP) return false; + if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + + switch (nv_encoder->dcb->type) { + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_DP: + break; + default: + return false; + } + } + return true; } @@ -729,7 +732,6 @@ nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) mutex_lock(&drm->audio.lock); if (nv_encoder->audio.enabled) { nv_encoder->audio.enabled = false; - nv_encoder->audio.connector = NULL; nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, NULL, 0); } mutex_unlock(&drm->audio.lock); @@ -754,7 +756,6 @@ nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, nv_connector->base.eld, drm_eld_size(nv_connector->base.eld)); nv_encoder->audio.enabled = true; - nv_encoder->audio.connector = &nv_connector->base; mutex_unlock(&drm->audio.lock); @@ -774,7 +775,6 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi; union hdmi_infoframe infoframe = { 0 }; const u8 rekey = 56; /* binary driver, and tegra, constant */ - u8 scdc = 0; u32 max_ac_packet; struct { struct nvif_outp_infoframe_v0 infoframe; @@ -787,8 +787,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, max_ac_packet -= 18; /* constant from tegra */ max_ac_packet /= 32; - if (hdmi->scdc.scrambling.supported) { + if (nv_encoder->i2c && hdmi->scdc.scrambling.supported) { const bool high_tmds_clock_ratio = mode->clock > 340000; + u8 scdc; ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &scdc); if (ret < 0) { @@ -808,8 +809,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, scdc, ret); } - ret = nvif_outp_acquire_tmds(&nv_encoder->outp, nv_crtc->index, true, - max_ac_packet, rekey, scdc, hda); + ret = nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, true, max_ac_packet, rekey, + mode->clock, hdmi->scdc.supported, hdmi->scdc.scrambling.supported, + hdmi->scdc.scrambling.low_rates); if (ret) return; @@ -838,7 +840,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, &args.infoframe, size); - nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode); + nv_encoder->hdmi.enabled = true; } /****************************************************************************** @@ -865,6 +867,8 @@ struct nv50_msto { struct nv50_mstc *mstc; bool disabled; bool enabled; + + u32 display_id; }; struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder) @@ -882,21 +886,33 @@ struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder) static void nv50_msto_cleanup(struct drm_atomic_state *state, - struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_topology_state *new_mst_state, struct drm_dp_mst_topology_mgr *mgr, struct nv50_msto *msto) { struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); - struct drm_dp_mst_atomic_payload *payload = - drm_atomic_get_mst_payload_state(mst_state, msto->mstc->port); + struct drm_dp_mst_atomic_payload *new_payload = + drm_atomic_get_mst_payload_state(new_mst_state, msto->mstc->port); + struct drm_dp_mst_topology_state *old_mst_state = + drm_atomic_get_old_mst_topology_state(state, mgr); + const struct drm_dp_mst_atomic_payload *old_payload = + drm_atomic_get_mst_payload_state(old_mst_state, msto->mstc->port); + struct nv50_mstc *mstc = msto->mstc; + struct nv50_mstm *mstm = mstc->mstm; NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); if (msto->disabled) { + if (msto->head->func->display_id) { + nvif_outp_dp_mst_id_put(&mstm->outp->outp, msto->display_id); + msto->display_id = 0; + } + msto->mstc = NULL; msto->disabled = false; + drm_dp_remove_payload_part2(mgr, new_mst_state, old_payload, new_payload); } else if (msto->enabled) { - drm_dp_add_payload_part2(mgr, state, payload); + drm_dp_add_payload_part2(mgr, state, new_payload); msto->enabled = false; } } @@ -910,28 +926,28 @@ nv50_msto_prepare(struct drm_atomic_state *state, struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; - struct drm_dp_mst_topology_state *old_mst_state; - struct drm_dp_mst_atomic_payload *payload, *old_payload; + struct drm_dp_mst_atomic_payload *payload; + int ret = 0; NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); - old_mst_state = drm_atomic_get_old_mst_topology_state(state, mgr); - payload = drm_atomic_get_mst_payload_state(mst_state, mstc->port); - old_payload = drm_atomic_get_mst_payload_state(old_mst_state, mstc->port); - // TODO: Figure out if we want to do a better job of handling VCPI allocation failures here? if (msto->disabled) { - drm_dp_remove_payload(mgr, mst_state, old_payload, payload); - + drm_dp_remove_payload_part1(mgr, mst_state, payload); nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); + ret = 1; } else { if (msto->enabled) - drm_dp_add_payload_part1(mgr, mst_state, payload); + ret = drm_dp_add_payload_part1(mgr, mst_state, payload); + } + if (ret == 0) { nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, payload->vc_start_slot, payload->time_slots, payload->pbn, payload->time_slots * mst_state->pbn_div); + } else { + nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); } } @@ -1028,8 +1044,13 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st return; if (!mstm->links++) { - /*XXX: MST audio. */ - nvif_outp_acquire_dp(&mstm->outp->outp, mstm->outp->dp.dpcd, 0, 0, false, true); + nvif_outp_acquire_sor(&mstm->outp->outp, false /*TODO: MST audio... */); + nouveau_dp_train(mstm->outp, true, 0, 0); + } + + if (head->func->display_id) { + if (!WARN_ON(nvif_outp_dp_mst_id_get(&mstm->outp->outp, &msto->display_id))) + head->func->display_id(head, msto->display_id); } if (mstm->outp->outp.or.link & 1) @@ -1052,6 +1073,9 @@ nv50_msto_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *s struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; + if (msto->head->func->display_id) + msto->head->func->display_id(msto->head, 0); + mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); mstm->modified = true; if (!--mstm->links) @@ -1290,6 +1314,12 @@ nv50_mstm_cleanup(struct drm_atomic_state *state, } } + if (mstm->disabled) { + nouveau_dp_power_down(mstm->outp); + nvif_outp_release(&mstm->outp->outp); + mstm->disabled = false; + } + mstm->modified = false; } @@ -1324,12 +1354,6 @@ nv50_mstm_prepare(struct drm_atomic_state *state, nv50_msto_prepare(state, mst_state, &mstm->mgr, msto); } } - - if (mstm->disabled) { - if (!mstm->links) - nvif_outp_release(&mstm->outp->outp); - mstm->disabled = false; - } } static struct drm_connector * @@ -1535,17 +1559,14 @@ static void nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); - struct nouveau_connector *nv_connector = nv50_outp_get_old_connector(state, nv_encoder); + struct nv50_head *head = nv50_head(nv_encoder->crtc); #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT + struct nouveau_connector *nv_connector = nv50_outp_get_old_connector(state, nv_encoder); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nouveau_backlight *backlight = nv_connector->backlight; -#endif struct drm_dp_aux *aux = &nv_connector->aux; int ret; - u8 pwr; -#ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT if (backlight && backlight->uses_dpcd) { ret = drm_edp_backlight_disable(aux, &backlight->edp_info); if (ret < 0) @@ -1554,19 +1575,20 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st } #endif - if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { - ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr); - - if (ret == 0) { - pwr &= ~DP_SET_POWER_MASK; - pwr |= DP_SET_POWER_D3; - drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr); - } + if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS && nv_encoder->hdmi.enabled) { + nvif_outp_hdmi(&nv_encoder->outp, head->base.index, + false, 0, 0, 0, false, false, false); + nv_encoder->hdmi.enabled = false; } - nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0); - nv50_audio_disable(encoder, nv_crtc); - nvif_outp_release(&nv_encoder->outp); + if (nv_encoder->dcb->type == DCB_OUTPUT_DP) + nouveau_dp_power_down(nv_encoder); + + if (head->func->display_id) + head->func->display_id(head, 0); + + nv_encoder->update(nv_encoder, head->base.index, NULL, 0, 0); + nv50_audio_disable(encoder, &head->base); nv_encoder->crtc = NULL; } @@ -1579,6 +1601,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base)); struct drm_display_mode *mode = &asyh->state.adjusted_mode; struct nv50_disp *disp = nv50_disp(encoder->dev); + struct nv50_head *head = nv50_head(&nv_crtc->base); struct nvif_outp *outp = &nv_encoder->outp; struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); @@ -1596,15 +1619,17 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta if ((disp->disp->object.oclass == GT214_DISP || disp->disp->object.oclass >= GF110_DISP) && + nv_encoder->dcb->type != DCB_OUTPUT_LVDS && drm_detect_monitor_audio(nv_connector->edid)) hda = true; + if (!nvif_outp_acquired(outp)) + nvif_outp_acquire_sor(outp, hda); + switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: - if (disp->disp->object.oclass == NV50_DISP || - !drm_detect_hdmi_monitor(nv_connector->edid)) - nvif_outp_acquire_tmds(outp, nv_crtc->index, false, 0, 0, 0, false); - else + if (disp->disp->object.oclass != NV50_DISP && + drm_detect_hdmi_monitor(nv_connector->edid)) nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda); if (nv_encoder->outp.or.link & 1) { @@ -1650,10 +1675,10 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta lvds_8bpc = true; } - nvif_outp_acquire_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc); + nvif_outp_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc); break; case DCB_OUTPUT_DP: - nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, hda, false); + nouveau_dp_train(nv_encoder, false, mode->clock, asyh->or.bpc); depth = nv50_dp_bpc_to_depth(asyh->or.bpc); if (nv_encoder->outp.or.link & 1) @@ -1661,8 +1686,6 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta else proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_B; - nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode); - #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT backlight = nv_connector->backlight; if (backlight && backlight->uses_dpcd) @@ -1676,6 +1699,9 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta break; } + if (head->func->display_id) + head->func->display_id(head, BIT(nv_encoder->outp.id)); + nv_encoder->update(nv_encoder, nv_crtc->index, asyh, proto, depth); } @@ -1691,14 +1717,13 @@ nv50_sor_destroy(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - nvif_outp_dtor(&nv_encoder->outp); - nv50_mstm_del(&nv_encoder->dp.mstm); drm_encoder_cleanup(encoder); if (nv_encoder->dcb->type == DCB_OUTPUT_DP) mutex_destroy(&nv_encoder->dp.hpd_irq_lock); + nvif_outp_dtor(&nv_encoder->outp); kfree(encoder); } @@ -1707,24 +1732,15 @@ nv50_sor_func = { .destroy = nv50_sor_destroy, }; -bool nv50_has_mst(struct nouveau_drm *drm) -{ - struct nvkm_bios *bios = nvxx_bios(&drm->client.device); - u32 data; - u8 ver, hdr, cnt, len; - - data = nvbios_dp_table(bios, &ver, &hdr, &cnt, &len); - return data && ver >= 0x40 && (nvbios_rd08(bios, data + 0x08) & 0x04); -} - static int -nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) +nv50_sor_create(struct nouveau_encoder *nv_encoder) { + struct drm_connector *connector = &nv_encoder->conn->base; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_drm *drm = nouveau_drm(connector->dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device); - struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; + struct dcb_output *dcbe = nv_encoder->dcb; struct nv50_disp *disp = nv50_disp(connector->dev); int type, ret; @@ -1737,15 +1753,9 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) break; } - nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); - if (!nv_encoder) - return -ENOMEM; - nv_encoder->dcb = dcbe; nv_encoder->update = nv50_sor_update; encoder = to_drm_encoder(nv_encoder); - encoder->possible_crtcs = dcbe->heads; - encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, "sor-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_sor_help); @@ -1756,40 +1766,40 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) nv50_outp_dump_caps(drm, nv_encoder); if (dcbe->type == DCB_OUTPUT_DP) { - struct nvkm_i2c_aux *aux = - nvkm_i2c_aux_find(i2c, dcbe->i2c_index); - mutex_init(&nv_encoder->dp.hpd_irq_lock); - if (aux) { - if (disp->disp->object.oclass < GF110_DISP) { - /* HW has no support for address-only - * transactions, so we're required to - * use custom I2C-over-AUX code. - */ - nv_encoder->i2c = &aux->i2c; - } else { - nv_encoder->i2c = &nv_connector->aux.ddc; - } - nv_encoder->aux = aux; + if (disp->disp->object.oclass < GF110_DISP) { + /* HW has no support for address-only + * transactions, so we're required to + * use custom I2C-over-AUX code. + */ + struct nvkm_i2c_aux *aux; + + aux = nvkm_i2c_aux_find(i2c, dcbe->i2c_index); + if (!aux) + return -EINVAL; + + nv_encoder->i2c = &aux->i2c; + } else { + nv_encoder->i2c = &nv_connector->aux.ddc; } - if (nv_connector->type != DCB_CONNECTOR_eDP && - nv50_has_mst(drm)) { + if (nv_connector->type != DCB_CONNECTOR_eDP && nv_encoder->outp.info.dp.mst) { ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16, nv_connector->base.base.id, &nv_encoder->dp.mstm); if (ret) return ret; } - } else { + } else + if (nv_encoder->outp.info.ddc != NVIF_OUTP_DDC_INVALID) { struct nvkm_i2c_bus *bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index); if (bus) nv_encoder->i2c = &bus->i2c; } - return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp); + return 0; } /****************************************************************************** @@ -1816,7 +1826,6 @@ nv50_pior_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *s core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL); nv_encoder->crtc = NULL; - nvif_outp_release(&nv_encoder->outp); } static void @@ -1844,14 +1853,16 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st default: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT; break; } + if (!nvif_outp_acquired(&nv_encoder->outp)) + nvif_outp_acquire_pior(&nv_encoder->outp); + switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); - nvif_outp_acquire_tmds(&nv_encoder->outp, false, false, 0, 0, 0, false); break; case DCB_OUTPUT_DP: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); - nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, false, false); + nouveau_dp_train(nv_encoder, false, asyh->state.adjusted_mode.clock, 6); break; default: BUG(); @@ -1888,8 +1899,9 @@ nv50_pior_func = { }; static int -nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) +nv50_pior_create(struct nouveau_encoder *nv_encoder) { + struct drm_connector *connector = &nv_encoder->conn->base; struct drm_device *dev = connector->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nv50_disp *disp = nv50_disp(dev); @@ -1897,18 +1909,18 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) struct nvkm_i2c_bus *bus = NULL; struct nvkm_i2c_aux *aux = NULL; struct i2c_adapter *ddc; - struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; + struct dcb_output *dcbe = nv_encoder->dcb; int type; switch (dcbe->type) { case DCB_OUTPUT_TMDS: - bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_EXT(dcbe->extdev)); + bus = nvkm_i2c_bus_find(i2c, nv_encoder->outp.info.ddc); ddc = bus ? &bus->i2c : NULL; type = DRM_MODE_ENCODER_TMDS; break; case DCB_OUTPUT_DP: - aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbe->extdev)); + aux = nvkm_i2c_aux_find(i2c, nv_encoder->outp.info.dp.aux); ddc = aux ? &aux->i2c : NULL; type = DRM_MODE_ENCODER_TMDS; break; @@ -1916,18 +1928,11 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) return -ENODEV; } - nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); - if (!nv_encoder) - return -ENOMEM; - nv_encoder->dcb = dcbe; nv_encoder->i2c = ddc; - nv_encoder->aux = aux; mutex_init(&nv_encoder->dp.hpd_irq_lock); encoder = to_drm_encoder(nv_encoder); - encoder->possible_crtcs = dcbe->heads; - encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type, "pior-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_pior_help); @@ -1937,7 +1942,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) disp->core->func->pior->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1); nv50_outp_dump_caps(drm, nv_encoder); - return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp); + return 0; } /****************************************************************************** @@ -1951,7 +1956,9 @@ nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock) struct drm_dp_mst_topology_state *mst_state; struct nouveau_drm *drm = nouveau_drm(state->dev); struct nv50_disp *disp = nv50_disp(drm->dev); + struct nv50_atom *atom = nv50_atom(state); struct nv50_core *core = disp->core; + struct nv50_outp_atom *outp; struct nv50_mstm *mstm; int i; @@ -1974,6 +1981,23 @@ nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock) if (mstm->modified) nv50_mstm_cleanup(state, mst_state, mstm); } + + list_for_each_entry(outp, &atom->outp, head) { + if (outp->encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(outp->encoder); + + if (outp->enabled) { + nv50_audio_enable(outp->encoder, nouveau_crtc(nv_encoder->crtc), + nv_encoder->conn, NULL, NULL); + outp->enabled = outp->disabled = false; + } else { + if (outp->disabled) { + nvif_outp_release(&nv_encoder->outp); + outp->disabled = false; + } + } + } + } } static void @@ -2065,14 +2089,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) if (outp->clr.mask) { help->atomic_disable(encoder, state); + outp->disabled = true; interlock[NV50_DISP_INTERLOCK_CORE] |= 1; - if (outp->flush_disable) { - nv50_disp_atomic_commit_wndw(state, interlock); - nv50_disp_atomic_commit_core(state, interlock); - memset(interlock, 0x00, sizeof(interlock)); - - flushed = true; - } } } @@ -2092,7 +2110,7 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) nv50_crc_atomic_init_notifier_contexts(state); /* Update output path(s). */ - list_for_each_entry_safe(outp, outt, &atom->outp, head) { + list_for_each_entry(outp, &atom->outp, head) { const struct drm_encoder_helper_funcs *help; struct drm_encoder *encoder; @@ -2104,11 +2122,9 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) if (outp->set.mask) { help->atomic_enable(encoder, state); + outp->enabled = true; interlock[NV50_DISP_INTERLOCK_CORE] = 1; } - - list_del(&outp->head); - kfree(outp); } /* Update head(s). */ @@ -2206,6 +2222,11 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) if (atom->lock_core) mutex_unlock(&disp->mutex); + list_for_each_entry_safe(outp, outt, &atom->outp, head) { + list_del(&outp->head); + kfree(outp); + } + /* Wait for HW to signal completion. */ for_each_new_plane_in_state(state, plane, new_plane_state, i) { struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state); @@ -2354,10 +2375,9 @@ nv50_disp_outp_atomic_check_clr(struct nv50_atom *atom, if (IS_ERR(outp)) return PTR_ERR(outp); - if (outp->encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { - outp->flush_disable = true; + if (outp->encoder->encoder_type == DRM_MODE_ENCODER_DPMST || + nouveau_encoder(outp->encoder)->dcb->type == DCB_OUTPUT_DP) atom->flush_disable = true; - } outp->clr.ctrl = true; atom->lock_core = true; } @@ -2518,6 +2538,104 @@ nv50_display_fini(struct drm_device *dev, bool runtime, bool suspend) cancel_work_sync(&drm->hpd_work); } +static inline void +nv50_display_read_hw_or_state(struct drm_device *dev, struct nv50_disp *disp, + struct nouveau_encoder *outp) +{ + struct drm_crtc *crtc; + struct drm_connector_list_iter conn_iter; + struct drm_connector *conn; + struct nv50_head_atom *armh; + const u32 encoder_mask = drm_encoder_mask(&outp->base.base); + bool found_conn = false, found_head = false; + u8 proto; + int head_idx; + int ret; + + switch (outp->dcb->type) { + case DCB_OUTPUT_TMDS: + ret = nvif_outp_inherit_tmds(&outp->outp, &proto); + break; + case DCB_OUTPUT_DP: + ret = nvif_outp_inherit_dp(&outp->outp, &proto); + break; + case DCB_OUTPUT_LVDS: + ret = nvif_outp_inherit_lvds(&outp->outp, &proto); + break; + case DCB_OUTPUT_ANALOG: + ret = nvif_outp_inherit_rgb_crt(&outp->outp, &proto); + break; + default: + drm_dbg_kms(dev, "Readback for %s not implemented yet, skipping\n", + outp->base.base.name); + drm_WARN_ON(dev, true); + return; + } + + if (ret < 0) + return; + + head_idx = ret; + + drm_for_each_crtc(crtc, dev) { + if (crtc->index != head_idx) + continue; + + armh = nv50_head_atom(crtc->state); + found_head = true; + break; + } + if (drm_WARN_ON(dev, !found_head)) + return; + + /* Figure out which connector is being used by this encoder */ + drm_connector_list_iter_begin(dev, &conn_iter); + nouveau_for_each_non_mst_connector_iter(conn, &conn_iter) { + if (nouveau_connector(conn)->index == outp->dcb->connector) { + found_conn = true; + break; + } + } + drm_connector_list_iter_end(&conn_iter); + if (drm_WARN_ON(dev, !found_conn)) + return; + + armh->state.encoder_mask = encoder_mask; + armh->state.connector_mask = drm_connector_mask(conn); + armh->state.active = true; + armh->state.enable = true; + pm_runtime_get_noresume(dev->dev); + + outp->crtc = crtc; + outp->ctrl = NVVAL(NV507D, SOR_SET_CONTROL, PROTOCOL, proto) | BIT(crtc->index); + + drm_connector_get(conn); + conn->state->crtc = crtc; + conn->state->best_encoder = &outp->base.base; +} + +/* Read back the currently programmed display state */ +static void +nv50_display_read_hw_state(struct nouveau_drm *drm) +{ + struct drm_device *dev = drm->dev; + struct drm_encoder *encoder; + struct drm_modeset_acquire_ctx ctx; + struct nv50_disp *disp = nv50_disp(dev); + int ret; + + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + + drm_for_each_encoder(encoder, dev) { + if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) + continue; + + nv50_display_read_hw_or_state(dev, disp, nouveau_encoder(encoder)); + } + + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); +} + static int nv50_display_init(struct drm_device *dev, bool resume, bool runtime) { @@ -2535,6 +2653,9 @@ nv50_display_init(struct drm_device *dev, bool resume, bool runtime) } } + if (!resume) + nv50_display_read_hw_state(nouveau_drm(dev)); + return 0; } @@ -2561,14 +2682,11 @@ nv50_display_destroy(struct drm_device *dev) int nv50_display_create(struct drm_device *dev) { - struct nvif_device *device = &nouveau_drm(dev)->client.device; struct nouveau_drm *drm = nouveau_drm(dev); - struct dcb_table *dcb = &drm->vbios.dcb; struct drm_connector *connector, *tmp; struct nv50_disp *disp; - struct dcb_output *dcbe; - int crtcs, ret, i; - bool has_mst = nv50_has_mst(drm); + int ret, i; + bool has_mst = false; disp = kzalloc(sizeof(*disp), GFP_KERNEL); if (!disp) @@ -2644,20 +2762,92 @@ nv50_display_create(struct drm_device *dev) dev->mode_config.cursor_height = 64; } - /* create crtc objects to represent the hw heads */ - if (disp->disp->object.oclass >= GV100_DISP) - crtcs = nvif_rd32(&device->object, 0x610060) & 0xff; - else - if (disp->disp->object.oclass >= GF110_DISP) - crtcs = nvif_rd32(&device->object, 0x612004) & 0xf; - else - crtcs = 0x3; + /* create encoder/connector objects based on VBIOS DCB table */ + for_each_set_bit(i, &disp->disp->outp_mask, sizeof(disp->disp->outp_mask) * 8) { + struct nouveau_encoder *outp; - for (i = 0; i < fls(crtcs); i++) { - struct nv50_head *head; + outp = kzalloc(sizeof(*outp), GFP_KERNEL); + if (!outp) + break; + + ret = nvif_outp_ctor(disp->disp, "kmsOutp", i, &outp->outp); + if (ret) { + kfree(outp); + continue; + } + + connector = nouveau_connector_create(dev, outp->outp.info.conn); + if (IS_ERR(connector)) { + nvif_outp_dtor(&outp->outp); + kfree(outp); + continue; + } + + outp->base.base.possible_crtcs = outp->outp.info.heads; + outp->base.base.possible_clones = 0; + outp->conn = nouveau_connector(connector); + + outp->dcb = kzalloc(sizeof(*outp->dcb), GFP_KERNEL); + if (!outp->dcb) + break; - if (!(crtcs & (1 << i))) + switch (outp->outp.info.proto) { + case NVIF_OUTP_RGB_CRT: + outp->dcb->type = DCB_OUTPUT_ANALOG; + outp->dcb->crtconf.maxfreq = outp->outp.info.rgb_crt.freq_max; + break; + case NVIF_OUTP_TMDS: + outp->dcb->type = DCB_OUTPUT_TMDS; + outp->dcb->duallink_possible = outp->outp.info.tmds.dual; + break; + case NVIF_OUTP_LVDS: + outp->dcb->type = DCB_OUTPUT_LVDS; + outp->dcb->lvdsconf.use_acpi_for_edid = outp->outp.info.lvds.acpi_edid; + break; + case NVIF_OUTP_DP: + outp->dcb->type = DCB_OUTPUT_DP; + outp->dcb->dpconf.link_nr = outp->outp.info.dp.link_nr; + outp->dcb->dpconf.link_bw = outp->outp.info.dp.link_bw; + if (outp->outp.info.dp.mst) + has_mst = true; + break; + default: + WARN_ON(1); + continue; + } + + outp->dcb->heads = outp->outp.info.heads; + outp->dcb->connector = outp->outp.info.conn; + outp->dcb->i2c_index = outp->outp.info.ddc; + + switch (outp->outp.info.type) { + case NVIF_OUTP_DAC : ret = nv50_dac_create(outp); break; + case NVIF_OUTP_SOR : ret = nv50_sor_create(outp); break; + case NVIF_OUTP_PIOR: ret = nv50_pior_create(outp); break; + default: + WARN_ON(1); continue; + } + + if (ret) { + NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n", + i, outp->outp.info.type, outp->outp.info.proto, ret); + } + } + + /* cull any connectors we created that don't have an encoder */ + list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { + if (connector->possible_encoders) + continue; + + NV_WARN(drm, "%s has no encoders, removing\n", + connector->name); + connector->funcs->destroy(connector); + } + + /* create crtc objects to represent the hw heads */ + for_each_set_bit(i, &disp->disp->head_mask, sizeof(disp->disp->head_mask) * 8) { + struct nv50_head *head; head = nv50_head_create(dev, i); if (IS_ERR(head)) { @@ -2683,50 +2873,8 @@ nv50_display_create(struct drm_device *dev) * Once these issues are closed, this should be * removed */ - head->msto->encoder.possible_crtcs = crtcs; - } - } - - /* create encoder/connector objects based on VBIOS DCB table */ - for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { - connector = nouveau_connector_create(dev, dcbe); - if (IS_ERR(connector)) - continue; - - if (dcbe->location == DCB_LOC_ON_CHIP) { - switch (dcbe->type) { - case DCB_OUTPUT_TMDS: - case DCB_OUTPUT_LVDS: - case DCB_OUTPUT_DP: - ret = nv50_sor_create(connector, dcbe); - break; - case DCB_OUTPUT_ANALOG: - ret = nv50_dac_create(connector, dcbe); - break; - default: - ret = -ENODEV; - break; - } - } else { - ret = nv50_pior_create(connector, dcbe); + head->msto->encoder.possible_crtcs = disp->disp->head_mask; } - - if (ret) { - NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n", - dcbe->location, dcbe->type, - ffs(dcbe->or) - 1, ret); - ret = 0; - } - } - - /* cull any connectors we created that don't have an encoder */ - list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { - if (connector->possible_encoders) - continue; - - NV_WARN(drm, "%s has no encoders, removing\n", - connector->name); - connector->funcs->destroy(connector); } /* Disable vblank irqs aggressively for power-saving, safe on nv50+ */ diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h b/drivers/gpu/drm/nouveau/dispnv50/disp.h index 9d66c9c726c3..5508a7cfd492 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h @@ -83,7 +83,9 @@ struct nv50_outp_atom { struct list_head head; struct drm_encoder *encoder; - bool flush_disable; + + bool disabled; + bool enabled; union nv50_outp_atom_mask { struct { @@ -106,8 +108,6 @@ void nv50_dmac_destroy(struct nv50_dmac *); */ struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder); -bool nv50_has_mst(struct nouveau_drm *drm); - u32 *evo_wait(struct nv50_dmac *, int nr); void evo_kick(u32 *, struct nv50_dmac *); diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.h b/drivers/gpu/drm/nouveau/dispnv50/head.h index 41c8788dfb31..e9d17037ffcf 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.h +++ b/drivers/gpu/drm/nouveau/dispnv50/head.h @@ -49,6 +49,7 @@ struct nv50_head_func { int (*procamp)(struct nv50_head *, struct nv50_head_atom *); int (*or)(struct nv50_head *, struct nv50_head_atom *); void (*static_wndw_map)(struct nv50_head *, struct nv50_head_atom *); + int (*display_id)(struct nv50_head *, u32 display_id); }; extern const struct nv50_head_func head507d; diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c index 543f08ceaad6..53b1248c40ec 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c @@ -28,6 +28,19 @@ #include <nvhw/class/clc57d.h> static int +headc57d_display_id(struct nv50_head *head, u32 display_id) +{ + struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push; + int ret; + + if ((ret = PUSH_WAIT(push, 2))) + return ret; + + PUSH_NVSQ(push, NVC57D, 0x2020 + (head->base.index * 0x400), display_id); + return 0; +} + +static int headc57d_or(struct nv50_head *head, struct nv50_head_atom *asyh) { struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push; @@ -250,4 +263,5 @@ headc57d = { .or = headc57d_or, /* TODO: flexible window mappings */ .static_wndw_map = headc37d_static_wndw_map, + .display_id = headc57d_display_id, }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/conn.h b/drivers/gpu/drm/nouveau/include/nvif/conn.h index dc355e1dfafa..406c12a111f9 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/conn.h +++ b/drivers/gpu/drm/nouveau/include/nvif/conn.h @@ -7,6 +7,21 @@ struct nvif_disp; struct nvif_conn { struct nvif_object object; + u32 id; + + struct { + enum { + NVIF_CONN_VGA, + NVIF_CONN_TV, + NVIF_CONN_DVI_I, + NVIF_CONN_DVI_D, + NVIF_CONN_LVDS, + NVIF_CONN_LVDS_SPWG, + NVIF_CONN_HDMI, + NVIF_CONN_DP, + NVIF_CONN_EDP, + } type; + } info; }; int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *); @@ -18,11 +33,6 @@ nvif_conn_id(struct nvif_conn *conn) return conn->object.handle; } -#define NVIF_CONN_HPD_STATUS_UNSUPPORTED 0 /* negative if query fails */ -#define NVIF_CONN_HPD_STATUS_NOT_PRESENT 1 -#define NVIF_CONN_HPD_STATUS_PRESENT 2 -int nvif_conn_hpd_status(struct nvif_conn *); - int nvif_conn_event_ctor(struct nvif_conn *, const char *name, nvif_event_func, u8 types, struct nvif_event *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0011.h b/drivers/gpu/drm/nouveau/include/nvif/if0011.h index 69b0b779f942..3ed0ddd75bd8 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0011.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0011.h @@ -7,6 +7,16 @@ union nvif_conn_args { __u8 version; __u8 id; /* DCB connector table index. */ __u8 pad02[6]; +#define NVIF_CONN_V0_VGA 0x00 +#define NVIF_CONN_V0_TV 0x01 +#define NVIF_CONN_V0_DVI_I 0x02 +#define NVIF_CONN_V0_DVI_D 0x03 +#define NVIF_CONN_V0_LVDS 0x04 +#define NVIF_CONN_V0_LVDS_SPWG 0x05 +#define NVIF_CONN_V0_HDMI 0x06 +#define NVIF_CONN_V0_DP 0x07 +#define NVIF_CONN_V0_EDP 0x08 + __u8 type; } v0; }; @@ -20,15 +30,4 @@ union nvif_conn_event_args { __u8 pad02[6]; } v0; }; - -#define NVIF_CONN_V0_HPD_STATUS 0x00000000 - -union nvif_conn_hpd_status_args { - struct nvif_conn_hpd_status_v0 { - __u8 version; - __u8 support; - __u8 present; - __u8 pad03[5]; - } v0; -}; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index 16d4ad5023a3..bde9bfae8d11 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -8,18 +8,86 @@ union nvif_outp_args { struct nvif_outp_v0 { __u8 version; __u8 id; /* DCB device index. */ - __u8 pad02[6]; +#define NVIF_OUTP_V0_TYPE_DAC 0x00 +#define NVIF_OUTP_V0_TYPE_SOR 0x01 +#define NVIF_OUTP_V0_TYPE_PIOR 0x02 + __u8 type; +#define NVIF_OUTP_V0_PROTO_RGB_CRT 0x00 +#define NVIF_OUTP_V0_PROTO_TMDS 0x01 +#define NVIF_OUTP_V0_PROTO_LVDS 0x02 +#define NVIF_OUTP_V0_PROTO_DP 0x03 + __u8 proto; + __u8 heads; + __u8 ddc; + __u8 conn; + union { + struct { + __u32 freq_max; + } rgb_crt; + struct { + __u8 dual; + } tmds; + struct { + __u8 acpi_edid; + } lvds; + struct { + __u8 aux; + __u8 mst; + __u8 increased_wm; + __u8 link_nr; + __u32 link_bw; + } dp; + }; } v0; }; -#define NVIF_OUTP_V0_LOAD_DETECT 0x00 -#define NVIF_OUTP_V0_ACQUIRE 0x01 -#define NVIF_OUTP_V0_RELEASE 0x02 -#define NVIF_OUTP_V0_INFOFRAME 0x03 -#define NVIF_OUTP_V0_HDA_ELD 0x04 -#define NVIF_OUTP_V0_DP_AUX_PWR 0x05 -#define NVIF_OUTP_V0_DP_RETRAIN 0x06 -#define NVIF_OUTP_V0_DP_MST_VCPI 0x07 +#define NVIF_OUTP_V0_DETECT 0x00 +#define NVIF_OUTP_V0_EDID_GET 0x01 + +#define NVIF_OUTP_V0_INHERIT 0x10 +#define NVIF_OUTP_V0_ACQUIRE 0x11 +#define NVIF_OUTP_V0_RELEASE 0x12 + +#define NVIF_OUTP_V0_LOAD_DETECT 0x20 + +#define NVIF_OUTP_V0_BL_GET 0x30 +#define NVIF_OUTP_V0_BL_SET 0x31 + +#define NVIF_OUTP_V0_LVDS 0x40 + +#define NVIF_OUTP_V0_HDMI 0x50 + +#define NVIF_OUTP_V0_INFOFRAME 0x60 +#define NVIF_OUTP_V0_HDA_ELD 0x61 + +#define NVIF_OUTP_V0_DP_AUX_PWR 0x70 +#define NVIF_OUTP_V0_DP_AUX_XFER 0x71 +#define NVIF_OUTP_V0_DP_RATES 0x72 +#define NVIF_OUTP_V0_DP_TRAIN 0x73 +#define NVIF_OUTP_V0_DP_DRIVE 0x74 +#define NVIF_OUTP_V0_DP_SST 0x75 +#define NVIF_OUTP_V0_DP_MST_ID_GET 0x76 +#define NVIF_OUTP_V0_DP_MST_ID_PUT 0x77 +#define NVIF_OUTP_V0_DP_MST_VCPI 0x78 + +union nvif_outp_detect_args { + struct nvif_outp_detect_v0 { + __u8 version; +#define NVIF_OUTP_DETECT_V0_NOT_PRESENT 0x00 +#define NVIF_OUTP_DETECT_V0_PRESENT 0x01 +#define NVIF_OUTP_DETECT_V0_UNKNOWN 0x02 + __u8 status; + } v0; +}; + +union nvif_outp_edid_get_args { + struct nvif_outp_edid_get_v0 { + __u8 version; + __u8 pad01; + __u16 size; + __u8 data[2048]; + } v0; +}; union nvif_outp_load_detect_args { struct nvif_outp_load_detect_v0 { @@ -33,40 +101,39 @@ union nvif_outp_load_detect_args { union nvif_outp_acquire_args { struct nvif_outp_acquire_v0 { __u8 version; -#define NVIF_OUTP_ACQUIRE_V0_RGB_CRT 0x00 -#define NVIF_OUTP_ACQUIRE_V0_TV 0x01 -#define NVIF_OUTP_ACQUIRE_V0_TMDS 0x02 -#define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03 -#define NVIF_OUTP_ACQUIRE_V0_DP 0x04 - __u8 proto; +#define NVIF_OUTP_ACQUIRE_V0_DAC 0x00 +#define NVIF_OUTP_ACQUIRE_V0_SOR 0x01 +#define NVIF_OUTP_ACQUIRE_V0_PIOR 0x02 + __u8 type; __u8 or; __u8 link; __u8 pad04[4]; union { struct { - __u8 head; - __u8 hdmi; - __u8 hdmi_max_ac_packet; - __u8 hdmi_rekey; -#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_SCRAMBLE (1 << 0) -#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_DIV_BY_4 (1 << 1) - __u8 hdmi_scdc; - __u8 hdmi_hda; - __u8 pad06[2]; - } tmds; - struct { - __u8 dual; - __u8 bpc8; - __u8 pad02[6]; - } lvds; + __u8 hda; + } sor; + }; + } v0; +}; + +union nvif_outp_inherit_args { + struct nvif_outp_inherit_v0 { + __u8 version; +#define NVIF_OUTP_INHERIT_V0_RGB_CRT 0x00 +#define NVIF_OUTP_INHERIT_V0_TV 0x01 +#define NVIF_OUTP_INHERIT_V0_TMDS 0x02 +#define NVIF_OUTP_INHERIT_V0_LVDS 0x03 +#define NVIF_OUTP_INHERIT_V0_DP 0x04 + // In/out. Input is one of the above values, output is the actual hw protocol + __u8 proto; + __u8 or; + __u8 link; + __u8 head; + union { struct { - __u8 link_nr; /* 0 = highest possible. */ - __u8 link_bw; /* 0 = highest possible, DP BW code otherwise. */ + // TODO: Figure out padding, and whether we even want this field __u8 hda; - __u8 mst; - __u8 pad04[4]; - __u8 dpcd[DP_RECEIVER_CAP_SIZE]; - } dp; + } tmds; }; } v0; }; @@ -76,6 +143,42 @@ union nvif_outp_release_args { } vn; }; +union nvif_outp_bl_get_args { + struct nvif_outp_bl_get_v0 { + __u8 version; + __u8 level; + } v0; +}; + +union nvif_outp_bl_set_args { + struct nvif_outp_bl_set_v0 { + __u8 version; + __u8 level; + } v0; +}; + +union nvif_outp_lvds_args { + struct nvif_outp_lvds_v0 { + __u8 version; + __u8 dual; + __u8 bpc8; + } v0; +}; + +union nvif_outp_hdmi_args { + struct nvif_outp_hdmi_v0 { + __u8 version; + __u8 head; + __u8 enable; + __u8 max_ac_packet; + __u8 rekey; + __u8 scdc; + __u8 scdc_scrambling; + __u8 scdc_low_rates; + __u32 khz; + } v0; +}; + union nvif_outp_infoframe_args { struct nvif_outp_infoframe_v0 { __u8 version; @@ -105,9 +208,77 @@ union nvif_outp_dp_aux_pwr_args { } v0; }; -union nvif_outp_dp_retrain_args { - struct nvif_outp_dp_retrain_vn { - } vn; +union nvif_outp_dp_aux_xfer_args { + struct nvif_outp_dp_aux_xfer_v0 { + __u8 version; + __u8 pad01; + __u8 type; + __u8 size; + __u32 addr; + __u8 data[16]; + } v0; +}; + +union nvif_outp_dp_rates_args { + struct nvif_outp_dp_rates_v0 { + __u8 version; + __u8 pad01[6]; + __u8 rates; + struct { + __s8 dpcd; + __u32 rate; + } rate[8]; + } v0; +}; + +union nvif_outp_dp_train_args { + struct nvif_outp_dp_train_v0 { + __u8 version; + __u8 retrain; + __u8 mst; + __u8 lttprs; + __u8 post_lt_adj; + __u8 link_nr; + __u32 link_bw; + __u8 dpcd[DP_RECEIVER_CAP_SIZE]; + } v0; +}; + +union nvif_outp_dp_drive_args { + struct nvif_outp_dp_drive_v0 { + __u8 version; + __u8 pad01[2]; + __u8 lanes; + __u8 pe[4]; + __u8 vs[4]; + } v0; +}; + +union nvif_outp_dp_sst_args { + struct nvif_outp_dp_sst_v0 { + __u8 version; + __u8 head; + __u8 pad02[2]; + __u32 watermark; + __u32 hblanksym; + __u32 vblanksym; + } v0; +}; + +union nvif_outp_dp_mst_id_put_args { + struct nvif_outp_dp_mst_id_put_v0 { + __u8 version; + __u8 pad01[3]; + __u32 id; + } v0; +}; + +union nvif_outp_dp_mst_id_get_args { + struct nvif_outp_dp_mst_id_get_v0 { + __u8 version; + __u8 pad01[3]; + __u32 id; + } v0; }; union nvif_outp_dp_mst_vcpi_args { diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index fa76a7b5e4b3..bc122a5ba7df 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -8,6 +8,46 @@ struct nvif_disp; struct nvif_outp { struct nvif_object object; + u32 id; + + struct { + enum { + NVIF_OUTP_DAC, + NVIF_OUTP_SOR, + NVIF_OUTP_PIOR, + } type; + + enum { + NVIF_OUTP_RGB_CRT, + NVIF_OUTP_TMDS, + NVIF_OUTP_LVDS, + NVIF_OUTP_DP, + } proto; + + u8 heads; +#define NVIF_OUTP_DDC_INVALID 0xff + u8 ddc; + u8 conn; + + union { + struct { + u32 freq_max; + } rgb_crt; + struct { + bool dual; + } tmds; + struct { + bool acpi_edid; + } lvds; + struct { + u8 aux; + bool mst; + bool increased_wm; + u8 link_nr; + u32 link_bw; + } dp; + }; + } info; struct { int id; @@ -17,18 +57,60 @@ struct nvif_outp { int nvif_outp_ctor(struct nvif_disp *, const char *name, int id, struct nvif_outp *); void nvif_outp_dtor(struct nvif_outp *); + +enum nvif_outp_detect_status { + NOT_PRESENT, + PRESENT, + UNKNOWN, +}; + +enum nvif_outp_detect_status nvif_outp_detect(struct nvif_outp *); +int nvif_outp_edid_get(struct nvif_outp *, u8 **pedid); + int nvif_outp_load_detect(struct nvif_outp *, u32 loadval); -int nvif_outp_acquire_rgb_crt(struct nvif_outp *); -int nvif_outp_acquire_tmds(struct nvif_outp *, int head, - bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda); -int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8); -int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], - int link_nr, int link_bw, bool hda, bool mst); +int nvif_outp_acquire_dac(struct nvif_outp *); +int nvif_outp_acquire_sor(struct nvif_outp *, bool hda); +int nvif_outp_acquire_pior(struct nvif_outp *); +int nvif_outp_inherit_rgb_crt(struct nvif_outp *outp, u8 *proto_out); +int nvif_outp_inherit_lvds(struct nvif_outp *outp, u8 *proto_out); +int nvif_outp_inherit_tmds(struct nvif_outp *outp, u8 *proto_out); +int nvif_outp_inherit_dp(struct nvif_outp *outp, u8 *proto_out); + void nvif_outp_release(struct nvif_outp *); + +static inline bool +nvif_outp_acquired(struct nvif_outp *outp) +{ + return outp->or.id >= 0; +} + +int nvif_outp_bl_get(struct nvif_outp *); +int nvif_outp_bl_set(struct nvif_outp *, int level); + +int nvif_outp_lvds(struct nvif_outp *, bool dual, bool bpc8); + +int nvif_outp_hdmi(struct nvif_outp *, int head, bool enable, u8 max_ac_packet, u8 rekey, u32 khz, + bool scdc, bool scdc_scrambling, bool scdc_low_rates); + int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size); int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size); + int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable); -int nvif_outp_dp_retrain(struct nvif_outp *); +int nvif_outp_dp_aux_xfer(struct nvif_outp *, u8 type, u8 *size, u32 addr, u8 *data); + +struct nvif_outp_dp_rate { + int dpcd; /* -1 for non-indexed rates */ + u32 rate; +}; + +int nvif_outp_dp_rates(struct nvif_outp *, struct nvif_outp_dp_rate *rate, int rate_nr); +int nvif_outp_dp_train(struct nvif_outp *, u8 dpcd[DP_RECEIVER_CAP_SIZE], + u8 lttprs, u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj, + bool retrain); +int nvif_outp_dp_drive(struct nvif_outp *, u8 link_nr, u8 pe[4], u8 vs[4]); +int nvif_outp_dp_sst(struct nvif_outp *, int head, u32 watermark, u32 hblanksym, u32 vblanksym); +int nvif_outp_dp_mst_id_get(struct nvif_outp *, u32 *id); +int nvif_outp_dp_mst_id_put(struct nvif_outp *, u32 id); int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h index d3b6a68ddda3..fc0f38981391 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h @@ -12,6 +12,7 @@ struct nvkm_tags { }; enum nvkm_memory_target { + NVKM_MEM_TARGET_INST_SR_LOST, /* instance memory - not preserved across suspend */ NVKM_MEM_TARGET_INST, /* instance memory */ NVKM_MEM_TARGET_VRAM, /* video memory */ NVKM_MEM_TARGET_HOST, /* coherent system memory */ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index fcdaefc99fe8..92a36ddfc29f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -26,7 +26,7 @@ struct nvkm_instmem { u32 nvkm_instmem_rd32(struct nvkm_instmem *, u32 addr); void nvkm_instmem_wr32(struct nvkm_instmem *, u32 addr, u32 data); -int nvkm_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero, +int nvkm_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero, bool preserve, struct nvkm_memory **); int nvkm_instobj_wrap(struct nvkm_device *, struct nvkm_memory *, struct nvkm_memory **); diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 91b5ecc57538..d47442125fa1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -109,42 +109,6 @@ nv40_backlight_init(struct nouveau_encoder *encoder, return 0; } -static int -nv50_get_intensity(struct backlight_device *bd) -{ - struct nouveau_encoder *nv_encoder = bl_get_data(bd); - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; - int or = ffs(nv_encoder->dcb->or) - 1; - u32 div = 1025; - u32 val; - - val = nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(or)); - val &= NV50_PDISP_SOR_PWM_CTL_VAL; - return ((val * 100) + (div / 2)) / div; -} - -static int -nv50_set_intensity(struct backlight_device *bd) -{ - struct nouveau_encoder *nv_encoder = bl_get_data(bd); - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; - int or = ffs(nv_encoder->dcb->or) - 1; - u32 div = 1025; - u32 val = (bd->props.brightness * div) / 100; - - nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), - NV50_PDISP_SOR_PWM_CTL_NEW | val); - return 0; -} - -static const struct backlight_ops nv50_bl_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = nv50_get_intensity, - .update_status = nv50_set_intensity, -}; - /* * eDP brightness callbacks need to happen under lock, since we need to * enable/disable the backlight ourselves for modesets @@ -238,53 +202,25 @@ static const struct backlight_ops nv50_edp_bl_ops = { }; static int -nva3_get_intensity(struct backlight_device *bd) +nv50_get_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; - int or = ffs(nv_encoder->dcb->or) - 1; - u32 div, val; - div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); - val = nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(or)); - val &= NVA3_PDISP_SOR_PWM_CTL_VAL; - if (div && div >= val) - return ((val * 100) + (div / 2)) / div; - - return 100; + return nvif_outp_bl_get(&nv_encoder->outp); } static int -nva3_set_intensity(struct backlight_device *bd) +nv50_set_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); - struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; - int or = ffs(nv_encoder->dcb->or) - 1; - u32 div, val; - - div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); - val = backlight_get_brightness(bd); - if (val) - val = (val * div) / 100; - - if (div) { - nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), - val | - NV50_PDISP_SOR_PWM_CTL_NEW | - NVA3_PDISP_SOR_PWM_CTL_UNK); - return 0; - } - - return -EINVAL; + return nvif_outp_bl_set(&nv_encoder->outp, backlight_get_brightness(bd)); } -static const struct backlight_ops nva3_bl_ops = { +static const struct backlight_ops nv50_bl_ops = { .options = BL_CORE_SUSPENDRESUME, - .get_brightness = nva3_get_intensity, - .update_status = nva3_set_intensity, + .get_brightness = nv50_get_intensity, + .update_status = nv50_set_intensity, }; /* FIXME: perform backlight probing for eDP _before_ this, this only gets called after connector @@ -298,13 +234,12 @@ nv50_backlight_init(struct nouveau_backlight *bl, const struct backlight_ops **ops) { struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_object *device = &drm->client.device.object; /* * Note when this runs the connectors have not been probed yet, * so nv_conn->base.status is not set yet. */ - if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - 1)) || + if (nvif_outp_bl_get(&nv_encoder->outp) < 0 || drm_helper_probe_detect(&nv_conn->base, NULL, false) != connector_status_connected) return -ENODEV; @@ -346,15 +281,8 @@ nv50_backlight_init(struct nouveau_backlight *bl, } } - if (drm->client.device.info.chipset <= 0xa0 || - drm->client.device.info.chipset == 0xaa || - drm->client.device.info.chipset == 0xac) - *ops = &nv50_bl_ops; - else - *ops = &nva3_bl_ops; - + *ops = &nv50_bl_ops; props->max_brightness = 100; - return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 189903b65edc..9e878cdc8e38 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2093,9 +2093,11 @@ nouveau_bios_init(struct drm_device *dev) if (!NVInitVBIOS(dev)) return -ENODEV; - ret = parse_dcb_table(dev, bios); - if (ret) - return ret; + if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) { + ret = parse_dcb_table(dev, bios); + if (ret) + return ret; + } if (!bios->major_version) /* we don't run version 0 bios */ return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 19cab37ac69c..0f3bd187ede6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -875,16 +875,10 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, if (ret) goto out_unlock; - ret = nouveau_fence_new(&fence); + ret = nouveau_fence_new(&fence, chan); if (ret) goto out_unlock; - ret = nouveau_fence_emit(fence, chan); - if (ret) { - nouveau_fence_unref(&fence); - goto out_unlock; - } - /* TODO: figure out a better solution here * * wait on the fence here explicitly as going through diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 1fd5ccf41128..bb3d6e5c122f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -70,11 +70,9 @@ nouveau_channel_idle(struct nouveau_channel *chan) struct nouveau_fence *fence = NULL; int ret; - ret = nouveau_fence_new(&fence); + ret = nouveau_fence_new(&fence, chan); if (!ret) { - ret = nouveau_fence_emit(fence, chan); - if (!ret) - ret = nouveau_fence_wait(fence, false, false); + ret = nouveau_fence_wait(fence, false, false); nouveau_fence_unref(&fence); } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 79ea30aac31f..856b3ef5edb8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -400,10 +400,8 @@ nouveau_connector_destroy(struct drm_connector *connector) kfree(nv_connector->edid); drm_connector_unregister(connector); drm_connector_cleanup(connector); - if (nv_connector->aux.transfer) { + if (nv_connector->aux.transfer) drm_dp_cec_unregister_connector(&nv_connector->aux); - kfree(nv_connector->aux.name); - } nvif_conn_dtor(&nv_connector->conn); kfree(connector); } @@ -413,6 +411,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct pci_dev *pdev = to_pci_dev(dev->dev); + struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL, *found = NULL; struct drm_encoder *encoder; int ret; @@ -421,33 +420,48 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) drm_connector_for_each_possible_encoder(connector, encoder) { nv_encoder = nouveau_encoder(encoder); - switch (nv_encoder->dcb->type) { - case DCB_OUTPUT_DP: - ret = nouveau_dp_detect(nouveau_connector(connector), - nv_encoder); - if (ret == NOUVEAU_DP_MST) - return NULL; - else if (ret == NOUVEAU_DP_SST) - found = nv_encoder; + if (nvif_object_constructed(&nv_encoder->outp.object)) { + enum nvif_outp_detect_status status; + + if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { + ret = nouveau_dp_detect(conn, nv_encoder); + if (ret == NOUVEAU_DP_MST) + return NULL; + if (ret != NOUVEAU_DP_SST) + continue; + + return nv_encoder; + } else { + status = nvif_outp_detect(&nv_encoder->outp); + switch (status) { + case PRESENT: + return nv_encoder; + case NOT_PRESENT: + continue; + case UNKNOWN: + break; + default: + WARN_ON(1); + break; + } + } + } - break; - case DCB_OUTPUT_LVDS: + if (!nv_encoder->i2c) + continue; + + if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS) { switcheroo_ddc = !!(vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC); - fallthrough; - default: - if (!nv_encoder->i2c) - break; + } - if (switcheroo_ddc) - vga_switcheroo_lock_ddc(pdev); - if (nvkm_probe_i2c(nv_encoder->i2c, 0x50)) - found = nv_encoder; - if (switcheroo_ddc) - vga_switcheroo_unlock_ddc(pdev); + if (switcheroo_ddc) + vga_switcheroo_lock_ddc(pdev); + if (nvkm_probe_i2c(nv_encoder->i2c, 0x50)) + found = nv_encoder; + if (switcheroo_ddc) + vga_switcheroo_unlock_ddc(pdev); - break; - } if (found) break; } @@ -554,7 +568,6 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL; struct nouveau_encoder *nv_partner; - struct i2c_adapter *i2c; int type; int ret; enum drm_connector_status conn_status = connector_status_disconnected; @@ -577,15 +590,20 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) } nv_encoder = nouveau_connector_ddc_detect(connector); - if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { - struct edid *new_edid; + if (nv_encoder) { + struct edid *new_edid = NULL; - if ((vga_switcheroo_handler_flags() & - VGA_SWITCHEROO_CAN_SWITCH_DDC) && - nv_connector->type == DCB_CONNECTOR_LVDS) - new_edid = drm_get_edid_switcheroo(connector, i2c); - else - new_edid = drm_get_edid(connector, i2c); + if (nv_encoder->i2c) { + if ((vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) && + nv_connector->type == DCB_CONNECTOR_LVDS) + new_edid = drm_get_edid_switcheroo(connector, nv_encoder->i2c); + else + new_edid = drm_get_edid(connector, nv_encoder->i2c); + } else { + ret = nvif_outp_edid_get(&nv_encoder->outp, (u8 **)&new_edid); + if (ret < 0) + return connector_status_disconnected; + } nouveau_connector_set_edid(nv_connector, new_edid); if (!nv_connector->edid) { @@ -1117,7 +1135,7 @@ nouveau_connector_atomic_check(struct drm_connector *connector, struct drm_atomi struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, connector); - if (!nv_conn->dp_encoder || !nv50_has_mst(nouveau_drm(connector->dev))) + if (!nv_conn->dp_encoder || !nv_conn->dp_encoder->dp.mstm) return 0; return drm_dp_mst_root_conn_atomic_check(conn_state, &nv_conn->dp_encoder->dp.mstm->mgr); @@ -1206,23 +1224,17 @@ nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg) struct nouveau_connector *nv_connector = container_of(obj, typeof(*nv_connector), aux); struct nouveau_encoder *nv_encoder; - struct nvkm_i2c_aux *aux; u8 size = msg->size; int ret; nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); - if (!nv_encoder || !(aux = nv_encoder->aux)) + if (!nv_encoder) return -ENODEV; if (WARN_ON(msg->size > 16)) return -E2BIG; - ret = nvkm_i2c_aux_acquire(aux); - if (ret) - return ret; - - ret = nvkm_i2c_aux_xfer(aux, false, msg->request, msg->address, - msg->buffer, &size); - nvkm_i2c_aux_release(aux); + ret = nvif_outp_dp_aux_xfer(&nv_encoder->outp, + msg->request, &size, msg->address, msg->buffer); if (ret >= 0) { msg->reply = ret; return size; @@ -1263,17 +1275,13 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb) } struct drm_connector * -nouveau_connector_create(struct drm_device *dev, - const struct dcb_output *dcbe) +nouveau_connector_create(struct drm_device *dev, int index) { - const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_display *disp = nouveau_display(dev); struct nouveau_connector *nv_connector = NULL; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; - char aux_name[48] = {0}; - int index = dcbe->connector; int type, ret = 0; bool dummy; @@ -1295,74 +1303,86 @@ nouveau_connector_create(struct drm_device *dev, nv_connector->index = index; INIT_WORK(&nv_connector->irq_work, nouveau_dp_irq); - /* attempt to parse vbios connector type and hotplug gpio */ - nv_connector->dcb = olddcb_conn(dev, index); - if (nv_connector->dcb) { - u32 entry = ROM16(nv_connector->dcb[0]); - if (olddcb_conntab(dev)[3] >= 4) - entry |= (u32)ROM16(nv_connector->dcb[2]) << 16; - - nv_connector->type = nv_connector->dcb[0]; - if (drm_conntype_from_dcb(nv_connector->type) == - DRM_MODE_CONNECTOR_Unknown) { - NV_WARN(drm, "unknown connector type %02x\n", - nv_connector->type); - nv_connector->type = DCB_CONNECTOR_NONE; + if (disp->disp.conn_mask & BIT(nv_connector->index)) { + ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index, + &nv_connector->conn); + if (ret) { + kfree(nv_connector); + return ERR_PTR(ret); } - /* Gigabyte NX85T */ - if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) { - if (nv_connector->type == DCB_CONNECTOR_HDMI_1) - nv_connector->type = DCB_CONNECTOR_DVI_I; + switch (nv_connector->conn.info.type) { + case NVIF_CONN_VGA : type = DCB_CONNECTOR_VGA; break; + case NVIF_CONN_DVI_I : type = DCB_CONNECTOR_DVI_I; break; + case NVIF_CONN_DVI_D : type = DCB_CONNECTOR_DVI_D; break; + case NVIF_CONN_LVDS : type = DCB_CONNECTOR_LVDS; break; + case NVIF_CONN_LVDS_SPWG: type = DCB_CONNECTOR_LVDS_SPWG; break; + case NVIF_CONN_DP : type = DCB_CONNECTOR_DP; break; + case NVIF_CONN_EDP : type = DCB_CONNECTOR_eDP; break; + case NVIF_CONN_HDMI : type = DCB_CONNECTOR_HDMI_0; break; + default: + WARN_ON(1); + return NULL; } - /* Gigabyte GV-NX86T512H */ - if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) { - if (nv_connector->type == DCB_CONNECTOR_HDMI_1) - nv_connector->type = DCB_CONNECTOR_DVI_I; - } + nv_connector->type = type; } else { - nv_connector->type = DCB_CONNECTOR_NONE; - } + u8 *dcb = olddcb_conn(dev, nv_connector->index); - /* no vbios data, or an unknown dcb connector type - attempt to - * figure out something suitable ourselves - */ - if (nv_connector->type == DCB_CONNECTOR_NONE) { - struct nouveau_drm *drm = nouveau_drm(dev); - struct dcb_table *dcbt = &drm->vbios.dcb; - u32 encoders = 0; - int i; - - for (i = 0; i < dcbt->entries; i++) { - if (dcbt->entry[i].connector == nv_connector->index) - encoders |= (1 << dcbt->entry[i].type); + if (dcb) + nv_connector->type = dcb[0]; + else + nv_connector->type = DCB_CONNECTOR_NONE; + + /* attempt to parse vbios connector type and hotplug gpio */ + if (nv_connector->type != DCB_CONNECTOR_NONE) { + if (drm_conntype_from_dcb(nv_connector->type) == + DRM_MODE_CONNECTOR_Unknown) { + NV_WARN(drm, "unknown connector type %02x\n", + nv_connector->type); + nv_connector->type = DCB_CONNECTOR_NONE; + } } - if (encoders & (1 << DCB_OUTPUT_DP)) { - if (encoders & (1 << DCB_OUTPUT_TMDS)) - nv_connector->type = DCB_CONNECTOR_DP; - else - nv_connector->type = DCB_CONNECTOR_eDP; - } else - if (encoders & (1 << DCB_OUTPUT_TMDS)) { - if (encoders & (1 << DCB_OUTPUT_ANALOG)) - nv_connector->type = DCB_CONNECTOR_DVI_I; - else - nv_connector->type = DCB_CONNECTOR_DVI_D; - } else - if (encoders & (1 << DCB_OUTPUT_ANALOG)) { - nv_connector->type = DCB_CONNECTOR_VGA; - } else - if (encoders & (1 << DCB_OUTPUT_LVDS)) { - nv_connector->type = DCB_CONNECTOR_LVDS; - } else - if (encoders & (1 << DCB_OUTPUT_TV)) { - nv_connector->type = DCB_CONNECTOR_TV_0; + /* no vbios data, or an unknown dcb connector type - attempt to + * figure out something suitable ourselves + */ + if (nv_connector->type == DCB_CONNECTOR_NONE && + !WARN_ON(drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)) { + struct dcb_table *dcbt = &drm->vbios.dcb; + u32 encoders = 0; + int i; + + for (i = 0; i < dcbt->entries; i++) { + if (dcbt->entry[i].connector == nv_connector->index) + encoders |= (1 << dcbt->entry[i].type); + } + + if (encoders & (1 << DCB_OUTPUT_TMDS)) { + if (encoders & (1 << DCB_OUTPUT_ANALOG)) + nv_connector->type = DCB_CONNECTOR_DVI_I; + else + nv_connector->type = DCB_CONNECTOR_DVI_D; + } else + if (encoders & (1 << DCB_OUTPUT_ANALOG)) { + nv_connector->type = DCB_CONNECTOR_VGA; + } else + if (encoders & (1 << DCB_OUTPUT_LVDS)) { + nv_connector->type = DCB_CONNECTOR_LVDS; + } else + if (encoders & (1 << DCB_OUTPUT_TV)) { + nv_connector->type = DCB_CONNECTOR_TV_0; + } } } - switch ((type = drm_conntype_from_dcb(nv_connector->type))) { + type = drm_conntype_from_dcb(nv_connector->type); + if (type == DRM_MODE_CONNECTOR_LVDS) + drm_connector_init(dev, connector, &nouveau_connector_funcs_lvds, type); + else + drm_connector_init(dev, connector, &nouveau_connector_funcs, type); + + switch (type) { case DRM_MODE_CONNECTOR_LVDS: ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy); if (ret) { @@ -1371,24 +1391,16 @@ nouveau_connector_create(struct drm_device *dev, return ERR_PTR(ret); } - funcs = &nouveau_connector_funcs_lvds; break; case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_eDP: nv_connector->aux.dev = connector->kdev; nv_connector->aux.drm_dev = dev; nv_connector->aux.transfer = nouveau_connector_aux_xfer; - snprintf(aux_name, sizeof(aux_name), "sor-%04x-%04x", - dcbe->hasht, dcbe->hashm); - nv_connector->aux.name = kstrdup(aux_name, GFP_KERNEL); - if (!nv_connector->aux.name) { - kfree(nv_connector); - return ERR_PTR(-ENOMEM); - } + nv_connector->aux.name = connector->name; drm_dp_aux_init(&nv_connector->aux); break; default: - funcs = &nouveau_connector_funcs; break; } @@ -1403,17 +1415,10 @@ nouveau_connector_create(struct drm_device *dev, connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_connector_init(dev, connector, funcs, type); drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); connector->polled = DRM_CONNECTOR_POLL_CONNECT; - if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) { - ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index, - &nv_connector->conn); - if (ret) { - goto drm_conn_err; - } - + if (nvif_object_constructed(&nv_connector->conn.object)) { ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug", nouveau_connector_hotplug, NVIF_CONN_EVENT_V0_PLUG | NVIF_CONN_EVENT_V0_UNPLUG, diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 35bcb541722b..a2df4918340c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -121,7 +121,6 @@ struct nouveau_connector { struct drm_connector base; enum dcb_connector_type type; u8 index; - u8 *dcb; struct nvif_conn conn; u64 hpd_pending; @@ -200,7 +199,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) } struct drm_connector * -nouveau_connector_create(struct drm_device *, const struct dcb_output *); +nouveau_connector_create(struct drm_device *, int id); void nouveau_connector_hpd(struct nouveau_connector *, u64 bits); extern int nouveau_tv_disable; diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index 053f703f2f68..e83db051e851 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -231,7 +231,7 @@ nouveau_debugfs_gpuva(struct seq_file *m, void *data) continue; nouveau_uvmm_lock(uvmm); - drm_debugfs_gpuva_info(m, &uvmm->umgr); + drm_debugfs_gpuva_info(m, &uvmm->base); seq_puts(m, "\n"); nouveau_debugfs_gpuva_regions(m, uvmm); nouveau_uvmm_unlock(uvmm); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 99977e5fe716..d8c92521226d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -724,10 +724,10 @@ nouveau_display_create(struct drm_device *dev) drm_kms_helper_poll_init(dev); drm_kms_helper_poll_disable(dev); - if (nouveau_modeset != 2 && drm->vbios.dcb.entries) { - ret = nvif_disp_ctor(&drm->client.device, "kmsDisp", 0, - &disp->disp); - if (ret == 0) { + if (nouveau_modeset != 2) { + ret = nvif_disp_ctor(&drm->client.device, "kmsDisp", 0, &disp->disp); + + if (!ret && (disp->disp.outp_mask || drm->vbios.dcb.entries)) { nouveau_display_create_properties(dev); if (disp->disp.object.oclass < NV50_DISP) { dev->mode_config.fb_modifiers_not_supported = true; diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c index 61e84562094a..12feecf71e75 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dmem.c +++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c @@ -209,8 +209,7 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf) goto done; } - if (!nouveau_fence_new(&fence)) - nouveau_fence_emit(fence, dmem->migrate.chan); + nouveau_fence_new(&fence, dmem->migrate.chan); migrate_vma_pages(&args); nouveau_dmem_fence_done(&fence); dma_unmap_page(drm->dev->dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); @@ -403,8 +402,7 @@ nouveau_dmem_evict_chunk(struct nouveau_dmem_chunk *chunk) } } - if (!nouveau_fence_new(&fence)) - nouveau_fence_emit(fence, chunk->drm->dmem->migrate.chan); + nouveau_fence_new(&fence, chunk->drm->dmem->migrate.chan); migrate_device_pages(src_pfns, dst_pfns, npages); nouveau_dmem_fence_done(&fence); migrate_device_finalize(src_pfns, dst_pfns, npages); @@ -677,8 +675,7 @@ static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm, addr += PAGE_SIZE; } - if (!nouveau_fence_new(&fence)) - nouveau_fence_emit(fence, drm->dmem->migrate.chan); + nouveau_fence_new(&fence, drm->dmem->migrate.chan); migrate_vma_pages(args); nouveau_dmem_fence_done(&fence); nouveau_pfns_map(svmm, args->vma->vm_mm, args->start, pfns, i); diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 6a4980b2d4d4..7de7707ec6a8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -42,6 +42,21 @@ nouveau_dp_has_sink_count(struct drm_connector *connector, return drm_dp_read_sink_count_cap(connector, outp->dp.dpcd, &outp->dp.desc); } +static bool +nouveau_dp_probe_lttpr(struct nouveau_encoder *outp) +{ + u8 rev, size = sizeof(rev); + int ret; + + ret = nvif_outp_dp_aux_xfer(&outp->outp, DP_AUX_NATIVE_READ, &size, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + &rev); + if (ret || size < sizeof(rev) || rev < 0x14) + return false; + + return true; +} + static enum drm_connector_status nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector, struct nouveau_encoder *outp) @@ -53,10 +68,112 @@ nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector, int ret; u8 *dpcd = outp->dp.dpcd; + outp->dp.lttpr.nr = 0; + outp->dp.rate_nr = 0; + outp->dp.link_nr = 0; + outp->dp.link_bw = 0; + + if (connector->connector_type != DRM_MODE_CONNECTOR_eDP && + nouveau_dp_probe_lttpr(outp) && + !drm_dp_read_dpcd_caps(aux, dpcd) && + !drm_dp_read_lttpr_common_caps(aux, dpcd, outp->dp.lttpr.caps)) { + int nr = drm_dp_lttpr_count(outp->dp.lttpr.caps); + + if (nr) { + drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE, + DP_PHY_REPEATER_MODE_TRANSPARENT); + + if (nr > 0) { + ret = drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE, + DP_PHY_REPEATER_MODE_NON_TRANSPARENT); + if (ret != 1) { + drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE, + DP_PHY_REPEATER_MODE_TRANSPARENT); + } else { + outp->dp.lttpr.nr = nr; + } + } + } + } + ret = drm_dp_read_dpcd_caps(aux, dpcd); if (ret < 0) goto out; + outp->dp.link_nr = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; + if (outp->dcb->dpconf.link_nr < outp->dp.link_nr) + outp->dp.link_nr = outp->dcb->dpconf.link_nr; + + if (outp->dp.lttpr.nr) { + int links = drm_dp_lttpr_max_lane_count(outp->dp.lttpr.caps); + + if (links && links < outp->dp.link_nr) + outp->dp.link_nr = links; + } + + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) { + __le16 rates[DP_MAX_SUPPORTED_RATES]; + + ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, rates, sizeof(rates)); + if (ret == sizeof(rates)) { + for (int i = 0; i < ARRAY_SIZE(rates); i++) { + u32 rate = (le16_to_cpu(rates[i]) * 200) / 10; + int j; + + if (!rate) + break; + + for (j = 0; j < outp->dp.rate_nr; j++) { + if (rate > outp->dp.rate[j].rate) { + for (int k = outp->dp.rate_nr; k > j; k--) + outp->dp.rate[k] = outp->dp.rate[k - 1]; + break; + } + } + + outp->dp.rate[j].dpcd = i; + outp->dp.rate[j].rate = rate; + outp->dp.rate_nr++; + } + } + } + + if (!outp->dp.rate_nr) { + const u32 rates[] = { 810000, 540000, 270000, 162000 }; + u32 max_rate = dpcd[DP_MAX_LINK_RATE] * 27000; + + if (outp->dp.lttpr.nr) { + int rate = drm_dp_lttpr_max_link_rate(outp->dp.lttpr.caps); + + if (rate && rate < max_rate) + max_rate = rate; + } + + max_rate = min_t(int, max_rate, outp->dcb->dpconf.link_bw); + + for (int i = 0; i < ARRAY_SIZE(rates); i++) { + if (rates[i] <= max_rate) { + outp->dp.rate[outp->dp.rate_nr].dpcd = -1; + outp->dp.rate[outp->dp.rate_nr].rate = rates[i]; + outp->dp.rate_nr++; + } + } + + if (WARN_ON(!outp->dp.rate_nr)) + goto out; + } + + ret = nvif_outp_dp_rates(&outp->outp, outp->dp.rate, outp->dp.rate_nr); + if (ret) + goto out; + + for (int i = 0; i < outp->dp.rate_nr; i++) { + u32 link_bw = outp->dp.rate[i].rate; + + if (link_bw > outp->dp.link_bw) + outp->dp.link_bw = link_bw; + } + ret = drm_dp_read_desc(aux, &outp->dp.desc, drm_dp_is_branch(dpcd)); if (ret < 0) goto out; @@ -132,14 +249,8 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, } } - /* Check status of HPD pin before attempting an AUX transaction that - * would result in a number of (futile) retries on a connector which - * has no display plugged. - * - * TODO: look into checking this before probing I2C to detect DVI/HDMI - */ - hpd = nvif_conn_hpd_status(&nv_connector->conn); - if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT) { + hpd = nvif_outp_detect(&nv_encoder->outp); + if (hpd == NOT_PRESENT) { nvif_outp_dp_aux_pwr(&nv_encoder->outp, false); goto out; } @@ -157,39 +268,14 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, goto out; } - nv_encoder->dp.link_bw = 27000 * dpcd[DP_MAX_LINK_RATE]; - nv_encoder->dp.link_nr = - dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; - - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) { - struct drm_dp_aux *aux = &nv_connector->aux; - int ret, i; - u8 sink_rates[16]; - - ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, sink_rates, sizeof(sink_rates)); - if (ret == sizeof(sink_rates)) { - for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { - int val = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; - if (val && (i == 0 || val > nv_encoder->dp.link_bw)) - nv_encoder->dp.link_bw = val; - } - } - } - - NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n", - nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, - dpcd[DP_DPCD_REV]); - NV_DEBUG(drm, "encoder: %dx%d\n", - nv_encoder->dcb->dpconf.link_nr, - nv_encoder->dcb->dpconf.link_bw); - - if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr) - nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr; - if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw) - nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw; + NV_DEBUG(drm, "sink dpcd version: 0x%02x\n", dpcd[DP_DPCD_REV]); + for (int i = 0; i < nv_encoder->dp.rate_nr; i++) + NV_DEBUG(drm, "sink rate %d: %d\n", i, nv_encoder->dp.rate[i].rate); - NV_DEBUG(drm, "maximum: %dx%d\n", - nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); + NV_DEBUG(drm, "encoder: %dx%d\n", nv_encoder->dcb->dpconf.link_nr, + nv_encoder->dcb->dpconf.link_bw); + NV_DEBUG(drm, "maximum: %dx%d\n", nv_encoder->dp.link_nr, + nv_encoder->dp.link_bw); if (mstm && mstm->can_mst) { ret = nv50_mstm_detect(nv_encoder); @@ -211,15 +297,186 @@ out: return ret; } +void +nouveau_dp_power_down(struct nouveau_encoder *outp) +{ + struct drm_dp_aux *aux = &outp->conn->aux; + int ret; + u8 pwr; + + mutex_lock(&outp->dp.hpd_irq_lock); + + ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr); + if (ret == 1) { + pwr &= ~DP_SET_POWER_MASK; + pwr |= DP_SET_POWER_D3; + drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr); + } + + outp->dp.lt.nr = 0; + mutex_unlock(&outp->dp.hpd_irq_lock); +} + +static bool +nouveau_dp_train_link(struct nouveau_encoder *outp, bool retrain) +{ + struct drm_dp_aux *aux = &outp->conn->aux; + bool post_lt = false; + int ret, retries = 0; + + if ( (outp->dp.dpcd[DP_MAX_LANE_COUNT] & 0x20) && + !(outp->dp.dpcd[DP_MAX_DOWNSPREAD] & DP_TPS4_SUPPORTED)) + post_lt = true; + +retry: + ret = nvif_outp_dp_train(&outp->outp, outp->dp.dpcd, + outp->dp.lttpr.nr, + outp->dp.lt.nr, + outp->dp.lt.bw, + outp->dp.lt.mst, + post_lt, + retrain); + if (ret) + return false; + + if (post_lt) { + u8 stat[DP_LINK_STATUS_SIZE]; + u8 prev[2]; + u8 time = 0, adjusts = 0, tmp; + + ret = drm_dp_dpcd_read_phy_link_status(aux, DP_PHY_DPRX, stat); + if (ret) + return false; + + for (;;) { + if (!drm_dp_channel_eq_ok(stat, outp->dp.lt.nr)) { + ret = 1; + break; + } + + if (!(stat[2] & 0x02)) + break; + + msleep(5); + time += 5; + + memcpy(prev, &stat[4], sizeof(prev)); + ret = drm_dp_dpcd_read_phy_link_status(aux, DP_PHY_DPRX, stat); + if (ret) + break; + + if (!memcmp(prev, &stat[4], sizeof(prev))) { + if (time > 200) + break; + } else { + u8 pe[4], vs[4]; + + if (adjusts++ == 6) + break; + + for (int i = 0; i < outp->dp.lt.nr; i++) { + pe[i] = drm_dp_get_adjust_request_pre_emphasis(stat, i) >> + DP_TRAIN_PRE_EMPHASIS_SHIFT; + vs[i] = drm_dp_get_adjust_request_voltage(stat, i) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + } + + ret = nvif_outp_dp_drive(&outp->outp, outp->dp.lt.nr, pe, vs); + if (ret) + break; + + time = 0; + } + } + + if (drm_dp_dpcd_readb(aux, DP_LANE_COUNT_SET, &tmp) == 1) { + tmp &= ~0x20; + drm_dp_dpcd_writeb(aux, DP_LANE_COUNT_SET, tmp); + } + } + + if (ret == 1 && retries++ < 3) + goto retry; + + return ret == 0; +} + bool -nouveau_dp_link_check(struct nouveau_connector *nv_connector) +nouveau_dp_train(struct nouveau_encoder *outp, bool mst, u32 khz, u8 bpc) +{ + struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev); + struct drm_dp_aux *aux = &outp->conn->aux; + u32 min_rate; + u8 pwr; + bool ret = true; + + if (mst) + min_rate = outp->dp.link_nr * outp->dp.rate[0].rate; + else + min_rate = DIV_ROUND_UP(khz * bpc * 3, 8); + + NV_DEBUG(drm, "%s link training (mst:%d min_rate:%d)\n", + outp->base.base.name, mst, min_rate); + + mutex_lock(&outp->dp.hpd_irq_lock); + + if (drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr) == 1) { + if ((pwr & DP_SET_POWER_MASK) != DP_SET_POWER_D0) { + pwr &= ~DP_SET_POWER_MASK; + pwr |= DP_SET_POWER_D0; + drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr); + } + } + + for (int nr = outp->dp.link_nr; nr; nr >>= 1) { + for (int rate = 0; rate < outp->dp.rate_nr; rate++) { + if (outp->dp.rate[rate].rate * nr >= min_rate) { + outp->dp.lt.nr = nr; + outp->dp.lt.bw = outp->dp.rate[rate].rate; + outp->dp.lt.mst = mst; + if (nouveau_dp_train_link(outp, false)) + goto done; + } + } + } + + ret = false; +done: + mutex_unlock(&outp->dp.hpd_irq_lock); + return ret; +} + +static bool +nouveau_dp_link_check_locked(struct nouveau_encoder *outp) { - struct nouveau_encoder *nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); + u8 link_status[DP_LINK_STATUS_SIZE]; - if (!nv_encoder || nv_encoder->outp.or.id < 0) + if (!outp || !outp->dp.lt.nr) return true; - return nvif_outp_dp_retrain(&nv_encoder->outp) == 0; + if (drm_dp_dpcd_read_phy_link_status(&outp->conn->aux, DP_PHY_DPRX, link_status) < 0) + return false; + + if (drm_dp_channel_eq_ok(link_status, outp->dp.lt.nr)) + return true; + + return nouveau_dp_train_link(outp, true); +} + +bool +nouveau_dp_link_check(struct nouveau_connector *nv_connector) +{ + struct nouveau_encoder *outp = nv_connector->dp_encoder; + bool link_ok = true; + + if (outp) { + mutex_lock(&outp->dp.hpd_irq_lock); + if (outp->dp.lt.nr) + link_ok = nouveau_dp_link_check_locked(outp); + mutex_unlock(&outp->dp.hpd_irq_lock); + } + + return link_ok; } void diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 4396f501b16a..50589f982d1a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -1133,7 +1133,10 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) } get_task_comm(tmpname, current); - snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); + rcu_read_lock(); + snprintf(name, sizeof(name), "%s[%d]", + tmpname, pid_nr(rcu_dereference(fpriv->pid))); + rcu_read_unlock(); if (!(cli = kzalloc(sizeof(*cli), GFP_KERNEL))) { ret = -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 1fe17ff95f5e..3666a7403e47 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -189,21 +189,12 @@ u_free(void *addr) static inline void * u_memcpya(uint64_t user, unsigned int nmemb, unsigned int size) { - void *mem; - void __user *userptr = (void __force __user *)(uintptr_t)user; + void __user *userptr = u64_to_user_ptr(user); + size_t bytes; - size *= nmemb; - - mem = kvmalloc(size, GFP_KERNEL); - if (!mem) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(mem, userptr, size)) { - u_free(mem); - return ERR_PTR(-EFAULT); - } - - return mem; + if (unlikely(check_mul_overflow(nmemb, size, &bytes))) + return NULL; + return vmemdup_user(userptr, bytes); } #include <nvif/object.h> diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index bcba1a14cfab..333042fc493f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -49,8 +49,9 @@ struct nouveau_encoder { struct nvif_outp outp; int or; + struct nouveau_connector *conn; + struct i2c_adapter *i2c; - struct nvkm_i2c_aux *aux; /* different to drm_encoder.crtc, this reflects what's * actually programmed on the hw, not the proposed crtc */ @@ -60,7 +61,6 @@ struct nouveau_encoder { /* Protected by nouveau_drm.audio.lock */ struct { bool enabled; - struct drm_connector *connector; } audio; struct drm_display_mode mode; @@ -68,18 +68,38 @@ struct nouveau_encoder { struct nv04_output_reg restore; - union { + struct { + struct { + bool enabled; + } hdmi; + struct { struct nv50_mstm *mstm; + + struct { + u8 caps[DP_LTTPR_COMMON_CAP_SIZE]; + u8 nr; + } lttpr; + + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + + struct nvif_outp_dp_rate rate[8]; + int rate_nr; + int link_nr; int link_bw; + struct { + bool mst; + u8 nr; + u32 bw; + } lt; + /* Protects DP state that needs to be accessed outside * connector reprobing contexts */ struct mutex hpd_irq_lock; - u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; struct drm_dp_desc desc; @@ -141,6 +161,8 @@ enum nouveau_dp_status { }; int nouveau_dp_detect(struct nouveau_connector *, struct nouveau_encoder *); +bool nouveau_dp_train(struct nouveau_encoder *, bool mst, u32 khz, u8 bpc); +void nouveau_dp_power_down(struct nouveau_encoder *); bool nouveau_dp_link_check(struct nouveau_connector *); void nouveau_dp_irq(struct work_struct *); enum drm_mode_status nv50_dp_mode_valid(struct nouveau_encoder *, diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c index a90c4cd8cbb2..bf6c12f4342a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.c +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -96,7 +96,8 @@ nouveau_exec_job_submit(struct nouveau_job *job) unsigned long index; int ret; - ret = nouveau_fence_new(&exec_job->fence); + /* Create a new fence, but do not emit yet. */ + ret = nouveau_fence_create(&exec_job->fence, exec_job->chan); if (ret) return ret; @@ -106,8 +107,8 @@ nouveau_exec_job_submit(struct nouveau_job *job) drm_exec_until_all_locked(exec) { struct drm_gpuva *va; - drm_gpuva_for_each_va(va, &uvmm->umgr) { - if (unlikely(va == &uvmm->umgr.kernel_alloc_node)) + drm_gpuvm_for_each_va(va, &uvmm->base) { + if (unlikely(va == &uvmm->base.kernel_alloc_node)) continue; ret = drm_exec_prepare_obj(exec, va->gem.obj, 1); @@ -170,13 +171,17 @@ nouveau_exec_job_run(struct nouveau_job *job) nv50_dma_push(chan, p->va, p->va_len, no_prefetch); } - ret = nouveau_fence_emit(fence, chan); + ret = nouveau_fence_emit(fence); if (ret) { + nouveau_fence_unref(&exec_job->fence); NV_PRINTK(err, job->cli, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); return ERR_PTR(ret); } + /* The fence was emitted successfully, set the job's fence pointer to + * NULL in order to avoid freeing it up when the job is cleaned up. + */ exec_job->fence = NULL; return &fence->base; @@ -189,7 +194,7 @@ nouveau_exec_job_free(struct nouveau_job *job) nouveau_job_free(job); - nouveau_fence_unref(&exec_job->fence); + kfree(exec_job->fence); kfree(exec_job->push.s); kfree(exec_job); } diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 77c739a55b19..61d9e70da9fd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -205,16 +205,13 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha } int -nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) +nouveau_fence_emit(struct nouveau_fence *fence) { + struct nouveau_channel *chan = fence->channel; struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_fence_priv *priv = (void*)chan->drm->fence; int ret; - if (unlikely(!chan->fence)) - return -ENODEV; - - fence->channel = chan; fence->timeout = jiffies + (15 * HZ); if (priv->uevent) @@ -406,18 +403,41 @@ nouveau_fence_unref(struct nouveau_fence **pfence) } int -nouveau_fence_new(struct nouveau_fence **pfence) +nouveau_fence_create(struct nouveau_fence **pfence, + struct nouveau_channel *chan) { struct nouveau_fence *fence; + if (unlikely(!chan->fence)) + return -ENODEV; + fence = kzalloc(sizeof(*fence), GFP_KERNEL); if (!fence) return -ENOMEM; + fence->channel = chan; + *pfence = fence; return 0; } +int +nouveau_fence_new(struct nouveau_fence **pfence, + struct nouveau_channel *chan) +{ + int ret = 0; + + ret = nouveau_fence_create(pfence, chan); + if (ret) + return ret; + + ret = nouveau_fence_emit(*pfence); + if (ret) + nouveau_fence_unref(pfence); + + return ret; +} + static const char *nouveau_fence_get_get_driver_name(struct dma_fence *fence) { return "nouveau"; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 2c72d96ef17d..64d33ae7f356 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -17,10 +17,11 @@ struct nouveau_fence { unsigned long timeout; }; -int nouveau_fence_new(struct nouveau_fence **); +int nouveau_fence_create(struct nouveau_fence **, struct nouveau_channel *); +int nouveau_fence_new(struct nouveau_fence **, struct nouveau_channel *); void nouveau_fence_unref(struct nouveau_fence **); -int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *); +int nouveau_fence_emit(struct nouveau_fence *); bool nouveau_fence_done(struct nouveau_fence *); int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr); int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index c0b10d8d3d03..a0d303e5ce3d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -914,11 +914,8 @@ revalidate: } } - ret = nouveau_fence_new(&fence); - if (!ret) - ret = nouveau_fence_emit(fence, chan); + ret = nouveau_fence_new(&fence, chan); if (ret) { - nouveau_fence_unref(&fence); NV_PRINTK(err, cli, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); goto out; diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index aae780e4a4aa..5cf892c50f43 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -329,7 +329,7 @@ nouveau_uvma_region_create(struct nouveau_uvmm *uvmm, struct nouveau_uvma_region *reg; int ret; - if (!drm_gpuva_interval_empty(&uvmm->umgr, addr, range)) + if (!drm_gpuvm_interval_empty(&uvmm->base, addr, range)) return -ENOSPC; ret = nouveau_uvma_region_alloc(®); @@ -384,7 +384,7 @@ nouveau_uvma_region_empty(struct nouveau_uvma_region *reg) { struct nouveau_uvmm *uvmm = reg->uvmm; - return drm_gpuva_interval_empty(&uvmm->umgr, + return drm_gpuvm_interval_empty(&uvmm->base, reg->va.addr, reg->va.range); } @@ -444,7 +444,7 @@ op_map_prepare_unwind(struct nouveau_uvma *uvma) static void op_unmap_prepare_unwind(struct drm_gpuva *va) { - drm_gpuva_insert(va->mgr, va); + drm_gpuva_insert(va->vm, va); } static void @@ -589,7 +589,7 @@ op_map_prepare(struct nouveau_uvmm *uvmm, uvma->region = args->region; uvma->kind = args->kind; - drm_gpuva_map(&uvmm->umgr, &uvma->va, op); + drm_gpuva_map(&uvmm->base, &uvma->va, op); /* Keep a reference until this uvma is destroyed. */ nouveau_uvma_gem_get(uvma); @@ -1194,7 +1194,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) goto unwind_continue; } - op->ops = drm_gpuva_sm_unmap_ops_create(&uvmm->umgr, + op->ops = drm_gpuvm_sm_unmap_ops_create(&uvmm->base, op->va.addr, op->va.range); if (IS_ERR(op->ops)) { @@ -1205,7 +1205,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) ret = nouveau_uvmm_sm_unmap_prepare(uvmm, &op->new, op->ops); if (ret) { - drm_gpuva_ops_free(&uvmm->umgr, op->ops); + drm_gpuva_ops_free(&uvmm->base, op->ops); op->ops = NULL; op->reg = NULL; goto unwind_continue; @@ -1240,7 +1240,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) } } - op->ops = drm_gpuva_sm_map_ops_create(&uvmm->umgr, + op->ops = drm_gpuvm_sm_map_ops_create(&uvmm->base, op->va.addr, op->va.range, op->gem.obj, @@ -1256,7 +1256,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) op->va.range, op->flags & 0xff); if (ret) { - drm_gpuva_ops_free(&uvmm->umgr, op->ops); + drm_gpuva_ops_free(&uvmm->base, op->ops); op->ops = NULL; goto unwind_continue; } @@ -1264,7 +1264,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) break; } case OP_UNMAP: - op->ops = drm_gpuva_sm_unmap_ops_create(&uvmm->umgr, + op->ops = drm_gpuvm_sm_unmap_ops_create(&uvmm->base, op->va.addr, op->va.range); if (IS_ERR(op->ops)) { @@ -1275,7 +1275,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) ret = nouveau_uvmm_sm_unmap_prepare(uvmm, &op->new, op->ops); if (ret) { - drm_gpuva_ops_free(&uvmm->umgr, op->ops); + drm_gpuva_ops_free(&uvmm->base, op->ops); op->ops = NULL; goto unwind_continue; } @@ -1404,7 +1404,7 @@ unwind: break; } - drm_gpuva_ops_free(&uvmm->umgr, op->ops); + drm_gpuva_ops_free(&uvmm->base, op->ops); op->ops = NULL; op->reg = NULL; } @@ -1509,7 +1509,7 @@ nouveau_uvmm_bind_job_free_work_fn(struct work_struct *work) } if (!IS_ERR_OR_NULL(op->ops)) - drm_gpuva_ops_free(&uvmm->umgr, op->ops); + drm_gpuva_ops_free(&uvmm->base, op->ops); if (obj) drm_gem_object_put(obj); @@ -1836,11 +1836,11 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, uvmm->kernel_managed_addr = kernel_managed_addr; uvmm->kernel_managed_size = kernel_managed_size; - drm_gpuva_manager_init(&uvmm->umgr, cli->name, - NOUVEAU_VA_SPACE_START, - NOUVEAU_VA_SPACE_END, - kernel_managed_addr, kernel_managed_size, - NULL); + drm_gpuvm_init(&uvmm->base, cli->name, + NOUVEAU_VA_SPACE_START, + NOUVEAU_VA_SPACE_END, + kernel_managed_addr, kernel_managed_size, + NULL); ret = nvif_vmm_ctor(&cli->mmu, "uvmm", cli->vmm.vmm.object.oclass, RAW, @@ -1855,7 +1855,7 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, return 0; out_free_gpuva_mgr: - drm_gpuva_manager_destroy(&uvmm->umgr); + drm_gpuvm_destroy(&uvmm->base); out_unlock: mutex_unlock(&cli->mutex); return ret; @@ -1877,11 +1877,11 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) wait_event(entity->job.wq, list_empty(&entity->job.list.head)); nouveau_uvmm_lock(uvmm); - drm_gpuva_for_each_va_safe(va, next, &uvmm->umgr) { + drm_gpuvm_for_each_va_safe(va, next, &uvmm->base) { struct nouveau_uvma *uvma = uvma_from_va(va); struct drm_gem_object *obj = va->gem.obj; - if (unlikely(va == &uvmm->umgr.kernel_alloc_node)) + if (unlikely(va == &uvmm->base.kernel_alloc_node)) continue; drm_gpuva_remove(va); @@ -1910,7 +1910,7 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) mutex_lock(&cli->mutex); nouveau_vmm_fini(&uvmm->vmm); - drm_gpuva_manager_destroy(&uvmm->umgr); + drm_gpuvm_destroy(&uvmm->base); mutex_unlock(&cli->mutex); dma_resv_fini(&uvmm->resv); diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.h b/drivers/gpu/drm/nouveau/nouveau_uvmm.h index fc7f6fd2a4e1..a308c59760a5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.h +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.h @@ -3,13 +3,13 @@ #ifndef __NOUVEAU_UVMM_H__ #define __NOUVEAU_UVMM_H__ -#include <drm/drm_gpuva_mgr.h> +#include <drm/drm_gpuvm.h> #include "nouveau_drv.h" struct nouveau_uvmm { + struct drm_gpuvm base; struct nouveau_vmm vmm; - struct drm_gpuva_manager umgr; struct maple_tree region_mt; struct mutex mutex; struct dma_resv resv; @@ -41,10 +41,10 @@ struct nouveau_uvma { u8 kind; }; -#define uvmm_from_mgr(x) container_of((x), struct nouveau_uvmm, umgr) +#define uvmm_from_gpuvm(x) container_of((x), struct nouveau_uvmm, base) #define uvma_from_va(x) container_of((x), struct nouveau_uvma, va) -#define to_uvmm(x) uvmm_from_mgr((x)->va.mgr) +#define to_uvmm(x) uvmm_from_gpuvm((x)->va.vm) struct nouveau_uvmm_bind_job { struct nouveau_job base; diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c index a3264a0e933a..3a27245f467f 100644 --- a/drivers/gpu/drm/nouveau/nvif/client.c +++ b/drivers/gpu/drm/nouveau/nvif/client.c @@ -69,7 +69,7 @@ nvif_client_ctor(struct nvif_client *parent, const char *name, u64 device, } nop = {}; int ret; - strncpy(args.name, name, sizeof(args.name)); + strscpy_pad(args.name, name, sizeof(args.name)); ret = nvif_object_ctor(parent != client ? &parent->object : NULL, name ? name : "nvifClient", 0, NVIF_CLASS_CLIENT, &args, sizeof(args), diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c index a3cf91aeae2d..9ee18cb99264 100644 --- a/drivers/gpu/drm/nouveau/nvif/conn.c +++ b/drivers/gpu/drm/nouveau/nvif/conn.c @@ -45,20 +45,6 @@ nvif_conn_event_ctor(struct nvif_conn *conn, const char *name, nvif_event_func f return ret; } -int -nvif_conn_hpd_status(struct nvif_conn *conn) -{ - struct nvif_conn_hpd_status_v0 args; - int ret; - - args.version = 0; - - ret = nvif_mthd(&conn->object, NVIF_CONN_V0_HPD_STATUS, &args, sizeof(args)); - NVIF_ERRON(ret, &conn->object, "[HPD_STATUS] support:%d present:%d", - args.support, args.present); - return ret ? ret : !!args.support + !!args.present; -} - void nvif_conn_dtor(struct nvif_conn *conn) { @@ -77,5 +63,25 @@ nvif_conn_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_con ret = nvif_object_ctor(&disp->object, name ?: "nvifConn", id, NVIF_CLASS_CONN, &args, sizeof(args), &conn->object); NVIF_ERRON(ret, &disp->object, "[NEW conn id:%d]", id); - return ret; + if (ret) + return ret; + + conn->id = id; + + switch (args.type) { + case NVIF_CONN_V0_VGA : conn->info.type = NVIF_CONN_VGA; break; + case NVIF_CONN_V0_TV : conn->info.type = NVIF_CONN_TV; break; + case NVIF_CONN_V0_DVI_I : conn->info.type = NVIF_CONN_DVI_I; break; + case NVIF_CONN_V0_DVI_D : conn->info.type = NVIF_CONN_DVI_D; break; + case NVIF_CONN_V0_LVDS : conn->info.type = NVIF_CONN_LVDS; break; + case NVIF_CONN_V0_LVDS_SPWG: conn->info.type = NVIF_CONN_LVDS_SPWG; break; + case NVIF_CONN_V0_HDMI : conn->info.type = NVIF_CONN_HDMI; break; + case NVIF_CONN_V0_DP : conn->info.type = NVIF_CONN_DP; break; + case NVIF_CONN_V0_EDP : conn->info.type = NVIF_CONN_EDP; break; + default: + break; + } + + return 0; + } diff --git a/drivers/gpu/drm/nouveau/nvif/disp.c b/drivers/gpu/drm/nouveau/nvif/disp.c index 09915f2715af..097246e10cdb 100644 --- a/drivers/gpu/drm/nouveau/nvif/disp.c +++ b/drivers/gpu/drm/nouveau/nvif/disp.c @@ -60,7 +60,7 @@ nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct cid = nvif_sclass(&device->object, disps, oclass); disp->object.client = NULL; if (cid < 0) { - NVIF_ERRON(cid, &device->object, "[NEW disp%04x] not supported", oclass); + NVIF_DEBUG(&device->object, "[NEW disp%04x] not supported", oclass); return cid; } diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index c24bc5eae3ec..5d3190c05250 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -47,10 +47,134 @@ nvif_outp_dp_mst_vcpi(struct nvif_outp *outp, int head, } int -nvif_outp_dp_retrain(struct nvif_outp *outp) +nvif_outp_dp_mst_id_put(struct nvif_outp *outp, u32 id) { - int ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_RETRAIN, NULL, 0); - NVIF_ERRON(ret, &outp->object, "[DP_RETRAIN]"); + struct nvif_outp_dp_mst_id_get_v0 args; + int ret; + + args.version = 0; + args.id = id; + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_ID_PUT, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_MST_ID_PUT id:%08x]", args.id); + return ret; +} + +int +nvif_outp_dp_mst_id_get(struct nvif_outp *outp, u32 *id) +{ + struct nvif_outp_dp_mst_id_get_v0 args; + int ret; + + args.version = 0; + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_MST_ID_GET, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_MST_ID_GET] id:%08x", args.id); + if (ret) + return ret; + + *id = args.id; + return 0; +} + +int +nvif_outp_dp_sst(struct nvif_outp *outp, int head, u32 watermark, u32 hblanksym, u32 vblanksym) +{ + struct nvif_outp_dp_sst_v0 args; + int ret; + + args.version = 0; + args.head = head; + args.watermark = watermark; + args.hblanksym = hblanksym; + args.vblanksym = vblanksym; + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_SST, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, + "[DP_SST head:%d watermark:%d hblanksym:%d vblanksym:%d]", + args.head, args.watermark, args.hblanksym, args.vblanksym); + return ret; +} + +int +nvif_outp_dp_drive(struct nvif_outp *outp, u8 link_nr, u8 pe[4], u8 vs[4]) +{ + struct nvif_outp_dp_drive_v0 args; + int ret; + + args.version = 0; + args.lanes = link_nr; + memcpy(args.pe, pe, sizeof(args.pe)); + memcpy(args.vs, vs, sizeof(args.vs)); + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_DRIVE, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_DRIVE lanes:%d]", args.lanes); + return ret; +} + +int +nvif_outp_dp_train(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], u8 lttprs, + u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj, bool retrain) +{ + struct nvif_outp_dp_train_v0 args; + int ret; + + args.version = 0; + args.retrain = retrain; + args.mst = mst; + args.lttprs = lttprs; + args.post_lt_adj = post_lt_adj; + args.link_nr = link_nr; + args.link_bw = link_bw; + memcpy(args.dpcd, dpcd, sizeof(args.dpcd)); + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_TRAIN, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, + "[DP_TRAIN retrain:%d mst:%d lttprs:%d post_lt_adj:%d nr:%d bw:%d]", + args.retrain, args.mst, args.lttprs, args.post_lt_adj, args.link_nr, + args.link_bw); + return ret; +} + +int +nvif_outp_dp_rates(struct nvif_outp *outp, struct nvif_outp_dp_rate *rate, int rate_nr) +{ + struct nvif_outp_dp_rates_v0 args; + int ret; + + if (rate_nr > ARRAY_SIZE(args.rate)) + return -EINVAL; + + args.version = 0; + args.rates = rate_nr; + for (int i = 0; i < args.rates; i++, rate++) { + args.rate[i].dpcd = rate->dpcd; + args.rate[i].rate = rate->rate; + } + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_RATES, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DP_RATES rates:%d]", args.rates); + return ret; +} + +int +nvif_outp_dp_aux_xfer(struct nvif_outp *outp, u8 type, u8 *psize, u32 addr, u8 *data) +{ + struct nvif_outp_dp_aux_xfer_v0 args; + u8 size = *psize; + int ret; + + args.version = 0; + args.type = type; + args.size = size; + args.addr = addr; + memcpy(args.data, data, size); + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_DP_AUX_XFER, &args, sizeof(args)); + NVIF_DEBUG(&outp->object, "[DP_AUX_XFER type:%d size:%d addr:%05x] %d size:%d (ret: %d)", + args.type, size, args.addr, ret, args.size, ret); + if (ret < 0) + return ret; + + *psize = args.size; + + memcpy(data, args.data, size); return ret; } @@ -101,6 +225,74 @@ nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_ return ret; } +int +nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, u8 rekey, + u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates) +{ + struct nvif_outp_hdmi_v0 args; + int ret; + + args.version = 0; + args.head = head; + args.enable = enable; + args.max_ac_packet = max_ac_packet; + args.rekey = rekey; + args.khz = khz; + args.scdc = scdc; + args.scdc_scrambling = scdc_scrambling; + args.scdc_low_rates = scdc_low_rates; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDMI, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, + "[HDMI head:%d enable:%d max_ac_packet:%d rekey:%d khz:%d scdc:%d " + "scdc_scrambling:%d scdc_low_rates:%d]", + args.head, args.enable, args.max_ac_packet, args.rekey, args.khz, + args.scdc, args.scdc_scrambling, args.scdc_low_rates); + return ret; +} + +int +nvif_outp_lvds(struct nvif_outp *outp, bool dual, bool bpc8) +{ + struct nvif_outp_lvds_v0 args; + int ret; + + args.version = 0; + args.dual = dual; + args.bpc8 = bpc8; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_LVDS, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[LVDS dual:%d 8bpc:%d]", args.dual, args.bpc8); + return ret; +} + +int +nvif_outp_bl_set(struct nvif_outp *outp, int level) +{ + struct nvif_outp_bl_set_v0 args; + int ret; + + args.version = 0; + args.level = level; + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_BL_SET, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[BL_SET level:%d]", args.level); + return ret; +} + +int +nvif_outp_bl_get(struct nvif_outp *outp) +{ + struct nvif_outp_bl_get_v0 args; + int ret; + + args.version = 0; + + ret = nvif_object_mthd(&outp->object, NVIF_OUTP_V0_BL_GET, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[BL_GET level:%d]", args.level); + return ret ? ret : args.level; +} + void nvif_outp_release(struct nvif_outp *outp) { @@ -110,12 +302,12 @@ nvif_outp_release(struct nvif_outp *outp) } static inline int -nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0 *args) +nvif_outp_acquire(struct nvif_outp *outp, u8 type, struct nvif_outp_acquire_v0 *args) { int ret; args->version = 0; - args->proto = proto; + args->type = type; ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_ACQUIRE, args, sizeof(*args)); if (ret) @@ -127,73 +319,106 @@ nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0 } int -nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], - int link_nr, int link_bw, bool hda, bool mst) +nvif_outp_acquire_pior(struct nvif_outp *outp) { struct nvif_outp_acquire_v0 args; int ret; - args.dp.link_nr = link_nr; - args.dp.link_bw = link_bw; - args.dp.hda = hda; - args.dp.mst = mst; - memcpy(args.dp.dpcd, dpcd, sizeof(args.dp.dpcd)); - - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DP, &args); - NVIF_ERRON(ret, &outp->object, - "[ACQUIRE proto:DP link_nr:%d link_bw:%02x hda:%d mst:%d] or:%d link:%d", - args.dp.link_nr, args.dp.link_bw, args.dp.hda, args.dp.mst, args.or, args.link); + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_PIOR, &args); + NVIF_ERRON(ret, &outp->object, "[ACQUIRE PIOR] or:%d", args.or); return ret; } int -nvif_outp_acquire_lvds(struct nvif_outp *outp, bool dual, bool bpc8) +nvif_outp_acquire_sor(struct nvif_outp *outp, bool hda) { struct nvif_outp_acquire_v0 args; int ret; - args.lvds.dual = dual; - args.lvds.bpc8 = bpc8; + args.sor.hda = hda; - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_LVDS, &args); - NVIF_ERRON(ret, &outp->object, - "[ACQUIRE proto:LVDS dual:%d 8bpc:%d] or:%d link:%d", - args.lvds.dual, args.lvds.bpc8, args.or, args.link); + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_SOR, &args); + NVIF_ERRON(ret, &outp->object, "[ACQUIRE SOR] or:%d link:%d", args.or, args.link); return ret; } int -nvif_outp_acquire_tmds(struct nvif_outp *outp, int head, - bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda) +nvif_outp_acquire_dac(struct nvif_outp *outp) { struct nvif_outp_acquire_v0 args; int ret; - args.tmds.head = head; - args.tmds.hdmi = hdmi; - args.tmds.hdmi_max_ac_packet = max_ac_packet; - args.tmds.hdmi_rekey = rekey; - args.tmds.hdmi_scdc = scdc; - args.tmds.hdmi_hda = hda; - - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_TMDS, &args); - NVIF_ERRON(ret, &outp->object, - "[ACQUIRE proto:TMDS head:%d hdmi:%d max_ac_packet:%d rekey:%d scdc:%d hda:%d]" - " or:%d link:%d", args.tmds.head, args.tmds.hdmi, args.tmds.hdmi_max_ac_packet, - args.tmds.hdmi_rekey, args.tmds.hdmi_scdc, args.tmds.hdmi_hda, - args.or, args.link); + ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_DAC, &args); + NVIF_ERRON(ret, &outp->object, "[ACQUIRE DAC] or:%d", args.or); return ret; } +static int +nvif_outp_inherit(struct nvif_outp *outp, + u8 proto, + struct nvif_outp_inherit_v0 *args, + u8 *proto_out) +{ + int ret; + + args->version = 0; + args->proto = proto; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_INHERIT, args, sizeof(*args)); + if (ret) + return ret; + + outp->or.id = args->or; + outp->or.link = args->link; + *proto_out = args->proto; + return 0; +} + int -nvif_outp_acquire_rgb_crt(struct nvif_outp *outp) +nvif_outp_inherit_lvds(struct nvif_outp *outp, u8 *proto_out) { - struct nvif_outp_acquire_v0 args; + struct nvif_outp_inherit_v0 args; int ret; - ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_RGB_CRT, &args); - NVIF_ERRON(ret, &outp->object, "[ACQUIRE proto:RGB_CRT] or:%d", args.or); - return ret; + ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_LVDS, &args, proto_out); + NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:LVDS] ret:%d", ret); + return ret ?: args.head; +} + +int +nvif_outp_inherit_tmds(struct nvif_outp *outp, u8 *proto_out) +{ + struct nvif_outp_inherit_v0 args; + int ret; + + ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_TMDS, &args, proto_out); + NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:TMDS] ret:%d", ret); + return ret ?: args.head; +} + +int +nvif_outp_inherit_dp(struct nvif_outp *outp, u8 *proto_out) +{ + struct nvif_outp_inherit_v0 args; + int ret; + + ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_DP, &args, proto_out); + NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:DP] ret:%d", ret); + + // TODO: Get current link info + + return ret ?: args.head; +} + +int +nvif_outp_inherit_rgb_crt(struct nvif_outp *outp, u8 *proto_out) +{ + struct nvif_outp_inherit_v0 args; + int ret; + + ret = nvif_outp_inherit(outp, NVIF_OUTP_INHERIT_V0_RGB_CRT, &args, proto_out); + NVIF_ERRON(ret && ret != -ENODEV, &outp->object, "[INHERIT proto:RGB_CRT] ret:%d", ret); + return ret ?: args.head; } int @@ -210,6 +435,61 @@ nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval) return ret < 0 ? ret : args.load; } +int +nvif_outp_edid_get(struct nvif_outp *outp, u8 **pedid) +{ + struct nvif_outp_edid_get_v0 *args; + int ret; + + args = kmalloc(sizeof(*args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + args->version = 0; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_EDID_GET, args, sizeof(*args)); + NVIF_ERRON(ret, &outp->object, "[EDID_GET] size:%d", args->size); + if (ret) + goto done; + + *pedid = kmalloc(args->size, GFP_KERNEL); + if (!*pedid) { + ret = -ENOMEM; + goto done; + } + + memcpy(*pedid, args->data, args->size); + ret = args->size; +done: + kfree(args); + return ret; +} + +enum nvif_outp_detect_status +nvif_outp_detect(struct nvif_outp *outp) +{ + struct nvif_outp_detect_v0 args; + int ret; + + args.version = 0; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_DETECT, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[DETECT] status:%02x", args.status); + if (ret) + return UNKNOWN; + + switch (args.status) { + case NVIF_OUTP_DETECT_V0_NOT_PRESENT: return NOT_PRESENT; + case NVIF_OUTP_DETECT_V0_PRESENT: return PRESENT; + case NVIF_OUTP_DETECT_V0_UNKNOWN: return UNKNOWN; + default: + WARN_ON(1); + break; + } + + return UNKNOWN; +} + void nvif_outp_dtor(struct nvif_outp *outp) { @@ -231,6 +511,50 @@ nvif_outp_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_out if (ret) return ret; + outp->id = args.id; + + switch (args.type) { + case NVIF_OUTP_V0_TYPE_DAC : outp->info.type = NVIF_OUTP_DAC; break; + case NVIF_OUTP_V0_TYPE_SOR : outp->info.type = NVIF_OUTP_SOR; break; + case NVIF_OUTP_V0_TYPE_PIOR: outp->info.type = NVIF_OUTP_PIOR; break; + break; + default: + WARN_ON(1); + nvif_outp_dtor(outp); + return -EINVAL; + } + + switch (args.proto) { + case NVIF_OUTP_V0_PROTO_RGB_CRT: + outp->info.proto = NVIF_OUTP_RGB_CRT; + outp->info.rgb_crt.freq_max = args.rgb_crt.freq_max; + break; + case NVIF_OUTP_V0_PROTO_TMDS: + outp->info.proto = NVIF_OUTP_TMDS; + outp->info.tmds.dual = args.tmds.dual; + break; + case NVIF_OUTP_V0_PROTO_LVDS: + outp->info.proto = NVIF_OUTP_LVDS; + outp->info.lvds.acpi_edid = args.lvds.acpi_edid; + break; + case NVIF_OUTP_V0_PROTO_DP: + outp->info.proto = NVIF_OUTP_DP; + outp->info.dp.aux = args.dp.aux; + outp->info.dp.mst = args.dp.mst; + outp->info.dp.increased_wm = args.dp.increased_wm; + outp->info.dp.link_nr = args.dp.link_nr; + outp->info.dp.link_bw = args.dp.link_bw; + break; + default: + WARN_ON(1); + nvif_outp_dtor(outp); + return -EINVAL; + } + + outp->info.heads = args.heads; + outp->info.ddc = args.ddc; + outp->info.conn = args.conn; + outp->or.id = -1; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c index 91fb494d4009..374212da9e95 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c @@ -79,8 +79,7 @@ nvkm_firmware_get(const struct nvkm_subdev *subdev, const char *fwname, int ver, int i; /* Convert device name to lowercase */ - strncpy(cname, device->chip->name, sizeof(cname)); - cname[sizeof(cname) - 1] = '\0'; + strscpy(cname, device->chip->name, sizeof(cname)); i = strlen(cname); while (i) { --i; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/memory.c b/drivers/gpu/drm/nouveau/nvkm/core/memory.c index c69daac9bac7..a705c2dfca80 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/memory.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/memory.c @@ -140,12 +140,23 @@ nvkm_memory_new(struct nvkm_device *device, enum nvkm_memory_target target, { struct nvkm_instmem *imem = device->imem; struct nvkm_memory *memory; + bool preserve = true; int ret; - if (unlikely(target != NVKM_MEM_TARGET_INST || !imem)) + if (unlikely(!imem)) return -ENOSYS; - ret = nvkm_instobj_new(imem, size, align, zero, &memory); + switch (target) { + case NVKM_MEM_TARGET_INST_SR_LOST: + preserve = false; + break; + case NVKM_MEM_TARGET_INST: + break; + default: + return -ENOSYS; + } + + ret = nvkm_instobj_new(imem, size, align, zero, preserve, &memory); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 73104b59f97f..39f7e7ce9f4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -23,15 +23,12 @@ */ #include "priv.h" #include "conn.h" -#include "dp.h" #include "head.h" #include "ior.h" #include "outp.h" #include <core/client.h> #include <core/ramht.h> -#include <subdev/bios.h> -#include <subdev/bios/dcb.h> #include <nvif/class.h> #include <nvif/cl0046.h> @@ -105,18 +102,14 @@ static int nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) { struct nvkm_disp *disp = nvkm_disp(engine); - struct nvkm_conn *conn; struct nvkm_outp *outp; if (disp->func->fini) disp->func->fini(disp); list_for_each_entry(outp, &disp->outps, head) { - nvkm_outp_fini(outp); - } - - list_for_each_entry(conn, &disp->conns, head) { - nvkm_conn_fini(conn); + if (outp->func->fini) + outp->func->fini(outp); } return 0; @@ -126,16 +119,12 @@ static int nvkm_disp_init(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); - struct nvkm_conn *conn; struct nvkm_outp *outp; struct nvkm_ior *ior; - list_for_each_entry(conn, &disp->conns, head) { - nvkm_conn_init(conn); - } - list_for_each_entry(outp, &disp->outps, head) { - nvkm_outp_init(outp); + if (outp->func->init) + outp->func->init(outp); } if (disp->func->init) { @@ -159,142 +148,15 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_subdev *subdev = &disp->engine.subdev; - struct nvkm_bios *bios = subdev->device->bios; - struct nvkm_outp *outp, *outt, *pair; - struct nvkm_conn *conn; struct nvkm_head *head; - struct nvkm_ior *ior; - struct nvbios_connE connE; - struct dcb_output dcbE; - u8 hpd = 0, ver, hdr; - u32 data; int ret, i; - /* Create output path objects for each VBIOS display path. */ - i = -1; - while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { - if (ver < 0x40) /* No support for chipsets prior to NV50. */ - break; - if (dcbE.type == DCB_OUTPUT_UNUSED) - continue; - if (dcbE.type == DCB_OUTPUT_EOL) - break; - outp = NULL; - - switch (dcbE.type) { - case DCB_OUTPUT_ANALOG: - case DCB_OUTPUT_TV: - case DCB_OUTPUT_TMDS: - case DCB_OUTPUT_LVDS: - ret = nvkm_outp_new(disp, i, &dcbE, &outp); - break; - case DCB_OUTPUT_DP: - ret = nvkm_dp_new(disp, i, &dcbE, &outp); - break; - case DCB_OUTPUT_WFD: - /* No support for WFD yet. */ - ret = -ENODEV; - continue; - default: - nvkm_warn(subdev, "dcb %d type %d unknown\n", - i, dcbE.type); - continue; - } - - if (ret) { - if (outp) { - if (ret != -ENODEV) - OUTP_ERR(outp, "ctor failed: %d", ret); - else - OUTP_DBG(outp, "not supported"); - nvkm_outp_del(&outp); - continue; - } - nvkm_error(subdev, "failed to create outp %d\n", i); - continue; - } - - list_add_tail(&outp->head, &disp->outps); - hpd = max(hpd, (u8)(dcbE.connector + 1)); - } - - /* Create connector objects based on available output paths. */ - list_for_each_entry_safe(outp, outt, &disp->outps, head) { - /* VBIOS data *should* give us the most useful information. */ - data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, - &connE); - - /* No bios connector data... */ - if (!data) { - /* Heuristic: anything with the same ccb index is - * considered to be on the same connector, any - * output path without an associated ccb entry will - * be put on its own connector. - */ - int ccb_index = outp->info.i2c_index; - if (ccb_index != 0xf) { - list_for_each_entry(pair, &disp->outps, head) { - if (pair->info.i2c_index == ccb_index) { - outp->conn = pair->conn; - break; - } - } - } - - /* Connector shared with another output path. */ - if (outp->conn) - continue; - - memset(&connE, 0x00, sizeof(connE)); - connE.type = DCB_CONNECTOR_NONE; - i = -1; - } else { - i = outp->info.connector; - } - - /* Check that we haven't already created this connector. */ - list_for_each_entry(conn, &disp->conns, head) { - if (conn->index == outp->info.connector) { - outp->conn = conn; - break; - } - } - - if (outp->conn) - continue; - - /* Apparently we need to create a new one! */ - ret = nvkm_conn_new(disp, i, &connE, &outp->conn); - if (ret) { - nvkm_error(subdev, "failed to create outp %d conn: %d\n", outp->index, ret); - nvkm_conn_del(&outp->conn); - list_del(&outp->head); - nvkm_outp_del(&outp); - continue; - } - - list_add_tail(&outp->conn->head, &disp->conns); - } - if (disp->func->oneinit) { ret = disp->func->oneinit(disp); if (ret) return ret; } - /* Enforce identity-mapped SOR assignment for panels, which have - * certain bits (ie. backlight controls) wired to a specific SOR. - */ - list_for_each_entry(outp, &disp->outps, head) { - if (outp->conn->info.type == DCB_CONNECTOR_LVDS || - outp->conn->info.type == DCB_CONNECTOR_eDP) { - ior = nvkm_ior_find(disp, SOR, ffs(outp->info.or) - 1); - if (!WARN_ON(!ior)) - ior->identity = true; - outp->identity = true; - } - } - i = 0; list_for_each_entry(head, &disp->heads, head) i = max(i, head->id + 1); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c index fbdae1137864..ff88a5a5253a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c @@ -30,16 +30,6 @@ #include <nvif/event.h> void -nvkm_conn_fini(struct nvkm_conn *conn) -{ -} - -void -nvkm_conn_init(struct nvkm_conn *conn) -{ -} - -void nvkm_conn_del(struct nvkm_conn **pconn) { struct nvkm_conn *conn = *pconn; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index a0600e72b0ec..01c3146c7066 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h @@ -19,8 +19,6 @@ struct nvkm_conn { int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *, struct nvkm_conn **); void nvkm_conn_del(struct nvkm_conn **); -void nvkm_conn_init(struct nvkm_conn *); -void nvkm_conn_fini(struct nvkm_conn *); #define CONN_MSG(c,l,f,a...) do { \ struct nvkm_conn *_conn = (c); \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index b8ac66b4a2c4..a109348bd63b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -41,6 +41,40 @@ */ #define AMPERE_IED_HACK(disp) ((disp)->engine.subdev.device->card_type >= GA100) +static int +nvkm_dp_mst_id_put(struct nvkm_outp *outp, u32 id) +{ + return 0; +} + +static int +nvkm_dp_mst_id_get(struct nvkm_outp *outp, u32 *pid) +{ + *pid = BIT(outp->index); + return 0; +} + +static int +nvkm_dp_aux_xfer(struct nvkm_outp *outp, u8 type, u32 addr, u8 *data, u8 *size) +{ + int ret = nvkm_i2c_aux_acquire(outp->dp.aux); + + if (ret) + return ret; + + ret = nvkm_i2c_aux_xfer(outp->dp.aux, false, type, addr, data, size); + nvkm_i2c_aux_release(outp->dp.aux); + return ret; +} + +static int +nvkm_dp_aux_pwr(struct nvkm_outp *outp, bool pu) +{ + outp->dp.enabled = pu; + nvkm_dp_enable(outp, outp->dp.enabled); + return 0; +} + struct lt_state { struct nvkm_outp *outp; @@ -282,31 +316,20 @@ nvkm_dp_train_link(struct nvkm_outp *outp, int rate) struct lt_state lt = { .outp = outp, .pc2 = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED, + .repeaters = outp->dp.lttprs, }; - u8 sink[2], data; + u8 sink[2]; int ret; OUTP_DBG(outp, "training %dx%02x", ior->dp.nr, ior->dp.bw); - /* Select LTTPR non-transparent mode if we have a valid configuration, - * use transparent mode otherwise. - */ - if (outp->dp.lttpr[0] >= 0x14) { - data = DPCD_LTTPR_MODE_TRANSPARENT; - nvkm_wraux(outp->dp.aux, DPCD_LTTPR_MODE, &data, sizeof(data)); - - if (outp->dp.lttprs) { - data = DPCD_LTTPR_MODE_NON_TRANSPARENT; - nvkm_wraux(outp->dp.aux, DPCD_LTTPR_MODE, &data, sizeof(data)); - lt.repeaters = outp->dp.lttprs; - } - } - /* Set desired link configuration on the sink. */ sink[0] = (outp->dp.rate[rate].dpcd < 0) ? ior->dp.bw : 0; sink[1] = ior->dp.nr; if (ior->dp.ef) sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; + if (outp->dp.lt.post_adj) + sink[1] |= 0x20; ret = nvkm_wraux(outp->dp.aux, DPCD_LC00_LINK_BW_SET, sink, 2); if (ret) @@ -447,71 +470,58 @@ nvkm_dp_train_init(struct nvkm_outp *outp) } static int -nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps) +nvkm_dp_drive(struct nvkm_outp *outp, u8 lanes, u8 pe[4], u8 vs[4]) +{ + struct lt_state lt = { + .outp = outp, + .stat[4] = (pe[0] << 2) | (vs[0] << 0) | + (pe[1] << 6) | (vs[1] << 4), + .stat[5] = (pe[2] << 2) | (vs[2] << 0) | + (pe[3] << 6) | (vs[3] << 4), + }; + + return nvkm_dp_train_drive(<, false); +} + +static int +nvkm_dp_train(struct nvkm_outp *outp, bool retrain) { struct nvkm_ior *ior = outp->ior; - int ret = -EINVAL, nr, rate; - u8 pwr; + int ret, rate; - /* Retraining link? Skip source configuration, it can mess up the active modeset. */ - if (atomic_read(&outp->dp.lt.done)) { - for (rate = 0; rate < outp->dp.rates; rate++) { - if (outp->dp.rate[rate].rate == ior->dp.bw * 27000) - return nvkm_dp_train_link(outp, ret); - } - WARN_ON(1); - return -EINVAL; + for (rate = 0; rate < outp->dp.rates; rate++) { + if (outp->dp.rate[rate].rate == (retrain ? ior->dp.bw : outp->dp.lt.bw) * 27000) + break; } - /* Ensure sink is not in a low-power state. */ - if (!nvkm_rdaux(outp->dp.aux, DPCD_SC00, &pwr, 1)) { - if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { - pwr &= ~DPCD_SC00_SET_POWER; - pwr |= DPCD_SC00_SET_POWER_D0; - nvkm_wraux(outp->dp.aux, DPCD_SC00, &pwr, 1); - } + if (WARN_ON(rate == outp->dp.rates)) + return -EINVAL; + + /* Retraining link? Skip source configuration, it can mess up the active modeset. */ + if (retrain) { + mutex_lock(&outp->dp.mutex); + ret = nvkm_dp_train_link(outp, rate); + mutex_unlock(&outp->dp.mutex); + return ret; } + mutex_lock(&outp->dp.mutex); + OUTP_DBG(outp, "training"); + ior->dp.mst = outp->dp.lt.mst; ior->dp.ef = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; - ior->dp.nr = 0; + ior->dp.bw = outp->dp.lt.bw; + ior->dp.nr = outp->dp.lt.nr; - /* Link training. */ - OUTP_DBG(outp, "training"); nvkm_dp_train_init(outp); - - /* Validate and train at configuration requested (if any) on ACQUIRE. */ - if (outp->dp.lt.nr) { - for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) { - for (rate = 0; nr == outp->dp.lt.nr && rate < outp->dp.rates; rate++) { - if (outp->dp.rate[rate].rate / 27000 == outp->dp.lt.bw) { - ior->dp.bw = outp->dp.rate[rate].rate / 27000; - ior->dp.nr = nr; - ret = nvkm_dp_train_links(outp, rate); - } - } - } - } - - /* Otherwise, loop through all valid link configurations that support the data rate. */ - for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) { - for (rate = 0; ret < 0 && rate < outp->dp.rates; rate++) { - if (outp->dp.rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) { - /* Program selected link configuration. */ - ior->dp.bw = outp->dp.rate[rate].rate / 27000; - ior->dp.nr = nr; - ret = nvkm_dp_train_links(outp, rate); - } - } - } - - /* Finish up. */ + ret = nvkm_dp_train_links(outp, rate); nvkm_dp_train_fini(outp); if (ret < 0) OUTP_ERR(outp, "training failed"); else OUTP_DBG(outp, "training done"); - atomic_set(&outp->dp.lt.done, 1); + + mutex_unlock(&outp->dp.mutex); return ret; } @@ -529,155 +539,10 @@ nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior) static void nvkm_dp_release(struct nvkm_outp *outp) { - /* Prevent link from being retrained if sink sends an IRQ. */ - atomic_set(&outp->dp.lt.done, 0); outp->ior->dp.nr = 0; -} - -static int -nvkm_dp_acquire(struct nvkm_outp *outp) -{ - struct nvkm_ior *ior = outp->ior; - struct nvkm_head *head; - bool retrain = true; - u32 datakbps = 0; - u32 dataKBps; - u32 linkKBps; - u8 stat[3]; - int ret, i; - - mutex_lock(&outp->dp.mutex); - - /* Check that link configuration meets current requirements. */ - list_for_each_entry(head, &outp->disp->heads, head) { - if (ior->asy.head & (1 << head->id)) { - u32 khz = (head->asy.hz >> ior->asy.rgdiv) / 1000; - datakbps += khz * head->asy.or.depth; - } - } - - linkKBps = ior->dp.bw * 27000 * ior->dp.nr; - dataKBps = DIV_ROUND_UP(datakbps, 8); - OUTP_DBG(outp, "data %d KB/s link %d KB/s mst %d->%d", - dataKBps, linkKBps, ior->dp.mst, outp->dp.lt.mst); - if (linkKBps < dataKBps || ior->dp.mst != outp->dp.lt.mst) { - OUTP_DBG(outp, "link requirements changed"); - goto done; - } - - /* Check that link is still trained. */ - ret = nvkm_rdaux(outp->dp.aux, DPCD_LS02, stat, 3); - if (ret) { - OUTP_DBG(outp, "failed to read link status, assuming no sink"); - goto done; - } - - if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) { - for (i = 0; i < ior->dp.nr; i++) { - u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f; - if (!(lane & DPCD_LS02_LANE0_CR_DONE) || - !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || - !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { - OUTP_DBG(outp, "lane %d not equalised", lane); - goto done; - } - } - retrain = false; - } else { - OUTP_DBG(outp, "no inter-lane alignment"); - } - -done: - if (retrain || !atomic_read(&outp->dp.lt.done)) - ret = nvkm_dp_train(outp, dataKBps); - mutex_unlock(&outp->dp.mutex); - return ret; -} - -static bool -nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp) -{ - u8 sink_rates[DPCD_RC10_SUPPORTED_LINK_RATES__SIZE]; - int i, j, k; - - if (outp->conn->info.type != DCB_CONNECTOR_eDP || - outp->dp.dpcd[DPCD_RC00_DPCD_REV] < 0x13 || - nvkm_rdaux(outp->dp.aux, DPCD_RC10_SUPPORTED_LINK_RATES(0), - sink_rates, sizeof(sink_rates))) - return false; - - for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { - const u32 rate = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; - - if (!rate || WARN_ON(outp->dp.rates == ARRAY_SIZE(outp->dp.rate))) - break; - - if (rate > outp->info.dpconf.link_bw * 27000) { - OUTP_DBG(outp, "rate %d !outp", rate); - continue; - } - - for (j = 0; j < outp->dp.rates; j++) { - if (rate > outp->dp.rate[j].rate) { - for (k = outp->dp.rates; k > j; k--) - outp->dp.rate[k] = outp->dp.rate[k - 1]; - break; - } - } - - outp->dp.rate[j].dpcd = i / 2; - outp->dp.rate[j].rate = rate; - outp->dp.rates++; - } - - for (i = 0; i < outp->dp.rates; i++) - OUTP_DBG(outp, "link_rate[%d] = %d", outp->dp.rate[i].dpcd, outp->dp.rate[i].rate); + nvkm_dp_disable(outp, outp->ior); - return outp->dp.rates != 0; -} - -/* XXX: This is a big fat hack, and this is just drm_dp_read_dpcd_caps() - * converted to work inside nvkm. This is a temporary holdover until we start - * passing the drm_dp_aux device through NVKM - */ -static int -nvkm_dp_read_dpcd_caps(struct nvkm_outp *outp) -{ - struct nvkm_i2c_aux *aux = outp->dp.aux; - u8 dpcd_ext[DP_RECEIVER_CAP_SIZE]; - int ret; - - ret = nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, DP_RECEIVER_CAP_SIZE); - if (ret < 0) - return ret; - - /* - * Prior to DP1.3 the bit represented by - * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved. - * If it is set DP_DPCD_REV at 0000h could be at a value less than - * the true capability of the panel. The only way to check is to - * then compare 0000h and 2200h. - */ - if (!(outp->dp.dpcd[DP_TRAINING_AUX_RD_INTERVAL] & - DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT)) - return 0; - - ret = nvkm_rdaux(aux, DP_DP13_DPCD_REV, dpcd_ext, sizeof(dpcd_ext)); - if (ret < 0) - return ret; - - if (outp->dp.dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) { - OUTP_DBG(outp, "Extended DPCD rev less than base DPCD rev (%d > %d)\n", - outp->dp.dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]); - return 0; - } - - if (!memcmp(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext))) - return 0; - - memcpy(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext)); - - return 0; + nvkm_outp_release(outp); } void @@ -711,66 +576,11 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) OUTP_DBG(outp, "aux power -> always"); nvkm_i2c_aux_monitor(aux, true); outp->dp.aux_pwr = true; - - /* Detect any LTTPRs before reading DPCD receiver caps. */ - if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, outp->dp.lttpr, sizeof(outp->dp.lttpr)) && - outp->dp.lttpr[0] >= 0x14 && outp->dp.lttpr[2]) { - switch (outp->dp.lttpr[2]) { - case 0x80: outp->dp.lttprs = 1; break; - case 0x40: outp->dp.lttprs = 2; break; - case 0x20: outp->dp.lttprs = 3; break; - case 0x10: outp->dp.lttprs = 4; break; - case 0x08: outp->dp.lttprs = 5; break; - case 0x04: outp->dp.lttprs = 6; break; - case 0x02: outp->dp.lttprs = 7; break; - case 0x01: outp->dp.lttprs = 8; break; - default: - /* Unknown LTTPR count, we'll switch to transparent mode. */ - WARN_ON(1); - outp->dp.lttprs = 0; - break; - } - } else { - /* No LTTPR support, or zero LTTPR count - don't touch it at all. */ - memset(outp->dp.lttpr, 0x00, sizeof(outp->dp.lttpr)); - } - - if (!nvkm_dp_read_dpcd_caps(outp)) { - const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 }; - const u8 *rate; - int rate_max; - - outp->dp.rates = 0; - outp->dp.links = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; - outp->dp.links = min(outp->dp.links, outp->info.dpconf.link_nr); - if (outp->dp.lttprs && outp->dp.lttpr[4]) - outp->dp.links = min_t(int, outp->dp.links, outp->dp.lttpr[4]); - - rate_max = outp->dp.dpcd[DPCD_RC01_MAX_LINK_RATE]; - rate_max = min(rate_max, outp->info.dpconf.link_bw); - if (outp->dp.lttprs && outp->dp.lttpr[1]) - rate_max = min_t(int, rate_max, outp->dp.lttpr[1]); - - if (!nvkm_dp_enable_supported_link_rates(outp)) { - for (rate = rates; *rate; rate++) { - if (*rate > rate_max) - continue; - - if (WARN_ON(outp->dp.rates == ARRAY_SIZE(outp->dp.rate))) - break; - - outp->dp.rate[outp->dp.rates].dpcd = -1; - outp->dp.rate[outp->dp.rates].rate = *rate * 27000; - outp->dp.rates++; - } - } - } } else if (!auxpwr && outp->dp.aux_pwr) { OUTP_DBG(outp, "aux power -> demand"); nvkm_i2c_aux_monitor(aux, false); outp->dp.aux_pwr = false; - atomic_set(&outp->dp.lt.done, 0); /* Restore eDP panel GPIO to its prior state if we changed it, as * it could potentially interfere with other outputs. @@ -793,6 +603,7 @@ nvkm_dp_fini(struct nvkm_outp *outp) static void nvkm_dp_init(struct nvkm_outp *outp) { + nvkm_outp_init(outp); nvkm_dp_enable(outp, outp->dp.enabled); } @@ -807,9 +618,18 @@ nvkm_dp_func = { .dtor = nvkm_dp_dtor, .init = nvkm_dp_init, .fini = nvkm_dp_fini, - .acquire = nvkm_dp_acquire, + .detect = nvkm_outp_detect, + .inherit = nvkm_outp_inherit, + .acquire = nvkm_outp_acquire, .release = nvkm_dp_release, - .disable = nvkm_dp_disable, + .bl.get = nvkm_outp_bl_get, + .bl.set = nvkm_outp_bl_set, + .dp.aux_pwr = nvkm_dp_aux_pwr, + .dp.aux_xfer = nvkm_dp_aux_xfer, + .dp.train = nvkm_dp_train, + .dp.drive = nvkm_dp_drive, + .dp.mst_id_get = nvkm_dp_mst_id_get, + .dp.mst_id_put = nvkm_dp_mst_id_put, }; int @@ -819,7 +639,7 @@ nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct n struct nvkm_bios *bios = device->bios; struct nvkm_i2c *i2c = device->i2c; struct nvkm_outp *outp; - u8 hdr, cnt, len; + u8 ver, hdr, cnt, len; u32 data; int ret; @@ -847,7 +667,9 @@ nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct n OUTP_DBG(outp, "bios dp %02x %02x %02x %02x", outp->dp.version, hdr, cnt, len); + data = nvbios_dp_table(bios, &ver, &hdr, &cnt, &len); + outp->dp.mst = data && ver >= 0x40 && (nvbios_rd08(bios, data + 0x08) & 0x04); + mutex_init(&outp->dp.mutex); - atomic_set(&outp->dp.lt.done, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 23ae451ba473..1be97a68a83e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -124,6 +124,7 @@ g84_sor = { .state = nv50_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, + .bl = &nv50_sor_bl, .hdmi = &g84_sor_hdmi, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 67ef889a0c5f..843a2661ce9d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -295,6 +295,7 @@ g94_sor = { .clock = nv50_sor_clock, .war_2 = g94_sor_war_2, .war_3 = g94_sor_war_3, + .bl = &nv50_sor_bl, .hdmi = &g84_sor_hdmi, .dp = &g94_sor_dp, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c index 52099b75f52a..efe66ba3c61f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c @@ -105,6 +105,7 @@ ga102_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = ga102_sor_clock, + .bl = >215_sor_bl, .hdmi = &gv100_sor_hdmi, .dp = &ga102_sor_dp, .hda = &gv100_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index a48e9bdf4cd0..b48ead31da30 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -328,6 +328,7 @@ gf119_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gf119_sor_hdmi, .dp = &gf119_sor_dp, .hda = &gf119_sor_hda, @@ -1038,7 +1039,6 @@ gf119_disp_super(struct work_struct *work) continue; nv50_disp_super_2_0(disp, head); } - nvkm_outp_route(disp); list_for_each_entry(head, &disp->heads, head) { if (!(mask[head->id] & 0x00010000)) continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 876a21a0cebb..a3e2fbadade4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -115,6 +115,7 @@ gk104_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gk104_sor_hdmi, .dp = &gf119_sor_dp, .hda = &gf119_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index b4d8e868616f..688e123ad482 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -70,6 +70,7 @@ gm107_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gk104_sor_hdmi, .dp = &gm107_sor_dp, .hda = &gf119_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 562ebae57d44..511e7831b2f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -68,15 +68,23 @@ gm200_sor_dp = { }; void -gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u8 scdc) +gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u32 khz, bool support, bool scrambling, + bool scrambling_low_rates) { struct nvkm_device *device = ior->disp->engine.subdev.device; const u32 soff = nv50_ior_base(ior); - const u32 ctrl = scdc & 0x3; + u32 ctrl = 0; - nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl); + ior->tmds.high_speed = khz > 340000; + + if (support && scrambling) { + if (ior->tmds.high_speed) + ctrl |= 0x00000002; + if (ior->tmds.high_speed || scrambling_low_rates) + ctrl |= 0x00000001; + } - ior->tmds.high_speed = !!(scdc & 0x2); + nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl); } const struct nvkm_ior_func_hdmi @@ -139,6 +147,7 @@ gm200_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gm200_sor_hdmi, .dp = &gm200_sor_dp, .hda = &gf119_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index 7f1eb4332040..4070447bd800 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -37,6 +37,7 @@ gp100_sor = { .state = gf119_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gm200_sor_hdmi, .dp = &gm200_sor_dp, .hda = &gf119_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 506ffbe7b842..6318721b66f6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -182,11 +182,49 @@ gt215_sor_hdmi = { .infoframe_vsi = gt215_sor_hdmi_infoframe_vsi, }; +static int +gt215_sor_bl_set(struct nvkm_ior *ior, int lvl) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(ior); + u32 div, val; + + div = nvkm_rd32(device, 0x61c080 + soff); + val = (lvl * div) / 100; + if (div) + nvkm_wr32(device, 0x61c084 + soff, 0xc0000000 | val); + + return 0; +} + +static int +gt215_sor_bl_get(struct nvkm_ior *ior) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(ior); + u32 div, val; + + div = nvkm_rd32(device, 0x61c080 + soff); + val = nvkm_rd32(device, 0x61c084 + soff); + val &= 0x00ffffff; + if (div && div >= val) + return ((val * 100) + (div / 2)) / div; + + return 100; +} + +const struct nvkm_ior_func_bl +gt215_sor_bl = { + .get = gt215_sor_bl_get, + .set = gt215_sor_bl_set, +}; + static const struct nvkm_ior_func gt215_sor = { .state = g94_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, + .bl = >215_sor_bl, .hdmi = >215_sor_hdmi, .dp = >215_sor_dp, .hda = >215_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c index 4ebc030e40d1..e1634f7bca56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c @@ -212,6 +212,7 @@ gv100_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gv100_sor_hdmi, .dp = &gv100_sor_dp, .hda = &gv100_sor_hda, @@ -863,7 +864,6 @@ gv100_disp_super(struct work_struct *work) continue; nv50_disp_super_2_0(disp, head); } - nvkm_outp_route(disp); list_for_each_entry(head, &disp->heads, head) { if (!(mask[head->id] & 0x00010000)) continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index da1b1a626ef2..9beb9d1e8633 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -63,11 +63,18 @@ struct nvkm_ior_func { void (*war_2)(struct nvkm_ior *); void (*war_3)(struct nvkm_ior *); + const struct nvkm_ior_func_bl { + int (*get)(struct nvkm_ior *); + int (*set)(struct nvkm_ior *, int lvl); + } *bl; + const struct nvkm_ior_func_hdmi { void (*ctrl)(struct nvkm_ior *, int head, bool enable, u8 max_ac_packet, u8 rekey); - void (*scdc)(struct nvkm_ior *, u8 scdc); + void (*scdc)(struct nvkm_ior *, u32 khz, bool support, bool scrambling, + bool scrambling_low_rates); void (*infoframe_avi)(struct nvkm_ior *, int head, void *data, u32 size); void (*infoframe_vsi)(struct nvkm_ior *, int head, void *data, u32 size); + void (*audio)(struct nvkm_ior *, int head, bool enable); } *hdmi; const struct nvkm_ior_func_dp { @@ -77,6 +84,8 @@ struct nvkm_ior_func { void (*pattern)(struct nvkm_ior *, int pattern); void (*drive)(struct nvkm_ior *, int ln, int pc, int dc, int pe, int tx_pu); + int (*sst)(struct nvkm_ior *, int head, bool ef, + u32 watermark, u32 hblanksym, u32 vblanksym); void (*vcpi)(struct nvkm_ior *, int head, u8 slot, u8 slot_nr, u16 pbn, u16 aligned); void (*audio)(struct nvkm_ior *, int head, bool enable); @@ -122,6 +131,7 @@ int nv50_sor_cnt(struct nvkm_disp *, unsigned long *); void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); void nv50_sor_clock(struct nvkm_ior *); +extern const struct nvkm_ior_func_bl nv50_sor_bl; int g84_sor_new(struct nvkm_disp *, int); extern const struct nvkm_ior_func_hdmi g84_sor_hdmi; @@ -138,6 +148,7 @@ void g94_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32); void g94_sor_dp_activesym(struct nvkm_ior *, int, u8, u8, u8, u8); void g94_sor_dp_watermark(struct nvkm_ior *, int, u8); +extern const struct nvkm_ior_func_bl gt215_sor_bl; extern const struct nvkm_ior_func_hdmi gt215_sor_hdmi; void gt215_sor_dp_audio(struct nvkm_ior *, int, bool); extern const struct nvkm_ior_func_hda gt215_sor_hda; @@ -167,7 +178,7 @@ void gm107_sor_dp_pattern(struct nvkm_ior *, int); void gm200_sor_route_set(struct nvkm_outp *, struct nvkm_ior *); int gm200_sor_route_get(struct nvkm_outp *, int *); extern const struct nvkm_ior_func_hdmi gm200_sor_hdmi; -void gm200_sor_hdmi_scdc(struct nvkm_ior *, u8); +void gm200_sor_hdmi_scdc(struct nvkm_ior *, u32, bool, bool, bool); extern const struct nvkm_ior_func_dp gm200_sor_dp; void gm200_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c index f96ba4752655..e0c5fb6df3d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c @@ -44,6 +44,7 @@ mcp89_sor = { .state = g94_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, + .bl = >215_sor_bl, .hdmi = >215_sor_hdmi, .dp = &mcp89_sor_dp, .hda = >215_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index be8116802960..2d05e2f7e46b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -23,7 +23,9 @@ */ #include "priv.h" #include "chan.h" +#include "conn.h" #include "head.h" +#include "dp.h" #include "ior.h" #include "outp.h" @@ -156,6 +158,37 @@ nv50_pior_cnt(struct nvkm_disp *disp, unsigned long *pmask) return 3; } +static int +nv50_sor_bl_set(struct nvkm_ior *ior, int lvl) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(ior); + u32 div = 1025; + u32 val = (lvl * div) / 100; + + nvkm_wr32(device, 0x61c084 + soff, 0x80000000 | val); + return 0; +} + +static int +nv50_sor_bl_get(struct nvkm_ior *ior) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(ior); + u32 div = 1025; + u32 val; + + val = nvkm_rd32(device, 0x61c084 + soff); + val &= 0x000007ff; + return ((val * 100) + (div / 2)) / div; +} + +const struct nvkm_ior_func_bl +nv50_sor_bl = { + .get = nv50_sor_bl_get, + .set = nv50_sor_bl_set, +}; + void nv50_sor_clock(struct nvkm_ior *sor) { @@ -220,6 +253,7 @@ nv50_sor = { .state = nv50_sor_state, .power = nv50_sor_power, .clock = nv50_sor_clock, + .bl = &nv50_sor_bl, }; static int @@ -1254,10 +1288,6 @@ nv50_disp_super_2_2(struct nvkm_disp *disp, struct nvkm_head *head) ior->asy.link = outp->lvds.dual ? 3 : 1; } - /* Handle any link training, etc. */ - if (outp && outp->func->acquire) - outp->func->acquire(outp); - /* Execute OnInt2 IED script. */ nv50_disp_super_ied_on(head, ior, 0, khz); @@ -1287,7 +1317,6 @@ nv50_disp_super_2_1(struct nvkm_disp *disp, struct nvkm_head *head) void nv50_disp_super_2_0(struct nvkm_disp *disp, struct nvkm_head *head) { - struct nvkm_outp *outp; struct nvkm_ior *ior; /* Determine which OR, if any, we're detaching from the head. */ @@ -1298,14 +1327,6 @@ nv50_disp_super_2_0(struct nvkm_disp *disp, struct nvkm_head *head) /* Execute OffInt2 IED script. */ nv50_disp_super_ied_off(head, ior, 2); - - /* If we're shutting down the OR's only active head, execute - * the output path's disable function. - */ - if (ior->arm.head == (1 << head->id)) { - if ((outp = ior->arm.outp) && outp->func->disable) - outp->func->disable(outp, ior); - } } void @@ -1371,7 +1392,6 @@ nv50_disp_super(struct work_struct *work) continue; nv50_disp_super_2_0(disp, head); } - nvkm_outp_route(disp); list_for_each_entry(head, &disp->heads, head) { if (!(super & (0x00000200 << head->id))) continue; @@ -1563,7 +1583,15 @@ nv50_disp_oneinit(struct nvkm_disp *disp) const struct nvkm_disp_func *func = disp->func; struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvkm_outp *outp, *outt, *pair; + struct nvkm_conn *conn; + struct nvkm_ior *ior; int ret, i; + u8 ver, hdr; + u32 data; + struct dcb_output dcbE; + struct nvbios_connE connE; if (func->wndw.cnt) { disp->wndw.nr = func->wndw.cnt(disp, &disp->wndw.mask); @@ -1610,8 +1638,130 @@ nv50_disp_oneinit(struct nvkm_disp *disp) if (ret) return ret; - return nvkm_ramht_new(device, func->ramht_size ? func->ramht_size : - 0x1000, 0, disp->inst, &disp->ramht); + ret = nvkm_ramht_new(device, func->ramht_size ? func->ramht_size : 0x1000, 0, disp->inst, + &disp->ramht); + if (ret) + return ret; + + /* Create output path objects for each VBIOS display path. */ + i = -1; + while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { + if (WARN_ON((ver & 0xf0) != 0x40)) + return -EINVAL; + if (dcbE.type == DCB_OUTPUT_UNUSED) + continue; + if (dcbE.type == DCB_OUTPUT_EOL) + break; + outp = NULL; + + switch (dcbE.type) { + case DCB_OUTPUT_ANALOG: + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_LVDS: + ret = nvkm_outp_new(disp, i, &dcbE, &outp); + break; + case DCB_OUTPUT_DP: + ret = nvkm_dp_new(disp, i, &dcbE, &outp); + break; + case DCB_OUTPUT_TV: + case DCB_OUTPUT_WFD: + /* No support for WFD yet. */ + ret = -ENODEV; + continue; + default: + nvkm_warn(subdev, "dcb %d type %d unknown\n", + i, dcbE.type); + continue; + } + + if (ret) { + if (outp) { + if (ret != -ENODEV) + OUTP_ERR(outp, "ctor failed: %d", ret); + else + OUTP_DBG(outp, "not supported"); + nvkm_outp_del(&outp); + continue; + } + nvkm_error(subdev, "failed to create outp %d\n", i); + continue; + } + + list_add_tail(&outp->head, &disp->outps); + } + + /* Create connector objects based on available output paths. */ + list_for_each_entry_safe(outp, outt, &disp->outps, head) { + /* VBIOS data *should* give us the most useful information. */ + data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, + &connE); + + /* No bios connector data... */ + if (!data) { + /* Heuristic: anything with the same ccb index is + * considered to be on the same connector, any + * output path without an associated ccb entry will + * be put on its own connector. + */ + int ccb_index = outp->info.i2c_index; + if (ccb_index != 0xf) { + list_for_each_entry(pair, &disp->outps, head) { + if (pair->info.i2c_index == ccb_index) { + outp->conn = pair->conn; + break; + } + } + } + + /* Connector shared with another output path. */ + if (outp->conn) + continue; + + memset(&connE, 0x00, sizeof(connE)); + connE.type = DCB_CONNECTOR_NONE; + i = -1; + } else { + i = outp->info.connector; + } + + /* Check that we haven't already created this connector. */ + list_for_each_entry(conn, &disp->conns, head) { + if (conn->index == outp->info.connector) { + outp->conn = conn; + break; + } + } + + if (outp->conn) + continue; + + /* Apparently we need to create a new one! */ + ret = nvkm_conn_new(disp, i, &connE, &outp->conn); + if (ret) { + nvkm_error(subdev, "failed to create outp %d conn: %d\n", outp->index, ret); + nvkm_conn_del(&outp->conn); + list_del(&outp->head); + nvkm_outp_del(&outp); + continue; + } + + list_add_tail(&outp->conn->head, &disp->conns); + } + + /* Enforce identity-mapped SOR assignment for panels, which have + * certain bits (ie. backlight controls) wired to a specific SOR. + */ + list_for_each_entry(outp, &disp->outps, head) { + if (outp->conn->info.type == DCB_CONNECTOR_LVDS || + outp->conn->info.type == DCB_CONNECTOR_eDP) { + ior = nvkm_ior_find(disp, SOR, ffs(outp->info.or) - 1); + if (!WARN_ON(!ior)) + ior->identity = true; + outp->identity = true; + } + } + + return 0; } static const struct nvkm_disp_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 6094805fbd63..bfb2a4db8d64 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -22,14 +22,16 @@ * Authors: Ben Skeggs */ #include "outp.h" +#include "conn.h" #include "dp.h" #include "ior.h" #include <subdev/bios.h> #include <subdev/bios/dcb.h> +#include <subdev/gpio.h> #include <subdev/i2c.h> -void +static void nvkm_outp_route(struct nvkm_disp *disp) { struct nvkm_outp *outp; @@ -46,8 +48,8 @@ nvkm_outp_route(struct nvkm_disp *disp) list_for_each_entry(ior, &disp->iors, head) { if ((outp = ior->asy.outp)) { - OUTP_DBG(outp, "acquire %s", ior->name); if (ior->asy.outp != ior->arm.outp) { + OUTP_DBG(outp, "acquire %s", ior->name); if (ior->func->route.set) ior->func->route.set(outp, ior); ior->arm.outp = ior->asy.outp; @@ -87,22 +89,20 @@ nvkm_outp_xlat(struct nvkm_outp *outp, enum nvkm_ior_type *type) } void -nvkm_outp_release(struct nvkm_outp *outp, u8 user) +nvkm_outp_release_or(struct nvkm_outp *outp, u8 user) { struct nvkm_ior *ior = outp->ior; OUTP_TRACE(outp, "release %02x &= %02x %p", outp->acquired, ~user, ior); if (ior) { outp->acquired &= ~user; if (!outp->acquired) { - if (outp->func->release && outp->ior) - outp->func->release(outp); outp->ior->asy.outp = NULL; outp->ior = NULL; } } } -static inline int +int nvkm_outp_acquire_ior(struct nvkm_outp *outp, u8 user, struct nvkm_ior *ior) { outp->ior = ior; @@ -140,7 +140,7 @@ nvkm_outp_acquire_hda(struct nvkm_outp *outp, enum nvkm_ior_type type, } int -nvkm_outp_acquire(struct nvkm_outp *outp, u8 user, bool hda) +nvkm_outp_acquire_or(struct nvkm_outp *outp, u8 user, bool hda) { struct nvkm_ior *ior = outp->ior; enum nvkm_ior_proto proto; @@ -207,39 +207,110 @@ nvkm_outp_acquire(struct nvkm_outp *outp, u8 user, bool hda) return nvkm_outp_acquire_hda(outp, type, user, false); } +int +nvkm_outp_bl_set(struct nvkm_outp *outp, int level) +{ + int ret; + + ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_PRIV, false); + if (ret) + return ret; + + if (outp->ior->func->bl) + ret = outp->ior->func->bl->set(outp->ior, level); + else + ret = -EINVAL; + + nvkm_outp_release_or(outp, NVKM_OUTP_PRIV); + return ret; +} + +int +nvkm_outp_bl_get(struct nvkm_outp *outp) +{ + int ret; + + ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_PRIV, false); + if (ret) + return ret; + + if (outp->ior->func->bl) + ret = outp->ior->func->bl->get(outp->ior); + else + ret = -EINVAL; + + nvkm_outp_release_or(outp, NVKM_OUTP_PRIV); + return ret; +} + +int +nvkm_outp_detect(struct nvkm_outp *outp) +{ + struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio; + int ret = -EINVAL; + + if (outp->conn->info.hpd != DCB_GPIO_UNUSED) { + ret = nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, outp->conn->info.hpd); + if (ret < 0) + return ret; + if (ret) + return 1; + + /*TODO: Look into returning NOT_PRESENT if !HPD on DVI/HDMI. + * + * It's uncertain whether this is accurate for all older chipsets, + * so we're returning UNKNOWN, and the DRM will probe DDC instead. + */ + if (outp->info.type == DCB_OUTPUT_DP) + return 0; + } + + return ret; +} + void -nvkm_outp_fini(struct nvkm_outp *outp) +nvkm_outp_release(struct nvkm_outp *outp) { - if (outp->func->fini) - outp->func->fini(outp); + nvkm_outp_release_or(outp, NVKM_OUTP_USER); + nvkm_outp_route(outp->disp); } -static void -nvkm_outp_init_route(struct nvkm_outp *outp) +int +nvkm_outp_acquire(struct nvkm_outp *outp, bool hda) +{ + int ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, hda); + + if (ret) + return ret; + + nvkm_outp_route(outp->disp); + return 0; +} + +struct nvkm_ior * +nvkm_outp_inherit(struct nvkm_outp *outp) { struct nvkm_disp *disp = outp->disp; + struct nvkm_ior *ior; enum nvkm_ior_proto proto; enum nvkm_ior_type type; - struct nvkm_ior *ior; int id, link; /* Find any OR from the class that is able to support this device. */ proto = nvkm_outp_xlat(outp, &type); if (proto == UNKNOWN) - return; + return NULL; ior = nvkm_ior_find(disp, type, -1); - if (!ior) { - WARN_ON(1); - return; - } + if (WARN_ON(!ior)) + return NULL; /* Determine the specific OR, if any, this device is attached to. */ if (ior->func->route.get) { id = ior->func->route.get(outp, &link); if (id < 0) { OUTP_DBG(outp, "no route"); - return; + return NULL; } } else { /* Prior to DCB 4.1, this is hardwired like so. */ @@ -248,10 +319,24 @@ nvkm_outp_init_route(struct nvkm_outp *outp) } ior = nvkm_ior_find(disp, type, id); - if (!ior) { - WARN_ON(1); + if (WARN_ON(!ior)) + return NULL; + + return ior; +} + +void +nvkm_outp_init(struct nvkm_outp *outp) +{ + enum nvkm_ior_proto proto; + enum nvkm_ior_type type; + struct nvkm_ior *ior; + + /* Find any OR from the class that is able to support this device. */ + proto = nvkm_outp_xlat(outp, &type); + ior = outp->func->inherit(outp); + if (!ior) return; - } /* Determine if the OR is already configured for this device. */ ior->func->state(ior, &ior->arm); @@ -274,14 +359,6 @@ nvkm_outp_init_route(struct nvkm_outp *outp) } void -nvkm_outp_init(struct nvkm_outp *outp) -{ - nvkm_outp_init_route(outp); - if (outp->func->init) - outp->func->init(outp); -} - -void nvkm_outp_del(struct nvkm_outp **poutp) { struct nvkm_outp *outp = *poutp; @@ -328,6 +405,13 @@ nvkm_outp_new_(const struct nvkm_outp_func *func, struct nvkm_disp *disp, static const struct nvkm_outp_func nvkm_outp = { + .init = nvkm_outp_init, + .detect = nvkm_outp_detect, + .inherit = nvkm_outp_inherit, + .acquire = nvkm_outp_acquire, + .release = nvkm_outp_release, + .bl.get = nvkm_outp_bl_get, + .bl.set = nvkm_outp_bl_set, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 4e7f873f66e2..ebd2f499b4b1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -35,6 +35,8 @@ struct nvkm_outp { struct { struct nvbios_dpout info; u8 version; + bool mst; + bool increased_wm; struct nvkm_i2c_aux *aux; @@ -50,14 +52,13 @@ struct nvkm_outp { u32 rate; } rate[8]; int rates; - int links; struct mutex mutex; struct { - atomic_t done; u8 nr; u8 bw; bool mst; + bool post_adj; } lt; } dp; }; @@ -74,17 +75,45 @@ int nvkm_outp_new(struct nvkm_disp *, int index, struct dcb_output *, struct nvk void nvkm_outp_del(struct nvkm_outp **); void nvkm_outp_init(struct nvkm_outp *); void nvkm_outp_fini(struct nvkm_outp *); -int nvkm_outp_acquire(struct nvkm_outp *, u8 user, bool hda); -void nvkm_outp_release(struct nvkm_outp *, u8 user); -void nvkm_outp_route(struct nvkm_disp *); + +int nvkm_outp_detect(struct nvkm_outp *); + +struct nvkm_ior *nvkm_outp_inherit(struct nvkm_outp *); +int nvkm_outp_acquire(struct nvkm_outp *, bool hda); +int nvkm_outp_acquire_or(struct nvkm_outp *, u8 user, bool hda); +int nvkm_outp_acquire_ior(struct nvkm_outp *, u8 user, struct nvkm_ior *); +void nvkm_outp_release(struct nvkm_outp *); +void nvkm_outp_release_or(struct nvkm_outp *, u8 user); + +int nvkm_outp_bl_get(struct nvkm_outp *); +int nvkm_outp_bl_set(struct nvkm_outp *, int level); struct nvkm_outp_func { void *(*dtor)(struct nvkm_outp *); void (*init)(struct nvkm_outp *); void (*fini)(struct nvkm_outp *); - int (*acquire)(struct nvkm_outp *); + + int (*detect)(struct nvkm_outp *); + int (*edid_get)(struct nvkm_outp *, u8 *data, u16 *size); + + struct nvkm_ior *(*inherit)(struct nvkm_outp *); + int (*acquire)(struct nvkm_outp *, bool hda); void (*release)(struct nvkm_outp *); - void (*disable)(struct nvkm_outp *, struct nvkm_ior *); + + struct { + int (*get)(struct nvkm_outp *); + int (*set)(struct nvkm_outp *, int level); + } bl; + + struct { + int (*aux_pwr)(struct nvkm_outp *, bool pu); + int (*aux_xfer)(struct nvkm_outp *, u8 type, u32 addr, u8 *data, u8 *size); + int (*rates)(struct nvkm_outp *); + int (*train)(struct nvkm_outp *, bool retrain); + int (*drive)(struct nvkm_outp *, u8 lanes, u8 pe[4], u8 vs[4]); + int (*mst_id_get)(struct nvkm_outp *, u32 *id); + int (*mst_id_put)(struct nvkm_outp *, u32 id); + } dp; }; #define OUTP_MSG(o,l,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c index f5242a672279..19f5d3a6035e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c @@ -88,6 +88,7 @@ tu102_sor = { .state = gv100_sor_state, .power = nv50_sor_power, .clock = gf119_sor_clock, + .bl = >215_sor_bl, .hdmi = &gv100_sor_hdmi, .dp = &tu102_sor_dp, .hda = &gv100_sor_hda, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c index 46b057fe1412..ff82bb248492 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c @@ -109,46 +109,6 @@ nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_ nvkm_uconn_uevent_gpio); } -static int -nvkm_uconn_mthd_hpd_status(struct nvkm_conn *conn, void *argv, u32 argc) -{ - struct nvkm_gpio *gpio = conn->disp->engine.subdev.device->gpio; - union nvif_conn_hpd_status_args *args = argv; - - if (argc != sizeof(args->v0) || args->v0.version != 0) - return -ENOSYS; - - args->v0.support = gpio && conn->info.hpd != DCB_GPIO_UNUSED; - args->v0.present = 0; - - if (args->v0.support) { - int ret = nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, conn->info.hpd); - - if (WARN_ON(ret < 0)) { - args->v0.support = false; - return 0; - } - - args->v0.present = ret; - } - - return 0; -} - -static int -nvkm_uconn_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc) -{ - struct nvkm_conn *conn = nvkm_uconn(object); - - switch (mthd) { - case NVIF_CONN_V0_HPD_STATUS: return nvkm_uconn_mthd_hpd_status(conn, argv, argc); - default: - break; - } - - return -EINVAL; -} - static void * nvkm_uconn_dtor(struct nvkm_object *object) { @@ -164,7 +124,6 @@ nvkm_uconn_dtor(struct nvkm_object *object) static const struct nvkm_object_func nvkm_uconn = { .dtor = nvkm_uconn_dtor, - .mthd = nvkm_uconn_mthd, .uevent = nvkm_uconn_uevent, }; @@ -192,6 +151,32 @@ nvkm_uconn_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv ret = -EBUSY; spin_lock(&disp->client.lock); if (!conn->object.func) { + switch (conn->info.type) { + case DCB_CONNECTOR_VGA : args->v0.type = NVIF_CONN_V0_VGA; break; + case DCB_CONNECTOR_TV_0 : + case DCB_CONNECTOR_TV_1 : + case DCB_CONNECTOR_TV_3 : args->v0.type = NVIF_CONN_V0_TV; break; + case DCB_CONNECTOR_DMS59_0 : + case DCB_CONNECTOR_DMS59_1 : + case DCB_CONNECTOR_DVI_I : args->v0.type = NVIF_CONN_V0_DVI_I; break; + case DCB_CONNECTOR_DVI_D : args->v0.type = NVIF_CONN_V0_DVI_D; break; + case DCB_CONNECTOR_LVDS : args->v0.type = NVIF_CONN_V0_LVDS; break; + case DCB_CONNECTOR_LVDS_SPWG: args->v0.type = NVIF_CONN_V0_LVDS_SPWG; break; + case DCB_CONNECTOR_DMS59_DP0: + case DCB_CONNECTOR_DMS59_DP1: + case DCB_CONNECTOR_DP : + case DCB_CONNECTOR_mDP : + case DCB_CONNECTOR_USB_C : args->v0.type = NVIF_CONN_V0_DP; break; + case DCB_CONNECTOR_eDP : args->v0.type = NVIF_CONN_V0_EDP; break; + case DCB_CONNECTOR_HDMI_0 : + case DCB_CONNECTOR_HDMI_1 : + case DCB_CONNECTOR_HDMI_C : args->v0.type = NVIF_CONN_V0_HDMI; break; + default: + WARN_ON(1); + ret = -EINVAL; + break; + } + nvkm_object_ctor(&nvkm_uconn, oclass, &conn->object); *pobject = &conn->object; ret = 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index fc283a4a1522..e4279f1772a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -25,6 +25,8 @@ #include "head.h" #include "ior.h" +#include <subdev/i2c.h> + #include <nvif/if0012.h> static int @@ -44,17 +46,121 @@ nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc) } static int -nvkm_uoutp_mthd_dp_retrain(struct nvkm_outp *outp, void *argv, u32 argc) +nvkm_uoutp_mthd_dp_mst_id_put(struct nvkm_outp *outp, void *argv, u32 argc) { - union nvif_outp_dp_retrain_args *args = argv; + union nvif_outp_dp_mst_id_put_args *args = argv; - if (argc != sizeof(args->vn)) + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!outp->func->dp.mst_id_put) + return -EINVAL; + + return outp->func->dp.mst_id_put(outp, args->v0.id); +} + +static int +nvkm_uoutp_mthd_dp_mst_id_get(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_mst_id_get_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!outp->func->dp.mst_id_get) + return -EINVAL; + + return outp->func->dp.mst_id_get(outp, &args->v0.id); +} + +static int +nvkm_uoutp_mthd_dp_sst(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_sst_args *args = argv; + struct nvkm_disp *disp = outp->disp; + struct nvkm_ior *ior = outp->ior; + + if (argc != sizeof(args->v0) || args->v0.version != 0) return -ENOSYS; - if (!atomic_read(&outp->dp.lt.done)) + if (!ior->func->dp || !nvkm_head_find(disp, args->v0.head)) + return -EINVAL; + if (!ior->func->dp->sst) return 0; - return outp->func->acquire(outp); + return ior->func->dp->sst(ior, args->v0.head, + outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP, + args->v0.watermark, args->v0.hblanksym, args->v0.vblanksym); +} + +static int +nvkm_uoutp_mthd_dp_drive(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_drive_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!outp->func->dp.drive) + return -EINVAL; + + return outp->func->dp.drive(outp, args->v0.lanes, args->v0.pe, args->v0.vs); +} + +static int +nvkm_uoutp_mthd_dp_train(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_train_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!outp->func->dp.train) + return -EINVAL; + + if (!args->v0.retrain) { + memcpy(outp->dp.dpcd, args->v0.dpcd, sizeof(outp->dp.dpcd)); + outp->dp.lttprs = args->v0.lttprs; + outp->dp.lt.nr = args->v0.link_nr; + outp->dp.lt.bw = args->v0.link_bw / 27000; + outp->dp.lt.mst = args->v0.mst; + outp->dp.lt.post_adj = args->v0.post_lt_adj; + } + + return outp->func->dp.train(outp, args->v0.retrain); +} + +static int +nvkm_uoutp_mthd_dp_rates(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_rates_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (args->v0.rates > ARRAY_SIZE(outp->dp.rate)) + return -EINVAL; + + for (int i = 0; i < args->v0.rates; i++) { + outp->dp.rate[i].dpcd = args->v0.rate[i].dpcd; + outp->dp.rate[i].rate = args->v0.rate[i].rate; + } + + outp->dp.rates = args->v0.rates; + + if (outp->func->dp.rates) + outp->func->dp.rates(outp); + + return 0; +} + +static int +nvkm_uoutp_mthd_dp_aux_xfer(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_dp_aux_xfer_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!outp->func->dp.aux_xfer) + return -EINVAL; + + return outp->func->dp.aux_xfer(outp, args->v0.type, args->v0.addr, + args->v0.data, &args->v0.size); } static int @@ -64,10 +170,10 @@ nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp *outp, void *argv, u32 argc) if (argc != sizeof(args->v0) || args->v0.version != 0) return -ENOSYS; + if (!outp->func->dp.aux_pwr) + return -EINVAL; - outp->dp.enabled = !!args->v0.state; - nvkm_dp_enable(outp, outp->dp.enabled); - return 0; + return outp->func->dp.aux_pwr(outp, !!args->v0.state); } static int @@ -88,12 +194,20 @@ nvkm_uoutp_mthd_hda_eld(struct nvkm_outp *outp, void *argv, u32 argc) if (argc && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) ior->func->dp->audio(ior, args->v0.head, true); + else + if (ior->func->hdmi->audio) + ior->func->hdmi->audio(ior, args->v0.head, true); + ior->func->hda->hpd(ior, args->v0.head, true); ior->func->hda->eld(ior, args->v0.head, args->v0.data, argc); } else { + ior->func->hda->hpd(ior, args->v0.head, false); + if (outp->info.type == DCB_OUTPUT_DP) ior->func->dp->audio(ior, args->v0.head, false); - ior->func->hda->hpd(ior, args->v0.head, false); + else + if (ior->func->hdmi->audio) + ior->func->hdmi->audio(ior, args->v0.head, false); } return 0; @@ -126,84 +240,105 @@ nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc) } static int -nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) +nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc) { - struct nvkm_head *head = outp->asy.head; + union nvif_outp_hdmi_args *args = argv; struct nvkm_ior *ior = outp->ior; - union nvif_outp_release_args *args = argv; - if (argc != sizeof(args->vn)) + if (argc != sizeof(args->v0) || args->v0.version != 0) return -ENOSYS; - if (ior->func->hdmi && head) { - ior->func->hdmi->infoframe_avi(ior, head->id, NULL, 0); - ior->func->hdmi->infoframe_vsi(ior, head->id, NULL, 0); - ior->func->hdmi->ctrl(ior, head->id, false, 0, 0); + if (!(outp->asy.head = nvkm_head_find(outp->disp, args->v0.head))) + return -EINVAL; + + if (!ior->func->hdmi || + args->v0.max_ac_packet > 0x1f || + args->v0.rekey > 0x7f || + (args->v0.scdc && !ior->func->hdmi->scdc)) + return -EINVAL; + + if (!args->v0.enable) { + ior->func->hdmi->infoframe_avi(ior, args->v0.head, NULL, 0); + ior->func->hdmi->infoframe_vsi(ior, args->v0.head, NULL, 0); + ior->func->hdmi->ctrl(ior, args->v0.head, false, 0, 0); + return 0; } - nvkm_outp_release(outp, NVKM_OUTP_USER); + ior->func->hdmi->ctrl(ior, args->v0.head, args->v0.enable, + args->v0.max_ac_packet, args->v0.rekey); + if (ior->func->hdmi->scdc) + ior->func->hdmi->scdc(ior, args->v0.khz, args->v0.scdc, args->v0.scdc_scrambling, + args->v0.scdc_low_rates); + return 0; } static int -nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], - u8 link_nr, u8 link_bw, bool hda, bool mst) +nvkm_uoutp_mthd_lvds(struct nvkm_outp *outp, void *argv, u32 argc) { - int ret; + union nvif_outp_lvds_args *args = argv; - ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hda); - if (ret) - return ret; + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (outp->info.type != DCB_OUTPUT_LVDS) + return -EINVAL; - memcpy(outp->dp.dpcd, dpcd, sizeof(outp->dp.dpcd)); - outp->dp.lt.nr = link_nr; - outp->dp.lt.bw = link_bw; - outp->dp.lt.mst = mst; + outp->lvds.dual = !!args->v0.dual; + outp->lvds.bpc8 = !!args->v0.bpc8; return 0; } static int -nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_max_ac_packet, - u8 hdmi_rekey, u8 hdmi_scdc, u8 hdmi_hda) +nvkm_uoutp_mthd_bl_set(struct nvkm_outp *outp, void *argv, u32 argc) { - struct nvkm_ior *ior; + union nvif_outp_bl_get_args *args = argv; int ret; - if (!(outp->asy.head = nvkm_head_find(outp->disp, head))) - return -EINVAL; + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; - ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hdmi && hdmi_hda); - if (ret) - return ret; + if (outp->func->bl.set) + ret = outp->func->bl.set(outp, args->v0.level); + else + ret = -EINVAL; - ior = outp->ior; + return ret; +} - if (hdmi) { - if (!ior->func->hdmi || - hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f || - (hdmi_scdc && !ior->func->hdmi->scdc)) { - nvkm_outp_release(outp, NVKM_OUTP_USER); - return -EINVAL; - } +static int +nvkm_uoutp_mthd_bl_get(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_bl_get_args *args = argv; + int ret; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; - ior->func->hdmi->ctrl(ior, head, hdmi, hdmi_max_ac_packet, hdmi_rekey); - if (ior->func->hdmi->scdc) - ior->func->hdmi->scdc(ior, hdmi_scdc); + if (outp->func->bl.get) { + ret = outp->func->bl.get(outp); + if (ret >= 0) { + args->v0.level = ret; + ret = 0; + } + } else { + ret = -EINVAL; } - return 0; + return ret; } static int -nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8) +nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) { - if (outp->info.type != DCB_OUTPUT_LVDS) - return -EINVAL; + union nvif_outp_release_args *args = argv; - outp->lvds.dual = dual; - outp->lvds.bpc8 = bpc8; + if (argc != sizeof(args->vn)) + return -ENOSYS; + if (!outp->ior) + return -EINVAL; - return nvkm_outp_acquire(outp, NVKM_OUTP_USER, false); + outp->func->release(outp); + return 0; } static int @@ -214,30 +349,16 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) if (argc != sizeof(args->v0) || args->v0.version != 0) return -ENOSYS; - if (outp->ior) + if (outp->ior && args->v0.type <= NVIF_OUTP_ACQUIRE_V0_PIOR) return -EBUSY; - switch (args->v0.proto) { - case NVIF_OUTP_ACQUIRE_V0_RGB_CRT: - ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, false); + switch (args->v0.type) { + case NVIF_OUTP_ACQUIRE_V0_DAC: + case NVIF_OUTP_ACQUIRE_V0_PIOR: + ret = outp->func->acquire(outp, false); break; - case NVIF_OUTP_ACQUIRE_V0_TMDS: - ret = nvkm_uoutp_mthd_acquire_tmds(outp, args->v0.tmds.head, - args->v0.tmds.hdmi, - args->v0.tmds.hdmi_max_ac_packet, - args->v0.tmds.hdmi_rekey, - args->v0.tmds.hdmi_scdc, - args->v0.tmds.hdmi_hda); - break; - case NVIF_OUTP_ACQUIRE_V0_LVDS: - ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8); - break; - case NVIF_OUTP_ACQUIRE_V0_DP: - ret = nvkm_uoutp_mthd_acquire_dp(outp, args->v0.dp.dpcd, - args->v0.dp.link_nr, - args->v0.dp.link_bw, - args->v0.dp.hda != 0, - args->v0.dp.mst != 0); + case NVIF_OUTP_ACQUIRE_V0_SOR: + ret = outp->func->acquire(outp, args->v0.sor.hda); break; default: ret = -EINVAL; @@ -253,6 +374,69 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc) } static int +nvkm_uoutp_mthd_inherit(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_inherit_args *args = argv; + struct nvkm_ior *ior; + int ret = 0; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + + /* Ensure an ior is hooked up to this outp already */ + ior = outp->func->inherit(outp); + if (!ior) + return -ENODEV; + + /* With iors, there will be a separate output path for each type of connector - and all of + * them will appear to be hooked up. Figure out which one is actually the one we're using + * based on the protocol we were given over nvif + */ + switch (args->v0.proto) { + case NVIF_OUTP_INHERIT_V0_TMDS: + if (ior->arm.proto != TMDS) + return -ENODEV; + break; + case NVIF_OUTP_INHERIT_V0_DP: + if (ior->arm.proto != DP) + return -ENODEV; + break; + case NVIF_OUTP_INHERIT_V0_LVDS: + if (ior->arm.proto != LVDS) + return -ENODEV; + break; + case NVIF_OUTP_INHERIT_V0_TV: + if (ior->arm.proto != TV) + return -ENODEV; + break; + case NVIF_OUTP_INHERIT_V0_RGB_CRT: + if (ior->arm.proto != CRT) + return -ENODEV; + break; + default: + ret = -EINVAL; + break; + } + + /* Make sure that userspace hasn't already acquired this */ + if (outp->acquired) { + OUTP_ERR(outp, "cannot inherit an already acquired (%02x) outp", outp->acquired); + return -EBUSY; + } + + /* Mark the outp acquired by userspace now that we've confirmed it's already active */ + OUTP_TRACE(outp, "inherit %02x |= %02x %p", outp->acquired, NVKM_OUTP_USER, ior); + nvkm_outp_acquire_ior(outp, NVKM_OUTP_USER, ior); + + args->v0.or = ior->id; + args->v0.link = ior->arm.link; + args->v0.head = ffs(ior->arm.head) - 1; + args->v0.proto = ior->arm.proto_evo; + + return ret; +} + +static int nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc) { union nvif_outp_load_detect_args *args = argv; @@ -261,7 +445,7 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc) if (argc != sizeof(args->v0) || args->v0.version != 0) return -ENOSYS; - ret = nvkm_outp_acquire(outp, NVKM_OUTP_PRIV, false); + ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_PRIV, false); if (ret == 0) { if (outp->ior->func->sense) { ret = outp->ior->func->sense(outp->ior, args->v0.data); @@ -269,21 +453,64 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc) } else { ret = -EINVAL; } - nvkm_outp_release(outp, NVKM_OUTP_PRIV); + nvkm_outp_release_or(outp, NVKM_OUTP_PRIV); } return ret; } static int +nvkm_uoutp_mthd_edid_get(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_edid_get_args *args = argv; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!outp->func->edid_get) + return -EINVAL; + + args->v0.size = ARRAY_SIZE(args->v0.data); + return outp->func->edid_get(outp, args->v0.data, &args->v0.size); +} + +static int +nvkm_uoutp_mthd_detect(struct nvkm_outp *outp, void *argv, u32 argc) +{ + union nvif_outp_detect_args *args = argv; + int ret; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + if (!outp->func->detect) + return -EINVAL; + + ret = outp->func->detect(outp); + switch (ret) { + case 0: args->v0.status = NVIF_OUTP_DETECT_V0_NOT_PRESENT; break; + case 1: args->v0.status = NVIF_OUTP_DETECT_V0_PRESENT; break; + default: + args->v0.status = NVIF_OUTP_DETECT_V0_UNKNOWN; + break; + } + + return 0; +} + +static int nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc) { switch (mthd) { - case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc); - case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc); - case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc); - case NVIF_OUTP_V0_DP_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc); - case NVIF_OUTP_V0_DP_MST_VCPI: return nvkm_uoutp_mthd_dp_mst_vcpi(outp, argv, argc); + case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc); + case NVIF_OUTP_V0_LVDS : return nvkm_uoutp_mthd_lvds (outp, argv, argc); + case NVIF_OUTP_V0_HDMI : return nvkm_uoutp_mthd_hdmi (outp, argv, argc); + case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc); + case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc); + case NVIF_OUTP_V0_DP_TRAIN : return nvkm_uoutp_mthd_dp_train (outp, argv, argc); + case NVIF_OUTP_V0_DP_DRIVE : return nvkm_uoutp_mthd_dp_drive (outp, argv, argc); + case NVIF_OUTP_V0_DP_SST : return nvkm_uoutp_mthd_dp_sst (outp, argv, argc); + case NVIF_OUTP_V0_DP_MST_ID_GET: return nvkm_uoutp_mthd_dp_mst_id_get(outp, argv, argc); + case NVIF_OUTP_V0_DP_MST_ID_PUT: return nvkm_uoutp_mthd_dp_mst_id_put(outp, argv, argc); + case NVIF_OUTP_V0_DP_MST_VCPI : return nvkm_uoutp_mthd_dp_mst_vcpi (outp, argv, argc); default: break; } @@ -292,17 +519,25 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc) } static int -nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc) +nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc, bool *invalid) { switch (mthd) { - case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, argv, argc); + case NVIF_OUTP_V0_DETECT : return nvkm_uoutp_mthd_detect (outp, argv, argc); + case NVIF_OUTP_V0_EDID_GET : return nvkm_uoutp_mthd_edid_get (outp, argv, argc); + case NVIF_OUTP_V0_INHERIT : return nvkm_uoutp_mthd_inherit (outp, argv, argc); case NVIF_OUTP_V0_ACQUIRE : return nvkm_uoutp_mthd_acquire (outp, argv, argc); + case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, argv, argc); + case NVIF_OUTP_V0_BL_GET : return nvkm_uoutp_mthd_bl_get (outp, argv, argc); + case NVIF_OUTP_V0_BL_SET : return nvkm_uoutp_mthd_bl_set (outp, argv, argc); case NVIF_OUTP_V0_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc); + case NVIF_OUTP_V0_DP_AUX_XFER: return nvkm_uoutp_mthd_dp_aux_xfer(outp, argv, argc); + case NVIF_OUTP_V0_DP_RATES : return nvkm_uoutp_mthd_dp_rates (outp, argv, argc); default: break; } - return 1; + *invalid = true; + return 0; } static int @@ -310,12 +545,13 @@ nvkm_uoutp_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc) { struct nvkm_outp *outp = nvkm_uoutp(object); struct nvkm_disp *disp = outp->disp; + bool invalid = false; int ret; mutex_lock(&disp->super.mutex); - ret = nvkm_uoutp_mthd_noacquire(outp, mthd, argv, argc); - if (ret <= 0) + ret = nvkm_uoutp_mthd_noacquire(outp, mthd, argv, argc, &invalid); + if (!invalid) goto done; if (outp->ior) @@ -370,10 +606,60 @@ nvkm_uoutp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv ret = -EBUSY; spin_lock(&disp->client.lock); if (!outp->object.func) { + switch (outp->info.type) { + case DCB_OUTPUT_ANALOG: + args->v0.type = NVIF_OUTP_V0_TYPE_DAC; + args->v0.proto = NVIF_OUTP_V0_PROTO_RGB_CRT; + args->v0.rgb_crt.freq_max = outp->info.crtconf.maxfreq; + break; + case DCB_OUTPUT_TMDS: + if (!outp->info.location) { + args->v0.type = NVIF_OUTP_V0_TYPE_SOR; + args->v0.tmds.dual = (outp->info.tmdsconf.sor.link == 3); + } else { + args->v0.type = NVIF_OUTP_V0_TYPE_PIOR; + args->v0.tmds.dual = 0; + } + args->v0.proto = NVIF_OUTP_V0_PROTO_TMDS; + break; + case DCB_OUTPUT_LVDS: + args->v0.type = NVIF_OUTP_V0_TYPE_SOR; + args->v0.proto = NVIF_OUTP_V0_PROTO_LVDS; + args->v0.lvds.acpi_edid = outp->info.lvdsconf.use_acpi_for_edid; + break; + case DCB_OUTPUT_DP: + if (!outp->info.location) { + args->v0.type = NVIF_OUTP_V0_TYPE_SOR; + args->v0.dp.aux = outp->info.i2c_index; + } else { + args->v0.type = NVIF_OUTP_V0_TYPE_PIOR; + args->v0.dp.aux = NVKM_I2C_AUX_EXT(outp->info.extdev); + } + args->v0.proto = NVIF_OUTP_V0_PROTO_DP; + args->v0.dp.mst = outp->dp.mst; + args->v0.dp.increased_wm = outp->dp.increased_wm; + args->v0.dp.link_nr = outp->info.dpconf.link_nr; + args->v0.dp.link_bw = outp->info.dpconf.link_bw * 27000; + break; + default: + WARN_ON(1); + ret = -EINVAL; + goto done; + } + + if (outp->info.location) + args->v0.ddc = NVKM_I2C_BUS_EXT(outp->info.extdev); + else + args->v0.ddc = outp->info.i2c_index; + args->v0.heads = outp->info.heads; + args->v0.conn = outp->info.connector; + nvkm_object_ctor(&nvkm_uoutp, oclass, &outp->object); *pobject = &outp->object; ret = 0; } + +done: spin_unlock(&disp->client.lock); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 3648868bb9fc..c494a1ff2d57 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -2032,18 +2032,18 @@ gf100_gr_oneinit(struct nvkm_gr *base) } /* Allocate global context buffers. */ - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->pagepool_size, - 0x100, false, &gr->pagepool); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST_SR_LOST, + gr->func->grctx->pagepool_size, 0x100, false, &gr->pagepool); if (ret) return ret; - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->bundle_size, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST_SR_LOST, gr->func->grctx->bundle_size, 0x100, false, &gr->bundle_cb); if (ret) return ret; - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, gr->func->grctx->attrib_cb_size(gr), - 0x1000, false, &gr->attrib_cb); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST_SR_LOST, + gr->func->grctx->attrib_cb_size(gr), 0x1000, false, &gr->attrib_cb); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 8fe0444f761e..131db2645f84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -462,7 +462,7 @@ nvkm_perfmon_mthd_query_domain(struct nvkm_perfmon *perfmon, args->v0.id = di; args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom); - strncpy(args->v0.name, dom->name, sizeof(args->v0.name) - 1); + strscpy(args->v0.name, dom->name, sizeof(args->v0.name)); /* Currently only global counters (PCOUNTER) are implemented * but this will be different for local counters (MP). */ @@ -513,8 +513,7 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_perfmon *perfmon, snprintf(args->v0.name, sizeof(args->v0.name), "/%s/%02x", dom->name, si); } else { - strncpy(args->v0.name, sig->name, - sizeof(args->v0.name) - 1); + strscpy(args->v0.name, sig->name, sizeof(args->v0.name)); } args->v0.signal = si; @@ -572,7 +571,7 @@ nvkm_perfmon_mthd_query_source(struct nvkm_perfmon *perfmon, args->v0.source = sig->source[si]; args->v0.mask = src->mask; - strncpy(args->v0.name, src->name, sizeof(args->v0.name) - 1); + strscpy(args->v0.name, src->name, sizeof(args->v0.name)); } if (++si < source_nr) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 6ae25d3e7f45..c011227f7052 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -82,7 +82,7 @@ struct nvkm_perfdom { u8 mode; u32 clk; u16 signal_nr; - struct nvkm_perfsig signal[]; + struct nvkm_perfsig signal[] __counted_by(signal_nr); }; struct nvkm_funcdom { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c index 81a1ad2c88a7..40997ad1d101 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c @@ -83,17 +83,9 @@ tu102_devinit_wait(struct nvkm_device *device) } int -tu102_devinit_post(struct nvkm_devinit *base, bool post) +tu102_devinit_post(struct nvkm_devinit *init, bool post) { - struct nv50_devinit *init = nv50_devinit(base); - int ret; - - ret = tu102_devinit_wait(init->base.subdev.device); - if (ret) - return ret; - - gm200_devinit_preos(init, post); - return 0; + return tu102_devinit_wait(init->subdev.device); } static const struct nvkm_devinit_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index e0e4f97be029..24886eabe8dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -94,15 +94,21 @@ nvkm_instobj_wrap(struct nvkm_device *device, struct nvkm_memory *memory, struct nvkm_memory **pmemory) { struct nvkm_instmem *imem = device->imem; + int ret; if (!imem->func->memory_wrap) return -ENOSYS; - return imem->func->memory_wrap(imem, memory, pmemory); + ret = imem->func->memory_wrap(imem, memory, pmemory); + if (ret) + return ret; + + container_of(*pmemory, struct nvkm_instobj, memory)->preserve = true; + return 0; } int -nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, +nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, bool preserve, struct nvkm_memory **pmemory) { struct nvkm_subdev *subdev = &imem->subdev; @@ -130,6 +136,7 @@ nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, nvkm_done(memory); } + container_of(memory, struct nvkm_instobj, memory)->preserve = preserve; done: if (ret) nvkm_memory_unref(&memory); @@ -176,9 +183,11 @@ nvkm_instmem_fini(struct nvkm_subdev *subdev, bool suspend) if (suspend) { list_for_each_entry(iobj, &imem->list, head) { - int ret = nvkm_instobj_save(iobj); - if (ret) - return ret; + if (iobj->preserve) { + int ret = nvkm_instobj_save(iobj); + if (ret) + return ret; + } } nvkm_bar_bar2_fini(subdev->device); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index fe92986a3885..390ca00ab567 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -25,6 +25,7 @@ void nvkm_instmem_boot(struct nvkm_instmem *); struct nvkm_instobj { struct nvkm_memory memory; struct list_head head; + bool preserve; u32 *suspend; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c index f3630d0e0d55..bddac77f48f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c @@ -558,7 +558,7 @@ gp100_vmm_invalidate_pdb(struct nvkm_vmm *vmm, u64 addr) void gp100_vmm_flush(struct nvkm_vmm *vmm, int depth) { - u32 type = (5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth) << 24; + u32 type = 0; if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR])) type |= 0x00000004; /* HUB_ONLY */ type |= 0x00000001; /* PAGE_ALL */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c index 6cb5eefa45e9..0095d58d4d9a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c @@ -27,7 +27,7 @@ static void tu102_vmm_flush(struct nvkm_vmm *vmm, int depth) { struct nvkm_device *device = vmm->mmu->subdev.device; - u32 type = (5 /* CACHE_LEVEL_UP_TO_PDE3 */ - depth) << 24; + u32 type = 0; type |= 0x00000001; /* PAGE_ALL */ if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR])) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index afeeb7737552..b2835b3ea6f5 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -817,6 +817,13 @@ static void pdev_remove(struct platform_device *pdev) kfree(priv); } +static void pdev_shutdown(struct platform_device *pdev) +{ + struct omap_drm_private *priv = platform_get_drvdata(pdev); + + drm_atomic_helper_shutdown(priv->ddev); +} + #ifdef CONFIG_PM_SLEEP static int omap_drm_suspend(struct device *dev) { @@ -846,6 +853,7 @@ static struct platform_driver pdev = { }, .probe = pdev_probe, .remove_new = pdev_remove, + .shutdown = pdev_shutdown, }; static struct platform_driver * const drivers[] = { diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 869e535faefa..ecb22ea326cb 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -244,6 +244,17 @@ config DRM_PANEL_JDI_LT070ME05000 The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses 24 bit per pixel. +config DRM_PANEL_JDI_LPM102A188A + tristate "JDI LPM102A188A DSI panel" + depends on OF && GPIOLIB + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for JDI LPM102A188A DSI + command mode panel as found in Google Pixel C devices. + The panel has a 2560×1800 resolution. It provides a MIPI DSI interface + to the host. + config DRM_PANEL_JDI_R63452 tristate "JDI R63452 Full HD DSI panel" depends on OF @@ -505,6 +516,15 @@ config DRM_PANEL_RAYDIUM_RM68200 Say Y here if you want to enable support for Raydium RM68200 720x1280 DSI video mode panel. +config DRM_PANEL_RAYDIUM_RM692E5 + tristate "Raydium RM692E5-based DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Raydium RM692E5-based + display panels, such as the one found in the Fairphone 5 smartphone. + config DRM_PANEL_RONBO_RB070D30 tristate "Ronbo Electronics RB070D30 panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 433e93d57949..e14ce55a0875 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o obj-$(CONFIG_DRM_PANEL_JADARD_JD9365DA_H3) += panel-jadard-jd9365da-h3.o obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o +obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o @@ -48,6 +49,7 @@ obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o +obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM692E5) += panel-raydium-rm692e5.o obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c index abb0788843c6..503ecea72c5e 100644 --- a/drivers/gpu/drm/panel/panel-arm-versatile.c +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -267,6 +267,8 @@ static int versatile_panel_get_modes(struct drm_panel *panel, connector->display_info.bus_flags = vpanel->panel_type->bus_flags; mode = drm_mode_duplicate(connector->dev, &vpanel->panel_type->mode); + if (!mode) + return -ENOMEM; drm_mode_set_name(mode); mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; diff --git a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c index 075a7af81eff..bcaa63d1955f 100644 --- a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c +++ b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c @@ -16,7 +16,6 @@ struct tm5p5_nt35596 { struct mipi_dsi_device *dsi; struct regulator_bulk_data supplies[2]; struct gpio_desc *reset_gpio; - bool prepared; }; static inline struct tm5p5_nt35596 *to_tm5p5_nt35596(struct drm_panel *panel) @@ -112,9 +111,6 @@ static int tm5p5_nt35596_prepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (ctx->prepared) - return 0; - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) { dev_err(dev, "Failed to enable regulators: %d\n", ret); @@ -132,7 +128,6 @@ static int tm5p5_nt35596_prepare(struct drm_panel *panel) return ret; } - ctx->prepared = true; return 0; } @@ -142,9 +137,6 @@ static int tm5p5_nt35596_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = tm5p5_nt35596_off(ctx); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); @@ -153,7 +145,6 @@ static int tm5p5_nt35596_unprepare(struct drm_panel *panel) regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - ctx->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c b/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c index 90098b753e3b..e77db8597eb7 100644 --- a/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c +++ b/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c @@ -34,7 +34,6 @@ struct boe_bf060y8m_aj0 { struct mipi_dsi_device *dsi; struct regulator_bulk_data vregs[BF060Y8M_VREG_MAX]; struct gpio_desc *reset_gpio; - bool prepared; }; static inline @@ -129,9 +128,6 @@ static int boe_bf060y8m_aj0_prepare(struct drm_panel *panel) struct device *dev = &boe->dsi->dev; int ret; - if (boe->prepared) - return 0; - /* * Enable EL Driving Voltage first - doing that at the beginning * or at the end of the power sequence doesn't matter, so enable @@ -166,7 +162,6 @@ static int boe_bf060y8m_aj0_prepare(struct drm_panel *panel) return ret; } - boe->prepared = true; return 0; err_vci: @@ -186,9 +181,6 @@ static int boe_bf060y8m_aj0_unprepare(struct drm_panel *panel) struct device *dev = &boe->dsi->dev; int ret; - if (!boe->prepared) - return 0; - ret = boe_bf060y8m_aj0_off(boe); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); @@ -196,7 +188,6 @@ static int boe_bf060y8m_aj0_unprepare(struct drm_panel *panel) gpiod_set_value_cansleep(boe->reset_gpio, 1); ret = regulator_bulk_disable(ARRAY_SIZE(boe->vregs), boe->vregs); - boe->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 61c872f0f7ca..4a6dcfd781e8 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -325,11 +325,6 @@ static struct regmap_bus ili9322_regmap_bus = { .val_format_endian_default = REGMAP_ENDIAN_BIG, }; -static bool ili9322_volatile_reg(struct device *dev, unsigned int reg) -{ - return false; -} - static bool ili9322_writeable_reg(struct device *dev, unsigned int reg) { /* Just register 0 is read-only */ @@ -342,8 +337,7 @@ static const struct regmap_config ili9322_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0x44, - .cache_type = REGCACHE_RBTREE, - .volatile_reg = ili9322_volatile_reg, + .cache_type = REGCACHE_MAPLE, .writeable_reg = ili9322_writeable_reg, }; diff --git a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c index 8912757a6f42..3e0a8e0d58a0 100644 --- a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c +++ b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c @@ -21,7 +21,6 @@ struct jdi_fhd_r63452 { struct drm_panel panel; struct mipi_dsi_device *dsi; struct gpio_desc *reset_gpio; - bool prepared; }; static inline struct jdi_fhd_r63452 *to_jdi_fhd_r63452(struct drm_panel *panel) @@ -157,9 +156,6 @@ static int jdi_fhd_r63452_prepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (ctx->prepared) - return 0; - jdi_fhd_r63452_reset(ctx); ret = jdi_fhd_r63452_on(ctx); @@ -169,7 +165,6 @@ static int jdi_fhd_r63452_prepare(struct drm_panel *panel) return ret; } - ctx->prepared = true; return 0; } @@ -179,16 +174,12 @@ static int jdi_fhd_r63452_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = jdi_fhd_r63452_off(ctx); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); gpiod_set_value_cansleep(ctx->reset_gpio, 1); - ctx->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c new file mode 100644 index 000000000000..5b5082efb282 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c @@ -0,0 +1,551 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2014 Google, Inc. + * + * Copyright (C) 2022 Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt> + * + * Adapted from the downstream Pixel C driver written by Sean Paul + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +#define MCS_CMD_ACS_PROT 0xB0 +#define MCS_CMD_ACS_PROT_OFF (0 << 0) + +#define MCS_PWR_CTRL_FUNC 0xD0 +#define MCS_PWR_CTRL_PARAM1_DEFAULT (2 << 0) +#define MCS_PWR_CTRL_PARAM1_VGH_210_DIV (1 << 4) +#define MCS_PWR_CTRL_PARAM1_VGH_240_DIV (2 << 4) +#define MCS_PWR_CTRL_PARAM1_VGH_280_DIV (3 << 4) +#define MCS_PWR_CTRL_PARAM1_VGH_330_DIV (4 << 4) +#define MCS_PWR_CTRL_PARAM1_VGH_410_DIV (5 << 4) +#define MCS_PWR_CTRL_PARAM2_DEFAULT (9 << 4) +#define MCS_PWR_CTRL_PARAM2_VGL_210_DIV (1 << 0) +#define MCS_PWR_CTRL_PARAM2_VGL_240_DIV (2 << 0) +#define MCS_PWR_CTRL_PARAM2_VGL_280_DIV (3 << 0) +#define MCS_PWR_CTRL_PARAM2_VGL_330_DIV (4 << 0) +#define MCS_PWR_CTRL_PARAM2_VGL_410_DIV (5 << 0) + +struct jdi_panel { + struct drm_panel base; + struct mipi_dsi_device *link1; + struct mipi_dsi_device *link2; + + struct regulator *supply; + struct regulator *ddi_supply; + struct backlight_device *backlight; + + struct gpio_desc *enable_gpio; + struct gpio_desc *reset_gpio; + + const struct drm_display_mode *mode; +}; + +static inline struct jdi_panel *to_panel_jdi(struct drm_panel *panel) +{ + return container_of(panel, struct jdi_panel, base); +} + +static void jdi_wait_frames(struct jdi_panel *jdi, unsigned int frames) +{ + unsigned int refresh = drm_mode_vrefresh(jdi->mode); + + if (WARN_ON(frames > refresh)) + return; + + msleep(1000 / (refresh / frames)); +} + +static int jdi_panel_disable(struct drm_panel *panel) +{ + struct jdi_panel *jdi = to_panel_jdi(panel); + + backlight_disable(jdi->backlight); + + jdi_wait_frames(jdi, 2); + + return 0; +} + +static int jdi_panel_unprepare(struct drm_panel *panel) +{ + struct jdi_panel *jdi = to_panel_jdi(panel); + int ret; + + ret = mipi_dsi_dcs_set_display_off(jdi->link1); + if (ret < 0) + dev_err(panel->dev, "failed to set display off: %d\n", ret); + + ret = mipi_dsi_dcs_set_display_off(jdi->link2); + if (ret < 0) + dev_err(panel->dev, "failed to set display off: %d\n", ret); + + /* Specified by JDI @ 50ms, subject to change */ + msleep(50); + + ret = mipi_dsi_dcs_enter_sleep_mode(jdi->link1); + if (ret < 0) + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); + ret = mipi_dsi_dcs_enter_sleep_mode(jdi->link2); + if (ret < 0) + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); + + /* Specified by JDI @ 150ms, subject to change */ + msleep(150); + + gpiod_set_value(jdi->reset_gpio, 1); + + /* T4 = 1ms */ + usleep_range(1000, 3000); + + gpiod_set_value(jdi->enable_gpio, 0); + + /* T5 = 2ms */ + usleep_range(2000, 4000); + + regulator_disable(jdi->ddi_supply); + + /* T6 = 2ms plus some time to discharge capacitors */ + usleep_range(7000, 9000); + + regulator_disable(jdi->supply); + /* Specified by JDI @ 20ms, subject to change */ + msleep(20); + + return ret; +} + +static int jdi_setup_symmetrical_split(struct mipi_dsi_device *left, + struct mipi_dsi_device *right, + const struct drm_display_mode *mode) +{ + int err; + + err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1); + if (err < 0) { + dev_err(&left->dev, "failed to set column address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_column_address(right, 0, mode->hdisplay / 2 - 1); + if (err < 0) { + dev_err(&right->dev, "failed to set column address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1); + if (err < 0) { + dev_err(&left->dev, "failed to set page address: %d\n", err); + return err; + } + + err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1); + if (err < 0) { + dev_err(&right->dev, "failed to set page address: %d\n", err); + return err; + } + + return 0; +} + +static int jdi_write_dcdc_registers(struct jdi_panel *jdi) +{ + /* Clear the manufacturer command access protection */ + mipi_dsi_generic_write_seq(jdi->link1, MCS_CMD_ACS_PROT, + MCS_CMD_ACS_PROT_OFF); + mipi_dsi_generic_write_seq(jdi->link2, MCS_CMD_ACS_PROT, + MCS_CMD_ACS_PROT_OFF); + /* + * Change the VGH/VGL divide rations to move the noise generated by the + * TCONN. This should hopefully avoid interaction with the backlight + * controller. + */ + mipi_dsi_generic_write_seq(jdi->link1, MCS_PWR_CTRL_FUNC, + MCS_PWR_CTRL_PARAM1_VGH_330_DIV | + MCS_PWR_CTRL_PARAM1_DEFAULT, + MCS_PWR_CTRL_PARAM2_VGL_410_DIV | + MCS_PWR_CTRL_PARAM2_DEFAULT); + + mipi_dsi_generic_write_seq(jdi->link2, MCS_PWR_CTRL_FUNC, + MCS_PWR_CTRL_PARAM1_VGH_330_DIV | + MCS_PWR_CTRL_PARAM1_DEFAULT, + MCS_PWR_CTRL_PARAM2_VGL_410_DIV | + MCS_PWR_CTRL_PARAM2_DEFAULT); + + return 0; +} + +static int jdi_panel_prepare(struct drm_panel *panel) +{ + struct jdi_panel *jdi = to_panel_jdi(panel); + int err; + + /* Disable backlight to avoid showing random pixels + * with a conservative delay for it to take effect. + */ + backlight_disable(jdi->backlight); + jdi_wait_frames(jdi, 3); + + jdi->link1->mode_flags |= MIPI_DSI_MODE_LPM; + jdi->link2->mode_flags |= MIPI_DSI_MODE_LPM; + + err = regulator_enable(jdi->supply); + if (err < 0) { + dev_err(panel->dev, "failed to enable supply: %d\n", err); + return err; + } + /* T1 = 2ms */ + usleep_range(2000, 4000); + + err = regulator_enable(jdi->ddi_supply); + if (err < 0) { + dev_err(panel->dev, "failed to enable ddi_supply: %d\n", err); + goto supply_off; + } + /* T2 = 1ms */ + usleep_range(1000, 3000); + + gpiod_set_value(jdi->enable_gpio, 1); + /* T3 = 10ms */ + usleep_range(10000, 15000); + + gpiod_set_value(jdi->reset_gpio, 0); + /* Specified by JDI @ 3ms, subject to change */ + usleep_range(3000, 5000); + + /* + * TODO: The device supports both left-right and even-odd split + * configurations, but this driver currently supports only the left- + * right split. To support a different mode a mechanism needs to be + * put in place to communicate the configuration back to the DSI host + * controller. + */ + err = jdi_setup_symmetrical_split(jdi->link1, jdi->link2, + jdi->mode); + if (err < 0) { + dev_err(panel->dev, "failed to set up symmetrical split: %d\n", + err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_tear_scanline(jdi->link1, + jdi->mode->vdisplay - 16); + if (err < 0) { + dev_err(panel->dev, "failed to set tear scanline: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_tear_scanline(jdi->link2, + jdi->mode->vdisplay - 16); + if (err < 0) { + dev_err(panel->dev, "failed to set tear scanline: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_tear_on(jdi->link1, + MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (err < 0) { + dev_err(panel->dev, "failed to set tear on: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_tear_on(jdi->link2, + MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (err < 0) { + dev_err(panel->dev, "failed to set tear on: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_pixel_format(jdi->link1, MIPI_DCS_PIXEL_FMT_24BIT); + if (err < 0) { + dev_err(panel->dev, "failed to set pixel format: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_pixel_format(jdi->link2, MIPI_DCS_PIXEL_FMT_24BIT); + if (err < 0) { + dev_err(panel->dev, "failed to set pixel format: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_exit_sleep_mode(jdi->link1); + if (err < 0) { + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_exit_sleep_mode(jdi->link2); + if (err < 0) { + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); + goto poweroff; + } + + err = jdi_write_dcdc_registers(jdi); + if (err < 0) { + dev_err(panel->dev, "failed to write dcdc registers: %d\n", err); + goto poweroff; + } + /* + * We need to wait 150ms between mipi_dsi_dcs_exit_sleep_mode() and + * mipi_dsi_dcs_set_display_on(). + */ + msleep(150); + + err = mipi_dsi_dcs_set_display_on(jdi->link1); + if (err < 0) { + dev_err(panel->dev, "failed to set display on: %d\n", err); + goto poweroff; + } + + err = mipi_dsi_dcs_set_display_on(jdi->link2); + if (err < 0) { + dev_err(panel->dev, "failed to set display on: %d\n", err); + goto poweroff; + } + + jdi->link1->mode_flags &= ~MIPI_DSI_MODE_LPM; + jdi->link2->mode_flags &= ~MIPI_DSI_MODE_LPM; + + return 0; + +poweroff: + regulator_disable(jdi->ddi_supply); + + /* T6 = 2ms plus some time to discharge capacitors */ + usleep_range(7000, 9000); +supply_off: + regulator_disable(jdi->supply); + /* Specified by JDI @ 20ms, subject to change */ + msleep(20); + + return err; +} + +static int jdi_panel_enable(struct drm_panel *panel) +{ + struct jdi_panel *jdi = to_panel_jdi(panel); + + /* + * Ensure we send image data before turning the backlight + * on, to avoid the display showing random pixels. + */ + jdi_wait_frames(jdi, 3); + + backlight_enable(jdi->backlight); + + return 0; +} + +static const struct drm_display_mode default_mode = { + .clock = (2560 + 80 + 80 + 80) * (1800 + 4 + 4 + 4) * 60 / 1000, + .hdisplay = 2560, + .hsync_start = 2560 + 80, + .hsync_end = 2560 + 80 + 80, + .htotal = 2560 + 80 + 80 + 80, + .vdisplay = 1800, + .vsync_start = 1800 + 4, + .vsync_end = 1800 + 4 + 4, + .vtotal = 1800 + 4 + 4 + 4, + .flags = 0, +}; + +static int jdi_panel_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + struct jdi_panel *jdi = to_panel_jdi(panel); + struct device *dev = &jdi->link1->dev; + + mode = drm_mode_duplicate(connector->dev, &default_mode); + if (!mode) { + dev_err(dev, "failed to add mode %ux%ux@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = 211; + connector->display_info.height_mm = 148; + connector->display_info.bpc = 8; + + return 1; +} + +static const struct drm_panel_funcs jdi_panel_funcs = { + .prepare = jdi_panel_prepare, + .enable = jdi_panel_enable, + .disable = jdi_panel_disable, + .unprepare = jdi_panel_unprepare, + .get_modes = jdi_panel_get_modes, +}; + +static const struct of_device_id jdi_of_match[] = { + { .compatible = "jdi,lpm102a188a", }, + { } +}; +MODULE_DEVICE_TABLE(of, jdi_of_match); + +static int jdi_panel_add(struct jdi_panel *jdi) +{ + struct device *dev = &jdi->link1->dev; + + jdi->mode = &default_mode; + + jdi->supply = devm_regulator_get(dev, "power"); + if (IS_ERR(jdi->supply)) + return dev_err_probe(dev, PTR_ERR(jdi->supply), + "failed to get power regulator\n"); + + jdi->ddi_supply = devm_regulator_get(dev, "ddi"); + if (IS_ERR(jdi->ddi_supply)) + return dev_err_probe(dev, PTR_ERR(jdi->ddi_supply), + "failed to get ddi regulator\n"); + + jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(jdi->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(jdi->reset_gpio), + "failed to get reset gpio\n"); + /* T4 = 1ms */ + usleep_range(1000, 3000); + + jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(jdi->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(jdi->enable_gpio), + "failed to get enable gpio\n"); + /* T5 = 2ms */ + usleep_range(2000, 4000); + + jdi->backlight = devm_of_find_backlight(dev); + if (IS_ERR(jdi->backlight)) + return dev_err_probe(dev, PTR_ERR(jdi->backlight), + "failed to create backlight\n"); + + drm_panel_init(&jdi->base, &jdi->link1->dev, &jdi_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + drm_panel_add(&jdi->base); + + return 0; +} + +static void jdi_panel_del(struct jdi_panel *jdi) +{ + if (jdi->base.dev) + drm_panel_remove(&jdi->base); + + if (jdi->link2) + put_device(&jdi->link2->dev); +} + +static int jdi_panel_dsi_probe(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_device *secondary = NULL; + struct jdi_panel *jdi; + struct device_node *np; + int err; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = 0; + + /* Find DSI-LINK1 */ + np = of_parse_phandle(dsi->dev.of_node, "link2", 0); + if (np) { + secondary = of_find_mipi_dsi_device_by_node(np); + of_node_put(np); + + if (!secondary) + return -EPROBE_DEFER; + } + + /* register a panel for only the DSI-LINK1 interface */ + if (secondary) { + jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL); + if (!jdi) { + put_device(&secondary->dev); + return -ENOMEM; + } + + mipi_dsi_set_drvdata(dsi, jdi); + + jdi->link1 = dsi; + jdi->link2 = secondary; + + err = jdi_panel_add(jdi); + if (err < 0) { + put_device(&secondary->dev); + return err; + } + } + + err = mipi_dsi_attach(dsi); + if (err < 0) { + if (secondary) + jdi_panel_del(jdi); + + return err; + } + + return 0; +} + +static void jdi_panel_dsi_remove(struct mipi_dsi_device *dsi) +{ + struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); + int err; + + /* only detach from host for the DSI-LINK2 interface */ + if (!jdi) + mipi_dsi_detach(dsi); + + err = jdi_panel_disable(&jdi->base); + if (err < 0) + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); + + err = mipi_dsi_detach(dsi); + if (err < 0) + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); + + jdi_panel_del(jdi); +} + +static void jdi_panel_dsi_shutdown(struct mipi_dsi_device *dsi) +{ + struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); + + if (!jdi) + return; + + jdi_panel_disable(&jdi->base); +} + +static struct mipi_dsi_driver jdi_panel_dsi_driver = { + .driver = { + .name = "panel-jdi-lpm102a188a", + .of_match_table = jdi_of_match, + }, + .probe = jdi_panel_dsi_probe, + .remove = jdi_panel_dsi_remove, + .shutdown = jdi_panel_dsi_shutdown, +}; +module_mipi_dsi_driver(jdi_panel_dsi_driver); + +MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>"); +MODULE_AUTHOR("Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>"); +MODULE_DESCRIPTION("DRM Driver for JDI LPM102A188A DSI panel, command mode"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c index 213008499caa..f9a69f347068 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -5,10 +5,6 @@ * * Copyright (C) 2016 Linaro Ltd * Author: Sumit Semwal <sumit.semwal@linaro.org> - * - * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a - * JDI model LT070ME05000, and its data sheet is at: - * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet */ #include <linux/backlight.h> diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index d41482d3a34f..6e3670508e3a 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -24,6 +24,7 @@ struct ltk050h3146w_cmd { struct ltk050h3146w; struct ltk050h3146w_desc { + const unsigned long mode_flags; const struct drm_display_mode *mode; int (*init)(struct ltk050h3146w *ctx); }; @@ -243,6 +244,91 @@ struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel) return container_of(panel, struct ltk050h3146w, panel); } +static int ltk050h3148w_init_sequence(struct ltk050h3146w *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + /* + * Init sequence was supplied by the panel vendor without much + * documentation. + */ + mipi_dsi_dcs_write_seq(dsi, 0xb9, 0xff, 0x83, 0x94); + mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x50, 0x15, 0x75, 0x09, 0x32, 0x44, + 0x71, 0x31, 0x55, 0x2f); + mipi_dsi_dcs_write_seq(dsi, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); + mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x88); + mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x80, 0x64, 0x10, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x05, 0x70, 0x05, 0x70, 0x01, 0x70, + 0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, 0x01, 0x74, + 0x01, 0x74, 0x01, 0x74, 0x01, 0x0c, 0x86); + mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x00, 0x00, 0x07, 0x07, 0x40, 0x1e, + 0x08, 0x00, 0x32, 0x10, 0x08, 0x00, 0x08, 0x54, + 0x15, 0x10, 0x05, 0x04, 0x02, 0x12, 0x10, 0x05, + 0x07, 0x33, 0x34, 0x0c, 0x0c, 0x37, 0x10, 0x07, + 0x17, 0x11, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, + 0x1a, 0x1a, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, + 0x02, 0x03, 0x20, 0x21, 0x18, 0x18, 0x22, 0x23, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq(dsi, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, + 0x1a, 0x1a, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, + 0x05, 0x04, 0x23, 0x22, 0x18, 0x18, 0x21, 0x20, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq(dsi, 0xe0, 0x00, 0x03, 0x09, 0x11, 0x11, 0x14, + 0x18, 0x16, 0x2e, 0x3d, 0x4d, 0x4d, 0x58, 0x6c, + 0x72, 0x78, 0x88, 0x8b, 0x86, 0xa4, 0xb2, 0x58, + 0x55, 0x59, 0x5b, 0x5d, 0x60, 0x64, 0x7f, 0x00, + 0x03, 0x09, 0x0f, 0x11, 0x14, 0x18, 0x16, 0x2e, + 0x3d, 0x4d, 0x4d, 0x58, 0x6d, 0x73, 0x78, 0x88, + 0x8b, 0x87, 0xa5, 0xb2, 0x58, 0x55, 0x58, 0x5b, + 0x5d, 0x61, 0x65, 0x7f); + mipi_dsi_dcs_write_seq(dsi, 0xcc, 0x0b); + mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x1f, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0xb6, 0xc4, 0xc4); + mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xc6, 0xef); + mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x29); + + ret = mipi_dsi_dcs_set_tear_on(dsi, 1); + if (ret < 0) { + dev_err(ctx->dev, "failed to set tear on: %d\n", ret); + return ret; + } + + msleep(60); + + return 0; +} + +static const struct drm_display_mode ltk050h3148w_mode = { + .hdisplay = 720, + .hsync_start = 720 + 12, + .hsync_end = 720 + 12 + 6, + .htotal = 720 + 12 + 6 + 24, + .vdisplay = 1280, + .vsync_start = 1280 + 9, + .vsync_end = 1280 + 9 + 2, + .vtotal = 1280 + 9 + 2 + 16, + .clock = 59756, + .width_mm = 62, + .height_mm = 110, +}; + +static const struct ltk050h3146w_desc ltk050h3148w_data = { + .mode = <k050h3148w_mode, + .init = ltk050h3148w_init_sequence, + .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, +}; + static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); @@ -330,6 +416,8 @@ static const struct drm_display_mode ltk050h3146w_mode = { static const struct ltk050h3146w_desc ltk050h3146w_data = { .mode = <k050h3146w_mode, .init = ltk050h3146w_init_sequence, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, }; static int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page) @@ -424,6 +512,8 @@ static const struct drm_display_mode ltk050h3146w_a2_mode = { static const struct ltk050h3146w_desc ltk050h3146w_a2_data = { .mode = <k050h3146w_a2_mode, .init = ltk050h3146w_a2_init_sequence, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, }; static int ltk050h3146w_unprepare(struct drm_panel *panel) @@ -583,8 +673,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + dsi->mode_flags = ctx->panel_desc->mode_flags; drm_panel_init(&ctx->panel, &dsi->dev, <k050h3146w_funcs, DRM_MODE_CONNECTOR_DSI); @@ -642,6 +731,10 @@ static const struct of_device_id ltk050h3146w_of_match[] = { .compatible = "leadtek,ltk050h3146w-a2", .data = <k050h3146w_a2_data, }, + { + .compatible = "leadtek,ltk050h3148w", + .data = <k050h3148w_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ltk050h3146w_of_match); diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c index ad98dd9322b4..79de6c886292 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c @@ -388,6 +388,13 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + /* + * The panel in the RG351V is identical to the 353P, except it + * requires MIPI_DSI_CLOCK_NON_CONTINUOUS to operate correctly. + */ + if (of_device_is_compatible(dev->of_node, "anbernic,rg351v-panel")) + dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; + drm_panel_init(&ctx->panel, &dsi->dev, &panel_nv3051d_funcs, DRM_MODE_CONNECTOR_DSI); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35950.c b/drivers/gpu/drm/panel/panel-novatek-nt35950.c index 412ca84d0581..648ce9201426 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35950.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35950.c @@ -59,7 +59,6 @@ struct nt35950 { int cur_mode; u8 last_page; - bool prepared; }; struct nt35950_panel_mode { @@ -431,9 +430,6 @@ static int nt35950_prepare(struct drm_panel *panel) struct device *dev = &nt->dsi[0]->dev; int ret; - if (nt->prepared) - return 0; - ret = regulator_enable(nt->vregs[0].consumer); if (ret) return ret; @@ -460,7 +456,6 @@ static int nt35950_prepare(struct drm_panel *panel) dev_err(dev, "Failed to initialize panel: %d\n", ret); goto end; } - nt->prepared = true; end: if (ret < 0) { @@ -477,9 +472,6 @@ static int nt35950_unprepare(struct drm_panel *panel) struct device *dev = &nt->dsi[0]->dev; int ret; - if (!nt->prepared) - return 0; - ret = nt35950_off(nt); if (ret < 0) dev_err(dev, "Failed to deinitialize panel: %d\n", ret); @@ -487,7 +479,6 @@ static int nt35950_unprepare(struct drm_panel *panel) gpiod_set_value_cansleep(nt->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs); - nt->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c index 9632b9e95b71..9b9a7eb1bc60 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c @@ -38,8 +38,6 @@ struct panel_info { struct gpio_desc *reset_gpio; struct backlight_device *backlight; struct regulator *vddio; - - bool prepared; }; struct panel_desc { @@ -1046,9 +1044,6 @@ static int nt36523_prepare(struct drm_panel *panel) struct panel_info *pinfo = to_panel_info(panel); int ret; - if (pinfo->prepared) - return 0; - ret = regulator_enable(pinfo->vddio); if (ret) { dev_err(panel->dev, "failed to enable vddio regulator: %d\n", ret); @@ -1064,8 +1059,6 @@ static int nt36523_prepare(struct drm_panel *panel) return ret; } - pinfo->prepared = true; - return 0; } @@ -1095,14 +1088,9 @@ static int nt36523_unprepare(struct drm_panel *panel) { struct panel_info *pinfo = to_panel_info(panel); - if (!pinfo->prepared) - return 0; - gpiod_set_value_cansleep(pinfo->reset_gpio, 1); regulator_disable(pinfo->vddio); - pinfo->prepared = false; - return 0; } diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index 898b892f1143..93183f30d7d6 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -70,7 +70,6 @@ struct otm8009a { struct gpio_desc *reset_gpio; struct regulator *supply; bool prepared; - bool enabled; }; static const struct drm_display_mode modes[] = { @@ -267,9 +266,6 @@ static int otm8009a_disable(struct drm_panel *panel) struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; - if (!ctx->enabled) - return 0; /* This is not an issue so we return 0 here */ - backlight_disable(ctx->bl_dev); ret = mipi_dsi_dcs_set_display_off(dsi); @@ -282,8 +278,6 @@ static int otm8009a_disable(struct drm_panel *panel) msleep(120); - ctx->enabled = false; - return 0; } @@ -291,9 +285,6 @@ static int otm8009a_unprepare(struct drm_panel *panel) { struct otm8009a *ctx = panel_to_otm8009a(panel); - if (!ctx->prepared) - return 0; - if (ctx->reset_gpio) { gpiod_set_value_cansleep(ctx->reset_gpio, 1); msleep(20); @@ -311,9 +302,6 @@ static int otm8009a_prepare(struct drm_panel *panel) struct otm8009a *ctx = panel_to_otm8009a(panel); int ret; - if (ctx->prepared) - return 0; - ret = regulator_enable(ctx->supply); if (ret < 0) { dev_err(panel->dev, "failed to enable supply: %d\n", ret); @@ -341,13 +329,8 @@ static int otm8009a_enable(struct drm_panel *panel) { struct otm8009a *ctx = panel_to_otm8009a(panel); - if (ctx->enabled) - return 0; - backlight_enable(ctx->bl_dev); - ctx->enabled = true; - return 0; } diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c index 5f9b340588fb..7b7fe987e292 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -77,8 +77,6 @@ struct rm68200 { struct drm_panel panel; struct gpio_desc *reset_gpio; struct regulator *supply; - bool prepared; - bool enabled; }; static const struct drm_display_mode default_mode = { @@ -231,27 +229,12 @@ static void rm68200_init_sequence(struct rm68200 *ctx) dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD1_UCS); } -static int rm68200_disable(struct drm_panel *panel) -{ - struct rm68200 *ctx = panel_to_rm68200(panel); - - if (!ctx->enabled) - return 0; - - ctx->enabled = false; - - return 0; -} - static int rm68200_unprepare(struct drm_panel *panel) { struct rm68200 *ctx = panel_to_rm68200(panel); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; - if (!ctx->prepared) - return 0; - ret = mipi_dsi_dcs_set_display_off(dsi); if (ret) dev_warn(panel->dev, "failed to set display off: %d\n", ret); @@ -269,8 +252,6 @@ static int rm68200_unprepare(struct drm_panel *panel) regulator_disable(ctx->supply); - ctx->prepared = false; - return 0; } @@ -280,9 +261,6 @@ static int rm68200_prepare(struct drm_panel *panel) struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; - if (ctx->prepared) - return 0; - ret = regulator_enable(ctx->supply); if (ret < 0) { dev_err(ctx->dev, "failed to enable supply: %d\n", ret); @@ -310,20 +288,6 @@ static int rm68200_prepare(struct drm_panel *panel) msleep(20); - ctx->prepared = true; - - return 0; -} - -static int rm68200_enable(struct drm_panel *panel) -{ - struct rm68200 *ctx = panel_to_rm68200(panel); - - if (ctx->enabled) - return 0; - - ctx->enabled = true; - return 0; } @@ -352,10 +316,8 @@ static int rm68200_get_modes(struct drm_panel *panel, } static const struct drm_panel_funcs rm68200_drm_funcs = { - .disable = rm68200_disable, .unprepare = rm68200_unprepare, .prepare = rm68200_prepare, - .enable = rm68200_enable, .get_modes = rm68200_get_modes, }; diff --git a/drivers/gpu/drm/panel/panel-raydium-rm692e5.c b/drivers/gpu/drm/panel/panel-raydium-rm692e5.c new file mode 100644 index 000000000000..a613ba5b816c --- /dev/null +++ b/drivers/gpu/drm/panel/panel-raydium-rm692e5.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2023 Linaro Limited + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.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> + +struct rm692e5_panel { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct drm_dsc_config dsc; + struct regulator_bulk_data supplies[3]; + struct gpio_desc *reset_gpio; + bool prepared; +}; + +static inline struct rm692e5_panel *to_rm692e5_panel(struct drm_panel *panel) +{ + return container_of(panel, struct rm692e5_panel, panel); +} + +static void rm692e5_reset(struct rm692e5_panel *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); +} + +static int rm692e5_on(struct rm692e5_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x41); + mipi_dsi_generic_write_seq(dsi, 0xd6, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x16); + mipi_dsi_generic_write_seq(dsi, 0x8a, 0x87); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x71); + mipi_dsi_generic_write_seq(dsi, 0x82, 0x01); + mipi_dsi_generic_write_seq(dsi, 0xc6, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xc7, 0x2c); + mipi_dsi_generic_write_seq(dsi, 0xc8, 0x64); + mipi_dsi_generic_write_seq(dsi, 0xc9, 0x3c); + mipi_dsi_generic_write_seq(dsi, 0xca, 0x80); + mipi_dsi_generic_write_seq(dsi, 0xcb, 0x02); + mipi_dsi_generic_write_seq(dsi, 0xcc, 0x02); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x38); + mipi_dsi_generic_write_seq(dsi, 0x18, 0x13); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf4); + mipi_dsi_generic_write_seq(dsi, 0x00, 0xff); + mipi_dsi_generic_write_seq(dsi, 0x01, 0xff); + mipi_dsi_generic_write_seq(dsi, 0x02, 0xcf); + mipi_dsi_generic_write_seq(dsi, 0x03, 0xbc); + mipi_dsi_generic_write_seq(dsi, 0x04, 0xb9); + mipi_dsi_generic_write_seq(dsi, 0x05, 0x99); + mipi_dsi_generic_write_seq(dsi, 0x06, 0x02); + mipi_dsi_generic_write_seq(dsi, 0x07, 0x0a); + mipi_dsi_generic_write_seq(dsi, 0x08, 0xe0); + mipi_dsi_generic_write_seq(dsi, 0x09, 0x4c); + mipi_dsi_generic_write_seq(dsi, 0x0a, 0xeb); + mipi_dsi_generic_write_seq(dsi, 0x0b, 0xe8); + mipi_dsi_generic_write_seq(dsi, 0x0c, 0x32); + mipi_dsi_generic_write_seq(dsi, 0x0d, 0x07); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf4); + mipi_dsi_generic_write_seq(dsi, 0x0d, 0xc0); + mipi_dsi_generic_write_seq(dsi, 0x0e, 0xff); + mipi_dsi_generic_write_seq(dsi, 0x0f, 0xff); + mipi_dsi_generic_write_seq(dsi, 0x10, 0x33); + mipi_dsi_generic_write_seq(dsi, 0x11, 0x6f); + mipi_dsi_generic_write_seq(dsi, 0x12, 0x6e); + mipi_dsi_generic_write_seq(dsi, 0x13, 0xa6); + mipi_dsi_generic_write_seq(dsi, 0x14, 0x80); + mipi_dsi_generic_write_seq(dsi, 0x15, 0x02); + mipi_dsi_generic_write_seq(dsi, 0x16, 0x38); + mipi_dsi_generic_write_seq(dsi, 0x17, 0xd3); + mipi_dsi_generic_write_seq(dsi, 0x18, 0x3a); + mipi_dsi_generic_write_seq(dsi, 0x19, 0xba); + mipi_dsi_generic_write_seq(dsi, 0x1a, 0xcc); + mipi_dsi_generic_write_seq(dsi, 0x1b, 0x01); + + ret = mipi_dsi_dcs_nop(dsi); + if (ret < 0) { + dev_err(dev, "Failed to nop: %d\n", ret); + return ret; + } + msleep(32); + + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x38); + mipi_dsi_generic_write_seq(dsi, 0x18, 0x13); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0xd1); + mipi_dsi_generic_write_seq(dsi, 0xd3, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xd0, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xd2, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xd4, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xb4, 0x01); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf9); + mipi_dsi_generic_write_seq(dsi, 0x00, 0xaf); + mipi_dsi_generic_write_seq(dsi, 0x1d, 0x37); + mipi_dsi_generic_write_seq(dsi, 0x44, 0x0a, 0x7b); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xfa, 0x01); + mipi_dsi_generic_write_seq(dsi, 0xc2, 0x08); + mipi_dsi_generic_write_seq(dsi, 0x35, 0x00); + mipi_dsi_generic_write_seq(dsi, 0x51, 0x05, 0x42); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + msleep(100); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display on: %d\n", ret); + return ret; + } + + return 0; +} + +static int rm692e5_disable(struct drm_panel *panel) +{ + struct rm692e5_panel *ctx = to_rm692e5_panel(panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x00); + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display off: %d\n", ret); + return ret; + } + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to enter sleep mode: %d\n", ret); + return ret; + } + msleep(100); + + return 0; +} + +static int rm692e5_prepare(struct drm_panel *panel) +{ + struct rm692e5_panel *ctx = to_rm692e5_panel(panel); + struct drm_dsc_picture_parameter_set pps; + struct device *dev = &ctx->dsi->dev; + int ret; + + if (ctx->prepared) + return 0; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + rm692e5_reset(ctx); + + ret = rm692e5_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(ctx->supplies), ctx->supplies); + return ret; + } + + drm_dsc_pps_payload_pack(&pps, &ctx->dsc); + + ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps); + if (ret < 0) { + dev_err(panel->dev, "failed to transmit PPS: %d\n", ret); + return ret; + } + + ret = mipi_dsi_compression_mode(ctx->dsi, true); + if (ret < 0) { + dev_err(dev, "failed to enable compression mode: %d\n", ret); + return ret; + } + + msleep(28); + + mipi_dsi_generic_write_seq(ctx->dsi, 0xfe, 0x40); + + /* 0x05 -> 90Hz, 0x00 -> 60Hz */ + mipi_dsi_generic_write_seq(ctx->dsi, 0xbd, 0x05); + + mipi_dsi_generic_write_seq(ctx->dsi, 0xfe, 0x00); + + ctx->prepared = true; + + return 0; +} + +static int rm692e5_unprepare(struct drm_panel *panel) +{ + struct rm692e5_panel *ctx = to_rm692e5_panel(panel); + + if (!ctx->prepared) + return 0; + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + + ctx->prepared = false; + return 0; +} + +static const struct drm_display_mode rm692e5_mode = { + .clock = (1224 + 32 + 8 + 8) * (2700 + 8 + 2 + 8) * 90 / 1000, + .hdisplay = 1224, + .hsync_start = 1224 + 32, + .hsync_end = 1224 + 32 + 8, + .htotal = 1224 + 32 + 8 + 8, + .vdisplay = 2700, + .vsync_start = 2700 + 8, + .vsync_end = 2700 + 8 + 2, + .vtotal = 2700 + 8 + 2 + 8, + .width_mm = 68, + .height_mm = 150, +}; + +static int rm692e5_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &rm692e5_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs rm692e5_panel_funcs = { + .prepare = rm692e5_prepare, + .unprepare = rm692e5_unprepare, + .disable = rm692e5_disable, + .get_modes = rm692e5_get_modes, +}; + +static int rm692e5_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 rm692e5_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 rm692e5_bl_ops = { + .update_status = rm692e5_bl_update_status, + .get_brightness = rm692e5_bl_get_brightness, +}; + +static struct backlight_device * +rm692e5_create_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, + &rm692e5_bl_ops, &props); +} + +static int rm692e5_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct rm692e5_panel *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->supplies[0].supply = "vddio"; + ctx->supplies[1].supply = "dvdd"; + ctx->supplies[2].supply = "vci"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + 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_NO_EOT_PACKET | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + + drm_panel_init(&ctx->panel, dev, &rm692e5_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = rm692e5_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); + + /* This panel only supports DSC; unconditionally enable it */ + dsi->dsc = &ctx->dsc; + + /* TODO: Pass slice_per_pkt = 2 */ + ctx->dsc.dsc_version_major = 1; + ctx->dsc.dsc_version_minor = 1; + ctx->dsc.slice_height = 60; + ctx->dsc.slice_width = 1224; + + ctx->dsc.slice_count = 1224 / ctx->dsc.slice_width; + ctx->dsc.bits_per_component = 8; + ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ + ctx->dsc.block_pred_enable = true; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "Failed to attach to DSI host: %d\n", ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void rm692e5_remove(struct mipi_dsi_device *dsi) +{ + struct rm692e5_panel *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 rm692e5_of_match[] = { + { .compatible = "fairphone,fp5-rm692e5-boe" }, + { } +}; +MODULE_DEVICE_TABLE(of, rm692e5_of_match); + +static struct mipi_dsi_driver rm692e5_driver = { + .probe = rm692e5_probe, + .remove = rm692e5_remove, + .driver = { + .name = "panel-rm692e5-boe-amoled", + .of_match_table = rm692e5_of_match, + }, +}; +module_mipi_dsi_driver(rm692e5_driver); + +MODULE_DESCRIPTION("DRM driver for rm692e5-equipped DSI panels"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c index b34fa4d5de07..a0e5698275a5 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c @@ -270,9 +270,6 @@ struct s6e63m0 { struct regulator_bulk_data supplies[2]; struct gpio_desc *reset_gpio; - bool prepared; - bool enabled; - /* * This field is tested by functions directly accessing bus before * transfer, transfer is skipped if it is set. In case of transfer @@ -502,9 +499,6 @@ static int s6e63m0_disable(struct drm_panel *panel) { struct s6e63m0 *ctx = panel_to_s6e63m0(panel); - if (!ctx->enabled) - return 0; - backlight_disable(ctx->bl_dev); s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF); @@ -512,8 +506,6 @@ static int s6e63m0_disable(struct drm_panel *panel) s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE); msleep(120); - ctx->enabled = false; - return 0; } @@ -522,17 +514,12 @@ static int s6e63m0_unprepare(struct drm_panel *panel) struct s6e63m0 *ctx = panel_to_s6e63m0(panel); int ret; - if (!ctx->prepared) - return 0; - s6e63m0_clear_error(ctx); ret = s6e63m0_power_off(ctx); if (ret < 0) return ret; - ctx->prepared = false; - return 0; } @@ -541,9 +528,6 @@ static int s6e63m0_prepare(struct drm_panel *panel) struct s6e63m0 *ctx = panel_to_s6e63m0(panel); int ret; - if (ctx->prepared) - return 0; - ret = s6e63m0_power_on(ctx); if (ret < 0) return ret; @@ -564,8 +548,6 @@ static int s6e63m0_prepare(struct drm_panel *panel) if (ret < 0) s6e63m0_unprepare(panel); - ctx->prepared = true; - return ret; } @@ -573,9 +555,6 @@ static int s6e63m0_enable(struct drm_panel *panel) { struct s6e63m0 *ctx = panel_to_s6e63m0(panel); - if (ctx->enabled) - return 0; - s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE); msleep(120); s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON); @@ -588,8 +567,6 @@ static int s6e63m0_enable(struct drm_panel *panel) backlight_enable(ctx->bl_dev); - ctx->enabled = true; - return 0; } @@ -709,8 +686,6 @@ int s6e63m0_probe(struct device *dev, void *trsp, dev_set_drvdata(dev, ctx); ctx->dev = dev; - ctx->enabled = false; - ctx->prepared = false; ret = device_property_read_u32(dev, "max-brightness", &max_brightness); if (ret) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c index 7431cae7427e..d2df227abbea 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c @@ -18,8 +18,6 @@ struct s6e88a0_ams452ef01 { struct mipi_dsi_device *dsi; struct regulator_bulk_data supplies[2]; struct gpio_desc *reset_gpio; - - bool prepared; }; static inline struct @@ -115,9 +113,6 @@ static int s6e88a0_ams452ef01_prepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (ctx->prepared) - return 0; - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) { dev_err(dev, "Failed to enable regulators: %d\n", ret); @@ -135,7 +130,6 @@ static int s6e88a0_ams452ef01_prepare(struct drm_panel *panel) return ret; } - ctx->prepared = true; return 0; } @@ -145,9 +139,6 @@ static int s6e88a0_ams452ef01_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = s6e88a0_ams452ef01_off(ctx); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); @@ -155,7 +146,6 @@ static int s6e88a0_ams452ef01_unprepare(struct drm_panel *panel) gpiod_set_value_cansleep(ctx->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - ctx->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-samsung-sofef00.c b/drivers/gpu/drm/panel/panel-samsung-sofef00.c index cbf9607dd576..04ce925b3d9d 100644 --- a/drivers/gpu/drm/panel/panel-samsung-sofef00.c +++ b/drivers/gpu/drm/panel/panel-samsung-sofef00.c @@ -23,7 +23,6 @@ struct sofef00_panel { struct regulator *supply; struct gpio_desc *reset_gpio; const struct drm_display_mode *mode; - bool prepared; }; static inline @@ -113,9 +112,6 @@ static int sofef00_panel_prepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (ctx->prepared) - return 0; - ret = regulator_enable(ctx->supply); if (ret < 0) { dev_err(dev, "Failed to enable regulator: %d\n", ret); @@ -131,7 +127,6 @@ static int sofef00_panel_prepare(struct drm_panel *panel) return ret; } - ctx->prepared = true; return 0; } @@ -141,16 +136,12 @@ static int sofef00_panel_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = sofef00_panel_off(ctx); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); regulator_disable(ctx->supply); - ctx->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c index 68f52eaaf4fa..74c760ee0c2d 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c @@ -24,7 +24,6 @@ struct sharp_ls060 { struct regulator *avdd_supply; struct regulator *avee_supply; struct gpio_desc *reset_gpio; - bool prepared; }; static inline struct sharp_ls060 *to_sharp_ls060(struct drm_panel *panel) @@ -101,9 +100,6 @@ static int sharp_ls060_prepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (ctx->prepared) - return 0; - ret = regulator_enable(ctx->vddi_supply); if (ret < 0) return ret; @@ -134,8 +130,6 @@ static int sharp_ls060_prepare(struct drm_panel *panel) goto err_on; } - ctx->prepared = true; - return 0; err_on: @@ -163,9 +157,6 @@ static int sharp_ls060_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = sharp_ls060_off(ctx); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); @@ -181,7 +172,6 @@ static int sharp_ls060_unprepare(struct drm_panel *panel) regulator_disable(ctx->vddi_supply); - ctx->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 95959dcc6e0e..4195cf54934b 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -40,6 +40,7 @@ #include <drm/drm_edid.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> +#include <drm/drm_of.h> /** * struct panel_desc - Describes a simple panel. @@ -549,6 +550,51 @@ static void panel_simple_parse_panel_timing_node(struct device *dev, dev_err(dev, "Reject override mode: No display_timing found\n"); } +static int panel_simple_override_nondefault_lvds_datamapping(struct device *dev, + struct panel_simple *panel) +{ + int ret, bpc; + + ret = drm_of_lvds_get_data_mapping(dev->of_node); + if (ret < 0) { + if (ret == -EINVAL) + dev_warn(dev, "Ignore invalid data-mapping property\n"); + + /* + * Ignore non-existing or malformatted property, fallback to + * default data-mapping, and return 0. + */ + return 0; + } + + switch (ret) { + default: + WARN_ON(1); + fallthrough; + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + fallthrough; + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: + bpc = 8; + break; + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + bpc = 6; + } + + if (panel->desc->bpc != bpc || panel->desc->bus_format != ret) { + struct panel_desc *override_desc; + + override_desc = devm_kmemdup(dev, panel->desc, sizeof(*panel->desc), GFP_KERNEL); + if (!override_desc) + return -ENOMEM; + + override_desc->bus_format = ret; + override_desc->bpc = bpc; + panel->desc = override_desc; + } + + return 0; +} + static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) { struct panel_simple *panel; @@ -601,6 +647,13 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel_simple_parse_panel_timing_node(dev, panel, &dt); } + if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { + /* Optional data-mapping property for overriding bus format */ + err = panel_simple_override_nondefault_lvds_datamapping(dev, panel); + if (err) + goto free_ddc; + } + connector_type = desc->connector_type; /* Catch common mistakes for panels. */ switch (connector_type) { @@ -2793,6 +2846,32 @@ static const struct panel_desc mitsubishi_aa070mc01 = { .bus_flags = DRM_BUS_FLAG_DE_HIGH, }; +static const struct drm_display_mode mitsubishi_aa084xe01_mode = { + .clock = 56234, + .hdisplay = 1024, + .hsync_start = 1024 + 24, + .hsync_end = 1024 + 24 + 63, + .htotal = 1024 + 24 + 63 + 1, + .vdisplay = 768, + .vsync_start = 768 + 3, + .vsync_end = 768 + 3 + 6, + .vtotal = 768 + 3 + 6 + 1, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, +}; + +static const struct panel_desc mitsubishi_aa084xe01 = { + .modes = &mitsubishi_aa084xe01_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 1024, + .height = 768, + }, + .bus_format = MEDIA_BUS_FMT_RGB565_1X16, + .connector_type = DRM_MODE_CONNECTOR_DPI, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, +}; + static const struct display_timing multi_inno_mi0700s4t_6_timing = { .pixelclock = { 29000000, 33000000, 38000000 }, .hactive = { 800, 800, 800 }, @@ -4322,6 +4401,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "mitsubishi,aa070mc01-ca1", .data = &mitsubishi_aa070mc01, }, { + .compatible = "mitsubishi,aa084xe01", + .data = &mitsubishi_aa084xe01, + }, { .compatible = "multi-inno,mi0700s4t-6", .data = &multi_inno_mi0700s4t_6, }, { diff --git a/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c b/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c index 1bde2f01786b..472195d4bbbe 100644 --- a/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c +++ b/drivers/gpu/drm/panel/panel-sony-td4353-jdi.c @@ -36,7 +36,6 @@ struct sony_td4353_jdi { struct regulator_bulk_data supplies[3]; struct gpio_desc *panel_reset_gpio; struct gpio_desc *touch_reset_gpio; - bool prepared; int type; }; @@ -150,9 +149,6 @@ static int sony_td4353_jdi_prepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (ctx->prepared) - return 0; - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) { dev_err(dev, "Failed to enable regulators: %d\n", ret); @@ -171,7 +167,6 @@ static int sony_td4353_jdi_prepare(struct drm_panel *panel) return ret; } - ctx->prepared = true; return 0; } @@ -181,9 +176,6 @@ static int sony_td4353_jdi_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = sony_td4353_jdi_off(ctx); if (ret < 0) dev_err(dev, "Failed to power off panel: %d\n", ret); @@ -191,7 +183,6 @@ static int sony_td4353_jdi_unprepare(struct drm_panel *panel) sony_td4353_assert_reset_gpios(ctx, 0); regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - ctx->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c b/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c index ee5d20ecc577..6d44970dccd9 100644 --- a/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c +++ b/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c @@ -23,8 +23,6 @@ struct truly_nt35521 { struct regulator_bulk_data supplies[2]; struct gpio_desc *reset_gpio; struct gpio_desc *blen_gpio; - bool prepared; - bool enabled; }; static inline @@ -296,9 +294,6 @@ static int truly_nt35521_prepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (ctx->prepared) - return 0; - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) { dev_err(dev, "Failed to enable regulators: %d\n", ret); @@ -314,7 +309,6 @@ static int truly_nt35521_prepare(struct drm_panel *panel) return ret; } - ctx->prepared = true; return 0; } @@ -324,9 +318,6 @@ static int truly_nt35521_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = truly_nt35521_off(ctx); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); @@ -335,7 +326,6 @@ static int truly_nt35521_unprepare(struct drm_panel *panel) regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - ctx->prepared = false; return 0; } @@ -343,12 +333,8 @@ static int truly_nt35521_enable(struct drm_panel *panel) { struct truly_nt35521 *ctx = to_truly_nt35521(panel); - if (ctx->enabled) - return 0; - gpiod_set_value_cansleep(ctx->blen_gpio, 1); - ctx->enabled = true; return 0; } @@ -356,12 +342,8 @@ static int truly_nt35521_disable(struct drm_panel *panel) { struct truly_nt35521 *ctx = to_truly_nt35521(panel); - if (!ctx->enabled) - return 0; - gpiod_set_value_cansleep(ctx->blen_gpio, 0); - ctx->enabled = false; return 0; } diff --git a/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c b/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c index 6e77a2d71d81..0156689f41cd 100644 --- a/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c +++ b/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c @@ -35,7 +35,6 @@ enum { }; struct stk_panel { - bool prepared; const struct drm_display_mode *mode; struct backlight_device *backlight; struct drm_panel base; @@ -145,16 +144,11 @@ static int stk_panel_unprepare(struct drm_panel *panel) { struct stk_panel *stk = to_stk_panel(panel); - if (!stk->prepared) - return 0; - stk_panel_off(stk); regulator_bulk_disable(ARRAY_SIZE(stk->supplies), stk->supplies); gpiod_set_value(stk->reset_gpio, 0); gpiod_set_value(stk->enable_gpio, 1); - stk->prepared = false; - return 0; } @@ -164,9 +158,6 @@ static int stk_panel_prepare(struct drm_panel *panel) struct device *dev = &stk->dsi->dev; int ret; - if (stk->prepared) - return 0; - gpiod_set_value(stk->reset_gpio, 0); gpiod_set_value(stk->enable_gpio, 0); ret = regulator_enable(stk->supplies[IOVCC].consumer); @@ -195,8 +186,6 @@ static int stk_panel_prepare(struct drm_panel *panel) goto poweroff; } - stk->prepared = true; - return 0; poweroff: diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c index 845304435e23..f6a212e542cb 100644 --- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c @@ -379,6 +379,8 @@ static int tpg110_get_modes(struct drm_panel *panel, connector->display_info.bus_flags = tpg->panel_mode->bus_flags; mode = drm_mode_duplicate(connector->dev, &tpg->panel_mode->mode); + if (!mode) + return -ENOMEM; drm_mode_set_name(mode); mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c index 4f4009f9fe25..b73448cf349d 100644 --- a/drivers/gpu/drm/panel/panel-truly-nt35597.c +++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c @@ -64,8 +64,6 @@ struct truly_nt35597 { struct mipi_dsi_device *dsi[2]; const struct nt35597_config *config; - bool prepared; - bool enabled; }; static inline struct truly_nt35597 *panel_to_ctx(struct drm_panel *panel) @@ -313,16 +311,12 @@ static int truly_nt35597_disable(struct drm_panel *panel) struct truly_nt35597 *ctx = panel_to_ctx(panel); int ret; - if (!ctx->enabled) - return 0; - if (ctx->backlight) { ret = backlight_disable(ctx->backlight); if (ret < 0) dev_err(ctx->dev, "backlight disable failed %d\n", ret); } - ctx->enabled = false; return 0; } @@ -331,9 +325,6 @@ static int truly_nt35597_unprepare(struct drm_panel *panel) struct truly_nt35597 *ctx = panel_to_ctx(panel); int ret = 0; - if (!ctx->prepared) - return 0; - ctx->dsi[0]->mode_flags = 0; ctx->dsi[1]->mode_flags = 0; @@ -354,7 +345,6 @@ static int truly_nt35597_unprepare(struct drm_panel *panel) if (ret < 0) dev_err(ctx->dev, "power_off failed ret = %d\n", ret); - ctx->prepared = false; return ret; } @@ -367,9 +357,6 @@ static int truly_nt35597_prepare(struct drm_panel *panel) const struct nt35597_config *config; u32 num_cmds; - if (ctx->prepared) - return 0; - ret = truly_35597_power_on(ctx); if (ret < 0) return ret; @@ -409,8 +396,6 @@ static int truly_nt35597_prepare(struct drm_panel *panel) /* Per DSI spec wait 120ms after sending set_display_on DCS command */ msleep(120); - ctx->prepared = true; - return 0; power_off: @@ -424,17 +409,12 @@ static int truly_nt35597_enable(struct drm_panel *panel) struct truly_nt35597 *ctx = panel_to_ctx(panel); int ret; - if (ctx->enabled) - return 0; - if (ctx->backlight) { ret = backlight_enable(ctx->backlight); if (ret < 0) dev_err(ctx->dev, "backlight enable failed %d\n", ret); } - ctx->enabled = true; - return 0; } diff --git a/drivers/gpu/drm/panel/panel-visionox-r66451.c b/drivers/gpu/drm/panel/panel-visionox-r66451.c index 00fc28ad3d07..fbb73464de33 100644 --- a/drivers/gpu/drm/panel/panel-visionox-r66451.c +++ b/drivers/gpu/drm/panel/panel-visionox-r66451.c @@ -22,7 +22,6 @@ struct visionox_r66451 { struct mipi_dsi_device *dsi; struct gpio_desc *reset_gpio; struct regulator_bulk_data supplies[2]; - bool prepared, enabled; }; static inline struct visionox_r66451 *to_visionox_r66451(struct drm_panel *panel) @@ -124,9 +123,6 @@ static int visionox_r66451_prepare(struct drm_panel *panel) struct device *dev = &dsi->dev; int ret; - if (ctx->prepared) - return 0; - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) @@ -144,7 +140,6 @@ static int visionox_r66451_prepare(struct drm_panel *panel) mipi_dsi_compression_mode(ctx->dsi, true); - ctx->prepared = true; return 0; } @@ -154,9 +149,6 @@ static int visionox_r66451_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = visionox_r66451_off(ctx); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); @@ -164,7 +156,6 @@ static int visionox_r66451_unprepare(struct drm_panel *panel) gpiod_set_value_cansleep(ctx->reset_gpio, 1); regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - ctx->prepared = false; return 0; } @@ -190,9 +181,6 @@ static int visionox_r66451_enable(struct drm_panel *panel) struct drm_dsc_picture_parameter_set pps; int ret; - if (ctx->enabled) - return 0; - if (!dsi->dsc) { dev_err(&dsi->dev, "DSC not attached to DSI\n"); return -ENODEV; @@ -219,8 +207,6 @@ static int visionox_r66451_enable(struct drm_panel *panel) } msleep(20); - ctx->enabled = true; - return 0; } @@ -231,8 +217,6 @@ static int visionox_r66451_disable(struct drm_panel *panel) struct device *dev = &dsi->dev; int ret; - ctx->enabled = false; - ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) { dev_err(dev, "Failed to set display off: %d\n", ret); diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c index c2806e4fd553..775144695283 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c @@ -20,8 +20,6 @@ struct visionox_rm69299 { struct regulator_bulk_data supplies[2]; struct gpio_desc *reset_gpio; struct mipi_dsi_device *dsi; - bool prepared; - bool enabled; }; static inline struct visionox_rm69299 *panel_to_ctx(struct drm_panel *panel) @@ -80,7 +78,6 @@ static int visionox_rm69299_unprepare(struct drm_panel *panel) ret = visionox_rm69299_power_off(ctx); - ctx->prepared = false; return ret; } @@ -89,9 +86,6 @@ static int visionox_rm69299_prepare(struct drm_panel *panel) struct visionox_rm69299 *ctx = panel_to_ctx(panel); int ret; - if (ctx->prepared) - return 0; - ret = visionox_rm69299_power_on(ctx); if (ret < 0) return ret; @@ -140,8 +134,6 @@ static int visionox_rm69299_prepare(struct drm_panel *panel) /* Per DSI spec wait 120ms after sending set_display_on DCS command */ msleep(120); - ctx->prepared = true; - return 0; power_off: diff --git a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c index bb0dfd86ea67..a23407b9f6fb 100644 --- a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c +++ b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c @@ -20,7 +20,6 @@ struct visionox_vtdr6130 { struct mipi_dsi_device *dsi; struct gpio_desc *reset_gpio; struct regulator_bulk_data supplies[3]; - bool prepared; }; static inline struct visionox_vtdr6130 *to_visionox_vtdr6130(struct drm_panel *panel) @@ -157,9 +156,6 @@ static int visionox_vtdr6130_prepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (ctx->prepared) - return 0; - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) @@ -175,7 +171,6 @@ static int visionox_vtdr6130_prepare(struct drm_panel *panel) return ret; } - ctx->prepared = true; return 0; } @@ -185,9 +180,6 @@ static int visionox_vtdr6130_unprepare(struct drm_panel *panel) struct device *dev = &ctx->dsi->dev; int ret; - if (!ctx->prepared) - return 0; - ret = visionox_vtdr6130_off(ctx); if (ret < 0) dev_err(dev, "Failed to un-initialize panel: %d\n", ret); @@ -196,7 +188,6 @@ static int visionox_vtdr6130_unprepare(struct drm_panel *panel) regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - ctx->prepared = false; return 0; } diff --git a/drivers/gpu/drm/panfrost/Makefile b/drivers/gpu/drm/panfrost/Makefile index 7da2b3f02ed9..2c01c1e7523e 100644 --- a/drivers/gpu/drm/panfrost/Makefile +++ b/drivers/gpu/drm/panfrost/Makefile @@ -12,4 +12,6 @@ panfrost-y := \ panfrost_perfcnt.o \ panfrost_dump.o +panfrost-$(CONFIG_DEBUG_FS) += panfrost_debugfs.o + obj-$(CONFIG_DRM_PANFROST) += panfrost.o diff --git a/drivers/gpu/drm/panfrost/panfrost_debugfs.c b/drivers/gpu/drm/panfrost/panfrost_debugfs.c new file mode 100644 index 000000000000..72d4286a6bf7 --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_debugfs.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright 2023 Collabora ltd. */ +/* Copyright 2023 Amazon.com, Inc. or its affiliates. */ + +#include <linux/debugfs.h> +#include <linux/platform_device.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_file.h> +#include <drm/panfrost_drm.h> + +#include "panfrost_device.h" +#include "panfrost_gpu.h" +#include "panfrost_debugfs.h" + +void panfrost_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev->dev)); + + debugfs_create_atomic_t("profile", 0600, minor->debugfs_root, &pfdev->profile_mode); +} diff --git a/drivers/gpu/drm/panfrost/panfrost_debugfs.h b/drivers/gpu/drm/panfrost/panfrost_debugfs.h new file mode 100644 index 000000000000..c5af5f35877f --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_debugfs.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2023 Collabora ltd. + * Copyright 2023 Amazon.com, Inc. or its affiliates. + */ + +#ifndef PANFROST_DEBUGFS_H +#define PANFROST_DEBUGFS_H + +#ifdef CONFIG_DEBUG_FS +void panfrost_debugfs_init(struct drm_minor *minor); +#endif + +#endif /* PANFROST_DEBUGFS_H */ diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index 58dfb15a8757..f59c82ea8870 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -58,6 +58,7 @@ static int panfrost_devfreq_get_dev_status(struct device *dev, spin_lock_irqsave(&pfdevfreq->lock, irqflags); panfrost_devfreq_update_utilization(pfdevfreq); + pfdevfreq->current_frequency = status->current_frequency; status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, pfdevfreq->idle_time)); @@ -96,7 +97,7 @@ static int panfrost_read_speedbin(struct device *dev) * keep going without it; any other error means that we are * supposed to read the bin value, but we failed doing so. */ - if (ret != -ENOENT) { + if (ret != -ENOENT && ret != -EOPNOTSUPP) { DRM_DEV_ERROR(dev, "Cannot read speed-bin (%d).", ret); return ret; } @@ -117,6 +118,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) struct devfreq *devfreq; struct thermal_cooling_device *cooling; struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + unsigned long freq = ULONG_MAX; if (pfdev->comp->num_supplies > 1) { /* @@ -172,6 +174,12 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) return ret; } + /* Find the fastest defined rate */ + opp = dev_pm_opp_find_freq_floor(dev, &freq); + if (IS_ERR(opp)) + return PTR_ERR(opp); + pfdevfreq->fast_rate = freq; + dev_pm_opp_put(opp); /* diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h index 1514c1f9d91c..48dbe185f206 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h @@ -19,6 +19,9 @@ struct panfrost_devfreq { struct devfreq_simple_ondemand_data gov_data; bool opp_of_table_added; + unsigned long current_frequency; + unsigned long fast_rate; + ktime_t busy_time; ktime_t idle_time; ktime_t time_last_update; diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index fa1a086a862b..28f7046e1b1a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -207,6 +207,8 @@ int panfrost_device_init(struct panfrost_device *pfdev) spin_lock_init(&pfdev->as_lock); + spin_lock_init(&pfdev->cycle_counter.lock); + err = panfrost_clk_init(pfdev); if (err) { dev_err(pfdev->dev, "clk init failed %d\n", err); diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index b0126b9fbadc..1e85656dc2f7 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -107,6 +107,7 @@ struct panfrost_device { struct list_head scheduled_jobs; struct panfrost_perfcnt *perfcnt; + atomic_t profile_mode; struct mutex sched_lock; @@ -121,6 +122,11 @@ struct panfrost_device { struct shrinker shrinker; struct panfrost_devfreq pfdevfreq; + + struct { + atomic_t use_count; + spinlock_t lock; + } cycle_counter; }; struct panfrost_mmu { @@ -135,12 +141,19 @@ struct panfrost_mmu { struct list_head list; }; +struct panfrost_engine_usage { + unsigned long long elapsed_ns[NUM_JOB_SLOTS]; + unsigned long long cycles[NUM_JOB_SLOTS]; +}; + struct panfrost_file_priv { struct panfrost_device *pfdev; struct drm_sched_entity sched_entity[NUM_JOB_SLOTS]; struct panfrost_mmu *mmu; + + struct panfrost_engine_usage engine_usage; }; static inline struct panfrost_device *to_panfrost_device(struct drm_device *ddev) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index a2ab99698ca8..b834777b409b 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -20,6 +20,7 @@ #include "panfrost_job.h" #include "panfrost_gpu.h" #include "panfrost_perfcnt.h" +#include "panfrost_debugfs.h" static bool unstable_ioctls; module_param_unsafe(unstable_ioctls, bool, 0600); @@ -267,6 +268,7 @@ static int panfrost_ioctl_submit(struct drm_device *dev, void *data, job->requirements = args->requirements; job->flush_id = panfrost_gpu_get_latest_flush_id(pfdev); job->mmu = file_priv->mmu; + job->engine_usage = &file_priv->engine_usage; slot = panfrost_job_get_slot(job); @@ -523,7 +525,58 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { PANFROST_IOCTL(MADVISE, madvise, DRM_RENDER_ALLOW), }; -DEFINE_DRM_GEM_FOPS(panfrost_drm_driver_fops); +static void panfrost_gpu_show_fdinfo(struct panfrost_device *pfdev, + struct panfrost_file_priv *panfrost_priv, + struct drm_printer *p) +{ + int i; + + /* + * IMPORTANT NOTE: drm-cycles and drm-engine measurements are not + * accurate, as they only provide a rough estimation of the number of + * GPU cycles and CPU time spent in a given context. This is due to two + * different factors: + * - Firstly, we must consider the time the CPU and then the kernel + * takes to process the GPU interrupt, which means additional time and + * GPU cycles will be added in excess to the real figure. + * - Secondly, the pipelining done by the Job Manager (2 job slots per + * engine) implies there is no way to know exactly how much time each + * job spent on the GPU. + */ + + static const char * const engine_names[] = { + "fragment", "vertex-tiler", "compute-only" + }; + + BUILD_BUG_ON(ARRAY_SIZE(engine_names) != NUM_JOB_SLOTS); + + for (i = 0; i < NUM_JOB_SLOTS - 1; i++) { + drm_printf(p, "drm-engine-%s:\t%llu ns\n", + engine_names[i], panfrost_priv->engine_usage.elapsed_ns[i]); + drm_printf(p, "drm-cycles-%s:\t%llu\n", + engine_names[i], panfrost_priv->engine_usage.cycles[i]); + drm_printf(p, "drm-maxfreq-%s:\t%lu Hz\n", + engine_names[i], pfdev->pfdevfreq.fast_rate); + drm_printf(p, "drm-curfreq-%s:\t%lu Hz\n", + engine_names[i], pfdev->pfdevfreq.current_frequency); + } +} + +static void panfrost_show_fdinfo(struct drm_printer *p, struct drm_file *file) +{ + struct drm_device *dev = file->minor->dev; + struct panfrost_device *pfdev = dev->dev_private; + + panfrost_gpu_show_fdinfo(pfdev, file->driver_priv, p); + + drm_show_memory_stats(p, file); +} + +static const struct file_operations panfrost_drm_driver_fops = { + .owner = THIS_MODULE, + DRM_GEM_FOPS, + .show_fdinfo = drm_show_fdinfo, +}; /* * Panfrost driver version: @@ -535,6 +588,7 @@ static const struct drm_driver panfrost_drm_driver = { .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, .open = panfrost_open, .postclose = panfrost_postclose, + .show_fdinfo = panfrost_show_fdinfo, .ioctls = panfrost_drm_driver_ioctls, .num_ioctls = ARRAY_SIZE(panfrost_drm_driver_ioctls), .fops = &panfrost_drm_driver_fops, @@ -546,6 +600,10 @@ static const struct drm_driver panfrost_drm_driver = { .gem_create_object = panfrost_gem_create_object, .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, + +#ifdef CONFIG_DEBUG_FS + .debugfs_init = panfrost_debugfs_init, +#endif }; static int panfrost_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c index 3c812fbd126f..0cf64456e29a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c @@ -195,6 +195,34 @@ static int panfrost_gem_pin(struct drm_gem_object *obj) return drm_gem_shmem_pin(&bo->base); } +static enum drm_gem_object_status panfrost_gem_status(struct drm_gem_object *obj) +{ + struct panfrost_gem_object *bo = to_panfrost_bo(obj); + enum drm_gem_object_status res = 0; + + if (bo->base.pages) + res |= DRM_GEM_OBJECT_RESIDENT; + + if (bo->base.madv == PANFROST_MADV_DONTNEED) + res |= DRM_GEM_OBJECT_PURGEABLE; + + return res; +} + +static size_t panfrost_gem_rss(struct drm_gem_object *obj) +{ + struct panfrost_gem_object *bo = to_panfrost_bo(obj); + + if (bo->is_heap) { + return bo->heap_rss_size; + } else if (bo->base.pages) { + WARN_ON(bo->heap_rss_size); + return bo->base.base.size; + } + + return 0; +} + static const struct drm_gem_object_funcs panfrost_gem_funcs = { .free = panfrost_gem_free_object, .open = panfrost_gem_open, @@ -206,6 +234,8 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = { .vmap = drm_gem_shmem_object_vmap, .vunmap = drm_gem_shmem_object_vunmap, .mmap = drm_gem_shmem_object_mmap, + .status = panfrost_gem_status, + .rss = panfrost_gem_rss, .vm_ops = &drm_gem_shmem_vm_ops, }; diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h index ad2877eeeccd..13c0a8149c3a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.h +++ b/drivers/gpu/drm/panfrost/panfrost_gem.h @@ -36,6 +36,11 @@ struct panfrost_gem_object { */ atomic_t gpu_usecount; + /* + * Object chunk size currently mapped onto physical memory + */ + size_t heap_rss_size; + bool noexec :1; bool is_heap :1; }; diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index d28b99732dde..f0be7e19b13e 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -73,6 +73,13 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL); gpu_write(pfdev, GPU_INT_MASK, GPU_IRQ_MASK_ALL); + /* + * All in-flight jobs should have released their cycle + * counter references upon reset, but let us make sure + */ + if (drm_WARN_ON(pfdev->ddev, atomic_read(&pfdev->cycle_counter.use_count) != 0)) + atomic_set(&pfdev->cycle_counter.use_count, 0); + return 0; } @@ -321,6 +328,40 @@ static void panfrost_gpu_init_features(struct panfrost_device *pfdev) pfdev->features.shader_present, pfdev->features.l2_present); } +void panfrost_cycle_counter_get(struct panfrost_device *pfdev) +{ + if (atomic_inc_not_zero(&pfdev->cycle_counter.use_count)) + return; + + spin_lock(&pfdev->cycle_counter.lock); + if (atomic_inc_return(&pfdev->cycle_counter.use_count) == 1) + gpu_write(pfdev, GPU_CMD, GPU_CMD_CYCLE_COUNT_START); + spin_unlock(&pfdev->cycle_counter.lock); +} + +void panfrost_cycle_counter_put(struct panfrost_device *pfdev) +{ + if (atomic_add_unless(&pfdev->cycle_counter.use_count, -1, 1)) + return; + + spin_lock(&pfdev->cycle_counter.lock); + if (atomic_dec_return(&pfdev->cycle_counter.use_count) == 0) + gpu_write(pfdev, GPU_CMD, GPU_CMD_CYCLE_COUNT_STOP); + spin_unlock(&pfdev->cycle_counter.lock); +} + +unsigned long long panfrost_cycle_counter_read(struct panfrost_device *pfdev) +{ + u32 hi, lo; + + do { + hi = gpu_read(pfdev, GPU_CYCLE_COUNT_HI); + lo = gpu_read(pfdev, GPU_CYCLE_COUNT_LO); + } while (hi != gpu_read(pfdev, GPU_CYCLE_COUNT_HI)); + + return ((u64)hi << 32) | lo; +} + void panfrost_gpu_power_on(struct panfrost_device *pfdev) { int ret; @@ -390,8 +431,8 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) dma_set_max_seg_size(pfdev->dev, UINT_MAX); irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); - if (irq <= 0) - return -ENODEV; + if (irq < 0) + return irq; err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler, IRQF_SHARED, KBUILD_MODNAME "-gpu", pfdev); diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h index 468c51e7e46d..876fdad9f721 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.h +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h @@ -16,6 +16,10 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev); void panfrost_gpu_power_on(struct panfrost_device *pfdev); void panfrost_gpu_power_off(struct panfrost_device *pfdev); +void panfrost_cycle_counter_get(struct panfrost_device *pfdev); +void panfrost_cycle_counter_put(struct panfrost_device *pfdev); +unsigned long long panfrost_cycle_counter_read(struct panfrost_device *pfdev); + void panfrost_gpu_amlogic_quirk(struct panfrost_device *pfdev); #endif diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index a8b4827dc425..fb16de2d0420 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -159,6 +159,16 @@ panfrost_dequeue_job(struct panfrost_device *pfdev, int slot) struct panfrost_job *job = pfdev->jobs[slot][0]; WARN_ON(!job); + if (job->is_profiled) { + if (job->engine_usage) { + job->engine_usage->elapsed_ns[slot] += + ktime_to_ns(ktime_sub(ktime_get(), job->start_time)); + job->engine_usage->cycles[slot] += + panfrost_cycle_counter_read(pfdev) - job->start_cycles; + } + panfrost_cycle_counter_put(job->pfdev); + } + pfdev->jobs[slot][0] = pfdev->jobs[slot][1]; pfdev->jobs[slot][1] = NULL; @@ -233,6 +243,13 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) subslot = panfrost_enqueue_job(pfdev, js, job); /* Don't queue the job if a reset is in progress */ if (!atomic_read(&pfdev->reset.pending)) { + if (atomic_read(&pfdev->profile_mode)) { + panfrost_cycle_counter_get(pfdev); + job->is_profiled = true; + job->start_time = ktime_get(); + job->start_cycles = panfrost_cycle_counter_read(pfdev); + } + job_write(pfdev, JS_COMMAND_NEXT(js), JS_COMMAND_START); dev_dbg(pfdev->dev, "JS: Submitting atom %p to js[%d][%d] with head=0x%llx AS %d", @@ -660,10 +677,14 @@ panfrost_reset(struct panfrost_device *pfdev, * stuck jobs. Let's make sure the PM counters stay balanced by * manually calling pm_runtime_put_noidle() and * panfrost_devfreq_record_idle() for each stuck job. + * Let's also make sure the cycle counting register's refcnt is + * kept balanced to prevent it from running forever */ spin_lock(&pfdev->js->job_lock); for (i = 0; i < NUM_JOB_SLOTS; i++) { for (j = 0; j < ARRAY_SIZE(pfdev->jobs[0]) && pfdev->jobs[i][j]; j++) { + if (pfdev->jobs[i][j]->is_profiled) + panfrost_cycle_counter_put(pfdev->jobs[i][j]->pfdev); pm_runtime_put_noidle(pfdev->dev); panfrost_devfreq_record_idle(&pfdev->pfdevfreq); } @@ -810,8 +831,8 @@ int panfrost_job_init(struct panfrost_device *pfdev) spin_lock_init(&js->job_lock); js->irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "job"); - if (js->irq <= 0) - return -ENODEV; + if (js->irq < 0) + return js->irq; ret = devm_request_threaded_irq(pfdev->dev, js->irq, panfrost_job_irq_handler, @@ -926,6 +947,9 @@ void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) } job_write(pfdev, JS_COMMAND(i), cmd); + + /* Jobs can outlive their file context */ + job->engine_usage = NULL; } } spin_unlock(&pfdev->js->job_lock); diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h index 8becc1ba0eb9..17ff808dba07 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.h +++ b/drivers/gpu/drm/panfrost/panfrost_job.h @@ -32,6 +32,11 @@ struct panfrost_job { /* Fence to be signaled by drm-sched once its done with the job */ struct dma_fence *render_done_fence; + + struct panfrost_engine_usage *engine_usage; + bool is_profiled; + ktime_t start_time; + u64 start_cycles; }; int panfrost_job_init(struct panfrost_device *pfdev); diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index c0123d09f699..846dd697c410 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -522,6 +522,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, IOMMU_WRITE | IOMMU_READ | IOMMU_NOEXEC, sgt); bomapping->active = true; + bo->heap_rss_size += SZ_2M; dev_dbg(pfdev->dev, "mapped page fault @ AS%d %llx", as, addr); @@ -755,8 +756,8 @@ int panfrost_mmu_init(struct panfrost_device *pfdev) int err, irq; irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu"); - if (irq <= 0) - return -ENODEV; + if (irq < 0) + return irq; err = devm_request_threaded_irq(pfdev->dev, irq, panfrost_mmu_irq_handler, diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h index 919f44ac853d..55ec807550b3 100644 --- a/drivers/gpu/drm/panfrost/panfrost_regs.h +++ b/drivers/gpu/drm/panfrost/panfrost_regs.h @@ -46,6 +46,8 @@ #define GPU_CMD_SOFT_RESET 0x01 #define GPU_CMD_PERFCNT_CLEAR 0x03 #define GPU_CMD_PERFCNT_SAMPLE 0x04 +#define GPU_CMD_CYCLE_COUNT_START 0x05 +#define GPU_CMD_CYCLE_COUNT_STOP 0x06 #define GPU_CMD_CLEAN_CACHES 0x07 #define GPU_CMD_CLEAN_INV_CACHES 0x08 #define GPU_STATUS 0x34 @@ -73,6 +75,9 @@ #define GPU_PRFCNT_TILER_EN 0x74 #define GPU_PRFCNT_MMU_L2_EN 0x7c +#define GPU_CYCLE_COUNT_LO 0x90 +#define GPU_CYCLE_COUNT_HI 0x94 + #define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */ #define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */ #define GPU_THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */ diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index ba3b5b5f0cdf..02e6b74d5016 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -323,12 +323,18 @@ static void pl111_amba_remove(struct amba_device *amba_dev) struct pl111_drm_dev_private *priv = drm->dev_private; drm_dev_unregister(drm); + drm_atomic_helper_shutdown(drm); if (priv->panel) drm_panel_bridge_remove(priv->bridge); drm_dev_put(drm); of_reserved_mem_device_release(dev); } +static void pl111_amba_shutdown(struct amba_device *amba_dev) +{ + drm_atomic_helper_shutdown(amba_get_drvdata(amba_dev)); +} + /* * This early variant lacks the 565 and 444 pixel formats. */ @@ -431,6 +437,7 @@ static struct amba_driver pl111_amba_driver __maybe_unused = { }, .probe = pl111_amba_probe, .remove = pl111_amba_remove, + .shutdown = pl111_amba_shutdown, .id_table = pl111_id_table, }; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index b30ede1cf62d..a4144c62ca93 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -163,6 +163,12 @@ qxl_pci_remove(struct pci_dev *pdev) vga_put(pdev, VGA_RSRC_LEGACY_IO); } +static void +qxl_pci_shutdown(struct pci_dev *pdev) +{ + drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); +} + DEFINE_DRM_GEM_FOPS(qxl_fops); static int qxl_drm_freeze(struct drm_device *dev) @@ -269,6 +275,7 @@ static struct pci_driver qxl_pci_driver = { .id_table = pciidlist, .probe = qxl_pci_probe, .remove = qxl_pci_remove, + .shutdown = qxl_pci_shutdown, .driver.pm = &qxl_pm_ops, }; diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 5d6b81a6578e..10be30366c2b 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -9534,17 +9534,8 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) u16 bridge_cfg2, gpu_cfg2; u32 max_lw, current_lw, tmp; - pcie_capability_read_word(root, PCI_EXP_LNKCTL, - &bridge_cfg); - pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL, - &gpu_cfg); - - tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; - pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16); - - tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; - pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL, - tmp16); + pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); + pcie_capability_set_word(rdev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); tmp = RREG32_PCIE_PORT(PCIE_LC_STATUS1); max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT; @@ -9591,21 +9582,14 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) msleep(100); /* linkctl */ - pcie_capability_read_word(root, PCI_EXP_LNKCTL, - &tmp16); - tmp16 &= ~PCI_EXP_LNKCTL_HAWD; - tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); - pcie_capability_write_word(root, PCI_EXP_LNKCTL, - tmp16); - - pcie_capability_read_word(rdev->pdev, - PCI_EXP_LNKCTL, - &tmp16); - tmp16 &= ~PCI_EXP_LNKCTL_HAWD; - tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); - pcie_capability_write_word(rdev->pdev, - PCI_EXP_LNKCTL, - tmp16); + pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_HAWD, + bridge_cfg & + PCI_EXP_LNKCTL_HAWD); + pcie_capability_clear_and_set_word(rdev->pdev, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_HAWD, + gpu_cfg & + PCI_EXP_LNKCTL_HAWD); /* linkctl2 */ pcie_capability_read_word(root, PCI_EXP_LNKCTL2, diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index c87a57c9c592..22dd8b445685 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -123,7 +123,7 @@ int radeon_sa_bo_new(struct radeon_sa_manager *sa_manager, unsigned int size, unsigned int align) { struct drm_suballoc *sa = drm_suballoc_new(&sa_manager->base, size, - GFP_KERNEL, true, align); + GFP_KERNEL, false, align); if (IS_ERR(sa)) { *sa_bo = NULL; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 8d5e4b25609d..a91012447b56 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -7131,17 +7131,8 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) u16 bridge_cfg2, gpu_cfg2; u32 max_lw, current_lw, tmp; - pcie_capability_read_word(root, PCI_EXP_LNKCTL, - &bridge_cfg); - pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL, - &gpu_cfg); - - tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; - pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16); - - tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; - pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL, - tmp16); + pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); + pcie_capability_set_word(rdev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD); tmp = RREG32_PCIE(PCIE_LC_STATUS1); max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT; @@ -7188,22 +7179,14 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) msleep(100); /* linkctl */ - pcie_capability_read_word(root, PCI_EXP_LNKCTL, - &tmp16); - tmp16 &= ~PCI_EXP_LNKCTL_HAWD; - tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); - pcie_capability_write_word(root, - PCI_EXP_LNKCTL, - tmp16); - - pcie_capability_read_word(rdev->pdev, - PCI_EXP_LNKCTL, - &tmp16); - tmp16 &= ~PCI_EXP_LNKCTL_HAWD; - tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); - pcie_capability_write_word(rdev->pdev, - PCI_EXP_LNKCTL, - tmp16); + pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_HAWD, + bridge_cfg & + PCI_EXP_LNKCTL_HAWD); + pcie_capability_clear_and_set_word(rdev->pdev, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_HAWD, + gpu_cfg & + PCI_EXP_LNKCTL_HAWD); /* linkctl2 */ pcie_capability_read_word(root, PCI_EXP_LNKCTL2, diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index 30493ce87419..e5db4e0095ba 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -172,7 +172,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(shmob_drm_pm_ops, * Platform driver */ -static int shmob_drm_remove(struct platform_device *pdev) +static void shmob_drm_remove(struct platform_device *pdev) { struct shmob_drm_device *sdev = platform_get_drvdata(pdev); struct drm_device *ddev = sdev->ddev; @@ -181,8 +181,6 @@ static int shmob_drm_remove(struct platform_device *pdev) drm_kms_helper_poll_fini(ddev); free_irq(sdev->irq, ddev); drm_dev_put(ddev); - - return 0; } static int shmob_drm_probe(struct platform_device *pdev) @@ -288,7 +286,7 @@ err_free_drm_dev: static struct platform_driver shmob_drm_platform_driver = { .probe = shmob_drm_probe, - .remove = shmob_drm_remove, + .remove_new = shmob_drm_remove, .driver = { .name = "shmob-drm", .pm = pm_sleep_ptr(&shmob_drm_pm_ops), diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index a29fbafce393..21254e4e107a 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1177,6 +1177,7 @@ static int cdn_dp_probe(struct platform_device *pdev) struct cdn_dp_device *dp; struct extcon_dev *extcon; struct phy *phy; + int ret; int i; dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); @@ -1217,9 +1218,19 @@ static int cdn_dp_probe(struct platform_device *pdev) mutex_init(&dp->lock); dev_set_drvdata(dev, dp); - cdn_dp_audio_codec_init(dp, dev); + ret = cdn_dp_audio_codec_init(dp, dev); + if (ret) + return ret; + + ret = component_add(dev, &cdn_dp_component_ops); + if (ret) + goto err_audio_deinit; - return component_add(dev, &cdn_dp_component_ops); + return 0; + +err_audio_deinit: + platform_device_unregister(dp->audio_pdev); + return ret; } static void cdn_dp_remove(struct platform_device *pdev) @@ -1250,7 +1261,7 @@ struct platform_driver cdn_dp_driver = { .driver = { .name = "cdn-dp", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(cdn_dp_dt_ids), + .of_match_table = cdn_dp_dt_ids, .pm = &cdn_dp_pm_ops, }, }; diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 0100162a73b2..6396f9324dab 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -198,6 +198,11 @@ #define RK3568_DSI1_TURNDISABLE BIT(2) #define RK3568_DSI1_FORCERXMODE BIT(0) +#define RV1126_GRF_DSIPHY_CON 0x10220 +#define RV1126_DSI_FORCETXSTOPMODE (0xf << 4) +#define RV1126_DSI_TURNDISABLE BIT(2) +#define RV1126_DSI_FORCERXMODE BIT(0) + #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) enum { @@ -1353,8 +1358,7 @@ static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev) if (!dsi) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dsi->base = devm_ioremap_resource(dev, res); + dsi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dsi->base)) { DRM_DEV_ERROR(dev, "Unable to get dsi registers\n"); return PTR_ERR(dsi->base); @@ -1651,6 +1655,18 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = { { /* sentinel */ } }; +static const struct rockchip_dw_dsi_chip_data rv1126_chip_data[] = { + { + .reg = 0xffb30000, + .lanecfg1_grf_reg = RV1126_GRF_DSIPHY_CON, + .lanecfg1 = HIWORD_UPDATE(0, RV1126_DSI_TURNDISABLE | + RV1126_DSI_FORCERXMODE | + RV1126_DSI_FORCETXSTOPMODE), + .max_data_lanes = 4, + }, + { /* sentinel */ } +}; + static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { { .compatible = "rockchip,px30-mipi-dsi", @@ -1664,6 +1680,9 @@ static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { }, { .compatible = "rockchip,rk3568-mipi-dsi", .data = &rk3568_chip_data, + }, { + .compatible = "rockchip,rv1126-mipi-dsi", + .data = &rv1126_chip_data, }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 14320bc73e5b..e1ea50c8fd39 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -765,11 +765,6 @@ out: } } -static void vop_plane_destroy(struct drm_plane *plane) -{ - drm_plane_cleanup(plane); -} - static inline bool rockchip_afbc(u64 modifier) { return modifier == ROCKCHIP_AFBC_MOD; @@ -1131,7 +1126,7 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = { static const struct drm_plane_funcs vop_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = vop_plane_destroy, + .destroy = drm_plane_cleanup, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, @@ -1602,11 +1597,6 @@ static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { .atomic_disable = vop_crtc_atomic_disable, }; -static void vop_crtc_destroy(struct drm_crtc *crtc) -{ - drm_crtc_cleanup(crtc); -} - static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) { struct rockchip_crtc_state *rockchip_state; @@ -1614,7 +1604,8 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) if (WARN_ON(!crtc->state)) return NULL; - rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL); + rockchip_state = kmemdup(to_rockchip_crtc_state(crtc->state), + sizeof(*rockchip_state), GFP_KERNEL); if (!rockchip_state) return NULL; @@ -1639,7 +1630,10 @@ static void vop_crtc_reset(struct drm_crtc *crtc) if (crtc->state) vop_crtc_destroy_state(crtc, crtc->state); - __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base); + if (crtc_state) + __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); } #ifdef CONFIG_DRM_ANALOGIX_DP @@ -1710,7 +1704,7 @@ vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, static const struct drm_crtc_funcs vop_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .destroy = vop_crtc_destroy, + .destroy = drm_crtc_cleanup, .reset = vop_crtc_reset, .atomic_duplicate_state = vop_crtc_duplicate_state, .atomic_destroy_state = vop_crtc_destroy_state, @@ -1961,7 +1955,7 @@ static void vop_destroy_crtc(struct vop *vop) */ list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, head) - vop_plane_destroy(plane); + drm_plane_cleanup(plane); /* * Destroy CRTC after vop_plane_destroy() since vop_disable_plane() diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 583df4d22f7e..ec7e0e6149af 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -469,8 +469,8 @@ static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format, return true; if (!rockchip_afbc(plane, modifier)) { - drm_err(vop2->drm, "Unsupported format modifier 0x%llx\n", - modifier); + drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n", + modifier); return false; } @@ -2079,30 +2079,15 @@ static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = { .atomic_disable = vop2_crtc_atomic_disable, }; -static void vop2_crtc_reset(struct drm_crtc *crtc) -{ - struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); - - if (crtc->state) { - __drm_atomic_helper_crtc_destroy_state(crtc->state); - kfree(vcstate); - } - - vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL); - if (!vcstate) - return; - - crtc->state = &vcstate->base; - crtc->state->crtc = crtc; -} - static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc) { - struct rockchip_crtc_state *vcstate, *old_vcstate; + struct rockchip_crtc_state *vcstate; - old_vcstate = to_rockchip_crtc_state(crtc->state); + if (WARN_ON(!crtc->state)) + return NULL; - vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL); + vcstate = kmemdup(to_rockchip_crtc_state(crtc->state), + sizeof(*vcstate), GFP_KERNEL); if (!vcstate) return NULL; @@ -2120,6 +2105,20 @@ static void vop2_crtc_destroy_state(struct drm_crtc *crtc, kfree(vcstate); } +static void vop2_crtc_reset(struct drm_crtc *crtc) +{ + struct rockchip_crtc_state *vcstate = + kzalloc(sizeof(*vcstate), GFP_KERNEL); + + if (crtc->state) + vop2_crtc_destroy_state(crtc, crtc->state); + + if (vcstate) + __drm_atomic_helper_crtc_reset(crtc, &vcstate->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); +} + static const struct drm_crtc_funcs vop2_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, @@ -2641,7 +2640,7 @@ static const struct regmap_config vop2_regmap_config = { .max_register = 0x3000, .name = "vop2", .volatile_table = &vop2_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int vop2_bind(struct device *dev, struct device *master, void *data) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 582859387792..f0f47e9abf5a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -752,6 +752,6 @@ struct platform_driver rockchip_lvds_driver = { .remove_new = rockchip_lvds_remove, .driver = { .name = "rockchip-lvds", - .of_match_table = of_match_ptr(rockchip_lvds_dt_ids), + .of_match_table = rockchip_lvds_dt_ids, }, }; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 62b573f282a7..fcd4cf3072cd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -274,6 +274,6 @@ struct platform_driver vop2_platform_driver = { .remove_new = vop2_remove, .driver = { .name = "rockchip-vop2", - .of_match_table = of_match_ptr(vop2_dt_match), + .of_match_table = vop2_dt_match, }, }; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 7b2805006776..d053ef027552 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -1120,6 +1120,59 @@ static const struct vop_data rk3328_vop = { .max_output = { 4096, 2160 }, }; +static const struct vop_common rv1126_common = { + .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1), + .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16), + .dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14), + .dither_down_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 8), + .dither_down_sel = VOP_REG(PX30_DSP_CTRL2, 0x1, 7), + .dither_down_mode = VOP_REG(PX30_DSP_CTRL2, 0x1, 6), + .cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0), + .dither_up = VOP_REG(PX30_DSP_CTRL2, 0x1, 2), + .dsp_lut_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 5), + .gate_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 0), +}; + +static const struct vop_modeset rv1126_modeset = { + .htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0), +}; + +static const struct vop_output rv1126_output = { + .rgb_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 1), + .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 2), + .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0), + .mipi_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 25), + .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 26), + .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24), +}; + +static const struct vop_misc rv1126_misc = { + .global_regdone_en = VOP_REG(PX30_SYS_CTRL2, 0x1, 13), +}; + +static const struct vop_win_data rv1126_vop_win_data[] = { + { .base = 0x00, .phy = &px30_win0_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &px30_win2_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +}; + +static const struct vop_data rv1126_vop = { + .version = VOP_VERSION(2, 0xb), + .intr = &px30_intr, + .common = &rv1126_common, + .modeset = &rv1126_modeset, + .output = &rv1126_output, + .misc = &rv1126_misc, + .win = rv1126_vop_win_data, + .win_size = ARRAY_SIZE(rv1126_vop_win_data), + .max_output = { 1920, 1080 }, + .lut_size = 1024, +}; + static const struct of_device_id vop_driver_dt_match[] = { { .compatible = "rockchip,rk3036-vop", .data = &rk3036_vop }, @@ -1147,6 +1200,8 @@ static const struct of_device_id vop_driver_dt_match[] = { .data = &rk3228_vop }, { .compatible = "rockchip,rk3328-vop", .data = &rk3328_vop }, + { .compatible = "rockchip,rv1126-vop", + .data = &rv1126_vop }, {}, }; MODULE_DEVICE_TABLE(of, vop_driver_dt_match); diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index 5a80b228d18c..6dcf3e041113 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -141,14 +141,23 @@ const struct ssd130x_deviceinfo ssd130x_variants[] = { }; EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X); +struct ssd130x_crtc_state { + struct drm_crtc_state base; + /* Buffer to store pixels in HW format and written to the panel */ + u8 *data_array; +}; + struct ssd130x_plane_state { struct drm_shadow_plane_state base; /* Intermediate buffer to convert pixels from XRGB8888 to HW format */ u8 *buffer; - /* Buffer to store pixels in HW format and written to the panel */ - u8 *data_array; }; +static inline struct ssd130x_crtc_state *to_ssd130x_crtc_state(struct drm_crtc_state *state) +{ + return container_of(state, struct ssd130x_crtc_state, base); +} + static inline struct ssd130x_plane_state *to_ssd130x_plane_state(struct drm_plane_state *state) { return container_of(state, struct ssd130x_plane_state, base.base); @@ -272,8 +281,8 @@ static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x) /* Enable the PWM */ pwm_enable(ssd130x->pwm); - dev_dbg(dev, "Using PWM%d with a %lluns period.\n", - ssd130x->pwm->pwm, pwm_get_period(ssd130x->pwm)); + dev_dbg(dev, "Using PWM %s with a %lluns period.\n", + ssd130x->pwm->label, pwm_get_period(ssd130x->pwm)); return 0; } @@ -448,13 +457,11 @@ static int ssd130x_init(struct ssd130x_device *ssd130x) } static int ssd130x_update_rect(struct ssd130x_device *ssd130x, - struct ssd130x_plane_state *ssd130x_state, - struct drm_rect *rect) + struct drm_rect *rect, u8 *buf, + u8 *data_array) { unsigned int x = rect->x1; unsigned int y = rect->y1; - u8 *buf = ssd130x_state->buffer; - u8 *data_array = ssd130x_state->data_array; unsigned int width = drm_rect_width(rect); unsigned int height = drm_rect_height(rect); unsigned int line_length = DIV_ROUND_UP(width, 8); @@ -550,28 +557,55 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x, return ret; } -static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, - struct ssd130x_plane_state *ssd130x_state) +static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) { - struct drm_rect fullscreen = { - .x1 = 0, - .x2 = ssd130x->width, - .y1 = 0, - .y2 = ssd130x->height, - }; - - ssd130x_update_rect(ssd130x, ssd130x_state, &fullscreen); + unsigned int page_height = ssd130x->device_info->page_height; + unsigned int pages = DIV_ROUND_UP(ssd130x->height, page_height); + unsigned int width = ssd130x->width; + int ret, i; + + if (!ssd130x->page_address_mode) { + memset(data_array, 0, width * pages); + + /* Set address range for horizontal addressing mode */ + ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset, width); + if (ret < 0) + return; + + ret = ssd130x_set_page_range(ssd130x, ssd130x->page_offset, pages); + if (ret < 0) + return; + + /* Write out update in one go if we aren't using page addressing mode */ + ssd130x_write_data(ssd130x, data_array, width * pages); + } else { + /* + * In page addressing mode, the start address needs to be reset, + * and each page then needs to be written out separately. + */ + memset(data_array, 0, width); + + for (i = 0; i < pages; i++) { + ret = ssd130x_set_page_pos(ssd130x, + ssd130x->page_offset + i, + ssd130x->col_offset); + if (ret < 0) + return; + + ret = ssd130x_write_data(ssd130x, data_array, width); + if (ret < 0) + return; + } + } } -static int ssd130x_fb_blit_rect(struct drm_plane_state *state, +static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *vmap, - struct drm_rect *rect) + struct drm_rect *rect, + u8 *buf, u8 *data_array) { - struct drm_framebuffer *fb = state->fb; struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev); unsigned int page_height = ssd130x->device_info->page_height; - struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(state); - u8 *buf = ssd130x_state->buffer; struct iosys_map dst; unsigned int dst_pitch; int ret = 0; @@ -591,24 +625,31 @@ static int ssd130x_fb_blit_rect(struct drm_plane_state *state, drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); - ssd130x_update_rect(ssd130x, ssd130x_state, rect); + ssd130x_update_rect(ssd130x, rect, buf, data_array); return ret; } -static int ssd130x_primary_plane_helper_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) +static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) { struct drm_device *drm = plane->dev; struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(plane_state); - unsigned int page_height = ssd130x->device_info->page_height; - unsigned int pages = DIV_ROUND_UP(ssd130x->height, page_height); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state; const struct drm_format_info *fi; unsigned int pitch; int ret; + if (!crtc) + return -EINVAL; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + ret = drm_plane_helper_atomic_check(plane, state); if (ret) return ret; @@ -623,23 +664,19 @@ static int ssd130x_primary_plane_helper_atomic_check(struct drm_plane *plane, if (!ssd130x_state->buffer) return -ENOMEM; - ssd130x_state->data_array = kcalloc(ssd130x->width, pages, GFP_KERNEL); - if (!ssd130x_state->data_array) { - kfree(ssd130x_state->buffer); - /* Set to prevent a double free in .atomic_destroy_state() */ - ssd130x_state->buffer = NULL; - return -ENOMEM; - } - return 0; } -static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) +static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) { struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); + struct ssd130x_crtc_state *ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state); + struct ssd130x_plane_state *ssd130x_plane_state = to_ssd130x_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; struct drm_atomic_helper_damage_iter iter; struct drm_device *drm = plane->dev; struct drm_rect dst_clip; @@ -656,24 +693,34 @@ static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane, if (!drm_rect_intersect(&dst_clip, &damage)) continue; - ssd130x_fb_blit_rect(plane_state, &shadow_plane_state->data[0], &dst_clip); + ssd130x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip, + ssd130x_plane_state->buffer, + ssd130x_crtc_state->data_array); } drm_dev_exit(idx); } -static void ssd130x_primary_plane_helper_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *state) +static void ssd130x_primary_plane_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) { struct drm_device *drm = plane->dev; struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); - struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(plane->state); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc_state *crtc_state; + struct ssd130x_crtc_state *ssd130x_crtc_state; int idx; + if (!plane_state->crtc) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); + ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state); + if (!drm_dev_enter(drm, &idx)) return; - ssd130x_clear_screen(ssd130x, ssd130x_state); + ssd130x_clear_screen(ssd130x, ssd130x_crtc_state->data_array); drm_dev_exit(idx); } @@ -706,9 +753,8 @@ static struct drm_plane_state *ssd130x_primary_plane_duplicate_state(struct drm_ if (!ssd130x_state) return NULL; - /* The buffers are not duplicated and are allocated in .atomic_check */ + /* The buffer is not duplicated and is allocated in .atomic_check */ ssd130x_state->buffer = NULL; - ssd130x_state->data_array = NULL; new_shadow_plane_state = &ssd130x_state->base; @@ -722,7 +768,6 @@ static void ssd130x_primary_plane_destroy_state(struct drm_plane *plane, { struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(state); - kfree(ssd130x_state->data_array); kfree(ssd130x_state->buffer); __drm_gem_destroy_shadow_plane_state(&ssd130x_state->base); @@ -732,9 +777,9 @@ static void ssd130x_primary_plane_destroy_state(struct drm_plane *plane, static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, - .atomic_check = ssd130x_primary_plane_helper_atomic_check, - .atomic_update = ssd130x_primary_plane_helper_atomic_update, - .atomic_disable = ssd130x_primary_plane_helper_atomic_disable, + .atomic_check = ssd130x_primary_plane_atomic_check, + .atomic_update = ssd130x_primary_plane_atomic_update, + .atomic_disable = ssd130x_primary_plane_atomic_disable, }; static const struct drm_plane_funcs ssd130x_primary_plane_funcs = { @@ -746,8 +791,8 @@ static const struct drm_plane_funcs ssd130x_primary_plane_funcs = { .destroy = drm_plane_cleanup, }; -static enum drm_mode_status ssd130x_crtc_helper_mode_valid(struct drm_crtc *crtc, - const struct drm_display_mode *mode) +static enum drm_mode_status ssd130x_crtc_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { struct ssd130x_device *ssd130x = drm_to_ssd130x(crtc->dev); @@ -762,27 +807,96 @@ static enum drm_mode_status ssd130x_crtc_helper_mode_valid(struct drm_crtc *crtc return MODE_OK; } +static int ssd130x_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(crtc_state); + unsigned int page_height = ssd130x->device_info->page_height; + unsigned int pages = DIV_ROUND_UP(ssd130x->height, page_height); + int ret; + + ret = drm_crtc_helper_atomic_check(crtc, state); + if (ret) + return ret; + + ssd130x_state->data_array = kmalloc(ssd130x->width * pages, GFP_KERNEL); + if (!ssd130x_state->data_array) + return -ENOMEM; + + return 0; +} + +/* Called during init to allocate the CRTC's atomic state. */ +static void ssd130x_crtc_reset(struct drm_crtc *crtc) +{ + struct ssd130x_crtc_state *ssd130x_state; + + WARN_ON(crtc->state); + + ssd130x_state = kzalloc(sizeof(*ssd130x_state), GFP_KERNEL); + if (!ssd130x_state) + return; + + __drm_atomic_helper_crtc_reset(crtc, &ssd130x_state->base); +} + +static struct drm_crtc_state *ssd130x_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct ssd130x_crtc_state *old_ssd130x_state; + struct ssd130x_crtc_state *ssd130x_state; + + if (WARN_ON(!crtc->state)) + return NULL; + + old_ssd130x_state = to_ssd130x_crtc_state(crtc->state); + ssd130x_state = kmemdup(old_ssd130x_state, sizeof(*ssd130x_state), GFP_KERNEL); + if (!ssd130x_state) + return NULL; + + /* The buffer is not duplicated and is allocated in .atomic_check */ + ssd130x_state->data_array = NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &ssd130x_state->base); + + return &ssd130x_state->base; +} + +static void ssd130x_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(state); + + kfree(ssd130x_state->data_array); + + __drm_atomic_helper_crtc_destroy_state(state); + + kfree(ssd130x_state); +} + /* * The CRTC is always enabled. Screen updates are performed by * the primary plane's atomic_update function. Disabling clears * the screen in the primary plane's atomic_disable function. */ static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs = { - .mode_valid = ssd130x_crtc_helper_mode_valid, - .atomic_check = drm_crtc_helper_atomic_check, + .mode_valid = ssd130x_crtc_mode_valid, + .atomic_check = ssd130x_crtc_atomic_check, }; static const struct drm_crtc_funcs ssd130x_crtc_funcs = { - .reset = drm_atomic_helper_crtc_reset, + .reset = ssd130x_crtc_reset, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .atomic_duplicate_state = ssd130x_crtc_duplicate_state, + .atomic_destroy_state = ssd130x_crtc_destroy_state, }; -static void ssd130x_encoder_helper_atomic_enable(struct drm_encoder *encoder, - struct drm_atomic_state *state) +static void ssd130x_encoder_atomic_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct drm_device *drm = encoder->dev; struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); @@ -807,8 +921,8 @@ power_off: return; } -static void ssd130x_encoder_helper_atomic_disable(struct drm_encoder *encoder, - struct drm_atomic_state *state) +static void ssd130x_encoder_atomic_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct drm_device *drm = encoder->dev; struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); @@ -821,15 +935,15 @@ static void ssd130x_encoder_helper_atomic_disable(struct drm_encoder *encoder, } static const struct drm_encoder_helper_funcs ssd130x_encoder_helper_funcs = { - .atomic_enable = ssd130x_encoder_helper_atomic_enable, - .atomic_disable = ssd130x_encoder_helper_atomic_disable, + .atomic_enable = ssd130x_encoder_atomic_enable, + .atomic_disable = ssd130x_encoder_atomic_disable, }; static const struct drm_encoder_funcs ssd130x_encoder_funcs = { .destroy = drm_encoder_cleanup, }; -static int ssd130x_connector_helper_get_modes(struct drm_connector *connector) +static int ssd130x_connector_get_modes(struct drm_connector *connector) { struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev); struct drm_display_mode *mode; @@ -849,7 +963,7 @@ static int ssd130x_connector_helper_get_modes(struct drm_connector *connector) } static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs = { - .get_modes = ssd130x_connector_helper_get_modes, + .get_modes = ssd130x_connector_get_modes, }; static const struct drm_connector_funcs ssd130x_connector_funcs = { @@ -1131,6 +1245,7 @@ EXPORT_SYMBOL_GPL(ssd130x_probe); void ssd130x_remove(struct ssd130x_device *ssd130x) { drm_dev_unplug(&ssd130x->drm); + drm_atomic_helper_shutdown(&ssd130x->drm); } EXPORT_SYMBOL_GPL(ssd130x_remove); diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h index 87968b3e7fb8..aa39b13615eb 100644 --- a/drivers/gpu/drm/solomon/ssd130x.h +++ b/drivers/gpu/drm/solomon/ssd130x.h @@ -40,8 +40,8 @@ struct ssd130x_deviceinfo { u32 default_width; u32 default_height; u32 page_height; - int need_pwm; - int need_chargepump; + bool need_pwm; + bool need_chargepump; bool page_mode_only; }; diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 2390c1bb6596..4bab93c4fefd 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -174,6 +174,7 @@ static void sti_cleanup(struct drm_device *ddev) drm_atomic_helper_shutdown(ddev); drm_mode_config_cleanup(ddev); component_unbind_all(ddev->dev, ddev); + dev_set_drvdata(ddev->dev, NULL); kfree(private); ddev->dev_private = NULL; } @@ -253,6 +254,11 @@ static void sti_platform_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &sti_ops); } +static void sti_platform_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct of_device_id sti_dt_ids[] = { { .compatible = "st,sti-display-subsystem", }, { /* end node */ }, @@ -262,6 +268,7 @@ MODULE_DEVICE_TABLE(of, sti_dt_ids); static struct platform_driver sti_platform_driver = { .probe = sti_platform_probe, .remove_new = sti_platform_remove, + .shutdown = sti_platform_shutdown, .driver = { .name = DRIVER_NAME, .of_match_table = sti_dt_ids, diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index c68c831136c9..e8523abef27a 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -114,6 +114,7 @@ static void drv_unload(struct drm_device *ddev) DRM_DEBUG("%s\n", __func__); drm_kms_helper_poll_fini(ddev); + drm_atomic_helper_shutdown(ddev); ltdc_unload(ddev); } @@ -225,6 +226,11 @@ static void stm_drm_platform_remove(struct platform_device *pdev) drm_dev_put(ddev); } +static void stm_drm_platform_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct of_device_id drv_dt_ids[] = { { .compatible = "st,stm32-ltdc"}, { /* end node */ }, @@ -234,6 +240,7 @@ MODULE_DEVICE_TABLE(of, drv_dt_ids); static struct platform_driver stm_drm_platform_driver = { .probe = stm_drm_platform_probe, .remove_new = stm_drm_platform_remove, + .shutdown = stm_drm_platform_shutdown, .driver = { .name = "stm32-display", .of_match_table = drv_dt_ids, diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 6a8dfc022d3c..35d7a7ffd208 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -413,6 +413,11 @@ static void sun4i_drv_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &sun4i_drv_master_ops); } +static void sun4i_drv_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct of_device_id sun4i_drv_of_table[] = { { .compatible = "allwinner,sun4i-a10-display-engine" }, { .compatible = "allwinner,sun5i-a10s-display-engine" }, @@ -437,6 +442,7 @@ MODULE_DEVICE_TABLE(of, sun4i_drv_of_table); static struct platform_driver sun4i_drv_platform_driver = { .probe = sun4i_drv_probe, .remove_new = sun4i_drv_remove, + .shutdown = sun4i_drv_shutdown, .driver = { .name = "sun4i-drm", .of_match_table = sun4i_drv_of_table, diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c index 6f076cf4b403..a1ca3916f42b 100644 --- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c @@ -141,6 +141,7 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, GFP_KERNEL); if (!clk_data) return -ENOMEM; + clk_data->num = CLK_NUM; tcon_top->clk_data = clk_data; spin_lock_init(&tcon_top->reg_lock); @@ -213,8 +214,6 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, goto err_unregister_gates; } - clk_data->num = CLK_NUM; - ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, clk_data); if (ret) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 13b182ab905f..be61c9d1a4f0 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1746,8 +1746,15 @@ static void tegra_dc_early_unregister(struct drm_crtc *crtc) unsigned int count = ARRAY_SIZE(debugfs_files); struct drm_minor *minor = crtc->dev->primary; struct tegra_dc *dc = to_tegra_dc(crtc); + struct dentry *root; + +#ifdef CONFIG_DEBUG_FS + root = crtc->debugfs_entry; +#else + root = NULL; +#endif - drm_debugfs_remove_files(dc->debugfs_files, count, minor); + drm_debugfs_remove_files(dc->debugfs_files, count, root, minor); kfree(dc->debugfs_files); dc->debugfs_files = NULL; } diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index f9d18e8cf6ab..ccb5d74fa227 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -120,9 +120,6 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, int host1x_client_iommu_attach(struct host1x_client *client); void host1x_client_iommu_detach(struct host1x_client *client); -int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); -int tegra_drm_exit(struct tegra_drm *tegra); - void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *iova); void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt, dma_addr_t iova); diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index a9870c828374..fbfe92a816d4 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -256,6 +256,7 @@ static void tegra_dsi_early_unregister(struct drm_connector *connector) struct tegra_dsi *dsi = to_dsi(output); drm_debugfs_remove_files(dsi->debugfs_files, count, + connector->debugfs_entry, connector->dev->primary); kfree(dsi->debugfs_files); dsi->debugfs_files = NULL; diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index a4023163493d..b4eb030ea961 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -177,18 +177,27 @@ static void tegra_bo_unpin(struct host1x_bo_mapping *map) static void *tegra_bo_mmap(struct host1x_bo *bo) { struct tegra_bo *obj = host1x_to_tegra_bo(bo); - struct iosys_map map; + struct iosys_map map = { 0 }; + void *vaddr; int ret; - if (obj->vaddr) { + if (obj->vaddr) return obj->vaddr; - } else if (obj->gem.import_attach) { + + if (obj->gem.import_attach) { ret = dma_buf_vmap_unlocked(obj->gem.import_attach->dmabuf, &map); - return ret ? NULL : map.vaddr; - } else { - return vmap(obj->pages, obj->num_pages, VM_MAP, - pgprot_writecombine(PAGE_KERNEL)); + if (ret < 0) + return ERR_PTR(ret); + + return map.vaddr; } + + vaddr = vmap(obj->pages, obj->num_pages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; } static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) @@ -198,10 +207,11 @@ static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) if (obj->vaddr) return; - else if (obj->gem.import_attach) - dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map); - else - vunmap(addr); + + if (obj->gem.import_attach) + return dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map); + + vunmap(addr); } static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 80c760986d9e..0ba3ca3ac509 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1116,7 +1116,8 @@ static void tegra_hdmi_early_unregister(struct drm_connector *connector) unsigned int count = ARRAY_SIZE(debugfs_files); struct tegra_hdmi *hdmi = to_hdmi(output); - drm_debugfs_remove_files(hdmi->debugfs_files, count, minor); + drm_debugfs_remove_files(hdmi->debugfs_files, count, + connector->debugfs_entry, minor); kfree(hdmi->debugfs_files); hdmi->debugfs_files = NULL; } diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 1af5f8318d91..f21e57e8599e 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -1101,7 +1101,7 @@ static int tegra_display_hub_probe(struct platform_device *pdev) for (i = 0; i < hub->soc->num_wgrps; i++) { struct tegra_windowgroup *wgrp = &hub->wgrps[i]; - char id[8]; + char id[16]; snprintf(id, sizeof(id), "wgrp%u", i); mutex_init(&wgrp->lock); diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 79566c9ea8ff..fc66bbd913b2 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -99,6 +99,7 @@ static void tegra_rgb_encoder_disable(struct drm_encoder *encoder) static void tegra_rgb_encoder_enable(struct drm_encoder *encoder) { + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct tegra_output *output = encoder_to_output(encoder); struct tegra_rgb *rgb = to_rgb(output); u32 value; @@ -108,10 +109,19 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder) value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; tegra_dc_writel(rgb->dc, value, DC_DISP_DATA_ENABLE_OPTIONS); - /* XXX: parameterize? */ + /* configure H- and V-sync signal polarities */ value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1)); - value &= ~LVS_OUTPUT_POLARITY_LOW; - value &= ~LHS_OUTPUT_POLARITY_LOW; + + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + value |= LHS_OUTPUT_POLARITY_LOW; + else + value &= ~LHS_OUTPUT_POLARITY_LOW; + + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + value |= LVS_OUTPUT_POLARITY_LOW; + else + value &= ~LVS_OUTPUT_POLARITY_LOW; + tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1)); /* XXX: parameterize? */ diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 61b437a84806..d5a3d3f4fece 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1708,6 +1708,7 @@ static void tegra_sor_early_unregister(struct drm_connector *connector) struct tegra_sor *sor = to_sor(output); drm_debugfs_remove_files(sor->debugfs_files, count, + connector->debugfs_entry, connector->dev->primary); kfree(sor->debugfs_files); sor->debugfs_files = NULL; diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index 474bb7a1c4ee..f6408e56f786 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -3,11 +3,13 @@ #include <kunit/test.h> #include <drm/drm_device.h> +#include <drm/drm_drv.h> #include <drm/drm_file.h> #include <drm/drm_format_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_kunit_helpers.h> #include <drm/drm_mode.h> #include <drm/drm_print.h> #include <drm/drm_rect.h> @@ -16,6 +18,8 @@ #define TEST_BUF_SIZE 50 +#define TEST_USE_DEFAULT_PITCH 0 + struct convert_to_gray8_result { unsigned int dst_pitch; const u8 expected[TEST_BUF_SIZE]; @@ -72,6 +76,21 @@ struct convert_to_mono_result { const u8 expected[TEST_BUF_SIZE]; }; +struct fb_swab_result { + unsigned int dst_pitch; + const u32 expected[TEST_BUF_SIZE]; +}; + +struct convert_to_xbgr8888_result { + unsigned int dst_pitch; + const u32 expected[TEST_BUF_SIZE]; +}; + +struct convert_to_abgr8888_result { + unsigned int dst_pitch; + const u32 expected[TEST_BUF_SIZE]; +}; + struct convert_xrgb8888_case { const char *name; unsigned int pitch; @@ -88,6 +107,9 @@ struct convert_xrgb8888_case { struct convert_to_xrgb2101010_result xrgb2101010_result; struct convert_to_argb2101010_result argb2101010_result; struct convert_to_mono_result mono_result; + struct fb_swab_result swab_result; + struct convert_to_xbgr8888_result xbgr8888_result; + struct convert_to_abgr8888_result abgr8888_result; }; static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { @@ -97,50 +119,62 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { .clip = DRM_RECT_INIT(0, 0, 1, 1), .xrgb8888 = { 0x01FF0000 }, .gray8_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x4C }, }, .rgb332_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xE0 }, }, .rgb565_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xF800 }, .expected_swab = { 0x00F8 }, }, .xrgb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x7C00 }, }, .argb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFC00 }, }, .rgba5551_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xF801 }, }, .rgb888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x00, 0x00, 0xFF }, }, .argb8888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF0000 }, }, .xrgb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x3FF00000 }, }, .argb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFF00000 }, }, .mono_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0b0 }, }, + .swab_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0x0000FF01 }, + }, + .xbgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0x010000FF }, + }, + .abgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0xFF0000FF }, + }, }, { .name = "single_pixel_clip_rectangle", @@ -151,50 +185,62 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x00000000, 0x10FF0000, }, .gray8_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x4C }, }, .rgb332_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xE0 }, }, .rgb565_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xF800 }, .expected_swab = { 0x00F8 }, }, .xrgb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x7C00 }, }, .argb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFC00 }, }, .rgba5551_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xF801 }, }, .rgb888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x00, 0x00, 0xFF }, }, .argb8888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF0000 }, }, .xrgb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x3FF00000 }, }, .argb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFF00000 }, }, .mono_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0b0 }, }, + .swab_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0x0000FF10 }, + }, + .xbgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0x100000FF }, + }, + .abgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0xFF0000FF }, + }, }, { /* Well known colors: White, black, red, green, blue, magenta, @@ -212,7 +258,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000, }, .gray8_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFF, 0x00, 0x4C, 0x99, @@ -221,7 +267,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .rgb332_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFF, 0x00, 0xE0, 0x1C, @@ -230,7 +276,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .rgb565_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF, 0x0000, 0xF800, 0x07E0, @@ -245,7 +291,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .xrgb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x7FFF, 0x0000, 0x7C00, 0x03E0, @@ -254,7 +300,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .argb1555_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF, 0x8000, 0xFC00, 0x83E0, @@ -263,7 +309,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .rgba5551_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFF, 0x0001, 0xF801, 0x07C1, @@ -272,7 +318,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .rgb888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, @@ -281,7 +327,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .argb8888_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFFFFFF, 0xFF000000, 0xFFFF0000, 0xFF00FF00, @@ -290,7 +336,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .xrgb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x3FFFFFFF, 0x00000000, 0x3FF00000, 0x000FFC00, @@ -299,7 +345,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .argb2101010_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0xFFFFFFFF, 0xC0000000, 0xFFF00000, 0xC00FFC00, @@ -308,7 +354,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { }, }, .mono_result = { - .dst_pitch = 0, + .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0b01, 0b10, @@ -316,6 +362,33 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0b11, }, }, + .swab_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { + 0xFFFFFF11, 0x00000022, + 0x0000FF33, 0x00FF0044, + 0xFF000055, 0xFF00FF66, + 0x00FFFF77, 0xFFFF0088, + }, + }, + .xbgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { + 0x11FFFFFF, 0x22000000, + 0x330000FF, 0x4400FF00, + 0x55FF0000, 0x66FF00FF, + 0x7700FFFF, 0x88FFFF00, + }, + }, + .abgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { + 0xFFFFFFFF, 0xFF000000, + 0xFF0000FF, 0xFF00FF00, + 0xFFFF0000, 0xFFFF00FF, + 0xFF00FFFF, 0xFFFFFF00, + }, + }, }, { /* Randomly picked colors. Full buffer within the clip area. */ @@ -423,6 +496,30 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0b010, 0b000, }, }, + .swab_result = { + .dst_pitch = 20, + .expected = { + 0x9C440EA1, 0x054D11B1, 0x03F3A8C1, 0x00000000, 0x00000000, + 0x73F06CD1, 0x9C440EA2, 0x054D11B2, 0x00000000, 0x00000000, + 0x0303A8C2, 0x73F06CD2, 0x9C440EA3, 0x00000000, 0x00000000, + }, + }, + .xbgr8888_result = { + .dst_pitch = 20, + .expected = { + 0xA19C440E, 0xB1054D11, 0xC103F3A8, 0x00000000, 0x00000000, + 0xD173F06C, 0xA29C440E, 0xB2054D11, 0x00000000, 0x00000000, + 0xC20303A8, 0xD273F06C, 0xA39C440E, 0x00000000, 0x00000000, + }, + }, + .abgr8888_result = { + .dst_pitch = 20, + .expected = { + 0xFF9C440E, 0xFF054D11, 0xFF03F3A8, 0x00000000, 0x00000000, + 0xFF73F06C, 0xFF9C440E, 0xFF054D11, 0x00000000, 0x00000000, + 0xFF0303A8, 0xFF73F06C, 0xFF9C440E, 0x00000000, 0x00000000, + }, + }, }, }; @@ -437,7 +534,7 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { * The size of the destination buffer or negative value on error. */ static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch, - const struct drm_rect *clip) + const struct drm_rect *clip, int plane) { const struct drm_format_info *dst_fi = drm_format_info(dst_format); @@ -445,7 +542,7 @@ static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch, return -EINVAL; if (!dst_pitch) - dst_pitch = drm_format_info_min_pitch(dst_fi, 0, drm_rect_width(clip)); + dst_pitch = drm_format_info_min_pitch(dst_fi, plane, drm_rect_width(clip)); return dst_pitch * drm_rect_height(clip); } @@ -519,7 +616,7 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_R8, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -530,7 +627,11 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_gray8(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_gray8(&dst, dst_pitch, &src, &fb, ¶ms->clip); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -549,7 +650,7 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_RGB332, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -560,7 +661,10 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_rgb332(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_rgb332(&dst, dst_pitch, &src, &fb, ¶ms->clip); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -579,7 +683,7 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_RGB565, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -590,7 +694,10 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, false); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, ¶ms->clip, false); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); @@ -598,6 +705,18 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, true); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size); + + buf = dst.vaddr; + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGB565, &src, &fb, ¶ms->clip); + + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) @@ -615,7 +734,7 @@ static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_XRGB1555, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -626,8 +745,23 @@ static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_xrgb1555(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_xrgb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip); + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB1555, &src, &fb, ¶ms->clip); + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + + KUNIT_EXPECT_FALSE(test, blit_result); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -646,7 +780,7 @@ static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_ARGB1555, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -657,8 +791,23 @@ static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_argb1555(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_argb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip); + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB1555, &src, &fb, ¶ms->clip); + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + + KUNIT_EXPECT_FALSE(test, blit_result); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -677,7 +826,7 @@ static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_RGBA5551, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -688,9 +837,24 @@ static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_rgba5551(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_rgba5551(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGBA5551, &src, &fb, ¶ms->clip); + + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) @@ -708,7 +872,7 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_RGB888, result->dst_pitch, - ¶ms->clip); + ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -723,7 +887,20 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) * RGB888 expected results are already in little-endian * order, so there's no need to convert the test output. */ - drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_rgb888(&dst, dst_pitch, &src, &fb, ¶ms->clip); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGB888, &src, &fb, ¶ms->clip); + + KUNIT_EXPECT_FALSE(test, blit_result); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } @@ -742,7 +919,7 @@ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_ARGB8888, - result->dst_pitch, ¶ms->clip); + result->dst_pitch, ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -753,9 +930,24 @@ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_argb8888(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_argb8888(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB8888, &src, &fb, ¶ms->clip); + + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) @@ -773,7 +965,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_XRGB2101010, - result->dst_pitch, ¶ms->clip); + result->dst_pitch, ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -784,9 +976,23 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_xrgb2101010(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB2101010, &src, &fb, + ¶ms->clip); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) @@ -804,7 +1010,7 @@ static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) }; dst_size = conversion_buf_size(DRM_FORMAT_ARGB2101010, - result->dst_pitch, ¶ms->clip); + result->dst_pitch, ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); @@ -815,9 +1021,25 @@ static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_argb2101010(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_argb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB2101010, &src, &fb, + ¶ms->clip); + + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_mono(struct kunit *test) @@ -834,7 +1056,7 @@ static void drm_test_fb_xrgb8888_to_mono(struct kunit *test) .pitches = { params->pitch, 0, 0 }, }; - dst_size = conversion_buf_size(DRM_FORMAT_C1, result->dst_pitch, ¶ms->clip); + dst_size = conversion_buf_size(DRM_FORMAT_C1, result->dst_pitch, ¶ms->clip, 0); KUNIT_ASSERT_GT(test, dst_size, 0); @@ -846,10 +1068,765 @@ static void drm_test_fb_xrgb8888_to_mono(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888); - drm_fb_xrgb8888_to_mono(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_xrgb8888_to_mono(&dst, dst_pitch, &src, &fb, ¶ms->clip); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } +static void drm_test_fb_swab(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct fb_swab_result *result = ¶ms->swab_result; + size_t dst_size; + u32 *buf = NULL; + __le32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_XRGB8888, result->dst_pitch, ¶ms->clip, 0); + + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + drm_fb_swab(&dst, dst_pitch, &src, &fb, ¶ms->clip, false); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB8888 | DRM_FORMAT_BIG_ENDIAN, + &src, &fb, ¶ms->clip); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; + memset(buf, 0, dst_size); + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_BGRX8888, &src, &fb, ¶ms->clip); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; + memset(buf, 0, dst_size); + + struct drm_format_info mock_format = *fb.format; + + mock_format.format |= DRM_FORMAT_BIG_ENDIAN; + fb.format = &mock_format; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB8888, &src, &fb, ¶ms->clip); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); +} + +static void drm_test_fb_xrgb8888_to_abgr8888(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_abgr8888_result *result = ¶ms->abgr8888_result; + size_t dst_size; + u32 *buf = NULL; + __le32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_XBGR8888, result->dst_pitch, ¶ms->clip, 0); + + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ABGR8888, &src, &fb, ¶ms->clip); + + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); +} + +static void drm_test_fb_xrgb8888_to_xbgr8888(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_xbgr8888_result *result = ¶ms->xbgr8888_result; + size_t dst_size; + u32 *buf = NULL; + __le32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_XBGR8888, result->dst_pitch, ¶ms->clip, 0); + + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XBGR8888, &src, &fb, ¶ms->clip); + + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); +} + +struct clip_offset_case { + const char *name; + unsigned int pitch; + u32 format; + struct drm_rect clip; + unsigned int expected_offset; +}; + +static struct clip_offset_case clip_offset_cases[] = { + { + .name = "pass through", + .pitch = TEST_USE_DEFAULT_PITCH, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(0, 0, 3, 3), + .expected_offset = 0 + }, + { + .name = "horizontal offset", + .pitch = TEST_USE_DEFAULT_PITCH, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(1, 0, 3, 3), + .expected_offset = 4, + }, + { + .name = "vertical offset", + .pitch = TEST_USE_DEFAULT_PITCH, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(0, 1, 3, 3), + .expected_offset = 12, + }, + { + .name = "horizontal and vertical offset", + .pitch = TEST_USE_DEFAULT_PITCH, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(1, 1, 3, 3), + .expected_offset = 16, + }, + { + .name = "horizontal offset (custom pitch)", + .pitch = 20, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(1, 0, 3, 3), + .expected_offset = 4, + }, + { + .name = "vertical offset (custom pitch)", + .pitch = 20, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(0, 1, 3, 3), + .expected_offset = 20, + }, + { + .name = "horizontal and vertical offset (custom pitch)", + .pitch = 20, + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(1, 1, 3, 3), + .expected_offset = 24, + }, +}; + +static void clip_offset_case_desc(struct clip_offset_case *t, char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(clip_offset, clip_offset_cases, clip_offset_case_desc); + +static void drm_test_fb_clip_offset(struct kunit *test) +{ + const struct clip_offset_case *params = test->param_value; + const struct drm_format_info *format_info = drm_format_info(params->format); + + unsigned int offset; + unsigned int pitch = params->pitch; + + if (pitch == TEST_USE_DEFAULT_PITCH) + pitch = drm_format_info_min_pitch(format_info, 0, + drm_rect_width(¶ms->clip)); + + /* + * Assure that the pitch is not zero, because this will inevitable cause the + * wrong expected result + */ + KUNIT_ASSERT_NE(test, pitch, 0); + + offset = drm_fb_clip_offset(pitch, format_info, ¶ms->clip); + + KUNIT_EXPECT_EQ(test, offset, params->expected_offset); +} + +struct fb_build_fourcc_list_case { + const char *name; + u32 native_fourccs[TEST_BUF_SIZE]; + size_t native_fourccs_size; + u32 expected[TEST_BUF_SIZE]; + size_t expected_fourccs_size; +}; + +static struct fb_build_fourcc_list_case fb_build_fourcc_list_cases[] = { + { + .name = "no native formats", + .native_fourccs = { }, + .native_fourccs_size = 0, + .expected = { DRM_FORMAT_XRGB8888 }, + .expected_fourccs_size = 1, + }, + { + .name = "XRGB8888 as native format", + .native_fourccs = { DRM_FORMAT_XRGB8888 }, + .native_fourccs_size = 1, + .expected = { DRM_FORMAT_XRGB8888 }, + .expected_fourccs_size = 1, + }, + { + .name = "remove duplicates", + .native_fourccs = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + }, + .native_fourccs_size = 11, + .expected = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, + }, + .expected_fourccs_size = 3, + }, + { + .name = "convert alpha formats", + .native_fourccs = { + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_BGRA5551, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_RGBA1010102, + DRM_FORMAT_BGRA1010102, + }, + .native_fourccs_size = 12, + .expected = { + DRM_FORMAT_XRGB1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_RGBX5551, + DRM_FORMAT_BGRX5551, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_RGBX1010102, + DRM_FORMAT_BGRX1010102, + }, + .expected_fourccs_size = 12, + }, + { + .name = "random formats", + .native_fourccs = { + DRM_FORMAT_Y212, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ABGR16161616F, + DRM_FORMAT_C8, + DRM_FORMAT_BGR888, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_BGR565_A8, + DRM_FORMAT_R10, + DRM_FORMAT_XYUV8888, + }, + .native_fourccs_size = 10, + .expected = { + DRM_FORMAT_Y212, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ABGR16161616F, + DRM_FORMAT_C8, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGBX5551, + DRM_FORMAT_BGR565_A8, + DRM_FORMAT_R10, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XRGB8888, + }, + .expected_fourccs_size = 10, + }, +}; + +static void fb_build_fourcc_list_case_desc(struct fb_build_fourcc_list_case *t, char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(fb_build_fourcc_list, fb_build_fourcc_list_cases, fb_build_fourcc_list_case_desc); + +static void drm_test_fb_build_fourcc_list(struct kunit *test) +{ + const struct fb_build_fourcc_list_case *params = test->param_value; + u32 fourccs_out[TEST_BUF_SIZE] = {0}; + size_t nfourccs_out; + struct drm_device *drm; + struct device *dev; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*drm), 0, DRIVER_MODESET); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + nfourccs_out = drm_fb_build_fourcc_list(drm, params->native_fourccs, + params->native_fourccs_size, + fourccs_out, TEST_BUF_SIZE); + + KUNIT_EXPECT_EQ(test, nfourccs_out, params->expected_fourccs_size); + KUNIT_EXPECT_MEMEQ(test, fourccs_out, params->expected, TEST_BUF_SIZE); +} + +struct fb_memcpy_case { + const char *name; + u32 format; + struct drm_rect clip; + unsigned int src_pitches[DRM_FORMAT_MAX_PLANES]; + const u32 src[DRM_FORMAT_MAX_PLANES][TEST_BUF_SIZE]; + unsigned int dst_pitches[DRM_FORMAT_MAX_PLANES]; + const u32 expected[DRM_FORMAT_MAX_PLANES][TEST_BUF_SIZE]; +}; + +/* The `src` and `expected` buffers are u32 arrays. To deal with planes that + * have a cpp != 4 the values are stored together on the same u32 number in a + * way so the order in memory is correct in a little-endian machine. + * + * Because of that, on some occasions, parts of a u32 will not be part of the + * test, to make this explicit the 0xFF byte is used on those parts. + */ + +static struct fb_memcpy_case fb_memcpy_cases[] = { + { + .name = "single_pixel_source_buffer", + .format = DRM_FORMAT_XRGB8888, + .clip = DRM_RECT_INIT(0, 0, 1, 1), + .src_pitches = { 1 * 4 }, + .src = {{ 0x01020304 }}, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = {{ 0x01020304 }}, + }, + { + .name = "single_pixel_source_buffer", + .format = DRM_FORMAT_XRGB8888_A8, + .clip = DRM_RECT_INIT(0, 0, 1, 1), + .src_pitches = { 1 * 4, 1 }, + .src = { + { 0x01020304 }, + { 0xFFFFFF01 }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x01020304 }, + { 0x00000001 }, + }, + }, + { + .name = "single_pixel_source_buffer", + .format = DRM_FORMAT_YUV444, + .clip = DRM_RECT_INIT(0, 0, 1, 1), + .src_pitches = { 1, 1, 1 }, + .src = { + { 0xFFFFFF01 }, + { 0xFFFFFF01 }, + { 0xFFFFFF01 }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x00000001 }, + { 0x00000001 }, + { 0x00000001 }, + }, + }, + { + .name = "single_pixel_clip_rectangle", + .format = DRM_FORMAT_XBGR8888, + .clip = DRM_RECT_INIT(1, 1, 1, 1), + .src_pitches = { 2 * 4 }, + .src = { + { + 0x00000000, 0x00000000, + 0x00000000, 0x01020304, + }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x01020304 }, + }, + }, + { + .name = "single_pixel_clip_rectangle", + .format = DRM_FORMAT_XRGB8888_A8, + .clip = DRM_RECT_INIT(1, 1, 1, 1), + .src_pitches = { 2 * 4, 2 * 1 }, + .src = { + { + 0x00000000, 0x00000000, + 0x00000000, 0x01020304, + }, + { 0x01000000 }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x01020304 }, + { 0x00000001 }, + }, + }, + { + .name = "single_pixel_clip_rectangle", + .format = DRM_FORMAT_YUV444, + .clip = DRM_RECT_INIT(1, 1, 1, 1), + .src_pitches = { 2 * 1, 2 * 1, 2 * 1 }, + .src = { + { 0x01000000 }, + { 0x01000000 }, + { 0x01000000 }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { 0x00000001 }, + { 0x00000001 }, + { 0x00000001 }, + }, + }, + { + .name = "well_known_colors", + .format = DRM_FORMAT_XBGR8888, + .clip = DRM_RECT_INIT(1, 1, 2, 4), + .src_pitches = { 4 * 4 }, + .src = { + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x11FFFFFF, 0x22000000, 0x00000000, + 0x00000000, 0x33FF0000, 0x4400FF00, 0x00000000, + 0x00000000, 0x550000FF, 0x66FF00FF, 0x00000000, + 0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000, + }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { + 0x11FFFFFF, 0x22000000, + 0x33FF0000, 0x4400FF00, + 0x550000FF, 0x66FF00FF, + 0x77FFFF00, 0x8800FFFF, + }, + }, + }, + { + .name = "well_known_colors", + .format = DRM_FORMAT_XRGB8888_A8, + .clip = DRM_RECT_INIT(1, 1, 2, 4), + .src_pitches = { 4 * 4, 4 * 1 }, + .src = { + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFF000000, 0x00000000, + 0x00000000, 0xFFFF0000, 0xFF00FF00, 0x00000000, + 0x00000000, 0xFF0000FF, 0xFFFF00FF, 0x00000000, + 0x00000000, 0xFFFFFF00, 0xFF00FFFF, 0x00000000, + }, + { + 0x00000000, + 0x00221100, + 0x00443300, + 0x00665500, + 0x00887700, + }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { + 0xFFFFFFFF, 0xFF000000, + 0xFFFF0000, 0xFF00FF00, + 0xFF0000FF, 0xFFFF00FF, + 0xFFFFFF00, 0xFF00FFFF, + }, + { + 0x44332211, + 0x88776655, + }, + }, + }, + { + .name = "well_known_colors", + .format = DRM_FORMAT_YUV444, + .clip = DRM_RECT_INIT(1, 1, 2, 4), + .src_pitches = { 4 * 1, 4 * 1, 4 * 1 }, + .src = { + { + 0x00000000, + 0x0000FF00, + 0x00954C00, + 0x00691D00, + 0x00B2E100, + }, + { + 0x00000000, + 0x00000000, + 0x00BEDE00, + 0x00436500, + 0x00229B00, + }, + { + 0x00000000, + 0x00000000, + 0x007E9C00, + 0x0083E700, + 0x00641A00, + }, + }, + .dst_pitches = { TEST_USE_DEFAULT_PITCH }, + .expected = { + { + 0x954C00FF, + 0xB2E1691D, + }, + { + 0xBEDE0000, + 0x229B4365, + }, + { + 0x7E9C0000, + 0x641A83E7, + }, + }, + }, + { + .name = "destination_pitch", + .format = DRM_FORMAT_XBGR8888, + .clip = DRM_RECT_INIT(0, 0, 3, 3), + .src_pitches = { 3 * 4 }, + .src = { + { + 0xA10E449C, 0xB1114D05, 0xC1A8F303, + 0xD16CF073, 0xA20E449C, 0xB2114D05, + 0xC2A80303, 0xD26CF073, 0xA30E449C, + }, + }, + .dst_pitches = { 5 * 4 }, + .expected = { + { + 0xA10E449C, 0xB1114D05, 0xC1A8F303, 0x00000000, 0x00000000, + 0xD16CF073, 0xA20E449C, 0xB2114D05, 0x00000000, 0x00000000, + 0xC2A80303, 0xD26CF073, 0xA30E449C, 0x00000000, 0x00000000, + }, + }, + }, + { + .name = "destination_pitch", + .format = DRM_FORMAT_XRGB8888_A8, + .clip = DRM_RECT_INIT(0, 0, 3, 3), + .src_pitches = { 3 * 4, 3 * 1 }, + .src = { + { + 0xFF0E449C, 0xFF114D05, 0xFFA8F303, + 0xFF6CF073, 0xFF0E449C, 0xFF114D05, + 0xFFA80303, 0xFF6CF073, 0xFF0E449C, + }, + { + 0xB2C1B1A1, + 0xD2A3D1A2, + 0xFFFFFFC2, + }, + }, + .dst_pitches = { 5 * 4, 5 * 1 }, + .expected = { + { + 0xFF0E449C, 0xFF114D05, 0xFFA8F303, 0x00000000, 0x00000000, + 0xFF6CF073, 0xFF0E449C, 0xFF114D05, 0x00000000, 0x00000000, + 0xFFA80303, 0xFF6CF073, 0xFF0E449C, 0x00000000, 0x00000000, + }, + { + 0x00C1B1A1, + 0xD1A2B200, + 0xD2A30000, + 0xFF0000C2, + }, + }, + }, + { + .name = "destination_pitch", + .format = DRM_FORMAT_YUV444, + .clip = DRM_RECT_INIT(0, 0, 3, 3), + .src_pitches = { 3 * 1, 3 * 1, 3 * 1 }, + .src = { + { + 0xBAC1323D, + 0xBA34323D, + 0xFFFFFF3D, + }, + { + 0xE1ABEC2A, + 0xE1EAEC2A, + 0xFFFFFF2A, + }, + { + 0xBCEBE4D7, + 0xBC65E4D7, + 0xFFFFFFD7, + }, + }, + .dst_pitches = { 5 * 1, 5 * 1, 5 * 1 }, + .expected = { + { + 0x00C1323D, + 0x323DBA00, + 0xBA340000, + 0xFF00003D, + }, + { + 0x00ABEC2A, + 0xEC2AE100, + 0xE1EA0000, + 0xFF00002A, + }, + { + 0x00EBE4D7, + 0xE4D7BC00, + 0xBC650000, + 0xFF0000D7, + }, + }, + }, +}; + +static void fb_memcpy_case_desc(struct fb_memcpy_case *t, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s: %p4cc", t->name, &t->format); +} + +KUNIT_ARRAY_PARAM(fb_memcpy, fb_memcpy_cases, fb_memcpy_case_desc); + +static void drm_test_fb_memcpy(struct kunit *test) +{ + const struct fb_memcpy_case *params = test->param_value; + size_t dst_size[DRM_FORMAT_MAX_PLANES] = { 0 }; + u32 *buf[DRM_FORMAT_MAX_PLANES] = { 0 }; + __le32 *src_cp[DRM_FORMAT_MAX_PLANES] = { 0 }; + __le32 *expected[DRM_FORMAT_MAX_PLANES] = { 0 }; + struct iosys_map dst[DRM_FORMAT_MAX_PLANES]; + struct iosys_map src[DRM_FORMAT_MAX_PLANES]; + + struct drm_framebuffer fb = { + .format = drm_format_info(params->format), + }; + + memcpy(fb.pitches, params->src_pitches, DRM_FORMAT_MAX_PLANES * sizeof(int)); + + for (size_t i = 0; i < fb.format->num_planes; i++) { + dst_size[i] = conversion_buf_size(params->format, params->dst_pitches[i], + ¶ms->clip, i); + KUNIT_ASSERT_GT(test, dst_size[i], 0); + + buf[i] = kunit_kzalloc(test, dst_size[i], GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf[i]); + iosys_map_set_vaddr(&dst[i], buf[i]); + + src_cp[i] = cpubuf_to_le32(test, params->src[i], TEST_BUF_SIZE); + iosys_map_set_vaddr(&src[i], src_cp[i]); + } + + const unsigned int *dst_pitches = params->dst_pitches[0] == TEST_USE_DEFAULT_PITCH ? NULL : + params->dst_pitches; + + drm_fb_memcpy(dst, dst_pitches, src, &fb, ¶ms->clip); + + for (size_t i = 0; i < fb.format->num_planes; i++) { + expected[i] = cpubuf_to_le32(test, params->expected[i], TEST_BUF_SIZE); + KUNIT_EXPECT_MEMEQ_MSG(test, buf[i], expected[i], dst_size[i], + "Failed expectation on plane %zu", i); + + memset(buf[i], 0, dst_size[i]); + } + + int blit_result; + + blit_result = drm_fb_blit(dst, dst_pitches, params->format, src, &fb, ¶ms->clip); + + KUNIT_EXPECT_FALSE(test, blit_result); + for (size_t i = 0; i < fb.format->num_planes; i++) { + expected[i] = cpubuf_to_le32(test, params->expected[i], TEST_BUF_SIZE); + KUNIT_EXPECT_MEMEQ_MSG(test, buf[i], expected[i], dst_size[i], + "Failed expectation on plane %zu", i); + } +} + static struct kunit_case drm_format_helper_test_cases[] = { KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_gray8, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb332, convert_xrgb8888_gen_params), @@ -862,6 +1839,12 @@ static struct kunit_case drm_format_helper_test_cases[] = { KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb2101010, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_mono, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_swab, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xbgr8888, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_abgr8888, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_clip_offset, clip_offset_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_build_fourcc_list, fb_build_fourcc_list_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_memcpy, fb_memcpy_gen_params), {} }; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index fe56beea3e93..8ebd7134ee21 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -175,6 +175,7 @@ static void tilcdc_fini(struct drm_device *dev) drm_dev_unregister(dev); drm_kms_helper_poll_fini(dev); + drm_atomic_helper_shutdown(dev); tilcdc_irq_uninstall(dev); drm_mode_config_cleanup(dev); @@ -389,6 +390,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) init_failed: tilcdc_fini(ddev); + platform_set_drvdata(pdev, NULL); return ret; } @@ -537,7 +539,8 @@ static void tilcdc_unbind(struct device *dev) if (!ddev->dev_private) return; - tilcdc_fini(dev_get_drvdata(dev)); + tilcdc_fini(ddev); + dev_set_drvdata(dev, NULL); } static const struct component_master_ops tilcdc_comp_ops = { @@ -582,6 +585,11 @@ static int tilcdc_pdev_remove(struct platform_device *pdev) return 0; } +static void tilcdc_pdev_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct of_device_id tilcdc_of_match[] = { { .compatible = "ti,am33xx-tilcdc", }, { .compatible = "ti,da850-tilcdc", }, @@ -592,6 +600,7 @@ MODULE_DEVICE_TABLE(of, tilcdc_of_match); static struct platform_driver tilcdc_platform_driver = { .probe = tilcdc_pdev_probe, .remove = tilcdc_pdev_remove, + .shutdown = tilcdc_pdev_shutdown, .driver = { .name = "tilcdc", .pm = pm_sleep_ptr(&tilcdc_pm_ops), diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c index d254679a136e..c23c9f0cf49c 100644 --- a/drivers/gpu/drm/tiny/bochs.c +++ b/drivers/gpu/drm/tiny/bochs.c @@ -690,6 +690,11 @@ static void bochs_pci_remove(struct pci_dev *pdev) drm_dev_put(dev); } +static void bochs_pci_shutdown(struct pci_dev *pdev) +{ + drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); +} + static const struct pci_device_id bochs_pci_tbl[] = { { .vendor = 0x1234, @@ -720,6 +725,7 @@ static struct pci_driver bochs_pci_driver = { .id_table = bochs_pci_tbl, .probe = bochs_pci_probe, .remove = bochs_pci_remove, + .shutdown = bochs_pci_shutdown, .driver.pm = &bochs_pm_ops, }; diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index 594bc472862f..c5c34cd2edc1 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -727,6 +727,11 @@ static void cirrus_pci_remove(struct pci_dev *pdev) drm_atomic_helper_shutdown(dev); } +static void cirrus_pci_shutdown(struct pci_dev *pdev) +{ + drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); +} + static const struct pci_device_id pciidlist[] = { { .vendor = PCI_VENDOR_ID_CIRRUS, @@ -748,6 +753,7 @@ static struct pci_driver cirrus_pci_driver = { .id_table = pciidlist, .probe = cirrus_pci_probe, .remove = cirrus_pci_remove, + .shutdown = cirrus_pci_shutdown, }; drm_module_pci_driver(cirrus_pci_driver) diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index c5bb683e440c..0187539ff5ea 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -70,10 +70,10 @@ MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)"); #define READ_STATUS_SIZE 13 #define MISC_VALUE_SIZE 4 -#define CMD_TIMEOUT msecs_to_jiffies(200) -#define DATA_TIMEOUT msecs_to_jiffies(1000) -#define IDLE_TIMEOUT msecs_to_jiffies(2000) -#define FIRST_FRAME_TIMEOUT msecs_to_jiffies(2000) +#define CMD_TIMEOUT 200 +#define DATA_TIMEOUT 1000 +#define IDLE_TIMEOUT 2000 +#define FIRST_FRAME_TIMEOUT 2000 #define MISC_REQ_GET_SET_ECO_A 0xff #define MISC_REQ_GET_SET_ECO_B 0x35 @@ -389,7 +389,7 @@ static void gm12u320_fb_update_work(struct work_struct *work) * switches back to showing its logo. */ queue_delayed_work(system_long_wq, &gm12u320->fb_update.work, - IDLE_TIMEOUT); + msecs_to_jiffies(IDLE_TIMEOUT)); return; err: diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index 13ae148f59b9..73dd4f4289c2 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -949,7 +949,7 @@ static int repaper_probe(struct spi_device *spi) match = device_get_match_data(dev); if (match) { - model = (enum repaper_model)match; + model = (enum repaper_model)(uintptr_t)match; } else { spi_id = spi_get_device_id(spi); model = (enum repaper_model)spi_id->driver_data; diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index ff86ba1ae1b8..8bdaf66044fc 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -6,6 +6,7 @@ #include <linux/of_address.h> #include <linux/platform_data/simplefb.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> #include <linux/regulator/consumer.h> #include <drm/drm_aperture.h> @@ -227,6 +228,12 @@ struct simpledrm_device { unsigned int regulator_count; struct regulator **regulators; #endif + /* power-domains */ +#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS + int pwr_dom_count; + struct device **pwr_dom_devs; + struct device_link **pwr_dom_links; +#endif /* simplefb settings */ struct drm_display_mode mode; @@ -468,6 +475,101 @@ static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) } #endif +#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS +/* + * Generic power domain handling code. + * + * Here we handle the power-domains properties of our "simple-framebuffer" + * dt node. This is only necessary if there is more than one power-domain. + * A single power-domains is handled automatically by the driver core. Multiple + * power-domains have to be handled by drivers since the driver core can't know + * the correct power sequencing. Power sequencing is not an issue for simpledrm + * since the bootloader has put the power domains already in the correct state. + * simpledrm has only to ensure they remain active for its lifetime. + * + * When the driver unloads, we detach from the power-domains. + * + * We only complain about errors here, no action is taken as the most likely + * error can only happen due to a mismatch between the bootloader which set + * up the "simple-framebuffer" dt node, and the PM domain providers in the + * device tree. Chances are that there are no adverse effects, and if there are, + * a clean teardown of the fb probe will not help us much either. So just + * complain and carry on, and hope that the user actually gets a working fb at + * the end of things. + */ +static void simpledrm_device_detach_genpd(void *res) +{ + int i; + struct simpledrm_device *sdev = res; + + if (sdev->pwr_dom_count <= 1) + return; + + for (i = sdev->pwr_dom_count - 1; i >= 0; i--) { + if (sdev->pwr_dom_links[i]) + device_link_del(sdev->pwr_dom_links[i]); + if (!IS_ERR_OR_NULL(sdev->pwr_dom_devs[i])) + dev_pm_domain_detach(sdev->pwr_dom_devs[i], true); + } +} + +static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev) +{ + struct device *dev = sdev->dev.dev; + int i; + + sdev->pwr_dom_count = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + /* + * Single power-domain devices are handled by driver core nothing to do + * here. The same for device nodes without "power-domains" property. + */ + if (sdev->pwr_dom_count <= 1) + return 0; + + sdev->pwr_dom_devs = devm_kcalloc(dev, sdev->pwr_dom_count, + sizeof(*sdev->pwr_dom_devs), + GFP_KERNEL); + if (!sdev->pwr_dom_devs) + return -ENOMEM; + + sdev->pwr_dom_links = devm_kcalloc(dev, sdev->pwr_dom_count, + sizeof(*sdev->pwr_dom_links), + GFP_KERNEL); + if (!sdev->pwr_dom_links) + return -ENOMEM; + + for (i = 0; i < sdev->pwr_dom_count; i++) { + sdev->pwr_dom_devs[i] = dev_pm_domain_attach_by_id(dev, i); + if (IS_ERR(sdev->pwr_dom_devs[i])) { + int ret = PTR_ERR(sdev->pwr_dom_devs[i]); + if (ret == -EPROBE_DEFER) { + simpledrm_device_detach_genpd(sdev); + return ret; + } + drm_warn(&sdev->dev, + "pm_domain_attach_by_id(%u) failed: %d\n", i, ret); + continue; + } + + sdev->pwr_dom_links[i] = device_link_add(dev, + sdev->pwr_dom_devs[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!sdev->pwr_dom_links[i]) + drm_warn(&sdev->dev, "failed to link power-domain %d\n", i); + } + + return devm_add_action_or_reset(dev, simpledrm_device_detach_genpd, sdev); +} +#else +static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev) +{ + return 0; +} +#endif + /* * Modesetting */ @@ -653,6 +755,9 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, ret = simpledrm_device_init_regulators(sdev); if (ret) return ERR_PTR(ret); + ret = simpledrm_device_attach_genpd(sdev); + if (ret) + return ERR_PTR(ret); if (pd) { width = simplefb_get_width_pd(dev, pd); diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index 0bb56d063536..acce210e2554 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -242,6 +242,7 @@ static void tve200_remove(struct platform_device *pdev) struct tve200_drm_dev_private *priv = drm->dev_private; drm_dev_unregister(drm); + drm_atomic_helper_shutdown(drm); if (priv->panel) drm_panel_bridge_remove(priv->bridge); drm_mode_config_cleanup(drm); @@ -249,6 +250,11 @@ static void tve200_remove(struct platform_device *pdev) drm_dev_put(drm); } +static void tve200_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct of_device_id tve200_of_match[] = { { .compatible = "faraday,tve200", @@ -263,6 +269,7 @@ static struct platform_driver tve200_driver = { }, .probe = tve200_probe, .remove_new = tve200_remove, + .shutdown = tve200_shutdown, }; drm_module_platform_driver(tve200_driver); diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 7f664a4b2a75..106454f28956 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -59,7 +59,7 @@ struct v3d_perfmon { * values can't be reset, but you can fake a reset by * destroying the perfmon and creating a new one. */ - u64 values[]; + u64 values[] __counted_by(ncounters); }; struct v3d_dev { diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c b/drivers/gpu/drm/vboxvideo/vbox_drv.c index 4fee15c97c34..047b95812334 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_drv.c +++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c @@ -12,6 +12,7 @@ #include <linux/vt_kern.h> #include <drm/drm_aperture.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fbdev_generic.h> #include <drm/drm_file.h> @@ -97,11 +98,19 @@ static void vbox_pci_remove(struct pci_dev *pdev) struct vbox_private *vbox = pci_get_drvdata(pdev); drm_dev_unregister(&vbox->ddev); + drm_atomic_helper_shutdown(&vbox->ddev); vbox_irq_fini(vbox); vbox_mode_fini(vbox); vbox_hw_fini(vbox); } +static void vbox_pci_shutdown(struct pci_dev *pdev) +{ + struct vbox_private *vbox = pci_get_drvdata(pdev); + + drm_atomic_helper_shutdown(&vbox->ddev); +} + static int vbox_pm_suspend(struct device *dev) { struct vbox_private *vbox = dev_get_drvdata(dev); @@ -165,6 +174,7 @@ static struct pci_driver vbox_pci_driver = { .id_table = pciidlist, .probe = vbox_pci_probe, .remove = vbox_pci_remove, + .shutdown = vbox_pci_shutdown, .driver.pm = pm_sleep_ptr(&vbox_pm_ops), }; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 1b3531374967..c133e96b8aca 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -324,21 +324,21 @@ static int vc4_drm_bind(struct device *dev) if (!is_vc5) { ret = drmm_mutex_init(drm, &vc4->bin_bo_lock); if (ret) - return ret; + goto err; ret = vc4_bo_cache_init(drm); if (ret) - return ret; + goto err; } ret = drmm_mode_config_init(drm); if (ret) - return ret; + goto err; if (!is_vc5) { ret = vc4_gem_init(drm); if (ret) - return ret; + goto err; } node = of_find_compatible_node(NULL, NULL, "raspberrypi,bcm2835-firmware"); @@ -346,13 +346,15 @@ static int vc4_drm_bind(struct device *dev) firmware = rpi_firmware_get(node); of_node_put(node); - if (!firmware) - return -EPROBE_DEFER; + if (!firmware) { + ret = -EPROBE_DEFER; + goto err; + } } ret = drm_aperture_remove_framebuffers(driver); if (ret) - return ret; + goto err; if (firmware) { ret = rpi_firmware_property(firmware, @@ -366,32 +368,33 @@ static int vc4_drm_bind(struct device *dev) ret = component_bind_all(dev, drm); if (ret) - return ret; + goto err; ret = devm_add_action_or_reset(dev, vc4_component_unbind_all, vc4); if (ret) - return ret; + goto err; ret = vc4_plane_create_additional_planes(drm); if (ret) - goto unbind_all; + goto err; ret = vc4_kms_load(drm); if (ret < 0) - goto unbind_all; + goto err; drm_for_each_crtc(crtc, drm) vc4_crtc_disable_at_boot(crtc); ret = drm_dev_register(drm, 0); if (ret < 0) - goto unbind_all; + goto err; drm_fbdev_dma_setup(drm, 16); return 0; -unbind_all: +err: + platform_set_drvdata(pdev, NULL); return ret; } @@ -401,6 +404,7 @@ static void vc4_drm_unbind(struct device *dev) drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); + dev_set_drvdata(dev, NULL); } static const struct component_master_ops vc4_drm_ops = { @@ -444,6 +448,11 @@ static void vc4_platform_drm_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &vc4_drm_ops); } +static void vc4_platform_drm_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); +} + static const struct of_device_id vc4_of_match[] = { { .compatible = "brcm,bcm2711-vc5", }, { .compatible = "brcm,bcm2835-vc4", }, @@ -455,6 +464,7 @@ MODULE_DEVICE_TABLE(of, vc4_of_match); static struct platform_driver vc4_platform_driver = { .probe = vc4_platform_drm_probe, .remove_new = vc4_platform_drm_remove, + .shutdown = vc4_platform_drm_shutdown, .driver = { .name = "vc4-drm", .of_match_table = vc4_of_match, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index bf66499765fb..ab61e96e7e14 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -76,7 +76,7 @@ struct vc4_perfmon { * Note that counter values can't be reset, but you can fake a reset by * destroying the perfmon and creating a new one. */ - u64 counters[]; + u64 counters[] __counted_by(ncounters); }; struct vc4_dev { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index a488625773dc..25c9c71256d3 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2615,9 +2615,13 @@ static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops vc4_snd_dai_ops = { + .probe = vc4_hdmi_audio_cpu_dai_probe, +}; + static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = { .name = "vc4-hdmi-cpu-dai", - .probe = vc4_hdmi_audio_cpu_dai_probe, + .ops = &vc4_snd_dai_ops, .playback = { .stream_name = "Playback", .channels_min = 1, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 4126c384286b..96365a772f77 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -119,7 +119,7 @@ struct virtio_gpu_object_array { struct ww_acquire_ctx ticket; struct list_head next; u32 nents, total; - struct drm_gem_object *objs[]; + struct drm_gem_object *objs[] __counted_by(total); }; struct virtio_gpu_vbuffer; @@ -344,8 +344,6 @@ void virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *obj, struct virtio_gpu_mem_entry *ents, unsigned int nents); -int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev); -int virtio_gpu_detach_status_page(struct virtio_gpu_device *vgdev); void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, struct virtio_gpu_output *output); int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev); @@ -394,11 +392,8 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_fence *fence); void virtio_gpu_ctrl_ack(struct virtqueue *vq); void virtio_gpu_cursor_ack(struct virtqueue *vq); -void virtio_gpu_fence_ack(struct virtqueue *vq); void virtio_gpu_dequeue_ctrl_func(struct work_struct *work); void virtio_gpu_dequeue_cursor_func(struct work_struct *work); -void virtio_gpu_dequeue_fence_func(struct work_struct *work); - void virtio_gpu_notify(struct virtio_gpu_device *vgdev); int @@ -465,8 +460,6 @@ struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj, int flags); struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev, struct dma_buf *buf); -int virtgpu_gem_prime_get_uuid(struct drm_gem_object *obj, - uuid_t *uuid); struct drm_gem_object *virtgpu_gem_prime_import_sg_table( struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index d5d4f642d367..3c99fb8b54e2 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -408,15 +408,10 @@ void vkms_set_composer(struct vkms_output *out, bool enabled) if (enabled) drm_crtc_vblank_get(&out->crtc); - mutex_lock(&out->enabled_lock); + spin_lock_irq(&out->lock); old_enabled = out->composer_enabled; out->composer_enabled = enabled; - - /* the composition wasn't enabled, so unlock the lock to make sure the lock - * will be balanced even if we have a failed commit - */ - if (!out->composer_enabled) - mutex_unlock(&out->enabled_lock); + spin_unlock_irq(&out->lock); if (old_enabled) drm_crtc_vblank_put(&out->crtc); diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index 3c5ebf106b66..61e500b8c9da 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -16,7 +16,7 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) struct drm_crtc *crtc = &output->crtc; struct vkms_crtc_state *state; u64 ret_overrun; - bool ret, fence_cookie, composer_enabled; + bool ret, fence_cookie; fence_cookie = dma_fence_begin_signalling(); @@ -25,15 +25,15 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) if (ret_overrun != 1) pr_warn("%s: vblank timer overrun\n", __func__); + spin_lock(&output->lock); ret = drm_crtc_handle_vblank(crtc); if (!ret) DRM_ERROR("vkms failure on handling vblank"); state = output->composer_state; - composer_enabled = output->composer_enabled; - mutex_unlock(&output->enabled_lock); + spin_unlock(&output->lock); - if (state && composer_enabled) { + if (state && output->composer_enabled) { u64 frame = drm_crtc_accurate_vblank_count(crtc); /* update frame_start only if a queued vkms_composer_worker() @@ -295,7 +295,6 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, spin_lock_init(&vkms_out->lock); spin_lock_init(&vkms_out->composer_lock); - mutex_init(&vkms_out->enabled_lock); vkms_out->composer_workq = alloc_ordered_workqueue("vkms_composer", 0); if (!vkms_out->composer_workq) diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index c7ae6c2ba1df..8f5710debb1e 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -108,10 +108,8 @@ struct vkms_output { struct workqueue_struct *composer_workq; /* protects concurrent access to composer */ spinlock_t lock; - /* guarantees that if the composer is enabled, a job will be queued */ - struct mutex enabled_lock; - /* protected by @enabled_lock */ + /* protected by @lock */ bool composer_enabled; struct vkms_crtc_state *composer_state; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 82094c137855..c43853597776 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -497,10 +497,9 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp, if (!(flags & drm_vmw_synccpu_allow_cs)) { atomic_dec(&vmw_bo->cpu_writers); } - ttm_bo_put(&vmw_bo->tbo); + vmw_user_bo_unref(vmw_bo); } - drm_gem_object_put(&vmw_bo->tbo.base); return ret; } @@ -540,8 +539,7 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, return ret; ret = vmw_user_bo_synccpu_grab(vbo, arg->flags); - vmw_bo_unreference(&vbo); - drm_gem_object_put(&vbo->tbo.base); + vmw_user_bo_unref(vbo); if (unlikely(ret != 0)) { if (ret == -ERESTARTSYS || ret == -EBUSY) return -EBUSY; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.h b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.h index 50a836e70994..1d433fceed3d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.h @@ -195,6 +195,14 @@ static inline struct vmw_bo *vmw_bo_reference(struct vmw_bo *buf) return buf; } +static inline void vmw_user_bo_unref(struct vmw_bo *vbo) +{ + if (vbo) { + ttm_bo_put(&vbo->tbo); + drm_gem_object_put(&vbo->tbo.base); + } +} + static inline struct vmw_bo *to_vmw_bo(struct drm_gem_object *gobj) { return container_of((gobj), struct vmw_bo, tbo.base); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 3810a9984a7f..58bfdf203eca 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1513,4 +1513,16 @@ static inline bool vmw_has_fences(struct vmw_private *vmw) return (vmw_fifo_caps(vmw) & SVGA_FIFO_CAP_FENCE) != 0; } +static inline bool vmw_shadertype_is_valid(enum vmw_sm_type shader_model, + u32 shader_type) +{ + SVGA3dShaderType max_allowed = SVGA3D_SHADERTYPE_PREDX_MAX; + + if (shader_model >= VMW_SM_5) + max_allowed = SVGA3D_SHADERTYPE_MAX; + else if (shader_model >= VMW_SM_4) + max_allowed = SVGA3D_SHADERTYPE_DX10_MAX; + return shader_type >= SVGA3D_SHADERTYPE_MIN && shader_type < max_allowed; +} + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 6b9aa2b4ef54..98e0723ca6f5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1164,8 +1164,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, } vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_MOB, VMW_BO_DOMAIN_MOB); ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo); - ttm_bo_put(&vmw_bo->tbo); - drm_gem_object_put(&vmw_bo->tbo.base); + vmw_user_bo_unref(vmw_bo); if (unlikely(ret != 0)) return ret; @@ -1221,8 +1220,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM); ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo); - ttm_bo_put(&vmw_bo->tbo); - drm_gem_object_put(&vmw_bo->tbo.base); + vmw_user_bo_unref(vmw_bo); if (unlikely(ret != 0)) return ret; @@ -1992,7 +1990,7 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv, cmd = container_of(header, typeof(*cmd), header); - if (cmd->body.type >= SVGA3D_SHADERTYPE_PREDX_MAX) { + if (!vmw_shadertype_is_valid(VMW_SM_LEGACY, cmd->body.type)) { VMW_DEBUG_USER("Illegal shader type %u.\n", (unsigned int) cmd->body.type); return -EINVAL; @@ -2115,8 +2113,6 @@ vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv, SVGA3dCmdHeader *header) { VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetSingleConstantBuffer); - SVGA3dShaderType max_shader_num = has_sm5_context(dev_priv) ? - SVGA3D_NUM_SHADERTYPE : SVGA3D_NUM_SHADERTYPE_DX10; struct vmw_resource *res = NULL; struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context); @@ -2133,6 +2129,14 @@ vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; + if (!vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type) || + cmd->body.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) { + VMW_DEBUG_USER("Illegal const buffer shader %u slot %u.\n", + (unsigned int) cmd->body.type, + (unsigned int) cmd->body.slot); + return -EINVAL; + } + binding.bi.ctx = ctx_node->ctx; binding.bi.res = res; binding.bi.bt = vmw_ctx_binding_cb; @@ -2141,14 +2145,6 @@ vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv, binding.size = cmd->body.sizeInBytes; binding.slot = cmd->body.slot; - if (binding.shader_slot >= max_shader_num || - binding.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) { - VMW_DEBUG_USER("Illegal const buffer shader %u slot %u.\n", - (unsigned int) cmd->body.type, - (unsigned int) binding.slot); - return -EINVAL; - } - vmw_binding_add(ctx_node->staged, &binding.bi, binding.shader_slot, binding.slot); @@ -2207,15 +2203,13 @@ static int vmw_cmd_dx_set_shader_res(struct vmw_private *dev_priv, { VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetShaderResources) = container_of(header, typeof(*cmd), header); - SVGA3dShaderType max_allowed = has_sm5_context(dev_priv) ? - SVGA3D_SHADERTYPE_MAX : SVGA3D_SHADERTYPE_DX10_MAX; u32 num_sr_view = (cmd->header.size - sizeof(cmd->body)) / sizeof(SVGA3dShaderResourceViewId); if ((u64) cmd->body.startView + (u64) num_sr_view > (u64) SVGA3D_DX_MAX_SRVIEWS || - cmd->body.type >= max_allowed) { + !vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type)) { VMW_DEBUG_USER("Invalid shader binding.\n"); return -EINVAL; } @@ -2239,8 +2233,6 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv, SVGA3dCmdHeader *header) { VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetShader); - SVGA3dShaderType max_allowed = has_sm5_context(dev_priv) ? - SVGA3D_SHADERTYPE_MAX : SVGA3D_SHADERTYPE_DX10_MAX; struct vmw_resource *res = NULL; struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context); struct vmw_ctx_bindinfo_shader binding; @@ -2251,8 +2243,7 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv, cmd = container_of(header, typeof(*cmd), header); - if (cmd->body.type >= max_allowed || - cmd->body.type < SVGA3D_SHADERTYPE_MIN) { + if (!vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type)) { VMW_DEBUG_USER("Illegal shader type %u.\n", (unsigned int) cmd->body.type); return -EINVAL; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c index c0da89e16e6f..a07e5b7e2f2f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c @@ -232,6 +232,7 @@ static int vmw_debugfs_gem_info_show(struct seq_file *m, void *unused) list_for_each_entry(file, &dev->filelist, lhead) { struct task_struct *task; struct drm_gem_object *gobj; + struct pid *pid; int id; /* @@ -241,8 +242,9 @@ static int vmw_debugfs_gem_info_show(struct seq_file *m, void *unused) * Therefore, we need to protect this ->comm access using RCU. */ rcu_read_lock(); - task = pid_task(file->pid, PIDTYPE_TGID); - seq_printf(m, "pid %8d command %s:\n", pid_nr(file->pid), + pid = rcu_dereference(file->pid); + task = pid_task(pid, PIDTYPE_TGID); + seq_printf(m, "pid %8d command %s:\n", pid_nr(pid), task ? task->comm : "<unknown>"); rcu_read_unlock(); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b62207be3363..1489ad73c103 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1665,10 +1665,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, err_out: /* vmw_user_lookup_handle takes one ref so does new_fb */ - if (bo) { - vmw_bo_unreference(&bo); - drm_gem_object_put(&bo->tbo.base); - } + if (bo) + vmw_user_bo_unref(bo); if (surface) vmw_surface_unreference(&surface); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 7e112319a23c..fb85f244c3d0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -451,8 +451,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data, ret = vmw_overlay_update_stream(dev_priv, buf, arg, true); - vmw_bo_unreference(&buf); - drm_gem_object_put(&buf->tbo.base); + vmw_user_bo_unref(buf); out_unlock: mutex_unlock(&overlay->mutex); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index e7226db8b242..1e81ff2422cf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -809,8 +809,7 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, shader_type, num_input_sig, num_output_sig, tfile, shader_handle); out_bad_arg: - vmw_bo_unreference(&buffer); - drm_gem_object_put(&buffer->tbo.base); + vmw_user_bo_unref(buffer); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 5db403ee8261..2d1d857f99ae 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -77,7 +77,7 @@ struct vmw_surface_offset { struct vmw_surface_dirty { struct vmw_surface_cache cache; u32 num_subres; - SVGA3dBox boxes[]; + SVGA3dBox boxes[] __counted_by(num_subres); }; static void vmw_user_surface_free(struct vmw_resource *res); |