4 * Copyright (C) 2007 OpenWrt.org
5 * Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
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.
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>
19 #include <asm/bootinfo.h>
20 #include <asm/addrspace.h>
22 #include <asm/mach-adm5120/adm5120_defs.h>
23 #include <asm/mach-adm5120/adm5120_switch.h>
24 #include <asm/mach-adm5120/adm5120_info.h>
25 #include <asm/mach-adm5120/myloader.h>
26 #include <asm/mach-adm5120/routerboot.h>
27 #include <asm/mach-adm5120/zynos.h>
32 struct adm5120_board adm5120_board
;
33 unsigned int adm5120_boot_loader
;
35 unsigned int adm5120_product_code
;
36 unsigned int adm5120_revision
;
37 unsigned int adm5120_package
;
38 unsigned int adm5120_nand_boot
;
39 unsigned long adm5120_speed
;
44 static char *boot_loader_names
[BOOT_LOADER_LAST
+1] = {
45 [BOOT_LOADER_UNKNOWN
] = "Unknown",
46 [BOOT_LOADER_CFE
] = "CFE",
47 [BOOT_LOADER_UBOOT
] = "U-Boot",
48 [BOOT_LOADER_MYLOADER
] = "MyLoader",
49 [BOOT_LOADER_ROUTERBOOT
]= "RouterBOOT",
50 [BOOT_LOADER_BOOTBASE
] = "Bootbase"
53 static struct adm5120_board __initdata adm5120_boards
[] = {
55 .name
= "Compex NetPassage 27G",
56 .mach_type
= MACH_ADM5120_NP27G
,
59 .flash0_size
= 4*1024*1024,
62 .name
= "Compex NetPassage 28G",
63 .mach_type
= MACH_ADM5120_NP28G
,
66 .flash0_size
= 4*1024*1024,
69 .name
= "Compex NP28G (HotSpot)",
70 .mach_type
= MACH_ADM5120_NP28GHS
,
73 .flash0_size
= 4*1024*1024,
76 .name
= "Compex WP54AG",
77 .mach_type
= MACH_ADM5120_WP54AG
,
80 .flash0_size
= 4*1024*1024,
83 .name
= "Compex WP54G",
84 .mach_type
= MACH_ADM5120_WP54G
,
87 .flash0_size
= 4*1024*1024,
90 .name
= "Compex WP54G-WRT",
91 .mach_type
= MACH_ADM5120_WP54G_WRT
,
94 .flash0_size
= 4*1024*1024,
97 .name
= "Compex WP54G v1C",
98 .mach_type
= MACH_ADM5120_WP54Gv1C
,
101 .flash0_size
= 2*1024*1024,
104 .name
= "Compex WPP54AG",
105 .mach_type
= MACH_ADM5120_WPP54AG
,
108 .flash0_size
= 4*1024*1024,
111 .name
= "Compex WPP54G",
112 .mach_type
= MACH_ADM5120_WPP54G
,
115 .flash0_size
= 4*1024*1024,
118 .name
= "RouterBOARD RB-111",
119 .mach_type
= MACH_ADM5120_RB_111
,
122 .flash0_size
= 128*1024,
125 .name
= "RouterBOARD RB-112",
126 .mach_type
= MACH_ADM5120_RB_112
,
129 .flash0_size
= 128*1024,
132 .name
= "RouterBOARD RB-133",
133 .mach_type
= MACH_ADM5120_RB_133
,
136 .flash0_size
= 128*1024,
139 .name
= "RouterBOARD RB-133C",
140 .mach_type
= MACH_ADM5120_RB_133C
,
143 .flash0_size
= 128*1024,
146 .name
= "RouterBOARD RB-150",
147 .mach_type
= MACH_ADM5120_RB_150
,
150 .flash0_size
= 128*1024,
153 .name
= "RouterBOARD RB-153",
154 .mach_type
= MACH_ADM5120_RB_153
,
157 .flash0_size
= 128*1024,
160 .name
= "ZyXEL HomeSafe 100/100W",
161 .mach_type
= MACH_ADM5120_HS100
,
164 .flash0_size
= 4*1024*1024,
167 .name
= "ZyXEL Prestige 334",
168 .mach_type
= MACH_ADM5120_P334
,
171 .flash0_size
= 2*1024*1024,
174 .name
= "ZyXEL Prestige 334U",
175 .mach_type
= MACH_ADM5120_P334U
,
178 .flash0_size
= 4*1024*1024,
181 .name
= "ZyXEL Prestige 334W",
182 .mach_type
= MACH_ADM5120_P334W
,
185 .flash0_size
= 2*1024*1024,
188 .name
= "ZyXEL Prestige 334WH",
189 .mach_type
= MACH_ADM5120_P334WH
,
192 .flash0_size
= 4*1024*1024,
195 .name
= "ZyXEL Prestige 334WHD",
196 .mach_type
= MACH_ADM5120_P334WHD
,
199 .flash0_size
= 4*1024*1024,
202 .name
= "ZyXEL Prestige 334WT",
203 .mach_type
= MACH_ADM5120_P334WT
,
206 .flash0_size
= 4*1024*1024,
209 .name
= "ZyXEL Prestige 335/335WT",
210 .mach_type
= MACH_ADM5120_P335
,
213 .flash0_size
= 4*1024*1024,
216 .name
= "ZyXEL Prestige 335Plus",
217 .mach_type
= MACH_ADM5120_P335PLUS
,
220 .flash0_size
= 4*1024*1024,
223 .name
= "ZyXEL Prestige 335U",
224 .mach_type
= MACH_ADM5120_P335U
,
227 .flash0_size
= 4*1024*1024,
230 .name
= "Unknown ADM5120 board",
231 .mach_type
= MACH_ADM5120_UNKNOWN
,
243 unsigned long mach_type
;
246 #define DUMMY_BOARD() {.mach_type = MACH_ADM5120_UNKNOWN}
248 #define MYLO_BOARD(v,d,sv,sd,mt) { .vid = (v), .did = (d), .svid = (sv), \
249 .sdid = (sd), .mach_type = (mt) }
251 #define COMPEX_BOARD(d,mt) MYLO_BOARD(VENID_COMPEX,(d),VENID_COMPEX,(d),(mt))
253 static struct mylo_board __initdata mylo_boards
[] = {
254 COMPEX_BOARD(DEVID_COMPEX_NP27G
, MACH_ADM5120_NP27G
),
255 COMPEX_BOARD(DEVID_COMPEX_NP28G
, MACH_ADM5120_NP28G
),
256 COMPEX_BOARD(DEVID_COMPEX_NP28GHS
, MACH_ADM5120_NP28GHS
),
257 COMPEX_BOARD(DEVID_COMPEX_WP54G
, MACH_ADM5120_WP54G
),
258 COMPEX_BOARD(DEVID_COMPEX_WP54Gv1C
, MACH_ADM5120_WP54Gv1C
),
259 COMPEX_BOARD(DEVID_COMPEX_WP54AG
, MACH_ADM5120_WP54AG
),
260 COMPEX_BOARD(DEVID_COMPEX_WPP54G
, MACH_ADM5120_WPP54G
),
261 COMPEX_BOARD(DEVID_COMPEX_WPP54AG
, MACH_ADM5120_WPP54AG
),
265 #define ROUTERBOARD_NAME_LEN 16
268 unsigned long mach_type
;
269 char name
[ROUTERBOARD_NAME_LEN
];
272 #define ROUTERBOARD(n, mt) { .name = (n), .mach_type = (mt) }
273 static struct routerboard __initdata routerboards
[] = {
274 ROUTERBOARD("111", MACH_ADM5120_RB_111
),
275 ROUTERBOARD("112", MACH_ADM5120_RB_112
),
276 ROUTERBOARD("133", MACH_ADM5120_RB_133
),
277 ROUTERBOARD("133C", MACH_ADM5120_RB_133C
),
278 ROUTERBOARD("miniROUTER", MACH_ADM5120_RB_150
),
279 ROUTERBOARD("153", MACH_ADM5120_RB_150
),
284 unsigned long mach_type
;
285 unsigned int vendor_id
;
289 #define ZYNOS_VENDOR_ID_INVALID 0
290 #define ZYNOS_VENDOR_ID_ZYXEL 1
291 #define ZYNOS_VENDOR_ID_DLINK 2
292 #define ZYNOS_VENDOR_ID_LUCENT 3
294 #define ZYNOS_BOARD(vi, bi, mt) { .vendor_id = (vi), .board_id = (bi), \
297 #define ZYXEL_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_ZYXEL, bi, mt)
298 #define DLINK_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_DLINK, bi, mt)
299 #define LUCENT_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_LUCENT, bi, mt)
301 static struct zynos_board __initdata zynos_boards
[] = {
302 ZYXEL_BOARD(ZYNOS_BOARD_HS100
, MACH_ADM5120_HS100
),
303 ZYXEL_BOARD(ZYNOS_BOARD_P334
, MACH_ADM5120_P334
),
304 ZYXEL_BOARD(ZYNOS_BOARD_P334U
, MACH_ADM5120_P334U
),
305 ZYXEL_BOARD(ZYNOS_BOARD_P334W
, MACH_ADM5120_P334W
),
306 ZYXEL_BOARD(ZYNOS_BOARD_P334WH
, MACH_ADM5120_P334WH
),
307 ZYXEL_BOARD(ZYNOS_BOARD_P334WHD
, MACH_ADM5120_P334WHD
),
308 ZYXEL_BOARD(ZYNOS_BOARD_P334WT
, MACH_ADM5120_P334WT
),
309 ZYXEL_BOARD(ZYNOS_BOARD_P335
, MACH_ADM5120_P335
),
310 ZYXEL_BOARD(ZYNOS_BOARD_P335PLUS
, MACH_ADM5120_P335PLUS
),
311 ZYXEL_BOARD(ZYNOS_BOARD_P335U
, MACH_ADM5120_P335U
),
318 static inline u16
read_le16(void *buf
)
323 return ((u16
)p
[0] + ((u16
)p
[1] << 8));
326 static inline u32
read_le32(void *buf
)
331 return ((u32
)p
[0] + ((u32
)p
[1] << 8) + ((u32
)p
[2] << 16) +
338 #define CFE_EPTSEAL 0x43464531 /* CFE1 is the magic number to recognize CFE
339 from other bootloaders */
341 static int __init
cfe_present(void)
344 * This method only works, when we are booted directly from the CFE.
346 u32 cfe_handle
= (u32
) fw_arg0
;
347 u32 cfe_a1_val
= (u32
) fw_arg1
;
348 u32 cfe_entry
= (u32
) fw_arg2
;
349 u32 cfe_seal
= (u32
) fw_arg3
;
351 /* Check for CFE by finding the CFE magic number */
352 if (cfe_seal
!= CFE_EPTSEAL
) {
353 /* We are not booted from CFE */
357 /* cfe_a1_val must be 0, because only one CPU present in the ADM5120 SoC
359 if (cfe_a1_val
!= 0) {
363 /* The cfe_handle, and the cfe_entry must be kernel mode addresses */
364 if ((cfe_handle
< KSEG0
) || (cfe_entry
< KSEG0
)) {
371 static unsigned long __init
cfe_detect_board(void)
373 return MACH_ADM5120_WP54G_WRT
;
377 * MyLoader based boards
379 #define SYS_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F000)
380 #define BOARD_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F800)
381 #define PART_TABLE_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x10000)
383 static unsigned long __init
myloader_detect_board(void)
385 struct mylo_system_params
*sysp
;
386 struct mylo_board_params
*boardp
;
387 struct mylo_partition_table
*parts
;
388 struct mylo_board
*board
;
391 ret
= MACH_ADM5120_UNKNOWN
;
393 sysp
= (struct mylo_system_params
*)(SYS_PARAMS_ADDR
);
394 boardp
= (struct mylo_board_params
*)(BOARD_PARAMS_ADDR
);
395 parts
= (struct mylo_partition_table
*)(PART_TABLE_ADDR
);
397 /* Check for some magic numbers */
398 if ((le32_to_cpu(sysp
->magic
) != MYLO_MAGIC_SYS_PARAMS
) ||
399 (le32_to_cpu(boardp
->magic
) != MYLO_MAGIC_BOARD_PARAMS
) ||
400 (le32_to_cpu(parts
->magic
) != MYLO_MAGIC_PARTITIONS
))
403 for (board
= mylo_boards
; board
->mach_type
!= MACH_ADM5120_UNKNOWN
;
405 if ((le16_to_cpu(sysp
->vid
) == board
->vid
) &&
406 (le16_to_cpu(sysp
->did
) == board
->did
) &&
407 (le16_to_cpu(sysp
->svid
) == board
->svid
) &&
408 (le16_to_cpu(sysp
->sdid
) == board
->sdid
)) {
409 ret
= board
->mach_type
;
414 /* assume MyLoader as the boot-loader */
415 adm5120_boot_loader
= BOOT_LOADER_MYLOADER
;
422 * RouterBOOT based boards
424 static int __init
routerboot_find_tag(u8
*buf
, u16 tagid
, void **tagval
,
436 if (id
== RB_ID_TERMINATOR
)
439 len
= read_le16(buf
);
454 #define RB_HS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x1000)
455 #define RB_SS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x2000)
456 #define RB_FW_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x10000)
458 static unsigned long __init
routerboot_detect_board(void)
460 struct routerboard
*board
;
466 ret
= MACH_ADM5120_UNKNOWN
;
468 magic
= le32_to_cpu(*(u32
*)RB_HS_ADDR
);
469 if (magic
!= RB_MAGIC_HARD
)
472 magic
= le32_to_cpu(*(u32
*)RB_SS_ADDR
);
473 if ((magic
!= RB_MAGIC_SOFT
) && (magic
!= RB_MAGIC_DAWN
))
476 if (routerboot_find_tag((u8
*)RB_HS_ADDR
, RB_ID_BOARD_NAME
,
477 (void *)&name
, &namelen
))
480 for (board
= routerboards
; board
->mach_type
!= MACH_ADM5120_UNKNOWN
;
482 if (strncmp(board
->name
, name
, strlen(board
->name
)) == 0) {
483 ret
= board
->mach_type
;
489 /* assume RouterBOOT as the boot-loader */
490 adm5120_boot_loader
= BOOT_LOADER_ROUTERBOOT
;
499 #define CHECK_VENDOR(n) (strnicmp(vendor, ZYNOS_VENDOR_ZYXEL, \
500 strlen(ZYNOS_VENDOR_ZYXEL)) == 0)
502 static unsigned int __init
zynos_get_vendor_id(unsigned char *vendor
)
506 ret
= ZYNOS_VENDOR_ID_INVALID
;
508 if CHECK_VENDOR(ZYNOS_VENDOR_ZYXEL
)
509 ret
= ZYNOS_VENDOR_ID_ZYXEL
;
511 /* TODO: there are no known ADM5120 based boards from other vendors */
512 else if CHECK_VENDOR(ZYNOS_VENDOR_DLINK
)
513 ret
= ZYNOS_VENDOR_ID_DLINK
;
514 else if CHECK_VENDOR(ZYNOS_VENDOR_LUCENT
)
515 ret
= ZYNOS_VENDOR_ID_LUCENT
;
521 #define ZYNOS_INFO_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x3F90)
522 #define BOOTEXT_ADDR_2M 0xBFC08000
523 #define BOOTEXT_ADDR_4M 0xBFC10000
525 static unsigned long __init
zynos_detect_board(void)
527 struct zynos_board_info
*info
;
528 struct zynos_board
*board
;
529 unsigned int vendor_id
;
533 ret
= MACH_ADM5120_UNKNOWN
;
535 info
= (struct zynos_board_info
*)(ZYNOS_INFO_ADDR
);
536 vendor_id
= zynos_get_vendor_id(&info
->vendor
);
537 if (vendor_id
== ZYNOS_VENDOR_ID_INVALID
)
540 bootext_addr
= be32_to_cpu(info
->bootext_addr
);
541 if ((bootext_addr
!= BOOTEXT_ADDR_2M
) ||
542 (bootext_addr
!= BOOTEXT_ADDR_4M
))
545 for (board
= zynos_boards
; board
->mach_type
!= MACH_ADM5120_UNKNOWN
;
547 if ((board
->vendor_id
== vendor_id
) &&
548 (board
->board_id
== be16_to_cpu(info
->board_id
))) {
549 ret
= board
->mach_type
;
554 /* assume Bootbase as the boot-loader */
555 adm5120_boot_loader
= BOOT_LOADER_BOOTBASE
;
562 * U-Boot based boards
564 static int __init
uboot_present(void)
566 /* FIXME: not yet implemented */
570 static unsigned long __init
uboot_detect_board(void)
572 /* FIXME: not yet implemented */
573 return MACH_ADM5120_UNKNOWN
;
576 static void __init
adm5120_detect_board(void)
578 struct adm5120_board
*board
;
581 adm5120_boot_loader
= BOOT_LOADER_UNKNOWN
;
583 /* Try to detect board type without bootloader */
584 t
= routerboot_detect_board();
586 if (t
== MACH_ADM5120_UNKNOWN
)
587 t
= zynos_detect_board();
589 if (t
== MACH_ADM5120_UNKNOWN
)
590 t
= myloader_detect_board();
592 /* Try to detect bootloader type */
594 adm5120_boot_loader
= BOOT_LOADER_CFE
;
595 if (t
== MACH_ADM5120_UNKNOWN
)
596 t
= cfe_detect_board();
597 } else if (uboot_present()) {
598 adm5120_boot_loader
= BOOT_LOADER_UBOOT
;
599 if (t
== MACH_ADM5120_UNKNOWN
)
600 t
= uboot_detect_board();
603 for (board
= adm5120_boards
; board
->mach_type
!= MACH_ADM5120_UNKNOWN
;
605 if (board
->mach_type
== t
)
609 memcpy(&adm5120_board
, board
, sizeof(adm5120_board
));
613 * CPU settings detection
615 #define CODE_GET_PC(c) ((c) & CODE_PC_MASK)
616 #define CODE_GET_REV(c) (((c) >> CODE_REV_SHIFT) & CODE_REV_MASK)
617 #define CODE_GET_PK(c) (((c) >> CODE_PK_SHIFT) & CODE_PK_MASK)
618 #define CODE_GET_CLKS(c) (((c) >> CODE_CLKS_SHIFT) & CODE_CLKS_MASK)
619 #define CODE_GET_NAB(c) (((c) & CODE_NAB) != 0)
621 static void __init
adm5120_detect_cpuinfo(void)
626 code
= *(u32
*)KSEG1ADDR(ADM5120_SWITCH_BASE
+SWITCH_REG_CODE
);
628 adm5120_product_code
= CODE_GET_PC(code
);
629 adm5120_revision
= CODE_GET_REV(code
);
630 adm5120_package
= (CODE_GET_PK(code
) == CODE_PK_BGA
) ?
631 ADM5120_PACKAGE_BGA
: ADM5120_PACKAGE_PQFP
;
632 adm5120_nand_boot
= CODE_GET_NAB(code
);
634 clks
= CODE_GET_CLKS(code
);
635 adm5120_speed
= ADM5120_SPEED_175
;
637 adm5120_speed
+= 25000000;
639 adm5120_speed
+= 50000000;
642 void __init
adm5120_info_show(void)
644 /* FIXME: move this somewhere else */
645 printk("ADM%04X%s revision %d, running at %ldMHz\n",
646 adm5120_product_code
,
647 (adm5120_package
== ADM5120_PACKAGE_BGA
) ? "" : "P",
648 adm5120_revision
, (adm5120_speed
/ 1000000)
650 printk("Boot loader is: %s\n", boot_loader_names
[adm5120_boot_loader
]);
651 printk("Booted from : %s flash\n", adm5120_nand_boot
? "NAND":"NOR");
652 printk("Board is : %s\n", adm5120_board_name());
655 void __init
adm5120_info_init(void)
657 adm5120_detect_cpuinfo();
658 adm5120_detect_board();