1 // SPDX-License-Identifier: GPL-2.0+
3 * Raspberry Pi driver for firmware controlled clocks
5 * Even though clk-bcm2835 provides an interface to the hardware registers for
6 * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it.
7 * We're not allowed to change it directly as we might race with the
8 * over-temperature and under-voltage protections provided by the firmware.
10 * Copyright (C) 2019 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
13 #include <linux/clkdev.h>
14 #include <linux/clk-provider.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
19 #include <soc/bcm2835/raspberrypi-firmware.h>
21 enum rpi_firmware_clk_id
{
22 RPI_FIRMWARE_EMMC_CLK_ID
= 1,
23 RPI_FIRMWARE_UART_CLK_ID
,
24 RPI_FIRMWARE_ARM_CLK_ID
,
25 RPI_FIRMWARE_CORE_CLK_ID
,
26 RPI_FIRMWARE_V3D_CLK_ID
,
27 RPI_FIRMWARE_H264_CLK_ID
,
28 RPI_FIRMWARE_ISP_CLK_ID
,
29 RPI_FIRMWARE_SDRAM_CLK_ID
,
30 RPI_FIRMWARE_PIXEL_CLK_ID
,
31 RPI_FIRMWARE_PWM_CLK_ID
,
32 RPI_FIRMWARE_HEVC_CLK_ID
,
33 RPI_FIRMWARE_EMMC2_CLK_ID
,
34 RPI_FIRMWARE_M2MC_CLK_ID
,
35 RPI_FIRMWARE_PIXEL_BVB_CLK_ID
,
36 RPI_FIRMWARE_NUM_CLK_ID
,
39 static char *rpi_firmware_clk_names
[] = {
40 [RPI_FIRMWARE_EMMC_CLK_ID
] = "emmc",
41 [RPI_FIRMWARE_UART_CLK_ID
] = "uart",
42 [RPI_FIRMWARE_ARM_CLK_ID
] = "arm",
43 [RPI_FIRMWARE_CORE_CLK_ID
] = "core",
44 [RPI_FIRMWARE_V3D_CLK_ID
] = "v3d",
45 [RPI_FIRMWARE_H264_CLK_ID
] = "h264",
46 [RPI_FIRMWARE_ISP_CLK_ID
] = "isp",
47 [RPI_FIRMWARE_SDRAM_CLK_ID
] = "sdram",
48 [RPI_FIRMWARE_PIXEL_CLK_ID
] = "pixel",
49 [RPI_FIRMWARE_PWM_CLK_ID
] = "pwm",
50 [RPI_FIRMWARE_HEVC_CLK_ID
] = "hevc",
51 [RPI_FIRMWARE_EMMC2_CLK_ID
] = "emmc2",
52 [RPI_FIRMWARE_M2MC_CLK_ID
] = "m2mc",
53 [RPI_FIRMWARE_PIXEL_BVB_CLK_ID
] = "pixel-bvb",
56 #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
57 #define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
59 struct raspberrypi_clk
{
61 struct rpi_firmware
*firmware
;
62 struct platform_device
*cpufreq
;
65 struct raspberrypi_clk_data
{
70 struct raspberrypi_clk
*rpi
;
74 * Structure of the message passed to Raspberry Pi's firmware in order to
75 * change clock rates. The 'disable_turbo' option is only available to the ARM
76 * clock (pllb) which we enable by default as turbo mode will alter multiple
79 * Even though we're able to access the clock registers directly we're bound to
80 * use the firmware interface as the firmware ultimately takes care of
81 * mitigating overheating/undervoltage situations and we would be changing
82 * frequencies behind his back.
84 * For more information on the firmware interface check:
85 * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
87 struct raspberrypi_firmware_prop
{
93 static int raspberrypi_clock_property(struct rpi_firmware
*firmware
,
94 const struct raspberrypi_clk_data
*data
,
97 struct raspberrypi_firmware_prop msg
= {
98 .id
= cpu_to_le32(data
->id
),
99 .val
= cpu_to_le32(*val
),
100 .disable_turbo
= cpu_to_le32(1),
104 ret
= rpi_firmware_property(firmware
, tag
, &msg
, sizeof(msg
));
108 *val
= le32_to_cpu(msg
.val
);
113 static int raspberrypi_fw_is_prepared(struct clk_hw
*hw
)
115 struct raspberrypi_clk_data
*data
=
116 container_of(hw
, struct raspberrypi_clk_data
, hw
);
117 struct raspberrypi_clk
*rpi
= data
->rpi
;
121 ret
= raspberrypi_clock_property(rpi
->firmware
, data
,
122 RPI_FIRMWARE_GET_CLOCK_STATE
, &val
);
126 return !!(val
& RPI_FIRMWARE_STATE_ENABLE_BIT
);
130 static unsigned long raspberrypi_fw_get_rate(struct clk_hw
*hw
,
131 unsigned long parent_rate
)
133 struct raspberrypi_clk_data
*data
=
134 container_of(hw
, struct raspberrypi_clk_data
, hw
);
135 struct raspberrypi_clk
*rpi
= data
->rpi
;
139 ret
= raspberrypi_clock_property(rpi
->firmware
, data
,
140 RPI_FIRMWARE_GET_CLOCK_RATE
, &val
);
147 static int raspberrypi_fw_set_rate(struct clk_hw
*hw
, unsigned long rate
,
148 unsigned long parent_rate
)
150 struct raspberrypi_clk_data
*data
=
151 container_of(hw
, struct raspberrypi_clk_data
, hw
);
152 struct raspberrypi_clk
*rpi
= data
->rpi
;
156 ret
= raspberrypi_clock_property(rpi
->firmware
, data
,
157 RPI_FIRMWARE_SET_CLOCK_RATE
, &_rate
);
159 dev_err_ratelimited(rpi
->dev
, "Failed to change %s frequency: %d",
160 clk_hw_get_name(hw
), ret
);
165 static int raspberrypi_fw_dumb_determine_rate(struct clk_hw
*hw
,
166 struct clk_rate_request
*req
)
169 * The firmware will do the rounding but that isn't part of
170 * the interface with the firmware, so we just do our best
173 req
->rate
= clamp(req
->rate
, req
->min_rate
, req
->max_rate
);
177 static const struct clk_ops raspberrypi_firmware_clk_ops
= {
178 .is_prepared
= raspberrypi_fw_is_prepared
,
179 .recalc_rate
= raspberrypi_fw_get_rate
,
180 .determine_rate
= raspberrypi_fw_dumb_determine_rate
,
181 .set_rate
= raspberrypi_fw_set_rate
,
184 static struct clk_hw
*raspberrypi_clk_register(struct raspberrypi_clk
*rpi
,
188 struct raspberrypi_clk_data
*data
;
189 struct clk_init_data init
= {};
190 u32 min_rate
, max_rate
;
193 data
= devm_kzalloc(rpi
->dev
, sizeof(*data
), GFP_KERNEL
);
195 return ERR_PTR(-ENOMEM
);
199 init
.name
= devm_kasprintf(rpi
->dev
, GFP_KERNEL
,
201 rpi_firmware_clk_names
[id
]);
202 init
.ops
= &raspberrypi_firmware_clk_ops
;
203 init
.flags
= CLK_GET_RATE_NOCACHE
;
205 data
->hw
.init
= &init
;
207 ret
= raspberrypi_clock_property(rpi
->firmware
, data
,
208 RPI_FIRMWARE_GET_MIN_CLOCK_RATE
,
211 dev_err(rpi
->dev
, "Failed to get clock %d min freq: %d",
216 ret
= raspberrypi_clock_property(rpi
->firmware
, data
,
217 RPI_FIRMWARE_GET_MAX_CLOCK_RATE
,
220 dev_err(rpi
->dev
, "Failed to get clock %d max freq: %d\n",
225 ret
= devm_clk_hw_register(rpi
->dev
, &data
->hw
);
229 clk_hw_set_rate_range(&data
->hw
, min_rate
, max_rate
);
231 if (id
== RPI_FIRMWARE_ARM_CLK_ID
) {
232 ret
= devm_clk_hw_register_clkdev(rpi
->dev
, &data
->hw
,
235 dev_err(rpi
->dev
, "Failed to initialize clkdev\n");
243 struct rpi_firmware_get_clocks_response
{
248 static int raspberrypi_discover_clocks(struct raspberrypi_clk
*rpi
,
249 struct clk_hw_onecell_data
*data
)
251 struct rpi_firmware_get_clocks_response
*clks
;
254 clks
= devm_kcalloc(rpi
->dev
,
255 sizeof(*clks
), RPI_FIRMWARE_NUM_CLK_ID
,
260 ret
= rpi_firmware_property(rpi
->firmware
, RPI_FIRMWARE_GET_CLOCKS
,
262 sizeof(*clks
) * RPI_FIRMWARE_NUM_CLK_ID
);
270 case RPI_FIRMWARE_ARM_CLK_ID
:
271 case RPI_FIRMWARE_CORE_CLK_ID
:
272 case RPI_FIRMWARE_M2MC_CLK_ID
:
273 case RPI_FIRMWARE_V3D_CLK_ID
:
274 case RPI_FIRMWARE_PIXEL_BVB_CLK_ID
:
275 hw
= raspberrypi_clk_register(rpi
, clks
->parent
,
280 data
->hws
[clks
->id
] = hw
;
281 data
->num
= clks
->id
+ 1;
293 static int raspberrypi_clk_probe(struct platform_device
*pdev
)
295 struct clk_hw_onecell_data
*clk_data
;
296 struct device_node
*firmware_node
;
297 struct device
*dev
= &pdev
->dev
;
298 struct rpi_firmware
*firmware
;
299 struct raspberrypi_clk
*rpi
;
303 * We can be probed either through the an old-fashioned
304 * platform device registration or through a DT node that is a
305 * child of the firmware node. Handle both cases.
308 firmware_node
= of_get_parent(dev
->of_node
);
310 firmware_node
= of_find_compatible_node(NULL
, NULL
,
311 "raspberrypi,bcm2835-firmware");
312 if (!firmware_node
) {
313 dev_err(dev
, "Missing firmware node\n");
317 firmware
= rpi_firmware_get(firmware_node
);
318 of_node_put(firmware_node
);
320 return -EPROBE_DEFER
;
322 rpi
= devm_kzalloc(dev
, sizeof(*rpi
), GFP_KERNEL
);
327 rpi
->firmware
= firmware
;
328 platform_set_drvdata(pdev
, rpi
);
330 clk_data
= devm_kzalloc(dev
, struct_size(clk_data
, hws
,
331 RPI_FIRMWARE_NUM_CLK_ID
),
336 ret
= raspberrypi_discover_clocks(rpi
, clk_data
);
340 ret
= devm_of_clk_add_hw_provider(dev
, of_clk_hw_onecell_get
,
345 rpi
->cpufreq
= platform_device_register_data(dev
, "raspberrypi-cpufreq",
351 static int raspberrypi_clk_remove(struct platform_device
*pdev
)
353 struct raspberrypi_clk
*rpi
= platform_get_drvdata(pdev
);
355 platform_device_unregister(rpi
->cpufreq
);
360 static const struct of_device_id raspberrypi_clk_match
[] = {
361 { .compatible
= "raspberrypi,firmware-clocks" },
364 MODULE_DEVICE_TABLE(of
, raspberrypi_clk_match
);
366 static struct platform_driver raspberrypi_clk_driver
= {
368 .name
= "raspberrypi-clk",
369 .of_match_table
= raspberrypi_clk_match
,
371 .probe
= raspberrypi_clk_probe
,
372 .remove
= raspberrypi_clk_remove
,
374 module_platform_driver(raspberrypi_clk_driver
);
376 MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
377 MODULE_DESCRIPTION("Raspberry Pi firmware clock driver");
378 MODULE_LICENSE("GPL");
379 MODULE_ALIAS("platform:raspberrypi-clk");