diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.9/0157-clk-bcm2835-Add-leaf-clock-measurement-support-disab.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.9/0157-clk-bcm2835-Add-leaf-clock-measurement-support-disab.patch | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.9/0157-clk-bcm2835-Add-leaf-clock-measurement-support-disab.patch b/target/linux/brcm2708/patches-4.9/0157-clk-bcm2835-Add-leaf-clock-measurement-support-disab.patch new file mode 100644 index 0000000000..16c5ec5cbf --- /dev/null +++ b/target/linux/brcm2708/patches-4.9/0157-clk-bcm2835-Add-leaf-clock-measurement-support-disab.patch @@ -0,0 +1,346 @@ +From 546bac0479e51024027f8c8820f912573643b101 Mon Sep 17 00:00:00 2001 +From: Eric Anholt <eric@anholt.net> +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 <eric@anholt.net> +Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> +(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 { +@@ -1008,6 +1067,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; + } + +@@ -1774,7 +1844,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. +@@ -1808,13 +1879,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 +@@ -1825,13 +1898,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 +@@ -1845,7 +1920,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( +@@ -1853,19 +1929,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, +@@ -1877,7 +1956,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( +@@ -1885,7 +1965,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( +@@ -1894,7 +1975,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, +@@ -1902,7 +1984,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, +@@ -1917,40 +2000,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( +@@ -1963,7 +2052,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( +@@ -1971,25 +2061,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 */ + |