1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-09-23 GuEe-GUI first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13
14 #define DBG_TAG "mailbox.pic"
15 #define DBG_LVL DBG_INFO
16 #include <rtdbg.h>
17
18 /*
19 * RT-Thread PIC Mailbox device driver
20 *
21 * The mailbox device(s) may be instantiated in one of three equivalent way:
22 *
23 * Device Tree node, eg.:
24 *
25 * interrupt-controller@0 {
26 * interrupt-controller;
27 * #interrupt-cells = <1>;
28 * };
29 *
30 * pic_mailbox@10000 {
31 * compatible = "rt-thread,pic-mailbox";
32 * reg = <0x10000 0x100>;
33 * position = <0>;
34 * interrupts = <34>;
35 * peer-interrupts = <35>;
36 * uid = <0>;
37 * #mbox-cells = <1>;
38 * };
39 */
40
41 #define MAILBOX_IMASK 0x00
42 #define MAILBOX_ISTATE 0x04
43 #define MAILBOX_MSG(n) (0x08 + (n) * 4)
44
45 struct pic_mbox
46 {
47 struct rt_mbox_controller parent;
48
49 void *regs;
50 void *peer_regs;
51
52 int position;
53 int chans_nr;
54 int irq;
55 int peer_hwirq;
56 struct rt_pic *pic;
57
58 struct rt_spinlock lock;
59 };
60
61 #define raw_to_pic_mbox(raw) rt_container_of(raw, struct pic_mbox, parent)
62
pic_mbox_request(struct rt_mbox_chan * chan)63 static rt_err_t pic_mbox_request(struct rt_mbox_chan *chan)
64 {
65 int index = chan - chan->ctrl->chans;
66 struct pic_mbox *pic_mbox = raw_to_pic_mbox(chan->ctrl);
67
68 HWREG32(pic_mbox->regs + MAILBOX_IMASK) &= ~RT_BIT(index);
69 HWREG32(pic_mbox->regs + MAILBOX_ISTATE) = 0;
70
71 return RT_EOK;
72 }
73
pic_mbox_release(struct rt_mbox_chan * chan)74 static void pic_mbox_release(struct rt_mbox_chan *chan)
75 {
76 int index = chan - chan->ctrl->chans;
77 struct pic_mbox *pic_mbox = raw_to_pic_mbox(chan->ctrl);
78
79 HWREG32(pic_mbox->regs + MAILBOX_IMASK) |= RT_BIT(index);
80 }
81
pic_mbox_send(struct rt_mbox_chan * chan,const void * data)82 static rt_err_t pic_mbox_send(struct rt_mbox_chan *chan, const void *data)
83 {
84 rt_ubase_t level;
85 int index = chan - chan->ctrl->chans;
86 struct pic_mbox *pic_mbox = raw_to_pic_mbox(chan->ctrl);
87
88 while (HWREG32(pic_mbox->peer_regs + MAILBOX_ISTATE) & RT_BIT(index))
89 {
90 rt_thread_yield();
91 }
92
93 if (HWREG32(pic_mbox->peer_regs + MAILBOX_IMASK) & RT_BIT(index))
94 {
95 return -RT_ERROR;
96 }
97
98 level = rt_spin_lock_irqsave(&pic_mbox->lock);
99
100 HWREG32(pic_mbox->regs + MAILBOX_MSG(index)) = *(rt_uint32_t *)data;
101 HWREG32(pic_mbox->peer_regs + MAILBOX_ISTATE) |= RT_BIT(index);
102 rt_hw_wmb();
103
104 rt_pic_irq_set_state_raw(pic_mbox->pic, pic_mbox->peer_hwirq,
105 RT_IRQ_STATE_PENDING, RT_TRUE);
106
107 rt_spin_unlock_irqrestore(&pic_mbox->lock, level);
108
109 return RT_EOK;
110 }
111
112 static const struct rt_mbox_controller_ops pic_mbox_ops =
113 {
114 .request = pic_mbox_request,
115 .release = pic_mbox_release,
116 .send = pic_mbox_send,
117 };
118
pic_mbox_isr(int irqno,void * param)119 static void pic_mbox_isr(int irqno, void *param)
120 {
121 rt_uint32_t isr;
122 struct pic_mbox *pic_mbox = param;
123
124 isr = HWREG32(pic_mbox->regs + MAILBOX_ISTATE);
125
126 for (int idx = 0; idx < 32; ++idx)
127 {
128 rt_uint32_t msg;
129
130 if (!(RT_BIT(idx) & isr))
131 {
132 continue;
133 }
134
135 rt_hw_rmb();
136 msg = HWREG32(pic_mbox->peer_regs + MAILBOX_MSG(idx));
137
138 rt_mbox_recv(&pic_mbox->parent.chans[idx], &msg);
139 }
140
141 HWREG32(pic_mbox->regs + MAILBOX_ISTATE) &= ~isr;
142 }
143
pic_mbox_free_resource(struct pic_mbox * pic_mbox)144 static void pic_mbox_free_resource(struct pic_mbox *pic_mbox)
145 {
146 if (pic_mbox->regs && pic_mbox->peer_regs)
147 {
148 if (pic_mbox->peer_regs > pic_mbox->regs)
149 {
150 rt_iounmap(pic_mbox->regs);
151 }
152 else
153 {
154 rt_iounmap(pic_mbox->peer_regs);
155 }
156 }
157
158 rt_free(pic_mbox);
159 }
160
pic_mbox_probe(struct rt_platform_device * pdev)161 static rt_err_t pic_mbox_probe(struct rt_platform_device *pdev)
162 {
163 rt_err_t err;
164 rt_uint64_t size;
165 rt_uint32_t value;
166 char dev_name[RT_NAME_MAX];
167 struct rt_ofw_node *pic_np;
168 struct rt_device *dev = &pdev->parent;
169 struct pic_mbox *pic_mbox = rt_calloc(1, sizeof(*pic_mbox));
170
171 if (!pic_mbox)
172 {
173 return -RT_ENOMEM;
174 }
175
176 if ((err = rt_dm_dev_get_address(dev, 0, RT_NULL, &size)))
177 {
178 goto _fail;
179 }
180
181 if ((err = rt_dm_dev_prop_read_u32(dev, "position", &value)))
182 {
183 goto _fail;
184 }
185
186 if (!value)
187 {
188 pic_mbox->regs = rt_dm_dev_iomap(dev, 0);
189
190 if (!pic_mbox->regs)
191 {
192 goto _fail;
193 }
194
195 pic_mbox->peer_regs = pic_mbox->regs + size / 2;
196
197 /* Init by the captain */
198 HWREG32(pic_mbox->regs + MAILBOX_IMASK) = 0xffffffff;
199 HWREG32(pic_mbox->regs + MAILBOX_ISTATE) = 0;
200 HWREG32(pic_mbox->peer_regs + MAILBOX_IMASK) = 0xffffffff;
201 HWREG32(pic_mbox->peer_regs + MAILBOX_ISTATE) = 0;
202 }
203 else
204 {
205 pic_mbox->peer_regs = rt_dm_dev_iomap(dev, 0);
206
207 if (!pic_mbox->peer_regs)
208 {
209 goto _fail;
210 }
211
212 pic_mbox->regs = pic_mbox->peer_regs + size / 2;
213 }
214
215 pic_mbox->irq = rt_dm_dev_get_irq(dev, 0);
216
217 if (pic_mbox->irq < 0)
218 {
219 err = pic_mbox->irq;
220
221 goto _fail;
222 }
223
224 if ((err = rt_dm_dev_prop_read_u32(dev, "peer-interrupts", &value)))
225 {
226 goto _fail;
227 }
228 pic_mbox->peer_hwirq = value;
229
230 if ((err = rt_dm_dev_prop_read_u32(dev, "uid", &value)))
231 {
232 goto _fail;
233 }
234
235 if (!(pic_np = rt_ofw_find_irq_parent(dev->ofw_node, RT_NULL)))
236 {
237 goto _fail;
238 }
239 pic_mbox->pic = rt_ofw_data(pic_np);
240 rt_ofw_node_put(pic_np);
241
242 rt_spin_lock_init(&pic_mbox->lock);
243
244 pic_mbox->parent.dev = dev;
245 pic_mbox->parent.num_chans = 32;
246 pic_mbox->parent.ops = &pic_mbox_ops;
247
248 if ((err = rt_mbox_controller_register(&pic_mbox->parent)))
249 {
250 goto _fail;
251 }
252
253 rt_snprintf(dev_name, sizeof(dev_name), "pic-mbox%d", value);
254 rt_hw_interrupt_install(pic_mbox->irq, pic_mbox_isr, pic_mbox, dev_name);
255 rt_hw_interrupt_umask(pic_mbox->irq);
256
257 return RT_EOK;
258
259 _fail:
260 pic_mbox_free_resource(pic_mbox);
261
262 return err;
263 }
264
pic_mbox_remove(struct rt_platform_device * pdev)265 static rt_err_t pic_mbox_remove(struct rt_platform_device *pdev)
266 {
267 struct pic_mbox *pic_mbox = pdev->parent.user_data;
268
269 rt_pic_detach_irq(pic_mbox->irq, pic_mbox);
270
271 rt_mbox_controller_unregister(&pic_mbox->parent);
272
273 pic_mbox_free_resource(pic_mbox);
274
275 return RT_EOK;
276 }
277
278 static const struct rt_ofw_node_id pic_mbox_ofw_ids[] =
279 {
280 { .compatible = "rt-thread,pic-mailbox" },
281 { /* sentinel */ }
282 };
283
284 static struct rt_platform_driver pic_mbox_driver =
285 {
286 .name = "mailbox-pic",
287 .ids = pic_mbox_ofw_ids,
288
289 .probe = pic_mbox_probe,
290 .remove = pic_mbox_remove,
291 };
292 RT_PLATFORM_DRIVER_EXPORT(pic_mbox_driver);
293