linux/arch/powerpc/boot/libfdt-wrapper.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * This file does the necessary interface mapping between the bootwrapper
   4 * device tree operations and the interface provided by shared source
   5 * files flatdevicetree.[ch].
   6 *
   7 * Copyright 2007 David Gibson, IBM Corporation.
   8 */
   9
  10#include <stddef.h>
  11#include <stdio.h>
  12#include <page.h>
  13#include <libfdt.h>
  14#include "ops.h"
  15
  16#define DEBUG   0
  17#define BAD_ERROR(err)  (((err) < 0) \
  18                         && ((err) != -FDT_ERR_NOTFOUND) \
  19                         && ((err) != -FDT_ERR_EXISTS))
  20
  21#define check_err(err) \
  22        ({ \
  23                if (BAD_ERROR(err) || ((err < 0) && DEBUG)) \
  24                        printf("%s():%d  %s\n\r", __func__, __LINE__, \
  25                               fdt_strerror(err)); \
  26                if (BAD_ERROR(err)) \
  27                        exit(); \
  28                (err < 0) ? -1 : 0; \
  29        })
  30
  31#define offset_devp(off)        \
  32        ({ \
  33                unsigned long _offset = (off); \
  34                check_err(_offset) ? NULL : (void *)(_offset+1); \
  35        })
  36
  37#define devp_offset_find(devp)  (((unsigned long)(devp))-1)
  38#define devp_offset(devp)       (devp ? ((unsigned long)(devp))-1 : 0)
  39
  40static void *fdt;
  41static void *buf; /* = NULL */
  42
  43#define EXPAND_GRANULARITY      1024
  44
  45static void expand_buf(int minexpand)
  46{
  47        int size = fdt_totalsize(fdt);
  48        int rc;
  49
  50        size = _ALIGN(size + minexpand, EXPAND_GRANULARITY);
  51        buf = platform_ops.realloc(buf, size);
  52        if (!buf)
  53                fatal("Couldn't find %d bytes to expand device tree\n\r", size);
  54        rc = fdt_open_into(fdt, buf, size);
  55        if (rc != 0)
  56                fatal("Couldn't expand fdt into new buffer: %s\n\r",
  57                      fdt_strerror(rc));
  58
  59        fdt = buf;
  60}
  61
  62static void *fdt_wrapper_finddevice(const char *path)
  63{
  64        return offset_devp(fdt_path_offset(fdt, path));
  65}
  66
  67static int fdt_wrapper_getprop(const void *devp, const char *name,
  68                               void *buf, const int buflen)
  69{
  70        const void *p;
  71        int len;
  72
  73        p = fdt_getprop(fdt, devp_offset(devp), name, &len);
  74        if (!p)
  75                return check_err(len);
  76        memcpy(buf, p, min(len, buflen));
  77        return len;
  78}
  79
  80static int fdt_wrapper_setprop(const void *devp, const char *name,
  81                               const void *buf, const int len)
  82{
  83        int rc;
  84
  85        rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len);
  86        if (rc == -FDT_ERR_NOSPACE) {
  87                expand_buf(len + 16);
  88                rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len);
  89        }
  90
  91        return check_err(rc);
  92}
  93
  94static int fdt_wrapper_del_node(const void *devp)
  95{
  96        return fdt_del_node(fdt, devp_offset(devp));
  97}
  98
  99static void *fdt_wrapper_get_parent(const void *devp)
 100{
 101        return offset_devp(fdt_parent_offset(fdt, devp_offset(devp)));
 102}
 103
 104static void *fdt_wrapper_create_node(const void *devp, const char *name)
 105{
 106        int offset;
 107
 108        offset = fdt_add_subnode(fdt, devp_offset(devp), name);
 109        if (offset == -FDT_ERR_NOSPACE) {
 110                expand_buf(strlen(name) + 16);
 111                offset = fdt_add_subnode(fdt, devp_offset(devp), name);
 112        }
 113
 114        return offset_devp(offset);
 115}
 116
 117static void *fdt_wrapper_find_node_by_prop_value(const void *prev,
 118                                                 const char *name,
 119                                                 const char *val,
 120                                                 int len)
 121{
 122        int offset = fdt_node_offset_by_prop_value(fdt, devp_offset_find(prev),
 123                                                   name, val, len);
 124        return offset_devp(offset);
 125}
 126
 127static void *fdt_wrapper_find_node_by_compatible(const void *prev,
 128                                                 const char *val)
 129{
 130        int offset = fdt_node_offset_by_compatible(fdt, devp_offset_find(prev),
 131                                                   val);
 132        return offset_devp(offset);
 133}
 134
 135static char *fdt_wrapper_get_path(const void *devp, char *buf, int len)
 136{
 137        int rc;
 138
 139        rc = fdt_get_path(fdt, devp_offset(devp), buf, len);
 140        if (check_err(rc))
 141                return NULL;
 142        return buf;
 143}
 144
 145static unsigned long fdt_wrapper_finalize(void)
 146{
 147        int rc;
 148
 149        rc = fdt_pack(fdt);
 150        if (rc != 0)
 151                fatal("Couldn't pack flat tree: %s\n\r",
 152                      fdt_strerror(rc));
 153        return (unsigned long)fdt;
 154}
 155
 156void fdt_init(void *blob)
 157{
 158        int err;
 159        int bufsize;
 160
 161        dt_ops.finddevice = fdt_wrapper_finddevice;
 162        dt_ops.getprop = fdt_wrapper_getprop;
 163        dt_ops.setprop = fdt_wrapper_setprop;
 164        dt_ops.get_parent = fdt_wrapper_get_parent;
 165        dt_ops.create_node = fdt_wrapper_create_node;
 166        dt_ops.find_node_by_prop_value = fdt_wrapper_find_node_by_prop_value;
 167        dt_ops.find_node_by_compatible = fdt_wrapper_find_node_by_compatible;
 168        dt_ops.del_node = fdt_wrapper_del_node;
 169        dt_ops.get_path = fdt_wrapper_get_path;
 170        dt_ops.finalize = fdt_wrapper_finalize;
 171
 172        /* Make sure the dt blob is the right version and so forth */
 173        fdt = blob;
 174        bufsize = fdt_totalsize(fdt) + EXPAND_GRANULARITY;
 175        buf = malloc(bufsize);
 176        if(!buf)
 177                fatal("malloc failed. can't relocate the device tree\n\r");
 178
 179        err = fdt_open_into(fdt, buf, bufsize);
 180
 181        if (err != 0)
 182                fatal("fdt_init(): %s\n\r", fdt_strerror(err));
 183
 184        fdt = buf;
 185}
 186