mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
To: Stefan Wahren <wahrenst@gmx.net>, linux-kernel@vger.kernel.org
Cc: f.fainelli@gmail.com, ptesarik@suse.com, sboyd@kernel.org,
	viresh.kumar@linaro.org, mturquette@baylibre.com,
	linux-pm@vger.kernel.org, rjw@rjwysocki.net, mbrugger@suse.de,
	eric@anholt.net, bcm-kernel-feedback-list@broadcom.com,
	linux-rpi-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, ssuloev@orpaltech.com
Subject: Re: [PATCH 2/4] clk: bcm283x: add driver interfacing with Raspberry Pi's firmware
Date: Wed, 05 Jun 2019 14:23:22 +0200	[thread overview]
Message-ID: <3455ad811500486a9144bb45a0e0933c533e5b66.camel@suse.de> (raw)
In-Reply-To: <7ff78cd1-3c39-925d-c66c-f7f295fe6d6e@gmx.net>

[-- Attachment #1: Type: text/plain, Size: 8329 bytes --]

Hi Stefan,
thanks for your review.

On Wed, 2019-06-05 at 12:44 +0200, Stefan Wahren wrote:
> Hi Nicolas,
> 
> Am 04.06.19 um 19:32 schrieb Nicolas Saenz Julienne:
> > Raspberry Pi's firmware offers and interface though which update it's
> > clock's frequencies. This is specially useful in order to change the CPU
> > clock (pllb_arm) which is 'owned' by the firmware and we're unable to
> > scale using the register interface.
> > 
> > Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
> > ---
> > 
> > Changes since RFC:
> >   - Moved firmware interface into own driver
> >   - Use of_find_compatible_node()
> >   - Remove error message on rpi_firmware_get() failure
> >   - Ratelimit messages on set_rate() failure
> >   - Use __le32 on firmware interface definition
> > 
> >  drivers/clk/bcm/Makefile          |   1 +
> >  drivers/clk/bcm/clk-raspberrypi.c | 316 ++++++++++++++++++++++++++++++
> >  2 files changed, 317 insertions(+)
> >  create mode 100644 drivers/clk/bcm/clk-raspberrypi.c
> > 
> > diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
> > index 002661d39128..07abe92df9d1 100644
> > --- a/drivers/clk/bcm/Makefile
> > +++ b/drivers/clk/bcm/Makefile
> > @@ -7,6 +7,7 @@ obj-$(CONFIG_CLK_BCM_KONA)	+= clk-bcm21664.o
> >  obj-$(CONFIG_COMMON_CLK_IPROC)	+= clk-iproc-armpll.o clk-iproc-pll.o
> > clk-iproc-asiu.o
> >  obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o
> >  obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835-aux.o
> > +obj-$(CONFIG_ARCH_BCM2835)	+= clk-raspberrypi.o
> Hm, on the one side it would be nice to avoid building this driver in
> case the firmware driver is disabled on the other side it would be good
> to keep compile test.
> >  obj-$(CONFIG_ARCH_BCM_53573)	+= clk-bcm53573-ilp.o
> >  obj-$(CONFIG_CLK_BCM_CYGNUS)	+= clk-cygnus.o
> >  obj-$(CONFIG_CLK_BCM_HR2)	+= clk-hr2.o
> > diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-
> > raspberrypi.c
> > new file mode 100644
> > index 000000000000..485c00288414
> > --- /dev/null
> > +++ b/drivers/clk/bcm/clk-raspberrypi.c
> > @@ -0,0 +1,316 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2019 Nicolas Saenz Julienne
> > + */
> > +
> > +#include <linux/clkdev.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +
> > +#include <soc/bcm2835/raspberrypi-firmware.h>
> > +
> > +#define RPI_FIRMWARE_ARM_CLK_ID		0x000000003
> > +
> > +#define RPI_FIRMWARE_STATE_ENABLE_BIT	0x1
> > +#define RPI_FIRMWARE_STATE_WAIT_BIT	0x2
> how about using the BIT() macro?
> > +
> > +/*
> > + * Even though the firmware interface alters 'pllb' the frequencies are
> > + * provided as per 'pllb_arm'. We need to scale before passing them trough.
> > + */
> > +#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE	2
> > +
> > +#define A2W_PLL_FRAC_BITS		20
> > +
> > +struct raspberrypi_clk {
> > +	struct device *dev;
> > +	struct rpi_firmware *firmware;
> > +
> > +	unsigned long min_rate;
> > +	unsigned long max_rate;
> > +
> > +	struct clk_hw pllb;
> > +	struct clk_hw *pllb_arm;
> > +	struct clk_lookup *pllb_arm_lookup;
> > +};
> > +
> > +/*
> > + * 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 raspberrypi_firmware_prop {
> > +	__le32 id;
> > +	__le32 val;
> > +	__le32 disable_turbo;
> > +} __packed;
> > +
> > +static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32
> > tag,
> > +				      u32 clk, u32 *val)
> > +{
> > +	struct raspberrypi_firmware_prop msg = {
> > +		.id = clk,
> > +		.val = *val,
> > +		.disable_turbo = 1,
> > +	};
> > +	int ret;
> > +
> > +	ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
> > +	if (ret)
> > +		return ret;
> > +
> > +	*val = msg.val;
> > +
> > +	return 0;
> > +}
> > +
> > +static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
> > +{
> > +	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
> > +						   pllb);
> > +	u32 val = 0;
> > +	int ret;
> > +
> > +	ret = raspberrypi_clock_property(rpi->firmware,
> > +					 RPI_FIRMWARE_GET_CLOCK_STATE,
> > +					 RPI_FIRMWARE_ARM_CLK_ID, &val);
> > +	if (ret)
> > +		return 0;
> > +
> > +	return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
> > +}
> > +
> > +
> > +static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
> > +						 unsigned long parent_rate)
> > +{
> > +	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
> > +						   pllb);
> > +	u32 val = 0;
> > +	int ret;
> > +
> > +	ret = raspberrypi_clock_property(rpi->firmware,
> > +					 RPI_FIRMWARE_GET_CLOCK_RATE,
> > +					 RPI_FIRMWARE_ARM_CLK_ID,
> > +					 &val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
> > +}
> > +
> > +static int raspberrypi_fw_pll_on(struct clk_hw *hw)
> > +{
> > +	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
> > +						   pllb);
> > +	u32 val;
> > +	int ret;
> > +
> > +	val = RPI_FIRMWARE_STATE_ENABLE_BIT | RPI_FIRMWARE_STATE_WAIT_BIT;
> > +
> > +	ret = raspberrypi_clock_property(rpi->firmware,
> > +					 RPI_FIRMWARE_SET_CLOCK_STATE,
> > +					 RPI_FIRMWARE_ARM_CLK_ID, &val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return 0;
> return ret;
> > +}
> > +
> > +static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long
> > rate,
> > +				       unsigned long parent_rate)
> > +{
> > +	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
> > +						   pllb);
> > +	u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
> > +	int ret;
> > +
> > +	ret = raspberrypi_clock_property(rpi->firmware,
> > +					 RPI_FIRMWARE_SET_CLOCK_RATE,
> > +					 RPI_FIRMWARE_ARM_CLK_ID,
> > +					 &new_rate);
> > +	if (ret)
> > +		dev_err_ratelimited(rpi->dev, "Failed to change %s frequency:
> > %d",
> > +				    clk_hw_get_name(hw), ret);
> > +
> > +	return ret;
> > +}
> > +
> > +/*
> > + * Sadly there is no firmware rate rounding interface. We borred it from
> borrowed?

Yes

> > + * clk-bcm2835.
> > + */
> > +static long raspberrypi_pll_round_rate(struct clk_hw *hw, unsigned long
> > rate,
> > +				       unsigned long *parent_rate)
> > +{
> > +	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
> > +						   pllb);
> > +	u64 div, final_rate;
> > +	u32 ndiv, fdiv;
> > +
> > +	rate = clamp(rate, rpi->min_rate, rpi->max_rate);
> > +
> > +	div = (u64)rate << A2W_PLL_FRAC_BITS;
> > +	do_div(div, *parent_rate);
> > +
> > +	ndiv = div >> A2W_PLL_FRAC_BITS;
> > +	fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
> > +
> > +	/* We can't use rate directly as it would overflow */
> > +	final_rate = ((u64)*parent_rate * ((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
> > +
> > +	return final_rate >> A2W_PLL_FRAC_BITS;
> > +}
> > +
> > +static void raspberrypi_fw_pll_off(struct clk_hw *hw)
> > +{
> > +	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
> > +						   pllb);
> > +	u32 val = RPI_FIRMWARE_STATE_WAIT_BIT;
> > +
> > +	raspberrypi_clock_property(rpi->firmware,
> > +				   RPI_FIRMWARE_SET_CLOCK_STATE,
> > +				   RPI_FIRMWARE_ARM_CLK_ID, &val);
> > +}
> I'm not sure. Does this operation really make sense?

You're right, I implemented it mindlessly as I saw the API available in the
firmware interface. I'll remove both prepare and unprepare as one is redundant
and the other harmful (though I wonder what whould happen if called).

Regards,
Nicolas


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

  reply	other threads:[~2019-06-05 12:23 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-04 17:32 [PATCH 0/4] cpufreq support for the Raspberry Pi Nicolas Saenz Julienne
2019-06-04 17:32 ` [PATCH 1/4] clk: bcm2835: remove pllb Nicolas Saenz Julienne
2019-06-05  0:03   ` Eric Anholt
2019-06-05 10:49   ` Stefan Wahren
2019-06-04 17:32 ` [PATCH 2/4] clk: bcm283x: add driver interfacing with Raspberry Pi's firmware Nicolas Saenz Julienne
2019-06-05 10:44   ` Stefan Wahren
2019-06-05 12:23     ` Nicolas Saenz Julienne [this message]
2019-06-04 17:32 ` [PATCH 3/4] clk: bcm2835: register Raspberry Pi's firmware clk device Nicolas Saenz Julienne
2019-06-05  0:00   ` Eric Anholt
2019-06-05  9:11     ` Nicolas Saenz Julienne
2019-06-05 10:01       ` Stefan Wahren
2019-06-04 17:32 ` [PATCH 4/4] cpufreq: add driver for Raspbery Pi Nicolas Saenz Julienne
2019-06-05  0:18   ` Eric Anholt
2019-06-05  9:12     ` Nicolas Saenz Julienne
2019-06-05 11:15   ` Stefan Wahren
2019-06-05  9:46 ` [PATCH 0/4] cpufreq support for the Raspberry Pi Stefan Wahren
2019-06-05 11:00   ` Nicolas Saenz Julienne
2019-06-05 11:34     ` Stefan Wahren
2019-06-05 12:27       ` Nicolas Saenz Julienne
2019-06-05 13:12         ` Stefan Wahren
2019-06-05 19:11       ` Nicolas Saenz Julienne
2019-06-05 20:15         ` Stefan Wahren

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3455ad811500486a9144bb45a0e0933c533e5b66.camel@suse.de \
    --to=nsaenzjulienne@suse.de \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=eric@anholt.net \
    --cc=f.fainelli@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-rpi-kernel@lists.infradead.org \
    --cc=mbrugger@suse.de \
    --cc=mturquette@baylibre.com \
    --cc=ptesarik@suse.com \
    --cc=rjw@rjwysocki.net \
    --cc=sboyd@kernel.org \
    --cc=ssuloev@orpaltech.com \
    --cc=viresh.kumar@linaro.org \
    --cc=wahrenst@gmx.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®