diff options
| author | Tvrtko Ursulin <tvrtko.ursulin@intel.com> | 2023-06-05 13:10:23 +0300 |
|---|---|---|
| committer | Tvrtko Ursulin <tvrtko.ursulin@intel.com> | 2023-06-05 13:10:23 +0300 |
| commit | 9ff17e6bdaa50892dd9bdb1b116cb71b73dd711a (patch) | |
| tree | cbffbccb83865b418a0aabb4487b6e8fe70c590d /drivers/gpu | |
| parent | d922b80b1010cd6164fa7d3c197b4fbf94b47beb (diff) | |
| parent | 2e1492835e439fceba57a5b0f9b17da8e78ffa3d (diff) | |
| download | linux-9ff17e6bdaa50892dd9bdb1b116cb71b73dd711a.tar.xz | |
Merge drm/drm-next into drm-intel-gt-next
For conflict avoidance we need the following commit:
c9a9f18d3ad8 drm/i915/huc: use const struct bus_type pointers
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Diffstat (limited to 'drivers/gpu')
350 files changed, 7111 insertions, 2956 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index ba3fb04bb691..bb2e48cc6cd6 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -95,6 +95,7 @@ config DRM_KUNIT_TEST config DRM_KMS_HELPER tristate depends on DRM + select FB_SYS_HELPERS_DEFERRED if DRM_FBDEV_EMULATION help CRTC helpers for KMS drivers. @@ -132,14 +133,6 @@ config DRM_FBDEV_EMULATION bool "Enable legacy fbdev support for your modesetting driver" depends on DRM_KMS_HELPER depends on FB=y || FB=DRM_KMS_HELPER - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_DEFERRED_IO - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT select FRAMEBUFFER_CONSOLE if !EXPERT select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE default y @@ -223,6 +216,7 @@ config DRM_TTM_HELPER config DRM_GEM_DMA_HELPER tristate depends on DRM + select FB_SYS_HELPERS if DRM_FBDEV_EMULATION help Choose this if you need the GEM DMA helper functions diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index dd8bc53411bd..415a7fa395c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -136,6 +136,7 @@ amdgpu-y += \ gfx_v9_0.o \ gfx_v9_4.o \ gfx_v9_4_2.o \ + gfx_v9_4_3.o \ gfx_v10_0.o \ imu_v11_0.o \ gfx_v11_0.o \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 8cf2cc50b3de..02b827785e39 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -185,7 +185,6 @@ extern char *amdgpu_disable_cu; extern char *amdgpu_virtual_display; extern uint amdgpu_pp_feature_mask; extern uint amdgpu_force_long_training; -extern int amdgpu_job_hang_limit; extern int amdgpu_lbpw; extern int amdgpu_compute_multipipe; extern int amdgpu_gpu_recovery; @@ -471,7 +470,7 @@ int amdgpu_file_to_fpriv(struct file *filp, struct amdgpu_fpriv **fpriv); /* * Writeback */ -#define AMDGPU_MAX_WB 256 /* Reserve at most 256 WB slots for amdgpu-owned rings. */ +#define AMDGPU_MAX_WB 1024 /* Reserve at most 1024 WB slots for amdgpu-owned rings. */ struct amdgpu_wb { struct amdgpu_bo *wb_obj; @@ -1222,7 +1221,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev); ((adev)->asic_funcs->flush_hdp ? (adev)->asic_funcs->flush_hdp((adev), (r)) : (adev)->hdp.funcs->flush_hdp((adev), (r))) #define amdgpu_asic_invalidate_hdp(adev, r) \ ((adev)->asic_funcs->invalidate_hdp ? (adev)->asic_funcs->invalidate_hdp((adev), (r)) : \ - ((adev)->hdp.funcs->invalidate_hdp ? (adev)->hdp.funcs->invalidate_hdp((adev), (r)) : 0)) + ((adev)->hdp.funcs->invalidate_hdp ? (adev)->hdp.funcs->invalidate_hdp((adev), (r)) : (void)0)) #define amdgpu_asic_need_full_reset(adev) (adev)->asic_funcs->need_full_reset((adev)) #define amdgpu_asic_init_doorbell_index(adev) (adev)->asic_funcs->init_doorbell_index((adev)) #define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1))) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 60b1857f469e..aeeec211861c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -981,7 +981,12 @@ static bool amdgpu_atcs_pci_probe_handle(struct pci_dev *pdev) */ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev) { - if (adev->flags & AMD_IS_APU) + if ((adev->flags & AMD_IS_APU) && + adev->gfx.imu.funcs) /* Not need to do mode2 reset for IMU enabled APUs */ + return false; + + if ((adev->flags & AMD_IS_APU) && + amdgpu_acpi_is_s3_active(adev)) return false; if (amdgpu_sriov_vf(adev)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index f99d4873bf22..0385f7f69278 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -96,7 +96,7 @@ static void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev, size_t *start_offset) { /* - * The first num_doorbells are used by amdgpu. + * The first num_kernel_doorbells are used by amdgpu. * amdkfd takes whatever's left in the aperture. */ if (adev->enable_mes) { @@ -109,11 +109,11 @@ static void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev, *aperture_base = adev->doorbell.base; *aperture_size = 0; *start_offset = 0; - } else if (adev->doorbell.size > adev->doorbell.num_doorbells * + } else if (adev->doorbell.size > adev->doorbell.num_kernel_doorbells * sizeof(u32)) { *aperture_base = adev->doorbell.base; *aperture_size = adev->doorbell.size; - *start_offset = adev->doorbell.num_doorbells * sizeof(u32); + *start_offset = adev->doorbell.num_kernel_doorbells * sizeof(u32); } else { *aperture_base = 0; *aperture_size = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index c87515210c4f..83a83ced2439 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -82,6 +82,25 @@ static bool kfd_mem_is_attached(struct amdgpu_vm *avm, return false; } +/** + * reuse_dmamap() - Check whether adev can share the original + * userptr BO + * + * If both adev and bo_adev are in direct mapping or + * in the same iommu group, they can share the original BO. + * + * @adev: Device to which can or cannot share the original BO + * @bo_adev: Device to which allocated BO belongs to + * + * Return: returns true if adev can share original userptr BO, + * false otherwise. + */ +static bool reuse_dmamap(struct amdgpu_device *adev, struct amdgpu_device *bo_adev) +{ + return (adev->ram_is_direct_mapped && bo_adev->ram_is_direct_mapped) || + (adev->dev->iommu_group == bo_adev->dev->iommu_group); +} + /* Set memory usage limits. Current, limits are * System (TTM + userptr) memory - 15/16th System RAM * TTM memory - 3/8th System RAM @@ -253,15 +272,19 @@ create_dmamap_sg_bo(struct amdgpu_device *adev, struct kgd_mem *mem, struct amdgpu_bo **bo_out) { struct drm_gem_object *gem_obj; - int ret, align; + int ret; + uint64_t flags = 0; ret = amdgpu_bo_reserve(mem->bo, false); if (ret) return ret; - align = 1; - ret = amdgpu_gem_object_create(adev, mem->bo->tbo.base.size, align, - AMDGPU_GEM_DOMAIN_CPU, AMDGPU_GEM_CREATE_PREEMPTIBLE, + if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) + flags |= mem->bo->flags & (AMDGPU_GEM_CREATE_COHERENT | + AMDGPU_GEM_CREATE_UNCACHED); + + ret = amdgpu_gem_object_create(adev, mem->bo->tbo.base.size, 1, + AMDGPU_GEM_DOMAIN_CPU, AMDGPU_GEM_CREATE_PREEMPTIBLE | flags, ttm_bo_type_sg, mem->bo->tbo.base.resv, &gem_obj); amdgpu_bo_unreserve(mem->bo); @@ -481,9 +504,6 @@ kfd_mem_dmamap_userptr(struct kgd_mem *mem, if (unlikely(ret)) goto release_sg; - drm_prime_sg_to_dma_addr_array(ttm->sg, ttm->dma_address, - ttm->num_pages); - amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT); ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); if (ret) @@ -805,11 +825,11 @@ static int kfd_mem_attach(struct amdgpu_device *adev, struct kgd_mem *mem, va + bo_size, vm); if ((adev == bo_adev && !(mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP)) || - (amdgpu_ttm_tt_get_usermm(mem->bo->tbo.ttm) && adev->ram_is_direct_mapped) || - same_hive) { + (amdgpu_ttm_tt_get_usermm(mem->bo->tbo.ttm) && reuse_dmamap(adev, bo_adev)) || + same_hive) { /* Mappings on the local GPU, or VRAM mappings in the - * local hive, or userptr mapping IOMMU direct map mode - * share the original BO + * local hive, or userptr mapping can reuse dma map + * address space share the original BO */ attachment[i]->type = KFD_MEM_ATT_SHARED; bo[i] = mem->bo; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 08eced097bd8..2eb2c66843a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1276,7 +1276,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, r = drm_sched_job_add_dependency(&leader->base, fence); if (r) { dma_fence_put(fence); - goto error_cleanup; + return r; } } @@ -1303,7 +1303,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, } if (r) { r = -EAGAIN; - goto error_unlock; + mutex_unlock(&p->adev->notifier_lock); + return r; } p->fence = dma_fence_get(&leader->base.s_fence->finished); @@ -1350,14 +1351,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, mutex_unlock(&p->adev->notifier_lock); mutex_unlock(&p->bo_list->bo_list_mutex); return 0; - -error_unlock: - mutex_unlock(&p->adev->notifier_lock); - -error_cleanup: - for (i = 0; i < p->gang_size; ++i) - drm_sched_job_cleanup(&p->jobs[i]->base); - return r; } /* Cleanup the parser structure */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index fac9312b1695..5c7d40873ee2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -602,7 +602,7 @@ u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index) if (amdgpu_device_skip_hw_access(adev)) return 0; - if (index < adev->doorbell.num_doorbells) { + if (index < adev->doorbell.num_kernel_doorbells) { return readl(adev->doorbell.ptr + index); } else { DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index); @@ -625,7 +625,7 @@ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v) if (amdgpu_device_skip_hw_access(adev)) return; - if (index < adev->doorbell.num_doorbells) { + if (index < adev->doorbell.num_kernel_doorbells) { writel(v, adev->doorbell.ptr + index); } else { DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index); @@ -646,7 +646,7 @@ u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index) if (amdgpu_device_skip_hw_access(adev)) return 0; - if (index < adev->doorbell.num_doorbells) { + if (index < adev->doorbell.num_kernel_doorbells) { return atomic64_read((atomic64_t *)(adev->doorbell.ptr + index)); } else { DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index); @@ -669,7 +669,7 @@ void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v) if (amdgpu_device_skip_hw_access(adev)) return; - if (index < adev->doorbell.num_doorbells) { + if (index < adev->doorbell.num_kernel_doorbells) { atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v); } else { DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index); @@ -1060,7 +1060,7 @@ static int amdgpu_device_doorbell_init(struct amdgpu_device *adev) if (adev->asic_type < CHIP_BONAIRE) { adev->doorbell.base = 0; adev->doorbell.size = 0; - adev->doorbell.num_doorbells = 0; + adev->doorbell.num_kernel_doorbells = 0; adev->doorbell.ptr = NULL; return 0; } @@ -1075,27 +1075,27 @@ static int amdgpu_device_doorbell_init(struct amdgpu_device *adev) adev->doorbell.size = pci_resource_len(adev->pdev, 2); if (adev->enable_mes) { - adev->doorbell.num_doorbells = + adev->doorbell.num_kernel_doorbells = adev->doorbell.size / sizeof(u32); } else { - adev->doorbell.num_doorbells = + adev->doorbell.num_kernel_doorbells = min_t(u32, adev->doorbell.size / sizeof(u32), adev->doorbell_index.max_assignment+1); - if (adev->doorbell.num_doorbells == 0) + if (adev->doorbell.num_kernel_doorbells == 0) return -EINVAL; /* For Vega, reserve and map two pages on doorbell BAR since SDMA * paging queue doorbell use the second page. The * AMDGPU_DOORBELL64_MAX_ASSIGNMENT definition assumes all the * doorbells are in the first page. So with paging queue enabled, - * the max num_doorbells should + 1 page (0x400 in dword) + * the max num_kernel_doorbells should + 1 page (0x400 in dword) */ if (adev->asic_type >= CHIP_VEGA10) - adev->doorbell.num_doorbells += 0x400; + adev->doorbell.num_kernel_doorbells += 0x400; } adev->doorbell.ptr = ioremap(adev->doorbell.base, - adev->doorbell.num_doorbells * + adev->doorbell.num_kernel_doorbells * sizeof(u32)); if (adev->doorbell.ptr == NULL) return -ENOMEM; @@ -2184,7 +2184,6 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) adev->has_pr3 = parent ? pci_pr3_present(parent) : false; } - amdgpu_amdkfd_device_probe(adev); adev->pm.pp_feature = amdgpu_pp_feature_mask; if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS) @@ -2240,6 +2239,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) if (!total) return -ENODEV; + amdgpu_amdkfd_device_probe(adev); adev->cg_flags &= amdgpu_cg_mask; adev->pg_flags &= amdgpu_pg_mask; @@ -2365,7 +2365,7 @@ static int amdgpu_device_init_schedulers(struct amdgpu_device *adev) } r = drm_sched_init(&ring->sched, &amdgpu_sched_ops, - ring->num_hw_submission, amdgpu_job_hang_limit, + ring->num_hw_submission, 0, timeout, adev->reset_domain->wq, ring->sched_score, ring->name, adev->dev); @@ -2539,8 +2539,6 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) amdgpu_fru_get_product_info(adev); init_failed: - if (amdgpu_sriov_vf(adev)) - amdgpu_virt_release_full_gpu(adev, true); return r; } @@ -3305,9 +3303,11 @@ static int amdgpu_device_ip_resume(struct amdgpu_device *adev) { int r; - r = amdgpu_amdkfd_resume_iommu(adev); - if (r) - return r; + if (!adev->in_s0ix) { + r = amdgpu_amdkfd_resume_iommu(adev); + if (r) + return r; + } r = amdgpu_device_ip_resume_phase1(adev); if (r) @@ -3578,6 +3578,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, int r, i; bool px = false; u32 max_MBps; + int tmp; adev->shutdown = false; adev->flags = flags; @@ -3756,6 +3757,12 @@ int amdgpu_device_init(struct amdgpu_device *adev, adev->have_atomics_support = ((struct amd_sriov_msg_pf2vf_info *) adev->virt.fw_reserve.p_pf2vf)->pcie_atomic_ops_support_flags == (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | PCI_EXP_DEVCAP2_ATOMIC_COMP64); + /* APUs w/ gfx9 onwards doesn't reply on PCIe atomics, rather it is a + * internal path natively support atomics, set have_atomics_support to true. + */ + else if ((adev->flags & AMD_IS_APU) && + (adev->ip_versions[GC_HWIP][0] > IP_VERSION(9, 0, 0))) + adev->have_atomics_support = true; else adev->have_atomics_support = !pci_enable_atomic_ops_to_root(adev->pdev, @@ -3799,7 +3806,13 @@ int amdgpu_device_init(struct amdgpu_device *adev, } } } else { + tmp = amdgpu_reset_method; + /* It should do a default reset when loading or reloading the driver, + * regardless of the module parameter reset_method. + */ + amdgpu_reset_method = AMD_RESET_METHOD_NONE; r = amdgpu_asic_reset(adev); + amdgpu_reset_method = tmp; if (r) { dev_err(adev->dev, "asic reset on init failed\n"); goto failed; @@ -3857,18 +3870,6 @@ fence_driver_init: r = amdgpu_device_ip_init(adev); if (r) { - /* failed in exclusive mode due to timeout */ - if (amdgpu_sriov_vf(adev) && - !amdgpu_sriov_runtime(adev) && - amdgpu_virt_mmio_blocked(adev) && - !amdgpu_virt_wait_reset(adev)) { - dev_err(adev->dev, "VF exclusive mode timeout\n"); - /* Don't send request since VF is inactive. */ - adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME; - adev->virt.ops = NULL; - r = -EAGAIN; - goto release_ras_con; - } dev_err(adev->dev, "amdgpu_device_ip_init failed\n"); amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 0); goto release_ras_con; @@ -3937,8 +3938,10 @@ fence_driver_init: msecs_to_jiffies(AMDGPU_RESUME_MS)); } - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev)) { + amdgpu_virt_release_full_gpu(adev, true); flush_delayed_work(&adev->delayed_init_work); + } r = sysfs_create_files(&adev->dev->kobj, amdgpu_dev_attributes); if (r) @@ -3978,6 +3981,20 @@ fence_driver_init: return 0; release_ras_con: + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_release_full_gpu(adev, true); + + /* failed in exclusive mode due to timeout */ + if (amdgpu_sriov_vf(adev) && + !amdgpu_sriov_runtime(adev) && + amdgpu_virt_mmio_blocked(adev) && + !amdgpu_virt_wait_reset(adev)) { + dev_err(adev->dev, "VF exclusive mode timeout\n"); + /* Don't send request since VF is inactive. */ + adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME; + adev->virt.ops = NULL; + r = -EAGAIN; + } amdgpu_release_ras_context(adev); failed: @@ -4495,7 +4512,11 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) dev_info(adev->dev, "recover vram bo from shadow start\n"); mutex_lock(&adev->shadow_list_lock); list_for_each_entry(vmbo, &adev->shadow_list, shadow_list) { - shadow = &vmbo->bo; + /* If vm is compute context or adev is APU, shadow will be NULL */ + if (!vmbo->shadow) + continue; + shadow = vmbo->shadow; + /* No need to recover an evicted BO */ if (shadow->tbo.resource->mem_type != TTM_PL_TT || shadow->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET || diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 5139334925ea..0ecce0b92b82 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -1502,6 +1502,7 @@ static int amdgpu_discovery_set_common_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(9, 4, 0): case IP_VERSION(9, 4, 1): case IP_VERSION(9, 4, 2): + case IP_VERSION(9, 4, 3): amdgpu_device_ip_block_add(adev, &vega10_common_ip_block); break; case IP_VERSION(10, 1, 10): diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h index 7199b6b0be81..8fd11497faba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h @@ -21,6 +21,9 @@ * */ +#ifndef AMDGPU_DOORBELL_H +#define AMDGPU_DOORBELL_H + /* * GPU doorbell structures, functions & helpers */ @@ -29,7 +32,9 @@ struct amdgpu_doorbell { resource_size_t base; resource_size_t size; u32 __iomem *ptr; - u32 num_doorbells; /* Number of doorbells actually reserved for amdgpu. */ + + /* Number of doorbells reserved for amdgpu kernel driver */ + u32 num_kernel_doorbells; }; /* Reserved doorbells for amdgpu (including multimedia). @@ -306,3 +311,4 @@ void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v); #define RDOORBELL64(index) amdgpu_mm_rdoorbell64(adev, (index)) #define WDOORBELL64(index, v) amdgpu_mm_wdoorbell64(adev, (index), (v)) +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index b4189d669b54..c9a41c997c6c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -157,7 +157,6 @@ char *amdgpu_virtual_display; */ uint amdgpu_pp_feature_mask = 0xfff7bfff; uint amdgpu_force_long_training; -int amdgpu_job_hang_limit; int amdgpu_lbpw = -1; int amdgpu_compute_multipipe = -1; int amdgpu_gpu_recovery = -1; /* auto */ @@ -521,13 +520,6 @@ MODULE_PARM_DESC(virtual_display, module_param_named(virtual_display, amdgpu_virtual_display, charp, 0444); /** - * DOC: job_hang_limit (int) - * Set how much time allow a job hang and not drop it. The default is 0. - */ -MODULE_PARM_DESC(job_hang_limit, "how much time allow a job hang and not drop it (default 0)"); -module_param_named(job_hang_limit, amdgpu_job_hang_limit, int ,0444); - -/** * DOC: lbpw (int) * Override Load Balancing Per Watt (LBPW) support (1 = enable, 0 = disable). The default is -1 (auto, enabled). */ @@ -2755,7 +2747,7 @@ static const struct file_operations amdgpu_driver_kms_fops = { .compat_ioctl = amdgpu_kms_compat_ioctl, #endif #ifdef CONFIG_PROC_FS - .show_fdinfo = amdgpu_show_fdinfo + .show_fdinfo = drm_show_fdinfo, #endif }; @@ -2810,6 +2802,9 @@ static const struct drm_driver amdgpu_kms_driver = { .dumb_map_offset = amdgpu_mode_dumb_mmap, .fops = &amdgpu_driver_kms_fops, .release = &amdgpu_driver_release_kms, +#ifdef CONFIG_PROC_FS + .show_fdinfo = amdgpu_show_fdinfo, +#endif .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c index c57252f004e8..13d7413d4ca3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c @@ -53,9 +53,8 @@ static const char *amdgpu_ip_name[AMDGPU_HW_IP_NUM] = { [AMDGPU_HW_IP_VCN_JPEG] = "jpeg", }; -void amdgpu_show_fdinfo(struct seq_file *m, struct file *f) +void amdgpu_show_fdinfo(struct drm_printer *p, struct drm_file *file) { - struct drm_file *file = f->private_data; struct amdgpu_device *adev = drm_to_adev(file->minor->dev); struct amdgpu_fpriv *fpriv = file->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; @@ -87,31 +86,30 @@ void amdgpu_show_fdinfo(struct seq_file *m, struct file *f) * ****************************************************************** */ - seq_printf(m, "pasid:\t%u\n", fpriv->vm.pasid); - seq_printf(m, "drm-driver:\t%s\n", file->minor->dev->driver->name); - seq_printf(m, "drm-pdev:\t%04x:%02x:%02x.%d\n", domain, bus, dev, fn); - seq_printf(m, "drm-client-id:\t%Lu\n", vm->immediate.fence_context); - seq_printf(m, "drm-memory-vram:\t%llu KiB\n", stats.vram/1024UL); - seq_printf(m, "drm-memory-gtt: \t%llu KiB\n", stats.gtt/1024UL); - seq_printf(m, "drm-memory-cpu: \t%llu KiB\n", stats.cpu/1024UL); - seq_printf(m, "amd-memory-visible-vram:\t%llu KiB\n", + drm_printf(p, "pasid:\t%u\n", fpriv->vm.pasid); + drm_printf(p, "drm-driver:\t%s\n", file->minor->dev->driver->name); + drm_printf(p, "drm-pdev:\t%04x:%02x:%02x.%d\n", domain, bus, dev, fn); + drm_printf(p, "drm-client-id:\t%Lu\n", vm->immediate.fence_context); + drm_printf(p, "drm-memory-vram:\t%llu KiB\n", stats.vram/1024UL); + drm_printf(p, "drm-memory-gtt: \t%llu KiB\n", stats.gtt/1024UL); + drm_printf(p, "drm-memory-cpu: \t%llu KiB\n", stats.cpu/1024UL); + drm_printf(p, "amd-memory-visible-vram:\t%llu KiB\n", stats.visible_vram/1024UL); - seq_printf(m, "amd-evicted-vram:\t%llu KiB\n", + drm_printf(p, "amd-evicted-vram:\t%llu KiB\n", stats.evicted_vram/1024UL); - seq_printf(m, "amd-evicted-visible-vram:\t%llu KiB\n", + drm_printf(p, "amd-evicted-visible-vram:\t%llu KiB\n", stats.evicted_visible_vram/1024UL); - seq_printf(m, "amd-requested-vram:\t%llu KiB\n", + drm_printf(p, "amd-requested-vram:\t%llu KiB\n", stats.requested_vram/1024UL); - seq_printf(m, "amd-requested-visible-vram:\t%llu KiB\n", + drm_printf(p, "amd-requested-visible-vram:\t%llu KiB\n", stats.requested_visible_vram/1024UL); - seq_printf(m, "amd-requested-gtt:\t%llu KiB\n", + drm_printf(p, "amd-requested-gtt:\t%llu KiB\n", stats.requested_gtt/1024UL); - for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { if (!usage[hw_ip]) continue; - seq_printf(m, "drm-engine-%s:\t%Ld ns\n", amdgpu_ip_name[hw_ip], + drm_printf(p, "drm-engine-%s:\t%Ld ns\n", amdgpu_ip_name[hw_ip], ktime_to_ns(usage[hw_ip])); } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h index e86834bfea1d..0398f5a159ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h @@ -37,6 +37,6 @@ #include "amdgpu_ids.h" uint32_t amdgpu_get_ip_count(struct amdgpu_device *adev, int id); -void amdgpu_show_fdinfo(struct seq_file *m, struct file *f); +void amdgpu_show_fdinfo(struct drm_printer *p, struct drm_file *file); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index c50d59855011..f3f541ba0aca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -305,6 +305,7 @@ int amdgpu_gfx_kiq_init_ring(struct amdgpu_device *adev, ring->ring_obj = NULL; ring->use_doorbell = true; ring->doorbell_index = adev->doorbell_index.kiq; + ring->vm_hub = AMDGPU_GFXHUB_0; r = amdgpu_gfx_kiq_acquire(adev, ring); if (r) @@ -686,9 +687,11 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r if (r) return r; - r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); - if (r) - goto late_fini; + if (adev->gfx.cp_ecc_error_irq.funcs) { + r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); + if (r) + goto late_fini; + } } else { amdgpu_ras_feature_enable_on_boot(adev, ras_block, 0); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index de9e7a00bb15..bfabea76d166 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -42,6 +42,8 @@ #define AMDGPU_GFX_CG_DISABLED_MODE 0x00000004L #define AMDGPU_GFX_LBPW_DISABLED_MODE 0x00000008L +#define AMDGPU_MAX_GC_INSTANCES 8 + #define AMDGPU_MAX_GFX_QUEUES KGD_MAX_QUEUES #define AMDGPU_MAX_COMPUTE_QUEUES KGD_MAX_QUEUES @@ -53,6 +55,15 @@ enum amdgpu_gfx_pipe_priority { #define AMDGPU_GFX_QUEUE_PRIORITY_MINIMUM 0 #define AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM 15 +enum amdgpu_gfx_partition { + AMDGPU_SPX_PARTITION_MODE = 0, + AMDGPU_DPX_PARTITION_MODE = 1, + AMDGPU_TPX_PARTITION_MODE = 2, + AMDGPU_QPX_PARTITION_MODE = 3, + AMDGPU_CPX_PARTITION_MODE = 4, + AMDGPU_UNKNOWN_COMPUTE_PARTITION_MODE, +}; + struct amdgpu_mec { struct amdgpu_bo *hpd_eop_obj; u64 hpd_eop_gpu_addr; @@ -323,7 +334,7 @@ struct amdgpu_gfx { bool cp_fw_write_wait; struct amdgpu_ring gfx_ring[AMDGPU_MAX_GFX_RINGS]; unsigned num_gfx_rings; - struct amdgpu_ring compute_ring[AMDGPU_MAX_COMPUTE_RINGS]; + struct amdgpu_ring compute_ring[AMDGPU_MAX_COMPUTE_RINGS * AMDGPU_MAX_GC_INSTANCES]; unsigned num_compute_rings; struct amdgpu_irq_src eop_irq; struct amdgpu_irq_src priv_reg_irq; @@ -364,6 +375,10 @@ struct amdgpu_gfx { struct amdgpu_ring sw_gfx_ring[AMDGPU_MAX_SW_GFX_RINGS]; struct amdgpu_ring_mux muxer; + + enum amdgpu_gfx_partition partition_mode; + uint32_t num_xcd; + uint32_t num_xcc_per_xcp; }; #define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 88bc7f5f46e6..4e2531758866 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -395,8 +395,21 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, while (fault->timestamp >= stamp) { uint64_t tmp; - if (atomic64_read(&fault->key) == key) - return true; + if (atomic64_read(&fault->key) == key) { + /* + * if we get a fault which is already present in + * the fault_ring and the timestamp of + * the fault is after the expired timestamp, + * then this is a new fault that needs to be added + * into the fault ring. + */ + if (fault->timestamp_expiry != 0 && + amdgpu_ih_ts_after(fault->timestamp_expiry, + timestamp)) + break; + else + return true; + } tmp = fault->timestamp; fault = &gmc->fault_ring[fault->next]; @@ -432,15 +445,32 @@ void amdgpu_gmc_filter_faults_remove(struct amdgpu_device *adev, uint64_t addr, { struct amdgpu_gmc *gmc = &adev->gmc; uint64_t key = amdgpu_gmc_fault_key(addr, pasid); + struct amdgpu_ih_ring *ih; struct amdgpu_gmc_fault *fault; + uint32_t last_wptr; + uint64_t last_ts; uint32_t hash; uint64_t tmp; + ih = adev->irq.retry_cam_enabled ? &adev->irq.ih_soft : &adev->irq.ih1; + /* Get the WPTR of the last entry in IH ring */ + last_wptr = amdgpu_ih_get_wptr(adev, ih); + /* Order wptr with ring data. */ + rmb(); + /* Get the timetamp of the last entry in IH ring */ + last_ts = amdgpu_ih_decode_iv_ts(adev, ih, last_wptr, -1); + hash = hash_64(key, AMDGPU_GMC_FAULT_HASH_ORDER); fault = &gmc->fault_ring[gmc->fault_hash[hash].idx]; do { - if (atomic64_cmpxchg(&fault->key, key, 0) == key) + if (atomic64_read(&fault->key) == key) { + /* + * Update the timestamp when this fault + * expired. + */ + fault->timestamp_expiry = last_ts; break; + } tmp = fault->timestamp; fault = &gmc->fault_ring[fault->next]; @@ -524,7 +554,7 @@ int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev) for (i = 0; i < adev->num_rings; ++i) { ring = adev->rings[i]; - vmhub = ring->funcs->vmhub; + vmhub = ring->vm_hub; if (ring == &adev->mes.ring) continue; @@ -540,7 +570,7 @@ int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev) vm_inv_engs[vmhub] &= ~(1 << ring->vm_inv_eng); dev_info(adev->dev, "ring %s uses VM inv eng %u on hub %u\n", - ring->name, ring->vm_inv_eng, ring->funcs->vmhub); + ring->name, ring->vm_inv_eng, ring->vm_hub); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index 232523e3e270..6d105d7fb98b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -70,6 +70,7 @@ struct amdgpu_gmc_fault { uint64_t timestamp:48; uint64_t next:AMDGPU_GMC_FAULT_RING_ORDER; atomic64_t key; + uint64_t timestamp_expiry:48; }; /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index df7eb0b7c4b9..4ff348e10e4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -267,7 +267,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, if (r) { dev_err(adev->dev, "failed to emit fence (%d)\n", r); if (job && job->vmid) - amdgpu_vmid_reset(adev, ring->funcs->vmhub, job->vmid); + amdgpu_vmid_reset(adev, ring->vm_hub, job->vmid); amdgpu_ring_undo(ring); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 3f07b1a2ce47..c991ca0b7a1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -202,7 +202,7 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; - unsigned vmhub = ring->funcs->vmhub; + unsigned vmhub = ring->vm_hub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; struct dma_fence **fences; unsigned i; @@ -277,7 +277,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; - unsigned vmhub = ring->funcs->vmhub; + unsigned vmhub = ring->vm_hub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; uint64_t fence_context = adev->fence_context + ring->idx; bool needs_flush = vm->use_cpu_for_update; @@ -338,7 +338,7 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; - unsigned vmhub = ring->funcs->vmhub; + unsigned vmhub = ring->vm_hub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; uint64_t fence_context = adev->fence_context + ring->idx; uint64_t updates = amdgpu_vm_tlb_seq(vm); @@ -398,7 +398,7 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, struct amdgpu_job *job, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; - unsigned vmhub = ring->funcs->vmhub; + unsigned vmhub = ring->vm_hub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; struct amdgpu_vmid *idle = NULL; struct amdgpu_vmid *id = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index d0a1cc88832c..fafebec5b7b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -596,6 +596,9 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, if (!src->enabled_types || !src->funcs->set) return -EINVAL; + if (WARN_ON(!amdgpu_irq_enabled(adev, src, type))) + return -EINVAL; + if (atomic_dec_and_test(&src->enabled_types[type])) return amdgpu_irq_update(adev, src, type); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h index e9f2c11ea416..be243adf3e65 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h @@ -98,6 +98,8 @@ struct amdgpu_irq { struct irq_domain *domain; /* GPU irq controller domain */ unsigned virq[AMDGPU_MAX_IRQ_SRC_ID]; uint32_t srbm_soft_reset; + u32 retry_cam_doorbell_index; + bool retry_cam_enabled; }; void amdgpu_irq_disable_all(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 0e55823ef6ca..f0f00466b59f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -1434,13 +1434,31 @@ int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe) struct amdgpu_firmware_info *info; char ucode_prefix[30]; char fw_name[40]; + bool need_retry = false; int r; - amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin", - ucode_prefix, - pipe == AMDGPU_MES_SCHED_PIPE ? "" : "1"); + amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, + sizeof(ucode_prefix)); + if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(11, 0, 0)) { + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin", + ucode_prefix, + pipe == AMDGPU_MES_SCHED_PIPE ? "_2" : "1"); + need_retry = true; + } else { + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin", + ucode_prefix, + pipe == AMDGPU_MES_SCHED_PIPE ? "" : "1"); + } + r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe], fw_name); + if (r && need_retry && pipe == AMDGPU_MES_SCHED_PIPE) { + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes.bin", + ucode_prefix); + DRM_INFO("try to fall back to %s\n", fw_name); + r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe], + fw_name); + } + if (r) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 4069bce9479f..3ab8a88789c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2341,7 +2341,6 @@ static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) { switch (adev->ip_versions[MP0_HWIP][0]) { case IP_VERSION(13, 0, 2): - case IP_VERSION(13, 0, 10): return true; default: return false; @@ -2430,6 +2429,13 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev) else adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__VCN | 1 << AMDGPU_RAS_BLOCK__JPEG); + + /* + * XGMI RAS is not supported if xgmi num physical nodes + * is zero + */ + if (!adev->gmc.xgmi.num_physical_nodes) + adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__XGMI_WAFL); } else { dev_info(adev->dev, "SRAM ECC is not presented.\n"); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index ef38f4c93df0..17b3d1992e80 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -583,6 +583,10 @@ amdgpu_ras_block_to_ta(enum amdgpu_ras_block block) { return TA_RAS_BLOCK__FUSE; case AMDGPU_RAS_BLOCK__MCA: return TA_RAS_BLOCK__MCA; + case AMDGPU_RAS_BLOCK__VCN: + return TA_RAS_BLOCK__VCN; + case AMDGPU_RAS_BLOCK__JPEG: + return TA_RAS_BLOCK__JPEG; default: WARN_ONCE(1, "RAS ERROR: unexpected block id %d\n", block); return TA_RAS_BLOCK__UMC; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 3106fa8a15ef..c2c2a7718613 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -107,47 +107,12 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev) { - if (adev->asic_type == CHIP_IP_DISCOVERY) { - switch (adev->ip_versions[MP1_HWIP][0]) { - case IP_VERSION(13, 0, 0): - case IP_VERSION(13, 0, 10): - return true; - default: - return false; - } - } - - return adev->asic_type == CHIP_VEGA20 || - adev->asic_type == CHIP_ARCTURUS || - adev->asic_type == CHIP_SIENNA_CICHLID || - adev->asic_type == CHIP_ALDEBARAN; -} - -static bool __get_eeprom_i2c_addr_arct(struct amdgpu_device *adev, - struct amdgpu_ras_eeprom_control *control) -{ - struct atom_context *atom_ctx = adev->mode_info.atom_context; - - if (!control || !atom_ctx) - return false; - - if (strnstr(atom_ctx->vbios_version, - "D342", - sizeof(atom_ctx->vbios_version))) - control->i2c_address = EEPROM_I2C_MADDR_0; - else - control->i2c_address = EEPROM_I2C_MADDR_4; - - return true; -} - -static bool __get_eeprom_i2c_addr_ip_discovery(struct amdgpu_device *adev, - struct amdgpu_ras_eeprom_control *control) -{ switch (adev->ip_versions[MP1_HWIP][0]) { + case IP_VERSION(11, 0, 2): /* VEGA20 and ARCTURUS */ + case IP_VERSION(11, 0, 7): /* Sienna cichlid */ case IP_VERSION(13, 0, 0): + case IP_VERSION(13, 0, 2): /* Aldebaran */ case IP_VERSION(13, 0, 10): - control->i2c_address = EEPROM_I2C_MADDR_4; return true; default: return false; @@ -178,29 +143,32 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, return true; } - switch (adev->asic_type) { - case CHIP_VEGA20: - control->i2c_address = EEPROM_I2C_MADDR_0; + switch (adev->ip_versions[MP1_HWIP][0]) { + case IP_VERSION(11, 0, 2): + /* VEGA20 and ARCTURUS */ + if (adev->asic_type == CHIP_VEGA20) + control->i2c_address = EEPROM_I2C_MADDR_0; + else if (strnstr(atom_ctx->vbios_version, + "D342", + sizeof(atom_ctx->vbios_version))) + control->i2c_address = EEPROM_I2C_MADDR_0; + else + control->i2c_address = EEPROM_I2C_MADDR_4; return true; - - case CHIP_ARCTURUS: - return __get_eeprom_i2c_addr_arct(adev, control); - - case CHIP_SIENNA_CICHLID: + case IP_VERSION(11, 0, 7): control->i2c_address = EEPROM_I2C_MADDR_0; return true; - - case CHIP_ALDEBARAN: + case IP_VERSION(13, 0, 2): if (strnstr(atom_ctx->vbios_version, "D673", sizeof(atom_ctx->vbios_version))) control->i2c_address = EEPROM_I2C_MADDR_4; else control->i2c_address = EEPROM_I2C_MADDR_0; return true; - - case CHIP_IP_DISCOVERY: - return __get_eeprom_i2c_addr_ip_discovery(adev, control); - + case IP_VERSION(13, 0, 0): + case IP_VERSION(13, 0, 10): + control->i2c_address = EEPROM_I2C_MADDR_4; + return true; default: return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 018f36b10de8..d8749444b689 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -165,7 +165,6 @@ struct amdgpu_ring_funcs { bool support_64bit_ptrs; bool no_user_fence; bool secure_submission_supported; - unsigned vmhub; unsigned extra_dw; /* ring read/write ptr handling */ @@ -250,6 +249,7 @@ struct amdgpu_ring { uint64_t ptr_mask; uint32_t buf_mask; u32 idx; + u32 xcc_id; u32 me; u32 pipe; u32 queue; @@ -275,6 +275,7 @@ struct amdgpu_ring { unsigned cond_exe_offs; u64 cond_exe_gpu_addr; volatile u32 *cond_exe_cpu_addr; + unsigned vm_hub; unsigned vm_inv_eng; struct dma_fence *vmid_wait; bool has_compute_vm_bug; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index e9b45089a28a..863b2a34b2d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -38,6 +38,7 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, { struct fd f = fdget(fd); struct amdgpu_fpriv *fpriv; + struct amdgpu_ctx_mgr *mgr; struct amdgpu_ctx *ctx; uint32_t id; int r; @@ -51,8 +52,11 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, return r; } - idr_for_each_entry(&fpriv->ctx_mgr.ctx_handles, ctx, id) + mgr = &fpriv->ctx_mgr; + mutex_lock(&mgr->lock); + idr_for_each_entry(&mgr->ctx_handles, ctx, id) amdgpu_ctx_priority_override(ctx, priority); + mutex_unlock(&mgr->lock); fdput(f); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 98d91ebf5c26..525dffbe046a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -233,7 +233,7 @@ TRACE_EVENT(amdgpu_vm_grab_id, __entry->pasid = vm->pasid; __assign_str(ring, ring->name); __entry->vmid = job->vmid; - __entry->vm_hub = ring->funcs->vmhub, + __entry->vm_hub = ring->vm_hub, __entry->pd_addr = job->vm_pd_addr; __entry->needs_flush = job->vm_needs_flush; ), @@ -427,7 +427,7 @@ TRACE_EVENT(amdgpu_vm_flush, TP_fast_assign( __assign_str(ring, ring->name); __entry->vmid = vmid; - __entry->vm_hub = ring->funcs->vmhub; + __entry->vm_hub = ring->vm_hub; __entry->pd_addr = pd_addr; ), TP_printk("ring=%s, id=%u, hub=%u, pd_addr=%010Lx", diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index 9e2e97207e53..1edf8e6aeb16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -302,3 +302,34 @@ void amdgpu_umc_fill_error_record(struct ras_err_data *err_data, err_data->err_addr_cnt++; } + +int amdgpu_umc_loop_channels(struct amdgpu_device *adev, + umc_func func, void *data) +{ + uint32_t node_inst = 0; + uint32_t umc_inst = 0; + uint32_t ch_inst = 0; + int ret = 0; + + if (adev->umc.node_inst_num) { + LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) { + ret = func(adev, node_inst, umc_inst, ch_inst, data); + if (ret) { + dev_err(adev->dev, "Node %d umc %d ch %d func returns %d\n", + node_inst, umc_inst, ch_inst, ret); + return ret; + } + } + } else { + LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { + ret = func(adev, 0, umc_inst, ch_inst, data); + if (ret) { + dev_err(adev->dev, "Umc %d ch %d func returns %d\n", + umc_inst, ch_inst, ret); + return ret; + } + } + } + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index d7f1229ff11f..86133f77a9a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -47,6 +47,10 @@ #define LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) \ LOOP_UMC_NODE_INST((node_inst)) LOOP_UMC_INST_AND_CH((umc_inst), (ch_inst)) + +typedef int (*umc_func)(struct amdgpu_device *adev, uint32_t node_inst, + uint32_t umc_inst, uint32_t ch_inst, void *data); + struct amdgpu_umc_ras { struct amdgpu_ras_block_object ras_block; void (*err_cnt_init)(struct amdgpu_device *adev); @@ -104,4 +108,7 @@ int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry); int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev, uint64_t err_addr, uint32_t ch_inst, uint32_t umc_inst); + +int amdgpu_umc_loop_channels(struct amdgpu_device *adev, + umc_func func, void *data); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 286e326bb4bd..3c0310576b3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -483,7 +483,7 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring, struct amdgpu_job *job) { struct amdgpu_device *adev = ring->adev; - unsigned vmhub = ring->funcs->vmhub; + unsigned vmhub = ring->vm_hub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; if (job->vmid == 0) @@ -517,7 +517,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_pipe_sync) { struct amdgpu_device *adev = ring->adev; - unsigned vmhub = ring->funcs->vmhub; + unsigned vmhub = ring->vm_hub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; struct amdgpu_vmid *id = &id_mgr->ids[job->vmid]; bool spm_update_needed = job->spm_update_needed; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 516409989235..f5b5ce1051a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -4461,6 +4461,7 @@ static int gfx_v10_0_gfx_ring_init(struct amdgpu_device *adev, int ring_id, ring->doorbell_index = adev->doorbell_index.gfx_ring0 << 1; else ring->doorbell_index = adev->doorbell_index.gfx_ring1 << 1; + ring->vm_hub = AMDGPU_GFXHUB_0; sprintf(ring->name, "gfx_%d.%d.%d", ring->me, ring->pipe, ring->queue); irq_type = AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP + ring->pipe; @@ -4489,6 +4490,7 @@ static int gfx_v10_0_compute_ring_init(struct amdgpu_device *adev, int ring_id, ring->doorbell_index = (adev->doorbell_index.mec_ring0 + ring_id) << 1; ring->eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr + (ring_id * GFX10_MEC_HPD_SIZE); + ring->vm_hub = AMDGPU_GFXHUB_0; sprintf(ring->name, "comp_%d.%d.%d", ring->me, ring->pipe, ring->queue); irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP @@ -9249,7 +9251,6 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_gfx = { .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v10_0_ring_get_rptr_gfx, .get_wptr = gfx_v10_0_ring_get_wptr_gfx, .set_wptr = gfx_v10_0_ring_set_wptr_gfx, @@ -9304,7 +9305,6 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_compute = { .align_mask = 0xff, .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v10_0_ring_get_rptr_compute, .get_wptr = gfx_v10_0_ring_get_wptr_compute, .set_wptr = gfx_v10_0_ring_set_wptr_compute, @@ -9340,7 +9340,6 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_kiq = { .align_mask = 0xff, .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v10_0_ring_get_rptr_compute, .get_wptr = gfx_v10_0_ring_get_wptr_compute, .set_wptr = gfx_v10_0_ring_set_wptr_compute, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index ecf8ceb53311..f5c376276984 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -866,6 +866,7 @@ static int gfx_v11_0_gfx_ring_init(struct amdgpu_device *adev, int ring_id, ring->doorbell_index = adev->doorbell_index.gfx_ring0 << 1; else ring->doorbell_index = adev->doorbell_index.gfx_ring1 << 1; + ring->vm_hub = AMDGPU_GFXHUB_0; sprintf(ring->name, "gfx_%d.%d.%d", ring->me, ring->pipe, ring->queue); irq_type = AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP + ring->pipe; @@ -896,6 +897,7 @@ static int gfx_v11_0_compute_ring_init(struct amdgpu_device *adev, int ring_id, ring->doorbell_index = (adev->doorbell_index.mec_ring0 + ring_id) << 1; ring->eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr + (ring_id * GFX11_MEC_HPD_SIZE); + ring->vm_hub = AMDGPU_GFXHUB_0; sprintf(ring->name, "comp_%d.%d.%d", ring->me, ring->pipe, ring->queue); irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP @@ -1313,13 +1315,6 @@ static int gfx_v11_0_sw_init(void *handle) if (r) return r; - /* ECC error */ - r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, - GFX_11_0_0__SRCID__CP_ECC_ERROR, - &adev->gfx.cp_ecc_error_irq); - if (r) - return r; - /* FED error */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX, GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT, @@ -4442,7 +4437,6 @@ static int gfx_v11_0_hw_fini(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -4671,11 +4665,24 @@ static int gfx_v11_0_post_soft_reset(void *handle) static uint64_t gfx_v11_0_get_gpu_clock_counter(struct amdgpu_device *adev) { uint64_t clock; + uint64_t clock_counter_lo, clock_counter_hi_pre, clock_counter_hi_after; amdgpu_gfx_off_ctrl(adev, false); mutex_lock(&adev->gfx.gpu_clock_mutex); - clock = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_LOWER) | - ((uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_UPPER) << 32ULL); + if (amdgpu_sriov_vf(adev)) { + clock_counter_hi_pre = (uint64_t)RREG32_SOC15(GC, 0, regCP_MES_MTIME_HI); + clock_counter_lo = (uint64_t)RREG32_SOC15(GC, 0, regCP_MES_MTIME_LO); + clock_counter_hi_after = (uint64_t)RREG32_SOC15(GC, 0, regCP_MES_MTIME_HI); + if (clock_counter_hi_pre != clock_counter_hi_after) + clock_counter_lo = (uint64_t)RREG32_SOC15(GC, 0, regCP_MES_MTIME_LO); + } else { + clock_counter_hi_pre = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_UPPER); + clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_LOWER); + clock_counter_hi_after = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_UPPER); + if (clock_counter_hi_pre != clock_counter_hi_after) + clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_LOWER); + } + clock = clock_counter_lo | (clock_counter_hi_after << 32ULL); mutex_unlock(&adev->gfx.gpu_clock_mutex); amdgpu_gfx_off_ctrl(adev, true); return clock; @@ -5882,36 +5889,6 @@ static void gfx_v11_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev } } -#define CP_ME1_PIPE_INST_ADDR_INTERVAL 0x1 -#define SET_ECC_ME_PIPE_STATE(reg_addr, state) \ - do { \ - uint32_t tmp = RREG32_SOC15_IP(GC, reg_addr); \ - tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, state); \ - WREG32_SOC15_IP(GC, reg_addr, tmp); \ - } while (0) - -static int gfx_v11_0_set_cp_ecc_error_state(struct amdgpu_device *adev, - struct amdgpu_irq_src *source, - unsigned type, - enum amdgpu_interrupt_state state) -{ - uint32_t ecc_irq_state = 0; - uint32_t pipe0_int_cntl_addr = 0; - int i = 0; - - ecc_irq_state = (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0; - - pipe0_int_cntl_addr = SOC15_REG_OFFSET(GC, 0, regCP_ME1_PIPE0_INT_CNTL); - - WREG32_FIELD15_PREREG(GC, 0, CP_INT_CNTL_RING0, CP_ECC_ERROR_INT_ENABLE, ecc_irq_state); - - for (i = 0; i < adev->gfx.mec.num_pipe_per_mec; i++) - SET_ECC_ME_PIPE_STATE(pipe0_int_cntl_addr + i * CP_ME1_PIPE_INST_ADDR_INTERVAL, - ecc_irq_state); - - return 0; -} - static int gfx_v11_0_set_eop_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type, @@ -6191,7 +6168,6 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = { .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v11_0_ring_get_rptr_gfx, .get_wptr = gfx_v11_0_ring_get_wptr_gfx, .set_wptr = gfx_v11_0_ring_set_wptr_gfx, @@ -6239,7 +6215,6 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_compute = { .align_mask = 0xff, .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v11_0_ring_get_rptr_compute, .get_wptr = gfx_v11_0_ring_get_wptr_compute, .set_wptr = gfx_v11_0_ring_set_wptr_compute, @@ -6275,7 +6250,6 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_kiq = { .align_mask = 0xff, .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v11_0_ring_get_rptr_compute, .get_wptr = gfx_v11_0_ring_get_wptr_compute, .set_wptr = gfx_v11_0_ring_set_wptr_compute, @@ -6329,11 +6303,6 @@ static const struct amdgpu_irq_src_funcs gfx_v11_0_priv_inst_irq_funcs = { .process = gfx_v11_0_priv_inst_irq, }; -static const struct amdgpu_irq_src_funcs gfx_v11_0_cp_ecc_error_irq_funcs = { - .set = gfx_v11_0_set_cp_ecc_error_state, - .process = amdgpu_gfx_cp_ecc_error_irq, -}; - static const struct amdgpu_irq_src_funcs gfx_v11_0_rlc_gc_fed_irq_funcs = { .process = gfx_v11_0_rlc_gc_fed_irq, }; @@ -6349,9 +6318,6 @@ static void gfx_v11_0_set_irq_funcs(struct amdgpu_device *adev) adev->gfx.priv_inst_irq.num_types = 1; adev->gfx.priv_inst_irq.funcs = &gfx_v11_0_priv_inst_irq_funcs; - adev->gfx.cp_ecc_error_irq.num_types = 1; /* CP ECC error */ - adev->gfx.cp_ecc_error_irq.funcs = &gfx_v11_0_cp_ecc_error_irq_funcs; - adev->gfx.rlc_gc_fed_irq.num_types = 1; /* 0x80 FED error */ adev->gfx.rlc_gc_fed_irq.funcs = &gfx_v11_0_rlc_gc_fed_irq_funcs; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c index b07a72ca25d9..068b9586a223 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c @@ -62,10 +62,18 @@ static int gfx_v11_0_3_rlc_gc_fed_irq(struct amdgpu_device *adev, return -EINVAL; } - ih_data.head = *ras_if; - dev_warn(adev->dev, "RLC %s FED IRQ\n", ras_if->name); - amdgpu_ras_interrupt_dispatch(adev, &ih_data); + + if (!amdgpu_sriov_vf(adev)) { + ih_data.head = *ras_if; + amdgpu_ras_interrupt_dispatch(adev, &ih_data); + } else { + if (adev->virt.ops && adev->virt.ops->ras_poison_handler) + adev->virt.ops->ras_poison_handler(adev); + else + dev_warn(adev->dev, + "No ras_poison_handler interface in SRIOV for %s!\n", ras_if->name); + } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index ae09fc1cfe6b..f46d4b18a3fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -149,6 +149,16 @@ MODULE_FIRMWARE("amdgpu/aldebaran_sjt_mec2.bin"); #define mmGOLDEN_TSC_COUNT_LOWER_Renoir 0x0026 #define mmGOLDEN_TSC_COUNT_LOWER_Renoir_BASE_IDX 1 +#define mmGOLDEN_TSC_COUNT_UPPER_Raven 0x007a +#define mmGOLDEN_TSC_COUNT_UPPER_Raven_BASE_IDX 0 +#define mmGOLDEN_TSC_COUNT_LOWER_Raven 0x007b +#define mmGOLDEN_TSC_COUNT_LOWER_Raven_BASE_IDX 0 + +#define mmGOLDEN_TSC_COUNT_UPPER_Raven2 0x0068 +#define mmGOLDEN_TSC_COUNT_UPPER_Raven2_BASE_IDX 0 +#define mmGOLDEN_TSC_COUNT_LOWER_Raven2 0x0069 +#define mmGOLDEN_TSC_COUNT_LOWER_Raven2_BASE_IDX 0 + enum ta_ras_gfx_subblock { /*CPC*/ TA_RAS_BLOCK__GFX_CPC_INDEX_START = 0, @@ -1995,6 +2005,7 @@ static int gfx_v9_0_compute_ring_init(struct amdgpu_device *adev, int ring_id, ring->doorbell_index = (adev->doorbell_index.mec_ring0 + ring_id) << 1; ring->eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr + (ring_id * GFX9_MEC_HPD_SIZE); + ring->vm_hub = AMDGPU_GFXHUB_0; sprintf(ring->name, "comp_%d.%d.%d", ring->me, ring->pipe, ring->queue); irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP @@ -2094,6 +2105,7 @@ static int gfx_v9_0_sw_init(void *handle) /* disable scheduler on the real ring */ ring->no_scheduler = true; + ring->vm_hub = AMDGPU_GFXHUB_0; r = amdgpu_ring_init(adev, ring, 1024, &adev->gfx.eop_irq, AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP, AMDGPU_RING_PRIO_DEFAULT, NULL); @@ -2111,6 +2123,7 @@ static int gfx_v9_0_sw_init(void *handle) ring->doorbell_index = adev->doorbell_index.gfx_ring0 << 1; ring->is_sw_ring = true; hw_prio = amdgpu_sw_ring_priority(i); + ring->vm_hub = AMDGPU_GFXHUB_0; r = amdgpu_ring_init(adev, ring, 1024, &adev->gfx.eop_irq, AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP, hw_prio, NULL); @@ -3751,7 +3764,8 @@ static int gfx_v9_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX)) + amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -3988,6 +4002,36 @@ static uint64_t gfx_v9_0_get_gpu_clock_counter(struct amdgpu_device *adev) preempt_enable(); clock = clock_lo | (clock_hi << 32ULL); break; + case IP_VERSION(9, 1, 0): + preempt_disable(); + clock_hi = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven); + clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven); + hi_check = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven); + /* The PWR TSC clock frequency is 100MHz, which sets 32-bit carry over + * roughly every 42 seconds. + */ + if (hi_check != clock_hi) { + clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven); + clock_hi = hi_check; + } + preempt_enable(); + clock = clock_lo | (clock_hi << 32ULL); + break; + case IP_VERSION(9, 2, 2): + preempt_disable(); + clock_hi = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven2); + clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven2); + hi_check = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven2); + /* The PWR TSC clock frequency is 100MHz, which sets 32-bit carry over + * roughly every 42 seconds. + */ + if (hi_check != clock_hi) { + clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven2); + clock_hi = hi_check; + } + preempt_enable(); + clock = clock_lo | (clock_hi << 32ULL); + break; default: amdgpu_gfx_off_ctrl(adev, false); mutex_lock(&adev->gfx.gpu_clock_mutex); @@ -6750,7 +6794,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_gfx = { .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v9_0_ring_get_rptr_gfx, .get_wptr = gfx_v9_0_ring_get_wptr_gfx, .set_wptr = gfx_v9_0_ring_set_wptr_gfx, @@ -6804,7 +6847,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_sw_ring_funcs_gfx = { .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = amdgpu_sw_ring_get_rptr_gfx, .get_wptr = amdgpu_sw_ring_get_wptr_gfx, .set_wptr = amdgpu_sw_ring_set_wptr_gfx, @@ -6858,7 +6900,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_compute = { .align_mask = 0xff, .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v9_0_ring_get_rptr_compute, .get_wptr = gfx_v9_0_ring_get_wptr_compute, .set_wptr = gfx_v9_0_ring_set_wptr_compute, @@ -6897,7 +6938,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = { .align_mask = 0xff, .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v9_0_ring_get_rptr_compute, .get_wptr = gfx_v9_0_ring_get_wptr_compute, .set_wptr = gfx_v9_0_ring_set_wptr_compute, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c new file mode 100644 index 000000000000..5f8500577c02 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -0,0 +1,430 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include <linux/firmware.h> + +#include "amdgpu.h" +#include "amdgpu_gfx.h" +#include "soc15.h" +#include "soc15_common.h" +#include "vega10_enum.h" + +#include "gc/gc_9_4_3_offset.h" +#include "gc/gc_9_4_3_sh_mask.h" + +#include "gfx_v9_4_3.h" + +#define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L + +static uint64_t gfx_v9_4_3_get_gpu_clock_counter(struct amdgpu_device *adev) +{ + uint64_t clock; + + amdgpu_gfx_off_ctrl(adev, false); + mutex_lock(&adev->gfx.gpu_clock_mutex); + WREG32_SOC15(GC, 0, regRLC_CAPTURE_GPU_CLOCK_COUNT, 1); + clock = (uint64_t)RREG32_SOC15(GC, 0, regRLC_GPU_CLOCK_COUNT_LSB) | + ((uint64_t)RREG32_SOC15(GC, 0, regRLC_GPU_CLOCK_COUNT_MSB) << 32ULL); + mutex_unlock(&adev->gfx.gpu_clock_mutex); + amdgpu_gfx_off_ctrl(adev, true); + + return clock; +} + +static void gfx_v9_4_3_select_se_sh(struct amdgpu_device *adev, + u32 se_num, + u32 sh_num, + u32 instance) +{ + u32 data; + + if (instance == 0xffffffff) + data = REG_SET_FIELD(0, GRBM_GFX_INDEX, + INSTANCE_BROADCAST_WRITES, 1); + else + data = REG_SET_FIELD(0, GRBM_GFX_INDEX, + INSTANCE_INDEX, instance); + + if (se_num == 0xffffffff) + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, + SE_BROADCAST_WRITES, 1); + else + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_INDEX, se_num); + + if (sh_num == 0xffffffff) + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, + SH_BROADCAST_WRITES, 1); + else + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_INDEX, sh_num); + + WREG32_SOC15_RLC_SHADOW_EX(reg, GC, 0, regGRBM_GFX_INDEX, data); +} + +static uint32_t wave_read_ind(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t address) +{ + WREG32_SOC15_RLC(GC, 0, regSQ_IND_INDEX, + (wave << SQ_IND_INDEX__WAVE_ID__SHIFT) | + (simd << SQ_IND_INDEX__SIMD_ID__SHIFT) | + (address << SQ_IND_INDEX__INDEX__SHIFT) | + (SQ_IND_INDEX__FORCE_READ_MASK)); + return RREG32_SOC15(GC, 0, regSQ_IND_DATA); +} + +static void wave_read_regs(struct amdgpu_device *adev, uint32_t simd, + uint32_t wave, uint32_t thread, + uint32_t regno, uint32_t num, uint32_t *out) +{ + WREG32_SOC15_RLC(GC, 0, regSQ_IND_INDEX, + (wave << SQ_IND_INDEX__WAVE_ID__SHIFT) | + (simd << SQ_IND_INDEX__SIMD_ID__SHIFT) | + (regno << SQ_IND_INDEX__INDEX__SHIFT) | + (thread << SQ_IND_INDEX__THREAD_ID__SHIFT) | + (SQ_IND_INDEX__FORCE_READ_MASK) | + (SQ_IND_INDEX__AUTO_INCR_MASK)); + while (num--) + *(out++) = RREG32_SOC15(GC, 0, regSQ_IND_DATA); +} + +static void gfx_v9_4_3_read_wave_data(struct amdgpu_device *adev, + uint32_t simd, uint32_t wave, + uint32_t *dst, int *no_fields) +{ + /* type 1 wave data */ + dst[(*no_fields)++] = 1; + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_STATUS); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_PC_LO); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_PC_HI); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_EXEC_LO); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_EXEC_HI); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_HW_ID); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_INST_DW0); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_INST_DW1); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_GPR_ALLOC); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_LDS_ALLOC); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_TRAPSTS); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_IB_STS); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_IB_DBG0); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0); + dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_MODE); +} + +static void gfx_v9_4_3_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd, + uint32_t wave, uint32_t start, + uint32_t size, uint32_t *dst) +{ + wave_read_regs(adev, simd, wave, 0, + start + SQIND_WAVE_SGPRS_OFFSET, size, dst); +} + +static void gfx_v9_4_3_read_wave_vgprs(struct amdgpu_device *adev, uint32_t simd, + uint32_t wave, uint32_t thread, + uint32_t start, uint32_t size, + uint32_t *dst) +{ + wave_read_regs(adev, simd, wave, thread, + start + SQIND_WAVE_VGPRS_OFFSET, size, dst); +} + +static void gfx_v9_4_3_select_me_pipe_q(struct amdgpu_device *adev, + u32 me, u32 pipe, u32 q, u32 vm) +{ + soc15_grbm_select(adev, me, pipe, q, vm); +} + +static bool gfx_v9_4_3_is_rlc_enabled(struct amdgpu_device *adev) +{ + uint32_t rlc_setting; + + /* if RLC is not enabled, do nothing */ + rlc_setting = RREG32_SOC15(GC, 0, regRLC_CNTL); + if (!(rlc_setting & RLC_CNTL__RLC_ENABLE_F32_MASK)) + return false; + + return true; +} + +static void gfx_v9_4_3_set_safe_mode(struct amdgpu_device *adev) +{ + uint32_t data; + unsigned i; + + data = RLC_SAFE_MODE__CMD_MASK; + data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT); + WREG32_SOC15(GC, 0, regRLC_SAFE_MODE, data); + + /* wait for RLC_SAFE_MODE */ + for (i = 0; i < adev->usec_timeout; i++) { + if (!REG_GET_FIELD(RREG32_SOC15(GC, 0, regRLC_SAFE_MODE), RLC_SAFE_MODE, CMD)) + break; + udelay(1); + } +} + +static void gfx_v9_4_3_unset_safe_mode(struct amdgpu_device *adev) +{ + uint32_t data; + + data = RLC_SAFE_MODE__CMD_MASK; + WREG32_SOC15(GC, 0, regRLC_SAFE_MODE, data); +} + +static int gfx_v9_4_3_rlc_init(struct amdgpu_device *adev) +{ + /* init spm vmid with 0xf */ + if (adev->gfx.rlc.funcs->update_spm_vmid) + adev->gfx.rlc.funcs->update_spm_vmid(adev, 0xf); + + return 0; +} + +static void gfx_v9_4_3_wait_for_rlc_serdes(struct amdgpu_device *adev) +{ + u32 i, j, k; + u32 mask; + + mutex_lock(&adev->grbm_idx_mutex); + for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { + for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { + gfx_v9_4_3_select_se_sh(adev, i, j, 0xffffffff); + for (k = 0; k < adev->usec_timeout; k++) { + if (RREG32_SOC15(GC, 0, regRLC_SERDES_CU_MASTER_BUSY) == 0) + break; + udelay(1); + } + if (k == adev->usec_timeout) { + gfx_v9_4_3_select_se_sh(adev, 0xffffffff, + 0xffffffff, 0xffffffff); + mutex_unlock(&adev->grbm_idx_mutex); + DRM_INFO("Timeout wait for RLC serdes %u,%u\n", + i, j); + return; + } + } + } + gfx_v9_4_3_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); + mutex_unlock(&adev->grbm_idx_mutex); + + mask = RLC_SERDES_NONCU_MASTER_BUSY__SE_MASTER_BUSY_MASK | + RLC_SERDES_NONCU_MASTER_BUSY__GC_MASTER_BUSY_MASK | + RLC_SERDES_NONCU_MASTER_BUSY__TC0_MASTER_BUSY_MASK | + RLC_SERDES_NONCU_MASTER_BUSY__TC1_MASTER_BUSY_MASK; + for (k = 0; k < adev->usec_timeout; k++) { + if ((RREG32_SOC15(GC, 0, regRLC_SERDES_NONCU_MASTER_BUSY) & mask) == 0) + break; + udelay(1); + } +} + +static void gfx_v9_4_3_enable_gui_idle_interrupt(struct amdgpu_device *adev, + bool enable) +{ + u32 tmp; + + /* These interrupts should be enabled to drive DS clock */ + + tmp = RREG32_SOC15(GC, 0, regCP_INT_CNTL_RING0); + + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE, enable ? 1 : 0); + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_EMPTY_INT_ENABLE, enable ? 1 : 0); + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CMP_BUSY_INT_ENABLE, enable ? 1 : 0); + if (adev->gfx.num_gfx_rings) + tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, GFX_IDLE_INT_ENABLE, enable ? 1 : 0); + + WREG32_SOC15(GC, 0, regCP_INT_CNTL_RING0, tmp); +} + +static void gfx_v9_4_3_rlc_stop(struct amdgpu_device *adev) +{ + WREG32_FIELD15_PREREG(GC, 0, RLC_CNTL, RLC_ENABLE_F32, 0); + gfx_v9_4_3_enable_gui_idle_interrupt(adev, false); + gfx_v9_4_3_wait_for_rlc_serdes(adev); +} + +static void gfx_v9_4_3_rlc_reset(struct amdgpu_device *adev) +{ + WREG32_FIELD15_PREREG(GC, 0, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1); + udelay(50); + WREG32_FIELD15_PREREG(GC, 0, GRBM_SOFT_RESET, SOFT_RESET_RLC, 0); + udelay(50); +} + +static void gfx_v9_4_3_rlc_start(struct amdgpu_device *adev) +{ +#ifdef AMDGPU_RLC_DEBUG_RETRY + u32 rlc_ucode_ver; +#endif + + WREG32_FIELD15_PREREG(GC, 0, RLC_CNTL, RLC_ENABLE_F32, 1); + udelay(50); + + /* carrizo do enable cp interrupt after cp inited */ + if (!(adev->flags & AMD_IS_APU)) { + gfx_v9_4_3_enable_gui_idle_interrupt(adev, true); + udelay(50); + } + +#ifdef AMDGPU_RLC_DEBUG_RETRY + /* RLC_GPM_GENERAL_6 : RLC Ucode version */ + rlc_ucode_ver = RREG32_SOC15(GC, 0, regRLC_GPM_GENERAL_6); + if (rlc_ucode_ver == 0x108) { + dev_info(adev->dev, + "Using rlc debug ucode. regRLC_GPM_GENERAL_6 ==0x08%x / fw_ver == %i \n", + rlc_ucode_ver, adev->gfx.rlc_fw_version); + /* RLC_GPM_TIMER_INT_3 : Timer interval in RefCLK cycles, + * default is 0x9C4 to create a 100us interval */ + WREG32_SOC15(GC, 0, regRLC_GPM_TIMER_INT_3, 0x9C4); + /* RLC_GPM_GENERAL_12 : Minimum gap between wptr and rptr + * to disable the page fault retry interrupts, default is + * 0x100 (256) */ + WREG32_SOC15(GC, 0, regRLC_GPM_GENERAL_12, 0x100); + } +#endif +} + +static int gfx_v9_4_3_rlc_load_microcode(struct amdgpu_device *adev) +{ + const struct rlc_firmware_header_v2_0 *hdr; + const __le32 *fw_data; + unsigned i, fw_size; + + if (!adev->gfx.rlc_fw) + return -EINVAL; + + hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; + amdgpu_ucode_print_rlc_hdr(&hdr->header); + + fw_data = (const __le32 *)(adev->gfx.rlc_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; + + WREG32_SOC15(GC, 0, regRLC_GPM_UCODE_ADDR, + RLCG_UCODE_LOADING_START_ADDRESS); + for (i = 0; i < fw_size; i++) { + if (amdgpu_emu_mode == 1 && i % 100 == 0) { + dev_info(adev->dev, "Write RLC ucode data %u DWs\n", i); + msleep(1); + } + WREG32_SOC15(GC, 0, regRLC_GPM_UCODE_DATA, le32_to_cpup(fw_data++)); + } + WREG32_SOC15(GC, 0, regRLC_GPM_UCODE_ADDR, adev->gfx.rlc_fw_version); + + return 0; +} + +static int gfx_v9_4_3_rlc_resume(struct amdgpu_device *adev) +{ + int r; + + adev->gfx.rlc.funcs->stop(adev); + + /* disable CG */ + WREG32_SOC15(GC, 0, regRLC_CGCG_CGLS_CTRL, 0); + + /* TODO: revisit pg function */ + /* gfx_v9_4_3_init_pg(adev);*/ + + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { + /* legacy rlc firmware loading */ + r = gfx_v9_4_3_rlc_load_microcode(adev); + if (r) + return r; + } + + adev->gfx.rlc.funcs->start(adev); + + return 0; +} + +static void gfx_v9_4_3_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) +{ + u32 reg, data; + + reg = SOC15_REG_OFFSET(GC, 0, regRLC_SPM_MC_CNTL); + if (amdgpu_sriov_is_pp_one_vf(adev)) + data = RREG32_NO_KIQ(reg); + else + data = RREG32(reg); + + data &= ~RLC_SPM_MC_CNTL__RLC_SPM_VMID_MASK; + data |= (vmid & RLC_SPM_MC_CNTL__RLC_SPM_VMID_MASK) << RLC_SPM_MC_CNTL__RLC_SPM_VMID__SHIFT; + + if (amdgpu_sriov_is_pp_one_vf(adev)) + WREG32_SOC15_NO_KIQ(GC, 0, regRLC_SPM_MC_CNTL, data); + else + WREG32_SOC15(GC, 0, regRLC_SPM_MC_CNTL, data); +} + +static const struct soc15_reg_rlcg rlcg_access_gc_9_4_3[] = { + {SOC15_REG_ENTRY(GC, 0, regGRBM_GFX_INDEX)}, + {SOC15_REG_ENTRY(GC, 0, regSQ_IND_INDEX)}, +}; + +static bool gfx_v9_4_3_check_rlcg_range(struct amdgpu_device *adev, + uint32_t offset, + struct soc15_reg_rlcg *entries, int arr_size) +{ + int i; + uint32_t reg; + + if (!entries) + return false; + + for (i = 0; i < arr_size; i++) { + const struct soc15_reg_rlcg *entry; + + entry = &entries[i]; + reg = adev->reg_offset[entry->hwip][entry->instance][entry->segment] + entry->reg; + if (offset == reg) + return true; + } + + return false; +} + +static bool gfx_v9_4_3_is_rlcg_access_range(struct amdgpu_device *adev, u32 offset) +{ + return gfx_v9_4_3_check_rlcg_range(adev, offset, + (void *)rlcg_access_gc_9_4_3, + ARRAY_SIZE(rlcg_access_gc_9_4_3)); +} + +const struct amdgpu_gfx_funcs gfx_v9_4_3_gfx_funcs = { + .get_gpu_clock_counter = &gfx_v9_4_3_get_gpu_clock_counter, + .select_se_sh = &gfx_v9_4_3_select_se_sh, + .read_wave_data = &gfx_v9_4_3_read_wave_data, + .read_wave_sgprs = &gfx_v9_4_3_read_wave_sgprs, + .read_wave_vgprs = &gfx_v9_4_3_read_wave_vgprs, + .select_me_pipe_q = &gfx_v9_4_3_select_me_pipe_q, +}; + +const struct amdgpu_rlc_funcs gfx_v9_4_3_rlc_funcs = { + .is_rlc_enabled = gfx_v9_4_3_is_rlc_enabled, + .set_safe_mode = gfx_v9_4_3_set_safe_mode, + .unset_safe_mode = gfx_v9_4_3_unset_safe_mode, + .init = gfx_v9_4_3_rlc_init, + .resume = gfx_v9_4_3_rlc_resume, + .stop = gfx_v9_4_3_rlc_stop, + .reset = gfx_v9_4_3_rlc_reset, + .start = gfx_v9_4_3_rlc_start, + .update_spm_vmid = gfx_v9_4_3_update_spm_vmid, + .is_rlcg_access_range = gfx_v9_4_3_is_rlcg_access_range, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.h b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.h new file mode 100644 index 000000000000..84e69701b81a --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.h @@ -0,0 +1,30 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __GFX_V9_4_3_H__ +#define __GFX_V9_4_3_H__ + +extern const struct amdgpu_gfx_funcs gfx_v9_4_3_gfx_funcs; +extern const struct amdgpu_rlc_funcs gfx_v9_4_3_rlc_funcs; + +#endif /* __GFX_V9_4_3_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c index be0d0f47415e..13712640fa46 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c @@ -417,34 +417,12 @@ static void gfxhub_v3_0_set_fault_enable_default(struct amdgpu_device *adev, tmp = REG_SET_FIELD(tmp, CP_DEBUG, CPG_UTCL1_ERROR_HALT_DISABLE, 1); WREG32_SOC15(GC, 0, regCP_DEBUG, tmp); - /** - * Set GRBM_GFX_INDEX in broad cast mode - * before programming GL1C_UTCL0_CNTL1 and SQG_CONFIG - */ - WREG32_SOC15(GC, 0, regGRBM_GFX_INDEX, regGRBM_GFX_INDEX_DEFAULT); - - /** - * Retry respond mode: RETRY - * Error (no retry) respond mode: SUCCESS - */ - tmp = RREG32_SOC15(GC, 0, regGL1C_UTCL0_CNTL1); - tmp = REG_SET_FIELD(tmp, GL1C_UTCL0_CNTL1, RESP_MODE, 0); - tmp = REG_SET_FIELD(tmp, GL1C_UTCL0_CNTL1, RESP_FAULT_MODE, 0x2); - WREG32_SOC15(GC, 0, regGL1C_UTCL0_CNTL1, tmp); - /* These registers are not accessible to VF-SRIOV. * The PF will program them instead. */ if (amdgpu_sriov_vf(adev)) return; - /* Disable SQ XNACK interrupt for all VMIDs */ - tmp = RREG32_SOC15(GC, 0, regSQG_CONFIG); - tmp = REG_SET_FIELD(tmp, SQG_CONFIG, XNACK_INTR_MASK, - SQG_CONFIG__XNACK_INTR_MASK_MASK >> - SQG_CONFIG__XNACK_INTR_MASK__SHIFT); - WREG32_SOC15(GC, 0, regSQG_CONFIG, tmp); - tmp = RREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL); tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL, RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, value); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index d99821692ba3..b213dcf8ca06 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -479,8 +479,8 @@ static int gmc_v10_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, static uint64_t gmc_v10_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - bool use_semaphore = gmc_v10_0_use_invalidate_semaphore(ring->adev, ring->funcs->vmhub); - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + bool use_semaphore = gmc_v10_0_use_invalidate_semaphore(ring->adev, ring->vm_hub); + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; uint32_t req = hub->vmhub_funcs->get_invalidate_req(vmid, 0); unsigned eng = ring->vm_inv_eng; @@ -534,7 +534,7 @@ static void gmc_v10_0_emit_pasid_mapping(struct amdgpu_ring *ring, unsigned vmid if (ring->is_mes_queue) return; - if (ring->funcs->vmhub == AMDGPU_GFXHUB_0) + if (ring->vm_hub == AMDGPU_GFXHUB_0) reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_VMID_0_LUT) + vmid; else reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_VMID_0_LUT_MM) + vmid; @@ -1143,7 +1143,6 @@ static int gmc_v10_0_hw_fini(void *handle) return 0; } - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index 9f4f28192c60..d95f9fe8f1c5 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -378,8 +378,8 @@ static int gmc_v11_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, static uint64_t gmc_v11_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - bool use_semaphore = gmc_v11_0_use_invalidate_semaphore(ring->adev, ring->funcs->vmhub); - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + bool use_semaphore = gmc_v11_0_use_invalidate_semaphore(ring->adev, ring->vm_hub); + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; uint32_t req = hub->vmhub_funcs->get_invalidate_req(vmid, 0); unsigned eng = ring->vm_inv_eng; @@ -433,7 +433,7 @@ static void gmc_v11_0_emit_pasid_mapping(struct amdgpu_ring *ring, unsigned vmid if (ring->is_mes_queue) return; - if (ring->funcs->vmhub == AMDGPU_GFXHUB_0) + if (ring->vm_hub == AMDGPU_GFXHUB_0) reg = SOC15_REG_OFFSET(OSSSYS, 0, regIH_VMID_0_LUT) + vmid; else reg = SOC15_REG_OFFSET(OSSSYS, 0, regIH_VMID_0_LUT_MM) + vmid; @@ -951,7 +951,6 @@ static int gmc_v11_0_hw_fini(void *handle) return 0; } - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v11_0_gart_disable(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 67ad92097a65..2fe21cefd772 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -555,32 +555,49 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, const char *mmhub_cid; const char *hub_name; u64 addr; + uint32_t cam_index = 0; + int ret; addr = (u64)entry->src_data[0] << 12; addr |= ((u64)entry->src_data[1] & 0xf) << 44; if (retry_fault) { - /* Returning 1 here also prevents sending the IV to the KFD */ + if (adev->irq.retry_cam_enabled) { + /* Delegate it to a different ring if the hardware hasn't + * already done it. + */ + if (entry->ih == &adev->irq.ih) { + amdgpu_irq_delegate(adev, entry, 8); + return 1; + } + + cam_index = entry->src_data[2] & 0x3ff; - /* Process it onyl if it's the first fault for this address */ - if (entry->ih != &adev->irq.ih_soft && - amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid, + ret = amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault); + WDOORBELL32(adev->irq.retry_cam_doorbell_index, cam_index); + if (ret) + return 1; + } else { + /* Process it onyl if it's the first fault for this address */ + if (entry->ih != &adev->irq.ih_soft && + amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid, entry->timestamp)) - return 1; + return 1; - /* Delegate it to a different ring if the hardware hasn't - * already done it. - */ - if (entry->ih == &adev->irq.ih) { - amdgpu_irq_delegate(adev, entry, 8); - return 1; - } + /* Delegate it to a different ring if the hardware hasn't + * already done it. + */ + if (entry->ih == &adev->irq.ih) { + amdgpu_irq_delegate(adev, entry, 8); + return 1; + } - /* Try to handle the recoverable page faults by filling page - * tables - */ - if (amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault)) - return 1; + /* Try to handle the recoverable page faults by filling page + * tables + */ + if (amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault)) + return 1; + } } if (!printk_ratelimit()) @@ -990,9 +1007,9 @@ static int gmc_v9_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - bool use_semaphore = gmc_v9_0_use_invalidate_semaphore(ring->adev, ring->funcs->vmhub); + bool use_semaphore = gmc_v9_0_use_invalidate_semaphore(ring->adev, ring->vm_hub); struct amdgpu_device *adev = ring->adev; - struct amdgpu_vmhub *hub = &adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &adev->vmhub[ring->vm_hub]; uint32_t req = gmc_v9_0_get_invalidate_req(vmid, 0); unsigned eng = ring->vm_inv_eng; @@ -1043,10 +1060,10 @@ static void gmc_v9_0_emit_pasid_mapping(struct amdgpu_ring *ring, unsigned vmid, uint32_t reg; /* Do nothing because there's no lut register for mmhub1. */ - if (ring->funcs->vmhub == AMDGPU_MMHUB_1) + if (ring->vm_hub == AMDGPU_MMHUB_1) return; - if (ring->funcs->vmhub == AMDGPU_GFXHUB_0) + if (ring->vm_hub == AMDGPU_GFXHUB_0) reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_VMID_0_LUT) + vmid; else reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_VMID_0_LUT_MM) + vmid; @@ -1982,7 +1999,6 @@ static int gmc_v9_0_hw_fini(void *handle) if (adev->mmhub.funcs->update_power_gating) adev->mmhub.funcs->update_power_gating(adev, false); - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c index 9360204da7fb..a3076eb8af6a 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c @@ -376,7 +376,7 @@ static void jpeg_v1_0_decode_ring_emit_reg_wait(struct amdgpu_ring *ring, static void jpeg_v1_0_decode_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; uint32_t data0, data1, mask; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -485,6 +485,7 @@ int jpeg_v1_0_sw_init(void *handle) return r; ring = &adev->jpeg.inst->ring_dec; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "jpeg_dec"); r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0, AMDGPU_RING_PRIO_DEFAULT, NULL); @@ -548,7 +549,6 @@ static const struct amdgpu_ring_funcs jpeg_v1_0_decode_ring_vm_funcs = { .nop = PACKET0(0x81ff, 0), .support_64bit_ptrs = false, .no_user_fence = true, - .vmhub = AMDGPU_MMHUB_0, .extra_dw = 64, .get_rptr = jpeg_v1_0_decode_ring_get_rptr, .get_wptr = jpeg_v1_0_decode_ring_get_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c index f3c1af5130ab..0eddf7c824a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c @@ -86,6 +86,7 @@ static int jpeg_v2_0_sw_init(void *handle) ring = &adev->jpeg.inst->ring_dec; ring->use_doorbell = true; ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "jpeg_dec"); r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0, AMDGPU_RING_PRIO_DEFAULT, NULL); @@ -613,7 +614,7 @@ void jpeg_v2_0_dec_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, void jpeg_v2_0_dec_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; uint32_t data0, data1, mask; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -762,7 +763,6 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = jpeg_v2_0_dec_ring_get_rptr, .get_wptr = jpeg_v2_0_dec_ring_get_wptr, .set_wptr = jpeg_v2_0_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c index 6b1887808782..b040f51d9aa9 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c @@ -127,6 +127,10 @@ static int jpeg_v2_5_sw_init(void *handle) ring = &adev->jpeg.inst[i].ring_dec; ring->use_doorbell = true; + if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(2, 5, 0)) + ring->vm_hub = AMDGPU_MMHUB_1; + else + ring->vm_hub = AMDGPU_MMHUB_0; ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1 + 8 * i; sprintf(ring->name, "jpeg_dec_%d", i); r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst[i].irq, @@ -645,7 +649,6 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, - .vmhub = AMDGPU_MMHUB_1, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr, @@ -675,7 +678,6 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c index a1b751d9ac06..1c2292cc5f2c 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c @@ -54,6 +54,7 @@ static int jpeg_v3_0_early_init(void *handle) switch (adev->ip_versions[UVD_HWIP][0]) { case IP_VERSION(3, 1, 1): + case IP_VERSION(3, 1, 2): break; default: harvest = RREG32_SOC15(JPEG, 0, mmCC_UVD_HARVESTING); @@ -100,6 +101,7 @@ static int jpeg_v3_0_sw_init(void *handle) ring = &adev->jpeg.inst->ring_dec; ring->use_doorbell = true; ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "jpeg_dec"); r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0, AMDGPU_RING_PRIO_DEFAULT, NULL); @@ -559,7 +561,6 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = jpeg_v3_0_dec_ring_get_rptr, .get_wptr = jpeg_v3_0_dec_ring_get_wptr, .set_wptr = jpeg_v3_0_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c index 5f2a034b9ec0..77e1e64aa1d1 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c @@ -108,6 +108,7 @@ static int jpeg_v4_0_sw_init(void *handle) ring = &adev->jpeg.inst->ring_dec; ring->use_doorbell = true; ring->doorbell_index = amdgpu_sriov_vf(adev) ? (((adev->doorbell_index.vcn.vcn_ring0_1) << 1) + 4) : ((adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1); + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "jpeg_dec"); r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0, @@ -429,7 +430,7 @@ static int jpeg_v4_0_start_sriov(struct amdgpu_device *adev) MMSCH_COMMAND__END; header.version = MMSCH_VERSION; - header.total_size = sizeof(struct mmsch_v4_0_init_header) >> 2; + header.total_size = RREG32_SOC15(VCN, 0, regMMSCH_VF_CTX_SIZE); header.jpegdec.init_status = 0; header.jpegdec.table_offset = 0; @@ -715,7 +716,6 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = jpeg_v4_0_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 5826eac270d7..45280f047180 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -33,14 +33,19 @@ #include "mes_v11_api_def.h" MODULE_FIRMWARE("amdgpu/gc_11_0_0_mes.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_0_mes_2.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_mes1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_1_mes.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_1_mes_2.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_1_mes1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes_2.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes_2.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes_2.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes1.bin"); static int mes_v11_0_hw_fini(void *handle); @@ -1089,13 +1094,14 @@ static int mes_v11_0_sw_fini(void *handle) return 0; } -static void mes_v11_0_kiq_dequeue_sched(struct amdgpu_device *adev) +static void mes_v11_0_kiq_dequeue(struct amdgpu_ring *ring) { uint32_t data; int i; + struct amdgpu_device *adev = ring->adev; mutex_lock(&adev->srbm_mutex); - soc21_grbm_select(adev, 3, AMDGPU_MES_SCHED_PIPE, 0, 0); + soc21_grbm_select(adev, 3, ring->pipe, 0, 0); /* disable the queue if it's active */ if (RREG32_SOC15(GC, 0, regCP_HQD_ACTIVE) & 1) { @@ -1121,8 +1127,6 @@ static void mes_v11_0_kiq_dequeue_sched(struct amdgpu_device *adev) soc21_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); - - adev->mes.ring.sched.ready = false; } static void mes_v11_0_kiq_setting(struct amdgpu_ring *ring) @@ -1139,6 +1143,16 @@ static void mes_v11_0_kiq_setting(struct amdgpu_ring *ring) WREG32_SOC15(GC, 0, regRLC_CP_SCHEDULERS, tmp); } +static void mes_v11_0_kiq_clear(struct amdgpu_device *adev) +{ + uint32_t tmp; + + /* tell RLC which is KIQ dequeue */ + tmp = RREG32_SOC15(GC, 0, regRLC_CP_SCHEDULERS); + tmp &= ~RLC_CP_SCHEDULERS__scheduler0_MASK; + WREG32_SOC15(GC, 0, regRLC_CP_SCHEDULERS, tmp); +} + static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev) { int r = 0; @@ -1176,11 +1190,17 @@ failure: static int mes_v11_0_kiq_hw_fini(struct amdgpu_device *adev) { - if (adev->mes.ring.sched.ready) - mes_v11_0_kiq_dequeue_sched(adev); + if (adev->mes.ring.sched.ready) { + mes_v11_0_kiq_dequeue(&adev->mes.ring); + adev->mes.ring.sched.ready = false; + } - if (!amdgpu_sriov_vf(adev)) - mes_v11_0_enable(adev, false); + if (amdgpu_sriov_vf(adev)) { + mes_v11_0_kiq_dequeue(&adev->gfx.kiq.ring); + mes_v11_0_kiq_clear(adev); + } + + mes_v11_0_enable(adev, false); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c index 19455a725939..685abf57ffdd 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c @@ -238,7 +238,7 @@ static void nbio_v7_4_ih_doorbell_range(struct amdgpu_device *adev, if (use_doorbell) { ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, OFFSET, doorbell_index); - ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 4); + ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 8); } else ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 47420b403871..0fb6013441f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -98,6 +98,16 @@ static const struct amdgpu_video_codecs nv_video_codecs_decode = }; /* Sienna Cichlid */ +static const struct amdgpu_video_codec_info sc_video_codecs_encode_array[] = { + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2160, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 7680, 4352, 0)}, +}; + +static const struct amdgpu_video_codecs sc_video_codecs_encode = { + .codec_count = ARRAY_SIZE(sc_video_codecs_encode_array), + .codec_array = sc_video_codecs_encode_array, +}; + static const struct amdgpu_video_codec_info sc_video_codecs_decode_array_vcn0[] = { {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, @@ -136,8 +146,8 @@ static const struct amdgpu_video_codecs sc_video_codecs_decode_vcn1 = /* SRIOV Sienna Cichlid, not const since data is controlled by host */ static struct amdgpu_video_codec_info sriov_sc_video_codecs_encode_array[] = { - {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, - {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2160, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 7680, 4352, 0)}, }; static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn0[] = @@ -237,12 +247,12 @@ static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode, } else { if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) { if (encode) - *codecs = &nv_video_codecs_encode; + *codecs = &sc_video_codecs_encode; else *codecs = &sc_video_codecs_decode_vcn1; } else { if (encode) - *codecs = &nv_video_codecs_encode; + *codecs = &sc_video_codecs_encode; else *codecs = &sc_video_codecs_decode_vcn0; } @@ -251,14 +261,14 @@ static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode, case IP_VERSION(3, 0, 16): case IP_VERSION(3, 0, 2): if (encode) - *codecs = &nv_video_codecs_encode; + *codecs = &sc_video_codecs_encode; else *codecs = &sc_video_codecs_decode_vcn0; return 0; case IP_VERSION(3, 1, 1): case IP_VERSION(3, 1, 2): if (encode) - *codecs = &nv_video_codecs_encode; + *codecs = &sc_video_codecs_encode; else *codecs = &yc_video_codecs_decode; return 0; @@ -531,13 +541,6 @@ static void nv_program_aspm(struct amdgpu_device *adev) } -static void nv_enable_doorbell_aperture(struct amdgpu_device *adev, - bool enable) -{ - adev->nbio.funcs->enable_doorbell_aperture(adev, enable); - adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, enable); -} - const struct amdgpu_ip_block_version nv_common_ip_block = { .type = AMD_IP_BLOCK_TYPE_COMMON, @@ -999,6 +1002,11 @@ static int nv_common_late_init(void *handle) } } + /* Enable selfring doorbell aperture late because doorbell BAR + * aperture will change if resize BAR successfully in gmc sw_init. + */ + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, true); + return 0; } @@ -1038,7 +1046,7 @@ static int nv_common_hw_init(void *handle) if (adev->nbio.funcs->remap_hdp_registers && !amdgpu_sriov_vf(adev)) adev->nbio.funcs->remap_hdp_registers(adev); /* enable the doorbell aperture */ - nv_enable_doorbell_aperture(adev, true); + adev->nbio.funcs->enable_doorbell_aperture(adev, true); return 0; } @@ -1047,8 +1055,13 @@ static int nv_common_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - /* disable the doorbell aperture */ - nv_enable_doorbell_aperture(adev, false); + /* Disable the doorbell aperture and selfring doorbell aperture + * separately in hw_fini because nv_enable_doorbell_aperture + * has been removed and there is no need to delay disabling + * selfring doorbell. + */ + adev->nbio.funcs->enable_doorbell_aperture(adev, false); + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, false); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index b5affba22156..9295ac7edd56 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -1823,6 +1823,15 @@ static int sdma_v4_0_sw_init(void *handle) /* doorbell size is 2 dwords, get DWORD offset */ ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1; + /* + * On Arcturus, SDMA instance 5~7 has a different vmhub + * type(AMDGPU_MMHUB_1). + */ + if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) && i >= 5) + ring->vm_hub = AMDGPU_MMHUB_1; + else + ring->vm_hub = AMDGPU_MMHUB_0; + sprintf(ring->name, "sdma%d", i); r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq, AMDGPU_SDMA_IRQ_INSTANCE0 + i, @@ -1841,6 +1850,11 @@ static int sdma_v4_0_sw_init(void *handle) ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1; ring->doorbell_index += 0x400; + if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) && i >= 5) + ring->vm_hub = AMDGPU_MMHUB_1; + else + ring->vm_hub = AMDGPU_MMHUB_0; + sprintf(ring->name, "page%d", i); r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq, @@ -1870,7 +1884,7 @@ static int sdma_v4_0_sw_fini(void *handle) amdgpu_ring_fini(&adev->sdma.instance[i].page); } - if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 0) || + if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) || adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 4, 0)) amdgpu_sdma_destroy_inst_ctx(adev, true); else @@ -1903,9 +1917,11 @@ static int sdma_v4_0_hw_fini(void *handle) return 0; } - for (i = 0; i < adev->sdma.num_instances; i++) { - amdgpu_irq_put(adev, &adev->sdma.ecc_irq, - AMDGPU_SDMA_IRQ_INSTANCE0 + i); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) { + for (i = 0; i < adev->sdma.num_instances; i++) { + amdgpu_irq_put(adev, &adev->sdma.ecc_irq, + AMDGPU_SDMA_IRQ_INSTANCE0 + i); + } } sdma_v4_0_ctx_switch_enable(adev, false); @@ -2294,44 +2310,6 @@ static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs = { .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_0, - .get_rptr = sdma_v4_0_ring_get_rptr, - .get_wptr = sdma_v4_0_ring_get_wptr, - .set_wptr = sdma_v4_0_ring_set_wptr, - .emit_frame_size = - 6 + /* sdma_v4_0_ring_emit_hdp_flush */ - 3 + /* hdp invalidate */ - 6 + /* sdma_v4_0_ring_emit_pipeline_sync */ - /* sdma_v4_0_ring_emit_vm_flush */ - SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + - SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6 + - 10 + 10 + 10, /* sdma_v4_0_ring_emit_fence x3 for user fence, vm fence */ - .emit_ib_size = 7 + 6, /* sdma_v4_0_ring_emit_ib */ - .emit_ib = sdma_v4_0_ring_emit_ib, - .emit_fence = sdma_v4_0_ring_emit_fence, - .emit_pipeline_sync = sdma_v4_0_ring_emit_pipeline_sync, - .emit_vm_flush = sdma_v4_0_ring_emit_vm_flush, - .emit_hdp_flush = sdma_v4_0_ring_emit_hdp_flush, - .test_ring = sdma_v4_0_ring_test_ring, - .test_ib = sdma_v4_0_ring_test_ib, - .insert_nop = sdma_v4_0_ring_insert_nop, - .pad_ib = sdma_v4_0_ring_pad_ib, - .emit_wreg = sdma_v4_0_ring_emit_wreg, - .emit_reg_wait = sdma_v4_0_ring_emit_reg_wait, - .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, -}; - -/* - * On Arcturus, SDMA instance 5~7 has a different vmhub type(AMDGPU_MMHUB_1). - * So create a individual constant ring_funcs for those instances. - */ -static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs_2nd_mmhub = { - .type = AMDGPU_RING_TYPE_SDMA, - .align_mask = 0xf, - .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), - .support_64bit_ptrs = true, - .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_1, .get_rptr = sdma_v4_0_ring_get_rptr, .get_wptr = sdma_v4_0_ring_get_wptr, .set_wptr = sdma_v4_0_ring_set_wptr, @@ -2364,40 +2342,6 @@ static const struct amdgpu_ring_funcs sdma_v4_0_page_ring_funcs = { .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_0, - .get_rptr = sdma_v4_0_ring_get_rptr, - .get_wptr = sdma_v4_0_page_ring_get_wptr, - .set_wptr = sdma_v4_0_page_ring_set_wptr, - .emit_frame_size = - 6 + /* sdma_v4_0_ring_emit_hdp_flush */ - 3 + /* hdp invalidate */ - 6 + /* sdma_v4_0_ring_emit_pipeline_sync */ - /* sdma_v4_0_ring_emit_vm_flush */ - SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + - SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6 + - 10 + 10 + 10, /* sdma_v4_0_ring_emit_fence x3 for user fence, vm fence */ - .emit_ib_size = 7 + 6, /* sdma_v4_0_ring_emit_ib */ - .emit_ib = sdma_v4_0_ring_emit_ib, - .emit_fence = sdma_v4_0_ring_emit_fence, - .emit_pipeline_sync = sdma_v4_0_ring_emit_pipeline_sync, - .emit_vm_flush = sdma_v4_0_ring_emit_vm_flush, - .emit_hdp_flush = sdma_v4_0_ring_emit_hdp_flush, - .test_ring = sdma_v4_0_ring_test_ring, - .test_ib = sdma_v4_0_ring_test_ib, - .insert_nop = sdma_v4_0_ring_insert_nop, - .pad_ib = sdma_v4_0_ring_pad_ib, - .emit_wreg = sdma_v4_0_ring_emit_wreg, - .emit_reg_wait = sdma_v4_0_ring_emit_reg_wait, - .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, -}; - -static const struct amdgpu_ring_funcs sdma_v4_0_page_ring_funcs_2nd_mmhub = { - .type = AMDGPU_RING_TYPE_SDMA, - .align_mask = 0xf, - .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), - .support_64bit_ptrs = true, - .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_1, .get_rptr = sdma_v4_0_ring_get_rptr, .get_wptr = sdma_v4_0_page_ring_get_wptr, .set_wptr = sdma_v4_0_page_ring_set_wptr, @@ -2429,19 +2373,10 @@ static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev) int i; for (i = 0; i < adev->sdma.num_instances; i++) { - if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) && i >= 5) - adev->sdma.instance[i].ring.funcs = - &sdma_v4_0_ring_funcs_2nd_mmhub; - else - adev->sdma.instance[i].ring.funcs = - &sdma_v4_0_ring_funcs; + adev->sdma.instance[i].ring.funcs = &sdma_v4_0_ring_funcs; adev->sdma.instance[i].ring.me = i; if (adev->sdma.has_page_queue) { - if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) && i >= 5) - adev->sdma.instance[i].page.funcs = - &sdma_v4_0_page_ring_funcs_2nd_mmhub; - else - adev->sdma.instance[i].page.funcs = + adev->sdma.instance[i].page.funcs = &sdma_v4_0_page_ring_funcs; adev->sdma.instance[i].page.me = i; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c index 1b04700a4d55..64dcaa2670dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c @@ -1309,6 +1309,7 @@ static int sdma_v4_4_2_sw_init(void *handle) /* doorbell size is 2 dwords, get DWORD offset */ ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "sdma%d", i); r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq, @@ -1327,6 +1328,7 @@ static int sdma_v4_4_2_sw_init(void *handle) */ ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1; ring->doorbell_index += 0x400; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "page%d", i); r = amdgpu_ring_init(adev, ring, 1024, @@ -1741,7 +1743,6 @@ static const struct amdgpu_ring_funcs sdma_v4_4_2_ring_funcs = { .align_mask = 0xf, .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), .support_64bit_ptrs = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = sdma_v4_4_2_ring_get_rptr, .get_wptr = sdma_v4_4_2_ring_get_wptr, .set_wptr = sdma_v4_4_2_ring_set_wptr, @@ -1773,7 +1774,6 @@ static const struct amdgpu_ring_funcs sdma_v4_4_2_page_ring_funcs = { .align_mask = 0xf, .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), .support_64bit_ptrs = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = sdma_v4_4_2_ring_get_rptr, .get_wptr = sdma_v4_4_2_page_ring_get_wptr, .set_wptr = sdma_v4_4_2_page_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c index 1941b3b7c5d9..92e1299be021 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c @@ -1389,6 +1389,7 @@ static int sdma_v5_0_sw_init(void *handle) (adev->doorbell_index.sdma_engine[0] << 1) //get DWORD offset : (adev->doorbell_index.sdma_engine[1] << 1); // get DWORD offset + ring->vm_hub = AMDGPU_GFXHUB_0; sprintf(ring->name, "sdma%d", i); r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq, (i == 0) ? AMDGPU_SDMA_IRQ_INSTANCE0 : @@ -1765,7 +1766,6 @@ static const struct amdgpu_ring_funcs sdma_v5_0_ring_funcs = { .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = sdma_v5_0_ring_get_rptr, .get_wptr = sdma_v5_0_ring_get_wptr, .set_wptr = sdma_v5_0_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c index 8e445eb9dd49..ca7e8757d78e 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c @@ -1253,6 +1253,7 @@ static int sdma_v5_2_sw_init(void *handle) ring->doorbell_index = (adev->doorbell_index.sdma_engine[i] << 1); //get DWORD offset + ring->vm_hub = AMDGPU_GFXHUB_0; sprintf(ring->name, "sdma%d", i); r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq, AMDGPU_SDMA_IRQ_INSTANCE0 + i, @@ -1653,7 +1654,6 @@ static const struct amdgpu_ring_funcs sdma_v5_2_ring_funcs = { .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = sdma_v5_2_ring_get_rptr, .get_wptr = sdma_v5_2_ring_get_wptr, .set_wptr = sdma_v5_2_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index 40e6b22daa22..3d9a80511a45 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -403,15 +403,26 @@ static void sdma_v6_0_rlc_stop(struct amdgpu_device *adev) } /** - * sdma_v6_0_ctx_switch_enable - stop the async dma engines context switch + * sdma_v6_0_ctxempty_int_enable - enable or disable context empty interrupts * * @adev: amdgpu_device pointer - * @enable: enable/disable the DMA MEs context switch. + * @enable: enable/disable context switching due to queue empty conditions * - * Halt or unhalt the async dma engines context switch. + * Enable or disable the async dma engines queue empty context switch. */ -static void sdma_v6_0_ctx_switch_enable(struct amdgpu_device *adev, bool enable) +static void sdma_v6_0_ctxempty_int_enable(struct amdgpu_device *adev, bool enable) { + u32 f32_cntl; + int i; + + if (!amdgpu_sriov_vf(adev)) { + for (i = 0; i < adev->sdma.num_instances; i++) { + f32_cntl = RREG32(sdma_v6_0_get_reg_offset(adev, i, regSDMA0_CNTL)); + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL, + CTXEMPTY_INT_ENABLE, enable ? 1 : 0); + WREG32(sdma_v6_0_get_reg_offset(adev, i, regSDMA0_CNTL), f32_cntl); + } + } } /** @@ -499,10 +510,7 @@ static int sdma_v6_0_gfx_resume(struct amdgpu_device *adev) lower_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFC); rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1); - if (amdgpu_sriov_vf(adev)) - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, WPTR_POLL_ENABLE, 1); - else - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, WPTR_POLL_ENABLE, 0); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, WPTR_POLL_ENABLE, 0); rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, F32_WPTR_POLL_ENABLE, 1); WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_BASE), ring->gpu_addr >> 8); @@ -579,10 +587,8 @@ static int sdma_v6_0_gfx_resume(struct amdgpu_device *adev) ring->sched.ready = true; - if (amdgpu_sriov_vf(adev)) { /* bare-metal sequence doesn't need below to lines */ - sdma_v6_0_ctx_switch_enable(adev, true); + if (amdgpu_sriov_vf(adev)) sdma_v6_0_enable(adev, true); - } r = amdgpu_ring_test_helper(ring); if (r) { @@ -778,7 +784,6 @@ static int sdma_v6_0_start(struct amdgpu_device *adev) int r = 0; if (amdgpu_sriov_vf(adev)) { - sdma_v6_0_ctx_switch_enable(adev, false); sdma_v6_0_enable(adev, false); /* set RB registers */ @@ -799,7 +804,7 @@ static int sdma_v6_0_start(struct amdgpu_device *adev) /* unhalt the MEs */ sdma_v6_0_enable(adev, true); /* enable sdma ring preemption */ - sdma_v6_0_ctx_switch_enable(adev, true); + sdma_v6_0_ctxempty_int_enable(adev, true); /* start the gfx rings and rlc compute queues */ r = sdma_v6_0_gfx_resume(adev); @@ -1173,7 +1178,28 @@ static void sdma_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring) static void sdma_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; + uint32_t req = hub->vmhub_funcs->get_invalidate_req(vmid, 0); + + /* Update the PD address for this VMID. */ + amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + + (hub->ctx_addr_distance * vmid), + lower_32_bits(pd_addr)); + amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_hi32 + + (hub->ctx_addr_distance * vmid), + upper_32_bits(pd_addr)); + + /* Trigger invalidation. */ + amdgpu_ring_write(ring, + SDMA_PKT_VM_INVALIDATION_HEADER_OP(SDMA_OP_POLL_REGMEM) | + SDMA_PKT_VM_INVALIDATION_HEADER_SUB_OP(SDMA_SUBOP_VM_INVALIDATION) | + SDMA_PKT_VM_INVALIDATION_HEADER_GFX_ENG_ID(ring->vm_inv_eng) | + SDMA_PKT_VM_INVALIDATION_HEADER_MM_ENG_ID(0x1f)); + amdgpu_ring_write(ring, req); + amdgpu_ring_write(ring, 0xFFFFFFFF); + amdgpu_ring_write(ring, + SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_INVALIDATEACK(1 << vmid) | + SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_ADDRESSRANGEHI(0x1F)); } static void sdma_v6_0_ring_emit_wreg(struct amdgpu_ring *ring, @@ -1272,6 +1298,7 @@ static int sdma_v6_0_sw_init(void *handle) ring->doorbell_index = (adev->doorbell_index.sdma_engine[i] << 1); // get DWORD offset + ring->vm_hub = AMDGPU_GFXHUB_0; sprintf(ring->name, "sdma%d", i); r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq, @@ -1319,7 +1346,7 @@ static int sdma_v6_0_hw_fini(void *handle) return 0; } - sdma_v6_0_ctx_switch_enable(adev, false); + sdma_v6_0_ctxempty_int_enable(adev, false); sdma_v6_0_enable(adev, false); return 0; @@ -1528,7 +1555,6 @@ static const struct amdgpu_ring_funcs sdma_v6_0_ring_funcs = { .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), .support_64bit_ptrs = true, .secure_submission_supported = true, - .vmhub = AMDGPU_GFXHUB_0, .get_rptr = sdma_v6_0_ring_get_rptr, .get_wptr = sdma_v6_0_ring_get_wptr, .set_wptr = sdma_v6_0_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c index 81a6d5b94987..8b8086d5c864 100644 --- a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c +++ b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c @@ -40,7 +40,7 @@ static bool sienna_cichlid_is_mode2_default(struct amdgpu_reset_control *reset_c adev->pm.fw_version >= 0x3a5500 && !amdgpu_sriov_vf(adev)) return true; #endif - return false; + return amdgpu_reset_method == AMD_RESET_METHOD_MODE2; } static struct amdgpu_reset_handler * diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 7d04c39332ad..6d15d5cd9e07 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -301,11 +301,10 @@ static u32 soc15_get_xclk(struct amdgpu_device *adev) u32 reference_clock = adev->clock.spll.reference_freq; if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 0) || - adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1)) - return 10000; - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 0) || + adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1) || + adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 0) || adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 1)) - return reference_clock / 4; + return 10000; return reference_clock; } @@ -620,13 +619,6 @@ static void soc15_program_aspm(struct amdgpu_device *adev) adev->nbio.funcs->program_aspm(adev); } -static void soc15_enable_doorbell_aperture(struct amdgpu_device *adev, - bool enable) -{ - adev->nbio.funcs->enable_doorbell_aperture(adev, enable); - adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, enable); -} - const struct amdgpu_ip_block_version vega10_common_ip_block = { .type = AMD_IP_BLOCK_TYPE_COMMON, @@ -1101,6 +1093,11 @@ static int soc15_common_early_init(void *handle) adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG; adev->external_rev_id = adev->rev_id + 0x3c; break; + case IP_VERSION(9, 4, 3): + adev->asic_funcs = &vega20_asic_funcs; + adev->cg_flags = 0; + adev->pg_flags = 0; + break; default: /* FIXME: not supported yet */ return -EINVAL; @@ -1121,6 +1118,11 @@ static int soc15_common_late_init(void *handle) if (amdgpu_sriov_vf(adev)) xgpu_ai_mailbox_get_irq(adev); + /* Enable selfring doorbell aperture late because doorbell BAR + * aperture will change if resize BAR successfully in gmc sw_init. + */ + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, true); + return 0; } @@ -1178,7 +1180,8 @@ static int soc15_common_hw_init(void *handle) adev->nbio.funcs->remap_hdp_registers(adev); /* enable the doorbell aperture */ - soc15_enable_doorbell_aperture(adev, true); + adev->nbio.funcs->enable_doorbell_aperture(adev, true); + /* HW doorbell routing policy: doorbell writing not * in SDMA/IH/MM/ACV range will be routed to CP. So * we need to init SDMA doorbell range prior @@ -1194,8 +1197,14 @@ static int soc15_common_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - /* disable the doorbell aperture */ - soc15_enable_doorbell_aperture(adev, false); + /* Disable the doorbell aperture and selfring doorbell aperture + * separately in hw_fini because soc15_enable_doorbell_aperture + * has been removed and there is no need to delay disabling + * selfring doorbell. + */ + adev->nbio.funcs->enable_doorbell_aperture(adev, false); + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, false); + if (amdgpu_sriov_vf(adev)) xgpu_ai_mailbox_put_irq(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 514bfc705d5a..d77162536514 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -450,13 +450,6 @@ static void soc21_program_aspm(struct amdgpu_device *adev) adev->nbio.funcs->program_aspm(adev); } -static void soc21_enable_doorbell_aperture(struct amdgpu_device *adev, - bool enable) -{ - adev->nbio.funcs->enable_doorbell_aperture(adev, enable); - adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, enable); -} - const struct amdgpu_ip_block_version soc21_common_ip_block = { .type = AMD_IP_BLOCK_TYPE_COMMON, @@ -718,7 +711,7 @@ static int soc21_common_early_init(void *handle) AMD_PG_SUPPORT_VCN_DPG | AMD_PG_SUPPORT_GFX_PG | AMD_PG_SUPPORT_JPEG; - adev->external_rev_id = adev->rev_id + 0x1; + adev->external_rev_id = adev->rev_id + 0x80; break; default: @@ -764,6 +757,11 @@ static int soc21_common_late_init(void *handle) amdgpu_irq_get(adev, &adev->nbio.ras_err_event_athub_irq, 0); } + /* Enable selfring doorbell aperture late because doorbell BAR + * aperture will change if resize BAR successfully in gmc sw_init. + */ + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, true); + return 0; } @@ -797,7 +795,7 @@ static int soc21_common_hw_init(void *handle) if (adev->nbio.funcs->remap_hdp_registers) adev->nbio.funcs->remap_hdp_registers(adev); /* enable the doorbell aperture */ - soc21_enable_doorbell_aperture(adev, true); + adev->nbio.funcs->enable_doorbell_aperture(adev, true); return 0; } @@ -806,8 +804,13 @@ static int soc21_common_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - /* disable the doorbell aperture */ - soc21_enable_doorbell_aperture(adev, false); + /* Disable the doorbell aperture and selfring doorbell aperture + * separately in hw_fini because soc21_enable_doorbell_aperture + * has been removed and there is no need to delay disabling + * selfring doorbell. + */ + adev->nbio.funcs->enable_doorbell_aperture(adev, false); + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, false); if (amdgpu_sriov_vf(adev)) { xgpu_nv_mailbox_put_irq(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h b/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h index 509d8a1945eb..30d0482ac466 100644 --- a/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h +++ b/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h @@ -84,6 +84,8 @@ enum ta_ras_block { TA_RAS_BLOCK__MP1, TA_RAS_BLOCK__FUSE, TA_RAS_BLOCK__MCA, + TA_RAS_BLOCK__VCN, + TA_RAS_BLOCK__JPEG, TA_NUM_BLOCK_MAX }; diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c index e08e25a3a1a9..530549314ce4 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c @@ -160,24 +160,28 @@ static void umc_v6_7_ecc_info_querry_uncorrectable_error_count(struct amdgpu_dev } } +static int umc_v6_7_ecc_info_querry_ecc_error_count(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) +{ + struct ras_err_data *err_data = (struct ras_err_data *)data; + + umc_v6_7_ecc_info_query_correctable_error_count(adev, + umc_inst, ch_inst, + &(err_data->ce_count)); + + umc_v6_7_ecc_info_querry_uncorrectable_error_count(adev, + umc_inst, ch_inst, + &(err_data->ue_count)); + + return 0; +} + static void umc_v6_7_ecc_info_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - - /*TODO: driver needs to toggle DF Cstate to ensure - * safe access of UMC registers. Will add the protection */ - LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { - umc_v6_7_ecc_info_query_correctable_error_count(adev, - umc_inst, ch_inst, - &(err_data->ce_count)); - umc_v6_7_ecc_info_querry_uncorrectable_error_count(adev, - umc_inst, ch_inst, - &(err_data->ue_count)); - } + amdgpu_umc_loop_channels(adev, + umc_v6_7_ecc_info_querry_ecc_error_count, ras_error_status); } void umc_v6_7_convert_error_address(struct amdgpu_device *adev, @@ -215,23 +219,23 @@ void umc_v6_7_convert_error_address(struct amdgpu_device *adev, } } -static void umc_v6_7_ecc_info_query_error_address(struct amdgpu_device *adev, - struct ras_err_data *err_data, - uint32_t ch_inst, - uint32_t umc_inst) +static int umc_v6_7_ecc_info_query_error_address(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) { uint64_t mc_umc_status, err_addr; uint32_t eccinfo_table_idx; struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + struct ras_err_data *err_data = (struct ras_err_data *)data; eccinfo_table_idx = umc_inst * adev->umc.channel_inst_num + ch_inst; mc_umc_status = ras->umc_ecc.ecc[eccinfo_table_idx].mca_umc_status; if (mc_umc_status == 0) - return; + return 0; if (!err_data->err_addr) - return; + return 0; /* calculate error address if ue error is detected */ if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 && @@ -243,25 +247,15 @@ static void umc_v6_7_ecc_info_query_error_address(struct amdgpu_device *adev, umc_v6_7_convert_error_address(adev, err_data, err_addr, ch_inst, umc_inst); } + + return 0; } static void umc_v6_7_ecc_info_query_ras_error_address(struct amdgpu_device *adev, void *ras_error_status) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - - /*TODO: driver needs to toggle DF Cstate to ensure - * safe access of UMC resgisters. Will add the protection - * when firmware interface is ready */ - LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { - umc_v6_7_ecc_info_query_error_address(adev, - err_data, - ch_inst, - umc_inst); - } + amdgpu_umc_loop_channels(adev, + umc_v6_7_ecc_info_query_error_address, ras_error_status); } static void umc_v6_7_query_correctable_error_count(struct amdgpu_device *adev, @@ -364,11 +358,14 @@ static void umc_v6_7_querry_uncorrectable_error_count(struct amdgpu_device *adev } } -static void umc_v6_7_reset_error_count_per_channel(struct amdgpu_device *adev, - uint32_t umc_reg_offset) +static int umc_v6_7_reset_error_count_per_channel(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) { uint32_t ecc_err_cnt_addr; uint32_t ecc_err_cnt_sel, ecc_err_cnt_sel_addr; + uint32_t umc_reg_offset = + get_umc_v6_7_reg_offset(adev, umc_inst, ch_inst); ecc_err_cnt_sel_addr = SOC15_REG_OFFSET(UMC, 0, @@ -402,58 +399,54 @@ static void umc_v6_7_reset_error_count_per_channel(struct amdgpu_device *adev, /* clear higher chip error count */ WREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4, UMC_V6_7_CE_CNT_INIT); + + return 0; } static void umc_v6_7_reset_error_count(struct amdgpu_device *adev) { - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - uint32_t umc_reg_offset = 0; + amdgpu_umc_loop_channels(adev, + umc_v6_7_reset_error_count_per_channel, NULL); +} + +static int umc_v6_7_query_ecc_error_count(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) +{ + struct ras_err_data *err_data = (struct ras_err_data *)data; + uint32_t umc_reg_offset = + get_umc_v6_7_reg_offset(adev, umc_inst, ch_inst); + + umc_v6_7_query_correctable_error_count(adev, + umc_reg_offset, + &(err_data->ce_count), + ch_inst, umc_inst); - LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { - umc_reg_offset = get_umc_v6_7_reg_offset(adev, - umc_inst, - ch_inst); + umc_v6_7_querry_uncorrectable_error_count(adev, + umc_reg_offset, + &(err_data->ue_count)); - umc_v6_7_reset_error_count_per_channel(adev, - umc_reg_offset); - } + return 0; } static void umc_v6_7_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - uint32_t umc_reg_offset = 0; - - /*TODO: driver needs to toggle DF Cstate to ensure - * safe access of UMC registers. Will add the protection */ - LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { - umc_reg_offset = get_umc_v6_7_reg_offset(adev, - umc_inst, - ch_inst); - umc_v6_7_query_correctable_error_count(adev, - umc_reg_offset, - &(err_data->ce_count), - ch_inst, umc_inst); - umc_v6_7_querry_uncorrectable_error_count(adev, - umc_reg_offset, - &(err_data->ue_count)); - } + amdgpu_umc_loop_channels(adev, + umc_v6_7_query_ecc_error_count, ras_error_status); umc_v6_7_reset_error_count(adev); } -static void umc_v6_7_query_error_address(struct amdgpu_device *adev, - struct ras_err_data *err_data, - uint32_t umc_reg_offset, uint32_t ch_inst, - uint32_t umc_inst) +static int umc_v6_7_query_error_address(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) { uint32_t mc_umc_status_addr; uint64_t mc_umc_status = 0, mc_umc_addrt0, err_addr; + struct ras_err_data *err_data = (struct ras_err_data *)data; + uint32_t umc_reg_offset = + get_umc_v6_7_reg_offset(adev, umc_inst, ch_inst); mc_umc_status_addr = SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0); @@ -463,12 +456,12 @@ static void umc_v6_7_query_error_address(struct amdgpu_device *adev, mc_umc_status = RREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4); if (mc_umc_status == 0) - return; + return 0; if (!err_data->err_addr) { /* clear umc status */ WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); - return; + return 0; } /* calculate error address if ue error is detected */ @@ -484,29 +477,15 @@ static void umc_v6_7_query_error_address(struct amdgpu_device *adev, /* clear umc status */ WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); + + return 0; } static void umc_v6_7_query_ras_error_address(struct amdgpu_device *adev, void *ras_error_status) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - uint32_t umc_reg_offset = 0; - - /*TODO: driver needs to toggle DF Cstate to ensure - * safe access of UMC resgisters. Will add the protection - * when firmware interface is ready */ - LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { - umc_reg_offset = get_umc_v6_7_reg_offset(adev, - umc_inst, - ch_inst); - umc_v6_7_query_error_address(adev, - err_data, - umc_reg_offset, ch_inst, - umc_inst); - } + amdgpu_umc_loop_channels(adev, + umc_v6_7_query_error_address, ras_error_status); } static uint32_t umc_v6_7_query_ras_poison_mode_per_channel( diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c index fb55e8cb9967..d51ae0bc36f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c @@ -76,10 +76,13 @@ static inline uint32_t get_umc_v8_10_reg_offset(struct amdgpu_device *adev, UMC_8_NODE_DIST * node_inst; } -static void umc_v8_10_clear_error_count_per_channel(struct amdgpu_device *adev, - uint32_t umc_reg_offset) +static int umc_v8_10_clear_error_count_per_channel(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) { uint32_t ecc_err_cnt_addr; + uint32_t umc_reg_offset = + get_umc_v8_10_reg_offset(adev, node_inst, umc_inst, ch_inst); ecc_err_cnt_addr = SOC15_REG_OFFSET(UMC, 0, regUMCCH0_0_GeccErrCnt); @@ -87,24 +90,14 @@ static void umc_v8_10_clear_error_count_per_channel(struct amdgpu_device *adev, /* clear error count */ WREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4, UMC_V8_10_CE_CNT_INIT); + + return 0; } static void umc_v8_10_clear_error_count(struct amdgpu_device *adev) { - uint32_t node_inst = 0; - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - uint32_t umc_reg_offset = 0; - - LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) { - umc_reg_offset = get_umc_v8_10_reg_offset(adev, - node_inst, - umc_inst, - ch_inst); - - umc_v8_10_clear_error_count_per_channel(adev, - umc_reg_offset); - } + amdgpu_umc_loop_channels(adev, + umc_v8_10_clear_error_count_per_channel, NULL); } static void umc_v8_10_query_correctable_error_count(struct amdgpu_device *adev, @@ -147,29 +140,29 @@ static void umc_v8_10_query_uncorrectable_error_count(struct amdgpu_device *adev *error_count += 1; } +static int umc_v8_10_query_ecc_error_count(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) +{ + struct ras_err_data *err_data = (struct ras_err_data *)data; + uint32_t umc_reg_offset = + get_umc_v8_10_reg_offset(adev, node_inst, umc_inst, ch_inst); + + umc_v8_10_query_correctable_error_count(adev, + umc_reg_offset, + &(err_data->ce_count)); + umc_v8_10_query_uncorrectable_error_count(adev, + umc_reg_offset, + &(err_data->ue_count)); + + return 0; +} + static void umc_v8_10_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - - uint32_t node_inst = 0; - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - uint32_t umc_reg_offset = 0; - - LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) { - umc_reg_offset = get_umc_v8_10_reg_offset(adev, - node_inst, - umc_inst, - ch_inst); - - umc_v8_10_query_correctable_error_count(adev, - umc_reg_offset, - &(err_data->ce_count)); - umc_v8_10_query_uncorrectable_error_count(adev, - umc_reg_offset, - &(err_data->ue_count)); - } + amdgpu_umc_loop_channels(adev, + umc_v8_10_query_ecc_error_count, ras_error_status); umc_v8_10_clear_error_count(adev); } @@ -248,28 +241,28 @@ static void umc_v8_10_convert_error_address(struct amdgpu_device *adev, } } -static void umc_v8_10_query_error_address(struct amdgpu_device *adev, - struct ras_err_data *err_data, - uint32_t umc_reg_offset, - uint32_t node_inst, - uint32_t ch_inst, - uint32_t umc_inst) +static int umc_v8_10_query_error_address(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) { uint64_t mc_umc_status_addr; uint64_t mc_umc_status, err_addr; uint64_t mc_umc_addrt0; + struct ras_err_data *err_data = (struct ras_err_data *)data; + uint32_t umc_reg_offset = + get_umc_v8_10_reg_offset(adev, node_inst, umc_inst, ch_inst); mc_umc_status_addr = SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0); mc_umc_status = RREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4); if (mc_umc_status == 0) - return; + return 0; if (!err_data->err_addr) { /* clear umc status */ WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); - return; + return 0; } /* calculate error address if ue error is detected */ @@ -287,37 +280,25 @@ static void umc_v8_10_query_error_address(struct amdgpu_device *adev, /* clear umc status */ WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); + + return 0; } static void umc_v8_10_query_ras_error_address(struct amdgpu_device *adev, void *ras_error_status) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - uint32_t node_inst = 0; - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - uint32_t umc_reg_offset = 0; - - LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) { - umc_reg_offset = get_umc_v8_10_reg_offset(adev, - node_inst, - umc_inst, - ch_inst); - - umc_v8_10_query_error_address(adev, - err_data, - umc_reg_offset, - node_inst, - ch_inst, - umc_inst); - } + amdgpu_umc_loop_channels(adev, + umc_v8_10_query_error_address, ras_error_status); } -static void umc_v8_10_err_cnt_init_per_channel(struct amdgpu_device *adev, - uint32_t umc_reg_offset) +static int umc_v8_10_err_cnt_init_per_channel(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) { uint32_t ecc_err_cnt_sel, ecc_err_cnt_sel_addr; uint32_t ecc_err_cnt_addr; + uint32_t umc_reg_offset = + get_umc_v8_10_reg_offset(adev, node_inst, umc_inst, ch_inst); ecc_err_cnt_sel_addr = SOC15_REG_OFFSET(UMC, 0, regUMCCH0_0_GeccErrCntSel); @@ -332,23 +313,14 @@ static void umc_v8_10_err_cnt_init_per_channel(struct amdgpu_device *adev, WREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4, ecc_err_cnt_sel); /* set error count to initial value */ WREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4, UMC_V8_10_CE_CNT_INIT); + + return 0; } static void umc_v8_10_err_cnt_init(struct amdgpu_device *adev) { - uint32_t node_inst = 0; - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - uint32_t umc_reg_offset = 0; - - LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) { - umc_reg_offset = get_umc_v8_10_reg_offset(adev, - node_inst, - umc_inst, - ch_inst); - - umc_v8_10_err_cnt_init_per_channel(adev, umc_reg_offset); - } + amdgpu_umc_loop_channels(adev, + umc_v8_10_err_cnt_init_per_channel, NULL); } static bool umc_v8_10_query_ras_poison_mode(struct amdgpu_device *adev) @@ -406,37 +378,35 @@ static void umc_v8_10_ecc_info_query_uncorrectable_error_count(struct amdgpu_dev } } +static int umc_v8_10_ecc_info_query_ecc_error_count(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) +{ + struct ras_err_data *err_data = (struct ras_err_data *)data; + + umc_v8_10_ecc_info_query_correctable_error_count(adev, + node_inst, umc_inst, ch_inst, + &(err_data->ce_count)); + umc_v8_10_ecc_info_query_uncorrectable_error_count(adev, + node_inst, umc_inst, ch_inst, + &(err_data->ue_count)); + return 0; +} + static void umc_v8_10_ecc_info_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - - uint32_t node_inst = 0; - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - - /* TODO: driver needs to toggle DF Cstate to ensure - * safe access of UMC registers. Will add the protection - */ - LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) { - umc_v8_10_ecc_info_query_correctable_error_count(adev, - node_inst, umc_inst, ch_inst, - &(err_data->ce_count)); - umc_v8_10_ecc_info_query_uncorrectable_error_count(adev, - node_inst, umc_inst, ch_inst, - &(err_data->ue_count)); - } + amdgpu_umc_loop_channels(adev, + umc_v8_10_ecc_info_query_ecc_error_count, ras_error_status); } -static void umc_v8_10_ecc_info_query_error_address(struct amdgpu_device *adev, - struct ras_err_data *err_data, - uint32_t ch_inst, - uint32_t umc_inst, - uint32_t node_inst) +static int umc_v8_10_ecc_info_query_error_address(struct amdgpu_device *adev, + uint32_t node_inst, uint32_t umc_inst, + uint32_t ch_inst, void *data) { uint32_t eccinfo_table_idx; uint64_t mc_umc_status, err_addr; - + struct ras_err_data *err_data = (struct ras_err_data *)data; struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); eccinfo_table_idx = node_inst * adev->umc.umc_inst_num * @@ -447,10 +417,10 @@ static void umc_v8_10_ecc_info_query_error_address(struct amdgpu_device *adev, mc_umc_status = ras->umc_ecc.ecc[eccinfo_table_idx].mca_umc_status; if (mc_umc_status == 0) - return; + return 0; if (!err_data->err_addr) - return; + return 0; /* calculate error address if ue error is detected */ if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 && @@ -463,28 +433,15 @@ static void umc_v8_10_ecc_info_query_error_address(struct amdgpu_device *adev, umc_v8_10_convert_error_address(adev, err_data, err_addr, ch_inst, umc_inst, node_inst, mc_umc_status); } + + return 0; } static void umc_v8_10_ecc_info_query_ras_error_address(struct amdgpu_device *adev, void *ras_error_status) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - - uint32_t node_inst = 0; - uint32_t umc_inst = 0; - uint32_t ch_inst = 0; - - /* TODO: driver needs to toggle DF Cstate to ensure - * safe access of UMC resgisters. Will add the protection - * when firmware interface is ready - */ - LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) { - umc_v8_10_ecc_info_query_error_address(adev, - err_data, - ch_inst, - umc_inst, - node_inst); - } + amdgpu_umc_loop_channels(adev, + umc_v8_10_ecc_info_query_error_address, ras_error_status); } const struct amdgpu_ras_block_hw_ops umc_v8_10_ras_hw_ops = { diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index e407be6cb63c..e32b656b3dab 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -444,6 +444,7 @@ static int uvd_v7_0_sw_init(void *handle) continue; if (!amdgpu_sriov_vf(adev)) { ring = &adev->uvd.inst[j].ring; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "uvd_%d", ring->me); r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.inst[j].irq, 0, @@ -454,6 +455,7 @@ static int uvd_v7_0_sw_init(void *handle) for (i = 0; i < adev->uvd.num_enc_rings; ++i) { ring = &adev->uvd.inst[j].ring_enc[i]; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "uvd_enc_%d.%d", ring->me, i); if (amdgpu_sriov_vf(adev)) { ring->use_doorbell = true; @@ -1397,7 +1399,7 @@ static void uvd_v7_0_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, static void uvd_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; uint32_t data0, data1, mask; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -1440,7 +1442,7 @@ static void uvd_v7_0_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, static void uvd_v7_0_enc_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned int vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -1802,7 +1804,6 @@ static const struct amdgpu_ring_funcs uvd_v7_0_ring_vm_funcs = { .align_mask = 0xf, .support_64bit_ptrs = false, .no_user_fence = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = uvd_v7_0_ring_get_rptr, .get_wptr = uvd_v7_0_ring_get_wptr, .set_wptr = uvd_v7_0_ring_set_wptr, @@ -1835,7 +1836,6 @@ static const struct amdgpu_ring_funcs uvd_v7_0_enc_ring_vm_funcs = { .nop = HEVC_ENC_CMD_NO_OP, .support_64bit_ptrs = false, .no_user_fence = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = uvd_v7_0_enc_ring_get_rptr, .get_wptr = uvd_v7_0_enc_ring_get_wptr, .set_wptr = uvd_v7_0_enc_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c index 66cd3d11aa4b..57b85bb6a1e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c @@ -466,6 +466,7 @@ static int vce_v4_0_sw_init(void *handle) enum amdgpu_ring_priority_level hw_prio = amdgpu_vce_get_ring_prio(i); ring = &adev->vce.ring[i]; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "vce%d", i); if (amdgpu_sriov_vf(adev)) { /* DOORBELL only works under SRIOV */ @@ -1021,7 +1022,7 @@ static void vce_v4_0_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, static void vce_v4_0_emit_vm_flush(struct amdgpu_ring *ring, unsigned int vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -1103,7 +1104,6 @@ static const struct amdgpu_ring_funcs vce_v4_0_ring_vm_funcs = { .nop = VCE_CMD_NO_OP, .support_64bit_ptrs = false, .no_user_fence = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vce_v4_0_ring_get_rptr, .get_wptr = vce_v4_0_ring_get_wptr, .set_wptr = vce_v4_0_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_sw_ring.c b/drivers/gpu/drm/amd/amdgpu/vcn_sw_ring.c index 1ceda3d0cd5b..2b9ddb3d2fe1 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_sw_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_sw_ring.c @@ -65,7 +65,7 @@ void vcn_dec_sw_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, void vcn_dec_sw_ring_emit_vm_flush(struct amdgpu_ring *ring, uint32_t vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; uint32_t data0, data1, mask; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index c305b2cb8490..761c28fa6ec1 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -120,6 +120,7 @@ static int vcn_v1_0_sw_init(void *handle) return r; ring = &adev->vcn.inst->ring_dec; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "vcn_dec"); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst->irq, 0, AMDGPU_RING_PRIO_DEFAULT, NULL); @@ -141,6 +142,7 @@ static int vcn_v1_0_sw_init(void *handle) enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i); ring = &adev->vcn.inst->ring_enc[i]; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "vcn_enc%d", i); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst->irq, 0, hw_prio, NULL); @@ -1548,7 +1550,7 @@ static void vcn_v1_0_dec_ring_emit_reg_wait(struct amdgpu_ring *ring, static void vcn_v1_0_dec_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; uint32_t data0, data1, mask; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -1693,7 +1695,7 @@ static void vcn_v1_0_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, static void vcn_v1_0_enc_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned int vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -1977,7 +1979,6 @@ static const struct amdgpu_ring_funcs vcn_v1_0_dec_ring_vm_funcs = { .support_64bit_ptrs = false, .no_user_fence = true, .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v1_0_dec_ring_get_rptr, .get_wptr = vcn_v1_0_dec_ring_get_wptr, .set_wptr = vcn_v1_0_dec_ring_set_wptr, @@ -2012,7 +2013,6 @@ static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = { .nop = VCN_ENC_CMD_NO_OP, .support_64bit_ptrs = false, .no_user_fence = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v1_0_enc_ring_get_rptr, .get_wptr = vcn_v1_0_enc_ring_get_wptr, .set_wptr = vcn_v1_0_enc_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c index 4b4cd88414e0..7c2b3aa48083 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c @@ -129,6 +129,7 @@ static int vcn_v2_0_sw_init(void *handle) ring->use_doorbell = true; ring->doorbell_index = adev->doorbell_index.vcn.vcn_ring0_1 << 1; + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "vcn_dec"); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst->irq, 0, @@ -159,6 +160,7 @@ static int vcn_v2_0_sw_init(void *handle) ring = &adev->vcn.inst->ring_enc[i]; ring->use_doorbell = true; + ring->vm_hub = AMDGPU_MMHUB_0; if (!amdgpu_sriov_vf(adev)) ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + i; else @@ -1511,7 +1513,7 @@ void vcn_v2_0_dec_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, void vcn_v2_0_dec_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; uint32_t data0, data1, mask; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -1671,7 +1673,7 @@ void vcn_v2_0_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, void vcn_v2_0_enc_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned int vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); @@ -2014,7 +2016,6 @@ static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0xf, .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v2_0_dec_ring_get_rptr, .get_wptr = vcn_v2_0_dec_ring_get_wptr, .set_wptr = vcn_v2_0_dec_ring_set_wptr, @@ -2045,7 +2046,6 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v2_0_enc_ring_get_rptr, .get_wptr = vcn_v2_0_enc_ring_get_wptr, .set_wptr = vcn_v2_0_enc_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index 223e7dfe4618..ab0b45d0ead1 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -186,6 +186,12 @@ static int vcn_v2_5_sw_init(void *handle) ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + (amdgpu_sriov_vf(adev) ? 2*j : 8*j); + + if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(2, 5, 0)) + ring->vm_hub = AMDGPU_MMHUB_1; + else + ring->vm_hub = AMDGPU_MMHUB_0; + sprintf(ring->name, "vcn_dec_%d", j); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq, 0, AMDGPU_RING_PRIO_DEFAULT, NULL); @@ -201,6 +207,11 @@ static int vcn_v2_5_sw_init(void *handle) ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i + 8*j)); + if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(2, 5, 0)) + ring->vm_hub = AMDGPU_MMHUB_1; + else + ring->vm_hub = AMDGPU_MMHUB_0; + sprintf(ring->name, "vcn_enc_%d.%d", j, i); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq, 0, @@ -1562,38 +1573,6 @@ static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0xf, .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_1, - .get_rptr = vcn_v2_5_dec_ring_get_rptr, - .get_wptr = vcn_v2_5_dec_ring_get_wptr, - .set_wptr = vcn_v2_5_dec_ring_set_wptr, - .emit_frame_size = - SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + - SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + - 8 + /* vcn_v2_0_dec_ring_emit_vm_flush */ - 14 + 14 + /* vcn_v2_0_dec_ring_emit_fence x2 vm fence */ - 6, - .emit_ib_size = 8, /* vcn_v2_0_dec_ring_emit_ib */ - .emit_ib = vcn_v2_0_dec_ring_emit_ib, - .emit_fence = vcn_v2_0_dec_ring_emit_fence, - .emit_vm_flush = vcn_v2_0_dec_ring_emit_vm_flush, - .test_ring = vcn_v2_0_dec_ring_test_ring, - .test_ib = amdgpu_vcn_dec_ring_test_ib, - .insert_nop = vcn_v2_0_dec_ring_insert_nop, - .insert_start = vcn_v2_0_dec_ring_insert_start, - .insert_end = vcn_v2_0_dec_ring_insert_end, - .pad_ib = amdgpu_ring_generic_pad_ib, - .begin_use = amdgpu_vcn_ring_begin_use, - .end_use = amdgpu_vcn_ring_end_use, - .emit_wreg = vcn_v2_0_dec_ring_emit_wreg, - .emit_reg_wait = vcn_v2_0_dec_ring_emit_reg_wait, - .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, -}; - -static const struct amdgpu_ring_funcs vcn_v2_6_dec_ring_vm_funcs = { - .type = AMDGPU_RING_TYPE_VCN_DEC, - .align_mask = 0xf, - .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v2_5_dec_ring_get_rptr, .get_wptr = vcn_v2_5_dec_ring_get_wptr, .set_wptr = vcn_v2_5_dec_ring_set_wptr, @@ -1693,7 +1672,6 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, - .vmhub = AMDGPU_MMHUB_1, .get_rptr = vcn_v2_5_enc_ring_get_rptr, .get_wptr = vcn_v2_5_enc_ring_get_wptr, .set_wptr = vcn_v2_5_enc_ring_set_wptr, @@ -1719,36 +1697,6 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, }; -static const struct amdgpu_ring_funcs vcn_v2_6_enc_ring_vm_funcs = { - .type = AMDGPU_RING_TYPE_VCN_ENC, - .align_mask = 0x3f, - .nop = VCN_ENC_CMD_NO_OP, - .vmhub = AMDGPU_MMHUB_0, - .get_rptr = vcn_v2_5_enc_ring_get_rptr, - .get_wptr = vcn_v2_5_enc_ring_get_wptr, - .set_wptr = vcn_v2_5_enc_ring_set_wptr, - .emit_frame_size = - SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + - SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 + - 4 + /* vcn_v2_0_enc_ring_emit_vm_flush */ - 5 + 5 + /* vcn_v2_0_enc_ring_emit_fence x2 vm fence */ - 1, /* vcn_v2_0_enc_ring_insert_end */ - .emit_ib_size = 5, /* vcn_v2_0_enc_ring_emit_ib */ - .emit_ib = vcn_v2_0_enc_ring_emit_ib, - .emit_fence = vcn_v2_0_enc_ring_emit_fence, - .emit_vm_flush = vcn_v2_0_enc_ring_emit_vm_flush, - .test_ring = amdgpu_vcn_enc_ring_test_ring, - .test_ib = amdgpu_vcn_enc_ring_test_ib, - .insert_nop = amdgpu_ring_insert_nop, - .insert_end = vcn_v2_0_enc_ring_insert_end, - .pad_ib = amdgpu_ring_generic_pad_ib, - .begin_use = amdgpu_vcn_ring_begin_use, - .end_use = amdgpu_vcn_ring_end_use, - .emit_wreg = vcn_v2_0_enc_ring_emit_wreg, - .emit_reg_wait = vcn_v2_0_enc_ring_emit_reg_wait, - .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, -}; - static void vcn_v2_5_set_dec_ring_funcs(struct amdgpu_device *adev) { int i; @@ -1756,10 +1704,7 @@ static void vcn_v2_5_set_dec_ring_funcs(struct amdgpu_device *adev) for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { if (adev->vcn.harvest_config & (1 << i)) continue; - if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(2, 5, 0)) - adev->vcn.inst[i].ring_dec.funcs = &vcn_v2_5_dec_ring_vm_funcs; - else /* CHIP_ALDEBARAN */ - adev->vcn.inst[i].ring_dec.funcs = &vcn_v2_6_dec_ring_vm_funcs; + adev->vcn.inst[i].ring_dec.funcs = &vcn_v2_5_dec_ring_vm_funcs; adev->vcn.inst[i].ring_dec.me = i; DRM_INFO("VCN(%d) decode is enabled in VM mode\n", i); } @@ -1773,10 +1718,7 @@ static void vcn_v2_5_set_enc_ring_funcs(struct amdgpu_device *adev) if (adev->vcn.harvest_config & (1 << j)) continue; for (i = 0; i < adev->vcn.num_enc_rings; ++i) { - if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(2, 5, 0)) - adev->vcn.inst[j].ring_enc[i].funcs = &vcn_v2_5_enc_ring_vm_funcs; - else /* CHIP_ALDEBARAN */ - adev->vcn.inst[j].ring_enc[i].funcs = &vcn_v2_6_enc_ring_vm_funcs; + adev->vcn.inst[j].ring_enc[i].funcs = &vcn_v2_5_enc_ring_vm_funcs; adev->vcn.inst[j].ring_enc[i].me = j; } DRM_INFO("VCN(%d) encode is enabled in VM mode\n", j); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 66439388faee..3eab186261aa 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -189,6 +189,7 @@ static int vcn_v3_0_sw_init(void *handle) } else { ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 8 * i; } + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "vcn_dec_%d", i); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0, AMDGPU_RING_PRIO_DEFAULT, @@ -212,6 +213,7 @@ static int vcn_v3_0_sw_init(void *handle) } else { ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + j + 8 * i; } + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "vcn_enc_%d.%d", i, j); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0, hw_prio, &adev->vcn.inst[i].sched_score); @@ -1738,7 +1740,6 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { .align_mask = 0x3f, .nop = VCN_DEC_SW_CMD_NO_OP, .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr, .set_wptr = vcn_v3_0_dec_ring_set_wptr, @@ -1899,7 +1900,6 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0xf, .secure_submission_supported = true, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr, .set_wptr = vcn_v3_0_dec_ring_set_wptr, @@ -2000,7 +2000,6 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v3_0_enc_ring_get_rptr, .get_wptr = vcn_v3_0_enc_ring_get_wptr, .set_wptr = vcn_v3_0_enc_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 720ab36f9c92..bf0674039598 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -149,7 +149,7 @@ static int vcn_v4_0_sw_init(void *handle) ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + i * (adev->vcn.num_enc_rings + 1) + 1; else ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + 8 * i; - + ring->vm_hub = AMDGPU_MMHUB_0; sprintf(ring->name, "vcn_unified_%d", i); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0, @@ -1798,7 +1798,6 @@ static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, - .vmhub = AMDGPU_MMHUB_0, .get_rptr = vcn_v4_0_unified_ring_get_rptr, .get_wptr = vcn_v4_0_unified_ring_get_wptr, .set_wptr = vcn_v4_0_unified_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c index 827e2768f867..536128447b71 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c @@ -38,6 +38,11 @@ #define mmIH_CHICKEN_ALDEBARAN 0x18d #define mmIH_CHICKEN_ALDEBARAN_BASE_IDX 0 +#define mmIH_RETRY_INT_CAM_CNTL_ALDEBARAN 0x00ea +#define mmIH_RETRY_INT_CAM_CNTL_ALDEBARAN_BASE_IDX 0 +#define IH_RETRY_INT_CAM_CNTL_ALDEBARAN__ENABLE__SHIFT 0x10 +#define IH_RETRY_INT_CAM_CNTL_ALDEBARAN__ENABLE_MASK 0x00010000L + static void vega20_ih_set_interrupt_funcs(struct amdgpu_device *adev); /** @@ -251,36 +256,14 @@ static int vega20_ih_enable_ring(struct amdgpu_device *adev, return 0; } -/** - * vega20_ih_reroute_ih - reroute VMC/UTCL2 ih to an ih ring - * - * @adev: amdgpu_device pointer - * - * Reroute VMC and UMC interrupts on primary ih ring to - * ih ring 1 so they won't lose when bunches of page faults - * interrupts overwhelms the interrupt handler(VEGA20) - */ -static void vega20_ih_reroute_ih(struct amdgpu_device *adev) +static uint32_t vega20_setup_retry_doorbell(u32 doorbell_index) { - uint32_t tmp; + u32 val = 0; - /* vega20 ih reroute will go through psp this - * function is used for newer asics starting arcturus - */ - if (adev->ip_versions[OSSSYS_HWIP][0] >= IP_VERSION(4, 2, 1)) { - /* Reroute to IH ring 1 for VMC */ - WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x12); - tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA); - tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, CLIENT_TYPE, 1); - tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1); - WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp); - - /* Reroute IH ring 1 for UTCL2 */ - WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x1B); - tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA); - tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1); - WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp); - } + val = REG_SET_FIELD(val, IH_DOORBELL_RPTR, OFFSET, doorbell_index); + val = REG_SET_FIELD(val, IH_DOORBELL_RPTR, ENABLE, 1); + + return val; } /** @@ -333,8 +316,6 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev) for (i = 0; i < ARRAY_SIZE(ih); i++) { if (ih[i]->ring_size) { - if (i == 1) - vega20_ih_reroute_ih(adev); ret = vega20_ih_enable_ring(adev, ih[i]); if (ret) return ret; @@ -347,6 +328,20 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev) pci_set_master(adev->pdev); + /* Allocate the doorbell for IH Retry CAM */ + adev->irq.retry_cam_doorbell_index = (adev->doorbell_index.ih + 3) << 1; + WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RETRY_CAM, + vega20_setup_retry_doorbell(adev->irq.retry_cam_doorbell_index)); + + /* Enable IH Retry CAM */ + if (adev->ip_versions[OSSSYS_HWIP][0] == IP_VERSION(4, 4, 0)) + WREG32_FIELD15(OSSSYS, 0, IH_RETRY_INT_CAM_CNTL_ALDEBARAN, + ENABLE, 1); + else + WREG32_FIELD15(OSSSYS, 0, IH_RETRY_INT_CAM_CNTL, ENABLE, 1); + + adev->irq.retry_cam_enabled = true; + /* enable interrupts */ ret = vega20_ih_toggle_interrupts(adev, true); if (ret) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 81d07ecf666d..1b54a9aaae70 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -93,7 +93,7 @@ int kfd_chardev_init(void) if (err < 0) goto err_register_chrdev; - kfd_class = class_create(THIS_MODULE, kfd_dev_name); + kfd_class = class_create(kfd_dev_name); err = PTR_ERR(kfd_class); if (IS_ERR(kfd_class)) goto err_class_create; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 0bf8d75950f7..00f528eb9812 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -204,6 +204,14 @@ static void kfd_device_info_init(struct kfd_dev *kfd, /* Navi1x+ */ if (gc_version >= IP_VERSION(10, 1, 1)) kfd->device_info.needs_pci_atomics = true; + } else if (gc_version < IP_VERSION(12, 0, 0)) { + /* + * PCIe atomics support acknowledgment in GFX11 RS64 CPFW requires + * MEC version >= 509. Prior RS64 CPFW versions (and all F32) require + * PCIe atomics support. + */ + kfd->device_info.needs_pci_atomics = true; + kfd->device_info.no_atomic_fw_version = kfd->adev->gfx.rs64_enable ? 509 : 0; } } else { kfd->device_info.doorbell_size = 4; @@ -315,10 +323,13 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) break; /* Aldebaran */ case IP_VERSION(9, 4, 2): - case IP_VERSION(9, 4, 3): gfx_target_version = 90010; f2g = &aldebaran_kfd2kgd; break; + case IP_VERSION(9, 4, 3): + gfx_target_version = 90400; + f2g = &aldebaran_kfd2kgd; + break; /* Navi10 */ case IP_VERSION(10, 1, 10): gfx_target_version = 100100; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index 4a9af800b1f1..5aa75f72caa1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -143,6 +143,13 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, 1 << CP_HQD_QUANTUM__QUANTUM_SCALE__SHIFT | 1 << CP_HQD_QUANTUM__QUANTUM_DURATION__SHIFT; + /* + * GFX11 RS64 CPFW version >= 509 supports PCIe atomics support + * acknowledgment. + */ + if (amdgpu_amdkfd_have_atomics_support(mm->dev->adev)) + m->cp_hqd_hq_status0 |= 1 << 29; + if (q->format == KFD_QUEUE_FORMAT_AQL) { m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; @@ -350,6 +357,10 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, m->sdmax_rlcx_doorbell_offset = q->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; + m->sdmax_rlcx_sched_cntl = (amdgpu_sdma_phase_quantum + << SDMA0_QUEUE0_SCHEDULE_CNTL__CONTEXT_QUANTUM__SHIFT) + & SDMA0_QUEUE0_SCHEDULE_CNTL__CONTEXT_QUANTUM_MASK; + m->sdma_engine_id = q->sdma_engine_id; m->sdma_queue_id = q->sdma_queue_id; m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 4dfae19714ab..fdbfd725841f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -224,6 +224,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, struct queue_properties *q, struct mqd_update_info *minfo) { + struct amdgpu_device *adev = (struct amdgpu_device *)mm->dev->adev; struct v9_mqd *m; m = get_mqd(mqd); @@ -269,10 +270,13 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_vmid = q->vmid; if (q->format == KFD_QUEUE_FORMAT_AQL) { - m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__NO_UPDATE_RPTR_MASK | + m->cp_hqd_pq_control |= 2 << CP_HQD_PQ_CONTROL__SLOT_BASED_WPTR__SHIFT | 1 << CP_HQD_PQ_CONTROL__QUEUE_FULL_EN__SHIFT | 1 << CP_HQD_PQ_CONTROL__WPP_CLAMP_EN__SHIFT; + if (adev->ip_versions[GC_HWIP][0] != IP_VERSION(9, 4, 3)) + m->cp_hqd_pq_control |= + CP_HQD_PQ_CONTROL__NO_UPDATE_RPTR_MASK; m->cp_hqd_pq_doorbell_control |= 1 << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_BIF_DROP__SHIFT; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index dc6fd6967050..96a138a39515 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -2172,7 +2172,15 @@ restart: pr_debug("drain retry fault gpu %d svms %p\n", i, svms); amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev, - &pdd->dev->adev->irq.ih1); + pdd->dev->adev->irq.retry_cam_enabled ? + &pdd->dev->adev->irq.ih : + &pdd->dev->adev->irq.ih1); + + if (pdd->dev->adev->irq.retry_cam_enabled) + amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev, + &pdd->dev->adev->irq.ih_soft); + + pr_debug("drain retry fault gpu %d svms 0x%p done\n", i, svms); } if (atomic_cmpxchg(&svms->drain_pagefaults, drain, 0) != drain) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 06b438217c61..2d8e55e29637 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -8,7 +8,7 @@ config DRM_AMD_DC depends on BROKEN || !CC_IS_CLANG || X86_64 || SPARC64 || ARM64 select SND_HDA_COMPONENT if SND_HDA_CORE # !CC_IS_CLANG: https://github.com/ClangBuiltLinux/linux/issues/1752 - select DRM_AMD_DC_FP if (X86 || PPC64 || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG)) + select DRM_AMD_DC_FP if (X86 || (PPC64 && ALTIVEC) || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG)) help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and 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 e29655a26dd4..8b4b186c57f5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1890,7 +1890,8 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) if (adev->dm.dc) dc_deinit_callbacks(adev->dm.dc); - dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv); + if (adev->dm.dc) + dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv); if (dc_enable_dmub_notifications(adev->dm.dc)) { kfree(adev->dm.dmub_notify); @@ -3127,9 +3128,12 @@ void amdgpu_dm_update_connector_after_detect( aconnector->edid); } - aconnector->timing_requested = kzalloc(sizeof(struct dc_crtc_timing), GFP_KERNEL); - if (!aconnector->timing_requested) - dm_error("%s: failed to create aconnector->requested_timing\n", __func__); + if (!aconnector->timing_requested) { + aconnector->timing_requested = + kzalloc(sizeof(struct dc_crtc_timing), GFP_KERNEL); + if (!aconnector->timing_requested) + dm_error("failed to create aconnector->requested_timing\n"); + } drm_connector_update_edid_property(connector, aconnector->edid); amdgpu_dm_update_freesync_caps(connector, aconnector->edid); @@ -4470,10 +4474,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) amdgpu_set_panel_orientation(&aconnector->base); } - /* If we didn't find a panel, notify the acpi video detection */ - if (dm->adev->flags & AMD_IS_APU && dm->num_of_edps == 0) - acpi_video_report_nolcd(); - /* Software is initialized. Now we can register interrupt handlers. */ switch (adev->asic_type) { #if defined(CONFIG_DRM_AMD_DC_SI) @@ -7897,6 +7897,13 @@ static void amdgpu_dm_commit_cursors(struct drm_atomic_state *state) amdgpu_dm_plane_handle_cursor_update(plane, old_plane_state); } +static inline uint32_t get_mem_type(struct drm_framebuffer *fb) +{ + struct amdgpu_bo *abo = gem_to_amdgpu_bo(fb->obj[0]); + + return abo->tbo.resource ? abo->tbo.resource->mem_type : 0; +} + static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct dc_state *dc_state, struct drm_device *dev, @@ -7971,6 +7978,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, continue; dc_plane = dm_new_plane_state->dc_state; + if (!dc_plane) + continue; bundle->surface_updates[planes_count].surface = dc_plane; if (new_pcrtc_state->color_mgmt_changed) { @@ -8037,11 +8046,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, /* * Only allow immediate flips for fast updates that don't - * change FB pitch, DCC state, rotation or mirroing. + * change memory domain, FB pitch, DCC state, rotation or + * mirroring. */ bundle->flip_addrs[planes_count].flip_immediate = crtc->state->async_flip && - acrtc_state->update_type == UPDATE_TYPE_FAST; + acrtc_state->update_type == UPDATE_TYPE_FAST && + get_mem_type(old_plane_state->fb) == get_mem_type(fb); timestamp_ns = ktime_get_ns(); bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); @@ -8553,6 +8564,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + if (!adev->dm.hdcp_workqueue) + continue; + pr_debug("[HDCP_DM] -------------- i : %x ----------\n", i); if (!connector) @@ -8601,6 +8615,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + if (!adev->dm.hdcp_workqueue) + continue; + new_crtc_state = NULL; old_crtc_state = NULL; @@ -9619,8 +9636,9 @@ static int dm_update_plane_state(struct dc *dc, return -EINVAL; } + if (dm_old_plane_state->dc_state) + dc_plane_state_release(dm_old_plane_state->dc_state); - dc_plane_state_release(dm_old_plane_state->dc_state); dm_new_plane_state->dc_state = NULL; *lock_and_validation_needed = true; @@ -10157,6 +10175,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); if (ret) { DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); + ret = -EINVAL; goto fail; } 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 1d924dc51a3e..e3762e806617 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 @@ -169,10 +169,21 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) if (rc) return rc; - irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; + if (amdgpu_in_reset(adev)) { + irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; + /* During gpu-reset we disable and then enable vblank irq, so + * don't use amdgpu_irq_get/put() to avoid refcount change. + */ + if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) + rc = -EBUSY; + } else { + rc = (enable) + ? amdgpu_irq_get(adev, &adev->crtc_irq, acrtc->crtc_id) + : amdgpu_irq_put(adev, &adev->crtc_irq, acrtc->crtc_id); + } - if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) - return -EBUSY; + if (rc) + return rc; skip: if (amdgpu_in_reset(adev)) 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 330ab036c830..c6ce2b7123b7 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 @@ -687,7 +687,6 @@ static void apply_synaptics_fifo_reset_wa(struct drm_dp_aux *aux) return; data[0] |= (1 << 1); // set bit 1 to 1 - return; if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x221198, data)) return; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 994ba426ca66..810ab682f424 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -379,13 +379,17 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) if (aconnector->dc_sink && connector->state) { struct drm_device *dev = connector->dev; struct amdgpu_device *adev = drm_to_adev(dev); - struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; - struct hdcp_workqueue *hdcp_w = &hdcp_work[aconnector->dc_link->link_index]; - connector->state->hdcp_content_type = - hdcp_w->hdcp_content_type[connector->index]; - connector->state->content_protection = - hdcp_w->content_protection[connector->index]; + if (adev->dm.hdcp_workqueue) { + struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; + struct hdcp_workqueue *hdcp_w = + &hdcp_work[aconnector->dc_link->link_index]; + + connector->state->hdcp_content_type = + hdcp_w->hdcp_content_type[connector->index]; + connector->state->content_protection = + hdcp_w->content_protection[connector->index]; + } } if (aconnector->dc_sink) { @@ -1406,6 +1410,7 @@ int pre_validate_dsc(struct drm_atomic_state *state, ret = pre_compute_mst_dsc_configs_for_state(state, local_dc_state, vars); if (ret != 0) { DRM_INFO_ONCE("pre_compute_mst_dsc_configs_for_state() failed\n"); + ret = -EINVAL; goto clean_exit; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index 1743ca0a3641..c42aa947c969 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -89,6 +89,7 @@ void dc_fpu_begin(const char *function_name, const int line) if (*pcpu == 1) { #if defined(CONFIG_X86) + migrate_disable(); kernel_fpu_begin(); #elif defined(CONFIG_PPC64) if (cpu_has_feature(CPU_FTR_VSX_COMP)) { @@ -129,6 +130,7 @@ void dc_fpu_end(const char *function_name, const int line) if (*pcpu <= 0) { #if defined(CONFIG_X86) kernel_fpu_end(); + migrate_enable(); #elif defined(CONFIG_PPC64) if (cpu_has_feature(CPU_FTR_VSX_COMP)) { disable_kernel_vsx(); diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index f0f948501e9a..cce47d3f1a13 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -515,11 +515,8 @@ static enum bp_result get_gpio_i2c_info( info->i2c_slave_address = record->i2c_slave_addr; /* TODO: check how to get register offset for en, Y, etc. */ - info->gpio_info.clk_a_register_index = - le16_to_cpu( - header->gpio_pin[table_index].data_a_reg_index); - info->gpio_info.clk_a_shift = - header->gpio_pin[table_index].gpio_bitshift; + info->gpio_info.clk_a_register_index = le16_to_cpu(pin->data_a_reg_index); + info->gpio_info.clk_a_shift = pin->gpio_bitshift; return BP_RESULT_OK; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index af108f88b112..8d9444db092a 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -399,6 +399,23 @@ static void dcn32_update_clocks_update_dentist( } +static int dcn32_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + uint32_t dispclk_wdivider; + int disp_divider; + + REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider); + disp_divider = dentist_get_divider_from_did(dispclk_wdivider); + + /* Return DISPCLK freq in Khz */ + if (disp_divider) + return (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / disp_divider; + + return 0; +} + + static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool safe_to_lower) @@ -852,6 +869,7 @@ static struct clk_mgr_funcs dcn32_funcs = { .are_clock_states_equal = dcn32_are_clock_states_equal, .enable_pme_wa = dcn32_enable_pme_wa, .is_smu_present = dcn32_is_smu_present, + .get_dispclk_from_dentist = dcn32_get_dispclk_from_dentist, }; void dcn32_clk_mgr_construct( @@ -860,6 +878,8 @@ void dcn32_clk_mgr_construct( struct pp_smu_funcs *pp_smu, struct dccg *dccg) { + struct clk_log_info log_info = {0}; + clk_mgr->base.ctx = ctx; clk_mgr->base.funcs = &dcn32_funcs; if (ASICREV_IS_GC_11_0_2(clk_mgr->base.ctx->asic_id.hw_internal_rev)) { @@ -893,6 +913,7 @@ void dcn32_clk_mgr_construct( clk_mgr->base.clks.ref_dtbclk_khz = 268750; } + /* integer part is now VCO frequency in kHz */ clk_mgr->base.dentist_vco_freq_khz = dcn32_get_vco_frequency_from_reg(clk_mgr); @@ -900,6 +921,8 @@ void dcn32_clk_mgr_construct( if (clk_mgr->base.dentist_vco_freq_khz == 0) clk_mgr->base.dentist_vco_freq_khz = 4300000; /* Updated as per HW docs */ + dcn32_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info); + if (ctx->dc->debug.disable_dtb_ref_clk_switch && clk_mgr->base.clks.ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) { clk_mgr->base.clks.ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c index 41198c729d90..30c0644d4418 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c @@ -622,7 +622,6 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state) int i, j; uint8_t valid_count = 0; uint8_t dig_stream_count = 0; - int matching_stream_ptrs = 0; int eng_ids_per_ep_id[MAX_PIPES] = {0}; int ep_ids_per_eng_id[MAX_PIPES] = {0}; int valid_bitmap = 0; @@ -645,9 +644,7 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state) struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; if (assignment.valid) { - if (assignment.stream == state->streams[i]) - matching_stream_ptrs++; - else + if (assignment.stream != state->streams[i]) valid_stream_ptrs = false; } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 85d54bfb595c..117d80cb36fb 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1707,6 +1707,9 @@ bool dc_remove_plane_from_context( struct dc_stream_status *stream_status = NULL; struct resource_pool *pool = dc->res_pool; + if (!plane_state) + return true; + for (i = 0; i < context->stream_count; i++) if (context->streams[i] == stream) { stream_status = &context->stream_status[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e363a3c88250..30f0ba05a6e6 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -45,7 +45,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.229" +#define DC_VER "3.2.230" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -405,6 +405,7 @@ struct dc_config { bool force_bios_enable_lttpr; uint8_t force_bios_fixed_vs; int sdpif_request_limit_words_per_umc; + bool use_old_fixed_vs_sequence; bool disable_subvp_drr; }; @@ -875,6 +876,9 @@ struct dc_debug_options { bool override_dispclk_programming; bool disable_fpo_optimizations; bool support_eDP1_5; + uint32_t fpo_vactive_margin_us; + bool disable_fpo_vactive; + bool disable_boot_optimizations; }; struct gpu_info_soc_bounding_box_v1_0; @@ -1450,6 +1454,7 @@ struct dc_link { struct ddc_service *ddc; + enum dp_panel_mode panel_mode; bool aux_mode; /* Private to DC core */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index dd6f643254fe..a9b9490a532c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -327,6 +327,7 @@ bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, stru int i = 0, k = 0; int ramp_up_num_steps = 1; // TODO: Ramp is currently disabled. Reenable it. uint8_t visual_confirm_enabled; + int pipe_idx = 0; if (dc == NULL) return false; @@ -339,6 +340,25 @@ bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, stru cmd.fw_assisted_mclk_switch.config_data.fams_enabled = should_manage_pstate; cmd.fw_assisted_mclk_switch.config_data.visual_confirm_enabled = visual_confirm_enabled; + if (should_manage_pstate) { + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (!pipe->stream) + continue; + + /* If FAMS is being used to support P-State and there is a stream + * that does not use FAMS, we are in an FPO + VActive scenario. + * Assign vactive stretch margin in this case. + */ + if (!pipe->stream->fpo_in_use) { + cmd.fw_assisted_mclk_switch.config_data.vactive_stretch_margin_us = dc->debug.fpo_vactive_margin_us; + break; + } + pipe_idx++; + } + } + for (i = 0, k = 0; context && i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 181a3408cc61..25284006019c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -144,7 +144,7 @@ struct test_pattern { unsigned int cust_pattern_size; }; -#define SUBVP_DRR_MARGIN_US 600 // 600us for DRR margin (SubVP + DRR) +#define SUBVP_DRR_MARGIN_US 100 // 100us for DRR margin (SubVP + DRR) enum mall_stream_type { SUBVP_NONE, // subvp not in use diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 9fe0ce91db00..8d2460d06bce 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -3031,10 +3031,12 @@ void dce110_enable_dp_link_output( const struct link_hwss *link_hwss = get_link_hwss(link, link_res); unsigned int i; - + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ if (link->connector_signal == SIGNAL_TYPE_EDP) { - if (!link->dc->config.edp_no_power_sequencing) - link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true); } @@ -3096,11 +3098,12 @@ void dce110_disable_link_output(struct dc_link *link, link_hwss->disable_link_output(link, link_res, signal); link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; - - if (signal == SIGNAL_TYPE_EDP && - link->dc->hwss.edp_backlight_control) - link->dc->hwss.edp_power_control(link, false); - else if (dmcu != NULL && dmcu->funcs->lock_phy) + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (dmcu != NULL && dmcu->funcs->lock_phy) dmcu->funcs->unlock_phy(dmcu); dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index a142a00bc432..bf399819ca80 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -755,8 +755,8 @@ bool hubp1_is_flip_pending(struct hubp *hubp) return false; } -uint32_t aperture_default_system = 1; -uint32_t context0_default_system; /* = 0;*/ +static uint32_t aperture_default_system = 1; +static uint32_t context0_default_system; /* = 0;*/ static void hubp1_set_vm_system_aperture_settings(struct hubp *hubp, struct vm_system_aperture_param *apt) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index 893c0809cd4e..7bdc146f7cb5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -205,6 +205,11 @@ type PHYDSYMCLK_GATE_DISABLE; \ type PHYESYMCLK_GATE_DISABLE; +#define DCCG314_REG_FIELD_LIST(type) \ + type DSCCLK3_DTO_PHASE;\ + type DSCCLK3_DTO_MODULO;\ + type DSCCLK3_DTO_ENABLE; + #define DCCG32_REG_FIELD_LIST(type) \ type DPSTREAMCLK0_EN;\ type DPSTREAMCLK1_EN;\ @@ -237,6 +242,7 @@ struct dccg_shift { DCCG_REG_FIELD_LIST(uint8_t) DCCG3_REG_FIELD_LIST(uint8_t) DCCG31_REG_FIELD_LIST(uint8_t) + DCCG314_REG_FIELD_LIST(uint8_t) DCCG32_REG_FIELD_LIST(uint8_t) }; @@ -244,6 +250,7 @@ struct dccg_mask { DCCG_REG_FIELD_LIST(uint32_t) DCCG3_REG_FIELD_LIST(uint32_t) DCCG31_REG_FIELD_LIST(uint32_t) + DCCG314_REG_FIELD_LIST(uint32_t) DCCG32_REG_FIELD_LIST(uint32_t) }; @@ -273,6 +280,7 @@ struct dccg_registers { uint32_t DSCCLK0_DTO_PARAM; uint32_t DSCCLK1_DTO_PARAM; uint32_t DSCCLK2_DTO_PARAM; + uint32_t DSCCLK3_DTO_PARAM; uint32_t DPSTREAMCLK_ROOT_GATE_DISABLE; uint32_t DPSTREAMCLK_GATE_DISABLE; uint32_t DCCG_GATE_DISABLE_CNTL; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 5403e9399a46..422fbf79da64 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -2113,6 +2113,15 @@ void dcn20_optimize_bandwidth( if (hubbub->funcs->program_compbuf_size) hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true); + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { + dc_dmub_srv_p_state_delegate(dc, + true, context); + context->bw_ctx.bw.dcn.clk.p_state_change_support = true; + dc->clk_mgr->clks.fw_based_mclk_switching = true; + } else { + dc->clk_mgr->clks.fw_based_mclk_switching = false; + } + dc->clk_mgr->funcs->update_clocks( dc->clk_mgr, context, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index 0e071fbc9154..8263a07f265f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -983,13 +983,36 @@ void dcn30_set_disp_pattern_generator(const struct dc *dc, } void dcn30_prepare_bandwidth(struct dc *dc, - struct dc_state *context) + struct dc_state *context) { + bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support; + /* Any transition into an FPO config should disable MCLK switching first to avoid + * driver and FW P-State synchronization issues. + */ + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) { + dc->optimized_required = true; + context->bw_ctx.bw.dcn.clk.p_state_change_support = false; + } + if (dc->clk_mgr->dc_mode_softmax_enabled) if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz); dcn20_prepare_bandwidth(dc, context); + /* + * enabled -> enabled: do not disable + * enabled -> disabled: disable + * disabled -> enabled: don't care + * disabled -> disabled: don't care + */ + if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) + dc_dmub_srv_p_state_delegate(dc, false, context); + + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) { + /* After disabling P-State, restore the original value to ensure we get the correct P-State + * on the next optimize. */ + context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support; + } } diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 965f5ceb33f7..67a34cda3774 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -701,7 +701,9 @@ static const struct dc_plane_cap plane_cap = { .argb8888 = 167, .nv12 = 167, .fp16 = 167 - } + }, + 16, + 16 }; static const struct dc_debug_options debug_defaults_drv = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c index 7d2b982506fd..4c2fdfea162f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c @@ -360,6 +360,15 @@ void dccg31_disable_dscclk(struct dccg *dccg, int inst) DSCCLK2_DTO_PHASE, 0, DSCCLK2_DTO_MODULO, 1); break; + case 3: + if (REG(DSCCLK3_DTO_PARAM)) { + REG_UPDATE(DSCCLK_DTO_CTRL, + DSCCLK3_DTO_ENABLE, 1); + REG_UPDATE_2(DSCCLK3_DTO_PARAM, + DSCCLK3_DTO_PHASE, 0, + DSCCLK3_DTO_MODULO, 1); + } + break; default: BREAK_TO_DEBUGGER(); return; @@ -395,6 +404,15 @@ void dccg31_enable_dscclk(struct dccg *dccg, int inst) REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_DTO_ENABLE, 0); break; + case 3: + if (REG(DSCCLK3_DTO_PARAM)) { + REG_UPDATE(DSCCLK_DTO_CTRL, + DSCCLK3_DTO_ENABLE, 0); + REG_UPDATE_2(DSCCLK3_DTO_PARAM, + DSCCLK3_DTO_PHASE, 0, + DSCCLK3_DTO_MODULO, 0); + } + break; default: BREAK_TO_DEBUGGER(); return; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 7ac6e69cff37..62ce36c75c4d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -295,6 +295,10 @@ void dcn31_init_hw(struct dc *dc) if (dc->res_pool->hubbub->funcs->init_crb) dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); #endif + + // Get DMCUB capabilities + dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub); + dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; } void dcn31_dsc_pg_control( diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index eaaa2e01f6d0..ff8cd5076434 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -1965,6 +1965,8 @@ static bool dcn31_resource_construct( dc->caps.color.mpc.ogam_rom_caps.hlg = 0; dc->caps.color.mpc.ocsc = 1; + dc->config.use_old_fixed_vs_sequence = true; + /* Use pipe context based otg sync logic */ dc->config.use_pipe_ctx_sync_logic = true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c index 081ce168f621..de7bfba2c179 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c @@ -274,6 +274,32 @@ static void dccg314_set_dpstreamclk( } } +static void dccg314_init(struct dccg *dccg) +{ + int otg_inst; + + /* Set HPO stream encoder to use refclk to avoid case where PHY is + * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which + * will cause DCN to hang. + */ + for (otg_inst = 0; otg_inst < 4; otg_inst++) + dccg31_disable_symclk32_se(dccg, otg_inst); + + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) + for (otg_inst = 0; otg_inst < 2; otg_inst++) + dccg31_disable_symclk32_le(dccg, otg_inst); + + if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) + for (otg_inst = 0; otg_inst < 4; otg_inst++) + dccg314_set_dpstreamclk(dccg, REFCLK, otg_inst, + otg_inst); + + if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk) + for (otg_inst = 0; otg_inst < 5; otg_inst++) + dccg31_set_physymclk(dccg, otg_inst, + PHYSYMCLK_FORCE_SRC_SYMCLK, false); +} + static void dccg314_set_valid_pixel_rate( struct dccg *dccg, int ref_dtbclk_khz, @@ -315,7 +341,7 @@ static const struct dccg_funcs dccg314_funcs = { .update_dpp_dto = dccg31_update_dpp_dto, .dpp_root_clock_control = dccg314_dpp_root_clock_control, .get_dccg_ref_freq = dccg31_get_dccg_ref_freq, - .dccg_init = dccg31_init, + .dccg_init = dccg314_init, .set_dpstreamclk = dccg314_set_dpstreamclk, .enable_symclk32_se = dccg31_enable_symclk32_se, .disable_symclk32_se = dccg31_disable_symclk32_se, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.h index 6a35986307af..90687a9e8fdd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.h @@ -68,6 +68,7 @@ SR(DSCCLK0_DTO_PARAM),\ SR(DSCCLK1_DTO_PARAM),\ SR(DSCCLK2_DTO_PARAM),\ + SR(DSCCLK3_DTO_PARAM),\ SR(DSCCLK_DTO_CTRL),\ SR(DCCG_GATE_DISABLE_CNTL2),\ SR(DCCG_GATE_DISABLE_CNTL3),\ @@ -149,12 +150,20 @@ DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_MODULO, mask_sh),\ DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, mask_sh),\ DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_MODULO, mask_sh),\ + DCCG_SF(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, mask_sh),\ + DCCG_SF(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_MODULO, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE1_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE1_GATE_DISABLE, mask_sh),\ DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_PHASE, mask_sh),\ DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_MODULO, mask_sh) @@ -178,6 +187,7 @@ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_DTO_ENABLE, mask_sh),\ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_DTO_ENABLE, mask_sh),\ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_DTO_ENABLE, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_DTO_ENABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_GATE_DISABLE, mask_sh),\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c index 40c488b26901..cc3fe9cac5b5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c @@ -423,3 +423,68 @@ void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool PERF_TRACE(); } +static void apply_symclk_on_tx_off_wa(struct dc_link *link) +{ + /* There are use cases where SYMCLK is referenced by OTG. For instance + * for TMDS signal, OTG relies SYMCLK even if TX video output is off. + * However current link interface will power off PHY when disabling link + * output. This will turn off SYMCLK generated by PHY. The workaround is + * to identify such case where SYMCLK is still in use by OTG when we + * power off PHY. When this is detected, we will temporarily power PHY + * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling + * program_pix_clk interface. When OTG is disabled, we will then power + * off PHY by calling disable link output again. + * + * In future dcn generations, we plan to rework transmitter control + * interface so that we could have an option to set SYMCLK ON TX OFF + * state in one step without this workaround + */ + + struct dc *dc = link->ctx->dc; + struct pipe_ctx *pipe_ctx = NULL; + uint8_t i; + + if (link->phy_state.symclk_ref_cnts.otg > 0) { + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { + pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dc->link_srv->dp_get_encoding_format( + &pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings); + link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + break; + } + } + } +} + +void dcn314_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->unlock_phy(dmcu); + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); + + apply_symclk_on_tx_off_wa(link); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h index c786d5e6a428..6d0b62503caa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h @@ -45,4 +45,6 @@ void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on); +void dcn314_disable_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); + #endif /* __DC_HWSS_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c index 5267e901a35c..a588f46b166f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c @@ -105,7 +105,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = { .enable_lvds_link_output = dce110_enable_lvds_link_output, .enable_tmds_link_output = dce110_enable_tmds_link_output, .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, + .disable_link_output = dcn314_disable_link_output, .z10_restore = dcn31_z10_restore, .z10_save_init = dcn31_z10_save_init, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 50ed7e09d5ba..abeeede38fb3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -885,7 +885,7 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = false, .enable_z9_disable_interface = true, - .minimum_z8_residency_time = 3080, + .minimum_z8_residency_time = 2000, .psr_skip_crtc_disable = true, .disable_dmcu = true, .force_abm_enable = false, @@ -1696,6 +1696,23 @@ static void dcn314_get_panel_config_defaults(struct dc_panel_config *panel_confi *panel_config = panel_config_defaults; } +static bool filter_modes_for_single_channel_workaround(struct dc *dc, + struct dc_state *context) +{ + // Filter 2K@240Hz+8K@24fps above combination timing if memory only has single dimm LPDDR + if (dc->clk_mgr->bw_params->vram_type == 34 && dc->clk_mgr->bw_params->num_channels < 2) { + int total_phy_pix_clk = 0; + + for (int i = 0; i < context->stream_count; i++) + if (context->res_ctx.pipe_ctx[i].stream) + total_phy_pix_clk += context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; + + if (total_phy_pix_clk >= (1148928+826260)) //2K@240Hz+8K@24fps + return true; + } + return false; +} + bool dcn314_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate) @@ -1711,6 +1728,9 @@ bool dcn314_validate_bandwidth(struct dc *dc, BW_VAL_TRACE_COUNT(); + if (filter_modes_for_single_channel_workaround(dc, context)) + goto validate_fail; + DC_FP_START(); // do not support self refresh only out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate, false); diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index b3824287c224..1f5ee5cde6e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -721,10 +721,19 @@ static void dcn32_initialize_min_clocks(struct dc *dc) clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000; clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000; clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000; - clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000; - clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; - clocks->fclk_p_state_change_support = true; - clocks->p_state_change_support = true; + if (dc->debug.disable_boot_optimizations) { + clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000; + } else { + /* Even though DPG_EN = 1 for the connected display, it still requires the + * correct timing so we cannot set DISPCLK to min freq or it could cause + * audio corruption. Read current DISPCLK from DENTIST and request the same + * freq to ensure that the timing is valid and unchanged. + */ + clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr); + clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; + clocks->fclk_p_state_change_support = true; + clocks->p_state_change_support = true; + } dc->clk_mgr->funcs->update_clocks( dc->clk_mgr, @@ -823,7 +832,14 @@ void dcn32_init_hw(struct dc *dc) * everything down. */ if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { - hws->funcs.init_pipes(dc, dc->current_state); + /* Disable boot optimizations means power down everything including PHY, DIG, + * and OTG (i.e. the boot is not optimized because we do a full power down). + */ + if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations) + dc->hwss.enable_accelerated_mode(dc, dc->current_state); + else + hws->funcs.init_pipes(dc, dc->current_state); + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); @@ -932,6 +948,7 @@ void dcn32_init_hw(struct dc *dc) if (dc->ctx->dmub_srv) { dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub); dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; + dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; } } diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index 502f990346b1..22dd1ebea618 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -324,7 +324,6 @@ static const struct dcn10_link_enc_shift le_shift = { static const struct dcn10_link_enc_mask le_mask = { LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ - //DPCS_DCN31_MASK_SH_LIST(_MASK) }; @@ -726,6 +725,9 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_unbounded_requesting = false, .override_dispclk_programming = true, .disable_fpo_optimizations = false, + .fpo_vactive_margin_us = 2000, // 2000us + .disable_fpo_vactive = true, + .disable_boot_optimizations = false, }; static const struct dc_debug_options debug_defaults_diags = { @@ -2021,7 +2023,7 @@ int dcn32_populate_dml_pipes_from_context( // In general cases we want to keep the dram clock change requirement // (prefer configs that support MCLK switch). Only override to false // for SubVP - if (subvp_in_use) + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || subvp_in_use) context->bw_ctx.dml.soc.dram_clock_change_requirement_final = false; else context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true; @@ -2077,6 +2079,14 @@ static struct resource_funcs dcn32_res_pool_funcs = { .restore_mall_state = dcn32_restore_mall_state, }; +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* DCN32 support max 4 pipes */ + value = value & 0xf; + return value; +} + static bool dcn32_resource_construct( uint8_t num_virtual_links, @@ -2090,27 +2100,28 @@ static bool dcn32_resource_construct( uint32_t pipe_fuses = 0; uint32_t num_pipes = 4; - #undef REG_STRUCT - #define REG_STRUCT bios_regs - bios_regs_init(); - - #undef REG_STRUCT - #define REG_STRUCT clk_src_regs - clk_src_regs_init(0, A), - clk_src_regs_init(1, B), - clk_src_regs_init(2, C), - clk_src_regs_init(3, D), - clk_src_regs_init(4, E); - #undef REG_STRUCT - #define REG_STRUCT abm_regs - abm_regs_init(0), - abm_regs_init(1), - abm_regs_init(2), - abm_regs_init(3); - - #undef REG_STRUCT - #define REG_STRUCT dccg_regs - dccg_regs_init(); +#undef REG_STRUCT +#define REG_STRUCT bios_regs + bios_regs_init(); + +#undef REG_STRUCT +#define REG_STRUCT clk_src_regs + clk_src_regs_init(0, A), + clk_src_regs_init(1, B), + clk_src_regs_init(2, C), + clk_src_regs_init(3, D), + clk_src_regs_init(4, E); + +#undef REG_STRUCT +#define REG_STRUCT abm_regs + abm_regs_init(0), + abm_regs_init(1), + abm_regs_init(2), + abm_regs_init(3); + +#undef REG_STRUCT +#define REG_STRUCT dccg_regs + dccg_regs_init(); DC_FP_START(); @@ -2119,7 +2130,7 @@ static bool dcn32_resource_construct( pool->base.res_cap = &res_cap_dcn32; /* max number of pipes for ASIC before checking for pipe fuses */ num_pipes = pool->base.res_cap->num_timing_generator; - pipe_fuses = REG_READ(CC_DC_PIPE_DIS); + pipe_fuses = read_pipe_fuses(ctx); for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) if (pipe_fuses & 1 << i) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h index 10a3350376e4..3937dbc1e552 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h @@ -39,6 +39,7 @@ #define DCN3_2_MBLK_HEIGHT_8BPE 64 #define DCN3_2_VMIN_DISPCLK_HZ 717000000 #define DCN3_2_DCFCLK_DS_INIT_KHZ 10000 // Choose 10Mhz for init DCFCLK DS freq +#define DCN3_2_MIN_ACTIVE_SWITCH_MARGIN_FPO_US 100 // Only allow FPO + Vactive if active margin >= 100 #define TO_DCN32_RES_POOL(pool)\ container_of(pool, struct dcn32_resource_pool, base) @@ -146,6 +147,8 @@ void dcn32_restore_mall_state(struct dc *dc, struct dc_state *context, struct mall_temp_config *temp_config); +struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, const struct dc_state *context); + bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe); unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans); @@ -472,6 +475,7 @@ double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *conte SRI_ARR(OTG_H_BLANK, DSCL, id), SRI_ARR(OTG_V_BLANK, DSCL, id), \ SRI_ARR(SCL_MODE, DSCL, id), SRI_ARR(LB_DATA_FORMAT, DSCL, id), \ SRI_ARR(LB_MEMORY_CTRL, DSCL, id), SRI_ARR(DSCL_AUTOCAL, DSCL, id), \ + SRI_ARR(DSCL_CONTROL, DSCL, id), \ SRI_ARR(SCL_TAP_CONTROL, DSCL, id), \ SRI_ARR(SCL_COEF_RAM_TAP_SELECT, DSCL, id), \ SRI_ARR(SCL_COEF_RAM_TAP_DATA, DSCL, id), \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index 47fa51c1d3f4..eeca16faf31a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -27,6 +27,7 @@ #include "dcn32_resource.h" #include "dcn20/dcn20_resource.h" #include "dml/dcn32/display_mode_vba_util_32.h" +#include "dml/dcn32/dcn32_fpu.h" static bool is_dual_plane(enum surface_pixel_format format) { @@ -500,3 +501,158 @@ void dcn32_restore_mall_state(struct dc *dc, pipe->plane_state->is_phantom = temp_config->is_phantom_plane[i]; } } + +#define MAX_STRETCHED_V_BLANK 1000 // in micro-seconds (must ensure to match value in FW) +/* + * Scaling factor for v_blank stretch calculations considering timing in + * micro-seconds and pixel clock in 100hz. + * Note: the parenthesis are necessary to ensure the correct order of + * operation where V_SCALE is used. + */ +#define V_SCALE (10000 / MAX_STRETCHED_V_BLANK) + +static int get_frame_rate_at_max_stretch_100hz( + struct dc_stream_state *fpo_candidate_stream, + uint32_t fpo_vactive_margin_us) +{ + struct dc_crtc_timing *timing = NULL; + uint32_t sec_per_100_lines; + uint32_t max_v_blank; + uint32_t curr_v_blank; + uint32_t v_stretch_max; + uint32_t stretched_frame_pix_cnt; + uint32_t scaled_stretched_frame_pix_cnt; + uint32_t scaled_refresh_rate; + uint32_t v_scale; + + if (fpo_candidate_stream == NULL) + return 0; + + /* check if refresh rate at least 120hz */ + timing = &fpo_candidate_stream->timing; + if (timing == NULL) + return 0; + + v_scale = 10000 / (MAX_STRETCHED_V_BLANK + fpo_vactive_margin_us); + + sec_per_100_lines = timing->pix_clk_100hz / timing->h_total + 1; + max_v_blank = sec_per_100_lines / v_scale + 1; + curr_v_blank = timing->v_total - timing->v_addressable; + v_stretch_max = (max_v_blank > curr_v_blank) ? (max_v_blank - curr_v_blank) : (0); + stretched_frame_pix_cnt = (v_stretch_max + timing->v_total) * timing->h_total; + scaled_stretched_frame_pix_cnt = stretched_frame_pix_cnt / 10000; + scaled_refresh_rate = (timing->pix_clk_100hz) / scaled_stretched_frame_pix_cnt + 1; + + return scaled_refresh_rate; + +} + +static bool is_refresh_rate_support_mclk_switch_using_fw_based_vblank_stretch( + struct dc_stream_state *fpo_candidate_stream, uint32_t fpo_vactive_margin_us) +{ + int refresh_rate_max_stretch_100hz; + int min_refresh_100hz; + + if (fpo_candidate_stream == NULL) + return false; + + refresh_rate_max_stretch_100hz = get_frame_rate_at_max_stretch_100hz(fpo_candidate_stream, fpo_vactive_margin_us); + min_refresh_100hz = fpo_candidate_stream->timing.min_refresh_in_uhz / 10000; + + if (refresh_rate_max_stretch_100hz < min_refresh_100hz) + return false; + + return true; +} + +static int get_refresh_rate(struct dc_stream_state *fpo_candidate_stream) +{ + int refresh_rate = 0; + int h_v_total = 0; + struct dc_crtc_timing *timing = NULL; + + if (fpo_candidate_stream == NULL) + return 0; + + /* check if refresh rate at least 120hz */ + timing = &fpo_candidate_stream->timing; + if (timing == NULL) + return 0; + + h_v_total = timing->h_total * timing->v_total; + if (h_v_total == 0) + return 0; + + refresh_rate = ((timing->pix_clk_100hz * 100) / (h_v_total)) + 1; + return refresh_rate; +} + +/** + * dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch - Determines if config can support FPO + * + * @param [in]: dc - current dc state + * @param [in]: context - new dc state + * + * Return: Pointer to FPO stream candidate if config can support FPO, otherwise NULL + */ +struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, const struct dc_state *context) +{ + int refresh_rate = 0; + const int minimum_refreshrate_supported = 120; + struct dc_stream_state *fpo_candidate_stream = NULL; + bool is_fpo_vactive = false; + uint32_t fpo_vactive_margin_us = 0; + + if (context == NULL) + return NULL; + + if (dc->debug.disable_fams) + return NULL; + + if (!dc->caps.dmub_caps.mclk_sw) + return NULL; + + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching_shut_down) + return NULL; + + /* For FPO we can support up to 2 display configs if: + * - first display uses FPO + * - Second display switches in VACTIVE */ + if (context->stream_count > 2) + return NULL; + else if (context->stream_count == 2) { + DC_FP_START(); + dcn32_assign_fpo_vactive_candidate(dc, context, &fpo_candidate_stream); + DC_FP_END(); + + DC_FP_START(); + is_fpo_vactive = dcn32_find_vactive_pipe(dc, context, DCN3_2_MIN_ACTIVE_SWITCH_MARGIN_FPO_US); + DC_FP_END(); + if (!is_fpo_vactive || dc->debug.disable_fpo_vactive) + return NULL; + } else + fpo_candidate_stream = context->streams[0]; + + if (!fpo_candidate_stream) + return NULL; + + if (fpo_candidate_stream->sink->edid_caps.panel_patch.disable_fams) + return NULL; + + refresh_rate = get_refresh_rate(fpo_candidate_stream); + if (refresh_rate < minimum_refreshrate_supported) + return NULL; + + fpo_vactive_margin_us = is_fpo_vactive ? dc->debug.fpo_vactive_margin_us : 0; // For now hardcode the FPO + Vactive stretch margin to be 2000us + if (!is_refresh_rate_support_mclk_switch_using_fw_based_vblank_stretch(fpo_candidate_stream, fpo_vactive_margin_us)) + return NULL; + + // check if freesync enabled + if (!fpo_candidate_stream->allow_freesync) + return NULL; + + if (fpo_candidate_stream->vrr_active_variable) + return NULL; + + return fpo_candidate_stream; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c index 79664ba7e7af..a60ddb343d13 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -724,6 +724,9 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_unbounded_requesting = false, .override_dispclk_programming = true, .disable_fpo_optimizations = false, + .fpo_vactive_margin_us = 2000, // 2000us + .disable_fpo_vactive = true, + .disable_boot_optimizations = false, }; static const struct dc_debug_options debug_defaults_diags = { @@ -1629,6 +1632,14 @@ static struct resource_funcs dcn321_res_pool_funcs = { .restore_mall_state = dcn32_restore_mall_state, }; +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* DCN321 support max 4 pipes */ + value = value & 0xf; + return value; +} + static bool dcn321_resource_construct( uint8_t num_virtual_links, @@ -1671,7 +1682,7 @@ static bool dcn321_resource_construct( pool->base.res_cap = &res_cap_dcn321; /* max number of pipes for ASIC before checking for pipe fuses */ num_pipes = pool->base.res_cap->num_timing_generator; - pipe_fuses = REG_READ(CC_DC_PIPE_DIS); + pipe_fuses = read_pipe_fuses(ctx); for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) if (pipe_fuses & 1 << i) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index 38d1f2be8cf3..f1c1a4b5fcac 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -917,19 +917,19 @@ void dcn20_populate_dml_writeback_from_context(struct dc *dc, } void dcn20_fpu_set_wb_arb_params(struct mcif_arb_params *wb_arb_params, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, int i) + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, int i) { - int k; + int k; - dc_assert_fp_enabled(); + dc_assert_fp_enabled(); - for (k = 0; k < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); k++) { - wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; - wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; - } - wb_arb_params->time_per_pixel = 16.0 * 1000 / (context->res_ctx.pipe_ctx[i].stream->phy_pix_clk / 1000); /* 4 bit fraction, ms */ + for (k = 0; k < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); k++) { + wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + } + wb_arb_params->time_per_pixel = 16.0 * 1000 / (context->res_ctx.pipe_ctx[i].stream->phy_pix_clk / 1000); /* 4 bit fraction, ms */ } static bool is_dtbclk_required(struct dc *dc, struct dc_state *context) @@ -1037,11 +1037,11 @@ static void dcn20_adjust_freesync_v_startup( *vstartup_start = ((newVstartup > *vstartup_start) ? newVstartup : *vstartup_start); } -void dcn20_calculate_dlg_params( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel) +void dcn20_calculate_dlg_params(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) { int i, pipe_idx; @@ -1083,6 +1083,7 @@ void dcn20_calculate_dlg_params( pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); + if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { // Phantom pipe requires that DET_SIZE = 0 and no unbounded requests context->res_ctx.pipe_ctx[i].det_buffer_size_kb = 0; @@ -1091,6 +1092,7 @@ void dcn20_calculate_dlg_params( context->res_ctx.pipe_ctx[i].det_buffer_size_kb = context->bw_ctx.dml.ip.det_buffer_size_kbytes; context->res_ctx.pipe_ctx[i].unbounded_req = pipes[pipe_idx].pipe.src.unbounded_req_mode; } + if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000; context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = @@ -1118,6 +1120,7 @@ void dcn20_calculate_dlg_params( if (!context->res_ctx.pipe_ctx[i].stream) continue; + /* cstate disabled on 201 */ if (dc->ctx->dce_version == DCN_VERSION_2_01) cstate_en = false; @@ -1201,11 +1204,10 @@ static void swizzle_to_dml_params( } } -int dcn20_populate_dml_pipes_from_context( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) +int dcn20_populate_dml_pipes_from_context(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) { int pipe_cnt, i; bool synchronized_vblank = true; @@ -1257,6 +1259,8 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0; + pipes[pipe_cnt].pipe.dest.use_maximum_vstartup = dc->ctx->dce_version == DCN_VERSION_2_01; + pipes[pipe_cnt].dout.dsc_enable = res_ctx->pipe_ctx[i].stream->timing.flags.DSC; /* todo: rotation?*/ pipes[pipe_cnt].dout.dsc_slices = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.num_slices_h; @@ -1296,8 +1300,7 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.dest.pixel_rate_mhz *= 2; pipes[pipe_cnt].pipe.dest.otg_inst = res_ctx->pipe_ctx[i].stream_res.tg->inst; pipes[pipe_cnt].dout.dp_lanes = 4; - if (res_ctx->pipe_ctx[i].stream->link) - pipes[pipe_cnt].dout.dp_rate = dm_dp_rate_na; + pipes[pipe_cnt].dout.dp_rate = dm_dp_rate_na; pipes[pipe_cnt].dout.is_virtual = 0; pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min; pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max; @@ -1357,7 +1360,6 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].dout.is_virtual = 1; pipes[pipe_cnt].dout.output_type = dm_dp; pipes[pipe_cnt].dout.dp_lanes = 4; - pipes[pipe_cnt].dout.dp_rate = dm_dp_rate_hbr2; } switch (res_ctx->pipe_ctx[i].stream->timing.display_color_depth) { @@ -1507,6 +1509,7 @@ int dcn20_populate_dml_pipes_from_context( default: break; } + pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport.y; pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c.y; pipes[pipe_cnt].pipe.src.viewport_x_y = scl->viewport.x; @@ -1615,13 +1618,12 @@ int dcn20_populate_dml_pipes_from_context( return pipe_cnt; } -void dcn20_calculate_wm( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int *out_pipe_cnt, - int *pipe_split_from, - int vlevel, - bool fast_validate) +void dcn20_calculate_wm(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *out_pipe_cnt, + int *pipe_split_from, + int vlevel, + bool fast_validate) { int pipe_cnt, i, pipe_idx; @@ -1733,8 +1735,11 @@ void dcn20_calculate_wm( context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; } -void dcn20_update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb, - struct pp_smu_nv_clock_table *max_clocks, unsigned int *uclk_states, unsigned int num_states) +void dcn20_update_bounding_box(struct dc *dc, + struct _vcs_dpi_soc_bounding_box_st *bb, + struct pp_smu_nv_clock_table *max_clocks, + unsigned int *uclk_states, + unsigned int num_states) { int num_calculated_states = 0; int min_dcfclk = 0; @@ -1796,9 +1801,8 @@ void dcn20_update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_s bb->clock_limits[num_calculated_states].state = bb->num_states; } -void dcn20_cap_soc_clocks( - struct _vcs_dpi_soc_bounding_box_st *bb, - struct pp_smu_nv_clock_table max_clocks) +void dcn20_cap_soc_clocks(struct _vcs_dpi_soc_bounding_box_st *bb, + struct pp_smu_nv_clock_table max_clocks) { int i; @@ -1954,80 +1958,80 @@ validate_out: } bool dcn20_validate_bandwidth_fp(struct dc *dc, - struct dc_state *context, - bool fast_validate) + struct dc_state *context, + bool fast_validate) { - bool voltage_supported = false; - bool full_pstate_supported = false; - bool dummy_pstate_supported = false; - double p_state_latency_us; + bool voltage_supported = false; + bool full_pstate_supported = false; + bool dummy_pstate_supported = false; + double p_state_latency_us; - dc_assert_fp_enabled(); + dc_assert_fp_enabled(); - p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us; - context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support = - dc->debug.disable_dram_clock_change_vactive_support; - context->bw_ctx.dml.soc.allow_dram_clock_one_display_vactive = - dc->debug.enable_dram_clock_change_one_display_vactive; + p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us; + context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support = + dc->debug.disable_dram_clock_change_vactive_support; + context->bw_ctx.dml.soc.allow_dram_clock_one_display_vactive = + dc->debug.enable_dram_clock_change_one_display_vactive; - /*Unsafe due to current pipe merge and split logic*/ - ASSERT(context != dc->current_state); + /*Unsafe due to current pipe merge and split logic*/ + ASSERT(context != dc->current_state); - if (fast_validate) { - return dcn20_validate_bandwidth_internal(dc, context, true); - } + if (fast_validate) { + return dcn20_validate_bandwidth_internal(dc, context, true); + } - // Best case, we support full UCLK switch latency - voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); - full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + // Best case, we support full UCLK switch latency + voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); + full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; - if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 || - (voltage_supported && full_pstate_supported)) { - context->bw_ctx.bw.dcn.clk.p_state_change_support = full_pstate_supported; - goto restore_dml_state; - } + if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 || + (voltage_supported && full_pstate_supported)) { + context->bw_ctx.bw.dcn.clk.p_state_change_support = full_pstate_supported; + goto restore_dml_state; + } - // Fallback: Try to only support G6 temperature read latency - context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us; + // Fallback: Try to only support G6 temperature read latency + context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us; - voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); - dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); + dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; - if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) { - context->bw_ctx.bw.dcn.clk.p_state_change_support = false; - goto restore_dml_state; - } + if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) { + context->bw_ctx.bw.dcn.clk.p_state_change_support = false; + goto restore_dml_state; + } - // ERROR: fallback is supposed to always work. - ASSERT(false); + // ERROR: fallback is supposed to always work. + ASSERT(false); restore_dml_state: - context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us; - return voltage_supported; + context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us; + return voltage_supported; } void dcn20_fpu_set_wm_ranges(int i, - struct pp_smu_wm_range_sets *ranges, - struct _vcs_dpi_soc_bounding_box_st *loaded_bb) + struct pp_smu_wm_range_sets *ranges, + struct _vcs_dpi_soc_bounding_box_st *loaded_bb) { - dc_assert_fp_enabled(); + dc_assert_fp_enabled(); - ranges->reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; - ranges->reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; + ranges->reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; + ranges->reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; } void dcn20_fpu_adjust_dppclk(struct vba_vars_st *v, - int vlevel, - int max_mpc_comb, - int pipe_idx, - bool is_validating_bw) + int vlevel, + int max_mpc_comb, + int pipe_idx, + bool is_validating_bw) { - dc_assert_fp_enabled(); + dc_assert_fp_enabled(); - if (is_validating_bw) - v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] *= 2; - else - v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] /= 2; + if (is_validating_bw) + v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] *= 2; + else + v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] /= 2; } int dcn21_populate_dml_pipes_from_context(struct dc *dc, @@ -2329,7 +2333,7 @@ void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params k++; } - memcpy(dcn2_1_soc.clock_limits, s, sizeof(dcn2_1_soc.clock_limits)); + memcpy(&dcn2_1_soc.clock_limits, s, sizeof(dcn2_1_soc.clock_limits)); if (clk_table->num_entries) { dcn2_1_soc.num_states = clk_table->num_entries + 1; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c index 80972ee5e55b..a352c703e258 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c @@ -368,7 +368,9 @@ void dcn30_fpu_update_soc_for_wm_a(struct dc *dc, struct dc_state *context) dc_assert_fp_enabled(); if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].valid) { - context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; + if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || + context->bw_ctx.dml.soc.dram_clock_change_latency_us == 0) + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us; context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us; } @@ -563,6 +565,20 @@ void dcn30_fpu_calculate_wm_and_dlg( pipe_idx++; } + // WA: restrict FPO to use first non-strobe mode (NV24 BW issue) + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && + dc->dml.soc.num_chans <= 4 && + context->bw_ctx.dml.vba.DRAMSpeed <= 1700 && + context->bw_ctx.dml.vba.DRAMSpeed >= 1500) { + + for (i = 0; i < dc->dml.soc.num_states; i++) { + if (dc->dml.soc.clock_limits[i].dram_speed_mts > 1700) { + context->bw_ctx.dml.vba.DRAMSpeed = dc->dml.soc.clock_limits[i].dram_speed_mts; + break; + } + } + } + dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); if (!pstate_en) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index d0303173ce80..7d0626e42ea6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -4864,7 +4864,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->DETBufferSizeCThisState[k], &v->UrgentBurstFactorCursorPre[k], &v->UrgentBurstFactorLumaPre[k], - &v->UrgentBurstFactorChroma[k], + &v->UrgentBurstFactorChromaPre[k], &v->NoUrgentLatencyHidingPre[k]); } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c index b37d14369a62..59836570603a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c @@ -222,7 +222,7 @@ struct _vcs_dpi_ip_params_st dcn3_15_ip = { .maximum_dsc_bits_per_component = 10, .dsc422_native_support = false, .is_line_buffer_bpp_fixed = true, - .line_buffer_fixed_bpp = 49, + .line_buffer_fixed_bpp = 48, .line_buffer_size_bits = 789504, .max_line_buffer_lines = 12, .writeback_interface_buffer_size_kbytes = 90, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index 536a63624595..bd674dc30df3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -5191,7 +5191,7 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->DETBufferSizeCThisState[k], &v->UrgentBurstFactorCursorPre[k], &v->UrgentBurstFactorLumaPre[k], - &v->UrgentBurstFactorChroma[k], + &v->UrgentBurstFactorChromaPre[k], &v->NotUrgentLatencyHidingPre[k]); } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c index c52b76610bd2..9e54e3d0eb78 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c @@ -97,7 +97,7 @@ struct _vcs_dpi_ip_params_st dcn3_14_ip = { .dcc_supported = true, }; -struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = { +static struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = { /*TODO: correct dispclk/dppclk voltage level determination*/ .clock_limits = { { @@ -149,8 +149,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = { .num_states = 5, .sr_exit_time_us = 16.5, .sr_enter_plus_exit_time_us = 18.5, - .sr_exit_z8_time_us = 210.0, - .sr_enter_plus_exit_z8_time_us = 310.0, + .sr_exit_z8_time_us = 268.0, + .sr_enter_plus_exit_z8_time_us = 393.0, .writeback_latency_us = 12.0, .dram_channel_width_bytes = 4, .round_trip_ping_latency_dcfclk_cycles = 106, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index daf319370190..7eb2173b7691 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -5288,7 +5288,7 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_ v->DETBufferSizeCThisState[k], &v->UrgentBurstFactorCursorPre[k], &v->UrgentBurstFactorLumaPre[k], - &v->UrgentBurstFactorChroma[k], + &v->UrgentBurstFactorChromaPre[k], &v->NotUrgentLatencyHidingPre[k]); } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 1e26adf987cc..47beb4ea779d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -109,7 +109,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = { { .state = 0, .dcfclk_mhz = 1564.0, - .fabricclk_mhz = 400.0, + .fabricclk_mhz = 2500.0, .dispclk_mhz = 2150.0, .dppclk_mhz = 2150.0, .phyclk_mhz = 810.0, @@ -117,7 +117,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = { .phyclk_d32_mhz = 625.0, .socclk_mhz = 1200.0, .dscclk_mhz = 716.667, - .dram_speed_mts = 16000.0, + .dram_speed_mts = 18000.0, .dtbclk_mhz = 1564.0, }, }, @@ -148,7 +148,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = { .max_avg_fabric_bw_use_normal_percent = 60.0, .max_avg_dram_bw_use_normal_strobe_percent = 50.0, .max_avg_dram_bw_use_normal_percent = 15.0, - .num_chans = 8, + .num_chans = 24, .dram_channel_width_bytes = 2, .fabric_datapath_to_dcn_data_return_bytes = 64, .return_bus_width_bytes = 64, @@ -1331,6 +1331,11 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != dm_dram_clock_change_unsupported; + /* Pstate change might not be supported by hardware, but it might be + * possible with firmware driven vertical blank stretching. + */ + context->bw_ctx.bw.dcn.clk.p_state_change_support |= context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching; + context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context); context->bw_ctx.bw.dcn.clk.ref_dtbclk_khz = context->bw_ctx.dml.vba.DTBCLKPerState[vlevel] * 1000; @@ -1927,6 +1932,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, unsigned int min_dram_speed_mts_margin; bool need_fclk_lat_as_dummy = false; bool is_subvp_p_drr = false; + struct dc_stream_state *fpo_candidate_stream = NULL; dc_assert_fp_enabled(); @@ -1968,8 +1974,11 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, if (!pstate_en || (!dc->debug.disable_fpo_optimizations && pstate_en && vlevel != 0)) { /* only when the mclk switch can not be natural, is the fw based vblank stretch attempted */ - context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = - dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(dc, context); + fpo_candidate_stream = dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch(dc, context); + if (fpo_candidate_stream) { + fpo_candidate_stream->fpo_in_use = true; + context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = true; + } if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { dummy_latency_index = dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(dc, @@ -2002,6 +2011,10 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, * voltage level) */ context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false; + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]) + context->streams[i]->fpo_in_use = false; + } context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.fclk_change_latency_us; dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false); } @@ -2157,7 +2170,13 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, * DCFCLK: Min, as reported by PM FW, when available * UCLK: Min, as reported by PM FW, when available */ - dc->res_pool->funcs->update_soc_for_wm_a(dc, context); + + /* For set A set the correct latency values (i.e. non-dummy values) unconditionally + */ + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; + context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us; + context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us; + context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; @@ -2792,3 +2811,74 @@ double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *conte } return max_vratio_pre; } + +/** + * dcn32_assign_fpo_vactive_candidate - Assign the FPO stream candidate for FPO + VActive case + * + * This function chooses the FPO candidate stream for FPO + VActive cases (2 stream config). + * For FPO + VAtive cases, the assumption is that one display has ActiveMargin > 0, and the + * other display has ActiveMargin <= 0. This function will choose the pipe/stream that has + * ActiveMargin <= 0 to be the FPO stream candidate if found. + * + * + * @param [in]: dc - current dc state + * @param [in]: context - new dc state + * @param [out]: fpo_candidate_stream - pointer to FPO stream candidate if one is found + * + * Return: void + */ +void dcn32_assign_fpo_vactive_candidate(struct dc *dc, const struct dc_state *context, struct dc_stream_state **fpo_candidate_stream) +{ + unsigned int i, pipe_idx; + const struct vba_vars_st *vba = &context->bw_ctx.dml.vba; + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (!pipe->stream) + continue; + + if (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) { + *fpo_candidate_stream = pipe->stream; + break; + } + pipe_idx++; + } +} + +/** + * dcn32_find_vactive_pipe - Determines if the config has a pipe that can switch in VACTIVE + * + * @param [in]: dc - current dc state + * @param [in]: context - new dc state + * @param [in]: vactive_margin_req_us - The vactive marign required for a vactive pipe to be + * considered "found" + * + * Return: True if VACTIVE display is found, false otherwise + */ +bool dcn32_find_vactive_pipe(struct dc *dc, const struct dc_state *context, uint32_t vactive_margin_req_us) +{ + unsigned int i, pipe_idx; + const struct vba_vars_st *vba = &context->bw_ctx.dml.vba; + bool vactive_found = false; + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (!pipe->stream) + continue; + + if (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] >= vactive_margin_req_us) { + vactive_found = true; + break; + } + pipe_idx++; + } + return vactive_found; +} + +void dcn32_set_clock_limits(const struct _vcs_dpi_soc_bounding_box_st *soc_bb) +{ + dc_assert_fp_enabled(); + dcn3_2_soc.clock_limits[0].dcfclk_mhz = 1200.0; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h index ab010e7e840b..dcf512cd3072 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h @@ -76,4 +76,10 @@ void dcn32_patch_dpm_table(struct clk_bw_params *bw_params); void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes, int pipe_cnt); +void dcn32_assign_fpo_vactive_candidate(struct dc *dc, const struct dc_state *context, struct dc_stream_state **fpo_candidate_stream); + +bool dcn32_find_vactive_pipe(struct dc *dc, const struct dc_state *context, uint32_t vactive_margin_req); + +void dcn32_set_clock_limits(const struct _vcs_dpi_soc_bounding_box_st *soc_bb); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index f74730c2abbd..d75248b6cae9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -810,7 +810,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->SwathHeightY[k], v->SwathHeightC[k], TWait, - v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ ? + (v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ || + v->DCFCLKPerState[mode_lib->vba.VoltageLevel] <= MIN_DCFCLK_FREQ_MHZ) ? mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, /* Output */ &v->DSTXAfterScaler[k], @@ -3310,7 +3311,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->swath_width_chroma_ub_this_state[k], v->SwathHeightYThisState[k], v->SwathHeightCThisState[k], v->TWait, - v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ ? + (v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ || v->DCFCLKState[i][j] <= MIN_DCFCLK_FREQ_MHZ) ? mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, /* Output */ @@ -3354,7 +3355,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /* Output */ &mode_lib->vba.UrgentBurstFactorCursorPre[k], &mode_lib->vba.UrgentBurstFactorLumaPre[k], - &mode_lib->vba.UrgentBurstFactorChroma[k], + &mode_lib->vba.UrgentBurstFactorChromaPre[k], &mode_lib->vba.NotUrgentLatencyHidingPre[k]); } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h index 500b3dd6052d..d98e36a9a09c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h @@ -53,6 +53,7 @@ #define BPP_BLENDED_PIPE 0xffffffff #define MEM_STROBE_FREQ_MHZ 1600 +#define MIN_DCFCLK_FREQ_MHZ 200 #define MEM_STROBE_MAX_DELIVERY_TIME_US 60.0 struct display_mode_lib; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c index 57b9bd896678..342a1bcb4927 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c @@ -106,16 +106,16 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { .clock_limits = { { .state = 0, - .dcfclk_mhz = 1564.0, - .fabricclk_mhz = 400.0, - .dispclk_mhz = 2150.0, - .dppclk_mhz = 2150.0, + .dcfclk_mhz = 1434.0, + .fabricclk_mhz = 2250.0, + .dispclk_mhz = 1720.0, + .dppclk_mhz = 1720.0, .phyclk_mhz = 810.0, .phyclk_d18_mhz = 667.0, - .phyclk_d32_mhz = 625.0, + .phyclk_d32_mhz = 313.0, .socclk_mhz = 1200.0, - .dscclk_mhz = 716.667, - .dram_speed_mts = 1600.0, + .dscclk_mhz = 573.333, + .dram_speed_mts = 16000.0, .dtbclk_mhz = 1564.0, }, }, @@ -125,14 +125,14 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { .sr_exit_z8_time_us = 285.0, .sr_enter_plus_exit_z8_time_us = 320, .writeback_latency_us = 12.0, - .round_trip_ping_latency_dcfclk_cycles = 263, + .round_trip_ping_latency_dcfclk_cycles = 207, .urgent_latency_pixel_data_only_us = 4, .urgent_latency_pixel_mixed_with_vm_data_us = 4, .urgent_latency_vm_data_only_us = 4, - .fclk_change_latency_us = 20, - .usr_retraining_latency_us = 2, - .smn_latency_us = 2, - .mall_allocated_for_dcn_mbytes = 64, + .fclk_change_latency_us = 7, + .usr_retraining_latency_us = 0, + .smn_latency_us = 0, + .mall_allocated_for_dcn_mbytes = 32, .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index 4125d3d111d1..bdf3ac6cadd5 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c @@ -41,51 +41,51 @@ #include "dcn32/display_rq_dlg_calc_32.h" #include "dml_logger.h" -const struct dml_funcs dml20_funcs = { +static const struct dml_funcs dml20_funcs = { .validate = dml20_ModeSupportAndSystemConfigurationFull, .recalculate = dml20_recalculate, .rq_dlg_get_dlg_reg = dml20_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg = dml20_rq_dlg_get_rq_reg }; -const struct dml_funcs dml20v2_funcs = { +static const struct dml_funcs dml20v2_funcs = { .validate = dml20v2_ModeSupportAndSystemConfigurationFull, .recalculate = dml20v2_recalculate, .rq_dlg_get_dlg_reg = dml20v2_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg = dml20v2_rq_dlg_get_rq_reg }; -const struct dml_funcs dml21_funcs = { - .validate = dml21_ModeSupportAndSystemConfigurationFull, - .recalculate = dml21_recalculate, - .rq_dlg_get_dlg_reg = dml21_rq_dlg_get_dlg_reg, - .rq_dlg_get_rq_reg = dml21_rq_dlg_get_rq_reg +static const struct dml_funcs dml21_funcs = { + .validate = dml21_ModeSupportAndSystemConfigurationFull, + .recalculate = dml21_recalculate, + .rq_dlg_get_dlg_reg = dml21_rq_dlg_get_dlg_reg, + .rq_dlg_get_rq_reg = dml21_rq_dlg_get_rq_reg }; -const struct dml_funcs dml30_funcs = { +static const struct dml_funcs dml30_funcs = { .validate = dml30_ModeSupportAndSystemConfigurationFull, .recalculate = dml30_recalculate, .rq_dlg_get_dlg_reg = dml30_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg = dml30_rq_dlg_get_rq_reg }; -const struct dml_funcs dml31_funcs = { +static const struct dml_funcs dml31_funcs = { .validate = dml31_ModeSupportAndSystemConfigurationFull, .recalculate = dml31_recalculate, .rq_dlg_get_dlg_reg = dml31_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg = dml31_rq_dlg_get_rq_reg }; -const struct dml_funcs dml314_funcs = { +static const struct dml_funcs dml314_funcs = { .validate = dml314_ModeSupportAndSystemConfigurationFull, .recalculate = dml314_recalculate, .rq_dlg_get_dlg_reg = dml314_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg = dml314_rq_dlg_get_rq_reg }; -const struct dml_funcs dml32_funcs = { +static const struct dml_funcs dml32_funcs = { .validate = dml32_ModeSupportAndSystemConfigurationFull, - .recalculate = dml32_recalculate, + .recalculate = dml32_recalculate, .rq_dlg_get_dlg_reg_v2 = dml32_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg_v2 = dml32_rq_dlg_get_rq_reg }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h index 591ab1389e3b..bef843cc32a1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h @@ -293,6 +293,9 @@ struct clk_mgr_funcs { /* Get SMU present */ bool (*is_smu_present)(struct clk_mgr *clk_mgr); + + int (*get_dispclk_from_dentist)(struct clk_mgr *clk_mgr_base); + }; struct clk_mgr { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index f6c5ee2d639b..2267fb097830 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -1927,6 +1927,11 @@ static void disable_link_dp(struct dc_link *link, dp_disable_link_phy(link, link_res, signal); + if (link->connector_signal == SIGNAL_TYPE_EDP) { + if (!link->dc->config.edp_no_power_sequencing) + link->dc->hwss.edp_power_control(link, false); + } + if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) /* set the sink to SST mode after disabling the link */ enable_mst_on_sink(link, false); @@ -2035,6 +2040,12 @@ static enum dc_status enable_link_dp(struct dc_state *state, uint32_t post_oui_delay = 30; // 30ms /* Reduce link bandwidth between failed link training attempts. */ bool do_fallback = false; + int lt_attempts = LINK_TRAINING_ATTEMPTS; + + // Increase retry count if attempting DP1.x on FIXED_VS link + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) + lt_attempts = 10; // check for seamless boot for (i = 0; i < state->stream_count; i++) { @@ -2099,7 +2110,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, if (perform_link_training_with_retries(link_settings, skip_video_pattern, - LINK_TRAINING_ATTEMPTS, + lt_attempts, pipe_ctx, pipe_ctx->stream->signal, do_fallback)) { diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index c840ef17802e..ba98013fecd0 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -1043,6 +1043,9 @@ static enum dc_status wake_up_aux_channel(struct dc_link *link) DP_SET_POWER, &dpcd_power_state, sizeof(dpcd_power_state)); + if (status < 0) + DC_LOG_DC("%s: Failed to power up sink: %s\n", __func__, + dpcd_power_state == DP_SET_POWER_D0 ? "D0" : "D3"); return DC_ERROR_UNEXPECTED; } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c index f301c9eaf2f9..579fa222810d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c @@ -212,27 +212,36 @@ enum dpcd_training_patterns switch (pattern) { case DP_TRAINING_PATTERN_SEQUENCE_1: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS1\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1; break; case DP_TRAINING_PATTERN_SEQUENCE_2: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS2\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2; break; case DP_TRAINING_PATTERN_SEQUENCE_3: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS3\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3; break; case DP_TRAINING_PATTERN_SEQUENCE_4: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS4\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4; break; case DP_128b_132b_TPS1: + DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS1\n", __func__); dpcd_tr_pattern = DPCD_128b_132b_TPS1; break; case DP_128b_132b_TPS2: + DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS2\n", __func__); dpcd_tr_pattern = DPCD_128b_132b_TPS2; break; case DP_128b_132b_TPS2_CDS: + DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS2 CDS\n", + __func__); dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS; break; case DP_TRAINING_PATTERN_VIDEOIDLE: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern videoidle\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE; break; default: @@ -1496,7 +1505,10 @@ enum link_training_result dp_perform_link_training( * Non-LT AUX transactions inside training mode. */ if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING) - status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); + if (link->dc->config.use_old_fixed_vs_sequence) + status = dp_perform_fixed_vs_pe_training_sequence_legacy(link, link_res, <_settings); + else + status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); else if (encoding == DP_8b_10b_ENCODING) status = dp_perform_8b_10b_link_training(link, link_res, <_settings); else if (encoding == DP_128b_132b_ENCODING) @@ -1557,9 +1569,10 @@ bool perform_link_training_with_retries( j = 0; while (j < attempts && fail_count < (attempts * 10)) { - DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n", - __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, - cur_link_settings.lane_count); + DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d) @ spread = %x\n", + __func__, link->link_index, (unsigned int)j + 1, attempts, + cur_link_settings.link_rate, cur_link_settings.lane_count, + cur_link_settings.link_spread); dp_enable_link_phy( link, @@ -1583,7 +1596,10 @@ bool perform_link_training_with_retries( * Report and continue with eDP panel mode to * perform eDP link training with right settings */ - cp_psp->funcs.enable_assr(cp_psp->handle, link); + bool result; + result = cp_psp->funcs.enable_assr(cp_psp->handle, link); + if (!result && link->panel_mode != DP_PANEL_MODE_EDP) + panel_mode = DP_PANEL_MODE_DEFAULT; } } @@ -1637,9 +1653,10 @@ bool perform_link_training_with_retries( break; } - DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n", - __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, - cur_link_settings.lane_count, status); + DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n", + __func__, link->link_index, (unsigned int)j + 1, attempts, + cur_link_settings.link_rate, cur_link_settings.lane_count, + cur_link_settings.link_spread, status); dp_disable_link_phy(link, &pipe_ctx->link_res, signal); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c index 14b98e096d39..3889ebb2256b 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c @@ -225,8 +225,10 @@ enum link_training_result perform_8b_10b_clock_recovery_sequence( offset); /* 5. check CR done*/ - if (dp_is_cr_done(lane_count, dpcd_lane_status)) + if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + DC_LOG_HW_LINK_TRAINING("%s: Clock recovery OK\n", __func__); return LINK_TRAINING_SUCCESS; + } /* 6. max VS reached*/ if ((link_dp_get_encoding_format(<_settings->link_settings) == diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c index ab4aafdb5e5c..4f4e899e5c46 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c @@ -401,6 +401,7 @@ static enum link_training_result dpia_training_cr_non_transparent( /* Check if clock recovery successful. */ if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + DC_LOG_HW_LINK_TRAINING("%s: Clock recovery OK\n", __func__); result = LINK_TRAINING_SUCCESS; break; } @@ -508,6 +509,7 @@ static enum link_training_result dpia_training_cr_transparent( /* Check if clock recovery successful. */ if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + DC_LOG_HW_LINK_TRAINING("%s: Clock recovery OK\n", __func__); result = LINK_TRAINING_SUCCESS; break; } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c index a4071d2959a0..5731c4b61f9f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c @@ -223,7 +223,7 @@ static enum link_training_result perform_fixed_vs_pe_nontransparent_training_seq } -enum link_training_result dp_perform_fixed_vs_pe_training_sequence( +enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( struct dc_link *link, const struct link_resource *link_res, struct link_training_settings *lt_settings) @@ -577,3 +577,379 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( return status; } + +enum link_training_result dp_perform_fixed_vs_pe_training_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; + const uint8_t offset = dp_parse_lttpr_repeater_count( + link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; + const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E}; + const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E}; + const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01}; + const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68}; + uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; + uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; + uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; + + uint32_t vendor_lttpr_write_address = 0xF004F; + enum link_training_result status = LINK_TRAINING_SUCCESS; + uint8_t lane = 0; + union down_spread_ctrl downspread = {0}; + union lane_count_set lane_count_set = {0}; + uint8_t toggle_rate; + uint8_t rate; + + /* Only 8b/10b is supported */ + ASSERT(link_dp_get_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING); + + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); + return status; + } + + if (offset != 0xFF) { + vendor_lttpr_write_address += + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + + /* Certain display and cable configuration require extra delay */ + if (offset > 2) + pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; + } + + /* Vendor specific: Reset lane settings */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_reset[0], + sizeof(vendor_lttpr_write_data_reset)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + /* Vendor specific: Enable intercept */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_en[0], + sizeof(vendor_lttpr_write_data_intercept_en)); + + /* 1. set link rate, lane count and spread. */ + + downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); + + lane_count_set.bits.LANE_COUNT_SET = + lt_settings->link_settings.lane_count; + + lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; + + + if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = + link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; + } + + core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, + &downspread.raw, sizeof(downspread)); + + core_link_write_dpcd(link, DP_LANE_COUNT_SET, + &lane_count_set.raw, 1); + + rate = get_dpcd_link_rate(<_settings->link_settings); + + /* Vendor specific: Toggle link rate */ + toggle_rate = (rate == 0x6) ? 0xA : 0x6; + + if (link->vendor_specific_lttpr_link_rate_wa == rate) { + core_link_write_dpcd( + link, + DP_LINK_BW_SET, + &toggle_rate, + 1); + } + + link->vendor_specific_lttpr_link_rate_wa = rate; + + core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", + __func__, + DP_LINK_BW_SET, + lt_settings->link_settings.link_rate, + DP_LANE_COUNT_SET, + lt_settings->link_settings.lane_count, + lt_settings->enhanced_framing, + DP_DOWNSPREAD_CTRL, + lt_settings->link_settings.link_spread); + + /* 2. Perform link training */ + + /* Perform Clock Recovery Sequence */ + if (status == LINK_TRAINING_SUCCESS) { + const uint8_t max_vendor_dpcd_retries = 10; + uint32_t retries_cr; + uint32_t retry_count; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; + union lane_align_status_updated dpcd_lane_status_updated; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + enum dc_status dpcd_status = DC_OK; + uint8_t i = 0; + + retries_cr = 0; + retry_count = 0; + + memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); + memset(&dpcd_lane_status_updated, '\0', + sizeof(dpcd_lane_status_updated)); + + while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && + (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + + + /* 1. call HWSS to set lane settings */ + dp_set_hw_lane_settings( + link, + link_res, + lt_settings, + 0); + + /* 2. update DPCD of the receiver */ + if (!retry_count) { + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration. + */ + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + lt_settings->pattern_for_cr, + 0); + /* Vendor specific: Disable intercept */ + for (i = 0; i < max_vendor_dpcd_retries; i++) { + msleep(pre_disable_intercept_delay_ms); + dpcd_status = core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_dis[0], + sizeof(vendor_lttpr_write_data_intercept_dis)); + + if (dpcd_status == DC_OK) + break; + + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_en[0], + sizeof(vendor_lttpr_write_data_intercept_en)); + } + } else { + vendor_lttpr_write_data_vs[3] = 0; + vendor_lttpr_write_data_pe[3] = 0; + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Vendor specific: Update VS and PE to DPRX requested value */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + dpcd_set_lane_settings( + link, + lt_settings, + 0); + } + + /* 3. wait receiver to lock-on*/ + wait_time_microsec = lt_settings->cr_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested drive + * settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + 0); + + /* 5. check CR done*/ + if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + status = LINK_TRAINING_SUCCESS; + break; + } + + /* 6. max VS reached*/ + if (dp_is_max_vs_reached(lt_settings)) + break; + + /* 7. same lane settings */ + /* Note: settings are the same for all lanes, + * so comparing first lane is sufficient + */ + if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == + dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) + retries_cr++; + else + retries_cr = 0; + + /* 8. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + retry_count++; + } + + if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { + ASSERT(0); + DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", + __func__, + LINK_TRAINING_MAX_CR_RETRY); + + } + + status = dp_get_cr_failure(lane_count, dpcd_lane_status); + } + + /* Perform Channel EQ Sequence */ + if (status == LINK_TRAINING_SUCCESS) { + enum dc_dp_training_pattern tr_pattern; + uint32_t retries_ch_eq; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_adicora_eq1[0], + sizeof(vendor_lttpr_write_data_adicora_eq1)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_adicora_eq2[0], + sizeof(vendor_lttpr_write_data_adicora_eq2)); + + /* Note: also check that TPS4 is a supported feature*/ + tr_pattern = lt_settings->pattern_for_eq; + + dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); + + status = LINK_TRAINING_EQ_FAIL_EQ; + + for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; + retries_ch_eq++) { + + dp_set_hw_lane_settings(link, link_res, lt_settings, 0); + + vendor_lttpr_write_data_vs[3] = 0; + vendor_lttpr_write_data_pe[3] = 0; + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Vendor specific: Update VS and PE to DPRX requested value */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + /* 2. update DPCD*/ + if (!retries_ch_eq) { + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration + */ + + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + tr_pattern, 0); + + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_adicora_eq3[0], + sizeof(vendor_lttpr_write_data_adicora_eq3)); + } else + dpcd_set_lane_settings(link, lt_settings, 0); + + /* 3. wait for receiver to lock-on*/ + wait_time_microsec = lt_settings->eq_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested + * drive settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + 0); + + /* 5. check CR done*/ + if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { + status = LINK_TRAINING_EQ_FAIL_CR; + break; + } + + /* 6. check CHEQ done*/ + if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && + dp_is_symbol_locked(lane_count, dpcd_lane_status) && + dp_is_interlane_aligned(dpcd_lane_status_updated)) { + status = LINK_TRAINING_SUCCESS; + break; + } + + /* 7. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + } + } + + return status; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h index e61970e27661..c0d6ea329504 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h @@ -28,6 +28,11 @@ #define __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ #include "link_dp_training.h" +enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings); + enum link_training_result dp_perform_fixed_vs_pe_training_sequence( struct dc_link *link, const struct link_resource *link_res, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index d895046787bc..8d1df863659c 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -83,6 +83,7 @@ void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode) ASSERT(result == DC_OK); } } + link->panel_mode = panel_mode; DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 15d26222597a..598fa1de54ce 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -362,7 +362,7 @@ union dmub_fw_boot_status { uint32_t defer_load : 1; /**< 1 if VBIOS data is deferred programmed */ uint32_t reserved : 1; uint32_t detection_required: 1; /**< if detection need to be triggered by driver */ - + uint32_t hw_power_init_done: 1; /**< 1 if hw power init is completed */ } bits; /**< status bits */ uint32_t all; /**< 32-bit access to status bits */ }; @@ -377,6 +377,7 @@ enum dmub_fw_boot_status_bit { DMUB_FW_BOOT_STATUS_BIT_RESTORE_REQUIRED = (1 << 3), /**< 1 if driver should call restore */ DMUB_FW_BOOT_STATUS_BIT_DEFERRED_LOADED = (1 << 4), /**< 1 if VBIOS data is deferred programmed */ DMUB_FW_BOOT_STATUS_BIT_DETECTION_REQUIRED = (1 << 6), /**< 1 if detection need to be triggered by driver*/ + DMUB_FW_BOOT_STATUS_BIT_HW_POWER_INIT_DONE = (1 << 7), /**< 1 if hw power init is completed */ }; /* Register bit definition for SCRATCH5 */ @@ -1104,7 +1105,12 @@ enum dmub_cmd_idle_opt_type { /** * DCN hardware save. */ - DMUB_CMD__IDLE_OPT_DCN_SAVE_INIT = 1 + DMUB_CMD__IDLE_OPT_DCN_SAVE_INIT = 1, + + /** + * DCN hardware notify idle. + */ + DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE = 2 }; /** @@ -1115,6 +1121,24 @@ struct dmub_rb_cmd_idle_opt_dcn_restore { }; /** + * struct dmub_dcn_notify_idle_cntl_data - Data passed to FW in a DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE command. + */ +struct dmub_dcn_notify_idle_cntl_data { + uint8_t driver_idle; + uint8_t d3_entry; + uint8_t trigger; + uint8_t pad[1]; +}; + +/** + * struct dmub_rb_cmd_idle_opt_dcn_notify_idle - Data passed to FW in a DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE command. + */ +struct dmub_rb_cmd_idle_opt_dcn_notify_idle { + struct dmub_cmd_header header; /**< header */ + struct dmub_dcn_notify_idle_cntl_data cntl_data; +}; + +/** * struct dmub_clocks - Clock update notification. */ struct dmub_clocks { diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c index a76da0131add..9c20516be066 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c @@ -130,12 +130,13 @@ void dmub_dcn32_reset(struct dmub_srv *dmub) REG_WRITE(DMCUB_INBOX1_WPTR, 0); REG_WRITE(DMCUB_OUTBOX1_RPTR, 0); REG_WRITE(DMCUB_OUTBOX1_WPTR, 0); + REG_WRITE(DMCUB_OUTBOX0_RPTR, 0); + REG_WRITE(DMCUB_OUTBOX0_WPTR, 0); REG_WRITE(DMCUB_SCRATCH0, 0); } void dmub_dcn32_reset_release(struct dmub_srv *dmub) { - REG_WRITE(DMCUB_GPINT_DATAIN1, 0); REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0); REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF); REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1); diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h index beed70179bb5..23a308c3eccb 100644 --- a/drivers/gpu/drm/amd/display/include/signal_types.h +++ b/drivers/gpu/drm/amd/display/include/signal_types.h @@ -104,6 +104,7 @@ static inline bool dc_is_audio_capable_signal(enum signal_type signal) { return (signal == SIGNAL_TYPE_DISPLAY_PORT || signal == SIGNAL_TYPE_DISPLAY_PORT_MST || + signal == SIGNAL_TYPE_VIRTUAL || dc_is_hdmi_signal(signal)); } diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 315da61ee897..5c41a4751db4 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -1129,7 +1129,6 @@ void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, { struct core_freesync *core_freesync = NULL; unsigned int last_render_time_in_us = 0; - unsigned int average_render_time_in_us = 0; if (mod_freesync == NULL) return; @@ -1138,7 +1137,6 @@ void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, if (in_out_vrr->supported && in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE) { - unsigned int i = 0; unsigned int oldest_index = plane->time.index + 1; if (oldest_index >= DC_PLANE_UPDATE_TIMES_MAX) @@ -1147,18 +1145,6 @@ void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync, last_render_time_in_us = curr_time_stamp_in_us - plane->time.prev_update_time_in_us; - /* Sum off all entries except oldest one */ - for (i = 0; i < DC_PLANE_UPDATE_TIMES_MAX; i++) { - average_render_time_in_us += - plane->time.time_elapsed_in_us[i]; - } - average_render_time_in_us -= - plane->time.time_elapsed_in_us[oldest_index]; - - /* Add render time for current flip */ - average_render_time_in_us += last_render_time_in_us; - average_render_time_in_us /= DC_PLANE_UPDATE_TIMES_MAX; - if (in_out_vrr->btr.btr_enabled) { apply_below_the_range(core_freesync, stream, diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 0d3a983cb9ec..51e76bce92ea 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -927,6 +927,10 @@ bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link, pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; + + if (stream->timing.dsc_cfg.num_slices_v == 0) + return false; + slice_height = pic_height / stream->timing.dsc_cfg.num_slices_v; config->dsc_slice_height = slice_height; diff --git a/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h index bd129266ebfd..a84a7cfaf71e 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h @@ -135,6 +135,8 @@ #define mmIH_RB_WPTR_ADDR_LO_BASE_IDX 0 #define mmIH_DOORBELL_RPTR 0x0087 #define mmIH_DOORBELL_RPTR_BASE_IDX 0 +#define mmIH_DOORBELL_RETRY_CAM 0x0088 +#define mmIH_DOORBELL_RETRY_CAM_BASE_IDX 0 #define mmIH_RB_CNTL_RING1 0x008c #define mmIH_RB_CNTL_RING1_BASE_IDX 0 #define mmIH_RB_BASE_RING1 0x008d @@ -159,6 +161,8 @@ #define mmIH_RB_WPTR_RING2_BASE_IDX 0 #define mmIH_DOORBELL_RPTR_RING2 0x009f #define mmIH_DOORBELL_RPTR_RING2_BASE_IDX 0 +#define mmIH_RETRY_CAM_ACK 0x00a4 +#define mmIH_RETRY_CAM_ACK_BASE_IDX 0 #define mmIH_VERSION 0x00a5 #define mmIH_VERSION_BASE_IDX 0 #define mmIH_CNTL 0x00c0 @@ -235,6 +239,8 @@ #define mmIH_MMHUB_ERROR_BASE_IDX 0 #define mmIH_MEM_POWER_CTRL 0x00e8 #define mmIH_MEM_POWER_CTRL_BASE_IDX 0 +#define mmIH_RETRY_INT_CAM_CNTL 0x00e9 +#define mmIH_RETRY_INT_CAM_CNTL_BASE_IDX 0 #define mmIH_REGISTER_LAST_PART2 0x00ff #define mmIH_REGISTER_LAST_PART2_BASE_IDX 0 #define mmSEM_CLK_CTRL 0x0100 diff --git a/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h index 3ea83ea9ce3a..75c04fc275a0 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h @@ -349,6 +349,17 @@ #define IH_DOORBELL_RPTR_RING2__ENABLE__SHIFT 0x1c #define IH_DOORBELL_RPTR_RING2__OFFSET_MASK 0x03FFFFFFL #define IH_DOORBELL_RPTR_RING2__ENABLE_MASK 0x10000000L +//IH_RETRY_INT_CAM_CNTL +#define IH_RETRY_INT_CAM_CNTL__CAM_SIZE__SHIFT 0x0 +#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_SKID_VALUE__SHIFT 0x8 +#define IH_RETRY_INT_CAM_CNTL__ENABLE__SHIFT 0x10 +#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_ENABLE__SHIFT 0x11 +#define IH_RETRY_INT_CAM_CNTL__PER_VF_ENTRY_SIZE__SHIFT 0x14 +#define IH_RETRY_INT_CAM_CNTL__CAM_SIZE_MASK 0x0000001FL +#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_SKID_VALUE_MASK 0x00003F00L +#define IH_RETRY_INT_CAM_CNTL__ENABLE_MASK 0x00010000L +#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_ENABLE_MASK 0x00020000L +#define IH_RETRY_INT_CAM_CNTL__PER_VF_ENTRY_SIZE_MASK 0x00300000L //IH_VERSION #define IH_VERSION__MINVER__SHIFT 0x0 #define IH_VERSION__MAJVER__SHIFT 0x8 diff --git a/drivers/gpu/drm/amd/include/v11_structs.h b/drivers/gpu/drm/amd/include/v11_structs.h index b8ff7456ae0b..f8008270f813 100644 --- a/drivers/gpu/drm/amd/include/v11_structs.h +++ b/drivers/gpu/drm/amd/include/v11_structs.h @@ -25,14 +25,14 @@ #define V11_STRUCTS_H_ struct v11_gfx_mqd { - uint32_t reserved_0; // offset: 0 (0x0) - uint32_t reserved_1; // offset: 1 (0x1) - uint32_t reserved_2; // offset: 2 (0x2) - uint32_t reserved_3; // offset: 3 (0x3) - uint32_t reserved_4; // offset: 4 (0x4) - uint32_t reserved_5; // offset: 5 (0x5) - uint32_t reserved_6; // offset: 6 (0x6) - uint32_t reserved_7; // offset: 7 (0x7) + uint32_t shadow_base_lo; // offset: 0 (0x0) + uint32_t shadow_base_hi; // offset: 1 (0x1) + uint32_t gds_bkup_base_lo; // offset: 2 (0x2) + uint32_t gds_bkup_base_hi; // offset: 3 (0x3) + uint32_t fw_work_area_base_lo; // offset: 4 (0x4) + uint32_t fw_work_area_base_hi; // offset: 5 (0x5) + uint32_t shadow_initialized; // offset: 6 (0x6) + uint32_t ib_vmid; // offset: 7 (0x7) uint32_t reserved_8; // offset: 8 (0x8) uint32_t reserved_9; // offset: 9 (0x9) uint32_t reserved_10; // offset: 10 (0xA) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 300e156b924f..078aaaa53162 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -36,6 +36,8 @@ #define amdgpu_dpm_enable_bapm(adev, e) \ ((adev)->powerplay.pp_funcs->enable_bapm((adev)->powerplay.pp_handle, (e))) +#define amdgpu_dpm_is_legacy_dpm(adev) ((adev)->powerplay.pp_handle == (adev)) + int amdgpu_dpm_get_sclk(struct amdgpu_device *adev, bool low) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; @@ -1460,15 +1462,24 @@ int amdgpu_dpm_get_smu_prv_buf_details(struct amdgpu_device *adev, int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev) { - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - struct smu_context *smu = adev->powerplay.pp_handle; + if (is_support_sw_smu(adev)) { + struct smu_context *smu = adev->powerplay.pp_handle; - if ((is_support_sw_smu(adev) && smu->od_enabled) || - (is_support_sw_smu(adev) && smu->is_apu) || - (!is_support_sw_smu(adev) && hwmgr->od_enabled)) - return true; + return (smu->od_enabled || smu->is_apu); + } else { + struct pp_hwmgr *hwmgr; - return false; + /* + * dpm on some legacy asics don't carry od_enabled member + * as its pp_handle is casted directly from adev. + */ + if (amdgpu_dpm_is_legacy_dpm(adev)) + return false; + + hwmgr = (struct pp_hwmgr *)adev->powerplay.pp_handle; + + return hwmgr->od_enabled; + } } int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index e011041e3ec6..58c2246918fd 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -3395,7 +3395,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */ effective_mode &= ~S_IWUSR; - /* not implemented yet for GC 10.3.1 APUs */ + /* In the case of APUs, this is only implemented on Vangogh */ if (((adev->family == AMDGPU_FAMILY_SI) || ((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(10, 3, 1)))) && (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr || @@ -3404,7 +3404,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, attr == &sensor_dev_attr_power1_cap_default.dev_attr.attr)) return 0; - /* not implemented yet for APUs having <= GC 9.3.0 */ + /* not implemented yet for APUs having < GC 9.3.0 (Renoir) */ if (((adev->family == AMDGPU_FAMILY_SI) || ((adev->flags & AMD_IS_APU) && (gc_ver < IP_VERSION(9, 3, 0)))) && (attr == &sensor_dev_attr_power1_average.dev_attr.attr)) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 056ac2b512eb..5633c5797e85 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1712,8 +1712,6 @@ static int smu_display_configuration_change(void *handle, const struct amd_pp_display_configuration *display_config) { struct smu_context *smu = handle; - int index = 0; - int num_of_active_display = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; @@ -1724,11 +1722,6 @@ static int smu_display_configuration_change(void *handle, smu_set_min_dcef_deep_sleep(smu, display_config->min_dcef_deep_sleep_set_clk / 100); - for (index = 0; index < display_config->num_path_including_non_display; index++) { - if (display_config->displays[index].controller_id != 0) - num_of_active_display++; - } - return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 0ef37837b164..df3baaab0037 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -62,6 +62,12 @@ #define CTF_OFFSET_HOTSPOT 5 #define CTF_OFFSET_MEM 5 +extern const int pmfw_decoded_link_speed[5]; +extern const int pmfw_decoded_link_width[7]; + +#define DECODE_GEN_SPEED(gen_speed_idx) (pmfw_decoded_link_speed[gen_speed_idx]) +#define DECODE_LANE_WIDTH(lane_width_idx) (pmfw_decoded_link_width[lane_width_idx]) + struct smu_13_0_max_sustainable_clocks { uint32_t display_clock; uint32_t phy_clock; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 73175c993da9..393c6a7b9609 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -85,6 +85,9 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_10.bin"); static const int link_width[] = {0, 1, 2, 4, 8, 12, 16}; static const int link_speed[] = {25, 50, 80, 160}; +const int pmfw_decoded_link_speed[5] = {1, 2, 3, 4, 5}; +const int pmfw_decoded_link_width[7] = {0, 1, 2, 4, 8, 12, 16}; + int smu_v13_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index e9766fe5656e..09405ef1e3c8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -1144,8 +1144,8 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, (pcie_table->pcie_lane[i] == 5) ? "x12" : (pcie_table->pcie_lane[i] == 6) ? "x16" : "", pcie_table->clk_freq[i], - ((gen_speed - 1) == pcie_table->pcie_gen[i]) && - (lane_width == link_width[pcie_table->pcie_lane[i]]) ? + (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && + (lane_width == DECODE_LANE_WIDTH(link_width[pcie_table->pcie_lane[i]])) ? "*" : ""); break; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 1b2c82449f20..3d9ff46706fb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -575,6 +575,14 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) dpm_table); if (ret) return ret; + + if (skutable->DriverReportedClocks.GameClockAc && + (dpm_table->dpm_levels[dpm_table->count - 1].value > + skutable->DriverReportedClocks.GameClockAc)) { + dpm_table->dpm_levels[dpm_table->count - 1].value = + skutable->DriverReportedClocks.GameClockAc; + dpm_table->max = skutable->DriverReportedClocks.GameClockAc; + } } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; @@ -828,6 +836,57 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu, return ret; } +static int smu_v13_0_7_get_dpm_ultimate_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, + uint32_t *max) +{ + struct smu_13_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_13_0_dpm_table *dpm_table; + + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + /* uclk dpm table */ + dpm_table = &dpm_context->dpm_tables.uclk_table; + break; + case SMU_GFXCLK: + case SMU_SCLK: + /* gfxclk dpm table */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + break; + case SMU_SOCCLK: + /* socclk dpm table */ + dpm_table = &dpm_context->dpm_tables.soc_table; + break; + case SMU_FCLK: + /* fclk dpm table */ + dpm_table = &dpm_context->dpm_tables.fclk_table; + break; + case SMU_VCLK: + case SMU_VCLK1: + /* vclk dpm table */ + dpm_table = &dpm_context->dpm_tables.vclk_table; + break; + case SMU_DCLK: + case SMU_DCLK1: + /* dclk dpm table */ + dpm_table = &dpm_context->dpm_tables.dclk_table; + break; + default: + dev_err(smu->adev->dev, "Unsupported clock type!\n"); + return -EINVAL; + } + + if (min) + *min = dpm_table->min; + if (max) + *max = dpm_table->max; + + return 0; +} + static int smu_v13_0_7_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor, void *data, @@ -1074,8 +1133,8 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu, (pcie_table->pcie_lane[i] == 5) ? "x12" : (pcie_table->pcie_lane[i] == 6) ? "x16" : "", pcie_table->clk_freq[i], - (gen_speed == pcie_table->pcie_gen[i]) && - (lane_width == pcie_table->pcie_lane[i]) ? + (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && + (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ? "*" : ""); break; @@ -1329,9 +1388,17 @@ static int smu_v13_0_7_populate_umd_state_clk(struct smu_context *smu) &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + DriverReportedClocks_t driver_clocks = + pptable->SkuTable.DriverReportedClocks; pstate_table->gfxclk_pstate.min = gfx_table->min; - pstate_table->gfxclk_pstate.peak = gfx_table->max; + if (driver_clocks.GameClockAc && + (driver_clocks.GameClockAc < gfx_table->max)) + pstate_table->gfxclk_pstate.peak = driver_clocks.GameClockAc; + else + pstate_table->gfxclk_pstate.peak = gfx_table->max; pstate_table->uclk_pstate.min = mem_table->min; pstate_table->uclk_pstate.peak = mem_table->max; @@ -1348,12 +1415,12 @@ static int smu_v13_0_7_populate_umd_state_clk(struct smu_context *smu) pstate_table->fclk_pstate.min = fclk_table->min; pstate_table->fclk_pstate.peak = fclk_table->max; - /* - * For now, just use the mininum clock frequency. - * TODO: update them when the real pstate settings available - */ - pstate_table->gfxclk_pstate.standard = gfx_table->min; - pstate_table->uclk_pstate.standard = mem_table->min; + if (driver_clocks.BaseClockAc && + driver_clocks.BaseClockAc < gfx_table->max) + pstate_table->gfxclk_pstate.standard = driver_clocks.BaseClockAc; + else + pstate_table->gfxclk_pstate.standard = gfx_table->max; + pstate_table->uclk_pstate.standard = mem_table->max; pstate_table->socclk_pstate.standard = soc_table->min; pstate_table->vclk_pstate.standard = vclk_table->min; pstate_table->dclk_pstate.standard = dclk_table->min; @@ -1678,7 +1745,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .dpm_set_jpeg_enable = smu_v13_0_set_jpeg_enable, .init_pptable_microcode = smu_v13_0_init_pptable_microcode, .populate_umd_state_clk = smu_v13_0_7_populate_umd_state_clk, - .get_dpm_ultimate_freq = smu_v13_0_get_dpm_ultimate_freq, + .get_dpm_ultimate_freq = smu_v13_0_7_get_dpm_ultimate_freq, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .read_sensor = smu_v13_0_7_read_sensor, .feature_is_enabled = smu_cmn_feature_is_enabled, diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 9020bf820bc8..12f5a2c7f03d 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -285,7 +285,7 @@ static int hdlcd_drm_bind(struct device *dev) */ if (hdlcd_read(hdlcd, HDLCD_REG_COMMAND)) { hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0); - drm_aperture_remove_framebuffers(false, &hdlcd_driver); + drm_aperture_remove_framebuffers(&hdlcd_driver); } drm_mode_config_reset(drm); diff --git a/drivers/gpu/drm/armada/Kconfig b/drivers/gpu/drm/armada/Kconfig index f5c66d89ba99..5afade25e217 100644 --- a/drivers/gpu/drm/armada/Kconfig +++ b/drivers/gpu/drm/armada/Kconfig @@ -3,6 +3,7 @@ config DRM_ARMADA tristate "DRM support for Marvell Armada SoCs" depends on DRM && HAVE_CLK && ARM && MMU select DRM_KMS_HELPER + select FB_IO_HELPERS if DRM_FBDEV_EMULATION help Support the "LCD" controllers found on the Marvell Armada 510 devices. There are two controllers on the device, each controller diff --git a/drivers/gpu/drm/armada/Makefile b/drivers/gpu/drm/armada/Makefile index 9bc3c3213724..dc75a7db9ed3 100644 --- a/drivers/gpu/drm/armada/Makefile +++ b/drivers/gpu/drm/armada/Makefile @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 -armada-y := armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \ +armada-y := armada_crtc.o armada_drv.o armada_fb.o \ armada_gem.o armada_overlay.o armada_plane.o armada_trace.o armada-y += armada_510.o armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o +armada-$(CONFIG_DRM_FBDEV_EMULATION) += armada_fbdev.o obj-$(CONFIG_DRM_ARMADA) := armada.o diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index 6a5a87932576..c303e8c7ff6c 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -16,7 +16,6 @@ struct armada_crtc; struct armada_gem_object; struct clk; struct drm_display_mode; -struct drm_fb_helper; static inline void armada_updatel(uint32_t val, uint32_t mask, void __iomem *ptr) @@ -55,7 +54,6 @@ extern const struct armada_variant armada510_ops; struct armada_private { struct drm_device drm; - struct drm_fb_helper *fbdev; struct armada_crtc *dcrtc[2]; struct drm_mm linear; /* protected by linear_lock */ struct mutex linear_lock; @@ -75,8 +73,12 @@ struct armada_private { #define drm_to_armada_dev(dev) container_of(dev, struct armada_private, drm) -int armada_fbdev_init(struct drm_device *); -void armada_fbdev_fini(struct drm_device *); +#if defined(CONFIG_DRM_FBDEV_EMULATION) +void armada_fbdev_setup(struct drm_device *dev); +#else +static inline void armada_fbdev_setup(struct drm_device *dev) +{ } +#endif int armada_overlay_plane_create(struct drm_device *, unsigned long); diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 0643887800b4..e120144d4b47 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -6,6 +6,7 @@ #include <linux/clk.h> #include <linux/component.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_graph.h> #include <linux/platform_device.h> @@ -16,7 +17,6 @@ #include <drm/drm_managed.h> #include <drm/drm_prime.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_of.h> #include <drm/drm_vblank.h> @@ -37,7 +37,6 @@ static const struct drm_ioctl_desc armada_ioctls[] = { DEFINE_DRM_GEM_FOPS(armada_drm_fops); static const struct drm_driver armada_drm_driver = { - .lastclose = drm_fb_helper_lastclose, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import = armada_gem_prime_import, @@ -55,7 +54,6 @@ static const struct drm_driver armada_drm_driver = { static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = { .fb_create = armada_fb_create, - .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -95,11 +93,10 @@ static int armada_drm_bind(struct device *dev) } /* Remove early framebuffers */ - ret = drm_aperture_remove_framebuffers(false, &armada_drm_driver); + ret = drm_aperture_remove_framebuffers(&armada_drm_driver); if (ret) { dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n", __func__, ret); - kfree(priv); return ret; } @@ -132,10 +129,6 @@ static int armada_drm_bind(struct device *dev) drm_mode_config_reset(&priv->drm); - ret = armada_fbdev_init(&priv->drm); - if (ret) - goto err_comp; - drm_kms_helper_poll_init(&priv->drm); ret = drm_dev_register(&priv->drm, 0); @@ -146,11 +139,12 @@ static int armada_drm_bind(struct device *dev) armada_drm_debugfs_init(priv->drm.primary); #endif + armada_fbdev_setup(&priv->drm); + return 0; err_poll: drm_kms_helper_poll_fini(&priv->drm); - armada_fbdev_fini(&priv->drm); err_comp: component_unbind_all(dev, &priv->drm); err_kms: @@ -165,7 +159,6 @@ static void armada_drm_unbind(struct device *dev) struct armada_private *priv = drm_to_armada_dev(drm); drm_kms_helper_poll_fini(&priv->drm); - armada_fbdev_fini(&priv->drm); drm_dev_unregister(&priv->drm); diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c index b87c71703c85..cf2e88218dc0 100644 --- a/drivers/gpu/drm/armada/armada_fb.c +++ b/drivers/gpu/drm/armada/armada_fb.c @@ -4,7 +4,6 @@ */ #include <drm/drm_modeset_helper.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index 0e44f53e9fa4..3943e89cc06c 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -5,9 +5,12 @@ */ #include <linux/errno.h> +#include <linux/fb.h> #include <linux/kernel.h> #include <linux/module.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> @@ -16,14 +19,24 @@ #include "armada_fb.h" #include "armada_gem.h" +static void armada_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *fbh = info->par; + + drm_fb_helper_fini(fbh); + + fbh->fb->funcs->destroy(fbh->fb); + + drm_client_release(&fbh->client); + drm_fb_helper_unprepare(fbh); + kfree(fbh); +} + static const struct fb_ops armada_fb_ops = { .owner = THIS_MODULE, + FB_DEFAULT_IO_OPS, DRM_FB_HELPER_DEFAULT_OPS, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, + .fb_destroy = armada_fbdev_fb_destroy, }; static int armada_fbdev_create(struct drm_fb_helper *fbh, @@ -117,56 +130,95 @@ static const struct drm_fb_helper_funcs armada_fb_helper_funcs = { .fb_probe = armada_fb_probe, }; -int armada_fbdev_init(struct drm_device *dev) +/* + * Fbdev client and struct drm_client_funcs + */ + +static void armada_fbdev_client_unregister(struct drm_client_dev *client) { - struct armada_private *priv = drm_to_armada_dev(dev); - struct drm_fb_helper *fbh; - int ret; + struct drm_fb_helper *fbh = drm_fb_helper_from_client(client); - fbh = devm_kzalloc(dev->dev, sizeof(*fbh), GFP_KERNEL); - if (!fbh) - return -ENOMEM; + if (fbh->info) { + drm_fb_helper_unregister_info(fbh); + } else { + drm_client_release(&fbh->client); + drm_fb_helper_unprepare(fbh); + kfree(fbh); + } +} - priv->fbdev = fbh; +static int armada_fbdev_client_restore(struct drm_client_dev *client) +{ + drm_fb_helper_lastclose(client->dev); - drm_fb_helper_prepare(dev, fbh, 32, &armada_fb_helper_funcs); + return 0; +} + +static int armada_fbdev_client_hotplug(struct drm_client_dev *client) +{ + struct drm_fb_helper *fbh = drm_fb_helper_from_client(client); + struct drm_device *dev = client->dev; + int ret; + + if (dev->fb_helper) + return drm_fb_helper_hotplug_event(dev->fb_helper); ret = drm_fb_helper_init(dev, fbh); - if (ret) { - DRM_ERROR("failed to initialize drm fb helper\n"); - goto err_fb_helper; - } + if (ret) + goto err_drm_err; + + if (!drm_drv_uses_atomic_modeset(dev)) + drm_helper_disable_unused_functions(dev); ret = drm_fb_helper_initial_config(fbh); - if (ret) { - DRM_ERROR("failed to set initial config\n"); - goto err_fb_setup; - } + if (ret) + goto err_drm_fb_helper_fini; return 0; - err_fb_setup: + +err_drm_fb_helper_fini: drm_fb_helper_fini(fbh); - err_fb_helper: - drm_fb_helper_unprepare(fbh); - priv->fbdev = NULL; +err_drm_err: + drm_err(dev, "armada: Failed to setup fbdev emulation (ret=%d)\n", ret); return ret; } -void armada_fbdev_fini(struct drm_device *dev) +static const struct drm_client_funcs armada_fbdev_client_funcs = { + .owner = THIS_MODULE, + .unregister = armada_fbdev_client_unregister, + .restore = armada_fbdev_client_restore, + .hotplug = armada_fbdev_client_hotplug, +}; + +void armada_fbdev_setup(struct drm_device *dev) { - struct armada_private *priv = drm_to_armada_dev(dev); - struct drm_fb_helper *fbh = priv->fbdev; + struct drm_fb_helper *fbh; + int ret; - if (fbh) { - drm_fb_helper_unregister_info(fbh); + drm_WARN(dev, !dev->registered, "Device has not been registered.\n"); + drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n"); + + fbh = kzalloc(sizeof(*fbh), GFP_KERNEL); + if (!fbh) + return; + drm_fb_helper_prepare(dev, fbh, 32, &armada_fb_helper_funcs); - drm_fb_helper_fini(fbh); + ret = drm_client_init(dev, &fbh->client, "fbdev", &armada_fbdev_client_funcs); + if (ret) { + drm_err(dev, "Failed to register client: %d\n", ret); + goto err_drm_client_init; + } - if (fbh->fb) - fbh->fb->funcs->destroy(fbh->fb); + ret = armada_fbdev_client_hotplug(&fbh->client); + if (ret) + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); - drm_fb_helper_unprepare(fbh); + drm_client_register(&fbh->client); - priv->fbdev = NULL; - } + return; + +err_drm_client_init: + drm_fb_helper_unprepare(fbh); + kfree(fbh); + return; } diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 794ffd4a29c5..f32ce29edba7 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -425,11 +425,12 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, return ERR_PTR(-EIO); /* - * If we don't have IO space at all, use MMIO now and - * assume the chip has MMIO enabled by default (rev 0x20 - * and higher). + * After AST2500, MMIO is enabled by default, and it should be adopted + * to be compatible with Arm. */ - if (!(pci_resource_flags(pdev, 2) & IORESOURCE_IO)) { + if (pdev->revision >= 0x40) { + ast->ioregs = ast->regs + AST_IO_MM_OFFSET; + } else if (!(pci_resource_flags(pdev, 2) & IORESOURCE_IO)) { drm_info(dev, "platform has no IO space, trying MMIO\n"); ast->ioregs = ast->regs + AST_IO_MM_OFFSET; } diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index f076a09afac0..82c68b042444 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -227,6 +227,7 @@ config DRM_SAMSUNG_DSIM select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY_MIPI_DPHY help The Samsung MIPI DSIM bridge controller driver. This MIPI DSIM bridge can be found it on Exynos SoCs and diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index ddceafa7b637..2254457ab5d0 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -1393,7 +1393,7 @@ static struct i2c_driver adv7511_driver = { .of_match_table = adv7511_of_ids, }, .id_table = adv7511_i2c_ids, - .probe_new = adv7511_probe, + .probe = adv7511_probe, .remove = adv7511_remove, }; diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index 3577c532abb4..72ab2ab77081 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -815,7 +815,7 @@ static struct i2c_driver anx6345_driver = { .name = "anx6345", .of_match_table = of_match_ptr(anx6345_match_table), }, - .probe_new = anx6345_i2c_probe, + .probe = anx6345_i2c_probe, .remove = anx6345_i2c_remove, .id_table = anx6345_id, }; diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index a3a38bbe2786..06a3e3243e19 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -1389,7 +1389,7 @@ static struct i2c_driver anx78xx_driver = { .name = "anx7814", .of_match_table = of_match_ptr(anx78xx_match_table), }, - .probe_new = anx78xx_i2c_probe, + .probe = anx78xx_i2c_probe, .remove = anx78xx_i2c_remove, .id_table = anx78xx_id, }; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 6846199a2ee1..8b985efdc086 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -17,7 +17,6 @@ #include <linux/types.h> #include <linux/workqueue.h> -#include <linux/of_gpio.h> #include <linux/of_graph.h> #include <linux/of_platform.h> @@ -1687,6 +1686,14 @@ static int anx7625_parse_dt(struct device *dev, if (of_property_read_bool(np, "analogix,audio-enable")) pdata->audio_en = 1; + return 0; +} + +static int anx7625_parse_dt_panel(struct device *dev, + struct anx7625_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + pdata->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0); if (IS_ERR(pdata->panel_bridge)) { if (PTR_ERR(pdata->panel_bridge) == -ENODEV) { @@ -2032,7 +2039,7 @@ static int anx7625_register_audio(struct device *dev, struct anx7625_data *ctx) return 0; } -static int anx7625_attach_dsi(struct anx7625_data *ctx) +static int anx7625_setup_dsi_device(struct anx7625_data *ctx) { struct mipi_dsi_device *dsi; struct device *dev = &ctx->client->dev; @@ -2042,9 +2049,6 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) .channel = 0, .node = NULL, }; - int ret; - - DRM_DEV_DEBUG_DRIVER(dev, "attach dsi\n"); host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); if (!host) { @@ -2065,14 +2069,24 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_HS_PKT_END_ALIGNED; - ret = devm_mipi_dsi_attach(dev, dsi); + ctx->dsi = dsi; + + return 0; +} + +static int anx7625_attach_dsi(struct anx7625_data *ctx) +{ + struct device *dev = &ctx->client->dev; + int ret; + + DRM_DEV_DEBUG_DRIVER(dev, "attach dsi\n"); + + ret = devm_mipi_dsi_attach(dev, ctx->dsi); if (ret) { DRM_DEV_ERROR(dev, "fail to attach dsi to host.\n"); return ret; } - ctx->dsi = dsi; - DRM_DEV_DEBUG_DRIVER(dev, "attach dsi succeeded.\n"); return 0; @@ -2560,6 +2574,40 @@ static void anx7625_runtime_disable(void *data) pm_runtime_disable(data); } +static int anx7625_link_bridge(struct drm_dp_aux *aux) +{ + struct anx7625_data *platform = container_of(aux, struct anx7625_data, aux); + struct device *dev = aux->dev; + int ret; + + ret = anx7625_parse_dt_panel(dev, &platform->pdata); + if (ret) { + DRM_DEV_ERROR(dev, "fail to parse DT for panel : %d\n", ret); + return ret; + } + + platform->bridge.funcs = &anx7625_bridge_funcs; + platform->bridge.of_node = dev->of_node; + if (!anx7625_of_panel_on_aux_bus(dev)) + platform->bridge.ops |= DRM_BRIDGE_OP_EDID; + if (!platform->pdata.panel_bridge) + platform->bridge.ops |= DRM_BRIDGE_OP_HPD | + DRM_BRIDGE_OP_DETECT; + platform->bridge.type = platform->pdata.panel_bridge ? + DRM_MODE_CONNECTOR_eDP : + DRM_MODE_CONNECTOR_DisplayPort; + + drm_bridge_add(&platform->bridge); + + if (!platform->pdata.is_dpi) { + ret = anx7625_attach_dsi(platform); + if (ret) + drm_bridge_remove(&platform->bridge); + } + + return ret; +} + static int anx7625_i2c_probe(struct i2c_client *client) { struct anx7625_data *platform; @@ -2634,6 +2682,24 @@ static int anx7625_i2c_probe(struct i2c_client *client) platform->aux.wait_hpd_asserted = anx7625_wait_hpd_asserted; drm_dp_aux_init(&platform->aux); + ret = anx7625_parse_dt(dev, pdata); + if (ret) { + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret); + goto free_wq; + } + + if (!platform->pdata.is_dpi) { + ret = anx7625_setup_dsi_device(platform); + if (ret < 0) + goto free_wq; + } + + /* + * Registering the i2c devices will retrigger deferred probe, so it + * needs to be done after calls that might return EPROBE_DEFER, + * otherwise we can get an infinite loop. + */ if (anx7625_register_i2c_dummy_clients(platform, client) != 0) { ret = -ENOMEM; DRM_DEV_ERROR(dev, "fail to reserve I2C bus.\n"); @@ -2648,13 +2714,21 @@ static int anx7625_i2c_probe(struct i2c_client *client) if (ret) goto free_wq; - devm_of_dp_aux_populate_ep_devices(&platform->aux); - - ret = anx7625_parse_dt(dev, pdata); + /* + * Populating the aux bus will retrigger deferred probe, so it needs to + * be done after calls that might return EPROBE_DEFER, otherwise we can + * get an infinite loop. + */ + ret = devm_of_dp_aux_populate_bus(&platform->aux, anx7625_link_bridge); if (ret) { - if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret); - goto free_wq; + if (ret != -ENODEV) { + DRM_DEV_ERROR(dev, "failed to populate aux bus : %d\n", ret); + goto free_wq; + } + + ret = anx7625_link_bridge(&platform->aux); + if (ret) + goto free_wq; } if (!platform->pdata.low_power_mode) { @@ -2667,27 +2741,6 @@ static int anx7625_i2c_probe(struct i2c_client *client) if (platform->pdata.intp_irq) queue_work(platform->workqueue, &platform->work); - platform->bridge.funcs = &anx7625_bridge_funcs; - platform->bridge.of_node = client->dev.of_node; - if (!anx7625_of_panel_on_aux_bus(&client->dev)) - platform->bridge.ops |= DRM_BRIDGE_OP_EDID; - if (!platform->pdata.panel_bridge) - platform->bridge.ops |= DRM_BRIDGE_OP_HPD | - DRM_BRIDGE_OP_DETECT; - platform->bridge.type = platform->pdata.panel_bridge ? - DRM_MODE_CONNECTOR_eDP : - DRM_MODE_CONNECTOR_DisplayPort; - - drm_bridge_add(&platform->bridge); - - if (!platform->pdata.is_dpi) { - ret = anx7625_attach_dsi(platform); - if (ret) { - DRM_DEV_ERROR(dev, "Fail to attach to dsi : %d\n", ret); - goto unregister_bridge; - } - } - if (platform->pdata.audio_en) anx7625_register_audio(dev, platform); @@ -2695,12 +2748,6 @@ static int anx7625_i2c_probe(struct i2c_client *client) return 0; -unregister_bridge: - drm_bridge_remove(&platform->bridge); - - if (!platform->pdata.low_power_mode) - pm_runtime_put_sync_suspend(&client->dev); - free_wq: if (platform->workqueue) destroy_workqueue(platform->workqueue); @@ -2753,7 +2800,7 @@ static struct i2c_driver anx7625_driver = { .of_match_table = anx_match_table, .pm = &anx7625_pm_ops, }, - .probe_new = anx7625_i2c_probe, + .probe = anx7625_i2c_probe, .remove = anx7625_i2c_remove, .id_table = anx7625_id, diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index 0e37840cd7a8..8bfce21d6b90 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -795,7 +795,7 @@ static struct i2c_device_id chipone_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, chipone_i2c_id); static struct i2c_driver chipone_i2c_driver = { - .probe_new = chipone_i2c_probe, + .probe = chipone_i2c_probe, .id_table = chipone_i2c_id, .driver = { .name = "chipone-icn6211-i2c", diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index 339b759e4c81..a854eb84e399 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -603,7 +603,7 @@ static const struct i2c_device_id ch7033_ids[] = { MODULE_DEVICE_TABLE(i2c, ch7033_ids); static struct i2c_driver ch7033_driver = { - .probe_new = ch7033_probe, + .probe = ch7033_probe, .remove = ch7033_remove, .driver = { .name = "ch7033", diff --git a/drivers/gpu/drm/bridge/cros-ec-anx7688.c b/drivers/gpu/drm/bridge/cros-ec-anx7688.c index fa91bdeddef0..c8abd9920fee 100644 --- a/drivers/gpu/drm/bridge/cros-ec-anx7688.c +++ b/drivers/gpu/drm/bridge/cros-ec-anx7688.c @@ -173,7 +173,7 @@ static const struct of_device_id cros_ec_anx7688_bridge_match_table[] = { MODULE_DEVICE_TABLE(of, cros_ec_anx7688_bridge_match_table); static struct i2c_driver cros_ec_anx7688_bridge_driver = { - .probe_new = cros_ec_anx7688_bridge_probe, + .probe = cros_ec_anx7688_bridge_probe, .remove = cros_ec_anx7688_bridge_remove, .driver = { .name = "cros-ec-anx7688-bridge", diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index 56ae511367b1..f7f436cf96e0 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -24,7 +24,7 @@ struct display_connector { struct gpio_desc *hpd_gpio; int hpd_irq; - struct regulator *dp_pwr; + struct regulator *supply; struct gpio_desc *ddc_en; }; @@ -191,6 +191,18 @@ static irqreturn_t display_connector_hpd_irq(int irq, void *arg) return IRQ_HANDLED; } +static int display_connector_get_supply(struct platform_device *pdev, + struct display_connector *conn, + const char *name) +{ + conn->supply = devm_regulator_get_optional(&pdev->dev, name); + + if (conn->supply == ERR_PTR(-ENODEV)) + conn->supply = NULL; + + return PTR_ERR_OR_ZERO(conn->supply); +} + static int display_connector_probe(struct platform_device *pdev) { struct display_connector *conn; @@ -316,36 +328,15 @@ static int display_connector_probe(struct platform_device *pdev) if (type == DRM_MODE_CONNECTOR_DisplayPort) { int ret; - conn->dp_pwr = devm_regulator_get_optional(&pdev->dev, "dp-pwr"); - - if (IS_ERR(conn->dp_pwr)) { - ret = PTR_ERR(conn->dp_pwr); - - switch (ret) { - case -ENODEV: - conn->dp_pwr = NULL; - break; - - case -EPROBE_DEFER: - return -EPROBE_DEFER; - - default: - dev_err(&pdev->dev, "failed to get DP PWR regulator: %d\n", ret); - return ret; - } - } - - if (conn->dp_pwr) { - ret = regulator_enable(conn->dp_pwr); - if (ret) { - dev_err(&pdev->dev, "failed to enable DP PWR regulator: %d\n", ret); - return ret; - } - } + ret = display_connector_get_supply(pdev, conn, "dp-pwr"); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to get DP PWR regulator\n"); } /* enable DDC */ if (type == DRM_MODE_CONNECTOR_HDMIA) { + int ret; + conn->ddc_en = devm_gpiod_get_optional(&pdev->dev, "ddc-en", GPIOD_OUT_HIGH); @@ -353,6 +344,18 @@ static int display_connector_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Couldn't get ddc-en gpio\n"); return PTR_ERR(conn->ddc_en); } + + ret = display_connector_get_supply(pdev, conn, "hdmi-pwr"); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to get HDMI +5V Power regulator\n"); + } + + if (conn->supply) { + ret = regulator_enable(conn->supply); + if (ret) { + dev_err(&pdev->dev, "failed to enable PWR regulator: %d\n", ret); + return ret; + } } conn->bridge.funcs = &display_connector_bridge_funcs; @@ -386,8 +389,8 @@ static void display_connector_remove(struct platform_device *pdev) if (conn->ddc_en) gpiod_set_value(conn->ddc_en, 0); - if (conn->dp_pwr) - regulator_disable(conn->dp_pwr); + if (conn->supply) + regulator_disable(conn->supply); drm_bridge_remove(&conn->bridge); diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c index 682623369498..b8e52156b07a 100644 --- a/drivers/gpu/drm/bridge/fsl-ldb.c +++ b/drivers/gpu/drm/bridge/fsl-ldb.c @@ -56,6 +56,7 @@ #define LVDS_CTRL_VBG_ADJ_MASK GENMASK(19, 17) enum fsl_ldb_devtype { + IMX6SX_LDB, IMX8MP_LDB, IMX93_LDB, }; @@ -64,9 +65,14 @@ struct fsl_ldb_devdata { u32 ldb_ctrl; u32 lvds_ctrl; bool lvds_en_bit; + bool single_ctrl_reg; }; static const struct fsl_ldb_devdata fsl_ldb_devdata[] = { + [IMX6SX_LDB] = { + .ldb_ctrl = 0x18, + .single_ctrl_reg = true, + }, [IMX8MP_LDB] = { .ldb_ctrl = 0x5c, .lvds_ctrl = 0x128, @@ -201,6 +207,9 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge, regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, reg); + if (fsl_ldb->devdata->single_ctrl_reg) + return; + /* Program LVDS_CTRL */ reg = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN | LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN; @@ -226,7 +235,8 @@ static void fsl_ldb_atomic_disable(struct drm_bridge *bridge, regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, LVDS_CTRL_LVDS_EN); else - regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, 0); + if (!fsl_ldb->devdata->single_ctrl_reg) + regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, 0); regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, 0); clk_disable_unprepare(fsl_ldb->clk); @@ -372,6 +382,8 @@ static void fsl_ldb_remove(struct platform_device *pdev) } static const struct of_device_id fsl_ldb_match[] = { + { .compatible = "fsl,imx6sx-ldb", + .data = &fsl_ldb_devdata[IMX6SX_LDB], }, { .compatible = "fsl,imx8mp-ldb", .data = &fsl_ldb_devdata[IMX8MP_LDB], }, { .compatible = "fsl,imx93-ldb", diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index abaf6e23775e..504d51c42f79 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -3207,7 +3207,7 @@ static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf, size_t len, loff_t *ppos) { struct it6505 *it6505 = file->private_data; - struct drm_display_mode *vid = &it6505->video_info; + struct drm_display_mode *vid; u8 read_buf[READ_BUFFER_SIZE]; u8 *str = read_buf, *end = read_buf + READ_BUFFER_SIZE; ssize_t ret, count; @@ -3216,6 +3216,7 @@ static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf, return -ENODEV; it6505_calc_video_info(it6505); + vid = &it6505->video_info; str += scnprintf(str, end - str, "---video timing---\n"); str += scnprintf(str, end - str, "PCLK:%d.%03dMHz\n", vid->clock / 1000, vid->clock % 1000); @@ -3478,7 +3479,7 @@ static struct i2c_driver it6505_i2c_driver = { .of_match_table = it6505_of_match, .pm = &it6505_bridge_pm_ops, }, - .probe_new = it6505_i2c_probe, + .probe = it6505_i2c_probe, .remove = it6505_i2c_remove, .shutdown = it6505_shutdown, .id_table = it6505_id, diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c index a2d723d6a4be..466641c77fe9 100644 --- a/drivers/gpu/drm/bridge/ite-it66121.c +++ b/drivers/gpu/drm/bridge/ite-it66121.c @@ -1640,7 +1640,7 @@ static struct i2c_driver it66121_driver = { .name = "it66121", .of_match_table = it66121_dt_match, }, - .probe_new = it66121_probe, + .probe = it66121_probe, .remove = it66121_remove, .id_table = it66121_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 13c131ade268..4eaea67fb71c 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -773,7 +773,7 @@ static struct i2c_driver lt8912_i2c_driver = { .name = "lt8912", .of_match_table = lt8912_dt_match, }, - .probe_new = lt8912_probe, + .probe = lt8912_probe, .remove = lt8912_remove, .id_table = lt8912_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c b/drivers/gpu/drm/bridge/lontium-lt9211.c index 3e19fff6547a..aa8d47e7f40d 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9211.c +++ b/drivers/gpu/drm/bridge/lontium-lt9211.c @@ -709,7 +709,9 @@ static int lt9211_host_attach(struct lt9211 *ctx) dsi->lanes = dsi_lanes; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_VIDEO_HSE; + MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_NO_HSA | + MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP | + MIPI_DSI_MODE_NO_EOT_PACKET; ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { @@ -785,7 +787,7 @@ static const struct of_device_id lt9211_match_table[] = { MODULE_DEVICE_TABLE(of, lt9211_match_table); static struct i2c_driver lt9211_driver = { - .probe_new = lt9211_probe, + .probe = lt9211_probe, .remove = lt9211_remove, .id_table = lt9211_id, .driver = { diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index a25d21a7d5c1..5163e5224aad 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -774,7 +774,9 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_VIDEO_HSE; + MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_NO_HSA | + MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP | + MIPI_DSI_MODE_NO_EOT_PACKET; ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { @@ -1190,7 +1192,7 @@ static struct i2c_driver lt9611_driver = { .name = "lt9611", .of_match_table = lt9611_match_table, }, - .probe_new = lt9611_probe, + .probe = lt9611_probe, .remove = lt9611_remove, .id_table = lt9611_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 583daacf3705..2a57e804ea02 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -1011,7 +1011,7 @@ static struct i2c_driver lt9611uxc_driver = { .of_match_table = lt9611uxc_match_table, .dev_groups = lt9611uxc_attr_groups, }, - .probe_new = lt9611uxc_probe, + .probe = lt9611uxc_probe, .remove = lt9611uxc_remove, .id_table = lt9611uxc_id, }; diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index 4fc494d9084b..460db3c8a08c 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -375,7 +375,7 @@ MODULE_DEVICE_TABLE(of, stdp4028_ge_b850v3_fw_match); static struct i2c_driver stdp4028_ge_b850v3_fw_driver = { .id_table = stdp4028_ge_b850v3_fw_i2c_table, - .probe_new = stdp4028_ge_b850v3_fw_probe, + .probe = stdp4028_ge_b850v3_fw_probe, .remove = stdp4028_ge_b850v3_fw_remove, .driver = { .name = "stdp4028-ge-b850v3-fw", @@ -422,7 +422,7 @@ MODULE_DEVICE_TABLE(of, stdp2690_ge_b850v3_fw_match); static struct i2c_driver stdp2690_ge_b850v3_fw_driver = { .id_table = stdp2690_ge_b850v3_fw_i2c_table, - .probe_new = stdp2690_ge_b850v3_fw_probe, + .probe = stdp2690_ge_b850v3_fw_probe, .remove = stdp2690_ge_b850v3_fw_remove, .driver = { .name = "stdp2690-ge-b850v3-fw", diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index cd292a2f894c..d81920227a8a 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -335,7 +335,7 @@ MODULE_DEVICE_TABLE(of, ptn3460_match); static struct i2c_driver ptn3460_driver = { .id_table = ptn3460_i2c_table, - .probe_new = ptn3460_probe, + .probe = ptn3460_probe, .remove = ptn3460_remove, .driver = { .name = "nxp,ptn3460", diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index efa80e309b98..c9b6cb7678e3 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table); static struct i2c_driver ps8622_driver = { .id_table = ps8622_i2c_table, - .probe_new = ps8622_probe, + .probe = ps8622_probe, .remove = ps8622_remove, .driver = { .name = "ps8622", diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index c3eb45179405..8801cdd033b5 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -791,7 +791,7 @@ static const struct of_device_id ps8640_match[] = { MODULE_DEVICE_TABLE(of, ps8640_match); static struct i2c_driver ps8640_driver = { - .probe_new = ps8640_probe, + .probe = ps8640_probe, .remove = ps8640_remove, .driver = { .name = "ps8640", diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index e0a402a85787..043b8109e64a 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -183,6 +183,8 @@ #define DSIM_AFC_CTL(x) (((x) & 0x7) << 5) /* DSIM_PLLCTRL */ +#define DSIM_PLL_DPDNSWAP_CLK (1 << 25) +#define DSIM_PLL_DPDNSWAP_DAT (1 << 24) #define DSIM_FREQ_BAND(x) ((x) << 24) #define DSIM_PLL_EN BIT(23) #define DSIM_PLL_P(x, offset) ((x) << (offset)) @@ -218,6 +220,8 @@ #define OLD_SCLK_MIPI_CLK_NAME "pll_clk" +#define PS_TO_CYCLE(ps, hz) DIV64_U64_ROUND_CLOSEST(((ps) * (hz)), 1000000000000ULL) + static const char *const clk_names[5] = { "bus_clk", "sclk_mipi", @@ -405,6 +409,9 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { @@ -418,6 +425,9 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { @@ -429,6 +439,9 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { @@ -441,6 +454,9 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .num_bits_resol = 12, .pll_p_offset = 13, .reg_values = exynos5433_reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { @@ -453,6 +469,9 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .num_bits_resol = 12, .pll_p_offset = 13, .reg_values = exynos5422_reg_values, + .m_min = 41, + .m_max = 125, + .min_freq = 500, }; static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { @@ -469,6 +488,9 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { */ .pll_p_offset = 14, .reg_values = imx8mm_dsim_reg_values, + .m_min = 64, + .m_max = 1023, + .min_freq = 1050, }; static const struct samsung_dsim_driver_data * @@ -547,12 +569,12 @@ static unsigned long samsung_dsim_pll_find_pms(struct samsung_dsim *dsi, tmp = (u64)fout * (_p << _s); do_div(tmp, fin); _m = tmp; - if (_m < 41 || _m > 125) + if (_m < driver_data->m_min || _m > driver_data->m_max) continue; tmp = (u64)_m * fin; do_div(tmp, _p); - if (tmp < 500 * MHZ || + if (tmp < driver_data->min_freq * MHZ || tmp > driver_data->max_freq * MHZ) continue; @@ -622,6 +644,11 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, reg |= DSIM_FREQ_BAND(band); } + if (dsi->swap_dn_dp_clk) + reg |= DSIM_PLL_DPDNSWAP_CLK; + if (dsi->swap_dn_dp_data) + reg |= DSIM_PLL_DPDNSWAP_DAT; + samsung_dsim_write(dsi, DSIM_PLLCTRL_REG, reg); timeout = 1000; @@ -633,16 +660,28 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, reg = samsung_dsim_read(dsi, DSIM_STATUS_REG); } while ((reg & DSIM_PLL_STABLE) == 0); + dsi->hs_clock = fout; + return fout; } static int samsung_dsim_enable_clock(struct samsung_dsim *dsi) { - unsigned long hs_clk, byte_clk, esc_clk; + unsigned long hs_clk, byte_clk, esc_clk, pix_clk; unsigned long esc_div; u32 reg; + struct drm_display_mode *m = &dsi->mode; + int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); + + /* m->clock is in KHz */ + pix_clk = m->clock * 1000; + + /* Use burst_clk_rate if available, otherwise use the pix_clk */ + if (dsi->burst_clk_rate) + hs_clk = samsung_dsim_set_pll(dsi, dsi->burst_clk_rate); + else + hs_clk = samsung_dsim_set_pll(dsi, DIV_ROUND_UP(pix_clk * bpp, dsi->lanes)); - hs_clk = samsung_dsim_set_pll(dsi, dsi->burst_clk_rate); if (!hs_clk) { dev_err(dsi->dev, "failed to configure DSI PLL\n"); return -EFAULT; @@ -680,13 +719,47 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; const unsigned int *reg_values = driver_data->reg_values; u32 reg; + struct phy_configure_opts_mipi_dphy cfg; + int clk_prepare, lpx, clk_zero, clk_post, clk_trail; + int hs_exit, hs_prepare, hs_zero, hs_trail; + unsigned long long byte_clock = dsi->hs_clock / 8; if (driver_data->has_freqband) return; + phy_mipi_dphy_get_default_config_for_hsclk(dsi->hs_clock, + dsi->lanes, &cfg); + + /* + * TODO: + * The tech Applications Processor manuals for i.MX8M Mini, Nano, + * and Plus don't state what the definition of the PHYTIMING + * bits are beyond their address and bit position. + * After reviewing NXP's downstream code, it appears + * that the various PHYTIMING registers take the number + * of cycles and use various dividers on them. This + * calculation does not result in an exact match to the + * downstream code, but it is very close to the values + * generated by their lookup table, and it appears + * to sync at a variety of resolutions. If someone + * can get a more accurate mathematical equation needed + * for these registers, this should be updated. + */ + + lpx = PS_TO_CYCLE(cfg.lpx, byte_clock); + hs_exit = PS_TO_CYCLE(cfg.hs_exit, byte_clock); + clk_prepare = PS_TO_CYCLE(cfg.clk_prepare, byte_clock); + clk_zero = PS_TO_CYCLE(cfg.clk_zero, byte_clock); + clk_post = PS_TO_CYCLE(cfg.clk_post, byte_clock); + clk_trail = PS_TO_CYCLE(cfg.clk_trail, byte_clock); + hs_prepare = PS_TO_CYCLE(cfg.hs_prepare, byte_clock); + hs_zero = PS_TO_CYCLE(cfg.hs_zero, byte_clock); + hs_trail = PS_TO_CYCLE(cfg.hs_trail, byte_clock); + /* B D-PHY: D-PHY Master & Slave Analog Block control */ reg = reg_values[PHYCTRL_ULPS_EXIT] | reg_values[PHYCTRL_VREG_LP] | reg_values[PHYCTRL_SLEW_UP]; + samsung_dsim_write(dsi, DSIM_PHYCTRL_REG, reg); /* @@ -694,7 +767,9 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) * T HS-EXIT: Time that the transmitter drives LP-11 following a HS * burst */ - reg = reg_values[PHYTIMING_LPX] | reg_values[PHYTIMING_HS_EXIT]; + + reg = DSIM_PHYTIMING_LPX(lpx) | DSIM_PHYTIMING_HS_EXIT(hs_exit); + samsung_dsim_write(dsi, DSIM_PHYTIMING_REG, reg); /* @@ -710,10 +785,11 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after * the last payload clock bit of a HS transmission burst */ - reg = reg_values[PHYTIMING_CLK_PREPARE] | - reg_values[PHYTIMING_CLK_ZERO] | - reg_values[PHYTIMING_CLK_POST] | - reg_values[PHYTIMING_CLK_TRAIL]; + + reg = DSIM_PHYTIMING1_CLK_PREPARE(clk_prepare) | + DSIM_PHYTIMING1_CLK_ZERO(clk_zero) | + DSIM_PHYTIMING1_CLK_POST(clk_post) | + DSIM_PHYTIMING1_CLK_TRAIL(clk_trail); samsung_dsim_write(dsi, DSIM_PHYTIMING1_REG, reg); @@ -726,8 +802,11 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) * T HS-TRAIL: Time that the transmitter drives the flipped differential * state after last payload data bit of a HS transmission burst */ - reg = reg_values[PHYTIMING_HS_PREPARE] | reg_values[PHYTIMING_HS_ZERO] | - reg_values[PHYTIMING_HS_TRAIL]; + + reg = DSIM_PHYTIMING2_HS_PREPARE(hs_prepare) | + DSIM_PHYTIMING2_HS_ZERO(hs_zero) | + DSIM_PHYTIMING2_HS_TRAIL(hs_trail); + samsung_dsim_write(dsi, DSIM_PHYTIMING2_REG, reg); } @@ -859,6 +938,10 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); reg &= ~DSIM_STOP_STATE_CNT_MASK; reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]); + + if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) + reg |= DSIM_FORCE_STOP_STATE; + samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); @@ -874,17 +957,29 @@ 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; + + /* remove packet overhead when possible */ + hfp = max(hfp - 6, 0); + hbp = max(hbp - 6, 0); + hsa = max(hsa - 6, 0); + + dev_dbg(dsi->dev, "calculated hfp: %u, hbp: %u, hsa: %u", + hfp, hbp, hsa); + reg = DSIM_CMD_ALLOW(0xf) | DSIM_STABLE_VFP(m->vsync_start - m->vdisplay) | DSIM_MAIN_VBP(m->vtotal - m->vsync_end); samsung_dsim_write(dsi, DSIM_MVPORCH_REG, reg); - reg = DSIM_MAIN_HFP(m->hsync_start - m->hdisplay) - | DSIM_MAIN_HBP(m->htotal - m->hsync_end); + reg = DSIM_MAIN_HFP(hfp) | DSIM_MAIN_HBP(hbp); samsung_dsim_write(dsi, DSIM_MHPORCH_REG, reg); reg = DSIM_MAIN_VSA(m->vsync_end - m->vsync_start) - | DSIM_MAIN_HSA(m->hsync_end - m->hsync_start); + | DSIM_MAIN_HSA(hsa); samsung_dsim_write(dsi, DSIM_MSYNC_REG, reg); } reg = DSIM_MAIN_HRESOL(m->hdisplay, num_bits_resol) | @@ -1340,6 +1435,9 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge, ret = samsung_dsim_init(dsi); if (ret) return; + + samsung_dsim_set_display_mode(dsi); + samsung_dsim_set_display_enable(dsi, true); } } @@ -1347,9 +1445,16 @@ 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; - samsung_dsim_set_display_mode(dsi); - samsung_dsim_set_display_enable(dsi, true); + 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); + } dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1358,10 +1463,17 @@ 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); + } + dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1682,11 +1794,11 @@ static const struct mipi_dsi_host_ops samsung_dsim_ops = { }; static int samsung_dsim_of_read_u32(const struct device_node *np, - const char *propname, u32 *out_value) + const char *propname, u32 *out_value, bool optional) { int ret = of_property_read_u32(np, propname, out_value); - if (ret < 0) + if (ret < 0 && !optional) pr_err("%pOF: failed to get '%s' property\n", np, propname); return ret; @@ -1696,23 +1808,52 @@ static int samsung_dsim_parse_dt(struct samsung_dsim *dsi) { struct device *dev = dsi->dev; struct device_node *node = dev->of_node; - int ret; + 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); - if (ret < 0) - return ret; + &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); + } + /* If it doesn't exist, use pixel clock instead of failing */ ret = samsung_dsim_of_read_u32(node, "samsung,burst-clock-frequency", - &dsi->burst_clk_rate); - if (ret < 0) - return ret; + &dsi->burst_clk_rate, 1); + if (ret < 0) { + dev_dbg(dev, "Using pixel clock for HS clock frequency\n"); + dsi->burst_clk_rate = 0; + } ret = samsung_dsim_of_read_u32(node, "samsung,esc-clock-frequency", - &dsi->esc_clk_rate); + &dsi->esc_clk_rate, 0); if (ret < 0) return ret; + endpoint = of_graph_get_endpoint_by_regs(node, 1, -1); + nr_lanes = of_property_count_u32_elems(endpoint, "data-lanes"); + if (nr_lanes > 0 && nr_lanes <= 4) { + /* Polarity 0 is clock lane, 1..4 are data lanes. */ + of_property_read_u32_array(endpoint, "lane-polarities", + lane_polarities, nr_lanes + 1); + for (i = 1; i <= nr_lanes; i++) { + if (lane_polarities[1] != lane_polarities[i]) + DRM_DEV_ERROR(dsi->dev, "Data lanes polarities do not match"); + } + if (lane_polarities[0]) + dsi->swap_dn_dp_clk = true; + if (lane_polarities[1]) + dsi->swap_dn_dp_data = true; + } + return 0; } @@ -1954,7 +2095,6 @@ static struct platform_driver samsung_dsim_driver = { .remove = samsung_dsim_remove, .driver = { .name = "samsung-dsim", - .owner = THIS_MODULE, .pm = &samsung_dsim_pm_ops, .of_match_table = samsung_dsim_of_match, }, diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index ef66461e7f7c..aac239729a1d 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -1151,7 +1151,7 @@ static const struct i2c_device_id sii902x_i2c_ids[] = { MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids); static struct i2c_driver sii902x_driver = { - .probe_new = sii902x_probe, + .probe = sii902x_probe, .remove = sii902x_remove, .driver = { .name = "sii902x", diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index 2d17f227867b..d8373d918324 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -955,7 +955,7 @@ static struct i2c_driver sii9234_driver = { .name = "sii9234", .of_match_table = sii9234_dt_match, }, - .probe_new = sii9234_probe, + .probe = sii9234_probe, .remove = sii9234_remove, .id_table = sii9234_id, }; diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index b96d03cd878d..79b09ccd1353 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2378,7 +2378,7 @@ static struct i2c_driver sii8620_driver = { .name = "sii8620", .of_match_table = of_match_ptr(sii8620_dt_match), }, - .probe_new = sii8620_probe, + .probe = sii8620_probe, .remove = sii8620_remove, .id_table = sii8620_id, }; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 603bb3c51027..9d6dcaf317a1 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -533,7 +533,7 @@ static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi) adap->owner = THIS_MODULE; adap->dev.parent = hdmi->dev; adap->algo = &dw_hdmi_algorithm; - strlcpy(adap->name, "DesignWare HDMI", sizeof(adap->name)); + strscpy(adap->name, "DesignWare HDMI", sizeof(adap->name)); i2c_set_adapdata(adap, hdmi); ret = i2c_add_adapter(adap); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 91f7cb56a654..65dc842e31f0 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1781,7 +1781,200 @@ static const struct drm_bridge_funcs tc_edp_bridge_funcs = { static bool tc_readable_reg(struct device *dev, unsigned int reg) { - return reg != SYSCTRL; + switch (reg) { + /* DSI D-PHY Layer */ + case 0x004: + case 0x020: + case 0x024: + case 0x028: + case 0x02c: + case 0x030: + case 0x038: + case 0x040: + case 0x044: + case 0x048: + case 0x04c: + case 0x050: + case 0x054: + /* DSI PPI Layer */ + case PPI_STARTPPI: + case 0x108: + case 0x110: + case PPI_LPTXTIMECNT: + case PPI_LANEENABLE: + case PPI_TX_RX_TA: + case 0x140: + case PPI_D0S_ATMR: + case PPI_D1S_ATMR: + case 0x14c: + case 0x150: + case PPI_D0S_CLRSIPOCOUNT: + case PPI_D1S_CLRSIPOCOUNT: + case PPI_D2S_CLRSIPOCOUNT: + case PPI_D3S_CLRSIPOCOUNT: + case 0x180: + case 0x184: + case 0x188: + case 0x18c: + case 0x190: + case 0x1a0: + case 0x1a4: + case 0x1a8: + case 0x1ac: + case 0x1b0: + case 0x1c0: + case 0x1c4: + case 0x1c8: + case 0x1cc: + case 0x1d0: + case 0x1e0: + case 0x1e4: + case 0x1f0: + case 0x1f4: + /* DSI Protocol Layer */ + case DSI_STARTDSI: + case 0x208: + case DSI_LANEENABLE: + case 0x214: + case 0x218: + case 0x220: + case 0x224: + case 0x228: + case 0x230: + /* DSI General */ + case 0x300: + /* DSI Application Layer */ + case 0x400: + case 0x404: + /* DPI */ + case DPIPXLFMT: + /* Parallel Output */ + case POCTRL: + /* Video Path0 Configuration */ + case VPCTRL0: + case HTIM01: + case HTIM02: + case VTIM01: + case VTIM02: + case VFUEN0: + /* System */ + case TC_IDREG: + case 0x504: + case SYSSTAT: + case SYSRSTENB: + case SYSCTRL: + /* I2C */ + case 0x520: + /* GPIO */ + case GPIOM: + case GPIOC: + case GPIOO: + case GPIOI: + /* Interrupt */ + case INTCTL_G: + case INTSTS_G: + case 0x570: + case 0x574: + case INT_GP0_LCNT: + case INT_GP1_LCNT: + /* DisplayPort Control */ + case DP0CTL: + /* DisplayPort Clock */ + case DP0_VIDMNGEN0: + case DP0_VIDMNGEN1: + case DP0_VMNGENSTATUS: + case 0x628: + case 0x62c: + case 0x630: + /* DisplayPort Main Channel */ + case DP0_SECSAMPLE: + case DP0_VIDSYNCDELAY: + case DP0_TOTALVAL: + case DP0_STARTVAL: + case DP0_ACTIVEVAL: + case DP0_SYNCVAL: + case DP0_MISC: + /* DisplayPort Aux Channel */ + case DP0_AUXCFG0: + case DP0_AUXCFG1: + case DP0_AUXADDR: + case 0x66c: + case 0x670: + case 0x674: + case 0x678: + case 0x67c: + case 0x680: + case 0x684: + case 0x688: + case DP0_AUXSTATUS: + case DP0_AUXI2CADR: + /* DisplayPort Link Training */ + case DP0_SRCCTRL: + case DP0_LTSTAT: + case DP0_SNKLTCHGREQ: + case DP0_LTLOOPCTRL: + case DP0_SNKLTCTRL: + case 0x6e8: + case 0x6ec: + case 0x6f0: + case 0x6f4: + /* DisplayPort Audio */ + case 0x700: + case 0x704: + case 0x708: + case 0x70c: + case 0x710: + case 0x714: + case 0x718: + case 0x71c: + case 0x720: + /* DisplayPort Source Control */ + case DP1_SRCCTRL: + /* DisplayPort PHY */ + case DP_PHY_CTRL: + case 0x810: + case 0x814: + case 0x820: + case 0x840: + /* I2S */ + case 0x880: + case 0x888: + case 0x88c: + case 0x890: + case 0x894: + case 0x898: + case 0x89c: + case 0x8a0: + case 0x8a4: + case 0x8a8: + case 0x8ac: + case 0x8b0: + case 0x8b4: + /* PLL */ + case DP0_PLLCTRL: + case DP1_PLLCTRL: + case PXL_PLLCTRL: + case PXL_PLLPARAM: + case SYS_PLLPARAM: + /* HDCP */ + case 0x980: + case 0x984: + case 0x988: + case 0x98c: + case 0x990: + case 0x994: + case 0x998: + case 0x99c: + case 0x9a0: + case 0x9a4: + case 0x9a8: + case 0x9ac: + /* Debug */ + case TSTCTL: + case PLL_DBG: + return true; + } + return false; } static const struct regmap_range tc_volatile_ranges[] = { @@ -1890,7 +2083,7 @@ static int tc_mipi_dsi_host_attach(struct tc_data *tc) if (dsi_lanes < 0) return dsi_lanes; - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) return dev_err_probe(dev, PTR_ERR(dsi), "failed to create dsi device\n"); @@ -1901,7 +2094,7 @@ static int tc_mipi_dsi_host_attach(struct tc_data *tc) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; - ret = mipi_dsi_attach(dsi); + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { dev_err(dev, "failed to attach dsi to host: %d\n", ret); return ret; @@ -2209,7 +2402,7 @@ static struct i2c_driver tc358767_driver = { .of_match_table = tc358767_of_ids, }, .id_table = tc358767_i2c_ids, - .probe_new = tc_probe, + .probe = tc_probe, .remove = tc_remove, }; module_i2c_driver(tc358767_driver); diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index 7c0cbe84611b..819a4b6ec2a0 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -9,6 +9,8 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/kernel.h> +#include <linux/media-bus-format.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -146,6 +148,7 @@ struct tc358768_priv { u32 pd_lines; /* number of Parallel Port Input Data Lines */ u32 dsi_lanes; /* number of DSI Lanes */ + u32 dsi_bpp; /* number of Bits Per Pixel over DSI */ /* Parameters for PLL programming */ u32 fbd; /* PLL feedback divider */ @@ -284,12 +287,12 @@ static void tc358768_hw_disable(struct tc358768_priv *priv) static u32 tc358768_pll_to_pclk(struct tc358768_priv *priv, u32 pll_clk) { - return (u32)div_u64((u64)pll_clk * priv->dsi_lanes, priv->pd_lines); + return (u32)div_u64((u64)pll_clk * priv->dsi_lanes, priv->dsi_bpp); } static u32 tc358768_pclk_to_pll(struct tc358768_priv *priv, u32 pclk) { - return (u32)div_u64((u64)pclk * priv->pd_lines, priv->dsi_lanes); + return (u32)div_u64((u64)pclk * priv->dsi_bpp, priv->dsi_lanes); } static int tc358768_calc_pll(struct tc358768_priv *priv, @@ -334,13 +337,17 @@ static int tc358768_calc_pll(struct tc358768_priv *priv, u32 fbd; for (fbd = 0; fbd < 512; ++fbd) { - u32 pll, diff; + u32 pll, diff, pll_in; pll = (u32)div_u64((u64)refclk * (fbd + 1), divisor); if (pll >= max_pll || pll < min_pll) continue; + pll_in = (u32)div_u64((u64)refclk, prd + 1); + if (pll_in < 4000000) + continue; + diff = max(pll, target_pll) - min(pll, target_pll); if (diff < best_diff) { @@ -422,6 +429,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, priv->output.panel = panel; priv->dsi_lanes = dev->lanes; + priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format); /* get input ep (port0/endpoint0) */ ret = -EINVAL; @@ -433,7 +441,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, } if (ret) - priv->pd_lines = mipi_dsi_pixel_format_to_bpp(dev->format); + priv->pd_lines = priv->dsi_bpp; drm_bridge_add(&priv->bridge); @@ -632,8 +640,9 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) struct mipi_dsi_device *dsi_dev = priv->output.dev; unsigned long mode_flags = dsi_dev->mode_flags; u32 val, val2, lptxcnt, hact, data_type; + s32 raw_val; const struct drm_display_mode *mode; - u32 dsibclk_nsk, dsiclk_nsk, ui_nsk, phy_delay_nsk; + u32 dsibclk_nsk, dsiclk_nsk, ui_nsk; u32 dsiclk, dsibclk, video_start; const u32 internal_delay = 40; int ret, i; @@ -717,11 +726,9 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) dsibclk); dsiclk_nsk = (u32)div_u64((u64)1000000000 * TC358768_PRECISION, dsiclk); ui_nsk = dsiclk_nsk / 2; - phy_delay_nsk = dsibclk_nsk + 2 * dsiclk_nsk; 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); - dev_dbg(priv->dev, "phy_delay_nsk: %u\n", phy_delay_nsk); /* LP11 > 100us for D-PHY Rx Init */ val = tc358768_ns_to_cnt(100 * 1000, dsibclk_nsk) - 1; @@ -736,25 +743,26 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) /* 38ns < TCLK_PREPARE < 95ns */ val = tc358768_ns_to_cnt(65, dsibclk_nsk) - 1; - /* TCLK_PREPARE > 300ns */ - val2 = tc358768_ns_to_cnt(300 + tc358768_to_ns(3 * ui_nsk), - dsibclk_nsk); - val |= (val2 - tc358768_to_ns(phy_delay_nsk - dsibclk_nsk)) << 8; + /* TCLK_PREPARE + TCLK_ZERO > 300ns */ + val2 = tc358768_ns_to_cnt(300 - tc358768_to_ns(2 * ui_nsk), + dsibclk_nsk) - 2; + val |= val2 << 8; dev_dbg(priv->dev, "TCLK_HEADERCNT: 0x%x\n", val); tc358768_write(priv, TC358768_TCLK_HEADERCNT, val); - /* TCLK_TRAIL > 60ns + 3*UI */ - val = 60 + tc358768_to_ns(3 * ui_nsk); - val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 5; + /* 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; + val = clamp(raw_val, 0, 127); dev_dbg(priv->dev, "TCLK_TRAILCNT: 0x%x\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; - /* THS_ZERO > 145ns + 10*UI */ - val2 = tc358768_ns_to_cnt(145 - tc358768_to_ns(ui_nsk), dsibclk_nsk); - val |= (val2 - tc358768_to_ns(phy_delay_nsk)) << 8; + /* THS_PREPARE + THS_ZERO > 145ns + 10*UI */ + raw_val = tc358768_ns_to_cnt(145 - tc358768_to_ns(3 * ui_nsk), dsibclk_nsk) - 10; + val2 = clamp(raw_val, 0, 127); + val |= val2 << 8; dev_dbg(priv->dev, "THS_HEADERCNT: 0x%x\n", val); tc358768_write(priv, TC358768_THS_HEADERCNT, val); @@ -770,9 +778,10 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) dev_dbg(priv->dev, "TCLK_POSTCNT: 0x%x\n", val); tc358768_write(priv, TC358768_TCLK_POSTCNT, val); - /* 60ns + 4*UI < THS_PREPARE < 105ns + 12*UI */ - val = tc358768_ns_to_cnt(60 + tc358768_to_ns(15 * ui_nsk), - dsibclk_nsk) - 5; + /* 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; + val = clamp(raw_val, 0, 15); dev_dbg(priv->dev, "THS_TRAILCNT: 0x%x\n", val); tc358768_write(priv, TC358768_THS_TRAILCNT, val); @@ -786,7 +795,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) /* TXTAGOCNT[26:16] RXTASURECNT[10:0] */ val = tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk * 4); - val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 1; + 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 = val << 16 | val2; @@ -866,8 +875,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) val = TC358768_DSI_CONFW_MODE_SET | TC358768_DSI_CONFW_ADDR_DSI_CONTROL; val |= (dsi_dev->lanes - 1) << 1; - if (!(dsi_dev->mode_flags & MIPI_DSI_MODE_LPM)) - val |= TC358768_DSI_CONTROL_TXMD; + val |= TC358768_DSI_CONTROL_TXMD; if (!(mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) val |= TC358768_DSI_CONTROL_HSCKMD; @@ -913,6 +921,44 @@ static void tc358768_bridge_enable(struct drm_bridge *bridge) } } +#define MAX_INPUT_SEL_FORMATS 1 + +static u32 * +tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct tc358768_priv *priv = bridge_to_tc358768(bridge); + u32 *input_fmts; + + *num_input_fmts = 0; + + input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), + GFP_KERNEL); + if (!input_fmts) + return NULL; + + switch (priv->pd_lines) { + case 16: + input_fmts[0] = MEDIA_BUS_FMT_RGB565_1X16; + break; + case 18: + input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X18; + break; + default: + case 24: + input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; + break; + } + + *num_input_fmts = MAX_INPUT_SEL_FORMATS; + + return input_fmts; +} + static const struct drm_bridge_funcs tc358768_bridge_funcs = { .attach = tc358768_bridge_attach, .mode_valid = tc358768_bridge_mode_valid, @@ -920,6 +966,11 @@ static const struct drm_bridge_funcs tc358768_bridge_funcs = { .enable = tc358768_bridge_enable, .disable = tc358768_bridge_disable, .post_disable = tc358768_bridge_post_disable, + + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_get_input_bus_fmts = tc358768_atomic_get_input_bus_fmts, }; static const struct drm_bridge_timings default_tc358768_timings = { @@ -1083,7 +1134,7 @@ static struct i2c_driver tc358768_driver = { .of_match_table = tc358768_of_ids, }, .id_table = tc358768_i2c_ids, - .probe_new = tc358768_i2c_probe, + .probe = tc358768_i2c_probe, .remove = tc358768_i2c_remove, }; module_i2c_driver(tc358768_driver); diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c index 19316994ddd1..90a89d70d832 100644 --- a/drivers/gpu/drm/bridge/tc358775.c +++ b/drivers/gpu/drm/bridge/tc358775.c @@ -728,7 +728,7 @@ static struct i2c_driver tc358775_driver = { .of_match_table = tc358775_of_ids, }, .id_table = tc358775_i2c_ids, - .probe_new = tc_probe, + .probe = tc_probe, .remove = tc_remove, }; module_i2c_driver(tc358775_driver); diff --git a/drivers/gpu/drm/bridge/ti-dlpc3433.c b/drivers/gpu/drm/bridge/ti-dlpc3433.c index 186a9e2ff24d..b65632ec7e7d 100644 --- a/drivers/gpu/drm/bridge/ti-dlpc3433.c +++ b/drivers/gpu/drm/bridge/ti-dlpc3433.c @@ -400,7 +400,7 @@ static const struct of_device_id dlpc3433_match_table[] = { MODULE_DEVICE_TABLE(of, dlpc3433_match_table); static struct i2c_driver dlpc3433_driver = { - .probe_new = dlpc3433_probe, + .probe = dlpc3433_probe, .remove = dlpc3433_remove, .id_table = dlpc3433_id, .driver = { diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 75286c9afbb9..7e9f4ec8e780 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -321,8 +321,8 @@ static u8 sn65dsi83_get_dsi_div(struct sn65dsi83 *ctx) return dsi_div - 1; } -static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); struct drm_atomic_state *state = old_bridge_state->base.state; @@ -478,17 +478,29 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret); /* On failure, disable PLL again and exit. */ regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00); + regulator_disable(ctx->vcc); return; } /* Trigger reset after CSR register update. */ regmap_write(ctx->regmap, REG_RC_RESET, REG_RC_RESET_SOFT_RESET); + /* Wait for 10ms after soft reset as specified in datasheet */ + usleep_range(10000, 12000); +} + +static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); + unsigned int pval; + /* Clear all errors that got asserted during initialization. */ regmap_read(ctx->regmap, REG_IRQ_STAT, &pval); regmap_write(ctx->regmap, REG_IRQ_STAT, pval); - usleep_range(10000, 12000); + /* Wait for 1ms and check for errors in status register */ + usleep_range(1000, 1100); regmap_read(ctx->regmap, REG_IRQ_STAT, &pval); if (pval) dev_err(ctx->dev, "Unexpected link status 0x%02x\n", pval); @@ -555,6 +567,7 @@ static const struct drm_bridge_funcs sn65dsi83_funcs = { .attach = sn65dsi83_attach, .detach = sn65dsi83_detach, .atomic_enable = sn65dsi83_atomic_enable, + .atomic_pre_enable = sn65dsi83_atomic_pre_enable, .atomic_disable = sn65dsi83_atomic_disable, .mode_valid = sn65dsi83_mode_valid, @@ -697,6 +710,7 @@ static int sn65dsi83_probe(struct i2c_client *client) ctx->bridge.funcs = &sn65dsi83_funcs; ctx->bridge.of_node = dev->of_node; + ctx->bridge.pre_enable_prev_first = true; drm_bridge_add(&ctx->bridge); ret = sn65dsi83_host_attach(ctx); @@ -734,7 +748,7 @@ static const struct of_device_id sn65dsi83_match_table[] = { MODULE_DEVICE_TABLE(of, sn65dsi83_match_table); static struct i2c_driver sn65dsi83_driver = { - .probe_new = sn65dsi83_probe, + .probe = sn65dsi83_probe, .remove = sn65dsi83_remove, .id_table = sn65dsi83_id, .driver = { diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 7a748785c545..597ceb7024e0 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -618,6 +618,24 @@ exit: return len; } +static int ti_sn_aux_wait_hpd_asserted(struct drm_dp_aux *aux, unsigned long wait_us) +{ + /* + * The HPD in this chip is a bit useless (See comment in + * ti_sn65dsi86_enable_comms) so if our driver is expected to wait + * for HPD, we just assume it's asserted after the wait_us delay. + * + * In case we are asked to wait forever (wait_us=0) take conservative + * 500ms delay. + */ + if (wait_us == 0) + wait_us = 500000; + + usleep_range(wait_us, wait_us + 1000); + + return 0; +} + static int ti_sn_aux_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) { @@ -627,6 +645,7 @@ static int ti_sn_aux_probe(struct auxiliary_device *adev, pdata->aux.name = "ti-sn65dsi86-aux"; pdata->aux.dev = &adev->dev; pdata->aux.transfer = ti_sn_aux_transfer; + pdata->aux.wait_hpd_asserted = ti_sn_aux_wait_hpd_asserted; drm_dp_aux_init(&pdata->aux); ret = devm_of_dp_aux_populate_ep_devices(&pdata->aux); @@ -1951,7 +1970,7 @@ static struct i2c_driver ti_sn65dsi86_driver = { .of_match_table = ti_sn65dsi86_match_table, .pm = &ti_sn65dsi86_pm_ops, }, - .probe_new = ti_sn65dsi86_probe, + .probe = ti_sn65dsi86_probe, .id_table = ti_sn65dsi86_id, }; diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index ab63225cd635..c06390da9ffd 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -408,7 +408,7 @@ static struct i2c_driver tfp410_i2c_driver = { .of_match_table = of_match_ptr(tfp410_match), }, .id_table = tfp410_i2c_ids, - .probe_new = tfp410_i2c_probe, + .probe = tfp410_i2c_probe, .remove = tfp410_i2c_remove, }; #endif /* IS_ENABLED(CONFIG_I2C) */ diff --git a/drivers/gpu/drm/display/drm_dp_aux_dev.c b/drivers/gpu/drm/display/drm_dp_aux_dev.c index 098e482e65a2..29555b9f03c8 100644 --- a/drivers/gpu/drm/display/drm_dp_aux_dev.c +++ b/drivers/gpu/drm/display/drm_dp_aux_dev.c @@ -330,7 +330,7 @@ int drm_dp_aux_dev_init(void) { int res; - drm_dp_aux_dev_class = class_create(THIS_MODULE, "drm_dp_aux_dev"); + drm_dp_aux_dev_class = class_create("drm_dp_aux_dev"); if (IS_ERR(drm_dp_aux_dev_class)) { return PTR_ERR(drm_dp_aux_dev_class); } diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c index 3b8fdeeafd53..5729f3bb4398 100644 --- a/drivers/gpu/drm/drm_aperture.c +++ b/drivers/gpu/drm/drm_aperture.c @@ -32,17 +32,13 @@ * * static int remove_conflicting_framebuffers(struct pci_dev *pdev) * { - * bool primary = false; * resource_size_t base, size; * int ret; * * base = pci_resource_start(pdev, 0); * size = pci_resource_len(pdev, 0); - * #ifdef CONFIG_X86 - * primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; - * #endif * - * return drm_aperture_remove_conflicting_framebuffers(base, size, primary, + * return drm_aperture_remove_conflicting_framebuffers(base, size, * &example_driver); * } * @@ -161,7 +157,6 @@ EXPORT_SYMBOL(devm_aperture_acquire_from_firmware); * drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range * @base: the aperture's base address in physical memory * @size: aperture size in bytes - * @primary: also kick vga16fb if present * @req_driver: requesting DRM driver * * This function removes graphics device drivers which use the memory range described by @@ -171,9 +166,9 @@ EXPORT_SYMBOL(devm_aperture_acquire_from_firmware); * 0 on success, or a negative errno code otherwise */ int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, - bool primary, const struct drm_driver *req_driver) + const struct drm_driver *req_driver) { - return aperture_remove_conflicting_devices(base, size, primary, req_driver->name); + return aperture_remove_conflicting_devices(base, size, req_driver->name); } EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 2c2c9caf0be5..41b8066f61ff 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1209,7 +1209,16 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) continue; ret = drm_crtc_vblank_get(crtc); - WARN_ONCE(ret != -EINVAL, "driver forgot to call drm_crtc_vblank_off()\n"); + /* + * Self-refresh is not a true "disable"; ensure vblank remains + * enabled. + */ + if (new_crtc_state->self_refresh_active) + WARN_ONCE(ret != 0, + "driver disabled vblank in self-refresh\n"); + else + WARN_ONCE(ret != -EINVAL, + "driver forgot to call drm_crtc_vblank_off()\n"); if (ret == 0) drm_crtc_vblank_put(crtc); } @@ -3145,7 +3154,7 @@ fail: EXPORT_SYMBOL(drm_atomic_helper_update_plane); /** - * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic + * drm_atomic_helper_disable_plane - Helper for primary plane disable using atomic * @plane: plane to disable * @ctx: lock acquire context * diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 3d1f50f481cf..7098f125b54a 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -146,8 +146,8 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) unsigned int order; u64 root_size; - root_size = rounddown_pow_of_two(size); - order = ilog2(root_size) - ilog2(chunk_size); + order = ilog2(size) - ilog2(chunk_size); + root_size = chunk_size << order; root = drm_block_alloc(mm, NULL, order, offset); if (!root) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index cee0cc522ed9..12687dd9e1ac 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -969,7 +969,9 @@ EXPORT_SYMBOL(drm_dev_register); * * Unregister the DRM device from the system. This does the reverse of * drm_dev_register() but does not deallocate the device. The caller must call - * drm_dev_put() to drop their final reference. + * drm_dev_put() to drop their final reference, unless it is managed with devres + * (as devices allocated with devm_drm_dev_alloc() are), in which case there is + * already an unwind action registered. * * A special form of unregistering for hotpluggable devices is drm_dev_unplug(), * which can be called while there are still open users of @dev. diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 64458982be40..9978147bbc8a 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -641,19 +641,27 @@ static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y, static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off, size_t len, struct drm_rect *clip) { + u32 line_length = info->fix.line_length; + u32 fb_height = info->var.yres; off_t end = off + len; u32 x1 = 0; - u32 y1 = off / info->fix.line_length; + u32 y1 = off / line_length; u32 x2 = info->var.xres; - u32 y2 = DIV_ROUND_UP(end, info->fix.line_length); + u32 y2 = DIV_ROUND_UP(end, line_length); + + /* Don't allow any of them beyond the bottom bound of display area */ + if (y1 > fb_height) + y1 = fb_height; + if (y2 > fb_height) + y2 = fb_height; if ((y2 - y1) == 1) { /* * We've only written to a single scanline. Try to reduce * the number of horizontal pixels that need an update. */ - off_t bit_off = (off % info->fix.line_length) * 8; - off_t bit_end = (end % info->fix.line_length) * 8; + off_t bit_off = (off % line_length) * 8; + off_t bit_end = (end % line_length) * 8; x1 = bit_off / info->var.bits_per_pixel; x2 = DIV_ROUND_UP(bit_end, info->var.bits_per_pixel); @@ -662,6 +670,28 @@ static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off, drm_rect_init(clip, x1, y1, x2 - x1, y2 - y1); } +/* Don't use in new code. */ +void drm_fb_helper_damage_range(struct fb_info *info, off_t off, size_t len) +{ + struct drm_fb_helper *fb_helper = info->par; + struct drm_rect damage_area; + + drm_fb_helper_memory_range_to_clip(info, off, len, &damage_area); + drm_fb_helper_damage(fb_helper, damage_area.x1, damage_area.y1, + drm_rect_width(&damage_area), + drm_rect_height(&damage_area)); +} +EXPORT_SYMBOL(drm_fb_helper_damage_range); + +/* Don't use in new code. */ +void drm_fb_helper_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) +{ + struct drm_fb_helper *fb_helper = info->par; + + drm_fb_helper_damage(fb_helper, x, y, width, height); +} +EXPORT_SYMBOL(drm_fb_helper_damage_area); + /** * drm_fb_helper_deferred_io() - fbdev deferred_io callback function * @info: fb_info struct pointer @@ -706,386 +736,6 @@ void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagerefli } EXPORT_SYMBOL(drm_fb_helper_deferred_io); -typedef ssize_t (*drm_fb_helper_read_screen)(struct fb_info *info, char __user *buf, - size_t count, loff_t pos); - -static ssize_t __drm_fb_helper_read(struct fb_info *info, char __user *buf, size_t count, - loff_t *ppos, drm_fb_helper_read_screen read_screen) -{ - loff_t pos = *ppos; - size_t total_size; - ssize_t ret; - - if (info->screen_size) - total_size = info->screen_size; - else - total_size = info->fix.smem_len; - - if (pos >= total_size) - return 0; - if (count >= total_size) - count = total_size; - if (total_size - count < pos) - count = total_size - pos; - - if (info->fbops->fb_sync) - info->fbops->fb_sync(info); - - ret = read_screen(info, buf, count, pos); - if (ret > 0) - *ppos += ret; - - return ret; -} - -typedef ssize_t (*drm_fb_helper_write_screen)(struct fb_info *info, const char __user *buf, - size_t count, loff_t pos); - -static ssize_t __drm_fb_helper_write(struct fb_info *info, const char __user *buf, size_t count, - loff_t *ppos, drm_fb_helper_write_screen write_screen) -{ - loff_t pos = *ppos; - size_t total_size; - ssize_t ret; - int err = 0; - - if (info->screen_size) - total_size = info->screen_size; - else - total_size = info->fix.smem_len; - - if (pos > total_size) - return -EFBIG; - if (count > total_size) { - err = -EFBIG; - count = total_size; - } - if (total_size - count < pos) { - if (!err) - err = -ENOSPC; - count = total_size - pos; - } - - if (info->fbops->fb_sync) - info->fbops->fb_sync(info); - - /* - * Copy to framebuffer even if we already logged an error. Emulates - * the behavior of the original fbdev implementation. - */ - ret = write_screen(info, buf, count, pos); - if (ret < 0) - return ret; /* return last error, if any */ - else if (!ret) - return err; /* return previous error, if any */ - - *ppos += ret; - - return ret; -} - -static ssize_t drm_fb_helper_read_screen_buffer(struct fb_info *info, char __user *buf, - size_t count, loff_t pos) -{ - const char *src = info->screen_buffer + pos; - - if (copy_to_user(buf, src, count)) - return -EFAULT; - - return count; -} - -/** - * drm_fb_helper_sys_read - Implements struct &fb_ops.fb_read for system memory - * @info: fb_info struct pointer - * @buf: userspace buffer to read from framebuffer memory - * @count: number of bytes to read from framebuffer memory - * @ppos: read offset within framebuffer memory - * - * Returns: - * The number of bytes read on success, or an error code otherwise. - */ -ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos) -{ - return __drm_fb_helper_read(info, buf, count, ppos, drm_fb_helper_read_screen_buffer); -} -EXPORT_SYMBOL(drm_fb_helper_sys_read); - -static ssize_t drm_fb_helper_write_screen_buffer(struct fb_info *info, const char __user *buf, - size_t count, loff_t pos) -{ - char *dst = info->screen_buffer + pos; - - if (copy_from_user(dst, buf, count)) - return -EFAULT; - - return count; -} - -/** - * drm_fb_helper_sys_write - Implements struct &fb_ops.fb_write for system memory - * @info: fb_info struct pointer - * @buf: userspace buffer to write to framebuffer memory - * @count: number of bytes to write to framebuffer memory - * @ppos: write offset within framebuffer memory - * - * Returns: - * The number of bytes written on success, or an error code otherwise. - */ -ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct drm_fb_helper *helper = info->par; - loff_t pos = *ppos; - ssize_t ret; - struct drm_rect damage_area; - - ret = __drm_fb_helper_write(info, buf, count, ppos, drm_fb_helper_write_screen_buffer); - if (ret <= 0) - return ret; - - if (helper->funcs->fb_dirty) { - drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area); - drm_fb_helper_damage(helper, damage_area.x1, damage_area.y1, - drm_rect_width(&damage_area), - drm_rect_height(&damage_area)); - } - - return ret; -} -EXPORT_SYMBOL(drm_fb_helper_sys_write); - -/** - * drm_fb_helper_sys_fillrect - wrapper around sys_fillrect - * @info: fbdev registered by the helper - * @rect: info about rectangle to fill - * - * A wrapper around sys_fillrect implemented by fbdev core - */ -void drm_fb_helper_sys_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct drm_fb_helper *helper = info->par; - - sys_fillrect(info, rect); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, rect->dx, rect->dy, rect->width, rect->height); -} -EXPORT_SYMBOL(drm_fb_helper_sys_fillrect); - -/** - * drm_fb_helper_sys_copyarea - wrapper around sys_copyarea - * @info: fbdev registered by the helper - * @area: info about area to copy - * - * A wrapper around sys_copyarea implemented by fbdev core - */ -void drm_fb_helper_sys_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct drm_fb_helper *helper = info->par; - - sys_copyarea(info, area); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, area->dx, area->dy, area->width, area->height); -} -EXPORT_SYMBOL(drm_fb_helper_sys_copyarea); - -/** - * drm_fb_helper_sys_imageblit - wrapper around sys_imageblit - * @info: fbdev registered by the helper - * @image: info about image to blit - * - * A wrapper around sys_imageblit implemented by fbdev core - */ -void drm_fb_helper_sys_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct drm_fb_helper *helper = info->par; - - sys_imageblit(info, image); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, image->dx, image->dy, image->width, image->height); -} -EXPORT_SYMBOL(drm_fb_helper_sys_imageblit); - -static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_t count, - loff_t pos) -{ - const char __iomem *src = info->screen_base + pos; - size_t alloc_size = min_t(size_t, count, PAGE_SIZE); - ssize_t ret = 0; - int err = 0; - char *tmp; - - tmp = kmalloc(alloc_size, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - while (count) { - size_t c = min_t(size_t, count, alloc_size); - - memcpy_fromio(tmp, src, c); - if (copy_to_user(buf, tmp, c)) { - err = -EFAULT; - break; - } - - src += c; - buf += c; - ret += c; - count -= c; - } - - kfree(tmp); - - return ret ? ret : err; -} - -/** - * drm_fb_helper_cfb_read - Implements struct &fb_ops.fb_read for I/O memory - * @info: fb_info struct pointer - * @buf: userspace buffer to read from framebuffer memory - * @count: number of bytes to read from framebuffer memory - * @ppos: read offset within framebuffer memory - * - * Returns: - * The number of bytes read on success, or an error code otherwise. - */ -ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos) -{ - return __drm_fb_helper_read(info, buf, count, ppos, fb_read_screen_base); -} -EXPORT_SYMBOL(drm_fb_helper_cfb_read); - -static ssize_t fb_write_screen_base(struct fb_info *info, const char __user *buf, size_t count, - loff_t pos) -{ - char __iomem *dst = info->screen_base + pos; - size_t alloc_size = min_t(size_t, count, PAGE_SIZE); - ssize_t ret = 0; - int err = 0; - u8 *tmp; - - tmp = kmalloc(alloc_size, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - while (count) { - size_t c = min_t(size_t, count, alloc_size); - - if (copy_from_user(tmp, buf, c)) { - err = -EFAULT; - break; - } - memcpy_toio(dst, tmp, c); - - dst += c; - buf += c; - ret += c; - count -= c; - } - - kfree(tmp); - - return ret ? ret : err; -} - -/** - * drm_fb_helper_cfb_write - Implements struct &fb_ops.fb_write for I/O memory - * @info: fb_info struct pointer - * @buf: userspace buffer to write to framebuffer memory - * @count: number of bytes to write to framebuffer memory - * @ppos: write offset within framebuffer memory - * - * Returns: - * The number of bytes written on success, or an error code otherwise. - */ -ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct drm_fb_helper *helper = info->par; - loff_t pos = *ppos; - ssize_t ret; - struct drm_rect damage_area; - - ret = __drm_fb_helper_write(info, buf, count, ppos, fb_write_screen_base); - if (ret <= 0) - return ret; - - if (helper->funcs->fb_dirty) { - drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area); - drm_fb_helper_damage(helper, damage_area.x1, damage_area.y1, - drm_rect_width(&damage_area), - drm_rect_height(&damage_area)); - } - - return ret; -} -EXPORT_SYMBOL(drm_fb_helper_cfb_write); - -/** - * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect - * @info: fbdev registered by the helper - * @rect: info about rectangle to fill - * - * A wrapper around cfb_fillrect implemented by fbdev core - */ -void drm_fb_helper_cfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct drm_fb_helper *helper = info->par; - - cfb_fillrect(info, rect); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, rect->dx, rect->dy, rect->width, rect->height); -} -EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect); - -/** - * drm_fb_helper_cfb_copyarea - wrapper around cfb_copyarea - * @info: fbdev registered by the helper - * @area: info about area to copy - * - * A wrapper around cfb_copyarea implemented by fbdev core - */ -void drm_fb_helper_cfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct drm_fb_helper *helper = info->par; - - cfb_copyarea(info, area); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, area->dx, area->dy, area->width, area->height); -} -EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea); - -/** - * drm_fb_helper_cfb_imageblit - wrapper around cfb_imageblit - * @info: fbdev registered by the helper - * @image: info about image to blit - * - * A wrapper around cfb_imageblit implemented by fbdev core - */ -void drm_fb_helper_cfb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct drm_fb_helper *helper = info->par; - - cfb_imageblit(info, image); - - if (helper->funcs->fb_dirty) - drm_fb_helper_damage(helper, image->dx, image->dy, image->width, image->height); -} -EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); - /** * drm_fb_helper_set_suspend - wrapper around fb_set_suspend * @fb_helper: driver-allocated fbdev helper, can be NULL diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c index 728deffcc0d9..d86773fa8ab0 100644 --- a/drivers/gpu/drm/drm_fbdev_dma.c +++ b/drivers/gpu/drm/drm_fbdev_dma.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT +#include <linux/fb.h> + #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> @@ -64,14 +66,11 @@ static const struct fb_ops drm_fbdev_dma_fb_ops = { .owner = THIS_MODULE, .fb_open = drm_fbdev_dma_fb_open, .fb_release = drm_fbdev_dma_fb_release, - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, + __FB_DEFAULT_SYS_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_destroy = drm_fbdev_dma_fb_destroy, + __FB_DEFAULT_SYS_OPS_DRAW, .fb_mmap = drm_fbdev_dma_fb_mmap, + .fb_destroy = drm_fbdev_dma_fb_destroy, }; /* diff --git a/drivers/gpu/drm/drm_fbdev_generic.c b/drivers/gpu/drm/drm_fbdev_generic.c index 8e5148bf40bb..98ae703848a0 100644 --- a/drivers/gpu/drm/drm_fbdev_generic.c +++ b/drivers/gpu/drm/drm_fbdev_generic.c @@ -34,6 +34,10 @@ static int drm_fbdev_generic_fb_release(struct fb_info *info, int user) return 0; } +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(drm_fbdev_generic, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area); + static void drm_fbdev_generic_fb_destroy(struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; @@ -56,13 +60,8 @@ static const struct fb_ops drm_fbdev_generic_fb_ops = { .owner = THIS_MODULE, .fb_open = drm_fbdev_generic_fb_open, .fb_release = drm_fbdev_generic_fb_release, - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, + FB_DEFAULT_DEFERRED_OPS(drm_fbdev_generic), DRM_FB_HELPER_DEFAULT_OPS, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_mmap = fb_deferred_io_mmap, .fb_destroy = drm_fbdev_generic_fb_destroy, }; diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index c1018c470047..883d83bc0e3d 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -42,6 +42,7 @@ #include <drm/drm_client.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> +#include <drm/drm_gem.h> #include <drm/drm_print.h> #include "drm_crtc_internal.h" @@ -148,6 +149,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev) */ struct drm_file *drm_file_alloc(struct drm_minor *minor) { + static atomic64_t ident = ATOMIC_INIT(0); struct drm_device *dev = minor->dev; struct drm_file *file; int ret; @@ -156,6 +158,8 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor) if (!file) return ERR_PTR(-ENOMEM); + /* Get a unique identifier for fdinfo: */ + file->client_id = atomic64_inc_return(&ident); file->pid = get_pid(task_tgid(current)); file->minor = minor; @@ -868,6 +872,134 @@ void drm_send_event(struct drm_device *dev, struct drm_pending_event *e) } EXPORT_SYMBOL(drm_send_event); +static void print_size(struct drm_printer *p, const char *stat, + const char *region, u64 sz) +{ + const char *units[] = {"", " KiB", " MiB"}; + unsigned u; + + for (u = 0; u < ARRAY_SIZE(units) - 1; u++) { + if (sz < SZ_1K) + break; + sz = div_u64(sz, SZ_1K); + } + + drm_printf(p, "drm-%s-%s:\t%llu%s\n", stat, region, sz, units[u]); +} + +/** + * drm_print_memory_stats - A helper to print memory stats + * @p: The printer to print output to + * @stats: The collected memory stats + * @supported_status: Bitmask of optional stats which are available + * @region: The memory region + * + */ +void drm_print_memory_stats(struct drm_printer *p, + const struct drm_memory_stats *stats, + enum drm_gem_object_status supported_status, + const char *region) +{ + print_size(p, "total", region, stats->private + stats->shared); + print_size(p, "shared", region, stats->shared); + print_size(p, "active", region, stats->active); + + if (supported_status & DRM_GEM_OBJECT_RESIDENT) + print_size(p, "resident", region, stats->resident); + + if (supported_status & DRM_GEM_OBJECT_PURGEABLE) + print_size(p, "purgeable", region, stats->purgeable); +} +EXPORT_SYMBOL(drm_print_memory_stats); + +/** + * drm_show_memory_stats - Helper to collect and show standard fdinfo memory stats + * @p: the printer to print output to + * @file: the DRM file + * + * Helper to iterate over GEM objects with a handle allocated in the specified + * file. + */ +void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) +{ + struct drm_gem_object *obj; + struct drm_memory_stats status = {}; + enum drm_gem_object_status supported_status; + int id; + + spin_lock(&file->table_lock); + idr_for_each_entry (&file->object_idr, obj, id) { + enum drm_gem_object_status s = 0; + + if (obj->funcs && obj->funcs->status) { + s = obj->funcs->status(obj); + supported_status = DRM_GEM_OBJECT_RESIDENT | + DRM_GEM_OBJECT_PURGEABLE; + } + + if (obj->handle_count > 1) { + status.shared += obj->size; + } else { + status.private += obj->size; + } + + if (s & DRM_GEM_OBJECT_RESIDENT) { + status.resident += obj->size; + } else { + /* If already purged or not yet backed by pages, don't + * count it as purgeable: + */ + s &= ~DRM_GEM_OBJECT_PURGEABLE; + } + + if (!dma_resv_test_signaled(obj->resv, dma_resv_usage_rw(true))) { + status.active += obj->size; + + /* If still active, don't count as purgeable: */ + s &= ~DRM_GEM_OBJECT_PURGEABLE; + } + + if (s & DRM_GEM_OBJECT_PURGEABLE) + status.purgeable += obj->size; + } + spin_unlock(&file->table_lock); + + drm_print_memory_stats(p, &status, supported_status, "memory"); +} +EXPORT_SYMBOL(drm_show_memory_stats); + +/** + * drm_show_fdinfo - helper for drm file fops + * @m: output stream + * @f: the device file instance + * + * Helper to implement fdinfo, for userspace to query usage stats, etc, of a + * process using the GPU. See also &drm_driver.show_fdinfo. + * + * For text output format description please see Documentation/gpu/drm-usage-stats.rst + */ +void drm_show_fdinfo(struct seq_file *m, struct file *f) +{ + struct drm_file *file = f->private_data; + struct drm_device *dev = file->minor->dev; + struct drm_printer p = drm_seq_file_printer(m); + + drm_printf(&p, "drm-driver:\t%s\n", dev->driver->name); + drm_printf(&p, "drm-client-id:\t%llu\n", file->client_id); + + if (dev_is_pci(dev->dev)) { + struct pci_dev *pdev = to_pci_dev(dev->dev); + + drm_printf(&p, "drm-pdev:\t%04x:%02x:%02x.%d\n", + pci_domain_nr(pdev->bus), pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + } + + if (dev->driver->show_fdinfo) + dev->driver->show_fdinfo(&p, file); +} +EXPORT_SYMBOL(drm_show_fdinfo); + /** * mock_drm_getfile - Create a new struct file for the drm device * @minor: drm minor to wrap (e.g. #drm_device.primary) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index e93533b86037..b8a615a138cd 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <drm/drm_damage_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem.h> @@ -164,6 +165,14 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, return -EINVAL; } + if (drm_drv_uses_atomic_modeset(dev) && + !drm_any_plane_has_format(dev, mode_cmd->pixel_format, + mode_cmd->modifier[0])) { + drm_dbg(dev, "Unsupported pixel format %p4cc / modifier 0x%llx\n", + &mode_cmd->pixel_format, mode_cmd->modifier[0]); + return -EINVAL; + } + for (i = 0; i < info->num_planes; i++) { unsigned int width = mode_cmd->width / (i ? info->hsub : 1); unsigned int height = mode_cmd->height / (i ? info->vsub : 1); diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 0bea3df2a16d..b67eafa55715 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -45,7 +45,7 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs; * the frame's scanout buffer or the cursor image. If there's no more space * left in VRAM, inactive GEM objects can be moved to system memory. * - * To initialize the VRAM helper library call drmm_vram_helper_alloc_mm(). + * To initialize the VRAM helper library call drmm_vram_helper_init(). * The function allocates and initializes an instance of &struct drm_vram_mm * in &struct drm_device.vram_mm . Use &DRM_GEM_VRAM_DRIVER to initialize * &struct drm_driver and &DRM_VRAM_MM_FILE_OPERATIONS to initialize @@ -73,7 +73,7 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs; * // setup device, vram base and size * // ... * - * ret = drmm_vram_helper_alloc_mm(dev, vram_base, vram_size); + * ret = drmm_vram_helper_init(dev, vram_base, vram_size); * if (ret) * return ret; * return 0; @@ -86,7 +86,7 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs; * to userspace. * * You don't have to clean up the instance of VRAM MM. - * drmm_vram_helper_alloc_mm() is a managed interface that installs a + * drmm_vram_helper_init() is a managed interface that installs a * clean-up handler to run during the DRM device's release. * * For drawing or scanout operations, rsp. buffer objects have to be pinned diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 7900a4707d7c..3fd6c733ff4e 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -160,7 +160,7 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg; - if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + if (of_alias_from_compatible(node, info.type, sizeof(info.type)) < 0) { drm_err(host, "modalias failure on %pOF\n", node); return ERR_PTR(-EINVAL); } @@ -221,7 +221,7 @@ mipi_dsi_device_register_full(struct mipi_dsi_host *host, return dsi; } - dsi->dev.of_node = info->node; + device_set_node(&dsi->dev, of_fwnode_handle(info->node)); dsi->channel = info->channel; strlcpy(dsi->name, info->type, sizeof(dsi->name)); diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 183130355997..f62767ff34b2 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -11,12 +11,14 @@ */ #include <linux/acpi.h> +#include <linux/component.h> #include <linux/device.h> #include <linux/err.h> #include <linux/export.h> #include <linux/gfp.h> #include <linux/i2c.h> #include <linux/kdev_t.h> +#include <linux/property.h> #include <linux/slab.h> #include <drm/drm_accel.h> @@ -96,6 +98,34 @@ static char *drm_devnode(const struct device *dev, umode_t *mode) return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); } +static int typec_connector_bind(struct device *dev, + struct device *typec_connector, void *data) +{ + int ret; + + ret = sysfs_create_link(&dev->kobj, &typec_connector->kobj, "typec_connector"); + if (ret) + return ret; + + ret = sysfs_create_link(&typec_connector->kobj, &dev->kobj, "drm_connector"); + if (ret) + sysfs_remove_link(&dev->kobj, "typec_connector"); + + return ret; +} + +static void typec_connector_unbind(struct device *dev, + struct device *typec_connector, void *data) +{ + sysfs_remove_link(&typec_connector->kobj, "drm_connector"); + sysfs_remove_link(&dev->kobj, "typec_connector"); +} + +static const struct component_ops typec_connector_ops = { + .bind = typec_connector_bind, + .unbind = typec_connector_unbind, +}; + static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810"); /** @@ -112,7 +142,7 @@ int drm_sysfs_init(void) { int err; - drm_class = class_create(THIS_MODULE, "drm"); + drm_class = class_create("drm"); if (IS_ERR(drm_class)) return PTR_ERR(drm_class); @@ -282,16 +312,27 @@ static ssize_t modes_show(struct device *device, return written; } +static ssize_t connector_id_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = to_drm_connector(device); + + return sysfs_emit(buf, "%d\n", connector->base.id); +} + static DEVICE_ATTR_RW(status); static DEVICE_ATTR_RO(enabled); static DEVICE_ATTR_RO(dpms); static DEVICE_ATTR_RO(modes); +static DEVICE_ATTR_RO(connector_id); static struct attribute *connector_dev_attrs[] = { &dev_attr_status.attr, &dev_attr_enabled.attr, &dev_attr_dpms.attr, &dev_attr_modes.attr, + &dev_attr_connector_id.attr, NULL }; @@ -353,9 +394,16 @@ int drm_sysfs_connector_add(struct drm_connector *connector) connector->kdev = kdev; + if (dev_fwnode(kdev)) { + r = component_add(kdev, &typec_connector_ops); + if (r) + 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: @@ -371,6 +419,9 @@ void drm_sysfs_connector_remove(struct drm_connector *connector) if (connector->ddc) sysfs_remove_link(&connector->kdev->kobj, "ddc"); + if (dev_fwnode(connector->kdev)) + component_del(connector->kdev, &typec_connector_ops); + DRM_DEBUG("removing \"%s\" from sysfs\n", connector->name); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 44ca803237a5..31a7f59ccb49 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -22,7 +22,6 @@ #include "etnaviv_gem.h" #include "etnaviv_mmu.h" #include "etnaviv_perfmon.h" -#include "common.xml.h" /* * DRM operations: @@ -476,47 +475,7 @@ static const struct drm_ioctl_desc etnaviv_ioctls[] = { ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW), }; -static void etnaviv_fop_show_fdinfo(struct seq_file *m, struct file *f) -{ - struct drm_file *file = f->private_data; - struct drm_device *dev = file->minor->dev; - struct etnaviv_drm_private *priv = dev->dev_private; - struct etnaviv_file_private *ctx = file->driver_priv; - - /* - * For a description of the text output format used here, see - * Documentation/gpu/drm-usage-stats.rst. - */ - seq_printf(m, "drm-driver:\t%s\n", dev->driver->name); - seq_printf(m, "drm-client-id:\t%u\n", ctx->id); - - for (int i = 0; i < ETNA_MAX_PIPES; i++) { - struct etnaviv_gpu *gpu = priv->gpu[i]; - char engine[10] = "UNK"; - int cur = 0; - - if (!gpu) - continue; - - if (gpu->identity.features & chipFeatures_PIPE_2D) - cur = snprintf(engine, sizeof(engine), "2D"); - if (gpu->identity.features & chipFeatures_PIPE_3D) - cur = snprintf(engine + cur, sizeof(engine) - cur, - "%s3D", cur ? "/" : ""); - if (gpu->identity.nn_core_count > 0) - cur = snprintf(engine + cur, sizeof(engine) - cur, - "%sNN", cur ? "/" : ""); - - seq_printf(m, "drm-engine-%s:\t%llu ns\n", engine, - ctx->sched_entity[i].elapsed_ns); - } -} - -static const struct file_operations fops = { - .owner = THIS_MODULE, - DRM_GEM_FOPS, - .show_fdinfo = etnaviv_fop_show_fdinfo, -}; +DEFINE_DRM_GEM_FOPS(fops); static const struct drm_driver etnaviv_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_RENDER, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c index 7031db145a77..3524b5811682 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c @@ -91,7 +91,15 @@ static void *etnaviv_gem_prime_vmap_impl(struct etnaviv_gem_object *etnaviv_obj) static int etnaviv_gem_prime_mmap_obj(struct etnaviv_gem_object *etnaviv_obj, struct vm_area_struct *vma) { - return dma_buf_mmap(etnaviv_obj->base.dma_buf, vma, 0); + int ret; + + ret = dma_buf_mmap(etnaviv_obj->base.dma_buf, vma, 0); + if (!ret) { + /* Drop the reference acquired by drm_gem_mmap_obj(). */ + drm_gem_object_put(&etnaviv_obj->base); + } + + return ret; } static const struct etnaviv_gem_ops etnaviv_gem_prime_ops = { diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 0cb92d651ff1..7ca7e1dab52c 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -7,6 +7,7 @@ config DRM_EXYNOS select DRM_DISPLAY_HELPER if DRM_EXYNOS_DP select DRM_KMS_HELPER select VIDEOMODE_HELPERS + select FB_IO_HELPERS if DRM_FBDEV_EMULATION select SND_SOC_HDMI_CODEC if SND_SOC help Choose this option if you have a Samsung SoC Exynos chipset. diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 16c539657f73..6b73fb7a83c3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -16,7 +16,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_file.h> #include <drm/drm_fourcc.h> #include <drm/drm_ioctl.h> @@ -108,7 +107,6 @@ static const struct drm_driver exynos_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_RENDER, .open = exynos_drm_open, - .lastclose = drm_fb_helper_lastclose, .postclose = exynos_drm_postclose, .dumb_create = exynos_drm_gem_dumb_create, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, @@ -288,19 +286,15 @@ static int exynos_drm_bind(struct device *dev) /* init kms poll for handling hpd */ drm_kms_helper_poll_init(drm); - ret = exynos_drm_fbdev_init(drm); - if (ret) - goto err_cleanup_poll; - /* register the DRM device */ ret = drm_dev_register(drm, 0); if (ret < 0) - goto err_cleanup_fbdev; + goto err_cleanup_poll; + + exynos_drm_fbdev_setup(drm); return 0; -err_cleanup_fbdev: - exynos_drm_fbdev_fini(drm); err_cleanup_poll: drm_kms_helper_poll_fini(drm); err_unbind_all: @@ -321,7 +315,6 @@ static void exynos_drm_unbind(struct device *dev) drm_dev_unregister(drm); - exynos_drm_fbdev_fini(drm); drm_kms_helper_poll_fini(drm); component_unbind_all(drm->dev, drm); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 6ae9056e7a18..81d501efd013 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -197,8 +197,6 @@ struct drm_exynos_file_private { * @wait: wait an atomic commit to finish */ struct exynos_drm_private { - struct drm_fb_helper *fb_helper; - struct device *g2d_dev; struct device *dma_dev; void *mapping; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 97f2dee2db29..fc1c5608db96 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -11,7 +11,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> @@ -157,7 +156,6 @@ static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = { static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { .fb_create = exynos_user_fb_create, - .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 4929ffe5a09a..fdf65587f1fe 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -8,16 +8,14 @@ * Seung-Woo Kim <sw0312.kim@samsung.com> */ -#include <linux/console.h> -#include <linux/dma-mapping.h> -#include <linux/vmalloc.h> +#include <linux/fb.h> -#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_prime.h> -#include <drm/drm_probe_helper.h> #include <drm/exynos_drm.h> #include "exynos_drm_drv.h" @@ -27,33 +25,35 @@ #define MAX_CONNECTOR 4 #define PREFERRED_BPP 32 -#define to_exynos_fbdev(x) container_of(x, struct exynos_drm_fbdev,\ - drm_fb_helper) +static int exynos_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *helper = info->par; + struct drm_gem_object *obj = drm_gem_fb_get_obj(helper->fb, 0); -struct exynos_drm_fbdev { - struct drm_fb_helper drm_fb_helper; - struct exynos_drm_gem *exynos_gem; -}; + return drm_gem_prime_mmap(obj, vma); +} -static int exynos_drm_fb_mmap(struct fb_info *info, - struct vm_area_struct *vma) +static void exynos_drm_fb_destroy(struct fb_info *info) { - struct drm_fb_helper *helper = info->par; - struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); - struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem; + struct drm_fb_helper *fb_helper = info->par; + struct drm_framebuffer *fb = fb_helper->fb; - return drm_gem_prime_mmap(&exynos_gem->base, vma); + drm_fb_helper_fini(fb_helper); + + drm_framebuffer_remove(fb); + + drm_client_release(&fb_helper->client); + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); } static const struct fb_ops exynos_drm_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_IO_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, + __FB_DEFAULT_IO_OPS_DRAW, .fb_mmap = exynos_drm_fb_mmap, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, + .fb_destroy = exynos_drm_fb_destroy, }; static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, @@ -89,7 +89,6 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); struct exynos_drm_gem *exynos_gem; struct drm_device *dev = helper->dev; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; @@ -113,8 +112,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, if (IS_ERR(exynos_gem)) return PTR_ERR(exynos_gem); - exynos_fbdev->exynos_gem = exynos_gem; - helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem, 1); if (IS_ERR(helper->fb)) { @@ -127,19 +124,13 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, if (ret < 0) goto err_destroy_framebuffer; - return ret; + return 0; err_destroy_framebuffer: drm_framebuffer_cleanup(helper->fb); + helper->fb = NULL; err_destroy_gem: exynos_drm_gem_destroy(exynos_gem); - - /* - * if failed, all resources allocated above would be released by - * drm_mode_config_cleanup() when drm_load() had been called prior - * to any specific driver such as fimd or hdmi driver. - */ - return ret; } @@ -147,80 +138,92 @@ static const struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { .fb_probe = exynos_drm_fbdev_create, }; -int exynos_drm_fbdev_init(struct drm_device *dev) +/* + * struct drm_client + */ + +static void exynos_drm_fbdev_client_unregister(struct drm_client_dev *client) { - struct exynos_drm_fbdev *fbdev; - struct exynos_drm_private *private = dev->dev_private; - struct drm_fb_helper *helper; - int ret; + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + + if (fb_helper->info) { + drm_fb_helper_unregister_info(fb_helper); + } else { + drm_client_release(&fb_helper->client); + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); + } +} - if (!dev->mode_config.num_crtc) - return 0; +static int exynos_drm_fbdev_client_restore(struct drm_client_dev *client) +{ + drm_fb_helper_lastclose(client->dev); - fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); - if (!fbdev) - return -ENOMEM; + return 0; +} - private->fb_helper = helper = &fbdev->drm_fb_helper; +static int exynos_drm_fbdev_client_hotplug(struct drm_client_dev *client) +{ + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + struct drm_device *dev = client->dev; + int ret; - drm_fb_helper_prepare(dev, helper, PREFERRED_BPP, &exynos_drm_fb_helper_funcs); + if (dev->fb_helper) + return drm_fb_helper_hotplug_event(dev->fb_helper); - ret = drm_fb_helper_init(dev, helper); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, - "failed to initialize drm fb helper.\n"); - goto err_init; - } + ret = drm_fb_helper_init(dev, fb_helper); + if (ret) + goto err_drm_err; - ret = drm_fb_helper_initial_config(helper); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, - "failed to set up hw configuration.\n"); - goto err_setup; - } + if (!drm_drv_uses_atomic_modeset(dev)) + drm_helper_disable_unused_functions(dev); - return 0; + ret = drm_fb_helper_initial_config(fb_helper); + if (ret) + goto err_drm_fb_helper_fini; -err_setup: - drm_fb_helper_fini(helper); -err_init: - drm_fb_helper_unprepare(helper); - private->fb_helper = NULL; - kfree(fbdev); + return 0; +err_drm_fb_helper_fini: + drm_fb_helper_fini(fb_helper); +err_drm_err: + drm_err(dev, "Failed to setup fbdev emulation (ret=%d)\n", ret); return ret; } -static void exynos_drm_fbdev_destroy(struct drm_device *dev, - struct drm_fb_helper *fb_helper) +static const struct drm_client_funcs exynos_drm_fbdev_client_funcs = { + .owner = THIS_MODULE, + .unregister = exynos_drm_fbdev_client_unregister, + .restore = exynos_drm_fbdev_client_restore, + .hotplug = exynos_drm_fbdev_client_hotplug, +}; + +void exynos_drm_fbdev_setup(struct drm_device *dev) { - struct drm_framebuffer *fb; + struct drm_fb_helper *fb_helper; + int ret; - /* release drm framebuffer and real buffer */ - if (fb_helper->fb && fb_helper->fb->funcs) { - fb = fb_helper->fb; - if (fb) - drm_framebuffer_remove(fb); - } + drm_WARN(dev, !dev->registered, "Device has not been registered.\n"); + drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n"); - drm_fb_helper_unregister_info(fb_helper); + fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL); + if (!fb_helper) + return; + drm_fb_helper_prepare(dev, fb_helper, PREFERRED_BPP, &exynos_drm_fb_helper_funcs); - drm_fb_helper_fini(fb_helper); -} + ret = drm_client_init(dev, &fb_helper->client, "fbdev", &exynos_drm_fbdev_client_funcs); + if (ret) + goto err_drm_client_init; -void exynos_drm_fbdev_fini(struct drm_device *dev) -{ - struct exynos_drm_private *private = dev->dev_private; - struct exynos_drm_fbdev *fbdev; + ret = exynos_drm_fbdev_client_hotplug(&fb_helper->client); + if (ret) + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); - if (!private || !private->fb_helper) - return; + drm_client_register(&fb_helper->client); - fbdev = to_exynos_fbdev(private->fb_helper); + return; - exynos_drm_fbdev_destroy(dev, private->fb_helper); - drm_fb_helper_unprepare(private->fb_helper); - kfree(fbdev); - private->fb_helper = NULL; +err_drm_client_init: + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); } - diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.h b/drivers/gpu/drm/exynos/exynos_drm_fbdev.h index 3b1e98e84580..1e1dea627cd9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.h @@ -12,27 +12,11 @@ #define _EXYNOS_DRM_FBDEV_H_ #ifdef CONFIG_DRM_FBDEV_EMULATION - -int exynos_drm_fbdev_init(struct drm_device *dev); -void exynos_drm_fbdev_fini(struct drm_device *dev); - +void exynos_drm_fbdev_setup(struct drm_device *dev); #else - -static inline int exynos_drm_fbdev_init(struct drm_device *dev) -{ - return 0; -} - -static inline void exynos_drm_fbdev_fini(struct drm_device *dev) +static inline void exynos_drm_fbdev_setup(struct drm_device *dev) { } - -static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev) -{ -} - -#define exynos_drm_output_poll_changed (NULL) - #endif #endif diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index 2efc0eb41c64..cd3d92725ed4 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig @@ -3,6 +3,7 @@ config DRM_GMA500 tristate "Intel GMA500/600/3600/3650 KMS Framebuffer" depends on DRM && PCI && X86 && MMU select DRM_KMS_HELPER + select FB_IO_HELPERS if DRM_FBDEV_EMULATION select I2C select I2C_ALGOBIT # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915 diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c index 62287407e717..955cbe9f05a7 100644 --- a/drivers/gpu/drm/gma500/fbdev.c +++ b/drivers/gpu/drm/gma500/fbdev.c @@ -5,6 +5,7 @@ * **************************************************************************/ +#include <linux/fb.h> #include <linux/pfn_t.h> #include <drm/drm_crtc_helper.h> @@ -134,13 +135,10 @@ static void psb_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops psb_fbdev_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_IO_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, .fb_setcolreg = psb_fbdev_fb_setcolreg, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, + __FB_DEFAULT_IO_OPS_DRAW, .fb_mmap = psb_fbdev_fb_mmap, .fb_destroy = psb_fbdev_fb_destroy, }; @@ -231,7 +229,7 @@ static int psb_fbdev_fb_probe(struct drm_fb_helper *fb_helper, info->fix.mmio_start = pci_resource_start(pdev, 0); info->fix.mmio_len = pci_resource_len(pdev, 0); - memset(info->screen_base, 0, info->screen_size); + fb_memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 2ce96b1b9c74..8b64f61ffaf9 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -7,6 +7,7 @@ * **************************************************************************/ +#include <linux/aperture.h> #include <linux/cpu.h> #include <linux/module.h> #include <linux/notifier.h> @@ -19,7 +20,6 @@ #include <acpi/video.h> #include <drm/drm.h> -#include <drm/drm_aperture.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> #include <drm/drm_ioctl.h> @@ -414,20 +414,45 @@ out_err: return ret; } +/* + * Hardware for gma500 is a hybrid device, which both acts as a PCI + * device (for legacy vga functionality) but also more like an + * integrated display on a SoC where the framebuffer simply + * resides in main memory and not in a special PCI bar (that + * internally redirects to a stolen range of main memory) like all + * other integrated PCI display devices implement it. + * + * To catch all cases we need to remove conflicting firmware devices + * for the stolen system memory and for the VGA functionality. As we + * currently cannot easily find the framebuffer's location in stolen + * memory, we remove all framebuffers here. + * + * TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then + * we might be able to read the framebuffer range from the + * device. + */ +static int gma_remove_conflicting_framebuffers(struct pci_dev *pdev, + const struct drm_driver *req_driver) +{ + resource_size_t base = 0; + resource_size_t size = U32_MAX; /* 4 GiB HW limit */ + const char *name = req_driver->name; + int ret; + + ret = aperture_remove_conflicting_devices(base, size, name); + if (ret) + return ret; + + return __aperture_remove_legacy_vga_devices(pdev); +} + static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct drm_psb_private *dev_priv; struct drm_device *dev; int ret; - /* - * We cannot yet easily find the framebuffer's location in memory. So - * remove all framebuffers here. - * - * TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then we - * might be able to read the framebuffer range from the device. - */ - ret = drm_aperture_remove_framebuffers(true, &driver); + ret = gma_remove_conflicting_framebuffers(pdev, &driver); if (ret) return ret; diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c index f830d62a5ce6..a7d2c92d6c6a 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c @@ -74,7 +74,6 @@ static int hyperv_setup_vram(struct hyperv_drm_device *hv, drm_aperture_remove_conflicting_framebuffers(screen_info.lfb_base, screen_info.lfb_size, - false, &hyperv_driver); hv->fb_size = (unsigned long)hv->mmio_megabytes * 1024 * 1024; diff --git a/drivers/gpu/drm/i2c/tda9950.c b/drivers/gpu/drm/i2c/tda9950.c index b8c143e573e0..82d618c40dce 100644 --- a/drivers/gpu/drm/i2c/tda9950.c +++ b/drivers/gpu/drm/i2c/tda9950.c @@ -492,7 +492,7 @@ static struct i2c_device_id tda9950_ids[] = { MODULE_DEVICE_TABLE(i2c, tda9950_ids); static struct i2c_driver tda9950_driver = { - .probe_new = tda9950_probe, + .probe = tda9950_probe, .remove = tda9950_remove, .driver = { .name = "tda9950", diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index db5c9343a3d2..40bcd9067e69 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -2099,7 +2099,7 @@ static const struct i2c_device_id tda998x_ids[] = { MODULE_DEVICE_TABLE(i2c, tda998x_ids); static struct i2c_driver tda998x_driver = { - .probe_new = tda998x_probe, + .probe = tda998x_probe, .remove = tda998x_remove, .driver = { .name = "tda998x", diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 06a0ca157e89..01b5a8272a27 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -17,6 +17,7 @@ config DRM_I915 select DRM_KMS_HELPER select DRM_PANEL select DRM_MIPI_DSI + select FB_IO_HELPERS if DRM_FBDEV_EMULATION select RELAY select I2C select I2C_ALGOBIT @@ -62,10 +63,11 @@ config DRM_I915_FORCE_PROBE This is the default value for the i915.force_probe module parameter. Using the module parameter overrides this option. - Force probe the i915 for Intel graphics devices that are - recognized but not properly supported by this kernel version. It is - recommended to upgrade to a kernel version with proper support as soon - as it is available. + Force probe the i915 driver for Intel graphics devices that are + recognized but not properly supported by this kernel version. Force + probing an unsupported device taints the kernel. It is recommended to + upgrade to a kernel version with proper support as soon as it is + available. It can also be used to block the probe of recognized and fully supported devices. @@ -75,7 +77,8 @@ config DRM_I915_FORCE_PROBE Use "<pci-id>[,<pci-id>,...]" to force probe the i915 for listed devices. For example, "4500" or "4500,4571". - Use "*" to force probe the driver for all known devices. + Use "*" to force probe the driver for all known devices. Not + recommended. Use "!" right before the ID to block the probe of the device. For example, "4500,!4571" forces the probe of 4500 and blocks the probe of diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index ad78148e0788..c9aeba0ecf91 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1140,7 +1140,7 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) /* panel power on related mipi dsi vbt sequences */ intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON); - intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay); + msleep(intel_dsi->panel_on_delay); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 40de9f0f171b..f33164b10292 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -1028,7 +1028,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, int ret; if (old_obj) { - const struct intel_crtc_state *crtc_state = + const struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, to_intel_crtc(old_plane_state->hw.crtc)); @@ -1043,7 +1043,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, * This should only fail upon a hung GPU, in which case we * can safely continue. */ - if (intel_crtc_needs_modeset(crtc_state)) { + if (new_crtc_state && intel_crtc_needs_modeset(new_crtc_state)) { ret = i915_sw_fence_await_reservation(&state->commit_ready, old_obj->base.resv, false, 0, diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index d0bb3a52ae5c..3a7b98837516 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3060,6 +3060,25 @@ void intel_ddi_update_pipe(struct intel_atomic_state *state, intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state); } +void intel_ddi_update_active_dpll(struct intel_atomic_state *state, + struct intel_encoder *encoder, + struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct intel_crtc *slave_crtc; + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (!intel_phy_is_tc(i915, phy)) + return; + + intel_update_active_dpll(state, crtc, encoder); + for_each_intel_crtc_in_pipe_mask(&i915->drm, slave_crtc, + intel_crtc_bigjoiner_slave_pipes(crtc_state)) + intel_update_active_dpll(state, slave_crtc, encoder); +} + static void intel_ddi_pre_pll_enable(struct intel_atomic_state *state, struct intel_encoder *encoder, @@ -3074,15 +3093,9 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state, if (is_tc_port) { struct intel_crtc *master_crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct intel_crtc *slave_crtc; intel_tc_port_get_link(dig_port, crtc_state->lane_count); - - intel_update_active_dpll(state, master_crtc, encoder); - - for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, slave_crtc, - intel_crtc_bigjoiner_slave_pipes(crtc_state)) - intel_update_active_dpll(state, slave_crtc, encoder); + intel_ddi_update_active_dpll(state, encoder, master_crtc); } main_link_aux_power_domain_get(dig_port, crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index c85e74ae68e4..2bc034042a93 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -72,5 +72,8 @@ void intel_ddi_sanitize_encoder_pll_mapping(struct intel_encoder *encoder); int intel_ddi_level(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, int lane); +void intel_ddi_update_active_dpll(struct intel_atomic_state *state, + struct intel_encoder *encoder, + struct intel_crtc *crtc); #endif /* __INTEL_DDI_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 010ee793e1ff..3c29792137a5 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -959,7 +959,7 @@ intel_get_crtc_new_encoder(const struct intel_atomic_state *state, num_encoders++; } - drm_WARN(encoder->base.dev, num_encoders != 1, + drm_WARN(state->base.dev, num_encoders != 1, "%d encoders for pipe %c\n", num_encoders, pipe_name(master_crtc->pipe)); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f0bace9d98a1..529ee22be872 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1601,6 +1601,11 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->dsc.slice_count = drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, true); + if (!pipe_config->dsc.slice_count) { + drm_dbg_kms(&dev_priv->drm, "Unsupported Slice Count %d\n", + pipe_config->dsc.slice_count); + return -EINVAL; + } } else { u16 dsc_max_output_bpp = 0; u8 dsc_dp_slice_count; diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index a88b852c437c..2c49d9ab86a2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -674,6 +674,13 @@ static void intel_mst_pre_pll_enable_dp(struct intel_atomic_state *state, if (intel_dp->active_mst_links == 0) dig_port->base.pre_pll_enable(state, &dig_port->base, pipe_config, NULL); + else + /* + * The port PLL state needs to get updated for secondary + * streams as for the primary stream. + */ + intel_ddi_update_active_dpll(state, &dig_port->base, + to_intel_crtc(pipe_config->uapi.crtc)); } static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 695b0d69a4cb..c7935ea498c4 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -763,17 +763,6 @@ void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, gpiod_set_value_cansleep(intel_dsi->gpio_backlight, 0); } -void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec) -{ - struct intel_connector *connector = intel_dsi->attached_connector; - - /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */ - if (is_vid_mode(intel_dsi) && connector->panel.vbt.dsi.seq_version >= 3) - return; - - msleep(msec); -} - void intel_dsi_log_params(struct intel_dsi *intel_dsi) { struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.h b/drivers/gpu/drm/i915/display/intel_dsi_vbt.h index dc642c1fe7ef..468d873fab1a 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.h +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.h @@ -16,7 +16,6 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on); void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi); void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, enum mipi_seq seq_id); -void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec); void intel_dsi_log_params(struct intel_dsi *intel_dsi); #endif /* __INTEL_DSI_VBT_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index aab1ae74a8f7..eccaceaf8b9d 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -28,6 +28,7 @@ #include <linux/console.h> #include <linux/delay.h> #include <linux/errno.h> +#include <linux/fb.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/mm.h> @@ -84,6 +85,10 @@ static void intel_fbdev_invalidate(struct intel_fbdev *ifbdev) intel_frontbuffer_invalidate(to_frontbuffer(ifbdev), ORIGIN_CPU); } +FB_GEN_DEFAULT_DEFERRED_IO_OPS(intel_fbdev, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area) + static int intel_fbdev_set_par(struct fb_info *info) { struct intel_fbdev *ifbdev = to_intel_fbdev(info->par); @@ -132,15 +137,12 @@ static int intel_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) static const struct fb_ops intelfb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_DEFERRED_OPS_RDWR(intel_fbdev), DRM_FB_HELPER_DEFAULT_OPS, .fb_set_par = intel_fbdev_set_par, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_pan_display = intel_fbdev_pan_display, .fb_blank = intel_fbdev_blank, + .fb_pan_display = intel_fbdev_pan_display, + __FB_DEFAULT_DEFERRED_OPS_DRAW(intel_fbdev), .fb_mmap = intel_fbdev_mmap, }; diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index 473d53610b92..0e7e014fcc71 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -111,6 +111,8 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); + int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); int min_src_w, min_src_h, min_dst_w, min_dst_h; int max_src_w, max_src_h, max_dst_w, max_dst_h; @@ -207,6 +209,21 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, return -EINVAL; } + /* + * The pipe scaler does not use all the bits of PIPESRC, at least + * on the earlier platforms. So even when we're scaling a plane + * the *pipe* source size must not be too large. For simplicity + * we assume the limits match the scaler source size limits. Might + * not be 100% accurate on all platforms, but good enough for now. + */ + if (pipe_src_w > max_src_w || pipe_src_h > max_src_h) { + drm_dbg_kms(&dev_priv->drm, + "scaler_user index %u.%u: pipe src size %ux%u " + "is out of scaler range\n", + crtc->pipe, scaler_user, pipe_src_w, pipe_src_h); + return -EINVAL; + } + /* mark this plane as a scaler user in crtc_state */ scaler_state->scaler_users |= (1 << scaler_user); drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: " diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 028965ab442d..61d008d4e5f1 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -737,7 +737,6 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, { struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); - struct intel_connector *connector = to_intel_connector(conn_state->connector); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; enum port port; @@ -779,21 +778,10 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, if (!IS_GEMINILAKE(dev_priv)) intel_dsi_prepare(encoder, pipe_config); + /* Give the panel time to power-on and then deassert its reset */ intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON); - - /* - * Give the panel time to power-on and then deassert its reset. - * Depending on the VBT MIPI sequences version the deassert-seq - * may contain the necessary delay, intel_dsi_msleep() will skip - * the delay in that case. If there is no deassert-seq, then an - * unconditional msleep is used to give the panel time to power-on. - */ - if (connector->panel.vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) { - intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay); - intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); - } else { - msleep(intel_dsi->panel_on_delay); - } + msleep(intel_dsi->panel_on_delay); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); if (IS_GEMINILAKE(dev_priv)) { glk_cold_boot = glk_dsi_enable_io(encoder); @@ -827,7 +815,7 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, msleep(20); /* XXX */ for_each_dsi_port(port, intel_dsi->ports) dpi_send_cmd(intel_dsi, TURN_ON, false, port); - intel_dsi_msleep(intel_dsi, 100); + msleep(100); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); @@ -949,7 +937,7 @@ static void intel_dsi_post_disable(struct intel_atomic_state *state, /* Assert reset */ intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET); - intel_dsi_msleep(intel_dsi, intel_dsi->panel_off_delay); + msleep(intel_dsi->panel_off_delay); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF); intel_dsi->panel_power_off_time = ktime_get_boottime(); diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index 763df437c20c..df6c9a84252c 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -115,7 +115,7 @@ static int get_huge_pages(struct drm_i915_gem_object *obj) do { struct page *page; - GEM_BUG_ON(order >= MAX_ORDER); + GEM_BUG_ON(order > MAX_ORDER); page = alloc_pages(GFP | __GFP_ZERO, order); if (!page) goto err; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index aefdaa62da99..04724ff56ded 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -190,7 +190,7 @@ static int gsc_notifier(struct notifier_block *nb, unsigned long action, void *d return 0; } -void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus) +void intel_huc_register_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus) { int ret; @@ -206,7 +206,7 @@ void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus } } -void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus) +void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus) { if (!huc->delayed_load.nb.notifier_call) return; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h index db555b3c1f56..0789184d81a2 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h @@ -52,8 +52,8 @@ int intel_huc_check_status(struct intel_huc *huc); void intel_huc_update_auth_status(struct intel_huc *huc); bool intel_huc_is_authenticated(struct intel_huc *huc); -void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus); -void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus); +void intel_huc_register_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus); +void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus); static inline bool intel_huc_is_supported(struct intel_huc *huc) { diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 3e38283cbe8f..75cbccd1a441 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1193,6 +1193,8 @@ static const struct intel_gt_definition xelpmp_extra_gt[] = { static const struct intel_device_info mtl_info = { XE_HP_FEATURES, XE_LPDP_FEATURES, + .__runtime.cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | + BIT(TRANSCODER_C) | BIT(TRANSCODER_D), /* * Real graphics IP version will be obtained from hardware GMD_ID * register. Value provided here is just for sanity checking. @@ -1405,6 +1407,12 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; } + if (intel_info->require_force_probe) { + dev_info(&pdev->dev, "Force probing unsupported Device ID %04x, tainting kernel\n", + pdev->device); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } + /* Only bind to function 0 of the device. Early generations * used function 1 as a placeholder for multi-head. This causes * us confusion instead, especially on the systems where both diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 736a8dcf777b..c4197e31962e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6349,8 +6349,8 @@ enum skl_power_gate { #define _PLANE_CSC_RY_GY_1(pipe) _PIPE(pipe, _PLANE_CSC_RY_GY_1_A, \ _PLANE_CSC_RY_GY_1_B) -#define _PLANE_CSC_RY_GY_2(pipe) _PIPE(pipe, _PLANE_INPUT_CSC_RY_GY_2_A, \ - _PLANE_INPUT_CSC_RY_GY_2_B) +#define _PLANE_CSC_RY_GY_2(pipe) _PIPE(pipe, _PLANE_CSC_RY_GY_2_A, \ + _PLANE_CSC_RY_GY_2_B) #define PLANE_CSC_COEFF(pipe, plane, index) _MMIO_PLANE(plane, \ _PLANE_CSC_RY_GY_1(pipe) + (index) * 4, \ _PLANE_CSC_RY_GY_2(pipe) + (index) * 4) diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c index 8e6d457917da..277ead6a459a 100644 --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c @@ -400,8 +400,8 @@ static int imx_lcdc_probe(struct platform_device *pdev) lcdc = devm_drm_dev_alloc(dev, &imx_lcdc_drm_driver, struct imx_lcdc, drm); - if (!lcdc) - return -ENOMEM; + if (IS_ERR(lcdc)) + return PTR_ERR(lcdc); drm = &lcdc->drm; diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index bb72fda9106d..ca6d1e59e5d9 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -285,7 +285,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) * Remove early framebuffers (ie. simplefb). The framebuffer can be * located anywhere in RAM */ - ret = drm_aperture_remove_framebuffers(false, &meson_driver); + ret = drm_aperture_remove_framebuffers(&meson_driver); if (ret) goto free_drm; diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index fcd532db19c1..27ef9f88e4ff 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -186,7 +186,7 @@ union meson_hdmi_venc_mode { } encp; }; -union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = { +static union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = { .enci = { .hso_begin = 5, .hso_end = 129, @@ -206,7 +206,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = { }, }; -union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = { +static union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = { .enci = { .hso_begin = 3, .hso_end = 129, @@ -226,7 +226,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = { .encp = { .dvi_settings = 0x21, .video_mode = 0x4000, @@ -272,7 +272,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = { .encp = { .dvi_settings = 0x21, .video_mode = 0x4000, @@ -318,7 +318,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = { .encp = { .dvi_settings = 0x2029, .video_mode = 0x4040, @@ -360,7 +360,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = { .encp = { .dvi_settings = 0x202d, .video_mode = 0x4040, @@ -405,7 +405,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = { .encp = { .dvi_settings = 0x2029, .video_mode = 0x5ffc, @@ -454,7 +454,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = { .encp = { .dvi_settings = 0x202d, .video_mode = 0x5ffc, @@ -503,7 +503,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = { .encp = { .dvi_settings = 0xd, .video_mode = 0x4040, @@ -552,7 +552,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = { .encp = { .dvi_settings = 0x1, .video_mode = 0x4040, @@ -596,7 +596,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = { .encp = { .dvi_settings = 0xd, .video_mode = 0x4040, @@ -644,7 +644,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { .encp = { .dvi_settings = 0x1, .video_mode = 0x4040, @@ -688,7 +688,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = { .encp = { .dvi_settings = 0x1, .video_mode = 0x4040, @@ -730,7 +730,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = { .encp = { .dvi_settings = 0x1, .video_mode = 0x4040, @@ -772,7 +772,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = { +static union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = { .encp = { .dvi_settings = 0x1, .video_mode = 0x4040, @@ -814,7 +814,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = { }, }; -struct meson_hdmi_venc_vic_mode { +static struct meson_hdmi_venc_vic_mode { unsigned int vic; union meson_hdmi_venc_mode *mode; } meson_hdmi_venc_vic_modes[] = { diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 85f5ab1d552c..a78662bd6273 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -21,6 +21,7 @@ config DRM_MSM select DRM_BRIDGE select DRM_PANEL_BRIDGE select DRM_SCHED + select FB_SYS_HELPERS if DRM_FBDEV_EMULATION select SHMEM select TMPFS select QCOM_SCM diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index b4cfa44a8a5c..58264ff2c4b1 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -455,7 +455,7 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) goto err_deinit_vram; /* the fw fb could be anywhere in memory */ - ret = drm_aperture_remove_framebuffers(false, drv); + ret = drm_aperture_remove_framebuffers(drv); if (ret) goto err_msm_uninit; @@ -1057,23 +1057,23 @@ static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_RENDER_ALLOW), }; -static void msm_fop_show_fdinfo(struct seq_file *m, struct file *f) +static void msm_show_fdinfo(struct drm_printer *p, struct drm_file *file) { - struct drm_file *file = f->private_data; struct drm_device *dev = file->minor->dev; struct msm_drm_private *priv = dev->dev_private; - struct drm_printer p = drm_seq_file_printer(m); if (!priv->gpu) return; - msm_gpu_show_fdinfo(priv->gpu, file->driver_priv, &p); + msm_gpu_show_fdinfo(priv->gpu, file->driver_priv, p); + + drm_show_memory_stats(p, file); } static const struct file_operations fops = { .owner = THIS_MODULE, DRM_GEM_FOPS, - .show_fdinfo = msm_fop_show_fdinfo, + .show_fdinfo = drm_show_fdinfo, }; static const struct drm_driver msm_driver = { @@ -1083,7 +1083,7 @@ static const struct drm_driver msm_driver = { DRIVER_MODESET | DRIVER_SYNCOBJ, .open = msm_open, - .postclose = msm_postclose, + .postclose = msm_postclose, .dumb_create = msm_gem_dumb_create, .dumb_map_offset = msm_gem_dumb_map_offset, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, @@ -1093,6 +1093,7 @@ static const struct drm_driver msm_driver = { #ifdef CONFIG_DEBUG_FS .debugfs_init = msm_debugfs_init, #endif + .show_fdinfo = msm_show_fdinfo, .ioctls = msm_ioctls, .num_ioctls = ARRAY_SIZE(msm_ioctls), .fops = &fops, diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 2ebc86381e1c..fa9c1cbffae3 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -4,6 +4,8 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/fb.h> + #include <drm/drm_drv.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> @@ -23,6 +25,10 @@ module_param(fbdev, bool, 0600); * fbdev funcs, to implement legacy fbdev interface on top of drm driver */ +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(msm_fbdev, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area) + static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par; @@ -52,16 +58,9 @@ static void msm_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops msm_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_DEFERRED_OPS_RDWR(msm_fbdev), DRM_FB_HELPER_DEFAULT_OPS, - - /* Note: to properly handle manual update displays, we wrap the - * basic fbdev ops which write to the framebuffer - */ - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, + __FB_DEFAULT_DEFERRED_OPS_DRAW(msm_fbdev), .fb_mmap = msm_fbdev_mmap, .fb_destroy = msm_fbdev_fb_destroy, }; @@ -121,9 +120,9 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, drm_fb_helper_fill_info(fbi, helper, sizes); - fbi->screen_base = msm_gem_get_vaddr(bo); - if (IS_ERR(fbi->screen_base)) { - ret = PTR_ERR(fbi->screen_base); + fbi->screen_buffer = msm_gem_get_vaddr(bo); + if (IS_ERR(fbi->screen_buffer)) { + ret = PTR_ERR(fbi->screen_buffer); goto fail; } fbi->screen_size = bo->size; diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index db6c4e281d75..c32264234ea1 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -1096,6 +1096,20 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, return ret; } +static enum drm_gem_object_status msm_gem_status(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + enum drm_gem_object_status status = 0; + + if (msm_obj->pages) + status |= DRM_GEM_OBJECT_RESIDENT; + + if (msm_obj->madv == MSM_MADV_DONTNEED) + status |= DRM_GEM_OBJECT_PURGEABLE; + + return status; +} + static const struct vm_operations_struct vm_ops = { .fault = msm_gem_fault, .open = drm_gem_vm_open, @@ -1110,6 +1124,7 @@ static const struct drm_gem_object_funcs msm_gem_object_funcs = { .vmap = msm_gem_prime_vmap, .vunmap = msm_gem_prime_vunmap, .mmap = msm_gem_object_mmap, + .status = msm_gem_status, .vm_ops = &vm_ops, }; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 26ebda40be4f..c403912d13ab 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -151,8 +151,6 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu) void msm_gpu_show_fdinfo(struct msm_gpu *gpu, struct msm_file_private *ctx, struct drm_printer *p) { - drm_printf(p, "drm-driver:\t%s\n", gpu->dev->driver->name); - drm_printf(p, "drm-client-id:\t%u\n", ctx->seqno); drm_printf(p, "drm-engine-gpu:\t%llu ns\n", ctx->elapsed_ns); drm_printf(p, "drm-cycles-gpu:\t%llu\n", ctx->cycles); drm_printf(p, "drm-maxfreq-gpu:\t%u Hz\n", gpu->fast_rate); diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c index 6fb5b469ee5a..c9d8cbb21407 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_drv.c +++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c @@ -9,13 +9,16 @@ #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_device.h> +#include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_drv.h> +#include <drm/drm_encoder.h> #include <drm/drm_fbdev_dma.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> @@ -38,21 +41,70 @@ static const struct drm_mode_config_helper_funcs lcdif_mode_config_helpers = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; +static const struct drm_encoder_funcs lcdif_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + static int lcdif_attach_bridge(struct lcdif_drm_private *lcdif) { - struct drm_device *drm = lcdif->drm; + struct device *dev = lcdif->drm->dev; + struct device_node *ep; struct drm_bridge *bridge; int ret; - bridge = devm_drm_of_get_bridge(drm->dev, drm->dev->of_node, 0, 0); - if (IS_ERR(bridge)) - return PTR_ERR(bridge); - - ret = drm_bridge_attach(&lcdif->encoder, bridge, NULL, 0); - if (ret) - return dev_err_probe(drm->dev, ret, "Failed to attach bridge\n"); - - lcdif->bridge = bridge; + for_each_endpoint_of_node(dev->of_node, ep) { + struct device_node *remote; + struct of_endpoint of_ep; + struct drm_encoder *encoder; + + remote = of_graph_get_remote_port_parent(ep); + if (!of_device_is_available(remote)) { + of_node_put(remote); + continue; + } + of_node_put(remote); + + ret = of_graph_parse_endpoint(ep, &of_ep); + if (ret < 0) { + dev_err(dev, "Failed to parse endpoint %pOF\n", ep); + of_node_put(ep); + return ret; + } + + bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, of_ep.id); + if (IS_ERR(bridge)) { + of_node_put(ep); + return dev_err_probe(dev, PTR_ERR(bridge), + "Failed to get bridge for endpoint%u\n", + of_ep.id); + } + + encoder = devm_kzalloc(dev, sizeof(*encoder), GFP_KERNEL); + if (!encoder) { + dev_err(dev, "Failed to allocate encoder for endpoint%u\n", + of_ep.id); + of_node_put(ep); + return -ENOMEM; + } + + encoder->possible_crtcs = drm_crtc_mask(&lcdif->crtc); + ret = drm_encoder_init(lcdif->drm, encoder, &lcdif_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) { + dev_err(dev, "Failed to initialize encoder for endpoint%u: %d\n", + of_ep.id, ret); + of_node_put(ep); + return ret; + } + + ret = drm_bridge_attach(encoder, bridge, NULL, 0); + if (ret) { + of_node_put(ep); + return dev_err_probe(dev, ret, + "Failed to attach bridge for endpoint%u\n", + of_ep.id); + } + } return 0; } @@ -199,6 +251,7 @@ static const struct drm_driver lcdif_driver = { static const struct of_device_id lcdif_dt_ids[] = { { .compatible = "fsl,imx8mp-lcdif" }, + { .compatible = "fsl,imx93-lcdif" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, lcdif_dt_ids); diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.h b/drivers/gpu/drm/mxsfb/lcdif_drv.h index 6cdba6e20c02..61483a4e058d 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_drv.h +++ b/drivers/gpu/drm/mxsfb/lcdif_drv.h @@ -11,7 +11,6 @@ #include <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> -#include <drm/drm_encoder.h> #include <drm/drm_plane.h> struct clk; @@ -30,8 +29,6 @@ struct lcdif_drm_private { /* i.MXRT does support overlay planes, add them here. */ } planes; struct drm_crtc crtc; - struct drm_encoder encoder; - struct drm_bridge *bridge; }; static inline struct lcdif_drm_private * diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c index 262bc43b1079..2541d2de4e45 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_kms.c +++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c @@ -17,6 +17,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_color_mgmt.h> +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include <drm/drm_encoder.h> #include <drm/drm_fb_dma_helper.h> @@ -30,6 +31,18 @@ #include "lcdif_drv.h" #include "lcdif_regs.h" +struct lcdif_crtc_state { + struct drm_crtc_state base; /* always be the first member */ + u32 bus_format; + u32 bus_flags; +}; + +static inline struct lcdif_crtc_state * +to_lcdif_crtc_state(struct drm_crtc_state *s) +{ + return container_of(s, struct lcdif_crtc_state, base); +} + /* ----------------------------------------------------------------------------- * CRTC */ @@ -385,48 +398,108 @@ static void lcdif_reset_block(struct lcdif_drm_private *lcdif) readl(lcdif->base + LCDC_V8_CTRL); } -static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif, - struct drm_plane_state *plane_state, - struct drm_bridge_state *bridge_state, - const u32 bus_format) +static void lcdif_crtc_mode_set_nofb(struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) { - struct drm_device *drm = lcdif->crtc.dev; - struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode; - u32 bus_flags = 0; - - if (lcdif->bridge && lcdif->bridge->timings) - bus_flags = lcdif->bridge->timings->input_bus_flags; - else if (bridge_state) - bus_flags = bridge_state->input_bus_cfg.flags; + struct lcdif_crtc_state *lcdif_crtc_state = to_lcdif_crtc_state(crtc_state); + struct drm_device *drm = crtc_state->crtc->dev; + struct lcdif_drm_private *lcdif = to_lcdif_drm_private(drm); + struct drm_display_mode *m = &crtc_state->adjusted_mode; DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", m->crtc_clock, (int)(clk_get_rate(lcdif->clk) / 1000)); DRM_DEV_DEBUG_DRIVER(drm->dev, "Bridge bus_flags: 0x%08X\n", - bus_flags); + lcdif_crtc_state->bus_flags); DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); /* Mandatory eLCDIF reset as per the Reference Manual */ lcdif_reset_block(lcdif); - lcdif_set_formats(lcdif, plane_state, bus_format); + lcdif_set_formats(lcdif, plane_state, lcdif_crtc_state->bus_format); - lcdif_set_mode(lcdif, bus_flags); + lcdif_set_mode(lcdif, lcdif_crtc_state->bus_flags); } static int lcdif_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { + struct drm_device *drm = crtc->dev; struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct lcdif_crtc_state *lcdif_crtc_state = to_lcdif_crtc_state(crtc_state); bool has_primary = crtc_state->plane_mask & drm_plane_mask(crtc->primary); + struct drm_connector_state *connector_state; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_bridge_state *bridge_state; + struct drm_bridge *bridge; + u32 bus_format, bus_flags; + bool format_set = false, flags_set = false; + int ret, i; /* The primary plane has to be enabled when the CRTC is active. */ if (crtc_state->active && !has_primary) return -EINVAL; - return drm_atomic_add_affected_planes(state, crtc); + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + + /* Try to find consistent bus format and flags across first bridges. */ + for_each_new_connector_in_state(state, connector, connector_state, i) { + if (!connector_state->crtc) + continue; + + encoder = connector_state->best_encoder; + + bridge = drm_bridge_chain_get_first_bridge(encoder); + if (!bridge) + continue; + + bridge_state = drm_atomic_get_new_bridge_state(state, bridge); + if (!bridge_state) + bus_format = MEDIA_BUS_FMT_FIXED; + else + bus_format = bridge_state->input_bus_cfg.format; + + if (bus_format == MEDIA_BUS_FMT_FIXED) { + dev_warn(drm->dev, + "[ENCODER:%d:%s]'s bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n" + "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n", + encoder->base.id, encoder->name); + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + } else if (!bus_format) { + /* If all else fails, default to RGB888_1X24 */ + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + } + + if (!format_set) { + lcdif_crtc_state->bus_format = bus_format; + format_set = true; + } else if (lcdif_crtc_state->bus_format != bus_format) { + DRM_DEV_DEBUG_DRIVER(drm->dev, "inconsistent bus format\n"); + return -EINVAL; + } + + if (bridge->timings) + bus_flags = bridge->timings->input_bus_flags; + else if (bridge_state) + bus_flags = bridge_state->input_bus_cfg.flags; + else + bus_flags = 0; + + if (!flags_set) { + lcdif_crtc_state->bus_flags = bus_flags; + flags_set = true; + } else if (lcdif_crtc_state->bus_flags != bus_flags) { + DRM_DEV_DEBUG_DRIVER(drm->dev, "inconsistent bus flags\n"); + return -EINVAL; + } + } + + return 0; } static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc, @@ -458,41 +531,18 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev); + struct drm_crtc_state *new_cstate = drm_atomic_get_new_crtc_state(state, crtc); struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state, crtc->primary); struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode; - struct drm_bridge_state *bridge_state = NULL; struct drm_device *drm = lcdif->drm; - u32 bus_format = 0; dma_addr_t paddr; - /* If there is a bridge attached to the LCDIF, use its bus format */ - if (lcdif->bridge) { - bridge_state = - drm_atomic_get_new_bridge_state(state, - lcdif->bridge); - if (!bridge_state) - bus_format = MEDIA_BUS_FMT_FIXED; - else - bus_format = bridge_state->input_bus_cfg.format; - - if (bus_format == MEDIA_BUS_FMT_FIXED) { - dev_warn_once(drm->dev, - "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n" - "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n"); - bus_format = MEDIA_BUS_FMT_RGB888_1X24; - } - } - - /* If all else fails, default to RGB888_1X24 */ - if (!bus_format) - bus_format = MEDIA_BUS_FMT_RGB888_1X24; - clk_set_rate(lcdif->clk, m->crtc_clock * 1000); pm_runtime_get_sync(drm->dev); - lcdif_crtc_mode_set_nofb(lcdif, new_pstate, bridge_state, bus_format); + lcdif_crtc_mode_set_nofb(new_cstate, new_pstate); /* Write cur_buf as well to avoid an initial corrupt frame */ paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); @@ -529,6 +579,48 @@ static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc, pm_runtime_put_sync(drm->dev); } +static void lcdif_crtc_atomic_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + __drm_atomic_helper_crtc_destroy_state(state); + kfree(to_lcdif_crtc_state(state)); +} + +static void lcdif_crtc_reset(struct drm_crtc *crtc) +{ + struct lcdif_crtc_state *state; + + if (crtc->state) + lcdif_crtc_atomic_destroy_state(crtc, crtc->state); + + crtc->state = NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_crtc_reset(crtc, &state->base); +} + +static struct drm_crtc_state * +lcdif_crtc_atomic_duplicate_state(struct drm_crtc *crtc) +{ + struct lcdif_crtc_state *old = to_lcdif_crtc_state(crtc->state); + struct lcdif_crtc_state *new; + + if (WARN_ON(!crtc->state)) + return NULL; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &new->base); + + new->bus_format = old->bus_format; + new->bus_flags = old->bus_flags; + + return &new->base; +} + static int lcdif_crtc_enable_vblank(struct drm_crtc *crtc) { struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev); @@ -557,25 +649,17 @@ static const struct drm_crtc_helper_funcs lcdif_crtc_helper_funcs = { }; static const struct drm_crtc_funcs lcdif_crtc_funcs = { - .reset = drm_atomic_helper_crtc_reset, + .reset = lcdif_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 = lcdif_crtc_atomic_duplicate_state, + .atomic_destroy_state = lcdif_crtc_atomic_destroy_state, .enable_vblank = lcdif_crtc_enable_vblank, .disable_vblank = lcdif_crtc_disable_vblank, }; /* ----------------------------------------------------------------------------- - * Encoder - */ - -static const struct drm_encoder_funcs lcdif_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -/* ----------------------------------------------------------------------------- * Planes */ @@ -667,7 +751,6 @@ int lcdif_kms_init(struct lcdif_drm_private *lcdif) BIT(DRM_COLOR_YCBCR_BT2020); const u32 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | BIT(DRM_COLOR_YCBCR_FULL_RANGE); - struct drm_encoder *encoder = &lcdif->encoder; struct drm_crtc *crtc = &lcdif->crtc; int ret; @@ -691,13 +774,7 @@ int lcdif_kms_init(struct lcdif_drm_private *lcdif) return ret; drm_crtc_helper_add(crtc, &lcdif_crtc_helper_funcs); - ret = drm_crtc_init_with_planes(lcdif->drm, crtc, - &lcdif->planes.primary, NULL, - &lcdif_crtc_funcs, NULL); - if (ret) - return ret; - - encoder->possible_crtcs = drm_crtc_mask(crtc); - return drm_encoder_init(lcdif->drm, encoder, &lcdif_encoder_funcs, - DRM_MODE_ENCODER_NONE, NULL); + return drm_crtc_init_with_planes(lcdif->drm, crtc, + &lcdif->planes.primary, NULL, + &lcdif_crtc_funcs, NULL); } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index ed9d374147b8..9b6824f6b9e4 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -64,6 +64,7 @@ #include "nouveau_connector.h" #include "nouveau_encoder.h" #include "nouveau_fence.h" +#include "nv50_display.h" #include <subdev/bios/dp.h> @@ -363,6 +364,35 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder, return 0; } +static void +nv50_outp_atomic_fix_depth(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state) +{ + struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_display_mode *mode = &asyh->state.adjusted_mode; + unsigned int max_rate, mode_rate; + + switch (nv_encoder->dcb->type) { + case DCB_OUTPUT_DP: + max_rate = nv_encoder->dp.link_nr * nv_encoder->dp.link_bw; + + /* we don't support more than 10 anyway */ + asyh->or.bpc = min_t(u8, asyh->or.bpc, 10); + + /* reduce the bpc until it works out */ + while (asyh->or.bpc > 6) { + mode_rate = DIV_ROUND_UP(mode->clock * asyh->or.bpc * 3, 8); + if (mode_rate <= max_rate) + break; + + asyh->or.bpc -= 2; + } + break; + default: + break; + } +} + static int nv50_outp_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -381,6 +411,9 @@ nv50_outp_atomic_check(struct drm_encoder *encoder, if (crtc_state->mode_changed || crtc_state->connectors_changed) asyh->or.bpc = connector->display_info.bpc; + /* We might have to reduce the bpc */ + nv50_outp_atomic_fix_depth(encoder, crtc_state); + return 0; } diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index eb99d84eb844..16d4ad5023a3 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -2,6 +2,8 @@ #ifndef __NVIF_IF0012_H__ #define __NVIF_IF0012_H__ +#include <drm/display/drm_dp.h> + union nvif_outp_args { struct nvif_outp_v0 { __u8 version; @@ -63,7 +65,7 @@ union nvif_outp_acquire_args { __u8 hda; __u8 mst; __u8 pad04[4]; - __u8 dpcd[16]; + __u8 dpcd[DP_RECEIVER_CAP_SIZE]; } dp; }; } v0; diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 40409a29f5b6..91b5ecc57538 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -33,6 +33,7 @@ #include <linux/apple-gmux.h> #include <linux/backlight.h> #include <linux/idr.h> +#include <drm/drm_probe_helper.h> #include "nouveau_drv.h" #include "nouveau_reg.h" @@ -299,8 +300,12 @@ nv50_backlight_init(struct nouveau_backlight *bl, 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)) || - nv_conn->base.status != connector_status_connected) + drm_helper_probe_detect(&nv_conn->base, NULL, false) != connector_status_connected) return -ENODEV; if (nv_conn->type == DCB_CONNECTOR_eDP) { diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index 2a36d1ca8fda..99d022a91afc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -73,13 +73,14 @@ nouveau_debugfs_pstate_get(struct seq_file *m, void *data) { struct drm_device *drm = m->private; struct nouveau_debugfs *debugfs = nouveau_debugfs(drm); - struct nvif_object *ctrl = &debugfs->ctrl; + struct nvif_object *ctrl; struct nvif_control_pstate_info_v0 info = {}; int ret, i; if (!debugfs) return -ENODEV; + ctrl = &debugfs->ctrl; ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_INFO, &info, sizeof(info)); if (ret) return ret; @@ -119,19 +120,19 @@ nouveau_debugfs_pstate_get(struct seq_file *m, void *data) if (state >= 0) { if (info.ustate_ac == state) - seq_printf(m, " AC"); + seq_puts(m, " AC"); if (info.ustate_dc == state) - seq_printf(m, " DC"); + seq_puts(m, " DC"); if (info.pstate == state) - seq_printf(m, " *"); + seq_puts(m, " *"); } else { if (info.ustate_ac < -1) - seq_printf(m, " AC"); + seq_puts(m, " AC"); if (info.ustate_dc < -1) - seq_printf(m, " DC"); + seq_puts(m, " DC"); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); } return 0; @@ -144,7 +145,6 @@ nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf, struct seq_file *m = file->private_data; struct drm_device *drm = m->private; struct nouveau_debugfs *debugfs = nouveau_debugfs(drm); - struct nvif_object *ctrl = &debugfs->ctrl; struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL }; char buf[32] = {}, *tmp, *cur = buf; long value, ret; @@ -188,7 +188,8 @@ nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf, return ret; } - ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args)); + ret = nvif_mthd(&debugfs->ctrl, NVIF_CONTROL_PSTATE_USER, + &args, sizeof(args)); pm_runtime_put_autosuspend(drm->dev); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index e00876f92aee..d49b4875fc3c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -263,8 +263,6 @@ nouveau_dp_irq(struct work_struct *work) } /* TODO: - * - Use the minimum possible BPC here, once we add support for the max bpc - * property. * - Validate against the DP caps advertised by the GPU (we don't check these * yet) */ @@ -276,7 +274,11 @@ nv50_dp_mode_valid(struct drm_connector *connector, { const unsigned int min_clock = 25000; unsigned int max_rate, mode_rate, ds_max_dotclock, clock = mode->clock; - const u8 bpp = connector->display_info.bpc * 3; + /* Check with the minmum bpc always, so we can advertise better modes. + * In particlar not doing this causes modes to be dropped on HDR + * displays as we might check with a bpc of 16 even. + */ + const u8 bpp = 6 * 3; if (mode->flags & DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace) return MODE_NO_INTERLACE; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index f77e44958037..ab9062e50977 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -645,7 +645,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, struct drm_nouveau_gem_pushbuf_reloc *reloc, struct drm_nouveau_gem_pushbuf_bo *bo) { - long ret = 0; + int ret = 0; unsigned i; for (i = 0; i < req->nr_relocs; i++) { @@ -653,6 +653,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, struct drm_nouveau_gem_pushbuf_bo *b; struct nouveau_bo *nvbo; uint32_t data; + long lret; if (unlikely(r->bo_index >= req->nr_buffers)) { NV_PRINTK(err, cli, "reloc bo index invalid\n"); @@ -703,13 +704,18 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, data |= r->vor; } - ret = dma_resv_wait_timeout(nvbo->bo.base.resv, - DMA_RESV_USAGE_BOOKKEEP, - false, 15 * HZ); - if (ret == 0) + lret = dma_resv_wait_timeout(nvbo->bo.base.resv, + DMA_RESV_USAGE_BOOKKEEP, + false, 15 * HZ); + if (!lret) ret = -EBUSY; + else if (lret > 0) + ret = 0; + else + ret = lret; + if (ret) { - NV_PRINTK(err, cli, "reloc wait_idle failed: %ld\n", + NV_PRINTK(err, cli, "reloc wait_idle failed: %d\n", ret); break; } diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index e844be49e11e..db30a4c2cd4d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -211,7 +211,7 @@ static const struct attribute_group temp1_auto_point_sensor_group = { #define N_ATTR_GROUPS 3 -static const struct hwmon_channel_info *nouveau_info[] = { +static const struct hwmon_channel_info * const nouveau_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h index fbd3b15583bc..60f77766766e 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.h +++ b/drivers/gpu/drm/nouveau/nv50_display.h @@ -31,7 +31,5 @@ #include "nouveau_reg.h" int nv50_display_create(struct drm_device *); -void nv50_display_destroy(struct drm_device *); -int nv50_display_init(struct drm_device *); -void nv50_display_fini(struct drm_device *); + #endif /* __NV50_DISPLAY_H__ */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c index 115d0997fd62..4ebc030e40d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c @@ -606,7 +606,7 @@ gv100_disp_curs = { .user = 73, }; -const struct nvkm_disp_mthd_list +static const struct nvkm_disp_mthd_list gv100_disp_core_mthd_base = { .mthd = 0x0000, .addr = 0x000000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index b7631c1ab242..4e7f873f66e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -3,6 +3,7 @@ #define __NVKM_DISP_OUTP_H__ #include "priv.h" +#include <drm/display/drm_dp.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> #include <subdev/bios/dp.h> @@ -42,7 +43,7 @@ struct nvkm_outp { bool aux_pwr_pu; u8 lttpr[6]; u8 lttprs; - u8 dpcd[16]; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; struct { int dpcd; /* -1, or index into SUPPORTED_LINK_RATES table */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 4f0ca709c85a..fc283a4a1522 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -146,7 +146,7 @@ nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) } static int -nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[16], +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) { int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/power_budget.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/power_budget.c index 03d2f970a29f..2ba992bdb19d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/power_budget.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/power_budget.c @@ -59,7 +59,6 @@ int nvbios_power_budget_header(struct nvkm_bios *bios, struct nvbios_power_budget *budget) { - struct nvkm_subdev *subdev = &bios->subdev; u8 ver, hdr, cnt, len, cap_entry; u32 header; @@ -82,7 +81,7 @@ nvbios_power_budget_header(struct nvkm_bios *bios, } if (cap_entry >= cnt && cap_entry != 0xff) { - nvkm_warn(subdev, + nvkm_warn(&bios->subdev, "invalid cap_entry in power budget table found\n"); budget->cap_entry = 0xff; return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index da07a2fbef06..178dc56909c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -417,7 +417,6 @@ nvkm_pstate_new(struct nvkm_clk *clk, int idx) return 0; pstate = kzalloc(sizeof(*pstate), GFP_KERNEL); - cstate = &pstate->base; if (!pstate) return -ENOMEM; @@ -427,6 +426,7 @@ nvkm_pstate_new(struct nvkm_clk *clk, int idx) pstate->fanspeed = perfE.fanspeed; pstate->pcie_speed = perfE.pcie_speed; pstate->pcie_width = perfE.pcie_width; + cstate = &pstate->base; cstate->voltage = perfE.voltage; cstate->domain[nv_clk_src_core] = perfE.core; cstate->domain[nv_clk_src_shader] = perfE.shader; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c index 76678dd60f93..c4c6f67af7cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c @@ -31,6 +31,7 @@ gf108_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gf108_ram_new, .default_bigpage = 17, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c index f73442ccb424..433fa966ba23 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c @@ -77,6 +77,7 @@ gk104_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gk104_ram_new, .default_bigpage = 17, .clkgate_pack = gk104_fb_clkgate_pack, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c index 45d6cdffafee..4dc283dedf8b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c @@ -59,6 +59,7 @@ gk110_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gk104_ram_new, .default_bigpage = 17, .clkgate_pack = gk110_fb_clkgate_pack, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c index de52462a92bf..90bfff616d35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c @@ -31,6 +31,7 @@ gm107_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gm107_ram_new, .default_bigpage = 17, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c index 525267412c3e..a3996ceca995 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c @@ -45,7 +45,7 @@ ga102_gsp_nofw(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif) return 0; } -struct nvkm_gsp_fwif +static struct nvkm_gsp_fwif ga102_gsps[] = { { -1, ga102_gsp_nofw, &ga102_gsp }, {} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c index 1e2eabec1a76..5d28d30d09d5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c @@ -47,7 +47,7 @@ ga100_mc_device_enabled(struct nvkm_mc *mc, u32 mask) return (nvkm_rd32(mc->subdev.device, 0x000600) & mask) == mask; } -const struct nvkm_mc_device_func +static const struct nvkm_mc_device_func ga100_mc_device = { .enabled = ga100_mc_device_enabled, .enable = ga100_mc_device_enable, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/pcie.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/pcie.c index d71e5db5028a..dd18d9d0bade 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/pcie.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/pcie.c @@ -114,18 +114,17 @@ nvkm_pcie_init(struct nvkm_pci *pci) int nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width) { - struct nvkm_subdev *subdev = &pci->subdev; + struct nvkm_subdev *subdev; enum nvkm_pcie_speed cur_speed, max_speed; - struct pci_bus *pbus; int ret; if (!pci || !pci_is_pcie(pci->pdev)) return 0; - pbus = pci->pdev->bus; if (!pci->func->pcie.set_link) return -ENOSYS; + subdev = &pci->subdev; nvkm_trace(subdev, "requested %s\n", nvkm_pcie_speeds[speed]); if (pci->func->pcie.version(pci) < 2) { @@ -134,7 +133,7 @@ nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width) } cur_speed = pci->func->pcie.cur_speed(pci); - max_speed = min(nvkm_pcie_speed(pbus->max_bus_speed), + max_speed = min(nvkm_pcie_speed(pci->pdev->bus->max_bus_speed), pci->func->pcie.max_speed(pci)); nvkm_trace(subdev, "current speed: %s\n", nvkm_pcie_speeds[cur_speed]); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c index 340f37a299dc..b13ba9b2f6be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c @@ -98,10 +98,10 @@ nvkm_fanpwm_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) return -ENODEV; fan = kzalloc(sizeof(*fan), GFP_KERNEL); - therm->fan = &fan->base; if (!fan) return -ENOMEM; + therm->fan = &fan->base; fan->base.type = "PWM"; fan->base.get = nvkm_fanpwm_get; fan->base.set = nvkm_fanpwm_set; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c index ff9fbe7950e5..bfdf4ca5625c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c @@ -100,10 +100,10 @@ nvkm_fantog_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) } fan = kzalloc(sizeof(*fan), GFP_KERNEL); - therm->fan = &fan->base; if (!fan) return -ENOMEM; + therm->fan = &fan->base; fan->base.type = "toggle"; fan->base.get = nvkm_fantog_get; fan->base.set = nvkm_fantog_set; diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index 76ded1568bd0..b4ac76c9f31b 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -4,6 +4,7 @@ config DRM_OMAP depends on DRM && OF depends on ARCH_OMAP2PLUS select DRM_KMS_HELPER + select FB_SYS_HELPERS if DRM_FBDEV_EMULATION select VIDEOMODE_HELPERS select HDMI default n diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c index bfb2ccb40bd1..a3d470468e5b 100644 --- a/drivers/gpu/drm/omapdrm/omap_debugfs.c +++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c @@ -47,15 +47,15 @@ static int fb_show(struct seq_file *m, void *arg) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - struct omap_drm_private *priv = dev->dev_private; + struct drm_fb_helper *helper = dev->fb_helper; struct drm_framebuffer *fb; seq_printf(m, "fbcon "); - omap_framebuffer_describe(priv->fbdev->fb, m); + omap_framebuffer_describe(helper->fb, m); mutex_lock(&dev->mode_config.fb_lock); list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - if (fb == priv->fbdev->fb) + if (fb == helper->fb) continue; seq_printf(m, "user "); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 699ed814e021..5ed549726104 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -6,6 +6,7 @@ #include <linux/dma-mapping.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <linux/sort.h> #include <linux/sys_soc.h> @@ -14,7 +15,6 @@ #include <drm/drm_bridge.h> #include <drm/drm_bridge_connector.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_file.h> #include <drm/drm_ioctl.h> #include <drm/drm_panel.h> @@ -24,6 +24,7 @@ #include "omap_dmm_tiler.h" #include "omap_drv.h" +#include "omap_fbdev.h" #define DRIVER_NAME MODULE_NAME #define DRIVER_DESC "OMAP DRM" @@ -219,7 +220,6 @@ static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs = static const struct drm_mode_config_funcs omap_mode_config_funcs = { .fb_create = omap_framebuffer_create, - .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = omap_atomic_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -652,7 +652,6 @@ static const struct drm_driver omap_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_RENDER, .open = dev_open, - .lastclose = drm_fb_helper_lastclose, #ifdef CONFIG_DEBUG_FS .debugfs_init = omap_debugfs_init, #endif @@ -741,8 +740,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) goto err_cleanup_modeset; } - omap_fbdev_init(ddev); - drm_kms_helper_poll_init(ddev); /* @@ -753,12 +750,12 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) if (ret) goto err_cleanup_helpers; + omap_fbdev_setup(ddev); + return 0; err_cleanup_helpers: drm_kms_helper_poll_fini(ddev); - - omap_fbdev_fini(ddev); err_cleanup_modeset: omap_modeset_fini(ddev); err_free_overlays: @@ -784,8 +781,6 @@ static void omapdrm_cleanup(struct omap_drm_private *priv) drm_kms_helper_poll_fini(ddev); - omap_fbdev_fini(ddev); - drm_atomic_helper_shutdown(ddev); omap_modeset_fini(ddev); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 825960fd3ea9..4c7217b35f6b 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -21,7 +21,6 @@ #include "omap_crtc.h" #include "omap_encoder.h" #include "omap_fb.h" -#include "omap_fbdev.h" #include "omap_gem.h" #include "omap_irq.h" #include "omap_plane.h" @@ -77,8 +76,6 @@ struct omap_drm_private { struct drm_private_obj glob_obj; - struct drm_fb_helper *fbdev; - struct workqueue_struct *wq; /* lock for obj_list below */ diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index a6c8542087ec..b7ccce0704a3 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -4,14 +4,19 @@ * Author: Rob Clark <rob@ti.com> */ -#include <drm/drm_crtc.h> -#include <drm/drm_util.h> +#include <linux/fb.h> + +#include <drm/drm_drv.h> +#include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_file.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_util.h> #include "omap_drv.h" +#include "omap_fbdev.h" MODULE_PARM_DESC(ywrap, "Enable ywrap scrolling (omap44xx and later, default 'y')"); static bool ywrap_enabled = true; @@ -25,8 +30,6 @@ module_param_named(ywrap, ywrap_enabled, bool, 0644); struct omap_fbdev { struct drm_fb_helper base; - struct drm_framebuffer *fb; - struct drm_gem_object *bo; bool ywrap_enabled; /* for deferred dmm roll when getting called in atomic ctx */ @@ -38,12 +41,14 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi); static void pan_worker(struct work_struct *work) { struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work); - struct fb_info *fbi = fbdev->base.info; + struct drm_fb_helper *helper = &fbdev->base; + struct fb_info *fbi = helper->info; + struct drm_gem_object *bo = drm_gem_fb_get_obj(helper->fb, 0); int npages; /* DMM roll shifts in 4K pages: */ npages = fbi->fix.line_length >> PAGE_SHIFT; - omap_gem_roll(fbdev->bo, fbi->var.yoffset * npages); + omap_gem_roll(bo, fbi->var.yoffset * npages); } static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, @@ -71,21 +76,35 @@ fallback: return drm_fb_helper_pan_display(var, fbi); } +static void omap_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *helper = info->par; + struct drm_framebuffer *fb = helper->fb; + struct drm_gem_object *bo = drm_gem_fb_get_obj(fb, 0); + struct omap_fbdev *fbdev = to_omap_fbdev(helper); + + DBG(); + + drm_fb_helper_fini(helper); + + omap_gem_unpin(bo); + drm_framebuffer_remove(fb); + + drm_client_release(&helper->client); + drm_fb_helper_unprepare(helper); + kfree(fbdev); +} + static const struct fb_ops omap_fb_ops = { .owner = THIS_MODULE, - + FB_DEFAULT_SYS_OPS, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_setcmap = drm_fb_helper_setcmap, .fb_blank = drm_fb_helper_blank, .fb_pan_display = omap_fbdev_pan_display, .fb_ioctl = drm_fb_helper_ioctl, - - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, + .fb_destroy = omap_fbdev_fb_destroy, }; static int omap_fbdev_create(struct drm_fb_helper *helper, @@ -98,6 +117,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, union omap_gem_size gsize; struct fb_info *fbi = NULL; struct drm_mode_fb_cmd2 mode_cmd = {0}; + struct drm_gem_object *bo; dma_addr_t dma_addr; int ret; @@ -128,20 +148,20 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, .bytes = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height), }; DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index); - fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC); - if (!fbdev->bo) { + bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC); + if (!bo) { dev_err(dev->dev, "failed to allocate buffer object\n"); ret = -ENOMEM; goto fail; } - fb = omap_framebuffer_init(dev, &mode_cmd, &fbdev->bo); + fb = omap_framebuffer_init(dev, &mode_cmd, &bo); if (IS_ERR(fb)) { dev_err(dev->dev, "failed to allocate fb\n"); /* note: if fb creation failed, we can't rely on fb destroy * to unref the bo: */ - drm_gem_object_put(fbdev->bo); + drm_gem_object_put(bo); ret = PTR_ERR(fb); goto fail; } @@ -154,7 +174,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, * to it). Then we just need to be sure that we are able to re- * pin it in case of an opps. */ - ret = omap_gem_pin(fbdev->bo, &dma_addr); + ret = omap_gem_pin(bo, &dma_addr); if (ret) { dev_err(dev->dev, "could not pin framebuffer\n"); ret = -ENOMEM; @@ -170,17 +190,16 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, DBG("fbi=%p, dev=%p", fbi, dev); - fbdev->fb = fb; helper->fb = fb; fbi->fbops = &omap_fb_ops; drm_fb_helper_fill_info(fbi, helper, sizes); - fbi->screen_buffer = omap_gem_vaddr(fbdev->bo); - fbi->screen_size = fbdev->bo->size; + fbi->screen_buffer = omap_gem_vaddr(bo); + fbi->screen_size = bo->size; fbi->fix.smem_start = dma_addr; - fbi->fix.smem_len = fbdev->bo->size; + fbi->fix.smem_len = bo->size; /* if we have DMM, then we can use it for scrolling by just * shuffling pages around in DMM rather than doing sw blit. @@ -193,7 +212,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); - DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); + DBG("allocated %dx%d fb", fb->width, fb->height); return 0; @@ -220,75 +239,94 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi) return fbi->par; } -/* initialize fbdev helper */ -void omap_fbdev_init(struct drm_device *dev) +/* + * struct drm_client + */ + +static void omap_fbdev_client_unregister(struct drm_client_dev *client) { - struct omap_drm_private *priv = dev->dev_private; - struct omap_fbdev *fbdev = NULL; - struct drm_fb_helper *helper; - int ret = 0; + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); - if (!priv->num_pipes) - return; + if (fb_helper->info) { + drm_fb_helper_unregister_info(fb_helper); + } else { + drm_client_release(&fb_helper->client); + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); + } +} - fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); - if (!fbdev) - return; +static int omap_fbdev_client_restore(struct drm_client_dev *client) +{ + drm_fb_helper_lastclose(client->dev); - INIT_WORK(&fbdev->work, pan_worker); + return 0; +} - helper = &fbdev->base; +static int omap_fbdev_client_hotplug(struct drm_client_dev *client) +{ + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + struct drm_device *dev = client->dev; + int ret; - drm_fb_helper_prepare(dev, helper, 32, &omap_fb_helper_funcs); + if (dev->fb_helper) + return drm_fb_helper_hotplug_event(dev->fb_helper); - ret = drm_fb_helper_init(dev, helper); + ret = drm_fb_helper_init(dev, fb_helper); if (ret) - goto fail; + goto err_drm_err; - ret = drm_fb_helper_initial_config(helper); + ret = drm_fb_helper_initial_config(fb_helper); if (ret) - goto fini; - - priv->fbdev = helper; - - return; + goto err_drm_fb_helper_fini; -fini: - drm_fb_helper_fini(helper); -fail: - drm_fb_helper_unprepare(helper); - kfree(fbdev); + return 0; - dev_warn(dev->dev, "omap_fbdev_init failed\n"); +err_drm_fb_helper_fini: + drm_fb_helper_fini(fb_helper); +err_drm_err: + drm_err(dev, "Failed to setup fbdev emulation (ret=%d)\n", ret); + return ret; } -void omap_fbdev_fini(struct drm_device *dev) +static const struct drm_client_funcs omap_fbdev_client_funcs = { + .owner = THIS_MODULE, + .unregister = omap_fbdev_client_unregister, + .restore = omap_fbdev_client_restore, + .hotplug = omap_fbdev_client_hotplug, +}; + +void omap_fbdev_setup(struct drm_device *dev) { - struct omap_drm_private *priv = dev->dev_private; - struct drm_fb_helper *helper = priv->fbdev; struct omap_fbdev *fbdev; + struct drm_fb_helper *helper; + int ret; - DBG(); + drm_WARN(dev, !dev->registered, "Device has not been registered.\n"); + drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n"); - if (!helper) + fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); + if (!fbdev) return; + helper = &fbdev->base; - drm_fb_helper_unregister_info(helper); + drm_fb_helper_prepare(dev, helper, 32, &omap_fb_helper_funcs); - drm_fb_helper_fini(helper); + ret = drm_client_init(dev, &helper->client, "fbdev", &omap_fbdev_client_funcs); + if (ret) + goto err_drm_client_init; + + INIT_WORK(&fbdev->work, pan_worker); - fbdev = to_omap_fbdev(helper); + ret = omap_fbdev_client_hotplug(&helper->client); + if (ret) + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); - /* unpin the GEM object pinned in omap_fbdev_create() */ - if (fbdev->bo) - omap_gem_unpin(fbdev->bo); + drm_client_register(&helper->client); - /* this will free the backing object */ - if (fbdev->fb) - drm_framebuffer_remove(fbdev->fb); + return; +err_drm_client_init: drm_fb_helper_unprepare(helper); kfree(fbdev); - - priv->fbdev = NULL; } diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.h b/drivers/gpu/drm/omapdrm/omap_fbdev.h index 74a68a5a6eab..74c691a8d45f 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.h +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.h @@ -10,16 +10,11 @@ #define __OMAPDRM_FBDEV_H__ struct drm_device; -struct drm_fb_helper; #ifdef CONFIG_DRM_FBDEV_EMULATION -void omap_fbdev_init(struct drm_device *dev); -void omap_fbdev_fini(struct drm_device *dev); +void omap_fbdev_setup(struct drm_device *dev); #else -static inline void omap_fbdev_init(struct drm_device *dev) -{ -} -static inline void omap_fbdev_fini(struct drm_device *dev) +static inline void omap_fbdev_setup(struct drm_device *dev) { } #endif diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 2b9d6db7860b..203c0ef0bbfd 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -553,6 +553,13 @@ config DRM_PANEL_SAMSUNG_S6D27A1 This panel can be found in Samsung Galaxy Ace 2 GT-I8160 mobile phone. +config DRM_PANEL_SAMSUNG_S6D7AA0 + tristate "Samsung S6D7AA0 MIPI-DSI video mode panel controller" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + select DRM_MIPI_DSI + select VIDEOMODE_HELPERS + config DRM_PANEL_SAMSUNG_S6E3HA2 tristate "Samsung S6E3HA2 DSI video mode panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index ff169781e82d..30cf553c8d1d 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0) += panel-samsung-s6d7aa0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c index 783234ae0f57..f5a6046f1d19 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c @@ -36,6 +36,7 @@ struct panel_desc { const struct panel_init_cmd *init_cmds; unsigned int lanes; bool discharge_on_disable; + bool lp11_before_reset; }; struct boe_panel { @@ -451,11 +452,14 @@ static const struct panel_init_cmd inx_hj110iz_init_cmd[] = { _INIT_DCS_CMD(0xFF, 0x20), _INIT_DCS_CMD(0xFB, 0x01), _INIT_DCS_CMD(0x05, 0xD1), - _INIT_DCS_CMD(0x0D, 0x63), - _INIT_DCS_CMD(0x07, 0x8C), + _INIT_DCS_CMD(0x06, 0xC0), + _INIT_DCS_CMD(0x07, 0x87), _INIT_DCS_CMD(0x08, 0x4B), + + _INIT_DCS_CMD(0x0D, 0x63), _INIT_DCS_CMD(0x0E, 0x91), _INIT_DCS_CMD(0x0F, 0x69), + _INIT_DCS_CMD(0x94, 0x00), _INIT_DCS_CMD(0x95, 0xF5), _INIT_DCS_CMD(0x96, 0xF5), _INIT_DCS_CMD(0x9D, 0x00), @@ -463,98 +467,96 @@ static const struct panel_init_cmd inx_hj110iz_init_cmd[] = { _INIT_DCS_CMD(0x69, 0x98), _INIT_DCS_CMD(0x75, 0xA2), _INIT_DCS_CMD(0x77, 0xB3), + + _INIT_DCS_CMD(0x58, 0x43), _INIT_DCS_CMD(0xFF, 0x24), _INIT_DCS_CMD(0xFB, 0x01), _INIT_DCS_CMD(0x91, 0x44), - _INIT_DCS_CMD(0x92, 0x7A), - _INIT_DCS_CMD(0x93, 0x1A), - _INIT_DCS_CMD(0x94, 0x40), - _INIT_DCS_CMD(0x9A, 0x08), + _INIT_DCS_CMD(0x92, 0x4C), + _INIT_DCS_CMD(0x94, 0x86), _INIT_DCS_CMD(0x60, 0x96), _INIT_DCS_CMD(0x61, 0xD0), _INIT_DCS_CMD(0x63, 0x70), - _INIT_DCS_CMD(0xC2, 0xCF), - _INIT_DCS_CMD(0x9B, 0x0F), - _INIT_DCS_CMD(0x9A, 0x08), + _INIT_DCS_CMD(0xC2, 0xCA), + _INIT_DCS_CMD(0x00, 0x03), _INIT_DCS_CMD(0x01, 0x03), _INIT_DCS_CMD(0x02, 0x03), - _INIT_DCS_CMD(0x03, 0x03), - _INIT_DCS_CMD(0x04, 0x03), - _INIT_DCS_CMD(0x05, 0x03), - _INIT_DCS_CMD(0x06, 0x22), - _INIT_DCS_CMD(0x07, 0x06), - _INIT_DCS_CMD(0x08, 0x00), - _INIT_DCS_CMD(0x09, 0x1D), - _INIT_DCS_CMD(0x0A, 0x1C), - _INIT_DCS_CMD(0x0B, 0x13), - _INIT_DCS_CMD(0x0C, 0x12), - _INIT_DCS_CMD(0x0D, 0x11), - _INIT_DCS_CMD(0x0E, 0x10), - _INIT_DCS_CMD(0x0F, 0x0F), - _INIT_DCS_CMD(0x10, 0x0E), - _INIT_DCS_CMD(0x11, 0x0D), - _INIT_DCS_CMD(0x12, 0x0C), + _INIT_DCS_CMD(0x03, 0x29), + _INIT_DCS_CMD(0x04, 0x22), + _INIT_DCS_CMD(0x05, 0x22), + _INIT_DCS_CMD(0x06, 0x0B), + _INIT_DCS_CMD(0x07, 0x1D), + _INIT_DCS_CMD(0x08, 0x1C), + _INIT_DCS_CMD(0x09, 0x05), + _INIT_DCS_CMD(0x0A, 0x08), + _INIT_DCS_CMD(0x0B, 0x09), + _INIT_DCS_CMD(0x0C, 0x0A), + _INIT_DCS_CMD(0x0D, 0x0C), + _INIT_DCS_CMD(0x0E, 0x0D), + _INIT_DCS_CMD(0x0F, 0x0E), + _INIT_DCS_CMD(0x10, 0x0F), + _INIT_DCS_CMD(0x11, 0x10), + _INIT_DCS_CMD(0x12, 0x11), _INIT_DCS_CMD(0x13, 0x04), - _INIT_DCS_CMD(0x14, 0x03), + _INIT_DCS_CMD(0x14, 0x00), _INIT_DCS_CMD(0x15, 0x03), _INIT_DCS_CMD(0x16, 0x03), _INIT_DCS_CMD(0x17, 0x03), _INIT_DCS_CMD(0x18, 0x03), - _INIT_DCS_CMD(0x19, 0x03), - _INIT_DCS_CMD(0x1A, 0x03), - _INIT_DCS_CMD(0x1B, 0x03), - _INIT_DCS_CMD(0x1C, 0x22), - _INIT_DCS_CMD(0x1D, 0x06), - _INIT_DCS_CMD(0x1E, 0x00), - _INIT_DCS_CMD(0x1F, 0x1D), - _INIT_DCS_CMD(0x20, 0x1C), - _INIT_DCS_CMD(0x21, 0x13), - _INIT_DCS_CMD(0x22, 0x12), - _INIT_DCS_CMD(0x23, 0x11), - _INIT_DCS_CMD(0x24, 0x10), - _INIT_DCS_CMD(0x25, 0x0F), - _INIT_DCS_CMD(0x26, 0x0E), - _INIT_DCS_CMD(0x27, 0x0D), - _INIT_DCS_CMD(0x28, 0x0C), + _INIT_DCS_CMD(0x19, 0x29), + _INIT_DCS_CMD(0x1A, 0x22), + _INIT_DCS_CMD(0x1B, 0x22), + _INIT_DCS_CMD(0x1C, 0x0B), + _INIT_DCS_CMD(0x1D, 0x1D), + _INIT_DCS_CMD(0x1E, 0x1C), + _INIT_DCS_CMD(0x1F, 0x05), + _INIT_DCS_CMD(0x20, 0x08), + _INIT_DCS_CMD(0x21, 0x09), + _INIT_DCS_CMD(0x22, 0x0A), + _INIT_DCS_CMD(0x23, 0x0C), + _INIT_DCS_CMD(0x24, 0x0D), + _INIT_DCS_CMD(0x25, 0x0E), + _INIT_DCS_CMD(0x26, 0x0F), + _INIT_DCS_CMD(0x27, 0x10), + _INIT_DCS_CMD(0x28, 0x11), _INIT_DCS_CMD(0x29, 0x04), - _INIT_DCS_CMD(0x2A, 0x03), + _INIT_DCS_CMD(0x2A, 0x00), _INIT_DCS_CMD(0x2B, 0x03), - _INIT_DCS_CMD(0x2F, 0x05), - _INIT_DCS_CMD(0x30, 0x32), - _INIT_DCS_CMD(0x31, 0x43), - _INIT_DCS_CMD(0x33, 0x05), - _INIT_DCS_CMD(0x34, 0x32), - _INIT_DCS_CMD(0x35, 0x43), - _INIT_DCS_CMD(0x37, 0x44), - _INIT_DCS_CMD(0x38, 0x40), + _INIT_DCS_CMD(0x2F, 0x0A), + _INIT_DCS_CMD(0x30, 0x35), + _INIT_DCS_CMD(0x37, 0xA7), _INIT_DCS_CMD(0x39, 0x00), - _INIT_DCS_CMD(0x3A, 0x18), - _INIT_DCS_CMD(0x3B, 0x00), - _INIT_DCS_CMD(0x3D, 0x93), - _INIT_DCS_CMD(0xAB, 0x44), - _INIT_DCS_CMD(0xAC, 0x40), + _INIT_DCS_CMD(0x3A, 0x46), + _INIT_DCS_CMD(0x3B, 0x32), + _INIT_DCS_CMD(0x3D, 0x12), + + _INIT_DCS_CMD(0x3F, 0x33), + _INIT_DCS_CMD(0x40, 0x31), + _INIT_DCS_CMD(0x41, 0x40), + _INIT_DCS_CMD(0x42, 0x42), + _INIT_DCS_CMD(0x47, 0x77), + _INIT_DCS_CMD(0x48, 0x77), + _INIT_DCS_CMD(0x4A, 0x45), + _INIT_DCS_CMD(0x4B, 0x45), + _INIT_DCS_CMD(0x4C, 0x14), _INIT_DCS_CMD(0x4D, 0x21), _INIT_DCS_CMD(0x4E, 0x43), _INIT_DCS_CMD(0x4F, 0x65), - _INIT_DCS_CMD(0x50, 0x87), - _INIT_DCS_CMD(0x51, 0x78), - _INIT_DCS_CMD(0x52, 0x56), - _INIT_DCS_CMD(0x53, 0x34), - _INIT_DCS_CMD(0x54, 0x21), - _INIT_DCS_CMD(0x55, 0x83), - _INIT_DCS_CMD(0x56, 0x08), + _INIT_DCS_CMD(0x55, 0x06), + _INIT_DCS_CMD(0x56, 0x06), _INIT_DCS_CMD(0x58, 0x21), - _INIT_DCS_CMD(0x59, 0x40), - _INIT_DCS_CMD(0x5A, 0x00), - _INIT_DCS_CMD(0x5B, 0x2C), - _INIT_DCS_CMD(0x5E, 0x00, 0x10), + _INIT_DCS_CMD(0x59, 0x70), + _INIT_DCS_CMD(0x5A, 0x46), + _INIT_DCS_CMD(0x5B, 0x32), + _INIT_DCS_CMD(0x5C, 0x88), + _INIT_DCS_CMD(0x5E, 0x00, 0x00), _INIT_DCS_CMD(0x5F, 0x00), - _INIT_DCS_CMD(0x7A, 0x00), - _INIT_DCS_CMD(0x7B, 0x00), + _INIT_DCS_CMD(0x7A, 0xFF), + _INIT_DCS_CMD(0x7B, 0xFF), _INIT_DCS_CMD(0x7C, 0x00), _INIT_DCS_CMD(0x7D, 0x00), _INIT_DCS_CMD(0x7E, 0x20), @@ -564,152 +566,183 @@ static const struct panel_init_cmd inx_hj110iz_init_cmd[] = { _INIT_DCS_CMD(0x82, 0x08), _INIT_DCS_CMD(0x97, 0x02), _INIT_DCS_CMD(0xC5, 0x10), + + _INIT_DCS_CMD(0xD7, 0x55), + _INIT_DCS_CMD(0xD8, 0x55), + _INIT_DCS_CMD(0xD9, 0x23), _INIT_DCS_CMD(0xDA, 0x05), _INIT_DCS_CMD(0xDB, 0x01), - _INIT_DCS_CMD(0xDC, 0x7A), + _INIT_DCS_CMD(0xDC, 0x65), _INIT_DCS_CMD(0xDD, 0x55), _INIT_DCS_CMD(0xDE, 0x27), _INIT_DCS_CMD(0xDF, 0x01), - _INIT_DCS_CMD(0xE0, 0x7A), + _INIT_DCS_CMD(0xE0, 0x65), _INIT_DCS_CMD(0xE1, 0x01), - _INIT_DCS_CMD(0xE2, 0x7A), + _INIT_DCS_CMD(0xE2, 0x65), _INIT_DCS_CMD(0xE3, 0x01), - _INIT_DCS_CMD(0xE4, 0x7A), + _INIT_DCS_CMD(0xE4, 0x65), _INIT_DCS_CMD(0xE5, 0x01), - _INIT_DCS_CMD(0xE6, 0x7A), + _INIT_DCS_CMD(0xE6, 0x65), _INIT_DCS_CMD(0xE7, 0x00), _INIT_DCS_CMD(0xE8, 0x00), _INIT_DCS_CMD(0xE9, 0x01), - _INIT_DCS_CMD(0xEA, 0x7A), + _INIT_DCS_CMD(0xEA, 0x65), _INIT_DCS_CMD(0xEB, 0x01), - _INIT_DCS_CMD(0xEE, 0x7A), + _INIT_DCS_CMD(0xEE, 0x65), _INIT_DCS_CMD(0xEF, 0x01), - _INIT_DCS_CMD(0xF0, 0x7A), - + _INIT_DCS_CMD(0xF0, 0x65), _INIT_DCS_CMD(0xB6, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00), + _INIT_DCS_CMD(0xFF, 0x25), - _INIT_DCS_CMD(0xFB, 0x01), + _INIT_DCS_CMD(0xFB, 0x01), _INIT_DCS_CMD(0x05, 0x00), - - _INIT_DCS_CMD(0x13, 0x02), - _INIT_DCS_CMD(0x14, 0xDF), _INIT_DCS_CMD(0xF1, 0x10), + _INIT_DCS_CMD(0x1E, 0x00), - _INIT_DCS_CMD(0x1F, 0x00), - _INIT_DCS_CMD(0x20, 0x2C), + _INIT_DCS_CMD(0x1F, 0x46), + _INIT_DCS_CMD(0x20, 0x32), + _INIT_DCS_CMD(0x25, 0x00), - _INIT_DCS_CMD(0x26, 0x00), - _INIT_DCS_CMD(0x27, 0x2C), + _INIT_DCS_CMD(0x26, 0x46), + _INIT_DCS_CMD(0x27, 0x32), + _INIT_DCS_CMD(0x3F, 0x80), _INIT_DCS_CMD(0x40, 0x00), _INIT_DCS_CMD(0x43, 0x00), - _INIT_DCS_CMD(0x44, 0x18), - _INIT_DCS_CMD(0x45, 0x00), + _INIT_DCS_CMD(0x44, 0x46), + _INIT_DCS_CMD(0x45, 0x46), + + _INIT_DCS_CMD(0x48, 0x46), + _INIT_DCS_CMD(0x49, 0x32), - _INIT_DCS_CMD(0x48, 0x00), - _INIT_DCS_CMD(0x49, 0x2C), _INIT_DCS_CMD(0x5B, 0x80), + _INIT_DCS_CMD(0x5C, 0x00), - _INIT_DCS_CMD(0x5D, 0x00), - _INIT_DCS_CMD(0x5E, 0x00), - _INIT_DCS_CMD(0x61, 0x00), - _INIT_DCS_CMD(0x62, 0x2C), - _INIT_DCS_CMD(0x68, 0x10), + _INIT_DCS_CMD(0x5D, 0x46), + _INIT_DCS_CMD(0x5E, 0x32), + + _INIT_DCS_CMD(0x5F, 0x46), + _INIT_DCS_CMD(0x60, 0x32), + + _INIT_DCS_CMD(0x61, 0x46), + _INIT_DCS_CMD(0x62, 0x32), + _INIT_DCS_CMD(0x68, 0x0C), + + _INIT_DCS_CMD(0x6C, 0x0D), + _INIT_DCS_CMD(0x6E, 0x0D), + _INIT_DCS_CMD(0x78, 0x00), + _INIT_DCS_CMD(0x79, 0xC5), + _INIT_DCS_CMD(0x7A, 0x0C), + _INIT_DCS_CMD(0x7B, 0xB0), + _INIT_DCS_CMD(0xFF, 0x26), _INIT_DCS_CMD(0xFB, 0x01), _INIT_DCS_CMD(0x00, 0xA1), _INIT_DCS_CMD(0x02, 0x31), - _INIT_DCS_CMD(0x0A, 0xF2), - _INIT_DCS_CMD(0x04, 0x28), + _INIT_DCS_CMD(0x0A, 0xF4), + _INIT_DCS_CMD(0x04, 0x50), _INIT_DCS_CMD(0x06, 0x30), _INIT_DCS_CMD(0x0C, 0x16), _INIT_DCS_CMD(0x0D, 0x0D), _INIT_DCS_CMD(0x0F, 0x00), _INIT_DCS_CMD(0x11, 0x00), _INIT_DCS_CMD(0x12, 0x50), - _INIT_DCS_CMD(0x13, 0x56), - _INIT_DCS_CMD(0x14, 0x57), + _INIT_DCS_CMD(0x13, 0x40), + _INIT_DCS_CMD(0x14, 0x58), _INIT_DCS_CMD(0x15, 0x00), _INIT_DCS_CMD(0x16, 0x10), _INIT_DCS_CMD(0x17, 0xA0), _INIT_DCS_CMD(0x18, 0x86), _INIT_DCS_CMD(0x22, 0x00), _INIT_DCS_CMD(0x23, 0x00), - _INIT_DCS_CMD(0x19, 0x0D), - _INIT_DCS_CMD(0x1A, 0x7F), - _INIT_DCS_CMD(0x1B, 0x0C), - _INIT_DCS_CMD(0x1C, 0xBF), - _INIT_DCS_CMD(0x2A, 0x0D), - _INIT_DCS_CMD(0x2B, 0x7F), - _INIT_DCS_CMD(0x20, 0x00), + + _INIT_DCS_CMD(0x19, 0x0E), + _INIT_DCS_CMD(0x1A, 0x31), + _INIT_DCS_CMD(0x1B, 0x0D), + _INIT_DCS_CMD(0x1C, 0x29), + _INIT_DCS_CMD(0x2A, 0x0E), + _INIT_DCS_CMD(0x2B, 0x31), _INIT_DCS_CMD(0x1D, 0x00), - _INIT_DCS_CMD(0x1E, 0x78), - _INIT_DCS_CMD(0x1F, 0x78), + _INIT_DCS_CMD(0x1E, 0x62), + _INIT_DCS_CMD(0x1F, 0x62), - _INIT_DCS_CMD(0x2F, 0x03), - _INIT_DCS_CMD(0x30, 0x78), - _INIT_DCS_CMD(0x33, 0x78), - _INIT_DCS_CMD(0x34, 0x66), - _INIT_DCS_CMD(0x35, 0x11), + _INIT_DCS_CMD(0x2F, 0x06), + _INIT_DCS_CMD(0x30, 0x62), + _INIT_DCS_CMD(0x31, 0x06), + _INIT_DCS_CMD(0x32, 0x7F), + _INIT_DCS_CMD(0x33, 0x11), + _INIT_DCS_CMD(0x34, 0x89), + _INIT_DCS_CMD(0x35, 0x67), - _INIT_DCS_CMD(0x39, 0x10), - _INIT_DCS_CMD(0x3A, 0x78), + _INIT_DCS_CMD(0x39, 0x0B), + _INIT_DCS_CMD(0x3A, 0x62), _INIT_DCS_CMD(0x3B, 0x06), _INIT_DCS_CMD(0xC8, 0x04), - _INIT_DCS_CMD(0xC9, 0x84), + _INIT_DCS_CMD(0xC9, 0x89), _INIT_DCS_CMD(0xCA, 0x4E), _INIT_DCS_CMD(0xCB, 0x00), + _INIT_DCS_CMD(0xA9, 0x3F), + _INIT_DCS_CMD(0xAA, 0x3E), + _INIT_DCS_CMD(0xAB, 0x3D), + _INIT_DCS_CMD(0xAC, 0x3C), + _INIT_DCS_CMD(0xAD, 0x3B), + _INIT_DCS_CMD(0xAE, 0x3A), + _INIT_DCS_CMD(0xAF, 0x39), + _INIT_DCS_CMD(0xB0, 0x38), - _INIT_DCS_CMD(0xA9, 0x50), - _INIT_DCS_CMD(0xAA, 0x4F), - _INIT_DCS_CMD(0xAB, 0x4D), - _INIT_DCS_CMD(0xAC, 0x4A), - _INIT_DCS_CMD(0xAD, 0x48), - _INIT_DCS_CMD(0xAE, 0x46), _INIT_DCS_CMD(0xFF, 0x27), _INIT_DCS_CMD(0xFB, 0x01), + + _INIT_DCS_CMD(0xD0, 0x11), + _INIT_DCS_CMD(0xD1, 0x54), + _INIT_DCS_CMD(0xDE, 0x43), + _INIT_DCS_CMD(0xDF, 0x02), + _INIT_DCS_CMD(0xC0, 0x18), _INIT_DCS_CMD(0xC1, 0x00), _INIT_DCS_CMD(0xC2, 0x00), + _INIT_DCS_CMD(0x00, 0x00), + _INIT_DCS_CMD(0xC3, 0x00), _INIT_DCS_CMD(0x56, 0x06), + _INIT_DCS_CMD(0x58, 0x80), - _INIT_DCS_CMD(0x59, 0x75), + _INIT_DCS_CMD(0x59, 0x78), _INIT_DCS_CMD(0x5A, 0x00), - _INIT_DCS_CMD(0x5B, 0x02), + _INIT_DCS_CMD(0x5B, 0x18), _INIT_DCS_CMD(0x5C, 0x00), - _INIT_DCS_CMD(0x5D, 0x00), + _INIT_DCS_CMD(0x5D, 0x01), _INIT_DCS_CMD(0x5E, 0x20), _INIT_DCS_CMD(0x5F, 0x10), _INIT_DCS_CMD(0x60, 0x00), - _INIT_DCS_CMD(0x61, 0x2E), + _INIT_DCS_CMD(0x61, 0x1C), _INIT_DCS_CMD(0x62, 0x00), _INIT_DCS_CMD(0x63, 0x01), - _INIT_DCS_CMD(0x64, 0x43), - _INIT_DCS_CMD(0x65, 0x2D), + _INIT_DCS_CMD(0x64, 0x44), + _INIT_DCS_CMD(0x65, 0x1B), _INIT_DCS_CMD(0x66, 0x00), _INIT_DCS_CMD(0x67, 0x01), - _INIT_DCS_CMD(0x68, 0x43), + _INIT_DCS_CMD(0x68, 0x44), + _INIT_DCS_CMD(0x98, 0x01), _INIT_DCS_CMD(0xB4, 0x03), - _INIT_DCS_CMD(0x9B, 0xBD), - _INIT_DCS_CMD(0xA0, 0x90), - _INIT_DCS_CMD(0xAB, 0x1B), - _INIT_DCS_CMD(0xBC, 0x0C), + _INIT_DCS_CMD(0x9B, 0xBE), + + _INIT_DCS_CMD(0xAB, 0x14), + _INIT_DCS_CMD(0xBC, 0x08), _INIT_DCS_CMD(0xBD, 0x28), _INIT_DCS_CMD(0xFF, 0x2A), _INIT_DCS_CMD(0xFB, 0x01), - _INIT_DCS_CMD(0x22, 0x2F), _INIT_DCS_CMD(0x23, 0x08), _INIT_DCS_CMD(0x24, 0x00), - _INIT_DCS_CMD(0x25, 0x65), + _INIT_DCS_CMD(0x25, 0x62), _INIT_DCS_CMD(0x26, 0xF8), _INIT_DCS_CMD(0x27, 0x00), _INIT_DCS_CMD(0x28, 0x1A), @@ -719,18 +752,29 @@ static const struct panel_init_cmd inx_hj110iz_init_cmd[] = { _INIT_DCS_CMD(0x2D, 0x1A), _INIT_DCS_CMD(0x64, 0x96), - _INIT_DCS_CMD(0x65, 0x00), + _INIT_DCS_CMD(0x65, 0x10), _INIT_DCS_CMD(0x66, 0x00), + _INIT_DCS_CMD(0x67, 0x96), + _INIT_DCS_CMD(0x68, 0x10), + _INIT_DCS_CMD(0x69, 0x00), _INIT_DCS_CMD(0x6A, 0x96), - _INIT_DCS_CMD(0x6B, 0x00), + _INIT_DCS_CMD(0x6B, 0x10), _INIT_DCS_CMD(0x6C, 0x00), _INIT_DCS_CMD(0x70, 0x92), - _INIT_DCS_CMD(0x71, 0x00), + _INIT_DCS_CMD(0x71, 0x10), _INIT_DCS_CMD(0x72, 0x00), - _INIT_DCS_CMD(0xA2, 0x33), + _INIT_DCS_CMD(0x79, 0x96), + _INIT_DCS_CMD(0x7A, 0x10), + _INIT_DCS_CMD(0x88, 0x96), + _INIT_DCS_CMD(0x89, 0x10), + + _INIT_DCS_CMD(0xA2, 0x3F), _INIT_DCS_CMD(0xA3, 0x30), _INIT_DCS_CMD(0xA4, 0xC0), + _INIT_DCS_CMD(0xA5, 0x03), + _INIT_DCS_CMD(0xE8, 0x00), + _INIT_DCS_CMD(0x97, 0x3C), _INIT_DCS_CMD(0x98, 0x02), _INIT_DCS_CMD(0x99, 0x95), @@ -739,38 +783,68 @@ static const struct panel_init_cmd inx_hj110iz_init_cmd[] = { _INIT_DCS_CMD(0x9C, 0x0B), _INIT_DCS_CMD(0x9D, 0x0A), _INIT_DCS_CMD(0x9E, 0x90), + + _INIT_DCS_CMD(0xFF, 0x25), + _INIT_DCS_CMD(0x13, 0x02), + _INIT_DCS_CMD(0x14, 0xD7), + _INIT_DCS_CMD(0xDB, 0x02), + _INIT_DCS_CMD(0xDC, 0xD7), + _INIT_DCS_CMD(0x17, 0xCF), + _INIT_DCS_CMD(0x19, 0x0F), + _INIT_DCS_CMD(0x1B, 0x5B), + + _INIT_DCS_CMD(0xFF, 0x20), + + _INIT_DCS_CMD(0xB0, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x24, 0x00, 0x38, 0x00, 0x4C, 0x00, 0x5E, 0x00, 0x6F, 0x00, 0x7E), + _INIT_DCS_CMD(0xB1, 0x00, 0x8C, 0x00, 0xBE, 0x00, 0xE5, 0x01, 0x27, 0x01, 0x58, 0x01, 0xA8, 0x01, 0xE8, 0x01, 0xEA), + _INIT_DCS_CMD(0xB2, 0x02, 0x28, 0x02, 0x71, 0x02, 0x9E, 0x02, 0xDA, 0x03, 0x00, 0x03, 0x31, 0x03, 0x40, 0x03, 0x51), + _INIT_DCS_CMD(0xB3, 0x03, 0x62, 0x03, 0x75, 0x03, 0x89, 0x03, 0x9C, 0x03, 0xAA, 0x03, 0xB2), + + _INIT_DCS_CMD(0xB4, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x27, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x64, 0x00, 0x75, 0x00, 0x84), + _INIT_DCS_CMD(0xB5, 0x00, 0x93, 0x00, 0xC5, 0x00, 0xEC, 0x01, 0x2C, 0x01, 0x5D, 0x01, 0xAC, 0x01, 0xEC, 0x01, 0xEE), + _INIT_DCS_CMD(0xB6, 0x02, 0x2B, 0x02, 0x73, 0x02, 0xA0, 0x02, 0xDB, 0x03, 0x01, 0x03, 0x31, 0x03, 0x41, 0x03, 0x51), + _INIT_DCS_CMD(0xB7, 0x03, 0x63, 0x03, 0x75, 0x03, 0x89, 0x03, 0x9C, 0x03, 0xAA, 0x03, 0xB2), + + _INIT_DCS_CMD(0xB8, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x2A, 0x00, 0x40, 0x00, 0x56, 0x00, 0x68, 0x00, 0x7A, 0x00, 0x89), + _INIT_DCS_CMD(0xB9, 0x00, 0x98, 0x00, 0xC9, 0x00, 0xF1, 0x01, 0x30, 0x01, 0x61, 0x01, 0xB0, 0x01, 0xEF, 0x01, 0xF1), + _INIT_DCS_CMD(0xBA, 0x02, 0x2E, 0x02, 0x76, 0x02, 0xA3, 0x02, 0xDD, 0x03, 0x02, 0x03, 0x32, 0x03, 0x42, 0x03, 0x53), + _INIT_DCS_CMD(0xBB, 0x03, 0x66, 0x03, 0x75, 0x03, 0x89, 0x03, 0x9C, 0x03, 0xAA, 0x03, 0xB2), + + _INIT_DCS_CMD(0xFF, 0x21), + _INIT_DCS_CMD(0xB0, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x24, 0x00, 0x38, 0x00, 0x4C, 0x00, 0x5E, 0x00, 0x6F, 0x00, 0x7E), + _INIT_DCS_CMD(0xB1, 0x00, 0x8C, 0x00, 0xBE, 0x00, 0xE5, 0x01, 0x27, 0x01, 0x58, 0x01, 0xA8, 0x01, 0xE8, 0x01, 0xEA), + _INIT_DCS_CMD(0xB2, 0x02, 0x28, 0x02, 0x71, 0x02, 0x9E, 0x02, 0xDA, 0x03, 0x00, 0x03, 0x31, 0x03, 0x40, 0x03, 0x51), + _INIT_DCS_CMD(0xB3, 0x03, 0x62, 0x03, 0x77, 0x03, 0x90, 0x03, 0xAC, 0x03, 0xCA, 0x03, 0xDA), + + _INIT_DCS_CMD(0xB4, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x27, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x64, 0x00, 0x75, 0x00, 0x84), + _INIT_DCS_CMD(0xB5, 0x00, 0x93, 0x00, 0xC5, 0x00, 0xEC, 0x01, 0x2C, 0x01, 0x5D, 0x01, 0xAC, 0x01, 0xEC, 0x01, 0xEE), + _INIT_DCS_CMD(0xB6, 0x02, 0x2B, 0x02, 0x73, 0x02, 0xA0, 0x02, 0xDB, 0x03, 0x01, 0x03, 0x31, 0x03, 0x41, 0x03, 0x51), + _INIT_DCS_CMD(0xB7, 0x03, 0x63, 0x03, 0x77, 0x03, 0x90, 0x03, 0xAC, 0x03, 0xCA, 0x03, 0xDA), + + _INIT_DCS_CMD(0xB8, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x2A, 0x00, 0x40, 0x00, 0x56, 0x00, 0x68, 0x00, 0x7A, 0x00, 0x89), + _INIT_DCS_CMD(0xB9, 0x00, 0x98, 0x00, 0xC9, 0x00, 0xF1, 0x01, 0x30, 0x01, 0x61, 0x01, 0xB0, 0x01, 0xEF, 0x01, 0xF1), + _INIT_DCS_CMD(0xBA, 0x02, 0x2E, 0x02, 0x76, 0x02, 0xA3, 0x02, 0xDD, 0x03, 0x02, 0x03, 0x32, 0x03, 0x42, 0x03, 0x53), + _INIT_DCS_CMD(0xBB, 0x03, 0x66, 0x03, 0x77, 0x03, 0x90, 0x03, 0xAC, 0x03, 0xCA, 0x03, 0xDA), + _INIT_DCS_CMD(0xFF, 0xF0), _INIT_DCS_CMD(0xFB, 0x01), _INIT_DCS_CMD(0x3A, 0x08), - _INIT_DCS_CMD(0xFF, 0xD0), - _INIT_DCS_CMD(0xFB, 0x01), - _INIT_DCS_CMD(0x00, 0x33), - _INIT_DCS_CMD(0x08, 0x01), - _INIT_DCS_CMD(0x09, 0xBF), - _INIT_DCS_CMD(0x2F, 0x33), - _INIT_DCS_CMD(0xFF, 0x23), - _INIT_DCS_CMD(0xFB, 0x01), - _INIT_DCS_CMD(0x00, 0x80), - _INIT_DCS_CMD(0x07, 0x00), - _INIT_DCS_CMD(0xFF, 0x20), - _INIT_DCS_CMD(0xFB, 0x01), - _INIT_DCS_CMD(0x30, 0x00), - _INIT_DCS_CMD(0xFF, 0x24), - _INIT_DCS_CMD(0x5C, 0x88), - _INIT_DCS_CMD(0x5D, 0x08), + _INIT_DCS_CMD(0xFF, 0x10), _INIT_DCS_CMD(0xB9, 0x01), + _INIT_DCS_CMD(0xFF, 0x20), + _INIT_DCS_CMD(0x18, 0x40), _INIT_DCS_CMD(0xFF, 0x10), + _INIT_DCS_CMD(0xB9, 0x02), _INIT_DCS_CMD(0xFF, 0x10), + _INIT_DCS_CMD(0xFB, 0x01), - _INIT_DCS_CMD(0xBB, 0x13), - _INIT_DCS_CMD(0x3B, 0x03, 0x96, 0x1A, 0x04, 0x04), + _INIT_DCS_CMD(0xB0, 0x01), _INIT_DCS_CMD(0x35, 0x00), - _INIT_DCS_CMD(0x51, 0x0F, 0xFF), - _INIT_DCS_CMD(0x53, 0x24), + _INIT_DCS_CMD(0x3B, 0x03, 0xAE, 0x1A, 0x04, 0x04), _INIT_DELAY_CMD(100), _INIT_DCS_CMD(0x11), _INIT_DELAY_CMD(200), @@ -780,7 +854,6 @@ static const struct panel_init_cmd inx_hj110iz_init_cmd[] = { }; static const struct panel_init_cmd boe_init_cmd[] = { - _INIT_DELAY_CMD(24), _INIT_DCS_CMD(0xB0, 0x05), _INIT_DCS_CMD(0xB1, 0xE5), _INIT_DCS_CMD(0xB3, 0x52), @@ -1366,6 +1439,10 @@ static int boe_panel_prepare(struct drm_panel *panel) usleep_range(10000, 11000); + if (boe->desc->lp11_before_reset) { + mipi_dsi_dcs_nop(boe->dsi); + usleep_range(1000, 2000); + } gpiod_set_value(boe->enable_gpio, 1); usleep_range(1000, 2000); gpiod_set_value(boe->enable_gpio, 0); @@ -1431,15 +1508,15 @@ static const struct panel_desc boe_tv110c9m_desc = { }; static const struct drm_display_mode inx_hj110iz_default_mode = { - .clock = 166594, + .clock = 168432, .hdisplay = 1200, .hsync_start = 1200 + 40, .hsync_end = 1200 + 40 + 8, .htotal = 1200 + 40 + 8 + 28, .vdisplay = 2000, .vsync_start = 2000 + 26, - .vsync_end = 2000 + 26 + 1, - .vtotal = 2000 + 26 + 1 + 149, + .vsync_end = 2000 + 26 + 2, + .vtotal = 2000 + 26 + 2 + 172, .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, }; @@ -1592,6 +1669,7 @@ static const struct panel_desc boe_tv105wum_nw0_desc = { .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_LPM, .init_cmds = boe_init_cmd, + .lp11_before_reset = true, }; static const struct drm_display_mode starry_qfh032011_53g_default_mode = { diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index e23ddab2126e..fbd114b4f0be 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -903,7 +903,7 @@ err_finished_ddc_init: return err; } -static int panel_edp_remove(struct device *dev) +static void panel_edp_remove(struct device *dev) { struct panel_edp *panel = dev_get_drvdata(dev); @@ -918,8 +918,6 @@ static int panel_edp_remove(struct device *dev) kfree(panel->edid); panel->edid = NULL; - - return 0; } static void panel_edp_shutdown(struct device *dev) @@ -1934,9 +1932,9 @@ static int panel_edp_platform_probe(struct platform_device *pdev) return panel_edp_probe(&pdev->dev, id->data, NULL); } -static int panel_edp_platform_remove(struct platform_device *pdev) +static void panel_edp_platform_remove(struct platform_device *pdev) { - return panel_edp_remove(&pdev->dev); + panel_edp_remove(&pdev->dev); } static void panel_edp_platform_shutdown(struct platform_device *pdev) @@ -1957,7 +1955,7 @@ static struct platform_driver panel_edp_platform_driver = { .pm = &panel_edp_pm_ops, }, .probe = panel_edp_platform_probe, - .remove = panel_edp_platform_remove, + .remove_new = panel_edp_platform_remove, .shutdown = panel_edp_platform_shutdown, }; diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35950.c b/drivers/gpu/drm/panel/panel-novatek-nt35950.c index abf752b36a52..8b108ac80b55 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35950.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35950.c @@ -585,8 +585,12 @@ static int nt35950_probe(struct mipi_dsi_device *dsi) DRM_MODE_CONNECTOR_DSI); ret = drm_panel_of_backlight(&nt->panel); - if (ret) + if (ret) { + if (num_dsis == 2) + mipi_dsi_device_unregister(nt->dsi[1]); + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + } drm_panel_add(&nt->panel); @@ -602,6 +606,10 @@ static int nt35950_probe(struct mipi_dsi_device *dsi) ret = mipi_dsi_attach(nt->dsi[i]); if (ret < 0) { + /* If we fail to attach to either host, we're done */ + if (num_dsis == 2) + mipi_dsi_device_unregister(nt->dsi[1]); + return dev_err_probe(dev, ret, "Cannot attach to DSI%d host.\n", i); } diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c index d30dbbfb67b1..c3befa7f253d 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c @@ -5,6 +5,7 @@ * Copyright (c) 2022, 2023 Jianhua Lu <lujianhua000@gmail.com> */ +#include <linux/backlight.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/module.h> @@ -12,6 +13,8 @@ #include <linux/of_graph.h> #include <linux/regulator/consumer.h> +#include <video/mipi_display.h> + #include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include <drm/drm_mipi_dsi.h> @@ -30,6 +33,7 @@ struct panel_info { struct drm_panel panel; struct mipi_dsi_device *dsi[2]; const struct panel_desc *desc; + enum drm_panel_orientation orientation; struct gpio_desc *reset_gpio; struct backlight_device *backlight; @@ -53,6 +57,7 @@ struct panel_desc { int (*init_sequence)(struct panel_info *pinfo); bool is_dual_dsi; + bool has_dcs_backlight; }; static inline struct panel_info *to_panel_info(struct drm_panel *panel) @@ -478,6 +483,456 @@ static int elish_csot_init_sequence(struct panel_info *pinfo) return 0; } +static int j606f_boe_init_sequence(struct panel_info *pinfo) +{ + struct mipi_dsi_device *dsi = pinfo->dsi[0]; + struct device *dev = &dsi->dev; + int ret; + + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0xd9); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0x78); + mipi_dsi_dcs_write_seq(dsi, 0x08, 0x5a); + mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x63); + mipi_dsi_dcs_write_seq(dsi, 0x0e, 0x91); + mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x73); + mipi_dsi_dcs_write_seq(dsi, 0x95, 0xeb); + mipi_dsi_dcs_write_seq(dsi, 0x96, 0xeb); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x66); + mipi_dsi_dcs_write_seq(dsi, 0x75, 0xa2); + mipi_dsi_dcs_write_seq(dsi, 0x77, 0xb3); + mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00, + 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); + mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01, + 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03, + 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); + mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03, + 0xfd, 0x03, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00, + 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); + mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01, + 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03, + 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); + mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03, + 0xfd, 0x03, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00, + 0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9); + mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01, + 0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0xba, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03, + 0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b); + mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03, + 0xfd, 0x03, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x21); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00, + 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); + mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01, + 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); + mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03, + 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); + mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03, + 0xf5, 0x03, 0xf7); + mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00, + 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); + mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01, + 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); + mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03, + 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); + mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03, + 0xf5, 0x03, 0xf7); + mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00, + 0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1); + mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01, + 0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29); + mipi_dsi_dcs_write_seq(dsi, 0xba, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03, + 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73); + mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03, + 0xf5, 0x03, 0xf7); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x23); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x11, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x12, 0x77); + mipi_dsi_dcs_write_seq(dsi, 0x15, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x01, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x02, 0x1c); + mipi_dsi_dcs_write_seq(dsi, 0x03, 0x1c); + mipi_dsi_dcs_write_seq(dsi, 0x04, 0x1d); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0x1d); + mipi_dsi_dcs_write_seq(dsi, 0x06, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x08, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x09, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x0a, 0x0e); + mipi_dsi_dcs_write_seq(dsi, 0x0b, 0x0e); + mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x0d); + mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x0d); + mipi_dsi_dcs_write_seq(dsi, 0x0e, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x10, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x11, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x12, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x13, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x14, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x15, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x17, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x18, 0x1c); + mipi_dsi_dcs_write_seq(dsi, 0x19, 0x1c); + mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x1d); + mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x1d); + mipi_dsi_dcs_write_seq(dsi, 0x1c, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x20, 0x0e); + mipi_dsi_dcs_write_seq(dsi, 0x21, 0x0e); + mipi_dsi_dcs_write_seq(dsi, 0x22, 0x0d); + mipi_dsi_dcs_write_seq(dsi, 0x23, 0x0d); + mipi_dsi_dcs_write_seq(dsi, 0x24, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x25, 0x0c); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x27, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x28, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x29, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x00); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_LUT, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x0a); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x44); + mipi_dsi_dcs_write_seq(dsi, 0x33, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x34, 0x32); + mipi_dsi_dcs_write_seq(dsi, 0x37, 0x44); + mipi_dsi_dcs_write_seq(dsi, 0x38, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x39, 0x00); + + ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x9a); + if (ret < 0) { + dev_err(dev, "Failed to set pixel format: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, 0x3b, 0xa0); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x42); + mipi_dsi_dcs_write_seq(dsi, 0x3f, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x43, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x47, 0x66); + mipi_dsi_dcs_write_seq(dsi, 0x4a, 0x9a); + mipi_dsi_dcs_write_seq(dsi, 0x4b, 0xa0); + mipi_dsi_dcs_write_seq(dsi, 0x4c, 0x91); + mipi_dsi_dcs_write_seq(dsi, 0x4d, 0x21); + mipi_dsi_dcs_write_seq(dsi, 0x4e, 0x43); + + ret = mipi_dsi_dcs_set_display_brightness(dsi, 18); + if (ret < 0) { + dev_err(dev, "Failed to set display brightness: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, 0x52, 0x34); + mipi_dsi_dcs_write_seq(dsi, 0x55, 0x82, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x56, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x58, 0x21); + mipi_dsi_dcs_write_seq(dsi, 0x59, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0x5a, 0xba); + mipi_dsi_dcs_write_seq(dsi, 0x5b, 0xa0); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x5f, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x65, 0x82); + mipi_dsi_dcs_write_seq(dsi, 0x7e, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x7f, 0x3c); + mipi_dsi_dcs_write_seq(dsi, 0x82, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x97, 0xc0); + mipi_dsi_dcs_write_seq(dsi, 0xb6, + 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x05, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x92, 0xc4); + mipi_dsi_dcs_write_seq(dsi, 0x93, 0x1a); + mipi_dsi_dcs_write_seq(dsi, 0x94, 0x5f); + mipi_dsi_dcs_write_seq(dsi, 0xd7, 0x55); + mipi_dsi_dcs_write_seq(dsi, 0xda, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0xde, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0xdb, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xdc, 0xc4); + mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x22); + mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xe0, 0xc4); + mipi_dsi_dcs_write_seq(dsi, 0xe1, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xe2, 0xc4); + mipi_dsi_dcs_write_seq(dsi, 0xe3, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xe4, 0xc4); + mipi_dsi_dcs_write_seq(dsi, 0xe5, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xe6, 0xc4); + mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x88); + mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x8d, 0x88); + mipi_dsi_dcs_write_seq(dsi, 0x8e, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x90); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x19, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0x1f, 0xba); + mipi_dsi_dcs_write_seq(dsi, 0x20, 0xa0); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0xba); + mipi_dsi_dcs_write_seq(dsi, 0x27, 0xa0); + mipi_dsi_dcs_write_seq(dsi, 0x33, 0xba); + mipi_dsi_dcs_write_seq(dsi, 0x34, 0xa0); + mipi_dsi_dcs_write_seq(dsi, 0x3f, 0xe0); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_VSYNC_TIMING, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x44, 0x00); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_GET_SCANLINE, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x48, 0xba); + mipi_dsi_dcs_write_seq(dsi, 0x49, 0xa0); + mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x00); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0xd0); + mipi_dsi_dcs_write_seq(dsi, 0x61, 0xba); + mipi_dsi_dcs_write_seq(dsi, 0x62, 0xa0); + mipi_dsi_dcs_write_seq(dsi, 0xf1, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x64, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0x67, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0x6a, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0x70, 0x30); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_READ_PPS_START, 0xf3); + mipi_dsi_dcs_write_seq(dsi, 0xa3, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0xa4, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0xa5, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0xd6, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x26); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0xa1); + mipi_dsi_dcs_write_seq(dsi, 0x0a, 0xf2); + mipi_dsi_dcs_write_seq(dsi, 0x04, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0x06, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x11, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x12, 0x50); + mipi_dsi_dcs_write_seq(dsi, 0x13, 0x51); + mipi_dsi_dcs_write_seq(dsi, 0x14, 0x65); + mipi_dsi_dcs_write_seq(dsi, 0x15, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0x17, 0xa0); + mipi_dsi_dcs_write_seq(dsi, 0x18, 0x86); + mipi_dsi_dcs_write_seq(dsi, 0x19, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x7b); + mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0x1c, 0xbb); + mipi_dsi_dcs_write_seq(dsi, 0x22, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x23, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x7b); + mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x1e, 0xc3); + mipi_dsi_dcs_write_seq(dsi, 0x1f, 0xc3); + mipi_dsi_dcs_write_seq(dsi, 0x24, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x25, 0xc3); + mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x05); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0xc3); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_COLUMNS, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x32, 0xc3); + mipi_dsi_dcs_write_seq(dsi, 0x39, 0x00); + + ret = mipi_dsi_dcs_set_pixel_format(dsi, 0xc3); + if (ret < 0) { + dev_err(dev, "Failed to set pixel format: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, 0x20, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x33, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x34, 0x78); + mipi_dsi_dcs_write_seq(dsi, 0x35, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xc9, 0x82); + mipi_dsi_dcs_write_seq(dsi, 0xca, 0x4e); + mipi_dsi_dcs_write_seq(dsi, 0xcb, 0x00); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_READ_PPS_CONTINUE, 0x4c); + mipi_dsi_dcs_write_seq(dsi, 0xaa, 0x47); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x27); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x56, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x58, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0x59, 0x53); + mipi_dsi_dcs_write_seq(dsi, 0x5a, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x14); + mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x01); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x5f, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0x60, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x61, 0x1d); + mipi_dsi_dcs_write_seq(dsi, 0x62, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x63, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x64, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0x65, 0x1c); + mipi_dsi_dcs_write_seq(dsi, 0x66, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x67, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x68, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x78, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x22, 0x2f); + mipi_dsi_dcs_write_seq(dsi, 0x23, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x24, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x25, 0xc3); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0xf8); + mipi_dsi_dcs_write_seq(dsi, 0x27, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x28, 0x1a); + mipi_dsi_dcs_write_seq(dsi, 0x29, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x1a); + mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x00); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_LUT, 0x1a); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0xe0); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x14, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0xc0); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0xf0); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + + ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x08); + if (ret < 0) { + dev_err(dev, "Failed to set pixel format: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + + ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x5d); + if (ret < 0) { + dev_err(dev, "Failed to set pixel format: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, 0x3b, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x4a, 0x5d); + mipi_dsi_dcs_write_seq(dsi, 0x4b, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x5a, 0x70); + mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x91, 0x44); + mipi_dsi_dcs_write_seq(dsi, 0x92, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0xdb, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xdc, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x22); + mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xe0, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0xe1, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xe2, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0xe3, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xe4, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0xe5, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0xe6, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x8d, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x8e, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x70); + mipi_dsi_dcs_write_seq(dsi, 0x20, 0x60); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0x70); + mipi_dsi_dcs_write_seq(dsi, 0x27, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x33, 0x70); + mipi_dsi_dcs_write_seq(dsi, 0x34, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x48, 0x70); + mipi_dsi_dcs_write_seq(dsi, 0x49, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x61, 0x70); + mipi_dsi_dcs_write_seq(dsi, 0x62, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x26); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x02, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0x19, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x7f); + mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x1c, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x7f); + mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0x25, 0x75); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x75); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_COLUMNS, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0x32, 0x8d); + + ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x75); + if (ret < 0) { + dev_err(dev, "Failed to set pixel format: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x25, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x18, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x02); + + ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (ret < 0) { + dev_err(dev, "Failed to set tear on: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0x3b, 0x03, 0x5f, 0x1a, 0x04, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); + usleep_range(10000, 11000); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + + ret = mipi_dsi_dcs_set_display_brightness(dsi, 0); + if (ret < 0) { + dev_err(dev, "Failed to set display brightness: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x2c); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x68, 0x05, 0x01); + + 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; + } + msleep(30); + + return 0; +} + static const struct drm_display_mode elish_boe_modes[] = { { /* There is only one 120 Hz timing, but it doesn't work perfectly, 104 Hz preferred */ @@ -508,6 +963,22 @@ static const struct drm_display_mode elish_csot_modes[] = { }, }; +static const struct drm_display_mode j606f_boe_modes[] = { + { + .clock = (1200 + 58 + 2 + 60) * (2000 + 26 + 2 + 93) * 60 / 1000, + .hdisplay = 1200, + .hsync_start = 1200 + 58, + .hsync_end = 1200 + 58 + 2, + .htotal = 1200 + 58 + 2 + 60, + .vdisplay = 2000, + .vsync_start = 2000 + 26, + .vsync_end = 2000 + 26 + 2, + .vtotal = 2000 + 26 + 2 + 93, + .width_mm = 143, + .height_mm = 235, + }, +}; + static const struct panel_desc elish_boe_desc = { .modes = elish_boe_modes, .num_modes = ARRAY_SIZE(elish_boe_modes), @@ -544,6 +1015,20 @@ static const struct panel_desc elish_csot_desc = { .is_dual_dsi = true, }; +static const struct panel_desc j606f_boe_desc = { + .modes = j606f_boe_modes, + .num_modes = ARRAY_SIZE(j606f_boe_modes), + .width_mm = 143, + .height_mm = 235, + .bpc = 8, + .lanes = 4, + .format = MIPI_DSI_FMT_RGB888, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM, + .init_sequence = j606f_boe_init_sequence, + .has_dcs_backlight = true, +}; + static void nt36523_reset(struct panel_info *pinfo) { gpiod_set_value_cansleep(pinfo->reset_gpio, 1); @@ -672,13 +1157,74 @@ static int nt36523_get_modes(struct drm_panel *panel, return pinfo->desc->num_modes; } +static enum drm_panel_orientation nt36523_get_orientation(struct drm_panel *panel) +{ + struct panel_info *pinfo = to_panel_info(panel); + + return pinfo->orientation; +} + static const struct drm_panel_funcs nt36523_panel_funcs = { .disable = nt36523_disable, .prepare = nt36523_prepare, .unprepare = nt36523_unprepare, .get_modes = nt36523_get_modes, + .get_orientation = nt36523_get_orientation, }; +static int nt36523_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 nt36523_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 nt36523_bl_ops = { + .update_status = nt36523_bl_update_status, + .get_brightness = nt36523_bl_get_brightness, +}; + +static struct backlight_device *nt36523_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 512, + .max_brightness = 4095, + .scale = BACKLIGHT_SCALE_NON_LINEAR, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &nt36523_bl_ops, &props); +} + static int nt36523_probe(struct mipi_dsi_device *dsi) { struct device *dev = &dsi->dev; @@ -730,9 +1276,22 @@ static int nt36523_probe(struct mipi_dsi_device *dsi) mipi_dsi_set_drvdata(dsi, pinfo); drm_panel_init(&pinfo->panel, dev, &nt36523_panel_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_of_backlight(&pinfo->panel); - if (ret) - return dev_err_probe(dev, ret, "failed to get backlight\n"); + ret = of_drm_get_panel_orientation(dev->of_node, &pinfo->orientation); + if (ret < 0) { + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); + return ret; + } + + if (pinfo->desc->has_dcs_backlight) { + pinfo->panel.backlight = nt36523_create_backlight(dsi); + if (IS_ERR(pinfo->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(pinfo->panel.backlight), + "Failed to create backlight\n"); + } else { + ret = drm_panel_of_backlight(&pinfo->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + } drm_panel_add(&pinfo->panel); @@ -751,6 +1310,10 @@ static int nt36523_probe(struct mipi_dsi_device *dsi) static const struct of_device_id nt36523_of_match[] = { { + .compatible = "lenovo,j606f-boe-nt36523w", + .data = &j606f_boe_desc, + }, + { .compatible = "xiaomi,elish-boe-nt36523", .data = &elish_boe_desc, }, diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c index aba556c98300..4819ada69482 100644 --- a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c +++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c @@ -308,7 +308,7 @@ static struct i2c_driver lcd_olinuxino_driver = { .name = "lcd_olinuxino", .of_match_table = lcd_olinuxino_of_ids, }, - .probe_new = lcd_olinuxino_probe, + .probe = lcd_olinuxino_probe, .remove = lcd_olinuxino_remove, }; diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index b4729a94c34a..898b892f1143 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -471,7 +471,7 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) DRM_MODE_CONNECTOR_DSI); ctx->bl_dev = devm_backlight_device_register(dev, dev_name(dev), - dsi->host->dev, ctx, + dev, ctx, &otm8009a_backlight_ops, NULL); if (IS_ERR(ctx->bl_dev)) { diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c index 11d6ca276c1e..90ea91e4311d 100644 --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c @@ -489,7 +489,7 @@ static struct i2c_driver rpi_touchscreen_driver = { .name = "rpi_touchscreen", .of_match_table = rpi_touchscreen_of_ids, }, - .probe_new = rpi_touchscreen_probe, + .probe = rpi_touchscreen_probe, .remove = rpi_touchscreen_remove, }; diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c new file mode 100644 index 000000000000..102e1fc7ee38 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Samsung S6D7AA0 MIPI-DSI TFT LCD controller drm_panel driver. + * + * Copyright (C) 2022 Artur Weber <aweber.kernel@gmail.com> + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#include <video/mipi_display.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +/* Manufacturer command set */ +#define MCS_BL_CTL 0xc3 +#define MCS_OTP_RELOAD 0xd0 +#define MCS_PASSWD1 0xf0 +#define MCS_PASSWD2 0xf1 +#define MCS_PASSWD3 0xfc + +struct s6d7aa0 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[2]; + const struct s6d7aa0_panel_desc *desc; +}; + +struct s6d7aa0_panel_desc { + unsigned int panel_type; + int (*init_func)(struct s6d7aa0 *ctx); + int (*off_func)(struct s6d7aa0 *ctx); + const struct drm_display_mode *drm_mode; + unsigned long mode_flags; + u32 bus_flags; + bool has_backlight; + bool use_passwd3; +}; + +enum s6d7aa0_panels { + S6D7AA0_PANEL_LSL080AL02, + S6D7AA0_PANEL_LSL080AL03, + S6D7AA0_PANEL_LTL101AT01, +}; + +static inline struct s6d7aa0 *panel_to_s6d7aa0(struct drm_panel *panel) +{ + return container_of(panel, struct s6d7aa0, panel); +} + +static void s6d7aa0_reset(struct s6d7aa0 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + msleep(50); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(50); +} + +static int s6d7aa0_lock(struct s6d7aa0 *ctx, bool lock) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + int ret = 0; + + if (lock) { + mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD1, 0xa5, 0xa5); + mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD2, 0xa5, 0xa5); + if (ctx->desc->use_passwd3) + mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD3, 0x5a, 0x5a); + } else { + mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD1, 0x5a, 0x5a); + mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD2, 0x5a, 0x5a); + if (ctx->desc->use_passwd3) + mipi_dsi_dcs_write_seq(dsi, MCS_PASSWD3, 0xa5, 0xa5); + } + + return ret; +} + +static int s6d7aa0_on(struct s6d7aa0 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + ret = ctx->desc->init_func(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + return ret; + } + + 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 s6d7aa0_off(struct s6d7aa0 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + ret = ctx->desc->off_func(ctx); + if (ret < 0) { + dev_err(dev, "Panel-specific off function failed: %d\n", ret); + return ret; + } + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display off: %d\n", ret); + return ret; + } + msleep(64); + + 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(120); + + return 0; +} + +static int s6d7aa0_prepare(struct drm_panel *panel) +{ + struct s6d7aa0 *ctx = panel_to_s6d7aa0(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + 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; + } + + s6d7aa0_reset(ctx); + + ret = s6d7aa0_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + return ret; + } + + return 0; +} + +static int s6d7aa0_disable(struct drm_panel *panel) +{ + struct s6d7aa0 *ctx = panel_to_s6d7aa0(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = s6d7aa0_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + return 0; +} + +static int s6d7aa0_unprepare(struct drm_panel *panel) +{ + struct s6d7aa0 *ctx = panel_to_s6d7aa0(panel); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + + return 0; +} + +/* Backlight control code */ + +static int s6d7aa0_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness); + if (ret < 0) + return ret; + + return 0; +} + +static int s6d7aa0_bl_get_brightness(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness; + int ret; + + ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness); + if (ret < 0) + return ret; + + return brightness & 0xff; +} + +static const struct backlight_ops s6d7aa0_bl_ops = { + .update_status = s6d7aa0_bl_update_status, + .get_brightness = s6d7aa0_bl_get_brightness, +}; + +static struct backlight_device * +s6d7aa0_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 255, + .max_brightness = 255, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &s6d7aa0_bl_ops, &props); +} + +/* Initialization code and structures for LSL080AL02 panel */ + +static int s6d7aa0_lsl080al02_init(struct s6d7aa0 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + usleep_range(20000, 25000); + + ret = s6d7aa0_lock(ctx, false); + if (ret < 0) { + dev_err(dev, "Failed to unlock registers: %d\n", ret); + return ret; + } + + mipi_dsi_dcs_write_seq(dsi, MCS_OTP_RELOAD, 0x00, 0x10); + usleep_range(1000, 1500); + + /* SEQ_B6_PARAM_8_R01 */ + mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x10); + + /* BL_CTL_ON */ + mipi_dsi_dcs_write_seq(dsi, MCS_BL_CTL, 0x40, 0x00, 0x28); + + usleep_range(5000, 6000); + + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x04); + + 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(120); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00); + + ret = s6d7aa0_lock(ctx, true); + if (ret < 0) { + dev_err(dev, "Failed to lock registers: %d\n", ret); + return ret; + } + + 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 s6d7aa0_lsl080al02_off(struct s6d7aa0 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + + /* BL_CTL_OFF */ + mipi_dsi_dcs_write_seq(dsi, MCS_BL_CTL, 0x40, 0x00, 0x20); + + return 0; +} + +static const struct drm_display_mode s6d7aa0_lsl080al02_mode = { + .clock = (800 + 16 + 4 + 140) * (1280 + 8 + 4 + 4) * 60 / 1000, + .hdisplay = 800, + .hsync_start = 800 + 16, + .hsync_end = 800 + 16 + 4, + .htotal = 800 + 16 + 4 + 140, + .vdisplay = 1280, + .vsync_start = 1280 + 8, + .vsync_end = 1280 + 8 + 4, + .vtotal = 1280 + 8 + 4 + 4, + .width_mm = 108, + .height_mm = 173, +}; + +static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al02_desc = { + .panel_type = S6D7AA0_PANEL_LSL080AL02, + .init_func = s6d7aa0_lsl080al02_init, + .off_func = s6d7aa0_lsl080al02_off, + .drm_mode = &s6d7aa0_lsl080al02_mode, + .mode_flags = MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_NO_HFP, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + + .has_backlight = false, + .use_passwd3 = false, +}; + +/* Initialization code and structures for LSL080AL03 panel */ + +static int s6d7aa0_lsl080al03_init(struct s6d7aa0 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + usleep_range(20000, 25000); + + ret = s6d7aa0_lock(ctx, false); + if (ret < 0) { + dev_err(dev, "Failed to unlock registers: %d\n", ret); + return ret; + } + + if (ctx->desc->panel_type == S6D7AA0_PANEL_LSL080AL03) { + mipi_dsi_dcs_write_seq(dsi, MCS_BL_CTL, 0xc7, 0x00, 0x29); + mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x01, 0x4e, 0xa0); + mipi_dsi_dcs_write_seq(dsi, 0xfd, 0x16, 0x10, 0x11, 0x23, + 0x09); + mipi_dsi_dcs_write_seq(dsi, 0xfe, 0x00, 0x02, 0x03, 0x21, + 0x80, 0x78); + } else if (ctx->desc->panel_type == S6D7AA0_PANEL_LTL101AT01) { + mipi_dsi_dcs_write_seq(dsi, MCS_BL_CTL, 0x40, 0x00, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x01, 0x4e, 0x0b); + mipi_dsi_dcs_write_seq(dsi, 0xfd, 0x16, 0x10, 0x11, 0x23, + 0x09); + mipi_dsi_dcs_write_seq(dsi, 0xfe, 0x00, 0x02, 0x03, 0x21, + 0x80, 0x68); + } + + mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x51); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0xf2, 0x02, 0x08, 0x08); + + usleep_range(10000, 11000); + + mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x80, 0x80, 0x30); + mipi_dsi_dcs_write_seq(dsi, 0xcd, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e); + mipi_dsi_dcs_write_seq(dsi, 0xce, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x03); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + + ret = s6d7aa0_lock(ctx, true); + if (ret < 0) { + dev_err(dev, "Failed to lock registers: %d\n", ret); + return ret; + } + + 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 s6d7aa0_lsl080al03_off(struct s6d7aa0 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + + mipi_dsi_dcs_write_seq(dsi, 0x22, 0x00); + + return 0; +} + +static const struct drm_display_mode s6d7aa0_lsl080al03_mode = { + .clock = (768 + 18 + 16 + 126) * (1024 + 8 + 2 + 6) * 60 / 1000, + .hdisplay = 768, + .hsync_start = 768 + 18, + .hsync_end = 768 + 18 + 16, + .htotal = 768 + 18 + 16 + 126, + .vdisplay = 1024, + .vsync_start = 1024 + 8, + .vsync_end = 1024 + 8 + 2, + .vtotal = 1024 + 8 + 2 + 6, + .width_mm = 122, + .height_mm = 163, +}; + +static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al03_desc = { + .panel_type = S6D7AA0_PANEL_LSL080AL03, + .init_func = s6d7aa0_lsl080al03_init, + .off_func = s6d7aa0_lsl080al03_off, + .drm_mode = &s6d7aa0_lsl080al03_mode, + .mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET, + .bus_flags = 0, + + .has_backlight = true, + .use_passwd3 = true, +}; + +/* Initialization structures for LTL101AT01 panel */ + +static const struct drm_display_mode s6d7aa0_ltl101at01_mode = { + .clock = (768 + 96 + 16 + 184) * (1024 + 8 + 2 + 6) * 60 / 1000, + .hdisplay = 768, + .hsync_start = 768 + 96, + .hsync_end = 768 + 96 + 16, + .htotal = 768 + 96 + 16 + 184, + .vdisplay = 1024, + .vsync_start = 1024 + 8, + .vsync_end = 1024 + 8 + 2, + .vtotal = 1024 + 8 + 2 + 6, + .width_mm = 148, + .height_mm = 197, +}; + +static const struct s6d7aa0_panel_desc s6d7aa0_ltl101at01_desc = { + .panel_type = S6D7AA0_PANEL_LTL101AT01, + .init_func = s6d7aa0_lsl080al03_init, /* Similar init to LSL080AL03 */ + .off_func = s6d7aa0_lsl080al03_off, + .drm_mode = &s6d7aa0_ltl101at01_mode, + .mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET, + .bus_flags = 0, + + .has_backlight = true, + .use_passwd3 = true, +}; + +static int s6d7aa0_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + struct s6d7aa0 *ctx; + + ctx = container_of(panel, struct s6d7aa0, panel); + if (!ctx) + return -EINVAL; + + mode = drm_mode_duplicate(connector->dev, ctx->desc->drm_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; + connector->display_info.bus_flags = ctx->desc->bus_flags; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs s6d7aa0_panel_funcs = { + .disable = s6d7aa0_disable, + .prepare = s6d7aa0_prepare, + .unprepare = s6d7aa0_unprepare, + .get_modes = s6d7aa0_get_modes, +}; + +static int s6d7aa0_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct s6d7aa0 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->desc = of_device_get_match_data(dev); + if (!ctx->desc) + return -ENODEV; + + ctx->supplies[0].supply = "power"; + ctx->supplies[1].supply = "vmipi"; + 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_VIDEO | MIPI_DSI_MODE_VIDEO_BURST + | ctx->desc->mode_flags; + + drm_panel_init(&ctx->panel, dev, &s6d7aa0_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + /* Use DSI-based backlight as fallback if available */ + if (ctx->desc->has_backlight && !ctx->panel.backlight) { + ctx->panel.backlight = s6d7aa0_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + } + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "Failed to attach to DSI host: %d\n", ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void s6d7aa0_remove(struct mipi_dsi_device *dsi) +{ + struct s6d7aa0 *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 s6d7aa0_of_match[] = { + { + .compatible = "samsung,lsl080al02", + .data = &s6d7aa0_lsl080al02_desc + }, + { + .compatible = "samsung,lsl080al03", + .data = &s6d7aa0_lsl080al03_desc + }, + { + .compatible = "samsung,ltl101at01", + .data = &s6d7aa0_ltl101at01_desc + }, + { /* sentinel */ } +}; + +static struct mipi_dsi_driver s6d7aa0_driver = { + .probe = s6d7aa0_probe, + .remove = s6d7aa0_remove, + .driver = { + .name = "panel-samsung-s6d7aa0", + .of_match_table = s6d7aa0_of_match, + }, +}; +module_mipi_dsi_driver(s6d7aa0_driver); + +MODULE_AUTHOR("Artur Weber <aweber.kernel@gmail.com>"); +MODULE_DESCRIPTION("Samsung S6D7AA0 MIPI-DSI LCD controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index d1ec80a3e3c7..855e64444daa 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -28,9 +28,6 @@ struct sharp_nt_panel { struct gpio_desc *reset_gpio; bool prepared; - bool enabled; - - const struct drm_display_mode *mode; }; static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel) @@ -97,19 +94,6 @@ static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt) return 0; } - -static int sharp_nt_panel_disable(struct drm_panel *panel) -{ - struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); - - if (!sharp_nt->enabled) - return 0; - - sharp_nt->enabled = false; - - return 0; -} - static int sharp_nt_panel_unprepare(struct drm_panel *panel) { struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); @@ -179,28 +163,16 @@ poweroff: return ret; } -static int sharp_nt_panel_enable(struct drm_panel *panel) -{ - struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); - - if (sharp_nt->enabled) - return 0; - - sharp_nt->enabled = true; - - return 0; -} - static const struct drm_display_mode default_mode = { - .clock = 41118, + .clock = (540 + 48 + 32 + 80) * (960 + 3 + 10 + 15) * 60 / 1000, .hdisplay = 540, .hsync_start = 540 + 48, - .hsync_end = 540 + 48 + 80, - .htotal = 540 + 48 + 80 + 32, + .hsync_end = 540 + 48 + 32, + .htotal = 540 + 48 + 32 + 80, .vdisplay = 960, .vsync_start = 960 + 3, - .vsync_end = 960 + 3 + 15, - .vtotal = 960 + 3 + 15 + 1, + .vsync_end = 960 + 3 + 10, + .vtotal = 960 + 3 + 10 + 15, }; static int sharp_nt_panel_get_modes(struct drm_panel *panel, @@ -227,10 +199,8 @@ static int sharp_nt_panel_get_modes(struct drm_panel *panel, } static const struct drm_panel_funcs sharp_nt_panel_funcs = { - .disable = sharp_nt_panel_disable, .unprepare = sharp_nt_panel_unprepare, .prepare = sharp_nt_panel_prepare, - .enable = sharp_nt_panel_enable, .get_modes = sharp_nt_panel_get_modes, }; @@ -239,8 +209,6 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) struct device *dev = &sharp_nt->dsi->dev; int ret; - sharp_nt->mode = &default_mode; - sharp_nt->supply = devm_regulator_get(dev, "avdd"); if (IS_ERR(sharp_nt->supply)) return PTR_ERR(sharp_nt->supply); @@ -280,6 +248,7 @@ static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi) dsi->lanes = 2; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_NO_EOT_PACKET; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 065f378bba9d..754c09c6d4c1 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -759,8 +759,8 @@ static const struct panel_desc ampire_am_480272h3tmqw_t01h = { .num_modes = 1, .bpc = 8, .size = { - .width = 105, - .height = 67, + .width = 99, + .height = 58, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; @@ -778,6 +778,36 @@ static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = { .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, }; +static const struct display_timing ampire_am_800480l1tmqw_t00h_timing = { + .pixelclock = { 29930000, 33260000, 36590000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 1, 40, 168 }, + .hback_porch = { 88, 88, 88 }, + .hsync_len = { 1, 128, 128 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 1, 35, 37 }, + .vback_porch = { 8, 8, 8 }, + .vsync_len = { 1, 2, 2 }, + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | + DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE | + DISPLAY_FLAGS_SYNC_POSEDGE, +}; + +static const struct panel_desc ampire_am_800480l1tmqw_t00h = { + .timings = &ire_am_800480l1tmqw_t00h_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 111, + .height = 67, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, + .connector_type = DRM_MODE_CONNECTOR_DPI, +}; + static const struct panel_desc ampire_am800480r3tmqwa1h = { .modes = &ire_am800480r3tmqwa1h_mode, .num_modes = 1, @@ -1211,6 +1241,37 @@ static const struct panel_desc bananapi_s070wv20_ct16 = { }, }; +static const struct display_timing boe_ev121wxm_n10_1850_timing = { + .pixelclock = { 69922000, 71000000, 72293000 }, + .hactive = { 1280, 1280, 1280 }, + .hfront_porch = { 48, 48, 48 }, + .hback_porch = { 80, 80, 80 }, + .hsync_len = { 32, 32, 32 }, + .vactive = { 800, 800, 800 }, + .vfront_porch = { 3, 3, 3 }, + .vback_porch = { 14, 14, 14 }, + .vsync_len = { 6, 6, 6 }, +}; + +static const struct panel_desc boe_ev121wxm_n10_1850 = { + .timings = &boe_ev121wxm_n10_1850_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 261, + .height = 163, + }, + .delay = { + .prepare = 9, + .enable = 300, + .unprepare = 300, + .disable = 560, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct drm_display_mode boe_hv070wsa_mode = { .clock = 42105, .hdisplay = 1024, @@ -2142,6 +2203,38 @@ static const struct panel_desc innolux_at070tn92 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; +static const struct display_timing innolux_g070ace_l01_timing = { + .pixelclock = { 25200000, 35000000, 35700000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 30, 32, 87 }, + .hback_porch = { 30, 32, 87 }, + .hsync_len = { 1, 1, 1 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 3, 3, 3 }, + .vback_porch = { 13, 13, 13 }, + .vsync_len = { 1, 1, 4 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc innolux_g070ace_l01 = { + .timings = &innolux_g070ace_l01_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 152, + .height = 91, + }, + .delay = { + .prepare = 10, + .enable = 50, + .disable = 50, + .unprepare = 500, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing innolux_g070y2_l01_timing = { .pixelclock = { 28000000, 29500000, 32000000 }, .hactive = { 800, 800, 800 }, @@ -3931,6 +4024,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "ampire,am-480272h3tmqw-t01h", .data = &ire_am_480272h3tmqw_t01h, }, { + .compatible = "ampire,am-800480l1tmqw-t00h", + .data = &ire_am_800480l1tmqw_t00h, + }, { .compatible = "ampire,am800480r3tmqwa1h", .data = &ire_am800480r3tmqwa1h, }, { @@ -3985,6 +4081,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "bananapi,s070wv20-ct16", .data = &bananapi_s070wv20_ct16, }, { + .compatible = "boe,ev121wxm-n10-1850", + .data = &boe_ev121wxm_n10_1850, + }, { .compatible = "boe,hv070wsa-100", .data = &boe_hv070wsa }, { @@ -4099,6 +4198,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "innolux,at070tn92", .data = &innolux_at070tn92, }, { + .compatible = "innolux,g070ace-l01", + .data = &innolux_g070ace_l01, + }, { .compatible = "innolux,g070y2-l01", .data = &innolux_g070y2_l01, }, { diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c index 6747ca237ced..3aa31f3d6157 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -28,6 +28,7 @@ /* Manufacturer specific Commands send via DSI */ #define ST7703_CMD_ALL_PIXEL_OFF 0x22 #define ST7703_CMD_ALL_PIXEL_ON 0x23 +#define ST7703_CMD_SETAPID 0xB1 #define ST7703_CMD_SETDISP 0xB2 #define ST7703_CMD_SETRGBIF 0xB3 #define ST7703_CMD_SETCYC 0xB4 @@ -41,12 +42,15 @@ #define ST7703_CMD_UNKNOWN_BF 0xBF #define ST7703_CMD_SETSCR 0xC0 #define ST7703_CMD_SETPOWER 0xC1 +#define ST7703_CMD_SETECO 0xC6 +#define ST7703_CMD_SETIO 0xC7 +#define ST7703_CMD_SETCABC 0xC8 #define ST7703_CMD_SETPANEL 0xCC -#define ST7703_CMD_UNKNOWN_C6 0xC6 #define ST7703_CMD_SETGAMMA 0xE0 #define ST7703_CMD_SETEQ 0xE3 #define ST7703_CMD_SETGIP1 0xE9 #define ST7703_CMD_SETGIP2 0xEA +#define ST7703_CMD_UNKNOWN_EF 0xEF struct st7703 { struct device *dev; @@ -249,8 +253,7 @@ static int xbd599_init_sequence(struct st7703 *ctx) * ESD_DET_TIME_SEL = 0 frames */); - /* Undocumented command. */ - mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00); mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */ @@ -338,6 +341,98 @@ static const struct st7703_panel_desc xbd599_desc = { .init_sequence = xbd599_init_sequence, }; +static int rg353v2_init_sequence(struct st7703 *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + /* + * Init sequence was supplied by the panel vendor. + */ + + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, + 0xda, 0x80); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28, + 0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x0a, 0x0a); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x92, 0x92); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, + 0xf0, 0x63); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, + 0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, + 0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50, + 0x00, 0x00, 0x12, 0x50, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32, + 0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33, + 0x33); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff, + 0x00, 0xff); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e, + 0x02); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d, + 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d, + 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07, + 0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, + 0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b, + 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0xc0, 0x10); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00, + 0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80, + 0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, + 0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35, + 0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02, + 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00, + 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00); + mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01); + + return 0; +} + +static const struct drm_display_mode rg353v2_mode = { + .hdisplay = 640, + .hsync_start = 640 + 40, + .hsync_end = 640 + 40 + 2, + .htotal = 640 + 40 + 2 + 80, + .vdisplay = 480, + .vsync_start = 480 + 18, + .vsync_end = 480 + 18 + 2, + .vtotal = 480 + 18 + 2 + 28, + .clock = 24150, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 70, + .height_mm = 57, +}; + +static const struct st7703_panel_desc rg353v2_desc = { + .mode = &rg353v2_mode, + .lanes = 4, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .init_sequence = rg353v2_init_sequence, +}; + static int st7703_enable(struct drm_panel *panel) { struct st7703 *ctx = panel_to_st7703(panel); @@ -598,6 +693,7 @@ static void st7703_remove(struct mipi_dsi_device *dsi) } static const struct of_device_id st7703_of_match[] = { + { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc }, { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc }, { .compatible = "xingbangda,xbd599", .data = &xbd599_desc }, { /* sentinel */ } diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index 666a5e53fe19..e961fa27702c 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -504,6 +504,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, if (IS_ERR(pages[i])) { mutex_unlock(&bo->base.pages_lock); ret = PTR_ERR(pages[i]); + pages[i] = NULL; goto err_pages; } } diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index e19d77d58810..fe498c8af1bb 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -11,6 +11,7 @@ config DRM_RADEON select DRM_SUBALLOC_HELPER select DRM_TTM select DRM_TTM_HELPER + select FB_IO_HELPERS if DRM_FBDEV_EMULATION select SND_HDA_COMPONENT if SND_HDA_CORE select POWER_SUPPLY select HWMON diff --git a/drivers/gpu/drm/radeon/radeon_fbdev.c b/drivers/gpu/drm/radeon/radeon_fbdev.c index fe76e29910ef..28212c2d6c98 100644 --- a/drivers/gpu/drm/radeon/radeon_fbdev.c +++ b/drivers/gpu/drm/radeon/radeon_fbdev.c @@ -24,6 +24,7 @@ * David Airlie */ +#include <linux/fb.h> #include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/vga_switcheroo.h> @@ -190,14 +191,10 @@ static void radeon_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops radeon_fbdev_fb_ops = { .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, .fb_open = radeon_fbdev_fb_open, .fb_release = radeon_fbdev_fb_release, - .fb_read = drm_fb_helper_cfb_read, - .fb_write = drm_fb_helper_cfb_write, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, + FB_DEFAULT_IO_OPS, + DRM_FB_HELPER_DEFAULT_OPS, .fb_destroy = radeon_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 8526dda91931..b6afe3786b74 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -273,10 +273,9 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector) edid->width_cm, edid->height_cm); dp->sink_has_audio = drm_detect_monitor_audio(edid); + + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); - if (ret) - drm_connector_update_edid_property(connector, - edid); } mutex_unlock(&dp->lock); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 6e0788d14c10..d97f2edc646b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -140,7 +140,7 @@ static int rockchip_drm_bind(struct device *dev) int ret; /* Remove existing drivers that may own the framebuffer memory. */ - ret = drm_aperture_remove_framebuffers(false, &rockchip_drm_driver); + ret = drm_aperture_remove_framebuffers(&rockchip_drm_driver); if (ret) { DRM_DEV_ERROR(dev, "Failed to remove existing framebuffers - %d.\n", diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index d8f5e064a1ba..a530ecc4d207 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -714,13 +714,13 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, if (crtc->state->self_refresh_active) rockchip_drm_set_win_enabled(crtc, false); + if (crtc->state->self_refresh_active) + goto out; + mutex_lock(&vop->vop_lock); drm_crtc_vblank_off(crtc); - if (crtc->state->self_refresh_active) - goto out; - /* * Vop standby will take effect at end of current frame, * if dsp hold valid irq happen, it means standby complete. @@ -754,9 +754,9 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, vop_core_clks_disable(vop); pm_runtime_put(vop->dev); -out: mutex_unlock(&vop->vop_lock); +out: if (crtc->state->event && !crtc->state->active) { spin_lock_irq(&crtc->dev->event_lock); drm_crtc_send_vblank_event(crtc, crtc->state->event); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 38554ca2fc39..ca73b8ccc29f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -843,6 +843,8 @@ static void vop2_enable(struct vop2 *vop2) return; } + regcache_sync(vop2->map); + if (vop2->data->soc_id == 3566) vop2_writel(vop2, RK3568_OTP_WIN_EN, 1); @@ -871,6 +873,8 @@ static void vop2_disable(struct vop2 *vop2) pm_runtime_put_sync(vop2->dev); + regcache_mark_dirty(vop2->map); + clk_disable_unprepare(vop2->aclk); clk_disable_unprepare(vop2->hclk); } diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 15d04a0ec623..68e807ae136a 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -72,7 +72,7 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, entity->num_sched_list = num_sched_list; entity->priority = priority; entity->sched_list = num_sched_list > 1 ? sched_list : NULL; - entity->last_scheduled = NULL; + RCU_INIT_POINTER(entity->last_scheduled, NULL); RB_CLEAR_NODE(&entity->rb_tree_node); if(num_sched_list) @@ -140,11 +140,32 @@ bool drm_sched_entity_is_ready(struct drm_sched_entity *entity) return true; } +/** + * drm_sched_entity_error - return error of last scheduled job + * @entity: scheduler entity to check + * + * Opportunistically return the error of the last scheduled job. Result can + * change any time when new jobs are pushed to the hw. + */ +int drm_sched_entity_error(struct drm_sched_entity *entity) +{ + struct dma_fence *fence; + int r; + + rcu_read_lock(); + fence = rcu_dereference(entity->last_scheduled); + r = fence ? fence->error : 0; + rcu_read_unlock(); + + return r; +} +EXPORT_SYMBOL(drm_sched_entity_error); + static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk) { struct drm_sched_job *job = container_of(wrk, typeof(*job), work); - drm_sched_fence_finished(job->s_fence); + drm_sched_fence_finished(job->s_fence, -ESRCH); WARN_ON(job->s_fence->parent); job->sched->ops->free_job(job); } @@ -191,12 +212,12 @@ static void drm_sched_entity_kill(struct drm_sched_entity *entity) /* Make sure this entity is not used by the scheduler at the moment */ wait_for_completion(&entity->entity_idle); - prev = dma_fence_get(entity->last_scheduled); + /* The entity is guaranteed to not be used by the scheduler */ + prev = rcu_dereference_check(entity->last_scheduled, true); + dma_fence_get(prev); while ((job = to_drm_sched_job(spsc_queue_pop(&entity->job_queue)))) { struct drm_sched_fence *s_fence = job->s_fence; - dma_fence_set_error(&s_fence->finished, -ESRCH); - dma_fence_get(&s_fence->finished); if (!prev || dma_fence_add_callback(prev, &job->finish_cb, drm_sched_entity_kill_jobs_cb)) @@ -280,8 +301,8 @@ void drm_sched_entity_fini(struct drm_sched_entity *entity) entity->dependency = NULL; } - dma_fence_put(entity->last_scheduled); - entity->last_scheduled = NULL; + dma_fence_put(rcu_dereference_check(entity->last_scheduled, true)); + RCU_INIT_POINTER(entity->last_scheduled, NULL); } EXPORT_SYMBOL(drm_sched_entity_fini); @@ -321,7 +342,7 @@ static void drm_sched_entity_wakeup(struct dma_fence *f, container_of(cb, struct drm_sched_entity, cb); drm_sched_entity_clear_dep(f, cb); - drm_sched_wakeup(entity->rq->sched); + drm_sched_wakeup_if_can_queue(entity->rq->sched); } /** @@ -423,9 +444,9 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) if (entity->guilty && atomic_read(entity->guilty)) dma_fence_set_error(&sched_job->s_fence->finished, -ECANCELED); - dma_fence_put(entity->last_scheduled); - - entity->last_scheduled = dma_fence_get(&sched_job->s_fence->finished); + dma_fence_put(rcu_dereference_check(entity->last_scheduled, true)); + rcu_assign_pointer(entity->last_scheduled, + dma_fence_get(&sched_job->s_fence->finished)); /* * If the queue is empty we allow drm_sched_entity_select_rq() to @@ -448,6 +469,12 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) drm_sched_rq_update_fifo(entity, next->submit_ts); } + /* Jobs and entities might have different lifecycles. Since we're + * removing the job from the entities queue, set the jobs entity pointer + * to NULL to prevent any future access of the entity through this job. + */ + sched_job->entity = NULL; + return sched_job; } @@ -473,7 +500,7 @@ void drm_sched_entity_select_rq(struct drm_sched_entity *entity) */ smp_rmb(); - fence = entity->last_scheduled; + fence = rcu_dereference_check(entity->last_scheduled, true); /* stay on the same engine if the previous job hasn't finished */ if (fence && !dma_fence_is_signaled(fence)) @@ -507,12 +534,19 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) { struct drm_sched_entity *entity = sched_job->entity; bool first; + ktime_t submit_ts; trace_drm_sched_job(sched_job, entity); atomic_inc(entity->rq->sched->score); WRITE_ONCE(entity->last_user, current->group_leader); + + /* + * After the sched_job is pushed into the entity queue, it may be + * completed and freed up at any time. We can no longer access it. + * Make sure to set the submit_ts first, to avoid a race. + */ + sched_job->submit_ts = submit_ts = ktime_get(); first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node); - sched_job->submit_ts = ktime_get(); /* first job wakes up scheduler */ if (first) { @@ -529,9 +563,9 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) spin_unlock(&entity->rq_lock); if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) - drm_sched_rq_update_fifo(entity, sched_job->submit_ts); + drm_sched_rq_update_fifo(entity, submit_ts); - drm_sched_wakeup(entity->rq->sched); + drm_sched_wakeup_if_can_queue(entity->rq->sched); } } EXPORT_SYMBOL(drm_sched_entity_push_job); diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c index fe9c6468e440..ef120475e7c6 100644 --- a/drivers/gpu/drm/scheduler/sched_fence.c +++ b/drivers/gpu/drm/scheduler/sched_fence.c @@ -53,8 +53,10 @@ void drm_sched_fence_scheduled(struct drm_sched_fence *fence) dma_fence_signal(&fence->scheduled); } -void drm_sched_fence_finished(struct drm_sched_fence *fence) +void drm_sched_fence_finished(struct drm_sched_fence *fence, int result) { + if (result) + dma_fence_set_error(&fence->finished, result); dma_fence_signal(&fence->finished); } diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index f6801eb21820..394010a60821 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -42,6 +42,10 @@ * the hardware. * * The jobs in a entity are always scheduled in the order that they were pushed. + * + * Note that once a job was taken from the entities queue and pushed to the + * hardware, i.e. the pending queue, the entity must not be referenced anymore + * through the jobs entity pointer. */ #include <linux/kthread.h> @@ -258,7 +262,7 @@ drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq) * * Finish the job's fence and wake up the worker thread. */ -static void drm_sched_job_done(struct drm_sched_job *s_job) +static void drm_sched_job_done(struct drm_sched_job *s_job, int result) { struct drm_sched_fence *s_fence = s_job->s_fence; struct drm_gpu_scheduler *sched = s_fence->sched; @@ -269,7 +273,7 @@ static void drm_sched_job_done(struct drm_sched_job *s_job) trace_drm_sched_process_job(s_fence); dma_fence_get(&s_fence->finished); - drm_sched_fence_finished(s_fence); + drm_sched_fence_finished(s_fence, result); dma_fence_put(&s_fence->finished); wake_up_interruptible(&sched->wake_up_worker); } @@ -283,7 +287,7 @@ static void drm_sched_job_done_cb(struct dma_fence *f, struct dma_fence_cb *cb) { struct drm_sched_job *s_job = container_of(cb, struct drm_sched_job, cb); - drm_sched_job_done(s_job); + drm_sched_job_done(s_job, f->error); } /** @@ -309,7 +313,8 @@ static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched) */ void drm_sched_fault(struct drm_gpu_scheduler *sched) { - mod_delayed_work(sched->timeout_wq, &sched->work_tdr, 0); + if (sched->timeout_wq) + mod_delayed_work(sched->timeout_wq, &sched->work_tdr, 0); } EXPORT_SYMBOL(drm_sched_fault); @@ -533,12 +538,12 @@ void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery) r = dma_fence_add_callback(fence, &s_job->cb, drm_sched_job_done_cb); if (r == -ENOENT) - drm_sched_job_done(s_job); + drm_sched_job_done(s_job, fence->error); else if (r) DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n", r); } else - drm_sched_job_done(s_job); + drm_sched_job_done(s_job, -ECANCELED); } if (full_recovery) { @@ -843,27 +848,26 @@ void drm_sched_job_cleanup(struct drm_sched_job *job) EXPORT_SYMBOL(drm_sched_job_cleanup); /** - * drm_sched_ready - is the scheduler ready - * + * drm_sched_can_queue -- Can we queue more to the hardware? * @sched: scheduler instance * * Return true if we can push more jobs to the hw, otherwise false. */ -static bool drm_sched_ready(struct drm_gpu_scheduler *sched) +static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched) { return atomic_read(&sched->hw_rq_count) < sched->hw_submission_limit; } /** - * drm_sched_wakeup - Wake up the scheduler when it is ready - * + * drm_sched_wakeup_if_can_queue - Wake up the scheduler * @sched: scheduler instance * + * Wake up the scheduler if we can queue jobs. */ -void drm_sched_wakeup(struct drm_gpu_scheduler *sched) +void drm_sched_wakeup_if_can_queue(struct drm_gpu_scheduler *sched) { - if (drm_sched_ready(sched)) + if (drm_sched_can_queue(sched)) wake_up_interruptible(&sched->wake_up_worker); } @@ -880,7 +884,7 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) struct drm_sched_entity *entity; int i; - if (!drm_sched_ready(sched)) + if (!drm_sched_can_queue(sched)) return NULL; /* Kernel run queue has higher priority than normal run queue*/ @@ -935,12 +939,6 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) spin_unlock(&sched->job_list_lock); - if (job) { - job->entity->elapsed_ns += ktime_to_ns( - ktime_sub(job->s_fence->finished.timestamp, - job->s_fence->scheduled.timestamp)); - } - return job; } @@ -1055,15 +1053,13 @@ static int drm_sched_main(void *param) r = dma_fence_add_callback(fence, &sched_job->cb, drm_sched_job_done_cb); if (r == -ENOENT) - drm_sched_job_done(sched_job); + drm_sched_job_done(sched_job, fence->error); else if (r) DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n", r); } else { - if (IS_ERR(fence)) - dma_fence_set_error(&s_fence->finished, PTR_ERR(fence)); - - drm_sched_job_done(sched_job); + drm_sched_job_done(sched_job, IS_ERR(fence) ? + PTR_ERR(fence) : 0); } wake_up(&sched->job_scheduled); diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig index 4ec5dc74a6b0..ad14112999ad 100644 --- a/drivers/gpu/drm/shmobile/Kconfig +++ b/drivers/gpu/drm/shmobile/Kconfig @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 config DRM_SHMOBILE tristate "DRM Support for SH Mobile" - depends on DRM && ARM - depends on ARCH_SHMOBILE || COMPILE_TEST + depends on DRM + depends on ARCH_RENESAS || ARCH_SHMOBILE || COMPILE_TEST select BACKLIGHT_CLASS_DEVICE select DRM_KMS_HELPER select DRM_GEM_DMA_HELPER diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index d354ab3077ce..11dd2bc803e7 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -18,6 +18,7 @@ #include <drm/drm_gem_dma_helper.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> @@ -232,6 +233,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) value = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; break; case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: default: value = LDDDSR_LS; break; @@ -355,8 +357,8 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc, format = shmob_drm_format_info(crtc->primary->fb->format->format); if (format == NULL) { - dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n", - crtc->primary->fb->format->format); + dev_dbg(sdev->dev, "mode_set: unsupported format %p4cc\n", + &crtc->primary->fb->format->format); return -EINVAL; } @@ -477,16 +479,41 @@ static const struct drm_crtc_funcs crtc_funcs = { .disable_vblank = shmob_drm_disable_vblank, }; +static const uint32_t modeset_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, +}; + +static const struct drm_plane_funcs primary_plane_funcs = { + DRM_PLANE_NON_ATOMIC_FUNCS, +}; + int shmob_drm_crtc_create(struct shmob_drm_device *sdev) { struct drm_crtc *crtc = &sdev->crtc.crtc; + struct drm_plane *primary; int ret; sdev->crtc.dpms = DRM_MODE_DPMS_OFF; - ret = drm_crtc_init(sdev->ddev, crtc, &crtc_funcs); - if (ret < 0) + primary = __drm_universal_plane_alloc(sdev->ddev, sizeof(*primary), 0, + 0, &primary_plane_funcs, + modeset_formats, + ARRAY_SIZE(modeset_formats), + NULL, DRM_PLANE_TYPE_PRIMARY, + NULL); + if (IS_ERR(primary)) + return PTR_ERR(primary); + + ret = drm_crtc_init_with_planes(sdev->ddev, crtc, primary, NULL, + &crtc_funcs, NULL); + if (ret < 0) { + drm_plane_cleanup(primary); + kfree(primary); return ret; + } drm_crtc_helper_add(crtc, &crtc_helper_funcs); diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index faacfee24763..30493ce87419 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <drm/drm_drv.h> +#include <drm/drm_fbdev_generic.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> @@ -271,6 +272,8 @@ static int shmob_drm_probe(struct platform_device *pdev) if (ret < 0) goto err_irq_uninstall; + drm_fbdev_generic_setup(ddev, 16); + return 0; err_irq_uninstall: diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c index 60a2c8d8a0d9..99381cc0abf3 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c @@ -40,6 +40,11 @@ static const struct shmob_drm_format_info shmob_drm_format_infos[] = { .yuv = false, .lddfr = LDDFR_PKF_ARGB32, }, { + .fourcc = DRM_FORMAT_XRGB8888, + .bpp = 32, + .yuv = false, + .lddfr = LDDFR_PKF_ARGB32, + }, { .fourcc = DRM_FORMAT_NV12, .bpp = 12, .yuv = true, @@ -96,8 +101,8 @@ shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv, format = shmob_drm_format_info(mode_cmd->pixel_format); if (format == NULL) { - dev_dbg(dev->dev, "unsupported pixel format %08x\n", - mode_cmd->pixel_format); + dev_dbg(dev->dev, "unsupported pixel format %p4cc\n", + &mode_cmd->pixel_format); return ERR_PTR(-EINVAL); } diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c index 604ae23825da..850986cee848 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c @@ -80,6 +80,7 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB; break; case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: default: format |= LDBBSIFR_SWPL; break; @@ -95,6 +96,9 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, case DRM_FORMAT_ARGB8888: format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32; break; + case DRM_FORMAT_XRGB8888: + format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDDFR_PKF_ARGB32; + break; case DRM_FORMAT_NV12: case DRM_FORMAT_NV21: format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420; @@ -231,6 +235,7 @@ static const uint32_t formats[] = { DRM_FORMAT_RGB565, DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12, DRM_FORMAT_NV21, DRM_FORMAT_NV16, diff --git a/drivers/gpu/drm/solomon/ssd130x-i2c.c b/drivers/gpu/drm/solomon/ssd130x-i2c.c index ddfa0bb5d9c9..b4eb2d64bf6e 100644 --- a/drivers/gpu/drm/solomon/ssd130x-i2c.c +++ b/drivers/gpu/drm/solomon/ssd130x-i2c.c @@ -100,7 +100,7 @@ static struct i2c_driver ssd130x_i2c_driver = { .name = DRIVER_NAME, .of_match_table = ssd130x_of_match, }, - .probe_new = ssd130x_i2c_probe, + .probe = ssd130x_i2c_probe, .remove = ssd130x_i2c_remove, .shutdown = ssd130x_i2c_shutdown, }; diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h index 03038c1b6476..db03ee5db392 100644 --- a/drivers/gpu/drm/solomon/ssd130x.h +++ b/drivers/gpu/drm/solomon/ssd130x.h @@ -10,8 +10,8 @@ * Copyright 2012 Free Electrons */ -#ifndef __SSD1307X_H__ -#define __SSD1307X_H__ +#ifndef __SSD130X_H__ +#define __SSD130X_H__ #include <drm/drm_connector.h> #include <drm/drm_crtc.h> @@ -94,4 +94,4 @@ struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap); void ssd130x_remove(struct ssd130x_device *ssd130x); void ssd130x_shutdown(struct ssd130x_device *ssd130x); -#endif /* __SSD1307X_H__ */ +#endif /* __SSD130X_H__ */ diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 577c477b5f46..0c6679e361c8 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -8,7 +8,7 @@ #include <linux/component.h> #include <linux/debugfs.h> #include <linux/module.h> -#include <linux/of_gpio.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <drm/drm_atomic_helper.h> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 8539fe1fedc4..dc1562f14ceb 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -266,6 +266,7 @@ static void hdmi_active_area(struct sti_hdmi *hdmi) */ static void hdmi_config(struct sti_hdmi *hdmi) { + struct drm_connector *connector = hdmi->drm_connector; u32 conf; DRM_DEBUG_DRIVER("\n"); @@ -275,7 +276,7 @@ static void hdmi_config(struct sti_hdmi *hdmi) /* Select encryption type and the framing mode */ conf |= HDMI_CFG_ESS_NOT_OESS; - if (hdmi->hdmi_monitor) + if (connector->display_info.is_hdmi) conf |= HDMI_CFG_HDMI_NOT_DVI; /* Set Hsync polarity */ @@ -985,15 +986,15 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector) if (!edid) goto fail; - hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid); - DRM_DEBUG_KMS("%s : %dx%d cm\n", - (hdmi->hdmi_monitor ? "hdmi monitor" : "dvi monitor"), - edid->width_cm, edid->height_cm); cec_notifier_set_phys_addr_from_edid(hdmi->notifier, edid); count = drm_add_edid_modes(connector, edid); drm_connector_update_edid_property(connector, edid); + DRM_DEBUG_KMS("%s : %dx%d cm\n", + (connector->display_info.is_hdmi ? "hdmi monitor" : "dvi monitor"), + edid->width_cm, edid->height_cm); + kfree(edid); return count; diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index 05b2f3d0d48d..6d4c3f57bc46 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h @@ -57,7 +57,6 @@ struct hdmi_audio_params { * @reset: reset control of the hdmi phy * @ddc_adapt: i2c ddc adapter * @colorspace: current colorspace selected - * @hdmi_monitor: true if HDMI monitor detected else DVI monitor assumed * @audio_pdev: ASoC hdmi-codec platform device * @audio: hdmi audio parameters. * @drm_connector: hdmi connector @@ -83,7 +82,6 @@ struct sti_hdmi { struct reset_control *reset; struct i2c_adapter *ddc_adapt; enum hdmi_colorspace colorspace; - bool hdmi_monitor; struct platform_device *audio_pdev; struct hdmi_audio_params audio; struct drm_connector *drm_connector; diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 422220df7d8c..cb4404b3ce62 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -185,7 +185,7 @@ static int stm_drm_platform_probe(struct platform_device *pdev) DRM_DEBUG("%s\n", __func__); - ret = drm_aperture_remove_framebuffers(false, &drv_driver); + ret = drm_aperture_remove_framebuffers(&drv_driver); if (ret) return ret; diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index 89897d5f5c72..1750b6a25e87 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -444,15 +444,13 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dw_mipi_dsi_stm *dsi; struct clk *pclk; - struct resource *res; int ret; dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); if (!dsi) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dsi->base = devm_ioremap_resource(dev, res); + dsi->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dsi->base)) { ret = PTR_ERR(dsi->base); DRM_ERROR("Unable to get dsi registers %d\n", ret); diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 03c6becda795..b8be4c1db423 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -1145,7 +1145,7 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source) { - struct ltdc_device *ldev = crtc_to_ltdc(crtc); + struct ltdc_device *ldev; int ret; DRM_DEBUG_DRIVER("\n"); @@ -1153,6 +1153,8 @@ static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source) if (!crtc) return -ENODEV; + ldev = crtc_to_ltdc(crtc); + if (source && strcmp(source, "auto") == 0) { ldev->crc_active = true; ret = regmap_set_bits(ldev->regmap, LTDC_GCR, GCR_CRCEN); diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 0d04f2447b01..bad7497a0d11 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -19,7 +19,7 @@ sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \ sun8i_vi_scaler.o sun8i_csc.o sun4i-tcon-y += sun4i_crtc.o -sun4i-tcon-y += sun4i_dotclock.o +sun4i-tcon-y += sun4i_tcon_dclk.o sun4i-tcon-y += sun4i_lvds.o sun4i-tcon-y += sun4i_tcon.o sun4i-tcon-y += sun4i_rgb.o diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index e49f78a6a8cf..daa7faf72a4b 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -98,7 +98,7 @@ static int sun4i_drv_bind(struct device *dev) goto unbind_all; /* Remove early framebuffers (ie. simplefb) */ - ret = drm_aperture_remove_framebuffers(false, &sun4i_drv_driver); + ret = drm_aperture_remove_framebuffers(&sun4i_drv_driver); if (ret) goto unbind_all; diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 523a6d787921..6a52fb12cbfb 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -31,12 +31,12 @@ #include <uapi/drm/drm_mode.h> #include "sun4i_crtc.h" -#include "sun4i_dotclock.h" #include "sun4i_drv.h" #include "sun4i_lvds.h" #include "sun4i_rgb.h" #include "sun4i_tcon.h" #include "sun6i_mipi_dsi.h" +#include "sun4i_tcon_dclk.h" #include "sun8i_tcon_top.h" #include "sunxi_engine.h" @@ -291,18 +291,6 @@ static int sun4i_tcon_get_clk_delay(const struct drm_display_mode *mode, return delay; } -static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon, - const struct drm_display_mode *mode) -{ - /* Configure the dot clock */ - clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); - - /* Set the resolution */ - regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, - SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | - SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); -} - static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon, const struct drm_connector *connector) { @@ -367,10 +355,18 @@ static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon, u32 block_space, start_delay; u32 tcon_div; + /* + * dclk is required to run at 1/4 the DSI per-lane bit rate. + */ tcon->dclk_min_div = SUN6I_DSI_TCON_DIV; tcon->dclk_max_div = SUN6I_DSI_TCON_DIV; + clk_set_rate(tcon->dclk, mode->crtc_clock * 1000 * (bpp / lanes) + / SUN6I_DSI_TCON_DIV); - sun4i_tcon0_mode_set_common(tcon, mode); + /* Set the resolution */ + regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, + SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | + SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); /* Set dithering if needed */ sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder)); @@ -438,7 +434,12 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, tcon->dclk_min_div = 7; tcon->dclk_max_div = 7; - sun4i_tcon0_mode_set_common(tcon, mode); + clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); + + /* Set the resolution */ + regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, + SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | + SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); /* Set dithering if needed */ sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder)); @@ -515,7 +516,12 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, tcon->dclk_min_div = tcon->quirks->dclk_min_div; tcon->dclk_max_div = 127; - sun4i_tcon0_mode_set_common(tcon, mode); + clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); + + /* Set the resolution */ + regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, + SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | + SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); /* Set dithering if needed */ sun4i_tcon0_mode_set_dithering(tcon, connector); @@ -778,21 +784,19 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private) static int sun4i_tcon_init_clocks(struct device *dev, struct sun4i_tcon *tcon) { - tcon->clk = devm_clk_get(dev, "ahb"); + tcon->clk = devm_clk_get_enabled(dev, "ahb"); if (IS_ERR(tcon->clk)) { dev_err(dev, "Couldn't get the TCON bus clock\n"); return PTR_ERR(tcon->clk); } - clk_prepare_enable(tcon->clk); if (tcon->quirks->has_channel_0) { - tcon->sclk0 = devm_clk_get(dev, "tcon-ch0"); + tcon->sclk0 = devm_clk_get_enabled(dev, "tcon-ch0"); if (IS_ERR(tcon->sclk0)) { dev_err(dev, "Couldn't get the TCON channel 0 clock\n"); return PTR_ERR(tcon->sclk0); } } - clk_prepare_enable(tcon->sclk0); if (tcon->quirks->has_channel_1) { tcon->sclk1 = devm_clk_get(dev, "tcon-ch1"); @@ -805,12 +809,6 @@ static int sun4i_tcon_init_clocks(struct device *dev, return 0; } -static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon) -{ - clk_disable_unprepare(tcon->sclk0); - clk_disable_unprepare(tcon->clk); -} - static int sun4i_tcon_init_irq(struct device *dev, struct sun4i_tcon *tcon) { @@ -1223,28 +1221,28 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, ret = sun4i_tcon_init_regmap(dev, tcon); if (ret) { dev_err(dev, "Couldn't init our TCON regmap\n"); - goto err_free_clocks; + goto err_assert_reset; } if (tcon->quirks->has_channel_0) { ret = sun4i_dclk_create(dev, tcon); if (ret) { dev_err(dev, "Couldn't create our TCON dot clock\n"); - goto err_free_clocks; + goto err_assert_reset; } } ret = sun4i_tcon_init_irq(dev, tcon); if (ret) { dev_err(dev, "Couldn't init our TCON interrupts\n"); - goto err_free_dotclock; + goto err_free_dclk; } tcon->crtc = sun4i_crtc_init(drm, engine, tcon); if (IS_ERR(tcon->crtc)) { dev_err(dev, "Couldn't create our CRTC\n"); ret = PTR_ERR(tcon->crtc); - goto err_free_dotclock; + goto err_free_dclk; } if (tcon->quirks->has_channel_0) { @@ -1264,7 +1262,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, of_node_put(remote); if (ret < 0) - goto err_free_dotclock; + goto err_free_dclk; } if (tcon->quirks->needs_de_be_mux) { @@ -1290,11 +1288,9 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, return 0; -err_free_dotclock: +err_free_dclk: if (tcon->quirks->has_channel_0) sun4i_dclk_free(tcon); -err_free_clocks: - sun4i_tcon_free_clocks(tcon); err_assert_reset: reset_control_assert(tcon->lcd_rst); return ret; @@ -1308,7 +1304,6 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master, list_del(&tcon->list); if (tcon->quirks->has_channel_0) sun4i_dclk_free(tcon); - sun4i_tcon_free_clocks(tcon); } static const struct component_ops sun4i_tcon_ops = { diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_tcon_dclk.c index 417ade3d2565..03d7de1911cd 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon_dclk.c @@ -10,7 +10,7 @@ #include <linux/regmap.h> #include "sun4i_tcon.h" -#include "sun4i_dotclock.h" +#include "sun4i_tcon_dclk.h" struct sun4i_dclk { struct clk_hw hw; diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.h b/drivers/gpu/drm/sun4i/sun4i_tcon_dclk.h index ac60da2455ca..ac60da2455ca 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon_dclk.h diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 56453ca277c2..498313778175 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -12,6 +12,7 @@ config DRM_TEGRA select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL + select FB_SYS_HELPERS if DRM_FBDEV_EMULATION select TEGRA_HOST1X select INTERCONNECT select IOMMU_IOVA diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 85ba96cddd51..35ff303c6674 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1244,7 +1244,7 @@ static int host1x_drm_probe(struct host1x_device *dev) drm_mode_config_reset(drm); - err = drm_aperture_remove_framebuffers(false, &tegra_drm_driver); + err = drm_aperture_remove_framebuffers(&tegra_drm_driver); if (err < 0) goto hub; diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c index dca9eccae466..e74d9be981c7 100644 --- a/drivers/gpu/drm/tegra/fbdev.c +++ b/drivers/gpu/drm/tegra/fbdev.c @@ -8,6 +8,7 @@ */ #include <linux/console.h> +#include <linux/fb.h> #include <linux/vmalloc.h> #include <drm/drm_drv.h> @@ -58,12 +59,9 @@ static void tegra_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, + __FB_DEFAULT_SYS_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, - .fb_read = drm_fb_helper_sys_read, - .fb_write = drm_fb_helper_sys_write, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, + __FB_DEFAULT_SYS_OPS_DRAW, .fb_mmap = tegra_fb_mmap, .fb_destroy = tegra_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c index f8ee714df396..09ee6f6af896 100644 --- a/drivers/gpu/drm/tests/drm_buddy_test.c +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -89,7 +89,8 @@ static int check_block(struct kunit *test, struct drm_buddy *mm, err = -EINVAL; } - if (!is_power_of_2(block_size)) { + /* We can't use is_power_of_2() for a u64 on 32-bit systems. */ + if (block_size & (block_size - 1)) { kunit_err(test, "block size not power of two\n"); err = -EINVAL; } diff --git a/drivers/gpu/drm/tests/drm_rect_test.c b/drivers/gpu/drm/tests/drm_rect_test.c index e9809ea32696..76332cd2ead8 100644 --- a/drivers/gpu/drm/tests/drm_rect_test.c +++ b/drivers/gpu/drm/tests/drm_rect_test.c @@ -8,6 +8,19 @@ #include <kunit/test.h> #include <drm/drm_rect.h> +#include <drm/drm_mode.h> + +#include <linux/string_helpers.h> +#include <linux/errno.h> + +static void drm_rect_compare(struct kunit *test, const struct drm_rect *r, + const struct drm_rect *expected) +{ + KUNIT_EXPECT_EQ(test, r->x1, expected->x1); + KUNIT_EXPECT_EQ(test, r->y1, expected->y1); + KUNIT_EXPECT_EQ(test, drm_rect_width(r), drm_rect_width(expected)); + KUNIT_EXPECT_EQ(test, drm_rect_height(r), drm_rect_height(expected)); +} static void drm_test_rect_clip_scaled_div_by_zero(struct kunit *test) { @@ -196,11 +209,313 @@ static void drm_test_rect_clip_scaled_signed_vs_unsigned(struct kunit *test) KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n"); } +struct drm_rect_intersect_case { + const char *description; + struct drm_rect r1, r2; + bool should_be_visible; + struct drm_rect expected_intersection; +}; + +static const struct drm_rect_intersect_case drm_rect_intersect_cases[] = { + { + .description = "top-left x bottom-right", + .r1 = DRM_RECT_INIT(1, 1, 2, 2), + .r2 = DRM_RECT_INIT(0, 0, 2, 2), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(1, 1, 1, 1), + }, + { + .description = "top-right x bottom-left", + .r1 = DRM_RECT_INIT(0, 0, 2, 2), + .r2 = DRM_RECT_INIT(1, -1, 2, 2), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(1, 0, 1, 1), + }, + { + .description = "bottom-left x top-right", + .r1 = DRM_RECT_INIT(1, -1, 2, 2), + .r2 = DRM_RECT_INIT(0, 0, 2, 2), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(1, 0, 1, 1), + }, + { + .description = "bottom-right x top-left", + .r1 = DRM_RECT_INIT(0, 0, 2, 2), + .r2 = DRM_RECT_INIT(1, 1, 2, 2), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(1, 1, 1, 1), + }, + { + .description = "right x left", + .r1 = DRM_RECT_INIT(0, 0, 2, 1), + .r2 = DRM_RECT_INIT(1, 0, 3, 1), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(1, 0, 1, 1), + }, + { + .description = "left x right", + .r1 = DRM_RECT_INIT(1, 0, 3, 1), + .r2 = DRM_RECT_INIT(0, 0, 2, 1), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(1, 0, 1, 1), + }, + { + .description = "up x bottom", + .r1 = DRM_RECT_INIT(0, 0, 1, 2), + .r2 = DRM_RECT_INIT(0, -1, 1, 3), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(0, 0, 1, 2), + }, + { + .description = "bottom x up", + .r1 = DRM_RECT_INIT(0, -1, 1, 3), + .r2 = DRM_RECT_INIT(0, 0, 1, 2), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(0, 0, 1, 2), + }, + { + .description = "touching corner", + .r1 = DRM_RECT_INIT(0, 0, 1, 1), + .r2 = DRM_RECT_INIT(1, 1, 2, 2), + .should_be_visible = false, + .expected_intersection = DRM_RECT_INIT(1, 1, 0, 0), + }, + { + .description = "touching side", + .r1 = DRM_RECT_INIT(0, 0, 1, 1), + .r2 = DRM_RECT_INIT(1, 0, 1, 1), + .should_be_visible = false, + .expected_intersection = DRM_RECT_INIT(1, 0, 0, 1), + }, + { + .description = "equal rects", + .r1 = DRM_RECT_INIT(0, 0, 2, 2), + .r2 = DRM_RECT_INIT(0, 0, 2, 2), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(0, 0, 2, 2), + }, + { + .description = "inside another", + .r1 = DRM_RECT_INIT(0, 0, 2, 2), + .r2 = DRM_RECT_INIT(1, 1, 1, 1), + .should_be_visible = true, + .expected_intersection = DRM_RECT_INIT(1, 1, 1, 1), + }, + { + .description = "far away", + .r1 = DRM_RECT_INIT(0, 0, 1, 1), + .r2 = DRM_RECT_INIT(3, 6, 1, 1), + .should_be_visible = false, + .expected_intersection = DRM_RECT_INIT(3, 6, -2, -5), + }, + { + .description = "points intersecting", + .r1 = DRM_RECT_INIT(5, 10, 0, 0), + .r2 = DRM_RECT_INIT(5, 10, 0, 0), + .should_be_visible = false, + .expected_intersection = DRM_RECT_INIT(5, 10, 0, 0), + }, + { + .description = "points not intersecting", + .r1 = DRM_RECT_INIT(0, 0, 0, 0), + .r2 = DRM_RECT_INIT(5, 10, 0, 0), + .should_be_visible = false, + .expected_intersection = DRM_RECT_INIT(5, 10, -5, -10), + }, +}; + +static void drm_rect_intersect_case_desc(const struct drm_rect_intersect_case *t, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "%s: " DRM_RECT_FMT " x " DRM_RECT_FMT, + t->description, DRM_RECT_ARG(&t->r1), DRM_RECT_ARG(&t->r2)); +} + +KUNIT_ARRAY_PARAM(drm_rect_intersect, drm_rect_intersect_cases, drm_rect_intersect_case_desc); + +static void drm_test_rect_intersect(struct kunit *test) +{ + const struct drm_rect_intersect_case *params = test->param_value; + struct drm_rect r1_aux = params->r1; + bool visible; + + visible = drm_rect_intersect(&r1_aux, ¶ms->r2); + + KUNIT_EXPECT_EQ(test, visible, params->should_be_visible); + drm_rect_compare(test, &r1_aux, ¶ms->expected_intersection); +} + +struct drm_rect_scale_case { + const char *name; + struct drm_rect src, dst; + int min_range, max_range; + int expected_scaling_factor; +}; + +static const struct drm_rect_scale_case drm_rect_scale_cases[] = { + { + .name = "normal use", + .src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16), + .dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16), + .min_range = 0, .max_range = INT_MAX, + .expected_scaling_factor = 2, + }, + { + .name = "out of max range", + .src = DRM_RECT_INIT(0, 0, 10 << 16, 10 << 16), + .dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16), + .min_range = 3, .max_range = 5, + .expected_scaling_factor = -ERANGE, + }, + { + .name = "out of min range", + .src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16), + .dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16), + .min_range = 3, .max_range = 5, + .expected_scaling_factor = -ERANGE, + }, + { + .name = "zero dst", + .src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16), + .dst = DRM_RECT_INIT(0, 0, 0 << 16, 0 << 16), + .min_range = 0, .max_range = INT_MAX, + .expected_scaling_factor = 0, + }, + { + .name = "negative src", + .src = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)), + .dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16), + .min_range = 0, .max_range = INT_MAX, + .expected_scaling_factor = -EINVAL, + }, + { + .name = "negative dst", + .src = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16), + .dst = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)), + .min_range = 0, .max_range = INT_MAX, + .expected_scaling_factor = -EINVAL, + }, +}; + +static void drm_rect_scale_case_desc(const struct drm_rect_scale_case *t, char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(drm_rect_scale, drm_rect_scale_cases, drm_rect_scale_case_desc); + +static void drm_test_rect_calc_hscale(struct kunit *test) +{ + const struct drm_rect_scale_case *params = test->param_value; + int scaling_factor; + + scaling_factor = drm_rect_calc_hscale(¶ms->src, ¶ms->dst, + params->min_range, params->max_range); + + KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor); +} + +static void drm_test_rect_calc_vscale(struct kunit *test) +{ + const struct drm_rect_scale_case *params = test->param_value; + int scaling_factor; + + scaling_factor = drm_rect_calc_vscale(¶ms->src, ¶ms->dst, + params->min_range, params->max_range); + + KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor); +} + +struct drm_rect_rotate_case { + const char *name; + unsigned int rotation; + struct drm_rect rect; + int width, height; + struct drm_rect expected; +}; + +static const struct drm_rect_rotate_case drm_rect_rotate_cases[] = { + { + .name = "reflect-x", + .rotation = DRM_MODE_REFLECT_X, + .rect = DRM_RECT_INIT(0, 0, 5, 5), + .width = 5, .height = 10, + .expected = DRM_RECT_INIT(0, 0, 5, 5), + }, + { + .name = "reflect-y", + .rotation = DRM_MODE_REFLECT_Y, + .rect = DRM_RECT_INIT(2, 0, 5, 5), + .width = 5, .height = 10, + .expected = DRM_RECT_INIT(2, 5, 5, 5), + }, + { + .name = "rotate-0", + .rotation = DRM_MODE_ROTATE_0, + .rect = DRM_RECT_INIT(0, 2, 5, 5), + .width = 5, .height = 10, + .expected = DRM_RECT_INIT(0, 2, 5, 5), + }, + { + .name = "rotate-90", + .rotation = DRM_MODE_ROTATE_90, + .rect = DRM_RECT_INIT(0, 0, 5, 10), + .width = 5, .height = 10, + .expected = DRM_RECT_INIT(0, 0, 10, 5), + }, + { + .name = "rotate-180", + .rotation = DRM_MODE_ROTATE_180, + .rect = DRM_RECT_INIT(11, 3, 5, 10), + .width = 5, .height = 10, + .expected = DRM_RECT_INIT(-11, -3, 5, 10), + }, + { + .name = "rotate-270", + .rotation = DRM_MODE_ROTATE_270, + .rect = DRM_RECT_INIT(6, 3, 5, 10), + .width = 5, .height = 10, + .expected = DRM_RECT_INIT(-3, 6, 10, 5), + }, +}; + +static void drm_rect_rotate_case_desc(const struct drm_rect_rotate_case *t, char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(drm_rect_rotate, drm_rect_rotate_cases, drm_rect_rotate_case_desc); + +static void drm_test_rect_rotate(struct kunit *test) +{ + const struct drm_rect_rotate_case *params = test->param_value; + struct drm_rect r = params->rect; + + drm_rect_rotate(&r, params->width, params->height, params->rotation); + + drm_rect_compare(test, &r, ¶ms->expected); +} + +static void drm_test_rect_rotate_inv(struct kunit *test) +{ + const struct drm_rect_rotate_case *params = test->param_value; + struct drm_rect r = params->expected; + + drm_rect_rotate_inv(&r, params->width, params->height, params->rotation); + + drm_rect_compare(test, &r, ¶ms->rect); +} + static struct kunit_case drm_rect_tests[] = { KUNIT_CASE(drm_test_rect_clip_scaled_div_by_zero), KUNIT_CASE(drm_test_rect_clip_scaled_not_clipped), KUNIT_CASE(drm_test_rect_clip_scaled_clipped), KUNIT_CASE(drm_test_rect_clip_scaled_signed_vs_unsigned), + KUNIT_CASE_PARAM(drm_test_rect_intersect, drm_rect_intersect_gen_params), + KUNIT_CASE_PARAM(drm_test_rect_calc_hscale, drm_rect_scale_gen_params), + KUNIT_CASE_PARAM(drm_test_rect_calc_vscale, drm_rect_scale_gen_params), + KUNIT_CASE_PARAM(drm_test_rect_rotate, drm_rect_rotate_gen_params), + KUNIT_CASE_PARAM(drm_test_rect_rotate_inv, drm_rect_rotate_gen_params), { } }; diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 4bca6b54520a..4212b8c91dd4 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -261,7 +261,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, * encryption bits. This is because the exact location of the * data may not be known at mmap() time and may also change * at arbitrary times while the data is mmap'ed. - * See vmf_insert_mixed_prot() for a discussion. + * See vmf_insert_pfn_prot() for a discussion. */ ret = vmf_insert_pfn_prot(vma, address, pfn, prot); diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c index 64a59f46f6c3..df4cf5468e7f 100644 --- a/drivers/gpu/drm/ttm/ttm_device.c +++ b/drivers/gpu/drm/ttm/ttm_device.c @@ -189,7 +189,7 @@ EXPORT_SYMBOL(ttm_device_swapout); * Returns: * !0: Failure. */ -int ttm_device_init(struct ttm_device *bdev, struct ttm_device_funcs *funcs, +int ttm_device_init(struct ttm_device *bdev, const struct ttm_device_funcs *funcs, struct device *dev, struct address_space *mapping, struct drm_vma_offset_manager *vma_manager, bool use_dma_alloc, bool use_dma32) diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c index 18c342a919a2..4db3982057be 100644 --- a/drivers/gpu/drm/ttm/ttm_pool.c +++ b/drivers/gpu/drm/ttm/ttm_pool.c @@ -47,11 +47,6 @@ #include "ttm_module.h" -#define TTM_MAX_ORDER (PMD_SHIFT - PAGE_SHIFT) -#define __TTM_DIM_ORDER (TTM_MAX_ORDER + 1) -/* Some architectures have a weird PMD_SHIFT */ -#define TTM_DIM_ORDER (__TTM_DIM_ORDER <= MAX_ORDER ? __TTM_DIM_ORDER : MAX_ORDER) - /** * struct ttm_pool_dma - Helper object for coherent DMA mappings * @@ -70,11 +65,11 @@ module_param(page_pool_size, ulong, 0644); static atomic_long_t allocated_pages; -static struct ttm_pool_type global_write_combined[TTM_DIM_ORDER]; -static struct ttm_pool_type global_uncached[TTM_DIM_ORDER]; +static struct ttm_pool_type global_write_combined[MAX_ORDER + 1]; +static struct ttm_pool_type global_uncached[MAX_ORDER + 1]; -static struct ttm_pool_type global_dma32_write_combined[TTM_DIM_ORDER]; -static struct ttm_pool_type global_dma32_uncached[TTM_DIM_ORDER]; +static struct ttm_pool_type global_dma32_write_combined[MAX_ORDER + 1]; +static struct ttm_pool_type global_dma32_uncached[MAX_ORDER + 1]; static spinlock_t shrinker_lock; static struct list_head shrinker_list; @@ -449,7 +444,7 @@ int ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, else gfp_flags |= GFP_HIGHUSER; - for (order = min_t(unsigned int, TTM_MAX_ORDER, __fls(num_pages)); + for (order = min_t(unsigned int, MAX_ORDER, __fls(num_pages)); num_pages; order = min_t(unsigned int, order, __fls(num_pages))) { struct ttm_pool_type *pt; @@ -568,7 +563,7 @@ void ttm_pool_init(struct ttm_pool *pool, struct device *dev, if (use_dma_alloc) { for (i = 0; i < TTM_NUM_CACHING_TYPES; ++i) - for (j = 0; j < TTM_DIM_ORDER; ++j) + for (j = 0; j <= MAX_ORDER; ++j) ttm_pool_type_init(&pool->caching[i].orders[j], pool, i, j); } @@ -588,7 +583,7 @@ void ttm_pool_fini(struct ttm_pool *pool) if (pool->use_dma_alloc) { for (i = 0; i < TTM_NUM_CACHING_TYPES; ++i) - for (j = 0; j < TTM_DIM_ORDER; ++j) + for (j = 0; j <= MAX_ORDER; ++j) ttm_pool_type_fini(&pool->caching[i].orders[j]); } @@ -642,7 +637,7 @@ static void ttm_pool_debugfs_header(struct seq_file *m) unsigned int i; seq_puts(m, "\t "); - for (i = 0; i < TTM_DIM_ORDER; ++i) + for (i = 0; i <= MAX_ORDER; ++i) seq_printf(m, " ---%2u---", i); seq_puts(m, "\n"); } @@ -653,7 +648,7 @@ static void ttm_pool_debugfs_orders(struct ttm_pool_type *pt, { unsigned int i; - for (i = 0; i < TTM_DIM_ORDER; ++i) + for (i = 0; i <= MAX_ORDER; ++i) seq_printf(m, " %8u", ttm_pool_type_count(&pt[i])); seq_puts(m, "\n"); } @@ -756,16 +751,13 @@ int ttm_pool_mgr_init(unsigned long num_pages) { unsigned int i; - BUILD_BUG_ON(TTM_DIM_ORDER > MAX_ORDER); - BUILD_BUG_ON(TTM_DIM_ORDER < 1); - if (!page_pool_size) page_pool_size = num_pages; spin_lock_init(&shrinker_lock); INIT_LIST_HEAD(&shrinker_list); - for (i = 0; i < TTM_DIM_ORDER; ++i) { + for (i = 0; i <= MAX_ORDER; ++i) { ttm_pool_type_init(&global_write_combined[i], NULL, ttm_write_combined, i); ttm_pool_type_init(&global_uncached[i], NULL, ttm_uncached, i); @@ -798,7 +790,7 @@ void ttm_pool_mgr_fini(void) { unsigned int i; - for (i = 0; i < TTM_DIM_ORDER; ++i) { + for (i = 0; i <= MAX_ORDER; ++i) { ttm_pool_type_fini(&global_write_combined[i]); ttm_pool_type_fini(&global_uncached[i]); diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index ab725d9d14a6..1ce4b36ab33b 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -137,7 +137,6 @@ static void ttm_tt_init_fields(struct ttm_tt *ttm, unsigned long extra_pages) { ttm->num_pages = (PAGE_ALIGN(bo->base.size) >> PAGE_SHIFT) + extra_pages; - ttm->caching = ttm_cached; ttm->page_flags = page_flags; ttm->dma_address = NULL; ttm->swap_storage = NULL; diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index abd557332b28..40b1168ad671 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -156,7 +156,6 @@ static int tve200_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct tve200_drm_dev_private *priv; struct drm_device *drm; - struct resource *res; int irq; int ret; @@ -192,8 +191,7 @@ static int tve200_probe(struct platform_device *pdev) goto clk_disable; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = devm_ioremap_resource(dev, res); + priv->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->regs)) { dev_err(dev, "%s failed mmio\n", __func__); ret = -EINVAL; diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 061cb88c08a2..3ebe2ce55dfd 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -255,7 +255,7 @@ static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout) list_del_init(&unode->entry); udl->urbs.available--; - return unode ? unode->urb : NULL; + return unode->urb; } #define GET_URB_TIMEOUT HZ diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h index db8e9a141ef8..2d0b339bd9f3 100644 --- a/drivers/gpu/drm/vc4/tests/vc4_mock.h +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h @@ -43,6 +43,9 @@ struct vc4_dummy_output { struct drm_connector connector; }; +#define encoder_to_vc4_dummy_output(_enc) \ + container_of_const(_enc, struct vc4_dummy_output, encoder.base) + struct vc4_dummy_output *vc4_dummy_output(struct kunit *test, struct drm_device *drm, struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c index 8d33be828d9a..6e11fcc9ef45 100644 --- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c @@ -80,7 +80,7 @@ int vc4_mock_atomic_add_output(struct kunit *test, crtc = vc4_find_crtc_for_encoder(test, drm, encoder); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); - output = container_of(encoder, struct vc4_dummy_output, encoder.base); + output = encoder_to_vc4_dummy_output(encoder); conn = &output->connector; conn_state = drm_atomic_get_connector_state(state, conn); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); @@ -126,7 +126,7 @@ int vc4_mock_atomic_del_output(struct kunit *test, ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); KUNIT_ASSERT_EQ(test, ret, 0); - output = container_of(encoder, struct vc4_dummy_output, encoder.base); + output = encoder_to_vc4_dummy_output(encoder); conn = &output->connector; conn_state = drm_atomic_get_connector_state(state, conn); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index f518d6e59ed6..e68c07d86040 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -97,11 +97,8 @@ struct vc4_dpi { struct debugfs_regset32 regset; }; -static inline struct vc4_dpi * -to_vc4_dpi(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_dpi, encoder.base); -} +#define to_vc4_dpi(_encoder) \ + container_of_const(_encoder, struct vc4_dpi, encoder.base) #define DPI_READ(offset) \ ({ \ diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index c8bf954042e0..823395c23cc3 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -350,7 +350,7 @@ static int vc4_drm_bind(struct device *dev) return -EPROBE_DEFER; } - ret = drm_aperture_remove_framebuffers(false, driver); + ret = drm_aperture_remove_framebuffers(driver); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 8768566c610b..bf66499765fb 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -232,11 +232,8 @@ struct vc4_dev { struct kref bin_bo_kref; }; -static inline struct vc4_dev * -to_vc4_dev(const struct drm_device *dev) -{ - return container_of(dev, struct vc4_dev, base); -} +#define to_vc4_dev(_dev) \ + container_of_const(_dev, struct vc4_dev, base) struct vc4_bo { struct drm_gem_dma_object base; @@ -285,11 +282,8 @@ struct vc4_bo { struct mutex madv_lock; }; -static inline struct vc4_bo * -to_vc4_bo(const struct drm_gem_object *bo) -{ - return container_of(to_drm_gem_dma_obj(bo), struct vc4_bo, base); -} +#define to_vc4_bo(_bo) \ + container_of_const(to_drm_gem_dma_obj(_bo), struct vc4_bo, base) struct vc4_fence { struct dma_fence base; @@ -298,11 +292,8 @@ struct vc4_fence { uint64_t seqno; }; -static inline struct vc4_fence * -to_vc4_fence(const struct dma_fence *fence) -{ - return container_of(fence, struct vc4_fence, base); -} +#define to_vc4_fence(_fence) \ + container_of_const(_fence, struct vc4_fence, base) struct vc4_seqno_cb { struct work_struct work; @@ -368,11 +359,8 @@ struct vc4_hvs_state { } fifo_state[HVS_NUM_CHANNELS]; }; -static inline struct vc4_hvs_state * -to_vc4_hvs_state(const struct drm_private_state *priv) -{ - return container_of(priv, struct vc4_hvs_state, base); -} +#define to_vc4_hvs_state(_state) \ + container_of_const(_state, struct vc4_hvs_state, base) struct vc4_hvs_state *vc4_hvs_get_global_state(struct drm_atomic_state *state); struct vc4_hvs_state *vc4_hvs_get_old_global_state(const struct drm_atomic_state *state); @@ -382,11 +370,8 @@ struct vc4_plane { struct drm_plane base; }; -static inline struct vc4_plane * -to_vc4_plane(const struct drm_plane *plane) -{ - return container_of(plane, struct vc4_plane, base); -} +#define to_vc4_plane(_plane) \ + container_of_const(_plane, struct vc4_plane, base) enum vc4_scaling_mode { VC4_SCALING_NONE, @@ -458,11 +443,8 @@ struct vc4_plane_state { u64 membus_load; }; -static inline struct vc4_plane_state * -to_vc4_plane_state(const struct drm_plane_state *state) -{ - return container_of(state, struct vc4_plane_state, base); -} +#define to_vc4_plane_state(_state) \ + container_of_const(_state, struct vc4_plane_state, base) enum vc4_encoder_type { VC4_ENCODER_TYPE_NONE, @@ -489,11 +471,8 @@ struct vc4_encoder { void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state); }; -static inline struct vc4_encoder * -to_vc4_encoder(const struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_encoder, base); -} +#define to_vc4_encoder(_encoder) \ + container_of_const(_encoder, struct vc4_encoder, base) static inline struct drm_encoder *vc4_find_encoder_by_type(struct drm_device *drm, @@ -591,11 +570,8 @@ struct vc4_crtc { unsigned int current_hvs_channel; }; -static inline struct vc4_crtc * -to_vc4_crtc(const struct drm_crtc *crtc) -{ - return container_of(crtc, struct vc4_crtc, base); -} +#define to_vc4_crtc(_crtc) \ + container_of_const(_crtc, struct vc4_crtc, base) static inline const struct vc4_crtc_data * vc4_crtc_to_vc4_crtc_data(const struct vc4_crtc *crtc) @@ -608,7 +584,7 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc) { const struct vc4_crtc_data *data = vc4_crtc_to_vc4_crtc_data(crtc); - return container_of(data, struct vc4_pv_data, base); + return container_of_const(data, struct vc4_pv_data, base); } struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, @@ -636,11 +612,8 @@ struct vc4_crtc_state { #define VC4_HVS_CHANNEL_DISABLED ((unsigned int)-1) -static inline struct vc4_crtc_state * -to_vc4_crtc_state(const struct drm_crtc_state *crtc_state) -{ - return container_of(crtc_state, struct vc4_crtc_state, base); -} +#define to_vc4_crtc_state(_state) \ + container_of_const(_state, struct vc4_crtc_state, base) #define V3D_READ(offset) \ ({ \ diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index a5c075f802e4..9e0c355b236f 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -600,19 +600,14 @@ struct vc4_dsi { struct debugfs_regset32 regset; }; -#define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host) +#define host_to_dsi(host) \ + container_of_const(host, struct vc4_dsi, dsi_host) -static inline struct vc4_dsi * -to_vc4_dsi(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_dsi, encoder.base); -} +#define to_vc4_dsi(_encoder) \ + container_of_const(_encoder, struct vc4_dsi, encoder.base) -static inline struct vc4_dsi * -bridge_to_vc4_dsi(struct drm_bridge *bridge) -{ - return container_of(bridge, struct vc4_dsi, bridge); -} +#define bridge_to_vc4_dsi(_bridge) \ + container_of_const(_bridge, struct vc4_dsi, bridge) static inline void dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 06713d8b82b5..6da41ea1250a 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -153,11 +153,17 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode, return clock > HDMI_14_MAX_TMDS_CLK; } -static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, - const struct drm_display_mode *mode) +static bool vc4_hdmi_is_full_range(struct vc4_hdmi *vc4_hdmi, + struct vc4_hdmi_connector_state *vc4_state) { + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct drm_display_info *display = &vc4_hdmi->connector.display_info; + if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED) + return false; + else if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL) + return true; + return !display->is_hdmi || drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; } @@ -528,14 +534,45 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, { struct drm_connector_state *old_state = drm_atomic_get_old_connector_state(state, connector); + struct vc4_hdmi_connector_state *old_vc4_state = + conn_state_to_vc4_hdmi_conn_state(old_state); struct drm_connector_state *new_state = drm_atomic_get_new_connector_state(state, connector); + struct vc4_hdmi_connector_state *new_vc4_state = + conn_state_to_vc4_hdmi_conn_state(new_state); struct drm_crtc *crtc = new_state->crtc; if (!crtc) return 0; + if (old_state->tv.margins.left != new_state->tv.margins.left || + old_state->tv.margins.right != new_state->tv.margins.right || + old_state->tv.margins.top != new_state->tv.margins.top || + old_state->tv.margins.bottom != new_state->tv.margins.bottom) { + struct drm_crtc_state *crtc_state; + int ret; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + /* + * Strictly speaking, we should be calling + * drm_atomic_helper_check_planes() after our call to + * drm_atomic_add_affected_planes(). However, the + * connector atomic_check is called as part of + * drm_atomic_helper_check_modeset() that already + * happens before a call to + * drm_atomic_helper_check_planes() in + * drm_atomic_helper_check(). + */ + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + } + if (old_state->colorspace != new_state->colorspace || + old_vc4_state->broadcast_rgb != new_vc4_state->broadcast_rgb || !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { struct drm_crtc_state *crtc_state; @@ -549,6 +586,49 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, return 0; } +static int vc4_hdmi_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct drm_device *drm = connector->dev; + struct vc4_hdmi *vc4_hdmi = + connector_to_vc4_hdmi(connector); + const struct vc4_hdmi_connector_state *vc4_conn_state = + conn_state_to_vc4_hdmi_conn_state(state); + + if (property == vc4_hdmi->broadcast_rgb_property) { + *val = vc4_conn_state->broadcast_rgb; + } else { + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); + return -EINVAL; + } + + return 0; +} + +static int vc4_hdmi_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *drm = connector->dev; + struct vc4_hdmi *vc4_hdmi = + connector_to_vc4_hdmi(connector); + struct vc4_hdmi_connector_state *vc4_conn_state = + conn_state_to_vc4_hdmi_conn_state(state); + + if (property == vc4_hdmi->broadcast_rgb_property) { + vc4_conn_state->broadcast_rgb = val; + return 0; + } + + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); + return -EINVAL; +} + static void vc4_hdmi_connector_reset(struct drm_connector *connector) { struct vc4_hdmi_connector_state *old_state = @@ -568,6 +648,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector) new_state->base.max_bpc = 8; new_state->base.max_requested_bpc = 8; new_state->output_format = VC4_HDMI_OUTPUT_RGB; + new_state->broadcast_rgb = VC4_HDMI_BROADCAST_RGB_AUTO; drm_atomic_helper_connector_tv_margins_reset(connector); } @@ -585,6 +666,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) new_state->tmds_char_rate = vc4_state->tmds_char_rate; new_state->output_bpc = vc4_state->output_bpc; new_state->output_format = vc4_state->output_format; + new_state->broadcast_rgb = vc4_state->broadcast_rgb; __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); return &new_state->base; @@ -595,6 +677,8 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { .reset = vc4_hdmi_connector_reset, .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_get_property = vc4_hdmi_connector_get_property, + .atomic_set_property = vc4_hdmi_connector_set_property, }; static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = { @@ -603,6 +687,33 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = .atomic_check = vc4_hdmi_connector_atomic_check, }; +static const struct drm_prop_enum_list broadcast_rgb_names[] = { + { VC4_HDMI_BROADCAST_RGB_AUTO, "Automatic" }, + { VC4_HDMI_BROADCAST_RGB_FULL, "Full" }, + { VC4_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235" }, +}; + +static void +vc4_hdmi_attach_broadcast_rgb_property(struct drm_device *dev, + struct vc4_hdmi *vc4_hdmi) +{ + struct drm_property *prop = vc4_hdmi->broadcast_rgb_property; + + if (!prop) { + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, + "Broadcast RGB", + broadcast_rgb_names, + ARRAY_SIZE(broadcast_rgb_names)); + if (!prop) + return; + + vc4_hdmi->broadcast_rgb_property = prop; + } + + drm_object_attach_property(&vc4_hdmi->connector.base, prop, + VC4_HDMI_BROADCAST_RGB_AUTO); +} + static int vc4_hdmi_connector_init(struct drm_device *dev, struct vc4_hdmi *vc4_hdmi) { @@ -649,6 +760,8 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, if (vc4_hdmi->variant->supports_hdr) drm_connector_attach_hdr_output_metadata_property(connector); + vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi); + drm_connector_attach_encoder(connector, encoder); return 0; @@ -803,7 +916,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) drm_hdmi_avi_infoframe_quant_range(&frame.avi, connector, mode, - vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ? + vc4_hdmi_is_full_range(vc4_hdmi, vc4_state) ? HDMI_QUANTIZATION_RANGE_FULL : HDMI_QUANTIZATION_RANGE_LIMITED); drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate); @@ -1046,6 +1159,8 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, const struct drm_display_mode *mode) { + struct vc4_hdmi_connector_state *vc4_state = + conn_state_to_vc4_hdmi_conn_state(state); struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; u32 csc_ctl; @@ -1059,7 +1174,7 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, VC4_HD_CSC_CTL_ORDER); - if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { + if (!vc4_hdmi_is_full_range(vc4_hdmi, vc4_state)) { /* CEA VICs other than #1 requre limited range RGB * output unless overridden by an AVI infoframe. * Apply a colorspace conversion to squash 0-255 down @@ -1092,68 +1207,134 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, } /* - * If we need to output Full Range RGB, then use the unity matrix - * - * [ 1 0 0 0] - * [ 0 1 0 0] - * [ 0 0 1 0] + * Matrices for (internal) RGB to RGB output. * - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets */ -static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = { - { 0x2000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x2000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x2000, 0x0000 }, +static const u16 vc5_hdmi_csc_full_rgb_to_rgb[2][3][4] = { + { + /* + * Full range - unity + * + * [ 1 0 0 0] + * [ 0 1 0 0] + * [ 0 0 1 0] + */ + { 0x2000, 0x0000, 0x0000, 0x0000 }, + { 0x0000, 0x2000, 0x0000, 0x0000 }, + { 0x0000, 0x0000, 0x2000, 0x0000 }, + }, + { + /* + * Limited range + * + * CEA VICs other than #1 require limited range RGB + * output unless overridden by an AVI infoframe. Apply a + * colorspace conversion to squash 0-255 down to 16-235. + * The matrix here is: + * + * [ 0.8594 0 0 16] + * [ 0 0.8594 0 16] + * [ 0 0 0.8594 16] + */ + { 0x1b80, 0x0000, 0x0000, 0x0400 }, + { 0x0000, 0x1b80, 0x0000, 0x0400 }, + { 0x0000, 0x0000, 0x1b80, 0x0400 }, + }, }; /* - * CEA VICs other than #1 require limited range RGB output unless - * overridden by an AVI infoframe. Apply a colorspace conversion to - * squash 0-255 down to 16-235. The matrix here is: - * - * [ 0.8594 0 0 16] - * [ 0 0.8594 0 16] - * [ 0 0 0.8594 16] + * Conversion between Full Range RGB and YUV using the BT.601 Colorspace * - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets */ -static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = { - { 0x1b80, 0x0000, 0x0000, 0x0400 }, - { 0x0000, 0x1b80, 0x0000, 0x0400 }, - { 0x0000, 0x0000, 0x1b80, 0x0400 }, +static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt601[2][3][4] = { + { + /* + * Full Range + * + * [ 0.299000 0.587000 0.114000 0 ] + * [ -0.168736 -0.331264 0.500000 128 ] + * [ 0.500000 -0.418688 -0.081312 128 ] + */ + { 0x0991, 0x12c9, 0x03a6, 0x0000 }, + { 0xfa9b, 0xf567, 0x1000, 0x2000 }, + { 0x1000, 0xf29b, 0xfd67, 0x2000 }, + }, + { + /* Limited Range + * + * [ 0.255785 0.502160 0.097523 16 ] + * [ -0.147644 -0.289856 0.437500 128 ] + * [ 0.437500 -0.366352 -0.071148 128 ] + */ + { 0x082f, 0x1012, 0x031f, 0x0400 }, + { 0xfb48, 0xf6ba, 0x0e00, 0x2000 }, + { 0x0e00, 0xf448, 0xfdba, 0x2000 }, + }, }; /* - * Conversion between Full Range RGB and Full Range YUV422 using the - * BT.709 Colorspace + * Conversion between Full Range RGB and YUV using the BT.709 Colorspace * - * - * [ 0.181906 0.611804 0.061758 16 ] - * [ -0.100268 -0.337232 0.437500 128 ] - * [ 0.437500 -0.397386 -0.040114 128 ] - * - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets */ -static const u16 vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709[3][4] = { - { 0x05d2, 0x1394, 0x01fa, 0x0400 }, - { 0xfccc, 0xf536, 0x0e00, 0x2000 }, - { 0x0e00, 0xf34a, 0xfeb8, 0x2000 }, +static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt709[2][3][4] = { + { + /* + * Full Range + * + * [ 0.212600 0.715200 0.072200 0 ] + * [ -0.114572 -0.385428 0.500000 128 ] + * [ 0.500000 -0.454153 -0.045847 128 ] + */ + { 0x06ce, 0x16e3, 0x024f, 0x0000 }, + { 0xfc56, 0xf3ac, 0x1000, 0x2000 }, + { 0x1000, 0xf179, 0xfe89, 0x2000 }, + }, + { + /* + * Limited Range + * + * [ 0.181906 0.611804 0.061758 16 ] + * [ -0.100268 -0.337232 0.437500 128 ] + * [ 0.437500 -0.397386 -0.040114 128 ] + */ + { 0x05d2, 0x1394, 0x01fa, 0x0400 }, + { 0xfccc, 0xf536, 0x0e00, 0x2000 }, + { 0x0e00, 0xf34a, 0xfeb8, 0x2000 }, + }, }; /* - * Conversion between Full Range RGB and Full Range YUV444 using the - * BT.709 Colorspace + * Conversion between Full Range RGB and YUV using the BT.2020 Colorspace * - * [ -0.100268 -0.337232 0.437500 128 ] - * [ 0.437500 -0.397386 -0.040114 128 ] - * [ 0.181906 0.611804 0.061758 16 ] - * - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets */ -static const u16 vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709[3][4] = { - { 0xfccc, 0xf536, 0x0e00, 0x2000 }, - { 0x0e00, 0xf34a, 0xfeb8, 0x2000 }, - { 0x05d2, 0x1394, 0x01fa, 0x0400 }, +static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt2020[2][3][4] = { + { + /* + * Full Range + * + * [ 0.262700 0.678000 0.059300 0 ] + * [ -0.139630 -0.360370 0.500000 128 ] + * [ 0.500000 -0.459786 -0.040214 128 ] + */ + { 0x0868, 0x15b2, 0x01e6, 0x0000 }, + { 0xfb89, 0xf479, 0x1000, 0x2000 }, + { 0x1000, 0xf14a, 0xfeb8, 0x2000 }, + }, + { + /* Limited Range + * + * [ 0.224732 0.580008 0.050729 16 ] + * [ -0.122176 -0.315324 0.437500 128 ] + * [ 0.437500 -0.402312 -0.035188 128 ] + */ + { 0x082f, 0x1012, 0x031f, 0x0400 }, + { 0xfb48, 0xf6ba, 0x0e00, 0x2000 }, + { 0x0e00, 0xf448, 0xfdba, 0x2000 }, + }, }; static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, @@ -1169,6 +1350,48 @@ static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_CSC_34_33, (coeffs[2][3] << 16) | coeffs[2][2]); } +static void vc5_hdmi_set_csc_coeffs_swap(struct vc4_hdmi *vc4_hdmi, + const u16 coeffs[3][4]) +{ + lockdep_assert_held(&vc4_hdmi->hw_lock); + + /* YUV444 needs the CSC matrices using the channels in a different order */ + HDMI_WRITE(HDMI_CSC_12_11, (coeffs[1][1] << 16) | coeffs[1][0]); + HDMI_WRITE(HDMI_CSC_14_13, (coeffs[1][3] << 16) | coeffs[1][2]); + HDMI_WRITE(HDMI_CSC_22_21, (coeffs[2][1] << 16) | coeffs[2][0]); + HDMI_WRITE(HDMI_CSC_24_23, (coeffs[2][3] << 16) | coeffs[2][2]); + HDMI_WRITE(HDMI_CSC_32_31, (coeffs[0][1] << 16) | coeffs[0][0]); + HDMI_WRITE(HDMI_CSC_34_33, (coeffs[0][3] << 16) | coeffs[0][2]); +} + +static const u16 +(*vc5_hdmi_find_yuv_csc_coeffs(struct vc4_hdmi *vc4_hdmi, u32 colorspace, bool limited))[4] +{ + switch (colorspace) { + case DRM_MODE_COLORIMETRY_SMPTE_170M_YCC: + case DRM_MODE_COLORIMETRY_XVYCC_601: + case DRM_MODE_COLORIMETRY_SYCC_601: + case DRM_MODE_COLORIMETRY_OPYCC_601: + case DRM_MODE_COLORIMETRY_BT601_YCC: + return vc5_hdmi_csc_full_rgb_to_yuv_bt601[limited]; + + default: + case DRM_MODE_COLORIMETRY_NO_DATA: + case DRM_MODE_COLORIMETRY_BT709_YCC: + case DRM_MODE_COLORIMETRY_XVYCC_709: + case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED: + case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT: + return vc5_hdmi_csc_full_rgb_to_yuv_bt709[limited]; + + case DRM_MODE_COLORIMETRY_BT2020_CYCC: + case DRM_MODE_COLORIMETRY_BT2020_YCC: + case DRM_MODE_COLORIMETRY_BT2020_RGB: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER: + return vc5_hdmi_csc_full_rgb_to_yuv_bt2020[limited]; + } +} + static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, const struct drm_display_mode *mode) @@ -1176,7 +1399,9 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_device *drm = vc4_hdmi->connector.dev; struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(state); + unsigned int lim_range = vc4_hdmi_is_full_range(vc4_hdmi, vc4_state) ? 0 : 1; unsigned long flags; + const u16 (*csc)[4]; u32 if_cfg = 0; u32 if_xbar = 0x543210; u32 csc_chan_ctl = 0; @@ -1191,10 +1416,14 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, switch (vc4_state->output_format) { case VC4_HDMI_OUTPUT_YUV444: - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709); + csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range); + + vc5_hdmi_set_csc_coeffs_swap(vc4_hdmi, csc); break; case VC4_HDMI_OUTPUT_YUV422: + csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range); + csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD, VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) | VC5_MT_CP_CSC_CTL_USE_444_TO_422 | @@ -1206,16 +1435,13 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY, VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422); - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709); + vc5_hdmi_set_csc_coeffs(vc4_hdmi, csc); break; case VC4_HDMI_OUTPUT_RGB: if_xbar = 0x354021; - if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb); - else - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity); + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_rgb[lim_range]); break; default: diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index e3619836ca17..934d5d61485a 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -117,6 +117,12 @@ enum vc4_hdmi_output_format { VC4_HDMI_OUTPUT_YUV420, }; +enum vc4_hdmi_broadcast_rgb { + VC4_HDMI_BROADCAST_RGB_AUTO, + VC4_HDMI_BROADCAST_RGB_FULL, + VC4_HDMI_BROADCAST_RGB_LIMITED, +}; + /* General HDMI hardware state. */ struct vc4_hdmi { struct vc4_hdmi_audio audio; @@ -129,6 +135,8 @@ struct vc4_hdmi { struct delayed_work scrambling_work; + struct drm_property *broadcast_rgb_property; + struct i2c_adapter *ddc; void __iomem *hdmicore_regs; void __iomem *hd_regs; @@ -222,17 +230,14 @@ struct vc4_hdmi { enum vc4_hdmi_output_format output_format; }; -static inline struct vc4_hdmi * -connector_to_vc4_hdmi(struct drm_connector *connector) -{ - return container_of(connector, struct vc4_hdmi, connector); -} +#define connector_to_vc4_hdmi(_connector) \ + container_of_const(_connector, struct vc4_hdmi, connector) static inline struct vc4_hdmi * encoder_to_vc4_hdmi(struct drm_encoder *encoder) { struct vc4_encoder *_encoder = to_vc4_encoder(encoder); - return container_of(_encoder, struct vc4_hdmi, encoder); + return container_of_const(_encoder, struct vc4_hdmi, encoder); } struct vc4_hdmi_connector_state { @@ -240,13 +245,11 @@ struct vc4_hdmi_connector_state { unsigned long long tmds_char_rate; unsigned int output_bpc; enum vc4_hdmi_output_format output_format; + enum vc4_hdmi_broadcast_rgb broadcast_rgb; }; -static inline struct vc4_hdmi_connector_state * -conn_state_to_vc4_hdmi_conn_state(struct drm_connector_state *conn_state) -{ - return container_of(conn_state, struct vc4_hdmi_connector_state, base); -} +#define conn_state_to_vc4_hdmi_conn_state(_state) \ + container_of_const(_state, struct vc4_hdmi_connector_state, base) void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct vc4_hdmi_connector_state *vc4_conn_state); diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index 1e6db0121ccd..563b3dfeb9b9 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -57,8 +57,6 @@ V3D_INT_FLDONE | \ V3D_INT_FRDONE) -DECLARE_WAIT_QUEUE_HEAD(render_wait); - static void vc4_overflow_mem_work(struct work_struct *work) { diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index a7e3d47c50f4..5495f2a94fa9 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -31,11 +31,8 @@ struct vc4_ctm_state { int fifo; }; -static struct vc4_ctm_state * -to_vc4_ctm_state(const struct drm_private_state *priv) -{ - return container_of(priv, struct vc4_ctm_state, base); -} +#define to_vc4_ctm_state(_state) \ + container_of_const(_state, struct vc4_ctm_state, base) struct vc4_load_tracker_state { struct drm_private_state base; @@ -43,11 +40,8 @@ struct vc4_load_tracker_state { u64 membus_load; }; -static struct vc4_load_tracker_state * -to_vc4_load_tracker_state(const struct drm_private_state *priv) -{ - return container_of(priv, struct vc4_load_tracker_state, base); -} +#define to_vc4_load_tracker_state(_state) \ + container_of_const(_state, struct vc4_load_tracker_state, base) static struct vc4_ctm_state *vc4_get_ctm_state(struct drm_atomic_state *state, struct drm_private_obj *manager) @@ -717,7 +711,7 @@ static void vc4_hvs_channels_destroy_state(struct drm_private_obj *obj, static void vc4_hvs_channels_print_state(struct drm_printer *p, const struct drm_private_state *state) { - struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state); + const struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state); unsigned int i; drm_printf(p, "HVS State\n"); diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 97c84a3f5a46..00e713faecd5 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1334,8 +1334,7 @@ out: u32 vc4_plane_dlist_size(const struct drm_plane_state *state) { - const struct vc4_plane_state *vc4_state = - container_of(state, typeof(*vc4_state), base); + const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); return vc4_state->dlist_count; } diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index ef5cab2a3aa9..c5abdec03103 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -168,15 +168,11 @@ struct vc4_txp { void __iomem *regs; }; -static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_txp, encoder.base); -} +#define encoder_to_vc4_txp(_encoder) \ + container_of_const(_encoder, struct vc4_txp, encoder.base) -static inline struct vc4_txp *connector_to_vc4_txp(struct drm_connector *conn) -{ - return container_of(conn, struct vc4_txp, connector.base); -} +#define connector_to_vc4_txp(_connector) \ + container_of_const(_connector, struct vc4_txp, connector.base) static const struct debugfs_reg32 txp_regs[] = { VC4_REG32(TXP_DST_PTR), diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index a3782d05cd66..d6e6a1a22eba 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -219,17 +219,11 @@ struct vc4_vec { writel(val, vec->regs + (offset)); \ } while (0) -static inline struct vc4_vec * -encoder_to_vc4_vec(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_vec, encoder.base); -} +#define encoder_to_vc4_vec(_encoder) \ + container_of_const(_encoder, struct vc4_vec, encoder.base) -static inline struct vc4_vec * -connector_to_vc4_vec(struct drm_connector *connector) -{ - return container_of(connector, struct vc4_vec, connector); -} +#define connector_to_vc4_vec(_connector) \ + container_of_const(_connector, struct vc4_vec, connector) enum vc4_vec_tv_mode_id { VC4_VEC_TV_MODE_NTSC, diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 8e53fa80742b..906d3df40cdb 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -4,6 +4,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_vblank.h> @@ -53,10 +54,30 @@ static void pre_mul_alpha_blend(struct vkms_frame_info *frame_info, } } -static bool check_y_limit(struct vkms_frame_info *frame_info, int y) +static int get_y_pos(struct vkms_frame_info *frame_info, int y) { - if (y >= frame_info->dst.y1 && y < frame_info->dst.y2) - return true; + if (frame_info->rotation & DRM_MODE_REFLECT_Y) + return drm_rect_height(&frame_info->rotated) - y - 1; + + switch (frame_info->rotation & DRM_MODE_ROTATE_MASK) { + case DRM_MODE_ROTATE_90: + return frame_info->rotated.x2 - y - 1; + case DRM_MODE_ROTATE_270: + return y + frame_info->rotated.x1; + default: + return y; + } +} + +static bool check_limit(struct vkms_frame_info *frame_info, int pos) +{ + if (drm_rotation_90_or_270(frame_info->rotation)) { + if (pos >= 0 && pos < drm_rect_width(&frame_info->rotated)) + return true; + } else { + if (pos >= frame_info->rotated.y1 && pos < frame_info->rotated.y2) + return true; + } return false; } @@ -86,6 +107,7 @@ static void blend(struct vkms_writeback_job *wb, { struct vkms_plane_state **plane = crtc_state->active_planes; u32 n_active_planes = crtc_state->num_active_planes; + int y_pos; const struct pixel_argb_u16 background_color = { .a = 0xffff }; @@ -96,10 +118,12 @@ static void blend(struct vkms_writeback_job *wb, /* The active planes are composed associatively in z-order. */ for (size_t i = 0; i < n_active_planes; i++) { - if (!check_y_limit(plane[i]->frame_info, y)) + y_pos = get_y_pos(plane[i]->frame_info, y); + + if (!check_limit(plane[i]->frame_info, y_pos)) continue; - plane[i]->plane_read(stage_buffer, plane[i]->frame_info, y); + vkms_compose_row(stage_buffer, plane[i], y_pos); pre_mul_alpha_blend(plane[i]->frame_info, stage_buffer, output_buffer); } @@ -107,7 +131,7 @@ static void blend(struct vkms_writeback_job *wb, *crc32 = crc32_le(*crc32, (void *)output_buffer->pixels, row_size); if (wb) - wb->wb_write(&wb->wb_frame_info, output_buffer, y); + wb->wb_write(&wb->wb_frame_info, output_buffer, y_pos); } } @@ -118,7 +142,7 @@ static int check_format_funcs(struct vkms_crtc_state *crtc_state, u32 n_active_planes = crtc_state->num_active_planes; for (size_t i = 0; i < n_active_planes; i++) - if (!planes[i]->plane_read) + if (!planes[i]->pixel_read) return -1; if (active_wb && !active_wb->wb_write) diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index 57bbd32e9beb..515f6772b866 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -161,7 +161,6 @@ static void vkms_atomic_crtc_reset(struct drm_crtc *crtc) static const struct drm_crtc_funcs vkms_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = drm_crtc_cleanup, .page_flip = drm_atomic_helper_page_flip, .reset = vkms_atomic_crtc_reset, .atomic_duplicate_state = vkms_atomic_crtc_duplicate_state, @@ -282,8 +281,8 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, struct vkms_output *vkms_out = drm_crtc_to_vkms_output(crtc); int ret; - ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor, - &vkms_crtc_funcs, NULL); + ret = drmm_crtc_init_with_planes(dev, crtc, primary, cursor, + &vkms_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to init CRTC\n"); return ret; diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 6d3a2d57d992..e3c9c9571c8d 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -133,8 +133,12 @@ static const struct drm_mode_config_helper_funcs vkms_mode_config_helpers = { static int vkms_modeset_init(struct vkms_device *vkmsdev) { struct drm_device *dev = &vkmsdev->drm; + int ret; + + ret = drmm_mode_config_init(dev); + if (ret) + return ret; - drm_mode_config_init(dev); dev->mode_config.funcs = &vkms_mode_funcs; dev->mode_config.min_width = XRES_MIN; dev->mode_config.min_height = YRES_MIN; diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 4a248567efb2..5f1a0a44a78c 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -26,7 +26,9 @@ struct vkms_frame_info { struct drm_framebuffer *fb; struct drm_rect src, dst; + struct drm_rect rotated; struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + unsigned int rotation; unsigned int offset; unsigned int pitch; unsigned int cpp; @@ -56,8 +58,7 @@ struct vkms_writeback_job { struct vkms_plane_state { struct drm_shadow_plane_state base; struct vkms_frame_info *frame_info; - void (*plane_read)(struct line_buffer *buffer, - const struct vkms_frame_info *frame_info, int y); + void (*pixel_read)(u8 *src_buffer, struct pixel_argb_u16 *out_pixel); }; struct vkms_plane { @@ -155,6 +156,7 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *source_name, /* Composer Support */ void vkms_composer_worker(struct work_struct *work); void vkms_set_composer(struct vkms_output *out, bool enabled); +void vkms_compose_row(struct line_buffer *stage_buffer, struct vkms_plane_state *plane, int y); /* Writeback */ int vkms_enable_writeback_connector(struct vkms_device *vkmsdev); diff --git a/drivers/gpu/drm/vkms/vkms_formats.c b/drivers/gpu/drm/vkms/vkms_formats.c index d4950688b3f1..5945da0beba6 100644 --- a/drivers/gpu/drm/vkms/vkms_formats.c +++ b/drivers/gpu/drm/vkms/vkms_formats.c @@ -2,6 +2,8 @@ #include <linux/kernel.h> #include <linux/minmax.h> + +#include <drm/drm_blend.h> #include <drm/drm_rect.h> #include <drm/drm_fixed.h> @@ -37,104 +39,93 @@ static void *packed_pixels_addr(const struct vkms_frame_info *frame_info, static void *get_packed_src_addr(const struct vkms_frame_info *frame_info, int y) { int x_src = frame_info->src.x1 >> 16; - int y_src = y - frame_info->dst.y1 + (frame_info->src.y1 >> 16); + int y_src = y - frame_info->rotated.y1 + (frame_info->src.y1 >> 16); return packed_pixels_addr(frame_info, x_src, y_src); } -static void ARGB8888_to_argb_u16(struct line_buffer *stage_buffer, - const struct vkms_frame_info *frame_info, int y) +static int get_x_position(const struct vkms_frame_info *frame_info, int limit, int x) { - struct pixel_argb_u16 *out_pixels = stage_buffer->pixels; - u8 *src_pixels = get_packed_src_addr(frame_info, y); - int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), - stage_buffer->n_pixels); - - for (size_t x = 0; x < x_limit; x++, src_pixels += 4) { - /* - * The 257 is the "conversion ratio". This number is obtained by the - * (2^16 - 1) / (2^8 - 1) division. Which, in this case, tries to get - * the best color value in a pixel format with more possibilities. - * A similar idea applies to others RGB color conversions. - */ - out_pixels[x].a = (u16)src_pixels[3] * 257; - out_pixels[x].r = (u16)src_pixels[2] * 257; - out_pixels[x].g = (u16)src_pixels[1] * 257; - out_pixels[x].b = (u16)src_pixels[0] * 257; - } + if (frame_info->rotation & (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270)) + return limit - x - 1; + return x; } -static void XRGB8888_to_argb_u16(struct line_buffer *stage_buffer, - const struct vkms_frame_info *frame_info, int y) +static void ARGB8888_to_argb_u16(u8 *src_pixels, struct pixel_argb_u16 *out_pixel) { - struct pixel_argb_u16 *out_pixels = stage_buffer->pixels; - u8 *src_pixels = get_packed_src_addr(frame_info, y); - int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), - stage_buffer->n_pixels); + /* + * The 257 is the "conversion ratio". This number is obtained by the + * (2^16 - 1) / (2^8 - 1) division. Which, in this case, tries to get + * the best color value in a pixel format with more possibilities. + * A similar idea applies to others RGB color conversions. + */ + out_pixel->a = (u16)src_pixels[3] * 257; + out_pixel->r = (u16)src_pixels[2] * 257; + out_pixel->g = (u16)src_pixels[1] * 257; + out_pixel->b = (u16)src_pixels[0] * 257; +} - for (size_t x = 0; x < x_limit; x++, src_pixels += 4) { - out_pixels[x].a = (u16)0xffff; - out_pixels[x].r = (u16)src_pixels[2] * 257; - out_pixels[x].g = (u16)src_pixels[1] * 257; - out_pixels[x].b = (u16)src_pixels[0] * 257; - } +static void XRGB8888_to_argb_u16(u8 *src_pixels, struct pixel_argb_u16 *out_pixel) +{ + out_pixel->a = (u16)0xffff; + out_pixel->r = (u16)src_pixels[2] * 257; + out_pixel->g = (u16)src_pixels[1] * 257; + out_pixel->b = (u16)src_pixels[0] * 257; } -static void ARGB16161616_to_argb_u16(struct line_buffer *stage_buffer, - const struct vkms_frame_info *frame_info, - int y) +static void ARGB16161616_to_argb_u16(u8 *src_pixels, struct pixel_argb_u16 *out_pixel) { - struct pixel_argb_u16 *out_pixels = stage_buffer->pixels; - u16 *src_pixels = get_packed_src_addr(frame_info, y); - int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), - stage_buffer->n_pixels); + u16 *pixels = (u16 *)src_pixels; - for (size_t x = 0; x < x_limit; x++, src_pixels += 4) { - out_pixels[x].a = le16_to_cpu(src_pixels[3]); - out_pixels[x].r = le16_to_cpu(src_pixels[2]); - out_pixels[x].g = le16_to_cpu(src_pixels[1]); - out_pixels[x].b = le16_to_cpu(src_pixels[0]); - } + out_pixel->a = le16_to_cpu(pixels[3]); + out_pixel->r = le16_to_cpu(pixels[2]); + out_pixel->g = le16_to_cpu(pixels[1]); + out_pixel->b = le16_to_cpu(pixels[0]); } -static void XRGB16161616_to_argb_u16(struct line_buffer *stage_buffer, - const struct vkms_frame_info *frame_info, - int y) +static void XRGB16161616_to_argb_u16(u8 *src_pixels, struct pixel_argb_u16 *out_pixel) { - struct pixel_argb_u16 *out_pixels = stage_buffer->pixels; - u16 *src_pixels = get_packed_src_addr(frame_info, y); - int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), - stage_buffer->n_pixels); + u16 *pixels = (u16 *)src_pixels; - for (size_t x = 0; x < x_limit; x++, src_pixels += 4) { - out_pixels[x].a = (u16)0xffff; - out_pixels[x].r = le16_to_cpu(src_pixels[2]); - out_pixels[x].g = le16_to_cpu(src_pixels[1]); - out_pixels[x].b = le16_to_cpu(src_pixels[0]); - } + out_pixel->a = (u16)0xffff; + out_pixel->r = le16_to_cpu(pixels[2]); + out_pixel->g = le16_to_cpu(pixels[1]); + out_pixel->b = le16_to_cpu(pixels[0]); } -static void RGB565_to_argb_u16(struct line_buffer *stage_buffer, - const struct vkms_frame_info *frame_info, int y) +static void RGB565_to_argb_u16(u8 *src_pixels, struct pixel_argb_u16 *out_pixel) { - struct pixel_argb_u16 *out_pixels = stage_buffer->pixels; - u16 *src_pixels = get_packed_src_addr(frame_info, y); - int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), - stage_buffer->n_pixels); + u16 *pixels = (u16 *)src_pixels; s64 fp_rb_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(31)); s64 fp_g_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(63)); - for (size_t x = 0; x < x_limit; x++, src_pixels++) { - u16 rgb_565 = le16_to_cpu(*src_pixels); - s64 fp_r = drm_int2fixp((rgb_565 >> 11) & 0x1f); - s64 fp_g = drm_int2fixp((rgb_565 >> 5) & 0x3f); - s64 fp_b = drm_int2fixp(rgb_565 & 0x1f); + u16 rgb_565 = le16_to_cpu(*pixels); + s64 fp_r = drm_int2fixp((rgb_565 >> 11) & 0x1f); + s64 fp_g = drm_int2fixp((rgb_565 >> 5) & 0x3f); + s64 fp_b = drm_int2fixp(rgb_565 & 0x1f); + + out_pixel->a = (u16)0xffff; + out_pixel->r = drm_fixp2int_round(drm_fixp_mul(fp_r, fp_rb_ratio)); + out_pixel->g = drm_fixp2int_round(drm_fixp_mul(fp_g, fp_g_ratio)); + out_pixel->b = drm_fixp2int_round(drm_fixp_mul(fp_b, fp_rb_ratio)); +} + +void vkms_compose_row(struct line_buffer *stage_buffer, struct vkms_plane_state *plane, int y) +{ + struct pixel_argb_u16 *out_pixels = stage_buffer->pixels; + struct vkms_frame_info *frame_info = plane->frame_info; + u8 *src_pixels = get_packed_src_addr(frame_info, y); + int limit = min_t(size_t, drm_rect_width(&frame_info->dst), stage_buffer->n_pixels); + + for (size_t x = 0; x < limit; x++, src_pixels += frame_info->cpp) { + int x_pos = get_x_position(frame_info, limit, x); + + if (drm_rotation_90_or_270(frame_info->rotation)) + src_pixels = get_packed_src_addr(frame_info, x + frame_info->rotated.y1) + + frame_info->cpp * y; - out_pixels[x].a = (u16)0xffff; - out_pixels[x].r = drm_fixp2int(drm_fixp_mul(fp_r, fp_rb_ratio)); - out_pixels[x].g = drm_fixp2int(drm_fixp_mul(fp_g, fp_g_ratio)); - out_pixels[x].b = drm_fixp2int(drm_fixp_mul(fp_b, fp_rb_ratio)); + plane->pixel_read(src_pixels, &out_pixels[x_pos]); } } @@ -241,15 +232,15 @@ static void argb_u16_to_RGB565(struct vkms_frame_info *frame_info, s64 fp_g = drm_int2fixp(in_pixels[x].g); s64 fp_b = drm_int2fixp(in_pixels[x].b); - u16 r = drm_fixp2int(drm_fixp_div(fp_r, fp_rb_ratio)); - u16 g = drm_fixp2int(drm_fixp_div(fp_g, fp_g_ratio)); - u16 b = drm_fixp2int(drm_fixp_div(fp_b, fp_rb_ratio)); + u16 r = drm_fixp2int_round(drm_fixp_div(fp_r, fp_rb_ratio)); + u16 g = drm_fixp2int_round(drm_fixp_div(fp_g, fp_g_ratio)); + u16 b = drm_fixp2int_round(drm_fixp_div(fp_b, fp_rb_ratio)); *dst_pixels = cpu_to_le16(r << 11 | g << 5 | b); } } -void *get_frame_to_line_function(u32 format) +void *get_pixel_conversion_function(u32 format) { switch (format) { case DRM_FORMAT_ARGB8888: diff --git a/drivers/gpu/drm/vkms/vkms_formats.h b/drivers/gpu/drm/vkms/vkms_formats.h index 43b7c1979018..c5b113495d0c 100644 --- a/drivers/gpu/drm/vkms/vkms_formats.h +++ b/drivers/gpu/drm/vkms/vkms_formats.h @@ -5,7 +5,7 @@ #include "vkms_drv.h" -void *get_frame_to_line_function(u32 format); +void *get_pixel_conversion_function(u32 format); void *get_line_to_frame_function(u32 format); diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index 991857125bb4..5ce70dd946aa 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -4,21 +4,19 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_edid.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> - -static void vkms_connector_destroy(struct drm_connector *connector) -{ - drm_connector_cleanup(connector); -} static const struct drm_connector_funcs vkms_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vkms_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; +static const struct drm_encoder_funcs vkms_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + static int vkms_conn_get_modes(struct drm_connector *connector) { int count; @@ -91,7 +89,8 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) drm_connector_helper_add(connector, &vkms_conn_helper_funcs); - ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_VIRTUAL); + ret = drm_encoder_init(dev, encoder, &vkms_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL, NULL); if (ret) { DRM_ERROR("Failed to init encoder\n"); goto err_encoder; diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index b3f8a115cc23..e5c625ab8e3e 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -4,6 +4,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> @@ -12,12 +13,6 @@ #include "vkms_formats.h" static const u32 vkms_formats[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XRGB16161616, - DRM_FORMAT_RGB565 -}; - -static const u32 vkms_plane_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XRGB16161616, @@ -117,13 +112,23 @@ static void vkms_plane_atomic_update(struct drm_plane *plane, frame_info = vkms_plane_state->frame_info; memcpy(&frame_info->src, &new_state->src, sizeof(struct drm_rect)); memcpy(&frame_info->dst, &new_state->dst, sizeof(struct drm_rect)); + memcpy(&frame_info->rotated, &new_state->dst, sizeof(struct drm_rect)); frame_info->fb = fb; memcpy(&frame_info->map, &shadow_plane_state->data, sizeof(frame_info->map)); drm_framebuffer_get(frame_info->fb); + frame_info->rotation = drm_rotation_simplify(new_state->rotation, DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_270 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y); + + drm_rect_rotate(&frame_info->rotated, drm_rect_width(&frame_info->rotated), + drm_rect_height(&frame_info->rotated), frame_info->rotation); + frame_info->offset = fb->offsets[0]; frame_info->pitch = fb->pitches[0]; frame_info->cpp = fb->format->cpp[0]; - vkms_plane_state->plane_read = get_frame_to_line_function(fmt); + vkms_plane_state->pixel_read = get_pixel_conversion_function(fmt); } static int vkms_plane_atomic_check(struct drm_plane *plane, @@ -132,7 +137,6 @@ static int vkms_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); struct drm_crtc_state *crtc_state; - bool can_position = false; int ret; if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) @@ -143,20 +147,13 @@ static int vkms_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (plane->type != DRM_PLANE_TYPE_PRIMARY) - can_position = true; - ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, DRM_PLANE_NO_SCALING, DRM_PLANE_NO_SCALING, - can_position, true); + true, true); if (ret != 0) return ret; - /* for now primary plane must be visible and full screen */ - if (!new_plane_state->visible && !can_position) - return -EINVAL; - return 0; } @@ -193,7 +190,7 @@ static void vkms_cleanup_fb(struct drm_plane *plane, drm_gem_fb_vunmap(fb, shadow_plane_state->map); } -static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { +static const struct drm_plane_helper_funcs vkms_plane_helper_funcs = { .atomic_update = vkms_plane_atomic_update, .atomic_check = vkms_plane_atomic_check, .prepare_fb = vkms_prepare_fb, @@ -204,38 +201,19 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, enum drm_plane_type type, int index) { struct drm_device *dev = &vkmsdev->drm; - const struct drm_plane_helper_funcs *funcs; struct vkms_plane *plane; - const u32 *formats; - int nformats; - - switch (type) { - case DRM_PLANE_TYPE_PRIMARY: - formats = vkms_formats; - nformats = ARRAY_SIZE(vkms_formats); - funcs = &vkms_primary_helper_funcs; - break; - case DRM_PLANE_TYPE_CURSOR: - case DRM_PLANE_TYPE_OVERLAY: - formats = vkms_plane_formats; - nformats = ARRAY_SIZE(vkms_plane_formats); - funcs = &vkms_primary_helper_funcs; - break; - default: - formats = vkms_formats; - nformats = ARRAY_SIZE(vkms_formats); - funcs = &vkms_primary_helper_funcs; - break; - } plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index, &vkms_plane_funcs, - formats, nformats, + vkms_formats, ARRAY_SIZE(vkms_formats), NULL, type, NULL); if (IS_ERR(plane)) return plane; - drm_plane_helper_add(&plane->base, funcs); + drm_plane_helper_add(&plane->base, &vkms_plane_helper_funcs); + + drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, + DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK); return plane; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 2588615a2a38..8b24ecf60e3e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -45,6 +45,9 @@ #include <drm/ttm/ttm_placement.h> #include <generated/utsrelease.h> +#ifdef CONFIG_X86 +#include <asm/hypervisor.h> +#endif #include <linux/cc_platform.h> #include <linux/dma-mapping.h> #include <linux/module.h> @@ -897,6 +900,16 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) cap2_names, ARRAY_SIZE(cap2_names)); } + if (!vmwgfx_supported(dev_priv)) { + vmw_disable_backdoor(); + drm_err_once(&dev_priv->drm, + "vmwgfx seems to be running on an unsupported hypervisor."); + drm_err_once(&dev_priv->drm, + "This configuration is likely broken."); + drm_err_once(&dev_priv->drm, + "Please switch to a supported graphics device to avoid problems."); + } + ret = vmw_dma_select_mode(dev_priv); if (unlikely(ret != 0)) { drm_info(&dev_priv->drm, @@ -1320,6 +1333,22 @@ static void vmw_master_drop(struct drm_device *dev, vmw_kms_legacy_hotspot_clear(dev_priv); } +bool vmwgfx_supported(struct vmw_private *vmw) +{ +#if defined(CONFIG_X86) + return hypervisor_is_type(X86_HYPER_VMWARE); +#elif defined(CONFIG_ARM64) + /* + * On aarch64 only svga3 is supported + */ + return vmw->pci_id == VMWGFX_PCI_ID_SVGA3; +#else + drm_warn_once(&vmw->drm, + "vmwgfx is running on an unknown architecture."); + return false; +#endif +} + /** * __vmw_svga_enable - Enable SVGA mode, FIFO and use of VRAM. * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index fb8f0c0642c0..3810a9984a7f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -773,6 +773,7 @@ static inline u32 vmw_max_num_uavs(struct vmw_private *dev_priv) extern void vmw_svga_enable(struct vmw_private *dev_priv); extern void vmw_svga_disable(struct vmw_private *dev_priv); +bool vmwgfx_supported(struct vmw_private *vmw); /** @@ -1358,6 +1359,7 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, struct vmw_diff_cpy *diff); /* Host messaging -vmwgfx_msg.c: */ +void vmw_disable_backdoor(void); int vmw_host_get_guestinfo(const char *guest_info_param, char *buffer, size_t *length); __printf(1, 2) int vmw_host_printf(const char *fmt, ...); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 5162a7a12792..b62207be3363 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1396,70 +1396,10 @@ static void vmw_framebuffer_bo_destroy(struct drm_framebuffer *framebuffer) kfree(vfbd); } -static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, - struct drm_file *file_priv, - unsigned int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int num_clips) -{ - struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); - struct vmw_framebuffer_bo *vfbd = - vmw_framebuffer_to_vfbd(framebuffer); - struct drm_clip_rect norect; - int ret, increment = 1; - - drm_modeset_lock_all(&dev_priv->drm); - - if (!num_clips) { - num_clips = 1; - clips = &norect; - norect.x1 = norect.y1 = 0; - norect.x2 = framebuffer->width; - norect.y2 = framebuffer->height; - } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { - num_clips /= 2; - increment = 2; - } - - switch (dev_priv->active_display_unit) { - case vmw_du_legacy: - ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, - clips, num_clips, increment); - break; - default: - ret = -EINVAL; - WARN_ONCE(true, "Dirty called with invalid display system.\n"); - break; - } - - vmw_cmd_flush(dev_priv, false); - - drm_modeset_unlock_all(&dev_priv->drm); - - return ret; -} - -static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer, - struct drm_file *file_priv, - unsigned int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int num_clips) -{ - struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); - - if (dev_priv->active_display_unit == vmw_du_legacy && - vmw_cmd_supported(dev_priv)) - return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags, - color, clips, num_clips); - - return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color, - clips, num_clips); -} - static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { .create_handle = vmw_framebuffer_bo_create_handle, .destroy = vmw_framebuffer_bo_destroy, - .dirty = vmw_framebuffer_bo_dirty_ext, + .dirty = drm_atomic_helper_dirtyfb, }; /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 3de7b4b6a230..db81e635dc06 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -507,11 +507,6 @@ void vmw_du_connector_destroy_state(struct drm_connector *connector, */ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv); int vmw_kms_ldu_close_display(struct vmw_private *dev_priv); -int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - unsigned int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int num_clips, int increment); int vmw_kms_update_proxy(struct vmw_resource *res, const struct drm_clip_rect *clips, unsigned num_clips, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index c0e42f2ed144..a82fa9700370 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -275,6 +275,7 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = { .atomic_duplicate_state = vmw_du_crtc_duplicate_state, .atomic_destroy_state = vmw_du_crtc_destroy_state, .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, }; @@ -314,6 +315,12 @@ static const struct drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = { }; +static int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned int flags, unsigned int color, + struct drm_mode_rect *clips, + unsigned int num_clips); + /* * Legacy Display Plane Functions */ @@ -332,7 +339,6 @@ vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane, struct drm_framebuffer *fb; struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc; - ldu = vmw_crtc_to_ldu(crtc); dev_priv = vmw_priv(plane->dev); fb = new_state->fb; @@ -345,8 +351,31 @@ vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane, vmw_ldu_del_active(dev_priv, ldu); vmw_ldu_commit_list(dev_priv); -} + if (vfb && vmw_cmd_supported(dev_priv)) { + struct drm_mode_rect fb_rect = { + .x1 = 0, + .y1 = 0, + .x2 = vfb->base.width, + .y2 = vfb->base.height + }; + struct drm_mode_rect *damage_rects = drm_plane_get_damage_clips(new_state); + u32 rect_count = drm_plane_get_damage_clips_count(new_state); + int ret; + + if (!damage_rects) { + damage_rects = &fb_rect; + rect_count = 1; + } + + ret = vmw_kms_ldu_do_bo_dirty(dev_priv, vfb, 0, 0, damage_rects, rect_count); + + drm_WARN_ONCE(plane->dev, ret, + "vmw_kms_ldu_do_bo_dirty failed with: ret=%d\n", ret); + + vmw_cmd_flush(dev_priv, false); + } +} static const struct drm_plane_funcs vmw_ldu_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, @@ -577,11 +606,11 @@ int vmw_kms_ldu_close_display(struct vmw_private *dev_priv) } -int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - unsigned int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int num_clips, int increment) +static int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned int flags, unsigned int color, + struct drm_mode_rect *clips, + unsigned int num_clips) { size_t fifo_size; int i; @@ -597,7 +626,7 @@ int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, return -ENOMEM; memset(cmd, 0, fifo_size); - for (i = 0; i < num_clips; i++, clips += increment) { + for (i = 0; i < num_clips; i++, clips++) { cmd[i].header = SVGA_CMD_UPDATE; cmd[i].body.x = clips->x1; cmd[i].body.y = clips->y1; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index e76976a95a1e..2651fe0ef518 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -703,32 +703,6 @@ static inline void hypervisor_ppn_remove(PPN64 pfn) #define MKSSTAT_KERNEL_DESCRIPTION "vmwgfx" /** - * mksstat_init_record: Initializes an MKSGuestStatCounter-based record - * for the respective mksGuestStat index. - * - * @stat_idx: Index of the MKSGuestStatCounter-based mksGuestStat record. - * @pstat: Pointer to array of MKSGuestStatCounterTime. - * @pinfo: Pointer to array of MKSGuestStatInfoEntry. - * @pstrs: Pointer to current end of the name/description sequence. - * Return: Pointer to the new end of the names/description sequence. - */ - -static inline char *mksstat_init_record(mksstat_kern_stats_t stat_idx, - MKSGuestStatCounterTime *pstat, MKSGuestStatInfoEntry *pinfo, char *pstrs) -{ - char *const pstrd = pstrs + strlen(mksstat_kern_name_desc[stat_idx][0]) + 1; - strcpy(pstrs, mksstat_kern_name_desc[stat_idx][0]); - strcpy(pstrd, mksstat_kern_name_desc[stat_idx][1]); - - pinfo[stat_idx].name.s = pstrs; - pinfo[stat_idx].description.s = pstrd; - pinfo[stat_idx].flags = MKS_GUEST_STAT_FLAG_NONE; - pinfo[stat_idx].stat.counter = (MKSGuestStatCounter *)&pstat[stat_idx]; - - return pstrd + strlen(mksstat_kern_name_desc[stat_idx][1]) + 1; -} - -/** * mksstat_init_record_time: Initializes an MKSGuestStatCounterTime-based record * for the respective mksGuestStat index. * @@ -1205,3 +1179,12 @@ int vmw_mksstat_remove_ioctl(struct drm_device *dev, void *data, return -EAGAIN; } + +/** + * vmw_disable_backdoor: Disables all backdoor communication + * with the hypervisor. + */ +void vmw_disable_backdoor(void) +{ + vmw_msg_enabled = 0; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 8d171d71cb8a..7e112319a23c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -53,12 +53,6 @@ struct vmw_overlay { struct vmw_stream stream[VMW_MAX_NUM_STREAMS]; }; -static inline struct vmw_overlay *vmw_overlay(struct drm_device *dev) -{ - struct vmw_private *dev_priv = vmw_priv(dev); - return dev_priv ? dev_priv->overlay_priv : NULL; -} - struct vmw_escape_header { uint32_t cmd; SVGAFifoCmdEscape body; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_so.c b/drivers/gpu/drm/vmwgfx/vmwgfx_so.c index 5af4db6d1f18..d199e718cb2d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_so.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_so.c @@ -71,7 +71,7 @@ struct vmw_view { unsigned view_id; /* Immutable */ u32 cmd_size; /* Immutable */ bool committed; /* Protected by binding_mutex */ - u32 cmd[1]; /* Immutable */ + u32 cmd[]; /* Immutable */ }; static int vmw_view_create(struct vmw_resource *res); diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index 291ac1bab66d..d4621b1ea7f1 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h @@ -8,6 +8,7 @@ struct ipu_soc; +#include <linux/io.h> #include <linux/types.h> #include <linux/device.h> #include <linux/clk.h> |
