linux-clk.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/5] cpufreq support for the Raspberry Pi
@ 2019-05-17 15:35 Nicolas Saenz Julienne
  2019-05-17 15:35 ` [RFC 1/5] clk: bcm2835: set CLK_GET_RATE_NOCACHE on CPU clocks Nicolas Saenz Julienne
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Nicolas Saenz Julienne @ 2019-05-17 15:35 UTC (permalink / raw)
  To: stefan.wahren, devicetree, linux-rpi-kernel, linux-arm-kernel, linux-pm
  Cc: mbrugger, viresh.kumar, rjw, sboyd, eric, f.fainelli,
	bcm-kernel-feedback-list, ptesarik, Nicolas Saenz Julienne,
	linux-kernel, linux-clk

Hi all,
as some of you may recall I've been spending some time looking into
providing 'cpufreq' support for the Raspberry Pi platform[1]. I think
I'm close to something workable, so I'd love for you to comment on it.

There has been some design changes since the last version. Namely the
fact that I now make sure *only* the CPU frequency is updated. The
firmware API we use has two modes, with or without turbo. Enabling turbo
implies not only scaling the CPU clock but also the VPU and other
peripheral related clocks.  This is problematic as some of them are not
prepared for this kind frequency changes. I spent some time adapting the
peripheral drivers, but the result was disappointing as they poorly
support live frequency changes (which most other chips accept, think for
instance I2C and clock stretching) but also turned out hard to integrate
into the kernel. As we were planning to use 'clk_notifiers' which turns
out not to be such a good idea as it's prone to deadlocks and not
recommended by the clock maintainers[2]. It's also worth mentioning that
the foundation kernel doesn't support VPU frequency scaling either.

With this in mind, and as suggested by clock maintainers[2], I've
decided to integrate the firmware clock interface into the bcm2835 clock
driver. This, in my opinion, provides the least friction with the
firmware and lets us write very simple and portable higher level
drivers. As I did with the 'cpufreq' driver which simply queries the max
and min frequencies available, which are configurable in the firmware,
to then trigger the generic 'cpufreq-dt'.

In the future we could further integrate other firmware dependent clocks
into the main driver. For instance to be able to scale the VPU clock,
which should be operated through a 'devfreq' driver.

This was tested on a RPi3b+ and if the series is well received I'll test
it further on all platforms I own.

That's all,
kind regards,
Nicolas

[1] https://lists.infradead.org/pipermail/linux-rpi-kernel/2019-April/008634.html
[2] https://www.spinics.net/lists/linux-clk/msg36937.html

---

Nicolas Saenz Julienne (5):
  clk: bcm2835: set CLK_GET_RATE_NOCACHE on CPU clocks
  clk: bcm2835: set pllb_arm divisor as readonly
  clk: bcm2835: use firmware interface to update pllb
  dts: bcm2837: add per-cpu clock devices
  cpufreq: add driver for Raspbery Pi

 arch/arm/boot/dts/bcm2837.dtsi        |   8 +
 drivers/clk/bcm/clk-bcm2835.c         | 284 ++++++++++++++++++++++++--
 drivers/cpufreq/Kconfig.arm           |   8 +
 drivers/cpufreq/Makefile              |   1 +
 drivers/cpufreq/raspberrypi-cpufreq.c |  79 +++++++
 5 files changed, 362 insertions(+), 18 deletions(-)
 create mode 100644 drivers/cpufreq/raspberrypi-cpufreq.c

-- 
2.21.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [RFC 1/5] clk: bcm2835: set CLK_GET_RATE_NOCACHE on CPU clocks
  2019-05-17 15:35 [RFC 0/5] cpufreq support for the Raspberry Pi Nicolas Saenz Julienne
@ 2019-05-17 15:35 ` Nicolas Saenz Julienne
  2019-05-17 15:35 ` [RFC 2/5] clk: bcm2835: set pllb_arm divisor as readonly Nicolas Saenz Julienne
  2019-05-17 15:35 ` [RFC 3/5] clk: bcm2835: use firmware interface to update pllb Nicolas Saenz Julienne
  2 siblings, 0 replies; 4+ messages in thread
