ARM: 7437/1: zImage: Allow DTB command line concatenation with ATAG_CMDLINE
authorGenoud Richard <richard.genoud@gmail.com>
Tue, 26 Jun 2012 15:37:59 +0000 (16:37 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 9 Jul 2012 16:39:39 +0000 (17:39 +0100)
This patch allows the ATAG_CMDLINE provided by the bootloader to be
concatenated to the bootargs property of the device tree.

This is useful to merge static values defined in the device tree
with the boot loader's (possibly) more dynamic values, such as
startup reasons and more.

The bootloader should use the device tree to pass those values to
the kernel, but that's not always simple (old bootloader or very
small one).

The behaviour is the same as the one introduced by Victor Boivie in
4394c1244249198c6b85093d46935b761b36ae05 by extending the CONFIG_CMDLINE.

Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/Kconfig
arch/arm/boot/compressed/atags_to_fdt.c

index b649c5904a4ff3c993732067411e7723fc4d4d19..8c9d264f2108814aad76bc255bd1b00af9f06e12 100644 (file)
@@ -1960,6 +1960,25 @@ config ARM_ATAG_DTB_COMPAT
          bootloaders, this option allows zImage to extract the information
          from the ATAG list and store it at run time into the appended DTB.
 
+choice
+       prompt "Kernel command line type" if ARM_ATAG_DTB_COMPAT
+       default ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER
+
+config ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER
+       bool "Use bootloader kernel arguments if available"
+       help
+         Uses the command-line options passed by the boot loader instead of
+         the device tree bootargs property. If the boot loader doesn't provide
+         any, the device tree bootargs property will be used.
+
+config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND
+       bool "Extend with bootloader kernel arguments"
+       help
+         The command-line arguments provided by the boot loader will be
+         appended to the the device tree bootargs property.
+
+endchoice
+
 config CMDLINE
        string "Default kernel command string"
        default ""
index 797f04bedb47e4175ed8cdc707efe12a71ec0693..aabc02a68482a912545ab67221070ad2ccf51e11 100644 (file)
@@ -1,6 +1,12 @@
 #include <asm/setup.h>
 #include <libfdt.h>
 
+#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND)
+#define do_extend_cmdline 1
+#else
+#define do_extend_cmdline 0
+#endif
+
 static int node_offset(void *fdt, const char *node_path)
 {
        int offset = fdt_path_offset(fdt, node_path);
@@ -36,6 +42,48 @@ static int setprop_cell(void *fdt, const char *node_path,
        return fdt_setprop_cell(fdt, offset, property, val);
 }
 
+static const void *getprop(const void *fdt, const char *node_path,
+                          const char *property, int *len)
+{
+       int offset = fdt_path_offset(fdt, node_path);
+
+       if (offset == -FDT_ERR_NOTFOUND)
+               return NULL;
+
+       return fdt_getprop(fdt, offset, property, len);
+}
+
+static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
+{
+       char cmdline[COMMAND_LINE_SIZE];
+       const char *fdt_bootargs;
+       char *ptr = cmdline;
+       int len = 0;
+
+       /* copy the fdt command line into the buffer */
+       fdt_bootargs = getprop(fdt, "/chosen", "bootargs", &len);
+       if (fdt_bootargs)
+               if (len < COMMAND_LINE_SIZE) {
+                       memcpy(ptr, fdt_bootargs, len);
+                       /* len is the length of the string
+                        * including the NULL terminator */
+                       ptr += len - 1;
+               }
+
+       /* and append the ATAG_CMDLINE */
+       if (fdt_cmdline) {
+               len = strlen(fdt_cmdline);
+               if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) {
+                       *ptr++ = ' ';
+                       memcpy(ptr, fdt_cmdline, len);
+                       ptr += len;
+               }
+       }
+       *ptr = '\0';
+
+       setprop_string(fdt, "/chosen", "bootargs", cmdline);
+}
+
 /*
  * Convert and fold provided ATAGs into the provided FDT.
  *
@@ -72,8 +120,18 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)
 
        for_each_tag(atag, atag_list) {
                if (atag->hdr.tag == ATAG_CMDLINE) {
-                       setprop_string(fdt, "/chosen", "bootargs",
-                                       atag->u.cmdline.cmdline);
+                       /* Append the ATAGS command line to the device tree
+                        * command line.
+                        * NB: This means that if the same parameter is set in
+                        * the device tree and in the tags, the one from the
+                        * tags will be chosen.
+                        */
+                       if (do_extend_cmdline)
+                               merge_fdt_bootargs(fdt,
+                                                  atag->u.cmdline.cmdline);
+                       else
+                               setprop_string(fdt, "/chosen", "bootargs",
+                                              atag->u.cmdline.cmdline);
                } else if (atag->hdr.tag == ATAG_MEM) {
                        if (memcount >= sizeof(mem_reg_property)/4)
                                continue;