root/arch/arm/boot/compressed/atags_to_fdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. node_offset
  2. setprop
  3. setprop_string
  4. setprop_cell
  5. getprop
  6. get_cell_size
  7. merge_fdt_bootargs
  8. hex_str
  9. atags_to_fdt

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <asm/setup.h>
   3 #include <libfdt.h>
   4 
   5 #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND)
   6 #define do_extend_cmdline 1
   7 #else
   8 #define do_extend_cmdline 0
   9 #endif
  10 
  11 #define NR_BANKS 16
  12 
  13 static int node_offset(void *fdt, const char *node_path)
  14 {
  15         int offset = fdt_path_offset(fdt, node_path);
  16         if (offset == -FDT_ERR_NOTFOUND)
  17                 offset = fdt_add_subnode(fdt, 0, node_path);
  18         return offset;
  19 }
  20 
  21 static int setprop(void *fdt, const char *node_path, const char *property,
  22                    uint32_t *val_array, int size)
  23 {
  24         int offset = node_offset(fdt, node_path);
  25         if (offset < 0)
  26                 return offset;
  27         return fdt_setprop(fdt, offset, property, val_array, size);
  28 }
  29 
  30 static int setprop_string(void *fdt, const char *node_path,
  31                           const char *property, const char *string)
  32 {
  33         int offset = node_offset(fdt, node_path);
  34         if (offset < 0)
  35                 return offset;
  36         return fdt_setprop_string(fdt, offset, property, string);
  37 }
  38 
  39 static int setprop_cell(void *fdt, const char *node_path,
  40                         const char *property, uint32_t val)
  41 {
  42         int offset = node_offset(fdt, node_path);
  43         if (offset < 0)
  44                 return offset;
  45         return fdt_setprop_cell(fdt, offset, property, val);
  46 }
  47 
  48 static const void *getprop(const void *fdt, const char *node_path,
  49                            const char *property, int *len)
  50 {
  51         int offset = fdt_path_offset(fdt, node_path);
  52 
  53         if (offset == -FDT_ERR_NOTFOUND)
  54                 return NULL;
  55 
  56         return fdt_getprop(fdt, offset, property, len);
  57 }
  58 
  59 static uint32_t get_cell_size(const void *fdt)
  60 {
  61         int len;
  62         uint32_t cell_size = 1;
  63         const uint32_t *size_len =  getprop(fdt, "/", "#size-cells", &len);
  64 
  65         if (size_len)
  66                 cell_size = fdt32_to_cpu(*size_len);
  67         return cell_size;
  68 }
  69 
  70 static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
  71 {
  72         char cmdline[COMMAND_LINE_SIZE];
  73         const char *fdt_bootargs;
  74         char *ptr = cmdline;
  75         int len = 0;
  76 
  77         /* copy the fdt command line into the buffer */
  78         fdt_bootargs = getprop(fdt, "/chosen", "bootargs", &len);
  79         if (fdt_bootargs)
  80                 if (len < COMMAND_LINE_SIZE) {
  81                         memcpy(ptr, fdt_bootargs, len);
  82                         /* len is the length of the string
  83                          * including the NULL terminator */
  84                         ptr += len - 1;
  85                 }
  86 
  87         /* and append the ATAG_CMDLINE */
  88         if (fdt_cmdline) {
  89                 len = strlen(fdt_cmdline);
  90                 if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) {
  91                         *ptr++ = ' ';
  92                         memcpy(ptr, fdt_cmdline, len);
  93                         ptr += len;
  94                 }
  95         }
  96         *ptr = '\0';
  97 
  98         setprop_string(fdt, "/chosen", "bootargs", cmdline);
  99 }
 100 
 101 static void hex_str(char *out, uint32_t value)
 102 {
 103         uint32_t digit;
 104         int idx;
 105 
 106         for (idx = 7; idx >= 0; idx--) {
 107                 digit = value >> 28;
 108                 value <<= 4;
 109                 digit &= 0xf;
 110                 if (digit < 10)
 111                         digit += '0';
 112                 else
 113                         digit += 'A'-10;
 114                 *out++ = digit;
 115         }
 116         *out = '\0';
 117 }
 118 
 119 /*
 120  * Convert and fold provided ATAGs into the provided FDT.
 121  *
 122  * REturn values:
 123  *    = 0 -> pretend success
 124  *    = 1 -> bad ATAG (may retry with another possible ATAG pointer)
 125  *    < 0 -> error from libfdt
 126  */
 127 int atags_to_fdt(void *atag_list, void *fdt, int total_space)
 128 {
 129         struct tag *atag = atag_list;
 130         /* In the case of 64 bits memory size, need to reserve 2 cells for
 131          * address and size for each bank */
 132         uint32_t mem_reg_property[2 * 2 * NR_BANKS];
 133         int memcount = 0;
 134         int ret, memsize;
 135 
 136         /* make sure we've got an aligned pointer */
 137         if ((u32)atag_list & 0x3)
 138                 return 1;
 139 
 140         /* if we get a DTB here we're done already */
 141         if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC))
 142                return 0;
 143 
 144         /* validate the ATAG */
 145         if (atag->hdr.tag != ATAG_CORE ||
 146             (atag->hdr.size != tag_size(tag_core) &&
 147              atag->hdr.size != 2))
 148                 return 1;
 149 
 150         /* let's give it all the room it could need */
 151         ret = fdt_open_into(fdt, fdt, total_space);
 152         if (ret < 0)
 153                 return ret;
 154 
 155         for_each_tag(atag, atag_list) {
 156                 if (atag->hdr.tag == ATAG_CMDLINE) {
 157                         /* Append the ATAGS command line to the device tree
 158                          * command line.
 159                          * NB: This means that if the same parameter is set in
 160                          * the device tree and in the tags, the one from the
 161                          * tags will be chosen.
 162                          */
 163                         if (do_extend_cmdline)
 164                                 merge_fdt_bootargs(fdt,
 165                                                    atag->u.cmdline.cmdline);
 166                         else
 167                                 setprop_string(fdt, "/chosen", "bootargs",
 168                                                atag->u.cmdline.cmdline);
 169                 } else if (atag->hdr.tag == ATAG_MEM) {
 170                         if (memcount >= sizeof(mem_reg_property)/4)
 171                                 continue;
 172                         if (!atag->u.mem.size)
 173                                 continue;
 174                         memsize = get_cell_size(fdt);
 175 
 176                         if (memsize == 2) {
 177                                 /* if memsize is 2, that means that
 178                                  * each data needs 2 cells of 32 bits,
 179                                  * so the data are 64 bits */
 180                                 uint64_t *mem_reg_prop64 =
 181                                         (uint64_t *)mem_reg_property;
 182                                 mem_reg_prop64[memcount++] =
 183                                         cpu_to_fdt64(atag->u.mem.start);
 184                                 mem_reg_prop64[memcount++] =
 185                                         cpu_to_fdt64(atag->u.mem.size);
 186                         } else {
 187                                 mem_reg_property[memcount++] =
 188                                         cpu_to_fdt32(atag->u.mem.start);
 189                                 mem_reg_property[memcount++] =
 190                                         cpu_to_fdt32(atag->u.mem.size);
 191                         }
 192 
 193                 } else if (atag->hdr.tag == ATAG_INITRD2) {
 194                         uint32_t initrd_start, initrd_size;
 195                         initrd_start = atag->u.initrd.start;
 196                         initrd_size = atag->u.initrd.size;
 197                         setprop_cell(fdt, "/chosen", "linux,initrd-start",
 198                                         initrd_start);
 199                         setprop_cell(fdt, "/chosen", "linux,initrd-end",
 200                                         initrd_start + initrd_size);
 201                 } else if (atag->hdr.tag == ATAG_SERIAL) {
 202                         char serno[16+2];
 203                         hex_str(serno, atag->u.serialnr.high);
 204                         hex_str(serno+8, atag->u.serialnr.low);
 205                         setprop_string(fdt, "/", "serial-number", serno);
 206                 }
 207         }
 208 
 209         if (memcount) {
 210                 setprop(fdt, "/memory", "reg", mem_reg_property,
 211                         4 * memcount * memsize);
 212         }
 213 
 214         return fdt_pack(fdt);
 215 }

/* [<][>][^][v][top][bottom][index][help] */