]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/clk/bcm/clk-bcm2835.c
clk: bcm2835: Register the DSI0/DSI1 pixel clocks.
[mirror_ubuntu-artful-kernel.git] / drivers / clk / bcm / clk-bcm2835.c
index 3acf61ddeda8c27e6da0fd7e2beb46341679eb66..428e75c8b970897d881b570228eb85e8aef28999 100644 (file)
 
 #define VCMSG_ID_CORE_CLOCK     4
 
+/*
+ * 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;
        struct rpi_firmware *fw;
        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;
@@ -913,6 +934,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.
@@ -936,7 +960,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);
 }
@@ -1241,7 +1270,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;
@@ -1337,18 +1366,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));
@@ -1483,6 +1516,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
@@ -1946,6 +2020,18 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .div_reg = CM_DSI1EDIV,
                .int_bits = 4,
                .frac_bits = 8),
+       [BCM2835_CLOCK_DSI0P]   = REGISTER_DSI0_CLK(
+               .name = "dsi0p",
+               .ctl_reg = CM_DSI0PCTL,
+               .div_reg = CM_DSI0PDIV,
+               .int_bits = 0,
+               .frac_bits = 0),
+       [BCM2835_CLOCK_DSI1P]   = REGISTER_DSI1_CLK(
+               .name = "dsi1p",
+               .ctl_reg = CM_DSI1PCTL,
+               .div_reg = CM_DSI1PDIV,
+               .int_bits = 0,
+               .frac_bits = 0),
 
        /* the gates */
 
@@ -2036,8 +2122,19 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
             i++)
                bcm2835_clk_claimed[clk_id]= true;
 
-       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);