#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <asm/bootinfo.h>
#include <asm/addrspace.h>
#include <asm/mach-adm5120/adm5120_defs.h>
#include <asm/mach-adm5120/adm5120_switch.h>
+#include <asm/mach-adm5120/adm5120_mpmc.h>
#include <asm/mach-adm5120/adm5120_info.h>
#include <asm/mach-adm5120/myloader.h>
#include <asm/mach-adm5120/routerboot.h>
#include <asm/mach-adm5120/zynos.h>
+extern char *prom_getenv(char *envname);
/*
* Globals
*/
struct adm5120_board adm5120_board;
+EXPORT_SYMBOL_GPL(adm5120_board);
+
unsigned int adm5120_boot_loader;
unsigned int adm5120_product_code;
};
static struct adm5120_board __initdata adm5120_boards[] = {
+ /* FIXME: some boards have invalid fields */
+ {
+ .name = "Cellvision CAS-630/630W",
+ .mach_type = MACH_ADM5120_CAS630,
+ .has_usb = 0,
+ .iface_num = 1,
+ .flash0_size = 4*1024*1024,
+ },
+ {
+ .name = "Cellvision CAS-670/670W",
+ .mach_type = MACH_ADM5120_CAS670,
+ .has_usb = 0,
+ .iface_num = 1,
+ .flash0_size = 4*1024*1024,
+ },
+ {
+ .name = "Cellvision CAS-700/700W",
+ .mach_type = MACH_ADM5120_CAS700,
+ .has_usb = 0,
+ .iface_num = 1,
+ .flash0_size = 4*1024*1024,
+ },
+ {
+ .name = "Cellvision CAS-771/771W",
+ .mach_type = MACH_ADM5120_CAS771,
+ .has_usb = 0,
+ .iface_num = 5,
+ .mem_size = (32 << 20),
+ .flash0_size = 4*1024*1024,
+ },
+ {
+ .name = "Cellvision CAS-790",
+ .mach_type = MACH_ADM5120_CAS790,
+ .has_usb = 0,
+ .iface_num = 1,
+ .flash0_size = 4*1024*1024,
+ },
+ {
+ .name = "Cellvision CAS-861/861W",
+ .mach_type = MACH_ADM5120_CAS861,
+ .has_usb = 0,
+ .iface_num = 1,
+ .flash0_size = 4*1024*1024,
+ },
+ {
+ .name = "Cellvision NFS-101U/101WU",
+ .mach_type = MACH_ADM5120_NFS101U,
+ .has_usb = 0,
+ .iface_num = 1,
+ .flash0_size = 4*1024*1024,
+ },
+ {
+ .name = "Cellvision NFS-202U/202WU",
+ .mach_type = MACH_ADM5120_NFS202U,
+ .has_usb = 0,
+ .iface_num = 1,
+ .flash0_size = 4*1024*1024,
+ },
{
.name = "Compex NetPassage 27G",
.mach_type = MACH_ADM5120_NP27G,
.mach_type = MACH_ADM5120_WP54AG,
.has_usb = 0,
.iface_num = 2,
+ .mem_size = (16 << 20),
.flash0_size = 4*1024*1024,
},
{
.iface_num = 2,
.flash0_size = 4*1024*1024,
},
+ {
+ .name = "Edimax BR-6104K",
+ .mach_type = MACH_ADM5120_BR6104K,
+ .has_usb = 0,
+ .iface_num = 5,
+ .mem_size = (16 << 20),
+ .flash0_size = 2*1024*1024,
+ },
+ {
+ .name = "Infineon EASY 5120",
+ .mach_type = MACH_ADM5120_EASY5120,
+ .has_usb = 0,
+ .iface_num = 0,
+ .flash0_size = 2*1024*1024,
+ },
+ {
+ .name = "Infineon EASY 5120-RT",
+ .mach_type = MACH_ADM5120_EASY5120RT,
+ .has_usb = 0,
+ .iface_num = 0,
+ .flash0_size = 2*1024*1024,
+ },
+ {
+ .name = "Infineon EASY 5120P-ATA",
+ .mach_type = MACH_ADM5120_EASY5120PATA,
+ .has_usb = 0,
+ .iface_num = 0,
+ .flash0_size = 2*1024*1024,
+ },
+ {
+ .name = "Infineon EASY 83000",
+ .mach_type = MACH_ADM5120_EASY83000,
+ .has_usb = 0,
+ .iface_num = 6,
+ .flash0_size = 4*1024*1024,
+ },
{
.name = "RouterBOARD 111",
.mach_type = MACH_ADM5120_RB_111,
.iface_num = 5,
.flash0_size = 128*1024,
},
+ {
+ .name = "ZyXEL ES-2024A",
+ .mach_type = MACH_ADM5120_ES2024A,
+ .has_usb = 0,
+ .iface_num = 0,
+ .flash0_size = 4*1024*1024,
+ },
+ {
+ .name = "ZyXEL ES-2024PWR",
+ .mach_type = MACH_ADM5120_ES2024PWR,
+ .has_usb = 0,
+ .iface_num = 0,
+ .flash0_size = 4*1024*1024,
+ },
{
.name = "ZyXEL ES-2108",
.mach_type = MACH_ADM5120_ES2108,
.flash0_size = 4*1024*1024,
},
{
- .name = "ZyXEL ES-2108PWR",
+ .name = "ZyXEL ES-2108-PWR",
.mach_type = MACH_ADM5120_ES2108PWR,
.has_usb = 0,
.iface_num = 0,
#define COMPEX_BOARD(d,mt) MYLO_BOARD(VENID_COMPEX,(d),VENID_COMPEX,(d),(mt))
-static struct mylo_board __initdata mylo_boards[] = {
+static struct mylo_board mylo_boards[] __initdata = {
COMPEX_BOARD(DEVID_COMPEX_NP27G, MACH_ADM5120_NP27G),
COMPEX_BOARD(DEVID_COMPEX_NP28G, MACH_ADM5120_NP28G),
COMPEX_BOARD(DEVID_COMPEX_NP28GHS, MACH_ADM5120_NP28GHS),
};
#define ROUTERBOARD(n, mt) { .name = (n), .mach_type = (mt) }
-static struct routerboard __initdata routerboards[] = {
+static struct routerboard routerboards[] __initdata = {
ROUTERBOARD("111", MACH_ADM5120_RB_111),
ROUTERBOARD("112", MACH_ADM5120_RB_112),
ROUTERBOARD("133", MACH_ADM5120_RB_133),
#define DLINK_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_DLINK, bi, mt)
#define LUCENT_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_LUCENT, bi, mt)
-static struct zynos_board __initdata zynos_boards[] = {
+static struct zynos_board zynos_boards[] __initdata = {
ZYXEL_BOARD(ZYNOS_BOARD_HS100, MACH_ADM5120_HS100),
ZYXEL_BOARD(ZYNOS_BOARD_P334, MACH_ADM5120_P334),
ZYXEL_BOARD(ZYNOS_BOARD_P334U, MACH_ADM5120_P334U),
DUMMY_BOARD()
};
+struct common_board {
+ char *name;
+ unsigned long mach_type;
+};
+
+#define DEFBOARD(n, mt) { .name = (n), .mach_type = (mt) }
+static struct common_board common_boards[] __initdata = {
+ DEFBOARD("CAS-630", MACH_ADM5120_CAS630),
+ DEFBOARD("CAS-670", MACH_ADM5120_CAS670),
+ DEFBOARD("CAS-700", MACH_ADM5120_CAS700),
+ DEFBOARD("CAS-771", MACH_ADM5120_CAS771),
+ DEFBOARD("CAS-790", MACH_ADM5120_CAS790),
+ DEFBOARD("CAS-861", MACH_ADM5120_CAS861),
+ DEFBOARD("NFS-101U", MACH_ADM5120_NFS101U),
+ DEFBOARD("NFS-202U", MACH_ADM5120_NFS202U),
+ DEFBOARD("EASY 5120", MACH_ADM5120_EASY5120),
+ DEFBOARD("EASY 5120-RT", MACH_ADM5120_EASY5120RT),
+ DEFBOARD("EASY 5120P-ATA", MACH_ADM5120_EASY5120PATA),
+ DEFBOARD("EASY 83000", MACH_ADM5120_EASY83000),
+ DEFBOARD("BR-6104K", MACH_ADM5120_BR6104K),
+ DEFBOARD("WP54G-WRT", MACH_ADM5120_WP54G_WRT),
+ DEFBOARD("P-334WT", MACH_ADM5120_P334WT),
+ DEFBOARD("P-335", MACH_ADM5120_P335),
+};
+
/*
* Helper routines
*/
return MACH_ADM5120_UNKNOWN;
}
+/*
+ * Misc boards
+ */
+static unsigned long __init prom_detect_board(void)
+{
+ char *name;
+ unsigned long ret;
+ int i;
+
+ ret = MACH_ADM5120_UNKNOWN;
+ name = prom_getenv("board_name");
+ if (name == NULL)
+ goto out;
+
+ if (*name == '\0')
+ goto out;
+
+ for (i=0; i<ARRAY_SIZE(common_boards); i++) {
+ if (strcmp(common_boards[i].name, name) == 0) {
+ ret = common_boards[i].mach_type;
+ break;
+ }
+ }
+
+out:
+ return ret;
+}
+
static void __init adm5120_detect_board(void)
{
struct adm5120_board *board;
adm5120_boot_loader = BOOT_LOADER_UBOOT;
if (t == MACH_ADM5120_UNKNOWN)
t = uboot_detect_board();
+ } else {
+ if (t == MACH_ADM5120_UNKNOWN)
+ t = prom_detect_board();
}
for (board = adm5120_boards; board->mach_type != MACH_ADM5120_UNKNOWN;
adm5120_speed += 50000000;
}
-#if 1
-# define mem_dbg(f, ...) prom_printf("mem_detect: " f, ## __VA_ARGS__)
+static void adm5120_ndelay(u32 ns)
+{
+ u32 t;
+
+ SWITCH_WRITE(SWITCH_REG_TIMER, TIMER_PERIOD_DEFAULT);
+ SWITCH_WRITE(SWITCH_REG_TIMER_INT, (TIMER_INT_TOS | TIMER_INT_TOM));
+
+ t = (ns+640) / 640;
+ t &= TIMER_PERIOD_MASK;
+ SWITCH_WRITE(SWITCH_REG_TIMER, t | TIMER_TE);
+
+ /* wait until the timer expires */
+ do {
+ t = SWITCH_READ(SWITCH_REG_TIMER_INT);
+ } while ((t & TIMER_INT_TOS) == 0);
+
+ /* leave the timer disabled */
+ SWITCH_WRITE(SWITCH_REG_TIMER, TIMER_PERIOD_DEFAULT);
+ SWITCH_WRITE(SWITCH_REG_TIMER_INT, (TIMER_INT_TOS | TIMER_INT_TOM));
+}
+
+#define MPMC_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))
+#define MPMC_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v)
+
extern void prom_printf(char *, ...);
+#if 1
+# define mem_dbg(f, a...) prom_printf("mem_detect: " f, ## a)
#else
-# define mem_dbg(f, ...)
+# define mem_dbg(f, a...)
#endif
+#define MEM_WR_DELAY 10000 /* 0.01 usec */
+
+static int mem_check_pattern(u8 *addr, unsigned long offs)
+{
+ volatile u32 *p1 = (volatile u32 *)addr;
+ volatile u32 *p2 = (volatile u32 *)(addr+offs);
+ u32 t,u,v;
+
+ /* save original value */
+ t = *p1;
+ u = *p2;
+
+ if (t != u)
+ return 0;
+
+ v = 0x55555555;
+ if (u == v)
+ v = 0xAAAAAAAA;
+
+ mem_dbg("write 0x%08lX to 0x%08lX\n", v, (unsigned long)p1);
+
+ *p1 = v;
+ mem_dbg("delay %d ns\n", MEM_WR_DELAY);
+ adm5120_ndelay(MEM_WR_DELAY);
+ u = *p2;
+
+ mem_dbg("pattern at 0x%08lX is 0x%08lX\n", (unsigned long)p2, u);
+
+ /* restore original value */
+ *p1 = t;
+
+ return (v == u);
+}
+
static void __init adm5120_detect_memsize(void)
{
u32 memctrl;
u32 size, maxsize;
- volatile u8 *p,*r;
- u8 t;
+ u8 *p;
memctrl = SWITCH_READ(SWITCH_REG_MEMCTRL);
switch (memctrl & MEMCTRL_SDRS_MASK) {
break;
}
- /* FIXME: need to disable buffers for both SDRAM bank? */
+ /* disable buffers for both SDRAM banks */
+ mem_dbg("disable buffers for both banks\n");
+ MPMC_WRITE(MPMC_REG_DC0, MPMC_READ(MPMC_REG_DC0) & ~DC_BE);
+ MPMC_WRITE(MPMC_REG_DC1, MPMC_READ(MPMC_REG_DC1) & ~DC_BE);
- mem_dbg("checking for %ldMB chip\n",maxsize >> 20);
+ mem_dbg("checking for %ldMB chip in 1st bank\n", maxsize >> 20);
/* detect size of the 1st SDRAM bank */
- p = (volatile u8 *)KSEG1ADDR(0);
- t = *p;
+ p = (u8 *)KSEG1ADDR(0);
for (size = 2<<20; size <= (maxsize >> 1); size <<= 1) {
-#if 1
- r = (p+size);
- *p = 0x55;
- mem_dbg("1st pattern at 0x%lx is 0x%02x\n", size, *r);
- if (*r == 0x55) {
- *p = 0xAA;
- mem_dbg("2nd pattern at 0x%lx is 0x%02x\n", size, *r);
- if (*r == 0xAA) {
- /* mirrored address */
- mem_dbg("mirrored data found at 0x%lx\n", size);
- break;
- }
+ if (mem_check_pattern(p, size)) {
+ /* mirrored address */
+ mem_dbg("mirrored data found at offset 0x%lX\n", size);
+ break;
}
-#else
- p[0] = 0x55;
- mem_dbg("1st pattern at 0x%lx is 0x%02x\n", size, p[size]);
- if (p[size] != 0x55)
- continue;
-
- p[0] = 0xAA;
- mem_dbg("2nd pattern at 0x%lx is 0x%02x\n", size, p[size]);
- if (p[size] != 0xAA)
- continue;
-
- /* mirrored address */
- mem_dbg("mirrored data found at 0x%lx\n", size);
- break;
-#endif
}
- *p = t;
- mem_dbg("%ldMB chip found\n", size >> 20);
+ mem_dbg("chip size in 1st bank is %ldMB\n", size >> 20);
+ adm5120_memsize = size;
- if (size == (32 << 20))
- /* if bank size is 32MB, 2nd bank is not supported */
+ if (size != maxsize)
+ /* 2nd bank is not supported */
goto out;
if ((memctrl & MEMCTRL_SDR1_ENABLE) == 0)
- /* if 2nd bank is not enabled, we are done */
+ /* 2nd bank is disabled */
goto out;
/*
* some bootloaders enable 2nd bank, even if the 2nd SDRAM chip
* are missing.
*/
- mem_dbg("checking second bank\n");
- p += (maxsize+size)-1;
- t = *p;
- *p = 0x55;
- if (*p != 0x55)
- goto out;
+ mem_dbg("check presence of 2nd bank\n");
- *p = 0xAA;
- if (*p != 0xAA)
- goto out;
+ p = (u8 *)KSEG1ADDR(maxsize+size-4);
+ if (mem_check_pattern(p, 0)) {
+ adm5120_memsize += size;
+ }
- *p = t;
if (maxsize != size) {
/* adjusting MECTRL register */
memctrl &= ~(MEMCTRL_SDRS_MASK);
}
SWITCH_WRITE(SWITCH_REG_MEMCTRL, memctrl);
}
- size <<= 1;
out:
- adm5120_memsize = size;
- mem_dbg("%ldMB memory found\n",size>>20);
+ /* reenable buffer for both SDRAM banks */
+ mem_dbg("enable buffers for both banks\n");
+ MPMC_WRITE(MPMC_REG_DC0, MPMC_READ(MPMC_REG_DC0) | DC_BE);
+ MPMC_WRITE(MPMC_REG_DC1, MPMC_READ(MPMC_REG_DC1) | DC_BE);
+
+ mem_dbg("%dx%ldMB memory found\n", (adm5120_memsize == size) ? 1 : 2 ,
+ size >>20);
+
+ size = adm5120_board_memsize();
+ if (size > 0 && size != adm5120_memsize) {
+ mem_dbg("wrong memory size detected, board settings will be used\n");
+ adm5120_memsize = size;
+ }
}
void __init adm5120_info_show(void)
{
/* FIXME: move this somewhere else */
- printk("ADM%04X%s revision %d, running at %ldMHz\n",
+ printk(KERN_INFO "ADM%04X%s revision %d, running at %ldMHz\n",
adm5120_product_code,
(adm5120_package == ADM5120_PACKAGE_BGA) ? "" : "P",
adm5120_revision, (adm5120_speed / 1000000)
);
- printk("Boot loader is: %s\n", boot_loader_names[adm5120_boot_loader]);
- printk("Booted from : %s flash\n", adm5120_nand_boot ? "NAND":"NOR");
- printk("Board is : %s\n", adm5120_board_name());
- printk("Memory size : %ldMB\n", adm5120_memsize >> 20);
-}
-
-void __init adm5120_swab_test(void)
-{
-#if CONFIG_ADM5120_HARDWARE_SWAB
- u32 t1,t2;
-
- t1 = 0x1234;
- t2 = __arch__swab16(t1);
- printk("hardware swab16 test %s, data:0x%04X, result:0x%04X\n",
- (t2 == 0x3412) ? "passed" :"failed", t1, t2);
-
- t1 = 0x12345678;
- t2 = __arch__swab32(t1);
- printk("hardware swab32 test %s, data:0x%08X, result:0x%08X\n",
- (t2 == 0x78563412) ? "passed" :"failed", t1, t2);
-
-#endif /* CONFIG_ADM5120_HARDWARE_SWAB */
+ printk(KERN_INFO "Boot loader is: %s\n", boot_loader_names[adm5120_boot_loader]);
+ printk(KERN_INFO "Booted from : %s flash\n", adm5120_nand_boot ? "NAND":"NOR");
+ printk(KERN_INFO "Board is : %s\n", adm5120_board_name());
+ printk(KERN_INFO "Memory size : %ldMB\n", adm5120_memsize >> 20);
}
void __init adm5120_info_init(void)
{
-
adm5120_detect_cpuinfo();
- adm5120_detect_memsize();
adm5120_detect_board();
+ adm5120_detect_memsize();
adm5120_info_show();
- adm5120_swab_test();
}