[PATCH RFC] WIP: clk: Draft for BCM2835 ARM core frequency control
Sergey Suloev
ssuloev at orpaltech.com
Wed Apr 4 09:29:01 PDT 2018
Hi Stefan
On 04/03/2018 11:05 PM, Stefan Wahren wrote:
> Disclaimer: DO NOT USE THIS UNTESTED CODE !!!
>
> This approach adds a new clock driver which controls the ARM core
> frequency via the mailbox interface. So the cpufreq-dt driver can
> operate via the common clock API.
>
> Signed-off-by: Stefan Wahren <stefan.wahren at i2se.com>
> ---
> arch/arm/boot/dts/bcm2835-rpi.dtsi | 7 ++
> arch/arm/boot/dts/bcm2837.dtsi | 26 ++++++++
> drivers/clk/bcm/Kconfig | 8 +++
> drivers/clk/bcm/Makefile | 1 +
> drivers/clk/bcm/clk-raspberrypi.c | 130 +++++++++++++++++++++++++++++++++++++
> 5 files changed, 172 insertions(+)
> create mode 100644 drivers/clk/bcm/clk-raspberrypi.c
>
> diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> index 6c3cfaa..e6d1627 100644
> --- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
> +++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> @@ -35,6 +35,13 @@
> reg = <0x7e00b840 0xf>;
> interrupts = <0 2>;
> };
> +
> + arm_clk: arm_clk {
> + compatible = "raspberrypi,bcm2835-cpu";
> + clocks = <&clocks BCM2835_CLOCK_VPU>;
> + #clock-cells = <0>;
> + clock-output-names = "arm";
> + };
> };
> };
>
> diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi
> index 7704bb0..faabc55 100644
> --- a/arch/arm/boot/dts/bcm2837.dtsi
> +++ b/arch/arm/boot/dts/bcm2837.dtsi
> @@ -38,6 +38,9 @@
> reg = <0>;
> enable-method = "spin-table";
> cpu-release-addr = <0x0 0x000000d8>;
> + clocks = <&arm_clk>;
> + clock-names = "cpu";
> + operating-points-v2 = <&cpu0_opp_table>;
> };
>
> cpu1: cpu at 1 {
> @@ -46,6 +49,9 @@
> reg = <1>;
> enable-method = "spin-table";
> cpu-release-addr = <0x0 0x000000e0>;
> + clocks = <&arm_clk>;
> + clock-names = "cpu";
> + operating-points-v2 = <&cpu0_opp_table>;
> };
>
> cpu2: cpu at 2 {
> @@ -54,6 +60,9 @@
> reg = <2>;
> enable-method = "spin-table";
> cpu-release-addr = <0x0 0x000000e8>;
> + clocks = <&arm_clk>;
> + clock-names = "cpu";
> + operating-points-v2 = <&cpu0_opp_table>;
> };
>
> cpu3: cpu at 3 {
> @@ -62,6 +71,23 @@
> reg = <3>;
> enable-method = "spin-table";
> cpu-release-addr = <0x0 0x000000f0>;
> + clocks = <&arm_clk>;
> + clock-names = "cpu";
> + operating-points-v2 = <&cpu0_opp_table>;
> + };
> +
> + cpu0_opp_table: opp_table0 {
> + compatible = "operating-points-v2";
> + opp-shared;
> +
> + opp at 600000000 {
> + opp-hz = /bits/ 64 <600000000>;
> + opp-suspend;
> + };
> +
> + opp at 1200000000 {
> + opp-hz = /bits/ 64 <1200000000>;
> + };
> };
> };
> };
> diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
> index 4c4bd85..3aaabe7 100644
> --- a/drivers/clk/bcm/Kconfig
> +++ b/drivers/clk/bcm/Kconfig
> @@ -63,3 +63,11 @@ config CLK_BCM_SR
> default ARCH_BCM_IPROC
> help
> Enable common clock framework support for the Broadcom Stingray SoC
> +
> +config CLK_RASPBERRYPI_CPU
> + bool "Raspberry Pi CPU clock driver"
> + depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
> + depends on RASPBERRYPI_FIRMWARE=y
> + help
> + This enables support for the RPi CPU clock which can be adjusted
> + via the RPi firmware.
> diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
> index 002661d..b5025eb 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_CLK_RASPBERRYPI_CPU) += clk-raspberrypi.o
> 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 0000000..d629744
> --- /dev/null
> +++ b/drivers/clk/bcm/clk-raspberrypi.c
> @@ -0,0 +1,130 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Raspberry Pi CPU clock driver
> + *
> + * Copyright (C) 2018 Stefan Wahren <stefan.wahren at i2se.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <soc/bcm2835/raspberrypi-firmware.h>
> +
> +#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */
> +
> +struct rpi_cpu_clkgen {
> + struct clk_hw hw;
> + struct rpi_firmware *fw;
> +};
> +
> +static int rpi_cpu_clock_property(struct rpi_firmware *fw, u32 tag, u32 *val)
> +{
> + struct {
> + u32 id;
> + u32 val;
> + } packet;
> + int ret;
> +
> + packet.id = VCMSG_ID_ARM_CLOCK;
> + packet.val = *val;
> + ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
> + if (ret)
> + return ret;
> +
> + *val = packet.val;
> +
> + return 0;
> +}
> +
> +static unsigned long rpi_cpu_get_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct rpi_cpu_clkgen *cpu = container_of(hw, struct rpi_cpu_clkgen, hw);
> + u32 rate = 0;
> +
> + rpi_cpu_clock_property(cpu->fw, RPI_FIRMWARE_GET_CLOCK_RATE, &rate);
> +
> + return rate;
> +}
> +
> +static long rpi_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *parent_rate)
> +{
> + return rate;
> +}
> +
> +static int rpi_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct rpi_cpu_clkgen *cpu = container_of(hw, struct rpi_cpu_clkgen, hw);
> + u32 new_rate = rate;
> +
> + return rpi_cpu_clock_property(cpu->fw, RPI_FIRMWARE_SET_CLOCK_RATE,
> + &new_rate);
> +}
> +
> +static const struct clk_ops rpi_cpu_ops = {
> + .recalc_rate = rpi_cpu_get_rate,
> + .round_rate = rpi_cpu_round_rate,
> + .set_rate = rpi_cpu_set_rate,
> +};
> +
> +static int rpi_cpu_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *fw_node;
> + struct rpi_cpu_clkgen *cpu;
> + struct clk_init_data init;
> + int ret;
> +
> + cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL);
> + if (!cpu)
> + return -ENOMEM;
> +
> + fw_node = of_find_compatible_node(NULL, NULL,
> + "raspberrypi,bcm2835-firmware");
> + if (!fw_node) {
> + dev_err(dev, "Missing firmware node\n");
> + return -ENOENT;
> + }
> +
> + cpu->fw = rpi_firmware_get(fw_node);
> + of_node_put(fw_node);
> + if (!cpu->fw)
> + return -EPROBE_DEFER;
> +
> + init.name = pdev->dev.of_node->name;
> + init.ops = &rpi_cpu_ops;
> +
> + cpu->hw.init = &init;
> + ret = devm_clk_hw_register(&pdev->dev, &cpu->hw);
> + if (ret)
> + return ret;
> +
> + return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_simple_get,
> + &cpu->hw);
> +}
> +
> +static const struct of_device_id rpi_cpu_of_match[] = {
> + { .compatible = "raspberrypi,bcm2835-cpu", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, rpi_cpu_of_match);
> +
> +static struct platform_driver rpi_cpu_driver = {
> + .driver = {
> + .name = "raspberrypi-cpu",
> + .of_match_table = rpi_cpu_of_match,
> + },
> + .probe = rpi_cpu_probe,
> +};
> +builtin_platform_driver(rpi_cpu_driver);
> +
> +MODULE_AUTHOR("Stefan Wahren <stefan.wahren at i2se.com>");
> +MODULE_DESCRIPTION("Raspberry Pi CPU clock driver");
> +MODULE_LICENSE("GPL v2");
I tried your patch with Rpi3 and there is a crash at boot. Didn't you
forget anything important ?
More information about the linux-rpi-kernel
mailing list