* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
-*/
+ */
#include <common.h>
#include <errno.h>
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 {
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)
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));
}
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;
}
return ret;
}
+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 (panel_name)
panel_off = fdt_path_offset(blob, panel_name);
ret = 0;
if (!panel_name)
return ret;
-
- off = fdt_path_offset(blob, "display/display-timings");
- off = karo_fdt_find_panel(blob, off, name);
+ 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) {
- char *pn;
+ int node = fdt_subnode_offset(blob, dt_node, name);
- 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 (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");
+
+ if (timing_node < 0) {
+ printf("Warning: No 'panel-timing' subnode found\n");
+ return -ENOENT;
+ }
+
+ 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;
+ }
+ } 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);
+ }
}
return ret;
}