]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - board/a4m072/a4m072.c
Merge branch 'elf_reloc'
[karo-tx-uboot.git] / board / a4m072 / a4m072.c
1 /*
2  * (C) Copyright 2003
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2004
6  * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com.
7  *
8  * (C) Copyright 2010
9  * Sergei Poselenov, Emcraft Systems, sposelenov@emcraft.com.
10  *
11  * See file CREDITS for list of people who contributed to this
12  * project.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2 of
17  * the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27  * MA 02111-1307 USA
28  */
29
30 #include <common.h>
31 #include <mpc5xxx.h>
32 #include <pci.h>
33 #include <asm/processor.h>
34 #include <asm/io.h>
35 #include <libfdt.h>
36 #include <netdev.h>
37 #include <led-display.h>
38 #include <linux/err.h>
39
40 #include "mt46v32m16.h"
41
42 #ifndef CONFIG_SYS_RAMBOOT
43 static void sdram_start (int hi_addr)
44 {
45         long hi_addr_bit = hi_addr ? 0x01000000 : 0;
46         long control = SDRAM_CONTROL | hi_addr_bit;
47
48         /* unlock mode register */
49         out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000000);
50         __asm__ volatile ("sync");
51
52         /* precharge all banks */
53         out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000002);
54         __asm__ volatile ("sync");
55
56 #if SDRAM_DDR
57         /* set mode register: extended mode */
58         out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_EMODE);
59         __asm__ volatile ("sync");
60
61         /* set mode register: reset DLL */
62         out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_MODE | 0x04000000);
63         __asm__ volatile ("sync");
64 #endif
65
66         /* precharge all banks */
67         out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000002);
68         __asm__ volatile ("sync");
69
70         /* auto refresh */
71         out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000004);
72         __asm__ volatile ("sync");
73
74         /* set mode register */
75         out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_MODE);
76         __asm__ volatile ("sync");
77
78         /* normal operation */
79         out_be32((void *)MPC5XXX_SDRAM_CTRL, control);
80         __asm__ volatile ("sync");
81 }
82 #endif
83
84 /*
85  * ATTENTION: Although partially referenced initdram does NOT make real use
86  *            use of CONFIG_SYS_SDRAM_BASE. The code does not work if CONFIG_SYS_SDRAM_BASE
87  *            is something else than 0x00000000.
88  */
89
90 phys_size_t initdram (int board_type)
91 {
92         ulong dramsize = 0;
93         uint svr, pvr;
94
95 #ifndef CONFIG_SYS_RAMBOOT
96         ulong test1, test2;
97
98         /* setup SDRAM chip selects */
99         out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0x0000001e); /* 2GB at 0x0 */
100         out_be32((void *)MPC5XXX_SDRAM_CS1CFG, 0x80000000); /* disabled */
101         __asm__ volatile ("sync");
102
103         /* setup config registers */
104         out_be32((void *)MPC5XXX_SDRAM_CONFIG1, SDRAM_CONFIG1);
105         out_be32((void *)MPC5XXX_SDRAM_CONFIG2, SDRAM_CONFIG2);
106         __asm__ volatile ("sync");
107
108 #if SDRAM_DDR
109         /* set tap delay */
110         out_be32((void *)MPC5XXX_CDM_PORCFG, SDRAM_TAPDELAY);
111         __asm__ volatile ("sync");
112 #endif
113
114         /* find RAM size using SDRAM CS0 only */
115         sdram_start(0);
116         test1 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x80000000);
117         sdram_start(1);
118         test2 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x80000000);
119         if (test1 > test2) {
120                 sdram_start(0);
121                 dramsize = test1;
122         } else {
123                 dramsize = test2;
124         }
125
126         /* memory smaller than 1MB is impossible */
127         if (dramsize < (1 << 20)) {
128                 dramsize = 0;
129         }
130
131         /* set SDRAM CS0 size according to the amount of RAM found */
132         if (dramsize > 0) {
133                 out_be32((void *)MPC5XXX_SDRAM_CS0CFG,
134                                  0x13 + __builtin_ffs(dramsize >> 20) - 1);
135         } else {
136                 out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0); /* disabled */
137         }
138
139 #else /* CONFIG_SYS_RAMBOOT */
140
141         /* retrieve size of memory connected to SDRAM CS0 */
142         dramsize = in_be32((void *)MPC5XXX_SDRAM_CS0CFG) & 0xFF;
143         if (dramsize >= 0x13) {
144                 dramsize = (1 << (dramsize - 0x13)) << 20;
145         } else {
146                 dramsize = 0;
147         }
148
149 #endif /* CONFIG_SYS_RAMBOOT */
150
151         /*
152          * On MPC5200B we need to set the special configuration delay in the
153          * DDR controller. Please refer to Freescale's AN3221 "MPC5200B SDRAM
154          * Initialization and Configuration", 3.3.1 SDelay--MBAR + 0x0190:
155          *
156          * "The SDelay should be written to a value of 0x00000004. It is
157          * required to account for changes caused by normal wafer processing
158          * parameters."
159          */
160         svr = get_svr();
161         pvr = get_pvr();
162         if ((SVR_MJREV(svr) >= 2) &&
163             (PVR_MAJ(pvr) == 1) && (PVR_MIN(pvr) == 4)) {
164
165                 out_be32((void *)MPC5XXX_SDRAM_SDELAY, 0x04);
166                 __asm__ volatile ("sync");
167         }
168
169         return dramsize;
170 }
171
172 int checkboard (void)
173 {
174         puts ("Board: A4M072\n");
175         return 0;
176 }
177
178 #ifdef  CONFIG_PCI
179 static struct pci_controller hose;
180
181 extern void pci_mpc5xxx_init(struct pci_controller *);
182
183 void pci_init_board(void)
184 {
185         pci_mpc5xxx_init(&hose);
186 }
187 #endif
188
189 #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
190 void
191 ft_board_setup(void *blob, bd_t *bd)
192 {
193         ft_cpu_setup(blob, bd);
194 }
195 #endif
196
197 int board_eth_init(bd_t *bis)
198 {
199         int rv, num_if = 0;
200
201         /* Initialize TSECs first */
202         if ((rv = cpu_eth_init(bis)) >= 0)
203                 num_if += rv;
204         else
205                 printf("ERROR: failed to initialize FEC.\n");
206
207         if ((rv = pci_eth_init(bis)) >= 0)
208                 num_if += rv;
209         else
210                 printf("ERROR: failed to initialize PCI Ethernet.\n");
211
212         return num_if;
213 }
214 /*
215  * Miscellaneous late-boot configurations
216  *
217  * Initialize EEPROM write-protect GPIO pin.
218  */
219 int misc_init_r(void)
220 {
221 #if defined(CONFIG_SYS_EEPROM_WREN)
222         /* Enable GPIO pin */
223         setbits_be32((void *)MPC5XXX_WU_GPIO_ENABLE, CONFIG_SYS_EEPROM_WP);
224         /* Set direction, output */
225         setbits_be32((void *)MPC5XXX_WU_GPIO_DIR, CONFIG_SYS_EEPROM_WP);
226         /* De-assert write enable */
227         setbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, CONFIG_SYS_EEPROM_WP);
228 #endif
229         return 0;
230 }
231 #if defined(CONFIG_SYS_EEPROM_WREN)
232 /* Input: <dev_addr>  I2C address of EEPROM device to enable.
233  *         <state>     -1: deliver current state
234  *                     0: disable write
235  *                     1: enable write
236  *  Returns:           -1: wrong device address
237  *                      0: dis-/en- able done
238  *                   0/1: current state if <state> was -1.
239  */
240 int eeprom_write_enable (unsigned dev_addr, int state)
241 {
242         if (CONFIG_SYS_I2C_EEPROM_ADDR != dev_addr) {
243                 return -1;
244         } else {
245                 switch (state) {
246                 case 1:
247                         /* Enable write access */
248                         clrbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, CONFIG_SYS_EEPROM_WP);
249                         state = 0;
250                         break;
251                 case 0:
252                         /* Disable write access */
253                         setbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, CONFIG_SYS_EEPROM_WP);
254                         state = 0;
255                         break;
256                 default:
257                         /* Read current status back. */
258                         state = (0 == (in_be32((void *)MPC5XXX_WU_GPIO_DATA_O) &
259                                                    CONFIG_SYS_EEPROM_WP));
260                         break;
261                 }
262         }
263         return state;
264 }
265 #endif
266
267 #ifdef CONFIG_CMD_DISPLAY
268 #define DISPLAY_BUF_SIZE        2
269 static u8 display_buf[DISPLAY_BUF_SIZE];
270 static u8 display_putc_pos;
271 static u8 display_out_pos;
272
273 static u8 display_dot_enable;
274
275 void display_set(int cmd) {
276
277         if (cmd & DISPLAY_CLEAR) {
278                 display_buf[0] = display_buf[1] = 0;
279         }
280
281         if (cmd & DISPLAY_HOME) {
282                 display_putc_pos = 0;
283         }
284
285         if (cmd & DISPLAY_MARK) {
286                 display_dot_enable = 1;
287         } else {
288                 display_dot_enable = 0;
289         }
290 }
291
292 #define SEG_A    (1<<0)
293 #define SEG_B    (1<<1)
294 #define SEG_C    (1<<2)
295 #define SEG_D    (1<<3)
296 #define SEG_E    (1<<4)
297 #define SEG_F    (1<<5)
298 #define SEG_G    (1<<6)
299 #define SEG_P    (1<<7)
300 #define SEG__    0
301
302 /*
303  * +- A -+
304  * |     |
305  * F     B
306  * |     |
307  * +- G -+
308  * |     |
309  * E     C
310  * |     |
311  * +- D -+  P
312  *
313  * 0..9         index 0..9
314  * A..Z         index 10..35
315  * -            index 36
316  * _            index 37
317  */
318
319 #define SYMBOL_DASH             (36)
320 #define SYMBOL_UNDERLINE        (37)
321
322 static u8 display_char2seg7_tbl[]=
323 {
324         SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,          /* 0 */
325         SEG_B | SEG_C,                                          /* 1 */
326         SEG_A | SEG_B | SEG_D | SEG_E | SEG_G,                  /* 2 */
327         SEG_A | SEG_B | SEG_C | SEG_D | SEG_G,                  /* 3 */
328         SEG_B | SEG_C | SEG_F | SEG_G,                          /* 4 */
329         SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,                  /* 5 */
330         SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,          /* 6 */
331         SEG_A | SEG_B | SEG_C,                                  /* 7 */
332         SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,  /* 8 */
333         SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,          /* 9 */
334         SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,          /* A */
335         SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,                  /* b */
336         SEG_A | SEG_D | SEG_E | SEG_F,                          /* C */
337         SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,                  /* d */
338         SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,                  /* E */
339         SEG_A | SEG_E | SEG_F | SEG_G,                          /* F */
340         SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,          /* g */
341         SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,                  /* H */
342         SEG_E | SEG_F,                                          /* I */
343         SEG_B | SEG_C | SEG_D | SEG_E,                          /* J */
344         SEG_A,                                          /* K - special 1 */
345         SEG_D | SEG_E | SEG_F,                                  /* L */
346         SEG_B,                                          /* m - special 2 */
347         SEG_C | SEG_E | SEG_G,                                  /* n */
348         SEG_C | SEG_D | SEG_E | SEG_G,                          /* o */
349         SEG_A | SEG_B | SEG_E | SEG_F | SEG_G,                  /* P */
350         SEG_A | SEG_B | SEG_C | SEG_F | SEG_G,                  /* q */
351         SEG_E | SEG_G,                                          /* r */
352         SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,                  /* S */
353         SEG_D | SEG_E | SEG_F | SEG_G,                          /* t */
354         SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,                  /* U */
355         SEG_C | SEG_D | SEG_E | SEG_F,                          /* V */
356         SEG_C,                                          /* w - special 3 */
357         SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,                  /* X */
358         SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,                  /* Y */
359         SEG_A | SEG_B | SEG_D | SEG_E | SEG_G,                  /* Z */
360         SEG_G,                                                  /* - */
361         SEG_D                                                   /* _ */
362 };
363
364 /* Convert char to the LED segments representation */
365 static u8 display_char2seg7(char c)
366 {
367         u8 val = 0;
368
369         if (c >= '0' && c <= '9')
370                 c -= '0';
371         else if (c >= 'a' && c <= 'z')
372                 c -= 'a' - 10;
373         else if (c >= 'A' && c <= 'Z')
374                 c -= 'A' - 10;
375         else if (c == '-')
376                 c = SYMBOL_DASH;
377         else if ((c == '_') || (c == '.'))
378                 c = SYMBOL_UNDERLINE;
379         else
380                 c = ' ';        /* display unsupported symbols as space */
381
382         if (c != ' ')
383                 val = display_char2seg7_tbl[(int)c];
384
385         /* Handle DP LED here */
386         if (display_dot_enable) {
387                 val |= SEG_P;
388         }
389
390         return val;
391 }
392
393 static inline int display_putc_nomark(char c)
394 {
395         if (display_putc_pos >= DISPLAY_BUF_SIZE)
396                 return -1;
397
398         display_buf[display_putc_pos++] = display_char2seg7(c);
399         /* one-symbol message should be steady */
400         if (display_putc_pos == 1)
401                 display_buf[display_putc_pos] = display_char2seg7(c);
402
403         return c;
404 }
405
406 int display_putc(char c)
407 {
408         /* Mark the codes from the "display" command with the DP LED */
409         display_set(DISPLAY_MARK);
410         return display_putc_nomark(c);
411 }
412
413 /*
414  * Flush current symbol to the LED display hardware
415  */
416 static inline void display_flush(void)
417 {
418         u32 val = display_buf[display_out_pos];
419
420         val |= (val << 8) | (val << 16) | (val << 24);
421         out_be32((void *)CONFIG_SYS_DISP_CHR_RAM, val);
422 }
423
424 /*
425  * Output contents of the software display buffer to the LED display every 0.5s
426  */
427 void board_show_activity(ulong timestamp)
428 {
429         static ulong last;
430         static u8 once;
431
432         if (!once || (timestamp - last >= (CONFIG_SYS_HZ / 2))) {
433                 display_flush();
434                 display_out_pos ^= 1;
435                 last = timestamp;
436                 once = 1;
437         }
438 }
439
440 /*
441  * Empty fake function
442  */
443 void show_activity(int arg)
444 {
445 }
446 #endif
447 #if defined (CONFIG_SHOW_BOOT_PROGRESS)
448 static int a4m072_status2code(int status, char *buf)
449 {
450         char c = 0;
451
452         if (((status > 0) && (status <= 8)) ||
453                                 ((status >= 100) && (status <= 108)) ||
454                                 ((status < 0) && (status >= -9)) ||
455                                 (status == -100) || (status == -101) ||
456                                 ((status <= -103) && (status >= -113))) {
457                 c = '5';
458         } else if (((status >= 9) && (status <= 14)) ||
459                         ((status >= 120) && (status <= 123)) ||
460                         ((status >= 125) && (status <= 129)) ||
461                         ((status >= -13) && (status <= -10)) ||
462                         (status == -120) || (status == -122) ||
463                         ((status <= -124) && (status >= -127)) ||
464                         (status == -129)) {
465                 c = '8';
466         } else if (status == 15) {
467                 c = '9';
468         } else if ((status <= -30) && (status >= -32)) {
469                 c = 'A';
470         } else if (((status <= -35) && (status >= -40)) ||
471                         ((status <= -42) && (status >= -51)) ||
472                         ((status <= -53) && (status >= -58)) ||
473                         (status == -64) ||
474                         ((status <= -80) && (status >= -83)) ||
475                         (status == -130) || (status == -140) ||
476                         (status == -150)) {
477                 c = 'B';
478         }
479
480         if (c == 0)
481                 return -EINVAL;
482
483         buf[0] = (status < 0) ? '-' : c;
484         buf[1] = c;
485
486         return 0;
487 }
488
489 void show_boot_progress(int status)
490 {
491         char buf[2];
492
493         if (a4m072_status2code(status, buf) < 0)
494                 return;
495
496         display_set(0); /* Clear DP Led */
497         display_putc_nomark(buf[0]);
498         display_putc_nomark(buf[1]);
499         display_set(DISPLAY_HOME);
500         display_out_pos = 0;    /* reset output position */
501
502         /* we want to flush status 15 now */
503         if (status == 15)
504                 display_flush();
505 }
506 #endif