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-06-04     GuEe-GUI     the first version
9  */
10 
11 #include <rtthread.h>
12 
13 #define DBG_TAG "drv.platform"
14 #define DBG_LVL DBG_INFO
15 #include <rtdbg.h>
16 
17 #include <drivers/ofw_io.h>
18 #include <drivers/ofw_fdt.h>
19 #include <drivers/platform.h>
20 #include <drivers/core/bus.h>
21 #include <drivers/core/dm.h>
22 
23 #include "../ofw/ofw_internal.h"
24 
25 static const struct rt_ofw_node_id platform_ofw_ids[] =
26 {
27     { .compatible = "simple-bus", },
28 #ifdef RT_USING_MFD
29     { .compatible = "simple-mfd", },
30 #endif
31 #ifdef RT_USING_ISA
32     { .compatible = "isa", },
33 #endif
34 #ifdef RT_USING_AMBA_BUS
35     /*
36      * Maybe ARM has replaced it with compatible: "arm,primecell" and will not
37      * used anymore in the future.
38      */
39     { .compatible = "arm,amba-bus", },
40 #endif
41     { /* sentinel */ }
42 };
43 
ofw_device_rename(struct rt_device * dev)44 static void ofw_device_rename(struct rt_device *dev)
45 {
46     rt_uint32_t mask;
47     rt_uint64_t addr;
48     const char *dev_name = dev->parent.name;
49     struct rt_ofw_node *np = dev->ofw_node;
50 
51 #if RT_NAME_MAX > 0
52     if (dev_name[0] == '\0')
53     {
54         dev_name = RT_NULL;
55     }
56 #endif
57 
58     while (np->parent)
59     {
60         if (!rt_ofw_get_address(np, 0, &addr, RT_NULL))
61         {
62             const char *node_name = rt_fdt_node_name(np->full_name);
63             rt_size_t tag_len = strchrnul(node_name, '@') - node_name;
64 
65             if (!rt_ofw_prop_read_u32(np, "mask", &mask))
66             {
67                 rt_dm_dev_set_name(dev, dev_name ? "%lx.%x.%.*s:%s" : "%lx.%x.%.*s",
68                     addr, __rt_ffs(mask) - 1, tag_len, node_name, dev_name);
69             }
70             else
71             {
72                 rt_dm_dev_set_name(dev, dev_name ? "%lx.%.*s:%s" : "%lx.%.*s",
73                     addr, tag_len, node_name, dev_name);
74             }
75 
76             return;
77         }
78 
79         rt_dm_dev_set_name(dev, dev_name ? "%s:%s" : "%s",
80                 rt_fdt_node_name(np->full_name), dev_name);
81 
82         np = np->parent;
83     }
84 }
85 
alloc_ofw_platform_device(struct rt_ofw_node * np)86 static struct rt_platform_device *alloc_ofw_platform_device(struct rt_ofw_node *np)
87 {
88     struct rt_platform_device *pdev = rt_platform_device_alloc("");
89 
90     if (pdev)
91     {
92         /* inc reference of dt-node */
93         rt_ofw_node_get(np);
94         rt_ofw_node_set_flag(np, RT_OFW_F_PLATFORM);
95 
96         pdev->parent.ofw_node = np;
97 
98         ofw_device_rename(&pdev->parent);
99     }
100     else
101     {
102         LOG_E("Alloc device fail for %s", rt_ofw_node_full_name(np));
103     }
104 
105     return pdev;
106 }
107 
platform_ofw_device_probe_once(struct rt_ofw_node * parent_np)108 static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
109 {
110     rt_err_t err = RT_EOK;
111     struct rt_ofw_node *np;
112     struct rt_platform_device *pdev;
113 
114     rt_ofw_foreach_available_child_node(parent_np, np)
115     {
116         const char *name;
117         struct rt_ofw_node_id *id;
118         struct rt_ofw_prop *compat_prop = RT_NULL;
119 
120         if (np->dev)
121         {
122             /* Check first */
123             continue;
124         }
125 
126         LOG_D("%s found in %s", np->full_name, parent_np->full_name);
127 
128         /* Is system node or have driver */
129         if (rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM) ||
130             rt_ofw_node_test_flag(np, RT_OFW_F_READLY))
131         {
132             continue;
133         }
134 
135         compat_prop = rt_ofw_get_prop(np, "compatible", RT_NULL);
136         name = rt_ofw_node_name(np);
137 
138         /* Not have name and compatible */
139         if (!compat_prop && (name == (const char *)"<NULL>" || !rt_strcmp(name, "<NULL>")))
140         {
141             continue;
142         }
143 
144         id = rt_ofw_prop_match(compat_prop, platform_ofw_ids);
145 
146         if (id && np->child)
147         {
148             /* scan next level */
149             err = platform_ofw_device_probe_once(np);
150 
151             if (err)
152             {
153                 rt_ofw_node_put(np);
154                 LOG_E("%s bus probe fail", np->full_name);
155 
156                 break;
157             }
158         }
159 
160         if (np->dev)
161         {
162             /* Maybe the childs have requested this node */
163             continue;
164         }
165 
166         pdev = alloc_ofw_platform_device(np);
167 
168         if (!pdev)
169         {
170             rt_ofw_node_put(np);
171             err = -RT_ENOMEM;
172 
173             break;
174         }
175 
176         pdev->dev_id = ofw_alias_node_id(np);
177         np->dev = &pdev->parent;
178         LOG_D("%s register to bus", np->full_name);
179 
180         rt_platform_device_register(pdev);
181     }
182 
183     return err;
184 }
185 
rt_platform_ofw_device_probe_child(struct rt_ofw_node * np)186 rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np)
187 {
188     rt_err_t err;
189     struct rt_ofw_node *parent = rt_ofw_get_parent(np);
190 
191     if (parent && rt_strcmp(parent->name, "/") &&
192         rt_ofw_get_prop(np, "compatible", RT_NULL) &&
193         !rt_ofw_node_test_flag(np, RT_OFW_F_PLATFORM))
194     {
195         struct rt_platform_device *pdev = alloc_ofw_platform_device(np);
196 
197         if (pdev)
198         {
199             err = rt_platform_device_register(pdev);
200         }
201         else
202         {
203             err = -RT_ENOMEM;
204         }
205     }
206     else
207     {
208         err = -RT_EINVAL;
209     }
210 
211     rt_ofw_node_put(parent);
212 
213     return err;
214 }
215 
rt_platform_ofw_request(struct rt_ofw_node * np)216 rt_err_t rt_platform_ofw_request(struct rt_ofw_node *np)
217 {
218     rt_err_t err;
219 
220     if (np)
221     {
222         struct rt_device *dev = np->dev;
223 
224         if (dev)
225         {
226             /* Was create */
227             if (dev->drv)
228             {
229                 /* Was probe OK */
230                 err = RT_EOK;
231             }
232             else
233             {
234                 err = rt_bus_reload_driver_device(dev->bus, dev);
235             }
236         }
237         else
238         {
239             struct rt_platform_device *pdev = alloc_ofw_platform_device(np);
240 
241             if (pdev)
242             {
243                 pdev->dev_id = ofw_alias_node_id(np);
244                 np->dev = &pdev->parent;
245                 LOG_D("%s register to bus", np->full_name);
246 
247                 err = rt_platform_device_register(pdev);
248             }
249             else
250             {
251                 err = -RT_ENOMEM;
252             }
253         }
254     }
255     else
256     {
257         err = -RT_EINVAL;
258     }
259 
260     return err;
261 }
262 
platform_ofw_device_probe(void)263 static int platform_ofw_device_probe(void)
264 {
265     rt_err_t err = RT_EOK;
266     struct rt_ofw_node *node;
267 
268     if (ofw_node_root)
269     {
270         rt_ofw_node_get(ofw_node_root);
271 
272         err = platform_ofw_device_probe_once(ofw_node_root);
273 
274         rt_ofw_node_put(ofw_node_root);
275 
276         if ((node = rt_ofw_find_node_by_path("/firmware")))
277         {
278             platform_ofw_device_probe_once(node);
279             rt_ofw_node_put(node);
280         }
281 
282         if ((node = rt_ofw_find_node_by_path("/clocks")))
283         {
284             platform_ofw_device_probe_once(node);
285             rt_ofw_node_put(node);
286         }
287 
288         rt_ofw_node_get(ofw_node_chosen);
289         if ((node = rt_ofw_get_child_by_compatible(ofw_node_chosen, "simple-framebuffer")))
290         {
291             platform_ofw_device_probe_once(node);
292             rt_ofw_node_put(node);
293         }
294         rt_ofw_node_get(ofw_node_chosen);
295     }
296     else
297     {
298         err = -RT_ENOSYS;
299     }
300 
301     return (int)err;
302 }
303 INIT_PLATFORM_EXPORT(platform_ofw_device_probe);
304 
rt_platform_ofw_free(struct rt_platform_device * pdev)305 rt_err_t rt_platform_ofw_free(struct rt_platform_device *pdev)
306 {
307     rt_err_t err = RT_EOK;
308 
309     if (pdev)
310     {
311         struct rt_ofw_node *np = pdev->parent.ofw_node;
312 
313         if (np)
314         {
315             rt_ofw_node_clear_flag(np, RT_OFW_F_PLATFORM);
316             rt_ofw_node_put(np);
317 
318             rt_free(pdev);
319         }
320     }
321     else
322     {
323         err = -RT_EINVAL;
324     }
325 
326     return err;
327 }
328