Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/clk/bcm/clk-raspberrypi.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0+
2
/*
3
* Raspberry Pi driver for firmware controlled clocks
4
*
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.
9
*
10
* Copyright (C) 2019 Nicolas Saenz Julienne <[email protected]>
11
*/
12
13
#include <linux/clkdev.h>
14
#include <linux/clk-provider.h>
15
#include <linux/io.h>
16
#include <linux/module.h>
17
#include <linux/platform_device.h>
18
19
#include <soc/bcm2835/raspberrypi-firmware.h>
20
21
static char *rpi_firmware_clk_names[] = {
22
[RPI_FIRMWARE_EMMC_CLK_ID] = "emmc",
23
[RPI_FIRMWARE_UART_CLK_ID] = "uart",
24
[RPI_FIRMWARE_ARM_CLK_ID] = "arm",
25
[RPI_FIRMWARE_CORE_CLK_ID] = "core",
26
[RPI_FIRMWARE_V3D_CLK_ID] = "v3d",
27
[RPI_FIRMWARE_H264_CLK_ID] = "h264",
28
[RPI_FIRMWARE_ISP_CLK_ID] = "isp",
29
[RPI_FIRMWARE_SDRAM_CLK_ID] = "sdram",
30
[RPI_FIRMWARE_PIXEL_CLK_ID] = "pixel",
31
[RPI_FIRMWARE_PWM_CLK_ID] = "pwm",
32
[RPI_FIRMWARE_HEVC_CLK_ID] = "hevc",
33
[RPI_FIRMWARE_EMMC2_CLK_ID] = "emmc2",
34
[RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc",
35
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb",
36
[RPI_FIRMWARE_VEC_CLK_ID] = "vec",
37
[RPI_FIRMWARE_DISP_CLK_ID] = "disp",
38
};
39
40
#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
41
#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
42
43
struct raspberrypi_clk_variant;
44
45
struct raspberrypi_clk {
46
struct device *dev;
47
struct rpi_firmware *firmware;
48
struct platform_device *cpufreq;
49
};
50
51
struct raspberrypi_clk_data {
52
struct clk_hw hw;
53
54
unsigned int id;
55
struct raspberrypi_clk_variant *variant;
56
57
struct raspberrypi_clk *rpi;
58
};
59
60
static inline
61
const struct raspberrypi_clk_data *clk_hw_to_data(const struct clk_hw *hw)
62
{
63
return container_of(hw, struct raspberrypi_clk_data, hw);
64
}
65
66
struct raspberrypi_clk_variant {
67
bool export;
68
char *clkdev;
69
unsigned long min_rate;
70
bool minimize;
71
};
72
73
static struct raspberrypi_clk_variant
74
raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = {
75
[RPI_FIRMWARE_ARM_CLK_ID] = {
76
.export = true,
77
.clkdev = "cpu0",
78
},
79
[RPI_FIRMWARE_CORE_CLK_ID] = {
80
.export = true,
81
82
/*
83
* The clock is shared between the HVS and the CSI
84
* controllers, on the BCM2711 and will change depending
85
* on the pixels composited on the HVS and the capture
86
* resolution on Unicam.
87
*
88
* Since the rate can get quite large, and we need to
89
* coordinate between both driver instances, let's
90
* always use the minimum the drivers will let us.
91
*/
92
.minimize = true,
93
},
94
[RPI_FIRMWARE_M2MC_CLK_ID] = {
95
.export = true,
96
97
/*
98
* If we boot without any cable connected to any of the
99
* HDMI connector, the firmware will skip the HSM
100
* initialization and leave it with a rate of 0,
101
* resulting in a bus lockup when we're accessing the
102
* registers even if it's enabled.
103
*
104
* Let's put a sensible default so that we don't end up
105
* in this situation.
106
*/
107
.min_rate = 120000000,
108
109
/*
110
* The clock is shared between the two HDMI controllers
111
* on the BCM2711 and will change depending on the
112
* resolution output on each. Since the rate can get
113
* quite large, and we need to coordinate between both
114
* driver instances, let's always use the minimum the
115
* drivers will let us.
116
*/
117
.minimize = true,
118
},
119
[RPI_FIRMWARE_V3D_CLK_ID] = {
120
.export = true,
121
.minimize = true,
122
},
123
[RPI_FIRMWARE_PIXEL_CLK_ID] = {
124
.export = true,
125
.minimize = true,
126
},
127
[RPI_FIRMWARE_HEVC_CLK_ID] = {
128
.export = true,
129
.minimize = true,
130
},
131
[RPI_FIRMWARE_ISP_CLK_ID] = {
132
.export = true,
133
.minimize = true,
134
},
135
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = {
136
.export = true,
137
.minimize = true,
138
},
139
[RPI_FIRMWARE_VEC_CLK_ID] = {
140
.export = true,
141
.minimize = true,
142
},
143
[RPI_FIRMWARE_DISP_CLK_ID] = {
144
.export = true,
145
.minimize = true,
146
},
147
};
148
149
/*
150
* Structure of the message passed to Raspberry Pi's firmware in order to
151
* change clock rates. The 'disable_turbo' option is only available to the ARM
152
* clock (pllb) which we enable by default as turbo mode will alter multiple
153
* clocks at once.
154
*
155
* Even though we're able to access the clock registers directly we're bound to
156
* use the firmware interface as the firmware ultimately takes care of
157
* mitigating overheating/undervoltage situations and we would be changing
158
* frequencies behind his back.
159
*
160
* For more information on the firmware interface check:
161
* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
162
*/
163
struct raspberrypi_firmware_prop {
164
__le32 id;
165
__le32 val;
166
__le32 disable_turbo;
167
} __packed;
168
169
static int raspberrypi_clock_property(struct rpi_firmware *firmware,
170
const struct raspberrypi_clk_data *data,
171
u32 tag, u32 *val)
172
{
173
struct raspberrypi_firmware_prop msg = {
174
.id = cpu_to_le32(data->id),
175
.val = cpu_to_le32(*val),
176
};
177
int ret;
178
179
ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
180
if (ret)
181
return ret;
182
183
*val = le32_to_cpu(msg.val);
184
185
return 0;
186
}
187
188
static int raspberrypi_fw_is_prepared(struct clk_hw *hw)
189
{
190
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
191
struct raspberrypi_clk *rpi = data->rpi;
192
u32 val = 0;
193
int ret;
194
195
ret = raspberrypi_clock_property(rpi->firmware, data,
196
RPI_FIRMWARE_GET_CLOCK_STATE, &val);
197
if (ret)
198
return 0;
199
200
return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
201
}
202
203
204
static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
205
unsigned long parent_rate)
206
{
207
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
208
struct raspberrypi_clk *rpi = data->rpi;
209
u32 val = 0;
210
int ret;
211
212
ret = raspberrypi_clock_property(rpi->firmware, data,
213
RPI_FIRMWARE_GET_CLOCK_RATE, &val);
214
if (ret)
215
return 0;
216
217
return val;
218
}
219
220
static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
221
unsigned long parent_rate)
222
{
223
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
224
struct raspberrypi_clk *rpi = data->rpi;
225
u32 _rate = rate;
226
int ret;
227
228
ret = raspberrypi_clock_property(rpi->firmware, data,
229
RPI_FIRMWARE_SET_CLOCK_RATE, &_rate);
230
if (ret)
231
dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d\n",
232
clk_hw_get_name(hw), ret);
233
234
return ret;
235
}
236
237
static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
238
struct clk_rate_request *req)
239
{
240
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
241
struct raspberrypi_clk_variant *variant = data->variant;
242
243
/*
244
* The firmware will do the rounding but that isn't part of
245
* the interface with the firmware, so we just do our best
246
* here.
247
*/
248
249
req->rate = clamp(req->rate, req->min_rate, req->max_rate);
250
251
/*
252
* We want to aggressively reduce the clock rate here, so let's
253
* just ignore the requested rate and return the bare minimum
254
* rate we can get away with.
255
*/
256
if (variant->minimize && req->min_rate > 0)
257
req->rate = req->min_rate;
258
259
return 0;
260
}
261
262
static const struct clk_ops raspberrypi_firmware_clk_ops = {
263
.is_prepared = raspberrypi_fw_is_prepared,
264
.recalc_rate = raspberrypi_fw_get_rate,
265
.determine_rate = raspberrypi_fw_dumb_determine_rate,
266
.set_rate = raspberrypi_fw_set_rate,
267
};
268
269
static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
270
unsigned int parent,
271
unsigned int id,
272
struct raspberrypi_clk_variant *variant)
273
{
274
struct raspberrypi_clk_data *data;
275
struct clk_init_data init = {};
276
u32 min_rate, max_rate;
277
int ret;
278
279
data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL);
280
if (!data)
281
return ERR_PTR(-ENOMEM);
282
data->rpi = rpi;
283
data->id = id;
284
data->variant = variant;
285
286
init.name = devm_kasprintf(rpi->dev, GFP_KERNEL,
287
"fw-clk-%s",
288
rpi_firmware_clk_names[id]);
289
if (!init.name)
290
return ERR_PTR(-ENOMEM);
291
init.ops = &raspberrypi_firmware_clk_ops;
292
init.flags = CLK_GET_RATE_NOCACHE;
293
294
data->hw.init = &init;
295
296
ret = raspberrypi_clock_property(rpi->firmware, data,
297
RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
298
&min_rate);
299
if (ret) {
300
dev_err(rpi->dev, "Failed to get clock %d min freq: %d\n",
301
id, ret);
302
return ERR_PTR(ret);
303
}
304
305
ret = raspberrypi_clock_property(rpi->firmware, data,
306
RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
307
&max_rate);
308
if (ret) {
309
dev_err(rpi->dev, "Failed to get clock %d max freq: %d\n",
310
id, ret);
311
return ERR_PTR(ret);
312
}
313
314
ret = devm_clk_hw_register(rpi->dev, &data->hw);
315
if (ret)
316
return ERR_PTR(ret);
317
318
clk_hw_set_rate_range(&data->hw, min_rate, max_rate);
319
320
if (variant->clkdev) {
321
ret = devm_clk_hw_register_clkdev(rpi->dev, &data->hw,
322
NULL, variant->clkdev);
323
if (ret) {
324
dev_err(rpi->dev, "Failed to initialize clkdev\n");
325
return ERR_PTR(ret);
326
}
327
}
328
329
if (variant->min_rate) {
330
unsigned long rate;
331
332
clk_hw_set_rate_range(&data->hw, variant->min_rate, max_rate);
333
334
rate = raspberrypi_fw_get_rate(&data->hw, 0);
335
if (rate < variant->min_rate) {
336
ret = raspberrypi_fw_set_rate(&data->hw, variant->min_rate, 0);
337
if (ret)
338
return ERR_PTR(ret);
339
}
340
}
341
342
return &data->hw;
343
}
344
345
struct rpi_firmware_get_clocks_response {
346
u32 parent;
347
u32 id;
348
};
349
350
static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
351
struct clk_hw_onecell_data *data)
352
{
353
struct rpi_firmware_get_clocks_response *clks;
354
int ret;
355
356
/*
357
* The firmware doesn't guarantee that the last element of
358
* RPI_FIRMWARE_GET_CLOCKS is zeroed. So allocate an additional
359
* zero element as sentinel.
360
*/
361
clks = devm_kcalloc(rpi->dev,
362
RPI_FIRMWARE_NUM_CLK_ID + 1, sizeof(*clks),
363
GFP_KERNEL);
364
if (!clks)
365
return -ENOMEM;
366
367
ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS,
368
clks,
369
sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID);
370
if (ret)
371
return ret;
372
373
while (clks->id) {
374
struct raspberrypi_clk_variant *variant;
375
376
if (clks->id >= RPI_FIRMWARE_NUM_CLK_ID) {
377
dev_err(rpi->dev, "Unknown clock id: %u (max: %u)\n",
378
clks->id, RPI_FIRMWARE_NUM_CLK_ID - 1);
379
return -EINVAL;
380
}
381
382
variant = &raspberrypi_clk_variants[clks->id];
383
if (variant->export) {
384
struct clk_hw *hw;
385
386
hw = raspberrypi_clk_register(rpi, clks->parent,
387
clks->id, variant);
388
if (IS_ERR(hw))
389
return PTR_ERR(hw);
390
391
data->num = clks->id + 1;
392
data->hws[clks->id] = hw;
393
}
394
395
clks++;
396
}
397
398
return 0;
399
}
400
401
static int raspberrypi_clk_probe(struct platform_device *pdev)
402
{
403
struct clk_hw_onecell_data *clk_data;
404
struct device_node *firmware_node;
405
struct device *dev = &pdev->dev;
406
struct rpi_firmware *firmware;
407
struct raspberrypi_clk *rpi;
408
int ret;
409
410
/*
411
* We can be probed either through the an old-fashioned
412
* platform device registration or through a DT node that is a
413
* child of the firmware node. Handle both cases.
414
*/
415
if (dev->of_node)
416
firmware_node = of_get_parent(dev->of_node);
417
else
418
firmware_node = of_find_compatible_node(NULL, NULL,
419
"raspberrypi,bcm2835-firmware");
420
if (!firmware_node) {
421
dev_err(dev, "Missing firmware node\n");
422
return -ENOENT;
423
}
424
425
firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node);
426
of_node_put(firmware_node);
427
if (!firmware)
428
return -EPROBE_DEFER;
429
430
rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL);
431
if (!rpi)
432
return -ENOMEM;
433
434
rpi->dev = dev;
435
rpi->firmware = firmware;
436
platform_set_drvdata(pdev, rpi);
437
438
clk_data = devm_kzalloc(dev, struct_size(clk_data, hws,
439
RPI_FIRMWARE_NUM_CLK_ID),
440
GFP_KERNEL);
441
if (!clk_data)
442
return -ENOMEM;
443
444
ret = raspberrypi_discover_clocks(rpi, clk_data);
445
if (ret)
446
return ret;
447
448
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
449
clk_data);
450
if (ret)
451
return ret;
452
453
rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
454
-1, NULL, 0);
455
456
return 0;
457
}
458
459
static void raspberrypi_clk_remove(struct platform_device *pdev)
460
{
461
struct raspberrypi_clk *rpi = platform_get_drvdata(pdev);
462
463
platform_device_unregister(rpi->cpufreq);
464
}
465
466
static const struct of_device_id raspberrypi_clk_match[] = {
467
{ .compatible = "raspberrypi,firmware-clocks" },
468
{ },
469
};
470
MODULE_DEVICE_TABLE(of, raspberrypi_clk_match);
471
472
static struct platform_driver raspberrypi_clk_driver = {
473
.driver = {
474
.name = "raspberrypi-clk",
475
.of_match_table = raspberrypi_clk_match,
476
},
477
.probe = raspberrypi_clk_probe,
478
.remove = raspberrypi_clk_remove,
479
};
480
module_platform_driver(raspberrypi_clk_driver);
481
482
MODULE_AUTHOR("Nicolas Saenz Julienne <[email protected]>");
483
MODULE_DESCRIPTION("Raspberry Pi firmware clock driver");
484
MODULE_LICENSE("GPL");
485
486