aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0149-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch
blob: 40523ef55281d82f08f4b29ea1ad470fe6f19d20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
From ba8242ab300638e8f6e46fe1596c5ee86c71b27d Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Thu, 2 May 2019 15:11:05 -0700
Subject: [PATCH] clk: bcm2835: Add support for setting leaf clock
 rates while running.

As long as you wait for !BUSY, you can do glitch-free updates of clock
rate while the clock is running.

Signed-off-by: Eric Anholt <eric@anholt.net>
---
 drivers/clk/bcm/clk-bcm2835.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1139,15 +1139,19 @@ static int bcm2835_clock_set_rate(struct
 
 	spin_lock(&cprman->regs_lock);
 
-	/*
-	 * Setting up frac support
-	 *
-	 * In principle it is recommended to stop/start the clock first,
-	 * but as we set CLK_SET_RATE_GATE during registration of the
-	 * clock this requirement should be take care of by the
-	 * clk-framework.
+	ctl = cprman_read(cprman, data->ctl_reg);
+
+	/* If the clock is running, we have to pause clock generation while
+	 * updating the control and div regs.  This is glitchless (no clock
+	 * signals generated faster than the rate) but each reg access is two
+	 * OSC cycles so the clock will slow down for a moment.
 	 */
-	ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
+	if (ctl & CM_ENABLE) {
+		cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE);
+		bcm2835_clock_wait_busy(clock);
+	}
+
+	ctl &= ~CM_FRAC;
 	ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
 	cprman_write(cprman, data->ctl_reg, ctl);
 
@@ -1523,7 +1527,7 @@ static struct clk_hw *bcm2835_register_c
 		init.ops = &bcm2835_vpu_clock_clk_ops;
 	} else {
 		init.ops = &bcm2835_clock_clk_ops;
-		init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+		init.flags |= CLK_SET_PARENT_GATE;
 
 		/* If the clock wasn't actually enabled at boot, it's not
 		 * critical.