]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
mxs: tx28: update FDT code for Linux 3.10
authorLothar Waßmann <LW@KARO-electronics.de>
Mon, 15 Jul 2013 10:05:48 +0000 (12:05 +0200)
committerLothar Waßmann <LW@KARO-electronics.de>
Mon, 15 Jul 2013 10:05:48 +0000 (12:05 +0200)
board/karo/common/fdt.c
board/karo/common/karo.h
board/karo/tx28/tx28.c

index d039c459d2ef45a38b5e868aadc09159885ea874..b4c77e92611c9bea931629220282035aaad8844f 100644 (file)
@@ -20,6 +20,8 @@
 #include <libfdt.h>
 #include <fdt_support.h>
 #include <nand.h>
+#include <linux/list.h>
+#include <linux/fb.h>
 #include <jffs2/load_kernel.h>
 
 #include "karo.h"
@@ -52,6 +54,11 @@ void karo_fdt_move_fdt(void)
        void *fdt;
        unsigned long fdt_addr = getenv_ulong("fdtaddr", 16, 0);
 
+       if (working_fdt) {
+               debug("DTB already loaded\n");
+               return;
+       }
+
        if (!fdt_addr) {
                fdt_addr = CONFIG_SYS_FDT_ADDR;
                printf("fdtaddr is not set; using default: %08lx\n",
@@ -77,15 +84,17 @@ void karo_fdt_move_fdt(void)
                memmove((void *)fdt_addr, fdt, fdt_totalsize(fdt));
        }
        set_working_fdt_addr((void *)fdt_addr);
+       gd->fdt_blob = fdt;
        karo_set_fdtsize(fdt);
 }
 
 void karo_fdt_remove_node(void *blob, const char *node)
 {
-       debug("Removing node '%s' from DT\n", node);
        int off = fdt_path_offset(blob, node);
        int ret;
 
+       debug("Removing node '%s' from DT\n", node);
+
        if (off < 0) {
                printf("Could not find node '%s': %d\n", node, off);
        } else {
@@ -115,44 +124,20 @@ void karo_fdt_enable_node(void *blob, const char *node, int enable)
 static const char *karo_touchpanels[] = {
        "ti,tsc2007",
        "edt,edt-ft5x06",
+       "fsl,imx28-lradc",
 };
 
 static void fdt_del_tp_node(void *blob, const char *name)
 {
        int offs = fdt_node_offset_by_compatible(blob, -1, name);
-       uint32_t ph1 = 0, ph2 = 0;
-       const uint32_t *prop;
 
        if (offs < 0) {
                debug("node '%s' not found: %d\n", name, offs);
                return;
        }
 
-       prop = fdt_getprop(blob, offs, "reset-switch", NULL);
-       if (prop)
-               ph1 = fdt32_to_cpu(*prop);
-
-       prop = fdt_getprop(blob, offs, "wake-switch", NULL);
-       if (prop)
-               ph2 = fdt32_to_cpu(*prop);
-
        debug("Removing node '%s' from DT\n", name);
        fdt_del_node(blob, offs);
-
-       if (ph1) {
-               offs = fdt_node_offset_by_phandle(blob, ph1);
-               if (offs > 0) {
-                       debug("Removing node %08x @ %08x\n", ph1, offs);
-                       fdt_del_node(blob, offs);
-               }
-       }
-       if (ph2) {
-               offs = fdt_node_offset_by_phandle(blob, ph2);
-               if (offs > 0) {
-                       debug("Removing node %08x @ %08x\n", ph2, offs);
-                       fdt_del_node(blob, offs);
-               }
-       }
 }
 
 void karo_fdt_fixup_touchpanel(void *blob)
@@ -178,29 +163,59 @@ void karo_fdt_fixup_touchpanel(void *blob)
        }
 }
 
