X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=board%2Fkaro%2Ftx48%2Ftx48.c;h=10b939095d350b63c1715946430fc8525f29f08c;hp=6d1c69cdf567edd3eb1ec5ecadf991d4cbcefaf6;hb=ab62e387cafb5e99819e24715dbc6496f5516e5a;hpb=49bd24770192ee9cf0619bdb351fc51941ec24b8 diff --git a/board/karo/tx48/tx48.c b/board/karo/tx48/tx48.c index 6d1c69cdf5..10b939095d 100644 --- a/board/karo/tx48/tx48.c +++ b/board/karo/tx48/tx48.c @@ -1,6 +1,5 @@ /* - * tx48.c - * Copyright (C) 2012 Lothar Waßmann + * Copyright (C) 2012-2013 Lothar Waßmann * * based on evm.c * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ @@ -26,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -48,6 +47,7 @@ DECLARE_GLOBAL_DATA_PTR; #define TX48_LCD_RST_GPIO AM33XX_GPIO_NR(1, 19) #define TX48_LCD_PWR_GPIO AM33XX_GPIO_NR(1, 22) #define TX48_LCD_BACKLIGHT_GPIO AM33XX_GPIO_NR(3, 14) +#define TX48_MMC_CD_GPIO AM33XX_GPIO_NR(3, 15) #define GMII_SEL (CTRL_BASE + 0x650) @@ -72,10 +72,6 @@ DECLARE_GLOBAL_DATA_PTR; #define NO_OF_MAC_ADDR 1 #define ETH_ALEN 6 -#define MUX_CFG(value, offset) { \ - __raw_writel(value, (CTRL_BASE + (offset))); \ - } - /* PAD Control Fields */ #define SLEWCTRL (0x1 << 6) #define RXACTIVE (0x1 << 5) @@ -315,7 +311,7 @@ static inline void tx48_set_pin_mux(const struct pin_mux *pin_mux, int i; for (i = 0; i < num_pins; i++) - MUX_CFG(pin_mux[i].val, pin_mux[i].reg_offset); + writel(pin_mux[i].val, CTRL_BASE + pin_mux[i].reg_offset); } #define PRM_RSTST_GLOBAL_COLD_RST (1 << 0) @@ -338,6 +334,13 @@ static const struct pin_mux stk5_pads[] = { { OFFSET(gpmc_a6), MODE(7) | PULLUDEN, }, /* LCD Backlight (PWM) */ { OFFSET(mcasp0_aclkx), MODE(7) | PULLUDEN, }, + /* MMC CD */ + { OFFSET(mcasp0_fsx), MODE(7) | PULLUDEN | PULLUP_EN, }, +}; + +static const struct gpio stk5_gpios[] = { + { TX48_LED_GPIO, GPIOF_OUTPUT_INIT_LOW, "HEARTBEAT LED", }, + { TX48_MMC_CD_GPIO, GPIOF_INPUT, "MMC0 CD", }, }; static const struct pin_mux stk5_lcd_pads[] = { @@ -365,10 +368,6 @@ static const struct pin_mux stk5_lcd_pads[] = { { OFFSET(lcd_ac_bias_en), MODE(0) | PULLUDEN, }, }; -static const struct gpio stk5_gpios[] = { - { AM33XX_GPIO_NR(1, 26), GPIOF_OUTPUT_INIT_LOW, "HEARTBEAT LED", }, -}; - static const struct gpio stk5_lcd_gpios[] = { { AM33XX_GPIO_NR(1, 19), GPIOF_OUTPUT_INIT_LOW, "LCD RESET", }, { AM33XX_GPIO_NR(1, 22), GPIOF_OUTPUT_INIT_LOW, "LCD POWER", }, @@ -395,18 +394,138 @@ vidinfo_t panel_info = { .cmap = tx48_cmap, }; -static struct da8xx_panel tx48_lcd_panel = { - .name = "640x480MR@60", - .width = 640, - .height = 480, - .hfp = 12, - .hbp = 144, - .hsw = 30, - .vfp = 10, - .vbp = 35, - .vsw = 3, - .pxl_clk = 25000000, - .invert_pxl_clk = 1, +#define FB_SYNC_OE_LOW_ACT (1 << 31) +#define FB_SYNC_CLK_LAT_FALL (1 << 30) + +static struct fb_videomode tx48_fb_modes[] = { + { + /* Standard VGA timing */ + .name = "VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = KHZ2PICOS(25175), + .left_margin = 48, + .hsync_len = 96, + .right_margin = 16, + .upper_margin = 31, + .vsync_len = 2, + .lower_margin = 12, + .sync = FB_SYNC_CLK_LAT_FALL, + }, + { + /* Emerging ETV570 640 x 480 display. Syncs low active, + * DE high active, 115.2 mm x 86.4 mm display area + * VGA compatible timing + */ + .name = "ETV570", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = KHZ2PICOS(25175), + .left_margin = 114, + .hsync_len = 30, + .right_margin = 16, + .upper_margin = 32, + .vsync_len = 3, + .lower_margin = 10, + .sync = FB_SYNC_CLK_LAT_FALL, + }, + { + /* Emerging ET0350G0DH6 320 x 240 display. + * 70.08 mm x 52.56 mm display area. + */ + .name = "ET0350", + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = KHZ2PICOS(6500), + .left_margin = 68 - 34, + .hsync_len = 34, + .right_margin = 20, + .upper_margin = 18 - 3, + .vsync_len = 3, + .lower_margin = 4, + .sync = FB_SYNC_CLK_LAT_FALL, + }, + { + /* Emerging ET0430G0DH6 480 x 272 display. + * 95.04 mm x 53.856 mm display area. + */ + .name = "ET0430", + .refresh = 60, + .xres = 480, + .yres = 272, + .pixclock = KHZ2PICOS(9000), + .left_margin = 2, + .hsync_len = 41, + .right_margin = 2, + .upper_margin = 2, + .vsync_len = 10, + .lower_margin = 2, + }, + { + /* Emerging ET0500G0DH6 800 x 480 display. + * 109.6 mm x 66.4 mm display area. + */ + .name = "ET0500", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = KHZ2PICOS(33260), + .left_margin = 216 - 128, + .hsync_len = 128, + .right_margin = 1056 - 800 - 216, + .upper_margin = 35 - 2, + .vsync_len = 2, + .lower_margin = 525 - 480 - 35, + .sync = FB_SYNC_CLK_LAT_FALL, + }, + { + /* Emerging ETQ570G0DH6 320 x 240 display. + * 115.2 mm x 86.4 mm display area. + */ + .name = "ETQ570", + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = KHZ2PICOS(6400), + .left_margin = 38, + .hsync_len = 30, + .right_margin = 30, + .upper_margin = 16, /* 15 according to datasheet */ + .vsync_len = 3, /* TVP -> 1>x>5 */ + .lower_margin = 4, /* 4.5 according to datasheet */ + .sync = FB_SYNC_CLK_LAT_FALL, + }, + { + /* Emerging ET0700G0DH6 800 x 480 display. + * 152.4 mm x 91.44 mm display area. + */ + .name = "ET0700", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = KHZ2PICOS(33260), + .left_margin = 216 - 128, + .hsync_len = 128, + .right_margin = 1056 - 800 - 216, + .upper_margin = 35 - 2, + .vsync_len = 2, + .lower_margin = 525 - 480 - 35, + .sync = FB_SYNC_CLK_LAT_FALL, + }, + { + /* unnamed entry for assigning parameters parsed from 'video_mode' string */ + .refresh = 60, + .left_margin = 48, + .hsync_len = 96, + .right_margin = 16, + .upper_margin = 31, + .vsync_len = 2, + .lower_margin = 12, + .sync = FB_SYNC_CLK_LAT_FALL, + }, }; void *lcd_base; /* Start of framebuffer memory */ @@ -419,6 +538,12 @@ short console_col; short console_row; static int lcd_enabled = 1; +static int lcd_bl_polarity; + +static int lcd_backlight_polarity(void) +{ + return lcd_bl_polarity; +} void lcd_initcolregs(void) { @@ -440,25 +565,49 @@ void lcd_enable(void) if (lcd_enabled) { karo_load_splashimage(1); + debug("Switching LCD on\n"); gpio_set_value(TX48_LCD_PWR_GPIO, 1); + udelay(100); gpio_set_value(TX48_LCD_RST_GPIO, 1); udelay(300000); - gpio_set_value(TX48_LCD_BACKLIGHT_GPIO, 0); + gpio_set_value(TX48_LCD_BACKLIGHT_GPIO, + lcd_backlight_polarity()); } } void lcd_disable(void) { if (lcd_enabled) { + printf("Disabling LCD\n"); da8xx_fb_disable(); lcd_enabled = 0; } } +static void tx48_lcd_panel_setup(struct da8xx_panel *p, + struct fb_videomode *fb) +{ + p->pxl_clk = PICOS2KHZ(fb->pixclock) * 1000; + + p->width = fb->xres; + p->hbp = fb->left_margin; + p->hsw = fb->hsync_len; + p->hfp = fb->right_margin; + + p->height = fb->yres; + p->vbp = fb->upper_margin; + p->vsw = fb->vsync_len; + p->vfp = fb->lower_margin; + + p->invert_pxl_clk = !!(fb->sync & FB_SYNC_CLK_LAT_FALL); +} + void lcd_panel_disable(void) { if (lcd_enabled) { - gpio_set_value(TX48_LCD_BACKLIGHT_GPIO, 1); + debug("Switching LCD off\n"); + gpio_set_value(TX48_LCD_BACKLIGHT_GPIO, + !lcd_backlight_polarity()); gpio_set_value(TX48_LCD_PWR_GPIO, 0); gpio_set_value(TX48_LCD_RST_GPIO, 0); } @@ -467,96 +616,177 @@ void lcd_panel_disable(void) void lcd_ctrl_init(void *lcdbase) { int color_depth = 24; - char *vm, *v; + const char *video_mode = karo_get_vmode(getenv("video_mode")); + const char *vm; unsigned long val; - struct da8xx_panel *p = &tx48_lcd_panel; int refresh = 60; + struct fb_videomode *p = &tx48_fb_modes[0]; + struct fb_videomode fb_mode; + int xres_set = 0, yres_set = 0, bpp_set = 0, refresh_set = 0; if (!lcd_enabled) { - printf("LCD disabled\n"); + debug("LCD disabled\n"); return; } - if (tstc() || (prm_rstst & PRM_RSTST_WDT1_RST)) { + if (had_ctrlc() || (prm_rstst & PRM_RSTST_WDT1_RST)) { + debug("Disabling LCD\n"); lcd_enabled = 0; + setenv("splashimage", NULL); return; } - vm = getenv("video_mode"); - if (vm == NULL) { + karo_fdt_move_fdt(); + lcd_bl_polarity = karo_fdt_get_backlight_polarity(working_fdt); + + if (video_mode == NULL) { + debug("Disabling LCD\n"); lcd_enabled = 0; return; } - - if ((v = strstr(vm, ":"))) - vm = v + 1; - - strncpy((char *)p->name, vm, sizeof(p->name)); - - val = simple_strtoul(vm, &vm, 10); - if (val != 0) { - if (val > panel_info.vl_col) - val = panel_info.vl_col; - p->width = val; - panel_info.vl_col = val; + vm = video_mode; + if (karo_fdt_get_fb_mode(working_fdt, video_mode, &fb_mode) == 0) { + p = &fb_mode; + debug("Using video mode from FDT\n"); + vm += strlen(vm); + if (fb_mode.xres > panel_info.vl_col || + fb_mode.yres > panel_info.vl_row) { + printf("video resolution from DT: %dx%d exceeds hardware limits: %dx%d\n", + fb_mode.xres, fb_mode.yres, + panel_info.vl_col, panel_info.vl_row); + lcd_enabled = 0; + return; + } } - if (*vm == 'x') { - val = simple_strtoul(vm + 1, &vm, 10); - if (val > panel_info.vl_row) - val = panel_info.vl_row; - p->height = val; - panel_info.vl_row = val; + if (p->name != NULL) + debug("Trying compiled-in video modes\n"); + while (p->name != NULL) { + if (strcmp(p->name, vm) == 0) { + 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; + + val = simple_strtoul(vm, &end, 0); + if (end > vm) { + if (!xres_set) { + if (val > panel_info.vl_col) + val = panel_info.vl_col; + p->xres = val; + panel_info.vl_col = val; + xres_set = 1; + } else if (!yres_set) { + if (val > panel_info.vl_row) + val = panel_info.vl_row; + p->yres = val; + panel_info.vl_row = val; + yres_set = 1; + } else if (!bpp_set) { + switch (val) { + case 24: + case 16: + case 8: + color_depth = val; + break; + + default: + printf("Invalid color depth: '%.*s' in video_mode; using default: '%u'\n", + end - vm, vm, color_depth); + } + bpp_set = 1; + } else if (!refresh_set) { + refresh = val; + refresh_set = 1; + } + } + vm = end; + } switch (*vm) { + case '@': + bpp_set = 1; + /* fallthru */ + case '-': + yres_set = 1; + /* fallthru */ + case 'x': + xres_set = 1; + /* fallthru */ case 'M': case 'R': vm++; break; - case '-': - color_depth = simple_strtoul(vm + 1, &vm, 10); - break; - - case '@': - refresh = simple_strtoul(vm + 1, &vm, 10); - break; - default: - debug("Ignoring '%c'\n", *vm); - vm++; + if (*vm != '\0') + vm++; } } + if (p->xres == 0 || p->yres == 0) { + printf("Invalid video mode: %s\n", getenv("video_mode")); + lcd_enabled = 0; + printf("Supported video modes are:"); + for (p = &tx48_fb_modes[0]; p->name != NULL; p++) { + printf(" %s", p->name); + } + printf("\n"); + return; + } + if (p->xres > panel_info.vl_col || p->yres > panel_info.vl_row) { + printf("video resolution: %dx%d exceeds hardware limits: %dx%d\n", + p->xres, p->yres, panel_info.vl_col, panel_info.vl_row); + lcd_enabled = 0; + return; + } + panel_info.vl_col = p->xres; + panel_info.vl_row = p->yres; + switch (color_depth) { case 8: - panel_info.vl_bpix = 3; + panel_info.vl_bpix = LCD_COLOR8; break; - case 16: - panel_info.vl_bpix = 4; + panel_info.vl_bpix = LCD_COLOR16; break; - - case 24: - panel_info.vl_bpix = 5; - break; - default: - printf("Invalid color_depth %u from video_mode '%s'; using default: %u\n", - color_depth, getenv("video_mode"), 24); + panel_info.vl_bpix = LCD_COLOR24; + } + + p->pixclock = KHZ2PICOS(refresh * + (p->xres + p->left_margin + p->right_margin + p->hsync_len) * + (p->yres + p->upper_margin + p->lower_margin + p->vsync_len) + / 1000); + debug("Pixel clock set to %lu.%03lu MHz\n", + PICOS2KHZ(p->pixclock) / 1000, + PICOS2KHZ(p->pixclock) % 1000); + + if (p != &fb_mode) { + int ret; + + debug("Creating new display-timing node from '%s'\n", + video_mode); + ret = karo_fdt_create_fb_mode(working_fdt, video_mode, p); + if (ret) + printf("Failed to create new display-timing node from '%s': %d\n", + video_mode, ret); } - lcd_line_length = NBITS(panel_info.vl_bpix) / 8 * panel_info.vl_col; - p->pxl_clk = refresh * - (p->width + p->hfp + p->hbp + p->hsw) * - (p->height + p->vfp + p->vbp + p->vsw); - debug("Pixel clock set to %u.%03uMHz\n", - p->pxl_clk / 1000000, p->pxl_clk / 1000 % 1000); gpio_request_array(stk5_lcd_gpios, ARRAY_SIZE(stk5_lcd_gpios)); tx48_set_pin_mux(stk5_lcd_pads, ARRAY_SIZE(stk5_lcd_pads)); - debug("Initializing FB driver\n"); - da8xx_video_init(&tx48_lcd_panel, color_depth); if (karo_load_splashimage(0) == 0) { + struct da8xx_panel da8xx_panel = { }; + + debug("Initializing FB driver\n"); + tx48_lcd_panel_setup(&da8xx_panel, p); + da8xx_video_init(&da8xx_panel, color_depth); + debug("Initializing LCD controller\n"); video_hw_init(); } else { @@ -569,6 +799,7 @@ void lcd_ctrl_init(void *lcdbase) static void stk5_board_init(void) { + gpio_request_array(stk5_gpios, ARRAY_SIZE(stk5_gpios)); tx48_set_pin_mux(stk5_pads, ARRAY_SIZE(stk5_pads)); } @@ -580,8 +811,9 @@ static void stk5v3_board_init(void) static void stk5v5_board_init(void) { stk5_board_init(); - tx48_set_pin_mux(stk5v5_pads, ARRAY_SIZE(stk5v5_pads)); + gpio_request_array(stk5v5_gpios, ARRAY_SIZE(stk5v5_gpios)); + tx48_set_pin_mux(stk5v5_pads, ARRAY_SIZE(stk5v5_pads)); } /* called with default environment! */ @@ -594,6 +826,9 @@ int board_init(void) /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; + if (ctrlc()) + printf("CTRL-C detected\n"); + return 0; } @@ -634,11 +869,8 @@ int checkboard(void) prm_rstst = readl(PRM_RSTST); show_reset_cause(prm_rstst); -#ifdef CONFIG_OF_LIBFDT - printf("Board: Ka-Ro TX48-7020 with FDT support\n"); -#else printf("Board: Ka-Ro TX48-7020\n"); -#endif + timer_init(); return 0; } @@ -646,18 +878,31 @@ int checkboard(void) static void tx48_set_cpu_clock(void) { unsigned long cpu_clk = getenv_ulong("cpu_clk", 10, 0); + unsigned long act_cpu_clk; - if (tstc() || (prm_rstst & PRM_RSTST_WDT1_RST)) + if (cpu_clk == 0 || cpu_clk == mpu_clk_rate() / 1000000) return; - if (cpu_clk == 0 || cpu_clk == mpu_clk_rate() / 1000000) + if (had_ctrlc() || (prm_rstst & PRM_RSTST_WDT1_RST)) { + if (prm_rstst & PRM_RSTST_WDT1_RST) { + printf("Watchdog reset detected; skipping cpu clock change\n"); + } else { + printf(" detected; skipping cpu clock change\n"); + } return; + } mpu_pll_config_val(cpu_clk); - printf("CPU clock set to %lu.%03lu MHz\n", - mpu_clk_rate() / 1000000, - mpu_clk_rate() / 1000 % 1000); + act_cpu_clk = mpu_clk_rate(); + if (cpu_clk * 1000000 != act_cpu_clk) { + printf("Failed to set CPU clock to %lu MHz; using %lu.%03lu MHz instead\n", + cpu_clk, act_cpu_clk / 1000000, + act_cpu_clk / 1000 % 1000); + } else { + printf("CPU clock set to %lu.%03lu MHz\n", + act_cpu_clk / 1000000, act_cpu_clk / 1000 % 1000); + } } static void tx48_init_mac(void) @@ -713,8 +958,10 @@ int board_late_init(void) baseboard); ret = -EINVAL; } + exit: tx48_init_mac(); + clear_ctrlc(); return ret; } @@ -782,6 +1029,13 @@ int board_eth_init(bd_t *bis) } #endif /* CONFIG_DRIVER_TI_CPSW */ +#if defined(CONFIG_OMAP_HSMMC) && !defined(CONFIG_SPL_BUILD) +int cpu_mmc_init(bd_t *bis) +{ + return omap_mmc_init(1, 0, 0, TX48_MMC_CD_GPIO, -1); +} +#endif + void tx48_disable_watchdog(void) { struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE; @@ -826,25 +1080,42 @@ void show_activity(int arg) #ifdef CONFIG_FDT_FIXUP_PARTITIONS #include #include -struct node_info nodes[] = { +static struct node_info nodes[] = { { "ti,omap2-nand", MTD_DEV_TYPE_NAND, }, + { "ti,am3352-gpmc", MTD_DEV_TYPE_NAND, }, }; #else #define fdt_fixup_mtdparts(b,n,c) do { } while (0) #endif /* CONFIG_FDT_FIXUP_PARTITIONS */ +static const char *tx48_touchpanels[] = { + "ti,tsc2007", + "edt,edt-ft5x06", + "ti,am3359-tscadc", +}; + void ft_board_setup(void *blob, bd_t *bd) { const char *baseboard = getenv("baseboard"); int stk5_v5 = baseboard != NULL && (strcmp(baseboard, "stk5-v5") == 0); + const char *video_mode = karo_get_vmode(getenv("video_mode")); + int ret; + + ret = fdt_increase_size(blob, 4096); + if (ret) + printf("Failed to increase FDT size: %s\n", fdt_strerror(ret)); fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); fdt_fixup_ethernet(blob); - karo_fdt_fixup_touchpanel(blob); + karo_fdt_fixup_touchpanel(blob, tx48_touchpanels, + ARRAY_SIZE(tx48_touchpanels)); + karo_fdt_fixup_usb_otg(blob, "usb0", "phys", "vcc-supply"); karo_fdt_fixup_flexcan(blob, stk5_v5); + karo_fdt_update_fb_mode(blob, video_mode); + tx48_disable_watchdog(); } #endif /* CONFIG_OF_BOARD_SETUP */