aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Behun <marek.behun@nic.cz>2019-03-30 23:15:33 -0400
committerJassi Brar <jaswinder.singh@linaro.org>2019-05-09 01:41:00 -0400
commit8fbbfd966efa67ef9aec37cb4ff412f9f26e1e84 (patch)
treedd7ce2e7dfc7360a2945d6a7f9710a446e9fc1ef
parent004c35cd8e0c81e0b4a34f0ad3ab0c4937ccaaea (diff)
mailbox: Add support for Armada 37xx rWTM mailbox
This adds support for the mailbox via which the kernel can communicate with the firmware running on the secure processor of the Armada 37xx SOC. The rWTM secure processor has access to internal eFuses and cryptographic circuits, such as the Entropy Bit Generator to generate true random numbers. Signed-off-by: Marek Behun <marek.behun@nic.cz> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
-rw-r--r--drivers/mailbox/Kconfig10
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/armada-37xx-rwtm-mailbox.c225
-rw-r--r--include/linux/armada-37xx-rwtm-mailbox.h23
4 files changed, 260 insertions, 0 deletions
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index d86e7a4ac04d..595542bfae85 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -41,6 +41,16 @@ config PL320_MBOX
41 Management Engine, primarily for cpufreq. Say Y here if you want 41 Management Engine, primarily for cpufreq. Say Y here if you want
42 to use the PL320 IPCM support. 42 to use the PL320 IPCM support.
43 43
44config ARMADA_37XX_RWTM_MBOX
45 tristate "Armada 37xx rWTM BIU Mailbox"
46 depends on ARCH_MVEBU || COMPILE_TEST
47 depends on OF
48 help
49 Mailbox implementation for communication with the the firmware
50 running on the Cortex-M3 rWTM secure processor of the Armada 37xx
51 SOC. Say Y here if you are building for such a device (for example
52 the Turris Mox router).
53
44config OMAP2PLUS_MBOX 54config OMAP2PLUS_MBOX
45 tristate "OMAP2+ Mailbox framework support" 55 tristate "OMAP2+ Mailbox framework support"
46 depends on ARCH_OMAP2PLUS 56 depends on ARCH_OMAP2PLUS
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 8be3bcbcf882..c22fad6f696b 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -9,6 +9,8 @@ obj-$(CONFIG_ARM_MHU) += arm_mhu.o
9 9
10obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o 10obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o
11 11
12obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX) += armada-37xx-rwtm-mailbox.o
13
12obj-$(CONFIG_PLATFORM_MHU) += platform_mhu.o 14obj-$(CONFIG_PLATFORM_MHU) += platform_mhu.o
13 15
14obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o 16obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
diff --git a/drivers/mailbox/armada-37xx-rwtm-mailbox.c b/drivers/mailbox/armada-37xx-rwtm-mailbox.c
new file mode 100644
index 000000000000..97f90e97a83c
--- /dev/null
+++ b/drivers/mailbox/armada-37xx-rwtm-mailbox.c
@@ -0,0 +1,225 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * rWTM BIU Mailbox driver for Armada 37xx
4 *
5 * Author: Marek Behun <marek.behun@nic.cz>
6 */
7
8#include <linux/device.h>
9#include <linux/interrupt.h>
10#include <linux/io.h>
11#include <linux/kernel.h>
12#include <linux/mailbox_controller.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/platform_device.h>
16#include <linux/armada-37xx-rwtm-mailbox.h>
17
18#define DRIVER_NAME "armada-37xx-rwtm-mailbox"
19
20/* relative to rWTM BIU Mailbox Registers */
21#define RWTM_MBOX_PARAM(i) (0x0 + ((i) << 2))
22#define RWTM_MBOX_COMMAND 0x40
23#define RWTM_MBOX_RETURN_STATUS 0x80
24#define RWTM_MBOX_STATUS(i) (0x84 + ((i) << 2))
25#define RWTM_MBOX_FIFO_STATUS 0xc4
26#define FIFO_STS_RDY 0x100
27#define FIFO_STS_CNTR_MASK 0x7
28#define FIFO_STS_CNTR_MAX 4
29
30#define RWTM_HOST_INT_RESET 0xc8
31#define RWTM_HOST_INT_MASK 0xcc
32#define SP_CMD_COMPLETE BIT(0)
33#define SP_CMD_QUEUE_FULL_ACCESS BIT(17)
34#define SP_CMD_QUEUE_FULL BIT(18)
35
36struct a37xx_mbox {
37 struct device *dev;
38 struct mbox_controller controller;
39 void __iomem *base;
40 int irq;
41};
42
43static void a37xx_mbox_receive(struct mbox_chan *chan)
44{
45 struct a37xx_mbox *mbox = chan->con_priv;
46 struct armada_37xx_rwtm_rx_msg rx_msg;
47 int i;
48
49 rx_msg.retval = readl(mbox->base + RWTM_MBOX_RETURN_STATUS);
50 for (i = 0; i < 16; ++i)
51 rx_msg.status[i] = readl(mbox->base + RWTM_MBOX_STATUS(i));
52
53 mbox_chan_received_data(chan, &rx_msg);
54}
55
56static irqreturn_t a37xx_mbox_irq_handler(int irq, void *data)
57{
58 struct mbox_chan *chan = data;
59 struct a37xx_mbox *mbox = chan->con_priv;
60 u32 reg;
61
62 reg = readl(mbox->base + RWTM_HOST_INT_RESET);
63
64 if (reg & SP_CMD_COMPLETE)
65 a37xx_mbox_receive(chan);
66
67 if (reg & (SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL))
68 dev_err(mbox->dev, "Secure processor command queue full\n");
69
70 writel(reg, mbox->base + RWTM_HOST_INT_RESET);
71 if (reg)
72 mbox_chan_txdone(chan, 0);
73
74 return reg ? IRQ_HANDLED : IRQ_NONE;
75}
76
77static int a37xx_mbox_send_data(struct mbox_chan *chan, void *data)
78{
79 struct a37xx_mbox *mbox = chan->con_priv;
80 struct armada_37xx_rwtm_tx_msg *msg = data;
81 int i;
82 u32 reg;
83
84 if (!data)
85 return -EINVAL;
86
87 reg = readl(mbox->base + RWTM_MBOX_FIFO_STATUS);
88 if (!(reg & FIFO_STS_RDY))
89 dev_warn(mbox->dev, "Secure processor not ready\n");
90
91 if ((reg & FIFO_STS_CNTR_MASK) >= FIFO_STS_CNTR_MAX) {
92 dev_err(mbox->dev, "Secure processor command queue full\n");
93 return -EBUSY;
94 }
95
96 for (i = 0; i < 16; ++i)
97 writel(msg->args[i], mbox->base + RWTM_MBOX_PARAM(i));
98 writel(msg->command, mbox->base + RWTM_MBOX_COMMAND);
99
100 return 0;
101}
102
103static int a37xx_mbox_startup(struct mbox_chan *chan)
104{
105 struct a37xx_mbox *mbox = chan->con_priv;
106 u32 reg;
107 int ret;
108
109 ret = devm_request_irq(mbox->dev, mbox->irq, a37xx_mbox_irq_handler, 0,
110 DRIVER_NAME, chan);
111 if (ret < 0) {
112 dev_err(mbox->dev, "Cannot request irq\n");
113 return ret;
114 }
115
116 /* enable IRQ generation */
117 reg = readl(mbox->base + RWTM_HOST_INT_MASK);
118 reg &= ~(SP_CMD_COMPLETE | SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL);
119 writel(reg, mbox->base + RWTM_HOST_INT_MASK);
120
121 return 0;
122}
123
124static void a37xx_mbox_shutdown(struct mbox_chan *chan)
125{
126 u32 reg;
127 struct a37xx_mbox *mbox = chan->con_priv;
128
129 /* disable interrupt generation */
130 reg = readl(mbox->base + RWTM_HOST_INT_MASK);
131 reg |= SP_CMD_COMPLETE | SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL;
132 writel(reg, mbox->base + RWTM_HOST_INT_MASK);
133
134 devm_free_irq(mbox->dev, mbox->irq, chan);
135}
136
137static const struct mbox_chan_ops a37xx_mbox_ops = {
138 .send_data = a37xx_mbox_send_data,
139 .startup = a37xx_mbox_startup,
140 .shutdown = a37xx_mbox_shutdown,
141};
142
143static int armada_37xx_mbox_probe(struct platform_device *pdev)
144{
145 struct a37xx_mbox *mbox;
146 struct resource *regs;
147 struct mbox_chan *chans;
148 int ret;
149
150 mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
151 if (!mbox)
152 return -ENOMEM;
153
154 /* Allocated one channel */
155 chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
156 if (!chans)
157 return -ENOMEM;
158
159 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
160
161 mbox->base = devm_ioremap_resource(&pdev->dev, regs);
162 if (IS_ERR(mbox->base)) {
163 dev_err(&pdev->dev, "ioremap failed\n");
164 return PTR_ERR(mbox->base);
165 }
166
167 mbox->irq = platform_get_irq(pdev, 0);
168 if (mbox->irq < 0) {
169 dev_err(&pdev->dev, "Cannot get irq\n");
170 return mbox->irq;
171 }
172
173 mbox->dev = &pdev->dev;
174
175 /* Hardware supports only one channel. */
176 chans[0].con_priv = mbox;
177 mbox->controller.dev = mbox->dev;
178 mbox->controller.num_chans = 1;
179 mbox->controller.chans = chans;
180 mbox->controller.ops = &a37xx_mbox_ops;
181 mbox->controller.txdone_irq = true;
182
183 ret = mbox_controller_register(&mbox->controller);
184 if (ret) {
185 dev_err(&pdev->dev, "Could not register mailbox controller\n");
186 return ret;
187 }
188
189 platform_set_drvdata(pdev, mbox);
190 return ret;
191}
192
193static int armada_37xx_mbox_remove(struct platform_device *pdev)
194{
195 struct a37xx_mbox *mbox = platform_get_drvdata(pdev);
196
197 if (!mbox)
198 return -EINVAL;
199
200 mbox_controller_unregister(&mbox->controller);
201
202 return 0;
203}
204
205static const struct of_device_id armada_37xx_mbox_match[] = {
206 { .compatible = "marvell,armada-3700-rwtm-mailbox" },
207 { },
208};
209
210MODULE_DEVICE_TABLE(of, armada_37xx_mbox_match);
211
212static struct platform_driver armada_37xx_mbox_driver = {
213 .probe = armada_37xx_mbox_probe,
214 .remove = armada_37xx_mbox_remove,
215 .driver = {
216 .name = DRIVER_NAME,
217 .of_match_table = armada_37xx_mbox_match,
218 },
219};
220
221module_platform_driver(armada_37xx_mbox_driver);
222
223MODULE_LICENSE("GPL v2");
224MODULE_DESCRIPTION("rWTM BIU Mailbox driver for Armada 37xx");
225MODULE_AUTHOR("Marek Behun <marek.behun@nic.cz>");
diff --git a/include/linux/armada-37xx-rwtm-mailbox.h b/include/linux/armada-37xx-rwtm-mailbox.h
new file mode 100644
index 000000000000..57bb54f6767a
--- /dev/null
+++ b/include/linux/armada-37xx-rwtm-mailbox.h
@@ -0,0 +1,23 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * rWTM BIU Mailbox driver for Armada 37xx
4 *
5 * Author: Marek Behun <marek.behun@nic.cz>
6 */
7
8#ifndef _LINUX_ARMADA_37XX_RWTM_MAILBOX_H_
9#define _LINUX_ARMADA_37XX_RWTM_MAILBOX_H_
10
11#include <linux/types.h>
12
13struct armada_37xx_rwtm_tx_msg {
14 u16 command;
15 u32 args[16];
16};
17
18struct armada_37xx_rwtm_rx_msg {
19 u32 retval;
20 u32 status[16];
21};
22
23#endif /* _LINUX_ARMADA_37XX_RWTM_MAILBOX_H_ */