-void karo_fdt_fixup_usb_otg(void *blob, const char *compat, phys_addr_t offs)
+void karo_fdt_fixup_usb_otg(void *blob, const char *node, const char *phy)
 {
        const char *otg_mode = getenv("otg_mode");
        int off;
+       int ret;
+       const uint32_t *ph;
 
        debug("OTG mode is '%s'\n", otg_mode ? otg_mode : "<UNSET>");
 
-       off = fdt_node_offset_by_compat_reg(blob, compat, offs);
+       off = fdt_path_offset(blob, node);
        if (off < 0) {
-               printf("Failed to find node %s@%08lx\n", compat, offs);
+               printf("Failed to find node %s\n", node);
                return;
        }
 
-       if (!otg_mode || strcmp(otg_mode, "device") != 0) {
-               printf("Deleting property gadget-device-name from node %s@%08lx\n",
-                       compat, offs);
-               fdt_delprop(blob, off, "gadget-device-name");
+       if (otg_mode && (strcmp(otg_mode, "device") == 0 ||
+                               strcmp(otg_mode, "gadget") == 0)) {
+               ret = fdt_setprop_string(blob, off, "dr_mode", "peripheral");
+               phy = NULL;
+       } else if (otg_mode && strcmp(otg_mode, "host") == 0) {
+               ret = fdt_setprop_string(blob, off, "dr_mode", "host");
+               phy = NULL;
+       } else {
+               if (otg_mode && strcmp(otg_mode, "none") != 0)
+                       printf("Invalid 'otg_mode' setting '%s'; disabling usbotg port\n",
+                               otg_mode);
+               ret = fdt_setprop_string(blob, off, "status", "disabled");
+       }
+       if (ret)
+               goto out;
+
+       if (phy == NULL)
+               goto out;
+
+       ph = fdt_getprop(blob, off, phy, NULL);
+       if (ph == NULL) {
+               printf("Failed to find '%s' phandle in node '%s'\n", phy,
+                       fdt_get_name(blob, off, NULL));
+               goto out;
        }
-       if (!otg_mode || strcmp(otg_mode, "host") != 0) {
-               printf("Deleting property host-device-name from node %s@%08lx\n",
-                       compat, offs);
-               fdt_delprop(blob, off, "host-device-name");
+
+       off = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*ph));
+       if (off <= 0) {
+               printf("Failed to find '%s' node via phandle %04x\n",
+                       phy, fdt32_to_cpu(*ph));
+               goto out;
        }
+       ret = fdt_setprop_string(blob, off, "status", "disabled");
+
+out:
+       if (ret)
+               printf("Failed to update usbotg: %d\n", ret);
+       printf("node '%s' updated\n", node);
        karo_set_fdtsize(blob);
 }
 
@@ -238,6 +253,208 @@ void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs,
        karo_set_fdtsize(blob);
 }
 