From: Nicolas Saenz Julienne @ 2019-05-17 15:35 UTC (permalink / raw)
  To: stefan.wahren, Florian Fainelli, Ray Jui, Scott Branden,
	bcm-kernel-feedback-list, Eric Anholt
  Cc: mbrugger, viresh.kumar, rjw, sboyd, ptesarik, linux-rpi-kernel,
	Nicolas Saenz Julienne, Michael Turquette, linux-clk,
	linux-arm-kernel, linux-kernel

Raspberry Pi's firmware is responsible for updating the cpu clocks and
pll. This makes sure we get the right rates anytime.

Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
 drivers/clk/bcm/clk-bcm2835.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 770bb01f523e..c2772dfb155a 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -411,6 +411,7 @@ struct bcm2835_pll_data {
 	u32 reference_enable_mask;
 	/* Bit in CM_LOCK to indicate when the PLL has locked. */
 	u32 lock_mask;
+	u32 flags;
 
 	const struct bcm2835_pll_ana_bits *ana;
 
@@ -1299,7 +1300,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
 	init.num_parents = 1;
 	init.name = data->name;
 	init.ops = &bcm2835_pll_clk_ops;
-	init.flags = CLK_IGNORE_UNUSED;
+	init.flags = data->flags | CLK_IGNORE_UNUSED;
 
 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 	if (!pll)
@@ -1660,6 +1661,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
 		.ana_reg_base = A2W_PLLB_ANA0,
 		.reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
 		.lock_mask = CM_LOCK_FLOCKB,
+		.flags = CLK_GET_RATE_NOCACHE,
 
 		.ana = &bcm2835_ana_default,
 
@@ -1674,7 +1676,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
 		.load_mask = CM_PLLB_LOADARM,
 		.hold_mask = CM_PLLB_HOLDARM,
 		.fixed_divider = 1,
-		.flags = CLK_SET_RATE_PARENT),
+		.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE),
 
 	/*
 	 * PLLC is the core PLL, used to drive the core VPU clock.
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [RFC 2/5] clk: bcm2835: set pllb_arm divisor as readonly
  2019-05-17 15:35 [RFC 0/5] cpufreq support for the Raspberry Pi Nicolas Saenz Julienne
  2019-05-17 15:35 ` [RFC 1/5] clk: bcm2835: set CLK_GET_RATE_NOCACHE on CPU clocks Nicolas Saenz Julienne
@ 2019-05-17 15:35 ` Nicolas Saenz Julienne
  2019-05-17 15:35 ` [RFC 3/5] clk: bcm2835: use firmware interface to update pllb Nicolas Saenz Julienne
  2 siblings, 0 replies; 4+ messages in thread
From: Nicolas Saenz Julienne @ 2019-05-17 15:35 UTC (permalink / raw)
  To: stefan.wahren, Florian Fainelli, Ray Jui, Scott Branden,
	bcm-kernel-feedback-list, Eric Anholt
  Cc: mbrugger, viresh.kumar, rjw, sboyd, ptesarik, linux-rpi-kernel,
	Nicolas Saenz Julienne, Michael Turquette, linux-clk,
	linux-arm-kernel, linux-kernel

This divisor is controlled by the firmware, we don't want the clock
subsystem to update it inadvertently.

Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
 drivers/clk/bcm/clk-bcm2835.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index c2772dfb155a..5aea110672f3 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -465,6 +465,7 @@ struct bcm2835_pll_divider_data {
 	u32 hold_mask;
 	u32 fixed_divider;
 	u32 flags;
+	u32 div_flags;
 };
 
 struct bcm2835_clock_data {
@@ -1349,7 +1350,7 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
 	divider->div.reg = cprman->regs + data->a2w_reg;
 	divider->div.shift = A2W_PLL_DIV_SHIFT;
 	divider->div.width = A2W_PLL_DIV_BITS;
-	divider->div.flags = CLK_DIVIDER_MAX_AT_ZERO;
+	divider->div.flags = data->div_flags | CLK_DIVIDER_MAX_AT_ZERO;
 	divider->div.lock = &cprman->regs_lock;
 	divider->div.hw.init = &init;
 	divider->div.table = NULL;
@@ -1676,7 +1677,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
 		.load_mask = CM_PLLB_LOADARM,
 		.hold_mask = CM_PLLB_HOLDARM,
 		.fixed_divider = 1,
-		.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE),
+		.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+		.div_flags = CLK_DIVIDER_READ_ONLY),
 
 	/*
 	 * PLLC is the core PLL, used to drive the core VPU clock.
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [RFC 3/5] clk: bcm2835: use firmware interface to update pllb
  2019-05-17 15:35 [RFC 0/5] cpufreq support for the Raspberry Pi Nicolas Saenz Julienne
  2019-05-17 15:35 ` [RFC 1/5] clk: bcm2835: set CLK_GET_RATE_NOCACHE on CPU clocks Nicolas Saenz Julienne
  2019-05-17 15:35 ` [RFC 2/5] clk: bcm2835: set pllb_arm divisor as readonly Nicolas Saenz Julienne
@ 2019-05-17 15:35 ` Nicolas Saenz Julienne
  2 siblings, 0 replies; 4+ messages in thread
From: Nicolas Saenz Julienne @ 2019-05-17 15:35 UTC (permalink / raw)
  To: stefan.wahren, Florian Fainelli, Ray Jui, Scott Branden,
	bcm-kernel-feedback-list, Eric Anholt
  Cc: mbrugger, viresh.kumar, rjw, sboyd, ptesarik, linux-rpi-kernel,
	Nicolas Saenz Julienne, Michael Turquette, linux-clk,
	linux-arm-kernel, linux-kernel

Raspberry Pi's firmware, which runs in a dedicated processor, keeps
track of the board's temperature and voltage. It's resposible for
scaling the CPU frequency whenever it deems the device reached an unsafe
state. On top of that the firmware provides an interface which allows
Linux to to query the clock's state or change it's frequency.

Being the sole user of the bcm2835 clock driver, this integrates the
firmware interface into the clock driver and adds a first user: the CPU
pll, also known as 'pllb'.

Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
 drivers/clk/bcm/clk-bcm2835.c | 274 ++++++++++++++++++++++++++++++++--
 1 file changed, 259 insertions(+), 15 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 5aea110672f3..ce5b16f3704e 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -35,6 +35,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
 
@@ -289,6 +290,30 @@
 #define LOCK_TIMEOUT_NS		100000000
 #define BCM2835_MAX_FB_RATE	1750000000u
 
+#define RPI_FIRMWARE_ARM_CLK_ID		0x000000003
+#define RPI_FIRMWARE_STATE_ENABLE_BIT	0x1
+#define RPI_FIRMWARE_STATE_WAIT_BIT	0x2
+
+/*
+ * Structure of the message passed to Raspberry Pi's firmware in order to
+ * change clock rates. The 'disable_turbo' option is only available to the ARM
+ * clock (pllb) which we enable by default as turbo mode will alter multiple
+ * clocks at once.
+ *
+ * Even though we're able to access the clock registers directly we're bound to
+ * use the firmware interface as the firmware ultimately takes care of
+ * mitigating overheating/undervoltage situations and we would be changing
+ * frequencies behind his back.
+ *
+ * For more information on the firmware interface check:
+ * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
+ */
+struct bcm2835_firmware_prop {
+       u32 id;
+       u32 val;
+       u32 disable_turbo;
+} __packed;
+
 /*
  * 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
@@ -316,6 +341,8 @@ struct bcm2835_cprman {
 	 */
 	const char *real_parent_names[ARRAY_SIZE(cprman_parent_names)];
 
