summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2015-10-25 21:39:22 -0400
committerOlof Johansson <olof@lixom.net>2015-10-25 21:39:22 -0400
commit2bf8bda933a04b5b9cdeb9a6b412fd8bd1ea7500 (patch)
tree64b758b1b4f33f4bedaa625c519ced86352ee767
parentd787dcdb9c8f412b1dd0727f90d3f793a61a2551 (diff)
parent16134b3bc317c571e953d18196acf0a92afda5ff (diff)
Merge tag 'arm/soc/for-4.4/rpi-drivers' of https://github.com/Broadcom/stblinux into next/drivers
This pull request contains the Raspberry Pi firmware driver, for communicating with the VPU which has exclusive control of some of the peripherals. Eric adds the actual firmware driver and Alexander fixes the header file which was missing include guards. * tag 'arm/soc/for-4.4/rpi-drivers' of https://github.com/Broadcom/stblinux: ARM: bcm2835: add mutual inclusion protection ARM: bcm2835: Add the Raspberry Pi firmware driver Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--drivers/firmware/Kconfig7
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/raspberrypi.c260
-rw-r--r--include/soc/bcm2835/raspberrypi-firmware.h120
4 files changed, 388 insertions, 0 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index d00c6d338cc3..cf478fe6b335 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -154,6 +154,13 @@ config ISCSI_IBFT
154 detect iSCSI boot parameters dynamically during system boot, say Y. 154 detect iSCSI boot parameters dynamically during system boot, say Y.
155 Otherwise, say N. 155 Otherwise, say N.
156 156
157config RASPBERRYPI_FIRMWARE
158 tristate "Raspberry Pi Firmware Driver"
159 depends on BCM2835_MBOX
160 help
161 This option enables support for communicating with the firmware on the
162 Raspberry Pi.
163
157config QCOM_SCM 164config QCOM_SCM
158 bool 165 bool
159 depends on ARM || ARM64 166 depends on ARM || ARM64
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index b984dd7d9ccb..48dd4175297e 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_DMIID) += dmi-id.o
13obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o 13obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
14obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o 14obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
15obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o 15obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
16obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
16obj-$(CONFIG_QCOM_SCM) += qcom_scm.o 17obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
17obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o 18obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
18obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o 19obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
new file mode 100644
index 000000000000..dd506cd3a5b8
--- /dev/null
+++ b/drivers/firmware/raspberrypi.c
@@ -0,0 +1,260 @@
1/*
2 * Defines interfaces for interacting wtih the Raspberry Pi firmware's
3 * property channel.
4 *
5 * Copyright © 2015 Broadcom
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/dma-mapping.h>
13#include <linux/mailbox_client.h>
14#include <linux/module.h>
15#include <linux/of_platform.h>
16#include <linux/platform_device.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
24struct rpi_firmware {
25 struct mbox_client cl;
26 struct mbox_chan *chan; /* The property channel. */
27 struct completion c;
28 u32 enabled;
29};
30
31static DEFINE_MUTEX(transaction_lock);
32
33static void response_callback(struct mbox_client *cl, void *msg)
34{
35 struct rpi_firmware *fw = container_of(cl, struct rpi_firmware, cl);
36 complete(&fw->c);
37}
38
39/*
40 * Sends a request to the firmware through the BCM2835 mailbox driver,
41 * and synchronously waits for the reply.
42 */
43static int
44rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data)
45{
46 u32 message = MBOX_MSG(chan, data);
47 int ret;
48
49 WARN_ON(data & 0xf);
50
51 mutex_lock(&transaction_lock);
52 reinit_completion(&fw->c);
53 ret = mbox_send_message(fw->chan, &message);
54 if (ret >= 0) {
55 wait_for_completion(&fw->c);
56 ret = 0;
57 } else {
58 dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret);
59 }
60 mutex_unlock(&transaction_lock);
61
62 return ret;
63}
64
65/**
66 * rpi_firmware_property_list - Submit firmware property list
67 * @fw: Pointer to firmware structure from rpi_firmware_get().
68 * @data: Buffer holding tags.
69 * @tag_size: Size of tags buffer.
70 *
71 * Submits a set of concatenated tags to the VPU firmware through the
72 * mailbox property interface.
73 *
74 * The buffer header and the ending tag are added by this function and
75 * don't need to be supplied, just the actual tags for your operation.
76 * See struct rpi_firmware_property_tag_header for the per-tag
77 * structure.
78 */
79int rpi_firmware_property_list(struct rpi_firmware *fw,
80 void *data, size_t tag_size)
81{
82 size_t size = tag_size + 12;
83 u32 *buf;
84 dma_addr_t bus_addr;
85 int ret;
86
87 /* Packets are processed a dword at a time. */
88 if (size & 3)
89 return -EINVAL;
90
91 buf = dma_alloc_coherent(fw->cl.dev, PAGE_ALIGN(size), &bus_addr,
92 GFP_ATOMIC);
93 if (!buf)
94 return -ENOMEM;
95
96 /* The firmware will error out without parsing in this case. */
97 WARN_ON(size >= 1024 * 1024);
98
99 buf[0] = size;
100 buf[1] = RPI_FIRMWARE_STATUS_REQUEST;
101 memcpy(&buf[2], data, tag_size);
102 buf[size / 4 - 1] = RPI_FIRMWARE_PROPERTY_END;
103 wmb();
104
105 ret = rpi_firmware_transaction(fw, MBOX_CHAN_PROPERTY, bus_addr);
106
107 rmb();
108 memcpy(data, &buf[2], tag_size);
109 if (ret == 0 && buf[1] != RPI_FIRMWARE_STATUS_SUCCESS) {
110 /*
111 * The tag name here might not be the one causing the
112 * error, if there were multiple tags in the request.
113 * But single-tag is the most common, so go with it.
114 */
115 dev_err(fw->cl.dev, "Request 0x%08x returned status 0x%08x\n",
116 buf[2], buf[1]);
117 ret = -EINVAL;
118 }
119
120 dma_free_coherent(fw->cl.dev, PAGE_ALIGN(size), buf, bus_addr);
121
122 return ret;
123}
124EXPORT_SYMBOL_GPL(rpi_firmware_property_list);
125
126/**
127 * rpi_firmware_property - Submit single firmware property
128 * @fw: Pointer to firmware structure from rpi_firmware_get().
129 * @tag: One of enum_mbox_property_tag.
130 * @tag_data: Tag data buffer.
131 * @buf_size: Buffer size.
132 *
133 * Submits a single tag to the VPU firmware through the mailbox
134 * property interface.
135 *
136 * This is a convenience wrapper around
137 * rpi_firmware_property_list() to avoid some of the
138 * boilerplate in property calls.
139 */
140int rpi_firmware_property(struct rpi_firmware *fw,
141 u32 tag, void *tag_data, size_t buf_size)
142{
143 /* Single tags are very small (generally 8 bytes), so the
144 * stack should be safe.
145 */
146 u8 data[buf_size + sizeof(struct rpi_firmware_property_tag_header)];
147 struct rpi_firmware_property_tag_header *header =
148 (struct rpi_firmware_property_tag_header *)data;
149 int ret;
150
151 header->tag = tag;
152 header->buf_size = buf_size;
153 header->req_resp_size = 0;
154 memcpy(data + sizeof(struct rpi_firmware_property_tag_header),
155 tag_data, buf_size);
156
157 ret = rpi_firmware_property_list(fw, &data, sizeof(data));
158 memcpy(tag_data,
159 data + sizeof(struct rpi_firmware_property_tag_header),
160 buf_size);
161
162 return ret;
163}
164EXPORT_SYMBOL_GPL(rpi_firmware_property);
165
166static void
167rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
168{
169 u32 packet;
170 int ret = rpi_firmware_property(fw,
171 RPI_FIRMWARE_GET_FIRMWARE_REVISION,
172 &packet, sizeof(packet));
173
174 if (ret == 0) {
175 struct tm tm;
176
177 time_to_tm(packet, 0, &tm);
178
179 dev_info(fw->cl.dev,
180 "Attached to firmware from %04ld-%02d-%02d %02d:%02d\n",
181 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
182 tm.tm_hour, tm.tm_min);
183 }
184}
185
186static int rpi_firmware_probe(struct platform_device *pdev)
187{
188 struct device *dev = &pdev->dev;
189 struct rpi_firmware *fw;
190
191 fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
192 if (!fw)
193 return -ENOMEM;
194
195 fw->cl.dev = dev;
196 fw->cl.rx_callback = response_callback;
197 fw->cl.tx_block = true;
198
199 fw->chan = mbox_request_channel(&fw->cl, 0);
200 if (IS_ERR(fw->chan)) {
201 int ret = PTR_ERR(fw->chan);
202 if (ret != -EPROBE_DEFER)
203 dev_err(dev, "Failed to get mbox channel: %d\n", ret);
204 return ret;
205 }
206
207 init_completion(&fw->c);
208
209 platform_set_drvdata(pdev, fw);
210
211 rpi_firmware_print_firmware_revision(fw);
212
213 return 0;
214}
215
216static int rpi_firmware_remove(struct platform_device *pdev)
217{
218 struct rpi_firmware *fw = platform_get_drvdata(pdev);
219
220 mbox_free_channel(fw->chan);
221
222 return 0;
223}
224
225/**
226 * rpi_firmware_get - Get pointer to rpi_firmware structure.
227 * @firmware_node: Pointer to the firmware Device Tree node.
228 *
229 * Returns NULL is the firmware device is not ready.
230 */
231struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
232{
233 struct platform_device *pdev = of_find_device_by_node(firmware_node);
234
235 if (!pdev)
236 return NULL;
237
238 return platform_get_drvdata(pdev);
239}
240EXPORT_SYMBOL_GPL(rpi_firmware_get);
241
242static const struct of_device_id rpi_firmware_of_match[] = {
243 { .compatible = "raspberrypi,bcm2835-firmware", },
244 {},
245};
246MODULE_DEVICE_TABLE(of, rpi_firmware_of_match);
247
248static struct platform_driver rpi_firmware_driver = {
249 .driver = {
250 .name = "raspberrypi-firmware",
251 .of_match_table = rpi_firmware_of_match,
252 },
253 .probe = rpi_firmware_probe,
254 .remove = rpi_firmware_remove,
255};
256module_platform_driver(rpi_firmware_driver);
257
258MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
259MODULE_DESCRIPTION("Raspberry Pi firmware driver");
260MODULE_LICENSE("GPL v2");
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
new file mode 100644
index 000000000000..c07d74aa39bf
--- /dev/null
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -0,0 +1,120 @@
1/*
2 * Copyright © 2015 Broadcom
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __SOC_RASPBERRY_FIRMWARE_H__
10#define __SOC_RASPBERRY_FIRMWARE_H__
11
12#include <linux/types.h>
13#include <linux/of_device.h>
14
15struct rpi_firmware;
16
17enum rpi_firmware_property_status {
18 RPI_FIRMWARE_STATUS_REQUEST = 0,
19 RPI_FIRMWARE_STATUS_SUCCESS = 0x80000000,
20 RPI_FIRMWARE_STATUS_ERROR = 0x80000001,
21};
22
23/**
24 * struct rpi_firmware_property_tag_header - Firmware property tag header
25 * @tag: One of enum_mbox_property_tag.
26 * @buf_size: The number of bytes in the value buffer following this
27 * struct.
28 * @req_resp_size: On submit, the length of the request (though it doesn't
29 * appear to be currently used by the firmware). On return,
30 * the length of the response (always 4 byte aligned), with
31 * the low bit set.
32 */
33struct rpi_firmware_property_tag_header {
34 u32 tag;
35 u32 buf_size;
36 u32 req_resp_size;
37};
38
39enum rpi_firmware_property_tag {
40 RPI_FIRMWARE_PROPERTY_END = 0,
41 RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
42
43 RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
44 RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
45
46 RPI_FIRMWARE_GET_BOARD_MODEL = 0x00010001,
47 RPI_FIRMWARE_GET_BOARD_REVISION = 0x00010002,
48 RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS = 0x00010003,
49 RPI_FIRMWARE_GET_BOARD_SERIAL = 0x00010004,
50 RPI_FIRMWARE_GET_ARM_MEMORY = 0x00010005,
51 RPI_FIRMWARE_GET_VC_MEMORY = 0x00010006,
52 RPI_FIRMWARE_GET_CLOCKS = 0x00010007,
53 RPI_FIRMWARE_GET_POWER_STATE = 0x00020001,
54 RPI_FIRMWARE_GET_TIMING = 0x00020002,
55 RPI_FIRMWARE_SET_POWER_STATE = 0x00028001,
56 RPI_FIRMWARE_GET_CLOCK_STATE = 0x00030001,
57 RPI_FIRMWARE_GET_CLOCK_RATE = 0x00030002,
58 RPI_FIRMWARE_GET_VOLTAGE = 0x00030003,
59 RPI_FIRMWARE_GET_MAX_CLOCK_RATE = 0x00030004,
60 RPI_FIRMWARE_GET_MAX_VOLTAGE = 0x00030005,
61 RPI_FIRMWARE_GET_TEMPERATURE = 0x00030006,
62 RPI_FIRMWARE_GET_MIN_CLOCK_RATE = 0x00030007,
63 RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
64 RPI_FIRMWARE_GET_TURBO = 0x00030009,
65 RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
66 RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
67 RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
68 RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
69 RPI_FIRMWARE_RELEASE_MEMORY = 0x0003000f,
70 RPI_FIRMWARE_EXECUTE_CODE = 0x00030010,
71 RPI_FIRMWARE_EXECUTE_QPU = 0x00030011,
72 RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
73 RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
74 RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
75 RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
76 RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
77 RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
78 RPI_FIRMWARE_SET_TURBO = 0x00038009,
79
80 /* Dispmanx TAGS */
81 RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
82 RPI_FIRMWARE_FRAMEBUFFER_BLANK = 0x00040002,
83 RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
84 RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
85 RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH = 0x00040005,
86 RPI_FIRMWARE_FRAMEBUFFER_GET_PIXEL_ORDER = 0x00040006,
87 RPI_FIRMWARE_FRAMEBUFFER_GET_ALPHA_MODE = 0x00040007,
88 RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH = 0x00040008,
89 RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
90 RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
91 RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
92 RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
93 RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
94 RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
95 RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
96 RPI_FIRMWARE_FRAMEBUFFER_TEST_PIXEL_ORDER = 0x00044006,
97 RPI_FIRMWARE_FRAMEBUFFER_TEST_ALPHA_MODE = 0x00044007,
98 RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
99 RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
100 RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
101 RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
102 RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
103 RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
104 RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
105 RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
106 RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
107 RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
108 RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
109
110 RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
111 RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
112};
113
114int rpi_firmware_property(struct rpi_firmware *fw,
115 u32 tag, void *data, size_t len);
116int rpi_firmware_property_list(struct rpi_firmware *fw,
117 void *data, size_t tag_size);
118struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node);
119
120#endif /* __SOC_RASPBERRY_FIRMWARE_H__ */