+static int fdt_init_fb_mode(const void *blob, int off, struct fb_videomode *fb_mode)
+{
+       const uint32_t *prop;
+
+       memset(fb_mode, 0, sizeof(*fb_mode));
+
+       prop = fdt_getprop(blob, off, "clock-frequency", NULL);
+       if (prop)
+               fb_mode->pixclock = KHZ2PICOS(fdt32_to_cpu(*prop) / 1000);
+
+       prop = fdt_getprop(blob, off, "hactive", NULL);
+       if (prop)
+               fb_mode->xres = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "vactive", NULL);
+       if (prop)
+               fb_mode->yres = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "hback-porch", NULL);
+       if (prop)
+               fb_mode->left_margin = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "hsync-len", NULL);
+       if (prop)
+               fb_mode->hsync_len = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "hfront-porch", NULL);
+       if (prop)
+               fb_mode->right_margin = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "vback-porch", NULL);
+       if (prop)
+               fb_mode->upper_margin = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "vsync-len", NULL);
+       if (prop)
+               fb_mode->vsync_len = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "vfront-porch", NULL);
+       if (prop)
+               fb_mode->lower_margin = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "hsync-active", NULL);
+       if (prop)
+               fb_mode->sync |= *prop ? FB_SYNC_VERT_HIGH_ACT : 0;
+
+       prop = fdt_getprop(blob, off, "vsync-active", NULL);
+       if (prop)
+               fb_mode->sync |= *prop ? FB_SYNC_VERT_HIGH_ACT : 0;
+#if 0
+       prop = fdt_getprop(blob, off, "de-active", NULL);
+       if (prop)
+               fb_mode->sync |= *prop ? FB_SYNC_DATA_ENABLE_HIGH_ACT : 0;
+
+       prop = fdt_getprop(blob, off, "pixelclk-active", NULL);
+       if (prop)
+               fb_mode->sync |= *prop ? FB_SYNC_DOTCLK_FALLING_ACT : 0;
+#endif
+       return 0;
+}
+
+static int fdt_update_native_fb_mode(void *blob, int off)
+{
+       int ret;
+       uint32_t ph;
+       int i;
+
+       for (i = 1; i < 16; i++) {
+               fdt_set_totalsize(blob, fdt_totalsize(blob) + 8 * 4);
+               karo_set_fdtsize(blob);
+               ph = fdt_create_phandle(blob, off);
+               if (ph)
+                       break;
+       }
+       if (ph == 0) {
+               printf("Failed to create phandle for video timing\n");
+               return -ENOMEM;
+       }
+
+       debug("phandle of %s @ %06x=%04x\n", fdt_get_name(blob, off, NULL),
+               off, ph);
+       off = fdt_parent_offset(blob, off);
+       if (off < 0)
+               return off;
+       debug("parent offset=%06x\n", off);
+       ret = fdt_setprop_cell(blob, off, "native-mode", ph);
+       return ret;
+}
+
+static int karo_fdt_find_video_timings(void *blob)
+{
+       int off = fdt_path_offset(blob, "display");
+       const char *subnode = "display-timings";
+
+       if (off < 0) {
+               printf("Could not find node 'display' in FDT: %d\n", off);
+               return off;
+       }
+
+       off = fdt_subnode_offset(blob, off, subnode);
+       if (off < 0) {
+               printf("Could not find node '%s' in FDT: %d\n", subnode, off);
+       }
+       return off;
+}
+
+int karo_fdt_get_fb_mode(void *blob, const char *name, struct fb_videomode *fb_mode)
+{
+       int off = karo_fdt_find_video_timings(blob);
+
+       if (off < 0)
+               return off;
+       do {
+               const char *n;
+               int d = 1;
+
+               off = fdt_next_node(blob, off, &d);
+               if (d > 2) {
+                       printf("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);
+               if (off < 0 || d < 1)
+                       break;
+
+               n = fdt_getprop(blob, off, "panel-name", NULL);
+               if (!n) {
+                       printf("Missing 'panel-name' property in node '%s'\n",
+                               fdt_get_name(blob, off, NULL));
+                       continue;
+               }
+               debug("Checking panel-name '%s'\n", n);
+               if (strcasecmp(n, name) == 0) {
+                       fdt_init_fb_mode(blob, off, fb_mode);
+                       return fdt_update_native_fb_mode(blob, off);
+
+               }
+       } while (off > 0);
+       return -EINVAL;
+}
+
+int karo_fdt_update_fb_mode(void *blob, const char *name)
+{
+       int off = fdt_path_offset(blob, "display");
+       const char *subnode = "display-timings";
+
+       if (off < 0)
+               return off;
+
+       if (name == NULL) {
+               int parent = fdt_parent_offset(blob, off);
+               int ret;
+
+               if (parent < 0) {
+                       printf("Failed to find parent of node '%s'\n",
+                               fdt_get_name(blob, off, NULL));
+                       return parent;
+               }
+               debug("parent offset=%06x\n", parent);
+               ret = fdt_setprop_string(blob, parent, "status", "disabled");
+               return ret;
+       }
+
+       off = fdt_subnode_offset(blob, off, subnode);
+       if (off < 0) {
+               printf("Could not find node '%s' in FDT: %d\n", subnode, off);
+       }
+       do {
+               const char *n;
+               int d = 1;
+               int node = fdt_next_node(blob, off, &d);
+
+               if (d > 2) {
+                       printf("Skipping node @ %04x %s depth %d\n", node, fdt_get_name(blob, node, NULL), d);
+                       continue;
+               }
+               debug("parsing subnode @ %04x %s depth %d\n", node, fdt_get_name(blob, node, NULL), d);
+               if (node < 0 || d < 1)
+                       break;
+
+               n = fdt_getprop(blob, node, "panel-name", NULL);
+               if (!n) {
+                       printf("Missing 'panel-name' property in node '%s'\n",
+                               fdt_get_name(blob, node, NULL));
+                       continue;
+               }
+               debug("Checking panel-name '%s'\n", n);
+               if (strcasecmp(n, name) == 0) {
+                       debug("Keeping node %s @ %04x\n",
+                               fdt_get_name(blob, node, NULL), node);
+                       off = node;
+                       continue;
+               }
+               debug("Deleting node %s @ %04x\n",
+                       fdt_get_name(blob, node, NULL), node);
+               fdt_del_node(blob, node);
+
+       } while (off > 0);
+
+       return 0;
+}
+
 static int karo_load_part(const char *part, void *addr, size_t len)
 {
        int ret;
@@ -280,9 +497,9 @@ static int karo_load_part(const char *part, void *addr, size_t len)
 void *karo_fdt_load_dtb(void)
 {
        int ret;
-       void *fdt = (void *)getenv_ulong("fdtaddr", 16, 0);
+       void *fdt = (void *)getenv_ulong("fdtaddr", 16, CONFIG_SYS_FDT_ADDR);
 
-       if (tstc() || !fdt) {
+       if (tstc()) {
                debug("aborting DTB load\n");
                return NULL;
        }
index cd628c0dd8b3f86999e85facea1ca91680984ec7..66d0702466ad0f36ec5e68a0d7f26f0109112568 100644 (file)
 void karo_fdt_remove_node(void *blob, const char *node);
 void karo_fdt_move_fdt(void);
 void karo_fdt_fixup_touchpanel(void *blob);
-void karo_fdt_fixup_usb_otg(void *blob, const char *compat, phys_addr_t offs);
+void karo_fdt_fixup_usb_otg(void *blob, const char *node, const char *phy);
 void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs,
                const char *prop);
 void karo_fdt_enable_node(void *blob, const char *node, int enable);
 void *karo_fdt_load_dtb(void);
+int karo_fdt_get_fb_mode(void *blob, const char *name,
+               struct fb_videomode *fb_mode);
+int karo_fdt_update_fb_mode(void *blob, const char *name);
 #else
 static inline void karo_fdt_remove_node(void *blob, const char *node)
 {
@@ -34,20 +37,31 @@ static inline void karo_fdt_move_fdt(void)
 static inline void karo_fdt_fixup_touchpanel(void *blob)
 {
 }
-static inline void karo_fdt_fixup_usb_otg(void *blob, const char *compat, phys_addr_t offs)
+static inline void karo_fdt_fixup_usb_otg(void *blob, const char *node,
+                                       const char *phy)
 {
 }
-static inline void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs,
-               const char *prop)
+static inline void karo_fdt_del_prop(void *blob, const char *compat,
+                               phys_addr_t offs, const char *prop)
 {
 }
-static inline void karo_fdt_enable_node(void *blob, const char *node, int enable)
+static inline void karo_fdt_enable_node(void *blob, const char *node,
+                                       int enable)
 {
 }
 static inline void *karo_fdt_load_dtb(void)
 {
        return NULL;
 }
+static inline int karo_fdt_get_fb_mode(void *blob, const char *name,
+                               struct fb_videomode *fb_mode)
+{
+       return NULL;
+}
+static inline int karo_fdt_update_fb_mode(void *blob, const char *name)
+{
+       return 0;
+}
 #endif
 
 int karo_load_splashimage(int mode);
index 79fe6f477522c36f17657dc4a4f4bf2f4deade2d..5b81809d0ebe4896a5264ed81d8376586cdc8b3a 100644 (file)
@@ -143,6 +143,9 @@ int board_early_init_f(void)
 int board_init(void)
 {
        /* Address of boot parameters */
+#ifdef CONFIG_OF_LIBFDT
+       gd->bd->bi_arch_number = -1;
+#endif
        gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x1000;
        return 0;
 }
@@ -548,7 +551,8 @@ void lcd_ctrl_init(void *lcdbase)
        char *vm;
        unsigned long val;
        int refresh = 60;
-       struct fb_videomode *p = &tx28_fb_modes[0];
+       struct fb_videomode *p = tx28_fb_modes;
+       struct fb_videomode fb_mode;
        int xres_set = 0, yres_set = 0, bpp_set = 0, refresh_set = 0;
 
        if (!lcd_enabled) {
@@ -562,21 +566,31 @@ void lcd_ctrl_init(void *lcdbase)
                return;
        }
 
+       karo_fdt_move_fdt();
+
        vm = getenv("video_mode");
        if (vm == NULL) {
                debug("Disabling LCD\n");
                lcd_enabled = 0;
                return;
        }
+       if (karo_fdt_get_fb_mode(working_fdt, vm, &fb_mode) == 0) {
+               p = &fb_mode;
+               debug("Using video mode from FDT\n");
+               vm += strlen(vm);
+       }
+       if (p->name != NULL)
+               debug("Trying compiled-in video modes\n");
        while (p->name != NULL) {
                if (strcmp(p->name, vm) == 0) {
-                       printf("Using video mode: '%s'\n", p->name);
+                       debug("Using video mode: '%s'\n", p->name);
                        vm += strlen(vm);
                        break;
                }
                p++;
        }
-
+       if (*vm != '\0')
+               debug("Trying to decode video_mode: '%s'\n", vm);
        while (*vm != '\0') {
                if (*vm >= '0' && *vm <= '9') {
                        char *end;
@@ -707,6 +721,13 @@ int board_late_init(void)
                        strcmp(baseboard, "stk5-v3") == 0) {
                        stk5v3_board_init();
                } else if (strcmp(baseboard, "stk5-v5") == 0) {
+                       const char *otg_mode = getenv("otg_mode");
+
+                       if (otg_mode && strcmp(otg_mode, "host") == 0) {
+                               printf("otg_mode='%s' is incompatible with baseboard %s; setting to 'none'\n",
+                                       otg_mode, baseboard);
+                               setenv("otg_mode", "none");
+                       }
                        stk5v5_board_init();
                } else {
                        printf("WARNING: Unsupported STK5 board rev.: %s\n",
@@ -740,13 +761,13 @@ struct node_info tx28_nand_nodes[] = {
 
 static void tx28_fixup_flexcan(void *blob)
 {
-       karo_fdt_del_prop(blob, "fsl,p1010-flexcan", 0x80032000, "transceiver-switch");
-       karo_fdt_del_prop(blob, "fsl,p1010-flexcan", 0x80034000, "transceiver-switch");
+       karo_fdt_del_prop(blob, "fsl,imx28-flexcan", 0x80032000, "transceiver-switch");
+       karo_fdt_del_prop(blob, "fsl,imx28-flexcan", 0x80034000, "transceiver-switch");
 }
 
 static void tx28_fixup_fec(void *blob)
 {
-       karo_fdt_remove_node(blob, "ethernet1");
+       karo_fdt_enable_node(blob, "ethernet1", 0);
 }
 
 void ft_board_setup(void *blob, bd_t *bd)
@@ -758,16 +779,9 @@ void ft_board_setup(void *blob, bd_t *bd)
         * and no I2C GPIO extender
         */
        karo_fdt_remove_node(blob, "ds1339");
-       karo_fdt_remove_node(blob, "pca9554");
+       karo_fdt_remove_node(blob, "gpio5");
 #endif
        if (baseboard != NULL && strcmp(baseboard, "stk5-v5") == 0) {
-               const char *otg_mode = getenv("otg_mode");
-
-               if (otg_mode && strcmp(otg_mode, "host") == 0) {
-                       printf("otg_mode=%s incompatible with baseboard %s\n",
-                               otg_mode, baseboard);
-                       setenv(otg_mode, "none");
-               }
                karo_fdt_remove_node(blob, "stk5led");
        } else {
                tx28_fixup_flexcan(blob);
@@ -777,14 +791,16 @@ void ft_board_setup(void *blob, bd_t *bd)
        if (baseboard != NULL && strcmp(baseboard, "stk5-v3") == 0) {
                const char *otg_mode = getenv("otg_mode");
 
-               if (otg_mode && strcmp(otg_mode, "device") == 0)
-                       karo_fdt_remove_node(blob, "can1");
+               if (otg_mode && (strcmp(otg_mode, "device") == 0 ||
+                                       strcmp(otg_mode, "gadget") == 0))
+                       karo_fdt_enable_node(blob, "can1", 0);
        }
 
        fdt_fixup_mtdparts(blob, tx28_nand_nodes, ARRAY_SIZE(tx28_nand_nodes));
        fdt_fixup_ethernet(blob);
 
        karo_fdt_fixup_touchpanel(blob);
-       karo_fdt_fixup_usb_otg(blob, "fsl,imx28-usbphy", 0x8007c000);
+       karo_fdt_fixup_usb_otg(blob, "usbotg", "fsl,usbphy");
+       karo_fdt_update_fb_mode(blob, getenv("video_mode"));
 }
 #endif