]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/karo/txa5/txa5.c
147f2e02faeef12d0f605652eaf131ca9e48d095
[karo-tx-uboot.git] / board / karo / txa5 / txa5.c
1 /*
2  * Copyright (C) 2015 Lothar Waßmann <LW@KARO-electronics.de>
3  * based on: board/atmel/sama5d4_xplained/sama5d4_xplained.c
4  *     Copyright (C) 2014 Atmel Bo Shen <voice.shen@atmel.com>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * SPDX-License-Identifier:     GPL-2.0+
10  */
11 #define DEBUG
12
13 #include <common.h>
14 #include <libfdt.h>
15 #include <fdt_support.h>
16 #include <lcd.h>
17 #include <netdev.h>
18 #include <mmc.h>
19 #include <net.h>
20 #include <nand.h>
21 #include <atmel_hlcdc.h>
22 #include <atmel_mci.h>
23 #include <linux/fb.h>
24 #include <asm/io.h>
25 #include <asm/gpio.h>
26 #include <asm/arch/at91_common.h>
27 #include <asm/arch/at91_pmc.h>
28 #include <asm/arch/at91_rstc.h>
29 #include <asm/arch/clk.h>
30 #include <asm/arch/sama5d3_smc.h>
31 #include <asm/arch/sama5d4.h>
32
33 #include "../common/karo.h"
34
35 #define TXA5_LCD_RST_GPIO       GPIO_PIN_PA(25)
36 #define TXA5_LCD_PWR_GPIO       GPIO_PIN_PB(15)
37 #define TXA5_LCD_BACKLIGHT_GPIO GPIO_PIN_PA(24)
38
39 #define TXA5_ETH_RST_GPIO       GPIO_PIN_PD(30)
40 //#define TXA5_ETH_PWR_GPIO     GPIO_PIN_BU(7)
41 #define TXA5_ETH_INT_GPIO       GPIO_PIN_PE(1)
42
43 #define TXA5_LED_GPIO           GPIO_PIN_PD(29)
44
45 DECLARE_GLOBAL_DATA_PTR;
46
47 static int wdreset;
48
49 #ifdef CONFIG_NAND_ATMEL
50 static void txa5_nand_hw_init(void)
51 {
52         struct at91_smc *smc = (void *)ATMEL_BASE_SMC;
53
54         at91_periph_clk_enable(ATMEL_ID_SMC);
55
56         /* Configure SMC CS3 for NAND */
57         writel(AT91_SMC_SETUP_NWE(1) | AT91_SMC_SETUP_NCS_WR(1) |
58                AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(1),
59                &smc->cs[3].setup);
60         writel(AT91_SMC_PULSE_NWE(2) | AT91_SMC_PULSE_NCS_WR(3) |
61                AT91_SMC_PULSE_NRD(2) | AT91_SMC_PULSE_NCS_RD(3),
62                &smc->cs[3].pulse);
63         writel(AT91_SMC_CYCLE_NWE(5) | AT91_SMC_CYCLE_NRD(5),
64                &smc->cs[3].cycle);
65         writel(AT91_SMC_TIMINGS_TCLR(2) | AT91_SMC_TIMINGS_TADL(7) |
66                AT91_SMC_TIMINGS_TAR(2)  | AT91_SMC_TIMINGS_TRR(3)   |
67                AT91_SMC_TIMINGS_TWB(7)  | AT91_SMC_TIMINGS_RBNSEL(3)|
68                AT91_SMC_TIMINGS_NFSEL(1), &smc->cs[3].timings);
69         writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE |
70                AT91_SMC_MODE_EXNW_DISABLE |
71                AT91_SMC_MODE_DBW_8 |
72                AT91_SMC_MODE_TDF_CYCLE(3),
73                &smc->cs[3].mode);
74
75         at91_set_a_periph(AT91_PIO_PORTC, 5, 0);        /* D0 */
76         at91_set_a_periph(AT91_PIO_PORTC, 6, 0);        /* D1 */
77         at91_set_a_periph(AT91_PIO_PORTC, 7, 0);        /* D2 */
78         at91_set_a_periph(AT91_PIO_PORTC, 8, 0);        /* D3 */
79         at91_set_a_periph(AT91_PIO_PORTC, 9, 0);        /* D4 */
80         at91_set_a_periph(AT91_PIO_PORTC, 10, 0);       /* D5 */
81         at91_set_a_periph(AT91_PIO_PORTC, 11, 0);       /* D6 */
82         at91_set_a_periph(AT91_PIO_PORTC, 12, 0);       /* D7 */
83         at91_set_a_periph(AT91_PIO_PORTC, 13, 0);       /* RE */
84         at91_set_a_periph(AT91_PIO_PORTC, 14, 0);       /* WE */
85         at91_set_a_periph(AT91_PIO_PORTC, 15, 1);       /* NCS */
86         at91_set_a_periph(AT91_PIO_PORTC, 16, 1);       /* RDY */
87         at91_set_a_periph(AT91_PIO_PORTC, 17, 1);       /* ALE */
88         at91_set_a_periph(AT91_PIO_PORTC, 18, 1);       /* CLE */
89 }
90 #endif
91
92 static inline void txa5_serial0_hw_init(void)
93 {
94         at91_set_a_periph(AT91_PIO_PORTD, 13, 1);       /* TXD0 */
95         at91_set_a_periph(AT91_PIO_PORTD, 12, 0);       /* RXD0 */
96         at91_set_a_periph(AT91_PIO_PORTD, 10, 1);       /* CTS0 */
97         at91_set_a_periph(AT91_PIO_PORTD, 11, 0);       /* RTS0 */
98
99         /* Enable clock */
100         at91_periph_clk_enable(ATMEL_ID_USART0);
101 }
102
103 static inline void txa5_serial1_hw_init(void)
104 {
105         at91_set_a_periph(AT91_PIO_PORTD, 17, 1);       /* TXD1 */
106         at91_set_a_periph(AT91_PIO_PORTD, 16, 0);       /* RXD1 */
107         at91_set_a_periph(AT91_PIO_PORTD, 14, 1);       /* CTS1 */
108         at91_set_a_periph(AT91_PIO_PORTD, 15, 0);       /* RTS1 */
109
110         /* Enable clock */
111         at91_periph_clk_enable(ATMEL_ID_USART1);
112 }
113
114 static inline void txa5_serial3_hw_init(void)
115 {
116         at91_set_b_periph(AT91_PIO_PORTE, 17, 1);       /* TXD3 */
117         at91_set_b_periph(AT91_PIO_PORTE, 16, 0);       /* RXD3 */
118         at91_set_b_periph(AT91_PIO_PORTE, 5, 1);        /* CTS3 */
119         at91_set_b_periph(AT91_PIO_PORTE, 24, 0);       /* RTS3 */
120
121         /* Enable clock */
122         at91_periph_clk_enable(ATMEL_ID_USART3);
123 }
124
125 #ifdef CONFIG_GENERIC_ATMEL_MCI
126 void txa5_mci1_hw_init(void)
127 {
128         at91_set_c_periph(AT91_PIO_PORTE, 19, 1);       /* MCI1 CDA */
129         at91_set_c_periph(AT91_PIO_PORTE, 20, 1);       /* MCI1 DA0 */
130         at91_set_c_periph(AT91_PIO_PORTE, 21, 1);       /* MCI1 DA1 */
131         at91_set_c_periph(AT91_PIO_PORTE, 22, 1);       /* MCI1 DA2 */
132         at91_set_c_periph(AT91_PIO_PORTE, 23, 1);       /* MCI1 DA3 */
133         at91_set_c_periph(AT91_PIO_PORTE, 18, 0);       /* MCI1 CLK */
134
135         /*
136          * As the mci io internal pull down is too strong, so if the io needs
137          * external pull up, the pull up resistor will be very small, if so
138          * the power consumption will increase, so disable the interanl pull
139          * down to save the power.
140          */
141         at91_set_pio_pulldown(AT91_PIO_PORTE, 18, 0);
142         at91_set_pio_pulldown(AT91_PIO_PORTE, 19, 0);
143         at91_set_pio_pulldown(AT91_PIO_PORTE, 20, 0);
144         at91_set_pio_pulldown(AT91_PIO_PORTE, 21, 0);
145         at91_set_pio_pulldown(AT91_PIO_PORTE, 22, 0);
146         at91_set_pio_pulldown(AT91_PIO_PORTE, 23, 0);
147
148         /* SD Card Detect */
149         at91_set_pio_input(AT91_PIO_PORTE, 6, 1);
150         at91_set_pio_deglitch(AT91_PIO_PORTE, 6, 1);
151
152         /* Enable clock */
153         at91_periph_clk_enable(ATMEL_ID_MCI1);
154 }
155 #endif
156
157 #ifdef CONFIG_MACB
158 void txa5_macb0_hw_init(void)
159 {
160         at91_set_a_periph(AT91_PIO_PORTB, 0, 0);        /* ETXCK_EREFCK */
161         at91_set_a_periph(AT91_PIO_PORTB, 6, 0);        /* ERXDV */
162         at91_set_a_periph(AT91_PIO_PORTB, 8, 0);        /* ERX0 */
163         at91_set_a_periph(AT91_PIO_PORTB, 9, 0);        /* ERX1 */
164         at91_set_a_periph(AT91_PIO_PORTB, 7, 0);        /* ERXER */
165         at91_set_a_periph(AT91_PIO_PORTB, 2, 0);        /* ETXEN */
166         at91_set_a_periph(AT91_PIO_PORTB, 12, 0);       /* ETX0 */
167         at91_set_a_periph(AT91_PIO_PORTB, 13, 0);       /* ETX1 */
168         at91_set_a_periph(AT91_PIO_PORTB, 17, 0);       /* EMDIO */
169         at91_set_a_periph(AT91_PIO_PORTB, 16, 0);       /* EMDC */
170
171         at91_set_pio_input(AT91_PIO_PORTE, 1, 0);       /* IRQ */
172         at91_set_pio_deglitch(AT91_PIO_PORTE, 1, 1);
173
174         at91_set_pio_output(AT91_PIO_PORTD, 30, 0);     /* PHY RESET */
175         at91_set_pio_pullup(AT91_PIO_PORTD, 30, 1);
176
177         /* Enable clock */
178         at91_periph_clk_enable(ATMEL_ID_GMAC0);
179 }
180 #endif
181
182 int board_early_init_f(void)
183 {
184         at91_periph_clk_enable(ATMEL_ID_PIOA);
185         at91_periph_clk_enable(ATMEL_ID_PIOB);
186         at91_periph_clk_enable(ATMEL_ID_PIOC);
187         at91_periph_clk_enable(ATMEL_ID_PIOD);
188         at91_periph_clk_enable(ATMEL_ID_PIOE);
189
190 #ifdef CONFIG_USART_ID
191 #if CONFIG_USART_ID == ATMEL_ID_USART0
192         txa5_serial0_hw_init();
193 #elif CONFIG_USART_ID == ATMEL_ID_USART1
194         txa5_serial1_hw_init();
195 #elif CONFIG_USART_ID == ATMEL_ID_USART3
196 #else
197 #error No console UART defined
198 #endif
199         txa5_serial3_hw_init();
200 #endif /* CONFIG_USART_ID */
201
202         return 0;
203 }
204
205 /* called with default environment! */
206 int board_init(void)
207 {
208         /* adress of boot parameters */
209         gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
210
211 #ifdef CONFIG_NAND_ATMEL
212         txa5_nand_hw_init();
213 #endif
214 #ifdef CONFIG_GENERIC_ATMEL_MCI
215         txa5_mci1_hw_init();
216 #endif
217         return 0;
218 }
219
220 int dram_init(void)
221 {
222         gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
223                                 CONFIG_SYS_SDRAM_SIZE);
224         return 0;
225 }
226
227 #ifdef CONFIG_GENERIC_ATMEL_MCI
228 int board_mmc_init(bd_t *bis)
229 {
230         return atmel_mci_init((void *)ATMEL_BASE_MCI1);
231 }
232 #endif /* CONFIG_GENERIC_ATMEL_MCI */
233
234 #ifdef CONFIG_MACB
235 int board_eth_init(bd_t *bis)
236 {
237         int ret;
238
239         txa5_macb0_hw_init();
240
241         /* delay at least 21ms for the PHY internal POR signal to deassert */
242         udelay(22000);
243
244         /* Deassert RESET to the external phy */
245         at91_set_gpio_value(TXA5_ETH_RST_GPIO, 1);
246
247         ret = macb_eth_initialize(0, (void *)ATMEL_BASE_GMAC0, 0x00);
248
249         return ret;
250 }
251 #endif
252
253 #ifndef ETH_ALEN
254 #define ETH_ALEN      6
255 #endif
256 #define MAC_ID0_HI      (void *)0xfc060040
257 #define MAC_ID0_LO      (void *)0xfc060044
258
259 static void txa5_init_mac(void)
260 {
261         uint8_t mac_addr[ETH_ALEN];
262         uint32_t mac_hi, mac_lo;
263
264         /* try reading mac address from efuse */
265         mac_lo = __raw_readl(MAC_ID0_LO);
266         mac_hi = __raw_readl(MAC_ID0_HI);
267
268         mac_addr[0] = mac_hi & 0xFF;
269         mac_addr[1] = (mac_hi >> 8) & 0xFF;
270         mac_addr[2] = (mac_hi >> 16) & 0xFF;
271         mac_addr[3] = (mac_hi >> 24) & 0xFF;
272         mac_addr[4] = mac_lo & 0xFF;
273         mac_addr[5] = (mac_lo >> 8) & 0xFF;
274
275         if (!is_valid_ethaddr(mac_addr)) {
276                 printf("No valid MAC address programmed\n");
277                 return;
278         }
279         printf("MAC addr from fuse: %pM\n", mac_addr);
280         eth_setenv_enetaddr("ethaddr", mac_addr);
281 }
282
283 enum {
284         LED_STATE_INIT = -1,
285         LED_STATE_OFF,
286         LED_STATE_ON,
287 };
288
289 void show_activity(int arg)
290 {
291         static int led_state = LED_STATE_INIT;
292         static ulong last;
293
294         if (led_state == LED_STATE_INIT) {
295                 last = get_timer(0);
296                 at91_set_gpio_value(TXA5_LED_GPIO, 1);
297                 led_state = LED_STATE_ON;
298         } else {
299                 if (get_timer(last) > CONFIG_SYS_HZ) {
300                         last = get_timer(0);
301                         if (led_state == LED_STATE_ON) {
302                                 at91_set_gpio_value(TXA5_LED_GPIO, 0);
303                         } else {
304                                 at91_set_gpio_value(TXA5_LED_GPIO, 1);
305                         }
306                         led_state = 1 - led_state;
307                 }
308         }
309 }
310
311 #ifdef CONFIG_LCD
312 vidinfo_t panel_info = {
313         /* set to max. size supported by SoC */
314         .vl_col = 2048,
315         .vl_row = 2048,
316         .vl_bpix = LCD_COLOR16,
317         .vl_tft = 1,
318         .mmio = (void *)ATMEL_BASE_LCDC,
319 };
320
321 #define FB_SYNC_OE_LOW_ACT      (1 << 31)
322 #define FB_SYNC_CLK_LAT_FALL    (1 << 30)
323
324 static struct fb_videomode txa5_fb_modes[] = {
325         {
326                 /* Standard VGA timing */
327                 .name           = "VGA",
328                 .refresh        = 60,
329                 .xres           = 640,
330                 .yres           = 480,
331                 .pixclock       = KHZ2PICOS(25175),
332                 .left_margin    = 48,
333                 .hsync_len      = 96,
334                 .right_margin   = 16,
335                 .upper_margin   = 31,
336                 .vsync_len      = 2,
337                 .lower_margin   = 12,
338                 .sync           = FB_SYNC_CLK_LAT_FALL,
339         },
340         {
341                 /* Emerging ETV570 640 x 480 display. Syncs low active,
342                  * DE high active, 115.2 mm x 86.4 mm display area
343                  * VGA compatible timing
344                  */
345                 .name           = "ETV570",
346                 .refresh        = 60,
347                 .xres           = 640,
348                 .yres           = 480,
349                 .pixclock       = KHZ2PICOS(25175),
350                 .left_margin    = 114,
351                 .hsync_len      = 30,
352                 .right_margin   = 16,
353                 .upper_margin   = 32,
354                 .vsync_len      = 3,
355                 .lower_margin   = 10,
356                 .sync           = FB_SYNC_CLK_LAT_FALL,
357         },
358         {
359                 /* Emerging ET0350G0DH6 320 x 240 display.
360                  * 70.08 mm x 52.56 mm display area.
361                  */
362                 .name           = "ET0350",
363                 .refresh        = 60,
364                 .xres           = 320,
365                 .yres           = 240,
366                 .pixclock       = KHZ2PICOS(6500),
367                 .left_margin    = 68 - 34,
368                 .hsync_len      = 34,
369                 .right_margin   = 20,
370                 .upper_margin   = 18 - 3,
371                 .vsync_len      = 3,
372                 .lower_margin   = 4,
373                 .sync           = FB_SYNC_CLK_LAT_FALL,
374         },
375         {
376                 /* Emerging ET0430G0DH6 480 x 272 display.
377                  * 95.04 mm x 53.856 mm display area.
378                  */
379                 .name           = "ET0430",
380                 .refresh        = 60,
381                 .xres           = 480,
382                 .yres           = 272,
383                 .pixclock       = KHZ2PICOS(9000),
384                 .left_margin    = 2,
385                 .hsync_len      = 41,
386                 .right_margin   = 2,
387                 .upper_margin   = 2,
388                 .vsync_len      = 10,
389                 .lower_margin   = 2,
390         },
391         {
392                 /* Emerging ET0500G0DH6 800 x 480 display.
393                  * 109.6 mm x 66.4 mm display area.
394                  */
395                 .name           = "ET0500",
396                 .refresh        = 60,
397                 .xres           = 800,
398                 .yres           = 480,
399                 .pixclock       = KHZ2PICOS(33260),
400                 .left_margin    = 216 - 128,
401                 .hsync_len      = 128,
402                 .right_margin   = 1056 - 800 - 216,
403                 .upper_margin   = 35 - 2,
404                 .vsync_len      = 2,
405                 .lower_margin   = 525 - 480 - 35,
406                 .sync           = FB_SYNC_CLK_LAT_FALL,
407         },
408         {
409                 /* Emerging ETQ570G0DH6 320 x 240 display.
410                  * 115.2 mm x 86.4 mm display area.
411                  */
412                 .name           = "ETQ570",
413                 .refresh        = 60,
414                 .xres           = 320,
415                 .yres           = 240,
416                 .pixclock       = KHZ2PICOS(6400),
417                 .left_margin    = 38,
418                 .hsync_len      = 30,
419                 .right_margin   = 30,
420                 .upper_margin   = 16, /* 15 according to datasheet */
421                 .vsync_len      = 3, /* TVP -> 1>x>5 */
422                 .lower_margin   = 4, /* 4.5 according to datasheet */
423                 .sync           = FB_SYNC_CLK_LAT_FALL,
424         },
425         {
426                 /* Emerging ET0700G0DH6 800 x 480 display.
427                  * 152.4 mm x 91.44 mm display area.
428                  */
429                 .name           = "ET0700",
430                 .refresh        = 60,
431                 .xres           = 800,
432                 .yres           = 480,
433                 .pixclock       = KHZ2PICOS(33260),
434                 .left_margin    = 216 - 128,
435                 .hsync_len      = 128,
436                 .right_margin   = 1056 - 800 - 216,
437                 .upper_margin   = 35 - 2,
438                 .vsync_len      = 2,
439                 .lower_margin   = 525 - 480 - 35,
440                 .sync           = FB_SYNC_CLK_LAT_FALL,
441         },
442         {
443                 /* unnamed entry for assigning parameters parsed from 'video_mode' string */
444                 .refresh        = 60,
445                 .left_margin    = 48,
446                 .hsync_len      = 96,
447                 .right_margin   = 16,
448                 .upper_margin   = 31,
449                 .vsync_len      = 2,
450                 .lower_margin   = 12,
451                 .sync           = FB_SYNC_CLK_LAT_FALL,
452         },
453 };
454
455 static int lcd_enabled = 1;
456 static int lcd_bl_polarity;
457 int lcd_output_bpp;
458
459 static int lcd_backlight_polarity(void)
460 {
461         return lcd_bl_polarity;
462 }
463
464 void lcd_enable(void)
465 {
466         /* HACK ALERT:
467          * global variable from common/lcd.c
468          * Set to 0 here to prevent messages from going to LCD
469          * rather than serial console
470          */
471         lcd_is_enabled = 0;
472
473         if (lcd_enabled) {
474                 karo_load_splashimage(1);
475
476                 debug("Switching LCD on\n");
477                 at91_set_gpio_value(TXA5_LCD_PWR_GPIO, 1);
478                 udelay(100);
479                 at91_set_gpio_value(TXA5_LCD_RST_GPIO, 1);
480                 udelay(300000);
481                 at91_set_gpio_value(TXA5_LCD_BACKLIGHT_GPIO,
482                                 lcd_backlight_polarity());
483         }
484 }
485
486 void lcd_disable(void)
487 {
488 }
489
490 void lcd_panel_disable(void)
491 {
492         if (lcd_enabled) {
493                 debug("Switching LCD off\n");
494                 at91_set_gpio_value(TXA5_LCD_BACKLIGHT_GPIO,
495                                 !lcd_backlight_polarity());
496                 at91_set_gpio_value(TXA5_LCD_PWR_GPIO, 0);
497                 at91_set_gpio_value(TXA5_LCD_RST_GPIO, 0);
498         }
499 }
500
501 static void txa5_lcd_panel_setup(struct fb_videomode *fb)
502 {
503         panel_info.vl_clk = PICOS2KHZ(fb->pixclock) * 1000;
504
505         panel_info.vl_col = fb->xres;
506         panel_info.vl_left_margin = fb->left_margin;
507         panel_info.vl_hsync_len = fb->hsync_len;
508         panel_info.vl_right_margin = fb->right_margin;
509
510         panel_info.vl_row = fb->yres;
511         panel_info.vl_upper_margin = fb->upper_margin;
512         panel_info.vl_vsync_len = fb->vsync_len;
513         panel_info.vl_lower_margin = fb->lower_margin;
514
515         if (!(fb->sync & FB_SYNC_HOR_HIGH_ACT))
516                 panel_info.vl_sync |= LCDC_LCDCFG5_HSPOL;
517         if (!(fb->sync & FB_SYNC_VERT_HIGH_ACT))
518                 panel_info.vl_sync |= LCDC_LCDCFG5_VSPOL;
519         if (fb->sync & FB_SYNC_OE_LOW_ACT)
520                 panel_info.vl_sync |= LCDC_LCDCFG5_DISPPOL;
521
522         panel_info.vl_clk_pol = !!(fb->sync & FB_SYNC_CLK_LAT_FALL);
523 }
524
525 static void txa5_lcd_hw_init(void)
526 {
527         at91_set_pio_output(AT91_PIO_PORTA, 24, 0);     /* LCDPWM */
528         at91_set_pio_output(AT91_PIO_PORTA, 25, 0);     /* LCD RST */
529         at91_set_pio_output(AT91_PIO_PORTB, 15, 0);     /* LCD PWR */
530
531         at91_set_a_periph(AT91_PIO_PORTA, 26, 0);       /* LCDVSYNC */
532         at91_set_a_periph(AT91_PIO_PORTA, 27, 0);       /* LCDHSYNC */
533         at91_set_a_periph(AT91_PIO_PORTA, 28, 0);       /* LCDDOTCK */
534         at91_set_a_periph(AT91_PIO_PORTA, 29, 0);       /* LCDDEN */
535
536         at91_set_a_periph(AT91_PIO_PORTA,  0, 0);       /* LCDD0 */
537         at91_set_a_periph(AT91_PIO_PORTA,  1, 0);       /* LCDD1 */
538         at91_set_a_periph(AT91_PIO_PORTA,  2, 0);       /* LCDD2 */
539         at91_set_a_periph(AT91_PIO_PORTA,  3, 0);       /* LCDD3 */
540         at91_set_a_periph(AT91_PIO_PORTA,  4, 0);       /* LCDD4 */
541         at91_set_a_periph(AT91_PIO_PORTA,  5, 0);       /* LCDD5 */
542         at91_set_a_periph(AT91_PIO_PORTA,  6, 0);       /* LCDD6 */
543         at91_set_a_periph(AT91_PIO_PORTA,  7, 0);       /* LCDD7 */
544
545         at91_set_a_periph(AT91_PIO_PORTA,  8, 0);       /* LCDD9 */
546         at91_set_a_periph(AT91_PIO_PORTA,  9, 0);       /* LCDD8 */
547         at91_set_a_periph(AT91_PIO_PORTA, 10, 0);       /* LCDD10 */
548         at91_set_a_periph(AT91_PIO_PORTA, 11, 0);       /* LCDD11 */
549         at91_set_a_periph(AT91_PIO_PORTA, 12, 0);       /* LCDD12 */
550         at91_set_a_periph(AT91_PIO_PORTA, 13, 0);       /* LCDD13 */
551         at91_set_a_periph(AT91_PIO_PORTA, 14, 0);       /* LCDD14 */
552         at91_set_a_periph(AT91_PIO_PORTA, 15, 0);       /* LCDD15 */
553
554         at91_set_a_periph(AT91_PIO_PORTA, 16, 0);       /* LCDD16 */
555         at91_set_a_periph(AT91_PIO_PORTA, 17, 0);       /* LCDD17 */
556         at91_set_a_periph(AT91_PIO_PORTA, 18, 0);       /* LCDD18 */
557         at91_set_a_periph(AT91_PIO_PORTA, 19, 0);       /* LCDD19 */
558         at91_set_a_periph(AT91_PIO_PORTA, 20, 0);       /* LCDD20 */
559         at91_set_a_periph(AT91_PIO_PORTA, 21, 0);       /* LCDD21 */
560         at91_set_a_periph(AT91_PIO_PORTA, 22, 0);       /* LCDD22 */
561         at91_set_a_periph(AT91_PIO_PORTA, 23, 0);       /* LCDD23 */
562
563         /* Enable clock */
564         at91_periph_clk_enable(ATMEL_ID_LCDC);
565 }
566
567 #ifdef CONFIG_LCD_INFO
568 void lcd_show_board_info(void)
569 {
570         ulong dram_size, nand_size;
571         int i;
572         char temp[32];
573
574         lcd_printf("2015 Ka-Ro electronics GmbH\n");
575         lcd_printf("%s CPU at %s MHz\n", get_cpu_name(),
576                    strmhz(temp, get_cpu_clk_rate()));
577
578         dram_size = 0;
579         for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
580                 dram_size += gd->bd->bi_dram[i].size;
581
582         nand_size = 0;
583 #ifdef CONFIG_NAND_ATMEL
584         for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
585                 nand_size += nand_info[i].size;
586 #endif
587         lcd_printf("%ld MB SDRAM, %ld MB NAND\n",
588                    dram_size >> 20, nand_size >> 20);
589 }
590 #endif /* CONFIG_LCD_INFO */
591
592 unsigned int has_lcdc(void)
593 {
594         int color_depth = 16;
595         const char *video_mode = karo_get_vmode(getenv("video_mode"));
596         const char *vm;
597         unsigned long val;
598         int refresh = 60;
599         struct fb_videomode *p = &txa5_fb_modes[0];
600         struct fb_videomode fb_mode;
601         int xres_set = 0, yres_set = 0, bpp_set = 0, refresh_set = 0;
602         int lcd_bus_width;
603
604         if (!lcd_enabled) {
605                 debug("LCD disabled\n");
606                 return 0;
607         }
608
609         if (had_ctrlc() || wdreset) {
610                 debug("Disabling LCD\n");
611                 lcd_enabled = 0;
612                 setenv("splashimage", NULL);
613                 return 0;
614         }
615
616         karo_fdt_move_fdt();
617
618         if (video_mode == NULL) {
619                 debug("Disabling LCD\n");
620                 lcd_enabled = 0;
621                 return 0;
622         }
623
624         lcd_bl_polarity = karo_fdt_get_backlight_polarity(working_fdt);
625         vm = video_mode;
626         if (karo_fdt_get_fb_mode(working_fdt, video_mode, &fb_mode) == 0) {
627                 p = &fb_mode;
628                 debug("Using video mode from FDT\n");
629                 vm += strlen(vm);
630                 if (fb_mode.xres > panel_info.vl_col ||
631                         fb_mode.yres > panel_info.vl_row) {
632                         printf("video resolution from DT: %dx%d exceeds hardware limits: %dx%d\n",
633                                 fb_mode.xres, fb_mode.yres,
634                                 panel_info.vl_col, panel_info.vl_row);
635                         lcd_enabled = 0;
636                         return 0;
637                 }
638         }
639         if (p->name != NULL)
640                 debug("Trying compiled-in video modes\n");
641         while (p->name != NULL) {
642                 if (strcmp(p->name, vm) == 0) {
643                         debug("Using video mode: '%s'\n", p->name);
644                         vm += strlen(vm);
645                         break;
646                 }
647                 p++;
648         }
649         if (*vm != '\0')
650                 debug("Trying to decode video_mode: '%s'\n", vm);
651         while (*vm != '\0') {
652                 if (*vm >= '0' && *vm <= '9') {
653                         char *end;
654
655                         val = simple_strtoul(vm, &end, 0);
656                         if (end > vm) {
657                                 if (!xres_set) {
658                                         if (val > panel_info.vl_col)
659                                                 val = panel_info.vl_col;
660                                         p->xres = val;
661                                         panel_info.vl_col = val;
662                                         xres_set = 1;
663                                 } else if (!yres_set) {
664                                         if (val > panel_info.vl_row)
665                                                 val = panel_info.vl_row;
666                                         p->yres = val;
667                                         panel_info.vl_row = val;
668                                         yres_set = 1;
669                                 } else if (!bpp_set) {
670                                         switch (val) {
671                                         case 16:
672                                                 color_depth = val;
673                                                 break;
674
675                                         default:
676                                                 printf("Invalid color depth: '%.*s' in video_mode; using default: '%u'\n",
677                                                         end - vm, vm, color_depth);
678                                         }
679                                         bpp_set = 1;
680                                 } else if (!refresh_set) {
681                                         refresh = val;
682                                         refresh_set = 1;
683                                 }
684                         }
685                         vm = end;
686                 }
687                 switch (*vm) {
688                 case '@':
689                         bpp_set = 1;
690                         /* fallthru */
691                 case '-':
692                         yres_set = 1;
693                         /* fallthru */
694                 case 'x':
695                         xres_set = 1;
696                         /* fallthru */
697                 case 'M':
698                 case 'R':
699                         vm++;
700                         break;
701
702                 default:
703                         if (*vm != '\0')
704                                 vm++;
705                 }
706         }
707         if (p->xres == 0 || p->yres == 0) {
708                 printf("Invalid video mode: %s\n", getenv("video_mode"));
709                 lcd_enabled = 0;
710                 printf("Supported video modes are:");
711                 for (p = &txa5_fb_modes[0]; p->name != NULL; p++) {
712                         printf(" %s", p->name);
713                 }
714                 printf("\n");
715                 return 0;
716         }
717         if (p->xres > panel_info.vl_col || p->yres > panel_info.vl_row) {
718                 printf("video resolution: %dx%d exceeds hardware limits: %dx%d\n",
719                         p->xres, p->yres, panel_info.vl_col, panel_info.vl_row);
720                 lcd_enabled = 0;
721                 return 0;
722         }
723         panel_info.vl_col = p->xres;
724         panel_info.vl_row = p->yres;
725
726         p->pixclock = KHZ2PICOS(refresh *
727                         (p->xres + p->left_margin + p->right_margin + p->hsync_len) *
728                         (p->yres + p->upper_margin + p->lower_margin + p->vsync_len) /
729                         1000);
730         debug("Pixel clock set to %lu.%03lu MHz\n",
731                 PICOS2KHZ(p->pixclock) / 1000, PICOS2KHZ(p->pixclock) % 1000);
732
733         if (p != &fb_mode) {
734                 int ret;
735
736                 debug("Creating new display-timing node from '%s'\n",
737                         video_mode);
738                 ret = karo_fdt_create_fb_mode(working_fdt, video_mode, p);
739                 if (ret)
740                         printf("Failed to create new display-timing node from '%s': %d\n",
741                                 video_mode, ret);
742         }
743
744         txa5_lcd_hw_init();
745
746         lcd_bus_width = karo_fdt_get_lcd_bus_width(working_fdt, 24);
747         switch (lcd_bus_width) {
748         case 16:
749         case 18:
750         case 24:
751                 lcd_output_bpp = lcd_bus_width;
752                 break;
753
754         default:
755                 lcd_enabled = 0;
756                 printf("Invalid LCD bus width: %d\n", lcd_bus_width);
757                 return 0;
758         }
759         if (karo_load_splashimage(0) == 0) {
760                 debug("Initializing FB driver\n");
761                 txa5_lcd_panel_setup(p);
762                 return 1;
763         } else {
764                 debug("Skipping initialization of LCD controller\n");
765                 return 0;
766         }
767 }
768 #else
769 #define lcd_enabled 0
770 #endif /* CONFIG_LCD */
771
772 static void stk5_board_init(void)
773 {
774 #if 0
775         gpio_request_array(stk5_gpios, ARRAY_SIZE(stk5_gpios));
776         txa5_set_pin_mux(stk5_pads, ARRAY_SIZE(stk5_pads));
777 #endif
778 }
779
780 static void stk5v3_board_init(void)
781 {
782         stk5_board_init();
783 }
784
785 static void stk5v5_board_init(void)
786 {
787         stk5_board_init();
788
789 #if 0
790         gpio_request_array(stk5v5_gpios, ARRAY_SIZE(stk5v5_gpios));
791         txa5_set_pin_mux(stk5v5_pads, ARRAY_SIZE(stk5v5_pads));
792 #endif
793 }
794
795 /* called with environment from NAND or MMC */
796 int board_late_init(void)
797 {
798         int ret = 0;
799         const char *baseboard;
800
801         env_cleanup();
802
803 //      txa5_set_cpu_clock();
804
805         if (had_ctrlc())
806                 setenv_ulong("safeboot", 1);
807 #if 0
808         else if (prm_rstst & PRM_RSTST_WDT1_RST)
809                 setenv_ulong("wdreset", 1);
810 #endif
811         else
812                 karo_fdt_move_fdt();
813
814         baseboard = getenv("baseboard");
815         if (!baseboard)
816                 goto exit;
817
818         if (strncmp(baseboard, "stk5", 4) == 0) {
819                 printf("Baseboard: %s\n", baseboard);
820                 if ((strlen(baseboard) == 4) ||
821                         strcmp(baseboard, "stk5-v3") == 0) {
822                         stk5v3_board_init();
823                 } else if (strcmp(baseboard, "stk5-v5") == 0) {
824                         stk5v5_board_init();
825                 } else {
826                         printf("WARNING: Unsupported STK5 board rev.: %s\n",
827                                 baseboard + 4);
828                 }
829         } else {
830                 printf("WARNING: Unsupported baseboard: '%s'\n",
831                         baseboard);
832                 ret = -EINVAL;
833         }
834
835 exit:
836         txa5_init_mac();
837         clear_ctrlc();
838         return ret;
839 }
840
841 #if defined(CONFIG_OF_BOARD_SETUP)
842 #ifdef CONFIG_FDT_FIXUP_PARTITIONS
843 #include <jffs2/jffs2.h>
844 #include <mtd_node.h>
845 static struct node_info nodes[] = {
846         { "atmel,sama5d4-nand", MTD_DEV_TYPE_NAND, },
847 };
848 #else
849 #define fdt_fixup_mtdparts(b,n,c) do { } while (0)
850 #endif
851
852 static const char *txa5_touchpanels[] = {
853         "ti,tsc2007",
854         "edt,edt-ft5x06",
855         "eeti,egalax_ts",
856 };
857
858 int ft_board_setup(void *blob, bd_t *bd)
859 {
860         const char *baseboard = getenv("baseboard");
861         int stk5_v5 = baseboard != NULL && (strcmp(baseboard, "stk5-v5") == 0);
862         const char *video_mode = karo_get_vmode(getenv("video_mode"));
863         int ret;
864
865         ret = fdt_increase_size(blob, 4096);
866         if (ret) {
867                 printf("Failed to increase FDT size: %s\n", fdt_strerror(ret));
868                 return ret;
869         }
870         if (stk5_v5)
871                 karo_fdt_enable_node(blob, "stk5led", 0);
872
873         fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
874
875         karo_fdt_fixup_touchpanel(blob, txa5_touchpanels,
876                                 ARRAY_SIZE(txa5_touchpanels));
877 //      karo_fdt_fixup_usb_otg(blob, "usbotg", "fsl,usbphy", "vbus-supply");
878 //      karo_fdt_fixup_flexcan(blob, stk5_v5);
879         karo_fdt_update_fb_mode(blob, video_mode);
880
881         return 0;
882 }
883 #endif /* CONFIG_OF_BOARD_SETUP */