#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"
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",
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 {
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)
}
}
-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);
}
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;
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;
}
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;
}
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) {
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;
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",
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)
* 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);
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