[PATCH RFC] WIP: clk: Draft for BCM2835 ARM core frequency control

Stefan Wahren stefan.wahren at i2se.com
Tue Apr 3 13:05:10 PDT 2018


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");
-- 
2.7.4




More information about the linux-rpi-kernel mailing list