]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - drivers/clk/bcm/clk-bcm2835.c
clk: bcm2835: Don't rate change PLLs on behalf of DSI PLL dividers.
[mirror_ubuntu-zesty-kernel.git] / drivers / clk / bcm / clk-bcm2835.c
index 0d14409097e777ce4546de30e9278fdebf74ec44..3acf61ddeda8c27e6da0fd7e2beb46341679eb66 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <dt-bindings/clock/bcm2835.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
 
 #define CM_PASSWORD            0x5a000000
 
 #define LOCK_TIMEOUT_NS                100000000
 #define BCM2835_MAX_FB_RATE    1750000000u
 
+#define VCMSG_ID_CORE_CLOCK     4
+
 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;
 
@@ -428,6 +432,7 @@ struct bcm2835_pll_divider_data {
        u32 load_mask;
        u32 hold_mask;
        u32 fixed_divider;
+       u32 flags;
 };
 
 struct bcm2835_clock_data {
@@ -535,8 +540,10 @@ static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw,
        using_prediv = cprman_read(cprman, data->ana_reg_base + 4) &
                data->ana->fb_prediv_mask;
 
-       if (using_prediv)
+       if (using_prediv) {
                ndiv *= 2;
+               fdiv *= 2;
+       }
 
        return bcm2835_pll_rate_from_divisors(parent_rate, ndiv, fdiv, pdiv);
 }
@@ -934,6 +941,30 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
        return bcm2835_clock_rate_from_divisor(clock, parent_rate, div);
 }
 
+static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+       struct bcm2835_cprman *cprman = clock->cprman;
+
+       if (cprman->fw) {
+               struct {
+                       u32 id;
+                       u32 val;
+               } packet;
+
+               packet.id = VCMSG_ID_CORE_CLOCK;
+               packet.val = 0;
+
+               if (!rpi_firmware_property(cprman->fw,
+                                          RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+                                          &packet, sizeof(packet)))
+                       return packet.val;
+       }
+
+       return bcm2835_clock_get_rate(hw, parent_rate);
+}
+
 static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock)
 {
        struct bcm2835_cprman *cprman = clock->cprman;
@@ -1190,7 +1221,7 @@ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
  */
 static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
        .is_prepared = bcm2835_vpu_clock_is_on,
-       .recalc_rate = bcm2835_clock_get_rate,
+       .recalc_rate = bcm2835_clock_get_rate_vpu,
        .set_rate = bcm2835_clock_set_rate,
        .determine_rate = bcm2835_clock_determine_rate,
        .set_parent = bcm2835_clock_set_parent,
@@ -1198,6 +1229,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
        .debug_init = bcm2835_clock_debug_init,
 };
 
+static bool bcm2835_clk_is_claimed(const char *name);
+
 static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
                                           const struct bcm2835_pll_data *data)
 {
@@ -1214,6 +1247,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
        init.ops = &bcm2835_pll_clk_ops;
        init.flags = CLK_IGNORE_UNUSED;
 
+       if (!bcm2835_clk_is_claimed(data->name))
+               init.flags |= CLK_IS_CRITICAL;
+
        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
        if (!pll)
                return NULL;
@@ -1252,7 +1288,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)
@@ -1266,6 +1302,13 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
        divider->div.hw.init = &init;
        divider->div.table = NULL;
 
+       if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) {
+               if (!bcm2835_clk_is_claimed(data->source_pll))
+                       init.flags |= CLK_IS_CRITICAL;
+               if (!bcm2835_clk_is_claimed(data->name))
+                       divider->div.flags |= CLK_IS_CRITICAL;
+       }
+
        divider->cprman = cprman;
        divider->data = data;
 
@@ -1314,6 +1357,15 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
        init.name = data->name;
        init.flags = data->flags | CLK_IGNORE_UNUSED;
 
+       /*
+        * Some GPIO clocks for ethernet/wifi PLLs are marked as
+        * critical (since some platforms use them), but if the
+        * firmware didn't have them turned on then they clearly
+        * aren't actually critical.
+        */
+       if ((cprman_read(cprman, data->ctl_reg) & CM_ENABLE) == 0)
+               init.flags &= ~CLK_IS_CRITICAL;
+
        /*
         * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
         * rate changes on at least of the parents.
@@ -1466,7 +1518,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 +1527,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 +1544,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 +1569,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 +1599,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 +1608,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 +1617,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 +1626,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 +1656,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 +1665,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 +1711,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 +1720,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 +1729,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 */
 
@@ -1896,6 +1961,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .ctl_reg = CM_PERIICTL),
 };
 
+static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)];
+
 /*
  * Permanently take a reference on the parent of the SDRAM clock.
  *
@@ -1915,6 +1982,19 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc)
        return clk_prepare_enable(parent);
 }
 
+static bool bcm2835_clk_is_claimed(const char *name)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) {
+               const char *clk_name = *(const char **)(clk_desc_array[i].data);
+               if (!strcmp(name, clk_name))
+                   return bcm2835_clk_claimed[i];
+       }
+
+       return false;
+}
+
 static int bcm2835_clk_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1923,7 +2003,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
        struct resource *res;
        const struct bcm2835_clk_desc *desc;
        const size_t asize = ARRAY_SIZE(clk_desc_array);
+       struct device_node *fw_node;
        size_t i;
+       u32 clk_id;
        int ret;
 
        cprman = devm_kzalloc(dev, sizeof(*cprman) +
@@ -1939,6 +2021,21 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
        if (IS_ERR(cprman->regs))
                return PTR_ERR(cprman->regs);
 
+       fw_node = of_parse_phandle(dev->of_node, "firmware", 0);
+       if (fw_node) {
+               struct rpi_firmware *fw = rpi_firmware_get(NULL);
+               if (!fw)
+                       return -EPROBE_DEFER;
+               cprman->fw = fw;
+       }
+
+       memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed));
+       for (i = 0;
+            !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks",
+                                        i, &clk_id);
+            i++)
+               bcm2835_clk_claimed[clk_id]= true;
+
        cprman->osc_name = of_clk_get_parent_name(dev->of_node, 0);
        if (!cprman->osc_name)
                return -ENODEV;
@@ -1958,8 +2055,15 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
+       ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
                                      &cprman->onecell);
+       if (ret)
+               return ret;
+
+       /* note that we have registered all the clocks */
+       dev_dbg(dev, "registered %d clocks\n", asize);
+
+       return 0;
 }
 
 static const struct of_device_id bcm2835_clk_of_match[] = {
@@ -1976,7 +2080,11 @@ static struct platform_driver bcm2835_clk_driver = {
        .probe          = bcm2835_clk_probe,
 };
 
-builtin_platform_driver(bcm2835_clk_driver);
+static int __init __bcm2835_clk_driver_init(void)
+{
+       return platform_driver_register(&bcm2835_clk_driver);
+}
+core_initcall(__bcm2835_clk_driver_init);
 
 MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
 MODULE_DESCRIPTION("BCM2835 clock driver");