X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=board%2Fkaro%2Ftx48%2Ftx48.c;h=91b4764d1543a2a5ef9c4b12628a378cbdac8dd4;hb=63652ce377ee8ce60a6217aefe238313d0989c60;hp=9bf75f8962cc726e3d33a3a92663c3d7cadcefb0;hpb=cdc9edbf6d5f28f1db64e1f2fa7ce1306e3d1055;p=karo-tx-uboot.git diff --git a/board/karo/tx48/tx48.c b/board/karo/tx48/tx48.c index 9bf75f8962..91b4764d15 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/ @@ -18,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,15 +25,15 @@ #include #include #include +#include #include #include -#include #include #include #include #include +#include #include -#include #include #include #include @@ -48,254 +47,12 @@ 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 GMII_SEL (CTRL_BASE + 0x650) - -/* UART Defines */ -#define UART_SYSCFG_OFFSET 0x54 -#define UART_SYSSTS_OFFSET 0x58 - -#define UART_RESET (0x1 << 1) -#define UART_CLK_RUNNING_MASK 0x1 -#define UART_SMART_IDLE_EN (0x1 << 0x3) - -/* Timer Defines */ -#define TSICR_REG 0x54 -#define TIOCP_CFG_REG 0x10 -#define TCLR_REG 0x38 - -/* RGMII mode define */ -#define RGMII_MODE_ENABLE 0xA -#define RMII_MODE_ENABLE 0x5 -#define MII_MODE_ENABLE 0x0 +#define TX48_MMC_CD_GPIO AM33XX_GPIO_NR(3, 15) #define NO_OF_MAC_ADDR 1 +#ifndef ETH_ALEN #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) -#define PULLUP_EN (0x1 << 4) /* Pull UP Selection */ -#define PULLUDEN (0x0 << 3) /* Pull up enabled */ -#define PULLUDDIS (0x1 << 3) /* Pull up disabled */ -#define MODE(val) (val) - -/* - * PAD CONTROL OFFSETS - * Field names corresponds to the pad signal name - */ -struct pad_signals { - int gpmc_ad0; - int gpmc_ad1; - int gpmc_ad2; - int gpmc_ad3; - int gpmc_ad4; - int gpmc_ad5; - int gpmc_ad6; - int gpmc_ad7; - int gpmc_ad8; - int gpmc_ad9; - int gpmc_ad10; - int gpmc_ad11; - int gpmc_ad12; - int gpmc_ad13; - int gpmc_ad14; - int gpmc_ad15; - int gpmc_a0; - int gpmc_a1; - int gpmc_a2; - int gpmc_a3; - int gpmc_a4; - int gpmc_a5; - int gpmc_a6; - int gpmc_a7; - int gpmc_a8; - int gpmc_a9; - int gpmc_a10; - int gpmc_a11; - int gpmc_wait0; - int gpmc_wpn; - int gpmc_be1n; - int gpmc_csn0; - int gpmc_csn1; - int gpmc_csn2; - int gpmc_csn3; - int gpmc_clk; - int gpmc_advn_ale; - int gpmc_oen_ren; - int gpmc_wen; - int gpmc_be0n_cle; - int lcd_data0; - int lcd_data1; - int lcd_data2; - int lcd_data3; - int lcd_data4; - int lcd_data5; - int lcd_data6; - int lcd_data7; - int lcd_data8; - int lcd_data9; - int lcd_data10; - int lcd_data11; - int lcd_data12; - int lcd_data13; - int lcd_data14; - int lcd_data15; - int lcd_vsync; - int lcd_hsync; - int lcd_pclk; - int lcd_ac_bias_en; - int mmc0_dat3; - int mmc0_dat2; - int mmc0_dat1; - int mmc0_dat0; - int mmc0_clk; - int mmc0_cmd; - int mii1_col; - int mii1_crs; - int mii1_rxerr; - int mii1_txen; - int mii1_rxdv; - int mii1_txd3; - int mii1_txd2; - int mii1_txd1; - int mii1_txd0; - int mii1_txclk; - int mii1_rxclk; - int mii1_rxd3; - int mii1_rxd2; - int mii1_rxd1; - int mii1_rxd0; - int rmii1_refclk; - int mdio_data; - int mdio_clk; - int spi0_sclk; - int spi0_d0; - int spi0_d1; - int spi0_cs0; - int spi0_cs1; - int ecap0_in_pwm0_out; - int uart0_ctsn; - int uart0_rtsn; - int uart0_rxd; - int uart0_txd; - int uart1_ctsn; - int uart1_rtsn; - int uart1_rxd; - int uart1_txd; - int i2c0_sda; - int i2c0_scl; - int mcasp0_aclkx; - int mcasp0_fsx; - int mcasp0_axr0; - int mcasp0_ahclkr; - int mcasp0_aclkr; - int mcasp0_fsr; - int mcasp0_axr1; - int mcasp0_ahclkx; - int xdma_event_intr0; - int xdma_event_intr1; - int nresetin_out; - int porz; - int nnmi; - int osc0_in; - int osc0_out; - int rsvd1; - int tms; - int tdi; - int tdo; - int tck; - int ntrst; - int emu0; - int emu1; - int osc1_in; - int osc1_out; - int pmic_power_en; - int rtc_porz; - int rsvd2; - int ext_wakeup; - int enz_kaldo_1p8v; - int usb0_dm; - int usb0_dp; - int usb0_ce; - int usb0_id; - int usb0_vbus; - int usb0_drvvbus; - int usb1_dm; - int usb1_dp; - int usb1_ce; - int usb1_id; - int usb1_vbus; - int usb1_drvvbus; - int ddr_resetn; - int ddr_csn0; - int ddr_cke; - int ddr_ck; - int ddr_nck; - int ddr_casn; - int ddr_rasn; - int ddr_wen; - int ddr_ba0; - int ddr_ba1; - int ddr_ba2; - int ddr_a0; - int ddr_a1; - int ddr_a2; - int ddr_a3; - int ddr_a4; - int ddr_a5; - int ddr_a6; - int ddr_a7; - int ddr_a8; - int ddr_a9; - int ddr_a10; - int ddr_a11; - int ddr_a12; - int ddr_a13; - int ddr_a14; - int ddr_a15; - int ddr_odt; - int ddr_d0; - int ddr_d1; - int ddr_d2; - int ddr_d3; - int ddr_d4; - int ddr_d5; - int ddr_d6; - int ddr_d7; - int ddr_d8; - int ddr_d9; - int ddr_d10; - int ddr_d11; - int ddr_d12; - int ddr_d13; - int ddr_d14; - int ddr_d15; - int ddr_dqm0; - int ddr_dqm1; - int ddr_dqs0; - int ddr_dqsn0; - int ddr_dqs1; - int ddr_dqsn1; - int ddr_vref; - int ddr_vtp; - int ddr_strben0; - int ddr_strben1; - int ain7; - int ain6; - int ain5; - int ain4; - int ain3; - int ain2; - int ain1; - int ain0; - int vrefp; - int vrefn; -}; +#endif struct pin_mux { short reg_offset; @@ -315,7 +72,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) @@ -329,6 +86,23 @@ static u32 prm_rstst __attribute__((section(".data"))); /* * Basic board specific setup */ +static const struct pin_mux tx48_pads[] = { + { OFFSET(i2c0_sda), MODE(7) | RXACTIVE | PULLUDEN | PULLUP_EN, }, + { OFFSET(i2c0_scl), MODE(7) | RXACTIVE | PULLUDEN | PULLUP_EN, }, + { OFFSET(emu1), MODE(7), }, /* ETH PHY Reset */ +}; + +static const struct pin_mux tx48_i2c_pads[] = { + { OFFSET(i2c0_sda), MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN, }, + { OFFSET(i2c0_scl), MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN, }, +}; + +static const struct gpio tx48_gpios[] = { + { AM33XX_GPIO_NR(3, 5), GPIOFLAG_INPUT, "I2C1_SDA", }, + { AM33XX_GPIO_NR(3, 6), GPIOFLAG_INPUT, "I2C1_SCL", }, + { AM33XX_GPIO_NR(3, 8), GPIOFLAG_OUTPUT_INIT_LOW, "ETH_PHY_RESET", }, +}; + static const struct pin_mux stk5_pads[] = { /* heartbeat LED */ { OFFSET(gpmc_a10), MODE(7) | PULLUDEN, }, @@ -338,6 +112,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, GPIOFLAG_OUTPUT_INIT_LOW, "HEARTBEAT LED", }, + { TX48_MMC_CD_GPIO, GPIOFLAG_INPUT, "MMC0 CD", }, }; static const struct pin_mux stk5_lcd_pads[] = { @@ -365,14 +146,10 @@ 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", }, - { AM33XX_GPIO_NR(3, 14), GPIOF_OUTPUT_INIT_HIGH, "LCD BACKLIGHT", }, + { AM33XX_GPIO_NR(1, 19), GPIOFLAG_OUTPUT_INIT_LOW, "LCD RESET", }, + { AM33XX_GPIO_NR(1, 22), GPIOFLAG_OUTPUT_INIT_LOW, "LCD POWER", }, + { AM33XX_GPIO_NR(3, 14), GPIOFLAG_OUTPUT_INIT_HIGH, "LCD BACKLIGHT", }, }; static const struct pin_mux stk5v5_pads[] = { @@ -381,32 +158,154 @@ static const struct pin_mux stk5v5_pads[] = { }; static const struct gpio stk5v5_gpios[] = { - { AM33XX_GPIO_NR(0, 22), GPIOF_OUTPUT_INIT_HIGH, "CAN XCVR", }, + { AM33XX_GPIO_NR(0, 22), GPIOFLAG_OUTPUT_INIT_HIGH, "CAN XCVR", }, }; #ifdef CONFIG_LCD -static u16 tx48_cmap[256]; vidinfo_t panel_info = { /* set to max. size supported by SoC */ .vl_col = 1366, .vl_row = 768, - .vl_bpix = LCD_COLOR24, /* Bits per pixel, 0: 1bpp, 1: 2bpp, 2: 4bpp, 3: 8bpp ... */ - .cmap = tx48_cmap, + .vl_bpix = LCD_COLOR32, /* Bits per pixel, 0: 1bpp, 1: 2bpp, 2: 4bpp, 3: 8bpp ... */ }; -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, +static struct lcd_ctrl_config lcd_cfg = { + .bpp = 24, +}; + +#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 +318,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 +345,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 +396,178 @@ 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(); + + 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; + lcd_bl_polarity = karo_fdt_get_backlight_polarity(working_fdt); + 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_COLOR32; + } + + 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, &lcd_cfg, color_depth); + debug("Initializing LCD controller\n"); video_hw_init(); } else { @@ -569,6 +580,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,13 +592,16 @@ 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! */ int board_init(void) { + int i; + /* mach type passed to kernel */ #ifdef CONFIG_OF_LIBFDT gd->bd->bi_arch_number = -1; @@ -594,6 +609,24 @@ int board_init(void) /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; + if (ctrlc() || (prm_rstst & PRM_RSTST_WDT1_RST)) { + if (prm_rstst & PRM_RSTST_WDT1_RST) + printf("WDOG RESET detected\n"); + else + printf(" detected; safeboot enabled\n"); + } + + gpio_request_array(tx48_gpios, ARRAY_SIZE(tx48_gpios)); + tx48_set_pin_mux(tx48_pads, ARRAY_SIZE(tx48_pads)); + + for (i = 0; i < ARRAY_SIZE(tx48_gpios); i++) { + int gpio = tx48_gpios[i].gpio; + + if (gpio_get_value(gpio) == 0) + gpio_direction_output(gpio, 1); + } + + tx48_set_pin_mux(tx48_pads, ARRAY_SIZE(tx48_i2c_pads)); return 0; } @@ -634,11 +667,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,32 +676,75 @@ 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)) { + printf("%s detected; skipping cpu clock change\n", + (prm_rstst & PRM_RSTST_WDT1_RST) ? + "WDOG RESET" : ""); 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) +{ + uint8_t mac_addr[ETH_ALEN]; + uint32_t mac_hi, mac_lo; + + /* try reading mac address from efuse */ + mac_lo = __raw_readl(MAC_ID0_LO); + mac_hi = __raw_readl(MAC_ID0_HI); + + mac_addr[0] = mac_hi & 0xFF; + mac_addr[1] = (mac_hi & 0xFF00) >> 8; + mac_addr[2] = (mac_hi & 0xFF0000) >> 16; + mac_addr[3] = (mac_hi & 0xFF000000) >> 24; + mac_addr[4] = mac_lo & 0xFF; + mac_addr[5] = (mac_lo & 0xFF00) >> 8; + + if (!is_valid_ethaddr(mac_addr)) { + printf("No valid MAC address programmed\n"); + return; + } + printf("MAC addr from fuse: %pM\n", mac_addr); + eth_setenv_enetaddr("ethaddr", mac_addr); } /* called with environment from NAND or MMC */ int board_late_init(void) { + int ret = 0; const char *baseboard; + env_cleanup(); + tx48_set_cpu_clock(); -#ifdef CONFIG_OF_BOARD_SETUP - karo_fdt_move_fdt(); -#endif + + if (had_ctrlc()) + setenv_ulong("safeboot", 1); + else if (prm_rstst & PRM_RSTST_WDT1_RST) + setenv_ulong("wdreset", 1); + else + karo_fdt_move_fdt(); + baseboard = getenv("baseboard"); if (!baseboard) - return 0; + goto exit; if (strncmp(baseboard, "stk5", 4) == 0) { printf("Baseboard: %s\n", baseboard); @@ -687,14 +760,17 @@ int board_late_init(void) } else { printf("WARNING: Unsupported baseboard: '%s'\n", baseboard); - return -EINVAL; + ret = -EINVAL; } - return 0; +exit: + tx48_init_mac(); + clear_ctrlc(); + return ret; } #ifdef CONFIG_DRIVER_TI_CPSW -static void tx48_phy_init(char *name, int addr) +static void tx48_phy_init(void) { debug("%s: Resetting ethernet PHY\n", __func__); @@ -719,7 +795,7 @@ static struct cpsw_slave_data cpsw_slaves[] = { { .slave_reg_ofs = 0x208, .sliver_reg_ofs = 0xd80, - .phy_id = 0, + .phy_addr = 0, .phy_if = PHY_INTERFACE_MODE_RMII, }, }; @@ -743,41 +819,25 @@ static struct cpsw_platform_data cpsw_data = { .hw_stats_reg_ofs = 0x900, .mac_control = (1 << 5) /* MIIEN */, .control = cpsw_control, - .phy_init = tx48_phy_init, - .gigabit_en = 0, .host_port_num = 0, .version = CPSW_CTRL_VERSION_2, }; int board_eth_init(bd_t *bis) { - uint8_t mac_addr[ETH_ALEN]; - uint32_t mac_hi, mac_lo; - - /* try reading mac address from efuse */ - mac_lo = __raw_readl(MAC_ID0_LO); - mac_hi = __raw_readl(MAC_ID0_HI); - - mac_addr[0] = mac_hi & 0xFF; - mac_addr[1] = (mac_hi & 0xFF00) >> 8; - mac_addr[2] = (mac_hi & 0xFF0000) >> 16; - mac_addr[3] = (mac_hi & 0xFF000000) >> 24; - mac_addr[4] = mac_lo & 0xFF; - mac_addr[5] = (mac_lo & 0xFF00) >> 8; - - if (is_valid_ether_addr(mac_addr)) { - printf("MAC addr from fuse: %pM\n", mac_addr); - eth_setenv_enetaddr("ethaddr", mac_addr); - } else { - printf("ERROR: Did not find a valid mac address in e-fuse\n"); - } - __raw_writel(RMII_MODE_ENABLE, MAC_MII_SEL); - __raw_writel(0x5D, GMII_SEL); + tx48_phy_init(); return cpsw_register(&cpsw_data); } #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; @@ -822,33 +882,50 @@ 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 void tx48_fixup_flexcan(void *blob) +static const char *tx48_touchpanels[] = { + "ti,tsc2007", + "edt,edt-ft5x06", + "ti,am3359-tscadc", +}; + +int 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)); + return ret; + } + fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); - if (baseboard && strcmp(baseboard, "stk5-v5") == 0) - return; + 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_del_prop(blob, "ti,dcan", 0x481cc000, "can-xcvr-enable"); - karo_fdt_del_prop(blob, "ti,dcan", 0x481d0000, "can-xcvr-enable"); -} + karo_fdt_update_fb_mode(blob, video_mode, "/lcd-panel"); -void ft_board_setup(void *blob, bd_t *bd) -{ - fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); - fdt_fixup_ethernet(blob); + tx48_disable_watchdog(); - karo_fdt_fixup_touchpanel(blob); - tx48_fixup_flexcan(blob); + if (get_cpu_rev() == 0) { + karo_fdt_del_prop(blob, "lltc,ltc3589-2", 0x34, "interrupts"); + karo_fdt_del_prop(blob, "lltc,ltc3589-2", 0x34, + "interrupt-parent"); + } - tx48_disable_watchdog(); + return 0; } #endif /* CONFIG_OF_BOARD_SETUP */