X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=board%2Fkaro%2Fcommon%2Ffdt.c;h=387208c78e4e317e36ce96a4079121c39812337f;hp=4e7eae79553bb4a35fdbf3c42ee58f6646d85b68;hb=cae0d09651975e122d2b4c66779adc77b8179432;hpb=2e06c9452fc7ed0840e8096516431e3a0de11244 diff --git a/board/karo/common/fdt.c b/board/karo/common/fdt.c index 4e7eae7955..387208c78e 100644 --- a/board/karo/common/fdt.c +++ b/board/karo/common/fdt.c @@ -48,57 +48,13 @@ static void karo_set_fdtsize(void *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; - - 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 (tstc()) { - debug("aborting DTB load\n"); + if (had_ctrlc()) { + printf("aborting DTB load\n"); return NULL; } @@ -130,6 +86,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", @@ -174,12 +132,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); } @@ -190,7 +149,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, @@ -199,56 +159,75 @@ void karo_fdt_enable_node(void *blob, const char *node, int enable) karo_set_fdtsize(blob); } -static const char *karo_touchpanels[] = { - "ti,tsc2007", - "edt,edt-ft5x06", -#ifdef CONFIG_MX28 - "fsl,imx28-lradc", -#endif -}; - 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); - return; + while (offs >= 0) { + debug("Disabling node '%s'\n", name); + fdt_set_node_status(blob, offs, FDT_STATUS_DISABLED, 0); + offs = fdt_node_offset_by_compatible(blob, offs, name); } - - debug("Disabling node '%s'\n", name); - fdt_set_node_status(blob, offs, FDT_STATUS_DISABLED, 0); } -void karo_fdt_fixup_touchpanel(void *blob) +void karo_fdt_fixup_touchpanel(void *blob, const char *panels[], + size_t num_panels) { int i; const char *model = getenv("touchpanel"); - for (i = 0; i < ARRAY_SIZE(karo_touchpanels); i++) { - const char *tp = karo_touchpanels[i]; - - if (model != NULL && strcmp(model, tp) == 0) - continue; + for (i = 0; i < num_panels; i++) { + const char *tp = panels[i]; if (model != NULL) { if (strcmp(model, tp) == 0) continue; - tp = strchr(tp, ','); - if (tp != NULL && *tp != '\0' && strcmp(model, tp + 1) == 0) + while (tp != NULL) { + if (*tp != '\0' && strcmp(model, tp + 1) == 0) + break; + tp = strpbrk(tp + 1, ",-"); + } + if (tp != NULL) continue; } - fdt_disable_tp_node(blob, karo_touchpanels[i]); + fdt_disable_tp_node(blob, panels[i]); } karo_set_fdtsize(blob); } +static int karo_fdt_disable_node_phandle(void *blob, const char *parent, + const char *name) +{ + const uint32_t *ph; + int off; + + off = fdt_path_offset(blob, parent); + if (off < 0) { + printf("Failed to find node '%s'\n", parent); + return off; + } + + ph = fdt_getprop(blob, off, name, NULL); + if (ph == NULL) { + debug("Failed to find '%s' phandle in node '%s'\n", name, + fdt_get_name(blob, off, NULL)); + return -FDT_ERR_NOTFOUND; + } + + off = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*ph)); + if (off <= 0) { + printf("Failed to find '%s' node via phandle %04x\n", + name, fdt32_to_cpu(*ph)); + return -FDT_ERR_NOTFOUND; + } + return fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); +} + 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; int disable_otg = 0; int disable_phy_pins = 1; @@ -271,6 +250,7 @@ void karo_fdt_fixup_usb_otg(void *blob, const char *node, const char *phy) } else if (otg_mode && strcmp(otg_mode, "otg") == 0) { debug("Setting dr_mode to 'host'\n"); ret = fdt_setprop_string(blob, off, "dr_mode", "otg"); + disable_phy_pins = 0; } else { if (otg_mode && strcmp(otg_mode, "none") != 0) printf("Invalid 'otg_mode' setting '%s'; disabling usbotg port\n", @@ -282,41 +262,33 @@ void karo_fdt_fixup_usb_otg(void *blob, const char *node, const char *phy) if ((!disable_phy_pins && !disable_otg) || ret) goto out; + ret = karo_fdt_disable_node_phandle(blob, node, "vbus-supply"); + if (ret) + goto out; + if (disable_otg) { + debug("Disabling usbphy\n"); ret = fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); if (ret) 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; - } - - 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 = karo_fdt_disable_node_phandle(blob, node, phy); + } else if (disable_phy_pins) { + debug("Removing 'vbus-supply' from usbotg node\n"); + fdt_delprop(blob, off, "vbus-supply"); } - if (disable_otg) { - debug("Disabling usbphy\n"); - ret = fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); - } 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); } -static int karo_fdt_flexcan_enabled(void *blob) +static inline int karo_fdt_flexcan_enabled(void *blob) { - const char *can_ifs[] = { + static const char *can_ifs[] = { "can0", "can1", }; @@ -340,7 +312,7 @@ static int karo_fdt_flexcan_enabled(void *blob) return 0; } -static void karo_fdt_set_lcd_pins(void *blob, const char *name) +static inline void karo_fdt_set_lcd_pins(void *blob, const char *name) { int off = fdt_path_offset(blob, name); u32 ph; @@ -368,25 +340,44 @@ static void karo_fdt_set_lcd_pins(void *blob, const char *name) void karo_fdt_fixup_flexcan(void *blob, int xcvr_present) { + int ret; const char *xcvr_status = "disabled"; + const char *otg_mode = getenv("otg_mode"); if (xcvr_present) { if (karo_fdt_flexcan_enabled(blob)) { - karo_fdt_set_lcd_pins(blob, "lcdif_23bit_pins_a"); - xcvr_status = "okay"; - } else { + if (!is_lvds()) { + debug("Changing LCD to use 23bits only\n"); + karo_fdt_set_lcd_pins(blob, "lcdif_23bit_pins_a"); + xcvr_status = NULL; + } + } else if (!is_lvds()) { + debug("Changing LCD to use 24bits\n"); karo_fdt_set_lcd_pins(blob, "lcdif_24bit_pins_a"); } } else { - const char *otg_mode = getenv("otg_mode"); + int off = fdt_path_offset(blob, "can0"); + + if (off >= 0) + fdt_delprop(blob, off, "xceiver-supply"); + off = fdt_path_offset(blob, "can1"); + if (off >= 0) + fdt_delprop(blob, off, "xceiver-supply"); + if (!is_lvds()) + karo_fdt_set_lcd_pins(blob, "lcdif_24bit_pins_a"); + } - if (otg_mode && (strcmp(otg_mode, "host") == 0)) - karo_fdt_enable_node(blob, "can1", 0); + if (otg_mode && strcmp(otg_mode, "host") == 0) + karo_fdt_enable_node(blob, "can1", 0); - karo_fdt_set_lcd_pins(blob, "lcdif_24bit_pins_a"); + if (xcvr_status) { + debug("Disabling CAN XCVR\n"); + ret = fdt_find_and_setprop(blob, "reg_can_xcvr", "status", + xcvr_status, strlen(xcvr_status) + 1, 1); + if (ret) + printf("Failed to disable CAN transceiver switch: %s\n", + fdt_strerror(ret)); } - fdt_find_and_setprop(blob, "/regulators/can-xcvr", "status", - xcvr_status, strlen(xcvr_status) + 1, 1); } void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs, @@ -491,7 +482,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); @@ -508,7 +500,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; } @@ -519,13 +512,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; } @@ -546,10 +541,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) { @@ -583,7 +580,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; \ }) @@ -603,23 +601,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; } 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; } } 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; @@ -671,95 +672,6 @@ 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\n", display, ret); - 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"); @@ -779,7 +691,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) { @@ -792,10 +705,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) { @@ -823,3 +738,95 @@ int karo_fdt_update_fb_mode(void *blob, const char *name) return fdt_update_native_fb_mode(blob, off); return off; } + +#ifdef CONFIG_SYS_LVDS_IF +int karo_fdt_get_lcd_bus_width(const void *blob, int default_width) +{ + int off = fdt_path_offset(blob, "display"); + + if (off >= 0) { + const uint32_t *prop; + + prop = fdt_getprop(blob, off, "fsl,data-width", NULL); + if (prop) + return fdt32_to_cpu(*prop); + } + return default_width; +} + +int karo_fdt_get_lvds_mapping(const void *blob, int default_mapping) +{ + int off = fdt_path_offset(blob, "display"); + + if (off >= 0) { + const char *prop; + + prop = fdt_getprop(blob, off, "fsl,data-mapping", NULL); + if (prop) + return strcmp(prop, "jeida") == 0; + } + return default_mapping; +} + +u8 karo_fdt_get_lvds_channels(const void *blob) +{ + static const char *lvds_chans[] = { + "lvds0", + "lvds1", + }; + u8 lvds_chan_mask = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(lvds_chans); i++) { + const char *status; + int off = fdt_path_offset(blob, lvds_chans[i]); + + if (off < 0) + continue; + + status = fdt_getprop(blob, off, "status", NULL); + if (status && strcmp(status, "okay") == 0) { + debug("%s is enabled\n", lvds_chans[i]); + lvds_chan_mask |= 1 << i; + } + } + return lvds_chan_mask; +} +#endif + +int karo_fdt_get_backlight_polarity(const void *blob) +{ +#ifdef CONFIG_SYS_LVDS_IF + const char *backlight_node = "/backlight0"; +#else + const char *backlight_node = "/backlight"; +#endif + int off = fdt_path_offset(blob, "backlight"); /* first try alias */ + const struct fdt_property *prop; + int len; + + if (off < 0) { + /* + * if no 'backlight' alias exists try finding '/backlight0' + * or '/backlight' depending on LVDS or not + */ + off = fdt_path_offset(blob, backlight_node); + if (off < 0) { + printf("/backlight node not found in DT\n"); + return off; + } + } + + prop = fdt_get_property(blob, off, "pwms", &len); + if (!prop) + printf("'pwms' property not found\n"); + else + debug("'pwms' property has len %d\n", len); + + len /= sizeof(u32); + if (prop && len > 3) { + const u32 *data = (const u32 *)prop->data; + return fdt32_to_cpu(data[3]) == 0; + } + return 0; +}