]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - board/karo/common/fdt.c
karo: fdt: check for <CTRL-C> only to abort loading DTB
[karo-tx-uboot.git] / board / karo / common / fdt.c
index 9c154eadb98f17504d9ec20d6effd8e4d58e75a8..f0b1ad2eafd7f63169a6f961a318d730e216c8fa 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/fb.h>
 #include <jffs2/load_kernel.h>
+#include <malloc.h>
 
 #include "karo.h"
 
@@ -37,7 +38,6 @@ DECLARE_GLOBAL_DATA_PTR;
 
 static void karo_set_fdtsize(void *fdt)
 {
-       char fdt_size[9];
        size_t fdtsize = getenv_ulong("fdtsize", 16, 0);
 
        if (fdtsize == fdt_totalsize(fdt)) {
@@ -45,9 +45,79 @@ static void karo_set_fdtsize(void *fdt)
        }
        debug("FDT size changed from %u to %u\n",
                fdtsize, fdt_totalsize(fdt));
+       setenv_hex("fdtsize", fdt_totalsize(fdt));
+}
+
+static int karo_load_part(const char *part, void *addr, size_t len)
+{
+       int ret;
+       struct mtd_device *dev;
+       struct part_info *part_info;
+       u8 part_num;
+       size_t actual;
 
-       snprintf(fdt_size, sizeof(fdt_size), "%08x", fdt_totalsize(fdt));
-       setenv("fdtsize", fdt_size);
+       debug("Initializing mtd_parts\n");
+       ret = mtdparts_init();
+       if (ret)
+               return ret;
+
+       debug("Trying to find NAND partition '%s'\n", part);
+       ret = find_dev_and_part(part, &dev, &part_num, &part_info);
+       if (ret) {
+               printf("Failed to find flash partition '%s': %d\n",
+                       part, ret);
+
+               return ret;
+       }
+       debug("Found partition '%s': offset=%08x size=%08x\n",
+               part, part_info->offset, part_info->size);
+       if (part_info->size < len) {
+               printf("Warning: partition '%s' smaller than requested size: %u; truncating data to %u byte\n",
+                       part, len, part_info->size);
+               len = part_info->size;
+       }
+       debug("Reading NAND partition '%s' to %p\n", part, addr);
+       ret = nand_read_skip_bad(&nand_info[0], part_info->offset, &len,
+                               &actual, len, addr);
+       if (ret) {
+               printf("Failed to load partition '%s' to %p\n", part, addr);
+               return ret;
+       }
+       if (actual < len)
+               printf("Read only %u of %u bytes due to bad blocks\n",
+                       actual, len);
+
+       debug("Read %u byte from partition '%s' @ offset %08x\n",
+               len, part, part_info->offset);
+       return 0;
+}
+
+static void *karo_fdt_load_dtb(void)
+{
+       int ret;
+       void *fdt = (void *)getenv_ulong("fdtaddr", 16, CONFIG_SYS_FDT_ADDR);
+
+       if (had_ctrlc()) {
+               printf("aborting DTB load\n");
+               return NULL;
+       }
+
+       /* clear FDT header in memory */
+       memset(fdt, 0, 4);
+
+       ret = karo_load_part("dtb", fdt, MAX_DTB_SIZE);
+       if (ret) {
+               printf("Failed to load dtb from flash: %d\n", ret);
+               return NULL;
+       }
+
+       if (fdt_check_header(fdt)) {
+               debug("No valid DTB in flash\n");
+               return NULL;
+       }
+       debug("Using DTB from flash\n");
+       karo_set_fdtsize(fdt);
+       return fdt;
 }
 
 void karo_fdt_move_fdt(void)
@@ -60,6 +130,8 @@ void karo_fdt_move_fdt(void)
                return;
        }
 
