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 <rthw.h>
12 #include <rtthread.h>
13
14 #define DBG_TAG "rtdm.mailbox"
15 #define DBG_LVL DBG_INFO
16 #include <rtdbg.h>
17
18 #include <drivers/ofw.h>
19 #include <drivers/mailbox.h>
20 #include <drivers/platform.h>
21 #include <drivers/core/dm.h>
22
23 static RT_DEFINE_SPINLOCK(mbox_ops_lock);
24 static rt_list_t mbox_nodes = RT_LIST_OBJECT_INIT(mbox_nodes);
25
26 static void mbox_chan_timeout(void *param);
27
rt_mbox_controller_register(struct rt_mbox_controller * ctrl)28 rt_err_t rt_mbox_controller_register(struct rt_mbox_controller *ctrl)
29 {
30 int len;
31 struct rt_mbox_chan *chan;
32 char timer_name[RT_NAME_MAX];
33
34 if (!ctrl || !ctrl->dev || !ctrl->ops || !ctrl->num_chans)
35 {
36 return -RT_EINVAL;
37 }
38
39 ctrl->chans = rt_calloc(ctrl->num_chans, sizeof(struct rt_mbox_chan));
40
41 if (!ctrl->chans)
42 {
43 return -RT_ENOMEM;
44 }
45
46 len = rt_snprintf(timer_name, sizeof(timer_name), "%s-",
47 rt_dm_dev_get_name(ctrl->dev));
48
49 RT_ASSERT(len < sizeof(timer_name));
50
51 chan = &ctrl->chans[0];
52
53 for (int i = 0; i < ctrl->num_chans; ++i, ++chan)
54 {
55 chan->ctrl = ctrl;
56 rt_spin_lock_init(&chan->lock);
57
58 rt_snprintf(&timer_name[len], sizeof(timer_name) - len, "%d", i);
59 rt_timer_init(&chan->timer, timer_name, mbox_chan_timeout, chan,
60 0, RT_TIMER_FLAG_ONE_SHOT);
61 }
62
63 rt_list_init(&ctrl->list);
64 rt_dm_dev_bind_fwdata(ctrl->dev, RT_NULL, ctrl);
65
66 rt_spin_lock(&mbox_ops_lock);
67
68 rt_list_insert_after(&mbox_nodes, &ctrl->list);
69
70 rt_spin_unlock(&mbox_ops_lock);
71
72 return RT_EOK;
73 }
74
rt_mbox_controller_unregister(struct rt_mbox_controller * ctrl)75 rt_err_t rt_mbox_controller_unregister(struct rt_mbox_controller *ctrl)
76 {
77 struct rt_mbox_chan *chan;
78
79 if (!ctrl)
80 {
81 return -RT_EINVAL;
82 }
83
84 rt_spin_lock(&mbox_ops_lock);
85
86 rt_dm_dev_unbind_fwdata(ctrl->dev, RT_NULL);
87 rt_list_remove(&ctrl->list);
88
89 rt_spin_unlock(&mbox_ops_lock);
90
91 chan = &ctrl->chans[0];
92
93 for (int i = ctrl->num_chans - 1; i >= 0; --i, ++chan)
94 {
95 rt_mbox_release(&ctrl->chans[i]);
96 }
97
98 rt_free(ctrl->chans);
99
100 return RT_EOK;
101 }
102
rt_mbox_send(struct rt_mbox_chan * chan,const void * data,rt_uint32_t timeout_ms)103 rt_err_t rt_mbox_send(struct rt_mbox_chan *chan, const void *data,
104 rt_uint32_t timeout_ms)
105 {
106 rt_err_t err;
107 rt_ubase_t level;
108 rt_bool_t timer_go = RT_FALSE;
109 struct rt_mbox_client *client;
110 struct rt_mbox_controller *ctrl;
111
112 if (!chan || !data)
113 {
114 return -RT_EINVAL;
115 }
116
117 ctrl = chan->ctrl;
118 client = chan->client;
119
120 level = rt_spin_lock_irqsave(&chan->lock);
121
122 if (client->tx_prepare)
123 {
124 client->tx_prepare(client, data);
125 }
126
127 chan->complete = RT_FALSE;
128 err = ctrl->ops->send(chan, data);
129
130 if (!err)
131 {
132 chan->data = (void *)data;
133
134 if (timeout_ms != RT_WAITING_FOREVER)
135 {
136 rt_tick_t tick = rt_tick_from_millisecond(timeout_ms);
137
138 rt_timer_control(&chan->timer, RT_TIMER_CTRL_SET_TIME, &tick);
139
140 timer_go = RT_TRUE;
141 }
142 }
143 else
144 {
145 chan->complete = RT_TRUE;
146 }
147
148 rt_spin_unlock_irqrestore(&chan->lock, level);
149
150 if (timer_go)
151 {
152 rt_timer_start(&chan->timer);
153 }
154
155 return err;
156 }
157
rt_mbox_send_done(struct rt_mbox_chan * chan,rt_err_t err)158 void rt_mbox_send_done(struct rt_mbox_chan *chan, rt_err_t err)
159 {
160 void *data;
161 rt_ubase_t level;
162
163 level = rt_spin_lock_irqsave(&chan->lock);
164
165 data = chan->data;
166 chan->data = RT_NULL;
167
168 rt_spin_unlock_irqrestore(&chan->lock, level);
169
170 if (chan->client->tx_done)
171 {
172 chan->client->tx_done(chan->client, data, err);
173 }
174
175 chan->complete = RT_TRUE;
176 }
177
mbox_chan_timeout(void * param)178 static void mbox_chan_timeout(void *param)
179 {
180 rt_err_t err = RT_EOK;
181 struct rt_mbox_chan *chan = param;
182
183 if (!chan->complete)
184 {
185 err = -RT_ETIMEOUT;
186 }
187
188 rt_mbox_send_done(chan, err);
189 }
190
rt_mbox_peek(struct rt_mbox_chan * chan)191 rt_bool_t rt_mbox_peek(struct rt_mbox_chan *chan)
192 {
193 if (chan && chan->ctrl->ops->peek)
194 {
195 return chan->ctrl->ops->peek(chan);
196 }
197
198 return RT_FALSE;
199 }
200
rt_mbox_recv(struct rt_mbox_chan * chan,void * data)201 rt_err_t rt_mbox_recv(struct rt_mbox_chan *chan, void *data)
202 {
203 if (!chan || !data)
204 {
205 return -RT_EINVAL;
206 }
207
208 if (chan->client->rx_callback)
209 {
210 chan->client->rx_callback(chan->client, data);
211 }
212
213 return RT_EOK;
214 }
215
mbox_controller_ofw_parse_default(struct rt_mbox_controller * ctrl,struct rt_ofw_cell_args * args)216 static int mbox_controller_ofw_parse_default(struct rt_mbox_controller *ctrl,
217 struct rt_ofw_cell_args *args)
218 {
219 if (args->args_count != 1)
220 {
221 return -RT_EINVAL;
222 }
223
224 return args->args[0];
225 }
226
rt_mbox_request_by_index(struct rt_mbox_client * client,int index)227 struct rt_mbox_chan *rt_mbox_request_by_index(struct rt_mbox_client *client, int index)
228 {
229 rt_err_t err;
230 struct rt_ofw_cell_args args;
231 struct rt_ofw_node *np, *ctrl_np;
232 struct rt_mbox_controller *ctrl;
233 struct rt_mbox_chan *chan = RT_NULL;
234
235 if (!client && index < 0)
236 {
237 return rt_err_ptr(-RT_EINVAL);
238 }
239
240 np = client->dev->ofw_node;
241
242 rt_spin_lock(&mbox_ops_lock);
243
244 err = rt_ofw_parse_phandle_cells(np, "mboxes", "#mbox-cells", index, &args);
245
246 if (err)
247 {
248 chan = rt_err_ptr(err);
249 goto _out_lock;
250 }
251
252 ctrl_np = args.data;
253
254 if (!rt_ofw_data(ctrl_np))
255 {
256 rt_spin_unlock(&mbox_ops_lock);
257
258 rt_platform_ofw_request(ctrl_np);
259
260 rt_spin_lock(&mbox_ops_lock);
261 }
262
263 ctrl = rt_ofw_data(ctrl_np);
264 rt_ofw_node_put(ctrl_np);
265
266 if (ctrl)
267 {
268 int index;
269
270 if (ctrl->ops->ofw_parse)
271 {
272 index = ctrl->ops->ofw_parse(ctrl, &args);
273 }
274 else
275 {
276 index = mbox_controller_ofw_parse_default(ctrl, &args);
277 }
278
279 if (index >= 0)
280 {
281 chan = &ctrl->chans[index];
282 }
283 else
284 {
285 LOG_E("Parse chan from %s error = %s",
286 rt_dm_dev_get_name(ctrl->dev), rt_strerror(index));
287
288 chan = rt_err_ptr(index);
289 goto _out_lock;
290 }
291
292 if (ctrl->ops->request)
293 {
294 rt_err_t err = ctrl->ops->request(chan);
295
296 if (err)
297 {
298 LOG_E("Request chan[%d] from %s error = %s",
299 index, rt_dm_dev_get_name(ctrl->dev), rt_strerror(err));
300
301 rt_mbox_release(chan);
302 chan = rt_err_ptr(err);
303 }
304 }
305
306 chan->client = client;
307 }
308 else
309 {
310 chan = rt_err_ptr(-RT_ENOSYS);
311 }
312
313 _out_lock:
314 rt_spin_unlock(&mbox_ops_lock);
315
316 return chan;
317 }
318
rt_mbox_request_by_name(struct rt_mbox_client * client,char * name)319 struct rt_mbox_chan *rt_mbox_request_by_name(struct rt_mbox_client *client, char *name)
320 {
321 int index;
322 struct rt_ofw_node *np;
323
324 if (!client || !name)
325 {
326 return rt_err_ptr(-RT_EINVAL);
327 }
328
329 np = client->dev->ofw_node;
330 index = rt_ofw_prop_index_of_string(np, "mbox-names", name);
331
332 if (index < 0)
333 {
334 return RT_NULL;
335 }
336
337 return rt_mbox_request_by_index(client, index);
338 }
339
rt_mbox_release(struct rt_mbox_chan * chan)340 rt_err_t rt_mbox_release(struct rt_mbox_chan *chan)
341 {
342 if (chan)
343 {
344 chan->ctrl->ops->release(chan);
345 }
346 else
347 {
348 return -RT_EINVAL;
349 }
350
351 return RT_EOK;
352 }
353