Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Copyright (C) 2010,2015 Broadcom
4 : : * Copyright (C) 2013-2014 Lubomir Rintel
5 : : * Copyright (C) 2013 Craig McGeachie
6 : : *
7 : : * Parts of the driver are based on:
8 : : * - arch/arm/mach-bcm2708/vcio.c file written by Gray Girling that was
9 : : * obtained from branch "rpi-3.6.y" of git://github.com/raspberrypi/
10 : : * linux.git
11 : : * - drivers/mailbox/bcm2835-ipc.c by Lubomir Rintel at
12 : : * https://github.com/hackerspace/rpi-linux/blob/lr-raspberry-pi/drivers/
13 : : * mailbox/bcm2835-ipc.c
14 : : * - documentation available on the following web site:
15 : : * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
16 : : */
17 : :
18 : : #include <linux/device.h>
19 : : #include <linux/dma-mapping.h>
20 : : #include <linux/err.h>
21 : : #include <linux/interrupt.h>
22 : : #include <linux/irq.h>
23 : : #include <linux/kernel.h>
24 : : #include <linux/mailbox_controller.h>
25 : : #include <linux/module.h>
26 : : #include <linux/of_address.h>
27 : : #include <linux/of_irq.h>
28 : : #include <linux/platform_device.h>
29 : : #include <linux/spinlock.h>
30 : :
31 : : /* Mailboxes */
32 : : #define ARM_0_MAIL0 0x00
33 : : #define ARM_0_MAIL1 0x20
34 : :
35 : : /*
36 : : * Mailbox registers. We basically only support mailbox 0 & 1. We
37 : : * deliver to the VC in mailbox 1, it delivers to us in mailbox 0. See
38 : : * BCM2835-ARM-Peripherals.pdf section 1.3 for an explanation about
39 : : * the placement of memory barriers.
40 : : */
41 : : #define MAIL0_RD (ARM_0_MAIL0 + 0x00)
42 : : #define MAIL0_POL (ARM_0_MAIL0 + 0x10)
43 : : #define MAIL0_STA (ARM_0_MAIL0 + 0x18)
44 : : #define MAIL0_CNF (ARM_0_MAIL0 + 0x1C)
45 : : #define MAIL1_WRT (ARM_0_MAIL1 + 0x00)
46 : : #define MAIL1_STA (ARM_0_MAIL1 + 0x18)
47 : :
48 : : /* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
49 : : #ifndef ARM_MS_FULL
50 : : /* Status register: FIFO state. */
51 : : #define ARM_MS_FULL BIT(31)
52 : : #define ARM_MS_EMPTY BIT(30)
53 : :
54 : : /* Configuration register: Enable interrupts. */
55 : : #define ARM_MC_IHAVEDATAIRQEN BIT(0)
56 : : #endif
57 : :
58 : : struct bcm2835_mbox {
59 : : void __iomem *regs;
60 : : spinlock_t lock;
61 : : struct mbox_controller controller;
62 : : };
63 : :
64 : : static struct bcm2835_mbox *bcm2835_link_mbox(struct mbox_chan *link)
65 : : {
66 : 160101 : return container_of(link->mbox, struct bcm2835_mbox, controller);
67 : : }
68 : :
69 : 79947 : static irqreturn_t bcm2835_mbox_irq(int irq, void *dev_id)
70 : : {
71 : : struct bcm2835_mbox *mbox = dev_id;
72 : : struct device *dev = mbox->controller.dev;
73 : 79947 : struct mbox_chan *link = &mbox->controller.chans[0];
74 : :
75 [ + + ]: 399735 : while (!(readl(mbox->regs + MAIL0_STA) & ARM_MS_EMPTY)) {
76 : 159894 : u32 msg = readl(mbox->regs + MAIL0_RD);
77 : : dev_dbg(dev, "Reply 0x%08X\n", msg);
78 : 79947 : mbox_chan_received_data(link, &msg);
79 : : }
80 : 79947 : return IRQ_HANDLED;
81 : : }
82 : :
83 : 79947 : static int bcm2835_send_data(struct mbox_chan *link, void *data)
84 : : {
85 : : struct bcm2835_mbox *mbox = bcm2835_link_mbox(link);
86 : 79947 : u32 msg = *(u32 *)data;
87 : :
88 : : spin_lock(&mbox->lock);
89 : 79947 : writel(msg, mbox->regs + MAIL1_WRT);
90 : : dev_dbg(mbox->controller.dev, "Request 0x%08X\n", msg);
91 : : spin_unlock(&mbox->lock);
92 : 79947 : return 0;
93 : : }
94 : :
95 : 207 : static int bcm2835_startup(struct mbox_chan *link)
96 : : {
97 : : struct bcm2835_mbox *mbox = bcm2835_link_mbox(link);
98 : :
99 : : /* Enable the interrupt on data reception */
100 : 207 : writel(ARM_MC_IHAVEDATAIRQEN, mbox->regs + MAIL0_CNF);
101 : :
102 : 207 : return 0;
103 : : }
104 : :
105 : 0 : static void bcm2835_shutdown(struct mbox_chan *link)
106 : : {
107 : : struct bcm2835_mbox *mbox = bcm2835_link_mbox(link);
108 : :
109 : 0 : writel(0, mbox->regs + MAIL0_CNF);
110 : 0 : }
111 : :
112 : 79947 : static bool bcm2835_last_tx_done(struct mbox_chan *link)
113 : : {
114 : : struct bcm2835_mbox *mbox = bcm2835_link_mbox(link);
115 : : bool ret;
116 : :
117 : : spin_lock(&mbox->lock);
118 : 159894 : ret = !(readl(mbox->regs + MAIL1_STA) & ARM_MS_FULL);
119 : : spin_unlock(&mbox->lock);
120 : 79947 : return ret;
121 : : }
122 : :
123 : : static const struct mbox_chan_ops bcm2835_mbox_chan_ops = {
124 : : .send_data = bcm2835_send_data,
125 : : .startup = bcm2835_startup,
126 : : .shutdown = bcm2835_shutdown,
127 : : .last_tx_done = bcm2835_last_tx_done
128 : : };
129 : :
130 : 207 : static struct mbox_chan *bcm2835_mbox_index_xlate(struct mbox_controller *mbox,
131 : : const struct of_phandle_args *sp)
132 : : {
133 [ + - ]: 207 : if (sp->args_count != 0)
134 : : return ERR_PTR(-EINVAL);
135 : :
136 : 207 : return &mbox->chans[0];
137 : : }
138 : :
139 : 207 : static int bcm2835_mbox_probe(struct platform_device *pdev)
140 : : {
141 : 207 : struct device *dev = &pdev->dev;
142 : : int ret = 0;
143 : : struct resource *iomem;
144 : : struct bcm2835_mbox *mbox;
145 : :
146 : : mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
147 [ + - ]: 207 : if (mbox == NULL)
148 : : return -ENOMEM;
149 : 207 : spin_lock_init(&mbox->lock);
150 : :
151 : 207 : ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
152 : : bcm2835_mbox_irq, 0, dev_name(dev), mbox);
153 [ - + ]: 207 : if (ret) {
154 : 0 : dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
155 : : ret);
156 : 0 : return -ENODEV;
157 : : }
158 : :
159 : 207 : iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
160 : 207 : mbox->regs = devm_ioremap_resource(&pdev->dev, iomem);
161 [ - + ]: 207 : if (IS_ERR(mbox->regs)) {
162 : : ret = PTR_ERR(mbox->regs);
163 : 0 : dev_err(&pdev->dev, "Failed to remap mailbox regs: %d\n", ret);
164 : 0 : return ret;
165 : : }
166 : :
167 : 207 : mbox->controller.txdone_poll = true;
168 : 207 : mbox->controller.txpoll_period = 5;
169 : 207 : mbox->controller.ops = &bcm2835_mbox_chan_ops;
170 : 207 : mbox->controller.of_xlate = &bcm2835_mbox_index_xlate;
171 : 207 : mbox->controller.dev = dev;
172 : 207 : mbox->controller.num_chans = 1;
173 : 207 : mbox->controller.chans = devm_kzalloc(dev,
174 : : sizeof(*mbox->controller.chans), GFP_KERNEL);
175 [ + - ]: 207 : if (!mbox->controller.chans)
176 : : return -ENOMEM;
177 : :
178 : 207 : ret = devm_mbox_controller_register(dev, &mbox->controller);
179 [ + - ]: 207 : if (ret)
180 : : return ret;
181 : :
182 : : platform_set_drvdata(pdev, mbox);
183 : 207 : dev_info(dev, "mailbox enabled\n");
184 : :
185 : 207 : return ret;
186 : : }
187 : :
188 : : static const struct of_device_id bcm2835_mbox_of_match[] = {
189 : : { .compatible = "brcm,bcm2835-mbox", },
190 : : {},
191 : : };
192 : : MODULE_DEVICE_TABLE(of, bcm2835_mbox_of_match);
193 : :
194 : : static struct platform_driver bcm2835_mbox_driver = {
195 : : .driver = {
196 : : .name = "bcm2835-mbox",
197 : : .of_match_table = bcm2835_mbox_of_match,
198 : : },
199 : : .probe = bcm2835_mbox_probe,
200 : : };
201 : :
202 : 207 : static int __init bcm2835_mbox_init(void)
203 : : {
204 : 207 : return platform_driver_register(&bcm2835_mbox_driver);
205 : : }
206 : : arch_initcall(bcm2835_mbox_init);
207 : :
208 : 0 : static void __init bcm2835_mbox_exit(void)
209 : : {
210 : 0 : platform_driver_unregister(&bcm2835_mbox_driver);
211 : 0 : }
212 : : module_exit(bcm2835_mbox_exit);
213 : :
214 : : MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
215 : : MODULE_DESCRIPTION("BCM2835 mailbox IPC driver");
216 : : MODULE_LICENSE("GPL v2");
|