]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
clk: bcm2835: Add leaf clock measurement support, disabled by default
authorEric Anholt <eric@anholt.net>
Tue, 17 Jan 2017 20:31:57 +0000 (07:31 +1100)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Tue, 19 Sep 2017 10:07:54 +0000 (12:07 +0200)
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)
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
drivers/clk/bcm/clk-bcm2835.c

index 428e75c8b970897d881b570228eb85e8aef28999..fe3298b54cdfb96bd90fb4f39e13921d2e1d4356 100644 (file)
@@ -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>
 #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
@@ -342,6 +344,61 @@ static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 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,
                                  struct debugfs_reg32 *regs, size_t nregs,
                                  struct dentry *dentry)
@@ -477,6 +534,8 @@ struct bcm2835_clock_data {
 
        bool is_vpu_clock;
        bool is_mash_clock;
+
+       u32 tcnt_mux;
 };
 
 struct bcm2835_gate_data {
@@ -1038,6 +1097,17 @@ static int bcm2835_clock_on(struct clk_hw *hw)
                     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;
 }
 
@@ -1816,7 +1886,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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.
@@ -1850,13 +1921,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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
@@ -1867,13 +1940,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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
@@ -1887,7 +1962,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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(
@@ -1895,19 +1971,22 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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,
@@ -1919,7 +1998,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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(
@@ -1927,7 +2007,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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(
@@ -1936,7 +2017,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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,
@@ -1944,7 +2026,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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,
@@ -1959,40 +2042,46 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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(
@@ -2005,7 +2094,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                 * 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(
@@ -2013,25 +2103,29 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .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 */