+       setenv("fdtsize", 0);
+
        if (!fdt_addr) {
                fdt_addr = CONFIG_SYS_FDT_ADDR;
                printf("fdtaddr is not set; using default: %08lx\n",
@@ -70,15 +142,22 @@ void karo_fdt_move_fdt(void)
        if (fdt == NULL) {
                fdt = (void *)gd->fdt_blob;
                if (fdt == NULL) {
-                       printf("Compiled in FDT not found\n");
-                       return;
+#ifdef CONFIG_OF_EMBED
+                       printf("Compiled in FDT not found");
+#else
+                       printf("No FDT found");
+#endif
+                       printf("; creating empty DTB\n");
+                       fdt = (void *)fdt_addr;
+                       fdt_create_empty_tree(fdt, 256);
+               } else {
+                       printf("No DTB in flash; using default DTB\n");
                }
                debug("Checking FDT header @ %p\n", fdt);
                if (fdt_check_header(fdt)) {
                        printf("ERROR: No valid DTB found at %p\n", fdt);
                        return;
                }
-               printf("No DTB in flash; using default DTB\n");
                debug("Moving FDT from %p..%p to %08lx..%08lx\n",
                        fdt, fdt + fdt_totalsize(fdt) - 1,
                        fdt_addr, fdt_addr + fdt_totalsize(fdt) - 1);
@@ -97,12 +176,13 @@ void karo_fdt_remove_node(void *blob, const char *node)
        debug("Removing node '%s' from DT\n", node);
 
        if (off < 0) {
-               printf("Could not find node '%s': %d\n", node, off);
+               printf("Could not find node '%s': %s\n", node,
+                       fdt_strerror(off));
        } else {
                ret = fdt_del_node(blob, off);
                if (ret)
-                       printf("Failed to remove node '%s': %d\n",
-                               node, ret);
+                       printf("Failed to remove node '%s': %s\n",
+                               node, fdt_strerror(ret));
        }
        karo_set_fdtsize(blob);
 }
@@ -113,7 +193,8 @@ void karo_fdt_enable_node(void *blob, const char *node, int enable)
 
        debug("%sabling node '%s'\n", enable ? "En" : "Dis", node);
        if (off < 0) {
-               printf("Could not find node '%s': %d\n", node, off);
+               printf("Could not find node '%s': %s\n", node,
+                       fdt_strerror(off));
                return;
        }
        fdt_set_node_status(blob, off,
@@ -135,7 +216,7 @@ static void fdt_disable_tp_node(void *blob, const char *name)
        int offs = fdt_node_offset_by_compatible(blob, -1, name);
 
        if (offs < 0) {
-               debug("node '%s' not found: %d\n", name, offs);
+               debug("node '%s' not found: %s\n", name, fdt_strerror(offs));
                return;
        }
 
@@ -231,7 +312,7 @@ void karo_fdt_fixup_usb_otg(void *blob, const char *node, const char *phy)
        }
 out:
        if (ret)
-               printf("Failed to update usbotg: %d\n", ret);
+               printf("Failed to update usbotg: %s\n", fdt_strerror(ret));
        else
                debug("node '%s' updated\n", node);
        karo_set_fdtsize(blob);
@@ -414,7 +495,8 @@ static int fdt_update_native_fb_mode(void *blob, int off)
 
        ret = fdt_increase_size(blob, 64);
        if (ret) {
-               printf("Warning: Failed to increase FDT size: %d\n", ret);
+               printf("Warning: Failed to increase FDT size: %s\n",
+                       fdt_strerror(ret));
        }
        debug("Creating phandle at offset %d\n", off);
        ph = fdt_create_phandle(blob, off);
@@ -431,7 +513,8 @@ static int fdt_update_native_fb_mode(void *blob, int off)
        debug("parent offset=%06x\n", off);
        ret = fdt_setprop_cell(blob, off, "native-mode", ph);
        if (ret)
-               printf("Failed to set property 'native-mode': %d\n", ret);
+               printf("Failed to set property 'native-mode': %s\n",
+                       fdt_strerror(ret));
        karo_set_fdtsize(blob);
        return ret;
 }
@@ -442,13 +525,15 @@ static int karo_fdt_find_video_timings(void *blob)
        const char *subnode = "display-timings";
 
        if (off < 0) {
-               debug("Could not find node 'display' in FDT: %d\n", off);
+               debug("Could not find node 'display' in FDT: %s\n",
+                       fdt_strerror(off));
                return off;
        }
 
        off = fdt_subnode_offset(blob, off, subnode);
        if (off < 0) {
-               debug("Could not find node '%s' in FDT: %d\n", subnode, off);
+               debug("Could not find node '%s' in FDT: %s\n", subnode,
+                       fdt_strerror(off));
        }
        return off;
 }
