2016-12-02 10:50:26 +00:00
|
|
|
From 3dbdbeedb865d12700dae53b59e259ea083e6186 Mon Sep 17 00:00:00 2001
|
2016-09-10 12:54:26 +00:00
|
|
|
From: Eric Anholt <eric@anholt.net>
|
|
|
|
Date: Wed, 1 Jun 2016 12:05:35 -0700
|
|
|
|
Subject: [PATCH] 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>
|
|
|
|
---
|
|
|
|
drivers/clk/bcm/clk-bcm2835.c | 25 +++++++++++++++++++++++++
|
|
|
|
1 file changed, 25 insertions(+)
|
|
|
|
|
|
|
|
--- 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>
|
2017-01-13 21:35:45 +00:00
|
|
|
@@ -1841,6 +1842,25 @@ static const struct bcm2835_clk_desc clk
|
2016-09-10 12:54:26 +00:00
|
|
|
.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;
|
2017-01-13 21:35:45 +00:00
|
|
|
@@ -1850,6 +1870,7 @@ static int bcm2835_clk_probe(struct plat
|
2016-09-10 12:54:26 +00:00
|
|
|
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),
|
2017-01-13 21:35:45 +00:00
|
|
|
@@ -1880,6 +1901,10 @@ static int bcm2835_clk_probe(struct plat
|
2016-09-10 12:54:26 +00:00
|
|
|
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);
|
|
|
|
}
|