Skip to content

Commit eb963d7

Browse files
loki666wens
authored andcommitted
clk: sunxi-ng: h616: Reparent GPU clock during frequency changes
The H616 manual does not state that the GPU PLL supports dynamic frequency configuration, so we must take extra care when changing the frequency. Currently any attempt to do device DVFS on the GPU lead to panfrost various ooops, and GPU hangs. The manual describes the algorithm for changing the PLL frequency, which the CPU PLL notifier code already support, so we reuse that to reparent the GPU clock to GPU1 clock during frequency changes. Signed-off-by: Philippe Simons <simons.philippe@gmail.com> Reviewed-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Link: https://patch.msgid.link/20250220113808.1122414-2-simons.philippe@gmail.com Signed-off-by: Chen-Yu Tsai <wens@csie.org>
1 parent 730feea commit eb963d7

File tree

1 file changed

+35
-1
lines changed

1 file changed

+35
-1
lines changed

drivers/clk/sunxi-ng/ccu-sun50i-h616.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,16 @@ static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670,
328328
24, 1, /* mux */
329329
BIT(31), /* gate */
330330
CLK_SET_RATE_PARENT);
331+
332+
/*
333+
* This clk is needed as a temporary fall back during GPU PLL freq changes.
334+
* Set CLK_IS_CRITICAL flag to prevent from being disabled.
335+
*/
336+
#define SUN50I_H616_GPU_CLK1_REG 0x674
331337
static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674,
332338
0, 2, /* M */
333339
BIT(31),/* gate */
334-
0);
340+
CLK_IS_CRITICAL);
335341

336342
static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2",
337343
0x67c, BIT(0), 0);
@@ -1144,6 +1150,19 @@ static struct ccu_pll_nb sun50i_h616_pll_cpu_nb = {
11441150
.lock = BIT(28),
11451151
};
11461152

1153+
static struct ccu_mux_nb sun50i_h616_gpu_nb = {
1154+
.common = &gpu0_clk.common,
1155+
.cm = &gpu0_clk.mux,
1156+
.delay_us = 1, /* manual doesn't really say */
1157+
.bypass_index = 1, /* GPU_CLK1@400MHz */
1158+
};
1159+
1160+
static struct ccu_pll_nb sun50i_h616_pll_gpu_nb = {
1161+
.common = &pll_gpu_clk.common,
1162+
.enable = BIT(29), /* LOCK_ENABLE */
1163+
.lock = BIT(28),
1164+
};
1165+
11471166
static int sun50i_h616_ccu_probe(struct platform_device *pdev)
11481167
{
11491168
void __iomem *reg;
@@ -1194,6 +1213,14 @@ static int sun50i_h616_ccu_probe(struct platform_device *pdev)
11941213
val |= BIT(0);
11951214
writel(val, reg + SUN50I_H616_PLL_AUDIO_REG);
11961215

1216+
/*
1217+
* Set the input-divider for the gpu1 clock to 3, to reach a safe 400 MHz.
1218+
*/
1219+
val = readl(reg + SUN50I_H616_GPU_CLK1_REG);
1220+
val &= ~GENMASK(1, 0);
1221+
val |= 2;
1222+
writel(val, reg + SUN50I_H616_GPU_CLK1_REG);
1223+
11971224
/*
11981225
* First clock parent (osc32K) is unusable for CEC. But since there
11991226
* is no good way to force parent switch (both run with same frequency),
@@ -1214,6 +1241,13 @@ static int sun50i_h616_ccu_probe(struct platform_device *pdev)
12141241
/* Re-lock the CPU PLL after any rate changes */
12151242
ccu_pll_notifier_register(&sun50i_h616_pll_cpu_nb);
12161243

1244+
/* Reparent GPU during GPU PLL rate changes */
1245+
ccu_mux_notifier_register(pll_gpu_clk.common.hw.clk,
1246+
&sun50i_h616_gpu_nb);
1247+
1248+
/* Re-lock the GPU PLL after any rate changes */
1249+
ccu_pll_notifier_register(&sun50i_h616_pll_gpu_nb);
1250+
12171251
return 0;
12181252
}
12191253

0 commit comments

Comments
 (0)