From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Paul Cercueil <paul@crapouillou.net>,
Sasha Levin <sashal@kernel.org>, Sam Ravnborg <sam@ravnborg.org>,
linux-mips@vger.kernel.org, dri-devel@lists.freedesktop.org
Subject: [PATCH AUTOSEL 5.10 002/217] drm/ingenic: Reset pixclock rate when parent clock rate changes
Date: Tue, 22 Dec 2020 21:12:51 -0500 [thread overview]
Message-ID: <20201223021626.2790791-2-sashal@kernel.org> (raw)
In-Reply-To: <20201223021626.2790791-1-sashal@kernel.org>
From: Paul Cercueil <paul@crapouillou.net>
[ Upstream commit 33700f6f7d9f6b4e1e6df933ef7fd388889c662c ]
Old Ingenic SoCs can overclock very well, up to +50% of their nominal
clock rate, whithout requiring overvolting or anything like that, just
by changing the rate of the main PLL. Unfortunately, all clocks on the
system are derived from that PLL, and when the PLL rate is updated, so
is our pixel clock.
To counter that issue, we make sure that the panel is in VBLANK before
the rate change happens, and we will then re-set the pixel clock rate
afterwards, once the PLL has been changed, to be as close as possible to
the pixel rate requested by the encoder.
v2: Add comment about mutex usage
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20200926170501.1109197-2-paul@crapouillou.net
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 61 ++++++++++++++++++++++-
1 file changed, 60 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index a3d1617d7c67e..819744d7d5897 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -68,6 +69,21 @@ struct ingenic_drm {
bool panel_is_sharp;
bool no_vblank;
+
+ /*
+ * clk_mutex is used to synchronize the pixel clock rate update with
+ * the VBLANK. When the pixel clock's parent clock needs to be updated,
+ * clock_nb's notifier function will lock the mutex, then wait until the
+ * next VBLANK. At that point, the parent clock's rate can be updated,
+ * and the mutex is then unlocked. If an atomic commit happens in the
+ * meantime, it will lock on the mutex, effectively waiting until the
+ * clock update process finishes. Finally, the pixel clock's rate will
+ * be recomputed when the mutex has been released, in the pending atomic
+ * commit, or a future one.
+ */
+ struct mutex clk_mutex;
+ bool update_clk_rate;
+ struct notifier_block clock_nb;
};
static const u32 ingenic_drm_primary_formats[] = {
@@ -111,6 +127,29 @@ static inline struct ingenic_drm *drm_crtc_get_priv(struct drm_crtc *crtc)
return container_of(crtc, struct ingenic_drm, crtc);
}
+static inline struct ingenic_drm *drm_nb_get_priv(struct notifier_block *nb)
+{
+ return container_of(nb, struct ingenic_drm, clock_nb);
+}
+
+static int ingenic_drm_update_pixclk(struct notifier_block *nb,
+ unsigned long action,
+ void *data)
+{
+ struct ingenic_drm *priv = drm_nb_get_priv(nb);
+
+ switch (action) {
+ case PRE_RATE_CHANGE:
+ mutex_lock(&priv->clk_mutex);
+ priv->update_clk_rate = true;
+ drm_crtc_wait_one_vblank(&priv->crtc);
+ return NOTIFY_OK;
+ default:
+ mutex_unlock(&priv->clk_mutex);
+ return NOTIFY_OK;
+ }
+}
+
static void ingenic_drm_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
@@ -276,8 +315,14 @@ static void ingenic_drm_crtc_atomic_flush(struct drm_crtc *crtc,
if (drm_atomic_crtc_needs_modeset(state)) {
ingenic_drm_crtc_update_timings(priv, &state->mode);
+ priv->update_clk_rate = true;
+ }
+ if (priv->update_clk_rate) {
+ mutex_lock(&priv->clk_mutex);
clk_set_rate(priv->pix_clk, state->adjusted_mode.clock * 1000);
+ priv->update_clk_rate = false;
+ mutex_unlock(&priv->clk_mutex);
}
if (event) {
@@ -934,16 +979,28 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
if (soc_info->has_osd)
regmap_write(priv->map, JZ_REG_LCD_OSDC, JZ_LCD_OSDC_OSDEN);
+ mutex_init(&priv->clk_mutex);
+ priv->clock_nb.notifier_call = ingenic_drm_update_pixclk;
+
+ parent_clk = clk_get_parent(priv->pix_clk);
+ ret = clk_notifier_register(parent_clk, &priv->clock_nb);
+ if (ret) {
+ dev_err(dev, "Unable to register clock notifier\n");
+ goto err_devclk_disable;
+ }
+
ret = drm_dev_register(drm, 0);
if (ret) {
dev_err(dev, "Failed to register DRM driver\n");
- goto err_devclk_disable;
+ goto err_clk_notifier_unregister;
}
drm_fbdev_generic_setup(drm, 32);
return 0;
+err_clk_notifier_unregister:
+ clk_notifier_unregister(parent_clk, &priv->clock_nb);
err_devclk_disable:
if (priv->lcd_clk)
clk_disable_unprepare(priv->lcd_clk);
@@ -965,7 +1022,9 @@ static int compare_of(struct device *dev, void *data)
static void ingenic_drm_unbind(struct device *dev)
{
struct ingenic_drm *priv = dev_get_drvdata(dev);
+ struct clk *parent_clk = clk_get_parent(priv->pix_clk);
+ clk_notifier_unregister(parent_clk, &priv->clock_nb);
if (priv->lcd_clk)
clk_disable_unprepare(priv->lcd_clk);
clk_disable_unprepare(priv->pix_clk);
--
2.27.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
next parent reply other threads:[~2020-12-23 2:16 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20201223021626.2790791-1-sashal@kernel.org>
2020-12-23 2:12 ` Sasha Levin [this message]
2020-12-23 2:12 ` [PATCH AUTOSEL 5.10 003/217] drm/bridge: ti-sn65dsi86: Add retries for link training Sasha Levin
2020-12-23 2:12 ` [PATCH AUTOSEL 5.10 004/217] drm/amd/display: setup system context in dm_init Sasha Levin
2020-12-23 2:12 ` [PATCH AUTOSEL 5.10 005/217] drm/amd/display: Fix the display corruption issue on Navi10 Sasha Levin
2020-12-23 2:12 ` [PATCH AUTOSEL 5.10 010/217] drm/amdgpu: change to save bad pages in UMC error interrupt callback Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 012/217] drm/amd/display: Do not silently accept DCC for multiplane formats Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 015/217] drm/msm: Fix race condition in msm driver with async layer updates Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 018/217] drm/amd/display: Fix compilation error Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 019/217] drm/amd/display: Force prefetch mode to 0 Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 020/217] drm/amd/display: Keep GSL for full updates with planes that flip VSYNC Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 021/217] drm/amd/display: stop top_mgr when type change to non-MST during s3 Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 022/217] drm/amd/display: correct eDP T9 delay Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 023/217] drm/amd/display: Update connector on DSC property change Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 024/217] drm/amd/display: fix recout calculation for left side clip Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 025/217] drm/amdgpu: disable gfxoff if VCN is busy Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 028/217] drm/amdgpu: set LDS_CONFIG=0x20 on Navy Flounder to fix a GPU hang (v2) Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 036/217] drm/amdgpu: add missing clock gating info in amdgpu_pm_info Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 052/217] drm: panel: simple: add missing platform_driver_unregister() in panel_simple_init Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 053/217] drm/bridge: lvds-codec: Use dev_err_probe for error handling Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 054/217] drm/ast: Fixed 1920x1080 sync. polarity issue Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 064/217] drm/omap: Fix runtime PM imbalance on error Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 068/217] drm/amd/amdgpu: Fix incorrect logic to increment VCN doorbell index Sasha Levin
2020-12-23 2:13 ` [PATCH AUTOSEL 5.10 069/217] drm/amd/amdgpu: Add rev_id workaround logic for SRIOV setup Sasha Levin
2020-12-23 2:14 ` [PATCH AUTOSEL 5.10 074/217] drm/amd/amdgpu: Update VCN initizalization behvaior Sasha Levin
2020-12-23 2:14 ` [PATCH AUTOSEL 5.10 075/217] drm/amdgpu: check hive pointer before access Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201223021626.2790791-2-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@vger.kernel.org \
--cc=paul@crapouillou.net \
--cc=sam@ravnborg.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox