Commit 3f919581 authored by Eric Anholt's avatar Eric Anholt Committed by Stephen Boyd

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: default avatarEric Anholt <eric@anholt.net>
Signed-off-by: default avatarStephen Boyd <sboyd@codeaurora.org>
parent 8a39e9fa
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk/bcm2835.h> #include <linux/clk/bcm2835.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -98,7 +99,8 @@ ...@@ -98,7 +99,8 @@
#define CM_SMIDIV 0x0b4 #define CM_SMIDIV 0x0b4
/* no definition for 0x0b8 and 0x0bc */ /* no definition for 0x0b8 and 0x0bc */
#define CM_TCNTCTL 0x0c0 #define CM_TCNTCTL 0x0c0
#define CM_TCNTDIV 0x0c4 # define CM_TCNT_SRC1_SHIFT 12
#define CM_TCNTCNT 0x0c4
#define CM_TECCTL 0x0c8 #define CM_TECCTL 0x0c8
#define CM_TECDIV 0x0cc #define CM_TECDIV 0x0cc
#define CM_TD0CTL 0x0d0 #define CM_TD0CTL 0x0d0
...@@ -338,6 +340,61 @@ static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg) ...@@ -338,6 +340,61 @@ static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg)
return readl(cprman->regs + reg); 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, static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
struct debugfs_reg32 *regs, size_t nregs, struct debugfs_reg32 *regs, size_t nregs,
struct dentry *dentry) struct dentry *dentry)
...@@ -473,6 +530,8 @@ struct bcm2835_clock_data { ...@@ -473,6 +530,8 @@ struct bcm2835_clock_data {
bool is_vpu_clock; bool is_vpu_clock;
bool is_mash_clock; bool is_mash_clock;
u32 tcnt_mux;
}; };
struct bcm2835_gate_data { struct bcm2835_gate_data {
...@@ -1008,6 +1067,17 @@ static int bcm2835_clock_on(struct clk_hw *hw) ...@@ -1008,6 +1067,17 @@ static int bcm2835_clock_on(struct clk_hw *hw)
CM_GATE); CM_GATE);
spin_unlock(&cprman->regs_lock); 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; return 0;
} }
...@@ -1765,7 +1835,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1765,7 +1835,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.ctl_reg = CM_OTPCTL, .ctl_reg = CM_OTPCTL,
.div_reg = CM_OTPDIV, .div_reg = CM_OTPDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 0), .frac_bits = 0,
.tcnt_mux = 6),
/* /*
* Used for a 1Mhz clock for the system clocksource, and also used * Used for a 1Mhz clock for the system clocksource, and also used
* bythe watchdog timer and the camera pulse generator. * bythe watchdog timer and the camera pulse generator.
...@@ -1799,13 +1870,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1799,13 +1870,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.ctl_reg = CM_H264CTL, .ctl_reg = CM_H264CTL,
.div_reg = CM_H264DIV, .div_reg = CM_H264DIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 1),
[BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK( [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK(
.name = "isp", .name = "isp",
.ctl_reg = CM_ISPCTL, .ctl_reg = CM_ISPCTL,
.div_reg = CM_ISPDIV, .div_reg = CM_ISPDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 2),
/* /*
* Secondary SDRAM clock. Used for low-voltage modes when the PLL * Secondary SDRAM clock. Used for low-voltage modes when the PLL
...@@ -1816,13 +1889,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1816,13 +1889,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.ctl_reg = CM_SDCCTL, .ctl_reg = CM_SDCCTL,
.div_reg = CM_SDCDIV, .div_reg = CM_SDCDIV,
.int_bits = 6, .int_bits = 6,
.frac_bits = 0), .frac_bits = 0,
.tcnt_mux = 3),
[BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
.name = "v3d", .name = "v3d",
.ctl_reg = CM_V3DCTL, .ctl_reg = CM_V3DCTL,
.div_reg = CM_V3DDIV, .div_reg = CM_V3DDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 4),
/* /*
* VPU clock. This doesn't have an enable bit, since it drives * 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 * the bus for everything else, and is special so it doesn't need
...@@ -1836,7 +1911,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1836,7 +1911,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.int_bits = 12, .int_bits = 12,
.frac_bits = 8, .frac_bits = 8,
.flags = CLK_IS_CRITICAL, .flags = CLK_IS_CRITICAL,
.is_vpu_clock = true), .is_vpu_clock = true,
.tcnt_mux = 5),
/* clocks with per parent mux */ /* clocks with per parent mux */
[BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK( [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK(
...@@ -1844,19 +1920,22 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1844,19 +1920,22 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.ctl_reg = CM_AVEOCTL, .ctl_reg = CM_AVEOCTL,
.div_reg = CM_AVEODIV, .div_reg = CM_AVEODIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 0), .frac_bits = 0,
.tcnt_mux = 38),
[BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK( [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK(
.name = "cam0", .name = "cam0",
.ctl_reg = CM_CAM0CTL, .ctl_reg = CM_CAM0CTL,
.div_reg = CM_CAM0DIV, .div_reg = CM_CAM0DIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 14),
[BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK( [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK(
.name = "cam1", .name = "cam1",
.ctl_reg = CM_CAM1CTL, .ctl_reg = CM_CAM1CTL,
.div_reg = CM_CAM1DIV, .div_reg = CM_CAM1DIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 15),
[BCM2835_CLOCK_DFT] = REGISTER_PER_CLK( [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK(
.name = "dft", .name = "dft",
.ctl_reg = CM_DFTCTL, .ctl_reg = CM_DFTCTL,
...@@ -1868,7 +1947,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1868,7 +1947,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.ctl_reg = CM_DPICTL, .ctl_reg = CM_DPICTL,
.div_reg = CM_DPIDIV, .div_reg = CM_DPIDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 17),
/* Arasan EMMC clock */ /* Arasan EMMC clock */
[BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK( [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK(
...@@ -1876,7 +1956,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1876,7 +1956,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.ctl_reg = CM_EMMCCTL, .ctl_reg = CM_EMMCCTL,
.div_reg = CM_EMMCDIV, .div_reg = CM_EMMCDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 39),
/* General purpose (GPIO) clocks */ /* General purpose (GPIO) clocks */
[BCM2835_CLOCK_GP0] = REGISTER_PER_CLK( [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK(
...@@ -1885,7 +1966,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1885,7 +1966,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.div_reg = CM_GP0DIV, .div_reg = CM_GP0DIV,
.int_bits = 12, .int_bits = 12,
.frac_bits = 12, .frac_bits = 12,
.is_mash_clock = true), .is_mash_clock = true,
.tcnt_mux = 20),
[BCM2835_CLOCK_GP1] = REGISTER_PER_CLK( [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK(
.name = "gp1", .name = "gp1",
.ctl_reg = CM_GP1CTL, .ctl_reg = CM_GP1CTL,
...@@ -1893,7 +1975,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1893,7 +1975,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.int_bits = 12, .int_bits = 12,
.frac_bits = 12, .frac_bits = 12,
.flags = CLK_IS_CRITICAL, .flags = CLK_IS_CRITICAL,
.is_mash_clock = true), .is_mash_clock = true,
.tcnt_mux = 21),
[BCM2835_CLOCK_GP2] = REGISTER_PER_CLK( [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
.name = "gp2", .name = "gp2",
.ctl_reg = CM_GP2CTL, .ctl_reg = CM_GP2CTL,
...@@ -1908,40 +1991,46 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1908,40 +1991,46 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.ctl_reg = CM_HSMCTL, .ctl_reg = CM_HSMCTL,
.div_reg = CM_HSMDIV, .div_reg = CM_HSMDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 22),
[BCM2835_CLOCK_PCM] = REGISTER_PER_CLK( [BCM2835_CLOCK_PCM] = REGISTER_PER_CLK(
.name = "pcm", .name = "pcm",
.ctl_reg = CM_PCMCTL, .ctl_reg = CM_PCMCTL,
.div_reg = CM_PCMDIV, .div_reg = CM_PCMDIV,
.int_bits = 12, .int_bits = 12,
.frac_bits = 12, .frac_bits = 12,
.is_mash_clock = true), .is_mash_clock = true,
.tcnt_mux = 23),
[BCM2835_CLOCK_PWM] = REGISTER_PER_CLK( [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK(
.name = "pwm", .name = "pwm",
.ctl_reg = CM_PWMCTL, .ctl_reg = CM_PWMCTL,
.div_reg = CM_PWMDIV, .div_reg = CM_PWMDIV,
.int_bits = 12, .int_bits = 12,
.frac_bits = 12, .frac_bits = 12,
.is_mash_clock = true), .is_mash_clock = true,
.tcnt_mux = 24),
[BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK( [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK(
.name = "slim", .name = "slim",
.ctl_reg = CM_SLIMCTL, .ctl_reg = CM_SLIMCTL,
.div_reg = CM_SLIMDIV, .div_reg = CM_SLIMDIV,
.int_bits = 12, .int_bits = 12,
.frac_bits = 12, .frac_bits = 12,
.is_mash_clock = true), .is_mash_clock = true,
.tcnt_mux = 25),
[BCM2835_CLOCK_SMI] = REGISTER_PER_CLK( [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK(
.name = "smi", .name = "smi",
.ctl_reg = CM_SMICTL, .ctl_reg = CM_SMICTL,
.div_reg = CM_SMIDIV, .div_reg = CM_SMIDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 27),
[BCM2835_CLOCK_UART] = REGISTER_PER_CLK( [BCM2835_CLOCK_UART] = REGISTER_PER_CLK(
.name = "uart", .name = "uart",
.ctl_reg = CM_UARTCTL, .ctl_reg = CM_UARTCTL,
.div_reg = CM_UARTDIV, .div_reg = CM_UARTDIV,
.int_bits = 10, .int_bits = 10,
.frac_bits = 12), .frac_bits = 12,
.tcnt_mux = 28),
/* TV encoder clock. Only operating frequency is 108Mhz. */ /* TV encoder clock. Only operating frequency is 108Mhz. */
[BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK(
...@@ -1954,7 +2043,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1954,7 +2043,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
* Allow rate change propagation only on PLLH_AUX which is * Allow rate change propagation only on PLLH_AUX which is
* assigned index 7 in the parent array. * assigned index 7 in the parent array.
*/ */
.set_rate_parent = BIT(7)), .set_rate_parent = BIT(7),
.tcnt_mux = 29),
/* dsi clocks */ /* dsi clocks */
[BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK(
...@@ -1962,25 +2052,29 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { ...@@ -1962,25 +2052,29 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.ctl_reg = CM_DSI0ECTL, .ctl_reg = CM_DSI0ECTL,
.div_reg = CM_DSI0EDIV, .div_reg = CM_DSI0EDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 18),
[BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK( [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK(
.name = "dsi1e", .name = "dsi1e",
.ctl_reg = CM_DSI1ECTL, .ctl_reg = CM_DSI1ECTL,
.div_reg = CM_DSI1EDIV, .div_reg = CM_DSI1EDIV,
.int_bits = 4, .int_bits = 4,
.frac_bits = 8), .frac_bits = 8,
.tcnt_mux = 19),
[BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK( [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK(
.name = "dsi0p", .name = "dsi0p",
.ctl_reg = CM_DSI0PCTL, .ctl_reg = CM_DSI0PCTL,
.div_reg = CM_DSI0PDIV, .div_reg = CM_DSI0PDIV,
.int_bits = 0, .int_bits = 0,
.frac_bits = 0), .frac_bits = 0,
.tcnt_mux = 12),
[BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK( [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK(
.name = "dsi1p", .name = "dsi1p",
.ctl_reg = CM_DSI1PCTL, .ctl_reg = CM_DSI1PCTL,
.div_reg = CM_DSI1PDIV, .div_reg = CM_DSI1PDIV,
.int_bits = 0, .int_bits = 0,
.frac_bits = 0), .frac_bits = 0,
.tcnt_mux = 13),
/* the gates */ /* the gates */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment