1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-04-20 ErikChan the first version
9 */
10
11 #include <rtthread.h>
12
13 #ifdef RT_USING_OFW
14 #include <drivers/ofw_io.h>
15 #include <drivers/ofw_irq.h>
16 #endif
17 #include <drivers/core/dm.h>
18
19 #ifdef RT_USING_SMP
rti_secondary_cpu_start(void)20 static int rti_secondary_cpu_start(void)
21 {
22 return 0;
23 }
24 INIT_EXPORT(rti_secondary_cpu_start, "6.end");
25
rti_secondary_cpu_end(void)26 static int rti_secondary_cpu_end(void)
27 {
28 return 0;
29 }
30 INIT_EXPORT(rti_secondary_cpu_end, "7.end");
31
rt_dm_secondary_cpu_init(void)32 void rt_dm_secondary_cpu_init(void)
33 {
34 #ifdef RT_DEBUGING_AUTO_INIT
35 int result;
36 const struct rt_init_desc *desc;
37
38 rt_kprintf("do secondary cpu initialization.\n");
39 for (desc = &__rt_init_desc_rti_secondary_cpu_start; desc < &__rt_init_desc_rti_secondary_cpu_end; ++desc)
40 {
41 rt_kprintf("initialize %s", desc->fn_name);
42 result = desc->fn();
43 rt_kprintf(":%d done\n", result);
44 }
45 #else
46 volatile const init_fn_t *fn_ptr;
47
48 for (fn_ptr = &__rt_init_rti_secondary_cpu_start; fn_ptr < &__rt_init_rti_secondary_cpu_end; ++fn_ptr)
49 {
50 (*fn_ptr)();
51 }
52 #endif /* RT_DEBUGING_AUTO_INIT */
53 }
54 #endif /* RT_USING_SMP */
55
56 /**
57 * @brief This function will alloc an id in an IDA object
58 *
59 * @param ida is the IDA object
60 *
61 * @return the id or -RT_EEMPTY
62 */
rt_dm_ida_alloc(struct rt_dm_ida * ida)63 int rt_dm_ida_alloc(struct rt_dm_ida *ida)
64 {
65 int id;
66 RT_ASSERT(ida != RT_NULL);
67
68 rt_spin_lock(&ida->lock);
69
70 id = rt_bitmap_next_clear_bit(ida->map, 0, RT_DM_IDA_NUM);
71
72 if (id != RT_DM_IDA_NUM)
73 {
74 rt_bitmap_set_bit(ida->map, id);
75 }
76
77 rt_spin_unlock(&ida->lock);
78
79 if (id != RT_DM_IDA_NUM)
80 {
81 return id;
82 }
83
84 return -RT_EEMPTY;
85 }
86
87 /**
88 * @brief This function will take (force) an id in an IDA object
89 *
90 * @param ida is the IDA object
91 *
92 * @param id is the id that want to take
93 *
94 * @return the result of taking
95 */
rt_dm_ida_take(struct rt_dm_ida * ida,int id)96 rt_bool_t rt_dm_ida_take(struct rt_dm_ida *ida, int id)
97 {
98 RT_ASSERT(ida != RT_NULL);
99 RT_ASSERT(id >= 0);
100
101 rt_spin_lock(&ida->lock);
102
103 if (!rt_bitmap_test_bit(ida->map, id))
104 {
105 rt_bitmap_set_bit(ida->map, id);
106 }
107 else
108 {
109 id = RT_DM_IDA_NUM;
110 }
111
112 rt_spin_unlock(&ida->lock);
113
114 return id != RT_DM_IDA_NUM;
115 }
116
117 /**
118 * @brief This function will release an id in an IDA object
119 *
120 * @param ida is the IDA object
121 *
122 * @param id is the id of IDA object
123 */
rt_dm_ida_free(struct rt_dm_ida * ida,int id)124 void rt_dm_ida_free(struct rt_dm_ida *ida, int id)
125 {
126 RT_ASSERT(ida != RT_NULL);
127 RT_ASSERT(id >= 0);
128
129 rt_spin_lock(&ida->lock);
130
131 rt_bitmap_clear_bit(ida->map, id);
132
133 rt_spin_unlock(&ida->lock);
134 }
135
136 /**
137 * @brief This function will return the specified master id and device id of device.
138 *
139 * @param master_id is the master id (0, 255] of device
140 *
141 * @param device_id is the device id [-1, 255] of device, when device_id is -1,
142 * the function will end when find the first device.
143 *
144 * @return the device object or RT_NULL
145 */
rt_dm_device_find(int master_id,int device_id)146 rt_device_t rt_dm_device_find(int master_id, int device_id)
147 {
148 struct rt_device *dev, *ret_dev = RT_NULL;
149 struct rt_object_information *information = RT_NULL;
150
151 if (master_id <= 0 || device_id > 255)
152 {
153 return RT_NULL;
154 }
155
156 information = rt_object_get_information(RT_Object_Class_Device);
157
158 /* parameter check */
159 if (!information)
160 {
161 return RT_NULL;
162 }
163
164 /* which is invoke in interrupt status */
165 RT_DEBUG_NOT_IN_INTERRUPT;
166
167 /* enter critical */
168 rt_enter_critical();
169
170 /* try to find object */
171 rt_list_for_each_entry(dev, &information->object_list, parent.list)
172 {
173 if (master_id == dev->master_id &&
174 (device_id == -1 || device_id == dev->device_id))
175 {
176 ret_dev = dev;
177 break;
178 }
179 }
180
181 /* leave critical */
182 rt_exit_critical();
183
184 return ret_dev;
185 }
186
187 struct prefix_track
188 {
189 rt_list_t list;
190
191 int uid;
192 const char *prefix;
193 };
194 static RT_DEFINE_SPINLOCK(_prefix_nodes_lock);
195 static rt_list_t _prefix_nodes = RT_LIST_OBJECT_INIT(_prefix_nodes);
196
rt_dm_dev_set_name_auto(rt_device_t dev,const char * prefix)197 int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix)
198 {
199 int uid = -1;
200 struct prefix_track *pt = RT_NULL;
201
202 RT_ASSERT(dev != RT_NULL);
203 RT_ASSERT(prefix != RT_NULL);
204
205 RT_DEBUG_NOT_IN_INTERRUPT;
206
207 rt_spin_lock(&_prefix_nodes_lock);
208
209 rt_list_for_each_entry(pt, &_prefix_nodes, list)
210 {
211 /* caller always input constants string, check ptr is faster */
212 if (pt->prefix == prefix || !rt_strcmp(pt->prefix, prefix))
213 {
214 uid = ++pt->uid;
215 break;
216 }
217 }
218
219 rt_spin_unlock(&_prefix_nodes_lock);
220
221 if (uid < 0)
222 {
223 pt = rt_malloc(sizeof(*pt));
224
225 if (!pt)
226 {
227 return -RT_ENOMEM;
228 }
229
230 rt_list_init(&pt->list);
231
232 pt->uid = uid = 0;
233 pt->prefix = prefix;
234
235 rt_spin_lock(&_prefix_nodes_lock);
236
237 rt_list_insert_before(&_prefix_nodes, &pt->list);
238
239 rt_spin_unlock(&_prefix_nodes_lock);
240 }
241
242 return rt_dm_dev_set_name(dev, "%s%u", prefix, uid);
243 }
244
rt_dm_dev_get_name_id(rt_device_t dev)245 int rt_dm_dev_get_name_id(rt_device_t dev)
246 {
247 int id = 0, len;
248 const char *name;
249
250 RT_ASSERT(dev != RT_NULL);
251
252 name = rt_dm_dev_get_name(dev);
253 len = rt_strlen(name) - 1;
254 name += len;
255
256 while (len --> 0)
257 {
258 if (*name < '0' || *name > '9')
259 {
260 while (*(++name))
261 {
262 id *= 10;
263 id += *name - '0';
264 }
265
266 break;
267 }
268
269 --name;
270 }
271
272 return id;
273 }
274
rt_dm_dev_set_name(rt_device_t dev,const char * format,...)275 int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...)
276 {
277 int n;
278 va_list arg_ptr;
279
280 RT_ASSERT(dev != RT_NULL);
281 RT_ASSERT(format != RT_NULL);
282
283 va_start(arg_ptr, format);
284 n = rt_vsnprintf(dev->parent.name, RT_NAME_MAX, format, arg_ptr);
285 va_end(arg_ptr);
286
287 return n;
288 }
289
rt_dm_dev_get_name(rt_device_t dev)290 const char *rt_dm_dev_get_name(rt_device_t dev)
291 {
292 RT_ASSERT(dev != RT_NULL);
293
294 return dev->parent.name;
295 }
296
297 #ifdef RT_USING_OFW
298 #define ofw_api_call(name, ...) rt_ofw_##name(__VA_ARGS__)
299 #define ofw_api_call_ptr(name, ...) ofw_api_call(name, __VA_ARGS__)
300 #else
301 #define ofw_api_call(name, ...) (-RT_ENOSYS)
302 #define ofw_api_call_ptr(name, ...) RT_NULL
303 #endif
304
rt_dm_dev_get_address_count(rt_device_t dev)305 int rt_dm_dev_get_address_count(rt_device_t dev)
306 {
307 RT_ASSERT(dev != RT_NULL);
308
309 #ifdef RT_USING_OFW
310 if (dev->ofw_node)
311 {
312 return ofw_api_call(get_address_count, dev->ofw_node);
313 }
314 #endif
315
316 return -RT_ENOSYS;
317 }
318
rt_dm_dev_get_address(rt_device_t dev,int index,rt_uint64_t * out_address,rt_uint64_t * out_size)319 rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index,
320 rt_uint64_t *out_address, rt_uint64_t *out_size)
321 {
322 RT_ASSERT(dev != RT_NULL);
323
324 #ifdef RT_USING_OFW
325 if (dev->ofw_node)
326 {
327 return ofw_api_call(get_address, dev->ofw_node, index,
328 out_address, out_size);
329 }
330 #endif
331
332 return -RT_ENOSYS;
333 }
334
rt_dm_dev_get_address_by_name(rt_device_t dev,const char * name,rt_uint64_t * out_address,rt_uint64_t * out_size)335 rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name,
336 rt_uint64_t *out_address, rt_uint64_t *out_size)
337 {
338 RT_ASSERT(dev != RT_NULL);
339
340 #ifdef RT_USING_OFW
341 if (dev->ofw_node)
342 {
343 return ofw_api_call(get_address_by_name, dev->ofw_node, name,
344 out_address, out_size);
345 }
346 #endif
347
348 return -RT_ENOSYS;
349 }
350
rt_dm_dev_get_address_array(rt_device_t dev,int nr,rt_uint64_t * out_regs)351 int rt_dm_dev_get_address_array(rt_device_t dev, int nr, rt_uint64_t *out_regs)
352 {
353 RT_ASSERT(dev != RT_NULL);
354
355 #ifdef RT_USING_OFW
356 if (dev->ofw_node)
357 {
358 return ofw_api_call(get_address_array, dev->ofw_node, nr, out_regs);
359 }
360 #endif
361
362 return -RT_ENOSYS;
363 }
364
rt_dm_dev_iomap(rt_device_t dev,int index)365 void *rt_dm_dev_iomap(rt_device_t dev, int index)
366 {
367 RT_ASSERT(dev != RT_NULL);
368
369 #ifdef RT_USING_OFW
370 if (dev->ofw_node)
371 {
372 return ofw_api_call_ptr(iomap, dev->ofw_node, index);
373 }
374 #endif
375
376 return RT_NULL;
377 }
378
rt_dm_dev_iomap_by_name(rt_device_t dev,const char * name)379 void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name)
380 {
381 RT_ASSERT(dev != RT_NULL);
382
383 #ifdef RT_USING_OFW
384 if (dev->ofw_node)
385 {
386 return ofw_api_call_ptr(iomap_by_name, dev->ofw_node, name);
387 }
388 #endif
389
390 return RT_NULL;
391 }
392
rt_dm_dev_get_irq_count(rt_device_t dev)393 int rt_dm_dev_get_irq_count(rt_device_t dev)
394 {
395 RT_ASSERT(dev != RT_NULL);
396
397 #if defined(RT_USING_OFW) && defined(RT_USING_PIC)
398 if (dev->ofw_node)
399 {
400 return ofw_api_call(get_irq_count, dev->ofw_node);
401 }
402 #endif
403
404 return -RT_ENOSYS;
405 }
406
rt_dm_dev_get_irq(rt_device_t dev,int index)407 int rt_dm_dev_get_irq(rt_device_t dev, int index)
408 {
409 RT_ASSERT(dev != RT_NULL);
410
411 #if defined(RT_USING_OFW) && defined(RT_USING_PIC)
412 if (dev->ofw_node)
413 {
414 return ofw_api_call(get_irq, dev->ofw_node, index);
415 }
416 #endif
417
418 return -RT_ENOSYS;
419 }
420
rt_dm_dev_get_irq_by_name(rt_device_t dev,const char * name)421 int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name)
422 {
423 RT_ASSERT(dev != RT_NULL);
424
425 #if defined(RT_USING_OFW) && defined(RT_USING_PIC)
426 if (dev->ofw_node)
427 {
428 return ofw_api_call(get_irq_by_name, dev->ofw_node, name);
429 }
430 #endif
431
432 return -RT_ENOSYS;
433 }
434
rt_dm_dev_bind_fwdata(rt_device_t dev,void * fw_np,void * data)435 void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data)
436 {
437 RT_ASSERT(dev != RT_NULL);
438
439 #ifdef RT_USING_OFW
440 if (!dev->ofw_node && fw_np)
441 {
442 dev->ofw_node = fw_np;
443 rt_ofw_data(fw_np) = data;
444 }
445
446 if (dev->ofw_node == RT_NULL)
447 {
448 rt_kprintf("[%s:%s] line=%d ofw_node is NULL\r\n", __FILE__, __func__, __LINE__);
449 return;
450 }
451
452 rt_ofw_data(dev->ofw_node) = data;
453 #endif
454 }
455
rt_dm_dev_unbind_fwdata(rt_device_t dev,void * fw_np)456 void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np)
457 {
458 RT_ASSERT(dev!= RT_NULL);
459
460 #ifdef RT_USING_OFW
461 void *dev_fw_np = RT_NULL;
462
463 if (!dev->ofw_node && fw_np)
464 {
465 dev_fw_np = fw_np;
466 rt_ofw_data(fw_np) = RT_NULL;
467 }
468
469 if (dev_fw_np == RT_NULL)
470 {
471 rt_kprintf("[%s:%s] line=%d dev_fw_np is NULL\r\n", __FILE__, __func__, __LINE__);
472 return;
473 }
474
475 rt_ofw_data(dev_fw_np) = RT_NULL;
476 #endif
477 }
478
rt_dm_dev_prop_read_u8_array_index(rt_device_t dev,const char * propname,int index,int nr,rt_uint8_t * out_values)479 int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname,
480 int index, int nr, rt_uint8_t *out_values)
481 {
482 RT_ASSERT(dev != RT_NULL);
483
484 #ifdef RT_UISNG_OFW
485 if (dev->ofw_node)
486 {
487 return ofw_api_call(prop_read_u8_array_index, dev->ofw_node, propname,
488 index, nr, out_value);
489 }
490 #endif
491
492 return -RT_ENOSYS;
493 }
494
rt_dm_dev_prop_read_u16_array_index(rt_device_t dev,const char * propname,int index,int nr,rt_uint16_t * out_values)495 int rt_dm_dev_prop_read_u16_array_index(rt_device_t dev, const char *propname,
496 int index, int nr, rt_uint16_t *out_values)
497 {
498 RT_ASSERT(dev != RT_NULL);
499
500 #ifdef RT_USING_OFW
501 if (dev->ofw_node)
502 {
503 return ofw_api_call(prop_read_u16_array_index, dev->ofw_node, propname,
504 index, nr, out_values);
505 }
506 #endif
507
508 return -RT_ENOSYS;
509 }
510
rt_dm_dev_prop_read_u32_array_index(rt_device_t dev,const char * propname,int index,int nr,rt_uint32_t * out_values)511 int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname,
512 int index, int nr, rt_uint32_t *out_values)
513 {
514 RT_ASSERT(dev != RT_NULL);
515
516 #ifdef RT_USING_OFW
517 if (dev->ofw_node)
518 {
519 return ofw_api_call(prop_read_u32_array_index, dev->ofw_node, propname,
520 index, nr, out_values);
521 }
522 #endif
523
524 return -RT_ENOSYS;
525 }
526
rt_dm_dev_prop_read_u64_array_index(rt_device_t dev,const char * propname,int index,int nr,rt_uint64_t * out_values)527 int rt_dm_dev_prop_read_u64_array_index(rt_device_t dev, const char *propname,
528 int index, int nr, rt_uint64_t *out_values)
529 {
530 RT_ASSERT(dev != RT_NULL);
531
532 #ifdef RT_USING_OFW
533 if (dev->ofw_node)
534 {
535 return ofw_api_call(prop_read_u64_array_index, dev->ofw_node, propname,
536 index, nr, out_values);
537 }
538 #endif
539
540 return -RT_ENOSYS;
541 }
542
rt_dm_dev_prop_read_string_array_index(rt_device_t dev,const char * propname,int index,int nr,const char ** out_strings)543 int rt_dm_dev_prop_read_string_array_index(rt_device_t dev, const char *propname,
544 int index, int nr, const char **out_strings)
545 {
546 RT_ASSERT(dev != RT_NULL);
547
548 #ifdef RT_USING_OFW
549 if (dev->ofw_node)
550 {
551 return ofw_api_call(prop_read_string_array_index, dev->ofw_node, propname,
552 index, nr, out_strings);
553 }
554 #endif
555
556 return -RT_ENOSYS;
557 }
558
rt_dm_dev_prop_count_of_size(rt_device_t dev,const char * propname,int size)559 int rt_dm_dev_prop_count_of_size(rt_device_t dev, const char *propname, int size)
560 {
561 RT_ASSERT(dev != RT_NULL);
562
563 #ifdef RT_USING_OFW
564 if (dev->ofw_node)
565 {
566 return ofw_api_call(prop_count_of_size, dev->ofw_node, propname, size);
567 }
568 #endif
569
570 return -RT_ENOSYS;
571 }
572
rt_dm_dev_prop_index_of_string(rt_device_t dev,const char * propname,const char * string)573 int rt_dm_dev_prop_index_of_string(rt_device_t dev, const char *propname, const char *string)
574 {
575 RT_ASSERT(dev != RT_NULL);
576
577 #ifdef RT_USING_OFW
578 if (dev->ofw_node)
579 {
580 return ofw_api_call(prop_index_of_string, dev->ofw_node, propname, string);
581 }
582 #endif
583
584 return -RT_ENOSYS;
585 }
586
rt_dm_dev_prop_read_bool(rt_device_t dev,const char * propname)587 rt_bool_t rt_dm_dev_prop_read_bool(rt_device_t dev, const char *propname)
588 {
589 RT_ASSERT(dev != RT_NULL);
590
591 #ifdef RT_USING_OFW
592 if (dev->ofw_node)
593 {
594 return ofw_api_call(prop_read_bool, dev->ofw_node, propname);
595 }
596 #endif
597
598 return RT_FALSE;
599 }
600
601