]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/clk/bcm/clk-bcm2835.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
[karo-tx-linux.git] / drivers / clk / bcm / clk-bcm2835.c
index 0d14409097e777ce4546de30e9278fdebf74ec44..02585387061967ac9408e18ac1bce67e9e9414c0 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>
@@ -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
 #define LOCK_TIMEOUT_NS                100000000
 #define BCM2835_MAX_FB_RATE    1750000000u
 
+/*
+ * Names of clocks used within the driver that need to be replaced
+ * with an external parent's name.  This array is in the order that
+ * the clocks node in the DT references external clocks.
+ */
+static const char *const cprman_parent_names[] = {
+       "xosc",
+       "dsi0_byte",
+       "dsi0_ddr2",
+       "dsi0_ddr",
+       "dsi1_byte",
+       "dsi1_ddr2",
+       "dsi1_ddr",
+};
+
 struct bcm2835_cprman {
        struct device *dev;
        void __iomem *regs;
        spinlock_t regs_lock; /* spinlock for all clocks */
-       const char *osc_name;
+
+       /*
+        * Real names of cprman clock parents looked up through
+        * of_clk_get_parent_name(), which will be used in the
+        * parent_names[] arrays for clock registration.
+        */
+       const char *real_parent_names[ARRAY_SIZE(cprman_parent_names)];
 
        /* Must be last */
        struct clk_hw_onecell_data onecell;
@@ -317,6 +340,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)
@@ -428,6 +506,7 @@ struct bcm2835_pll_divider_data {
        u32 load_mask;
        u32 hold_mask;
        u32 fixed_divider;
+       u32 flags;
 };
 
 struct bcm2835_clock_data {
@@ -451,6 +530,8 @@ struct bcm2835_clock_data {
 
        bool is_vpu_clock;
        bool is_mash_clock;
+
+       u32 tcnt_mux;
 };
 
 struct bcm2835_gate_data {
@@ -906,6 +987,9 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
        const struct bcm2835_clock_data *data = clock->data;
        u64 temp;
 
+       if (data->int_bits == 0 && data->frac_bits == 0)
+               return parent_rate;
+
        /*
         * The divisor is a 12.12 fixed point field, but only some of
         * the bits are populated in any given clock.
@@ -929,7 +1013,12 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
        struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
        struct bcm2835_cprman *cprman = clock->cprman;
        const struct bcm2835_clock_data *data = clock->data;
-       u32 div = cprman_read(cprman, data->div_reg);
+       u32 div;
+
+       if (data->int_bits == 0 && data->frac_bits == 0)
+               return parent_rate;
+
+       div = cprman_read(cprman, data->div_reg);
 
        return bcm2835_clock_rate_from_divisor(clock, parent_rate, div);
 }
@@ -978,6 +1067,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;
 }
 
@@ -1208,7 +1308,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
        memset(&init, 0, sizeof(init));
 
        /* All of the PLLs derive from the external oscillator. */
-       init.parent_names = &cprman->osc_name;
+       init.parent_names = &cprman->real_parent_names[0];
        init.num_parents = 1;
        init.name = data->name;
        init.ops = &bcm2835_pll_clk_ops;
@@ -1252,7 +1352,7 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
        init.num_parents = 1;
        init.name = divider_name;
        init.ops = &bcm2835_pll_divider_clk_ops;
-       init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED;
+       init.flags = data->flags | CLK_IGNORE_UNUSED;
 
        divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL);
        if (!divider)
@@ -1294,18 +1394,22 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
        struct bcm2835_clock *clock;
        struct clk_init_data init;
        const char *parents[1 << CM_SRC_BITS];
-       size_t i;
+       size_t i, j;
        int ret;
 
        /*
-        * Replace our "xosc" references with the oscillator's
-        * actual name.
+        * Replace our strings referencing parent clocks with the
+        * actual clock-output-name of the parent.
         */
        for (i = 0; i < data->num_mux_parents; i++) {
-               if (strcmp(data->parents[i], "xosc") == 0)
-                       parents[i] = cprman->osc_name;
-               else
-                       parents[i] = data->parents[i];
+               parents[i] = data->parents[i];
+
+               for (j = 0; j < ARRAY_SIZE(cprman_parent_names); j++) {
+                       if (strcmp(parents[i], cprman_parent_names[j]) == 0) {
+                               parents[i] = cprman->real_parent_names[j];
+                               break;
+                       }
+               }
        }
 
        memset(&init, 0, sizeof(init));
@@ -1431,6 +1535,47 @@ static const char *const bcm2835_clock_vpu_parents[] = {
        .parents = bcm2835_clock_vpu_parents,                           \
        __VA_ARGS__)
 
+/*
+ * DSI parent clocks.  The DSI byte/DDR/DDR2 clocks come from the DSI
+ * analog PHY.  The _inv variants are generated internally to cprman,
+ * but we don't use them so they aren't hooked up.
+ */
+static const char *const bcm2835_clock_dsi0_parents[] = {
+       "gnd",
+       "xosc",
+       "testdebug0",
+       "testdebug1",
+       "dsi0_ddr",
+       "dsi0_ddr_inv",
+       "dsi0_ddr2",
+       "dsi0_ddr2_inv",
+       "dsi0_byte",
+       "dsi0_byte_inv",
+};
+
+static const char *const bcm2835_clock_dsi1_parents[] = {
+       "gnd",
+       "xosc",
+       "testdebug0",
+       "testdebug1",
+       "dsi1_ddr",
+       "dsi1_ddr_inv",
+       "dsi1_ddr2",
+       "dsi1_ddr2_inv",
+       "dsi1_byte",
+       "dsi1_byte_inv",
+};
+
+#define REGISTER_DSI0_CLK(...) REGISTER_CLK(                           \
+       .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi0_parents),      \
+       .parents = bcm2835_clock_dsi0_parents,                          \
+       __VA_ARGS__)
+
+#define REGISTER_DSI1_CLK(...) REGISTER_CLK(                           \
+       .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi1_parents),      \
+       .parents = bcm2835_clock_dsi1_parents,                          \
+       __VA_ARGS__)
+
 /*
  * the real definition of all the pll, pll_dividers and clocks
  * these make use of the above REGISTER_* macros
@@ -1466,7 +1611,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLA_CORE,
                .load_mask = CM_PLLA_LOADCORE,
                .hold_mask = CM_PLLA_HOLDCORE,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLA_PER]      = REGISTER_PLL_DIV(
                .name = "plla_per",
                .source_pll = "plla",
@@ -1474,7 +1620,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLA_PER,
                .load_mask = CM_PLLA_LOADPER,
                .hold_mask = CM_PLLA_HOLDPER,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLA_DSI0]     = REGISTER_PLL_DIV(
                .name = "plla_dsi0",
                .source_pll = "plla",
@@ -1490,7 +1637,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLA_CCP2,
                .load_mask = CM_PLLA_LOADCCP2,
                .hold_mask = CM_PLLA_HOLDCCP2,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
 
        /* PLLB is used for the ARM's clock. */
        [BCM2835_PLLB]          = REGISTER_PLL(
@@ -1514,7 +1662,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLB_ARM,
                .load_mask = CM_PLLB_LOADARM,
                .hold_mask = CM_PLLB_HOLDARM,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
 
        /*
         * PLLC is the core PLL, used to drive the core VPU clock.
@@ -1543,7 +1692,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLC_CORE0,
                .load_mask = CM_PLLC_LOADCORE0,
                .hold_mask = CM_PLLC_HOLDCORE0,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLC_CORE1]    = REGISTER_PLL_DIV(
                .name = "pllc_core1",
                .source_pll = "pllc",
@@ -1551,7 +1701,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLC_CORE1,
                .load_mask = CM_PLLC_LOADCORE1,
                .hold_mask = CM_PLLC_HOLDCORE1,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLC_CORE2]    = REGISTER_PLL_DIV(
                .name = "pllc_core2",
                .source_pll = "pllc",
@@ -1559,7 +1710,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLC_CORE2,
                .load_mask = CM_PLLC_LOADCORE2,
                .hold_mask = CM_PLLC_HOLDCORE2,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLC_PER]      = REGISTER_PLL_DIV(
                .name = "pllc_per",
                .source_pll = "pllc",
@@ -1567,7 +1719,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLC_PER,
                .load_mask = CM_PLLC_LOADPER,
                .hold_mask = CM_PLLC_HOLDPER,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
 
        /*
         * PLLD is the display PLL, used to drive DSI display panels.
@@ -1596,7 +1749,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLD_CORE,
                .load_mask = CM_PLLD_LOADCORE,
                .hold_mask = CM_PLLD_HOLDCORE,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLD_PER]      = REGISTER_PLL_DIV(
                .name = "plld_per",
                .source_pll = "plld",
@@ -1604,7 +1758,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLD_PER,
                .load_mask = CM_PLLD_LOADPER,
                .hold_mask = CM_PLLD_HOLDPER,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLD_DSI0]     = REGISTER_PLL_DIV(
                .name = "plld_dsi0",
                .source_pll = "plld",
@@ -1649,7 +1804,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLH_RCAL,
                .load_mask = CM_PLLH_LOADRCAL,
                .hold_mask = 0,
-               .fixed_divider = 10),
+               .fixed_divider = 10,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLH_AUX]      = REGISTER_PLL_DIV(
                .name = "pllh_aux",
                .source_pll = "pllh",
@@ -1657,7 +1813,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLH_AUX,
                .load_mask = CM_PLLH_LOADAUX,
                .hold_mask = 0,
-               .fixed_divider = 1),
+               .fixed_divider = 1,
+               .flags = CLK_SET_RATE_PARENT),
        [BCM2835_PLLH_PIX]      = REGISTER_PLL_DIV(
                .name = "pllh_pix",
                .source_pll = "pllh",
@@ -1665,7 +1822,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .a2w_reg = A2W_PLLH_PIX,
                .load_mask = CM_PLLH_LOADPIX,
                .hold_mask = 0,
-               .fixed_divider = 10),
+               .fixed_divider = 10,
+               .flags = CLK_SET_RATE_PARENT),
 
        /* the clocks */
 
@@ -1677,7 +1835,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.
@@ -1711,13 +1870,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
@@ -1728,13 +1889,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
@@ -1748,7 +1911,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(
@@ -1756,19 +1920,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,
@@ -1780,7 +1947,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(
@@ -1788,7 +1956,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(
@@ -1797,7 +1966,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,
@@ -1805,7 +1975,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,
@@ -1820,40 +1991,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(
@@ -1866,7 +2043,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(
@@ -1874,13 +2052,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,
+               .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,
+               .tcnt_mux = 13),
 
        /* the gates */
 
@@ -1939,8 +2133,19 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
        if (IS_ERR(cprman->regs))
                return PTR_ERR(cprman->regs);
 
-       cprman->osc_name = of_clk_get_parent_name(dev->of_node, 0);
-       if (!cprman->osc_name)
+       memcpy(cprman->real_parent_names, cprman_parent_names,
+              sizeof(cprman_parent_names));
+       of_clk_parent_fill(dev->of_node, cprman->real_parent_names,
+                          ARRAY_SIZE(cprman_parent_names));
+
+       /*
+        * Make sure the external oscillator has been registered.
+        *
+        * The other (DSI) clocks are not present on older device
+        * trees, which we still need to support for backwards
+        * compatibility.
+        */
+       if (!cprman->real_parent_names[0])
                return -ENODEV;
 
        platform_set_drvdata(pdev, cprman);