+	struct rpi_firmware *firmware;
+
 	/* Must be last */
 	struct clk_hw_onecell_data onecell;
 };
@@ -424,6 +451,23 @@ struct bcm2835_pll_data {
 	unsigned long max_fb_rate;
 };
 
+struct bcm2835_fw_pll_data {
+	const char *name;
+	int firmware_clk_id;
+	u32 flags;
+
+	unsigned long min_rate;
+	unsigned long max_rate;
+
+	/*
+	 * The rate provided to the firmware interface might not always match
+	 * the clock subsystem's. For instance, in the case of the ARM cpu
+	 * clock, even though the firmware ultimately edits 'pllb' it takes the
+	 * expected 'pllb_arm' rate as it's input.
+	 */
+	unsigned int rate_rescale;
+};
+
 struct bcm2835_pll_ana_bits {
 	u32 mask0;
 	u32 set0;
@@ -505,6 +549,7 @@ struct bcm2835_pll {
 	struct clk_hw hw;
 	struct bcm2835_cprman *cprman;
 	const struct bcm2835_pll_data *data;
+	const struct bcm2835_fw_pll_data *fw_data;
 };
 
 static int bcm2835_pll_is_on(struct clk_hw *hw)
@@ -517,6 +562,41 @@ static int bcm2835_pll_is_on(struct clk_hw *hw)
 		A2W_PLL_CTRL_PRST_DISABLE;
 }
 
