]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/karo/tx48/tx48.c
e89dda8cc29092c92b51d6c034b33fe9fc0c2d0b
[karo-tx-uboot.git] / board / karo / tx48 / tx48.c
1 /*
2  * Copyright (C) 2012-2013 Lothar Waßmann <LW@KARO-electronics.de>
3  *
4  * based on evm.c
5  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
12  * kind, whether express or implied; without even the implied warranty
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  */
16
17 #include <common.h>
18 #include <errno.h>
19 #include <miiphy.h>
20 #include <cpsw.h>
21 #include <serial.h>
22 #include <libfdt.h>
23 #include <lcd.h>
24 #include <fdt_support.h>
25 #include <nand.h>
26 #include <net.h>
27 #include <linux/mtd/nand.h>
28 #include <linux/fb.h>
29 #include <asm/gpio.h>
30 #include <asm/cache.h>
31 #include <asm/io.h>
32 #include <asm/arch/cpu.h>
33 #include <asm/arch/hardware.h>
34 #include <asm/arch/mmc_host_def.h>
35 #include <asm/arch/mux.h>
36 #include <asm/arch/sys_proto.h>
37 #include <asm/arch/clock.h>
38 #include <video_fb.h>
39 #include <asm/arch/da8xx-fb.h>
40
41 #include "../common/karo.h"
42
43 DECLARE_GLOBAL_DATA_PTR;
44
45 #define TX48_LED_GPIO           AM33XX_GPIO_NR(1, 26)
46 #define TX48_ETH_PHY_RST_GPIO   AM33XX_GPIO_NR(3, 8)
47 #define TX48_LCD_RST_GPIO       AM33XX_GPIO_NR(1, 19)
48 #define TX48_LCD_PWR_GPIO       AM33XX_GPIO_NR(1, 22)
49 #define TX48_LCD_BACKLIGHT_GPIO AM33XX_GPIO_NR(3, 14)
50 #define TX48_MMC_CD_GPIO        AM33XX_GPIO_NR(3, 15)
51
52 #define NO_OF_MAC_ADDR          1
53 #ifndef ETH_ALEN
54 #define ETH_ALEN                6
55 #endif
56
57 struct pin_mux {
58         short reg_offset;
59         uint8_t val;
60 };
61
62 #define PAD_CTRL_BASE   0x800
63 #define OFFSET(x)       (unsigned int) (&((struct pad_signals *) \
64                                 (PAD_CTRL_BASE))->x)
65
66 /*
67  * Configure the pin mux for the module
68  */
69 static inline void tx48_set_pin_mux(const struct pin_mux *pin_mux,
70                         int num_pins)
71 {
72         int i;
73
74         for (i = 0; i < num_pins; i++)
75                 writel(pin_mux[i].val, CTRL_BASE + pin_mux[i].reg_offset);
76 }
77
78 #define PRM_RSTST_GLOBAL_COLD_RST       (1 << 0)
79 #define PRM_RSTST_GLOBAL_WARM_SW_RST    (1 << 1)
80 #define PRM_RSTST_WDT1_RST              (1 << 4)
81 #define PRM_RSTST_EXTERNAL_WARM_RST     (1 << 5)
82 #define PRM_RSTST_ICEPICK_RST           (1 << 9)
83
84 static u32 prm_rstst __attribute__((section(".data")));
85
86 /*
87  * Basic board specific setup
88  */
89 static const struct pin_mux tx48_pads[] = {
90         { OFFSET(i2c0_sda), MODE(7) | RXACTIVE | PULLUDEN | PULLUP_EN, },
91         { OFFSET(i2c0_scl), MODE(7) | RXACTIVE | PULLUDEN | PULLUP_EN, },
92         { OFFSET(emu1), MODE(7), }, /* ETH PHY Reset */
93 };
94
95 static const struct pin_mux tx48_i2c_pads[] = {
96         { OFFSET(i2c0_sda), MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN, },
97         { OFFSET(i2c0_scl), MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN, },
98 };
99
100 static const struct gpio tx48_gpios[] = {
101         { AM33XX_GPIO_NR(3, 5), GPIOFLAG_INPUT, "I2C1_SDA", },
102         { AM33XX_GPIO_NR(3, 6), GPIOFLAG_INPUT, "I2C1_SCL", },
103         { AM33XX_GPIO_NR(3, 8), GPIOFLAG_OUTPUT_INIT_LOW, "ETH_PHY_RESET", },
104 };
105
106 static const struct pin_mux stk5_pads[] = {
107         /* heartbeat LED */
108         { OFFSET(gpmc_a10), MODE(7) | PULLUDEN, },
109         /* LCD RESET */
110         { OFFSET(gpmc_a3), MODE(7) | PULLUDEN, },
111         /* LCD POWER_ENABLE */
112         { OFFSET(gpmc_a6), MODE(7) | PULLUDEN, },
113         /* LCD Backlight (PWM) */
114         { OFFSET(mcasp0_aclkx), MODE(7) | PULLUDEN, },
115         /* MMC CD */
116         { OFFSET(mcasp0_fsx), MODE(7) | PULLUDEN | PULLUP_EN, },
117 };
118
119 static const struct gpio stk5_gpios[] = {
120         { TX48_LED_GPIO, GPIOFLAG_OUTPUT_INIT_LOW, "HEARTBEAT LED", },
121         { TX48_MMC_CD_GPIO, GPIOFLAG_INPUT, "MMC0 CD", },
122 };
123
124 static const struct pin_mux stk5_lcd_pads[] = {
125         /* LCD data bus */
126         { OFFSET(lcd_data0), MODE(0) | PULLUDEN, },
127         { OFFSET(lcd_data1), MODE(0) | PULLUDEN, },
128         { OFFSET(lcd_data2), MODE(0) | PULLUDEN, },
129         { OFFSET(lcd_data3), MODE(0) | PULLUDEN, },
130         { OFFSET(lcd_data4), MODE(0) | PULLUDEN, },
131         { OFFSET(lcd_data5), MODE(0) | PULLUDEN, },
132         { OFFSET(lcd_data6), MODE(0) | PULLUDEN, },
133         { OFFSET(lcd_data7), MODE(0) | PULLUDEN, },
134         { OFFSET(lcd_data8), MODE(0) | PULLUDEN, },
135         { OFFSET(lcd_data9), MODE(0) | PULLUDEN, },
136         { OFFSET(lcd_data10), MODE(0) | PULLUDEN, },
137         { OFFSET(lcd_data11), MODE(0) | PULLUDEN, },
138         { OFFSET(lcd_data12), MODE(0) | PULLUDEN, },
139         { OFFSET(lcd_data13), MODE(0) | PULLUDEN, },
140         { OFFSET(lcd_data14), MODE(0) | PULLUDEN, },
141         { OFFSET(lcd_data15), MODE(0) | PULLUDEN, },
142         /* LCD control signals */
143         { OFFSET(lcd_hsync), MODE(0) | PULLUDEN, },
144         { OFFSET(lcd_vsync), MODE(0) | PULLUDEN, },
145         { OFFSET(lcd_pclk), MODE(0) | PULLUDEN, },
146         { OFFSET(lcd_ac_bias_en), MODE(0) | PULLUDEN, },
147 };
148
149 static const struct gpio stk5_lcd_gpios[] = {
150         { AM33XX_GPIO_NR(1, 19), GPIOFLAG_OUTPUT_INIT_LOW, "LCD RESET", },
151         { AM33XX_GPIO_NR(1, 22), GPIOFLAG_OUTPUT_INIT_LOW, "LCD POWER", },
152         { AM33XX_GPIO_NR(3, 14), GPIOFLAG_OUTPUT_INIT_HIGH, "LCD BACKLIGHT", },
153 };
154
155 static const struct pin_mux stk5v5_pads[] = {
156         /* CAN transceiver control */
157         { OFFSET(gpmc_ad8), MODE(7) | PULLUDEN, },
158 };
159
160 static const struct gpio stk5v5_gpios[] = {
161         { AM33XX_GPIO_NR(0, 22), GPIOFLAG_OUTPUT_INIT_HIGH, "CAN XCVR", },
162 };
163
164 #ifdef CONFIG_LCD
165 static u16 tx48_cmap[256];
166 vidinfo_t panel_info = {
167         /* set to max. size supported by SoC */
168         .vl_col = 1366,
169         .vl_row = 768,
170
171         .vl_bpix = LCD_COLOR32,    /* Bits per pixel, 0: 1bpp, 1: 2bpp, 2: 4bpp, 3: 8bpp ... */
172         .cmap = tx48_cmap,
173 };
174
175 static struct lcd_ctrl_config lcd_cfg = {
176         .bpp = 24,
177 };
178
179 #define FB_SYNC_OE_LOW_ACT      (1 << 31)
180 #define FB_SYNC_CLK_LAT_FALL    (1 << 30)
181
182 static struct fb_videomode tx48_fb_modes[] = {
183         {
184                 /* Standard VGA timing */
185                 .name           = "VGA",
186                 .refresh        = 60,
187                 .xres           = 640,
188                 .yres           = 480,
189                 .pixclock       = KHZ2PICOS(25175),
190                 .left_margin    = 48,
191                 .hsync_len      = 96,
192                 .right_margin   = 16,
193                 .upper_margin   = 31,
194                 .vsync_len      = 2,
195                 .lower_margin   = 12,
196                 .sync           = FB_SYNC_CLK_LAT_FALL,
197         },
198         {
199                 /* Emerging ETV570 640 x 480 display. Syncs low active,
200                  * DE high active, 115.2 mm x 86.4 mm display area
201                  * VGA compatible timing
202                  */
203                 .name           = "ETV570",
204                 .refresh        = 60,
205                 .xres           = 640,
206                 .yres           = 480,
207                 .pixclock       = KHZ2PICOS(25175),
208                 .left_margin    = 114,
209                 .hsync_len      = 30,
210                 .right_margin   = 16,
211                 .upper_margin   = 32,
212                 .vsync_len      = 3,
213                 .lower_margin   = 10,
214                 .sync           = FB_SYNC_CLK_LAT_FALL,
215         },
216         {
217                 /* Emerging ET0350G0DH6 320 x 240 display.
218                  * 70.08 mm x 52.56 mm display area.
219                  */
220                 .name           = "ET0350",
221                 .refresh        = 60,
222                 .xres           = 320,
223                 .yres           = 240,
224                 .pixclock       = KHZ2PICOS(6500),
225                 .left_margin    = 68 - 34,
226                 .hsync_len      = 34,
227                 .right_margin   = 20,
228                 .upper_margin   = 18 - 3,
229                 .vsync_len      = 3,
230                 .lower_margin   = 4,
231                 .sync           = FB_SYNC_CLK_LAT_FALL,
232         },
233         {
234                 /* Emerging ET0430G0DH6 480 x 272 display.
235                  * 95.04 mm x 53.856 mm display area.
236                  */
237                 .name           = "ET0430",
238                 .refresh        = 60,
239                 .xres           = 480,
240                 .yres           = 272,
241                 .pixclock       = KHZ2PICOS(9000),
242                 .left_margin    = 2,
243                 .hsync_len      = 41,
244                 .right_margin   = 2,
245                 .upper_margin   = 2,
246                 .vsync_len      = 10,
247                 .lower_margin   = 2,
248         },
249         {
250                 /* Emerging ET0500G0DH6 800 x 480 display.
251                  * 109.6 mm x 66.4 mm display area.
252                  */
253                 .name           = "ET0500",
254                 .refresh        = 60,
255                 .xres           = 800,
256                 .yres           = 480,
257                 .pixclock       = KHZ2PICOS(33260),
258                 .left_margin    = 216 - 128,
259                 .hsync_len      = 128,
260                 .right_margin   = 1056 - 800 - 216,
261                 .upper_margin   = 35 - 2,
262                 .vsync_len      = 2,
263                 .lower_margin   = 525 - 480 - 35,
264                 .sync           = FB_SYNC_CLK_LAT_FALL,
265         },
266         {
267                 /* Emerging ETQ570G0DH6 320 x 240 display.
268                  * 115.2 mm x 86.4 mm display area.
269                  */
270                 .name           = "ETQ570",
271                 .refresh        = 60,
272                 .xres           = 320,
273                 .yres           = 240,
274                 .pixclock       = KHZ2PICOS(6400),
275                 .left_margin    = 38,
276                 .hsync_len      = 30,
277                 .right_margin   = 30,
278                 .upper_margin   = 16, /* 15 according to datasheet */
279                 .vsync_len      = 3, /* TVP -> 1>x>5 */
280                 .lower_margin   = 4, /* 4.5 according to datasheet */
281                 .sync           = FB_SYNC_CLK_LAT_FALL,
282         },
283         {
284                 /* Emerging ET0700G0DH6 800 x 480 display.
285                  * 152.4 mm x 91.44 mm display area.
286                  */
287                 .name           = "ET0700",
288                 .refresh        = 60,
289                 .xres           = 800,
290                 .yres           = 480,
291                 .pixclock       = KHZ2PICOS(33260),
292                 .left_margin    = 216 - 128,
293                 .hsync_len      = 128,
294                 .right_margin   = 1056 - 800 - 216,
295                 .upper_margin   = 35 - 2,
296                 .vsync_len      = 2,
297                 .lower_margin   = 525 - 480 - 35,
298                 .sync           = FB_SYNC_CLK_LAT_FALL,
299         },
300         {
301                 /* unnamed entry for assigning parameters parsed from 'video_mode' string */
302                 .refresh        = 60,
303                 .left_margin    = 48,
304                 .hsync_len      = 96,
305                 .right_margin   = 16,
306                 .upper_margin   = 31,
307                 .vsync_len      = 2,
308                 .lower_margin   = 12,
309                 .sync           = FB_SYNC_CLK_LAT_FALL,
310         },
311 };
312
313 void *lcd_base;                 /* Start of framebuffer memory  */
314 void *lcd_console_address;      /* Start of console buffer      */
315
316 int lcd_color_fg;
317 int lcd_color_bg;
318
319 short console_col;
320 short console_row;
321
322 static int lcd_enabled = 1;
323 static int lcd_bl_polarity;
324
325 static int lcd_backlight_polarity(void)
326 {
327         return lcd_bl_polarity;
328 }
329
330 void lcd_initcolregs(void)
331 {
332 }
333
334 void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
335 {
336 }
337
338 void lcd_enable(void)
339 {
340         /* HACK ALERT:
341          * global variable from common/lcd.c
342          * Set to 0 here to prevent messages from going to LCD
343          * rather than serial console
344          */
345         lcd_is_enabled = 0;
346
347         if (lcd_enabled) {
348                 karo_load_splashimage(1);
349
350                 debug("Switching LCD on\n");
351                 gpio_set_value(TX48_LCD_PWR_GPIO, 1);
352                 udelay(100);
353                 gpio_set_value(TX48_LCD_RST_GPIO, 1);
354                 udelay(300000);
355                 gpio_set_value(TX48_LCD_BACKLIGHT_GPIO,
356                         lcd_backlight_polarity());
357         }
358 }
359
360 void lcd_disable(void)
361 {
362         if (lcd_enabled) {
363                 printf("Disabling LCD\n");
364                 da8xx_fb_disable();
365                 lcd_enabled = 0;
366         }
367 }
368
369 static void tx48_lcd_panel_setup(struct da8xx_panel *p,
370                                 struct fb_videomode *fb)
371 {
372         p->pxl_clk = PICOS2KHZ(fb->pixclock) * 1000;
373
374         p->width = fb->xres;
375         p->hbp = fb->left_margin;
376         p->hsw = fb->hsync_len;
377         p->hfp = fb->right_margin;
378
379         p->height = fb->yres;
380         p->vbp = fb->upper_margin;
381         p->vsw = fb->vsync_len;
382         p->vfp = fb->lower_margin;
383
384         p->invert_pxl_clk = !!(fb->sync & FB_SYNC_CLK_LAT_FALL);
385 }
386
387 void lcd_panel_disable(void)
388 {
389         if (lcd_enabled) {
390                 debug("Switching LCD off\n");
391                 gpio_set_value(TX48_LCD_BACKLIGHT_GPIO,
392                         !lcd_backlight_polarity());
393                 gpio_set_value(TX48_LCD_PWR_GPIO, 0);
394                 gpio_set_value(TX48_LCD_RST_GPIO, 0);
395         }
396 }
397
398 void lcd_ctrl_init(void *lcdbase)
399 {
400         int color_depth = 24;
401         const char *video_mode = karo_get_vmode(getenv("video_mode"));
402         const char *vm;
403         unsigned long val;
404         int refresh = 60;
405         struct fb_videomode *p = &tx48_fb_modes[0];
406         struct fb_videomode fb_mode;
407         int xres_set = 0, yres_set = 0, bpp_set = 0, refresh_set = 0;
408
409         if (!lcd_enabled) {
410                 debug("LCD disabled\n");
411                 return;
412         }
413
414         if (had_ctrlc() || (prm_rstst & PRM_RSTST_WDT1_RST)) {
415                 debug("Disabling LCD\n");
416                 lcd_enabled = 0;
417                 setenv("splashimage", NULL);
418                 return;
419         }
420
421         karo_fdt_move_fdt();
422
423         if (video_mode == NULL) {
424                 debug("Disabling LCD\n");
425                 lcd_enabled = 0;
426                 return;
427         }
428
429         lcd_bl_polarity = karo_fdt_get_backlight_polarity(working_fdt);
430         vm = video_mode;
431         if (karo_fdt_get_fb_mode(working_fdt, video_mode, &fb_mode) == 0) {
432                 p = &fb_mode;
433                 debug("Using video mode from FDT\n");
434                 vm += strlen(vm);
435                 if (fb_mode.xres > panel_info.vl_col ||
436                         fb_mode.yres > panel_info.vl_row) {
437                         printf("video resolution from DT: %dx%d exceeds hardware limits: %dx%d\n",
438                                 fb_mode.xres, fb_mode.yres,
439                                 panel_info.vl_col, panel_info.vl_row);
440                         lcd_enabled = 0;
441                         return;
442                 }
443         }
444         if (p->name != NULL)
445                 debug("Trying compiled-in video modes\n");
446         while (p->name != NULL) {
447                 if (strcmp(p->name, vm) == 0) {
448                         debug("Using video mode: '%s'\n", p->name);
449                         vm += strlen(vm);
450                         break;
451                 }
452                 p++;
453         }
454         if (*vm != '\0')
455                 debug("Trying to decode video_mode: '%s'\n", vm);
456         while (*vm != '\0') {
457                 if (*vm >= '0' && *vm <= '9') {
458                         char *end;
459
460                         val = simple_strtoul(vm, &end, 0);
461                         if (end > vm) {
462                                 if (!xres_set) {
463                                         if (val > panel_info.vl_col)
464                                                 val = panel_info.vl_col;
465                                         p->xres = val;
466                                         panel_info.vl_col = val;
467                                         xres_set = 1;
468                                 } else if (!yres_set) {
469                                         if (val > panel_info.vl_row)
470                                                 val = panel_info.vl_row;
471                                         p->yres = val;
472                                         panel_info.vl_row = val;
473                                         yres_set = 1;
474                                 } else if (!bpp_set) {
475                                         switch (val) {
476                                         case 24:
477                                         case 16:
478                                         case 8:
479                                                 color_depth = val;
480                                                 break;
481
482                                         default:
483                                                 printf("Invalid color depth: '%.*s' in video_mode; using default: '%u'\n",
484                                                         end - vm, vm, color_depth);
485                                         }
486                                         bpp_set = 1;
487                                 } else if (!refresh_set) {
488                                         refresh = val;
489                                         refresh_set = 1;
490                                 }
491                         }
492                         vm = end;
493                 }
494                 switch (*vm) {
495                 case '@':
496                         bpp_set = 1;
497                         /* fallthru */
498                 case '-':
499                         yres_set = 1;
500                         /* fallthru */
501                 case 'x':
502                         xres_set = 1;
503                         /* fallthru */
504                 case 'M':
505                 case 'R':
506                         vm++;
507                         break;
508
509                 default:
510                         if (*vm != '\0')
511                                 vm++;
512                 }
513         }
514         if (p->xres == 0 || p->yres == 0) {
515                 printf("Invalid video mode: %s\n", getenv("video_mode"));
516                 lcd_enabled = 0;
517                 printf("Supported video modes are:");
518                 for (p = &tx48_fb_modes[0]; p->name != NULL; p++) {
519                         printf(" %s", p->name);
520                 }
521                 printf("\n");
522                 return;
523         }
524         if (p->xres > panel_info.vl_col || p->yres > panel_info.vl_row) {
525                 printf("video resolution: %dx%d exceeds hardware limits: %dx%d\n",
526                         p->xres, p->yres, panel_info.vl_col, panel_info.vl_row);
527                 lcd_enabled = 0;
528                 return;
529         }
530         panel_info.vl_col = p->xres;
531         panel_info.vl_row = p->yres;
532
533         switch (color_depth) {
534         case 8:
535                 panel_info.vl_bpix = LCD_COLOR8;
536                 break;
537         case 16:
538                 panel_info.vl_bpix = LCD_COLOR16;
539                 break;
540         default:
541                 panel_info.vl_bpix = LCD_COLOR32;
542         }
543
544         p->pixclock = KHZ2PICOS(refresh *
545                 (p->xres + p->left_margin + p->right_margin + p->hsync_len) *
546                 (p->yres + p->upper_margin + p->lower_margin + p->vsync_len)
547                 / 1000);
548         debug("Pixel clock set to %lu.%03lu MHz\n",
549                 PICOS2KHZ(p->pixclock) / 1000,
550                 PICOS2KHZ(p->pixclock) % 1000);
551
552         if (p != &fb_mode) {
553                 int ret;
554
555                 debug("Creating new display-timing node from '%s'\n",
556                         video_mode);
557                 ret = karo_fdt_create_fb_mode(working_fdt, video_mode, p);
558                 if (ret)
559                         printf("Failed to create new display-timing node from '%s': %d\n",
560                                 video_mode, ret);
561         }
562
563         gpio_request_array(stk5_lcd_gpios, ARRAY_SIZE(stk5_lcd_gpios));
564         tx48_set_pin_mux(stk5_lcd_pads, ARRAY_SIZE(stk5_lcd_pads));
565
566         if (karo_load_splashimage(0) == 0) {
567                 struct da8xx_panel da8xx_panel = { };
568
569                 debug("Initializing FB driver\n");
570                 tx48_lcd_panel_setup(&da8xx_panel, p);
571                 da8xx_video_init(&da8xx_panel, &lcd_cfg, color_depth);
572
573                 debug("Initializing LCD controller\n");
574                 video_hw_init();
575         } else {
576                 debug("Skipping initialization of LCD controller\n");
577         }
578 }
579 #else
580 #define lcd_enabled 0
581 #endif /* CONFIG_LCD */
582
583 static void stk5_board_init(void)
584 {
585         gpio_request_array(stk5_gpios, ARRAY_SIZE(stk5_gpios));
586         tx48_set_pin_mux(stk5_pads, ARRAY_SIZE(stk5_pads));
587 }
588
589 static void stk5v3_board_init(void)
590 {
591         stk5_board_init();
592 }
593
594 static void stk5v5_board_init(void)
595 {
596         stk5_board_init();
597
598         gpio_request_array(stk5v5_gpios, ARRAY_SIZE(stk5v5_gpios));
599         tx48_set_pin_mux(stk5v5_pads, ARRAY_SIZE(stk5v5_pads));
600 }
601
602 /* called with default environment! */
603 int board_init(void)
604 {
605         int i;
606
607         /* mach type passed to kernel */
608 #ifdef CONFIG_OF_LIBFDT
609         gd->bd->bi_arch_number = -1;
610 #endif
611         /* address of boot parameters */
612         gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
613
614         if (ctrlc() || (prm_rstst & PRM_RSTST_WDT1_RST)) {
615                 if (prm_rstst & PRM_RSTST_WDT1_RST)
616                         printf("WDOG RESET detected\n");
617                 else
618                         printf("<CTRL-C> detected; safeboot enabled\n");
619         }
620
621         gpio_request_array(tx48_gpios, ARRAY_SIZE(tx48_gpios));
622         tx48_set_pin_mux(tx48_pads, ARRAY_SIZE(tx48_pads));
623
624         for (i = 0; i < ARRAY_SIZE(tx48_gpios); i++) {
625                 int gpio = tx48_gpios[i].gpio;
626
627                 if (gpio_get_value(gpio) == 0)
628                         gpio_direction_output(gpio, 1);
629         }
630
631         tx48_set_pin_mux(tx48_pads, ARRAY_SIZE(tx48_i2c_pads));
632         return 0;
633 }
634
635 static void show_reset_cause(u32 prm_rstst)
636 {
637         const char *dlm = "";
638
639         printf("RESET cause: ");
640         if (prm_rstst & PRM_RSTST_GLOBAL_COLD_RST) {
641                 printf("%sPOR", dlm);
642                 dlm = " | ";
643         }
644         if (prm_rstst & PRM_RSTST_GLOBAL_WARM_SW_RST) {
645                 printf("%sSW", dlm);
646                 dlm = " | ";
647         }
648         if (prm_rstst & PRM_RSTST_WDT1_RST) {
649                 printf("%sWATCHDOG", dlm);
650                 dlm = " | ";
651         }
652         if (prm_rstst & PRM_RSTST_EXTERNAL_WARM_RST) {
653                 printf("%sWARM", dlm);
654                 dlm = " | ";
655         }
656         if (prm_rstst & PRM_RSTST_ICEPICK_RST) {
657                 printf("%sJTAG", dlm);
658                 dlm = " | ";
659         }
660         if (*dlm == '\0')
661                 printf("unknown");
662
663         printf(" RESET\n");
664 }
665
666 /* called with default environment! */
667 int checkboard(void)
668 {
669         prm_rstst = readl(PRM_RSTST);
670         show_reset_cause(prm_rstst);
671
672         printf("Board: Ka-Ro TX48-7020\n");
673
674         timer_init();
675         return 0;
676 }
677
678 static void tx48_set_cpu_clock(void)
679 {
680         unsigned long cpu_clk = getenv_ulong("cpu_clk", 10, 0);
681         unsigned long act_cpu_clk;
682
683         if (cpu_clk == 0 || cpu_clk == mpu_clk_rate() / 1000000)
684                 return;
685
686         if (had_ctrlc() || (prm_rstst & PRM_RSTST_WDT1_RST)) {
687                 printf("%s detected; skipping cpu clock change\n",
688                         (prm_rstst & PRM_RSTST_WDT1_RST) ?
689                         "WDOG RESET" : "<CTRL-C>");
690                 return;
691         }
692
693         mpu_pll_config_val(cpu_clk);
694
695         act_cpu_clk = mpu_clk_rate();
696         if (cpu_clk * 1000000 != act_cpu_clk) {
697                 printf("Failed to set CPU clock to %lu MHz; using %lu.%03lu MHz instead\n",
698                         cpu_clk, act_cpu_clk / 1000000,
699                         act_cpu_clk / 1000 % 1000);
700         } else {
701                 printf("CPU clock set to %lu.%03lu MHz\n",
702                         act_cpu_clk / 1000000, act_cpu_clk / 1000 % 1000);
703         }
704 }
705
706 static void tx48_init_mac(void)
707 {
708         uint8_t mac_addr[ETH_ALEN];
709         uint32_t mac_hi, mac_lo;
710
711         /* try reading mac address from efuse */
712         mac_lo = __raw_readl(MAC_ID0_LO);
713         mac_hi = __raw_readl(MAC_ID0_HI);
714
715         mac_addr[0] = mac_hi & 0xFF;
716         mac_addr[1] = (mac_hi & 0xFF00) >> 8;
717         mac_addr[2] = (mac_hi & 0xFF0000) >> 16;
718         mac_addr[3] = (mac_hi & 0xFF000000) >> 24;
719         mac_addr[4] = mac_lo & 0xFF;
720         mac_addr[5] = (mac_lo & 0xFF00) >> 8;
721
722         if (!is_valid_ethaddr(mac_addr)) {
723                 printf("No valid MAC address programmed\n");
724                 return;
725         }
726         printf("MAC addr from fuse: %pM\n", mac_addr);
727         eth_setenv_enetaddr("ethaddr", mac_addr);
728 }
729
730 /* called with environment from NAND or MMC */
731 int board_late_init(void)
732 {
733         int ret = 0;
734         const char *baseboard;
735
736         env_cleanup();
737
738         tx48_set_cpu_clock();
739
740         if (had_ctrlc())
741                 setenv_ulong("safeboot", 1);
742         else if (prm_rstst & PRM_RSTST_WDT1_RST)
743                 setenv_ulong("wdreset", 1);
744         else
745                 karo_fdt_move_fdt();
746
747         baseboard = getenv("baseboard");
748         if (!baseboard)
749                 goto exit;
750
751         if (strncmp(baseboard, "stk5", 4) == 0) {
752                 printf("Baseboard: %s\n", baseboard);
753                 if ((strlen(baseboard) == 4) ||
754                         strcmp(baseboard, "stk5-v3") == 0) {
755                         stk5v3_board_init();
756                 } else if (strcmp(baseboard, "stk5-v5") == 0) {
757                         stk5v5_board_init();
758                 } else {
759                         printf("WARNING: Unsupported STK5 board rev.: %s\n",
760                                 baseboard + 4);
761                 }
762         } else {
763                 printf("WARNING: Unsupported baseboard: '%s'\n",
764                         baseboard);
765                 ret = -EINVAL;
766         }
767
768 exit:
769         tx48_init_mac();
770         clear_ctrlc();
771         return ret;
772 }
773
774 #ifdef CONFIG_DRIVER_TI_CPSW
775 static void tx48_phy_init(void)
776 {
777         debug("%s: Resetting ethernet PHY\n", __func__);
778
779         gpio_direction_output(TX48_ETH_PHY_RST_GPIO, 0);
780
781         udelay(100);
782
783         /* Release nRST */
784         gpio_set_value(TX48_ETH_PHY_RST_GPIO, 1);
785
786         /* Wait for PHY internal POR signal to deassert */
787         udelay(25000);
788 }
789
790 static void cpsw_control(int enabled)
791 {
792         /* nothing for now */
793         /* TODO : VTP was here before */
794 }
795
796 static struct cpsw_slave_data cpsw_slaves[] = {
797         {
798                 .slave_reg_ofs  = 0x208,
799                 .sliver_reg_ofs = 0xd80,
800                 .phy_addr       = 0,
801                 .phy_if         = PHY_INTERFACE_MODE_RMII,
802         },
803 };
804
805 void s_init(void)
806 {
807         /* Nothing to be done here */
808 }
809
810 static struct cpsw_platform_data cpsw_data = {
811         .mdio_base              = CPSW_MDIO_BASE,
812         .cpsw_base              = CPSW_BASE,
813         .mdio_div               = 0xff,
814         .channels               = 8,
815         .cpdma_reg_ofs          = 0x800,
816         .slaves                 = ARRAY_SIZE(cpsw_slaves),
817         .slave_data             = cpsw_slaves,
818         .ale_reg_ofs            = 0xd00,
819         .ale_entries            = 1024,
820         .host_port_reg_ofs      = 0x108,
821         .hw_stats_reg_ofs       = 0x900,
822         .mac_control            = (1 << 5) /* MIIEN */,
823         .control                = cpsw_control,
824         .host_port_num          = 0,
825         .version                = CPSW_CTRL_VERSION_2,
826 };
827
828 int board_eth_init(bd_t *bis)
829 {
830         __raw_writel(RMII_MODE_ENABLE, MAC_MII_SEL);
831         tx48_phy_init();
832         return cpsw_register(&cpsw_data);
833 }
834 #endif /* CONFIG_DRIVER_TI_CPSW */
835
836 #if defined(CONFIG_OMAP_HSMMC) && !defined(CONFIG_SPL_BUILD)
837 int cpu_mmc_init(bd_t *bis)
838 {
839         return omap_mmc_init(1, 0, 0, TX48_MMC_CD_GPIO, -1);
840 }
841 #endif
842
843 void tx48_disable_watchdog(void)
844 {
845         struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE;
846
847         while (readl(&wdtimer->wdtwwps) & (1 << 4))
848                 ;
849         writel(0xaaaa, &wdtimer->wdtwspr);
850         while (readl(&wdtimer->wdtwwps) & (1 << 4))
851                 ;
852         writel(0x5555, &wdtimer->wdtwspr);
853 }
854
855 enum {
856         LED_STATE_INIT = -1,
857         LED_STATE_OFF,
858         LED_STATE_ON,
859 };
860
861 void show_activity(int arg)
862 {
863         static int led_state = LED_STATE_INIT;
864         static ulong last;
865
866         if (led_state == LED_STATE_INIT) {
867                 last = get_timer(0);
868                 gpio_set_value(TX48_LED_GPIO, 1);
869                 led_state = LED_STATE_ON;
870         } else {
871                 if (get_timer(last) > CONFIG_SYS_HZ) {
872                         last = get_timer(0);
873                         if (led_state == LED_STATE_ON) {
874                                 gpio_set_value(TX48_LED_GPIO, 0);
875                         } else {
876                                 gpio_set_value(TX48_LED_GPIO, 1);
877                         }
878                         led_state = 1 - led_state;
879                 }
880         }
881 }
882
883 #ifdef CONFIG_OF_BOARD_SETUP
884 #ifdef CONFIG_FDT_FIXUP_PARTITIONS
885 #include <jffs2/jffs2.h>
886 #include <mtd_node.h>
887 static struct node_info nodes[] = {
888         { "ti,omap2-nand", MTD_DEV_TYPE_NAND, },
889         { "ti,am3352-gpmc", MTD_DEV_TYPE_NAND, },
890 };
891
892 #else
893 #define fdt_fixup_mtdparts(b,n,c) do { } while (0)
894 #endif /* CONFIG_FDT_FIXUP_PARTITIONS */
895
896 static const char *tx48_touchpanels[] = {
897         "ti,tsc2007",
898         "edt,edt-ft5x06",
899         "ti,am3359-tscadc",
900 };
901
902 int ft_board_setup(void *blob, bd_t *bd)
903 {
904         const char *baseboard = getenv("baseboard");
905         int stk5_v5 = baseboard != NULL && (strcmp(baseboard, "stk5-v5") == 0);
906         const char *video_mode = karo_get_vmode(getenv("video_mode"));
907         int ret;
908
909         ret = fdt_increase_size(blob, 4096);
910         if (ret) {
911                 printf("Failed to increase FDT size: %s\n", fdt_strerror(ret));
912                 return ret;
913         }
914         fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
915
916         karo_fdt_fixup_touchpanel(blob, tx48_touchpanels,
917                                 ARRAY_SIZE(tx48_touchpanels));
918         karo_fdt_fixup_usb_otg(blob, "usb0", "phys", "vcc-supply");
919         karo_fdt_fixup_flexcan(blob, stk5_v5);
920
921         karo_fdt_update_fb_mode(blob, video_mode);
922
923         tx48_disable_watchdog();
924
925         if (get_cpu_rev() == 0) {
926                 karo_fdt_del_prop(blob, "lltc,ltc3589-2", 0x34, "interrupts");
927                 karo_fdt_del_prop(blob, "lltc,ltc3589-2", 0x34,
928                                 "interrupt-parent");
929         }
930
931         return 0;
932 }
933 #endif /* CONFIG_OF_BOARD_SETUP */