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