+static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
+				      u32 clk, u32 *val)
+{
+	int ret;
+	struct bcm2835_firmware_prop msg = {
+		.id = clk,
+		.val = *val,
+		.disable_turbo = 1,
+	};
+
+	ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
+	if (ret)
+		return ret;
+
+	*val = msg.val;
+
+	return 0;
+}
+
+static int bcm2835_fw_pll_is_on(struct clk_hw *hw)
+{
+	struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
+	struct bcm2835_cprman *cprman = pll->cprman;
+	u32 val = 0;
+	int ret;
+
+	ret = raspberrypi_clock_property(cprman->firmware,
+					 RPI_FIRMWARE_GET_CLOCK_STATE,
+					 pll->fw_data->firmware_clk_id, &val);
+	if (ret)
+		return 0;
+
+	return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
+}
+
 static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate,
 					     unsigned long parent_rate,
 					     u32 *ndiv, u32 *fdiv)
@@ -547,16 +627,37 @@ 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);
+	if (pll->data)
+		rate = clamp(rate, pll->data->min_rate, pll->data->max_rate);
+	else
+		rate = clamp(rate, pll->fw_data->min_rate,
+			     pll->fw_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);
 }
 
+static unsigned long bcm2835_fw_pll_get_rate(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
+	struct bcm2835_cprman *cprman = pll->cprman;
+	u32 val = 0;
+	int ret;
+
+	ret = raspberrypi_clock_property(cprman->firmware,
+					 RPI_FIRMWARE_GET_CLOCK_RATE,
+					 pll->fw_data->firmware_clk_id,
+					 &val);
+	if (ret)
+		return ret;
+
+	return val * pll->fw_data->rate_rescale;
+}
+
 static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw,
 					  unsigned long parent_rate)
 {
@@ -584,6 +685,35 @@ static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw,
 	return bcm2835_pll_rate_from_divisors(parent_rate, ndiv, fdiv, pdiv);
 }
 
