]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
clk: bcm2835: Register the DSI0/DSI1 pixel clocks.
authorEric Anholt <eric@anholt.net>
Tue, 17 Jan 2017 20:31:56 +0000 (07:31 +1100)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Tue, 19 Sep 2017 10:07:54 +0000 (12:07 +0200)
The DSI pixel clocks are muxed from clocks generated in the analog phy
by the DSI driver.  In order to set them as parents, we need to do the
same name lookup dance on them as we do for our root oscillator.

Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
(cherry picked from commit 8a39e9fa578229fd4604266c6ebb1a3a77d7994c)
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Documentation/devicetree/bindings/clock/brcm,bcm2835-cprman.txt
drivers/clk/bcm/clk-bcm2835.c
include/dt-bindings/clock/bcm2835.h

index e56a1df3a9d3ca7fefbc5058072ee392c49b4cfc..dd906db34b328a581e4f4d99d11284544ff817f4 100644 (file)
@@ -16,7 +16,20 @@ Required properties:
 - #clock-cells:        Should be <1>. The permitted clock-specifier values can be
                  found in include/dt-bindings/clock/bcm2835.h
 - reg:         Specifies base physical address and size of the registers
-- clocks:      The external oscillator clock phandle
+- clocks:      phandles to the parent clocks used as input to the module, in
+                 the following order:
+
+                 - External oscillator
+                 - DSI0 byte clock
+                 - DSI0 DDR2 clock
+                 - DSI0 DDR clock
+                 - DSI1 byte clock
+                 - DSI1 DDR2 clock
+                 - DSI1 DDR clock
+
+                 Only external oscillator is required.  The DSI clocks may
+                 not be present, in which case their children will be
+                 unusable.
 
 Example:
 
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);
index 360e00cefd35679b49890234b5c369fb52b89e20..a0c812b0fa391d149b4f546db39bdc4bef207960 100644 (file)
@@ -64,3 +64,5 @@
 #define BCM2835_CLOCK_CAM1             46
 #define BCM2835_CLOCK_DSI0E            47
 #define BCM2835_CLOCK_DSI1E            48
+#define BCM2835_CLOCK_DSI0P            49
+#define BCM2835_CLOCK_DSI1P            50