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

6-freebsd-12
Last change on this file was 3489e3b, checked in by Sebastian Huber <sebastian.huber@…>, on 08/22/18 at 12:59:50

Update to FreeBSD head 2018-09-17

Git mirror commit 6c2192b1ef8c50788c751f878552526800b1e319.

Update #3472.

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