From: Lothar Waßmann Date: Mon, 15 Jul 2013 10:05:48 +0000 (+0200) Subject: mxs: tx28: update FDT code for Linux 3.10 X-Git-Tag: KARO_TX6-2013-08-01~24 X-Git-Url: https://git.kernelconcepts.de/?a=commitdiff_plain;h=584906b884d94887f97ca2df25f98445533d6933;p=karo-tx-uboot.git mxs: tx28: update FDT code for Linux 3.10 --- diff --git a/board/karo/common/fdt.c b/board/karo/common/fdt.c index d039c459d2..b4c77e9261 100644 --- a/board/karo/common/fdt.c +++ b/board/karo/common/fdt.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #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 : ""); - 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; } diff --git a/board/karo/common/karo.h b/board/karo/common/karo.h index cd628c0dd8..66d0702466 100644 --- a/board/karo/common/karo.h +++ b/board/karo/common/karo.h @@ -19,11 +19,14 @@ 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); diff --git a/board/karo/tx28/tx28.c b/board/karo/tx28/tx28.c index 79fe6f4775..5b81809d0e 100644 --- a/board/karo/tx28/tx28.c +++ b/board/karo/tx28/tx28.c @@ -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