+static int bcm2835_fw_pll_on(struct clk_hw *hw)
+{
+	struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
+	struct bcm2835_cprman *cprman = pll->cprman;
+	u32 val;
+	int ret;
+
+	val = RPI_FIRMWARE_STATE_ENABLE_BIT | RPI_FIRMWARE_STATE_WAIT_BIT;
+
+	ret = raspberrypi_clock_property(cprman->firmware,
+					 RPI_FIRMWARE_SET_CLOCK_STATE,
+					 pll->fw_data->firmware_clk_id, &val);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void bcm2835_fw_pll_off(struct clk_hw *hw)
+{
+	struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
+	struct bcm2835_cprman *cprman = pll->cprman;
+	u32 val = RPI_FIRMWARE_STATE_WAIT_BIT;
+
+	raspberrypi_clock_property(cprman->firmware,
+				   RPI_FIRMWARE_SET_CLOCK_STATE,
+				   pll->fw_data->firmware_clk_id, &val);
+}
+
 static void bcm2835_pll_off(struct clk_hw *hw)
 {
 	struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
@@ -651,6 +781,25 @@ bcm2835_pll_write_ana(struct bcm2835_cprman *cprman, u32 ana_reg_base, u32 *ana)
 		cprman_write(cprman, ana_reg_base + i * 4, ana[i]);
 }
 
+static int bcm2835_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
+	u32 new_rate = rate / pll->fw_data->rate_rescale;
+	struct bcm2835_cprman *cprman = pll->cprman;
+	int ret;
+
+	ret = raspberrypi_clock_property(cprman->firmware,
+					 RPI_FIRMWARE_SET_CLOCK_RATE,
+					 pll->fw_data->firmware_clk_id,
+					 &new_rate);
+	if (ret)
+		dev_err(cprman->dev, "Failed to change %s frequency: %d",
+			clk_hw_get_name(hw), ret);
+
+	return ret;
+}
+
 static int bcm2835_pll_set_rate(struct clk_hw *hw,
 				unsigned long rate, unsigned long parent_rate)
 {
@@ -759,6 +908,15 @@ static const struct clk_ops bcm2835_pll_clk_ops = {
 	.debug_init = bcm2835_pll_debug_init,
 };
 
+static const struct clk_ops bcm2835_firmware_pll_clk_ops = {
+	.is_prepared = bcm2835_fw_pll_is_on,
+	.prepare = bcm2835_fw_pll_on,
+	.unprepare = bcm2835_fw_pll_off,
+	.recalc_rate = bcm2835_fw_pll_get_rate,
+	.set_rate = bcm2835_fw_pll_set_rate,
+	.round_rate = bcm2835_pll_round_rate,
+};
+
 struct bcm2835_pll_divider {
 	struct clk_divider div;
 	struct bcm2835_cprman *cprman;
@@ -1287,6 +1445,83 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
 	.debug_init = bcm2835_clock_debug_init,
 };
 
+static int bcm2835_firmware_get_min_max_rates(struct bcm2835_cprman *cprman,
+					      struct bcm2835_fw_pll_data *data)
+{
+	u32 min_rate = 0, max_rate = 0;
+	int ret;
+
+	ret = raspberrypi_clock_property(cprman->firmware,
+					 RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
+					 data->firmware_clk_id,
+					 &min_rate);
+	if (ret) {
+		dev_err(cprman->dev, "Failed to get %s min freq: %d\n",
+			data->name, ret);
+		return ret;
+	}
+
+	ret = raspberrypi_clock_property(cprman->firmware,
+					 RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+					 data->firmware_clk_id,
+					 &max_rate);
+	if (ret) {
+		dev_err(cprman->dev, "Failed to get %s max freq: %d\n",
+			data->name, ret);
+		return ret;
+	}
+
+	data->min_rate = min_rate * data->rate_rescale;
+	data->max_rate = max_rate * data->rate_rescale;
+
+	dev_info(cprman->dev, "min %lu, max %lu\n", data->min_rate, data->max_rate);
+	return 0;
+}
+
+static struct clk_hw *bcm2835_register_fw_pll(struct bcm2835_cprman *cprman,
+					const struct bcm2835_fw_pll_data *data)
+{
+	struct bcm2835_fw_pll_data *fw_data;
+	struct clk_init_data init;
+	struct bcm2835_pll *pll;
+	int ret;
+
+	memset(&init, 0, sizeof(init));
+
+	/* All of the PLLs derive from the external oscillator. */
+	init.parent_names = &cprman->real_parent_names[0];
+	init.num_parents = 1;
+	init.name = data->name;
+	init.ops = &bcm2835_firmware_pll_clk_ops;
+	init.flags = data->flags | CLK_IGNORE_UNUSED;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return NULL;
+
+	/*
+	 * As the max and min rate values are firmware dependent we need a non
+	 * constant version of struct bcm2835_fw_pll_data.
+	 */
+	fw_data = devm_kmemdup(cprman->dev, data, sizeof(*data),
+				     GFP_KERNEL);
+	if (!fw_data)
+		return NULL;
+
+	ret = bcm2835_firmware_get_min_max_rates(cprman, fw_data);
+	if (ret)
+		return NULL;
+
+	pll->cprman = cprman;
+	pll->hw.init = &init;
+	pll->fw_data = fw_data;
+
+	ret = devm_clk_hw_register(cprman->dev, &pll->hw);
+	if (ret)
+		return NULL;
+	return &pll->hw;
+}
+
 static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
 					   const struct bcm2835_pll_data *data)
 {
@@ -1462,6 +1697,9 @@ struct bcm2835_clk_desc {
 #define REGISTER_PLL(...)	_REGISTER(&bcm2835_register_pll,	\
 					  &(struct bcm2835_pll_data)	\
 					  {__VA_ARGS__})
+#define REGISTER_FW_PLL(...)	_REGISTER(&bcm2835_register_fw_pll,	\
+					  &(struct bcm2835_fw_pll_data)	\
+					  {__VA_ARGS__})
 #define REGISTER_PLL_DIV(...)	_REGISTER(&bcm2835_register_pll_divider, \
 					  &(struct bcm2835_pll_divider_data) \
 					  {__VA_ARGS__})
