|
|
|
@ -0,0 +1,273 @@
|
|
|
|
|
From 624e057827435de39274c34e20c2d937cb9d4ac3 Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: Peter Robinson <pbrobinson@gmail.com>
|
|
|
|
|
Date: Thu, 31 May 2018 19:08:12 +0100
|
|
|
|
|
Subject: [PATCH] bcm2835: cpufreq: add CPU frequency control driver
|
|
|
|
|
|
|
|
|
|
Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
|
|
|
|
|
---
|
|
|
|
|
arch/arm/boot/dts/bcm2835-rpi.dtsi | 7 ++
|
|
|
|
|
arch/arm/boot/dts/bcm2837.dtsi | 33 +++++++
|
|
|
|
|
drivers/clk/bcm/Kconfig | 8 ++
|
|
|
|
|
drivers/clk/bcm/Makefile | 1 +
|
|
|
|
|
drivers/clk/bcm/clk-raspberrypi.c | 138 +++++++++++++++++++++++++++++
|
|
|
|
|
5 files changed, 187 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 6c3cfaa77f3d..e6d1627ec421 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 7704bb029605..c24176282a1f 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@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@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@3 {
|
|
|
|
|
@@ -62,6 +71,30 @@
|
|
|
|
|
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@600000000 {
|
|
|
|
|
+ opp-hz = /bits/ 64 <600000000>;
|
|
|
|
|
+ clock-latency-ns = <355000>;
|
|
|
|
|
+ opp-suspend;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ opp@900000000 {
|
|
|
|
|
+ opp-hz = /bits/ 64 <900000000>;
|
|
|
|
|
+ clock-latency-ns = <355000>;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ opp@1200000000 {
|
|
|
|
|
+ opp-hz = /bits/ 64 <1200000000>;
|
|
|
|
|
+ clock-latency-ns = <355000>;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
|
|
|
|
|
index 4c4bd85f707c..e40bd19da22b 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 002661d39128..a028b0a90b6e 100644
|
|
|
|
|
--- a/drivers/clk/bcm/Makefile
|
|
|
|
|
+++ b/drivers/clk/bcm/Makefile
|
|
|
|
|
@@ -8,6 +8,7 @@ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-a
|
|
|
|
|
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
|
|
|
|
|
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
|
|
|
|
|
obj-$(CONFIG_ARCH_BCM_53573) += clk-bcm53573-ilp.o
|
|
|
|
|
+obj-$(CONFIG_CLK_RASPBERRYPI_CPU) += clk-raspberrypi.o
|
|
|
|
|
obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o
|
|
|
|
|
obj-$(CONFIG_CLK_BCM_HR2) += clk-hr2.o
|
|
|
|
|
obj-$(CONFIG_CLK_BCM_NSP) += clk-nsp.o
|
|
|
|
|
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 000000000000..046efc822a59
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/drivers/clk/bcm/clk-raspberrypi.c
|
|
|
|
|
@@ -0,0 +1,138 @@
|
|
|
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Raspberry Pi CPU clock driver
|
|
|
|
|
+ *
|
|
|
|
|
+ * Copyright (C) 2018 Stefan Wahren <stefan.wahren@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;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/* tag part of the message */
|
|
|
|
|
+struct prop {
|
|
|
|
|
+ u32 id; /* the ID of the clock/voltage to get or set */
|
|
|
|
|
+ u32 val; /* the value (e.g. rate (in Hz)) to set */
|
|
|
|
|
+} __packed;
|
|
|
|
|
+
|
|
|
|
|
+static int rpi_cpu_clock_property(struct rpi_firmware *fw, u32 tag, u32 *val)
|
|
|
|
|
+{
|
|
|
|
|
+ int ret;
|
|
|
|
|
+ struct prop msg = {
|
|
|
|
|
+ .id = VCMSG_ID_ARM_CLOCK,
|
|
|
|
|
+ .val = *val,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ ret = rpi_firmware_property(fw, tag, &msg, sizeof(msg));
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ return ret;
|
|
|
|
|
+
|
|
|
|
|
+ *val = msg.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;
|
|
|
|
|
+
|
|
|
|
|
+ init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL);
|
|
|
|
|
+ if (!init)
|
|
|
|
|
+ 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 = dev->of_node->name;
|
|
|
|
|
+ init->ops = &rpi_cpu_ops;
|
|
|
|
|
+
|
|
|
|
|
+ cpu->hw.init = init;
|
|
|
|
|
+ ret = devm_clk_hw_register(dev, &cpu->hw);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ return ret;
|
|
|
|
|
+
|
|
|
|
|
+ return of_clk_add_hw_provider(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@i2se.com>");
|
|
|
|
|
+MODULE_DESCRIPTION("Raspberry Pi CPU clock driver");
|
|
|
|
|
+MODULE_LICENSE("GPL v2");
|
|
|
|
|
--
|
|
|
|
|
2.17.0
|
|
|
|
|
|