]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/a4m072/a4m072.c
a4m072: led display support
[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
39 #include "mt46v32m16.h"
40
41 #ifndef CONFIG_SYS_RAMBOOT
42 static void sdram_start (int hi_addr)
43 {
44         long hi_addr_bit = hi_addr ? 0x01000000 : 0;
45         long control = SDRAM_CONTROL | hi_addr_bit;
46
47         /* unlock mode register */
48         out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000000);
49         __asm__ volatile ("sync");
50
51         /* precharge all banks */
52         out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000002);
53         __asm__ volatile ("sync");
54
55 #if SDRAM_DDR
56         /* set mode register: extended mode */
57         out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_EMODE);
58         __asm__ volatile ("sync");
59
60         /* set mode register: reset DLL */
61         out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_MODE | 0x04000000);
62         __asm__ volatile ("sync");
63 #endif
64
65         /* precharge all banks */
66         out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000002);
67         __asm__ volatile ("sync");
68
69         /* auto refresh */
70         out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000004);
71         __asm__ volatile ("sync");
72
73         /* set mode register */
74         out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_MODE);
75         __asm__ volatile ("sync");
76
77         /* normal operation */
78         out_be32((void *)MPC5XXX_SDRAM_CTRL, control);
79         __asm__ volatile ("sync");
80 }
81 #endif
82
83 /*
84  * ATTENTION: Although partially referenced initdram does NOT make real use
85  *            use of CONFIG_SYS_SDRAM_BASE. The code does not work if CONFIG_SYS_SDRAM_BASE
86  *            is something else than 0x00000000.
87  */
88
89 phys_size_t initdram (int board_type)
90 {
91         ulong dramsize = 0;
92         uint svr, pvr;
93
94 #ifndef CONFIG_SYS_RAMBOOT
95         ulong test1, test2;
96
97         /* setup SDRAM chip selects */
98         out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0x0000001e); /* 2GB at 0x0 */
99         out_be32((void *)MPC5XXX_SDRAM_CS1CFG, 0x80000000); /* disabled */
100         __asm__ volatile ("sync");
101
102         /* setup config registers */
103         out_be32((void *)MPC5XXX_SDRAM_CONFIG1, SDRAM_CONFIG1);
104         out_be32((void *)MPC5XXX_SDRAM_CONFIG2, SDRAM_CONFIG2);
105         __asm__ volatile ("sync");
106
107 #if SDRAM_DDR
108         /* set tap delay */
109         out_be32((void *)MPC5XXX_CDM_PORCFG, SDRAM_TAPDELAY);
110         __asm__ volatile ("sync");
111 #endif
112
113         /* find RAM size using SDRAM CS0 only */
114         sdram_start(0);
115         test1 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x80000000);
116         sdram_start(1);
117         test2 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x80000000);
118         if (test1 > test2) {
119                 sdram_start(0);
120                 dramsize = test1;
121         } else {
122                 dramsize = test2;
123         }
124
125         /* memory smaller than 1MB is impossible */
126         if (dramsize < (1 << 20)) {
127                 dramsize = 0;
128         }
129
130         /* set SDRAM CS0 size according to the amount of RAM found */
131         if (dramsize > 0) {
132                 out_be32((void *)MPC5XXX_SDRAM_CS0CFG,
133                                  0x13 + __builtin_ffs(dramsize >> 20) - 1);
134         } else {
135                 out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0); /* disabled */
136         }
137
138 #else /* CONFIG_SYS_RAMBOOT */
139
140         /* retrieve size of memory connected to SDRAM CS0 */
141         dramsize = in_be32((void *)MPC5XXX_SDRAM_CS0CFG) & 0xFF;
142         if (dramsize >= 0x13) {
143                 dramsize = (1 << (dramsize - 0x13)) << 20;
144         } else {
145                 dramsize = 0;
146         }
147
148 #endif /* CONFIG_SYS_RAMBOOT */
149
150         /*
151          * On MPC5200B we need to set the special configuration delay in the
152          * DDR controller. Please refer to Freescale's AN3221 "MPC5200B SDRAM
153          * Initialization and Configuration", 3.3.1 SDelay--MBAR + 0x0190:
154          *
155          * "The SDelay should be written to a value of 0x00000004. It is
156          * required to account for changes caused by normal wafer processing
157          * parameters."
158          */
159         svr = get_svr();
160         pvr = get_pvr();
161         if ((SVR_MJREV(svr) >= 2) &&
162             (PVR_MAJ(pvr) == 1) && (PVR_MIN(pvr) == 4)) {
163
164                 out_be32((void *)MPC5XXX_SDRAM_SDELAY, 0x04);
165                 __asm__ volatile ("sync");
166         }
167
168         return dramsize;
169 }
170
171 int checkboard (void)
172 {
173         puts ("Board: A4M072\n");
174         return 0;
175 }
176
177 #ifdef  CONFIG_PCI
178 static struct pci_controller hose;
179
180 extern void pci_mpc5xxx_init(struct pci_controller *);
181
182 void pci_init_board(void)
183 {
184         pci_mpc5xxx_init(&hose);
185 }
186 #endif
187
188 #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
189 void
190 ft_board_setup(void *blob, bd_t *bd)
191 {
192         ft_cpu_setup(blob, bd);
193 }
194 #endif
195
196 int board_eth_init(bd_t *bis)
197 {
198         int rv, num_if = 0;
199
200         /* Initialize TSECs first */
201         if ((rv = cpu_eth_init(bis)) >= 0)
202                 num_if += rv;
203         else
204                 printf("ERROR: failed to initialize FEC.\n");
205
206         if ((rv = pci_eth_init(bis)) >= 0)
207                 num_if += rv;
208         else
209                 printf("ERROR: failed to initialize PCI Ethernet.\n");
210
211         return num_if;
212 }
213 /*
214  * Miscellaneous late-boot configurations
215  *
216  * Initialize EEPROM write-protect GPIO pin.
217  */
218 int misc_init_r(void)
219 {
220 #if defined(CONFIG_SYS_EEPROM_WREN)
221         /* Enable GPIO pin */
222         setbits_be32((void *)MPC5XXX_WU_GPIO_ENABLE, CONFIG_SYS_EEPROM_WP);
223         /* Set direction, output */
224         setbits_be32((void *)MPC5XXX_WU_GPIO_DIR, CONFIG_SYS_EEPROM_WP);
225         /* De-assert write enable */
226         setbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, CONFIG_SYS_EEPROM_WP);
227 #endif
228         return 0;
229 }
230 #if defined(CONFIG_SYS_EEPROM_WREN)
231 /* Input: <dev_addr>  I2C address of EEPROM device to enable.
232  *         <state>     -1: deliver current state
233  *                     0: disable write
234  *                     1: enable write
235  *  Returns:           -1: wrong device address
236  *                      0: dis-/en- able done
237  *                   0/1: current state if <state> was -1.
238  */
239 int eeprom_write_enable (unsigned dev_addr, int state)
240 {
241         if (CONFIG_SYS_I2C_EEPROM_ADDR != dev_addr) {
242                 return -1;
243         } else {
244                 switch (state) {
245                 case 1:
246                         /* Enable write access */
247                         clrbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, CONFIG_SYS_EEPROM_WP);
248                         state = 0;
249                         break;
250                 case 0:
251                         /* Disable write access */
252                         setbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, CONFIG_SYS_EEPROM_WP);
253                         state = 0;
254                         break;
255                 default:
256                         /* Read current status back. */
257                         state = (0 == (in_be32((void *)MPC5XXX_WU_GPIO_DATA_O) &
258                                                    CONFIG_SYS_EEPROM_WP));
259                         break;
260                 }
261         }
262         return state;
263 }
264 #endif
265
266 #ifdef CONFIG_CMD_DISPLAY
267 #define DISPLAY_BUF_SIZE        2
268 static u8 display_buf[DISPLAY_BUF_SIZE];
269 static u8 display_putc_pos;
270 static u8 display_out_pos;
271
272 static u8 display_dot_enable;
273
274 void display_set(int cmd) {
275
276         if (cmd & DISPLAY_CLEAR) {
277                 display_buf[0] = display_buf[1] = 0;
278         }
279
280         if (cmd & DISPLAY_HOME) {
281                 display_putc_pos = 0;
282         }
283
284         if (cmd & DISPLAY_MARK) {
285                 display_dot_enable = 1;
286         } else {
287                 display_dot_enable = 0;
288         }
289 }
290
291 #define SEG_A    (1<<0)
292 #define SEG_B    (1<<1)
293 #define SEG_C    (1<<2)
294 #define SEG_D    (1<<3)
295 #define SEG_E    (1<<4)
296 #define SEG_F    (1<<5)
297 #define SEG_G    (1<<6)
298 #define SEG_P    (1<<7)
299 #define SEG__    0
300
301 /*
302  * +- A -+
303  * |     |
304  * F     B
305  * |     |
306  * +- G -+
307  * |     |
308  * E     C
309  * |     |
310  * +- D -+  P
311  *
312  * 0..9         index 0..9
313  * A..Z         index 10..35
314  * -            index 36
315  * _            index 37
316  */
317
318 #define SYMBOL_DASH             (36)
319 #define SYMBOL_UNDERLINE        (37)
320
321 static u8 display_char2seg7_tbl[]=
322 {
323         SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,          /* 0 */
324         SEG_B | SEG_C,                                          /* 1 */
325         SEG_A | SEG_B | SEG_D | SEG_E | SEG_G,                  /* 2 */
326         SEG_A | SEG_B | SEG_C | SEG_D | SEG_G,                  /* 3 */
327         SEG_B | SEG_C | SEG_F | SEG_G,                          /* 4 */
328         SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,                  /* 5 */
329         SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,          /* 6 */
330         SEG_A | SEG_B | SEG_C,                                  /* 7 */
331         SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,  /* 8 */
332         SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,          /* 9 */
333         SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,          /* A */
334         SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,                  /* b */
335         SEG_A | SEG_D | SEG_E | SEG_F,                          /* C */
336         SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,                  /* d */
337         SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,                  /* E */
338         SEG_A | SEG_E | SEG_F | SEG_G,                          /* F */
339         SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,          /* g */
340         SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,                  /* H */
341         SEG_E | SEG_F,                                          /* I */
342         SEG_B | SEG_C | SEG_D | SEG_E,                          /* J */
343         SEG_A,                                          /* K - special 1 */
344         SEG_D | SEG_E | SEG_F,                                  /* L */
345         SEG_B,                                          /* m - special 2 */
346         SEG_C | SEG_E | SEG_G,                                  /* n */
347         SEG_C | SEG_D | SEG_E | SEG_G,                          /* o */
348         SEG_A | SEG_B | SEG_E | SEG_F | SEG_G,                  /* P */
349         SEG_A | SEG_B | SEG_C | SEG_F | SEG_G,                  /* q */
350         SEG_E | SEG_G,                                          /* r */
351         SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,                  /* S */
352         SEG_D | SEG_E | SEG_F | SEG_G,                          /* t */
353         SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,                  /* U */
354         SEG_C | SEG_D | SEG_E | SEG_F,                          /* V */
355         SEG_C,                                          /* w - special 3 */
356         SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,                  /* X */
357         SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,                  /* Y */
358         SEG_A | SEG_B | SEG_D | SEG_E | SEG_G,                  /* Z */
359         SEG_G,                                                  /* - */
360         SEG_D                                                   /* _ */
361 };
362
363 /* Convert char to the LED segments representation */
364 static u8 display_char2seg7(char c)
365 {
366         u8 val = 0;
367
368         if (c >= '0' && c <= '9')
369                 c -= '0';
370         else if (c >= 'a' && c <= 'z')
371                 c -= 'a' - 10;
372         else if (c >= 'A' && c <= 'Z')
373                 c -= 'A' - 10;
374         else if (c == '-')
375                 c = SYMBOL_DASH;
376         else if ((c == '_') || (c == '.'))
377                 c = SYMBOL_UNDERLINE;
378         else
379                 c = ' ';        /* display unsupported symbols as space */
380
381         if (c != ' ')
382                 val = display_char2seg7_tbl[(int)c];
383
384         /* Handle DP LED here */
385         if (display_dot_enable) {
386                 val |= SEG_P;
387         }
388
389         return val;
390 }
391
392 static inline int display_putc_nomark(char c)
393 {
394         if (display_putc_pos >= DISPLAY_BUF_SIZE)
395                 return -1;
396
397         display_buf[display_putc_pos++] = display_char2seg7(c);
398         /* one-symbol message should be steady */
399         if (display_putc_pos == 1)
400                 display_buf[display_putc_pos] = display_char2seg7(c);
401
402         return c;
403 }
404
405 int display_putc(char c)
406 {
407         /* Mark the codes from the "display" command with the DP LED */
408         display_set(DISPLAY_MARK);
409         return display_putc_nomark(c);
410 }
411
412 /*
413  * Output content of the software display buffer to the LED display every 0.5s
414  */
415 void board_show_activity(ulong timestamp)
416 {
417         static ulong last;
418         static u8 once;
419         u32 val;
420
421         if (!once || (timestamp - last >= (CONFIG_SYS_HZ / 2))) {
422                 val = display_buf[display_out_pos];
423                 val |= (val << 8) | (val << 16) | (val << 24);
424                 out_be32((void *)CONFIG_SYS_DISP_CHR_RAM, val);
425                 display_out_pos ^= 1;
426                 last = timestamp;
427                 once = 1;
428         }
429 }
430
431 /*
432  * Empty fake function
433  */
434 void show_activity(int arg)
435 {
436 }
437 #endif