summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin M. Forbes <jforbes@redhat.com>2016-10-24 16:22:14 -0500
committerJustin M. Forbes <jforbes@redhat.com>2016-10-24 16:22:14 -0500
commitd3e1de200c66cd2d2de363d359ea45cb207de835 (patch)
treee894c57e70b9f8a0f368cd792c5852960b007b38
parente4b3d2ead04685e1f0f39096a2322c9e4ee56db9 (diff)
downloadkernel-d3e1de200c66cd2d2de363d359ea45cb207de835.tar.gz
kernel-d3e1de200c66cd2d2de363d359ea45cb207de835.tar.xz
kernel-d3e1de200c66cd2d2de363d359ea45cb207de835.zip
A collection of other clock fixes in -next for the RPi
-rw-r--r--bcm283x-vc4-fixes.patch311
1 files changed, 311 insertions, 0 deletions
diff --git a/bcm283x-vc4-fixes.patch b/bcm283x-vc4-fixes.patch
index 89793b62b..afde6e2f2 100644
--- a/bcm283x-vc4-fixes.patch
+++ b/bcm283x-vc4-fixes.patch
@@ -634,3 +634,314 @@ index 9ecd6ff..a4b5370 100644
--
2.9.3
+From c4e634ce412d97f0e61223b2a5b3f8f9600cd4dc Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 30 Sep 2016 10:07:27 -0700
+Subject: clk: bcm2835: Clamp the PLL's requested rate to the hardware limits.
+
+Fixes setting low-resolution video modes on HDMI. Now the PLLH_PIX
+divider adjusts itself until the PLLH is within bounds.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index b68bf57..8c7763f 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -502,8 +502,12 @@ static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate,
+ static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+ {
++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
++ const struct bcm2835_pll_data *data = pll->data;
+ u32 ndiv, fdiv;
+
++ rate = clamp(rate, data->min_rate, data->max_rate);
++
+ bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv);
+
+ return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1);
+@@ -608,13 +612,6 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
+ u32 ana[4];
+ int i;
+
+- if (rate < data->min_rate || rate > data->max_rate) {
+- dev_err(cprman->dev, "%s: rate out of spec: %lu vs (%lu, %lu)\n",
+- clk_hw_get_name(hw), rate,
+- data->min_rate, data->max_rate);
+- return -EINVAL;
+- }
+-
+ if (rate > data->max_fb_rate) {
+ use_fb_prediv = true;
+ rate /= 2;
+--
+cgit v0.12
+
+From e69fdcca836f0b81a2260b69429c8622a80ea891 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 1 Jun 2016 12:05:33 -0700
+Subject: clk: bcm2835: Mark the VPU clock as critical
+
+The VPU clock is also the clock for our AXI bus, so we really can't
+disable it. This might have happened during boot if, for example,
+uart1 (aux_uart clock) probed and was then disabled before the other
+consumers of the VPU clock had probed.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index 7a79708..d9db03c 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -443,6 +443,8 @@ struct bcm2835_clock_data {
+ /* Number of fractional bits in the divider */
+ u32 frac_bits;
+
++ u32 flags;
++
+ bool is_vpu_clock;
+ bool is_mash_clock;
+ };
+@@ -1230,7 +1232,7 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
+ init.parent_names = parents;
+ init.num_parents = data->num_mux_parents;
+ init.name = data->name;
+- init.flags = CLK_IGNORE_UNUSED;
++ init.flags = data->flags | CLK_IGNORE_UNUSED;
+
+ if (data->is_vpu_clock) {
+ init.ops = &bcm2835_vpu_clock_clk_ops;
+@@ -1649,6 +1651,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
+ .div_reg = CM_VPUDIV,
+ .int_bits = 12,
+ .frac_bits = 8,
++ .flags = CLK_IS_CRITICAL,
+ .is_vpu_clock = true),
+
+ /* clocks with per parent mux */
+--
+cgit v0.12
+
+From eddcbe8398fc7103fccd22aa6df6917caf0123bf Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 1 Jun 2016 12:05:34 -0700
+Subject: clk: bcm2835: Mark GPIO clocks enabled at boot as critical
+
+These divide off of PLLD_PER and are used for the ethernet and wifi
+PHYs source PLLs. Neither of them is currently represented by a phy
+device that would grab the clock for us.
+
+This keeps other drivers from killing the networking PHYs when they
+disable their own clocks and trigger PLLD_PER's refcount going to 0.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index d9db03c..400615b 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1239,6 +1239,12 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
+ } else {
+ init.ops = &bcm2835_clock_clk_ops;
+ init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
++
++ /* If the clock wasn't actually enabled at boot, it's not
++ * critical.
++ */
++ if (!(cprman_read(cprman, data->ctl_reg) & CM_ENABLE))
++ init.flags &= ~CLK_IS_CRITICAL;
+ }
+
+ clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL);
+@@ -1708,13 +1714,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
+ .div_reg = CM_GP1DIV,
+ .int_bits = 12,
+ .frac_bits = 12,
++ .flags = CLK_IS_CRITICAL,
+ .is_mash_clock = true),
+ [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
+ .name = "gp2",
+ .ctl_reg = CM_GP2CTL,
+ .div_reg = CM_GP2DIV,
+ .int_bits = 12,
+- .frac_bits = 12),
++ .frac_bits = 12,
++ .flags = CLK_IS_CRITICAL),
+
+ /* HDMI state machine */
+ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
+--
+cgit v0.12
+
+From 9e400c5cc5c105e35216ac59a346f20cdd7613be Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 1 Jun 2016 12:05:35 -0700
+Subject: clk: bcm2835: Mark the CM SDRAM clock's parent as critical
+
+While the SDRAM is being driven by its dedicated PLL most of the time,
+there is a little loop running in the firmware that periodically turns
+on the CM SDRAM clock (using its pre-initialized parent) and switches
+SDRAM to using the CM clock to do PVT recalibration.
+
+This avoids system hangs if we choose SDRAM's parent for some other
+clock, then disable that clock.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index 400615b..c6420b3 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -36,6 +36,7 @@
+
+ #include <linux/clk-provider.h>
+ #include <linux/clkdev.h>
++#include <linux/clk.h>
+ #include <linux/clk/bcm2835.h>
+ #include <linux/debugfs.h>
+ #include <linux/module.h>
+@@ -1801,6 +1802,25 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
+ .ctl_reg = CM_PERIICTL),
+ };
+
++/*
++ * Permanently take a reference on the parent of the SDRAM clock.
++ *
++ * While the SDRAM is being driven by its dedicated PLL most of the
++ * time, there is a little loop running in the firmware that
++ * periodically switches the SDRAM to using our CM clock to do PVT
++ * recalibration, with the assumption that the previously configured
++ * SDRAM parent is still enabled and running.
++ */
++static int bcm2835_mark_sdc_parent_critical(struct clk *sdc)
++{
++ struct clk *parent = clk_get_parent(sdc);
++
++ if (IS_ERR(parent))
++ return PTR_ERR(parent);
++
++ return clk_prepare_enable(parent);
++}
++
+ static int bcm2835_clk_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -1810,6 +1830,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ const struct bcm2835_clk_desc *desc;
+ const size_t asize = ARRAY_SIZE(clk_desc_array);
+ size_t i;
++ int ret;
+
+ cprman = devm_kzalloc(dev,
+ sizeof(*cprman) + asize * sizeof(*clks),
+@@ -1840,6 +1861,10 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ clks[i] = desc->clk_register(cprman, desc->data);
+ }
+
++ ret = bcm2835_mark_sdc_parent_critical(clks[BCM2835_CLOCK_SDRAM]);
++ if (ret)
++ return ret;
++
+ return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+ &cprman->onecell);
+ }
+--
+cgit v0.12
+
+From 67615c588a059b731df9d019edc3c561d8006ec9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 1 Jun 2016 12:05:36 -0700
+Subject: clk: bcm2835: Skip PLLC clocks when deciding on a new clock parent
+
+If the firmware had set up a clock to source from PLLC, go along with
+it. But if we're looking for a new parent, we don't want to switch it
+to PLLC because the firmware will force PLLC (and thus the AXI bus
+clock) to different frequencies during over-temp/under-voltage,
+without notification to Linux.
+
+On my system, this moves the Linux-enabled HDMI state machine and DSI1
+escape clock over to plld_per from pllc_per. EMMC still ends up on
+pllc_per, because the firmware had set it up to use that.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks")
+Acked-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index c6420b3..e8a9646a 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1009,16 +1009,28 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
+ return 0;
+ }
+
++static bool
++bcm2835_clk_is_pllc(struct clk_hw *hw)
++{
++ if (!hw)
++ return false;
++
++ return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
++}
++
+ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+ {
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct clk_hw *parent, *best_parent = NULL;
++ bool current_parent_is_pllc;
+ unsigned long rate, best_rate = 0;
+ unsigned long prate, best_prate = 0;
+ size_t i;
+ u32 div;
+
++ current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw));
++
+ /*
+ * Select parent clock that results in the closest but lower rate
+ */
+@@ -1026,6 +1038,17 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+ parent = clk_hw_get_parent_by_index(hw, i);
+ if (!parent)
+ continue;
++
++ /*
++ * Don't choose a PLLC-derived clock as our parent
++ * unless it had been manually set that way. PLLC's
++ * frequency gets adjusted by the firmware due to
++ * over-temp or under-voltage conditions, without
++ * prior notification to our clock consumer.
++ */
++ if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
++ continue;
++
+ prate = clk_hw_get_rate(parent);
+ div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
+ rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
+--
+cgit v0.12
+