| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- From 546bac0479e51024027f8c8820f912573643b101 Mon Sep 17 00:00:00 2001
- From: Eric Anholt <[email protected]>
- Date: Wed, 18 Jan 2017 07:31:57 +1100
- Subject: [PATCH] clk: bcm2835: Add leaf clock measurement support, disabled by
- default
- This proved incredibly useful during debugging of the DSI driver, to
- see if our clocks were running at rate we requested. Let's leave it
- here for the next person interacting with clocks on the platform (and
- so that hopefully we can just hook it up to debugfs some day).
- Signed-off-by: Eric Anholt <[email protected]>
- Signed-off-by: Stephen Boyd <[email protected]>
- (cherry picked from commit 3f9195811d8d829556c4cd88d3f9e56a80d5ba60)
- ---
- drivers/clk/bcm/clk-bcm2835.c | 144 ++++++++++++++++++++++++++++++++++--------
- 1 file changed, 119 insertions(+), 25 deletions(-)
- --- a/drivers/clk/bcm/clk-bcm2835.c
- +++ b/drivers/clk/bcm/clk-bcm2835.c
- @@ -39,6 +39,7 @@
- #include <linux/clk.h>
- #include <linux/clk/bcm2835.h>
- #include <linux/debugfs.h>
- +#include <linux/delay.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/platform_device.h>
- @@ -98,7 +99,8 @@
- #define CM_SMIDIV 0x0b4
- /* no definition for 0x0b8 and 0x0bc */
- #define CM_TCNTCTL 0x0c0
- -#define CM_TCNTDIV 0x0c4
- +# define CM_TCNT_SRC1_SHIFT 12
- +#define CM_TCNTCNT 0x0c4
- #define CM_TECCTL 0x0c8
- #define CM_TECDIV 0x0cc
- #define CM_TD0CTL 0x0d0
- @@ -338,6 +340,61 @@ static inline u32 cprman_read(struct bcm
- return readl(cprman->regs + reg);
- }
-
- +/* Does a cycle of measuring a clock through the TCNT clock, which may
- + * source from many other clocks in the system.
- + */
- +static unsigned long bcm2835_measure_tcnt_mux(struct bcm2835_cprman *cprman,
- + u32 tcnt_mux)
- +{
- + u32 osccount = 19200; /* 1ms */
- + u32 count;
- + ktime_t timeout;
- +
- + spin_lock(&cprman->regs_lock);
- +
- + cprman_write(cprman, CM_TCNTCTL, CM_KILL);
- +
- + cprman_write(cprman, CM_TCNTCTL,
- + (tcnt_mux & CM_SRC_MASK) |
- + (tcnt_mux >> CM_SRC_BITS) << CM_TCNT_SRC1_SHIFT);
- +
- + cprman_write(cprman, CM_OSCCOUNT, osccount);
- +
- + /* do a kind delay at the start */
- + mdelay(1);
- +
- + /* Finish off whatever is left of OSCCOUNT */
- + timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
- + while (cprman_read(cprman, CM_OSCCOUNT)) {
- + if (ktime_after(ktime_get(), timeout)) {
- + dev_err(cprman->dev, "timeout waiting for OSCCOUNT\n");
- + count = 0;
- + goto out;
- + }
- + cpu_relax();
- + }
- +
- + /* Wait for BUSY to clear. */
- + timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
- + while (cprman_read(cprman, CM_TCNTCTL) & CM_BUSY) {
- + if (ktime_after(ktime_get(), timeout)) {
- + dev_err(cprman->dev, "timeout waiting for !BUSY\n");
- + count = 0;
- + goto out;
- + }
- + cpu_relax();
- + }
- +
- + count = cprman_read(cprman, CM_TCNTCNT);
- +
- + cprman_write(cprman, CM_TCNTCTL, 0);
- +
- +out:
- + spin_unlock(&cprman->regs_lock);
- +
- + return count * 1000;
- +}
- +
- static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
- struct debugfs_reg32 *regs, size_t nregs,
- struct dentry *dentry)
- @@ -473,6 +530,8 @@ struct bcm2835_clock_data {
-
- bool is_vpu_clock;
- bool is_mash_clock;
- +
- + u32 tcnt_mux;
- };
-
- struct bcm2835_gate_data {
- @@ -1014,6 +1073,17 @@ static int bcm2835_clock_on(struct clk_h
- CM_GATE);
- spin_unlock(&cprman->regs_lock);
-
- + /* Debug code to measure the clock once it's turned on to see
- + * if it's ticking at the rate we expect.
- + */
- + if (data->tcnt_mux && false) {
- + dev_info(cprman->dev,
- + "clk %s: rate %ld, measure %ld\n",
- + data->name,
- + clk_hw_get_rate(hw),
- + bcm2835_measure_tcnt_mux(cprman, data->tcnt_mux));
- + }
- +
- return 0;
- }
-
- @@ -1780,7 +1850,8 @@ static const struct bcm2835_clk_desc clk
- .ctl_reg = CM_OTPCTL,
- .div_reg = CM_OTPDIV,
- .int_bits = 4,
- - .frac_bits = 0),
- + .frac_bits = 0,
- + .tcnt_mux = 6),
- /*
- * Used for a 1Mhz clock for the system clocksource, and also used
- * bythe watchdog timer and the camera pulse generator.
- @@ -1814,13 +1885,15 @@ static const struct bcm2835_clk_desc clk
- .ctl_reg = CM_H264CTL,
- .div_reg = CM_H264DIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 1),
- [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK(
- .name = "isp",
- .ctl_reg = CM_ISPCTL,
- .div_reg = CM_ISPDIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 2),
-
- /*
- * Secondary SDRAM clock. Used for low-voltage modes when the PLL
- @@ -1831,13 +1904,15 @@ static const struct bcm2835_clk_desc clk
- .ctl_reg = CM_SDCCTL,
- .div_reg = CM_SDCDIV,
- .int_bits = 6,
- - .frac_bits = 0),
- + .frac_bits = 0,
- + .tcnt_mux = 3),
- [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
- .name = "v3d",
- .ctl_reg = CM_V3DCTL,
- .div_reg = CM_V3DDIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 4),
- /*
- * VPU clock. This doesn't have an enable bit, since it drives
- * the bus for everything else, and is special so it doesn't need
- @@ -1851,7 +1926,8 @@ static const struct bcm2835_clk_desc clk
- .int_bits = 12,
- .frac_bits = 8,
- .flags = CLK_IS_CRITICAL,
- - .is_vpu_clock = true),
- + .is_vpu_clock = true,
- + .tcnt_mux = 5),
-
- /* clocks with per parent mux */
- [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK(
- @@ -1859,19 +1935,22 @@ static const struct bcm2835_clk_desc clk
- .ctl_reg = CM_AVEOCTL,
- .div_reg = CM_AVEODIV,
- .int_bits = 4,
- - .frac_bits = 0),
- + .frac_bits = 0,
- + .tcnt_mux = 38),
- [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK(
- .name = "cam0",
- .ctl_reg = CM_CAM0CTL,
- .div_reg = CM_CAM0DIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 14),
- [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK(
- .name = "cam1",
- .ctl_reg = CM_CAM1CTL,
- .div_reg = CM_CAM1DIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 15),
- [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK(
- .name = "dft",
- .ctl_reg = CM_DFTCTL,
- @@ -1883,7 +1962,8 @@ static const struct bcm2835_clk_desc clk
- .ctl_reg = CM_DPICTL,
- .div_reg = CM_DPIDIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 17),
-
- /* Arasan EMMC clock */
- [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK(
- @@ -1891,7 +1971,8 @@ static const struct bcm2835_clk_desc clk
- .ctl_reg = CM_EMMCCTL,
- .div_reg = CM_EMMCDIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 39),
-
- /* General purpose (GPIO) clocks */
- [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK(
- @@ -1900,7 +1981,8 @@ static const struct bcm2835_clk_desc clk
- .div_reg = CM_GP0DIV,
- .int_bits = 12,
- .frac_bits = 12,
- - .is_mash_clock = true),
- + .is_mash_clock = true,
- + .tcnt_mux = 20),
- [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK(
- .name = "gp1",
- .ctl_reg = CM_GP1CTL,
- @@ -1908,7 +1990,8 @@ static const struct bcm2835_clk_desc clk
- .int_bits = 12,
- .frac_bits = 12,
- .flags = CLK_IS_CRITICAL,
- - .is_mash_clock = true),
- + .is_mash_clock = true,
- + .tcnt_mux = 21),
- [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
- .name = "gp2",
- .ctl_reg = CM_GP2CTL,
- @@ -1923,40 +2006,46 @@ static const struct bcm2835_clk_desc clk
- .ctl_reg = CM_HSMCTL,
- .div_reg = CM_HSMDIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 22),
- [BCM2835_CLOCK_PCM] = REGISTER_PER_CLK(
- .name = "pcm",
- .ctl_reg = CM_PCMCTL,
- .div_reg = CM_PCMDIV,
- .int_bits = 12,
- .frac_bits = 12,
- - .is_mash_clock = true),
- + .is_mash_clock = true,
- + .tcnt_mux = 23),
- [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK(
- .name = "pwm",
- .ctl_reg = CM_PWMCTL,
- .div_reg = CM_PWMDIV,
- .int_bits = 12,
- .frac_bits = 12,
- - .is_mash_clock = true),
- + .is_mash_clock = true,
- + .tcnt_mux = 24),
- [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK(
- .name = "slim",
- .ctl_reg = CM_SLIMCTL,
- .div_reg = CM_SLIMDIV,
- .int_bits = 12,
- .frac_bits = 12,
- - .is_mash_clock = true),
- + .is_mash_clock = true,
- + .tcnt_mux = 25),
- [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK(
- .name = "smi",
- .ctl_reg = CM_SMICTL,
- .div_reg = CM_SMIDIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 27),
- [BCM2835_CLOCK_UART] = REGISTER_PER_CLK(
- .name = "uart",
- .ctl_reg = CM_UARTCTL,
- .div_reg = CM_UARTDIV,
- .int_bits = 10,
- - .frac_bits = 12),
- + .frac_bits = 12,
- + .tcnt_mux = 28),
-
- /* TV encoder clock. Only operating frequency is 108Mhz. */
- [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK(
- @@ -1969,7 +2058,8 @@ static const struct bcm2835_clk_desc clk
- * Allow rate change propagation only on PLLH_AUX which is
- * assigned index 7 in the parent array.
- */
- - .set_rate_parent = BIT(7)),
- + .set_rate_parent = BIT(7),
- + .tcnt_mux = 29),
-
- /* dsi clocks */
- [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK(
- @@ -1977,25 +2067,29 @@ static const struct bcm2835_clk_desc clk
- .ctl_reg = CM_DSI0ECTL,
- .div_reg = CM_DSI0EDIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 18),
- [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK(
- .name = "dsi1e",
- .ctl_reg = CM_DSI1ECTL,
- .div_reg = CM_DSI1EDIV,
- .int_bits = 4,
- - .frac_bits = 8),
- + .frac_bits = 8,
- + .tcnt_mux = 19),
- [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK(
- .name = "dsi0p",
- .ctl_reg = CM_DSI0PCTL,
- .div_reg = CM_DSI0PDIV,
- .int_bits = 0,
- - .frac_bits = 0),
- + .frac_bits = 0,
- + .tcnt_mux = 12),
- [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK(
- .name = "dsi1p",
- .ctl_reg = CM_DSI1PCTL,
- .div_reg = CM_DSI1PDIV,
- .int_bits = 0,
- - .frac_bits = 0),
- + .frac_bits = 0,
- + .tcnt_mux = 13),
-
- /* the gates */
-
|