From 682f99b8ae886c22ba9f16df454aecc8c6d803ba Mon Sep 17 00:00:00 2001 From: "maxime@cerno.tech" Date: Mon, 24 Oct 2022 11:36:33 +0200 Subject: drm/vc4: hdmi: Take our lock to reset the link We access some fields protected by our internal mutex in vc4_hdmi_reset_link() (saved_adjusted_mode, output_bpc, output_format) and are calling functions that need to have that lock taken (vc4_hdmi_supports_scrambling()). However, the current code doesn't lock that mutex. Let's make sure it does. Fixes: 6bed2ea3cb38 ("drm/vc4: hdmi: Reset link on hotplug") Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20221024093634.118190-1-maxime@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 596e311d6e58..9e549fa07467 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -349,27 +349,40 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector, if (!crtc_state->active) return 0; - if (!vc4_hdmi_supports_scrambling(encoder)) + mutex_lock(&vc4_hdmi->mutex); + + if (!vc4_hdmi_supports_scrambling(encoder)) { + mutex_unlock(&vc4_hdmi->mutex); return 0; + } scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode, vc4_hdmi->output_bpc, vc4_hdmi->output_format); - if (!scrambling_needed) + if (!scrambling_needed) { + mutex_unlock(&vc4_hdmi->mutex); return 0; + } if (conn_state->commit && - !try_wait_for_completion(&conn_state->commit->hw_done)) + !try_wait_for_completion(&conn_state->commit->hw_done)) { + mutex_unlock(&vc4_hdmi->mutex); return 0; + } ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config); if (ret < 0) { drm_err(drm, "Failed to read TMDS config: %d\n", ret); + mutex_unlock(&vc4_hdmi->mutex); return 0; } - if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) + if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) { + mutex_unlock(&vc4_hdmi->mutex); return 0; + } + + mutex_unlock(&vc4_hdmi->mutex); /* * HDMI 2.0 says that one should not send scrambled data -- cgit v1.2.3-59-g8ed1b From 76ffa2af16c67bbb806b8224a5289eb03f7a537d Mon Sep 17 00:00:00 2001 From: "maxime@cerno.tech" Date: Mon, 24 Oct 2022 11:36:34 +0200 Subject: drm/vc4: hdmi: Fix outdated function name in comment A comment introduced by commit 6bed2ea3cb38 ("drm/vc4: hdmi: Reset link on hotplug") mentions a drm_atomic_helper_connector_hdmi_reset_link() function that was part of the earlier versions but got moved internally and is now named vc4_hdmi_reset_link(). Let's fix the function name. Fixes: 6bed2ea3cb38 ("drm/vc4: hdmi: Reset link on hotplug") Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20221024093634.118190-2-maxime@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 9e549fa07467..79eda8f5fea0 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -410,9 +410,8 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi, * .adap_enable, which leads to that funtion being called with * our mutex held. * - * A similar situation occurs with - * drm_atomic_helper_connector_hdmi_reset_link() that will call - * into our KMS hooks if the scrambling was enabled. + * A similar situation occurs with vc4_hdmi_reset_link() that + * will call into our KMS hooks if the scrambling was enabled. * * Concurrency isn't an issue at the moment since we don't share * any state with any of the other frameworks so we can ignore -- cgit v1.2.3-59-g8ed1b From 3bc6a37f59f21a8bfaf74d0975b2eb0b2d52a065 Mon Sep 17 00:00:00 2001 From: "maxime@cerno.tech" Date: Fri, 21 Oct 2022 15:13:39 +0200 Subject: drm/vc4: hdmi: Fix HSM clock too low on Pi4 Commit ae71ab585c81 ("drm/vc4: hdmi: Enforce the minimum rate at runtime_resume") reintroduced the call to clk_set_min_rate in an attempt to fix the boot without a monitor connected on the RaspberryPi3. However, that introduced a regression breaking the display output entirely (black screen but no vblank timeout) on the Pi4. This is due to the fact that we now have in a typical modeset at boot, in vc4_hdmi_encoder_pre_crtc_configure(), we have a first call to clk_set_min_rate() asking for the minimum rate of the HSM clock for our given resolution, and then a call to pm_runtime_resume_and_get(). We will thus execute vc4_hdmi_runtime_resume() which, since the commit mentioned above, will call clk_set_min_rate() a second time with the absolute minimum rate we want to enforce on the HSM clock. We're thus effectively erasing the minimum mandated by the mode we're trying to set. The fact that only the Pi4 is affected is due to the fact that it uses a different clock driver that tries to minimize the HSM clock at all time. It will thus lower the HSM clock rate to 120MHz on the second clk_set_min_rate() call. The Pi3 doesn't use the same driver and will not change the frequency on the second clk_set_min_rate() call since it's still within the new boundaries and it doesn't have the code to minimize the clock rate as needed. So even though the boundaries are still off, the clock rate is still the right one for our given mode, so everything works. There is a lot of moving parts, so I couldn't find any obvious solution: - Reverting the original is not an option, as that would break the Pi3 again. - We can't move the clk_set_min_rate() call in _pre_crtc_configure() since because, on the Pi3, the HSM clock has the CLK_SET_RATE_GATE flag which prevents the clock rate from being changed after it's been enabled. Our calls to clk_set_min_rate() can change it, so they need to be done before clk_prepare_enable(). - We can't remove the call to clk_prepare_enable() from the runtime_resume hook to put it into _pre_crtc_configure() either, since we need that clock to be enabled to access the registers, and we can't count on the fact that the display will be active in all situations (doing any CEC operation, or listing the modes while inactive are valid for example()). - We can't drop the call to clk_set_min_rate() in _pre_crtc_configure() since we would need to still enforce the minimum rate for a given resolution, and runtime_resume doesn't have access to the current mode, if there's any. - We can't copy the TMDS character rate into vc4_hdmi and reuse it since, because it's part of the KMS atomic state, it needs to be protected by a mutex. Unfortunately, some functions (CEC operations, mostly) can be reentrant (through the CEC framework) and still need a pm_runtime_get. However, we can work around this issue by leveraging the fact that the clk_set_min_rate() calls set boundaries for its given struct clk, and that each different clk_get() call will return a different instance of struct clk. The clock framework will then aggregate the boundaries for each struct clk instances linked to a given clock, plus its hardware boundaries, and will use that. We can thus get an extra HSM clock user for runtime_pm use only, and use our different clock instances depending on the context: runtime_pm will use its own to set the absolute minimum clock setup so that we never lock the CPU waiting for a register access, and the modeset part will set its requirement for the current resolution. And we let the CCF do the coordination. It's not an ideal solution, but it's fairly unintrusive and doesn't really change any part of the logic so it looks like a rather safe fix. Link: https://bugzilla.redhat.com/show_bug.cgi?id=2136234 Fixes: ae71ab585c81 ("drm/vc4: hdmi: Enforce the minimum rate at runtime_resume") Reported-by: Peter Robinson Reviewed-by: Javier Martinez Canillas Tested-by: Peter Robinson Link: https://lore.kernel.org/r/20221021131339.2203291-1-maxime@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 21 +++++++++++++++++---- drivers/gpu/drm/vc4/vc4_hdmi.h | 1 + 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 79eda8f5fea0..470432c8fd70 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -3172,9 +3172,16 @@ static int vc4_hdmi_init_resources(struct drm_device *drm, DRM_ERROR("Failed to get HDMI state machine clock\n"); return PTR_ERR(vc4_hdmi->hsm_clock); } + vc4_hdmi->audio_clock = vc4_hdmi->hsm_clock; vc4_hdmi->cec_clock = vc4_hdmi->hsm_clock; + vc4_hdmi->hsm_rpm_clock = devm_clk_get(dev, "hdmi"); + if (IS_ERR(vc4_hdmi->hsm_rpm_clock)) { + DRM_ERROR("Failed to get HDMI state machine clock\n"); + return PTR_ERR(vc4_hdmi->hsm_rpm_clock); + } + return 0; } @@ -3257,6 +3264,12 @@ static int vc5_hdmi_init_resources(struct drm_device *drm, return PTR_ERR(vc4_hdmi->hsm_clock); } + vc4_hdmi->hsm_rpm_clock = devm_clk_get(dev, "hdmi"); + if (IS_ERR(vc4_hdmi->hsm_rpm_clock)) { + DRM_ERROR("Failed to get HDMI state machine clock\n"); + return PTR_ERR(vc4_hdmi->hsm_rpm_clock); + } + vc4_hdmi->pixel_bvb_clock = devm_clk_get(dev, "bvb"); if (IS_ERR(vc4_hdmi->pixel_bvb_clock)) { DRM_ERROR("Failed to get pixel bvb clock\n"); @@ -3320,7 +3333,7 @@ static int vc4_hdmi_runtime_suspend(struct device *dev) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); - clk_disable_unprepare(vc4_hdmi->hsm_clock); + clk_disable_unprepare(vc4_hdmi->hsm_rpm_clock); return 0; } @@ -3338,11 +3351,11 @@ static int vc4_hdmi_runtime_resume(struct device *dev) * its frequency while the power domain is active so that it * keeps its rate. */ - ret = clk_set_min_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ); + ret = clk_set_min_rate(vc4_hdmi->hsm_rpm_clock, HSM_MIN_CLOCK_FREQ); if (ret) return ret; - ret = clk_prepare_enable(vc4_hdmi->hsm_clock); + ret = clk_prepare_enable(vc4_hdmi->hsm_rpm_clock); if (ret) return ret; @@ -3355,7 +3368,7 @@ static int vc4_hdmi_runtime_resume(struct device *dev) * case, it will lead to a silent CPU stall. Let's make sure we * prevent such a case. */ - rate = clk_get_rate(vc4_hdmi->hsm_clock); + rate = clk_get_rate(vc4_hdmi->hsm_rpm_clock); if (!rate) { ret = -EINVAL; goto err_disable_clk; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index db823efb2563..1ad8e8c377e2 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -172,6 +172,7 @@ struct vc4_hdmi { struct clk *cec_clock; struct clk *pixel_clock; struct clk *hsm_clock; + struct clk *hsm_rpm_clock; struct clk *audio_clock; struct clk *pixel_bvb_clock; -- cgit v1.2.3-59-g8ed1b From cf53db768a8790fdaae2fa3a81322b080285f7e5 Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Thu, 3 Nov 2022 01:47:05 +0000 Subject: drm/vc4: Fix missing platform_unregister_drivers() call in vc4_drm_register() A problem about modprobe vc4 failed is triggered with the following log given: [ 420.327987] Error: Driver 'vc4_hvs' is already registered, aborting... [ 420.333904] failed to register platform driver vc4_hvs_driver [vc4]: -16 modprobe: ERROR: could not insert 'vc4': Device or resource busy The reason is that vc4_drm_register() returns platform_driver_register() directly without checking its return value, if platform_driver_register() fails, it returns without unregistering all the vc4 drivers, resulting the vc4 can never be installed later. A simple call graph is shown as below: vc4_drm_register() platform_register_drivers() # all vc4 drivers are registered platform_driver_register() driver_register() bus_add_driver() priv = kzalloc(...) # OOM happened # return without unregister drivers Fixing this problem by checking the return value of platform_driver_register() and do platform_unregister_drivers() if error happened. Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.") Signed-off-by: Yuan Can Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20221103014705.109322-1-yuancan@huawei.com --- drivers/gpu/drm/vc4/vc4_drv.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 2027063fdc30..8c329c071c62 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -476,7 +476,12 @@ static int __init vc4_drm_register(void) if (ret) return ret; - return platform_driver_register(&vc4_platform_driver); + ret = platform_driver_register(&vc4_platform_driver); + if (ret) + platform_unregister_drivers(component_drivers, + ARRAY_SIZE(component_drivers)); + + return ret; } static void __exit vc4_drm_unregister(void) -- cgit v1.2.3-59-g8ed1b From 308451d9c7fece33d9551230cb8e5eb7f3914988 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Sep 2022 15:32:58 +0200 Subject: drm: panel-orientation-quirks: Add quirk for Nanote UMPC-01 The Nanote UMPC-01 is a mini laptop with a 1200x1920 portrait screen mounted in a landscape oriented clamshell case. Add a quirk for this. Signed-off-by: Hans de Goede Acked-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20220919133258.711639-1-hdegoede@redhat.com --- drivers/gpu/drm/drm_panel_orientation_quirks.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index 8a0c0e0bb5bd..f0f6fa306521 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -319,6 +319,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"), }, .driver_data = (void *)&lcd1200x1920_rightside_up, + }, { /* Nanote UMPC-01 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"), + DMI_MATCH(DMI_PRODUCT_NAME, "UMPC-01"), + }, + .driver_data = (void *)&lcd1200x1920_rightside_up, }, { /* OneGX1 Pro */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SYSTEM_MANUFACTURER"), -- cgit v1.2.3-59-g8ed1b From 653f2d94fcda200b02bd79cea2e0307b26c1b747 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 6 Nov 2022 22:50:52 +0100 Subject: drm: panel-orientation-quirks: Add quirk for Acer Switch V 10 (SW5-017) Like the Acer Switch One 10 S1003, for which there already is a quirk, the Acer Switch V 10 (SW5-017) has a 800x1280 portrait screen mounted in the tablet part of a landscape oriented 2-in-1. Add a quirk for this. Cc: Rudolf Polzer Signed-off-by: Hans de Goede Acked-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20221106215052.66995-1-hdegoede@redhat.com --- drivers/gpu/drm/drm_panel_orientation_quirks.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index f0f6fa306521..52d8800a8ab8 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -134,6 +134,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"), }, .driver_data = (void *)&lcd800x1280_rightside_up, + }, { /* Acer Switch V 10 (SW5-017) */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017"), + }, + .driver_data = (void *)&lcd800x1280_rightside_up, }, { /* Anbernic Win600 */ .matches = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Anbernic"), -- cgit v1.2.3-59-g8ed1b From e0b26b9482461e9528552f54fa662c2269f75b3f Mon Sep 17 00:00:00 2001 From: Ma Jun Date: Wed, 14 Sep 2022 20:53:31 +0800 Subject: drm/amdgpu: Fix the lpfn checking condition in drm buddy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because the value of man->size is changed during suspend/resume process, use mgr->mm.size instead of man->size here for lpfn checking. Signed-off-by: Ma Jun Suggested-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20220914125331.2467162-1-Jun.Ma2@amd.com Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 73a517bcf5c1..80dd1343594c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -435,7 +435,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, if (place->flags & TTM_PL_FLAG_TOPDOWN) vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; - if (fpfn || lpfn != man->size) + if (fpfn || lpfn != mgr->mm.size) /* Allocate blocks in desired range */ vres->flags |= DRM_BUDDY_RANGE_ALLOCATION; -- cgit v1.2.3-59-g8ed1b From f352262f727215553879705bacbcb208979f3eff Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 8 Nov 2022 17:06:19 +0000 Subject: drm/panfrost: Split io-pgtable requests properly Although we don't use 1GB block mappings, we still need to split map/unmap requests at 1GB boundaries to match what io-pgtable expects. Fix that, and add some explanation to make sense of it all. Fixes: 3740b081795a ("drm/panfrost: Update io-pgtable API") Reported-by: Dmitry Osipenko Signed-off-by: Robin Murphy Tested-by: Dmitry Osipenko Reviewed-by: Steven Price Signed-off-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/49e54bb4019cd06e01549b106d7ac37c3d182cd3.1667927179.git.robin.murphy@arm.com --- drivers/gpu/drm/panfrost/panfrost_mmu.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index e246d914e7f6..4e83a1891f3e 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -250,13 +250,22 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev) static size_t get_pgsize(u64 addr, size_t size, size_t *count) { + /* + * io-pgtable only operates on multiple pages within a single table + * entry, so we need to split at boundaries of the table size, i.e. + * the next block size up. The distance from address A to the next + * boundary of block size B is logically B - A % B, but in unsigned + * two's complement where B is a power of two we get the equivalence + * B - A % B == (B - A) % B == (n * B - A) % B, and choose n = 0 :) + */ size_t blk_offset = -addr % SZ_2M; if (blk_offset || size < SZ_2M) { *count = min_not_zero(blk_offset, size) / SZ_4K; return SZ_4K; } - *count = size / SZ_2M; + blk_offset = -addr % SZ_1G ?: SZ_1G; + *count = min(blk_offset, size) / SZ_2M; return SZ_2M; } -- cgit v1.2.3-59-g8ed1b