@@ -1654,21 +1892,11 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
 		.flags = CLK_SET_RATE_PARENT),
 
 	/* PLLB is used for the ARM's clock. */
-	[BCM2835_PLLB]		= REGISTER_PLL(
+	[BCM2835_PLLB]		= REGISTER_FW_PLL(
 		.name = "pllb",
-		.cm_ctrl_reg = CM_PLLB,
-		.a2w_ctrl_reg = A2W_PLLB_CTRL,
-		.frac_reg = A2W_PLLB_FRAC,
-		.ana_reg_base = A2W_PLLB_ANA0,
-		.reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
-		.lock_mask = CM_LOCK_FLOCKB,
 		.flags = CLK_GET_RATE_NOCACHE,
-
-		.ana = &bcm2835_ana_default,
-
-		.min_rate = 600000000u,
-		.max_rate = 3000000000u,
-		.max_fb_rate = BCM2835_MAX_FB_RATE),
+		.rate_rescale = 2,
+		.firmware_clk_id = RPI_FIRMWARE_ARM_CLK_ID),
 	[BCM2835_PLLB_ARM]	= REGISTER_PLL_DIV(
 		.name = "pllb_arm",
 		.source_pll = "pllb",
@@ -2133,9 +2361,24 @@ 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 *firmware_node;
+	struct rpi_firmware *firmware;
 	size_t i;
 	int ret;
 
+	firmware_node = of_find_node_by_name(NULL, "firmware");
+	if (!firmware_node) {
+		dev_err(dev, "Missing firmware node\n");
+		return -ENOENT;
+	}
+
+	firmware = rpi_firmware_get(firmware_node);
+	of_node_put(firmware_node);
+	if (!firmware) {
+		dev_err(dev, "Can't get raspberrypi's firmware\n");
+		return -EPROBE_DEFER;
+	}
+
 	cprman = devm_kzalloc(dev,
 			      struct_size(cprman, onecell.hws, asize),
 			      GFP_KERNEL);
@@ -2144,6 +2387,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
 
 	spin_lock_init(&cprman->regs_lock);
 	cprman->dev = dev;
+	cprman->firmware = firmware;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cprman->regs = devm_ioremap_resource(dev, res);
 	if (IS_ERR(cprman->regs))
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-05-17 15:35 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-17 15:35 [RFC 0/5] cpufreq support for the Raspberry Pi Nicolas Saenz Julienne
2019-05-17 15:35 ` [RFC 1/5] clk: bcm2835: set CLK_GET_RATE_NOCACHE on CPU clocks Nicolas Saenz Julienne
2019-05-17 15:35 ` [RFC 2/5] clk: bcm2835: set pllb_arm divisor as readonly Nicolas Saenz Julienne
2019-05-17 15:35 ` [RFC 3/5] clk: bcm2835: use firmware interface to update pllb Nicolas Saenz Julienne

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).