rewrite of memory detection code, should be fix #1909
[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 #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("miniROUTER", MACH_ADM5120_RB_150),
431 ROUTERBOARD("153", MACH_ADM5120_RB_150),
432 DUMMY_BOARD()
433 };
434
435 struct zynos_board {
436 unsigned long mach_type;
437 unsigned int vendor_id;
438 u16 board_id;
439 };
440
441 #define ZYNOS_BOARD(vi, bi, mt) { .vendor_id = (vi), .board_id = (bi), \
442 .mach_type = (mt) }
443
444 #define ZYXEL_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_ZYXEL, bi, mt)
445 #define DLINK_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_DLINK, bi, mt)
446 #define LUCENT_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_LUCENT, bi, mt)
447
448 static struct zynos_board zynos_boards[] __initdata = {
449 ZYXEL_BOARD(ZYNOS_BOARD_HS100, MACH_ADM5120_HS100),
450 ZYXEL_BOARD(ZYNOS_BOARD_P334, MACH_ADM5120_P334),
451 ZYXEL_BOARD(ZYNOS_BOARD_P334U, MACH_ADM5120_P334U),
452 ZYXEL_BOARD(ZYNOS_BOARD_P334W, MACH_ADM5120_P334W),
453 ZYXEL_BOARD(ZYNOS_BOARD_P334WH, MACH_ADM5120_P334WH),
454 ZYXEL_BOARD(ZYNOS_BOARD_P334WHD, MACH_ADM5120_P334WHD),
455 ZYXEL_BOARD(ZYNOS_BOARD_P334WT, MACH_ADM5120_P334WT),
456 ZYXEL_BOARD(ZYNOS_BOARD_P335, MACH_ADM5120_P335),
457 ZYXEL_BOARD(ZYNOS_BOARD_P335PLUS, MACH_ADM5120_P335PLUS),
458 ZYXEL_BOARD(ZYNOS_BOARD_P335U, MACH_ADM5120_P335U),
459 DUMMY_BOARD()
460 };
461
462 struct common_board {
463 char *name;
464 unsigned long mach_type;
465 };
466
467 #define DEFBOARD(n, mt) { .name = (n), .mach_type = (mt) }
468 static struct common_board common_boards[] __initdata = {
469 DEFBOARD("CAS-630", MACH_ADM5120_CAS630),
470 DEFBOARD("CAS-670", MACH_ADM5120_CAS670),
471 DEFBOARD("CAS-700", MACH_ADM5120_CAS700),
472 DEFBOARD("CAS-771", MACH_ADM5120_CAS771),
473 DEFBOARD("CAS-790", MACH_ADM5120_CAS790),
474 DEFBOARD("CAS-861", MACH_ADM5120_CAS861),
475 DEFBOARD("NFS-101U", MACH_ADM5120_NFS101U),
476 DEFBOARD("NFS-202U", MACH_ADM5120_NFS202U),
477 DEFBOARD("EASY 5120", MACH_ADM5120_EASY5120),
478 DEFBOARD("EASY 5120-RT", MACH_ADM5120_EASY5120RT),
479 DEFBOARD("EASY 5120P-ATA", MACH_ADM5120_EASY5120PATA),
480 DEFBOARD("EASY 83000", MACH_ADM5120_EASY83000),
481 DEFBOARD("BR-6104K", MACH_ADM5120_BR6104K),
482 DEFBOARD("WP54G-WRT", MACH_ADM5120_WP54G_WRT),
483 DEFBOARD("P-334WT", MACH_ADM5120_P334WT),
484 DEFBOARD("P-335", MACH_ADM5120_P335),
485 };
486
487 /*
488 * Helper routines
489 */
490 static inline u16 read_le16(void *buf)
491 {
492 u8 *p;
493
494 p = buf;
495 return ((u16)p[0] + ((u16)p[1] << 8));
496 }
497
498 static inline u32 read_le32(void *buf)
499 {
500 u8 *p;
501
502 p = buf;
503 return ((u32)p[0] + ((u32)p[1] << 8) + ((u32)p[2] << 16) +
504 ((u32)p[3] << 24));
505 }
506
507 static inline u16 read_be16(void *buf)
508 {
509 u8 *p;
510
511 p = buf;
512 return (((u16)p[0] << 8) + (u16)p[1]);
513 }
514
515 static inline u32 read_be32(void *buf)
516 {
517 u8 *p;
518
519 p = buf;
520 return (((u32)p[0] << 24) + ((u32)p[1] << 16) + ((u32)p[2] << 8) +
521 ((u32)p[3]));
522 }
523
524 /*
525 * CFE based boards
526 */
527 #define CFE_EPTSEAL 0x43464531 /* CFE1 is the magic number to recognize CFE
528 from other bootloaders */
529
530 static int __init cfe_present(void)
531 {
532 /*
533 * This method only works, when we are booted directly from the CFE.
534 */
535 u32 cfe_handle = (u32) fw_arg0;
536 u32 cfe_a1_val = (u32) fw_arg1;
537 u32 cfe_entry = (u32) fw_arg2;
538 u32 cfe_seal = (u32) fw_arg3;
539
540 /* Check for CFE by finding the CFE magic number */
541 if (cfe_seal != CFE_EPTSEAL) {
542 /* We are not booted from CFE */
543 return 0;
544 }
545
546 /* cfe_a1_val must be 0, because only one CPU present in the ADM5120 */
547 if (cfe_a1_val != 0) {
548 return 0;
549 }
550
551 /* The cfe_handle, and the cfe_entry must be kernel mode addresses */
552 if ((cfe_handle < KSEG0) || (cfe_entry < KSEG0)) {
553 return 0;
554 }
555
556 return 1;
557 }
558
559 static unsigned long __init cfe_detect_board(void)
560 {
561 return MACH_ADM5120_WP54G_WRT;
562 }
563
564 /*
565 * MyLoader based boards
566 */
567 #define SYS_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F000)
568 #define BOARD_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F800)
569 #define PART_TABLE_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x10000)
570
571 static unsigned long __init myloader_detect_board(void)
572 {
573 struct mylo_system_params *sysp;
574 struct mylo_board_params *boardp;
575 struct mylo_partition_table *parts;
576 struct mylo_board *board;
577 unsigned long ret;
578
579 ret = MACH_ADM5120_UNKNOWN;
580
581 sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR);
582 boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR);
583 parts = (struct mylo_partition_table *)(PART_TABLE_ADDR);
584
585 /* Check for some magic numbers */
586 if ((le32_to_cpu(sysp->magic) != MYLO_MAGIC_SYS_PARAMS) ||
587 (le32_to_cpu(boardp->magic) != MYLO_MAGIC_BOARD_PARAMS) ||
588 (le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS))
589 goto out;
590
591 for (board = mylo_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
592 board++) {
593 if ((le16_to_cpu(sysp->vid) == board->vid) &&
594 (le16_to_cpu(sysp->did) == board->did) &&
595 (le16_to_cpu(sysp->svid) == board->svid) &&
596 (le16_to_cpu(sysp->sdid) == board->sdid)) {
597 ret = board->mach_type;
598 break;
599 }
600 }
601
602 /* assume MyLoader as the boot-loader */
603 adm5120_boot_loader = BOOT_LOADER_MYLOADER;
604
605 out:
606 return ret;
607 }
608
609 /*
610 * RouterBOOT based boards
611 */
612 static int __init routerboot_load_hs(u8 *buf, u16 buflen,
613 struct rb_hard_settings *hs)
614 {
615 u16 id,len;
616 u8 *mac;
617 int i,j;
618
619 if (buflen < 4)
620 return -1;
621
622 if (read_le32(buf) != RB_MAGIC_HARD)
623 return -1;
624
625 /* skip magic value */
626 buf += 4;
627 buflen -= 4;
628
629 while (buflen > 2) {
630 id = read_le16(buf);
631 buf += 2;
632 buflen -= 2;
633 if (id == RB_ID_TERMINATOR || buflen < 2)
634 break;
635
636 len = read_le16(buf);
637 buf += 2;
638 buflen -= 2;
639
640 if (buflen < len)
641 break;
642
643 switch (id) {
644 case RB_ID_BIOS_VERSION:
645 hs->bios_ver = (char *)buf;
646 break;
647 case RB_ID_BOARD_NAME:
648 hs->name = (char *)buf;
649 break;
650 case RB_ID_MEMORY_SIZE:
651 hs->mem_size = read_le32(buf);
652 break;
653 case RB_ID_MAC_ADDRESS_COUNT:
654 hs->mac_count = read_le32(buf);
655 break;
656 case RB_ID_MAC_ADDRESS_PACK:
657 hs->mac_count = len/RB_MAC_SIZE;
658 if (hs->mac_count > RB_MAX_MAC_COUNT)
659 hs->mac_count = RB_MAX_MAC_COUNT;
660 mac = buf;
661 for (i=0; i < hs->mac_count; i++) {
662 for (j=0; j < RB_MAC_SIZE; j++)
663 hs->macs[i][j] = mac[j];
664 mac += RB_MAC_SIZE;
665 }
666 break;
667 }
668
669 buf += len;
670 buflen -= len;
671
672 }
673
674 return 0;
675 }
676
677 #define RB_BS_OFFS 0x14
678 #define RB_OFFS_MAX (128*1024)
679
680 static unsigned long __init routerboot_detect_board(void)
681 {
682 struct routerboard *board;
683 struct rb_hard_settings hs;
684 struct rb_bios_settings *bs;
685 u8 *base;
686 u32 off,len;
687 unsigned long ret;
688
689 ret = MACH_ADM5120_UNKNOWN;
690
691 base = (u8 *)KSEG1ADDR(ADM5120_SRAM0_BASE);
692 bs = (struct rb_bios_settings *)(base + RB_BS_OFFS);
693
694 off = read_le32(&bs->hs_offs);
695 len = read_le32(&bs->hs_size);
696 if (off > RB_OFFS_MAX)
697 return ret;
698
699 memset(&hs, 0, sizeof(hs));
700 if (routerboot_load_hs(base+off, len, &hs) != 0)
701 return ret;
702
703 /* assume RouterBOOT as the boot-loader */
704 adm5120_boot_loader = BOOT_LOADER_ROUTERBOOT;
705
706 if (hs.name == NULL)
707 return ret;
708
709 for (board = routerboards; board->mach_type != MACH_ADM5120_UNKNOWN;
710 board++) {
711 if (strncmp(board->name, hs.name, strlen(board->name)) == 0) {
712 ret = board->mach_type;
713 break;
714 }
715 }
716
717 return ret;
718 }
719
720 /*
721 * ZyNOS based boards
722 */
723 static inline u32 zynos_dbgarea_present(u8 *data)
724 {
725 u32 t;
726
727 t = read_be32(data+5);
728 if (t != ZYNOS_MAGIC_DBGAREA1)
729 return 0;
730
731 t = read_be32(data+9);
732 if (t != ZYNOS_MAGIC_DBGAREA2)
733 return 0;
734
735 return 1;
736 }
737
738 #define CHECK_VENDOR(n) (strnicmp(vendor,(n),strlen(n)) == 0)
739
740 static inline unsigned int zynos_get_vendor_id(struct zynos_board_info *info)
741 {
742 unsigned char vendor[ZYNOS_NAME_LEN];
743 int i;
744
745 for (i=0; i<ZYNOS_NAME_LEN; i++)
746 vendor[i]=info->vendor[i];
747
748 if CHECK_VENDOR(ZYNOS_VENDOR_ZYXEL)
749 return ZYNOS_VENDOR_ID_ZYXEL;
750 #if 0
751 /* TODO: there are no known ADM5120 based boards from other vendors */
752 if CHECK_VENDOR(ZYNOS_VENDOR_DLINK)
753 return ZYNOS_VENDOR_ID_DLINK;
754
755 if CHECK_VENDOR(ZYNOS_VENDOR_LUCENT)
756 return ZYNOS_VENDOR_ID_LUCENT;
757
758 if CHECK_VENDOR(ZYNOS_VENDOR_NETGEAR)
759 return ZYNOS_VENDOR_ID_NETGEAR;
760 #endif
761
762 return ZYNOS_VENDOR_ID_OTHER;
763 }
764
765 static inline u16 zynos_get_board_id(struct zynos_board_info *info)
766 {
767 return read_be16(&info->board_id);
768 }
769
770 static inline u32 zynos_get_bootext_addr(struct zynos_board_info *info)
771 {
772 return read_be32(&info->bootext_addr);
773 }
774
775
776 #define ZYNOS_INFO_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x3F90)
777 #define ZYNOS_HDBG_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x4000)
778 #define BOOTEXT_ADDR_MIN KSEG1ADDR(ADM5120_SRAM0_BASE)
779 #define BOOTEXT_ADDR_MAX (BOOTEXT_ADDR_MIN + (2*1024*1024))
780
781 static unsigned long __init zynos_detect_board(void)
782 {
783 struct zynos_board_info *info;
784 struct zynos_board *board;
785 unsigned int vendor_id;
786 u16 board_id;
787 u32 t;
788 unsigned long ret;
789
790 ret = MACH_ADM5120_UNKNOWN;
791 /* check presence of the dbgarea */
792 if (zynos_dbgarea_present((u8 *)ZYNOS_HDBG_ADDR) == 0)
793 goto out;
794
795 info = (struct zynos_board_info *)(ZYNOS_INFO_ADDR);
796
797 /* check for a valid BootExt address */
798 t = zynos_get_bootext_addr(info);
799 if ((t < BOOTEXT_ADDR_MIN) || (t > BOOTEXT_ADDR_MAX))
800 goto out;
801
802 vendor_id = zynos_get_vendor_id(info);
803 board_id = zynos_get_board_id(info);
804
805 for (board = zynos_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
806 board++) {
807 if ((board->vendor_id == vendor_id) &&
808 (board->board_id == board_id)) {
809 ret = board->mach_type;
810 break;
811 }
812 }
813
814 /* assume Bootbase as the boot-loader */
815 adm5120_boot_loader = BOOT_LOADER_BOOTBASE;
816
817 out:
818 return ret;
819 }
820
821 /*
822 * U-Boot based boards
823 */
824 static int __init uboot_present(void)
825 {
826 /* FIXME: not yet implemented */
827 return 0;
828 }
829
830 static unsigned long __init uboot_detect_board(void)
831 {
832 /* FIXME: not yet implemented */
833 return MACH_ADM5120_UNKNOWN;
834 }
835
836 /*
837 * Misc boards
838 */
839 static unsigned long __init prom_detect_board(void)
840 {
841 char *name;
842 unsigned long ret;
843 int i;
844
845 ret = MACH_ADM5120_UNKNOWN;
846 name = prom_getenv("board_name");
847 if (name == NULL)
848 goto out;
849
850 if (*name == '\0')
851 goto out;
852
853 for (i=0; i<ARRAY_SIZE(common_boards); i++) {
854 if (strcmp(common_boards[i].name, name) == 0) {
855 ret = common_boards[i].mach_type;
856 break;
857 }
858 }
859
860 out:
861 return ret;
862 }
863
864 static void __init adm5120_detect_board(void)
865 {
866 struct adm5120_board *board;
867 unsigned long t;
868
869 adm5120_boot_loader = BOOT_LOADER_UNKNOWN;
870
871 /* Try to detect board type without bootloader */
872 t = routerboot_detect_board();
873
874 if (t == MACH_ADM5120_UNKNOWN)
875 t = zynos_detect_board();
876
877 if (t == MACH_ADM5120_UNKNOWN)
878 t = myloader_detect_board();
879
880 /* Try to detect bootloader type */
881 if (cfe_present()) {
882 adm5120_boot_loader = BOOT_LOADER_CFE;
883 if (t == MACH_ADM5120_UNKNOWN)
884 t = cfe_detect_board();
885 } else if (uboot_present()) {
886 adm5120_boot_loader = BOOT_LOADER_UBOOT;
887 if (t == MACH_ADM5120_UNKNOWN)
888 t = uboot_detect_board();
889 } else {
890 if (t == MACH_ADM5120_UNKNOWN)
891 t = prom_detect_board();
892 }
893
894 for (board = adm5120_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
895 board++) {
896 if (board->mach_type == t)
897 break;
898 }
899
900 memcpy(&adm5120_board, board, sizeof(adm5120_board));
901 }
902
903 #define SWITCH_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))
904 #define SWITCH_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v)
905
906 /*
907 * CPU settings detection
908 */
909 #define CODE_GET_PC(c) ((c) & CODE_PC_MASK)
910 #define CODE_GET_REV(c) (((c) >> CODE_REV_SHIFT) & CODE_REV_MASK)
911 #define CODE_GET_PK(c) (((c) >> CODE_PK_SHIFT) & CODE_PK_MASK)
912 #define CODE_GET_CLKS(c) (((c) >> CODE_CLKS_SHIFT) & CODE_CLKS_MASK)
913 #define CODE_GET_NAB(c) (((c) & CODE_NAB) != 0)
914
915 static void __init adm5120_detect_cpuinfo(void)
916 {
917 u32 code;
918 u32 clks;
919
920 code = SWITCH_READ(SWITCH_REG_CODE);
921
922 adm5120_product_code = CODE_GET_PC(code);
923 adm5120_revision = CODE_GET_REV(code);
924 adm5120_package = (CODE_GET_PK(code) == CODE_PK_BGA) ?
925 ADM5120_PACKAGE_BGA : ADM5120_PACKAGE_PQFP;
926 adm5120_nand_boot = CODE_GET_NAB(code);
927
928 clks = CODE_GET_CLKS(code);
929 adm5120_speed = ADM5120_SPEED_175;
930 if (clks & 1)
931 adm5120_speed += 25000000;
932 if (clks & 2)
933 adm5120_speed += 50000000;
934 }
935
936 static void adm5120_ndelay(u32 ns)
937 {
938 u32 t;
939
940 SWITCH_WRITE(SWITCH_REG_TIMER, TIMER_PERIOD_DEFAULT);
941 SWITCH_WRITE(SWITCH_REG_TIMER_INT, (TIMER_INT_TOS | TIMER_INT_TOM));
942
943 t = (ns+640) / 640;
944 t &= TIMER_PERIOD_MASK;
945 SWITCH_WRITE(SWITCH_REG_TIMER, t | TIMER_TE);
946
947 /* wait until the timer expires */
948 do {
949 t = SWITCH_READ(SWITCH_REG_TIMER_INT);
950 } while ((t & TIMER_INT_TOS) == 0);
951
952 /* leave the timer disabled */
953 SWITCH_WRITE(SWITCH_REG_TIMER, TIMER_PERIOD_DEFAULT);
954 SWITCH_WRITE(SWITCH_REG_TIMER_INT, (TIMER_INT_TOS | TIMER_INT_TOM));
955 }
956
957 #define MPMC_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))
958 #define MPMC_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v)
959
960 extern void prom_printf(char *, ...);
961 #if 1
962 # define mem_dbg(f, a...) prom_printf("mem_detect: " f, ## a)
963 #else
964 # define mem_dbg(f, a...)
965 #endif
966
967 #define MEM_WR_DELAY 10000 /* 0.01 usec */
968
969 static int mem_check_pattern(u8 *addr, unsigned long offs)
970 {
971 volatile u32 *p1 = (volatile u32 *)addr;
972 volatile u32 *p2 = (volatile u32 *)(addr+offs);
973 u32 t,u,v;
974
975 /* save original value */
976 t = *p1;
977 u = *p2;
978
979 if (t != u)
980 return 0;
981
982 v = 0x55555555;
983 if (u == v)
984 v = 0xAAAAAAAA;
985
986 mem_dbg("write 0x%08lX to 0x%08lX\n", v, (unsigned long)p1);
987
988 *p1 = v;
989 mem_dbg("delay %d ns\n", MEM_WR_DELAY);
990 adm5120_ndelay(MEM_WR_DELAY);
991 u = *p2;
992
993 mem_dbg("pattern at 0x%08lX is 0x%08lX\n", (unsigned long)p2, u);
994
995 /* restore original value */
996 *p1 = t;
997
998 return (v == u);
999 }
1000
1001 static void __init adm5120_detect_memsize(void)
1002 {
1003 u32 memctrl;
1004 u32 size, maxsize;
1005 u8 *p;
1006
1007 memctrl = SWITCH_READ(SWITCH_REG_MEMCTRL);
1008 switch (memctrl & MEMCTRL_SDRS_MASK) {
1009 case MEMCTRL_SDRS_4M:
1010 maxsize = 4 << 20;
1011 break;
1012 case MEMCTRL_SDRS_8M:
1013 maxsize = 8 << 20;
1014 break;
1015 case MEMCTRL_SDRS_16M:
1016 maxsize = 16 << 20;
1017 break;
1018 default:
1019 maxsize = 64 << 20;
1020 break;
1021 }
1022
1023 /* disable buffers for both SDRAM banks */
1024 mem_dbg("disable buffers for both banks\n");
1025 MPMC_WRITE(MPMC_REG_DC0, MPMC_READ(MPMC_REG_DC0) & ~DC_BE);
1026 MPMC_WRITE(MPMC_REG_DC1, MPMC_READ(MPMC_REG_DC1) & ~DC_BE);
1027
1028 mem_dbg("checking for %ldMB chip in 1st bank\n", maxsize >> 20);
1029
1030 /* detect size of the 1st SDRAM bank */
1031 p = (u8 *)KSEG1ADDR(0);
1032 for (size = 2<<20; size <= (maxsize >> 1); size <<= 1) {
1033 if (mem_check_pattern(p, size)) {
1034 /* mirrored address */
1035 mem_dbg("mirrored data found at offset 0x%lX\n", size);
1036 break;
1037 }
1038 }
1039
1040 mem_dbg("chip size in 1st bank is %ldMB\n", size >> 20);
1041 adm5120_memsize = size;
1042
1043 if (size != maxsize)
1044 /* 2nd bank is not supported */
1045 goto out;
1046
1047 if ((memctrl & MEMCTRL_SDR1_ENABLE) == 0)
1048 /* 2nd bank is disabled */
1049 goto out;
1050
1051 /*
1052 * some bootloaders enable 2nd bank, even if the 2nd SDRAM chip
1053 * are missing.
1054 */
1055 mem_dbg("check presence of 2nd bank\n");
1056
1057 p = (u8 *)KSEG1ADDR(maxsize+size-4);
1058 if (mem_check_pattern(p, 0)) {
1059 adm5120_memsize += size;
1060 }
1061
1062 if (maxsize != size) {
1063 /* adjusting MECTRL register */
1064 memctrl &= ~(MEMCTRL_SDRS_MASK);
1065 switch (size>>20) {
1066 case 4:
1067 memctrl |= MEMCTRL_SDRS_4M;
1068 break;
1069 case 8:
1070 memctrl |= MEMCTRL_SDRS_8M;
1071 break;
1072 case 16:
1073 memctrl |= MEMCTRL_SDRS_16M;
1074 break;
1075 default:
1076 memctrl |= MEMCTRL_SDRS_64M;
1077 break;
1078 }
1079 SWITCH_WRITE(SWITCH_REG_MEMCTRL, memctrl);
1080 }
1081
1082 out:
1083 /* reenable buffer for both SDRAM banks */
1084 mem_dbg("enable buffers for both banks\n");
1085 MPMC_WRITE(MPMC_REG_DC0, MPMC_READ(MPMC_REG_DC0) | DC_BE);
1086 MPMC_WRITE(MPMC_REG_DC1, MPMC_READ(MPMC_REG_DC1) | DC_BE);
1087
1088 mem_dbg("%dx%ldMB memory found\n", (adm5120_memsize == size) ? 1 : 2 ,
1089 size >>20);
1090
1091 size = adm5120_board_memsize();
1092 if (size > 0 && size != adm5120_memsize) {
1093 mem_dbg("wrong memory size detected, board settings will be used\n");
1094 adm5120_memsize = size;
1095 }
1096 }
1097
1098 void __init adm5120_info_show(void)
1099 {
1100 /* FIXME: move this somewhere else */
1101 printk(KERN_INFO "ADM%04X%s revision %d, running at %ldMHz\n",
1102 adm5120_product_code,
1103 (adm5120_package == ADM5120_PACKAGE_BGA) ? "" : "P",
1104 adm5120_revision, (adm5120_speed / 1000000)
1105 );
1106 printk(KERN_INFO "Boot loader is: %s\n", boot_loader_names[adm5120_boot_loader]);
1107 printk(KERN_INFO "Booted from : %s flash\n", adm5120_nand_boot ? "NAND":"NOR");
1108 printk(KERN_INFO "Board is : %s\n", adm5120_board_name());
1109 printk(KERN_INFO "Memory size : %ldMB\n", adm5120_memsize >> 20);
1110 }
1111
1112 void __init adm5120_info_init(void)
1113 {
1114 adm5120_detect_cpuinfo();
1115 adm5120_detect_board();
1116 adm5120_detect_memsize();
1117
1118 adm5120_info_show();
1119 }