Re: [PATCH v5 6/7] phy: phy-mtk-dp: Add driver for DP phy
On 22-10-21, 15:06, Markus Schneider-Pargmann wrote: > > > + dp_phy->regs = *(struct regmap **)dev->platform_data; > > > + if (!dp_phy->regs) { > > > + dev_err(dev, "No data passed, requires struct regmap**\n"); > > > + return -EINVAL; > > > + } > > > > is there a reason to do it this way? Why not set the IORESOURCE_MEM for > > this device and let the driver map here? > > > > NO clocks? > > As briefly mentioned in the commit message, this phy is not a dedicated > phy. It is embedded in the DisplayPort controller that is added in patch > 7 of this series. The registerspace of the DisplayPort controller starts > at offset 0x0, continues with 0x1000 for PHY related functions and goes > on with encoder related and other registers at 0x2000, 0x3000 and > 0x4000. > > As this seems to me to be a single function block (also from what I read > from the datasheet), I designed the binding documentation so that the > DisplayPort controller starts at 0x0 and spans all registers. Based on > that I wanted to share the regmap created in the DisplayPort controller > with this PHY driver that is a direct child of that driver, similar to > multi function device drivers. > > That also means that the PHY does not have any clocks it requires as it > only exists in the context of the DisplayPort controller. I could pass > the same clocks to the PHY, but the use of these clocks does not make > any difference. Okay, that sounds sensible > As I don't have a piece of devicetree, I struggled with using phy_get > as, if I understand it correctly, it uses the devicetree to find the > correct PHY device? Not really, device tree is one of the backends phy_get() relies on. If you are having issues, then chances are there are bugs somewhere or usage is incorrect > Do you have a suggestion on how I could improve this interaction between > DP controller and PHY? Maybe some driver that I could look at that has > similar constraints? I would say use phy_get() and fix if we have any issues around it, that should make it much cleaner to use -- ~Vinod
Re: [PATCH] drm: bridge: fix unmet dependency on DRM_KMS_HELPER for DRM_PANEL_BRIDGE
Hi Julian, Thank you for catching this. On Mon, 25 Oct 2021 at 05:44, Julian Braha wrote: > > When DRM_CHIPONE_ICN6211 is selected, and DRM_KMS_HELPER is not selected, > Kbuild gives the following warning: > > WARNING: unmet direct dependencies detected for DRM_PANEL_BRIDGE > Depends on [n]: HAS_IOMEM [=y] && DRM_BRIDGE [=y] && DRM_KMS_HELPER [=n] > Selected by [y]: > - DRM_CHIPONE_ICN6211 [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_BRIDGE [=y] > && OF [=y] > > This is because DRM_CHIPONE_ICN6211 selects DRM_PANEL_BRIDGE > without depending on or selecting DRM_KMS_HELPER, > despite DRM_PANEL_BRIDGE depending on DRM_KMS_HELPER. > > This unmet dependency bug was detected by Kismet, > a static analysis tool for Kconfig. > Please advise if this is not the appropriate solution. Could you add a Fixes tag to this commit. ce517f18944e - drm: bridge: Add Chipone ICN6211 MIPI-DSI to RGB bridge With that, resubmit with my r-b. Reviewed-by: Robert Foss > > Signed-off-by: Julian Braha > --- > drivers/gpu/drm/bridge/Kconfig | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig > index 431b6e12a81f..a630cb8fd1c8 100644 > --- a/drivers/gpu/drm/bridge/Kconfig > +++ b/drivers/gpu/drm/bridge/Kconfig > @@ -30,6 +30,7 @@ config DRM_CDNS_DSI > config DRM_CHIPONE_ICN6211 > tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge" > depends on OF > + select DRM_KMS_HELPER > select DRM_MIPI_DSI > select DRM_PANEL_BRIDGE > help > -- > 2.30.2 >
Re: [PATCH v11 09/16] soc: mediatek: add mtk-mmsys support for mt8195 vdosys0
On Fri, Oct 22, 2021 at 6:13 PM Jason-JH Lin wrote: > > Hi Angelo, > > Thanks for the reviews. > > > On Thu, 2021-10-14 at 16:05 +0200, AngeloGioacchino Del Regno wrote: > > > Add mt8195 vdosys0 clock driver name and routing table to > > > the driver data of mtk-mmsys. > > > > > [snip] > > > > > > > --- > > > > Hello Jason, > > thanks for the patch! However, there are a few things to improve: > > > > [snip] > > > > +#define MT8195_VDO0_SEL_IN 0xf34 > > > +#define MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT (0 << > > > 0) > > > > Bitshifting 0 by 0 bits == 0, so this is simply 0. > > > > > +#define MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1 (1 << > > > 0) > > > > I would write 0x1 here > > > > > +#define MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0 (2 << > > > 0) > > > > and 0x2 here: bitshifting of 0 bits makes little sense. > > > > > +#define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0 > > > (0 << 4) > > > > Bitshifting 0 by 4 bits is still 0, so this is again 0. > > This is repeated too many times, so I will not list it for all of the > > occurrences. > > > > > +#define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE (1 << > > > 4) > > > > This is BIT(4). > > > > > +#define MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1 > > > (0 << 5) > +#define MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE > > > (1 << 5) > > > > ...and this is BIT(5) > > > > > +#define MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE (0 << > > > 8) > > > +#define MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT > > > (1 << 8) > > > > BIT(8) > > > > > +#define MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT > > > (0 << 9) > > > +#define MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT (0 << > > > 12) > > > +#define MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE > > > (1 << 12) > > > > BIT(12) > > > > > +#define MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0 (2 << > > > 12) > > > > BIT(13) > > > > ... and please, use the BIT(nr) macro for all these bit definitions, > > it's way more > > readable like that. > > > > Regards, > > - Angelo > > Because the HW register design of MT8195_VDO0_SEL_IN 0xf34 is like > this: > > bit[1:0] as MT8195_SEL_IN_VPP_MERGE and > value: 0 as MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT > value: 1 as MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1 > value: 2 as MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0 > bit[4:4] as MT8195_SEL_IN_DSC_WRAP0_IN and > value 0 as MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0 > value 1 as MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE > bit[5:5] as MT8195_SEL_IN_DSC_WRAP1_IN and > value 0 as > MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1 > value 1 as > MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE > and so on... > > I think using BIT(nr) macro directly is not easy to debug. > > > Is it better to define another MACRO like this? > > #define BIT_VAL(val, bit) ((val) << (bit)) > #define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0 BIT_VAL(0, 4) > #define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE BIT_VAL(1, 4) > ... > > or > > #define MT8195_SEL_IN_DSC_WRAP0_IN (4) > #define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0 (0 > << MT8195_SEL_IN_DSC_WRAP0_IN) > #define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE (1 << > MT8195_SEL_IN_DSC_WRAP0_IN) > ... > > What do you think? Hi Jason, If that's the case you can still use BIT(nr) for the definitions and describe their usage in the comment, so both code readability and the ease of maintenance are preserved, and people can easily tell if there are duplicated/missing definitions while reading through the code. Adding informative comments is never a bad thing. I would do something like this (and further split the definitions into sections by their functionalities with blank lines for visual comfort): /* * MT8195_VDO0_SEL_IN[1:0]: VPP_MERGE * 0x0 : DSC_WRAP0_OUT * 0x1 : DISP_DITHER1 * 0x10: VDO1_VIRTUAL0 */ #define MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT 0 #define MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1BIT(0) #define MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0 BIT(1) /* * MT8195_VDO0_SEL_IN[4:4]: DSC_WRAP0_IN * 0x0: DISP_DITHER0 * 0x1: VPP_MERGE */ #define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0 0 #define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGEBIT(4) ... and so on. Regards, Fei > > > Regards, > Jason-JH Lin >
[PATCH] dma-buf: fix uninitialized variable usage in selftests
"i" can be used uninitialized in one of the error branches. Fix this. Signed-off-by: Christian König Reported-by: kernel test robot --- drivers/dma-buf/st-dma-resv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma-buf/st-dma-resv.c b/drivers/dma-buf/st-dma-resv.c index 6f3ba756da3e..bc2265807f6c 100644 --- a/drivers/dma-buf/st-dma-resv.c +++ b/drivers/dma-buf/st-dma-resv.c @@ -295,7 +295,7 @@ static int test_get_fences(void *arg, bool shared) if (r) { pr_err("Resv shared slot allocation failed\n"); dma_resv_unlock(&resv); - goto err_free; + goto err_fini; } dma_resv_add_shared_fence(&resv, f); @@ -336,6 +336,7 @@ static int test_get_fences(void *arg, bool shared) while (i--) dma_fence_put(fences[i]); kfree(fences); +err_fini: dma_resv_fini(&resv); dma_fence_put(f); return r; -- 2.25.1
[PATCH v2 1/2] drm/aperture: Move conflicting fbdev frame buffer removal to a helper
The logic to remove the conflicting frame buffers for fbdev devices that use a given memory range is only compiled if CONFIG_FB option is enabled. But having an ifdefery in drm_aperture_remove_conflicting_framebuffers() makes the function harder to extend. Move the logic into its own helper. Suggested-by: Thomas Zimmermann Signed-off-by: Javier Martinez Canillas --- (no changes since v1) drivers/gpu/drm/drm_aperture.c | 39 ++ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c index 74bd4a76b253..1a8ed0c616d6 100644 --- a/drivers/gpu/drm/drm_aperture.c +++ b/drivers/gpu/drm/drm_aperture.c @@ -273,6 +273,30 @@ static void drm_aperture_detach_drivers(resource_size_t base, resource_size_t si mutex_unlock(&drm_apertures_lock); } +static int drm_aperture_remove_conflicting_fbdev_framebuffers(resource_size_t base, + resource_size_t size, bool primary, + const struct drm_driver *req_driver) +{ +#if IS_REACHABLE(CONFIG_FB) + struct apertures_struct *a; + int ret; + + a = alloc_apertures(1); + if (!a) + return -ENOMEM; + + a->ranges[0].base = base; + a->ranges[0].size = size; + + ret = remove_conflicting_framebuffers(a, req_driver->name, primary); + kfree(a); + + if (ret) + return ret; +#endif + return 0; +} + /** * drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range * @base: the aperture's base address in physical memory @@ -289,23 +313,12 @@ static void drm_aperture_detach_drivers(resource_size_t base, resource_size_t si int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, bool primary, const struct drm_driver *req_driver) { -#if IS_REACHABLE(CONFIG_FB) - struct apertures_struct *a; int ret; - a = alloc_apertures(1); - if (!a) - return -ENOMEM; - - a->ranges[0].base = base; - a->ranges[0].size = size; - - ret = remove_conflicting_framebuffers(a, req_driver->name, primary); - kfree(a); - + ret = drm_aperture_remove_conflicting_fbdev_framebuffers(base, size, primary, +req_driver); if (ret) return ret; -#endif drm_aperture_detach_drivers(base, size); -- 2.31.1
[PATCH v2 0/2] Add a drm.disable_native_drivers command line option
This patch-series add a drm.disable_native_drivers option that can be used to prevent native DRM drivers to be probed. That way, the simpledrm driver won't be removed which can be useful to troubleshoot DRM drivers problems. Patch #1 is just a small preparatory patch that moves the logic to remove the conflicting fbdev frame buffer to a helper function. Patch #2 adds the new kernel command line option and if set, prevents the drm_aperture_remove_conflicting_framebuffers() function to succeed. This is a v2 that addresses the issues pointed out by Thomas and Neal. Best regards, Javier Changes in v2: - Rename command line parameter to drm.disable_native_drivers. - Return -EBUSY instead of -EINVAL when the function fails. - Invert the parameter logic and make it false by default. Javier Martinez Canillas (2): drm/aperture: Move conflicting fbdev frame buffer removal to a helper drm/aperture: Prevent conflicting framebuffers removal if option is set drivers/gpu/drm/drm_aperture.c | 54 ++ 1 file changed, 42 insertions(+), 12 deletions(-) -- 2.31.1
[PATCH v2 2/2] drm/aperture: Prevent conflicting framebuffers removal if option is set
The simpledrm driver allows to use the frame buffer that was set-up by the firmware. This gives early video output before the platform DRM driver is probed and takes over. But it would be useful to have a way to disable this take over by native DRM drivers. For example, there may be bugs in the DRM drivers that could cause the display output to not work correctly. For those cases, it would be good to keep the simpledrm driver instead and at least get a working display as set-up by the firmware. Let's add a drm.disable_native_drivers kernel command line parameter, that when set to true it prevents the conflicting framebuffers to being removed. Since the drivers call drm_aperture_remove_conflicting_framebuffers() very early in their probe callback, this will cause the drivers' probe to fail. Thanks to Neal Gompa for the suggestion and Thomas Zimmermann for the idea on how this could be implemented. Suggested-by: Neal Gompa Signed-off-by: Javier Martinez Canillas --- Changes in v2: - Rename command line parameter to drm.disable_native_drivers. - Return -EBUSY instead of -EINVAL when the function fails. - Invert the parameter logic and make it false by default. drivers/gpu/drm/drm_aperture.c | 17 + 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c index 1a8ed0c616d6..6ae20b6d6499 100644 --- a/drivers/gpu/drm/drm_aperture.c +++ b/drivers/gpu/drm/drm_aperture.c @@ -14,6 +14,11 @@ #include #include +static bool drm_disable_native_drivers; +module_param_named(disable_native_drivers, drm_disable_native_drivers, bool, 0600); +MODULE_PARM_DESC(disable_native_drivers, +"Disable native DRM drivers probing [default=false]"); + /** * DOC: overview * @@ -307,6 +312,9 @@ static int drm_aperture_remove_conflicting_fbdev_framebuffers(resource_size_t ba * This function removes graphics device drivers which use memory range described by * @base and @size. * + * The conflicting framebuffers removal does not happen when drm.disable_native_drivers=1 is + * set. When this option is enabled, the function will return an -EBUSY errno code instead. + * * Returns: * 0 on success, or a negative errno code otherwise */ @@ -315,6 +323,9 @@ int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_ { int ret; + if (drm_disable_native_drivers) + return -EBUSY; + ret = drm_aperture_remove_conflicting_fbdev_framebuffers(base, size, primary, req_driver); if (ret) @@ -335,6 +346,9 @@ EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); * for any of @pdev's memory bars. The function assumes that PCI device with * shadowed ROM drives a primary display and so kicks out vga16fb. * + * The conflicting framebuffers removal does not happen when drm.disable_native_drivers=1 is + * set. When this option is enabled, the function will return an -EBUSY errno code instead. + * * Returns: * 0 on success, or a negative errno code otherwise */ @@ -344,6 +358,9 @@ int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, resource_size_t base, size; int bar, ret = 0; + if (drm_disable_native_drivers) + return -EBUSY; + for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) { if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) continue; -- 2.31.1
Re: [PATCH] drm/i915/selftests: Fix inconsistent IS_ERR and PTR_ERR
On 22/10/2021 13:06, Kai Song wrote: Fix inconsistent IS_ERR and PTR_ERR in i915_gem_dmabuf.c Signed-off-by: Kai Song Pushed to drm-intel-gt-next. Thanks. --- drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index 4a6bb64c3a35..3cc74b0fed06 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -102,7 +102,7 @@ static int igt_dmabuf_import_same_driver_lmem(void *arg) obj = __i915_gem_object_create_user(i915, PAGE_SIZE, &lmem, 1); if (IS_ERR(obj)) { pr_err("__i915_gem_object_create_user failed with err=%ld\n", - PTR_ERR(dmabuf)); + PTR_ERR(obj)); err = PTR_ERR(obj); goto out_ret; } @@ -158,7 +158,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915, regions, num_regions); if (IS_ERR(obj)) { pr_err("__i915_gem_object_create_user failed with err=%ld\n", - PTR_ERR(dmabuf)); + PTR_ERR(obj)); err = PTR_ERR(obj); goto out_ret; }
Two minor etnaviv DMA-buf cleanups
Hi guys, just two minor cleanups related to the new DMA-buf iterators. Can I get an rb or ack-by for that? Thanks, Christian.
[PATCH 2/2] drm/etnaviv: replace dma_resv_get_excl_unlocked
We certainly hold the reservation lock here, no need for the RCU dance. Signed-off-by: Christian König --- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 4dd7d9d541c0..7e17bc2b5df1 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -195,7 +195,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit) if (ret) return ret; } else { - bo->excl = dma_resv_get_excl_unlocked(robj); + bo->excl = dma_fence_get(dma_resv_excl_fence(robj)); } } -- 2.25.1
[PATCH 1/2] drm/etnaviv: use new iterator in etnaviv_gem_describe
Instead of hand rolling the logic. Signed-off-by: Christian König --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 31 ++- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 8f1b5af47dd6..0eeb33de2ff4 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -428,19 +428,17 @@ int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj, static void etnaviv_gem_describe_fence(struct dma_fence *fence, const char *type, struct seq_file *m) { - if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) - seq_printf(m, "\t%9s: %s %s seq %llu\n", - type, - fence->ops->get_driver_name(fence), - fence->ops->get_timeline_name(fence), - fence->seqno); + seq_printf(m, "\t%9s: %s %s seq %llu\n", type, + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + fence->seqno); } static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); struct dma_resv *robj = obj->resv; - struct dma_resv_list *fobj; + struct dma_resv_iter cursor; struct dma_fence *fence; unsigned long off = drm_vma_node_start(&obj->vma_node); @@ -449,21 +447,14 @@ static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m) obj->name, kref_read(&obj->refcount), off, etnaviv_obj->vaddr, obj->size); - rcu_read_lock(); - fobj = dma_resv_shared_list(robj); - if (fobj) { - unsigned int i, shared_count = fobj->shared_count; - - for (i = 0; i < shared_count; i++) { - fence = rcu_dereference(fobj->shared[i]); + dma_resv_iter_begin(&cursor, robj, true); + dma_resv_for_each_fence_unlocked(&cursor, fence) { + if (dma_resv_iter_is_exclusive(&cursor)) + etnaviv_gem_describe_fence(fence, "Exclusive", m); + else etnaviv_gem_describe_fence(fence, "Shared", m); - } } - - fence = dma_resv_excl_fence(robj); - if (fence) - etnaviv_gem_describe_fence(fence, "Exclusive", m); - rcu_read_unlock(); + dma_resv_iter_end(&cursor); } void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv, -- 2.25.1
Re: [PATCH] drm/i915/vlv_dsi: Double pixelclock on read-back for dual-link panels
On Sun, 24 Oct 2021, Hans de Goede wrote: > In intel_dsi_get_config() double the pclk returned by foo_dsi_get_pclk() > for dual-link panels. This fixes the following WARN triggering: > > i915 :00:02.0: [drm] *ERROR* [CRTC:51:pipe A] mismatch in pixel_rate > (expected 235710, found 118056) > i915 :00:02.0: [drm] *ERROR* [CRTC:51:pipe A] mismatch in > hw.pipe_mode.crtc_clock (expected 235710, found 118056) > i915 :00:02.0: [drm] *ERROR* [CRTC:51:pipe A] mismatch in > hw.adjusted_mode.crtc_clock (expected 235710, found 118056) > i915 :00:02.0: [drm] *ERROR* [CRTC:51:pipe A] mismatch in port_clock > (expected 235710, found 118056) > [ cut here ] > pipe state doesn't match! > WARNING: CPU: 3 PID: 136 at > drivers/gpu/drm/i915/display/intel_display.c:9125 > intel_display_finish_reset+0x1bd3/0x2050 [i915] > ... > > This has been tested on a Xiaomi Mi Pad 2 (with CHT x5-Z8500 SoC) tablet, > with a 1536x2048 dual-link DSI panel. > > Note this fix was taken from icl_dsi.c which does the same in > its get_config(). > > Cc: Tsuchiya Yuto > Signed-off-by: Hans de Goede Acked-by: Jani Nikula > --- > drivers/gpu/drm/i915/display/vlv_dsi.c | 5 + > 1 file changed, 5 insertions(+) > > diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c > b/drivers/gpu/drm/i915/display/vlv_dsi.c > index 3e646a58b38a..2b7909bc52ff 100644 > --- a/drivers/gpu/drm/i915/display/vlv_dsi.c > +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c > @@ -1265,7 +1265,9 @@ static void intel_dsi_get_config(struct intel_encoder > *encoder, >struct intel_crtc_state *pipe_config) > { > struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); > + struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); > u32 pclk; > + > drm_dbg_kms(&dev_priv->drm, "\n"); > > pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI); > @@ -1277,6 +1279,9 @@ static void intel_dsi_get_config(struct intel_encoder > *encoder, > pclk = vlv_dsi_get_pclk(encoder, pipe_config); > } > > + if (intel_dsi->dual_link) > + pclk *= 2; > + > if (pclk) { > pipe_config->hw.adjusted_mode.crtc_clock = pclk; > pipe_config->port_clock = pclk; -- Jani Nikula, Intel Open Source Graphics Center
Re: [PATCH] drm/i915: Add NO_VLV_DISP_PW_DPIO_CMN_BC_INIT quirk
On Sun, 24 Oct 2021, Hans de Goede wrote: > Add a NO_VLV_DISP_PW_DPIO_CMN_BC_INIT quirk to fix i915 not working on > the Xiaomi Mi Pad 2 (with CHT x5-Z8500 SoC). > > The Xiaomi Mi Pad 2 uses quite an unusual hardware-design for a Cherry > Trail tablet. It deviates from the typical reference design based tablets > in many ways. > > The Mi Pad 2 does not have any DisplayPort or HDMI outouts. I suspect that > as part of its unusual design it also has some supply rail which is only > used for DisplayPort or HDMI not connected. > > Force-enabling the dpio-common-bc powerwell as the i915 normal does at boot > appears to cause the P-Unit to hang. When booting with a serial-usb console > the following errors are logged before the system freezes: > > i915 :00:02.0: [drm] *ERROR* timeout setting power well state > (f3ff) > i915 :00:02.0: [drm] *ERROR* Display PHY 0 is not power up > [ cut here ] > i915 :00:02.0: DPIO read pipe A reg 0x8170 == 0x > WARNING: CPU: 3 PID: 258 at drivers/gpu/drm/i915/intel_sideband.c:257 > vlv_dpio_read+0x95/0xb0 [i915] > ... > Call Trace: > chv_dpio_cmn_power_well_enable+0xab/0x210 [i915] > __intel_display_power_get_domain.part.0+0xa0/0xc0 [i915] > intel_power_domains_init_hw+0x26d/0x760 [i915] > intel_modeset_init_noirq+0x5d/0x270 [i915] > i915_driver_probe+0x6b6/0xd10 [i915] > ... > > If I disable the WARN about the register being 0x, so that the > system can log some more dmesg output over the serial console before > freezing, the following errors are also logged: > > i915 :00:02.0: [drm] *ERROR* timeout setting power well state > (fcfff3ff) > i915 :00:02.0: [drm] *ERROR* Display PHY 1 is not power up > > With this patch to disable the force-enabling of the PHY 0 / dpio-common-bc > powerwell in place, this error for PHY 1 goes away. So it seems that trying > the force-enabling of the PHY 0 / dpio-common-bc powerwell freezes the > P-Unit, causing the subsequent enabling of PHY 1 to also fail (and causing > the entire system to freeze within seconds). > > With this patch the PHY 1 error disappears and the entire system works. > > Note this change also moves the intel_init_quirks() call a bit up inside > intel_modeset_init_noirq() this is necessary so that the quirk is set > before the intel_power_domains_init_hw() call. This is harmless, all that > intel_init_quirks() does is set some bits in drm_i915_private.quirks and > make some drm_info() log calls. > > Reported-by: Tsuchiya Yuto > Signed-off-by: Hans de Goede > --- > drivers/gpu/drm/i915/display/intel_display.c | 4 ++-- > .../gpu/drm/i915/display/intel_display_power.c | 16 ++-- > drivers/gpu/drm/i915/display/intel_quirks.c | 10 ++ > drivers/gpu/drm/i915/i915_drv.h | 1 + > 4 files changed, 27 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_display.c > b/drivers/gpu/drm/i915/display/intel_display.c > index 015854b5078c..1fb885cc86c9 100644 > --- a/drivers/gpu/drm/i915/display/intel_display.c > +++ b/drivers/gpu/drm/i915/display/intel_display.c > @@ -12467,6 +12467,8 @@ int intel_modeset_init_noirq(struct drm_i915_private > *i915) > if (ret) > goto cleanup_bios; > > + intel_init_quirks(i915); > + > /* FIXME: completely on the wrong abstraction layer */ > intel_power_domains_init_hw(i915, false); > > @@ -12501,8 +12503,6 @@ int intel_modeset_init_noirq(struct drm_i915_private > *i915) > INIT_WORK(&i915->atomic_helper.free_work, > intel_atomic_helper_free_state_worker); > > - intel_init_quirks(i915); > - > intel_fbc_init(i915); > > return 0; > diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c > b/drivers/gpu/drm/i915/display/intel_display_power.c > index cce1a926fcc1..eeaba3dc064b 100644 > --- a/drivers/gpu/drm/i915/display/intel_display_power.c > +++ b/drivers/gpu/drm/i915/display/intel_display_power.c > @@ -2090,8 +2090,14 @@ __intel_display_power_get_domain(struct > drm_i915_private *dev_priv, > if (intel_display_power_grab_async_put_ref(dev_priv, domain)) > return; > > - for_each_power_domain_well(dev_priv, power_well, BIT_ULL(domain)) > + for_each_power_domain_well(dev_priv, power_well, BIT_ULL(domain)) { > + if (domain == POWER_DOMAIN_INIT && > + (dev_priv->quirks & QUIRK_NO_VLV_DISP_PW_DPIO_CMN_BC_INIT) > && > + power_well->desc->id == VLV_DISP_PW_DPIO_CMN_BC) > + continue; > + > intel_power_well_get(dev_priv, power_well); > + } Cc: Imre There has got to be a way to hide this better. Having this here is unacceptable. BR, Jani. > > power_domains->domain_use_count[domain]++; > } > @@ -2184,8 +2190,14 @@ __intel_display_power_put_domain(struct > drm_i915_private *dev_priv, > > power_domains->domain_use_co
Re: [PATCH v6 3/3] drm/bridge: ti-sn65dsi86: Implement the pwm_chip
Hello, [replaced Andrzej Hajda's email address with his new one] On Wed, Sep 29, 2021 at 10:05:57PM -0500, Bjorn Andersson wrote: > The SN65DSI86 provides the ability to supply a PWM signal on GPIO 4, > with the primary purpose of controlling the backlight of the attached > panel. Add an implementation that exposes this using the standard PWM > framework, to allow e.g. pwm-backlight to expose this to the user. Sorry for the long delay in reviewing this. > Signed-off-by: Bjorn Andersson > --- > > Changes since v5: > - Make ti_sn65dsi86_read_u16() use regmap_bulk_read() > - Update the wording related to the formula for the period being wrong to not > just say I'm "assuming because it's easier". > - Updated comment related to minimum period > - Clamp duty <= period in get_state() > > drivers/gpu/drm/bridge/ti-sn65dsi86.c | 366 +- > 1 file changed, 360 insertions(+), 6 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c > b/drivers/gpu/drm/bridge/ti-sn65dsi86.c > index 412fb6f564ea..ccf6496cc9ff 100644 > --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c > +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c > @@ -4,7 +4,9 @@ > * datasheet: https://www.ti.com/lit/ds/symlink/sn65dsi86.pdf > */ > > +#include > #include > +#include > #include > #include > #include > @@ -15,6 +17,7 @@ > #include > #include > #include > +#include > #include > #include > > @@ -91,6 +94,13 @@ > #define SN_ML_TX_MODE_REG0x96 > #define ML_TX_MAIN_LINK_OFF 0 > #define ML_TX_NORMAL_MODE BIT(0) > +#define SN_PWM_PRE_DIV_REG 0xA0 > +#define SN_BACKLIGHT_SCALE_REG 0xA1 > +#define BACKLIGHT_SCALE_MAX 0x > +#define SN_BACKLIGHT_REG 0xA3 > +#define SN_PWM_EN_INV_REG0xA5 > +#define SN_PWM_INV_MASK BIT(0) > +#define SN_PWM_EN_MASK BIT(1) > #define SN_AUX_CMD_STATUS_REG0xF4 > #define AUX_IRQ_STATUS_AUX_RPLY_TOUTBIT(3) > #define AUX_IRQ_STATUS_AUX_SHORTBIT(5) > @@ -113,11 +123,14 @@ > > #define SN_LINK_TRAINING_TRIES 10 > > +#define SN_PWM_GPIO_IDX 3 /* 4th GPIO */ > + > /** > * struct ti_sn65dsi86 - Platform data for ti-sn65dsi86 driver. > * @bridge_aux: AUX-bus sub device for MIPI-to-eDP bridge functionality. > * @gpio_aux: AUX-bus sub device for GPIO controller functionality. > * @aux_aux: AUX-bus sub device for eDP AUX channel functionality. > + * @pwm_aux: AUX-bus sub device for PWM controller functionality. > * > * @dev: Pointer to the top level (i2c) device. > * @regmap: Regmap for accessing i2c. > @@ -145,11 +158,17 @@ > *bitmap so we can do atomic ops on it without an extra > *lock so concurrent users of our 4 GPIOs don't stomp on > *each other's read-modify-write. > + * > + * @pchip:pwm_chip if the PWM is exposed. > + * @pwm_enabled: Used to track if the PWM signal is currently enabled. > + * @pwm_pin_busy: Track if GPIO4 is currently requested for GPIO or PWM. > + * @pwm_refclk_freq: Cache for the reference clock input to the PWM. > */ > struct ti_sn65dsi86 { > struct auxiliary_device bridge_aux; > struct auxiliary_device gpio_aux; > struct auxiliary_device aux_aux; > + struct auxiliary_device pwm_aux; > > struct device *dev; > struct regmap *regmap; > @@ -172,6 +191,12 @@ struct ti_sn65dsi86 { > struct gpio_chipgchip; > DECLARE_BITMAP(gchip_output, SN_NUM_GPIOS); > #endif > +#if defined(CONFIG_PWM) > + struct pwm_chip pchip; > + boolpwm_enabled; > + atomic_tpwm_pin_busy; > +#endif > + unsigned intpwm_refclk_freq; > }; > > static const struct regmap_range ti_sn65dsi86_volatile_ranges[] = { > @@ -190,6 +215,21 @@ static const struct regmap_config > ti_sn65dsi86_regmap_config = { > .cache_type = REGCACHE_NONE, > }; > > +static int ti_sn65dsi86_read_u16(struct ti_sn65dsi86 *pdata, > + unsigned int reg, u16 *val) > +{ > + u8 buf[2]; > + int ret; > + > + ret = regmap_bulk_read(pdata->regmap, reg, buf, ARRAY_SIZE(buf)); > + if (ret) > + return ret; > + > + *val = buf[0] | (buf[1] << 8); > + > + return 0; > +} > + > static void ti_sn65dsi86_write_u16(struct ti_sn65dsi86 *pdata, > unsigned int reg, u16 val) > { > @@ -254,6 +294,12 @@ static void ti_sn_bridge_set_refclk_freq(struct > ti_sn65dsi86 *pdata) > > regmap_update_bits(pdata->regmap, SN_DPPLL_SRC_REG, REFCLK_FREQ_MASK, > REFCLK_FREQ(
Re: [PATCH v6 1/3] pwm: Introduce single-PWM of_xlate function
On Wed, Sep 29, 2021 at 10:05:55PM -0500, Bjorn Andersson wrote: > The existing pxa driver and the upcoming addition of PWM support in the > TI sn565dsi86 DSI/eDP bridge driver both has a single PWM channel and > thereby a need for a of_xlate function with the period as its single > argument. > > Introduce a common helper function in the core that can be used as > of_xlate by such drivers and migrate the pxa driver to use this. > > Signed-off-by: Bjorn Andersson I'm OK with this patch, in the long run I'd like to share more code with of_pwm_xlate_with_flags, but this shouldn't be a stopper here. Acked-by: Uwe Kleine-König Best regards Uwe -- Pengutronix e.K. | Uwe Kleine-König| Industrial Linux Solutions | https://www.pengutronix.de/ | signature.asc Description: PGP signature
Re: [PATCH] drm/i915: Add NO_VLV_DISP_PW_DPIO_CMN_BC_INIT quirk
Hi, On 10/25/21 10:25, Jani Nikula wrote: > On Sun, 24 Oct 2021, Hans de Goede wrote: >> Add a NO_VLV_DISP_PW_DPIO_CMN_BC_INIT quirk to fix i915 not working on >> the Xiaomi Mi Pad 2 (with CHT x5-Z8500 SoC). >> >> The Xiaomi Mi Pad 2 uses quite an unusual hardware-design for a Cherry >> Trail tablet. It deviates from the typical reference design based tablets >> in many ways. >> >> The Mi Pad 2 does not have any DisplayPort or HDMI outouts. I suspect that >> as part of its unusual design it also has some supply rail which is only >> used for DisplayPort or HDMI not connected. >> >> Force-enabling the dpio-common-bc powerwell as the i915 normal does at boot >> appears to cause the P-Unit to hang. When booting with a serial-usb console >> the following errors are logged before the system freezes: >> >> i915 :00:02.0: [drm] *ERROR* timeout setting power well state >> (f3ff) >> i915 :00:02.0: [drm] *ERROR* Display PHY 0 is not power up >> [ cut here ] >> i915 :00:02.0: DPIO read pipe A reg 0x8170 == 0x >> WARNING: CPU: 3 PID: 258 at drivers/gpu/drm/i915/intel_sideband.c:257 >> vlv_dpio_read+0x95/0xb0 [i915] >> ... >> Call Trace: >> chv_dpio_cmn_power_well_enable+0xab/0x210 [i915] >> __intel_display_power_get_domain.part.0+0xa0/0xc0 [i915] >> intel_power_domains_init_hw+0x26d/0x760 [i915] >> intel_modeset_init_noirq+0x5d/0x270 [i915] >> i915_driver_probe+0x6b6/0xd10 [i915] >> ... >> >> If I disable the WARN about the register being 0x, so that the >> system can log some more dmesg output over the serial console before >> freezing, the following errors are also logged: >> >> i915 :00:02.0: [drm] *ERROR* timeout setting power well state >> (fcfff3ff) >> i915 :00:02.0: [drm] *ERROR* Display PHY 1 is not power up >> >> With this patch to disable the force-enabling of the PHY 0 / dpio-common-bc >> powerwell in place, this error for PHY 1 goes away. So it seems that trying >> the force-enabling of the PHY 0 / dpio-common-bc powerwell freezes the >> P-Unit, causing the subsequent enabling of PHY 1 to also fail (and causing >> the entire system to freeze within seconds). >> >> With this patch the PHY 1 error disappears and the entire system works. >> >> Note this change also moves the intel_init_quirks() call a bit up inside >> intel_modeset_init_noirq() this is necessary so that the quirk is set >> before the intel_power_domains_init_hw() call. This is harmless, all that >> intel_init_quirks() does is set some bits in drm_i915_private.quirks and >> make some drm_info() log calls. >> >> Reported-by: Tsuchiya Yuto >> Signed-off-by: Hans de Goede >> --- >> drivers/gpu/drm/i915/display/intel_display.c | 4 ++-- >> .../gpu/drm/i915/display/intel_display_power.c | 16 ++-- >> drivers/gpu/drm/i915/display/intel_quirks.c | 10 ++ >> drivers/gpu/drm/i915/i915_drv.h | 1 + >> 4 files changed, 27 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/gpu/drm/i915/display/intel_display.c >> b/drivers/gpu/drm/i915/display/intel_display.c >> index 015854b5078c..1fb885cc86c9 100644 >> --- a/drivers/gpu/drm/i915/display/intel_display.c >> +++ b/drivers/gpu/drm/i915/display/intel_display.c >> @@ -12467,6 +12467,8 @@ int intel_modeset_init_noirq(struct drm_i915_private >> *i915) >> if (ret) >> goto cleanup_bios; >> >> +intel_init_quirks(i915); >> + >> /* FIXME: completely on the wrong abstraction layer */ >> intel_power_domains_init_hw(i915, false); >> >> @@ -12501,8 +12503,6 @@ int intel_modeset_init_noirq(struct drm_i915_private >> *i915) >> INIT_WORK(&i915->atomic_helper.free_work, >>intel_atomic_helper_free_state_worker); >> >> -intel_init_quirks(i915); >> - >> intel_fbc_init(i915); >> >> return 0; >> diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c >> b/drivers/gpu/drm/i915/display/intel_display_power.c >> index cce1a926fcc1..eeaba3dc064b 100644 >> --- a/drivers/gpu/drm/i915/display/intel_display_power.c >> +++ b/drivers/gpu/drm/i915/display/intel_display_power.c >> @@ -2090,8 +2090,14 @@ __intel_display_power_get_domain(struct >> drm_i915_private *dev_priv, >> if (intel_display_power_grab_async_put_ref(dev_priv, domain)) >> return; >> >> -for_each_power_domain_well(dev_priv, power_well, BIT_ULL(domain)) >> +for_each_power_domain_well(dev_priv, power_well, BIT_ULL(domain)) { >> +if (domain == POWER_DOMAIN_INIT && >> +(dev_priv->quirks & QUIRK_NO_VLV_DISP_PW_DPIO_CMN_BC_INIT) >> && >> +power_well->desc->id == VLV_DISP_PW_DPIO_CMN_BC) >> +continue; >> + >> intel_power_well_get(dev_priv, power_well); >> +} > > Cc: Imre > > There has got to be a way to hide this better. Having this here is > unacceptable. Thank you for your quick review. For a first quick hack I just re
Re: [PATCH 1/5] xen: add "not_essential" flag to struct xenbus_driver
On 22.10.21 11:28, Andrew Cooper wrote: On 22/10/2021 07:47, Juergen Gross wrote: When booting the xenbus driver will wait for PV devices to have connected to their backends before continuing. The timeout is different between essential and non-essential devices. Non-essential devices are identified by their nodenames directly in the xenbus driver, which requires to update this list in case a new device type being non-essential is added (this was missed for several types in the past). In order to avoid this problem, add a "not_essential" flag to struct xenbus_driver which can be set to "true" by the respective frontend. Set this flag for the frontends currently regarded to be not essential (vkbs and vfb) and use it for testing in the xenbus driver. Signed-off-by: Juergen Gross Wouldn't it be better to annotate essential? That way, when new misc drivers come along, they don't by default block boot. It isn't as if new drivers would "block boot". Normally the short timeout for all drivers of 30 seconds is more than enough for all of them. I'm a little bit hesitant to have a kind of "white listing" essential drivers, as there might be different views which drivers should have that flag. Doing this the other way round is easier: in case of disagreement such a patch just wouldn't go in, not breaking anything in that case. Additionally there might be out-of-tree PV drivers, which could be hit by not being flagged to be essential. With the not_essential flag the situation wouldn't change for such a driver. Juergen OpenPGP_0xB0DE9DD628BF132F.asc Description: OpenPGP public key OpenPGP_signature Description: OpenPGP digital signature
[PATCH v7 0/6] Add Unisoc's drm kms module
ChangeList: RFC v1: 1. only upstream modeset and atomic at first commit. 2. remove some unused code; 3. use alpha and blend_mode properties; 3. add yaml support; 4. remove auto-adaptive panel driver; 5. bugfix RFC v2: 1. add sprd crtc and plane module for KMS, preparing for multi crtc&encoder 2. remove gem drivers, use generic CMA handlers 3. remove redundant "module_init", all the sub modules loading by KMS RFC v3: 1. multi crtc&encoder design have problem, so rollback to v1 RFC v4: 1. update to gcc-linaro-7.5.0 2. update to Linux 5.6-rc3 3. remove pm_runtime support 4. add COMPILE_TEST, remove unused kconfig 5. "drm_dev_put" on drm_unbind 6. fix some naming convention issue 7. remove semaphore lock for crtc flip 8. remove static variables RFC v5: 1. optimize encoder and connector code implementation 2. use "platform_get_irq" and "platform_get_resource" 3. drop useless function return type, drop unless debug log 4. custom properties should be separate, so drop it 5. use DRM_XXX replase pr_xxx 6. drop dsi&dphy hal callback ops 7. drop unless callback ops checking 8. add comments for sprd dpu structure RFC v6: 1. Access registers via readl/writel 2. Checking for unsupported KMS properties (format, rotation, blend_mode, etc) on plane_check ops 3. Remove always true checks for dpu core ops RFC v7: 1. Fix DTC unit name warnings 2. Fix the problem of maintainers 3. Call drmm_mode_config_init to mode config init 4. Embed drm_device in sprd_drm and use devm_drm_dev_alloc 5. Replace DRM_XXX with drm_xxx on KMS module, but not suitable for other subsystems 6. Remove plane_update stuff, dpu handles all the HW update in crtc->atomic_flush 7. Dsi&Dphy Code structure adjustment, all move to "sprd/" v0: 1. Remove dpu_core_ops stuff layer for sprd drtc driver, but dpu_layer need to keeping. Because all the HW update in crtc->atomic_flush, we need temporary storage all layers for the dpu pageflip of atomic_flush. 2. Add ports subnode with port@X. v1: 1. Remove dphy and dsi graph binding, merge the dphy driver into the dsi. 2. Add commit messages for Unisoc's virtual nodes. v2: 1. Use drm_xxx to replace all DRM_XXX. 2. Use kzalloc to replace devm_kzalloc for sprd_dsi/sprd_dpu structure init. 3. Remove dpu_core_ops midlayer. v3: 1. Remove dpu_layer midlayer and commit layers by aotmic_update v4: 1. Move the devm_drm_dev_alloc to master_ops->bind function. 2. The managed drmm_mode_config_init() it is no longer necessary for drivers to explicitly call drm_mode_config_cleanup, so delete it. 3. Use drmm_helpers to allocate crtc ,planes and encoder. 4. Move allocate crtc ,planes, encoder to bind funtion. 5. Move rotation enum definitions to crtc layer reg bitfields. v5: 1. Remove subdir-ccflgas-y for Makefile. 2. Keep the selects sorted by alphabet for Kconfig. 3. Fix the checkpatch warnings. 4. Use mode_set_nofb instead of mode_valid callback. 5. Follow the OF-Graph bindings, use of_graph_get_port_by_id instead of of_parse_phandle. 6. Use zpos to represent the layer position. 7. Rebase to last drm misc branch. 8. Remove panel_in port for dsi node. 9. Drop the dsi ip file prefix. 10. Add Signed-off-by for dsi&dphy patch. 11. Use the mode_flags of mipi_dsi_device to setup crtc DPI and EDPI mode. v6: 1. Disable and clear interrupts before register dpu IRQ 2. Init dpi config used by crtc_state->adjusted_mode on mode_set_nofb 3. Remove enable_irq and disable_irq function call. 4. Remove drm_format_info function call. 5. Redesign the way to access the dsi register. 6. Reduce the dsi_context member variables. v7: 1. Fix codeing style issue by checkpatch. 2. Drop the pll registers structure define. 3. Use bridge API instead of drm panel API. 4. Register mipi_dsi_host on probe phase; 5. Remove iommu error interrupt handling function. 6. Remove some unused function. Kevin Tang (6): dt-bindings: display: add Unisoc's drm master bindings drm/sprd: add Unisoc's drm kms master dt-bindings: display: add Unisoc's dpu bindings drm/sprd: add Unisoc's drm display controller driver dt-bindings: display: add Unisoc's mipi dsi controller bindings drm/sprd: add Unisoc's drm mipi dsi&dphy driver .../display/sprd/sprd,display-subsystem.yaml | 64 + .../display/sprd/sprd,sharkl3-dpu.yaml| 77 ++ .../display/sprd/sprd,sharkl3-dsi-host.yaml | 88 ++ drivers/gpu/drm/Kconfig |2 + drivers/gpu/drm/Makefile |1 + drivers/gpu/drm/sprd/Kconfig | 13 + drivers/gpu/drm/sprd/Makefile |6 + drivers/gpu/drm/sprd/megacores_pll.c | 305 + drivers/gpu/drm/sprd/sprd_dpu.c | 884 ++ drivers/gpu/drm/sprd/sprd_dpu.h | 109 ++ drivers/gpu/drm/sprd/sprd_drm.c | 205 drivers/gpu/drm/sprd/sprd_drm.h | 19 + drivers/gpu/drm/sprd/sprd_dsi.c | 1065 + drivers/gpu/drm/sprd/sprd_dsi.h | 126 ++ 14 fil
[PATCH v7 1/6] dt-bindings: display: add Unisoc's drm master bindings
From: Kevin Tang The Unisoc DRM master device is a virtual device needed to list all DPU devices or other display interface nodes that comprise the graphics subsystem Unisoc's display pipeline have several components as below description, multi display controllers and corresponding physical interfaces. For different display scenarios, dpu0 and dpu1 maybe binding to different encoder. E.g: dpu0 and dpu1 both binding to DSI for dual mipi-dsi display; dpu0 binding to DSI for primary display, and dpu1 binding to DP for external display; Cc: Orson Zhai Cc: Chunyan Zhang Signed-off-by: Kevin Tang Reviewed-by: Rob Herring --- .../display/sprd/sprd,display-subsystem.yaml | 64 +++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/sprd,display-subsystem.yaml diff --git a/Documentation/devicetree/bindings/display/sprd/sprd,display-subsystem.yaml b/Documentation/devicetree/bindings/display/sprd/sprd,display-subsystem.yaml new file mode 100644 index 0..3d107e943 --- /dev/null +++ b/Documentation/devicetree/bindings/display/sprd/sprd,display-subsystem.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/sprd,display-subsystem.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc DRM master device + +maintainers: + - Kevin Tang + +description: | + The Unisoc DRM master device is a virtual device needed to list all + DPU devices or other display interface nodes that comprise the + graphics subsystem. + + Unisoc's display pipeline have several components as below description, + multi display controllers and corresponding physical interfaces. + For different display scenarios, dpu0 and dpu1 maybe binding to different + encoder. + + E.g: + dpu0 and dpu1 both binding to DSI for dual mipi-dsi display; + dpu0 binding to DSI for primary display, and dpu1 binding to DP for external display; + + +-+ + | | + |+-+ | + ++ | +++-+|DPHY/CPHY| | +--+ + |+->+dpu0+--->+MIPI|DSI +--->+Combo+->+Panel0| + |AXI | | +++-++-+ | +--+ + || | ^ | + || | | | + || | +---+ | + || | | | + |APB | | +--+-++---++---+ | +--+ + |+->+dpu1+--->+DisplayPort+--->+PHY+->+Panel1| + || | +++---++---+ | +--+ + ++ | | + +-+ + +properties: + compatible: +const: sprd,display-subsystem + + ports: +$ref: /schemas/types.yaml#/definitions/phandle-array +description: + Should contain a list of phandles pointing to display interface port + of DPU devices. + +required: + - compatible + - ports + +additionalProperties: false + +examples: + - | +display-subsystem { +compatible = "sprd,display-subsystem"; +ports = <&dpu_out>; +}; + -- 2.29.0
[PATCH v7 2/6] drm/sprd: add Unisoc's drm kms master
Adds drm support for the Unisoc's display subsystem. This is drm kms driver, this driver provides support for the application framework in Android, Yocto and more. Application framework can access Unisoc's display internal peripherals through libdrm or libkms, it's test ok by modetest (DRM/KMS test tool) and Android HWComposer. Cc: Orson Zhai Cc: Chunyan Zhang Signed-off-by: Kevin Tang v4: - Move the devm_drm_dev_alloc to master_ops->bind function. - The managed drmm_mode_config_init() it is no longer necessary for drivers to explicitly call drm_mode_config_cleanup, so delete it. v5: - Remove subdir-ccflgas-y for Makefile. - Keep the selects sorted by alphabet for Kconfig. --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile| 1 + drivers/gpu/drm/sprd/Kconfig| 11 ++ drivers/gpu/drm/sprd/Makefile | 3 + drivers/gpu/drm/sprd/sprd_drm.c | 203 drivers/gpu/drm/sprd/sprd_drm.h | 16 +++ 6 files changed, 236 insertions(+) create mode 100644 drivers/gpu/drm/sprd/Kconfig create mode 100644 drivers/gpu/drm/sprd/Makefile create mode 100644 drivers/gpu/drm/sprd/sprd_drm.c create mode 100644 drivers/gpu/drm/sprd/sprd_drm.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 2a926d0de..8220be1b5 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -380,6 +380,8 @@ source "drivers/gpu/drm/xlnx/Kconfig" source "drivers/gpu/drm/gud/Kconfig" +source "drivers/gpu/drm/sprd/Kconfig" + config DRM_HYPERV tristate "DRM Support for Hyper-V synthetic video device" depends on DRM && PCI && MMU && HYPERV diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 0dff40bb8..ec2756806 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -127,3 +127,4 @@ obj-$(CONFIG_DRM_TIDSS) += tidss/ obj-y += xlnx/ obj-y += gud/ obj-$(CONFIG_DRM_HYPERV) += hyperv/ +obj-$(CONFIG_DRM_SPRD) += sprd/ diff --git a/drivers/gpu/drm/sprd/Kconfig b/drivers/gpu/drm/sprd/Kconfig new file mode 100644 index 0..726c3e76d --- /dev/null +++ b/drivers/gpu/drm/sprd/Kconfig @@ -0,0 +1,11 @@ +config DRM_SPRD + tristate "DRM Support for Unisoc SoCs Platform" + depends on ARCH_SPRD || COMPILE_TEST + depends on DRM && OF + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_KMS_HELPER + help + Choose this option if you have a Unisoc chipset. + If M is selected the module will be called sprd_drm. + diff --git a/drivers/gpu/drm/sprd/Makefile b/drivers/gpu/drm/sprd/Makefile new file mode 100644 index 0..9850f00b8 --- /dev/null +++ b/drivers/gpu/drm/sprd/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y := sprd_drm.o diff --git a/drivers/gpu/drm/sprd/sprd_drm.c b/drivers/gpu/drm/sprd/sprd_drm.c new file mode 100644 index 0..bb87f28f2 --- /dev/null +++ b/drivers/gpu/drm/sprd/sprd_drm.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Unisoc Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sprd_drm.h" + +#define DRIVER_NAME"sprd" +#define DRIVER_DESC"Spreadtrum SoCs' DRM Driver" +#define DRIVER_DATE"20200201" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = { + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, +}; + +static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static void sprd_drm_mode_config_init(struct drm_device *drm) +{ + drm->mode_config.min_width = 0; + drm->mode_config.min_height = 0; + drm->mode_config.max_width = 8192; + drm->mode_config.max_height = 8192; + drm->mode_config.allow_fb_modifiers = true; + + drm->mode_config.funcs = &sprd_drm_mode_config_funcs; + drm->mode_config.helper_private = &sprd_drm_mode_config_helper; +} + +DEFINE_DRM_GEM_CMA_FOPS(sprd_drm_fops); + +static struct drm_driver sprd_drm_drv = { + .driver_features= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + .fops = &sprd_drm_fops, + + /* GEM Operations */ + DRM_GEM_CMA_DRIVER_OPS, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, +}; + +static int sprd_drm_bind(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm; + struct sprd_drm *sprd; + int ret; + + sprd = devm_drm
[PATCH v7 3/6] dt-bindings: display: add Unisoc's dpu bindings
From: Kevin Tang DPU (Display Processor Unit) is the Display Controller for the Unisoc SoCs which transfers the image data from a video memory buffer to an internal LCD interface. Cc: Orson Zhai Cc: Chunyan Zhang Signed-off-by: Kevin Tang Reviewed-by: Rob Herring --- .../display/sprd/sprd,sharkl3-dpu.yaml| 77 +++ 1 file changed, 77 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/sprd,sharkl3-dpu.yaml diff --git a/Documentation/devicetree/bindings/display/sprd/sprd,sharkl3-dpu.yaml b/Documentation/devicetree/bindings/display/sprd/sprd,sharkl3-dpu.yaml new file mode 100644 index 0..4ebea60b8 --- /dev/null +++ b/Documentation/devicetree/bindings/display/sprd/sprd,sharkl3-dpu.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/sprd,sharkl3-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc Sharkl3 Display Processor Unit (DPU) + +maintainers: + - Kevin Tang + +description: | + DPU (Display Processor Unit) is the Display Controller for the Unisoc SoCs + which transfers the image data from a video memory buffer to an internal + LCD interface. + +properties: + compatible: +const: sprd,sharkl3-dpu + + reg: +maxItems: 1 + + interrupts: +maxItems: 1 + + clocks: +minItems: 2 + + clock-names: +items: + - const: clk_src_128m + - const: clk_src_384m + + power-domains: +maxItems: 1 + + iommus: +maxItems: 1 + + port: +type: object +description: + A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + That port should be the output endpoint, usually output to + the associated DSI. + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | +#include +#include +dpu: dpu@6300 { +compatible = "sprd,sharkl3-dpu"; +reg = <0x6300 0x1000>; +interrupts = ; +clock-names = "clk_src_128m", "clk_src_384m"; + +clocks = <&pll CLK_TWPLL_128M>, + <&pll CLK_TWPLL_384M>; + +dpu_port: port { +dpu_out: endpoint { +remote-endpoint = <&dsi_in>; +}; +}; +}; -- 2.29.0
[PATCH v7 4/6] drm/sprd: add Unisoc's drm display controller driver
Adds DPU(Display Processor Unit) support for the Unisoc's display subsystem. It's support multi planes, scaler, rotation, PQ(Picture Quality) and more. v2: - Use drm_xxx to replace all DRM_XXX. - Use kzalloc to replace devm_kzalloc for sprd_dpu structure init. v3: - Remove dpu_layer stuff layer and commit layers by aotmic_update v4: - Use drmm_helpers to allocate crtc and planes. - Move rotation enum definitions to crtc layer reg bitfields. - Move allocate crtc and planes to bind function. v5: - Fix the checkpatch warnings. - Use mode_set_nofb instead of mode_valid callback. - Follow the OF-Graph bindings, use of_graph_get_port_by_id instead of of_parse_phandle. - Use zpos to represent the layer position. - Rebase to last drm misc branch. v6: - Disable and clear interrupts before register dpu IRQ - Init dpi config used by crtc_state->adjusted_mode on mode_set_nofb - Remove enable_irq and disable_irq function call. - Remove drm_format_info function call. v7: - Remove iommu error interrupt handling function. Cc: Orson Zhai Cc: Chunyan Zhang Signed-off-by: Kevin Tang --- drivers/gpu/drm/sprd/Kconfig| 1 + drivers/gpu/drm/sprd/Makefile | 3 +- drivers/gpu/drm/sprd/sprd_dpu.c | 867 drivers/gpu/drm/sprd/sprd_dpu.h | 109 drivers/gpu/drm/sprd/sprd_drm.c | 1 + drivers/gpu/drm/sprd/sprd_drm.h | 2 + 6 files changed, 982 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h diff --git a/drivers/gpu/drm/sprd/Kconfig b/drivers/gpu/drm/sprd/Kconfig index 726c3e76d..37762c333 100644 --- a/drivers/gpu/drm/sprd/Kconfig +++ b/drivers/gpu/drm/sprd/Kconfig @@ -5,6 +5,7 @@ config DRM_SPRD select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER select DRM_KMS_HELPER + select VIDEOMODE_HELPERS help Choose this option if you have a Unisoc chipset. If M is selected the module will be called sprd_drm. diff --git a/drivers/gpu/drm/sprd/Makefile b/drivers/gpu/drm/sprd/Makefile index 9850f00b8..ab12b95e6 100644 --- a/drivers/gpu/drm/sprd/Makefile +++ b/drivers/gpu/drm/sprd/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y := sprd_drm.o +obj-y := sprd_drm.o \ + sprd_dpu.o diff --git a/drivers/gpu/drm/sprd/sprd_dpu.c b/drivers/gpu/drm/sprd/sprd_dpu.c new file mode 100644 index 0..1d10d0998 --- /dev/null +++ b/drivers/gpu/drm/sprd/sprd_dpu.c @@ -0,0 +1,867 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Unisoc Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sprd_drm.h" +#include "sprd_dpu.h" + +/* Global control registers */ +#define REG_DPU_CTRL 0x04 +#define REG_DPU_CFG0 0x08 +#define REG_PANEL_SIZE 0x20 +#define REG_BLEND_SIZE 0x24 +#define REG_BG_COLOR 0x2C + +/* Layer0 control registers */ +#define REG_LAY_BASE_ADDR0 0x30 +#define REG_LAY_BASE_ADDR1 0x34 +#define REG_LAY_BASE_ADDR2 0x38 +#define REG_LAY_CTRL 0x40 +#define REG_LAY_SIZE 0x44 +#define REG_LAY_PITCH 0x48 +#define REG_LAY_POS0x4C +#define REG_LAY_ALPHA 0x50 +#define REG_LAY_CROP_START 0x5C + +/* Interrupt control registers */ +#define REG_DPU_INT_EN 0x1E0 +#define REG_DPU_INT_CLR0x1E4 +#define REG_DPU_INT_STS0x1E8 + +/* DPI control registers */ +#define REG_DPI_CTRL 0x1F0 +#define REG_DPI_H_TIMING 0x1F4 +#define REG_DPI_V_TIMING 0x1F8 + +/* MMU control registers */ +#define REG_MMU_EN 0x800 +#define REG_MMU_VPN_RANGE 0x80C +#define REG_MMU_PPN1 0x83C +#define REG_MMU_RANGE1 0x840 +#define REG_MMU_PPN2 0x844 +#define REG_MMU_RANGE2 0x848 + +/* Global control bits */ +#define BIT_DPU_RUNBIT(0) +#define BIT_DPU_STOP BIT(1) +#define BIT_DPU_REG_UPDATE BIT(2) +#define BIT_DPU_IF_EDPIBIT(0) + +/* Layer control bits */ +#define BIT_DPU_LAY_EN BIT(0) +#define BIT_DPU_LAY_LAYER_ALPHA(0x01 << 2) +#define BIT_DPU_LAY_COMBO_ALPHA(0x02 << 2) +#define BIT_DPU_LAY_FORMAT_YUV422_2PLANE (0x00 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_2PLANE (0x01 << 4) +#define BIT_DPU_LAY_FORMAT_YUV420_3PLANE (0x02 << 4) +#define BIT_DPU_LAY_FORMAT_ARGB(0x03 << 4) +#define BIT_DPU_LAY_FORMAT_RGB565 (0x04 << 4) +#define BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 (0x00 << 8) +#define BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 (0x01 << 8) +#define BIT_DPU_LAY_NO_SWITCH
[PATCH v7 5/6] dt-bindings: display: add Unisoc's mipi dsi controller bindings
From: Kevin Tang Adds MIPI DSI Controller support for Unisoc's display subsystem. v5: - Remove panel_in port for dsi node. Cc: Orson Zhai Cc: Chunyan Zhang Signed-off-by: Kevin Tang Reviewed-by: Rob Herring --- .../display/sprd/sprd,sharkl3-dsi-host.yaml | 88 +++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/sprd/sprd,sharkl3-dsi-host.yaml diff --git a/Documentation/devicetree/bindings/display/sprd/sprd,sharkl3-dsi-host.yaml b/Documentation/devicetree/bindings/display/sprd/sprd,sharkl3-dsi-host.yaml new file mode 100644 index 0..bc5594d18 --- /dev/null +++ b/Documentation/devicetree/bindings/display/sprd/sprd,sharkl3-dsi-host.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sprd/sprd,sharkl3-dsi-host.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc MIPI DSI Controller + +maintainers: + - Kevin Tang + +properties: + compatible: +const: sprd,sharkl3-dsi-host + + reg: +maxItems: 1 + + interrupts: +maxItems: 2 + + clocks: +minItems: 1 + + clock-names: +items: + - const: clk_src_96m + + power-domains: +maxItems: 1 + + ports: +type: object + +properties: + "#address-cells": +const: 1 + + "#size-cells": +const: 0 + + port@0: +type: object +description: + A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + That port should be the input endpoint, usually coming from + the associated DPU. + +required: + - "#address-cells" + - "#size-cells" + - port@0 + +additionalProperties: false + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - ports + +additionalProperties: false + +examples: + - | +#include +#include +dsi: dsi@6310 { +compatible = "sprd,sharkl3-dsi-host"; +reg = <0x6310 0x1000>; +interrupts = , + ; +clock-names = "clk_src_96m"; +clocks = <&pll CLK_TWPLL_96M>; +ports { +#address-cells = <1>; +#size-cells = <0>; +port@0 { +reg = <0>; +dsi_in: endpoint { +remote-endpoint = <&dpu_out>; +}; +}; +}; +}; -- 2.29.0
[PATCH v7 6/6] drm/sprd: add Unisoc's drm mipi dsi&dphy driver
Adds dsi host controller support for the Unisoc's display subsystem. Adds dsi phy support for the Unisoc's display subsystem. Only MIPI DSI Displays supported, DP/TV/HMDI will be support in the feature. v1: - Remove dphy and dsi graph binding, merge the dphy driver into the dsi. v2: - Use drm_xxx to replace all DRM_XXX. - Use kzalloc to replace devm_kzalloc for sprd_dsi structure init. v4: - Use drmm_helpers to allocate encoder. - Move allocate encoder and connector to bind function. v5: - Drop the dsi ip file prefix. - Fix the checkpatch warnings. - Add Signed-off-by for dsi&dphy patch. - Use the mode_flags of mipi_dsi_device to setup crtc DPI and EDPI mode. v6: - Redesign the way to access the dsi register. - Reduce the dsi_context member variables. v7: - Fix codeing style issue by checkpatch. - Drop the pll registers structure define. - Use bridge API instead of drm panel API. - Register mipi_dsi_host on probe phase; - Remove some unused function. --- drivers/gpu/drm/sprd/Kconfig |1 + drivers/gpu/drm/sprd/Makefile|4 +- drivers/gpu/drm/sprd/megacores_pll.c | 305 drivers/gpu/drm/sprd/sprd_dpu.c | 17 + drivers/gpu/drm/sprd/sprd_drm.c |1 + drivers/gpu/drm/sprd/sprd_drm.h |1 + drivers/gpu/drm/sprd/sprd_dsi.c | 1065 ++ drivers/gpu/drm/sprd/sprd_dsi.h | 126 +++ 8 files changed, 1519 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sprd/megacores_pll.c create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.c create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.h diff --git a/drivers/gpu/drm/sprd/Kconfig b/drivers/gpu/drm/sprd/Kconfig index 37762c333..3edeaeca0 100644 --- a/drivers/gpu/drm/sprd/Kconfig +++ b/drivers/gpu/drm/sprd/Kconfig @@ -5,6 +5,7 @@ config DRM_SPRD select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER select DRM_KMS_HELPER + select DRM_MIPI_DSI select VIDEOMODE_HELPERS help Choose this option if you have a Unisoc chipset. diff --git a/drivers/gpu/drm/sprd/Makefile b/drivers/gpu/drm/sprd/Makefile index ab12b95e6..73f96c459 100644 --- a/drivers/gpu/drm/sprd/Makefile +++ b/drivers/gpu/drm/sprd/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-y := sprd_drm.o \ - sprd_dpu.o + sprd_dpu.o \ + sprd_dsi.o \ + megacores_pll.o diff --git a/drivers/gpu/drm/sprd/megacores_pll.c b/drivers/gpu/drm/sprd/megacores_pll.c new file mode 100644 index 0..3091dfdc1 --- /dev/null +++ b/drivers/gpu/drm/sprd/megacores_pll.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Unisoc Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "sprd_dsi.h" + +#define L 0 +#define H 1 +#define CLK0 +#define DATA 1 +#define INFINITY 0x +#define MIN_OUTPUT_FREQ(100) + +#define AVERAGE(a, b) (min(a, b) + abs((b) - (a)) / 2) + +/* sharkle */ +#define VCO_BAND_LOW 750 +#define VCO_BAND_MID 1100 +#define VCO_BAND_HIGH 1500 +#define PHY_REF_CLK26000 + +static int dphy_calc_pll_param(struct dphy_pll *pll) +{ + const u32 khz = 1000; + const u32 mhz = 100; + const unsigned long long factor = 100; + unsigned long long tmp; + int i; + + pll->potential_fvco = pll->freq / khz; + pll->ref_clk = PHY_REF_CLK / khz; + + for (i = 0; i < 4; ++i) { + if (pll->potential_fvco >= VCO_BAND_LOW && + pll->potential_fvco <= VCO_BAND_HIGH) { + pll->fvco = pll->potential_fvco; + pll->out_sel = BIT(i); + break; + } + pll->potential_fvco <<= 1; + } + if (pll->fvco == 0) + return -EINVAL; + + if (pll->fvco >= VCO_BAND_LOW && pll->fvco <= VCO_BAND_MID) { + /* vco band control */ + pll->vco_band = 0x0; + /* low pass filter control */ + pll->lpf_sel = 1; + } else if (pll->fvco > VCO_BAND_MID && pll->fvco <= VCO_BAND_HIGH) { + pll->vco_band = 0x1; + pll->lpf_sel = 0; + } else { + return -EINVAL; + } + + pll->nint = pll->fvco / pll->ref_clk; + tmp = pll->fvco * factor * mhz; + do_div(tmp, pll->ref_clk); + tmp = tmp - pll->nint * factor * mhz; + tmp *= BIT(20); + do_div(tmp, 1); + pll->kint = (u32)tmp; + pll->refin = 3; /* pre-divider bypass */ + pll->sdm_en = true; /* use fraction N PLL */ + pll->fdk_s = 0x1; /* fraction */ + pll->cp_s = 0x0; + pll->det_delay = 0x1; + + return 0; +} + +static void dphy_set_pll_
Re: [PATCH 00/47] GuC submission support
Quoting Matthew Brost (2021-10-22 19:42:19) > On Fri, Oct 22, 2021 at 12:35:04PM +0300, Joonas Lahtinen wrote: > > Hi Matt & John, > > > > Can you please queue patches with the right Fixes: references to convert > > all the GuC tracepoints to be protected by the LOW_LEVEL_TRACEPOINTS > > protection for now. Please do so before next Wednesday so we get it > > queued in drm-intel-next-fixes. > > > > Don't we already do that? I checked i915_trace.h and every tracepoint I > added (intel_context class, i915_request_guc_submit) is protected by > LOW_LEVEL_TRACEPOINTS. > > The only thing I changed outside of that protection is adding the guc_id > field to existing i915_request class tracepoints. It's the first search hit for "guc" inside the i915_trace.h file :) > Without the guc_id in > those tracepoints these are basically useless with GuC submission. We > could revert that if it is a huge deal but as I said then they are > useless... Let's eliminate it for now and restore the tracepoint exactly as it was. If there is an immediate need, we should instead have an auxilary tracepoint which is enabled only through LOW_LEVEL_TRACEPOINTS and that amends the information of the basic tracepoint. For the longer term solution we should align towards the dma fence tracepoints. When those are combined with the OA information, one should be able to get a good understanding of both the software and hardware scheduling decisions. Regards, Joonas > > Matt > > > There's the orthogonal track to discuss what would be the stable set of > > tracepoints we could expose. However, before that discussion is closed, > > let's keep a rather strict line to avoid potential maintenance burned. > > > > We can then relax in the future as needed. > > > > Regards, Joonas > > > > Quoting Matthew Brost (2021-06-24 10:04:29) > > > As discussed in [1], [2] we are enabling GuC submission support in the > > > i915. This is a subset of the patches in step 5 described in [1], > > > basically it is absolute to enable CI with GuC submission on gen11+ > > > platforms. > > > > > > This series itself will likely be broken down into smaller patch sets to > > > merge. Likely into CTBs changes, basic submission, virtual engines, and > > > resets. > > > > > > A following series will address the missing patches remaining from [1]. > > > > > > Locally tested on TGL machine and basic tests seem to be passing. > > > > > > Signed-off-by: Matthew Brost > > > > > > [1] https://patchwork.freedesktop.org/series/89844/ > > > [2] https://patchwork.freedesktop.org/series/91417/ > > > > > > Daniele Ceraolo Spurio (1): > > > drm/i915/guc: Unblock GuC submission on Gen11+ > > > > > > John Harrison (10): > > > drm/i915/guc: Module load failure test for CT buffer creation > > > drm/i915: Track 'serial' counts for virtual engines > > > drm/i915/guc: Provide mmio list to be saved/restored on engine reset > > > drm/i915/guc: Don't complain about reset races > > > drm/i915/guc: Enable GuC engine reset > > > drm/i915/guc: Fix for error capture after full GPU reset with GuC > > > drm/i915/guc: Hook GuC scheduling policies up > > > drm/i915/guc: Connect reset modparam updates to GuC policy flags > > > drm/i915/guc: Include scheduling policies in the debugfs state dump > > > drm/i915/guc: Add golden context to GuC ADS > > > > > > Matthew Brost (36): > > > drm/i915/guc: Relax CTB response timeout > > > drm/i915/guc: Improve error message for unsolicited CT response > > > drm/i915/guc: Increase size of CTB buffers > > > drm/i915/guc: Add non blocking CTB send function > > > drm/i915/guc: Add stall timer to non blocking CTB send function > > > drm/i915/guc: Optimize CTB writes and reads > > > drm/i915/guc: Add new GuC interface defines and structures > > > drm/i915/guc: Remove GuC stage descriptor, add lrc descriptor > > > drm/i915/guc: Add lrc descriptor context lookup array > > > drm/i915/guc: Implement GuC submission tasklet > > > drm/i915/guc: Add bypass tasklet submission path to GuC > > > drm/i915/guc: Implement GuC context operations for new inteface > > > drm/i915/guc: Insert fence on context when deregistering > > > drm/i915/guc: Defer context unpin until scheduling is disabled > > > drm/i915/guc: Disable engine barriers with GuC during unpin > > > drm/i915/guc: Extend deregistration fence to schedule disable > > > drm/i915: Disable preempt busywait when using GuC scheduling > > > drm/i915/guc: Ensure request ordering via completion fences > > > drm/i915/guc: Disable semaphores when using GuC scheduling > > > drm/i915/guc: Ensure G2H response has space in buffer > > > drm/i915/guc: Update intel_gt_wait_for_idle to work with GuC > > > drm/i915/guc: Update GuC debugfs to support new GuC > > > drm/i915/guc: Add several request trace points > > > drm/i915: Add intel_context tracing > > > drm/i915/guc: GuC virtual engines > > > drm/i915: Hold reference to intel_context over life of i915
Re: [PATCH v2] dma-buf: move dma-buf symbols into the DMA_BUF module namespace
On Sun, Oct 10, 2021 at 02:46:28PM +0200, Greg Kroah-Hartman wrote: > In order to better track where in the kernel the dma-buf code is used, > put the symbols in the namespace DMA_BUF and modify all users of the > symbols to properly import the namespace to not break the build at the > same time. > > Now the output of modinfo shows the use of these symbols, making it > easier to watch for users over time: > > $ modinfo drivers/misc/fastrpc.ko | grep import > import_ns: DMA_BUF > > Cc: "Pan, Xinhui" > Cc: David Airlie > Cc: Maarten Lankhorst > Cc: Maxime Ripard > Cc: Thomas Zimmermann > Cc: Mauro Carvalho Chehab > Cc: dri-devel@lists.freedesktop.org > Acked-by: Daniel Vetter > Acked-by: Christian König > Acked-by: Arnd Bergmann > Acked-by: Sumit Semwal > Acked-by: Alex Deucher > Signed-off-by: Greg Kroah-Hartman > --- > v2: added lots of acks > added 2 more drivers that needed the change, as found by Arnd Ping? Any ideas on what needs to happen to get this into the tree? Or can I take it through my char-misc tree? I seem to have a bunch of acks on it by the respective maintainers... thanks, greg k-h
Re: [RFC PATCH] drm/aperture: Add param to disable conflicting framebuffers removal
On 2021-10-24 22:32, Javier Martinez Canillas wrote: > Hello Ville, > > On 10/22/21 21:12, Ville Syrjälä wrote: >> On Fri, Oct 22, 2021 at 04:40:40PM +0200, Javier Martinez Canillas wrote: >>> The simpledrm driver allows to use the frame buffer that was set-up by the >>> firmware. This gives early video output before the platform DRM driver is >>> probed and takes over. >>> >>> But it would be useful to have a way to disable this take over by the real >>> DRM drivers. For example, there may be bugs in the DRM drivers that could >>> cause the display output to not work correctly. >>> >>> For those cases, it would be good to keep the simpledrm driver instead and >>> at least get a working display as set-up by the firmware. >>> >>> Let's add a drm.remove_fb boolean kernel command line parameter, that when >>> set to false will prevent the conflicting framebuffers to being removed. >>> >>> Since the drivers call drm_aperture_remove_conflicting_framebuffers() very >>> early in their probe callback, this will cause the drivers' probe to fail. >> >> Why is that better than just modprobe.blacklisting those drivers? > > Because would allow to deny list all native (as Thomas called it) DRM drivers > and only allow the simpledrm driver to be probed. This is useful for distros, > since could add a "Basic graphics mode" to the boot menu entries, that could > boot the kernel passing a "drm.disable_native_drivers=1" cmdline option. > > That way, if there's any problem with a given DRM driver, the distro may be > installed and booted using the simpledrm driver and troubleshoot why a native > DRM driver is not working. Or try updating the kernel package, etc. For troubleshooting, it'll be helpful if this new parameter can be enabled for the boot via the kernel command line, then disabled again after boot-up. One simple possibility for this would be allowing the parameter to be changed via /sys/module/drm/parameters/, which I suspect doesn't work with the patch as is (due to the 0600 permissions). -- Earthling Michel Dänzer| https://redhat.com Libre software enthusiast | Mesa and Xwayland developer
Re: [PATCH v2] dma-buf: move dma-buf symbols into the DMA_BUF module namespace
Am 25.10.21 um 12:36 schrieb Greg Kroah-Hartman: On Sun, Oct 10, 2021 at 02:46:28PM +0200, Greg Kroah-Hartman wrote: In order to better track where in the kernel the dma-buf code is used, put the symbols in the namespace DMA_BUF and modify all users of the symbols to properly import the namespace to not break the build at the same time. Now the output of modinfo shows the use of these symbols, making it easier to watch for users over time: $ modinfo drivers/misc/fastrpc.ko | grep import import_ns: DMA_BUF Cc: "Pan, Xinhui" Cc: David Airlie Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: Mauro Carvalho Chehab Cc: dri-devel@lists.freedesktop.org Acked-by: Daniel Vetter Acked-by: Christian König Acked-by: Arnd Bergmann Acked-by: Sumit Semwal Acked-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- v2: added lots of acks added 2 more drivers that needed the change, as found by Arnd Ping? Any ideas on what needs to happen to get this into the tree? Or can I take it through my char-misc tree? I seem to have a bunch of acks on it by the respective maintainers... I could push that upstream through the drm-misc-next tree if you like, but honestly char-misc sounds like the better approach since this touches a lot of drivers outside of drm as well. Thanks, Christian. thanks, greg k-h
Re: [PATCH] drm/bridge: Fix the bridge chain order for pre_enable / post_disable
Hi All, On 21.10.2021 22:21, Sam Ravnborg wrote: Hi Douglas, On Thu, Oct 21, 2021 at 12:29:01PM -0700, Douglas Anderson wrote: Right now, the chaining order of pre_enable/enable/disable/post_disable looks like this: pre_enable: start from connector and move to encoder enable: start from encoder and move to connector disable: start from connector and move to encoder post_disable: start from encoder and move to connector In the above, it can be seen that at least pre_enable() and post_disable() are opposites of each other and enable() and disable() are opposites. However, it seems broken that pre_enable() and enable() would not move in the same direction. In other parts of Linux you can see that various stages move in the same order. For instance, during system suspend the "early" calls run in the same order as the normal calls run in the same order as the "late" calls run in the same order as the "noirq" calls. Let fix the above so that it makes more sense. Now we'll have: pre_enable: start from encoder and move to connector enable: start from encoder and move to connector disable: start from connector and move to encoder post_disable: start from connector and move to encoder This order is chosen because if there are parent-child relationships anywhere I would expect that the encoder would be a parent and the connector a child--not the other way around. This makes good sense as you describe it. I hope others can add more useful feedback. Added Andrzej Hajda to the mail, as he have expressed concerns with the chain of bridges before. Thanks Sam, but I am not sure about useful feedback - when I see bridge chain issues it automatically triggers "whining mode" in my head :) This can be important when using the DP AUX bus to instantiate a panel. The DP AUX bus is likely part of a bridge driver and is a parent of the panel. We'd like the bridge to be pre_enabled before the panel and the panel to be post_disabled before the bridge. Specifically, this allows pm_runtime_put_sync_suspend() in a bridge driver's post_suspend to work properly even a panel is under it. NOTE: it's entirely possible that this change could break someone who was relying on the old order. Hopefully this isn't the case, but if this does break someone it seems like it's better to do it sonner rather than later so we can fix everyone to handle the order that makes the most sense. It will break for sure. So the question is: if it is worth changing? New order seems good for eDP, DSI sinks [1], probably other as well. Old order is better for example for THC63LVD1024 [2 p. 20], I guess for many other sinks as well. I am not even sure if it is protocol specific (LVDS, RGB, HDMI,...), or it depends on specific hw pairs (source->sink). This is why I complain about the bridge chain - assumption that one fixed call order will work for all setups seems to me ridiculous. Going back to the question - changing the order from fixed one to another fixed one will not solve general issue. What can we do then? 1. Configurable call order? Probably doable: every chain element should expose info if it's call should be before or after source, then some core helper will create queue of callbacks. Seems quite complicated, hides the logic from implementer and not fully flexible (for example, there are protocols which require to perform sth on source, then on sink, then again on the source). 2. Stop using bridge chain and call sink ops directly from the source (this is what Exynos and VC4 do): is flexible and straightforward, gives full control to the source. 3. Use different abstractions to enforce proper initialization order (like extending mipi_dsi_host_ops): requires existence of transport bus abstraction (only DSI at the moment(?)). ... other ideas? Another idea, connected to the subject - some protocols require some negotiations between source and sink bus format, or more steps than pre_enable, enable ops to establish link. I wonder if encapsulating drm_bridge in some protocol specific struct wouldn't be a solution, it can be helpful as well in case of the subject. For example: struct drm_bridge_edp { const struct drm_bridge_edp_funcs *funcs; struct drm_bridge base; ... }; Then source could promote bridge pointer to bridge_edp pointer (if applicable) and perform edp specific stuff. To make it working well pre-enable order should be as proposed in this patchsets (encoder -> connector), as the source should initiate negotiations. Btw this encapsulation stuff above asks to rename drm_bridge to drm_sink, otherwise it would be confusing as bridges have two ends. Regards Andrzej [1]: I use term sink as short equivalent for 'bridges AND panels' (another issue in DRMs). [2]: https://www.mouser.com/datasheet/2/286/THC63LVD1024-1396205.pdf Regards Andrzej A FURTHER NOTE: Looking closer at commit 4e5763f03e10 ("drm/bridge: ti-sn65dsi86: Wrap panel
Re: [Intel-gfx] [PATCH v2 14/17] uapi/drm/dg2: Format modifier for DG2 unified compression and clear color
On 21.10.2021 17.35, Ville Syrjälä wrote: On Thu, Oct 21, 2021 at 07:56:24PM +0530, Ramalingam C wrote: From: Matt Roper DG2 unifies render compression and media compression into a single format for the first time. The programming and buffer layout is supposed to match compression on older gen12 platforms, but the actual compression algorithm is different from any previous platform; as such, we need a new framebuffer modifier to represent buffers in this format, but otherwise we can re-use the existing gen12 compression driver logic. DG2 clear color render compression uses Tile4 layout. Therefore, we need to define a new format modifier for uAPI to support clear color rendering. Signed-off-by: Matt Roper Signed-off-by: Mika Kahola (v2) Signed-off-by: Juha-Pekka Heikkilä Signed-off-by: Ramalingam C cc: Simon Ser Cc: Pekka Paalanen --- drivers/gpu/drm/i915/display/intel_display.c | 3 ++ .../drm/i915/display/intel_display_types.h| 10 +++- drivers/gpu/drm/i915/display/intel_fb.c | 7 +++ .../drm/i915/display/skl_universal_plane.c| 49 +-- include/uapi/drm/drm_fourcc.h | 30 5 files changed, 94 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9b678839bf2b..2949fe9f5b9f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1013,6 +1013,9 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd) cmd->pixel_format); case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: + case I915_FORMAT_MOD_F_TILED_DG2_RC_CCS: + case I915_FORMAT_MOD_F_TILED_DG2_MC_CCS: + case I915_FORMAT_MOD_F_TILED_DG2_RC_CCS_CC: return lookup_format_info(gen12_ccs_formats, ARRAY_SIZE(gen12_ccs_formats), cmd->pixel_format); That seems not right. Flat CCS is invisible to the user so the format info should not include a CCS plane. I had cleaned out those rc and mc ccs from here long time ago, I wonder where did they come back from? On my development tree they're not there. Also I915_FORMAT_MOD_F_TILED_DG2_RC_CCS_CC is here in totally wrong place, it should have its own gen12_flat_ccs_cc_formats table. /Juha-Pekka
Re: [PATCH] drm/bridge: Fix the bridge chain order for pre_enable / post_disable
Hello, On Mon, Oct 25, 2021 at 01:00:10PM +0200, Andrzej Hajda wrote: > On 21.10.2021 22:21, Sam Ravnborg wrote: > > On Thu, Oct 21, 2021 at 12:29:01PM -0700, Douglas Anderson wrote: > >> Right now, the chaining order of > >> pre_enable/enable/disable/post_disable looks like this: > >> > >> pre_enable: start from connector and move to encoder > >> enable: start from encoder and move to connector > >> disable: start from connector and move to encoder > >> post_disable: start from encoder and move to connector > >> > >> In the above, it can be seen that at least pre_enable() and > >> post_disable() are opposites of each other and enable() and disable() > >> are opposites. However, it seems broken that pre_enable() and enable() > >> would not move in the same direction. In other parts of Linux you can > >> see that various stages move in the same order. For instance, during > >> system suspend the "early" calls run in the same order as the normal > >> calls run in the same order as the "late" calls run in the same order > >> as the "noirq" calls. > >> > >> Let fix the above so that it makes more sense. Now we'll have: > >> > >> pre_enable: start from encoder and move to connector > >> enable: start from encoder and move to connector > >> disable: start from connector and move to encoder > >> post_disable: start from connector and move to encoder > >> > >> This order is chosen because if there are parent-child relationships > >> anywhere I would expect that the encoder would be a parent and the > >> connector a child--not the other way around. > > > > This makes good sense as you describe it. I hope others can add more > > useful feedback. > > Added Andrzej Hajda to the mail, as he have > > expressed concerns with the chain of bridges before. > > Thanks Sam, but I am not sure about useful feedback - when I see bridge > chain issues it automatically triggers "whining mode" in my head :) > > >> This can be important when using the DP AUX bus to instantiate a > >> panel. The DP AUX bus is likely part of a bridge driver and is a > >> parent of the panel. We'd like the bridge to be pre_enabled before the > >> panel and the panel to be post_disabled before the > >> bridge. Specifically, this allows pm_runtime_put_sync_suspend() in a > >> bridge driver's post_suspend to work properly even a panel is under > >> it. > >> > >> NOTE: it's entirely possible that this change could break someone who > >> was relying on the old order. Hopefully this isn't the case, but if > >> this does break someone it seems like it's better to do it sonner > >> rather than later so we can fix everyone to handle the order that > >> makes the most sense. > > It will break for sure. So the question is: if it is worth changing? > > New order seems good for eDP, DSI sinks [1], probably other as well. > > Old order is better for example for THC63LVD1024 [2 p. 20], I guess for > many other sinks as well. > > I am not even sure if it is protocol specific (LVDS, RGB, HDMI,...), or > it depends on specific hw pairs (source->sink). > > This is why I complain about the bridge chain - assumption that one > fixed call order will work for all setups seems to me ridiculous. > > Going back to the question - changing the order from fixed one to > another fixed one will not solve general issue. > > What can we do then? > > 1. Configurable call order? Probably doable: every chain element should > expose info if it's call should be before or after source, then some > core helper will create queue of callbacks. Seems quite complicated, > hides the logic from implementer and not fully flexible (for example, > there are protocols which require to perform sth on source, then on > sink, then again on the source). > > 2. Stop using bridge chain and call sink ops directly from the source > (this is what Exynos and VC4 do): is flexible and straightforward, gives > full control to the source. And breaks interoperability, because different sources end up calling operations in different orders. We end up having different sinks that expect calls in different ways, and divide the world in sink/source groups that don't interoperate :-( > 3. Use different abstractions to enforce proper initialization order > (like extending mipi_dsi_host_ops): requires existence of transport bus > abstraction (only DSI at the moment(?)). A real bus seems overkill, but we could have drm_bridge operations specific to particular hardware interfaces. > ... other ideas? I don't like it because of the amount of work it would require to switch to such a model, but I'm really starting to think that a variation of the second option would be best, where the sink controls the source instead of having the source controlling the sink. It's the sink that knows about its enabling/disabling sequence, and about how the source needs to be controlled to match it. > Another idea, connected to the subject - some protocols require some > negotiations bet
[PATCH] drm/i915: Use ERR_CAST instead of ERR_PTR(PTR_ERR())
Fix following coccicheck warning: ./drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:3117:15-22: WARNING: ERR_CAST can be used with eb->requests[i]. Signed-off-by: Wan Jiabing --- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 4d7da07442f2..eb2dcaf78d08 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -3114,7 +3114,7 @@ eb_requests_create(struct i915_execbuffer *eb, struct dma_fence *in_fence, /* Allocate a request for this batch buffer nice and early. */ eb->requests[i] = i915_request_create(eb_find_context(eb, i)); if (IS_ERR(eb->requests[i])) { - out_fence = ERR_PTR(PTR_ERR(eb->requests[i])); + out_fence = ERR_CAST(eb->requests[i]); eb->requests[i] = NULL; return out_fence; } -- 2.20.1
[PATCH] drm/udl: fix control-message timeout
USB control-message timeouts are specified in milliseconds and should specifically not vary with CONFIG_HZ. Fixes: 5320918b9a87 ("drm/udl: initial UDL driver (v4)") Cc: sta...@vger.kernel.org # 3.4 Signed-off-by: Johan Hovold --- drivers/gpu/drm/udl/udl_connector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 3750fd216131..930574ad2bca 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -30,7 +30,7 @@ static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, int bval = (i + block * EDID_LENGTH) << 8; ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x02, (0x80 | (0x02 << 5)), bval, - 0xA1, read_buff, 2, HZ); + 0xA1, read_buff, 2, 1000); if (ret < 1) { DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); kfree(read_buff); -- 2.32.0
Re: [PATCH v2] dma-buf: move dma-buf symbols into the DMA_BUF module namespace
Hi Greg, On Mon, 25 Oct 2021 at 16:29, Christian König wrote: > > Am 25.10.21 um 12:36 schrieb Greg Kroah-Hartman: > > On Sun, Oct 10, 2021 at 02:46:28PM +0200, Greg Kroah-Hartman wrote: > >> In order to better track where in the kernel the dma-buf code is used, > >> put the symbols in the namespace DMA_BUF and modify all users of the > >> symbols to properly import the namespace to not break the build at the > >> same time. > >> > >> Now the output of modinfo shows the use of these symbols, making it > >> easier to watch for users over time: > >> > >> $ modinfo drivers/misc/fastrpc.ko | grep import > >> import_ns: DMA_BUF > >> > >> Cc: "Pan, Xinhui" > >> Cc: David Airlie > >> Cc: Maarten Lankhorst > >> Cc: Maxime Ripard > >> Cc: Thomas Zimmermann > >> Cc: Mauro Carvalho Chehab > >> Cc: dri-devel@lists.freedesktop.org > >> Acked-by: Daniel Vetter > >> Acked-by: Christian König > >> Acked-by: Arnd Bergmann > >> Acked-by: Sumit Semwal > >> Acked-by: Alex Deucher > >> Signed-off-by: Greg Kroah-Hartman > >> --- > >> v2: added lots of acks > >> added 2 more drivers that needed the change, as found by Arnd > > Ping? Any ideas on what needs to happen to get this into the tree? > > > > Or can I take it through my char-misc tree? I seem to have a bunch of > > acks on it by the respective maintainers... > > I could push that upstream through the drm-misc-next tree if you like, > but honestly char-misc sounds like the better approach since this > touches a lot of drivers outside of drm as well. I agree with Christian here - char-misc might be a better way for this. > > > Thanks, > Christian. > > > > > thanks, > > > > greg k-h > Best, Sumit.
gpu: drm_fb_cma_helper.c:46: undefined reference to `drm_gem_fb_get_obj'
Regression found on arm gcc-11 built with multi_v5_defconfig Following build warnings / errors reported on linux next 20211025. metadata: git_describe: next-20211025 git_repo: https://gitlab.com/Linaro/lkft/mirrors/next/linux-next git_short_log: 9ae1fbdeabd3 (\"Add linux-next specific files for 20211025\") target_arch: arm toolchain: gcc-11 config: multi_v5_defconfig build error : -- arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.o: in function `drm_fb_cma_get_gem_obj': drivers/gpu/drm/drm_fb_cma_helper.c:46: undefined reference to `drm_gem_fb_get_obj' arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.c:46: undefined reference to `drm_gem_fb_get_obj' arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.c:46: undefined reference to `drm_gem_fb_get_obj' arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.o: in function `drm_fb_cma_sync_non_coherent': drivers/gpu/drm/drm_fb_cma_helper.c:133: undefined reference to `drm_atomic_helper_damage_iter_init' arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.c:135: undefined reference to `drm_atomic_helper_damage_iter_next' make[1]: *** [Makefile:1252: vmlinux] Error 1 make[1]: Target '__all' not remade because of errors. make: *** [Makefile:226: __sub-make] Error 2 Reported-by: Linux Kernel Functional Testing build link: --- https://builds.tuxbuild.com/1zzgFZBGjpQ5R0lawQFW9iJ39Hp/build.log build config: - https://builds.tuxbuild.com/1zzgFZBGjpQ5R0lawQFW9iJ39Hp/config # To install tuxmake on your system globally # sudo pip3 install -U tuxmake tuxmake --runtime podman --target-arch arm --toolchain gcc-11 --kconfig multi_v5_defconfig -- Linaro LKFT https://lkft.linaro.org
Re: [PATCH] drm/i915/guc: Fix recursive lock in GuC submission
Quoting Thomas Hellström (2021-10-21 08:39:48) > On Wed, 2021-10-20 at 12:21 -0700, Matthew Brost wrote: > > Fixes: 1a52faed31311 ("drm/i915/guc: Take engine PM when a context is > > pinned with GuC submission") > > Signed-off-by: Matthew Brost > > Cc: sta...@vger.kernel.org This Cc: stable annotation is unnecessary. Please always use "dim fixes 1a52faed31311" for helping to decide which Cc's are needed. In this case stable is not needed. If it was, there would be an indication of kernel version. In this case this is fine to be picked up by in drm-intel-next-fixes PR. Let's pay attention to the right Fixes: annotation while submitting and reviewing patches. Regards, Joonas
Re: [RFC PATCH] drm/aperture: Add param to disable conflicting framebuffers removal
Hello Michel, On 10/25/21 12:45, Michel Dänzer wrote: > On 2021-10-24 22:32, Javier Martinez Canillas wrote: >> Hello Ville, >> >> On 10/22/21 21:12, Ville Syrjälä wrote: >>> On Fri, Oct 22, 2021 at 04:40:40PM +0200, Javier Martinez Canillas wrote: The simpledrm driver allows to use the frame buffer that was set-up by the firmware. This gives early video output before the platform DRM driver is probed and takes over. But it would be useful to have a way to disable this take over by the real DRM drivers. For example, there may be bugs in the DRM drivers that could cause the display output to not work correctly. For those cases, it would be good to keep the simpledrm driver instead and at least get a working display as set-up by the firmware. Let's add a drm.remove_fb boolean kernel command line parameter, that when set to false will prevent the conflicting framebuffers to being removed. Since the drivers call drm_aperture_remove_conflicting_framebuffers() very early in their probe callback, this will cause the drivers' probe to fail. >>> >>> Why is that better than just modprobe.blacklisting those drivers? >> >> Because would allow to deny list all native (as Thomas called it) DRM drivers >> and only allow the simpledrm driver to be probed. This is useful for distros, >> since could add a "Basic graphics mode" to the boot menu entries, that could >> boot the kernel passing a "drm.disable_native_drivers=1" cmdline option. >> >> That way, if there's any problem with a given DRM driver, the distro may be >> installed and booted using the simpledrm driver and troubleshoot why a native >> DRM driver is not working. Or try updating the kernel package, etc. > > For troubleshooting, it'll be helpful if this new parameter can be enabled > for the boot via the kernel command line, then disabled again after boot-up. > One simple possibility for this would be allowing the parameter to be changed > via /sys/module That's already the case with the current patch, i.e: $ grep -o drm.* /proc/cmdline drm.disable_native_drivers=1 $ cat /proc/fb 0 simpledrm $ modprobe virtio_gpu $ dmesg [ 125.731549] [drm] pci: virtio-vga detected at :00:01.0 [ 125.732410] virtio_gpu: probe of virtio0 failed with error -16 $ echo 0 > /sys/module/drm/parameters/disable_native_drivers $ modprobe virtio_gpu $ dmesg [ 187.889136] [drm] pci: virtio-vga detected at :00:01.0 [ 187.894578] Console: switching to colour dummy device 80x25 [ 187.897090] virtio-pci :00:01.0: vgaarb: deactivate vga console [ 187.899983] [drm] features: -virgl +edid -resource_blob -host_visible [ 187.907176] [drm] number of scanouts: 1 [ 187.907714] [drm] number of cap sets: 0 [ 187.914108] [drm] Initialized virtio_gpu 0.1.0 0 for virtio0 on minor 1 [ 187.930807] Console: switching to colour frame buffer device 128x48 [ 187.938737] virtio_gpu virtio0: [drm] fb0: virtio_gpu frame buffer device $ cat /proc/fb 0 virtio_gpu /drm/parameters/, which I suspect doesn't work with the patch as is (due to the 0600 permissions). > > I followed the convention used by other drm module parameters, hence the 0600. Do you mean that for this parameter we should be less restrictive ? Best regards, -- Javier Martinez Canillas Linux Engineering Red Hat
Re: [RFC PATCH] drm/aperture: Add param to disable conflicting framebuffers removal
On Mon, Oct 25, 2021 at 8:28 AM Javier Martinez Canillas wrote: > > Hello Michel, > > On 10/25/21 12:45, Michel Dänzer wrote: > > On 2021-10-24 22:32, Javier Martinez Canillas wrote: > >> Hello Ville, > >> > >> On 10/22/21 21:12, Ville Syrjälä wrote: > >>> On Fri, Oct 22, 2021 at 04:40:40PM +0200, Javier Martinez Canillas wrote: > The simpledrm driver allows to use the frame buffer that was set-up by > the > firmware. This gives early video output before the platform DRM driver is > probed and takes over. > > But it would be useful to have a way to disable this take over by the > real > DRM drivers. For example, there may be bugs in the DRM drivers that could > cause the display output to not work correctly. > > For those cases, it would be good to keep the simpledrm driver instead > and > at least get a working display as set-up by the firmware. > > Let's add a drm.remove_fb boolean kernel command line parameter, that > when > set to false will prevent the conflicting framebuffers to being removed. > > Since the drivers call drm_aperture_remove_conflicting_framebuffers() > very > early in their probe callback, this will cause the drivers' probe to > fail. > >>> > >>> Why is that better than just modprobe.blacklisting those drivers? > >> > >> Because would allow to deny list all native (as Thomas called it) DRM > >> drivers > >> and only allow the simpledrm driver to be probed. This is useful for > >> distros, > >> since could add a "Basic graphics mode" to the boot menu entries, that > >> could > >> boot the kernel passing a "drm.disable_native_drivers=1" cmdline option. > >> > >> That way, if there's any problem with a given DRM driver, the distro may be > >> installed and booted using the simpledrm driver and troubleshoot why a > >> native > >> DRM driver is not working. Or try updating the kernel package, etc. > > > > For troubleshooting, it'll be helpful if this new parameter can be enabled > > for the boot via the kernel command line, then disabled again after > > boot-up. One simple possibility for this would be allowing the parameter to > > be changed via /sys/module > > That's already the case with the current patch, i.e: > > $ grep -o drm.* /proc/cmdline > drm.disable_native_drivers=1 > > $ cat /proc/fb > 0 simpledrm > > $ modprobe virtio_gpu > > $ dmesg > [ 125.731549] [drm] pci: virtio-vga detected at :00:01.0 > [ 125.732410] virtio_gpu: probe of virtio0 failed with error -16 > > $ echo 0 > /sys/module/drm/parameters/disable_native_drivers > > $ modprobe virtio_gpu > > $ dmesg > [ 187.889136] [drm] pci: virtio-vga detected at :00:01.0 > [ 187.894578] Console: switching to colour dummy device 80x25 > [ 187.897090] virtio-pci :00:01.0: vgaarb: deactivate vga console > [ 187.899983] [drm] features: -virgl +edid -resource_blob -host_visible > [ 187.907176] [drm] number of scanouts: 1 > [ 187.907714] [drm] number of cap sets: 0 > [ 187.914108] [drm] Initialized virtio_gpu 0.1.0 0 for virtio0 on minor 1 > [ 187.930807] Console: switching to colour frame buffer device 128x48 > [ 187.938737] virtio_gpu virtio0: [drm] fb0: virtio_gpu frame buffer device > > $ cat /proc/fb > 0 virtio_gpu > > /drm/parameters/, which I suspect doesn't work with the patch as is > (due to the 0600 permissions). > > > > > > I followed the convention used by other drm module parameters, hence the > 0600. Do you mean that for this parameter we should be less restrictive ? > I would think that the 600 permissions would still permit it, since the root user can still access and manipulate it. -- 真実はいつも一つ!/ Always, there's only one truth!
Re: [PATCH v2] dma-buf: move dma-buf symbols into the DMA_BUF module namespace
On Mon, Oct 25, 2021 at 05:43:49PM +0530, Sumit Semwal wrote: > Hi Greg, > > On Mon, 25 Oct 2021 at 16:29, Christian König > wrote: > > > > Am 25.10.21 um 12:36 schrieb Greg Kroah-Hartman: > > > On Sun, Oct 10, 2021 at 02:46:28PM +0200, Greg Kroah-Hartman wrote: > > >> In order to better track where in the kernel the dma-buf code is used, > > >> put the symbols in the namespace DMA_BUF and modify all users of the > > >> symbols to properly import the namespace to not break the build at the > > >> same time. > > >> > > >> Now the output of modinfo shows the use of these symbols, making it > > >> easier to watch for users over time: > > >> > > >> $ modinfo drivers/misc/fastrpc.ko | grep import > > >> import_ns: DMA_BUF > > >> > > >> Cc: "Pan, Xinhui" > > >> Cc: David Airlie > > >> Cc: Maarten Lankhorst > > >> Cc: Maxime Ripard > > >> Cc: Thomas Zimmermann > > >> Cc: Mauro Carvalho Chehab > > >> Cc: dri-devel@lists.freedesktop.org > > >> Acked-by: Daniel Vetter > > >> Acked-by: Christian König > > >> Acked-by: Arnd Bergmann > > >> Acked-by: Sumit Semwal > > >> Acked-by: Alex Deucher > > >> Signed-off-by: Greg Kroah-Hartman > > >> --- > > >> v2: added lots of acks > > >> added 2 more drivers that needed the change, as found by Arnd > > > Ping? Any ideas on what needs to happen to get this into the tree? > > > > > > Or can I take it through my char-misc tree? I seem to have a bunch of > > > acks on it by the respective maintainers... > > > > I could push that upstream through the drm-misc-next tree if you like, > > but honestly char-misc sounds like the better approach since this > > touches a lot of drivers outside of drm as well. > > I agree with Christian here - char-misc might be a better way for this. Good idea, I'll take it through this tree as it will need to add the symbol to the habanalabs driver at the same time as it has picked up support for these symbols in my tree. thanks, greg k-h
[PATCH 3/8] drm: implement top-down allocation method
Implemented a function which walk through the order list, compares the offset and returns the maximum offset block, this method is unpredictable in obtaining the high range address blocks which depends on allocation and deallocation. for instance, if driver requests address at a low specific range, allocator traverses from the root block and splits the larger blocks until it reaches the specific block and in the process of splitting, lower orders in the freelist are occupied with low range address blocks and for the subsequent TOPDOWN memory request we may return the low range blocks.To overcome this issue, we may go with the below approach. The other approach, sorting each order list entries in ascending order and compares the last entry of each order list in the freelist and return the max block. This creates sorting overhead on every drm_buddy_free() request and split up of larger blocks for a single page request. Signed-off-by: Arunpravin --- drivers/gpu/drm/drm_buddy.c | 42 +++-- include/drm/drm_buddy.h | 1 + 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 406e3d521903..9d3547bcc5da 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -362,6 +362,27 @@ alloc_range(struct drm_buddy_mm *mm, return ERR_PTR(err); } +static struct drm_buddy_block * +get_maxblock(struct list_head *head) +{ + struct drm_buddy_block *max_block = NULL, *node; + + max_block = list_first_entry_or_null(head, +struct drm_buddy_block, +link); + + if (!max_block) + return NULL; + + list_for_each_entry(node, head, link) { + if (drm_buddy_block_offset(node) > + drm_buddy_block_offset(max_block)) + max_block = node; + } + + return max_block; +} + static struct drm_buddy_block * alloc_from_freelist(struct drm_buddy_mm *mm, unsigned int order, @@ -372,13 +393,22 @@ alloc_from_freelist(struct drm_buddy_mm *mm, int err; for (i = order; i <= mm->max_order; ++i) { - if (!list_empty(&mm->free_list[i])) { - block = list_first_entry_or_null(&mm->free_list[i], -struct drm_buddy_block, -link); + if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { + if (!list_empty(&mm->free_list[i])) { + block = get_maxblock(&mm->free_list[i]); - if (block) - break; + if (block) + break; + } + } else { + if (!list_empty(&mm->free_list[i])) { + block = list_first_entry_or_null(&mm->free_list[i], +struct drm_buddy_block, +link); + + if (block) + break; + } } } diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h index c7bb5509a7ad..cd8021d2d6e7 100644 --- a/include/drm/drm_buddy.h +++ b/include/drm/drm_buddy.h @@ -28,6 +28,7 @@ }) #define DRM_BUDDY_RANGE_ALLOCATION (1 << 0) +#define DRM_BUDDY_TOPDOWN_ALLOCATION (1 << 1) struct drm_buddy_block { #define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) -- 2.25.1
[PATCH 4/8] drm/i915: add top-down alloc support to i915
add top down allocation support to i915 driver Signed-off-by: Arunpravin --- drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c index 75197ba6e40d..963468228392 100644 --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c @@ -53,6 +53,9 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, INIT_LIST_HEAD(&bman_res->blocks); bman_res->mm = mm; + if (place->flags & TTM_PL_FLAG_TOPDOWN) + bman_res->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; + if (place->fpfn || lpfn != man->size) bman_res->flags |= DRM_BUDDY_RANGE_ALLOCATION; -- 2.25.1
[PATCH 5/8] drm: Implement method to free unused pages
On contiguous allocation, we round up the size to the *next* power of 2, implement a function to free the unused pages after the newly allocate block. Signed-off-by: Arunpravin --- drivers/gpu/drm/drm_buddy.c | 103 include/drm/drm_buddy.h | 4 ++ 2 files changed, 107 insertions(+) diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 9d3547bcc5da..0da8510736eb 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -284,6 +284,109 @@ static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) return s1 <= s2 && e1 >= e2; } +/** + * drm_buddy_free_unused_pages - free unused pages + * + * @mm: DRM buddy manager + * @actual_size: original size requested + * @blocks: output list head to add allocated blocks + * + * For contiguous allocation, we round up the size to the nearest + * power of two value, drivers consume *actual* size, so remaining + * portions are unused and it can be freed. + * + * Returns: + * 0 on success, error code on failure. + */ +int drm_buddy_free_unused_pages(struct drm_buddy_mm *mm, + u64 actual_size, + struct list_head *blocks) +{ + struct drm_buddy_block *block; + struct drm_buddy_block *buddy; + u64 actual_start; + u64 actual_end; + LIST_HEAD(dfs); + u64 count = 0; + int err; + + if (!list_is_singular(blocks)) + return -EINVAL; + + block = list_first_entry_or_null(blocks, +struct drm_buddy_block, +link); + + if (!block) + return -EINVAL; + + if (actual_size > drm_buddy_block_size(mm, block)) + return -EINVAL; + + if (actual_size == drm_buddy_block_size(mm, block)) + return 0; + + list_del(&block->link); + + actual_start = drm_buddy_block_offset(block); + actual_end = actual_start + actual_size - 1; + + if (drm_buddy_block_is_allocated(block)) + mark_free(mm, block); + + list_add(&block->tmp_link, &dfs); + + while (1) { + block = list_first_entry_or_null(&dfs, +struct drm_buddy_block, +tmp_link); + + if (!block) + break; + + list_del(&block->tmp_link); + + if (count == actual_size) + return 0; + + if (contains(actual_start, actual_end, drm_buddy_block_offset(block), + (drm_buddy_block_offset(block) + drm_buddy_block_size(mm, block) - 1))) { + BUG_ON(!drm_buddy_block_is_free(block)); + + /* Allocate only required blocks */ + mark_allocated(block); + mm->avail -= drm_buddy_block_size(mm, block); + list_add_tail(&block->link, blocks); + count += drm_buddy_block_size(mm, block); + continue; + } + + if (drm_buddy_block_order(block) == 0) + continue; + + if (!drm_buddy_block_is_split(block)) { + err = split_block(mm, block); + + if (unlikely(err)) + goto err_undo; + } + + list_add(&block->right->tmp_link, &dfs); + list_add(&block->left->tmp_link, &dfs); + } + + return -ENOSPC; + +err_undo: + buddy = get_buddy(block); + if (buddy && + (drm_buddy_block_is_free(block) && +drm_buddy_block_is_free(buddy))) + __drm_buddy_free(mm, block); + return err; +} +EXPORT_SYMBOL(drm_buddy_free_unused_pages); + static struct drm_buddy_block * alloc_range(struct drm_buddy_mm *mm, u64 start, u64 end, diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h index cd8021d2d6e7..1dfc80c88e1f 100644 --- a/include/drm/drm_buddy.h +++ b/include/drm/drm_buddy.h @@ -145,6 +145,10 @@ int drm_buddy_alloc(struct drm_buddy_mm *mm, struct list_head *blocks, unsigned long flags); +int drm_buddy_free_unused_pages(struct drm_buddy_mm *mm, + u64 actual_size, + struct list_head *blocks); + void drm_buddy_free(struct drm_buddy_mm *mm, struct drm_buddy_block *block); void drm_buddy_free_list(struct drm_buddy_mm *mm, struct list_head *objects); -- 2.25.1
[PATCH 6/8] drm/i915: add free_unused_pages support to i915
add drm_buddy_free_unused_pages() support on contiguous allocation Signed-off-by: Arunpravin --- drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c index 963468228392..162947af8e04 100644 --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c @@ -98,6 +98,14 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, if (unlikely(err)) goto err_free_blocks; + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { + err = drm_buddy_free_unused_pages(mm, (uint64_t)n_pages << PAGE_SHIFT, + &bman_res->blocks); + + if (unlikely(err)) + goto err_free_blocks; + } + *res = &bman_res->base; return 0; -- 2.25.1
[PATCH 7/8] drm/amdgpu: move vram inline functions into a header
Move shared vram inline functions and structs into a header file Signed-off-by: Arunpravin --- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 51 1 file changed, 51 insertions(+) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h new file mode 100644 index ..32cd6f54b6f3 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: MIT + * Copyright 2021 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 __AMDGPU_VRAM_MGR_H__ +#define __AMDGPU_VRAM_MGR_H__ + +#include + +struct amdgpu_vram_mgr_node { + struct ttm_resource base; + struct list_head blocks; + unsigned long flags; +}; + +static inline uint64_t amdgpu_node_start(struct drm_buddy_block *block) +{ + return drm_buddy_block_offset(block); +} + +static inline uint64_t amdgpu_node_size(struct drm_buddy_block *block) +{ + return PAGE_SIZE << drm_buddy_block_order(block); +} + +static inline struct amdgpu_vram_mgr_node * +to_amdgpu_vram_mgr_node(struct ttm_resource *res) +{ + return container_of(res, struct amdgpu_vram_mgr_node, base); +} + +#endif -- 2.25.1
[PATCH 8/8] drm/amdgpu: add drm buddy support to amdgpu
- Remove drm_mm references and replace with drm buddy functionalities - Add res cursor support for drm buddy Signed-off-by: Arunpravin --- .../gpu/drm/amd/amdgpu/amdgpu_res_cursor.h| 97 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 4 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 239 ++ 3 files changed, 221 insertions(+), 119 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h index acfa207cf970..da12b4ff2e45 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h @@ -30,12 +30,15 @@ #include #include +#include "amdgpu_vram_mgr.h" + /* state back for walking over vram_mgr and gtt_mgr allocations */ struct amdgpu_res_cursor { uint64_tstart; uint64_tsize; uint64_tremaining; - struct drm_mm_node *node; + void*node; + uint32_tmem_type; }; /** @@ -52,27 +55,63 @@ static inline void amdgpu_res_first(struct ttm_resource *res, uint64_t start, uint64_t size, struct amdgpu_res_cursor *cur) { + struct drm_buddy_block *block; + struct list_head *head, *next; struct drm_mm_node *node; - if (!res || res->mem_type == TTM_PL_SYSTEM) { - cur->start = start; - cur->size = size; - cur->remaining = size; - cur->node = NULL; - WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT); - return; - } + if (!res) + goto err_out; BUG_ON(start + size > res->num_pages << PAGE_SHIFT); - node = to_ttm_range_mgr_node(res)->mm_nodes; - while (start >= node->size << PAGE_SHIFT) - start -= node++->size << PAGE_SHIFT; + cur->mem_type = res->mem_type; + + switch (cur->mem_type) { + case TTM_PL_VRAM: + head = &to_amdgpu_vram_mgr_node(res)->blocks; + + block = list_first_entry_or_null(head, +struct drm_buddy_block, +link); + if (!block) + goto err_out; + + while (start >= amdgpu_node_size(block)) { + start -= amdgpu_node_size(block); + + next = block->link.next; + if (next != head) + block = list_entry(next, struct drm_buddy_block, link); + } + + cur->start = amdgpu_node_start(block) + start; + cur->size = min(amdgpu_node_size(block) - start, size); + cur->remaining = size; + cur->node = block; + break; + case TTM_PL_TT: + node = to_ttm_range_mgr_node(res)->mm_nodes; + while (start >= node->size << PAGE_SHIFT) + start -= node++->size << PAGE_SHIFT; + + cur->start = (node->start << PAGE_SHIFT) + start; + cur->size = min((node->size << PAGE_SHIFT) - start, size); + cur->remaining = size; + cur->node = node; + break; + default: + goto err_out; + } - cur->start = (node->start << PAGE_SHIFT) + start; - cur->size = min((node->size << PAGE_SHIFT) - start, size); + return; + +err_out: + cur->start = start; + cur->size = size; cur->remaining = size; - cur->node = node; + cur->node = NULL; + WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT); + return; } /** @@ -85,7 +124,9 @@ static inline void amdgpu_res_first(struct ttm_resource *res, */ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size) { - struct drm_mm_node *node = cur->node; + struct drm_buddy_block *block; + struct drm_mm_node *node; + struct list_head *next; BUG_ON(size > cur->remaining); @@ -99,9 +140,27 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size) return; } - cur->node = ++node; - cur->start = node->start << PAGE_SHIFT; - cur->size = min(node->size << PAGE_SHIFT, cur->remaining); + switch (cur->mem_type) { + case TTM_PL_VRAM: + block = cur->node; + + next = block->link.next; + block = list_entry(next, struct drm_buddy_block, link); + + cur->node = block; + cur->start = amdgpu_node_start(block); + cur->size = min(amdgpu_node_size(block), cur->remaining); + break; + case TTM_PL_TT: + node = cur->node; + + cur->node = ++node; + cur->start =
[PATCH v2 1/8] drm: move the buddy allocator from i915 into common drm
Move the base i915 buddy allocator code into drm - Move i915_buddy.h to include/drm - Move i915_buddy.c to drm root folder - Rename "i915" string with "drm" string wherever applicable - Rename "I915" string with "DRM" string wherever applicable - Fix header file dependencies - Fix alignment issues - add Makefile support for drm buddy - export functions and write kerneldoc description - Remove i915 selftest config check condition as buddy selftest will be moved to drm selftest folder cleanup i915 buddy references in i915 driver module and replace with drm buddy V2: - include header file in alphabetical order (Thomas) - merged changes listed in the body section into a single patch to keep the build intact (Christian, Jani) Signed-off-by: Arunpravin --- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_buddy.c | 521 ++ drivers/gpu/drm/drm_drv.c | 3 + drivers/gpu/drm/i915/Makefile | 1 - drivers/gpu/drm/i915/i915_buddy.c | 466 drivers/gpu/drm/i915/i915_buddy.h | 143 - drivers/gpu/drm/i915/i915_module.c| 3 - drivers/gpu/drm/i915/i915_scatterlist.c | 11 +- drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 33 +- drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 4 +- include/drm/drm_buddy.h | 153 + 11 files changed, 702 insertions(+), 638 deletions(-) create mode 100644 drivers/gpu/drm/drm_buddy.c delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h create mode 100644 include/drm/drm_buddy.h diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 0dff40bb863c..dc61e91a3154 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -18,7 +18,7 @@ drm-y :=drm_aperture.o drm_auth.o drm_cache.o \ drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \ drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o \ - drm_managed.o drm_vblank_work.o + drm_managed.o drm_vblank_work.o drm_buddy.o drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o drm_dma.o \ drm_legacy_misc.o drm_lock.o drm_memory.o drm_scatter.o \ diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c new file mode 100644 index ..39eb1d224bec --- /dev/null +++ b/drivers/gpu/drm/drm_buddy.c @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include +#include + +#include + +static struct kmem_cache *slab_blocks; + +static struct drm_buddy_block *drm_block_alloc(struct drm_buddy_mm *mm, + struct drm_buddy_block *parent, + unsigned int order, + u64 offset) +{ + struct drm_buddy_block *block; + + BUG_ON(order > DRM_BUDDY_MAX_ORDER); + + block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); + if (!block) + return NULL; + + block->header = offset; + block->header |= order; + block->parent = parent; + + BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED); + return block; +} + +static void drm_block_free(struct drm_buddy_mm *mm, + struct drm_buddy_block *block) +{ + kmem_cache_free(slab_blocks, block); +} + +static void mark_allocated(struct drm_buddy_block *block) +{ + block->header &= ~DRM_BUDDY_HEADER_STATE; + block->header |= DRM_BUDDY_ALLOCATED; + + list_del(&block->link); +} + +static void mark_free(struct drm_buddy_mm *mm, + struct drm_buddy_block *block) +{ + block->header &= ~DRM_BUDDY_HEADER_STATE; + block->header |= DRM_BUDDY_FREE; + + list_add(&block->link, +&mm->free_list[drm_buddy_block_order(block)]); +} + +static void mark_split(struct drm_buddy_block *block) +{ + block->header &= ~DRM_BUDDY_HEADER_STATE; + block->header |= DRM_BUDDY_SPLIT; + + list_del(&block->link); +} + +/** + * drm_buddy_init - init memory manager + * + * @mm: DRM buddy manager to initialize + * @size: size in bytes to manage + * @chunk_size: minimum page size in bytes for our allocations + * + * Initializes the memory manager and its resources. + * + * Returns: + * 0 on success, error code on failure. + */ +int drm_buddy_init(struct drm_buddy_mm *mm, u64 size, u64 chunk_size) +{ + unsigned int i; + u64 offset; + + if (size < chunk_size) + return -EINVAL; + + if (chunk_size < PAGE_SIZE) + return -EINVAL; + + if (!is_power_of_2(chunk_size)) + return -EINVAL; + + size = round_down(size, chunk_size); + + mm->size = size; + mm->av
[PATCH v2 2/8] drm: improve drm_buddy_alloc function
- Make drm_buddy_alloc a single function to handle range allocation and non-range allocation demands - Implemented a new function alloc_range() which allocates the requested power-of-two block comply with range limitations - Moved order computation and memory alignment logic from i915 driver to drm buddy V2: merged below changes to keep the build unbroken - drm_buddy_alloc_range() becomes obsolete and may be removed - enable ttm range allocation (fpfn / lpfn) support in i915 driver - apply enhanced drm_buddy_alloc() function to i915 driver Signed-off-by: Arunpravin --- drivers/gpu/drm/drm_buddy.c | 265 +++--- drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 67 ++--- drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 2 + include/drm/drm_buddy.h | 22 +- 4 files changed, 207 insertions(+), 149 deletions(-) diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 39eb1d224bec..406e3d521903 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -274,63 +274,6 @@ void drm_buddy_free_list(struct drm_buddy_mm *mm, struct list_head *objects) } EXPORT_SYMBOL(drm_buddy_free_list); -/** - * drm_buddy_alloc - allocate power-of-two blocks - * - * @mm: DRM buddy manager to allocate from - * @order: size of the allocation - * - * The order value here translates to: - * - * 0 = 2^0 * mm->chunk_size - * 1 = 2^1 * mm->chunk_size - * 2 = 2^2 * mm->chunk_size - * - * Returns: - * allocated ptr to the &drm_buddy_block on success - */ -struct drm_buddy_block * -drm_buddy_alloc(struct drm_buddy_mm *mm, unsigned int order) -{ - struct drm_buddy_block *block = NULL; - unsigned int i; - int err; - - for (i = order; i <= mm->max_order; ++i) { - block = list_first_entry_or_null(&mm->free_list[i], -struct drm_buddy_block, -link); - if (block) - break; - } - - if (!block) - return ERR_PTR(-ENOSPC); - - BUG_ON(!drm_buddy_block_is_free(block)); - - while (i != order) { - err = split_block(mm, block); - if (unlikely(err)) - goto out_free; - - /* Go low */ - block = block->left; - i--; - } - - mark_allocated(block); - mm->avail -= drm_buddy_block_size(mm, block); - kmemleak_update_trace(block); - return block; - -out_free: - if (i != order) - __drm_buddy_free(mm, block); - return ERR_PTR(err); -} -EXPORT_SYMBOL(drm_buddy_alloc); - static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) { return s1 <= e2 && e1 >= s2; @@ -341,52 +284,22 @@ static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) return s1 <= s2 && e1 >= e2; } -/** - * drm_buddy_alloc_range - allocate range - * - * @mm: DRM buddy manager to allocate from - * @blocks: output list head to add allocated blocks - * @start: start of the allowed range for this block - * @size: size of the allocation - * - * Intended for pre-allocating portions of the address space, for example to - * reserve a block for the initial framebuffer or similar, hence the expectation - * here is that drm_buddy_alloc() is still the main vehicle for - * allocations, so if that's not the case then the drm_mm range allocator is - * probably a much better fit, and so you should probably go use that instead. - * - * Note that it's safe to chain together multiple alloc_ranges - * with the same blocks list - * - * Returns: - * 0 on success, error code on failure. - */ -int drm_buddy_alloc_range(struct drm_buddy_mm *mm, - struct list_head *blocks, - u64 start, u64 size) +static struct drm_buddy_block * +alloc_range(struct drm_buddy_mm *mm, + u64 start, u64 end, + unsigned int order) { struct drm_buddy_block *block; struct drm_buddy_block *buddy; - LIST_HEAD(allocated); LIST_HEAD(dfs); - u64 end; int err; int i; - if (size < mm->chunk_size) - return -EINVAL; - - if (!IS_ALIGNED(size | start, mm->chunk_size)) - return -EINVAL; - - if (range_overflows(start, size, mm->size)) - return -EINVAL; + end = end - 1; for (i = 0; i < mm->n_roots; ++i) list_add_tail(&mm->roots[i]->tmp_link, &dfs); - end = start + size - 1; - do { u64 block_start; u64 block_end; @@ -394,31 +307,32 @@ int drm_buddy_alloc_range(struct drm_buddy_mm *mm, block = list_first_entry_or_null(&dfs, struct drm_buddy_block, tmp_link); + if (!block) break;
Re: [RFC PATCH] drm/aperture: Add param to disable conflicting framebuffers removal
On 2021-10-25 14:28, Javier Martinez Canillas wrote: > Hello Michel, > > On 10/25/21 12:45, Michel Dänzer wrote: >> On 2021-10-24 22:32, Javier Martinez Canillas wrote: >>> Hello Ville, >>> >>> On 10/22/21 21:12, Ville Syrjälä wrote: On Fri, Oct 22, 2021 at 04:40:40PM +0200, Javier Martinez Canillas wrote: > The simpledrm driver allows to use the frame buffer that was set-up by the > firmware. This gives early video output before the platform DRM driver is > probed and takes over. > > But it would be useful to have a way to disable this take over by the real > DRM drivers. For example, there may be bugs in the DRM drivers that could > cause the display output to not work correctly. > > For those cases, it would be good to keep the simpledrm driver instead and > at least get a working display as set-up by the firmware. > > Let's add a drm.remove_fb boolean kernel command line parameter, that when > set to false will prevent the conflicting framebuffers to being removed. > > Since the drivers call drm_aperture_remove_conflicting_framebuffers() very > early in their probe callback, this will cause the drivers' probe to fail. Why is that better than just modprobe.blacklisting those drivers? >>> >>> Because would allow to deny list all native (as Thomas called it) DRM >>> drivers >>> and only allow the simpledrm driver to be probed. This is useful for >>> distros, >>> since could add a "Basic graphics mode" to the boot menu entries, that could >>> boot the kernel passing a "drm.disable_native_drivers=1" cmdline option. >>> >>> That way, if there's any problem with a given DRM driver, the distro may be >>> installed and booted using the simpledrm driver and troubleshoot why a >>> native >>> DRM driver is not working. Or try updating the kernel package, etc. >> >> For troubleshooting, it'll be helpful if this new parameter can be enabled >> for the boot via the kernel command line, then disabled again after boot-up. >> One simple possibility for this would be allowing the parameter to be >> changed via /sys/module > > That's already the case with the current patch, i.e: > > $ grep -o drm.* /proc/cmdline > drm.disable_native_drivers=1 > > $ cat /proc/fb > 0 simpledrm > > $ modprobe virtio_gpu > > $ dmesg > [ 125.731549] [drm] pci: virtio-vga detected at :00:01.0 > [ 125.732410] virtio_gpu: probe of virtio0 failed with error -16 > > $ echo 0 > /sys/module/drm/parameters/disable_native_drivers > > $ modprobe virtio_gpu > > $ dmesg > [ 187.889136] [drm] pci: virtio-vga detected at :00:01.0 > [ 187.894578] Console: switching to colour dummy device 80x25 > [ 187.897090] virtio-pci :00:01.0: vgaarb: deactivate vga console > [ 187.899983] [drm] features: -virgl +edid -resource_blob -host_visible > [ 187.907176] [drm] number of scanouts: 1 > [ 187.907714] [drm] number of cap sets: 0 > [ 187.914108] [drm] Initialized virtio_gpu 0.1.0 0 for virtio0 on minor 1 > [ 187.930807] Console: switching to colour frame buffer device 128x48 > [ 187.938737] virtio_gpu virtio0: [drm] fb0: virtio_gpu frame buffer device > > $ cat /proc/fb > 0 virtio_gpu > > /drm/parameters/, which I suspect doesn't work with the patch as is > (due to the 0600 permissions). >> >> > > I followed the convention used by other drm module parameters, hence the > 0600. Do you mean that for this parameter we should be less restrictive ? No, it was simply a brain fart on my part. :} Thanks for confirming this works! -- Earthling Michel Dänzer| https://redhat.com Libre software enthusiast | Mesa and Xwayland developer
[PATCH] MAINTAINERS: Add Tvrtko as drm/i915 co-maintainer
Add Tvrtko Ursulin as a co-maintainer for drm/i915 driver. Tvrtko will bring added bandwidth and focus to the GT/GEM domain (drm-intel-gt-next). This will help with the increased driver maintenance efforts, allows alternating the drm-intel-gt-next pull requests and also should increase the coverage for the maintenance in general. Signed-off-by: Joonas Lahtinen Cc: David Airlie Cc: Daniel Vetter Acked-by: Jani Nikula Acked-by: Rodrigo Vivi Acked-by: Tvrtko Ursulin Cc: Sean Paul Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: dri-devel@lists.freedesktop.org --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 98aa1f55ed41..07553156a1c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9361,6 +9361,7 @@ INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets) M: Jani Nikula M: Joonas Lahtinen M: Rodrigo Vivi +M: Tvrtko Ursulin L: intel-...@lists.freedesktop.org S: Supported W: https://01.org/linuxgraphics/ -- 2.31.1
Re: [PATCH] MAINTAINERS: Add Tvrtko as drm/i915 co-maintainer
On Mon, Oct 25, 2021 at 3:49 PM Joonas Lahtinen wrote: > > Add Tvrtko Ursulin as a co-maintainer for drm/i915 driver. > Tvrtko will bring added bandwidth and focus to the GT/GEM domain > (drm-intel-gt-next). > > This will help with the increased driver maintenance efforts, allows > alternating the drm-intel-gt-next pull requests and also should increase > the coverage for the maintenance in general. > > Signed-off-by: Joonas Lahtinen > Cc: David Airlie > Cc: Daniel Vetter > Acked-by: Jani Nikula > Acked-by: Rodrigo Vivi > Acked-by: Tvrtko Ursulin > Cc: Sean Paul > Cc: Maarten Lankhorst > Cc: Maxime Ripard > Cc: dri-devel@lists.freedesktop.org Acked-by: Daniel Vetter > --- > MAINTAINERS | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/MAINTAINERS b/MAINTAINERS > index 98aa1f55ed41..07553156a1c2 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -9361,6 +9361,7 @@ INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and > derivative chipsets) > M: Jani Nikula > M: Joonas Lahtinen > M: Rodrigo Vivi > +M: Tvrtko Ursulin > L: intel-...@lists.freedesktop.org > S: Supported > W: https://01.org/linuxgraphics/ > -- > 2.31.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Re: amdgpu "Fatal error during GPU init"; Ryzen 5600G integrated GPU + kernel 5.14.13
adding a trace, ... [5.201715] [drm] amdgpu kernel modesetting enabled. [5.201902] amdgpu: Virtual CRAT table created for CPU [5.201909] amdgpu: Topology: Add CPU node [5.201968] checking generic (e100 1d5000) vs hw (c000 1000) [5.201969] checking generic (e100 1d5000) vs hw (d000 20) [5.201970] checking generic (e100 1d5000) vs hw (fc50 8) [5.201988] amdgpu :30:00.0: enabling device ( -> 0003) [5.202020] [drm] initializing kernel modesetting (RENOIR 0x1002:0x1638 0x1002:0x1636 0xC9). [5.202024] amdgpu :30:00.0: amdgpu: Trusted Memory Zone (TMZ) feature enabled [5.202033] [drm] register mmio base: 0xFC50 [5.202033] [drm] register mmio size: 524288 [5.202035] [drm] PCIE atomic ops is not supported [5.203075] [drm] add ip block number 0 [5.203076] [drm] add ip block number 1 [5.203077] [drm] add ip block number 2 [5.203078] [drm] add ip block number 3 [5.203078] [drm] add ip block number 4 [5.203079] [drm] add ip block number 5 [5.203079] [drm] add ip block number 6 [5.203080] [drm] add ip block number 7 [5.203081] [drm] add ip block number 8 [5.203081] [drm] add ip block number 9 [5.208784] [drm] BIOS signature incorrect 0 0 [5.208789] amdgpu :30:00.0: BAR 6: can't assign [??? 0x flags 0x2000] (bogus alignment) [5.214038] [drm] BIOS signature incorrect 0 0 [5.214042] amdgpu :30:00.0: amdgpu: Unable to locate a BIOS ROM [5.214044] amdgpu :30:00.0: amdgpu: Fatal error during GPU init [5.214045] amdgpu :30:00.0: amdgpu: amdgpu: finishing device. [5.214048] [ cut here ] [5.214049] WARNING: CPU: 5 PID: 539 at kernel/workqueue.c:3044 __flush_work.isra.0+0x1ef/0x200 [5.214054] Modules linked in: fjes(-) amdgpu(+) raid1 ast drm_vram_helper drm_ttm_helper iommu_v2 ttm gpu_sched drm_kms_helper igb crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel cec dca i2c_algo_bit sp5100_tco ccp drm uas usb_storage wmi video sunrpc tcp_bbr nct6775 hwmon_vid k10temp [5.214065] CPU: 5 PID: 539 Comm: systemd-udevd Not tainted 5.14.13-200.fc34.x86_64 #1 [5.214067] Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./X470D4U, BIOS P4.20 04/14/2021 [5.214068] RIP: 0010:__flush_work.isra.0+0x1ef/0x200 [5.214070] Code: 8b 4d 00 48 8b 55 08 83 e1 08 48 0f ba 6d 00 03 80 c9 f0 e9 37 ff ff ff 0f 0b 48 83 c4 48 44 89 e0 5b 5d 41 5c 41 5d 41 5e c3 <0f> 0b 45 31 e4 e9 46 ff ff ff 0f 1f 80 00 00 00 00 0f 1f 44 00 00 [5.214071] RSP: 0018:9d5f00f0fa80 EFLAGS: 00010246 [5.214073] RAX: 0011 RBX: RCX: 0027 [5.214074] RDX: 0001 RSI: 0001 RDI: 88bc91e25ab8 [5.214074] RBP: 88bc91e25ab8 R08: R09: 9d5f00f0f898 [5.214075] R10: 9d5f00f0f890 R11: 88c39e1fcfe8 R12: 0001 [5.214075] R13: 88bc92622800 R14: 88bc91e2 R15: 9d5f00f0fde0 [5.214076] FS: 7f231d7deb40() GS:88c37df4() knlGS: [5.214077] CS: 0010 DS: ES: CR0: 80050033 [5.214078] CR2: 7fa1bbfa5ff0 CR3: 000104b94000 CR4: 00750ea0 [5.214078] PKRU: 5554 [5.214079] Call Trace: [5.214082] ? dev_printk_emit+0x3e/0x40 [5.214085] __cancel_work_timer+0xea/0x170 [5.214086] ? del_timer_sync+0x57/0x80 [5.214089] ttm_bo_lock_delayed_workqueue+0x11/0x20 [ttm] [5.214093] amdgpu_device_fini_hw+0x33/0x2c5 [amdgpu] [5.214225] amdgpu_driver_load_kms.cold+0x72/0x94 [amdgpu] [5.214338] amdgpu_pci_probe+0x110/0x1a0 [amdgpu] [5.214420] local_pci_probe+0x42/0x80 [5.214423] ? __cond_resched+0x16/0x40 [5.214426] pci_device_probe+0xd9/0x190 [5.214427] really_probe+0x1f5/0x3f0 [5.214429] __driver_probe_device+0xfe/0x180 [5.214430] driver_probe_device+0x1e/0x90 [5.214431] __driver_attach+0xc0/0x1c0 [5.214433] ? __device_attach_driver+0xe0/0xe0 [5.214434] ? __device_attach_driver+0xe0/0xe0 [5.214434] bus_for_each_dev+0x64/0x90 [5.214436] bus_add_driver+0x12b/0x1e0 [5.214438] driver_register+0x8f/0xe0 [5.214439] ? 0xc0d62000 [5.214440] do_one_initcall+0x44/0x1d0 [5.214443] ? kmem_cache_alloc_trace+0x15c/0x280 [5.214445] do_init_module+0x5c/0x270 [5.214448] __do_sys_init_module+0x11d/0x180 [5.214450] do_syscall_64+0x3b/0x90 [5.214452] ? handle_mm_fault+0xcf/0x2a0 [5.214454] ? do_user_addr_fault+0x1d5/0x680 [5.214457] ? syscall_exit_to_user_mode+0x18/0x40 [5.214458] ? exc_page_fault+0x72/0x150 [5.214459] entry_SYSCALL_64_after_hwframe+0x44/0xae [5.214461] RIP: 0033:0x7f231e42a0fe [5.214463] Code: 48 8b 0d 7d 1d 0c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 af 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73
Re: gpu: drm_fb_cma_helper.c:46: undefined reference to `drm_gem_fb_get_obj'
On Mon, 25 Oct 2021 at 17:43, Naresh Kamboju wrote: > > Regression found on arm gcc-11 built with multi_v5_defconfig > Following build warnings / errors reported on linux next 20211025. > > metadata: > git_describe: next-20211025 > git_repo: https://gitlab.com/Linaro/lkft/mirrors/next/linux-next > git_short_log: 9ae1fbdeabd3 (\"Add linux-next specific files for > 20211025\") > target_arch: arm > toolchain: gcc-11 > config: multi_v5_defconfig > > build error : > -- > arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.o: in > function `drm_fb_cma_get_gem_obj': > drivers/gpu/drm/drm_fb_cma_helper.c:46: undefined reference to > `drm_gem_fb_get_obj' > arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.c:46: > undefined reference to `drm_gem_fb_get_obj' > arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.c:46: > undefined reference to `drm_gem_fb_get_obj' > arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.o: in > function `drm_fb_cma_sync_non_coherent': > drivers/gpu/drm/drm_fb_cma_helper.c:133: undefined reference to > `drm_atomic_helper_damage_iter_init' > arm-linux-gnueabihf-ld: drivers/gpu/drm/drm_fb_cma_helper.c:135: > undefined reference to `drm_atomic_helper_damage_iter_next' > make[1]: *** [Makefile:1252: vmlinux] Error 1 > make[1]: Target '__all' not remade because of errors. > make: *** [Makefile:226: __sub-make] Error 2 > > Reported-by: Linux Kernel Functional Testing The bisection script pointed to the first bad commit, commit 4b2b5e142ff499a2bef2b8db0272bbda1088a3fe drm: Move GEM memory managers into modules > build link: > --- > https://builds.tuxbuild.com/1zzgFZBGjpQ5R0lawQFW9iJ39Hp/build.log > > build config: > - > https://builds.tuxbuild.com/1zzgFZBGjpQ5R0lawQFW9iJ39Hp/config > > # To install tuxmake on your system globally > # sudo pip3 install -U tuxmake > tuxmake --runtime podman --target-arch arm --toolchain gcc-11 > --kconfig multi_v5_defconfig > > -- > Linaro LKFT > https://lkft.linaro.org - Naresh
[PATCH 0/9] drm/vc4: Introduce locking and remove !KMS state access
Hi, This is a follow-up of the series here: https://lore.kernel.org/all/20210924135530.1036564-1-max...@cerno.tech/ and the discussion that occured here: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ The original series aimed at getting rid of the encoder->crtc pointer usage in the vc4 HDMI driver, some regression was noticed and the following discussion pointed out that we were doing a fair number of KMS state access outside of the mode set path, which is disallowed and unsafe. We already have a bug that was a result of that access which is fixed in the second patch, but other instabilities might have occured without being reported. That series thus removes all those accesses, and add some locking in the process. Sudip, since that series changed very significantly since you last tested it, could you give it a test run on the Codethink farm? Let me know what you think, Maxime Maxime Ripard (9): drm/vc4: crtc: Drop feed_txp from state drm/vc4: Fix non-blocking commit getting stuck forever drm/vc4: crtc: Copy assigned channel to the CRTC drm/vc4: hdmi: Add a spinlock to protect register access drm/vc4: hdmi: Use a mutex to prevent concurrent framework access drm/vc4: hdmi: Prevent access to crtc->state outside of KMS drm/vc4: hdmi: Check the device state in prepare() drm/vc4: hdmi: Introduce an output_enabled flag drm/vc4: hdmi: Introduce a scdc_enabled flag drivers/gpu/drm/vc4/vc4_crtc.c | 12 +- drivers/gpu/drm/vc4/vc4_drv.h | 29 +- drivers/gpu/drm/vc4/vc4_hdmi.c | 415 +--- drivers/gpu/drm/vc4/vc4_hdmi.h | 37 +++ drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 37 +++ drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 2 + drivers/gpu/drm/vc4/vc4_hvs.c | 26 +- drivers/gpu/drm/vc4/vc4_kms.c | 3 +- drivers/gpu/drm/vc4/vc4_txp.c | 4 +- 9 files changed, 509 insertions(+), 56 deletions(-) -- 2.31.1
[PATCH 1/9] drm/vc4: crtc: Drop feed_txp from state
Accessing the crtc->state pointer from outside the modesetting context is not allowed. We thus need to copy whatever we need from the KMS state to our structure in order to access it. In VC4, a number of users of that pointers have crept in over the years, the first one being whether or not the downstream controller of the pixelvalve is our writeback controller. Fortunately for us, Since commit 39fcb2808376 ("drm/vc4: txp: Turn the TXP into a CRTC of its own") this is no longer something that can change from one commit to the other and is hardcoded. Let's set this flag in struct vc4_crtc if we happen to be the TXP, and drop the flag from our private state structure. Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ Fixes: 008095e065a8 ("drm/vc4: Add support for the transposer block") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 3 +-- drivers/gpu/drm/vc4/vc4_drv.h | 6 +- drivers/gpu/drm/vc4/vc4_hvs.c | 7 +++ drivers/gpu/drm/vc4/vc4_kms.c | 3 ++- drivers/gpu/drm/vc4/vc4_txp.c | 3 +-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index c0df11e5fcf2..b90187d2c819 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -715,7 +715,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) spin_lock_irqsave(&dev->event_lock, flags); if (vc4_crtc->event && (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) || -vc4_state->feed_txp)) { +vc4_crtc->feeds_txp)) { drm_crtc_send_vblank_event(crtc, vc4_crtc->event); vc4_crtc->event = NULL; drm_crtc_vblank_put(crtc); @@ -893,7 +893,6 @@ struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) return NULL; old_vc4_state = to_vc4_crtc_state(crtc->state); - vc4_state->feed_txp = old_vc4_state->feed_txp; vc4_state->margins = old_vc4_state->margins; vc4_state->assigned_channel = old_vc4_state->assigned_channel; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index ef73e0aaf726..3c69b89363cb 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -495,6 +495,11 @@ struct vc4_crtc { struct drm_pending_vblank_event *event; struct debugfs_regset32 regset; + + /** +* @feeds_txp: True if the CRTC feeds our writeback controller. +*/ + bool feeds_txp; }; static inline struct vc4_crtc * @@ -521,7 +526,6 @@ struct vc4_crtc_state { struct drm_crtc_state base; /* Dlist area for this CRTC configuration. */ struct drm_mm_node mm; - bool feed_txp; bool txp_armed; unsigned int assigned_channel; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index c239045e05d6..9ddaee6b368d 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -375,7 +375,7 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) spin_lock_irqsave(&dev->event_lock, flags); - if (!vc4_state->feed_txp || vc4_state->txp_armed) { + if (!vc4_crtc->feeds_txp || vc4_state->txp_armed) { vc4_crtc->event = crtc->state->event; crtc->state->event = NULL; } @@ -395,10 +395,9 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); - struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(new_crtc_state); struct drm_display_mode *mode = &crtc->state->adjusted_mode; - bool oneshot = vc4_state->feed_txp; + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + bool oneshot = vc4_crtc->feeds_txp; vc4_hvs_update_dlist(crtc); vc4_hvs_init_channel(vc4, crtc, mode, oneshot); diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index f0b3e4cf5bce..028f19f7a5f8 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -233,6 +233,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, unsigned int i; for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); u32 dispctrl; u32 dsp3_mux; @@ -253,7 +254,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 * route. */ - if (vc4_state->feed_txp) + if (vc4_crtc->feeds_txp) dsp3_mux = VC4_SET_FIELD(3, SCALER_D
[PATCH 4/9] drm/vc4: hdmi: Add a spinlock to protect register access
The vc4 HDMI driver has multiple path shared between the CEC, ALSA and KMS frameworks, plus two interrupt handlers (CEC and hotplug) that will read and modify a number of registers. Even though not bug has been reported so far, it's definitely unsafe, so let's just add a spinlock to protect the register access of the HDMI controller. Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 202 ++-- drivers/gpu/drm/vc4/vc4_hdmi.h | 5 + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 37 + drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 2 + 4 files changed, 236 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 8cc84395f4cb..484450831483 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -118,6 +118,10 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST); udelay(1); HDMI_WRITE(HDMI_M_CTL, 0); @@ -129,24 +133,36 @@ static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) VC4_HDMI_SW_RESET_FORMAT_DETECT); HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + reset_control_reset(vc4_hdmi->reset); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_DVP_CTL, 0); HDMI_WRITE(HDMI_CLOCK_STOP, HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } #ifdef CONFIG_DRM_VC4_HDMI_CEC static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) { + unsigned long cec_rate = clk_get_rate(vc4_hdmi->cec_clock); + unsigned long flags; u16 clk_cnt; u32 value; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + value = HDMI_READ(HDMI_CEC_CNTRL_1); value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK; @@ -154,9 +170,11 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) * Set the clock divider: the hsm_clock rate and this divider * setting will give a 40 kHz CEC clock. */ - clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ; + clk_cnt = cec_rate / CEC_CLOCK_FREQ; value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT; HDMI_WRITE(HDMI_CEC_CNTRL_1, value); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } #else static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {} @@ -175,8 +193,16 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) connected = true; } else if (drm_probe_ddc(vc4_hdmi->ddc)) { connected = true; - } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) { - connected = true; + } else { + unsigned long flags; + u32 hotplug; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + hotplug = HDMI_READ(HDMI_HOTPLUG); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + if (hotplug & VC4_HDMI_HOTPLUG_CONNECTED) + connected = true; } if (connected) { @@ -369,9 +395,12 @@ static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); u32 packet_id = type - 0x80; + unsigned long flags; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); if (!poll) return 0; @@ -391,6 +420,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi, ram_packet_start->reg); uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; + unsigned long flags; ssize_t len, i; int ret; @@ -408,6 +438,8 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, return; } + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + for (i = 0; i < len; i += 7) { writel(buffer[i + 0] << 0 | buffer[i + 1] << 8 | @@ -425,6 +457,9 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id)); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock,
[PATCH 5/9] drm/vc4: hdmi: Use a mutex to prevent concurrent framework access
The vc4 HDMI controller registers into the KMS, CEC and ALSA frameworks. However, no particular care is done to prevent the concurrent execution of different framework hooks from happening at the same time. In order to protect against that scenario, let's introduce a mutex that relevant ALSA and KMS hooks will need to take to prevent concurrent execution. CEC is left out at the moment though, since the .get_modes and .detect KMS hooks, when running cec_s_phys_addr_from_edid, can end up calling CEC's .adap_enable hook. This introduces some reentrancy that isn't easy to deal with properly. The CEC hooks also don't share much state with the rest of the driver: the registers are entirely separate, we don't share any variable, the only thing that can conflict is the CEC clock divider setup that can be affected by a mode set. However, after discussing it, it looks like CEC should be able to recover from this if it was to happen. Fixes: bb7d78568814 ("drm/vc4: Add HDMI audio support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 118 +++-- drivers/gpu/drm/vc4/vc4_hdmi.h | 14 2 files changed, 126 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 484450831483..814f98414f2b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -186,6 +186,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); bool connected = false; + mutex_lock(&vc4_hdmi->mutex); + WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); if (vc4_hdmi->hpd_gpio && @@ -217,11 +219,13 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) } pm_runtime_put(&vc4_hdmi->pdev->dev); + mutex_unlock(&vc4_hdmi->mutex); return connector_status_connected; } cec_phys_addr_invalidate(vc4_hdmi->cec_adap); pm_runtime_put(&vc4_hdmi->pdev->dev); + mutex_unlock(&vc4_hdmi->mutex); return connector_status_disconnected; } @@ -238,10 +242,14 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) int ret = 0; struct edid *edid; + mutex_lock(&vc4_hdmi->mutex); + edid = drm_get_edid(connector, vc4_hdmi->ddc); cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); - if (!edid) - return -ENODEV; + if (!edid) { + ret = -ENODEV; + goto out; + } vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); @@ -261,6 +269,9 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) } } +out: + mutex_unlock(&vc4_hdmi->mutex); + return ret; } @@ -477,6 +488,8 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) union hdmi_infoframe frame; int ret; + lockdep_assert_held(&vc4_hdmi->mutex); + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, connector, mode); if (ret < 0) { @@ -528,6 +541,8 @@ static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder) struct drm_connector_state *conn_state = connector->state; union hdmi_infoframe frame; + lockdep_assert_held(&vc4_hdmi->mutex); + if (!vc4_hdmi->variant->supports_hdr) return; @@ -544,6 +559,8 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + lockdep_assert_held(&vc4_hdmi->mutex); + vc4_hdmi_set_avi_infoframe(encoder); vc4_hdmi_set_spd_infoframe(encoder); /* @@ -563,6 +580,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder, struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_display_info *display = &vc4_hdmi->connector.display_info; + lockdep_assert_held(&vc4_hdmi->mutex); + if (!vc4_encoder->hdmi_monitor) return false; @@ -581,6 +600,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); unsigned long flags; + lockdep_assert_held(&vc4_hdmi->mutex); + if (!vc4_hdmi_supports_scrambling(encoder, mode)) return; @@ -650,6 +671,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); unsigned long flags; + mutex_lock(&vc4_hdmi->mutex); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); @@ -666,6 +689,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
[PATCH 7/9] drm/vc4: hdmi: Check the device state in prepare()
Even though we already check that the encoder->crtc pointer is there during in startup(), which is part of the open() path in ASoC, nothing guarantees that our encoder state won't change between the time when we open the device and the time we prepare it. Move the sanity checks we do in startup() to a helper and call it from prepare(). Fixes: 91e99e113929 ("drm/vc4: hdmi: Register HDMI codec") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 35 +++--- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index cb444571a3f7..291fad018be3 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1394,20 +1394,36 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) return snd_soc_card_get_drvdata(card); } +static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi) +{ + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + + lockdep_assert_held(&vc4_hdmi->mutex); + + /* +* The encoder doesn't have a CRTC until the first modeset. +*/ + if (!encoder->crtc) + return false; + + /* +* If the encoder is currently in DVI mode, treat the codec DAI +* as missing. +*/ + if (!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE)) + return false; + + return true; +} + static int vc4_hdmi_audio_startup(struct device *dev, void *data) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); - struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; unsigned long flags; mutex_lock(&vc4_hdmi->mutex); - /* -* If the HDMI encoder hasn't probed, or the encoder is -* currently in DVI mode, treat the codec dai as missing. -*/ - if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & - VC4_HDMI_RAM_PACKET_ENABLE)) { + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { mutex_unlock(&vc4_hdmi->mutex); return -ENODEV; } @@ -1537,6 +1553,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, mutex_lock(&vc4_hdmi->mutex); + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { + mutex_unlock(&vc4_hdmi->mutex); + return -EINVAL; + } + vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -- 2.31.1
[PATCH 2/9] drm/vc4: Fix non-blocking commit getting stuck forever
In some situation, we can end up being stuck on a non-blocking that went through properly. The situation that seems to trigger it reliably is to first start a non-blocking commit, and then right after, and before we had any vblank interrupt), start a blocking commit. This will lead to the first commit workqueue to be scheduled, setup the display, while the second commit is waiting for the first one to be completed. The vblank interrupt will then be raised, vc4_crtc_handle_vblank() will run and will compare the active dlist in the HVS channel to the one associated with the crtc->state. However, at that point, the second commit is waiting using drm_atomic_helper_wait_for_dependencies that occurs after drm_atomic_helper_swap_state has been called, so crtc->state points to the second commit state. vc4_crtc_handle_vblank() will compare the two dlist addresses and since they don't match will ignore the interrupt. The vblank event will never be reported, and the first and second commit will wait for the first commit completion until they timeout. The underlying reason is that it was never safe to do so. Indeed, accessing the ->state pointer access synchronization is based on ownership guarantees that can only occur within the functions and hooks defined as part of the KMS framework, and obviously the irq handler isn't one of them. The rework to move to generic helpers only uncovered the underlying issue. However, since the code path between drm_atomic_helper_wait_for_dependencies() and drm_atomic_helper_wait_for_vblanks() is serialised and we can't get two commits in that path at the same time, we can work around this issue by setting a variable associated to struct drm_crtc to the dlist we expect, and then using it from the vc4_crtc_handle_vblank() function. Since that state is shared with the modesetting path, we also need to introduce a spinlock to protect the code shared between the interrupt handler and the modesetting path, protecting only our new variable for now. Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ Fixes: 56d1fe0979dc ("drm/vc4: Make pageflip completion handling more robust.") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 5 - drivers/gpu/drm/vc4/vc4_drv.h | 14 ++ drivers/gpu/drm/vc4/vc4_hvs.c | 7 +-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index b90187d2c819..98de8b265220 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -713,8 +713,9 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); + spin_lock(&vc4_crtc->irq_lock); if (vc4_crtc->event && - (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) || + (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) || vc4_crtc->feeds_txp)) { drm_crtc_send_vblank_event(crtc, vc4_crtc->event); vc4_crtc->event = NULL; @@ -728,6 +729,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) */ vc4_hvs_unmask_underrun(dev, chan); } + spin_unlock(&vc4_crtc->irq_lock); spin_unlock_irqrestore(&dev->event_lock, flags); } @@ -1127,6 +1129,7 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, return PTR_ERR(primary_plane); } + spin_lock_init(&vc4_crtc->irq_lock); drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, crtc_funcs, NULL); drm_crtc_helper_add(crtc, crtc_helper_funcs); diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 3c69b89363cb..6d2480abcf08 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -500,6 +500,20 @@ struct vc4_crtc { * @feeds_txp: True if the CRTC feeds our writeback controller. */ bool feeds_txp; + + /** +* @irq_lock: Spinlock protecting the resources shared between +* the atomic code and our vblank handler. +*/ + spinlock_t irq_lock; + + /** +* @current_dlist: Start offset of the display list currently +* set in the HVS for that CRTC. Protected by @irq_lock, and +* copied in vc4_hvs_update_dlist() for the CRTC interrupt +* handler to have access to that value. +*/ + unsigned int current_dlist; }; static inline struct vc4_crtc * diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 9ddaee6b368d..f8ed0f6a57e0 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -365,10 +365,9 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc
[PATCH 3/9] drm/vc4: crtc: Copy assigned channel to the CRTC
Accessing the crtc->state pointer from outside the modesetting context is not allowed. We thus need to copy whatever we need from the KMS state to our structure in order to access it. In VC4, a number of users of that pointers have crept in over the years, and the previous commits removed them all but the HVS channel a CRTC has been assigned. Let's move this channel in struct vc4_crtc at atomic_begin() time, drop it from our private state structure, and remove our use of crtc->state from our vblank handler entirely. Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ Fixes: 87ebcd42fb7b ("drm/vc4: crtc: Assign output to channel automatically") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 4 ++-- drivers/gpu/drm/vc4/vc4_drv.h | 9 + drivers/gpu/drm/vc4/vc4_hvs.c | 12 drivers/gpu/drm/vc4/vc4_txp.c | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 98de8b265220..e3ed52d96f42 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -708,8 +708,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) struct drm_crtc *crtc = &vc4_crtc->base; struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); - u32 chan = vc4_state->assigned_channel; + u32 chan = vc4_crtc->current_hvs_channel; unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); @@ -955,6 +954,7 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = { static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { .mode_valid = vc4_crtc_mode_valid, .atomic_check = vc4_crtc_atomic_check, + .atomic_begin = vc4_hvs_atomic_begin, .atomic_flush = vc4_hvs_atomic_flush, .atomic_enable = vc4_crtc_atomic_enable, .atomic_disable = vc4_crtc_atomic_disable, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 6d2480abcf08..4b550ebd9572 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -514,6 +514,14 @@ struct vc4_crtc { * handler to have access to that value. */ unsigned int current_dlist; + + /** +* @current_hvs_channel: HVS channel currently assigned to the +* CRTC. Protected by @irq_lock, and copied in +* vc4_hvs_atomic_begin() for the CRTC interrupt handler to have +* access to that value. +*/ + unsigned int current_hvs_channel; }; static inline struct vc4_crtc * @@ -926,6 +934,7 @@ extern struct platform_driver vc4_hvs_driver; void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output); int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output); int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state); +void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index f8ed0f6a57e0..604933e20e6a 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -393,6 +393,18 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); } +void vc4_hvs_atomic_begin(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + unsigned long flags; + + spin_lock_irqsave(&vc4_crtc->irq_lock, flags); + vc4_crtc->current_hvs_channel = vc4_state->assigned_channel; + spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); +} + void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index 26eda7542f74..9809ca3e2945 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -435,6 +435,7 @@ static void vc4_txp_atomic_disable(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = { .atomic_check = vc4_txp_atomic_check, + .atomic_begin = vc4_hvs_atomic_begin, .atomic_flush = vc4_hvs_atomic_flush, .atomic_enable = vc4_txp_atomic_enable, .atomic_disable = vc4_txp_atomic_disable, -- 2.31.1
[PATCH 6/9] drm/vc4: hdmi: Prevent access to crtc->state outside of KMS
Accessing the crtc->state pointer from outside the modesetting context is not allowed. We thus need to copy whatever we need from the KMS state to our structure in order to access it. However, in the vc4 HDMI driver we do use that pointer in the ALSA code path, and potentially in the hotplug interrupt handler path. These paths both need access to the CRTC adjusted mode in order for the proper dividers to be set for ALSA, and the scrambler state to be reinstated properly for hotplug. Let's copy this mode into our private encoder structure and reference it from there when needed. Since that part is shared between KMS and other paths, we need to protect it using our mutex. Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ Fixes: bb7d78568814 ("drm/vc4: Add HDMI audio support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 38 +++--- drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 814f98414f2b..cb444571a3f7 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -483,8 +483,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); struct drm_connector *connector = &vc4_hdmi->connector; struct drm_connector_state *cstate = connector->state; - struct drm_crtc *crtc = encoder->crtc; - const struct drm_display_mode *mode = &crtc->state->adjusted_mode; + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; union hdmi_infoframe frame; int ret; @@ -596,8 +595,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder, static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) { - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; unsigned long flags; lockdep_assert_held(&vc4_hdmi->mutex); @@ -623,18 +622,21 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct drm_crtc *crtc = encoder->crtc; unsigned long flags; + lockdep_assert_held(&vc4_hdmi->mutex); + /* * At boot, encoder->crtc will be NULL. Since we don't know the * state of the scrambler and in order to avoid any * inconsistency, let's disable it all the time. */ - if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode)) + if (crtc && !vc4_hdmi_supports_scrambling(encoder, mode)) return; - if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode)) + if (crtc && !vc4_hdmi_mode_needs_scrambling(mode)) return; if (delayed_work_pending(&vc4_hdmi->scrambling_work)) @@ -1007,8 +1009,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, vc4_hdmi_encoder_get_connector_state(encoder, state); struct vc4_hdmi_connector_state *vc4_conn_state = conn_state_to_vc4_hdmi_conn_state(conn_state); - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; unsigned long pixel_rate = vc4_conn_state->pixel_rate; unsigned long bvb_rate, hsm_rate; unsigned long flags; @@ -1110,9 +1112,9 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; - struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); unsigned long flags; mutex_lock(&vc4_hdmi->mutex); @@ -1140,8 +1142,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mod
[PATCH 8/9] drm/vc4: hdmi: Introduce an output_enabled flag
We currently poke at encoder->crtc in the ALSA code path to determine whether the HDMI output is enabled or not, and thus whether we should allow the audio output. However, that pointer is deprecated and shouldn't really be used by atomic drivers anymore. Since we have the infrastructure in place now, let's just create a flag that we toggle to report whether the controller is currently enabled and use that instead of encoder->crtc in ALSA. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 16 drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 291fad018be3..8fb8e7e57f9c 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -724,6 +724,11 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + + mutex_lock(&vc4_hdmi->mutex); + vc4_hdmi->output_enabled = false; + mutex_unlock(&vc4_hdmi->mutex); } static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) @@ -1217,6 +1222,11 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + + mutex_lock(&vc4_hdmi->mutex); + vc4_hdmi->output_enabled = true; + mutex_unlock(&vc4_hdmi->mutex); } static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, @@ -1396,14 +1406,12 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi) { - struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; - lockdep_assert_held(&vc4_hdmi->mutex); /* -* The encoder doesn't have a CRTC until the first modeset. +* If the controller is disabled, prevent any ALSA output. */ - if (!encoder->crtc) + if (!vc4_hdmi->output_enabled) return false; /* diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index a43cc5614d19..5d3e97703e8d 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -203,6 +203,12 @@ struct vc4_hdmi { * for use by ALSA hooks and interrupt handlers. Protected by @mutex. */ struct drm_display_mode saved_adjusted_mode; + + /** +* @output_enabled: Is the HDMI controller currently active? +* Protected by @mutex. +*/ + bool output_enabled; }; static inline struct vc4_hdmi * -- 2.31.1
[PATCH 9/9] drm/vc4: hdmi: Introduce a scdc_enabled flag
We currently rely on two functions, vc4_hdmi_supports_scrambling() and vc4_hdmi_mode_needs_scrambling() to determine if we should enable and disable the scrambler for any given mode. Since we might need to disable the controller at boot, we also always run vc4_hdmi_disable_scrambling() and thus call those functions without a mode yet, which in turns need to make some special casing in order for it to work. Instead of duplicating the check for whether or not we need to take care of the scrambler in both vc4_hdmi_enable_scrambling() and vc4_hdmi_disable_scrambling(), we can do that check only when we enable it and store whether or not it's been enabled in our private structure. We also need to initialize that flag at true to make sure we disable the scrambler at boot since we can't really know its state yet. This allows to simplify a bit that part of the driver, and removes one user of our copy of the CRTC adjusted mode outside of KMS (since vc4_hdmi_disable_scrambling() might be called from the hotplug interrupt handler). It also removes our last user of the legacy encoder->crtc pointer. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 22 -- drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 8fb8e7e57f9c..7b0cb08e6563 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -615,6 +615,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) VC5_HDMI_SCRAMBLER_CTL_ENABLE); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + vc4_hdmi->scdc_enabled = true; + queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work, msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS)); } @@ -622,22 +624,14 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); - struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; - struct drm_crtc *crtc = encoder->crtc; unsigned long flags; lockdep_assert_held(&vc4_hdmi->mutex); - /* -* At boot, encoder->crtc will be NULL. Since we don't know the -* state of the scrambler and in order to avoid any -* inconsistency, let's disable it all the time. -*/ - if (crtc && !vc4_hdmi_supports_scrambling(encoder, mode)) + if (!vc4_hdmi->scdc_enabled) return; - if (crtc && !vc4_hdmi_mode_needs_scrambling(mode)) - return; + vc4_hdmi->scdc_enabled = false; if (delayed_work_pending(&vc4_hdmi->scrambling_work)) cancel_delayed_work_sync(&vc4_hdmi->scrambling_work); @@ -2511,6 +2505,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi->pdev = pdev; vc4_hdmi->variant = variant; + /* +* Since we don't know the state of the controller and its +* display (if any), let's assume it's always enabled. +* vc4_hdmi_disable_scrambling() will thus run at boot, make +* sure it's disabled, and avoid any inconsistency. +*/ + vc4_hdmi->scdc_enabled = true; + ret = variant->init_resources(vc4_hdmi); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 5d3e97703e8d..36c0b082a43b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -209,6 +209,12 @@ struct vc4_hdmi { * Protected by @mutex. */ bool output_enabled; + + /** +* @scdc_enabled: Is the HDMI controller currently running with +* the scrambler on? Protected by @mutex. +*/ + bool scdc_enabled; }; static inline struct vc4_hdmi * -- 2.31.1
Re: Regression with mainline kernel on rpi4
Hi, On Thu, Oct 14, 2021 at 03:15:36PM +0200, Daniel Vetter wrote: > On Wed, Oct 13, 2021 at 05:01:03PM +0200, Maxime Ripard wrote: > > On Thu, Sep 30, 2021 at 11:19:59AM +0200, Daniel Vetter wrote: > > > On Tue, Sep 28, 2021 at 10:34:46AM +0200, Maxime Ripard wrote: > > > > Hi Daniel, > > > > > > > > On Sat, Sep 25, 2021 at 12:50:17AM +0200, Daniel Vetter wrote: > > > > > On Fri, Sep 24, 2021 at 3:30 PM Maxime Ripard > > > > > wrote: > > > > > > > > > > > > On Wed, Sep 22, 2021 at 01:25:21PM -0700, Linus Torvalds wrote: > > > > > > > On Wed, Sep 22, 2021 at 1:19 PM Sudip Mukherjee > > > > > > > wrote: > > > > > > > > > > > > > > > > I added some debugs to print the addresses, and I am getting: > > > > > > > > [ 38.813809] sudip crtc > > > > > > > > > > > > > > > > This is from struct drm_crtc *crtc = connector->state->crtc; > > > > > > > > > > > > > > Yeah, that was my personal suspicion, because while the line > > > > > > > number > > > > > > > implied "crtc->state" being NULL, the drm data structure > > > > > > > documentation > > > > > > > and other drivers both imply that "crtc" was the more likely one. > > > > > > > > > > > > > > I suspect a simple > > > > > > > > > > > > > > if (!crtc) > > > > > > > return; > > > > > > > > > > > > > > in vc4_hdmi_set_n_cts() is at least part of the fix for this all, > > > > > > > but > > > > > > > I didn't check if there is possibly something else that needs to > > > > > > > be > > > > > > > done too. > > > > > > > > > > > > Thanks for the decode_stacktrace.sh and the follow-up > > > > > > > > > > > > Yeah, it looks like we have several things wrong here: > > > > > > > > > > > > * we only check that connector->state is set, and not > > > > > > connector->state->crtc indeed. > > > > > > > > > > > > * We also check only in startup(), so at open() and not later on > > > > > > when > > > > > > the sound streaming actually start. This has been there for a > > > > > > while, > > > > > > so I guess it's never really been causing a practical issue > > > > > > before. > > > > > > > > > > You also have no locking > > > > > > > > Indeed. Do we just need locking to prevent a concurrent audio setup and > > > > modeset, or do you have another corner case in mind? > > > > > > > > Also, generally, what locks should we make sure we have locked when > > > > accessing the connector and CRTC state? drm_mode_config.connection_mutex > > > > and drm_mode_config.mutex, respectively? > > > > > > > > > plus looking at ->state objects outside of atomic commit machinery > > > > > makes no sense because you're not actually in sync with the hw state. > > > > > Relevant bits need to be copied over at commit time, protected by some > > > > > spinlock (and that spinlock also needs to be held over whatever other > > > > > stuff you're setting to make sure we don't get a funny out-of-sync > > > > > state anywhere). > > > > > > > > If we already have a lock protecting against having both an ASoC and KMS > > > > function running, it's not clear to me what the spinlock would prevent > > > > here? > > > > > > Replicating the irc chat here. With > > > > > > commit 6c5ed5ae353cdf156f9ac4db17e15db56b4de880 > > > Author: Maarten Lankhorst > > > Date: Thu Apr 6 20:55:20 2017 +0200 > > > > > > drm/atomic: Acquire connection_mutex lock in > > > drm_helper_probe_single_connector_modes, v4. > > > > > > this is already taken care of for drivers and should be all good from a > > > locking pov. > > > > So, if I understand this properly, this superseeds your comment on the > > spinlock for the hw state, but not the comment that we need some locking > > to synchronize between the audio and KMS path (and CEC?). Right? > > Other way round. There's 3 things involved here: > 1. kms output probe code > 2. kms atomic commit code > 3. calls from asoc side > > The above referenced commit makes sure 1&2 are synchronized. The problem > is that 2&3 are not synchonronized, and from 3, no matter how much locking > you have, you cannot look at kms state. I.e. not allowed to look at > crtc->state for example, irrespective of whether you're holding > drm_modeset_lock or not. This is because the atomic nonblocking commit is > done without holding any locks, protection is purely down to ownership > rules of state structures and ordering (through drm_crtc_commit) of > in-flight nonblocking atomic commits. > > That's why you need a sperate lock _and_ copy state, so taht 2&3 stay in > sync. > > In practice you only care about modeset changes from 2 vs anything from 3, > and most userspace does modeset atomic commits as blocking commits, which > means you won't notice that your locking has gaps. > > btw same problem exists between atomic and (vblank) irq handler. There you > need a irqsafe spinlock and you also have to copy (because the irq handler > just cannot access ->state in any safe way, because it doesn't own that > structure). > > This is
Re: [PATCH v2 09/11] drm/msm/disp/dpu1: Add support for DSC in topology
On 14/10/2021 17:13, Dmitry Baryshkov wrote: On 07/10/2021 10:08, Vinod Koul wrote: For DSC to work we typically need a 2,2,1 configuration. This should suffice for resolutions upto 4k. For more resolutions like 8k this won't work. Also, it is better to use 2 LMs and DSC instances as half width results in lesser power consumption as compared to single LM, DSC at full width. The panel has been tested only with 2,2,1 configuration, so for now we blindly create 2,2,1 topology when DSC is enabled Co-developed-by: Abhinav Kumar Signed-off-by: Abhinav Kumar Signed-off-by: Vinod Koul --- Changes since RFC: - Add more details in changelog drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 16 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index aac51c1bdf94..70f57a071165 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -538,6 +538,8 @@ static struct msm_display_topology dpu_encoder_get_topology( struct drm_display_mode *mode) { struct msm_display_topology topology = {0}; + struct drm_encoder *drm_enc; + struct msm_drm_private *priv; int i, intf_count = 0; for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) @@ -572,8 +574,22 @@ static struct msm_display_topology dpu_encoder_get_topology( topology.num_enc = 0; topology.num_intf = intf_count; + drm_enc = &dpu_enc->base; + priv = drm_enc->dev->dev_private; + if (priv && priv->dsc) { + /* In case of Display Stream Compression DSC, we would use + * 2 encoders, 2 line mixers and 1 interface + * this is power optimal and can drive upto (including) 4k + * screens + */ + topology.num_enc = 2; + topology.num_intf = 1; + topology.num_lm = 2; So, here you'd set the topology.num_rm. I meant 'num_dsc', please excuse the typo. + } + return topology; } + static int dpu_encoder_virt_atomic_check( struct drm_encoder *drm_enc, struct drm_crtc_state *crtc_state, -- With best wishes Dmitry
Re: [PATCH v2 06/11] drm/msm/disp/dpu1: Don't use DSC with mode_3d
On 20/10/2021 09:57, Vinod Koul wrote: On 14-10-21, 16:50, Dmitry Baryshkov wrote: On 14/10/2021 16:41, Dmitry Baryshkov wrote: On 07/10/2021 10:08, Vinod Koul wrote: We cannot enable mode_3d when we are using the DSC. So pass configuration to detect DSC is enabled and not enable mode_3d when we are using DSC We add a helper dpu_encoder_helper_get_dsc_mode() to detect dsc enabled and pass this to .setup_intf_cfg() Signed-off-by: Vinod Koul --- Changes since v1: - Move this patch from 7 to 6 - Update the changelog - Make dsc as int and store the DSC indices drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 11 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 2 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 5 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 2 ++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index e7270eb6b84b..fca07ed03317 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -332,6 +332,17 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode( return BLEND_3D_NONE; } +static inline bool dpu_encoder_helper_get_dsc_mode(struct dpu_encoder_phys *phys_enc) +{ + struct drm_encoder *drm_enc = phys_enc->parent; + struct msm_drm_private *priv = drm_enc->dev->dev_private; + + if (priv->dsc) + return BIT(0) | BIT(1); /* Hardcoding for 2 DSC topology */ Please use defined values here rater than just BIT(). Ah, it's a list of DSC blocks used. So the function name is misleading (as it's not a mode). I think we'd better pass DSC_n names here. What about using an array for cfg->dsc? Yeah I can do better names. + + return 0; +} + /** * dpu_encoder_helper_split_config - split display configuration helper function * This helper function may be used by physical encoders to configure diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index aa01698d6b25..8e5c0911734c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -70,6 +70,8 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg( intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_CMD; intf_cfg.stream_sel = cmd_enc->stream_sel; intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc); + intf_cfg.dsc = dpu_encoder_helper_get_dsc_mode(phys_enc); + ctl->ops.setup_intf_cfg(ctl, &intf_cfg); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index 64740ddb983e..3c79bd9c2fe5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -118,7 +118,7 @@ static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) return ctx->pending_flush_mask; } -static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx) +static void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx) { if (ctx->pending_flush_mask & BIT(MERGE_3D_IDX)) @@ -519,7 +519,8 @@ static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, intf_cfg |= (cfg->intf & 0xF) << 4; - if (cfg->mode_3d) { + /* In DSC we can't set merge, so check for dsc too */ + if (cfg->mode_3d && !cfg->dsc) { The more I think about this hunk, the more I'm unsure about it. Downstream has the following topoligies defined: * @SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC: 2 LM, 2 PP, 3DMux, 1 DSC, 1 INTF/WB * @SDE_RM_TOPOLOGY_QUADPIPE_3DMERGE_DSC 4 LM, 4 PP, 3DMux, 3 DSC, 2 INTF While the latter is not supported on sdm845, the former one should be (by the hardware). So in the driver I think we should make sure that mode_3d does not get set rather than disallowing it here. intf_cfg |= BIT(19); intf_cfg |= (cfg->mode_3d - 0x1) << 20; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 806c171e5df2..5dfac5994bd4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -39,6 +39,7 @@ struct dpu_hw_stage_cfg { * @mode_3d: 3d mux configuration * @merge_3d: 3d merge block used * @intf_mode_sel: Interface mode, cmd / vid + * @dsc: DSC BIT masks * @stream_sel: Stream selection for multi-stream interfaces */ struct dpu_hw_intf_cfg { @@ -46,6 +47,7 @@ struct dpu_hw_intf_cfg { enum dpu_3d_blend_mode mode_3d; enum dpu_merge_3d merge_3d; enum dpu_ctl_mode_sel intf_mode_sel; + unsigned int dsc; I think this should be: enum dpu_dsc dsc[MAX_DSCS]; unsigned int num_dsc; hmmm, how do we go about getting the num_dsc value here. dpu_encoder_phys does
Re: [PATCH v2 01/11] drm/msm/dsi: add support for dsc data
On 07/10/2021 10:08, Vinod Koul wrote: Display Stream Compression (DSC) parameters need to be calculated. Add helpers and struct msm_display_dsc_config in msm_drv for this msm_display_dsc_config uses drm_dsc_config for DSC parameters. Signed-off-by: Vinod Koul --- Changes since v1: - Drop unused fields from msm_display_dsc_config RFC: - Drop the DT parsing code - Port dsc param calculation from downstream drivers/gpu/drm/msm/dsi/dsi_host.c | 132 + drivers/gpu/drm/msm/msm_drv.h | 18 2 files changed, 150 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index e269df285136..ba24458c2e38 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -31,6 +31,8 @@ #define DSI_RESET_TOGGLE_DELAY_MS 20 +static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc); + static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) { u32 ver; @@ -156,6 +158,7 @@ struct msm_dsi_host { struct regmap *sfpb; struct drm_display_mode *mode; + struct msm_display_dsc_config *dsc; /* connected device info */ struct device_node *device_node; @@ -1748,6 +1751,135 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host, return -EINVAL; } +static u32 dsi_dsc_rc_buf_thresh[DSC_NUM_BUF_RANGES - 1] = { + 0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, + 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e +}; + +/* only 8bpc, 8bpp added */ +static char min_qp[DSC_NUM_BUF_RANGES] = { + 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13 +}; + +static char max_qp[DSC_NUM_BUF_RANGES] = { + 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15 +}; + +static char bpg_offset[DSC_NUM_BUF_RANGES] = { + 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 +}; + +static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc) +{ + int mux_words_size; + int groups_per_line, groups_total; + int min_rate_buffer_size; + int hrd_delay; + int pre_num_extra_mux_bits, num_extra_mux_bits; + int slice_bits; + int target_bpp_x16; + int data; + int final_value, final_scale; + int i; + + dsc->drm->rc_model_size = 8192; + dsc->drm->first_line_bpg_offset = 12; + dsc->drm->rc_edge_factor = 6; + dsc->drm->rc_tgt_offset_high = 3; + dsc->drm->rc_tgt_offset_low = 3; + dsc->drm->simple_422 = 0; + dsc->drm->convert_rgb = 1; + dsc->drm->vbr_enable = 0; + + /* handle only bpp = bpc = 8 */ + for (i = 0; i < DSC_NUM_BUF_RANGES - 1 ; i++) + dsc->drm->rc_buf_thresh[i] = dsi_dsc_rc_buf_thresh[i]; + + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + dsc->drm->rc_range_params[i].range_min_qp = min_qp[i]; + dsc->drm->rc_range_params[i].range_max_qp = max_qp[i]; + dsc->drm->rc_range_params[i].range_bpg_offset = bpg_offset[i]; + } + + dsc->drm->initial_offset = 6144; /* Not bpp 12 */ + if (dsc->drm->bits_per_pixel != 8) + dsc->drm->initial_offset = 2048; /* bpp = 12 */ + + mux_words_size = 48;/* bpc == 8/10 */ + if (dsc->drm->bits_per_component == 12) + mux_words_size = 64; + + dsc->drm->initial_xmit_delay = 512; + dsc->drm->initial_scale_value = 32; + dsc->drm->first_line_bpg_offset = 12; + dsc->drm->line_buf_depth = dsc->drm->bits_per_component + 1; + + /* bpc 8 */ + dsc->drm->flatness_min_qp = 3; + dsc->drm->flatness_max_qp = 12; + dsc->det_thresh_flatness = 7 + 2 * (dsc->drm->bits_per_component - 8); + dsc->drm->rc_quant_incr_limit0 = 11; + dsc->drm->rc_quant_incr_limit1 = 11; + dsc->drm->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; + + /* FIXME: need to call drm_dsc_compute_rc_parameters() so that rest of +* params are calculated +*/ + dsc->slice_last_group_size = 3 - (dsc->drm->slice_width % 3); + groups_per_line = DIV_ROUND_UP(dsc->drm->slice_width, 3); + dsc->drm->slice_chunk_size = dsc->drm->slice_width * dsc->drm->bits_per_pixel / 8; + if ((dsc->drm->slice_width * dsc->drm->bits_per_pixel) % 8) + dsc->drm->slice_chunk_size++; + + /* rbs-min */ + min_rate_buffer_size = dsc->drm->rc_model_size - dsc->drm->initial_offset + + dsc->drm->initial_xmit_delay * dsc->drm->bits_per_pixel + + groups_per_line * dsc->drm->first_line_bpg_offset; + + hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, dsc->drm->bits_per_pixel); + + dsc->drm->initial_dec_delay = hrd_delay - dsc->drm->initial_xmit_delay; + + dsc->drm->initial_scale_value = 8 * dsc->drm->rc_model_size / + (dsc->drm->rc_model_size - dsc->drm->initial_offset); + +
Re: [PATCH v2 08/11] drm/msm/disp/dpu1: Add support for DSC in encoder
On 07/10/2021 10:08, Vinod Koul wrote: We need to configure the encoder for DSC configuration and calculate DSC parameters for the given timing so this patch adds that support by adding dpu_encoder_prep_dsc() which is invoked when DSC is enabled. Signed-off-by: Vinod Koul --- Changes since v1: - Remove duplicate defines - Update changelog drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 139 +++- 1 file changed, 138 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 0e9d3fa1544b..aac51c1bdf94 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -21,6 +21,7 @@ #include "dpu_hw_intf.h" #include "dpu_hw_ctl.h" #include "dpu_hw_dspp.h" +#include "dpu_hw_dsc.h" #include "dpu_formats.h" #include "dpu_encoder_phys.h" #include "dpu_crtc.h" @@ -136,6 +137,7 @@ enum dpu_enc_rc_states { * @cur_slave:As above but for the slave encoder. * @hw_pp:Handle to the pingpong blocks used for the display. No. *pingpong blocks can be different than num_phys_encs. + * @hw_dsc:Handle to the DSC blocks used for the display. * @intfs_swapped:Whether or not the phys_enc interfaces have been swapped *for partial update right-only cases, such as pingpong *split where virtual pingpong does not generate IRQs @@ -181,6 +183,7 @@ struct dpu_encoder_virt { struct dpu_encoder_phys *cur_master; struct dpu_encoder_phys *cur_slave; struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; bool intfs_swapped; @@ -977,7 +980,8 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC]; struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC]; struct dpu_hw_blk *hw_dspp[MAX_CHANNELS_PER_ENC] = { NULL }; - int num_lm, num_ctl, num_pp; + struct dpu_hw_blk *hw_dsc[MAX_CHANNELS_PER_ENC]; + int num_lm, num_ctl, num_pp, num_dsc; int i, j; if (!drm_enc) { @@ -1035,6 +1039,13 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i]) : NULL; + if (priv->dsc) { + num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, + drm_enc->base.id, DPU_HW_BLK_DSC, hw_dsc, ARRAY_SIZE(hw_dsc)); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) + dpu_enc->hw_dsc[i] = i < num_dsc ? to_dpu_hw_dsc(hw_dsc[i]) : NULL; + } + cstate = to_dpu_crtc_state(drm_crtc->state); for (i = 0; i < num_lm; i++) { @@ -1778,10 +1789,132 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) nsecs_to_jiffies(ktime_to_ns(wakeup_time))); } +static void +dpu_encoder_dsc_pclk_param_calc(struct msm_display_dsc_config *dsc, u32 width) +{ + int slice_count, slice_per_intf; + int bytes_in_slice, total_bytes_per_intf; + + if (!dsc || !dsc->drm->slice_width || !dsc->drm->slice_count) { + DPU_ERROR("Invalid DSC/slices\n"); + return; + } + + slice_count = dsc->drm->slice_count; + slice_per_intf = DIV_ROUND_UP(width, dsc->drm->slice_width); + + /* +* If slice_count is greater than slice_per_intf then default to 1. +* This can happen during partial update. +*/ + if (slice_count > slice_per_intf) + slice_count = 1; + + bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width * + dsc->drm->bits_per_pixel, 8); + total_bytes_per_intf = bytes_in_slice * slice_per_intf; + + dsc->eol_byte_num = total_bytes_per_intf % 3; + dsc->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + dsc->bytes_in_slice = bytes_in_slice; + dsc->bytes_per_pkt = bytes_in_slice * slice_count; + dsc->pkt_per_line = slice_per_intf / slice_count; +} + +static void +dpu_encoder_dsc_initial_line_calc(struct msm_display_dsc_config *dsc, + u32 enc_ip_width) +{ + int ssm_delay, total_pixels, soft_slice_per_enc; + + soft_slice_per_enc = enc_ip_width / dsc->drm->slice_width; + + /* +* minimum number of initial line pixels is a sum of: +* 1. sub-stream multiplexer delay (83 groups for 8bpc, +*91 for 10 bpc) * 3 +* 2. for two soft slice cases, add extra sub-stream multiplexer * 3 +* 3. the initial xmit delay +* 4. total pipeline delay through the "lock step" of encoder (47) +* 5. 6 additional pixels as the output of the rate buffer is +*48 bits wide +*
Re: [PATCH -next] drm: Small optimization to intel_dp_mst_atomic_master_trans_check
On Thu, Oct 21, 2021 at 10:22:43PM -0400, He Ying wrote: > If we want to return from for_each_intel_connector_iter(), one > way is calling drm_connector_list_iter_end() before returning > to avoid memleak. The other way is just breaking from the bracket > and then returning after the outside drm_connector_list_iter_end(). > Obviously, the second way makes code smaller and more clear. > Apply it to the function intel_dp_mst_atomic_master_trans_check(). Matches what we seem to be doing everywhere else. Applied to drm-intel-next. Thanks. > > Signed-off-by: He Ying > --- > drivers/gpu/drm/i915/display/intel_dp_mst.c | 18 -- > 1 file changed, 8 insertions(+), 10 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c > b/drivers/gpu/drm/i915/display/intel_dp_mst.c > index 8d13d7b26a25..bbecbbbcb10d 100644 > --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c > +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c > @@ -231,6 +231,7 @@ intel_dp_mst_atomic_master_trans_check(struct > intel_connector *connector, > struct drm_i915_private *dev_priv = to_i915(state->base.dev); > struct drm_connector_list_iter connector_list_iter; > struct intel_connector *connector_iter; > + int ret = 0; > > if (DISPLAY_VER(dev_priv) < 12) > return 0; > @@ -243,7 +244,6 @@ intel_dp_mst_atomic_master_trans_check(struct > intel_connector *connector, > struct intel_digital_connector_state *conn_iter_state; > struct intel_crtc_state *crtc_state; > struct intel_crtc *crtc; > - int ret; > > if (connector_iter->mst_port != connector->mst_port || > connector_iter == connector) > @@ -252,8 +252,8 @@ intel_dp_mst_atomic_master_trans_check(struct > intel_connector *connector, > conn_iter_state = > intel_atomic_get_digital_connector_state(state, > > connector_iter); > if (IS_ERR(conn_iter_state)) { > - drm_connector_list_iter_end(&connector_list_iter); > - return PTR_ERR(conn_iter_state); > + ret = PTR_ERR(conn_iter_state); > + break; > } > > if (!conn_iter_state->base.crtc) > @@ -262,20 +262,18 @@ intel_dp_mst_atomic_master_trans_check(struct > intel_connector *connector, > crtc = to_intel_crtc(conn_iter_state->base.crtc); > crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); > if (IS_ERR(crtc_state)) { > - drm_connector_list_iter_end(&connector_list_iter); > - return PTR_ERR(crtc_state); > + ret = PTR_ERR(crtc_state); > + break; > } > > ret = drm_atomic_add_affected_planes(&state->base, &crtc->base); > - if (ret) { > - drm_connector_list_iter_end(&connector_list_iter); > - return ret; > - } > + if (ret) > + break; > crtc_state->uapi.mode_changed = true; > } > drm_connector_list_iter_end(&connector_list_iter); > > - return 0; > + return ret; > } > > static int > -- > 2.17.1 -- Ville Syrjälä Intel
Re: [PATCH 28/28] drm/i915: Remove short-term pins from execbuf, v4.
On Thu, 21 Oct 2021 at 11:37, Maarten Lankhorst wrote: > > Add a flag PIN_VALIDATE, to indicate we don't need to pin and only > protected by the object lock. > > This removes the need to unpin, which is done by just releasing the > lock. > > eb_reserve is slightly reworked for readability, but the same steps > are still done: > - First pass pins with NONBLOCK. > - Second pass unbinds all objects first, then pins. > - Third pass is only called when not all objects are softpinned, and > unbinds all objects, then calls i915_gem_evict_vm(), then pins. > > When evicting the entire vm in eb_reserve() we do temporarily pin objects > that are marked with EXEC_OBJECT_PINNED. This is because they are already > at their destination, and i915_gem_evict_vm() would otherwise unbind them. > > However, we reduce the visibility of those pins by limiting the pin > to our call to i915_gem_evict_vm() only, and pin with vm->mutex held, > instead of the entire duration of the execbuf. > > Not sure the latter matters, one can hope.. > In theory we could kill the pinning by adding an extra flag to the vma > to temporarily prevent unbinding for gtt for i915_gem_evict_vm only, but > I think that might be overkill. We're still holding the object lock, and > we don't have blocking eviction yet. It's likely sufficient to simply > enforce EXEC_OBJECT_PINNED for all objects on >= gen12. > > Changes since v1: > - Split out eb_reserve() into separate functions for readability. > Changes since v2: > - Make batch buffer mappable on platforms where only GGTT is available, > to prevent moving the batch buffer during relocations. > Changes since v3: > - Preserve current behavior for batch buffer, instead be cautious when > calling i915_gem_object_ggtt_pin_ww, and re-use the current batch vma > if it's inside ggtt and map-and-fenceable. > > Signed-off-by: Maarten Lankhorst > --- > .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 252 ++ > drivers/gpu/drm/i915/i915_gem_gtt.h | 1 + > drivers/gpu/drm/i915/i915_vma.c | 24 +- > 3 files changed, 161 insertions(+), 116 deletions(-) > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > index bbf2a10738f7..19f91143cfcf 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > @@ -439,7 +439,7 @@ eb_pin_vma(struct i915_execbuffer *eb, > else > pin_flags = entry->offset & PIN_OFFSET_MASK; > > - pin_flags |= PIN_USER | PIN_NOEVICT | PIN_OFFSET_FIXED; > + pin_flags |= PIN_USER | PIN_NOEVICT | PIN_OFFSET_FIXED | PIN_VALIDATE; > if (unlikely(ev->flags & EXEC_OBJECT_NEEDS_GTT)) > pin_flags |= PIN_GLOBAL; > > @@ -457,17 +457,15 @@ eb_pin_vma(struct i915_execbuffer *eb, > entry->pad_to_size, > entry->alignment, > eb_pin_flags(entry, ev->flags) | > -PIN_USER | PIN_NOEVICT); > +PIN_USER | PIN_NOEVICT | > PIN_VALIDATE); > if (unlikely(err)) > return err; > } > > if (unlikely(ev->flags & EXEC_OBJECT_NEEDS_FENCE)) { > err = i915_vma_pin_fence(vma); > - if (unlikely(err)) { > - i915_vma_unpin(vma); > + if (unlikely(err)) > return err; > - } > > if (vma->fence) > ev->flags |= __EXEC_OBJECT_HAS_FENCE; > @@ -483,13 +481,9 @@ eb_pin_vma(struct i915_execbuffer *eb, > static inline void > eb_unreserve_vma(struct eb_vma *ev) > { > - if (!(ev->flags & __EXEC_OBJECT_HAS_PIN)) > - return; > - > if (unlikely(ev->flags & __EXEC_OBJECT_HAS_FENCE)) > __i915_vma_unpin_fence(ev->vma); > > - __i915_vma_unpin(ev->vma); > ev->flags &= ~__EXEC_OBJECT_RESERVED; > } > > @@ -682,10 +676,8 @@ static int eb_reserve_vma(struct i915_execbuffer *eb, > > if (unlikely(ev->flags & EXEC_OBJECT_NEEDS_FENCE)) { > err = i915_vma_pin_fence(vma); > - if (unlikely(err)) { > - i915_vma_unpin(vma); > + if (unlikely(err)) > return err; > - } > > if (vma->fence) > ev->flags |= __EXEC_OBJECT_HAS_FENCE; > @@ -697,85 +689,129 @@ static int eb_reserve_vma(struct i915_execbuffer *eb, > return 0; > } > > -static int eb_reserve(struct i915_execbuffer *eb) > +static int eb_evict_vm(struct i915_execbuffer *eb) > +{ > + const unsigned int count = eb->buffer_count; > + unsigned int i; > + int err; > + > + err = mutex_lock_interruptible(&eb->context->vm->mutex); > + if (e
Re: [PATCH 21/28] drm/i915: Drain the ttm delayed workqueue too
On Thu, 21 Oct 2021 at 11:37, Maarten Lankhorst wrote: > > Be thorough.. > > Signed-off-by: Maarten Lankhorst Is this strictly needed for something? Needs a proper commit message anyway. > --- > drivers/gpu/drm/i915/i915_drv.h | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 22c891720c6d..7c5ed5957fe2 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -1819,6 +1819,7 @@ static inline void i915_gem_drain_freed_objects(struct > drm_i915_private *i915) > */ > while (atomic_read(&i915->mm.free_count)) { > flush_work(&i915->mm.free_work); > + flush_delayed_work(&i915->bdev.wq); > rcu_barrier(); > } > } > -- > 2.33.0 >
[PATCH v6 01/21] drm/bridge: adv7533: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. This also avoids leaking the device when we detach the bridge. Acked-by: Sam Ravnborg Tested-by: John Stultz Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/adv7511/adv7511.h | 1 - drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 2 -- drivers/gpu/drm/bridge/adv7511/adv7533.c | 20 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 05e3abb5a0c9..592ecfcf00ca 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -401,7 +401,6 @@ void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode); int adv7533_patch_registers(struct adv7511 *adv); int adv7533_patch_cec_registers(struct adv7511 *adv); int adv7533_attach_dsi(struct adv7511 *adv); -void adv7533_detach_dsi(struct adv7511 *adv); int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv); #ifdef CONFIG_DRM_I2C_ADV7511_AUDIO diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 76555ae64e9c..9e3585f23cf1 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -1307,8 +1307,6 @@ static int adv7511_remove(struct i2c_client *i2c) { struct adv7511 *adv7511 = i2c_get_clientdata(i2c); - if (adv7511->type == ADV7533 || adv7511->type == ADV7535) - adv7533_detach_dsi(adv7511); i2c_unregister_device(adv7511->i2c_cec); clk_disable_unprepare(adv7511->cec_clk); diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index 59d718bde8c4..eb7579dec40a 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -153,11 +153,10 @@ int adv7533_attach_dsi(struct adv7511 *adv) return -EPROBE_DEFER; } - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { dev_err(dev, "failed to create dsi device\n"); - ret = PTR_ERR(dsi); - goto err_dsi_device; + return PTR_ERR(dsi); } adv->dsi = dsi; @@ -167,24 +166,13 @@ int adv7533_attach_dsi(struct adv7511 *adv) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE; - ret = mipi_dsi_attach(dsi); + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { dev_err(dev, "failed to attach dsi to host\n"); - goto err_dsi_attach; + return ret; } return 0; - -err_dsi_attach: - mipi_dsi_device_unregister(dsi); -err_dsi_device: - return ret; -} - -void adv7533_detach_dsi(struct adv7511 *adv) -{ - mipi_dsi_detach(adv->dsi); - mipi_dsi_device_unregister(adv->dsi); } int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) -- 2.31.1
[PATCH v6 00/21] drm/bridge: Make panel and bridge probe order consistent
Hi, We've encountered an issue with the RaspberryPi DSI panel that prevented the whole display driver from probing. The issue is described in detail in the commit 7213246a803f ("drm/vc4: dsi: Only register our component once a DSI device is attached"), but the basic idea is that since the panel is probed through i2c, there's no synchronization between its probe and the registration of the MIPI-DSI host it's attached to. We initially moved the component framework registration to the MIPI-DSI Host attach hook to make sure we register our component only when we have a DSI device attached to our MIPI-DSI host, and then use lookup our DSI device in our bind hook. However, all the DSI bridges controlled through i2c are only registering their associated DSI device in their bridge attach hook, meaning with our change above, we never got that far, and therefore ended up in the same situation than the one we were trying to fix for panels. The best practice to avoid those issues is to register its functions only after all its dependencies are live. We also shouldn't wait any longer than we should to play nice with the other components that are waiting for us, so in our case that would mean moving the DSI device registration to the bridge probe. This has been tested on vc4 (with sn65dsi83 and ps8640), msm (sn65dsi86, lt9611), kirin (adv7511) and exynos. Let me know what you think, Maxime --- Changes from v5: - Collected more tags - Fixed a compilation error for ps8640 Changes from v4: - Rebased on current drm-misc-next - Collected the various tags - Fix for Kirin - Added conversion patch for msm Changes from v3: - Converted exynos and kirin - Converted all the affected bridge drivers - Reworded the documentation a bit Changes from v2: - Changed the approach as suggested by Andrzej, and aligned the bridge on the panel this time. - Fixed some typos Changes from v1: - Change the name of drm_of_get_next function to drm_of_get_bridge - Mention the revert of 87154ff86bf6 and squash the two patches that were reverting that commit - Add some documentation - Make drm_panel_attach and _detach succeed when no callback is there Maxime Ripard (20): drm/bridge: adv7533: Switch to devm MIPI-DSI helpers drm/bridge: adv7511: Register and attach our DSI device at probe drm/bridge: anx7625: Switch to devm MIPI-DSI helpers drm/bridge: anx7625: Register and attach our DSI device at probe drm/bridge: lt8912b: Switch to devm MIPI-DSI helpers drm/bridge: lt8912b: Register and attach our DSI device at probe drm/bridge: lt9611: Switch to devm MIPI-DSI helpers drm/bridge: lt9611: Register and attach our DSI device at probe drm/bridge: lt9611uxc: Switch to devm MIPI-DSI helpers drm/bridge: lt9611uxc: Register and attach our DSI device at probe drm/bridge: ps8640: Switch to devm MIPI-DSI helpers drm/bridge: ps8640: Register and attach our DSI device at probe drm/bridge: sn65dsi83: Fix bridge removal drm/bridge: sn65dsi83: Switch to devm MIPI-DSI helpers drm/bridge: sn65dsi83: Register and attach our DSI device at probe drm/bridge: sn65dsi86: Switch to devm MIPI-DSI helpers drm/bridge: sn65dsi86: Register and attach our DSI device at probe drm/bridge: tc358775: Switch to devm MIPI-DSI helpers drm/bridge: tc358775: Register and attach our DSI device at probe drm/kirin: dsi: Adjust probe order Rob Clark (1): drm/msm/dsi: Adjust probe order drivers/gpu/drm/bridge/adv7511/adv7511.h | 1 - drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 15 ++- drivers/gpu/drm/bridge/adv7511/adv7533.c | 20 +--- drivers/gpu/drm/bridge/analogix/anx7625.c| 40 --- drivers/gpu/drm/bridge/lontium-lt8912b.c | 31 ++ drivers/gpu/drm/bridge/lontium-lt9611.c | 62 --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 65 +--- drivers/gpu/drm/bridge/parade-ps8640.c | 105 ++- drivers/gpu/drm/bridge/tc358775.c| 50 + drivers/gpu/drm/bridge/ti-sn65dsi83.c| 88 drivers/gpu/drm/bridge/ti-sn65dsi86.c| 101 +- drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 52 + drivers/gpu/drm/msm/dsi/dsi.c| 50 + drivers/gpu/drm/msm/dsi/dsi.h| 2 +- drivers/gpu/drm/msm/dsi/dsi_host.c | 22 ++-- drivers/gpu/drm/msm/dsi/dsi_manager.c| 6 +- drivers/gpu/drm/msm/msm_drv.h| 2 + 17 files changed, 348 insertions(+), 364 deletions(-) -- 2.31.1
[PATCH v6 02/21] drm/bridge: adv7511: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Tested-by: John Stultz Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 9e3585f23cf1..f8e5da148599 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -910,9 +910,6 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge, return ret; } - if (adv->type == ADV7533 || adv->type == ADV7535) - ret = adv7533_attach_dsi(adv); - if (adv->i2c_main->irq) regmap_write(adv->regmap, ADV7511_REG_INT_ENABLE(0), ADV7511_INT0_HPD); @@ -1288,8 +1285,18 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) drm_bridge_add(&adv7511->bridge); adv7511_audio_init(dev, adv7511); + + if (adv7511->type == ADV7533 || adv7511->type == ADV7535) { + ret = adv7533_attach_dsi(adv7511); + if (ret) + goto err_unregister_audio; + } + return 0; +err_unregister_audio: + adv7511_audio_exit(adv7511); + drm_bridge_remove(&adv7511->bridge); err_unregister_cec: i2c_unregister_device(adv7511->i2c_cec); clk_disable_unprepare(adv7511->cec_clk); -- 2.31.1
[PATCH v6 04/21] drm/bridge: anx7625: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/analogix/anx7625.c | 20 ++-- 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 4adeb2bad03a..d0317651cd75 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1367,12 +1367,6 @@ static int anx7625_bridge_attach(struct drm_bridge *bridge, return -ENODEV; } - err = anx7625_attach_dsi(ctx); - if (err) { - DRM_DEV_ERROR(dev, "Fail to attach to dsi : %d\n", err); - return err; - } - if (ctx->pdata.panel_bridge) { err = drm_bridge_attach(bridge->encoder, ctx->pdata.panel_bridge, @@ -1845,10 +1839,24 @@ static int anx7625_i2c_probe(struct i2c_client *client, platform->bridge.type = DRM_MODE_CONNECTOR_eDP; drm_bridge_add(&platform->bridge); + ret = anx7625_attach_dsi(platform); + if (ret) { + DRM_DEV_ERROR(dev, "Fail to attach to dsi : %d\n", ret); + goto unregister_bridge; + } + DRM_DEV_DEBUG_DRIVER(dev, "probe done\n"); return 0; +unregister_bridge: + drm_bridge_remove(&platform->bridge); + + if (!platform->pdata.low_power_mode) + pm_runtime_put_sync_suspend(&client->dev); + + anx7625_unregister_i2c_dummy_clients(platform); + free_wq: if (platform->workqueue) destroy_workqueue(platform->workqueue); -- 2.31.1
[PATCH v6 05/21] drm/bridge: lt8912b: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt8912b.c | 20 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 1b0c7eaf6c84..cc968d65936b 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -472,11 +472,11 @@ static int lt8912_attach_dsi(struct lt8912 *lt) return -EPROBE_DEFER; } - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { ret = PTR_ERR(dsi); dev_err(dev, "failed to create dsi device (%d)\n", ret); - goto err_dsi_device; + return ret; } lt->dsi = dsi; @@ -489,24 +489,13 @@ static int lt8912_attach_dsi(struct lt8912 *lt) MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; - ret = mipi_dsi_attach(dsi); + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { dev_err(dev, "failed to attach dsi to host\n"); - goto err_dsi_attach; + return ret; } return 0; - -err_dsi_attach: - mipi_dsi_device_unregister(dsi); -err_dsi_device: - return ret; -} - -static void lt8912_detach_dsi(struct lt8912 *lt) -{ - mipi_dsi_detach(lt->dsi); - mipi_dsi_device_unregister(lt->dsi); } static int lt8912_bridge_connector_init(struct drm_bridge *bridge) @@ -573,7 +562,6 @@ static void lt8912_bridge_detach(struct drm_bridge *bridge) struct lt8912 *lt = bridge_to_lt8912(bridge); if (lt->is_attached) { - lt8912_detach_dsi(lt); lt8912_hard_power_off(lt); drm_connector_unregister(<->connector); drm_connector_cleanup(<->connector); -- 2.31.1
[PATCH v6 03/21] drm/bridge: anx7625: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/analogix/anx7625.c | 20 +--- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 1a871f6b6822..4adeb2bad03a 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1316,6 +1316,7 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) .channel = 0, .node = NULL, }; + int ret; DRM_DEV_DEBUG_DRIVER(dev, "attach dsi\n"); @@ -1325,7 +1326,7 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) return -EINVAL; } - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { DRM_DEV_ERROR(dev, "fail to create dsi device.\n"); return -EINVAL; @@ -1337,10 +1338,10 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO_HSE; - if (mipi_dsi_attach(dsi) < 0) { + ret = devm_mipi_dsi_attach(dev, dsi); + if (ret) { DRM_DEV_ERROR(dev, "fail to attach dsi to host.\n"); - mipi_dsi_device_unregister(dsi); - return -EINVAL; + return ret; } ctx->dsi = dsi; @@ -1350,16 +1351,6 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) return 0; } -static void anx7625_bridge_detach(struct drm_bridge *bridge) -{ - struct anx7625_data *ctx = bridge_to_anx7625(bridge); - - if (ctx->dsi) { - mipi_dsi_detach(ctx->dsi); - mipi_dsi_device_unregister(ctx->dsi); - } -} - static int anx7625_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -1624,7 +1615,6 @@ static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, static const struct drm_bridge_funcs anx7625_bridge_funcs = { .attach = anx7625_bridge_attach, - .detach = anx7625_bridge_detach, .disable = anx7625_bridge_disable, .mode_valid = anx7625_bridge_mode_valid, .mode_set = anx7625_bridge_mode_set, -- 2.31.1
[PATCH v6 08/21] drm/bridge: lt9611: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Tested-by: John Stultz Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt9611.c | 38 - 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 654131aca5ed..d2f45a0f79c8 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -825,26 +825,7 @@ static int lt9611_bridge_attach(struct drm_bridge *bridge, return ret; } - /* Attach primary DSI */ - lt9611->dsi0 = lt9611_attach_dsi(lt9611, lt9611->dsi0_node); - if (IS_ERR(lt9611->dsi0)) - return PTR_ERR(lt9611->dsi0); - - /* Attach secondary DSI, if specified */ - if (lt9611->dsi1_node) { - lt9611->dsi1 = lt9611_attach_dsi(lt9611, lt9611->dsi1_node); - if (IS_ERR(lt9611->dsi1)) { - ret = PTR_ERR(lt9611->dsi1); - goto err_unregister_dsi0; - } - } - return 0; - -err_unregister_dsi0: - drm_connector_cleanup(<9611->connector); - - return ret; } static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge, @@ -1165,10 +1146,29 @@ static int lt9611_probe(struct i2c_client *client, drm_bridge_add(<9611->bridge); + /* Attach primary DSI */ + lt9611->dsi0 = lt9611_attach_dsi(lt9611, lt9611->dsi0_node); + if (IS_ERR(lt9611->dsi0)) { + ret = PTR_ERR(lt9611->dsi0); + goto err_remove_bridge; + } + + /* Attach secondary DSI, if specified */ + if (lt9611->dsi1_node) { + lt9611->dsi1 = lt9611_attach_dsi(lt9611, lt9611->dsi1_node); + if (IS_ERR(lt9611->dsi1)) { + ret = PTR_ERR(lt9611->dsi1); + goto err_remove_bridge; + } + } + lt9611_enable_hpd_interrupts(lt9611); return lt9611_audio_init(dev, lt9611); +err_remove_bridge: + drm_bridge_remove(<9611->bridge); + err_disable_regulators: regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies); -- 2.31.1
[PATCH v6 07/21] drm/bridge: lt9611: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. Acked-by: Sam Ravnborg Tested-by: John Stultz Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt9611.c | 24 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 29b1ce2140ab..654131aca5ed 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -760,6 +760,7 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, const struct mipi_dsi_device_info info = { "lt9611", 0, NULL }; struct mipi_dsi_device *dsi; struct mipi_dsi_host *host; + struct device *dev = lt9611->dev; int ret; host = of_find_mipi_dsi_host_by_node(dsi_node); @@ -768,7 +769,7 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, return ERR_PTR(-EPROBE_DEFER); } - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { dev_err(lt9611->dev, "failed to create dsi device\n"); return dsi; @@ -779,29 +780,15 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO_HSE; - ret = mipi_dsi_attach(dsi); + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { - dev_err(lt9611->dev, "failed to attach dsi to host\n"); - mipi_dsi_device_unregister(dsi); + dev_err(dev, "failed to attach dsi to host\n"); return ERR_PTR(ret); } return dsi; } -static void lt9611_bridge_detach(struct drm_bridge *bridge) -{ - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - - if (lt9611->dsi1) { - mipi_dsi_detach(lt9611->dsi1); - mipi_dsi_device_unregister(lt9611->dsi1); - } - - mipi_dsi_detach(lt9611->dsi0); - mipi_dsi_device_unregister(lt9611->dsi0); -} - static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt9611) { int ret; @@ -855,9 +842,7 @@ static int lt9611_bridge_attach(struct drm_bridge *bridge, return 0; err_unregister_dsi0: - lt9611_bridge_detach(bridge); drm_connector_cleanup(<9611->connector); - mipi_dsi_device_unregister(lt9611->dsi0); return ret; } @@ -952,7 +937,6 @@ static void lt9611_bridge_hpd_enable(struct drm_bridge *bridge) static const struct drm_bridge_funcs lt9611_bridge_funcs = { .attach = lt9611_bridge_attach, - .detach = lt9611_bridge_detach, .mode_valid = lt9611_bridge_mode_valid, .enable = lt9611_bridge_enable, .disable = lt9611_bridge_disable, -- 2.31.1
[PATCH v6 10/21] drm/bridge: lt9611uxc: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 31 +- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index ab1a0c00aad8..33f9716da0ee 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -367,18 +367,6 @@ static int lt9611uxc_bridge_attach(struct drm_bridge *bridge, return ret; } - /* Attach primary DSI */ - lt9611uxc->dsi0 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi0_node); - if (IS_ERR(lt9611uxc->dsi0)) - return PTR_ERR(lt9611uxc->dsi0); - - /* Attach secondary DSI, if specified */ - if (lt9611uxc->dsi1_node) { - lt9611uxc->dsi1 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi1_node); - if (IS_ERR(lt9611uxc->dsi1)) - return PTR_ERR(lt9611uxc->dsi1); - } - return 0; } @@ -958,8 +946,27 @@ static int lt9611uxc_probe(struct i2c_client *client, drm_bridge_add(<9611uxc->bridge); + /* Attach primary DSI */ + lt9611uxc->dsi0 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi0_node); + if (IS_ERR(lt9611uxc->dsi0)) { + ret = PTR_ERR(lt9611uxc->dsi0); + goto err_remove_bridge; + } + + /* Attach secondary DSI, if specified */ + if (lt9611uxc->dsi1_node) { + lt9611uxc->dsi1 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi1_node); + if (IS_ERR(lt9611uxc->dsi1)) { + ret = PTR_ERR(lt9611uxc->dsi1); + goto err_remove_bridge; + } + } + return lt9611uxc_audio_init(dev, lt9611uxc); +err_remove_bridge: + drm_bridge_remove(<9611uxc->bridge); + err_disable_regulators: regulator_bulk_disable(ARRAY_SIZE(lt9611uxc->supplies), lt9611uxc->supplies); -- 2.31.1
[PATCH v6 09/21] drm/bridge: lt9611uxc: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 38 +- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 010657ea7af7..ab1a0c00aad8 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -258,17 +258,18 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc, const struct mipi_dsi_device_info info = { "lt9611uxc", 0, NULL }; struct mipi_dsi_device *dsi; struct mipi_dsi_host *host; + struct device *dev = lt9611uxc->dev; int ret; host = of_find_mipi_dsi_host_by_node(dsi_node); if (!host) { - dev_err(lt9611uxc->dev, "failed to find dsi host\n"); + dev_err(dev, "failed to find dsi host\n"); return ERR_PTR(-EPROBE_DEFER); } - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { - dev_err(lt9611uxc->dev, "failed to create dsi device\n"); + dev_err(dev, "failed to create dsi device\n"); return dsi; } @@ -277,10 +278,9 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc, dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO_HSE; - ret = mipi_dsi_attach(dsi); + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { - dev_err(lt9611uxc->dev, "failed to attach dsi to host\n"); - mipi_dsi_device_unregister(dsi); + dev_err(dev, "failed to attach dsi to host\n"); return ERR_PTR(ret); } @@ -355,19 +355,6 @@ static int lt9611uxc_connector_init(struct drm_bridge *bridge, struct lt9611uxc return drm_connector_attach_encoder(<9611uxc->connector, bridge->encoder); } -static void lt9611uxc_bridge_detach(struct drm_bridge *bridge) -{ - struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge); - - if (lt9611uxc->dsi1) { - mipi_dsi_detach(lt9611uxc->dsi1); - mipi_dsi_device_unregister(lt9611uxc->dsi1); - } - - mipi_dsi_detach(lt9611uxc->dsi0); - mipi_dsi_device_unregister(lt9611uxc->dsi0); -} - static int lt9611uxc_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -388,19 +375,11 @@ static int lt9611uxc_bridge_attach(struct drm_bridge *bridge, /* Attach secondary DSI, if specified */ if (lt9611uxc->dsi1_node) { lt9611uxc->dsi1 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi1_node); - if (IS_ERR(lt9611uxc->dsi1)) { - ret = PTR_ERR(lt9611uxc->dsi1); - goto err_unregister_dsi0; - } + if (IS_ERR(lt9611uxc->dsi1)) + return PTR_ERR(lt9611uxc->dsi1); } return 0; - -err_unregister_dsi0: - mipi_dsi_detach(lt9611uxc->dsi0); - mipi_dsi_device_unregister(lt9611uxc->dsi0); - - return ret; } static enum drm_mode_status @@ -544,7 +523,6 @@ static struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge, static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = { .attach = lt9611uxc_bridge_attach, - .detach = lt9611uxc_bridge_detach, .mode_valid = lt9611uxc_bridge_mode_valid, .mode_set = lt9611uxc_bridge_mode_set, .detect = lt9611uxc_bridge_detect, -- 2.31.1
[PATCH v6 06/21] drm/bridge: lt8912b: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt8912b.c | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index cc968d65936b..c642d1e02b2f 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -544,10 +544,6 @@ static int lt8912_bridge_attach(struct drm_bridge *bridge, if (ret) goto error; - ret = lt8912_attach_dsi(lt); - if (ret) - goto error; - lt->is_attached = true; return 0; @@ -706,8 +702,15 @@ static int lt8912_probe(struct i2c_client *client, drm_bridge_add(<->bridge); + ret = lt8912_attach_dsi(lt); + if (ret) + goto err_attach; + return 0; +err_attach: + drm_bridge_remove(<->bridge); + lt8912_free_i2c(lt); err_i2c: lt8912_put_dt(lt); err_dt_parse: -- 2.31.1
[PATCH v6 17/21] drm/bridge: sn65dsi86: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 77 ++- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 36a82e3d17ab..b6ce6776cdf1 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -655,58 +655,27 @@ static struct ti_sn65dsi86 *bridge_to_ti_sn65dsi86(struct drm_bridge *bridge) return container_of(bridge, struct ti_sn65dsi86, bridge); } -static int ti_sn_bridge_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) +static int ti_sn_attach_host(struct ti_sn65dsi86 *pdata) { int ret, val; - struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); struct mipi_dsi_host *host; struct mipi_dsi_device *dsi; struct device *dev = pdata->dev; const struct mipi_dsi_device_info info = { .type = "ti_sn_bridge", .channel = 0, .node = NULL, -}; + }; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } - - pdata->aux.drm_dev = bridge->dev; - ret = drm_dp_aux_register(&pdata->aux); - if (ret < 0) { - drm_err(bridge->dev, "Failed to register DP AUX channel: %d\n", ret); - return ret; - } - - ret = ti_sn_bridge_connector_init(pdata); - if (ret < 0) - goto err_conn_init; - - /* -* TODO: ideally finding host resource and dsi dev registration needs -* to be done in bridge probe. But some existing DSI host drivers will -* wait for any of the drm_bridge/drm_panel to get added to the global -* bridge/panel list, before completing their probe. So if we do the -* dsi dev registration part in bridge probe, before populating in -* the global bridge list, then it will cause deadlock as dsi host probe -* will never complete, neither our bridge probe. So keeping it here -* will satisfy most of the existing host drivers. Once the host driver -* is fixed we can move the below code to bridge probe safely. -*/ host = of_find_mipi_dsi_host_by_node(pdata->host_node); if (!host) { DRM_ERROR("failed to find dsi host\n"); - ret = -ENODEV; - goto err_dsi_host; + return -ENODEV; } dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { DRM_ERROR("failed to create dsi device\n"); - ret = PTR_ERR(dsi); - goto err_dsi_host; + return PTR_ERR(dsi); } /* TODO: setting to 4 MIPI lanes always for now */ @@ -721,12 +690,38 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, if (!(val & DPPLL_CLK_SRC_DSICLK)) dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; + pdata->dsi = dsi; + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { DRM_ERROR("failed to attach dsi to host\n"); - goto err_dsi_host; + return ret; } - pdata->dsi = dsi; + + return 0; +} + +static int ti_sn_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); + int ret; + + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { + DRM_ERROR("Fix bridge driver to make connector optional!"); + return -EINVAL; + } + + pdata->aux.drm_dev = bridge->dev; + ret = drm_dp_aux_register(&pdata->aux); + if (ret < 0) { + drm_err(bridge->dev, "Failed to register DP AUX channel: %d\n", ret); + return ret; + } + + ret = ti_sn_bridge_connector_init(pdata); + if (ret < 0) + goto err_conn_init; /* We never want the next bridge to *also* create a connector: */ flags |= DRM_BRIDGE_ATTACH_NO_CONNECTOR; @@ -1224,7 +1219,15 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev, drm_bridge_add(&pdata->bridge); + ret = ti_sn_attach_host(pdata); + if (ret) + goto err_remove_bridge; + return 0; + +err_remove_bridge: + drm_bridge_remove(&pdata->bridge); + return ret; } static void ti_sn_bridge_remove(struct auxiliary_device *adev) -- 2.31.1
[PATCH v6 15/21] drm/bridge: sn65dsi83: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Tested-by: Laurent Pinchart Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 80 +++ 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 539edd2c19f5..945f08de45f1 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -245,40 +245,6 @@ static int sn65dsi83_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); - struct device *dev = ctx->dev; - struct mipi_dsi_device *dsi; - struct mipi_dsi_host *host; - int ret = 0; - - const struct mipi_dsi_device_info info = { - .type = "sn65dsi83", - .channel = 0, - .node = NULL, - }; - - host = of_find_mipi_dsi_host_by_node(ctx->host_node); - if (!host) { - dev_err(dev, "failed to find dsi host\n"); - return -EPROBE_DEFER; - } - - 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"); - } - - ctx->dsi = dsi; - - dsi->lanes = ctx->dsi_lanes; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; - - ret = devm_mipi_dsi_attach(dev, dsi); - if (ret < 0) { - dev_err(dev, "failed to attach dsi to host\n"); - return ret; - } return drm_bridge_attach(bridge->encoder, ctx->panel_bridge, &ctx->bridge, flags); @@ -636,6 +602,44 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) return 0; } +static int sn65dsi83_host_attach(struct sn65dsi83 *ctx) +{ + struct device *dev = ctx->dev; + struct mipi_dsi_device *dsi; + struct mipi_dsi_host *host; + const struct mipi_dsi_device_info info = { + .type = "sn65dsi83", + .channel = 0, + .node = NULL, + }; + int ret; + + host = of_find_mipi_dsi_host_by_node(ctx->host_node); + if (!host) { + dev_err(dev, "failed to find dsi host\n"); + return -EPROBE_DEFER; + } + + 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"); + + ctx->dsi = dsi; + + dsi->lanes = ctx->dsi_lanes; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; + + ret = devm_mipi_dsi_attach(dev, dsi); + if (ret < 0) { + dev_err(dev, "failed to attach dsi to host: %d\n", ret); + return ret; + } + + return 0; +} + static int sn65dsi83_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -679,7 +683,15 @@ static int sn65dsi83_probe(struct i2c_client *client, ctx->bridge.of_node = dev->of_node; drm_bridge_add(&ctx->bridge); + ret = sn65dsi83_host_attach(ctx); + if (ret) + goto err_remove_bridge; + return 0; + +err_remove_bridge: + drm_bridge_remove(&ctx->bridge); + return ret; } static int sn65dsi83_remove(struct i2c_client *client) -- 2.31.1
[PATCH v6 14/21] drm/bridge: sn65dsi83: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. This also avoids leaking the device when we detach the bridge but don't remove its driver. Acked-by: Sam Ravnborg Tested-by: Laurent Pinchart Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 12 +++- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 3bfd07caf8d7..539edd2c19f5 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -262,7 +262,7 @@ static int sn65dsi83_attach(struct drm_bridge *bridge, return -EPROBE_DEFER; } - 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"); @@ -274,18 +274,14 @@ static int sn65dsi83_attach(struct drm_bridge *bridge, dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST; - ret = mipi_dsi_attach(dsi); + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { dev_err(dev, "failed to attach dsi to host\n"); - goto err_dsi_attach; + return ret; } return drm_bridge_attach(bridge->encoder, ctx->panel_bridge, &ctx->bridge, flags); - -err_dsi_attach: - mipi_dsi_device_unregister(dsi); - return ret; } static void sn65dsi83_detach(struct drm_bridge *bridge) @@ -295,8 +291,6 @@ static void sn65dsi83_detach(struct drm_bridge *bridge) if (!ctx->dsi) return; - mipi_dsi_detach(ctx->dsi); - mipi_dsi_device_unregister(ctx->dsi); ctx->dsi = NULL; } -- 2.31.1
[PATCH v6 12/21] drm/bridge: ps8640: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/parade-ps8640.c | 98 +++--- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 5ae15fc407c5..4b36e4dc78f1 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -401,54 +401,11 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, { struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); struct device *dev = &ps_bridge->page[0]->dev; - struct device_node *in_ep, *dsi_node; - struct mipi_dsi_device *dsi; - struct mipi_dsi_host *host; int ret; - const struct mipi_dsi_device_info info = { .type = "ps8640", - .channel = 0, - .node = NULL, -}; if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) return -EINVAL; - /* port@0 is ps8640 dsi input port */ - in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); - if (!in_ep) - return -ENODEV; - - dsi_node = of_graph_get_remote_port_parent(in_ep); - of_node_put(in_ep); - if (!dsi_node) - return -ENODEV; - - host = of_find_mipi_dsi_host_by_node(dsi_node); - of_node_put(dsi_node); - if (!host) - return -ENODEV; - - dsi = devm_mipi_dsi_device_register_full(dev, host, &info); - if (IS_ERR(dsi)) { - dev_err(dev, "failed to create dsi device\n"); - ret = PTR_ERR(dsi); - return ret; - } - - ps_bridge->dsi = dsi; - - dsi->host = host; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | - MIPI_DSI_MODE_VIDEO_SYNC_PULSE; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->lanes = NUM_MIPI_LANES; - - ret = devm_mipi_dsi_attach(dev, dsi); - if (ret) { - dev_err(dev, "failed to attach dsi device: %d\n", ret); - return ret; - } - ret = drm_dp_aux_register(&ps_bridge->aux); if (ret) { dev_err(dev, "failed to register DP AUX channel: %d\n", ret); @@ -507,6 +464,53 @@ static const struct drm_bridge_funcs ps8640_bridge_funcs = { .pre_enable = ps8640_pre_enable, }; +static int ps8640_bridge_host_attach(struct device *dev, struct ps8640 *ps_bridge) +{ + struct device_node *in_ep, *dsi_node; + struct mipi_dsi_device *dsi; + struct mipi_dsi_host *host; + int ret; + const struct mipi_dsi_device_info info = { .type = "ps8640", + .channel = 0, + .node = NULL, +}; + + /* port@0 is ps8640 dsi input port */ + in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); + if (!in_ep) + return -ENODEV; + + dsi_node = of_graph_get_remote_port_parent(in_ep); + of_node_put(in_ep); + if (!dsi_node) + return -ENODEV; + + host = of_find_mipi_dsi_host_by_node(dsi_node); + of_node_put(dsi_node); + if (!host) + return -EPROBE_DEFER; + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { + dev_err(dev, "failed to create dsi device\n"); + return PTR_ERR(dsi); + } + + ps_bridge->dsi = dsi; + + dsi->host = host; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->lanes = NUM_MIPI_LANES; + + ret = devm_mipi_dsi_attach(dev, dsi); + if (ret) + return ret; + + return 0; +} + static int ps8640_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -584,7 +588,15 @@ static int ps8640_probe(struct i2c_client *client) drm_bridge_add(&ps_bridge->bridge); + ret = ps8640_bridge_host_attach(dev, ps_bridge); + if (ret) + goto err_bridge_remove; + return 0; + +err_bridge_remove: + drm_bridge_remove(&ps_bridge->bridge); + return ret; } static int ps8640_remove(struct i2c_client *client) -- 2.31.1
[PATCH v6 16/21] drm/bridge: sn65dsi86: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. This also avoids leaking the device when we detach the bridge. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 22 +++--- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 6154bed0af5b..36a82e3d17ab 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -662,6 +662,7 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); struct mipi_dsi_host *host; struct mipi_dsi_device *dsi; + struct device *dev = pdata->dev; const struct mipi_dsi_device_info info = { .type = "ti_sn_bridge", .channel = 0, .node = NULL, @@ -701,7 +702,7 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, goto err_dsi_host; } - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { DRM_ERROR("failed to create dsi device\n"); ret = PTR_ERR(dsi); @@ -714,16 +715,16 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, dsi->mode_flags = MIPI_DSI_MODE_VIDEO; /* check if continuous dsi clock is required or not */ - pm_runtime_get_sync(pdata->dev); + pm_runtime_get_sync(dev); regmap_read(pdata->regmap, SN_DPPLL_SRC_REG, &val); - pm_runtime_put_autosuspend(pdata->dev); + pm_runtime_put_autosuspend(dev); if (!(val & DPPLL_CLK_SRC_DSICLK)) dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; - ret = mipi_dsi_attach(dsi); + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { DRM_ERROR("failed to attach dsi to host\n"); - goto err_dsi_attach; + goto err_dsi_host; } pdata->dsi = dsi; @@ -734,14 +735,10 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, ret = drm_bridge_attach(bridge->encoder, pdata->next_bridge, &pdata->bridge, flags); if (ret < 0) - goto err_dsi_detach; + goto err_dsi_host; return 0; -err_dsi_detach: - mipi_dsi_detach(dsi); -err_dsi_attach: - mipi_dsi_device_unregister(dsi); err_dsi_host: drm_connector_cleanup(&pdata->connector); err_conn_init: @@ -1237,11 +1234,6 @@ static void ti_sn_bridge_remove(struct auxiliary_device *adev) if (!pdata) return; - if (pdata->dsi) { - mipi_dsi_detach(pdata->dsi); - mipi_dsi_device_unregister(pdata->dsi); - } - drm_bridge_remove(&pdata->bridge); of_node_put(pdata->host_node); -- 2.31.1
[PATCH v6 13/21] drm/bridge: sn65dsi83: Fix bridge removal
Commit 24417d5b0c00 ("drm/bridge: ti-sn65dsi83: Implement .detach callback") moved the unregistration of the bridge DSI device and bridge itself to the detach callback. While this is correct for the DSI device detach and unregistration, the bridge is added in the driver probe, and should thus be removed as part of its remove callback. Acked-by: Sam Ravnborg Reviewed-by: Marek Vasut Fixes: 24417d5b0c00 ("drm/bridge: ti-sn65dsi83: Implement .detach callback") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 52030a82f3e1..3bfd07caf8d7 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -297,7 +297,6 @@ static void sn65dsi83_detach(struct drm_bridge *bridge) mipi_dsi_detach(ctx->dsi); mipi_dsi_device_unregister(ctx->dsi); - drm_bridge_remove(&ctx->bridge); ctx->dsi = NULL; } @@ -693,6 +692,7 @@ static int sn65dsi83_remove(struct i2c_client *client) { struct sn65dsi83 *ctx = i2c_get_clientdata(client); + drm_bridge_remove(&ctx->bridge); of_node_put(ctx->host_node); return 0; -- 2.31.1
[PATCH v6 11/21] drm/bridge: ps8640: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. This also avoids leaking the device on removal. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/parade-ps8640.c | 15 +-- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 3aaa90913bf8..5ae15fc407c5 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -428,7 +428,7 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, if (!host) return -ENODEV; - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { dev_err(dev, "failed to create dsi device\n"); ret = PTR_ERR(dsi); @@ -442,27 +442,22 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, MIPI_DSI_MODE_VIDEO_SYNC_PULSE; dsi->format = MIPI_DSI_FMT_RGB888; dsi->lanes = NUM_MIPI_LANES; - ret = mipi_dsi_attach(dsi); + + ret = devm_mipi_dsi_attach(dev, dsi); if (ret) { dev_err(dev, "failed to attach dsi device: %d\n", ret); - goto err_dsi_attach; + return ret; } ret = drm_dp_aux_register(&ps_bridge->aux); if (ret) { dev_err(dev, "failed to register DP AUX channel: %d\n", ret); - goto err_aux_register; + return ret; } /* Attach the panel-bridge to the dsi bridge */ return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, &ps_bridge->bridge, flags); - -err_aux_register: - mipi_dsi_detach(dsi); -err_dsi_attach: - mipi_dsi_device_unregister(dsi); - return ret; } static void ps8640_bridge_detach(struct drm_bridge *bridge) -- 2.31.1
[PATCH v6 18/21] drm/bridge: tc358775: Switch to devm MIPI-DSI helpers
Let's switch to the new devm MIPI-DSI function to register and attach our secondary device. This also avoids leaking the device when we detach the bridge. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/tc358775.c | 13 - 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c index 2272adcc5b4a..35e66d1b6456 100644 --- a/drivers/gpu/drm/bridge/tc358775.c +++ b/drivers/gpu/drm/bridge/tc358775.c @@ -610,11 +610,10 @@ static int tc_bridge_attach(struct drm_bridge *bridge, return -EPROBE_DEFER; } - dsi = mipi_dsi_device_register_full(host, &info); + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { dev_err(dev, "failed to create dsi device\n"); - ret = PTR_ERR(dsi); - goto err_dsi_device; + return PTR_ERR(dsi); } tc->dsi = dsi; @@ -623,19 +622,15 @@ static int tc_bridge_attach(struct drm_bridge *bridge, dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO; - ret = mipi_dsi_attach(dsi); + ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { dev_err(dev, "failed to attach dsi to host\n"); - goto err_dsi_attach; + return ret; } /* Attach the panel-bridge to the dsi bridge */ return drm_bridge_attach(bridge->encoder, tc->panel_bridge, &tc->bridge, flags); -err_dsi_attach: - mipi_dsi_device_unregister(dsi); -err_dsi_device: - return ret; } static const struct drm_bridge_funcs tc_bridge_funcs = { -- 2.31.1
[PATCH v6 21/21] drm/msm/dsi: Adjust probe order
From: Rob Clark Switch to the documented order dsi-host vs bridge probe. Tested-by: Amit Pundir Tested-by: Caleb Connolly Tested-by: John Stultz Signed-off-by: Rob Clark Signed-off-by: Maxime Ripard --- drivers/gpu/drm/msm/dsi/dsi.c | 50 --- drivers/gpu/drm/msm/dsi/dsi.h | 2 +- drivers/gpu/drm/msm/dsi/dsi_host.c| 22 drivers/gpu/drm/msm/dsi/dsi_manager.c | 6 ++-- drivers/gpu/drm/msm/msm_drv.h | 2 ++ 5 files changed, 43 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 614dc7f26f2c..ad73ebb84b2d 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -112,18 +112,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = dev_get_drvdata(master); struct msm_drm_private *priv = drm->dev_private; - struct platform_device *pdev = to_platform_device(dev); - struct msm_dsi *msm_dsi; - - DBG(""); - msm_dsi = dsi_init(pdev); - if (IS_ERR(msm_dsi)) { - /* Don't fail the bind if the dsi port is not connected */ - if (PTR_ERR(msm_dsi) == -ENODEV) - return 0; - else - return PTR_ERR(msm_dsi); - } + struct msm_dsi *msm_dsi = dev_get_drvdata(dev); priv->dsi[msm_dsi->id] = msm_dsi; @@ -136,12 +125,8 @@ static void dsi_unbind(struct device *dev, struct device *master, struct drm_device *drm = dev_get_drvdata(master); struct msm_drm_private *priv = drm->dev_private; struct msm_dsi *msm_dsi = dev_get_drvdata(dev); - int id = msm_dsi->id; - if (priv->dsi[id]) { - dsi_destroy(msm_dsi); - priv->dsi[id] = NULL; - } + priv->dsi[msm_dsi->id] = NULL; } static const struct component_ops dsi_ops = { @@ -149,15 +134,40 @@ static const struct component_ops dsi_ops = { .unbind = dsi_unbind, }; -static int dsi_dev_probe(struct platform_device *pdev) +int dsi_dev_attach(struct platform_device *pdev) { return component_add(&pdev->dev, &dsi_ops); } -static int dsi_dev_remove(struct platform_device *pdev) +void dsi_dev_detach(struct platform_device *pdev) { - DBG(""); component_del(&pdev->dev, &dsi_ops); +} + +static int dsi_dev_probe(struct platform_device *pdev) +{ + struct msm_dsi *msm_dsi; + + DBG(""); + msm_dsi = dsi_init(pdev); + if (IS_ERR(msm_dsi)) { + /* Don't fail the bind if the dsi port is not connected */ + if (PTR_ERR(msm_dsi) == -ENODEV) + return 0; + else + return PTR_ERR(msm_dsi); + } + + return 0; +} + +static int dsi_dev_remove(struct platform_device *pdev) +{ + struct msm_dsi *msm_dsi = platform_get_drvdata(pdev); + + DBG(""); + dsi_destroy(msm_dsi); + return 0; } diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index b50db91cb8a7..83787cbee419 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -116,7 +116,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host); unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host); struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host); -int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer); +int msm_dsi_host_register(struct mipi_dsi_host *host); void msm_dsi_host_unregister(struct mipi_dsi_host *host); int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, struct msm_dsi_phy *src_phy); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index e269df285136..f741494b1bf6 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1624,6 +1624,10 @@ static int dsi_host_attach(struct mipi_dsi_host *host, if (ret) return ret; + ret = dsi_dev_attach(msm_host->pdev); + if (ret) + return ret; + DBG("id=%d", msm_host->id); if (msm_host->dev) queue_work(msm_host->workqueue, &msm_host->hpd_work); @@ -1636,6 +1640,8 @@ static int dsi_host_detach(struct mipi_dsi_host *host, { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + dsi_dev_detach(msm_host->pdev); + msm_host->device_node = NULL; DBG("id=%d", msm_host->id); @@ -1970,7 +1976,7 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, return 0; } -int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer) +int msm_dsi_host_register(struct mipi_dsi_host *host) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); int ret; @@ -1984,20 +1990,6 @@ int msm_dsi_ho
[PATCH v6 19/21] drm/bridge: tc358775: Register and attach our DSI device at probe
In order to avoid any probe ordering issue, the best practice is to move the secondary MIPI-DSI device registration and attachment to the MIPI-DSI host at probe time. Let's do this. Acked-by: Sam Ravnborg Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/tc358775.c | 37 +-- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c index 35e66d1b6456..2c76331b251d 100644 --- a/drivers/gpu/drm/bridge/tc358775.c +++ b/drivers/gpu/drm/bridge/tc358775.c @@ -594,11 +594,26 @@ static int tc_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct tc_data *tc = bridge_to_tc(bridge); + + /* Attach the panel-bridge to the dsi bridge */ + return drm_bridge_attach(bridge->encoder, tc->panel_bridge, +&tc->bridge, flags); +} + +static const struct drm_bridge_funcs tc_bridge_funcs = { + .attach = tc_bridge_attach, + .pre_enable = tc_bridge_pre_enable, + .enable = tc_bridge_enable, + .mode_valid = tc_mode_valid, + .post_disable = tc_bridge_post_disable, +}; + +static int tc_attach_host(struct tc_data *tc) +{ struct device *dev = &tc->i2c->dev; struct mipi_dsi_host *host; struct mipi_dsi_device *dsi; int ret; - const struct mipi_dsi_device_info info = { .type = "tc358775", .channel = 0, .node = NULL, @@ -628,19 +643,9 @@ static int tc_bridge_attach(struct drm_bridge *bridge, return ret; } - /* Attach the panel-bridge to the dsi bridge */ - return drm_bridge_attach(bridge->encoder, tc->panel_bridge, -&tc->bridge, flags); + return 0; } -static const struct drm_bridge_funcs tc_bridge_funcs = { - .attach = tc_bridge_attach, - .pre_enable = tc_bridge_pre_enable, - .enable = tc_bridge_enable, - .mode_valid = tc_mode_valid, - .post_disable = tc_bridge_post_disable, -}; - static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; @@ -704,7 +709,15 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_set_clientdata(client, tc); + ret = tc_attach_host(tc); + if (ret) + goto err_bridge_remove; + return 0; + +err_bridge_remove: + drm_bridge_remove(&tc->bridge); + return ret; } static int tc_remove(struct i2c_client *client) -- 2.31.1
[PATCH v6 20/21] drm/kirin: dsi: Adjust probe order
Without proper care and an agreement between how DSI hosts and devices drivers register their MIPI-DSI entities and potential components, we can end up in a situation where the drivers can never probe. Most drivers were taking evasive maneuvers to try to workaround this, but not all of them were following the same conventions, resulting in various incompatibilities between DSI hosts and devices. Now that we have a sequence agreed upon and documented, let's convert kirin to it. Tested-by: John Stultz Signed-off-by: Maxime Ripard --- drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 52 +--- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c index 952cfdb1961d..1d556482bb46 100644 --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c @@ -81,7 +81,7 @@ struct dsi_hw_ctx { struct dw_dsi { struct drm_encoder encoder; - struct drm_bridge *bridge; + struct device *dev; struct mipi_dsi_host host; struct drm_display_mode cur_mode; struct dsi_hw_ctx *ctx; @@ -720,10 +720,13 @@ static int dw_drm_encoder_init(struct device *dev, return 0; } +static const struct component_ops dsi_ops; static int dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *mdsi) { struct dw_dsi *dsi = host_to_dsi(host); + struct device *dev = host->dev; + int ret; if (mdsi->lanes < 1 || mdsi->lanes > 4) { DRM_ERROR("dsi device params invalid\n"); @@ -734,13 +737,20 @@ static int dsi_host_attach(struct mipi_dsi_host *host, dsi->format = mdsi->format; dsi->mode_flags = mdsi->mode_flags; + ret = component_add(dev, &dsi_ops); + if (ret) + return ret; + return 0; } static int dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *mdsi) { - /* do nothing */ + struct device *dev = host->dev; + + component_del(dev, &dsi_ops); + return 0; } @@ -768,7 +778,17 @@ static int dsi_host_init(struct device *dev, struct dw_dsi *dsi) static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi) { struct drm_encoder *encoder = &dsi->encoder; - struct drm_bridge *bridge = dsi->bridge; + struct drm_bridge *bridge; + struct device_node *np = dsi->dev->of_node; + int ret; + + /* +* Get the endpoint node. In our case, dsi has one output port1 +* to which the external HDMI bridge is connected. +*/ + ret = drm_of_find_panel_or_bridge(np, 1, 0, NULL, &bridge); + if (ret) + return ret; /* associate the bridge to dsi encoder */ return drm_bridge_attach(encoder, bridge, NULL, 0); @@ -785,10 +805,6 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - ret = dsi_host_init(dev, dsi); - if (ret) - return ret; - ret = dsi_bridge_init(drm_dev, dsi); if (ret) return ret; @@ -809,17 +825,7 @@ static const struct component_ops dsi_ops = { static int dsi_parse_dt(struct platform_device *pdev, struct dw_dsi *dsi) { struct dsi_hw_ctx *ctx = dsi->ctx; - struct device_node *np = pdev->dev.of_node; struct resource *res; - int ret; - - /* -* Get the endpoint node. In our case, dsi has one output port1 -* to which the external HDMI bridge is connected. -*/ - ret = drm_of_find_panel_or_bridge(np, 1, 0, NULL, &dsi->bridge); - if (ret) - return ret; ctx->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(ctx->pclk)) { @@ -852,6 +858,7 @@ static int dsi_probe(struct platform_device *pdev) dsi = &data->dsi; ctx = &data->ctx; dsi->ctx = ctx; + dsi->dev = &pdev->dev; ret = dsi_parse_dt(pdev, dsi); if (ret) @@ -859,12 +866,19 @@ static int dsi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); - return component_add(&pdev->dev, &dsi_ops); + ret = dsi_host_init(&pdev->dev, dsi); + if (ret) + return ret; + + return 0; } static int dsi_remove(struct platform_device *pdev) { - component_del(&pdev->dev, &dsi_ops); + struct dsi_data *data = platform_get_drvdata(pdev); + struct dw_dsi *dsi = &data->dsi; + + mipi_dsi_host_unregister(&dsi->host); return 0; } -- 2.31.1
Re: [PATCH v5 00/21] drm/bridge: Make panel and bridge probe order consistent
Hi Sam, On Thu, Oct 21, 2021 at 05:22:55PM +0200, Sam Ravnborg wrote: > Hi Maxime, > > > Let me know what you think, > > apply the lot to drm-misc-next. Maybe wait for an r-b or a-b on the kirin > patch but the rest is IMO good to go. I had a compilation error since the rebase of the v4, so I sent a new version. John Stultz has tested this series and given his tested-by, and is the kirin maintainer. I guess it's enough? Maxime signature.asc Description: PGP signature
Re: [PATCH 00/47] GuC submission support
On Mon, Oct 25, 2021 at 12:37:02PM +0300, Joonas Lahtinen wrote: > Quoting Matthew Brost (2021-10-22 19:42:19) > > On Fri, Oct 22, 2021 at 12:35:04PM +0300, Joonas Lahtinen wrote: > > > Hi Matt & John, > > > > > > Can you please queue patches with the right Fixes: references to convert > > > all the GuC tracepoints to be protected by the LOW_LEVEL_TRACEPOINTS > > > protection for now. Please do so before next Wednesday so we get it > > > queued in drm-intel-next-fixes. > > > > > > > Don't we already do that? I checked i915_trace.h and every tracepoint I > > added (intel_context class, i915_request_guc_submit) is protected by > > LOW_LEVEL_TRACEPOINTS. > > > > The only thing I changed outside of that protection is adding the guc_id > > field to existing i915_request class tracepoints. > > It's the first search hit for "guc" inside the i915_trace.h file :) > > > Without the guc_id in > > those tracepoints these are basically useless with GuC submission. We > > could revert that if it is a huge deal but as I said then they are > > useless... > > Let's eliminate it for now and restore the tracepoint exactly as it was. > Don't really agree - let's render tracepoints to be useless? Are tracepoints ABI? I googled this and couldn't really find a definie answer. If tracepoints are ABI, then OK I can revert this change but still this is a poor technical decision (tracepoints should not be ABI). > If there is an immediate need, we should instead have an auxilary tracepoint > which is enabled only through LOW_LEVEL_TRACEPOINTS and that amends the > information of the basic tracepoint. > Regardless of what I said above, I'll post 2 patches. The 1st just remove the GuC, the 2nd modify the tracepoint to include guc_id if LOW_LEVEL_TRACEPOINTS is defined. > For the longer term solution we should align towards the dma fence > tracepoints. When those are combined with the OA information, one should > be able to get a good understanding of both the software and hardware > scheduling decisions. > Not sure about this either. I use these tracepoins to correlate things to the GuC log. Between the 2, if you know what you are doing you basically can figure out everything that is happening. Fields in the trace translate directly to fields in the GuC log. Some of these fields are backend specific, not sure how these could be pushed the dma fence tracepoints. For what it is worth, without these tracepoints we'd likely still have a bunch of bugs in the GuC firmware. I understand these points, several other i915 developers do, and several of the GuC firmware developers do too. Matt > Regards, Joonas > > > > > Matt > > > > > There's the orthogonal track to discuss what would be the stable set of > > > tracepoints we could expose. However, before that discussion is closed, > > > let's keep a rather strict line to avoid potential maintenance burned. > > > > > > We can then relax in the future as needed. > > > > > > Regards, Joonas > > > > > > Quoting Matthew Brost (2021-06-24 10:04:29) > > > > As discussed in [1], [2] we are enabling GuC submission support in the > > > > i915. This is a subset of the patches in step 5 described in [1], > > > > basically it is absolute to enable CI with GuC submission on gen11+ > > > > platforms. > > > > > > > > This series itself will likely be broken down into smaller patch sets to > > > > merge. Likely into CTBs changes, basic submission, virtual engines, and > > > > resets. > > > > > > > > A following series will address the missing patches remaining from [1]. > > > > > > > > Locally tested on TGL machine and basic tests seem to be passing. > > > > > > > > Signed-off-by: Matthew Brost > > > > > > > > [1] https://patchwork.freedesktop.org/series/89844/ > > > > [2] https://patchwork.freedesktop.org/series/91417/ > > > > > > > > Daniele Ceraolo Spurio (1): > > > > drm/i915/guc: Unblock GuC submission on Gen11+ > > > > > > > > John Harrison (10): > > > > drm/i915/guc: Module load failure test for CT buffer creation > > > > drm/i915: Track 'serial' counts for virtual engines > > > > drm/i915/guc: Provide mmio list to be saved/restored on engine reset > > > > drm/i915/guc: Don't complain about reset races > > > > drm/i915/guc: Enable GuC engine reset > > > > drm/i915/guc: Fix for error capture after full GPU reset with GuC > > > > drm/i915/guc: Hook GuC scheduling policies up > > > > drm/i915/guc: Connect reset modparam updates to GuC policy flags > > > > drm/i915/guc: Include scheduling policies in the debugfs state dump > > > > drm/i915/guc: Add golden context to GuC ADS > > > > > > > > Matthew Brost (36): > > > > drm/i915/guc: Relax CTB response timeout > > > > drm/i915/guc: Improve error message for unsolicited CT response > > > > drm/i915/guc: Increase size of CTB buffers > > > > drm/i915/guc: Add non blocking CTB send function > > > > drm/i915/guc: Add stall timer to non blocking CTB send function > > > > drm/i915/guc: Optimize CTB write
Re: [PATCH v6 3/3] drm/bridge: ti-sn65dsi86: Implement the pwm_chip
On Mon 25 Oct 01:42 PDT 2021, Uwe Kleine-K?nig wrote: > Hello, > > [replaced Andrzej Hajda's email address with his new one] > > On Wed, Sep 29, 2021 at 10:05:57PM -0500, Bjorn Andersson wrote: > > The SN65DSI86 provides the ability to supply a PWM signal on GPIO 4, > > with the primary purpose of controlling the backlight of the attached > > panel. Add an implementation that exposes this using the standard PWM > > framework, to allow e.g. pwm-backlight to expose this to the user. > > Sorry for the long delay in reviewing this. > No worries, glad to hear from you again. > > Signed-off-by: Bjorn Andersson > > --- > > [..] > > +static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, > > + const struct pwm_state *state) > > +{ > > + struct ti_sn65dsi86 *pdata = pwm_chip_to_ti_sn_bridge(chip); > > + unsigned int pwm_en_inv; > > + unsigned int backlight; > > + unsigned int pre_div; > > + unsigned int scale; > > + u64 period_max; > > + u64 period; > > + int ret; > > + > > + if (!pdata->pwm_enabled) { > > + ret = pm_runtime_get_sync(pdata->dev); > > + if (ret < 0) { > > + pm_runtime_put_sync(pdata->dev); > > + return ret; > > + } > > + } > > + > > + if (state->enabled) { > > + if (!pdata->pwm_enabled) { > > + /* > > +* The chip might have been powered down while we > > +* didn't hold a PM runtime reference, so mux in the > > +* PWM function on the GPIO pin again. > > +*/ > > + ret = regmap_update_bits(pdata->regmap, > > SN_GPIO_CTRL_REG, > > +SN_GPIO_MUX_MASK << (2 * > > SN_PWM_GPIO_IDX), > > +SN_GPIO_MUX_SPECIAL << (2 * > > SN_PWM_GPIO_IDX)); > > + if (ret) { > > + dev_err(pdata->dev, "failed to mux in PWM > > function\n"); > > + goto out; > > + } > > + } > > + > > + /* > > +* Per the datasheet the PWM frequency is given by: > > +* > > +* REFCLK_FREQ > > +* PWM_FREQ = --- > > +* PWM_PRE_DIV * BACKLIGHT_SCALE + 1 > > +* > > +* However, after careful review the author is convinced that > > +* the documentation has lost some parenthesis around > > +* "BACKLIGHT_SCALE + 1". > > +* With that the formula can be written: > > +* > > +* T_pwm * REFCLK_FREQ = PWM_PRE_DIV * (BACKLIGHT_SCALE + 1) > > For my understanding: T_pwm = period length = 1 / PWM_FREQ, right? Maybe > it's a good idea to state this more explicitly? > Correct. I've improved the comment accordingly. > > +* In order to keep BACKLIGHT_SCALE within its 16 bits, > > +* PWM_PRE_DIV must be: > > +* > > +* T_pwm * REFCLK_FREQ > > +* PWM_PRE_DIV >= - > > +* BACKLIGHT_SCALE_MAX + 1 > > +* > > +* To simplify the search and to favour higher resolution of > > +* the duty cycle over accuracy of the period, the lowest > > +* possible PWM_PRE_DIV is used. Finally the scale is > > +* calculated as: > > +* > > +* T_pwm * REFCLK_FREQ > > +* BACKLIGHT_SCALE = -- - 1 > > +* PWM_PRE_DIV > > +* > > +* Here T_pwm is represented in seconds, so appropriate scaling > > +* to nanoseconds is necessary. > > +*/ > > + > > + /* Minimum T_pwm is 1 / REFCLK_FREQ */ > > + if (state->period <= NSEC_PER_SEC / pdata->pwm_refclk_freq) { > > + ret = -EINVAL; > > + goto out; > > + } > > + > > + /* > > +* Maximum T_pwm is 255 * (65535 + 1) / REFCLK_FREQ > > +* Limit period to this to avoid overflows > > +*/ > > + period_max = div_u64((u64)NSEC_PER_SEC * 255 * (65535 + 1), > > +pdata->pwm_refclk_freq); > > + if (period > period_max) > > period is uninitialized here. This must be > > if (state->period > period_max) > > . Alternatively to the if you could use > > period = min(state->period, period_max); > Yes of course. > > Apart from this I'm happy with your patch set now. > Thank you. > > + period = period_max; > > + else > > + period = state->period; > > + > > + pre_div = DIV64_U64_ROUND_UP(period * pdata->pwm_refc
[PATCH v8 00/10] drm/vc4: hdmi: Support the 4k @ 60Hz modes
Hi, Here is a series that enables the higher resolutions on the HDMI0 Controller found in the BCM2711 (RPi4). In order to work it needs a few adjustments to config.txt, most notably to enable the enable_hdmi_4kp60 option. Let me know what you think, Maxime --- Changes from v7: - Rebased on current drm-misc-next Changes from v6: - Rebased on current drm-misc-next - Removed stale clk_request pointer Changes from v5: - Fixed unused variables warning Changes from v4: - Removed the patches already applied - Added various fixes for the issues that have been discovered on the downstream tree Changes from v3: - Rework the encoder retrieval code that was broken on the RPi3 and older - Fix a scrambling enabling issue on some display Changes from v2: - Gathered the various tags - Added Cc stable when relevant - Split out the check to test whether the scrambler is required into an helper - Fixed a bug where the scrambler state wouldn't be tracked properly if it was enabled at boot Changes from v1: - Dropped the range accessors - Drop the mention of force_turbo - Reordered the SCRAMBLER_CTL register to match the offset - Removed duplicate HDMI_14_MAX_TMDS_CLK define - Warn about enable_hdmi_4kp60 only if there's some modes that can't be reached - Rework the BVB clock computation Maxime Ripard (10): drm/vc4: hdmi: Remove the DDC probing for status detection drm/vc4: hdmi: Fix HPD GPIO detection drm/vc4: Make vc4_crtc_get_encoder public drm/vc4: crtc: Add encoder to vc4_crtc_config_pv prototype drm/vc4: crtc: Rework the encoder retrieval code (again) drm/vc4: crtc: Add some logging drm/vc4: Leverage the load tracker on the BCM2711 drm/vc4: hdmi: Raise the maximum clock rate drm/vc4: hdmi: Enable the scrambler on reconnection drm/vc4: Increase the core clock based on HVS load drivers/gpu/drm/vc4/vc4_crtc.c| 60 -- drivers/gpu/drm/vc4/vc4_debugfs.c | 7 +- drivers/gpu/drm/vc4/vc4_drv.h | 8 +- drivers/gpu/drm/vc4/vc4_hdmi.c| 13 +-- drivers/gpu/drm/vc4/vc4_kms.c | 126 +- drivers/gpu/drm/vc4/vc4_plane.c | 5 -- 6 files changed, 157 insertions(+), 62 deletions(-) -- 2.31.1
[PATCH v8 01/10] drm/vc4: hdmi: Remove the DDC probing for status detection
Commit 9d44a8d5 ("drm/vc4: Fall back to using an EDID probe in the absence of a GPIO.") added some code to read the EDID through DDC in the HDMI driver detect hook since the Pi3 had no HPD GPIO back then. However, commit b1b8f45b3130 ("ARM: dts: bcm2837: Add missing GPIOs of Expander") changed that a couple of years later. This causes an issue though since some TV (like the LG 55C8) when it comes out of standy will deassert the HPD line, but the EDID will remain readable. It causes an issues nn platforms without an HPD GPIO, like the Pi4, where the DDC probing will be our primary mean to detect a display, and thus we will never detect the HPD pulse. This was fine before since the pulse was small enough that we would never detect it, and we also didn't have anything (like the scrambler) that needed to be set up in the display. However, now that we have both, the display during the HPD pulse will clear its scrambler status, and since we won't detect the disconnect/reconnect cycle we will never enable the scrambler back. As our main reason for that DDC probing is gone, let's just remove it. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 7b0cb08e6563..338968275724 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -193,8 +193,6 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) if (vc4_hdmi->hpd_gpio && gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) { connected = true; - } else if (drm_probe_ddc(vc4_hdmi->ddc)) { - connected = true; } else { unsigned long flags; u32 hotplug; -- 2.31.1
[PATCH v8 04/10] drm/vc4: crtc: Add encoder to vc4_crtc_config_pv prototype
vc4_crtc_config_pv() retrieves the encoder again, even though its only caller, vc4_crtc_atomic_enable(), already did. Pass the encoder pointer as an argument instead of going through all the connectors to retrieve it again. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 7cfd4a097847..e5c2e29a6f01 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -315,12 +315,11 @@ static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc) CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_FIFO_CLR); } -static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_atomic_state *state) +static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); - struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, state, - drm_atomic_get_new_connector_state); struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc); @@ -597,7 +596,7 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, if (vc4_encoder->pre_crtc_configure) vc4_encoder->pre_crtc_configure(encoder, state); - vc4_crtc_config_pv(crtc, state); + vc4_crtc_config_pv(crtc, encoder, state); CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_EN); -- 2.31.1
[PATCH v8 02/10] drm/vc4: hdmi: Fix HPD GPIO detection
Prior to commit 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod"), in the detect hook, if we had an HPD GPIO we would only rely on it and return whatever state it was in. However, that commit changed that by mistake to only consider the case where we have a GPIO and it returns a logical high, and would fall back to the other methods otherwise. Since we can read the EDIDs when the HPD signal is low on some displays, we changed the detection status from disconnected to connected, and we would ignore an HPD pulse. Fixes: 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 338968275724..dde67b991ae7 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -190,9 +190,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); - if (vc4_hdmi->hpd_gpio && - gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) { - connected = true; + if (vc4_hdmi->hpd_gpio) { + if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) + connected = true; } else { unsigned long flags; u32 hotplug; -- 2.31.1
[PATCH v8 03/10] drm/vc4: Make vc4_crtc_get_encoder public
We'll need that function in vc4_kms to compute the core clock rate requirements. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 8 drivers/gpu/drm/vc4/vc4_drv.h | 5 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index e3ed52d96f42..7cfd4a097847 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -281,10 +281,10 @@ static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc, * allows drivers to push pixels to more than one encoder from the * same CRTC. */ -static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, - struct drm_atomic_state *state, - struct drm_connector_state *(*get_state)(struct drm_atomic_state *state, - struct drm_connector *connector)) +struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, +struct drm_atomic_state *state, +struct drm_connector_state *(*get_state)(struct drm_atomic_state *state, + struct drm_connector *connector)) { struct drm_connector *connector; struct drm_connector_list_iter conn_iter; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 4b550ebd9572..f5e678491502 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -544,6 +544,11 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc) return container_of(data, struct vc4_pv_data, base); } +struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, +struct drm_atomic_state *state, +struct drm_connector_state *(*get_state)(struct drm_atomic_state *state, + struct drm_connector *connector)); + struct vc4_crtc_state { struct drm_crtc_state base; /* Dlist area for this CRTC configuration. */ -- 2.31.1