diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-06 20:20:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-06 20:20:14 -0400 |
commit | 28da7be5ebc096ada5e6bc526c623bdd8c47800a (patch) | |
tree | 0714d6ca447818cc1aa348ae538ed18a901512df | |
parent | 9eda2d2dca830f0f8923b1f377d0fb70f576af1d (diff) | |
parent | 41c0e939d70ddb6860e340e7532df8984783f867 (diff) |
Merge tag 'mailbox-v4.17' of git://git.linaro.org/landing-teams/working/fujitsu/integration
Pull mailbox updates from Jassi Brar:
- New Hi3660 mailbox driver
- Fix TEGRA Kconfig warning
- Broadcom: use dma_pool_zalloc instead of dma_pool_alloc+memset
* tag 'mailbox-v4.17' of git://git.linaro.org/landing-teams/working/fujitsu/integration:
mailbox: Add support for Hi3660 mailbox
dt-bindings: mailbox: Introduce Hi3660 controller binding
mailbox: tegra: relax TEGRA_HSP_MBOX Kconfig dependencies
maillbox: bcm-flexrm-mailbox: Use dma_pool_zalloc()
-rw-r--r-- | Documentation/devicetree/bindings/mailbox/hisilicon,hi3660-mailbox.txt | 51 | ||||
-rw-r--r-- | drivers/mailbox/Kconfig | 10 | ||||
-rw-r--r-- | drivers/mailbox/Makefile | 2 | ||||
-rw-r--r-- | drivers/mailbox/bcm-flexrm-mailbox.c | 3 | ||||
-rw-r--r-- | drivers/mailbox/hi3660-mailbox.c | 312 |
5 files changed, 375 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/mailbox/hisilicon,hi3660-mailbox.txt b/Documentation/devicetree/bindings/mailbox/hisilicon,hi3660-mailbox.txt new file mode 100644 index 000000000000..3e5b4537407d --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/hisilicon,hi3660-mailbox.txt | |||
@@ -0,0 +1,51 @@ | |||
1 | Hisilicon Hi3660 Mailbox Controller | ||
2 | |||
3 | Hisilicon Hi3660 mailbox controller supports up to 32 channels. Messages | ||
4 | are passed between processors, including application & communication | ||
5 | processors, MCU, HIFI, etc. Each channel is unidirectional and accessed | ||
6 | by using MMIO registers; it supports maximum to 8 words message. | ||
7 | |||
8 | Controller | ||
9 | ---------- | ||
10 | |||
11 | Required properties: | ||
12 | - compatible: : Shall be "hisilicon,hi3660-mbox" | ||
13 | - reg: : Offset and length of the device's register set | ||
14 | - #mbox-cells: : Must be 3 | ||
15 | <&phandle channel dst_irq ack_irq> | ||
16 | phandle : Label name of controller | ||
17 | channel : Channel number | ||
18 | dst_irq : Remote interrupt vector | ||
19 | ack_irq : Local interrupt vector | ||
20 | |||
21 | - interrupts: : Contains the two IRQ lines for mailbox. | ||
22 | |||
23 | Example: | ||
24 | |||
25 | mailbox: mailbox@e896b000 { | ||
26 | compatible = "hisilicon,hi3660-mbox"; | ||
27 | reg = <0x0 0xe896b000 0x0 0x1000>; | ||
28 | interrupts = <0x0 0xc0 0x4>, | ||
29 | <0x0 0xc1 0x4>; | ||
30 | #mbox-cells = <3>; | ||
31 | }; | ||
32 | |||
33 | Client | ||
34 | ------ | ||
35 | |||
36 | Required properties: | ||
37 | - compatible : See the client docs | ||
38 | - mboxes : Standard property to specify a Mailbox (See ./mailbox.txt) | ||
39 | Cells must match 'mbox-cells' (See Controller docs above) | ||
40 | |||
41 | Optional properties | ||
42 | - mbox-names : Name given to channels seen in the 'mboxes' property. | ||
43 | |||
44 | Example: | ||
45 | |||
46 | stub_clock: stub_clock@e896b500 { | ||
47 | compatible = "hisilicon,hi3660-stub-clk"; | ||
48 | reg = <0x0 0xe896b500 0x0 0x0100>; | ||
49 | #clock-cells = <1>; | ||
50 | mboxes = <&mailbox 13 3 0>; | ||
51 | }; | ||
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index ba2f1525f4ee..a2bb27446dce 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig | |||
@@ -108,6 +108,14 @@ config TI_MESSAGE_MANAGER | |||
108 | multiple processors within the SoC. Select this driver if your | 108 | multiple processors within the SoC. Select this driver if your |
109 | platform has support for the hardware block. | 109 | platform has support for the hardware block. |
110 | 110 | ||
111 | config HI3660_MBOX | ||
112 | tristate "Hi3660 Mailbox" | ||
113 | depends on ARCH_HISI && OF | ||
114 | help | ||
115 | An implementation of the hi3660 mailbox. It is used to send message | ||
116 | between application processors and other processors/MCU/DSP. Select | ||
117 | Y here if you want to use Hi3660 mailbox controller. | ||
118 | |||
111 | config HI6220_MBOX | 119 | config HI6220_MBOX |
112 | tristate "Hi6220 Mailbox" | 120 | tristate "Hi6220 Mailbox" |
113 | depends on ARCH_HISI | 121 | depends on ARCH_HISI |
@@ -134,7 +142,7 @@ config QCOM_APCS_IPC | |||
134 | 142 | ||
135 | config TEGRA_HSP_MBOX | 143 | config TEGRA_HSP_MBOX |
136 | bool "Tegra HSP (Hardware Synchronization Primitives) Driver" | 144 | bool "Tegra HSP (Hardware Synchronization Primitives) Driver" |
137 | depends on ARCH_TEGRA_186_SOC | 145 | depends on ARCH_TEGRA |
138 | help | 146 | help |
139 | The Tegra HSP driver is used for the interprocessor communication | 147 | The Tegra HSP driver is used for the interprocessor communication |
140 | between different remote processors and host processors on Tegra186 | 148 | between different remote processors and host processors on Tegra186 |
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 4896f8dcae95..cc23c3a43fcd 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile | |||
@@ -27,6 +27,8 @@ obj-$(CONFIG_TI_MESSAGE_MANAGER) += ti-msgmgr.o | |||
27 | 27 | ||
28 | obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o | 28 | obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o |
29 | 29 | ||
30 | obj-$(CONFIG_HI3660_MBOX) += hi3660-mailbox.o | ||
31 | |||
30 | obj-$(CONFIG_HI6220_MBOX) += hi6220-mailbox.o | 32 | obj-$(CONFIG_HI6220_MBOX) += hi6220-mailbox.o |
31 | 33 | ||
32 | obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o | 34 | obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o |
diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c index a8cf4333a68f..8ab077ff58f4 100644 --- a/drivers/mailbox/bcm-flexrm-mailbox.c +++ b/drivers/mailbox/bcm-flexrm-mailbox.c | |||
@@ -1268,7 +1268,7 @@ static int flexrm_startup(struct mbox_chan *chan) | |||
1268 | } | 1268 | } |
1269 | 1269 | ||
1270 | /* Allocate completion memory */ | 1270 | /* Allocate completion memory */ |
1271 | ring->cmpl_base = dma_pool_alloc(ring->mbox->cmpl_pool, | 1271 | ring->cmpl_base = dma_pool_zalloc(ring->mbox->cmpl_pool, |
1272 | GFP_KERNEL, &ring->cmpl_dma_base); | 1272 | GFP_KERNEL, &ring->cmpl_dma_base); |
1273 | if (!ring->cmpl_base) { | 1273 | if (!ring->cmpl_base) { |
1274 | dev_err(ring->mbox->dev, | 1274 | dev_err(ring->mbox->dev, |
@@ -1277,7 +1277,6 @@ static int flexrm_startup(struct mbox_chan *chan) | |||
1277 | ret = -ENOMEM; | 1277 | ret = -ENOMEM; |
1278 | goto fail_free_bd_memory; | 1278 | goto fail_free_bd_memory; |
1279 | } | 1279 | } |
1280 | memset(ring->cmpl_base, 0, RING_CMPL_SIZE); | ||
1281 | 1280 | ||
1282 | /* Request IRQ */ | 1281 | /* Request IRQ */ |
1283 | if (ring->irq == UINT_MAX) { | 1282 | if (ring->irq == UINT_MAX) { |
diff --git a/drivers/mailbox/hi3660-mailbox.c b/drivers/mailbox/hi3660-mailbox.c new file mode 100644 index 000000000000..3eea6b642484 --- /dev/null +++ b/drivers/mailbox/hi3660-mailbox.c | |||
@@ -0,0 +1,312 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (c) 2017-2018 Hisilicon Limited. | ||
3 | // Copyright (c) 2017-2018 Linaro Limited. | ||
4 | |||
5 | #include <linux/bitops.h> | ||
6 | #include <linux/delay.h> | ||
7 | #include <linux/device.h> | ||
8 | #include <linux/err.h> | ||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/io.h> | ||
11 | #include <linux/iopoll.h> | ||
12 | #include <linux/mailbox_controller.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include "mailbox.h" | ||
18 | |||
19 | #define MBOX_CHAN_MAX 32 | ||
20 | |||
21 | #define MBOX_RX 0x0 | ||
22 | #define MBOX_TX 0x1 | ||
23 | |||
24 | #define MBOX_BASE(mbox, ch) ((mbox)->base + ((ch) * 0x40)) | ||
25 | #define MBOX_SRC_REG 0x00 | ||
26 | #define MBOX_DST_REG 0x04 | ||
27 | #define MBOX_DCLR_REG 0x08 | ||
28 | #define MBOX_DSTAT_REG 0x0c | ||
29 | #define MBOX_MODE_REG 0x10 | ||
30 | #define MBOX_IMASK_REG 0x14 | ||
31 | #define MBOX_ICLR_REG 0x18 | ||
32 | #define MBOX_SEND_REG 0x1c | ||
33 | #define MBOX_DATA_REG 0x20 | ||
34 | |||
35 | #define MBOX_IPC_LOCK_REG 0xa00 | ||
36 | #define MBOX_IPC_UNLOCK 0x1acce551 | ||
37 | |||
38 | #define MBOX_AUTOMATIC_ACK 1 | ||
39 | |||
40 | #define MBOX_STATE_IDLE BIT(4) | ||
41 | #define MBOX_STATE_ACK BIT(7) | ||
42 | |||
43 | #define MBOX_MSG_LEN 8 | ||
44 | |||
45 | /** | ||
46 | * Hi3660 mailbox channel information | ||
47 | * | ||
48 | * A channel can be used for TX or RX, it can trigger remote | ||
49 | * processor interrupt to notify remote processor and can receive | ||
50 | * interrupt if has incoming message. | ||
51 | * | ||
52 | * @dst_irq: Interrupt vector for remote processor | ||
53 | * @ack_irq: Interrupt vector for local processor | ||
54 | */ | ||
55 | struct hi3660_chan_info { | ||
56 | unsigned int dst_irq; | ||
57 | unsigned int ack_irq; | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * Hi3660 mailbox controller data | ||
62 | * | ||
63 | * Mailbox controller includes 32 channels and can allocate | ||
64 | * channel for message transferring. | ||
65 | * | ||
66 | * @dev: Device to which it is attached | ||
67 | * @base: Base address of the register mapping region | ||
68 | * @chan: Representation of channels in mailbox controller | ||
69 | * @mchan: Representation of channel info | ||
70 | * @controller: Representation of a communication channel controller | ||
71 | */ | ||
72 | struct hi3660_mbox { | ||
73 | struct device *dev; | ||
74 | void __iomem *base; | ||
75 | struct mbox_chan chan[MBOX_CHAN_MAX]; | ||
76 | struct hi3660_chan_info mchan[MBOX_CHAN_MAX]; | ||
77 | struct mbox_controller controller; | ||
78 | }; | ||
79 | |||
80 | static struct hi3660_mbox *to_hi3660_mbox(struct mbox_controller *mbox) | ||
81 | { | ||
82 | return container_of(mbox, struct hi3660_mbox, controller); | ||
83 | } | ||
84 | |||
85 | static int hi3660_mbox_check_state(struct mbox_chan *chan) | ||
86 | { | ||
87 | unsigned long ch = (unsigned long)chan->con_priv; | ||
88 | struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox); | ||
89 | struct hi3660_chan_info *mchan = &mbox->mchan[ch]; | ||
90 | void __iomem *base = MBOX_BASE(mbox, ch); | ||
91 | unsigned long val; | ||
92 | unsigned int ret; | ||
93 | |||
94 | /* Mailbox is idle so directly bail out */ | ||
95 | if (readl(base + MBOX_MODE_REG) & MBOX_STATE_IDLE) | ||
96 | return 0; | ||
97 | |||
98 | /* Wait for acknowledge from remote */ | ||
99 | ret = readx_poll_timeout_atomic(readl, base + MBOX_MODE_REG, | ||
100 | val, (val & MBOX_STATE_ACK), 1000, 300000); | ||
101 | if (ret) { | ||
102 | dev_err(mbox->dev, "%s: timeout for receiving ack\n", __func__); | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | /* Ensure channel is released */ | ||
107 | writel(0xffffffff, base + MBOX_IMASK_REG); | ||
108 | writel(BIT(mchan->ack_irq), base + MBOX_SRC_REG); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static int hi3660_mbox_unlock(struct mbox_chan *chan) | ||
113 | { | ||
114 | struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox); | ||
115 | unsigned int val, retry = 3; | ||
116 | |||
117 | do { | ||
118 | writel(MBOX_IPC_UNLOCK, mbox->base + MBOX_IPC_LOCK_REG); | ||
119 | |||
120 | val = readl(mbox->base + MBOX_IPC_LOCK_REG); | ||
121 | if (!val) | ||
122 | break; | ||
123 | |||
124 | udelay(10); | ||
125 | } while (retry--); | ||
126 | |||
127 | if (val) | ||
128 | dev_err(mbox->dev, "%s: failed to unlock mailbox\n", __func__); | ||
129 | |||
130 | return (!val) ? 0 : -ETIMEDOUT; | ||
131 | } | ||
132 | |||
133 | static int hi3660_mbox_acquire_channel(struct mbox_chan *chan) | ||
134 | { | ||
135 | unsigned long ch = (unsigned long)chan->con_priv; | ||
136 | struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox); | ||
137 | struct hi3660_chan_info *mchan = &mbox->mchan[ch]; | ||
138 | void __iomem *base = MBOX_BASE(mbox, ch); | ||
139 | unsigned int val, retry; | ||
140 | |||
141 | for (retry = 10; retry; retry--) { | ||
142 | /* Check if channel is in idle state */ | ||
143 | if (readl(base + MBOX_MODE_REG) & MBOX_STATE_IDLE) { | ||
144 | writel(BIT(mchan->ack_irq), base + MBOX_SRC_REG); | ||
145 | |||
146 | /* Check ack bit has been set successfully */ | ||
147 | val = readl(base + MBOX_SRC_REG); | ||
148 | if (val & BIT(mchan->ack_irq)) | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | if (!retry) | ||
154 | dev_err(mbox->dev, "%s: failed to acquire channel\n", __func__); | ||
155 | |||
156 | return retry ? 0 : -ETIMEDOUT; | ||
157 | } | ||
158 | |||
159 | static int hi3660_mbox_startup(struct mbox_chan *chan) | ||
160 | { | ||
161 | int ret; | ||
162 | |||
163 | ret = hi3660_mbox_check_state(chan); | ||
164 | if (ret) | ||
165 | return ret; | ||
166 | |||
167 | ret = hi3660_mbox_unlock(chan); | ||
168 | if (ret) | ||
169 | return ret; | ||
170 | |||
171 | ret = hi3660_mbox_acquire_channel(chan); | ||
172 | if (ret) | ||
173 | return ret; | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int hi3660_mbox_send_data(struct mbox_chan *chan, void *msg) | ||
179 | { | ||
180 | unsigned long ch = (unsigned long)chan->con_priv; | ||
181 | struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox); | ||
182 | struct hi3660_chan_info *mchan = &mbox->mchan[ch]; | ||
183 | void __iomem *base = MBOX_BASE(mbox, ch); | ||
184 | u32 *buf = msg; | ||
185 | unsigned int i; | ||
186 | |||
187 | /* Ensure channel is released */ | ||
188 | writel_relaxed(0xffffffff, base + MBOX_IMASK_REG); | ||
189 | writel_relaxed(BIT(mchan->ack_irq), base + MBOX_SRC_REG); | ||
190 | |||
191 | /* Clear mask for destination interrupt */ | ||
192 | writel_relaxed(~BIT(mchan->dst_irq), base + MBOX_IMASK_REG); | ||
193 | |||
194 | /* Config destination for interrupt vector */ | ||
195 | writel_relaxed(BIT(mchan->dst_irq), base + MBOX_DST_REG); | ||
196 | |||
197 | /* Automatic acknowledge mode */ | ||
198 | writel_relaxed(MBOX_AUTOMATIC_ACK, base + MBOX_MODE_REG); | ||
199 | |||
200 | /* Fill message data */ | ||
201 | for (i = 0; i < MBOX_MSG_LEN; i++) | ||
202 | writel_relaxed(buf[i], base + MBOX_DATA_REG + i * 4); | ||
203 | |||
204 | /* Trigger data transferring */ | ||
205 | writel(BIT(mchan->ack_irq), base + MBOX_SEND_REG); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static struct mbox_chan_ops hi3660_mbox_ops = { | ||
210 | .startup = hi3660_mbox_startup, | ||
211 | .send_data = hi3660_mbox_send_data, | ||
212 | }; | ||
213 | |||
214 | static struct mbox_chan *hi3660_mbox_xlate(struct mbox_controller *controller, | ||
215 | const struct of_phandle_args *spec) | ||
216 | { | ||
217 | struct hi3660_mbox *mbox = to_hi3660_mbox(controller); | ||
218 | struct hi3660_chan_info *mchan; | ||
219 | unsigned int ch = spec->args[0]; | ||
220 | |||
221 | if (ch >= MBOX_CHAN_MAX) { | ||
222 | dev_err(mbox->dev, "Invalid channel idx %d\n", ch); | ||
223 | return ERR_PTR(-EINVAL); | ||
224 | } | ||
225 | |||
226 | mchan = &mbox->mchan[ch]; | ||
227 | mchan->dst_irq = spec->args[1]; | ||
228 | mchan->ack_irq = spec->args[2]; | ||
229 | |||
230 | return &mbox->chan[ch]; | ||
231 | } | ||
232 | |||
233 | static const struct of_device_id hi3660_mbox_of_match[] = { | ||
234 | { .compatible = "hisilicon,hi3660-mbox", }, | ||
235 | {}, | ||
236 | }; | ||
237 | |||
238 | MODULE_DEVICE_TABLE(of, hi3660_mbox_of_match); | ||
239 | |||
240 | static int hi3660_mbox_probe(struct platform_device *pdev) | ||
241 | { | ||
242 | struct device *dev = &pdev->dev; | ||
243 | struct hi3660_mbox *mbox; | ||
244 | struct mbox_chan *chan; | ||
245 | struct resource *res; | ||
246 | unsigned long ch; | ||
247 | int err; | ||
248 | |||
249 | mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); | ||
250 | if (!mbox) | ||
251 | return -ENOMEM; | ||
252 | |||
253 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
254 | mbox->base = devm_ioremap_resource(dev, res); | ||
255 | if (IS_ERR(mbox->base)) | ||
256 | return PTR_ERR(mbox->base); | ||
257 | |||
258 | mbox->dev = dev; | ||
259 | mbox->controller.dev = dev; | ||
260 | mbox->controller.chans = mbox->chan; | ||
261 | mbox->controller.num_chans = MBOX_CHAN_MAX; | ||
262 | mbox->controller.ops = &hi3660_mbox_ops; | ||
263 | mbox->controller.of_xlate = hi3660_mbox_xlate; | ||
264 | |||
265 | /* Initialize mailbox channel data */ | ||
266 | chan = mbox->chan; | ||
267 | for (ch = 0; ch < MBOX_CHAN_MAX; ch++) | ||
268 | chan[ch].con_priv = (void *)ch; | ||
269 | |||
270 | err = mbox_controller_register(&mbox->controller); | ||
271 | if (err) { | ||
272 | dev_err(dev, "Failed to register mailbox %d\n", err); | ||
273 | return err; | ||
274 | } | ||
275 | |||
276 | platform_set_drvdata(pdev, mbox); | ||
277 | dev_info(dev, "Mailbox enabled\n"); | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int hi3660_mbox_remove(struct platform_device *pdev) | ||
282 | { | ||
283 | struct hi3660_mbox *mbox = platform_get_drvdata(pdev); | ||
284 | |||
285 | mbox_controller_unregister(&mbox->controller); | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static struct platform_driver hi3660_mbox_driver = { | ||
290 | .probe = hi3660_mbox_probe, | ||
291 | .remove = hi3660_mbox_remove, | ||
292 | .driver = { | ||
293 | .name = "hi3660-mbox", | ||
294 | .of_match_table = hi3660_mbox_of_match, | ||
295 | }, | ||
296 | }; | ||
297 | |||
298 | static int __init hi3660_mbox_init(void) | ||
299 | { | ||
300 | return platform_driver_register(&hi3660_mbox_driver); | ||
301 | } | ||
302 | core_initcall(hi3660_mbox_init); | ||
303 | |||
304 | static void __exit hi3660_mbox_exit(void) | ||
305 | { | ||
306 | platform_driver_unregister(&hi3660_mbox_driver); | ||
307 | } | ||
308 | module_exit(hi3660_mbox_exit); | ||
309 | |||
310 | MODULE_LICENSE("GPL"); | ||
311 | MODULE_DESCRIPTION("Hisilicon Hi3660 Mailbox Controller"); | ||
312 | MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>"); | ||