]> git.enpas.org Git - openwrt.git/blob - target/linux/adm5120-2.6/files/arch/mips/adm5120/adm5120_info.c
87e3d865a55671947df4a5e1f5b924cfb8fabf02
[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 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      = 0,
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                 t = prom_detect_board();
884         }
885
886         for (board = adm5120_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
887                 board++) {
888                 if (board->mach_type == t)
889                         break;
890         }
891
892         memcpy(&adm5120_board, board, sizeof(adm5120_board));
893 }
894
895 #define SWITCH_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))
896 #define SWITCH_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v)
897
898 /*
899  * CPU settings detection
900  */
901 #define CODE_GET_PC(c)          ((c) & CODE_PC_MASK)
902 #define CODE_GET_REV(c)         (((c) >> CODE_REV_SHIFT) & CODE_REV_MASK)
903 #define CODE_GET_PK(c)          (((c) >> CODE_PK_SHIFT) & CODE_PK_MASK)
904 #define CODE_GET_CLKS(c)        (((c) >> CODE_CLKS_SHIFT) & CODE_CLKS_MASK)
905 #define CODE_GET_NAB(c)         (((c) & CODE_NAB) != 0)
906
907 static void __init adm5120_detect_cpuinfo(void)
908 {
909         u32 code;
910         u32 clks;
911
912         code = SWITCH_READ(SWITCH_REG_CODE);
913
914         adm5120_product_code = CODE_GET_PC(code);
915         adm5120_revision = CODE_GET_REV(code);
916         adm5120_package = (CODE_GET_PK(code) == CODE_PK_BGA) ?
917                 ADM5120_PACKAGE_BGA : ADM5120_PACKAGE_PQFP;
918         adm5120_nand_boot = CODE_GET_NAB(code);
919
920         clks = CODE_GET_CLKS(code);
921         adm5120_speed = ADM5120_SPEED_175;
922         if (clks & 1)
923                 adm5120_speed += 25000000;
924         if (clks & 2)
925                 adm5120_speed += 50000000;
926 }
927
928 #if 1
929 #  define mem_dbg(f, ...)       prom_printf("mem_detect: " f, ## __VA_ARGS__)
930 extern void prom_printf(char *, ...);
931 #else
932 #  define mem_dbg(f, ...)
933 #endif
934
935 static void __init adm5120_detect_memsize(void)
936 {
937         u32     memctrl;
938         u32     size, maxsize;
939         volatile u8     *p,*r;
940         u8      t;
941
942         memctrl = SWITCH_READ(SWITCH_REG_MEMCTRL);
943         switch (memctrl & MEMCTRL_SDRS_MASK) {
944         case MEMCTRL_SDRS_4M:
945                 maxsize = 4 << 20;
946                 break;
947         case MEMCTRL_SDRS_8M:
948                 maxsize = 8 << 20;
949                 break;
950         case MEMCTRL_SDRS_16M:
951                 maxsize = 16 << 20;
952                 break;
953         default:
954                 maxsize = 64 << 20;
955                 break;
956         }
957
958         /* FIXME: need to disable buffers for both SDRAM banks? */
959
960         mem_dbg("checking for %ldMB chip\n",maxsize >> 20);
961
962         /* detect size of the 1st SDRAM bank */
963         p = (volatile u8 *)KSEG1ADDR(0);
964         t = *p;
965         for (size = 2<<20; size <= (maxsize >> 1); size <<= 1) {
966 #if 1
967                 r = (p+size);
968                 *p = 0x55;
969                 mem_dbg("1st pattern at 0x%lx is 0x%02x\n", size, *r);
970                 if (*r == 0x55) {
971                         *p = 0xAA;
972                         mem_dbg("2nd pattern at 0x%lx is 0x%02x\n", size, *r);
973                         if (*r == 0xAA) {
974                                 /* mirrored address */
975                                 mem_dbg("mirrored data found at 0x%lx\n", size);
976                                 break;
977                         }
978                 }
979 #else
980                 p[0] = 0x55;
981                 mem_dbg("1st pattern at 0x%lx is 0x%02x\n", size, p[size]);
982                 if (p[size] != 0x55)
983                         continue;
984
985                 p[0] = 0xAA;
986                 mem_dbg("2nd pattern at 0x%lx is 0x%02x\n", size, p[size]);
987                 if (p[size] != 0xAA)
988                         continue;
989
990                 /* mirrored address */
991                 mem_dbg("mirrored data found at 0x%lx\n", size);
992                 break;
993 #endif
994         }
995         *p = t;
996
997         mem_dbg("%ldMB chip found\n", size >> 20);
998
999         if (size == (32 << 20))
1000                 /* if bank size is 32MB, 2nd bank is not supported */
1001                 goto out;
1002
1003         if ((memctrl & MEMCTRL_SDR1_ENABLE) == 0)
1004                 /* if 2nd bank is not enabled, we are done */
1005                 goto out;
1006
1007         /*
1008          * some bootloaders enable 2nd bank, even if the 2nd SDRAM chip
1009          * are missing.
1010          */
1011         mem_dbg("checking second bank\n");
1012         p += (maxsize+size)-1;
1013         t = *p;
1014         *p = 0x55;
1015         if (*p != 0x55)
1016                 goto out;
1017
1018         *p = 0xAA;
1019         if (*p != 0xAA)
1020                 goto out;
1021
1022         *p = t;
1023         if (maxsize != size) {
1024                 /* adjusting MECTRL register */
1025                 memctrl &= ~(MEMCTRL_SDRS_MASK);
1026                 switch (size>>20) {
1027                 case 4:
1028                         memctrl |= MEMCTRL_SDRS_4M;
1029                         break;
1030                 case 8:
1031                         memctrl |= MEMCTRL_SDRS_8M;
1032                         break;
1033                 case 16:
1034                         memctrl |= MEMCTRL_SDRS_16M;
1035                         break;
1036                 default:
1037                         memctrl |= MEMCTRL_SDRS_64M;
1038                         break;
1039                 }
1040                 SWITCH_WRITE(SWITCH_REG_MEMCTRL, memctrl);
1041         }
1042         size <<= 1;
1043
1044 out:
1045         adm5120_memsize = size;
1046         mem_dbg("%ldMB memory found\n",size>>20);
1047 }
1048
1049 void __init adm5120_info_show(void)
1050 {
1051         /* FIXME: move this somewhere else */
1052         printk(KERN_INFO "ADM%04X%s revision %d, running at %ldMHz\n",
1053                 adm5120_product_code,
1054                 (adm5120_package == ADM5120_PACKAGE_BGA) ? "" : "P",
1055                 adm5120_revision, (adm5120_speed / 1000000)
1056                 );
1057         printk(KERN_INFO "Boot loader is: %s\n", boot_loader_names[adm5120_boot_loader]);
1058         printk(KERN_INFO "Booted from   : %s flash\n", adm5120_nand_boot ? "NAND":"NOR");
1059         printk(KERN_INFO "Board is      : %s\n", adm5120_board_name());
1060         printk(KERN_INFO "Memory size   : %ldMB\n", adm5120_memsize >> 20);
1061 }
1062
1063 void __init adm5120_info_init(void)
1064 {
1065
1066         adm5120_detect_cpuinfo();
1067         adm5120_detect_memsize();
1068         adm5120_detect_board();
1069
1070         adm5120_info_show();
1071 }