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