linux/arch/arm/boot/compressed/atags_to_fdt.c
<<
>>
Prefs
   1#include <asm/setup.h>
   2#include <libfdt.h>
   3
   4#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND)
   5#define do_extend_cmdline 1
   6#else
   7#define do_extend_cmdline 0
   8#endif
   9
  10static int node_offset(void *fdt, const char *node_path)
  11{
  12        int offset = fdt_path_offset(fdt, node_path);
  13        if (offset == -FDT_ERR_NOTFOUND)
  14                offset = fdt_add_subnode(fdt, 0, node_path);
  15        return offset;
  16}
  17
  18static int setprop(void *fdt, const char *node_path, const char *property,
  19                   uint32_t *val_array, int size)
  20{
  21        int offset = node_offset(fdt, node_path);
  22        if (offset < 0)
  23                return offset;
  24        return fdt_setprop(fdt, offset, property, val_array, size);
  25}
  26
  27static int setprop_string(void *fdt, const char *node_path,
  28                          const char *property, const char *string)
  29{
  30        int offset = node_offset(fdt, node_path);
  31        if (offset < 0)
  32                return offset;
  33        return fdt_setprop_string(fdt, offset, property, string);
  34}
  35
  36static int setprop_cell(void *fdt, const char *node_path,
  37                        const char *property, uint32_t val)
  38{
  39        int offset = node_offset(fdt, node_path);
  40        if (offset < 0)
  41                return offset;
  42        return fdt_setprop_cell(fdt, offset, property, val);
  43}
  44
  45static const void *getprop(const void *fdt, const char *node_path,
  46                           const char *property, int *len)
  47{
  48        int offset = fdt_path_offset(fdt, node_path);
  49
  50        if (offset == -FDT_ERR_NOTFOUND)
  51                return NULL;
  52
  53        return fdt_getprop(fdt, offset, property, len);
  54}
  55
  56static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
  57{
  58        char cmdline[COMMAND_LINE_SIZE];
  59        const char *fdt_bootargs;
  60        char *ptr = cmdline;
  61        int len = 0;
  62
  63        /* copy the fdt command line into the buffer */
  64        fdt_bootargs = getprop(fdt, "/chosen", "bootargs", &len);
  65        if (fdt_bootargs)
  66                if (len < COMMAND_LINE_SIZE) {
  67                        memcpy(ptr, fdt_bootargs, len);
  68                        /* len is the length of the string
  69                         * including the NULL terminator */
  70                        ptr += len - 1;
  71                }
  72
  73        /* and append the ATAG_CMDLINE */
  74        if (fdt_cmdline) {
  75                len = strlen(fdt_cmdline);
  76                if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) {
  77                        *ptr++ = ' ';
  78                        memcpy(ptr, fdt_cmdline, len);
  79                        ptr += len;
  80                }
  81        }
  82        *ptr = '\0';
  83
  84        setprop_string(fdt, "/chosen", "bootargs", cmdline);
  85}
  86
  87/*
  88 * Convert and fold provided ATAGs into the provided FDT.
  89 *
  90 * REturn values:
  91 *    = 0 -> pretend success
  92 *    = 1 -> bad ATAG (may retry with another possible ATAG pointer)
  93 *    < 0 -> error from libfdt
  94 */
  95int atags_to_fdt(void *atag_list, void *fdt, int total_space)
  96{
  97        struct tag *atag = atag_list;
  98        uint32_t mem_reg_property[2 * NR_BANKS];
  99        int memcount = 0;
 100        int ret;
 101
 102        /* make sure we've got an aligned pointer */
 103        if ((u32)atag_list & 0x3)
 104                return 1;
 105
 106        /* if we get a DTB here we're done already */
 107        if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC))
 108               return 0;
 109
 110        /* validate the ATAG */
 111        if (atag->hdr.tag != ATAG_CORE ||
 112            (atag->hdr.size != tag_size(tag_core) &&
 113             atag->hdr.size != 2))
 114                return 1;
 115
 116        /* let's give it all the room it could need */
 117        ret = fdt_open_into(fdt, fdt, total_space);
 118        if (ret < 0)
 119                return ret;
 120
 121        for_each_tag(atag, atag_list) {
 122                if (atag->hdr.tag == ATAG_CMDLINE) {
 123                        /* Append the ATAGS command line to the device tree
 124                         * command line.
 125                         * NB: This means that if the same parameter is set in
 126                         * the device tree and in the tags, the one from the
 127                         * tags will be chosen.
 128                         */
 129                        if (do_extend_cmdline)
 130                                merge_fdt_bootargs(fdt,
 131                                                   atag->u.cmdline.cmdline);
 132                        else
 133                                setprop_string(fdt, "/chosen", "bootargs",
 134                                               atag->u.cmdline.cmdline);
 135                } else if (atag->hdr.tag == ATAG_MEM) {
 136                        if (memcount >= sizeof(mem_reg_property)/4)
 137                                continue;
 138                        if (!atag->u.mem.size)
 139                                continue;
 140                        mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start);
 141                        mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size);
 142                } else if (atag->hdr.tag == ATAG_INITRD2) {
 143                        uint32_t initrd_start, initrd_size;
 144                        initrd_start = atag->u.initrd.start;
 145                        initrd_size = atag->u.initrd.size;
 146                        setprop_cell(fdt, "/chosen", "linux,initrd-start",
 147                                        initrd_start);
 148                        setprop_cell(fdt, "/chosen", "linux,initrd-end",
 149                                        initrd_start + initrd_size);
 150                }
 151        }
 152
 153        if (memcount)
 154                setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount);
 155
 156        return fdt_pack(fdt);
 157}
 158