Fix memory detection and hcd compilation, thanks Gabor ! (closes #1813)
[openwrt/openwrt.git] / target / linux / adm5120-2.6 / files / arch / mips / adm5120 / adm5120_info.c
1 /*
2 * $Id$
3 *
4 * Copyright (C) 2007 OpenWrt.org
5 * Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13 #include <linux/types.h>
14 #include <linux/autoconf.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/string.h>
18
19 #include <asm/bootinfo.h>
20 #include <asm/addrspace.h>
21
22 #include <asm/mach-adm5120/adm5120_defs.h>
23 #include <asm/mach-adm5120/adm5120_switch.h>
24 #include <asm/mach-adm5120/adm5120_info.h>
25 #include <asm/mach-adm5120/myloader.h>
26 #include <asm/mach-adm5120/routerboot.h>
27 #include <asm/mach-adm5120/zynos.h>
28
29 /*
30 * Globals
31 */
32 struct adm5120_board adm5120_board;
33 unsigned int adm5120_boot_loader;
34
35 unsigned int adm5120_product_code;
36 unsigned int adm5120_revision;
37 unsigned int adm5120_package;
38 unsigned int adm5120_nand_boot;
39 unsigned long adm5120_speed;
40 unsigned long adm5120_memsize;
41
42 /*
43 * Locals
44 */
45 static char *boot_loader_names[BOOT_LOADER_LAST+1] = {
46 [BOOT_LOADER_UNKNOWN] = "Unknown",
47 [BOOT_LOADER_CFE] = "CFE",
48 [BOOT_LOADER_UBOOT] = "U-Boot",
49 [BOOT_LOADER_MYLOADER] = "MyLoader",
50 [BOOT_LOADER_ROUTERBOOT]= "RouterBOOT",
51 [BOOT_LOADER_BOOTBASE] = "Bootbase"
52 };
53
54 static struct adm5120_board __initdata adm5120_boards[] = {
55 {
56 .name = "Compex NetPassage 27G",
57 .mach_type = MACH_ADM5120_NP27G,
58 .has_usb = 1,
59 .iface_num = 5,
60 .flash0_size = 4*1024*1024,
61 },
62 {
63 .name = "Compex NetPassage 28G",
64 .mach_type = MACH_ADM5120_NP28G,
65 .has_usb = 0,
66 .iface_num = 4,
67 .flash0_size = 4*1024*1024,
68 },
69 {
70 .name = "Compex NP28G (HotSpot)",
71 .mach_type = MACH_ADM5120_NP28GHS,
72 .has_usb = 0,
73 .iface_num = 4,
74 .flash0_size = 4*1024*1024,
75 },
76 {
77 .name = "Compex WP54AG",
78 .mach_type = MACH_ADM5120_WP54AG,
79 .has_usb = 0,
80 .iface_num = 2,
81 .flash0_size = 4*1024*1024,
82 },
83 {
84 .name = "Compex WP54G",
85 .mach_type = MACH_ADM5120_WP54G,
86 .has_usb = 0,
87 .iface_num = 2,
88 .flash0_size = 4*1024*1024,
89 },
90 {
91 .name = "Compex WP54G-WRT",
92 .mach_type = MACH_ADM5120_WP54G_WRT,
93 .has_usb = 0,
94 .iface_num = 2,
95 .flash0_size = 4*1024*1024,
96 },
97 {
98 .name = "Compex WP54G v1C",
99 .mach_type = MACH_ADM5120_WP54Gv1C,
100 .has_usb = 0,
101 .iface_num = 2,
102 .flash0_size = 2*1024*1024,
103 },
104 {
105 .name = "Compex WPP54AG",
106 .mach_type = MACH_ADM5120_WPP54AG,
107 .has_usb = 0,
108 .iface_num = 2,
109 .flash0_size = 4*1024*1024,
110 },
111 {
112 .name = "Compex WPP54G",
113 .mach_type = MACH_ADM5120_WPP54G,
114 .has_usb = 0,
115 .iface_num = 2,
116 .flash0_size = 4*1024*1024,
117 },
118 {
119 .name = "RouterBOARD 111",
120 .mach_type = MACH_ADM5120_RB_111,
121 .has_usb = 0,
122 .iface_num = 1,
123 .flash0_size = 128*1024,
124 },
125 {
126 .name = "RouterBOARD 112",
127 .mach_type = MACH_ADM5120_RB_112,
128 .has_usb = 0,
129 .iface_num = 1,
130 .flash0_size = 128*1024,
131 },
132 {
133 .name = "RouterBOARD 133",
134 .mach_type = MACH_ADM5120_RB_133,
135 .has_usb = 0,
136 .iface_num = 3,
137 .flash0_size = 128*1024,
138 },
139 {
140 .name = "RouterBOARD 133C",
141 .mach_type = MACH_ADM5120_RB_133C,
142 .has_usb = 0,
143 .iface_num = 1,
144 .flash0_size = 128*1024,
145 },
146 {
147 .name = "RouterBOARD 150",
148 .mach_type = MACH_ADM5120_RB_150,
149 .has_usb = 0,
150 .iface_num = 5,
151 .flash0_size = 128*1024,
152 },
153 {
154 .name = "RouterBOARD 153",
155 .mach_type = MACH_ADM5120_RB_153,
156 .has_usb = 0,
157 .iface_num = 5,
158 .flash0_size = 128*1024,
159 },
160 {
161 .name = "ZyXEL ES-2108",
162 .mach_type = MACH_ADM5120_ES2108,
163 .has_usb = 0,
164 .iface_num = 0,
165 .flash0_size = 4*1024*1024,
166 },
167 {
168 .name = "ZyXEL ES-2108-F",
169 .mach_type = MACH_ADM5120_ES2108F,
170 .has_usb = 0,
171 .iface_num = 0,
172 .flash0_size = 4*1024*1024,
173 },
174 {
175 .name = "ZyXEL ES-2108-G",
176 .mach_type = MACH_ADM5120_ES2108G,
177 .has_usb = 0,
178 .iface_num = 0,
179 .flash0_size = 4*1024*1024,
180 },
181 {
182 .name = "ZyXEL ES-2108-LC",
183 .mach_type = MACH_ADM5120_ES2108LC,
184 .has_usb = 0,
185 .iface_num = 0,
186 .flash0_size = 4*1024*1024,
187 },
188 {
189 .name = "ZyXEL ES-2108PWR",
190 .mach_type = MACH_ADM5120_ES2108PWR,
191 .has_usb = 0,
192 .iface_num = 0,
193 .flash0_size = 4*1024*1024,
194 },
195 {
196 .name = "ZyXEL HomeSafe 100/100W",
197 .mach_type = MACH_ADM5120_HS100,
198 .has_usb = 0,
199 .iface_num = 5,
200 .flash0_size = 4*1024*1024,
201 },
202 {
203 .name = "ZyXEL Prestige 334",
204 .mach_type = MACH_ADM5120_P334,
205 .has_usb = 0,
206 .iface_num = 5,
207 .flash0_size = 2*1024*1024,
208 },
209 {
210 .name = "ZyXEL Prestige 334U",
211 .mach_type = MACH_ADM5120_P334U,
212 .has_usb = 0,
213 .iface_num = 5,
214 .flash0_size = 4*1024*1024,
215 },
216 {
217 .name = "ZyXEL Prestige 334W",
218 .mach_type = MACH_ADM5120_P334W,
219 .has_usb = 0,
220 .iface_num = 5,
221 .flash0_size = 2*1024*1024,
222 },
223 {
224 .name = "ZyXEL Prestige 334WH",
225 .mach_type = MACH_ADM5120_P334WH,
226 .has_usb = 0,
227 .iface_num = 5,
228 .flash0_size = 4*1024*1024,
229 },
230 {
231 .name = "ZyXEL Prestige 334WHD",
232 .mach_type = MACH_ADM5120_P334WHD,
233 .has_usb = 0,
234 .iface_num = 5,
235 .flash0_size = 4*1024*1024,
236 },
237 {
238 .name = "ZyXEL Prestige 334WT",
239 .mach_type = MACH_ADM5120_P334WT,
240 .has_usb = 1,
241 .iface_num = 5,
242 .flash0_size = 4*1024*1024,
243 },
244 {
245 .name = "ZyXEL Prestige 335/335WT",
246 .mach_type = MACH_ADM5120_P335,
247 .has_usb = 1,
248 .iface_num = 5,
249 .flash0_size = 4*1024*1024,
250 },
251 {
252 .name = "ZyXEL Prestige 335Plus",
253 .mach_type = MACH_ADM5120_P335PLUS,
254 .has_usb = 1,
255 .iface_num = 5,
256 .flash0_size = 4*1024*1024,
257 },
258 {
259 .name = "ZyXEL Prestige 335U",
260 .mach_type = MACH_ADM5120_P335U,
261 .has_usb = 1,
262 .iface_num = 5,
263 .flash0_size = 4*1024*1024,
264 },
265 {
266 .name = "Unknown ADM5120 board",
267 .mach_type = MACH_ADM5120_UNKNOWN,
268 .has_usb = 1,
269 .iface_num = 5,
270 .flash0_size = 4*1024*1024,
271 }
272 };
273
274 #define DUMMY_BOARD() {.mach_type = MACH_ADM5120_UNKNOWN}
275
276 struct mylo_board {
277 u16 vid;
278 u16 did;
279 u16 svid;
280 u16 sdid;
281 unsigned long mach_type;
282 };
283
284
285 #define MYLO_BOARD(v,d,sv,sd,mt) { .vid = (v), .did = (d), .svid = (sv), \
286 .sdid = (sd), .mach_type = (mt) }
287
288 #define COMPEX_BOARD(d,mt) MYLO_BOARD(VENID_COMPEX,(d),VENID_COMPEX,(d),(mt))
289
290 static struct mylo_board __initdata mylo_boards[] = {
291 COMPEX_BOARD(DEVID_COMPEX_NP27G, MACH_ADM5120_NP27G),
292 COMPEX_BOARD(DEVID_COMPEX_NP28G, MACH_ADM5120_NP28G),
293 COMPEX_BOARD(DEVID_COMPEX_NP28GHS, MACH_ADM5120_NP28GHS),
294 COMPEX_BOARD(DEVID_COMPEX_WP54G, MACH_ADM5120_WP54G),
295 COMPEX_BOARD(DEVID_COMPEX_WP54Gv1C, MACH_ADM5120_WP54Gv1C),
296 COMPEX_BOARD(DEVID_COMPEX_WP54AG, MACH_ADM5120_WP54AG),
297 COMPEX_BOARD(DEVID_COMPEX_WPP54G, MACH_ADM5120_WPP54G),
298 COMPEX_BOARD(DEVID_COMPEX_WPP54AG, MACH_ADM5120_WPP54AG),
299 DUMMY_BOARD()
300 };
301
302 #define ROUTERBOARD_NAME_LEN 16
303
304 struct routerboard {
305 unsigned long mach_type;
306 char name[ROUTERBOARD_NAME_LEN];
307 };
308
309 #define ROUTERBOARD(n, mt) { .name = (n), .mach_type = (mt) }
310 static struct routerboard __initdata routerboards[] = {
311 ROUTERBOARD("111", MACH_ADM5120_RB_111),
312 ROUTERBOARD("112", MACH_ADM5120_RB_112),
313 ROUTERBOARD("133", MACH_ADM5120_RB_133),
314 ROUTERBOARD("133C", MACH_ADM5120_RB_133C),
315 ROUTERBOARD("miniROUTER", MACH_ADM5120_RB_150),
316 ROUTERBOARD("153", MACH_ADM5120_RB_150),
317 DUMMY_BOARD()
318 };
319
320 struct zynos_board {
321 unsigned long mach_type;
322 unsigned int vendor_id;
323 u16 board_id;
324 };
325
326 #define ZYNOS_BOARD(vi, bi, mt) { .vendor_id = (vi), .board_id = (bi), \
327 .mach_type = (mt) }
328
329 #define ZYXEL_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_ZYXEL, bi, mt)
330 #define DLINK_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_DLINK, bi, mt)
331 #define LUCENT_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_LUCENT, bi, mt)
332
333 static struct zynos_board __initdata zynos_boards[] = {
334 ZYXEL_BOARD(ZYNOS_BOARD_HS100, MACH_ADM5120_HS100),
335 ZYXEL_BOARD(ZYNOS_BOARD_P334, MACH_ADM5120_P334),
336 ZYXEL_BOARD(ZYNOS_BOARD_P334U, MACH_ADM5120_P334U),
337 ZYXEL_BOARD(ZYNOS_BOARD_P334W, MACH_ADM5120_P334W),
338 ZYXEL_BOARD(ZYNOS_BOARD_P334WH, MACH_ADM5120_P334WH),
339 ZYXEL_BOARD(ZYNOS_BOARD_P334WHD, MACH_ADM5120_P334WHD),
340 ZYXEL_BOARD(ZYNOS_BOARD_P334WT, MACH_ADM5120_P334WT),
341 ZYXEL_BOARD(ZYNOS_BOARD_P335, MACH_ADM5120_P335),
342 ZYXEL_BOARD(ZYNOS_BOARD_P335PLUS, MACH_ADM5120_P335PLUS),
343 ZYXEL_BOARD(ZYNOS_BOARD_P335U, MACH_ADM5120_P335U),
344 DUMMY_BOARD()
345 };
346
347 /*
348 * Helper routines
349 */
350 static inline u16 read_le16(void *buf)
351 {
352 u8 *p;
353
354 p = buf;
355 return ((u16)p[0] + ((u16)p[1] << 8));
356 }
357
358 static inline u32 read_le32(void *buf)
359 {
360 u8 *p;
361
362 p = buf;
363 return ((u32)p[0] + ((u32)p[1] << 8) + ((u32)p[2] << 16) +
364 ((u32)p[3] << 24));
365 }
366
367 static inline u16 read_be16(void *buf)
368 {
369 u8 *p;
370
371 p = buf;
372 return (((u16)p[0] << 8) + (u16)p[1]);
373 }
374
375 static inline u32 read_be32(void *buf)
376 {
377 u8 *p;
378
379 p = buf;
380 return (((u32)p[0] << 24) + ((u32)p[1] << 16) + ((u32)p[2] << 8) +
381 ((u32)p[3]));
382 }
383
384 /*
385 * CFE based boards
386 */
387 #define CFE_EPTSEAL 0x43464531 /* CFE1 is the magic number to recognize CFE
388 from other bootloaders */
389
390 static int __init cfe_present(void)
391 {
392 /*
393 * This method only works, when we are booted directly from the CFE.
394 */
395 u32 cfe_handle = (u32) fw_arg0;
396 u32 cfe_a1_val = (u32) fw_arg1;
397 u32 cfe_entry = (u32) fw_arg2;
398 u32 cfe_seal = (u32) fw_arg3;
399
400 /* Check for CFE by finding the CFE magic number */
401 if (cfe_seal != CFE_EPTSEAL) {
402 /* We are not booted from CFE */
403 return 0;
404 }
405
406 /* cfe_a1_val must be 0, because only one CPU present in the ADM5120 */
407 if (cfe_a1_val != 0) {
408 return 0;
409 }
410
411 /* The cfe_handle, and the cfe_entry must be kernel mode addresses */
412 if ((cfe_handle < KSEG0) || (cfe_entry < KSEG0)) {
413 return 0;
414 }
415
416 return 1;
417 }
418
419 static unsigned long __init cfe_detect_board(void)
420 {
421 return MACH_ADM5120_WP54G_WRT;
422 }
423
424 /*
425 * MyLoader based boards
426 */
427 #define SYS_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F000)
428 #define BOARD_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F800)
429 #define PART_TABLE_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x10000)
430
431 static unsigned long __init myloader_detect_board(void)
432 {
433 struct mylo_system_params *sysp;
434 struct mylo_board_params *boardp;
435 struct mylo_partition_table *parts;
436 struct mylo_board *board;
437 unsigned long ret;
438
439 ret = MACH_ADM5120_UNKNOWN;
440
441 sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR);
442 boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR);
443 parts = (struct mylo_partition_table *)(PART_TABLE_ADDR);
444
445 /* Check for some magic numbers */
446 if ((le32_to_cpu(sysp->magic) != MYLO_MAGIC_SYS_PARAMS) ||
447 (le32_to_cpu(boardp->magic) != MYLO_MAGIC_BOARD_PARAMS) ||
448 (le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS))
449 goto out;
450
451 for (board = mylo_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
452 board++) {
453 if ((le16_to_cpu(sysp->vid) == board->vid) &&
454 (le16_to_cpu(sysp->did) == board->did) &&
455 (le16_to_cpu(sysp->svid) == board->svid) &&
456 (le16_to_cpu(sysp->sdid) == board->sdid)) {
457 ret = board->mach_type;
458 break;
459 }
460 }
461
462 /* assume MyLoader as the boot-loader */
463 adm5120_boot_loader = BOOT_LOADER_MYLOADER;
464
465 out:
466 return ret;
467 }
468
469 /*
470 * RouterBOOT based boards
471 */
472 static int __init routerboot_load_hs(u8 *buf, u16 buflen,
473 struct rb_hard_settings *hs)
474 {
475 u16 id,len;
476 u8 *mac;
477 int i,j;
478
479 if (buflen < 4)
480 return -1;
481
482 if (read_le32(buf) != RB_MAGIC_HARD)
483 return -1;
484
485 /* skip magic value */
486 buf += 4;
487 buflen -= 4;
488
489 while (buflen > 2) {
490 id = read_le16(buf);
491 buf += 2;
492 buflen -= 2;
493 if (id == RB_ID_TERMINATOR || buflen < 2)
494 break;
495
496 len = read_le16(buf);
497 buf += 2;
498 buflen -= 2;
499
500 if (buflen < len)
501 break;
502
503 switch (id) {
504 case RB_ID_BIOS_VERSION:
505 hs->bios_ver = (char *)buf;
506 break;
507 case RB_ID_BOARD_NAME:
508 hs->name = (char *)buf;
509 break;
510 case RB_ID_MEMORY_SIZE:
511 hs->mem_size = read_le32(buf);
512 break;
513 case RB_ID_MAC_ADDRESS_COUNT:
514 hs->mac_count = read_le32(buf);
515 break;
516 case RB_ID_MAC_ADDRESS_PACK:
517 hs->mac_count = len/RB_MAC_SIZE;
518 if (hs->mac_count > RB_MAX_MAC_COUNT)
519 hs->mac_count = RB_MAX_MAC_COUNT;
520 mac = buf;
521 for (i=0; i < hs->mac_count; i++) {
522 for (j=0; j < RB_MAC_SIZE; j++)
523 hs->macs[i][j] = mac[j];
524 mac += RB_MAC_SIZE;
525 }
526 break;
527 }
528
529 buf += len;
530 buflen -= len;
531
532 }
533
534 return 0;
535 }
536
537 #define RB_BS_OFFS 0x14
538 #define RB_OFFS_MAX (128*1024)
539
540 static unsigned long __init routerboot_detect_board(void)
541 {
542 struct routerboard *board;
543 struct rb_hard_settings hs;
544 struct rb_bios_settings *bs;
545 u8 *base;
546 u32 off,len;
547 unsigned long ret;
548
549 ret = MACH_ADM5120_UNKNOWN;
550
551 base = (u8 *)KSEG1ADDR(ADM5120_SRAM0_BASE);
552 bs = (struct rb_bios_settings *)(base + RB_BS_OFFS);
553
554 off = read_le32(&bs->hs_offs);
555 len = read_le32(&bs->hs_size);
556 if (off > RB_OFFS_MAX)
557 return ret;
558
559 memset(&hs, 0, sizeof(hs));
560 if (routerboot_load_hs(base+off, len, &hs) != 0)
561 return ret;
562
563 /* assume RouterBOOT as the boot-loader */
564 adm5120_boot_loader = BOOT_LOADER_ROUTERBOOT;
565
566 if (hs.name == NULL)
567 return ret;
568
569 for (board = routerboards; board->mach_type != MACH_ADM5120_UNKNOWN;
570 board++) {
571 if (strncmp(board->name, hs.name, strlen(board->name)) == 0) {
572 ret = board->mach_type;
573 break;
574 }
575 }
576
577 return ret;
578 }
579
580 /*
581 * ZyNOS based boards
582 */
583 static inline u32 zynos_dbgarea_present(u8 *data)
584 {
585 u32 t;
586
587 t = read_be32(data+5);
588 if (t != ZYNOS_MAGIC_DBGAREA1)
589 return 0;
590
591 t = read_be32(data+9);
592 if (t != ZYNOS_MAGIC_DBGAREA2)
593 return 0;
594
595 return 1;
596 }
597
598 #define CHECK_VENDOR(n) (strnicmp(vendor,(n),strlen(n)) == 0)
599
600 static inline unsigned int zynos_get_vendor_id(struct zynos_board_info *info)
601 {
602 unsigned char vendor[ZYNOS_NAME_LEN];
603 int i;
604
605 for (i=0; i<ZYNOS_NAME_LEN; i++)
606 vendor[i]=info->vendor[i];
607
608 if CHECK_VENDOR(ZYNOS_VENDOR_ZYXEL)
609 return ZYNOS_VENDOR_ID_ZYXEL;
610 #if 0
611 /* TODO: there are no known ADM5120 based boards from other vendors */
612 if CHECK_VENDOR(ZYNOS_VENDOR_DLINK)
613 return ZYNOS_VENDOR_ID_DLINK;
614
615 if CHECK_VENDOR(ZYNOS_VENDOR_LUCENT)
616 return ZYNOS_VENDOR_ID_LUCENT;
617
618 if CHECK_VENDOR(ZYNOS_VENDOR_NETGEAR)
619 return ZYNOS_VENDOR_ID_NETGEAR;
620 #endif
621
622 return ZYNOS_VENDOR_ID_OTHER;
623 }
624
625 static inline u16 zynos_get_board_id(struct zynos_board_info *info)
626 {
627 return read_be16(&info->board_id);
628 }
629
630 static inline u32 zynos_get_bootext_addr(struct zynos_board_info *info)
631 {
632 return read_be32(&info->bootext_addr);
633 }
634
635
636 #define ZYNOS_INFO_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x3F90)
637 #define ZYNOS_HDBG_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x4000)
638 #define BOOTEXT_ADDR_MIN KSEG1ADDR(ADM5120_SRAM0_BASE)
639 #define BOOTEXT_ADDR_MAX (BOOTEXT_ADDR_MIN + (2*1024*1024))
640
641 static unsigned long __init zynos_detect_board(void)
642 {
643 struct zynos_board_info *info;
644 struct zynos_board *board;
645 unsigned int vendor_id;
646 u16 board_id;
647 u32 t;
648 unsigned long ret;
649
650 ret = MACH_ADM5120_UNKNOWN;
651 /* check presence of the dbgarea */
652 if (zynos_dbgarea_present((u8 *)ZYNOS_HDBG_ADDR) == 0)
653 goto out;
654
655 info = (struct zynos_board_info *)(ZYNOS_INFO_ADDR);
656
657 /* check for a valid BootExt address */
658 t = zynos_get_bootext_addr(info);
659 if ((t < BOOTEXT_ADDR_MIN) || (t > BOOTEXT_ADDR_MAX))
660 goto out;
661
662 vendor_id = zynos_get_vendor_id(info);
663 board_id = zynos_get_board_id(info);
664
665 for (board = zynos_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
666 board++) {
667 if ((board->vendor_id == vendor_id) &&
668 (board->board_id == board_id)) {
669 ret = board->mach_type;
670 break;
671 }
672 }
673
674 /* assume Bootbase as the boot-loader */
675 adm5120_boot_loader = BOOT_LOADER_BOOTBASE;
676
677 out:
678 return ret;
679 }
680
681 /*
682 * U-Boot based boards
683 */
684 static int __init uboot_present(void)
685 {
686 /* FIXME: not yet implemented */
687 return 0;
688 }
689
690 static unsigned long __init uboot_detect_board(void)
691 {
692 /* FIXME: not yet implemented */
693 return MACH_ADM5120_UNKNOWN;
694 }
695
696 static void __init adm5120_detect_board(void)
697 {
698 struct adm5120_board *board;
699 unsigned long t;
700
701 adm5120_boot_loader = BOOT_LOADER_UNKNOWN;
702
703 /* Try to detect board type without bootloader */
704 t = routerboot_detect_board();
705
706 if (t == MACH_ADM5120_UNKNOWN)
707 t = zynos_detect_board();
708
709 if (t == MACH_ADM5120_UNKNOWN)
710 t = myloader_detect_board();
711
712 /* Try to detect bootloader type */
713 if (cfe_present()) {
714 adm5120_boot_loader = BOOT_LOADER_CFE;
715 if (t == MACH_ADM5120_UNKNOWN)
716 t = cfe_detect_board();
717 } else if (uboot_present()) {
718 adm5120_boot_loader = BOOT_LOADER_UBOOT;
719 if (t == MACH_ADM5120_UNKNOWN)
720 t = uboot_detect_board();
721 }
722
723 for (board = adm5120_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
724 board++) {
725 if (board->mach_type == t)
726 break;
727 }
728
729 memcpy(&adm5120_board, board, sizeof(adm5120_board));
730 }
731
732 #define SWITCH_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))
733 #define SWITCH_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v)
734
735 /*
736 * CPU settings detection
737 */
738 #define CODE_GET_PC(c) ((c) & CODE_PC_MASK)
739 #define CODE_GET_REV(c) (((c) >> CODE_REV_SHIFT) & CODE_REV_MASK)
740 #define CODE_GET_PK(c) (((c) >> CODE_PK_SHIFT) & CODE_PK_MASK)
741 #define CODE_GET_CLKS(c) (((c) >> CODE_CLKS_SHIFT) & CODE_CLKS_MASK)
742 #define CODE_GET_NAB(c) (((c) & CODE_NAB) != 0)
743
744 static void __init adm5120_detect_cpuinfo(void)
745 {
746 u32 code;
747 u32 clks;
748
749 code = SWITCH_READ(SWITCH_REG_CODE);
750
751 adm5120_product_code = CODE_GET_PC(code);
752 adm5120_revision = CODE_GET_REV(code);
753 adm5120_package = (CODE_GET_PK(code) == CODE_PK_BGA) ?
754 ADM5120_PACKAGE_BGA : ADM5120_PACKAGE_PQFP;
755 adm5120_nand_boot = CODE_GET_NAB(code);
756
757 clks = CODE_GET_CLKS(code);
758 adm5120_speed = ADM5120_SPEED_175;
759 if (clks & 1)
760 adm5120_speed += 25000000;
761 if (clks & 2)
762 adm5120_speed += 50000000;
763 }
764
765 #if 1
766 # define mem_dbg(f, ...) prom_printf("mem_detect: " f, ## __VA_ARGS__)
767 extern void prom_printf(char *, ...);
768 #else
769 # define mem_dbg(f, ...)
770 #endif
771
772 static void __init adm5120_detect_memsize(void)
773 {
774 u32 memctrl;
775 u32 size, maxsize;
776 volatile u8 *p,*r;
777 u8 t;
778
779 memctrl = SWITCH_READ(SWITCH_REG_MEMCTRL);
780 switch (memctrl & MEMCTRL_SDRS_MASK) {
781 case MEMCTRL_SDRS_4M:
782 maxsize = 4 << 20;
783 break;
784 case MEMCTRL_SDRS_8M:
785 maxsize = 8 << 20;
786 break;
787 case MEMCTRL_SDRS_16M:
788 maxsize = 16 << 20;
789 break;
790 default:
791 maxsize = 64 << 20;
792 break;
793 }
794
795 /* FIXME: need to disable buffers for both SDRAM bank? */
796
797 mem_dbg("checking for %ldMB chip\n",maxsize >> 20);
798
799 /* detect size of the 1st SDRAM bank */
800 p = (volatile u8 *)KSEG1ADDR(0);
801 t = *p;
802 for (size = 2<<20; size <= (maxsize >> 1); size <<= 1) {
803 #if 1
804 r = (p+size);
805 *p = 0x55;
806 mem_dbg("1st pattern at 0x%lx is 0x%02x\n", size, *r);
807 if (*r == 0x55) {
808 *p = 0xAA;
809 mem_dbg("2nd pattern at 0x%lx is 0x%02x\n", size, *r);
810 if (*r == 0xAA) {
811 /* mirrored address */
812 mem_dbg("mirrored data found at 0x%lx\n", size);
813 break;
814 }
815 }
816 #else
817 p[0] = 0x55;
818 mem_dbg("1st pattern at 0x%lx is 0x%02x\n", size, p[size]);
819 if (p[size] != 0x55)
820 continue;
821
822 p[0] = 0xAA;
823 mem_dbg("2nd pattern at 0x%lx is 0x%02x\n", size, p[size]);
824 if (p[size] != 0xAA)
825 continue;
826
827 /* mirrored address */
828 mem_dbg("mirrored data found at 0x%lx\n", size);
829 break;
830 #endif
831 }
832 *p = t;
833
834 mem_dbg("%ldMB chip found\n", size >> 20);
835
836 if (size == (32 << 20))
837 /* if bank size is 32MB, 2nd bank is not supported */
838 goto out;
839
840 if ((memctrl & MEMCTRL_SDR1_ENABLE) == 0)
841 /* if 2nd bank is not enabled, we are done */
842 goto out;
843
844 /*
845 * some bootloaders enable 2nd bank, even if the 2nd SDRAM chip
846 * are missing.
847 */
848 mem_dbg("checking second bank\n");
849 p += (maxsize+size)-1;
850 t = *p;
851 *p = 0x55;
852 if (*p != 0x55)
853 goto out;
854
855 *p = 0xAA;
856 if (*p != 0xAA)
857 goto out;
858
859 *p = t;
860 if (maxsize != size) {
861 /* adjusting MECTRL register */
862 memctrl &= ~(MEMCTRL_SDRS_MASK);
863 switch (size>>20) {
864 case 4:
865 memctrl |= MEMCTRL_SDRS_4M;
866 break;
867 case 8:
868 memctrl |= MEMCTRL_SDRS_8M;
869 break;
870 case 16:
871 memctrl |= MEMCTRL_SDRS_16M;
872 break;
873 default:
874 memctrl |= MEMCTRL_SDRS_64M;
875 break;
876 }
877 SWITCH_WRITE(SWITCH_REG_MEMCTRL, memctrl);
878 }
879 size <<= 1;
880
881 out:
882 adm5120_memsize = size;
883 mem_dbg("%ldMB memory found\n",size>>20);
884 }
885
886 void __init adm5120_info_show(void)
887 {
888 /* FIXME: move this somewhere else */
889 printk("ADM%04X%s revision %d, running at %ldMHz\n",
890 adm5120_product_code,
891 (adm5120_package == ADM5120_PACKAGE_BGA) ? "" : "P",
892 adm5120_revision, (adm5120_speed / 1000000)
893 );
894 printk("Boot loader is: %s\n", boot_loader_names[adm5120_boot_loader]);
895 printk("Booted from : %s flash\n", adm5120_nand_boot ? "NAND":"NOR");
896 printk("Board is : %s\n", adm5120_board_name());
897 printk("Memory size : %ldMB\n", adm5120_memsize >> 20);
898 }
899
900 void __init adm5120_info_init(void)
901 {
902 adm5120_detect_cpuinfo();
903 adm5120_detect_memsize();
904 adm5120_detect_board();
905
906 adm5120_info_show();
907 }