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