X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=board%2Fkaro%2Fcommon%2Ffdt.c;h=909f0ca770a4df3dbb4a6c17e71697732265b372;hp=d43a1170fc27a27748b55eadb131dcc7ec8df03d;hb=HEAD;hpb=a177608da04b386f0d686e1774795b6f229b2f5c diff --git a/board/karo/common/fdt.c b/board/karo/common/fdt.c index d43a1170fc..909f0ca770 100644 --- a/board/karo/common/fdt.c +++ b/board/karo/common/fdt.c @@ -13,7 +13,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * -*/ + */ #include #include @@ -385,11 +385,15 @@ void karo_fdt_fixup_flexcan(void *blob, int xcvr_present) if (karo_fdt_flexcan_enabled(blob)) { if (!is_lvds()) { debug("Changing LCD to use 23bits only\n"); + karo_fdt_set_lcd_pins(blob, "lcdif-23bit-pins-a"); + /* handle legacy alias name */ 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"); + /* handle legacy alias name */ karo_fdt_set_lcd_pins(blob, "lcdif_24bit_pins_a"); } } else { @@ -400,8 +404,11 @@ void karo_fdt_fixup_flexcan(void *blob, int xcvr_present) off = fdt_path_offset(blob, "can1"); if (off >= 0) fdt_delprop(blob, off, "xceiver-supply"); - if (!is_lvds()) + if (!is_lvds()) { + karo_fdt_set_lcd_pins(blob, "lcdif-24bit-pins-a"); + /* handle legacy alias name */ karo_fdt_set_lcd_pins(blob, "lcdif_24bit_pins_a"); + } } if (otg_mode && strcasecmp(otg_mode, "host") == 0) @@ -409,9 +416,12 @@ void karo_fdt_fixup_flexcan(void *blob, int xcvr_present) if (xcvr_status) { debug("Disabling CAN XCVR\n"); - ret = fdt_find_and_setprop(blob, "reg_can_xcvr", "status", + ret = fdt_find_and_setprop(blob, "reg-can-xcvr", "status", xcvr_status, strlen(xcvr_status) + 1, 1); - if (ret) + if (ret == -FDT_ERR_NOTFOUND || ret == -FDT_ERR_BADPATH) + ret = fdt_find_and_setprop(blob, "reg_can_xcvr", "status", + xcvr_status, strlen(xcvr_status) + 1, 1); + if (ret && ret != -FDT_ERR_NOTFOUND && ret != -FDT_ERR_BADPATH) printf("Failed to disable CAN transceiver switch: %s\n", fdt_strerror(ret)); } @@ -498,7 +508,7 @@ static int fdt_init_fb_mode(const void *blob, int off, struct fb_videomode *fb_m prop = fdt_getprop(blob, off, "pixelclk-active", NULL); if (prop) - fb_mode->sync |= *prop ? 0 : FB_SYNC_CLK_LAT_FALL; + fb_mode->sync |= *prop ? FB_SYNC_CLK_LAT_FALL : 0; return 0; } @@ -553,15 +563,27 @@ static int karo_fdt_find_video_timings(void *blob) return off; } -int karo_fdt_get_fb_mode(void *blob, const char *name, struct fb_videomode *fb_mode) +static int karo_fdt_check_panel_name(const char *pn, const char *name, int len) { - int off = karo_fdt_find_video_timings(blob); + const char *endp = pn + len; - if (off < 0) - return off; + if (len < 0) + return 0; + while (pn < endp) { + if (strcasecmp(pn, name) == 0) + return 1; + pn += strlen(pn) + 1; + } + return 0; +} + +static int karo_fdt_find_panel(const void *blob, int off, const char *name) +{ + debug("Searching panel '%s'\n", name); while (off > 0) { - const char *n, *endp; - int len, d = 1; + const char *pn; + int d = 1; + int len; off = fdt_next_node(blob, off, &d); if (off < 0) @@ -574,28 +596,30 @@ int karo_fdt_get_fb_mode(void *blob, const char *name, struct fb_videomode *fb_m continue; } - n = fdt_getprop(blob, off, "panel-name", &len); - if (!n) { - n = fdt_get_name(blob, off, NULL); - if (strcasecmp(n, name) == 0) { - break; - } - } else { - int found = 0; - - for (endp = n + len; n < endp; n += strlen(n) + 1) { - debug("Checking panel-name '%s'\n", n); - if (strcasecmp(n, name) == 0) { - debug("Using node %s @ %04x\n", - fdt_get_name(blob, off, NULL), off); - found = 1; - break; - } - } - if (found) - break; - } + pn = fdt_get_name(blob, off, NULL); + debug("Checking node name '%s'\n", pn); + if (strcasecmp(pn, name) == 0) + break; + pn = fdt_getprop(blob, off, "u-boot,panel-name", &len); + if (!pn) + continue; + if (karo_fdt_check_panel_name(pn, name, len)) + break; } + if (off > 0) + debug("Found LCD panel: '%s' @ off %03x\n", + fdt_get_name(blob, off, NULL), 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; + off = karo_fdt_find_panel(blob, off, name); if (off > 0) { return fdt_init_fb_mode(blob, off, fb_mode); } @@ -698,21 +722,107 @@ out: return ret; } -int karo_fdt_update_fb_mode(void *blob, const char *name) +static const char *karo_panel_timing_props[] = { + "clock-frequency", + "hactive", + "vactive", + "hback-porch", + "hsync-len", + "hfront-porch", + "vback-porch", + "vsync-len", + "vfront-porch", + "hsync-active", + "vsync-active", + "de-active", + "pixelclk-active", +}; + +static int karo_fixup_panel_timing(void *fdt, int dest, int src) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(karo_panel_timing_props); i++) { + const char *name = karo_panel_timing_props[i]; + int len; + int ret; + const void *val; + bool restart; + + val = fdt_getprop(fdt, src, name, &len); + if (!val) { + if (fdt_getprop(fdt, dest, name, NULL)) { + printf("Removing '%s' from '%s'\n", name, + fdt_get_name(fdt, dest, NULL)); + fdt_delprop(fdt, dest, name); + return -EAGAIN; + } + continue; + } + if (len != sizeof(u32)) { + printf("Property '%s' has invalid size %u\n", + name, len); + return -EINVAL; + } + debug("setting '%s' to <0x%08x>\n", name, be32_to_cpup(val)); + + restart = !fdt_getprop(fdt, dest, name, &len); + restart |= len != sizeof(u32); + /* DTB offsets will change when adding a new property */ + if (restart) { + ret = fdt_increase_size(fdt, len); + if (ret) { + printf("Failed to increase FDT size by %u: %s\n", len, + fdt_strerror(ret)); + return -ENOMEM; + } + printf("Adding new property '%s' to '%s'\n", + name, fdt_get_name(fdt, dest, NULL)); + } + ret = fdt_setprop_u32(fdt, dest, name, be32_to_cpup(val)); + if (ret) { + printf("Failed to set %s property: %s\n", name, + fdt_strerror(ret)); + return -EINVAL; + } + if (restart) + return -EAGAIN; + } + return 0; +} + +int karo_fdt_update_fb_mode(void *blob, const char *name, + const char *panel_name) { + int ret; int off = fdt_path_offset(blob, "display"); + int dt_node; + int panel_off = -1; const char *subnode = "display-timings"; + size_t i = 0; - if (off < 0) + if (panel_name) + panel_off = fdt_path_offset(blob, panel_name); + + if (off < 0 && panel_off < 0) return off; if (name == NULL) { - int ret; - debug("Disabling node '%s' at %03x\n", fdt_get_name(blob, off, NULL), off); ret = fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); - return ret; + if (ret) + printf("Failed to disable node '%s': %s\n", + fdt_get_name(blob, off, NULL), + fdt_strerror(ret)); + if (!panel_name) + return ret; + + panel_off = fdt_path_offset(blob, panel_name); + if (panel_off < 0) + return 0; + return fdt_set_node_status(blob, panel_off, + FDT_STATUS_DISABLED, 0); } off = fdt_subnode_offset(blob, off, subnode); @@ -721,46 +831,70 @@ int karo_fdt_update_fb_mode(void *blob, const char *name) fdt_strerror(off)); return off; } - while (off > 0) { - const char *n, *endp; - int len, d = 1; - - off = fdt_next_node(blob, off, &d); - if (off < 0) - return off; - if (d < 1) - return -EINVAL; - if (d > 2) { - debug("Skipping node @ %04x %s depth %d\n", off, - fdt_get_name(blob, off, NULL), d); - continue; + off = karo_fdt_find_panel(blob, off, name); + if (off > 0) + ret = fdt_update_native_fb_mode(blob, off); + else + ret = 0; + if (!panel_name) + return ret; + restart: + dt_node = fdt_path_offset(blob, "display/display-timings"); + off = karo_fdt_find_panel(blob, dt_node, name); + panel_off = fdt_path_offset(blob, panel_name); + if (panel_off > 0) { + int node = fdt_subnode_offset(blob, dt_node, name); + + if (node < 0) { + printf("Warning: No '%s' subnode found in 'display-timings'\n", + name); + return -ENOENT; } + if (fdt_node_check_compatible(blob, panel_off, "panel-dpi") == 0) { + int timing_node = fdt_subnode_offset(blob, panel_off, + "panel-timing"); - n = fdt_getprop(blob, off, "panel-name", &len); - if (!n) { - n = fdt_get_name(blob, off, NULL); - if (strcasecmp(n, name) == 0) { - break; + if (timing_node < 0) { + printf("Warning: No 'panel-timing' subnode found\n"); + return -ENOENT; } - } else { - int found = 0; - - for (endp = n + len; n < endp; n += strlen(n) + 1) { - debug("Checking panel-name '%s'\n", n); - if (strcasecmp(n, name) == 0) { - debug("Using node %s @ %04x\n", - fdt_get_name(blob, off, NULL), off); - found = 1; - break; - } + + if (i == 0) + printf("Copying video timing from %s\n", name); + ret = karo_fixup_panel_timing(blob, + timing_node, + node); + if (ret == -EAGAIN) { + if (i++ > ARRAY_SIZE(karo_panel_timing_props)) + return -EINVAL; + goto restart; } - if (found) - break; + } else { + char *pn; + + name = fdt_getprop(blob, off, "u-boot,panel-name", + NULL); + if (!name) + return 0; + + pn = strdup(name); + if (!pn) + return -ENOMEM; + debug("%s@%d: Updating 'compatible' property of '%s' from '%s' to '%s'\n", + __func__, __LINE__, fdt_get_name(blob, panel_off, NULL), + (char *)fdt_getprop(blob, panel_off, "compatible", NULL), + pn); + + ret = fdt_setprop_string(blob, panel_off, "compatible", + pn); + if (ret) + printf("Failed to set 'compatible' property of node '%s': %s\n", + fdt_get_name(blob, panel_off, NULL), + fdt_strerror(off)); + free(pn); } } - if (off > 0) - return fdt_update_native_fb_mode(blob, off); - return off; + return ret; } #ifdef CONFIG_SYS_LVDS_IF