1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Defines interfaces for interacting with the Raspberry Pi firmware's |
4 | * property channel. |
5 | * |
6 | * Copyright © 2015 Broadcom |
7 | */ |
8 | |
9 | #include <linux/dma-mapping.h> |
10 | #include <linux/kref.h> |
11 | #include <linux/mailbox_client.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_platform.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/slab.h> |
17 | #include <soc/bcm2835/raspberrypi-firmware.h> |
18 | |
19 | #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) |
20 | #define MBOX_CHAN(msg) ((msg) & 0xf) |
21 | #define MBOX_DATA28(msg) ((msg) & ~0xf) |
22 | #define MBOX_CHAN_PROPERTY 8 |
23 | |
24 | static struct platform_device *rpi_hwmon; |
25 | static struct platform_device *rpi_clk; |
26 | |
27 | struct rpi_firmware { |
28 | struct mbox_client cl; |
29 | struct mbox_chan *chan; /* The property channel. */ |
30 | struct completion c; |
31 | u32 enabled; |
32 | |
33 | struct kref consumers; |
34 | }; |
35 | |
36 | static DEFINE_MUTEX(transaction_lock); |
37 | |
38 | static void response_callback(struct mbox_client *cl, void *msg) |
39 | { |
40 | struct rpi_firmware *fw = container_of(cl, struct rpi_firmware, cl); |
41 | complete(&fw->c); |
42 | } |
43 | |
44 | /* |
45 | * Sends a request to the firmware through the BCM2835 mailbox driver, |
46 | * and synchronously waits for the reply. |
47 | */ |
48 | static int |
49 | rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data) |
50 | { |
51 | u32 message = MBOX_MSG(chan, data); |
52 | int ret; |
53 | |
54 | WARN_ON(data & 0xf); |
55 | |
56 | mutex_lock(&transaction_lock); |
57 | reinit_completion(x: &fw->c); |
58 | ret = mbox_send_message(chan: fw->chan, mssg: &message); |
59 | if (ret >= 0) { |
60 | if (wait_for_completion_timeout(x: &fw->c, HZ)) { |
61 | ret = 0; |
62 | } else { |
63 | ret = -ETIMEDOUT; |
64 | WARN_ONCE(1, "Firmware transaction timeout" ); |
65 | } |
66 | } else { |
67 | dev_err(fw->cl.dev, "mbox_send_message returned %d\n" , ret); |
68 | } |
69 | mutex_unlock(lock: &transaction_lock); |
70 | |
71 | return ret; |
72 | } |
73 | |
74 | /** |
75 | * rpi_firmware_property_list - Submit firmware property list |
76 | * @fw: Pointer to firmware structure from rpi_firmware_get(). |
77 | * @data: Buffer holding tags. |
78 | * @tag_size: Size of tags buffer. |
79 | * |
80 | * Submits a set of concatenated tags to the VPU firmware through the |
81 | * mailbox property interface. |
82 | * |
83 | * The buffer header and the ending tag are added by this function and |
84 | * don't need to be supplied, just the actual tags for your operation. |
85 | * See struct rpi_firmware_property_tag_header for the per-tag |
86 | * structure. |
87 | */ |
88 | int rpi_firmware_property_list(struct rpi_firmware *fw, |
89 | void *data, size_t tag_size) |
90 | { |
91 | size_t size = tag_size + 12; |
92 | u32 *buf; |
93 | dma_addr_t bus_addr; |
94 | int ret; |
95 | |
96 | /* Packets are processed a dword at a time. */ |
97 | if (size & 3) |
98 | return -EINVAL; |
99 | |
100 | buf = dma_alloc_coherent(dev: fw->cl.dev, PAGE_ALIGN(size), dma_handle: &bus_addr, |
101 | GFP_ATOMIC); |
102 | if (!buf) |
103 | return -ENOMEM; |
104 | |
105 | /* The firmware will error out without parsing in this case. */ |
106 | WARN_ON(size >= 1024 * 1024); |
107 | |
108 | buf[0] = size; |
109 | buf[1] = RPI_FIRMWARE_STATUS_REQUEST; |
110 | memcpy(&buf[2], data, tag_size); |
111 | buf[size / 4 - 1] = RPI_FIRMWARE_PROPERTY_END; |
112 | wmb(); |
113 | |
114 | ret = rpi_firmware_transaction(fw, MBOX_CHAN_PROPERTY, data: bus_addr); |
115 | |
116 | rmb(); |
117 | memcpy(data, &buf[2], tag_size); |
118 | if (ret == 0 && buf[1] != RPI_FIRMWARE_STATUS_SUCCESS) { |
119 | /* |
120 | * The tag name here might not be the one causing the |
121 | * error, if there were multiple tags in the request. |
122 | * But single-tag is the most common, so go with it. |
123 | */ |
124 | dev_err(fw->cl.dev, "Request 0x%08x returned status 0x%08x\n" , |
125 | buf[2], buf[1]); |
126 | ret = -EINVAL; |
127 | } |
128 | |
129 | dma_free_coherent(dev: fw->cl.dev, PAGE_ALIGN(size), cpu_addr: buf, dma_handle: bus_addr); |
130 | |
131 | return ret; |
132 | } |
133 | EXPORT_SYMBOL_GPL(rpi_firmware_property_list); |
134 | |
135 | /** |
136 | * rpi_firmware_property - Submit single firmware property |
137 | * @fw: Pointer to firmware structure from rpi_firmware_get(). |
138 | * @tag: One of enum_mbox_property_tag. |
139 | * @tag_data: Tag data buffer. |
140 | * @buf_size: Buffer size. |
141 | * |
142 | * Submits a single tag to the VPU firmware through the mailbox |
143 | * property interface. |
144 | * |
145 | * This is a convenience wrapper around |
146 | * rpi_firmware_property_list() to avoid some of the |
147 | * boilerplate in property calls. |
148 | */ |
149 | int rpi_firmware_property(struct rpi_firmware *fw, |
150 | u32 tag, void *tag_data, size_t buf_size) |
151 | { |
152 | struct rpi_firmware_property_tag_header *; |
153 | int ret; |
154 | |
155 | /* Some mailboxes can use over 1k bytes. Rather than checking |
156 | * size and using stack or kmalloc depending on requirements, |
157 | * just use kmalloc. Mailboxes don't get called enough to worry |
158 | * too much about the time taken in the allocation. |
159 | */ |
160 | void *data = kmalloc(size: sizeof(*header) + buf_size, GFP_KERNEL); |
161 | |
162 | if (!data) |
163 | return -ENOMEM; |
164 | |
165 | header = data; |
166 | header->tag = tag; |
167 | header->buf_size = buf_size; |
168 | header->req_resp_size = 0; |
169 | memcpy(data + sizeof(*header), tag_data, buf_size); |
170 | |
171 | ret = rpi_firmware_property_list(fw, data, buf_size + sizeof(*header)); |
172 | |
173 | memcpy(tag_data, data + sizeof(*header), buf_size); |
174 | |
175 | kfree(objp: data); |
176 | |
177 | return ret; |
178 | } |
179 | EXPORT_SYMBOL_GPL(rpi_firmware_property); |
180 | |
181 | static void |
182 | rpi_firmware_print_firmware_revision(struct rpi_firmware *fw) |
183 | { |
184 | time64_t date_and_time; |
185 | u32 packet; |
186 | int ret = rpi_firmware_property(fw, |
187 | RPI_FIRMWARE_GET_FIRMWARE_REVISION, |
188 | &packet, sizeof(packet)); |
189 | |
190 | if (ret) |
191 | return; |
192 | |
193 | /* This is not compatible with y2038 */ |
194 | date_and_time = packet; |
195 | dev_info(fw->cl.dev, "Attached to firmware from %ptT\n" , &date_and_time); |
196 | } |
197 | |
198 | static void |
199 | rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw) |
200 | { |
201 | u32 packet; |
202 | int ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_THROTTLED, |
203 | &packet, sizeof(packet)); |
204 | |
205 | if (ret) |
206 | return; |
207 | |
208 | rpi_hwmon = platform_device_register_data(parent: dev, name: "raspberrypi-hwmon" , |
209 | id: -1, NULL, size: 0); |
210 | } |
211 | |
212 | static void rpi_register_clk_driver(struct device *dev) |
213 | { |
214 | struct device_node *firmware; |
215 | |
216 | /* |
217 | * Earlier DTs don't have a node for the firmware clocks but |
218 | * rely on us creating a platform device by hand. If we do |
219 | * have a node for the firmware clocks, just bail out here. |
220 | */ |
221 | firmware = of_get_compatible_child(parent: dev->of_node, |
222 | compatible: "raspberrypi,firmware-clocks" ); |
223 | if (firmware) { |
224 | of_node_put(node: firmware); |
225 | return; |
226 | } |
227 | |
228 | rpi_clk = platform_device_register_data(parent: dev, name: "raspberrypi-clk" , |
229 | id: -1, NULL, size: 0); |
230 | } |
231 | |
232 | unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, unsigned int id) |
233 | { |
234 | struct rpi_firmware_clk_rate_request msg = |
235 | RPI_FIRMWARE_CLK_RATE_REQUEST(id); |
236 | int ret; |
237 | |
238 | ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_MAX_CLOCK_RATE, |
239 | &msg, sizeof(msg)); |
240 | if (ret) |
241 | /* |
242 | * If our firmware doesn't support that operation, or fails, we |
243 | * assume the maximum clock rate is absolute maximum we can |
244 | * store over our type. |
245 | */ |
246 | return UINT_MAX; |
247 | |
248 | return le32_to_cpu(msg.rate); |
249 | } |
250 | EXPORT_SYMBOL_GPL(rpi_firmware_clk_get_max_rate); |
251 | |
252 | static void rpi_firmware_delete(struct kref *kref) |
253 | { |
254 | struct rpi_firmware *fw = container_of(kref, struct rpi_firmware, |
255 | consumers); |
256 | |
257 | mbox_free_channel(chan: fw->chan); |
258 | kfree(objp: fw); |
259 | } |
260 | |
261 | void rpi_firmware_put(struct rpi_firmware *fw) |
262 | { |
263 | kref_put(kref: &fw->consumers, release: rpi_firmware_delete); |
264 | } |
265 | EXPORT_SYMBOL_GPL(rpi_firmware_put); |
266 | |
267 | static void devm_rpi_firmware_put(void *data) |
268 | { |
269 | struct rpi_firmware *fw = data; |
270 | |
271 | rpi_firmware_put(fw); |
272 | } |
273 | |
274 | static int rpi_firmware_probe(struct platform_device *pdev) |
275 | { |
276 | struct device *dev = &pdev->dev; |
277 | struct rpi_firmware *fw; |
278 | |
279 | /* |
280 | * Memory will be freed by rpi_firmware_delete() once all users have |
281 | * released their firmware handles. Don't use devm_kzalloc() here. |
282 | */ |
283 | fw = kzalloc(size: sizeof(*fw), GFP_KERNEL); |
284 | if (!fw) |
285 | return -ENOMEM; |
286 | |
287 | fw->cl.dev = dev; |
288 | fw->cl.rx_callback = response_callback; |
289 | fw->cl.tx_block = true; |
290 | |
291 | fw->chan = mbox_request_channel(cl: &fw->cl, index: 0); |
292 | if (IS_ERR(ptr: fw->chan)) { |
293 | int ret = PTR_ERR(ptr: fw->chan); |
294 | kfree(objp: fw); |
295 | return dev_err_probe(dev, err: ret, fmt: "Failed to get mbox channel\n" ); |
296 | } |
297 | |
298 | init_completion(x: &fw->c); |
299 | kref_init(kref: &fw->consumers); |
300 | |
301 | platform_set_drvdata(pdev, data: fw); |
302 | |
303 | rpi_firmware_print_firmware_revision(fw); |
304 | rpi_register_hwmon_driver(dev, fw); |
305 | rpi_register_clk_driver(dev); |
306 | |
307 | return 0; |
308 | } |
309 | |
310 | static void rpi_firmware_shutdown(struct platform_device *pdev) |
311 | { |
312 | struct rpi_firmware *fw = platform_get_drvdata(pdev); |
313 | |
314 | if (!fw) |
315 | return; |
316 | |
317 | rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT, NULL, 0); |
318 | } |
319 | |
320 | static void rpi_firmware_remove(struct platform_device *pdev) |
321 | { |
322 | struct rpi_firmware *fw = platform_get_drvdata(pdev); |
323 | |
324 | platform_device_unregister(rpi_hwmon); |
325 | rpi_hwmon = NULL; |
326 | platform_device_unregister(rpi_clk); |
327 | rpi_clk = NULL; |
328 | |
329 | rpi_firmware_put(fw); |
330 | } |
331 | |
332 | static const struct of_device_id rpi_firmware_of_match[] = { |
333 | { .compatible = "raspberrypi,bcm2835-firmware" , }, |
334 | {}, |
335 | }; |
336 | MODULE_DEVICE_TABLE(of, rpi_firmware_of_match); |
337 | |
338 | struct device_node *rpi_firmware_find_node(void) |
339 | { |
340 | return of_find_matching_node(NULL, matches: rpi_firmware_of_match); |
341 | } |
342 | EXPORT_SYMBOL_GPL(rpi_firmware_find_node); |
343 | |
344 | /** |
345 | * rpi_firmware_get - Get pointer to rpi_firmware structure. |
346 | * @firmware_node: Pointer to the firmware Device Tree node. |
347 | * |
348 | * The reference to rpi_firmware has to be released with rpi_firmware_put(). |
349 | * |
350 | * Returns NULL is the firmware device is not ready. |
351 | */ |
352 | struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) |
353 | { |
354 | struct platform_device *pdev = of_find_device_by_node(np: firmware_node); |
355 | struct rpi_firmware *fw; |
356 | |
357 | if (!pdev) |
358 | return NULL; |
359 | |
360 | fw = platform_get_drvdata(pdev); |
361 | if (!fw) |
362 | goto err_put_device; |
363 | |
364 | if (!kref_get_unless_zero(kref: &fw->consumers)) |
365 | goto err_put_device; |
366 | |
367 | put_device(dev: &pdev->dev); |
368 | |
369 | return fw; |
370 | |
371 | err_put_device: |
372 | put_device(dev: &pdev->dev); |
373 | return NULL; |
374 | } |
375 | EXPORT_SYMBOL_GPL(rpi_firmware_get); |
376 | |
377 | /** |
378 | * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. |
379 | * @dev: The firmware device structure |
380 | * @firmware_node: Pointer to the firmware Device Tree node. |
381 | * |
382 | * Returns NULL is the firmware device is not ready. |
383 | */ |
384 | struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, |
385 | struct device_node *firmware_node) |
386 | { |
387 | struct rpi_firmware *fw; |
388 | |
389 | fw = rpi_firmware_get(firmware_node); |
390 | if (!fw) |
391 | return NULL; |
392 | |
393 | if (devm_add_action_or_reset(dev, devm_rpi_firmware_put, fw)) |
394 | return NULL; |
395 | |
396 | return fw; |
397 | } |
398 | EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); |
399 | |
400 | static struct platform_driver rpi_firmware_driver = { |
401 | .driver = { |
402 | .name = "raspberrypi-firmware" , |
403 | .of_match_table = rpi_firmware_of_match, |
404 | }, |
405 | .probe = rpi_firmware_probe, |
406 | .shutdown = rpi_firmware_shutdown, |
407 | .remove_new = rpi_firmware_remove, |
408 | }; |
409 | module_platform_driver(rpi_firmware_driver); |
410 | |
411 | MODULE_AUTHOR("Eric Anholt <eric@anholt.net>" ); |
412 | MODULE_DESCRIPTION("Raspberry Pi firmware driver" ); |
413 | MODULE_LICENSE("GPL v2" ); |
414 | |