summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJernej Skrabec <jernej.skrabec@gmail.com>2023-10-13 21:17:12 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-05-17 12:43:50 +0300
commitfe11826ffa200e1a7a826e745163cb2f47875f66 (patch)
treea1750cb7af2d063ce17ac1ac885d82e35dcb6323 /drivers
parent2f87fd9476cf9725d774e6dcb7d17859c6a6d1ae (diff)
downloadlinux-fe11826ffa200e1a7a826e745163cb2f47875f66.tar.xz
clk: sunxi-ng: h6: Reparent CPUX during PLL CPUX rate change
[ Upstream commit 7e91ed763dc07437777bd012af7a2bd4493731ff ] While PLL CPUX clock rate change when CPU is running from it works in vast majority of cases, now and then it causes instability. This leads to system crashes and other undefined behaviour. After a lot of testing (30+ hours) while also doing a lot of frequency switches, we can't observe any instability issues anymore when doing reparenting to stable clock like 24 MHz oscillator. Fixes: 524353ea480b ("clk: sunxi-ng: add support for the Allwinner H6 CCU") Reported-by: Chad Wagner <wagnerch42@gmail.com> Link: https://forum.libreelec.tv/thread/27295-orange-pi-3-lts-freezes/ Tested-by: Chad Wagner <wagnerch42@gmail.com> Reviewed-by: Chen-Yu Tsai <wens@csie.org> Link: https://lore.kernel.org/r/20231013181712.2128037-1-jernej.skrabec@gmail.com Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun50i-h6.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
index 2f00f1b7b9c0..c02f4e4a69e4 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
@@ -1172,12 +1172,19 @@ static const u32 usb2_clk_regs[] = {
SUN50I_H6_USB3_CLK_REG,
};
+static struct ccu_mux_nb sun50i_h6_cpu_nb = {
+ .common = &cpux_clk.common,
+ .cm = &cpux_clk.mux,
+ .delay_us = 1,
+ .bypass_index = 0, /* index of 24 MHz oscillator */
+};
+
static int sun50i_h6_ccu_probe(struct platform_device *pdev)
{
struct resource *res;
void __iomem *reg;
+ int i, ret;
u32 val;
- int i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, res);
@@ -1231,7 +1238,15 @@ static int sun50i_h6_ccu_probe(struct platform_device *pdev)
val |= BIT(24);
writel(val, reg + SUN50I_H6_HDMI_CEC_CLK_REG);
- return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h6_ccu_desc);
+ ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h6_ccu_desc);
+ if (ret)
+ return ret;
+
+ /* Reparent CPU during PLL CPUX rate changes */
+ ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
+ &sun50i_h6_cpu_nb);
+
+ return 0;
}
static const struct of_device_id sun50i_h6_ccu_ids[] = {