source: rtems-libbsd/freebsd/sys/dev/ofw/ofw_fdt.c @ f0dd0c5

55-freebsd-126-freebsd-12
Last change on this file since f0dd0c5 was f0dd0c5, checked in by Sebastian Huber <sebastian.huber@…>, on 03/02/17 at 15:28:14

FDT(4): Import from FreeBSD

  • Property mode set to 100644
File size: 12.3 KB
RevLine 
[f0dd0c5]1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * All rights reserved.
6 *
7 * This software was developed by Semihalf under sponsorship from
8 * the FreeBSD Foundation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34
35#include <rtems/bsd/sys/param.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/systm.h>
39
40#include <contrib/libfdt/libfdt.h>
41
42#include <machine/stdarg.h>
43
44#include <dev/fdt/fdt_common.h>
45#include <dev/ofw/ofwvar.h>
46#include <dev/ofw/openfirm.h>
47
48#include <rtems/bsd/local/ofw_if.h>
49
50#ifdef DEBUG
51#define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
52    printf(fmt,##args); } while (0)
53#else
54#define debugf(fmt, args...)
55#endif
56
57#if defined(__arm__)
58#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) || \
59    defined(SOC_MV_DISCOVERY) || defined(SOC_MV_DOVE) || \
60    defined(SOC_MV_FREY) || defined(SOC_MV_KIRKWOOD) || \
61    defined(SOC_MV_LOKIPLUS) || defined(SOC_MV_ORION)
62#define FDT_MARVELL
63#endif
64#endif
65
66static int ofw_fdt_init(ofw_t, void *);
67static phandle_t ofw_fdt_peer(ofw_t, phandle_t);
68static phandle_t ofw_fdt_child(ofw_t, phandle_t);
69static phandle_t ofw_fdt_parent(ofw_t, phandle_t);
70static phandle_t ofw_fdt_instance_to_package(ofw_t, ihandle_t);
71static ssize_t ofw_fdt_getproplen(ofw_t, phandle_t, const char *);
72static ssize_t ofw_fdt_getprop(ofw_t, phandle_t, const char *, void *, size_t);
73static int ofw_fdt_nextprop(ofw_t, phandle_t, const char *, char *, size_t);
74static int ofw_fdt_setprop(ofw_t, phandle_t, const char *, const void *,
75    size_t);
76static ssize_t ofw_fdt_canon(ofw_t, const char *, char *, size_t);
77static phandle_t ofw_fdt_finddevice(ofw_t, const char *);
78static ssize_t ofw_fdt_instance_to_path(ofw_t, ihandle_t, char *, size_t);
79static ssize_t ofw_fdt_package_to_path(ofw_t, phandle_t, char *, size_t);
80static int ofw_fdt_interpret(ofw_t, const char *, int, cell_t *);
81
82static ofw_method_t ofw_fdt_methods[] = {
83        OFWMETHOD(ofw_init,                     ofw_fdt_init),
84        OFWMETHOD(ofw_peer,                     ofw_fdt_peer),
85        OFWMETHOD(ofw_child,                    ofw_fdt_child),
86        OFWMETHOD(ofw_parent,                   ofw_fdt_parent),
87        OFWMETHOD(ofw_instance_to_package,      ofw_fdt_instance_to_package),
88        OFWMETHOD(ofw_getproplen,               ofw_fdt_getproplen),
89        OFWMETHOD(ofw_getprop,                  ofw_fdt_getprop),
90        OFWMETHOD(ofw_nextprop,                 ofw_fdt_nextprop),
91        OFWMETHOD(ofw_setprop,                  ofw_fdt_setprop),
92        OFWMETHOD(ofw_canon,                    ofw_fdt_canon),
93        OFWMETHOD(ofw_finddevice,               ofw_fdt_finddevice),
94        OFWMETHOD(ofw_instance_to_path,         ofw_fdt_instance_to_path),
95        OFWMETHOD(ofw_package_to_path,          ofw_fdt_package_to_path),
96        OFWMETHOD(ofw_interpret,                ofw_fdt_interpret),
97        { 0, 0 }
98};
99
100static ofw_def_t ofw_fdt = {
101        OFW_FDT,
102        ofw_fdt_methods,
103        0
104};
105OFW_DEF(ofw_fdt);
106
107static void *fdtp = NULL;
108
109static int
110sysctl_handle_dtb(SYSCTL_HANDLER_ARGS)
111{
112
113        return (sysctl_handle_opaque(oidp, fdtp, fdt_totalsize(fdtp), req));
114}
115
116static void
117sysctl_register_fdt_oid(void *arg)
118{
119
120        /* If there is no FDT registered, skip adding the sysctl */
121        if (fdtp == NULL)
122                return;
123
124        SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_fdt), OID_AUTO, "dtb",
125            CTLTYPE_OPAQUE | CTLFLAG_RD, NULL, 0, sysctl_handle_dtb, "",
126            "Device Tree Blob");
127}
128SYSINIT(dtb_oid, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_fdt_oid, 0);
129
130static int
131ofw_fdt_init(ofw_t ofw, void *data)
132{
133        int err;
134
135        /* Check FDT blob integrity */
136        if ((err = fdt_check_header(data)) != 0)
137                return (err);
138
139        fdtp = data;
140        return (0);
141}
142
143/*
144 * Device tree functions.
145 *
146 * We use the offset from fdtp to the node as the 'phandle' in OF interface.
147 *
148 * phandle is a u32 value, therefore we cannot use the pointer to node as
149 * phandle in 64 bit. We also do not use the usual fdt offset as phandle,
150 * as it can be 0, and the OF interface has special meaning for phandle 0.
151 */
152
153static phandle_t
154fdt_offset_phandle(int offset)
155{
156        if (offset < 0)
157                return (0);
158        return ((phandle_t)offset + fdt_off_dt_struct(fdtp));
159}
160
161static int
162fdt_phandle_offset(phandle_t p)
163{
164        int pint = (int)p;
165        int dtoff = fdt_off_dt_struct(fdtp);
166
167        if (pint < dtoff)
168                return (-1);
169        return (pint - dtoff);
170}
171
172/* Return the next sibling of this node or 0. */
173static phandle_t
174ofw_fdt_peer(ofw_t ofw, phandle_t node)
175{
176        int depth, offset;
177
178        if (node == 0) {
179                /* Find root node */
180                offset = fdt_path_offset(fdtp, "/");
181
182                return (fdt_offset_phandle(offset));
183        }
184
185        offset = fdt_phandle_offset(node);
186        if (offset < 0)
187                return (0);
188
189        for (depth = 1, offset = fdt_next_node(fdtp, offset, &depth);
190            offset >= 0;
191            offset = fdt_next_node(fdtp, offset, &depth)) {
192                if (depth < 0)
193                        return (0);
194                if (depth == 1)
195                        return (fdt_offset_phandle(offset));
196        }
197
198        return (0);
199}
200
201/* Return the first child of this node or 0. */
202static phandle_t
203ofw_fdt_child(ofw_t ofw, phandle_t node)
204{
205        int depth, offset;
206
207        offset = fdt_phandle_offset(node);
208        if (offset < 0)
209                return (0);
210
211        for (depth = 0, offset = fdt_next_node(fdtp, offset, &depth);
212            (offset >= 0) && (depth > 0);
213            offset = fdt_next_node(fdtp, offset, &depth)) {
214                if (depth < 0)
215                        return (0);
216                if (depth == 1)
217                        return (fdt_offset_phandle(offset));
218        }
219
220        return (0);
221}
222
223/* Return the parent of this node or 0. */
224static phandle_t
225ofw_fdt_parent(ofw_t ofw, phandle_t node)
226{
227        int offset, paroffset;
228
229        offset = fdt_phandle_offset(node);
230        if (offset < 0)
231                return (0);
232
233        paroffset = fdt_parent_offset(fdtp, offset);
234        return (fdt_offset_phandle(paroffset));
235}
236
237/* Return the package handle that corresponds to an instance handle. */
238static phandle_t
239ofw_fdt_instance_to_package(ofw_t ofw, ihandle_t instance)
240{
241
242        /* Where real OF uses ihandles in the tree, FDT uses xref phandles */
243        return (OF_node_from_xref(instance));
244}
245
246/* Get the length of a property of a package. */
247static ssize_t
248ofw_fdt_getproplen(ofw_t ofw, phandle_t package, const char *propname)
249{
250        const struct fdt_property *prop;
251        int offset, len;
252
253        offset = fdt_phandle_offset(package);
254        if (offset < 0)
255                return (-1);
256
257        len = -1;
258        prop = fdt_get_property(fdtp, offset, propname, &len);
259
260        if (prop == NULL && strcmp(propname, "name") == 0) {
261                /* Emulate the 'name' property */
262                fdt_get_name(fdtp, offset, &len);
263                return (len + 1);
264        }
265
266        if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) {
267                if (strcmp(propname, "fdtbootcpu") == 0)
268                        return (sizeof(cell_t));
269                if (strcmp(propname, "fdtmemreserv") == 0)
270                        return (sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp));
271        }
272
273        if (prop == NULL)
274                return (-1);
275
276        return (len);
277}
278
279/* Get the value of a property of a package. */
280static ssize_t
281ofw_fdt_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
282    size_t buflen)
283{
284        const void *prop;
285        const char *name;
286        int len, offset;
287        uint32_t cpuid;
288
289        offset = fdt_phandle_offset(package);
290        if (offset < 0)
291                return (-1);
292
293        prop = fdt_getprop(fdtp, offset, propname, &len);
294
295        if (prop == NULL && strcmp(propname, "name") == 0) {
296                /* Emulate the 'name' property */
297                name = fdt_get_name(fdtp, offset, &len);
298                strncpy(buf, name, buflen);
299                if (len + 1 > buflen)
300                        len = buflen;
301                return (len + 1);
302        }
303
304        if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) {
305                if (strcmp(propname, "fdtbootcpu") == 0) {
306                        cpuid = cpu_to_fdt32(fdt_boot_cpuid_phys(fdtp));
307                        len = sizeof(cpuid);
308                        prop = &cpuid;
309                }
310                if (strcmp(propname, "fdtmemreserv") == 0) {
311                        prop = (char *)fdtp + fdt_off_mem_rsvmap(fdtp);
312                        len = sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp);
313                }
314        }
315
316        if (prop == NULL)
317                return (-1);
318
319        if (len > buflen)
320                len = buflen;
321        bcopy(prop, buf, len);
322        return (len);
323}
324
325/*
326 * Get the next property of a package. Return values:
327 *  -1: package or previous property does not exist
328 *   0: no more properties
329 *   1: success
330 */
331static int
332ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf,
333    size_t size)
334{
335        const struct fdt_property *prop;
336        const char *name;
337        int offset;
338
339        offset = fdt_phandle_offset(package);
340        if (offset < 0)
341                return (-1);
342
343        /* Find the first prop in the node */
344        offset = fdt_first_property_offset(fdtp, offset);
345        if (offset < 0)
346                return (0); /* No properties */
347
348        if (previous != NULL) {
349                while (offset >= 0) {
350                        prop = fdt_get_property_by_offset(fdtp, offset, NULL);
351                        if (prop == NULL)
352                                return (-1); /* Internal error */
353
354                        offset = fdt_next_property_offset(fdtp, offset);
355                        if (offset < 0)
356                                return (0); /* No more properties */
357
358                        /* Check if the last one was the one we wanted */
359                        name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
360                        if (strcmp(name, previous) == 0)
361                                break;
362                }
363        }
364
365        prop = fdt_get_property_by_offset(fdtp, offset, &offset);
366        if (prop == NULL)
367                return (-1); /* Internal error */
368
369        strncpy(buf, fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)), size);
370
371        return (1);
372}
373
374/* Set the value of a property of a package. */
375static int
376ofw_fdt_setprop(ofw_t ofw, phandle_t package, const char *propname,
377    const void *buf, size_t len)
378{
379        int offset;
380
381        offset = fdt_phandle_offset(package);
382        if (offset < 0)
383                return (-1);
384
385        return (fdt_setprop_inplace(fdtp, offset, propname, buf, len));
386}
387
388/* Convert a device specifier to a fully qualified pathname. */
389static ssize_t
390ofw_fdt_canon(ofw_t ofw, const char *device, char *buf, size_t len)
391{
392
393        return (-1);
394}
395
396/* Return a package handle for the specified device. */
397static phandle_t
398ofw_fdt_finddevice(ofw_t ofw, const char *device)
399{
400        int offset;
401
402        offset = fdt_path_offset(fdtp, device);
403        if (offset < 0)
404                return (-1);
405        return (fdt_offset_phandle(offset));
406}
407
408/* Return the fully qualified pathname corresponding to an instance. */
409static ssize_t
410ofw_fdt_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
411{
412        phandle_t phandle;
413
414        phandle = OF_instance_to_package(instance);
415        if (phandle == -1)
416                return (-1);
417
418        return (OF_package_to_path(phandle, buf, len));
419}
420
421/* Return the fully qualified pathname corresponding to a package. */
422static ssize_t
423ofw_fdt_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
424{
425
426        return (-1);
427}
428
429#if defined(FDT_MARVELL) || defined(__powerpc__)
430static int
431ofw_fdt_fixup(ofw_t ofw)
432{
433#define FDT_MODEL_LEN   80
434        char model[FDT_MODEL_LEN];
435        phandle_t root;
436        ssize_t len;
437        int i;
438
439        if ((root = ofw_fdt_finddevice(ofw, "/")) == -1)
440                return (ENODEV);
441
442        if ((len = ofw_fdt_getproplen(ofw, root, "model")) <= 0)
443                return (0);
444
445        bzero(model, FDT_MODEL_LEN);
446        if (ofw_fdt_getprop(ofw, root, "model", model, FDT_MODEL_LEN) <= 0)
447                return (0);
448
449        /*
450         * Search fixup table and call handler if appropriate.
451         */
452        for (i = 0; fdt_fixup_table[i].model != NULL; i++) {
453                if (strncmp(model, fdt_fixup_table[i].model,
454                    FDT_MODEL_LEN) != 0)
455                        continue;
456
457                if (fdt_fixup_table[i].handler != NULL)
458                        (*fdt_fixup_table[i].handler)(root);
459        }
460
461        return (0);
462}
463#endif
464
465static int
466ofw_fdt_interpret(ofw_t ofw, const char *cmd, int nret, cell_t *retvals)
467{
468#if defined(FDT_MARVELL) || defined(__powerpc__)
469        int rv;
470
471        /*
472         * Note: FDT does not have the possibility to 'interpret' commands,
473         * but we abuse the interface a bit to use it for doing non-standard
474         * operations on the device tree blob.
475         *
476         * Currently the only supported 'command' is to trigger performing
477         * fixups.
478         */
479        if (strncmp("perform-fixup", cmd, 13) != 0)
480                return (0);
481
482        rv = ofw_fdt_fixup(ofw);
483        if (nret > 0)
484                retvals[0] = rv;
485
486        return (rv);
487#else
488        return (0);
489#endif
490}
Note: See TracBrowser for help on using the repository browser.