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,
238 #define DUMMY_BOARD() {.mach_type = MACH_ADM5120_UNKNOWN}
245 unsigned long mach_type;
249 #define MYLO_BOARD(v,d,sv,sd,mt) { .vid = (v), .did = (d), .svid = (sv), \
250 .sdid = (sd), .mach_type = (mt) }
252 #define COMPEX_BOARD(d,mt) MYLO_BOARD(VENID_COMPEX,(d),VENID_COMPEX,(d),(mt))
254 static struct mylo_board __initdata mylo_boards[] = {
255 COMPEX_BOARD(DEVID_COMPEX_NP27G, MACH_ADM5120_NP27G),
256 COMPEX_BOARD(DEVID_COMPEX_NP28G, MACH_ADM5120_NP28G),
257 COMPEX_BOARD(DEVID_COMPEX_NP28GHS, MACH_ADM5120_NP28GHS),
258 COMPEX_BOARD(DEVID_COMPEX_WP54G, MACH_ADM5120_WP54G),
259 COMPEX_BOARD(DEVID_COMPEX_WP54Gv1C, MACH_ADM5120_WP54Gv1C),
260 COMPEX_BOARD(DEVID_COMPEX_WP54AG, MACH_ADM5120_WP54AG),
261 COMPEX_BOARD(DEVID_COMPEX_WPP54G, MACH_ADM5120_WPP54G),
262 COMPEX_BOARD(DEVID_COMPEX_WPP54AG, MACH_ADM5120_WPP54AG),
266 #define ROUTERBOARD_NAME_LEN 16
269 unsigned long mach_type;
270 char name[ROUTERBOARD_NAME_LEN];
273 #define ROUTERBOARD(n, mt) { .name = (n), .mach_type = (mt) }
274 static struct routerboard __initdata routerboards[] = {
275 ROUTERBOARD("111", MACH_ADM5120_RB_111),
276 ROUTERBOARD("112", MACH_ADM5120_RB_112),
277 ROUTERBOARD("133", MACH_ADM5120_RB_133),
278 ROUTERBOARD("133C", MACH_ADM5120_RB_133C),
279 ROUTERBOARD("miniROUTER", MACH_ADM5120_RB_150),
280 ROUTERBOARD("153", MACH_ADM5120_RB_150),
285 unsigned long mach_type;
286 unsigned int vendor_id;
290 #define ZYNOS_BOARD(vi, bi, mt) { .vendor_id = (vi), .board_id = (bi), \
293 #define ZYXEL_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_ZYXEL, bi, mt)
294 #define DLINK_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_DLINK, bi, mt)
295 #define LUCENT_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_LUCENT, bi, mt)
297 static struct zynos_board __initdata zynos_boards[] = {
298 ZYXEL_BOARD(ZYNOS_BOARD_HS100, MACH_ADM5120_HS100),
299 ZYXEL_BOARD(ZYNOS_BOARD_P334, MACH_ADM5120_P334),
300 ZYXEL_BOARD(ZYNOS_BOARD_P334U, MACH_ADM5120_P334U),
301 ZYXEL_BOARD(ZYNOS_BOARD_P334W, MACH_ADM5120_P334W),
302 ZYXEL_BOARD(ZYNOS_BOARD_P334WH, MACH_ADM5120_P334WH),
303 ZYXEL_BOARD(ZYNOS_BOARD_P334WHD, MACH_ADM5120_P334WHD),
304 ZYXEL_BOARD(ZYNOS_BOARD_P334WT, MACH_ADM5120_P334WT),
305 ZYXEL_BOARD(ZYNOS_BOARD_P335, MACH_ADM5120_P335),
306 ZYXEL_BOARD(ZYNOS_BOARD_P335PLUS, MACH_ADM5120_P335PLUS),
307 ZYXEL_BOARD(ZYNOS_BOARD_P335U, MACH_ADM5120_P335U),
314 static inline u16 read_le16(void *buf)
319 return ((u16)p[0] + ((u16)p[1] << 8));
322 static inline u32 read_le32(void *buf)
327 return ((u32)p[0] + ((u32)p[1] << 8) + ((u32)p[2] << 16) +
331 static inline u16 read_be16(void *buf)
336 return (((u16)p[0] << 8) + (u16)p[1]);
339 static inline u32 read_be32(void *buf)
344 return (((u32)p[0] << 24) + ((u32)p[1] << 16) + ((u32)p[2] << 8) +
351 #define CFE_EPTSEAL 0x43464531 /* CFE1 is the magic number to recognize CFE
352 from other bootloaders */
354 static int __init cfe_present(void)
357 * This method only works, when we are booted directly from the CFE.
359 u32 cfe_handle = (u32) fw_arg0;
360 u32 cfe_a1_val = (u32) fw_arg1;
361 u32 cfe_entry = (u32) fw_arg2;
362 u32 cfe_seal = (u32) fw_arg3;
364 /* Check for CFE by finding the CFE magic number */
365 if (cfe_seal != CFE_EPTSEAL) {
366 /* We are not booted from CFE */
370 /* cfe_a1_val must be 0, because only one CPU present in the ADM5120 SoC
372 if (cfe_a1_val != 0) {
376 /* The cfe_handle, and the cfe_entry must be kernel mode addresses */
377 if ((cfe_handle < KSEG0) || (cfe_entry < KSEG0)) {
384 static unsigned long __init cfe_detect_board(void)
386 return MACH_ADM5120_WP54G_WRT;
390 * MyLoader based boards
392 #define SYS_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F000)
393 #define BOARD_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F800)
394 #define PART_TABLE_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x10000)
396 static unsigned long __init myloader_detect_board(void)
398 struct mylo_system_params *sysp;
399 struct mylo_board_params *boardp;
400 struct mylo_partition_table *parts;
401 struct mylo_board *board;
404 ret = MACH_ADM5120_UNKNOWN;
406 sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR);
407 boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR);
408 parts = (struct mylo_partition_table *)(PART_TABLE_ADDR);
410 /* Check for some magic numbers */
411 if ((le32_to_cpu(sysp->magic) != MYLO_MAGIC_SYS_PARAMS) ||
412 (le32_to_cpu(boardp->magic) != MYLO_MAGIC_BOARD_PARAMS) ||
413 (le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS))
416 for (board = mylo_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
418 if ((le16_to_cpu(sysp->vid) == board->vid) &&
419 (le16_to_cpu(sysp->did) == board->did) &&
420 (le16_to_cpu(sysp->svid) == board->svid) &&
421 (le16_to_cpu(sysp->sdid) == board->sdid)) {
422 ret = board->mach_type;
427 /* assume MyLoader as the boot-loader */
428 adm5120_boot_loader = BOOT_LOADER_MYLOADER;
435 * RouterBOOT based boards
437 static int __init routerboot_find_tag(u8 *buf, u16 tagid, void **tagval,
449 if (id == RB_ID_TERMINATOR)
452 len = read_le16(buf);
467 #define RB_HS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x1000)
468 #define RB_SS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x2000)
469 #define RB_FW_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x10000)
471 static unsigned long __init routerboot_detect_board(void)
473 struct routerboard *board;
479 ret = MACH_ADM5120_UNKNOWN;
481 magic = le32_to_cpu(*(u32 *)RB_HS_ADDR);
482 if (magic != RB_MAGIC_HARD)
485 magic = le32_to_cpu(*(u32 *)RB_SS_ADDR);
486 if ((magic != RB_MAGIC_SOFT) && (magic != RB_MAGIC_DAWN))
489 if (routerboot_find_tag((u8 *)RB_HS_ADDR, RB_ID_BOARD_NAME,
490 (void *)&name, &namelen))
493 for (board = routerboards; board->mach_type != MACH_ADM5120_UNKNOWN;
495 if (strncmp(board->name, name, strlen(board->name)) == 0) {
496 ret = board->mach_type;
502 /* assume RouterBOOT as the boot-loader */
503 adm5120_boot_loader = BOOT_LOADER_ROUTERBOOT;
512 static inline u32 zynos_dbgarea_present(u8 *data)
516 t = read_be32(data+5);
517 if (t != ZYNOS_MAGIC_DBGAREA1)
520 t = read_be32(data+9);
521 if (t != ZYNOS_MAGIC_DBGAREA2)
527 #define CHECK_VENDOR(n) (strnicmp(vendor,(n),strlen(n)) == 0)
529 static inline unsigned int zynos_get_vendor_id(struct zynos_board_info *info)
531 unsigned char vendor[ZYNOS_NAME_LEN];
534 for (i=0; i<ZYNOS_NAME_LEN; i++)
535 vendor[i]=info->vendor[i];
537 if CHECK_VENDOR(ZYNOS_VENDOR_ZYXEL)
538 return ZYNOS_VENDOR_ID_ZYXEL;
540 /* TODO: there are no known ADM5120 based boards from other vendors */
541 if CHECK_VENDOR(ZYNOS_VENDOR_DLINK)
542 return ZYNOS_VENDOR_ID_DLINK;
544 if CHECK_VENDOR(ZYNOS_VENDOR_LUCENT)
545 return ZYNOS_VENDOR_ID_LUCENT;
547 if CHECK_VENDOR(ZYNOS_VENDOR_NETGEAR)
548 return ZYNOS_VENDOR_ID_NETGEAR;
551 return ZYNOS_VENDOR_ID_OTHER;
554 static inline u16 zynos_get_board_id(struct zynos_board_info *info)
556 return read_be16(&info->board_id);
559 static inline u32 zynos_get_bootext_addr(struct zynos_board_info *info)
561 return read_be32(&info->bootext_addr);
565 #define ZYNOS_INFO_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x3F90)
566 #define ZYNOS_HDBG_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x4000)
567 #define BOOTEXT_ADDR_MIN KSEG1ADDR(ADM5120_SRAM0_BASE)
568 #define BOOTEXT_ADDR_MAX (BOOTEXT_ADDR_MIN + (2*1024*1024))
570 static unsigned long __init zynos_detect_board(void)
572 struct zynos_board_info *info;
573 struct zynos_board *board;
574 unsigned int vendor_id;
579 ret = MACH_ADM5120_UNKNOWN;
580 /* check presence of the dbgarea */
581 if (zynos_dbgarea_present((u8 *)ZYNOS_HDBG_ADDR) == 0)
584 info = (struct zynos_board_info *)(ZYNOS_INFO_ADDR);
586 /* check for a valid BootExt address */
587 t = zynos_get_bootext_addr(info);
588 if ((t < BOOTEXT_ADDR_MIN) || (t > BOOTEXT_ADDR_MAX))
591 vendor_id = zynos_get_vendor_id(info);
592 board_id = zynos_get_board_id(info);
594 for (board = zynos_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
596 if ((board->vendor_id == vendor_id) &&
597 (board->board_id == board_id)) {
598 ret = board->mach_type;
603 /* assume Bootbase as the boot-loader */
604 adm5120_boot_loader = BOOT_LOADER_BOOTBASE;
611 * U-Boot based boards
613 static int __init uboot_present(void)
615 /* FIXME: not yet implemented */
619 static unsigned long __init uboot_detect_board(void)
621 /* FIXME: not yet implemented */
622 return MACH_ADM5120_UNKNOWN;
625 static void __init adm5120_detect_board(void)
627 struct adm5120_board *board;
630 adm5120_boot_loader = BOOT_LOADER_UNKNOWN;
632 /* Try to detect board type without bootloader */
633 t = routerboot_detect_board();
635 if (t == MACH_ADM5120_UNKNOWN)
636 t = zynos_detect_board();
638 if (t == MACH_ADM5120_UNKNOWN)
639 t = myloader_detect_board();
641 /* Try to detect bootloader type */
643 adm5120_boot_loader = BOOT_LOADER_CFE;
644 if (t == MACH_ADM5120_UNKNOWN)
645 t = cfe_detect_board();
646 } else if (uboot_present()) {
647 adm5120_boot_loader = BOOT_LOADER_UBOOT;
648 if (t == MACH_ADM5120_UNKNOWN)
649 t = uboot_detect_board();
652 for (board = adm5120_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
654 if (board->mach_type == t)
658 memcpy(&adm5120_board, board, sizeof(adm5120_board));
662 * CPU settings detection
664 #define CODE_GET_PC(c) ((c) & CODE_PC_MASK)
665 #define CODE_GET_REV(c) (((c) >> CODE_REV_SHIFT) & CODE_REV_MASK)
666 #define CODE_GET_PK(c) (((c) >> CODE_PK_SHIFT) & CODE_PK_MASK)
667 #define CODE_GET_CLKS(c) (((c) >> CODE_CLKS_SHIFT) & CODE_CLKS_MASK)
668 #define CODE_GET_NAB(c) (((c) & CODE_NAB) != 0)
670 static void __init adm5120_detect_cpuinfo(void)
675 code = *(u32 *)KSEG1ADDR(ADM5120_SWITCH_BASE+SWITCH_REG_CODE);
677 adm5120_product_code = CODE_GET_PC(code);
678 adm5120_revision = CODE_GET_REV(code);
679 adm5120_package = (CODE_GET_PK(code) == CODE_PK_BGA) ?
680 ADM5120_PACKAGE_BGA : ADM5120_PACKAGE_PQFP;
681 adm5120_nand_boot = CODE_GET_NAB(code);
683 clks = CODE_GET_CLKS(code);
684 adm5120_speed = ADM5120_SPEED_175;
686 adm5120_speed += 25000000;
688 adm5120_speed += 50000000;
691 void __init adm5120_info_show(void)
693 /* FIXME: move this somewhere else */
694 printk("ADM%04X%s revision %d, running at %ldMHz\n",
695 adm5120_product_code,
696 (adm5120_package == ADM5120_PACKAGE_BGA) ? "" : "P",
697 adm5120_revision, (adm5120_speed / 1000000)
699 printk("Boot loader is: %s\n", boot_loader_names[adm5120_boot_loader]);
700 printk("Booted from : %s flash\n", adm5120_nand_boot ? "NAND":"NOR");
701 printk("Board is : %s\n", adm5120_board_name());
704 void __init adm5120_info_init(void)
706 adm5120_detect_cpuinfo();
707 adm5120_detect_board();