@@ -469,10 +554,12 @@ int karo_fdt_get_fb_mode(void *blob, const char *name, struct fb_videomode *fb_m
                if (d < 1)
                        return -EINVAL;
                if (d > 2) {
-                       debug("Skipping node @ %04x %s depth %d\n", off, fdt_get_name(blob, off, NULL), d);
+                       debug("Skipping node @ %04x %s depth %d\n", off,
+                               fdt_get_name(blob, off, NULL), d);
                        continue;
                }
-               debug("parsing subnode @ %04x %s depth %d\n", off, fdt_get_name(blob, off, NULL), d);
+               debug("parsing subnode @ %04x %s depth %d\n", off,
+                       fdt_get_name(blob, off, NULL), d);
 
                n = fdt_getprop(blob, off, "panel-name", &len);
                if (!n) {
@@ -506,7 +593,8 @@ int karo_fdt_get_fb_mode(void *blob, const char *name, struct fb_videomode *fb_m
        int ret;                                                        \
        ret = fdt_setprop_u32(blob, off, n, v);                         \
        if (ret) {                                                      \
-               printf("Failed to set property %s: %d\n", name, ret);   \
+               printf("Failed to set property %s: %s\n", name,         \
+                       fdt_strerror(ret));                             \
        }                                                               \
        ret;                                                            \
 })
@@ -526,25 +614,26 @@ int karo_fdt_create_fb_mode(void *blob, const char *name,
 
        ret = fdt_increase_size(blob, 512);
        if (ret) {
-               printf("Failed to increase FDT size: %d\n", ret);
+               printf("Failed to increase FDT size: %s\n", fdt_strerror(ret));
                return ret;
        }
 
-       printf("node '%s' offset=%d\n", "display", off);
        ret = fdt_subnode_offset(blob, off, subnode);
        if (ret < 0) {
-               debug("Could not find node '%s' in FDT: %d\n", subnode, ret);
+               debug("Could not find node '%s' in FDT: %s\n", subnode,
+                       fdt_strerror(ret));
                ret = fdt_add_subnode(blob, off, subnode);
                if (ret < 0) {
-                       printf("Failed to add %s subnode: %d\n", subnode, ret);
+                       printf("Failed to add %s subnode: %s\n", subnode,
+                               fdt_strerror(ret));
                        return ret;
                }
        }
 
-       printf("node '%s' offset=%d\n", subnode, ret);
        ret = fdt_add_subnode(blob, ret, name);
        if (ret < 0) {
-               printf("Failed to add %s subnode: %d\n", name, ret);
+               printf("Failed to add %s subnode: %s\n", name,
+                       fdt_strerror(ret));
                return ret;
        }
        off = ret;
@@ -596,6 +685,96 @@ out:
        return ret;
 }
 
+static int karo_fdt_set_display_alias(void *blob, const char *path,
+                               const char *name)
+{
+       int ret;
+       int off;
+       size_t size = strlen(path) + strlen(name) + 2;
+       char *display;
+
+       display = malloc(size);
+       if (display == NULL) {
+               printf("%s: Failed to allocate buffer\n", __func__);
+               return -ENOMEM;
+       }
+       sprintf(display, "%s/%s", path, name);
+       if (strlen(display) != size - 1)
+               hang();
+       off = fdt_path_offset(blob, "/aliases");
+       if (off == FDT_ERR_BADMAGIC)
+               return -EINVAL;
+       ret = fdt_resize(blob);
+       if (ret < 0) {
+               printf("%s: Failed to resize FDT: %s\n",
+                       __func__, fdt_strerror(ret));
+       }
+       if (off < 0) {
+               off = fdt_add_subnode(blob, 0, "aliases");
+               if (off < 0) {
+                       printf("%s: Failed to create 'aliases' node: %s\n",
+                               __func__, fdt_strerror(off));
+                       return off;
+               }
+       }
+       ret = fdt_setprop_string(blob, off, "display", display);
+       debug("setprop_string(display='%s') returned %d (%s)\n", display, ret,
+               ret < 0 ? fdt_strerror(ret) : "OK");
+       return ret;
+}
+
+const char *karo_fdt_set_display(const char *video_mode, const char *lcd_path,
+                               const char *lvds_path)
+{
+       const char *vmode = NULL;
+       int ret;
+       void *blob = working_fdt;
+
+       if (video_mode == NULL || strlen(video_mode) == 0)
+               return NULL;
+
+       vmode = strchr(video_mode, ':');
+
+       if (lvds_path == NULL)
+               return vmode ? vmode + 1 : video_mode;
+
+       if (lvds_path != NULL && vmode != NULL) {
+               if (strncmp(video_mode, "LVDS:", 5) == 0 ||
+                       strncmp(video_mode, "LVDS0:", 6) == 0) {
+                       ret = karo_fdt_set_display_alias(blob, lvds_path,
+                                                       "lvds-channel@0");
+               } else if (strncmp(video_mode, "LVDS1:", 6) == 0) {
+                       ret = karo_fdt_set_display_alias(blob, lvds_path,
+                                                       "lvds-channel@1");
+               } else {
+                       debug("%s: Syntax error in video_mode\n", __func__);
+                       return vmode + 1;
+               }
+               video_mode = vmode + 1;
+       } else {
+               int off;
+
+               ret = karo_fdt_set_display_alias(blob, lcd_path,
+                                               "display@di0");
+
+               off = fdt_path_offset(blob, "lvds0");
+               if (off >= 0) {
+                       ret = fdt_set_node_status(blob, off,
+                                               FDT_STATUS_DISABLED, 0);
+               }
+               off = fdt_path_offset(blob, "lvds1");
+               if (off >= 0) {
+                       ret = fdt_set_node_status(blob, off,
+                                               FDT_STATUS_DISABLED, 0);
+               }
+       }
+       if (ret) {
+               printf("%s: failed to set 'display' alias: %s\n",
+                       __func__, fdt_strerror(ret));
+       }
+       return video_mode;
+}
+
 int karo_fdt_update_fb_mode(void *blob, const char *name)
 {
        int off = fdt_path_offset(blob, "display");
@@ -615,7 +794,8 @@ int karo_fdt_update_fb_mode(void *blob, const char *name)
 
        off = fdt_subnode_offset(blob, off, subnode);
        if (off < 0) {
-               debug("Could not find node '%s' in FDT: %d\n", subnode, off);
+               debug("Could not find node '%s' in FDT: %s\n", subnode,
+                       fdt_strerror(off));
                return off;
        }
        while (off > 0) {
@@ -628,10 +808,12 @@ int karo_fdt_update_fb_mode(void *blob, const char *name)
                if (d < 1)
                        return -EINVAL;
                if (d > 2) {
-                       debug("Skipping node @ %04x %s depth %d\n", off, fdt_get_name(blob, off, NULL), d);
+                       debug("Skipping node @ %04x %s depth %d\n", off,
+                               fdt_get_name(blob, off, NULL), d);
                        continue;
                }
-               debug("parsing subnode @ %04x %s depth %d\n", off, fdt_get_name(blob, off, NULL), d);
+               debug("parsing subnode @ %04x %s depth %d\n", off,
+                       fdt_get_name(blob, off, NULL), d);
 
                n = fdt_getprop(blob, off, "panel-name", &len);
                if (!n) {
@@ -659,75 +841,3 @@ int karo_fdt_update_fb_mode(void *blob, const char *name)
                return fdt_update_native_fb_mode(blob, off);
        return off;
 }
-
-static int karo_load_part(const char *part, void *addr, size_t len)
-{
-       int ret;
-       struct mtd_device *dev;
-       struct part_info *part_info;
-       u8 part_num;
-       size_t actual;
-
-       debug("Initializing mtd_parts\n");
-       ret = mtdparts_init();
-       if (ret)
-               return ret;
-
-       debug("Trying to find NAND partition '%s'\n", part);
-       ret = find_dev_and_part(part, &dev, &part_num, &part_info);
-       if (ret) {
-               printf("Failed to find flash partition '%s': %d\n",
-                       part, ret);
-
-               return ret;
-       }
-       debug("Found partition '%s': offset=%08x size=%08x\n",
-               part, part_info->offset, part_info->size);
-       if (part_info->size < len) {
-               printf("Warning: partition '%s' smaller than requested size: %u; truncating data to %u byte\n",
-                       part, len, part_info->size);
-               len = part_info->size;
-       }
-       debug("Reading NAND partition '%s' to %p\n", part, addr);
-       ret = nand_read_skip_bad(&nand_info[0], part_info->offset, &len,
-                               &actual, len, addr);
-       if (ret) {
-               printf("Failed to load partition '%s' to %p\n", part, addr);
-               return ret;
-       }
-       if (actual < len)
-               printf("Read only %u of %u bytes due to bad blocks\n",
-                       actual, len);
-
-       debug("Read %u byte from partition '%s' @ offset %08x\n",
-               len, part, part_info->offset);
-       return 0;
-}
-
-void *karo_fdt_load_dtb(void)
-{
-       int ret;
-       void *fdt = (void *)getenv_ulong("fdtaddr", 16, CONFIG_SYS_FDT_ADDR);
-
-       if (tstc()) {
-               debug("aborting DTB load\n");
-               return NULL;
-       }
-
-       /* clear FDT header in memory */
-       memset(fdt, 0, 4);
-
-       ret = karo_load_part("dtb", fdt, MAX_DTB_SIZE);
-       if (ret) {
-               printf("Failed to load dtb from flash: %d\n", ret);
-               return NULL;
-       }
-
-       if (fdt_check_header(fdt)) {
-               debug("No valid DTB in flash\n");
-               return NULL;
-       }
-       debug("Using DTB from flash\n");
-       karo_set_fdtsize(fdt);
-       return fdt;
-}