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