summaryrefslogtreecommitdiffstats
path: root/target/linux/adm5120/files/arch/mips
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/adm5120/files/arch/mips')
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/Kconfig20
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/Makefile15
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/adm5120_info.c93
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/board.c129
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/boards/Makefile11
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/boards/cellvision.c192
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/boards/compex.c222
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/boards/edimax.c84
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/boards/generic.c53
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/boards/infineon.c167
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/boards/mikrotik.c172
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/boards/zyxel.c127
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/clock.c76
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/gpio.c356
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/irq.c203
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/memory.c179
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/platform.c181
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/prom.c276
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/prom/Makefile9
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/prom/bootbase.c124
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/prom/cfe.c86
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/prom/generic.c60
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/prom/myloader.c75
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/prom/prom_read.h63
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/prom/routerboot.c142
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/reset.c62
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/setup.c73
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/time.c54
-rw-r--r--target/linux/adm5120/files/arch/mips/adm5120/trxsplit.c208
-rw-r--r--target/linux/adm5120/files/arch/mips/pci/fixup-adm5120.c175
-rw-r--r--target/linux/adm5120/files/arch/mips/pci/ops-adm5120.c143
-rw-r--r--target/linux/adm5120/files/arch/mips/pci/pci-adm5120.c80
32 files changed, 3910 insertions, 0 deletions
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/Kconfig b/target/linux/adm5120/files/arch/mips/adm5120/Kconfig
new file mode 100644
index 000000000..7738d8175
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/Kconfig
@@ -0,0 +1,20 @@
+if MIPS_ADM5120
+
+menu "ADM5120 Implementation Options"
+
+config ADM5120_CPU_OVERRIDES
+ bool "Enable CPU feature overrides"
+ default y
+
+config PCI_ADM5120
+ bool "Enable PCI support"
+ select PCI
+ default y
+
+endmenu
+
+config ARM_AMBA
+ bool
+ default y
+
+endif
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/Makefile b/target/linux/adm5120/files/arch/mips/adm5120/Makefile
new file mode 100644
index 000000000..bb0a7c8b0
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the ADMtek ADM5120 SoC specific parts of the kernel
+#
+
+obj-y := setup.o prom.o irq.o memory.o adm5120_info.o
+obj-y += board.o
+obj-y += clock.o
+obj-y += gpio.o
+obj-y += platform.o
+obj-y += reset.o
+obj-y += time.o
+
+obj-y += trxsplit.o
+
+EXTRA_AFLAGS := $(CFLAGS)
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/adm5120_info.c b/target/linux/adm5120/files/arch/mips/adm5120/adm5120_info.c
new file mode 100644
index 000000000..e2ee5ca56
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/adm5120_info.c
@@ -0,0 +1,93 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_switch.h>
+
+unsigned int adm5120_product_code;
+unsigned int adm5120_revision;
+unsigned int adm5120_package;
+unsigned int adm5120_nand_boot;
+unsigned long adm5120_speed;
+
+#define SWITCH_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))
+#define SWITCH_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v)
+
+/*
+ * CPU settings detection
+ */
+#define CODE_GET_PC(c) ((c) & CODE_PC_MASK)
+#define CODE_GET_REV(c) (((c) >> CODE_REV_SHIFT) & CODE_REV_MASK)
+#define CODE_GET_PK(c) (((c) >> CODE_PK_SHIFT) & CODE_PK_MASK)
+#define CODE_GET_CLKS(c) (((c) >> CODE_CLKS_SHIFT) & CODE_CLKS_MASK)
+#define CODE_GET_NAB(c) (((c) & CODE_NAB) != 0)
+
+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));
+}
+
+void __init adm5120_soc_init(void)
+{
+ u32 code;
+ u32 clks;
+
+ code = SWITCH_READ(SWITCH_REG_CODE);
+
+ adm5120_product_code = CODE_GET_PC(code);
+ adm5120_revision = CODE_GET_REV(code);
+ adm5120_package = (CODE_GET_PK(code) == CODE_PK_BGA) ?
+ ADM5120_PACKAGE_BGA : ADM5120_PACKAGE_PQFP;
+ adm5120_nand_boot = CODE_GET_NAB(code);
+
+ clks = CODE_GET_CLKS(code);
+ adm5120_speed = ADM5120_SPEED_175;
+ if (clks & 1)
+ adm5120_speed += 25000000;
+ if (clks & 2)
+ adm5120_speed += 50000000;
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/board.c b/target/linux/adm5120/files/arch/mips/adm5120/board.c
new file mode 100644
index 000000000..74bacaa2e
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/board.c
@@ -0,0 +1,129 @@
+/*
+ * $Id$
+ *
+ * ADM5120 generic board code
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include <asm/bootinfo.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_irq.h>
+#include <asm/mach-adm5120/adm5120_board.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static LIST_HEAD(adm5120_boards);
+static char adm5120_board_name[ADM5120_BOARD_NAMELEN];
+
+const char *get_system_type(void)
+{
+ return adm5120_board_name;
+}
+
+static struct adm5120_board * __init adm5120_board_find(unsigned long machtype)
+{
+ struct list_head *this;
+ struct adm5120_board *board;
+ void *ret;
+
+ ret = NULL;
+ list_for_each(this, &adm5120_boards) {
+ board = list_entry(this, struct adm5120_board, list);
+ if (board->mach_type == machtype) {
+ ret = board;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int __init adm5120_board_setup(void)
+{
+ struct adm5120_board *board;
+ int err;
+
+ board = adm5120_board_find(mips_machtype);
+ if (board == NULL) {
+ printk(KERN_ALERT "adm5120: no board registered for machtype %lu"
+ ", trying generic\n", mips_machtype);
+ board = adm5120_board_find(MACH_ADM5120_GENERIC);
+ if (board == NULL)
+ panic("adm5120: unsupported board\n");
+ }
+
+ printk(KERN_INFO "adm5120: setting up board '%s'\n", board->name);
+
+ memcpy(&adm5120_board_name, board->name, ADM5120_BOARD_NAMELEN);
+
+ adm5120_board_reset = board->board_reset;
+ if (board->eth_num_ports > 0)
+ adm5120_eth_num_ports = board->eth_num_ports;
+
+ if (board->eth_vlans)
+ memcpy(adm5120_eth_vlans, board->eth_vlans,
+ sizeof(adm5120_eth_vlans));
+
+
+ if (board->board_setup)
+ board->board_setup();
+
+ /* register UARTs */
+ amba_device_register(&adm5120_uart0_device, &iomem_resource);
+ amba_device_register(&adm5120_uart1_device, &iomem_resource);
+
+ /* register PCI controller */
+ if (adm5120_package_bga())
+ platform_device_register(&adm5120_pci_device);
+
+ /* register board devices */
+ if (board->num_devices > 0 && board->devices != NULL ) {
+ err = platform_add_devices(board->devices, board->num_devices);
+ if (err)
+ printk(KERN_ALERT "adm5120: adding board devices failed\n");
+ }
+
+ return 0;
+}
+
+void __init adm5120_board_register(struct adm5120_board *board)
+{
+ list_add(&board->list, &adm5120_boards);
+ printk(KERN_INFO "adm5120: registered board '%s'\n", board->name);
+}
+
+void __init adm5120_register_boards(struct adm5120_board **boards,
+ int num)
+{
+ int i;
+
+ for (i=0; i<num; i++)
+ adm5120_board_register(boards[i]);
+}
+
+arch_initcall(adm5120_board_setup);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/Makefile b/target/linux/adm5120/files/arch/mips/adm5120/boards/Makefile
new file mode 100644
index 000000000..a05c89156
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for platforms based on ADM5120 SoC
+#
+
+obj-y += generic.o
+obj-y += cellvision.o
+obj-y += compex.o
+obj-y += edimax.o
+obj-y += infineon.o
+obj-y += mikrotik.o
+obj-y += zyxel.o
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/cellvision.c b/target/linux/adm5120/files/arch/mips/adm5120/boards/cellvision.c
new file mode 100644
index 000000000..f7d44e257
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/cellvision.c
@@ -0,0 +1,192 @@
+/*
+ * $Id$
+ *
+ * Cellvision/SparkLAN boards
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_board.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static void switch_bank_gpio5(unsigned bank)
+{
+ switch (bank) {
+ case 0:
+ gpio_set_value(ADM5120_GPIO_PIN5, 0);
+ break;
+ case 1:
+ gpio_set_value(ADM5120_GPIO_PIN5, 1);
+ break;
+ }
+}
+
+static struct mtd_partition cas6xx_partitions[] = {
+ {
+ .name = "admboot",
+ .offset = 0,
+ .size = 32*1024,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "config",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 32*1024,
+ } , {
+ .name = "nvfs1",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 64*1024,
+ } , {
+ .name = "nvfs2",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 64*1024,
+ } , {
+ .name = "firmware",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+static struct mtd_partition cas7xx_partitions[] = {
+ {
+ .name = "admboot",
+ .offset = 0,
+ .size = 32*1024,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "config",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 32*1024,
+ } , {
+ .name = "nvfs",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 128*1024,
+ } , {
+ .name = "firmware",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+static struct platform_device *cas6xx_devices[] __initdata = {
+ &adm5120_flash0_device,
+};
+
+static struct platform_device *cas7xx_devices[] __initdata = {
+ &adm5120_flash0_device,
+};
+
+static void __init cas6xx_setup(void)
+{
+ gpio_request(ADM5120_GPIO_PIN5, NULL); /* for flash A20 line */
+ gpio_direction_output(ADM5120_GPIO_PIN5, 0);
+
+ /* setup data for flash0 device */
+ adm5120_flash0_data.switch_bank = switch_bank_gpio5;
+ adm5120_flash0_data.nr_parts = ARRAY_SIZE(cas6xx_partitions);
+ adm5120_flash0_data.parts = cas6xx_partitions;
+
+ /* TODO: setup mac address */
+}
+
+static void __init cas7xx_setup(void)
+{
+ gpio_request(ADM5120_GPIO_PIN5, NULL); /* for flash A20 line */
+ gpio_direction_output(ADM5120_GPIO_PIN5, 0);
+
+ /* setup data for flash0 device */
+ adm5120_flash0_data.switch_bank = switch_bank_gpio5;
+ adm5120_flash0_data.nr_parts = ARRAY_SIZE(cas7xx_partitions);
+ adm5120_flash0_data.parts = cas7xx_partitions;
+
+ /* TODO: setup mac address */
+}
+
+static struct adm5120_board cas630_board __initdata = {
+ .mach_type = MACH_ADM5120_CAS630,
+ .name = "Cellvision CAS-630/630W",
+ .board_setup = cas6xx_setup,
+ .eth_num_ports = 1,
+ .num_devices = ARRAY_SIZE(cas6xx_devices),
+ .devices = cas6xx_devices,
+};
+
+static struct adm5120_board cas670_board __initdata = {
+ .mach_type = MACH_ADM5120_CAS670,
+ .name = "Cellvision CAS-670/670W",
+ .board_setup = cas6xx_setup,
+ .eth_num_ports = 1,
+ .num_devices = ARRAY_SIZE(cas6xx_devices),
+ .devices = cas6xx_devices,
+};
+
+static struct adm5120_board cas700_board __initdata = {
+ .mach_type = MACH_ADM5120_CAS700,
+ .name = "Cellvision CAS-700/700W",
+ .board_setup = cas7xx_setup,
+ .eth_num_ports = 1,
+ .num_devices = ARRAY_SIZE(cas7xx_devices),
+ .devices = cas7xx_devices,
+};
+
+static struct adm5120_board cas771_board __initdata = {
+ .mach_type = MACH_ADM5120_CAS771,
+ .name = "Cellvision CAS-771/771W",
+ .board_setup = cas7xx_setup,
+ .eth_num_ports = 1,
+ .num_devices = ARRAY_SIZE(cas7xx_devices),
+ .devices = cas7xx_devices,
+};
+
+static struct adm5120_board cas790_board __initdata = {
+ .mach_type = MACH_ADM5120_CAS790,
+ .name = "Cellvision CAS-790",
+ .board_setup = cas7xx_setup,
+ .eth_num_ports = 1,
+ .num_devices = ARRAY_SIZE(cas7xx_devices),
+ .devices = cas7xx_devices,
+};
+
+static struct adm5120_board cas861_board __initdata = {
+ .mach_type = MACH_ADM5120_CAS861,
+ .name = "Cellvision CAS-861/861W",
+ .board_setup = cas7xx_setup,
+ .eth_num_ports = 1,
+ .num_devices = ARRAY_SIZE(cas7xx_devices),
+ .devices = cas7xx_devices,
+};
+
+static int __init register_boards(void)
+{
+ adm5120_board_register(&cas630_board);
+ adm5120_board_register(&cas670_board);
+ adm5120_board_register(&cas700_board);
+ adm5120_board_register(&cas771_board);
+ adm5120_board_register(&cas790_board);
+ adm5120_board_register(&cas861_board);
+ return 0;
+}
+
+pure_initcall(register_boards);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/compex.c b/target/linux/adm5120/files/arch/mips/adm5120/boards/compex.c
new file mode 100644
index 000000000..620179744
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/compex.c
@@ -0,0 +1,222 @@
+/*
+ * $Id$
+ *
+ * Compex boards
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_board.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static void switch_bank_gpio5(unsigned bank)
+{
+ switch (bank) {
+ case 0:
+ gpio_set_value(ADM5120_GPIO_PIN5, 0);
+ break;
+ case 1:
+ gpio_set_value(ADM5120_GPIO_PIN5, 1);
+ break;
+ }
+}
+
+static void wp54_reset(void)
+{
+ gpio_set_value(ADM5120_GPIO_PIN3, 0);
+}
+
+static struct mtd_partition wp54g_wrt_partitions[] = {
+ {
+ .name = "cfe",
+ .offset = 0,
+ .size = 0x050000,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "trx",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 0x3A0000,
+ } , {
+ .name = "nvram",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 0x010000,
+ }
+};
+
+static struct platform_device *np2xg_devices[] __initdata = {
+ &adm5120_flash0_device,
+ &adm5120_usbc_device,
+};
+
+static struct platform_device *wp54_devices[] __initdata = {
+ &adm5120_flash0_device,
+};
+
+static void __init np2xg_setup(void)
+{
+ gpio_request(ADM5120_GPIO_PIN5, NULL); /* for flash A20 line */
+ gpio_direction_output(ADM5120_GPIO_PIN5, 0);
+
+ /* setup data for flash0 device */
+ adm5120_flash0_data.switch_bank = switch_bank_gpio5;
+
+ /* TODO: setup mac address */
+}
+
+static void __init wp54_setup(void)
+{
+ gpio_request(ADM5120_GPIO_PIN5, NULL); /* for flash A20 line */
+ gpio_direction_output(ADM5120_GPIO_PIN5, 0);
+
+ gpio_request(ADM5120_GPIO_PIN3, NULL); /* for system reset */
+ gpio_direction_output(ADM5120_GPIO_PIN3, 1);
+
+
+ /* setup data for flash0 device */
+ adm5120_flash0_data.switch_bank = switch_bank_gpio5;
+
+ /* TODO: setup mac address */
+}
+
+static void __init wp54_wrt_setup(void)
+{
+ gpio_request(ADM5120_GPIO_PIN5, NULL); /* for flash A20 line */
+ gpio_direction_output(ADM5120_GPIO_PIN5, 0);
+
+ gpio_request(ADM5120_GPIO_PIN3, NULL); /* for system reset */
+ gpio_direction_output(ADM5120_GPIO_PIN3, 1);
+
+ /* setup data for flash0 device */
+ adm5120_flash0_data.switch_bank = switch_bank_gpio5;
+ adm5120_flash0_data.nr_parts = ARRAY_SIZE(wp54g_wrt_partitions);
+ adm5120_flash0_data.parts = wp54g_wrt_partitions;
+
+ /* TODO: setup mac address */
+}
+
+unsigned char np27g_vlans[6] __initdata = {
+ /* FIXME: untested */
+ 0x41, 0x42, 0x44, 0x48, 0x50, 0x00
+};
+
+unsigned char np28g_vlans[6] __initdata = {
+ /* FIXME: untested */
+ 0x41, 0x42, 0x44, 0x48, 0x00, 0x00
+};
+
+unsigned char wp54_vlans[6] __initdata = {
+ /* FIXME: untested */
+ 0x41, 0x42, 0x00, 0x00, 0x00, 0x00
+};
+
+static struct adm5120_board np27g_board __initdata = {
+ .mach_type = MACH_ADM5120_NP27G,
+ .name = "Compex NetPassage 27G",
+ .board_setup = np2xg_setup,
+ .eth_num_ports = 5,
+ .eth_vlans = np27g_vlans,
+ .num_devices = ARRAY_SIZE(np2xg_devices),
+ .devices = np2xg_devices,
+};
+
+static struct adm5120_board np28g_board __initdata = {
+ .mach_type = MACH_ADM5120_NP28G,
+ .name = "Compex NetPassage 28G",
+ .board_setup = np2xg_setup,
+ .eth_num_ports = 4,
+ .eth_vlans = np28g_vlans,
+ .num_devices = ARRAY_SIZE(np2xg_devices),
+ .devices = np2xg_devices,
+};
+
+static struct adm5120_board wp54ag_board __initdata = {
+ .mach_type = MACH_ADM5120_WP54AG,
+ .name = "Compex WP54AG",
+ .board_setup = wp54_setup,
+ .board_reset = wp54_reset,
+ .eth_num_ports = 2,
+ .eth_vlans = wp54_vlans,
+ .num_devices = ARRAY_SIZE(wp54_devices),
+ .devices = wp54_devices,
+};
+
+static struct adm5120_board wp54g_board __initdata = {
+ .mach_type = MACH_ADM5120_WP54G,
+ .name = "Compex WP54G",
+ .board_setup = wp54_setup,
+ .board_reset = wp54_reset,
+ .eth_num_ports = 2,
+ .eth_vlans = wp54_vlans,
+ .num_devices = ARRAY_SIZE(wp54_devices),
+ .devices = wp54_devices,
+};
+
+static struct adm5120_board wp54g_wrt_board __initdata = {
+ .mach_type = MACH_ADM5120_WP54G,
+ .name = "Compex WP54G-WRT",
+ .board_setup = wp54_wrt_setup,
+ .board_reset = wp54_reset,
+ .eth_num_ports = 2,
+ .eth_vlans = wp54_vlans,
+ .num_devices = ARRAY_SIZE(wp54_devices),
+ .devices = wp54_devices,
+};
+
+static struct adm5120_board wpp54ag_board __initdata = {
+ .mach_type = MACH_ADM5120_WPP54AG,
+ .name = "Compex WPP54AG",
+ .board_setup = wp54_setup,
+ .board_reset = wp54_reset,
+ .eth_num_ports = 2,
+ .eth_vlans = wp54_vlans,
+ .num_devices = ARRAY_SIZE(wp54_devices),
+ .devices = wp54_devices,
+};
+
+static struct adm5120_board wpp54g_board __initdata = {
+ .mach_type = MACH_ADM5120_WPP54G,
+ .name = "Compex WPP54G",
+ .board_setup = wp54_setup,
+ .board_reset = wp54_reset,
+ .eth_num_ports = 2,
+ .eth_vlans = wp54_vlans,
+ .num_devices = ARRAY_SIZE(wp54_devices),
+ .devices = wp54_devices,
+};
+
+static int __init register_boards(void)
+{
+ adm5120_board_register(&np27g_board);
+ adm5120_board_register(&np28g_board);
+ adm5120_board_register(&wp54ag_board);
+ adm5120_board_register(&wp54g_board);
+ adm5120_board_register(&wp54g_wrt_board);
+ adm5120_board_register(&wpp54ag_board);
+ adm5120_board_register(&wpp54g_board);
+ return 0;
+}
+
+pure_initcall(register_boards);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/edimax.c b/target/linux/adm5120/files/arch/mips/adm5120/boards/edimax.c
new file mode 100644
index 000000000..a184cbce4
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/edimax.c
@@ -0,0 +1,84 @@
+/*
+ * $Id$
+ *
+ * Edimax boards
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_board.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static struct mtd_partition br6104k_partitions[] = {
+ {
+ .name = "admboot",
+ .offset = 0,
+ .size = 32*1024,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "config",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 32*1024,
+ } , {
+ .name = "firmware",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+static struct platform_device *br6104k_devices[] __initdata = {
+ &adm5120_flash0_device,
+};
+
+static void __init br6104k_setup(void) {
+ /* setup data for flash0 device */
+ adm5120_flash0_data.nr_parts = ARRAY_SIZE(br6104k_partitions);
+ adm5120_flash0_data.parts = br6104k_partitions;
+
+ /* TODO: setup mac addresses, if possible */
+}
+
+unsigned char br6104k_vlans[6] = {
+ 0x41, 0x42, 0x44, 0x48, 0x50, 0x00
+};
+
+static struct adm5120_board br6104k_board __initdata = {
+ .mach_type = MACH_ADM5120_BR6104K,
+ .name = "Edimax BR-6104K",
+ .board_setup = br6104k_setup,
+ .eth_num_ports = 5,
+ .eth_vlans = br6104k_vlans,
+ .num_devices = ARRAY_SIZE(br6104k_devices),
+ .devices = br6104k_devices,
+};
+
+static int __init register_boards(void)
+{
+ adm5120_board_register(&br6104k_board);
+ return 0;
+}
+
+pure_initcall(register_boards);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/generic.c b/target/linux/adm5120/files/arch/mips/adm5120/boards/generic.c
new file mode 100644
index 000000000..de78ca40e
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/generic.c
@@ -0,0 +1,53 @@
+/*
+ * $Id$
+ *
+ * Generic ADM5120 based board
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_board.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static struct platform_device *generic_devices[] __initdata = {
+ &adm5120_flash0_device,
+};
+
+static struct adm5120_board generic_board __initdata = {
+ .mach_type = MACH_ADM5120_GENERIC,
+ .name = "Generic ADM5120 board",
+ .eth_num_ports = 6,
+ .num_devices = ARRAY_SIZE(generic_devices),
+ .devices = generic_devices,
+};
+
+static int __init register_boards(void)
+{
+ adm5120_board_register(&generic_board);
+ return 0;
+}
+
+pure_initcall(register_boards);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/infineon.c b/target/linux/adm5120/files/arch/mips/adm5120/boards/infineon.c
new file mode 100644
index 000000000..ebeb5aa87
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/infineon.c
@@ -0,0 +1,167 @@
+/*
+ * $Id$
+ *
+ * Infineon boards
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_board.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static void switch_bank_gpio3(unsigned bank)
+{
+ switch (bank) {
+ case 0:
+ gpio_set_value(ADM5120_GPIO_PIN3, 0);
+ break;
+ case 1:
+ gpio_set_value(ADM5120_GPIO_PIN3, 1);
+ break;
+ }
+}
+
+static void switch_bank_gpio5(unsigned bank)
+{
+ switch (bank) {
+ case 0:
+ gpio_set_value(ADM5120_GPIO_PIN5, 0);
+ break;
+ case 1:
+ gpio_set_value(ADM5120_GPIO_PIN5, 1);
+ break;
+ }
+}
+
+static struct mtd_partition easy_partitions[] = {
+ {
+ .name = "admboot",
+ .offset = 0,
+ .size = 64*1024,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "boardcfg",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 64*1024,
+ } , {
+ .name = "firmware",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+static struct platform_device *easy5120pata_devices[] __initdata = {
+ &adm5120_flash0_device,
+ /* TODO: add VINETIC2 device? */
+};
+
+static struct platform_device *easy5120rt_devices[] __initdata = {
+ &adm5120_flash0_device,
+ &adm5120_usbc_device
+};
+
+static struct platform_device *easy5120wvoip_devices[] __initdata = {
+ &adm5120_flash0_device,
+ /* TODO: add VINETIC2 device? */
+};
+
+static struct platform_device *easy83000_devices[] __initdata = {
+ &adm5120_flash0_device,
+ /* TODO: add VINAX device? */
+};
+
+static void __init easy_setup_pqfp(void)
+{
+ gpio_request(ADM5120_GPIO_PIN3, NULL); /* for flash A20 line */
+ gpio_direction_output(ADM5120_GPIO_PIN3, 0);
+
+ /* setup data for flash0 device */
+ adm5120_flash0_data.switch_bank = switch_bank_gpio3;
+ adm5120_flash0_data.nr_parts = ARRAY_SIZE(easy_partitions);
+ adm5120_flash0_data.parts = easy_partitions;
+
+ /* TODO: setup mac addresses */
+}
+
+static void __init easy_setup_bga(void)
+{
+ gpio_request(ADM5120_GPIO_PIN5, NULL); /* for flash A20 line */
+ gpio_direction_output(ADM5120_GPIO_PIN5, 0);
+
+ /* setup data for flash0 device */
+ adm5120_flash0_data.switch_bank = switch_bank_gpio5;
+ adm5120_flash0_data.nr_parts = ARRAY_SIZE(easy_partitions);
+ adm5120_flash0_data.parts = easy_partitions;
+
+ /* TODO: setup mac addresses */
+}
+
+static struct adm5120_board easy5120pata_board __initdata = {
+ .mach_type = MACH_ADM5120_EASY5120PATA,
+ .name = "Infineon EASY 5120P-ATA Reference Board",
+ .board_setup = easy_setup_pqfp,
+ .eth_num_ports = 6,
+ .num_devices = ARRAY_SIZE(easy5120pata_devices),
+ .devices = easy5120pata_devices,
+};
+
+static struct adm5120_board easy5120rt_board __initdata = {
+ .mach_type = MACH_ADM5120_EASY5120RT,
+ .name = "Infineon EASY 5120-RT Reference Board",
+ .board_setup = easy_setup_bga,
+ .eth_num_ports = 5,
+ .num_devices = ARRAY_SIZE(easy5120rt_devices),
+ .devices = easy5120rt_devices,
+};
+
+static struct adm5120_board easy5120wvoip_board __initdata = {
+ .mach_type = MACH_ADM5120_EASY5120WVOIP,
+ .name = "Infineon EASY 5120-WVoIP Reference Board",
+ .board_setup = easy_setup_bga,
+ .eth_num_ports = 6,
+ .num_devices = ARRAY_SIZE(easy5120wvoip_devices),
+ .devices = easy5120wvoip_devices,
+};
+
+static struct adm5120_board easy83000_board __initdata = {
+ .mach_type = MACH_ADM5120_EASY83000,
+ .name = "Infineon EASY 83000 Reference Board",
+ .board_setup = easy_setup_pqfp,
+ .eth_num_ports = 6,
+ .num_devices = ARRAY_SIZE(easy83000_devices),
+ .devices = easy83000_devices,
+};
+
+static int __init register_boards(void)
+{
+ adm5120_board_register(&easy5120pata_board);
+ adm5120_board_register(&easy5120rt_board);
+ adm5120_board_register(&easy5120wvoip_board);
+ adm5120_board_register(&easy83000_board);
+ return 0;
+}
+
+pure_initcall(register_boards);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/mikrotik.c b/target/linux/adm5120/files/arch/mips/adm5120/boards/mikrotik.c
new file mode 100644
index 000000000..f233772d0
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/mikrotik.c
@@ -0,0 +1,172 @@
+/*
+ * $Id$
+ *
+ * Mikrotik RouterBOARDs 111/112/133/133C/150/153
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_board.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static struct mtd_partition rb1xx_partitions[] = {
+ {
+ .name = "booter",
+ .offset = 0,
+ .size = 64*1024,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "firmware",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+static struct platform_device *rb1xx_devices[] __initdata = {
+ &adm5120_flash0_device,
+ &adm5120_nand_device,
+};
+
+static struct platform_device *rb150_devices[] __initdata = {
+ &adm5120_flash0_device,
+ /* TODO: nand device is not yet supported */
+};
+
+static void __init rb1xx_setup(void)
+{
+ /* setup data for flash0 device */
+ adm5120_flash0_data.nr_parts = ARRAY_SIZE(rb1xx_partitions);
+ adm5120_flash0_data.parts = rb1xx_partitions;
+
+ /* TODO: setup mac address */
+}
+
+#if 0
+/*
+ * RB1xx boards have bad network performance with the default VLAN matrixes.
+ * Disable it while the ethernet driver gets fixed.
+ */
+static unsigned char rb11x_vlans[6] __initdata = {
+ /* FIXME: untested */
+ 0x41, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char rb133_vlans[6] __initdata = {
+ /* FIXME: untested */
+ 0x44, 0x42, 0x41, 0x00, 0x00, 0x00
+};
+
+static unsigned char rb133c_vlans[6] __initdata = {
+ /* FIXME: untested */
+ 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char rb15x_vlans[6] __initdata = {
+ /* FIXME: untested */
+ 0x41, 0x42, 0x44, 0x48, 0x50, 0x00
+};
+#else
+static unsigned char rb_vlans[6] __initdata = {
+ 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#define rb11x_vlans rb_vlans
+#define rb133_vlans rb_vlans
+#define rb133c_vlans rb_vlans
+#define rb15x_vlans rb_vlans
+#endif
+
+static struct adm5120_board rb111_board __initdata = {
+ .mach_type = MACH_ADM5120_RB_111,
+ .name = "Mikrotik RouterBOARD 111",
+ .board_setup = rb1xx_setup,
+ .eth_num_ports = 1,
+ .eth_vlans = rb11x_vlans,
+ .num_devices = ARRAY_SIZE(rb1xx_devices),
+ .devices = rb1xx_devices,
+};
+
+static struct adm5120_board rb112_board __initdata = {
+ .mach_type = MACH_ADM5120_RB_112,
+ .name = "Mikrotik RouterBOARD 112",
+ .board_setup = rb1xx_setup,
+ .eth_num_ports = 1,
+ .eth_vlans = rb11x_vlans,
+ .num_devices = ARRAY_SIZE(rb1xx_devices),
+ .devices = rb1xx_devices,
+};
+
+static struct adm5120_board rb133_board __initdata = {
+ .mach_type = MACH_ADM5120_RB_133,
+ .name = "Mikrotik RouterBOARD 133",
+ .board_setup = rb1xx_setup,
+ .eth_num_ports = 3,
+ .eth_vlans = rb133_vlans,
+ .num_devices = ARRAY_SIZE(rb1xx_devices),
+ .devices = rb1xx_devices,
+};
+
+static struct adm5120_board rb133c_board __initdata = {
+ .mach_type = MACH_ADM5120_RB_133C,
+ .name = "Mikrotik RouterBOARD 133C",
+ .board_setup = rb1xx_setup,
+ .eth_num_ports = 1,
+ .eth_vlans = rb133c_vlans,
+ .num_devices = ARRAY_SIZE(rb1xx_devices),
+ .devices = rb1xx_devices,
+};
+
+static struct adm5120_board rb150_board __initdata = {
+ .mach_type = MACH_ADM5120_RB_150,
+ .name = "Mikrotik RouterBOARD 150",
+ .board_setup = rb1xx_setup,
+ .eth_num_ports = 5,
+ .eth_vlans = rb15x_vlans,
+ .num_devices = ARRAY_SIZE(rb150_devices),
+ .devices = rb150_devices,
+};
+
+static struct adm5120_board rb153_board __initdata = {
+ .mach_type = MACH_ADM5120_RB_153,
+ .name = "Mikrotik RouterBOARD 153",
+ .board_setup = rb1xx_setup,
+ .eth_num_ports = 5,
+ .eth_vlans = rb15x_vlans,
+ .num_devices = ARRAY_SIZE(rb1xx_devices),
+ .devices = rb1xx_devices,
+};
+
+static int __init register_boards(void)
+{
+ adm5120_board_register(&rb111_board);
+ adm5120_board_register(&rb112_board);
+ adm5120_board_register(&rb133_board);
+ adm5120_board_register(&rb133c_board);
+ adm5120_board_register(&rb150_board);
+ adm5120_board_register(&rb153_board);
+ return 0;
+}
+
+pure_initcall(register_boards);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/zyxel.c b/target/linux/adm5120/files/arch/mips/adm5120/boards/zyxel.c
new file mode 100644
index 000000000..0a60205eb
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/zyxel.c
@@ -0,0 +1,127 @@
+/*
+ * $Id$
+ *
+ * ZyXEL Prestige P-334/P-335 boards
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_board.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static void switch_bank_gpio5(unsigned bank)
+{
+ switch (bank) {
+ case 0:
+ gpio_set_value(ADM5120_GPIO_PIN5, 0);
+ break;
+ case 1:
+ gpio_set_value(ADM5120_GPIO_PIN5, 1);
+ break;
+ }
+}
+
+static struct mtd_partition p33x_partitions[] = {
+ {
+ .name = "bootbase",
+ .offset = 0,
+ .size = 16*1024,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "rom",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 16*1024,
+ } , {
+ .name = "bootext",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 96*1024,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "trx",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ } , {
+ .name = "firmware",
+ .offset = 32*1024,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+static struct platform_device *p334_devices[] __initdata = {
+ &adm5120_flash0_device,
+};
+
+static struct platform_device *p335_devices[] __initdata = {
+ &adm5120_flash0_device,
+ &adm5120_usbc_device,
+};
+
+static void __init p33x_setup(void)
+{
+ gpio_request(ADM5120_GPIO_PIN5, NULL); /* for flash A20 line */
+ gpio_direction_output(ADM5120_GPIO_PIN5, 0);
+
+ /* setup data for flash0 device */
+ adm5120_flash0_data.switch_bank = switch_bank_gpio5;
+ adm5120_flash0_data.nr_parts = ARRAY_SIZE(p33x_partitions);
+ adm5120_flash0_data.parts = p33x_partitions;
+
+ /* TODO: setup mac address */
+}
+
+unsigned char p33x_vlans[6] __initdata = {
+ /* FIXME: untested */
+ 0x50, 0x48, 0x44, 0x42, 0x41, 0x00
+};
+
+static struct adm5120_board p334wt_board __initdata = {
+ .mach_type = MACH_ADM5120_P334WT,
+ .name = "ZyXEL Prestige 334WT",
+ .board_setup = p33x_setup,
+ .eth_num_ports = 5,
+ .eth_vlans = p33x_vlans,
+ .num_devices = ARRAY_SIZE(p334_devices),
+ .devices = p334_devices,
+};
+
+static struct adm5120_board p335_board __initdata = {
+ .mach_type = MACH_ADM5120_P335,
+ .name = "ZyXEL Prestige 335/335WT",
+ .board_setup = p33x_setup,
+ .eth_num_ports = 5,
+ .eth_vlans = p33x_vlans,
+ .num_devices = ARRAY_SIZE(p335_devices),
+ .devices = p335_devices,
+};
+
+static int __init register_boards(void)
+{
+ adm5120_board_register(&p334wt_board);
+ adm5120_board_register(&p335_board);
+ return 0;
+}
+
+pure_initcall(register_boards);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/clock.c b/target/linux/adm5120/files/arch/mips/adm5120/clock.c
new file mode 100644
index 000000000..4a8b69b4c
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/clock.c
@@ -0,0 +1,76 @@
+/*
+ * $Id$
+ *
+ * ADM5120 minimal CLK API implementation
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This file was based on the CLK API implementation in:
+ * arch/mips/tx4938/toshiba_rbtx4938/setup.c
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ * 2003-2005 (c) MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/mach-adm5120/adm5120_defs.h>
+
+struct clk {
+ unsigned long rate;
+};
+
+static struct clk uart_clk = {
+ .rate = ADM5120_UART_CLOCK
+};
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ if (!strcmp(id, "UARTCLK"))
+ return &uart_clk;
+
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/gpio.c b/target/linux/adm5120/files/arch/mips/adm5120/gpio.c
new file mode 100644
index 000000000..d073b659a
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/gpio.c
@@ -0,0 +1,356 @@
+/*
+ * $Id$
+ *
+ * ADM5120 GPIO support
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_switch.h>
+
+typedef void __iomem * gpio_reg_t;
+#define GPIO_READ(r) readl((r))
+#define GPIO_WRITE(v,r) writel((v),(r))
+#define GPIO_REG(r) (gpio_reg_t)(KSEG1ADDR(ADM5120_SWITCH_BASE)+r)
+
+struct adm5120_gpio_line {
+ u32 flags;
+ const char *label;
+};
+
+#define GPIO_FLAG_VALID 0x01
+#define GPIO_FLAG_USED 0x02
+
+struct led_desc {
+ gpio_reg_t reg; /* LED register address */
+ u8 iv_shift; /* shift amount for input bit */
+ u8 mode_shift; /* shift amount for mode bits */
+};
+
+#define LED_DESC(_port,_led) { \
+ .reg = GPIO_REG(SWITCH_REG_PORT0_LED+_port*4), \
+ .iv_shift = LED0_IV_SHIFT+_led, \
+ .mode_shift = _led*4 \
+ }
+
+static struct led_desc led_table[15] = {
+ LED_DESC(0, 0), LED_DESC(0, 1), LED_DESC(0, 2),
+ LED_DESC(1, 0), LED_DESC(1, 1), LED_DESC(1, 2),
+ LED_DESC(2, 0), LED_DESC(2, 1), LED_DESC(2, 2),
+ LED_DESC(3, 0), LED_DESC(3, 1), LED_DESC(3, 2),
+ LED_DESC(4, 0), LED_DESC(4, 1), LED_DESC(4, 2)
+};
+
+static struct adm5120_gpio_line adm5120_gpio_map[ADM5120_GPIO_COUNT] = {
+ [ADM5120_GPIO_PIN0] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_PIN1] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_PIN2] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_PIN3] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_PIN4] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_PIN5] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_PIN6] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_PIN7] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P0L0] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P0L1] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P0L2] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P1L0] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P1L1] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P1L2] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P2L0] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P2L1] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P2L2] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P3L0] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P3L1] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P3L2] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P4L0] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P4L1] = {.flags = GPIO_FLAG_VALID},
+ [ADM5120_GPIO_P4L2] = {.flags = GPIO_FLAG_VALID}
+};
+
+#define gpio_is_invalid(g) ( \
+ (g) > ADM5120_GPIO_MAX || \
+ ((adm5120_gpio_map[(g)].flags & GPIO_FLAG_VALID) == 0) \
+ )
+
+#define gpio_is_used(g) ((adm5120_gpio_map[(g)].flags & GPIO_FLAG_USED) != 0)
+
+/*
+ * Helpers for GPIO lines in GPIO_CONF0 register
+ */
+#define PIN_IM(p) ((1 << GPIO_CONF0_IM_SHIFT) << p)
+#define PIN_IV(p) ((1 << GPIO_CONF0_IV_SHIFT) << p)
+#define PIN_OE(p) ((1 << GPIO_CONF0_OE_SHIFT) << p)
+#define PIN_OV(p) ((1 << GPIO_CONF0_OV_SHIFT) << p)
+
+static inline int pins_direction_input(unsigned pin)
+{
+ gpio_reg_t *reg;
+ u32 t;
+
+ reg = GPIO_REG(SWITCH_REG_GPIO_CONF0);
+
+ t = GPIO_READ(reg);
+ t &= ~(PIN_OE(pin));
+ t |= PIN_IM(pin);
+ GPIO_WRITE(t,reg);
+
+ return 0;
+}
+
+static inline int pins_direction_output(unsigned pin, int value)
+{
+ gpio_reg_t *reg;
+ u32 t;
+
+ reg = GPIO_REG(SWITCH_REG_GPIO_CONF0);
+
+ t = GPIO_READ(reg);
+ t &= ~(PIN_IM(pin) | PIN_OV(pin));
+ t |= PIN_OE(pin);
+
+ if (value)
+ t |= PIN_OV(pin);
+
+ GPIO_WRITE(t,reg);
+
+ return 0;
+}
+
+static inline int pins_get_value(unsigned pin)
+{
+ gpio_reg_t *reg;
+ u32 t;
+
+ reg = GPIO_REG(SWITCH_REG_GPIO_CONF0);
+
+ t = GPIO_READ(reg);
+ if ((t & PIN_IM(pin)) != 0)
+ t &= PIN_IV(pin);
+ else
+ t &= PIN_OV(pin);
+
+ return (t) ? 1 : 0;
+}
+
+static inline void pins_set_value(unsigned pin, int value)
+{
+ gpio_reg_t *reg;
+ u32 t;
+
+ reg = GPIO_REG(SWITCH_REG_GPIO_CONF0);
+
+ t = GPIO_READ(reg);
+ if (value == 0)
+ t &= ~(PIN_OV(pin));
+ else
+ t |= PIN_OV(pin);
+
+ GPIO_WRITE(t,reg);
+}
+
+/*
+ * Helpers for GPIO lines in PORTx_LED registers
+ */
+static inline int leds_direction_input(unsigned led)
+{
+ gpio_reg_t *reg;
+ u32 t;
+
+ reg = led_table[led].reg;
+ t = GPIO_READ(reg);
+ t &= ~(LED_MODE_MASK << led_table[led].mode_shift);
+ GPIO_WRITE(t,reg);
+
+ return 0;
+}
+
+static inline int leds_direction_output(unsigned led, int value)
+{
+ gpio_reg_t *reg;
+ u32 t, s;
+
+ reg = led_table[led].reg;
+ s = led_table[led].mode_shift;
+
+ t = GPIO_READ(reg);
+ t &= ~(LED_MODE_MASK << s);
+
+ switch (value) {
+ case ADM5120_GPIO_LOW:
+ t |= (LED_MODE_OUT_LOW << s);
+ break;
+ case ADM5120_GPIO_FLASH:
+ case ADM5120_GPIO_LINK:
+ case ADM5120_GPIO_SPEED:
+ case ADM5120_GPIO_DUPLEX:
+ case ADM5120_GPIO_ACT:
+ case ADM5120_GPIO_COLL:
+ case ADM5120_GPIO_LINK_ACT:
+ case ADM5120_GPIO_DUPLEX_COLL:
+ case ADM5120_GPIO_10M_ACT:
+ case ADM5120_GPIO_100M_ACT:
+ t |= ((value & LED_MODE_MASK) << s);
+ break;
+ default:
+ t |= (LED_MODE_OUT_HIGH << s);
+ break;
+ }
+
+ GPIO_WRITE(t,reg);
+
+ return 0;
+}
+
+static inline int leds_get_value(unsigned led)
+{
+ gpio_reg_t *reg;
+ u32 t, m;
+
+ reg = led_table[led].reg;
+
+ t = GPIO_READ(reg);
+ m = (t >> led_table[led].mode_shift) & LED_MODE_MASK;
+ if (m == LED_MODE_INPUT)
+ return (t >> led_table[led].iv_shift) & 1;
+
+ if (m == LED_MODE_OUT_LOW)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Main GPIO support routines
+ */
+int adm5120_gpio_direction_input(unsigned gpio)
+{
+ if (gpio_is_invalid(gpio))
+ return -EINVAL;
+
+ if (gpio < ADM5120_GPIO_P0L0)
+ return pins_direction_input(gpio);
+
+ gpio -= ADM5120_GPIO_P0L0;
+ return leds_direction_input(gpio);
+}
+
+int adm5120_gpio_direction_output(unsigned gpio, int value)
+{
+ if (gpio_is_invalid(gpio))
+ return -EINVAL;
+
+ if (gpio < ADM5120_GPIO_P0L0)
+ return pins_direction_output(gpio, value);
+
+ gpio -= ADM5120_GPIO_P0L0;
+ return leds_direction_output(gpio, value);
+}
+
+int adm5120_gpio_get_value(unsigned gpio)
+{
+ if (gpio < ADM5120_GPIO_P0L0)
+ return pins_get_value(gpio);
+
+ gpio -= ADM5120_GPIO_P0L0;
+ return leds_get_value(gpio);
+}
+
+void adm5120_gpio_set_value(unsigned gpio, int value)
+{
+ if (gpio < ADM5120_GPIO_P0L0) {
+ pins_set_value(gpio, value);
+ return;
+ }
+
+ gpio -= ADM5120_GPIO_P0L0;
+ leds_direction_output(gpio, value);
+}
+
+int adm5120_gpio_request(unsigned gpio, const char *label)
+{
+ if (gpio_is_invalid(gpio))
+ return -EINVAL;
+
+ if (gpio_is_used(gpio))
+ return -EBUSY;
+
+ adm5120_gpio_map[gpio].flags |= GPIO_FLAG_USED;
+ adm5120_gpio_map[gpio].label = label;
+
+ return 0;
+}
+
+void adm5120_gpio_free(unsigned gpio)
+{
+ if (gpio_is_invalid(gpio))
+ return;
+
+ adm5120_gpio_map[gpio].flags &= ~GPIO_FLAG_USED;
+ adm5120_gpio_map[gpio].label = NULL;
+}
+
+int adm5120_gpio_to_irq(unsigned gpio)
+{
+ /* FIXME: not yet implemented */
+ return -EINVAL;
+}
+
+int adm5120_irq_to_gpio(unsigned irq)
+{
+ /* FIXME: not yet implemented */
+ return -EINVAL;
+}
+
+static int __init adm5120_gpio_init(void)
+{
+ int i;
+
+ if (adm5120_package_pqfp()) {
+ /* GPIO pins 4-7 are unavailable in ADM5120P */
+ for (i=ADM5120_GPIO_PIN4; i<=ADM5120_GPIO_PIN7; i++)
+ adm5120_gpio_map[i].flags &= ~GPIO_FLAG_VALID;
+ }
+
+ return 0;
+}
+
+pure_initcall(adm5120_gpio_init);
+
+EXPORT_SYMBOL(adm5120_gpio_direction_output);
+EXPORT_SYMBOL(adm5120_gpio_direction_input);
+EXPORT_SYMBOL(adm5120_gpio_get_value);
+EXPORT_SYMBOL(adm5120_gpio_set_value);
+EXPORT_SYMBOL(adm5120_gpio_request);
+EXPORT_SYMBOL(adm5120_gpio_free);
+EXPORT_SYMBOL(adm5120_gpio_to_irq);
+EXPORT_SYMBOL(adm5120_irq_to_gpio);
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/irq.c b/target/linux/adm5120/files/arch/mips/adm5120/irq.c
new file mode 100644
index 000000000..8d6fbe6a3
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/irq.c
@@ -0,0 +1,203 @@
+/*
+ * $Id$
+ *
+ * ADM5120 specific interrupt handlers
+ *
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2007 OpenWrt.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/irq.h>
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/bitops.h>
+
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_irq.h>
+
+#define INTC_REG(r) (*(volatile u32 *)(KSEG1ADDR(ADM5120_INTC_BASE) + r))
+
+static void adm5120_intc_irq_unmask(unsigned int irq);
+static void adm5120_intc_irq_mask(unsigned int irq);
+static int adm5120_intc_irq_set_type(unsigned int irq, unsigned int flow_type);
+
+static struct irq_chip adm5120_intc_irq_chip = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ .name = "INTC",
+#else
+ .typename = "INTC",
+#endif
+ .unmask = adm5120_intc_irq_unmask,
+ .mask = adm5120_intc_irq_mask,
+ .mask_ack = adm5120_intc_irq_mask,
+ .set_type = adm5120_intc_irq_set_type
+};
+
+static struct irqaction adm5120_intc_irq_action = {
+ .handler = no_action,
+ .name = "cascade [INTC]"
+};
+
+static void adm5120_intc_irq_unmask(unsigned int irq)
+{
+ unsigned long flags;
+
+ irq -= ADM5120_INTC_IRQ_BASE;
+ local_irq_save(flags);
+ INTC_REG(INTC_REG_IRQ_ENABLE) = (1 << irq);
+ local_irq_restore(flags);
+}
+
+static void adm5120_intc_irq_mask(unsigned int irq)
+{
+ unsigned long flags;
+
+ irq -= ADM5120_INTC_IRQ_BASE;
+ local_irq_save(flags);
+ INTC_REG(INTC_REG_IRQ_DISABLE) = (1 << irq);
+ local_irq_restore(flags);
+}
+
+static int adm5120_intc_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+ /* TODO: not yet tested */
+#if 1
+ unsigned int sense;
+ unsigned long mode;
+ int err;
+
+ err = 0;
+ sense = flow_type & (IRQ_TYPE_SENSE_MASK);
+ switch (sense) {
+ case IRQ_TYPE_NONE:
+ case IRQ_TYPE_LEVEL_HIGH:
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ switch (irq) {
+ case ADM5120_IRQ_GPIO2:
+ case ADM5120_IRQ_GPIO4:
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ if (err)
+ return err;
+
+ switch (irq) {
+ case ADM5120_IRQ_GPIO2:
+ case ADM5120_IRQ_GPIO4:
+ mode = INTC_REG(INTC_REG_INT_MODE);
+ if (sense == IRQ_TYPE_LEVEL_LOW)
+ mode |= (1 << (irq-ADM5120_INTC_IRQ_BASE));
+ else
+ mode &= (1 << (irq-ADM5120_INTC_IRQ_BASE));
+
+ INTC_REG(INTC_REG_INT_MODE) = mode;
+ /* fallthrogh */
+ default:
+ irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
+ irq_desc[irq].status |= sense;
+ break;
+ }
+#endif
+ return 0;
+}
+
+static void adm5120_intc_irq_dispatch(void)
+{
+ unsigned long status;
+ int irq;
+
+#if 1
+ /* dispatch only one IRQ at a time */
+ status = INTC_REG(INTC_REG_IRQ_STATUS) & INTC_INT_ALL;
+
+ if (status) {
+ irq = ADM5120_INTC_IRQ_BASE+fls(status)-1;
+ do_IRQ(irq);
+ } else
+ spurious_interrupt();
+#else
+ status = INTC_REG(INTC_REG_IRQ_STATUS) & INTC_INT_ALL;
+ if (status) {
+ for (irq=ADM5120_INTC_IRQ_BASE; irq <= ADM5120_INTC_IRQ_BASE +
+ INTC_IRQ_LAST; irq++, status >>=1) {
+ if ((status & 1) == 1)
+ do_IRQ(irq);
+ }
+ } else
+ spurious_interrupt();
+#endif
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned long pending;
+
+ pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP7)
+ do_IRQ(ADM5120_IRQ_COUNTER);
+ else if (pending & STATUSF_IP2)
+ adm5120_intc_irq_dispatch();
+ else
+ spurious_interrupt();
+}
+
+#define INTC_IRQ_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED)
+static void __init adm5120_intc_irq_init(int base)
+{
+ int i;
+
+ /* disable all interrupts */
+ INTC_REG(INTC_REG_IRQ_DISABLE) = INTC_INT_ALL;
+ /* setup all interrupts to generate IRQ instead of FIQ */
+ INTC_REG(INTC_REG_INT_MODE) = 0;
+ /* set active level for all external interrupts to HIGH */
+ INTC_REG(INTC_REG_INT_LEVEL) = 0;
+ /* disable usage of the TEST_SOURCE register */
+ INTC_REG(INTC_REG_IRQ_SOURCE_SELECT) = 0;
+
+ for(i=ADM5120_INTC_IRQ_BASE; i <= ADM5120_INTC_IRQ_BASE+INTC_IRQ_LAST;
+ i++) {
+ irq_desc[i].status = INTC_IRQ_STATUS;
+ set_irq_chip_and_handler(i, &adm5120_intc_irq_chip,
+ handle_level_irq);
+ }
+
+ setup_irq(ADM5120_IRQ_INTC, &adm5120_intc_irq_action);
+}
+
+void __init arch_init_irq(void) {
+ mips_cpu_irq_init();
+ adm5120_intc_irq_init(ADM5120_INTC_IRQ_BASE);
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/memory.c b/target/linux/adm5120/files/arch/mips/adm5120/memory.c
new file mode 100644
index 000000000..1bde6b02d
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/memory.c
@@ -0,0 +1,179 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_switch.h>
+#include <asm/mach-adm5120/adm5120_mpmc.h>
+
+#define SWITCH_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))
+#define SWITCH_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v)
+
+#define MPMC_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))
+#define MPMC_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v)
+
+#if 1
+# define mem_dbg(f, a...) printk("mem_detect: " f, ## a)
+#else
+# define mem_dbg(f, a...)
+#endif
+
+#define MEM_WR_DELAY 10000 /* 0.01 usec */
+
+unsigned long adm5120_memsize;
+
+static int __init 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%08X 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%08X\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;
+ u8 *p;
+
+ memctrl = SWITCH_READ(SWITCH_REG_MEMCTRL);
+ switch (memctrl & MEMCTRL_SDRS_MASK) {
+ case MEMCTRL_SDRS_4M:
+ maxsize = 4 << 20;
+ break;
+ case MEMCTRL_SDRS_8M:
+ maxsize = 8 << 20;
+ break;
+ case MEMCTRL_SDRS_16M:
+ maxsize = 16 << 20;
+ break;
+ default:
+ maxsize = 64 << 20;
+ break;
+ }
+
+ /* 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 %uMB chip in 1st bank\n", maxsize >> 20);
+
+ /* detect size of the 1st SDRAM bank */
+ p = (u8 *)KSEG1ADDR(0);
+ for (size = 2<<20; size <= (maxsize >> 1); size <<= 1) {
+ if (mem_check_pattern(p, size)) {
+ /* mirrored address */
+ mem_dbg("mirrored data found at offset 0x%08X\n", size);
+ break;
+ }
+ }
+
+ mem_dbg("chip size in 1st bank is %uMB\n", size >> 20);
+ adm5120_memsize = size;
+
+ if (size != maxsize)
+ /* 2nd bank is not supported */
+ goto out;
+
+ if ((memctrl & MEMCTRL_SDR1_ENABLE) == 0)
+ /* 2nd bank is disabled */
+ goto out;
+
+ /*
+ * some bootloaders enable 2nd bank, even if the 2nd SDRAM chip
+ * are missing.
+ */
+ mem_dbg("check presence of 2nd bank\n");
+
+ p = (u8 *)KSEG1ADDR(maxsize+size-4);
+ if (mem_check_pattern(p, 0)) {
+ adm5120_memsize += size;
+ }
+
+ if (maxsize != size) {
+ /* adjusting MECTRL register */
+ memctrl &= ~(MEMCTRL_SDRS_MASK);
+ switch (size>>20) {
+ case 4:
+ memctrl |= MEMCTRL_SDRS_4M;
+ break;
+ case 8:
+ memctrl |= MEMCTRL_SDRS_8M;
+ break;
+ case 16:
+ memctrl |= MEMCTRL_SDRS_16M;
+ break;
+ default:
+ memctrl |= MEMCTRL_SDRS_64M;
+ break;
+ }
+ SWITCH_WRITE(SWITCH_REG_MEMCTRL, memctrl);
+ }
+
+out:
+ /* 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%uMB memory found\n", (adm5120_memsize == size) ? 1 : 2 ,
+ size >>20);
+}
+
+void __init adm5120_mem_init(void)
+{
+ adm5120_detect_memsize();
+ add_memory_region(0, adm5120_memsize, BOOT_MEM_RAM);
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/platform.c b/target/linux/adm5120/files/arch/mips/adm5120/platform.c
new file mode 100644
index 000000000..a79893d54
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/platform.c
@@ -0,0 +1,181 @@
+/*
+ * $Id$
+ *
+ * Generic ADM5120 platform devices
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include <asm/bootinfo.h>
+#include <asm/gpio.h>
+
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_irq.h>
+#include <asm/mach-adm5120/adm5120_switch.h>
+#include <asm/mach-adm5120/adm5120_platform.h>
+
+static void adm5120_uart_set_mctrl(struct amba_device *dev, void __iomem *base,
+ unsigned int mctrl);
+
+#if 1
+/*
+ * TODO:remove global adm5120_eth* variables when the switch driver will be
+ * converted into a real platform driver
+ */
+unsigned int adm5120_eth_num_ports = 6;
+EXPORT_SYMBOL_GPL(adm5120_eth_num_ports);
+
+unsigned char adm5120_eth_macs[6][6] = {
+ {'\00', 'A', 'D', 'M', '\x51', '\x20' },
+ {'\00', 'A', 'D', 'M', '\x51', '\x21' },
+ {'\00', 'A', 'D', 'M', '\x51', '\x22' },
+ {'\00', 'A', 'D', 'M', '\x51', '\x23' },
+ {'\00', 'A', 'D', 'M', '\x51', '\x24' },
+ {'\00', 'A', 'D', 'M', '\x51', '\x25' }
+};
+EXPORT_SYMBOL_GPL(adm5120_eth_macs);
+
+unsigned char adm5120_eth_vlans[6] = {
+ 0x41, 0x42, 0x44, 0x48, 0x50, 0x60
+};
+EXPORT_SYMBOL_GPL(adm5120_eth_vlans);
+
+#else
+/* Built-in ethernet switch */
+struct adm5120_switch_platform_data adm5120_switch_data;
+struct platform_device adm5120_switch_device = {
+ .name = "adm5120-switch",
+ .id = -1,
+ .dev.platform_data = &adm5120_switch_data,
+};
+#endif
+
+/* PCI Host Controller */
+struct adm5120_pci_platform_data adm5120_pci_data;
+struct platform_device adm5120_pci_device = {
+ .name = "adm5120-pci",
+ .id = -1,
+ .dev.platform_data = &adm5120_pci_data,
+};
+
+/* USB Host Controller */
+struct resource adm5120_usbc_resources[] = {
+ [0] = {
+ .start = ADM5120_USBC_BASE,
+ .end = ADM5120_USBC_BASE+ADM5120_USBC_SIZE-1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = ADM5120_IRQ_USBC,
+ .end = ADM5120_IRQ_USBC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device adm5120_usbc_device = {
+ .name = "adm5120-hcd",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(adm5120_usbc_resources),
+ .resource = adm5120_usbc_resources,
+};
+
+/* NOR flash 0 */
+struct adm5120_flash_platform_data adm5120_flash0_data;
+struct platform_device adm5120_flash0_device = {
+ .name = "adm5120-flash",
+ .id = 0,
+ .dev.platform_data = &adm5120_flash0_data,
+};
+
+/* NOR flash 1 */
+struct adm5120_flash_platform_data adm5120_flash1_data;
+struct platform_device adm5120_flash1_device = {
+ .name = "adm5120-flash",
+ .id = 1,
+ .dev.platform_data = &adm5120_flash1_data,
+};
+
+/* NAND flash */
+struct resource adm5120_nand_resource[] = {
+ [0] = {
+ .start = ADM5120_SRAM1_BASE,
+ .end = ADM5120_SRAM1_BASE+ADM5120_MPMC_SIZE-1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct adm5120_nand_platform_data adm5120_nand_data;
+
+struct platform_device adm5120_nand_device = {
+ .name = "adm5120-nand",
+ .id = -1,
+ .dev.platform_data = &adm5120_nand_data,
+ .num_resources = ARRAY_SIZE(adm5120_nand_resource),
+ .resource = adm5120_nand_resource,
+};
+
+/* built-in UARTs */
+struct amba_pl010_data adm5120_uart0_data = {
+ .set_mctrl = adm5120_uart_set_mctrl
+};
+
+struct amba_device adm5120_uart0_device = {
+ .dev = {
+ .bus_id = "APB:UART0",
+ .platform_data = &adm5120_uart0_data,
+ },
+ .res = {
+ .start = ADM5120_UART0_BASE,
+ .end = ADM5120_UART0_BASE + ADM5120_UART_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ .irq = { ADM5120_IRQ_UART0, -1 },
+ .periphid = 0x0041010,
+};
+
+struct amba_pl010_data adm5120_uart1_data = {
+ .set_mctrl = adm5120_uart_set_mctrl
+};
+
+struct amba_device adm5120_uart1_device = {
+ .dev = {
+ .bus_id = "APB:UART1",
+ .platform_data = &adm5120_uart1_data,
+ },
+ .res = {
+ .start = ADM5120_UART1_BASE,
+ .end = ADM5120_UART1_BASE + ADM5120_UART_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ .irq = { ADM5120_IRQ_UART1, -1 },
+ .periphid = 0x0041010,
+};
+
+static void adm5120_uart_set_mctrl(struct amba_device *dev, void __iomem *base,
+ unsigned int mctrl)
+{
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/prom.c b/target/linux/adm5120/files/arch/mips/adm5120/prom.c
new file mode 100644
index 000000000..2187477d0
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/prom.c
@@ -0,0 +1,276 @@
+/*
+ * $Id$
+ *
+ * ADM5120 specific prom routines
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_uart.h>
+
+#include <prom/cfe.h>
+#include <prom/generic.h>
+#include <prom/routerboot.h>
+#include <prom/myloader.h>
+#include <prom/zynos.h>
+
+unsigned int adm5120_prom_type = ADM5120_PROM_GENERIC;
+
+struct board_desc {
+ unsigned long mach_type;
+ char *name;
+};
+
+#define DEFBOARD(n, mt) { .mach_type = (mt), .name = (n)}
+static struct board_desc common_boards[] __initdata = {
+ /* Cellvision/SparkLAN boards */
+ DEFBOARD("CAS-630", MACH_ADM5120_CAS630),
+ DEFBOARD("CAS-670", MACH_ADM5120_CAS670),
+ DEFBOARD("CAS-771", MACH_ADM5120_CAS771),
+ DEFBOARD("CAS-790", MACH_ADM5120_CAS790),
+ DEFBOARD("CAS-861", MACH_ADM5120_CAS861),
+ /* Compex boards */
+ DEFBOARD("WP54G-WRT", MACH_ADM5120_WP54G_WRT),
+ /* Edimax boards */
+ DEFBOARD("BR-6104K", MACH_ADM5120_BR6104K),
+ DEFBOARD("BR-6104KP", MACH_ADM5120_BR6104K),
+ /* Infineon boards */
+ DEFBOARD("EASY 5120P-ATA", MACH_ADM5120_EASY5120PATA),
+ DEFBOARD("EASY 5120-RT", MACH_ADM5120_EASY5120RT),
+ DEFBOARD("EASY 5120-WVoIP", MACH_ADM5120_EASY5120WVOIP),
+ DEFBOARD("EASY 83000", MACH_ADM5120_EASY83000),
+ /* Mikrotik RouterBOARDs */
+ DEFBOARD("111", MACH_ADM5120_RB_111),
+ DEFBOARD("112", MACH_ADM5120_RB_112),
+ DEFBOARD("133", MACH_ADM5120_RB_133),
+ DEFBOARD("133C", MACH_ADM5120_RB_133C),
+ DEFBOARD("133C3", MACH_ADM5120_RB_133C),
+ DEFBOARD("150", MACH_ADM5120_RB_153), /* it's intentional */
+ DEFBOARD("153", MACH_ADM5120_RB_153),
+ DEFBOARD("miniROUTER", MACH_ADM5120_RB_150),
+};
+
+static unsigned long __init find_machtype_byname(char *name)
+{
+ unsigned long ret;
+ int i;
+
+ ret = MACH_ADM5120_GENERIC;
+ 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 unsigned long __init detect_machtype_routerboot(void)
+{
+ char *name;
+
+ name = routerboot_get_boardname();
+ return find_machtype_byname(name);
+}
+
+static unsigned long __init detect_machtype_generic(void)
+{
+ char *name;
+
+ name = generic_prom_getenv("board_name");
+ return find_machtype_byname(name);
+}
+
+unsigned long __init detect_machtype_cfe(void)
+{
+ char *name;
+
+ name = cfe_getenv("BOARD_NAME");
+ return find_machtype_byname(name);
+}
+
+static struct {
+ unsigned long mach_type;
+ u16 vendor_id;
+ u16 board_id;
+} zynos_boards[] __initdata = {
+#define ZYNOS_BOARD(vi, bi, mt) { .vendor_id = (vi), .board_id = (bi), \
+ .mach_type = (mt) }
+
+#define ZYXEL_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_ZYXEL, bi, mt)
+#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)
+ ZYXEL_BOARD(ZYNOS_BOARD_HS100, MACH_ADM5120_HS100),
+ ZYXEL_BOARD(ZYNOS_BOARD_P334, MACH_ADM5120_P334),
+ ZYXEL_BOARD(ZYNOS_BOARD_P334U, MACH_ADM5120_P334U),
+ ZYXEL_BOARD(ZYNOS_BOARD_P334W, MACH_ADM5120_P334W),
+ ZYXEL_BOARD(ZYNOS_BOARD_P334WH, MACH_ADM5120_P334WH),
+ ZYXEL_BOARD(ZYNOS_BOARD_P334WHD, MACH_ADM5120_P334WHD),
+ ZYXEL_BOARD(ZYNOS_BOARD_P334WT, MACH_ADM5120_P334WT),
+ ZYXEL_BOARD(ZYNOS_BOARD_P335, MACH_ADM5120_P335),
+ ZYXEL_BOARD(ZYNOS_BOARD_P335PLUS, MACH_ADM5120_P335PLUS),
+ ZYXEL_BOARD(ZYNOS_BOARD_P335U, MACH_ADM5120_P335U)
+};
+
+static unsigned long __init detect_machtype_bootbase(void)
+{
+ unsigned long ret;
+ int i;
+
+ ret = MACH_ADM5120_GENERIC;
+ for (i=0; i<ARRAY_SIZE(zynos_boards); i++) {
+ if (zynos_boards[i].vendor_id == bootbase_info.vendor_id &&
+ zynos_boards[i].board_id == bootbase_info.board_id) {
+ ret = zynos_boards[i].mach_type;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static struct {
+ unsigned long mach_type;
+ u16 vid;
+ u16 did;
+ u16 svid;
+ u16 sdid;
+} mylo_boards[] __initdata = {
+#define MYLO_BOARD(v,d,sv,sd,mt) { .vid = (v), .did = (d), .svid = (sv), \
+ .sdid = (sd), .mach_type = (mt) }
+#define COMPEX_BOARD(d,mt) MYLO_BOARD(VENID_COMPEX,(d),VENID_COMPEX,(d),(mt))
+
+ COMPEX_BOARD(DEVID_COMPEX_NP27G, MACH_ADM5120_NP27G),
+ COMPEX_BOARD(DEVID_COMPEX_NP28G, MACH_ADM5120_NP28G),
+ COMPEX_BOARD(DEVID_COMPEX_NP28GHS, MACH_ADM5120_NP28GHS),
+ COMPEX_BOARD(DEVID_COMPEX_WP54G, MACH_ADM5120_WP54G),
+ COMPEX_BOARD(DEVID_COMPEX_WP54Gv1C, MACH_ADM5120_WP54Gv1C),
+ COMPEX_BOARD(DEVID_COMPEX_WP54AG, MACH_ADM5120_WP54AG),
+ COMPEX_BOARD(DEVID_COMPEX_WPP54G, MACH_ADM5120_WPP54G),
+ COMPEX_BOARD(DEVID_COMPEX_WPP54AG, MACH_ADM5120_WPP54AG),
+};
+
+static unsigned long __init detect_machtype_myloader(void)
+{
+ unsigned long ret;
+ int i;
+
+ ret = MACH_ADM5120_GENERIC;
+ for (i=0; i<ARRAY_SIZE(mylo_boards); i++) {
+ if (mylo_boards[i].vid == myloader_info.vid &&
+ mylo_boards[i].did == myloader_info.did &&
+ mylo_boards[i].svid == myloader_info.svid &&
+ mylo_boards[i].sdid == myloader_info.sdid) {
+ ret = mylo_boards[i].mach_type;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void __init prom_detect_machtype(void)
+{
+ if (bootbase_present()) {
+ adm5120_prom_type = ADM5120_PROM_BOOTBASE;
+ mips_machtype = detect_machtype_bootbase();
+ return;
+ }
+
+ if (cfe_present()) {
+ adm5120_prom_type = ADM5120_PROM_CFE;
+ mips_machtype = detect_machtype_cfe();
+ return;
+ }
+
+ if (myloader_present()) {
+ adm5120_prom_type = ADM5120_PROM_MYLOADER;
+ mips_machtype = detect_machtype_myloader();
+ return;
+ }
+
+ if (routerboot_present()) {
+ adm5120_prom_type = ADM5120_PROM_ROUTERBOOT;
+ mips_machtype = detect_machtype_routerboot();
+ return;
+ }
+
+ if (generic_prom_present()) {
+ adm5120_prom_type = ADM5120_PROM_GENERIC;
+ mips_machtype = detect_machtype_generic();
+ return;
+ }
+
+ mips_machtype = MACH_ADM5120_GENERIC;
+}
+
+/* TODO: this is an ugly hack for RouterBOARDS */
+extern char _image_cmdline;
+static void __init prom_init_cmdline(void)
+{
+ char *cmd;
+
+ /* init command line, register a default kernel command line */
+ cmd = &_image_cmdline + 8;
+ if( strlen(cmd) > 0) strcpy( &(arcs_cmdline[0]), cmd);
+ else strcpy(&(arcs_cmdline[0]), CONFIG_CMDLINE);
+
+}
+
+#define UART_READ(r) *(volatile u32 *)(KSEG1ADDR(ADM5120_UART0_BASE)+(r))
+#define UART_WRITE(r,v) *(volatile u32 *)(KSEG1ADDR(ADM5120_UART0_BASE)+(r))=(v)
+
+void __init prom_putchar(char ch)
+{
+ while ((UART_READ(UART_REG_FLAG) & UART_FLAG_TXFE) == 0);
+ UART_WRITE(UART_REG_DATA, ch);
+ while ((UART_READ(UART_REG_FLAG) & UART_FLAG_TXFE) == 0);
+}
+
+void __init prom_init(void)
+{
+ mips_machgroup = MACH_GROUP_ADM5120;
+ prom_detect_machtype();
+
+ prom_init_cmdline();
+}
+
+void __init prom_free_prom_memory(void)
+{
+ /* We do not have to prom memory to free */
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/prom/Makefile b/target/linux/adm5120/files/arch/mips/adm5120/prom/Makefile
new file mode 100644
index 000000000..d844b600f
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/prom/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the ADMtek ADM5120 SoC specific parts of the kernel
+#
+
+lib-y += bootbase.o
+lib-y += cfe.o
+lib-y += generic.o
+lib-y += myloader.o
+lib-y += routerboot.o
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/prom/bootbase.c b/target/linux/adm5120/files/arch/mips/adm5120/prom/bootbase.c
new file mode 100644
index 000000000..7ab9d46bd
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/prom/bootbase.c
@@ -0,0 +1,124 @@
+/*
+ * $Id$
+ *
+ * ZyXEL's Bootbase specific prom routines
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+#include <asm/byteorder.h>
+
+#include <adm5120_defs.h>
+#include <prom/zynos.h>
+#include "prom_read.h"
+
+#define ZYNOS_INFO_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x3F90)
+#define ZYNOS_HDBG_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x4000)
+#define BOOTEXT_ADDR_MIN KSEG1ADDR(ADM5120_SRAM0_BASE)
+#define BOOTEXT_ADDR_MAX (BOOTEXT_ADDR_MIN + (2*1024*1024))
+
+static int bootbase_found = 0;
+static struct zynos_board_info *board_info;
+
+struct bootbase_info bootbase_info;
+
+static inline int bootbase_dbgarea_present(u8 *data)
+{
+ u32 t;
+
+ t = prom_read_be32(data+5);
+ if (t != ZYNOS_MAGIC_DBGAREA1)
+ return 0;
+
+ t = prom_read_be32(data+9);
+ if (t != ZYNOS_MAGIC_DBGAREA2)
+ return 0;
+
+ return 1;
+}
+
+static inline u32 bootbase_get_bootext_addr(void)
+{
+ return prom_read_be32(&board_info->bootext_addr);
+}
+
+static inline u16 bootbase_get_vendor_id(void)
+{
+#define CHECK_VENDOR(n) (strnicmp(board_info->vendor,(n),strlen(n)) == 0)
+ unsigned char vendor[ZYNOS_NAME_LEN];
+ int i;
+
+ for (i=0; i<ZYNOS_NAME_LEN; i++)
+ vendor[i]=board_info->vendor[i];
+
+ if CHECK_VENDOR(ZYNOS_VENDOR_ZYXEL)
+ return ZYNOS_VENDOR_ID_ZYXEL;
+
+ if CHECK_VENDOR(ZYNOS_VENDOR_DLINK)
+ return ZYNOS_VENDOR_ID_DLINK;
+
+ if CHECK_VENDOR(ZYNOS_VENDOR_LUCENT)
+ return ZYNOS_VENDOR_ID_LUCENT;
+
+ if CHECK_VENDOR(ZYNOS_VENDOR_NETGEAR)
+ return ZYNOS_VENDOR_ID_NETGEAR;
+
+ return ZYNOS_VENDOR_ID_OTHER;
+}
+
+static inline u16 bootbase_get_board_id(void)
+{
+ return prom_read_be16(&board_info->board_id);
+}
+
+int __init bootbase_present(void)
+{
+ u32 t;
+
+ if (bootbase_found)
+ goto out;
+
+ /* check presence of the dbgarea */
+ if (bootbase_dbgarea_present((u8 *)ZYNOS_HDBG_ADDR) == 0)
+ goto out;
+
+ board_info = (struct zynos_board_info *)(ZYNOS_INFO_ADDR);
+
+ /* check for a valid BootExt address */
+ t = bootbase_get_bootext_addr();
+ if ((t < BOOTEXT_ADDR_MIN) || (t > BOOTEXT_ADDR_MAX))
+ goto out;
+
+ bootbase_info.vendor_id = bootbase_get_vendor_id();
+ bootbase_info.board_id = bootbase_get_board_id();
+
+ bootbase_found = 1;
+
+out:
+ return bootbase_found;
+}
+
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/prom/cfe.c b/target/linux/adm5120/files/arch/mips/adm5120/prom/cfe.c
new file mode 100644
index 000000000..6c03a4e85
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/prom/cfe.c
@@ -0,0 +1,86 @@
+/*
+ * $Id$
+ *
+ * Broadcom's CFE specific prom routines
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include <prom/cfe.h>
+#include "prom_read.h"
+
+/*
+ * CFE based boards
+ */
+#define CFE_EPTSEAL 0x43464531 /* CFE1 is the magic number to recognize CFE
+from other bootloaders */
+
+static int cfe_found = 0;
+
+static u32 cfe_handle;
+static u32 cfe_entry;
+static u32 cfe_seal;
+
+int __init cfe_present(void)
+{
+ /*
+ * This method only works, when we are booted directly from the CFE.
+ */
+ u32 a1 = (u32) fw_arg1;
+
+ if (cfe_found)
+ return 1;
+
+ cfe_handle = (u32) fw_arg0;
+ cfe_entry = (u32) fw_arg2;
+ cfe_seal = (u32) fw_arg3;
+
+ /* Check for CFE by finding the CFE magic number */
+ if (cfe_seal != CFE_EPTSEAL) {
+ /* We are not booted from CFE */
+ return 0;
+ }
+
+ /* cfe_a1_val must be 0, because only one CPU present in the ADM5120 */
+ if (a1 != 0) {
+ return 0;
+ }
+
+ /* The cfe_handle, and the cfe_entry must be kernel mode addresses */
+ if ((cfe_handle < KSEG0) || (cfe_entry < KSEG0)) {
+ return 0;
+ }
+
+ cfe_found = 1;
+ return 1;
+}
+
+char *cfe_getenv(char *envname)
+{
+ if (cfe_found == 0)
+ return NULL;
+
+ return NULL;
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/prom/generic.c b/target/linux/adm5120/files/arch/mips/adm5120/prom/generic.c
new file mode 100644
index 000000000..3b5c3bdc0
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/prom/generic.c
@@ -0,0 +1,60 @@
+/*
+ * $Id$
+ *
+ * Generic PROM routines
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+#include <prom/generic.h>
+
+static int *_prom_argc;
+static char **_prom_argv;
+static char **_prom_envp;
+
+char *generic_prom_getenv(char *envname)
+{
+ char **env;
+ char *ret;
+
+ ret = NULL;
+ for (env = _prom_envp; *env != NULL; env++) {
+ if (strcmp(envname, *env++) == 0) {
+ ret = *env;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int generic_prom_present(void)
+{
+ _prom_argc = (int *)fw_arg0;
+ _prom_argv = (char **)fw_arg1;
+ _prom_envp = (char **)fw_arg2;
+
+ return 1;
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/prom/myloader.c b/target/linux/adm5120/files/arch/mips/adm5120/prom/myloader.c
new file mode 100644
index 000000000..8a44509a0
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/prom/myloader.c
@@ -0,0 +1,75 @@
+/*
+ * $Id$
+ *
+ * Compex's MyLoader specific prom routines
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+#include <asm/byteorder.h>
+
+#include <adm5120_defs.h>
+#include <prom/myloader.h>
+#include "prom_read.h"
+
+#define SYS_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F000)
+#define BOARD_PARAMS_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x0F800)
+#define PART_TABLE_ADDR KSEG1ADDR(ADM5120_SRAM0_BASE+0x10000)
+
+static int myloader_found = 0;
+
+struct myloader_info myloader_info;
+
+int __init myloader_present(void)
+{
+ struct mylo_system_params *sysp;
+ struct mylo_board_params *boardp;
+ struct mylo_partition_table *parts;
+
+ if (myloader_found)
+ goto out;
+
+ sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR);
+ boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR);
+ parts = (struct mylo_partition_table *)(PART_TABLE_ADDR);
+
+ /* Check for some magic numbers */
+ if ((le32_to_cpu(sysp->magic) != MYLO_MAGIC_SYS_PARAMS) ||
+ (le32_to_cpu(boardp->magic) != MYLO_MAGIC_BOARD_PARAMS) ||
+ (le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS))
+ goto out;
+
+ myloader_info.vid = le32_to_cpu(sysp->vid);
+ myloader_info.did = le32_to_cpu(sysp->did);
+ myloader_info.svid = le32_to_cpu(sysp->svid);
+ myloader_info.sdid = le32_to_cpu(sysp->sdid);
+
+ myloader_found = 1;
+
+out:
+ return myloader_found;
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/prom/prom_read.h b/target/linux/adm5120/files/arch/mips/adm5120/prom/prom_read.h
new file mode 100644
index 000000000..06e6863fe
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/prom/prom_read.h
@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ *
+ * Generic prom definitions
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _ADM5120_PROM_H_
+#define _ADM5120_PROM_H_
+
+/*
+ * Helper routines
+ */
+static inline u16 prom_read_le16(void *buf)
+{
+ u8 *p = buf;
+
+ return ((u16)p[0] + ((u16)p[1] << 8));
+}
+
+static inline u32 prom_read_le32(void *buf)
+{
+ u8 *p = buf;
+
+ return ((u32)p[0] + ((u32)p[1] << 8) + ((u32)p[2] << 16) +
+ ((u32)p[3] << 24));
+}
+
+static inline u16 prom_read_be16(void *buf)
+{
+ u8 *p = buf;
+
+ return (((u16)p[0] << 8) + (u16)p[1]);
+}
+
+static inline u32 prom_read_be32(void *buf)
+{
+ u8 *p = buf;
+
+ return (((u32)p[0] << 24) + ((u32)p[1] << 16) + ((u32)p[2] << 8) +
+ ((u32)p[3]));
+}
+
+#endif /* _ADM5120_PROM_H_ */
+
+
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/prom/routerboot.c b/target/linux/adm5120/files/arch/mips/adm5120/prom/routerboot.c
new file mode 100644
index 000000000..7116f412f
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/prom/routerboot.c
@@ -0,0 +1,142 @@
+/*
+ * $Id$
+ *
+ * Mikrotik's RouterBOOT specific prom routines
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include <adm5120_defs.h>
+#include <prom/routerboot.h>
+#include "prom_read.h"
+
+static struct rb_hard_settings rb_hs;
+static int rb_found = 0;
+
+static int __init routerboot_load_hs(u8 *buf, u16 buflen)
+{
+ u16 id,len;
+ u8 *mac;
+ int i,j;
+
+ memset(&rb_hs, 0, sizeof(rb_hs));
+
+ if (buflen < 4)
+ return -1;
+
+ if (prom_read_le32(buf) != RB_MAGIC_HARD)
+ return -1;
+
+ /* skip magic value */
+ buf += 4;
+ buflen -= 4;
+
+ while (buflen > 2) {
+ id = prom_read_le16(buf);
+ buf += 2;
+ buflen -= 2;
+ if (id == RB_ID_TERMINATOR || buflen < 2)
+ break;
+
+ len = prom_read_le16(buf);
+ buf += 2;
+ buflen -= 2;
+
+ if (buflen < len)
+ break;
+
+ switch (id) {
+ case RB_ID_BIOS_VERSION:
+ rb_hs.bios_ver = (char *)buf;
+ break;
+ case RB_ID_BOARD_NAME:
+ rb_hs.name = (char *)buf;
+ break;
+ case RB_ID_MEMORY_SIZE:
+ rb_hs.mem_size = prom_read_le32(buf);
+ break;
+ case RB_ID_MAC_ADDRESS_COUNT:
+ rb_hs.mac_count = prom_read_le32(buf);
+ break;
+ case RB_ID_MAC_ADDRESS_PACK:
+ rb_hs.mac_count = len/RB_MAC_SIZE;
+ if (rb_hs.mac_count > RB_MAX_MAC_COUNT)
+ rb_hs.mac_count = RB_MAX_MAC_COUNT;
+ mac = buf;
+ for (i=0; i < rb_hs.mac_count; i++) {
+ for (j=0; j < RB_MAC_SIZE; j++)
+ rb_hs.macs[i][j] = mac[j];
+ mac += RB_MAC_SIZE;
+ }
+ break;
+ }
+
+ buf += len;
+ buflen -= len;
+
+ }
+
+ return 0;
+}
+
+#define RB_BS_OFFS 0x14
+#define RB_OFFS_MAX (128*1024)
+
+int __init routerboot_present(void)
+{
+ struct rb_bios_settings *bs;
+ u8 *base;
+ u32 off,len;
+
+ if (rb_found)
+ goto out;
+
+ base = (u8 *)KSEG1ADDR(ADM5120_SRAM0_BASE);
+ bs = (struct rb_bios_settings *)(base + RB_BS_OFFS);
+
+ off = prom_read_le32(&bs->hs_offs);
+ len = prom_read_le32(&bs->hs_size);
+ if (off > RB_OFFS_MAX)
+ goto out;
+
+ if (routerboot_load_hs(base+off, len) != 0)
+ goto out;
+
+ rb_found = 1;
+
+out:
+ return rb_found;
+}
+
+char *routerboot_get_boardname(void)
+{
+ if (rb_found == 0)
+ return NULL;
+
+ return rb_hs.name;
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/reset.c b/target/linux/adm5120/files/arch/mips/adm5120/reset.c
new file mode 100644
index 000000000..abcbb1c8b
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/reset.c
@@ -0,0 +1,62 @@
+/*
+ * $Id$
+ *
+ * ADM5120 specific reset routines
+ *
+ * Copyright (C) ADMtek Incorporated.
+ * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2007 OpenWrt.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_switch.h>
+
+#define ADM5120_SOFTRESET 0x12000004
+
+void (*adm5120_board_reset)(void);
+
+void adm5120_restart(char *command)
+{
+ /* TODO: stop switch before reset */
+
+ if (adm5120_board_reset)
+ adm5120_board_reset();
+
+ *(u32*)KSEG1ADDR(ADM5120_SOFTRESET)=1;
+}
+
+void adm5120_halt(void)
+{
+ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+ while (1);
+}
+
+void adm5120_power_off(void)
+{
+ adm5120_halt();
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/setup.c b/target/linux/adm5120/files/arch/mips/adm5120/setup.c
new file mode 100644
index 000000000..ed7966b41
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/setup.c
@@ -0,0 +1,73 @@
+/*
+ * $Id$
+ *
+ * ADM5120 specific setup
+ *
+ * Copyright (C) ADMtek Incorporated.
+ * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2007 OpenWrt.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <asm/reboot.h>
+#include <asm/io.h>
+#include <asm/time.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_switch.h>
+#include <asm/mach-adm5120/adm5120_board.h>
+
+static char *prom_names[ADM5120_PROM_LAST+1] __initdata = {
+ [ADM5120_PROM_GENERIC] = "Generic",
+ [ADM5120_PROM_CFE] = "CFE",
+ [ADM5120_PROM_UBOOT] = "U-Boot",
+ [ADM5120_PROM_MYLOADER] = "MyLoader",
+ [ADM5120_PROM_ROUTERBOOT] = "RouterBOOT",
+ [ADM5120_PROM_BOOTBASE] = "Bootbase"
+};
+
+static void __init adm5120_report(void)
+{
+ printk(KERN_INFO "SoC : ADM%04X%s revision %d, running at %ldMHz\n",
+ adm5120_product_code,
+ (adm5120_package == ADM5120_PACKAGE_BGA) ? "" : "P",
+ adm5120_revision, (adm5120_speed / 1000000)
+ );
+ printk(KERN_INFO "Bootdev : %s flash\n", adm5120_nand_boot ? "NAND":"NOR");
+ printk(KERN_INFO "Prom : %s\n", prom_names[adm5120_prom_type]);
+}
+
+void __init plat_mem_setup(void)
+{
+ adm5120_soc_init();
+ adm5120_mem_init();
+ adm5120_report();
+
+ board_time_init = adm5120_time_init;
+
+ _machine_restart = adm5120_restart;
+ _machine_halt = adm5120_halt;
+ pm_power_off = adm5120_power_off;
+
+ set_io_port_base(KSEG1);
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/time.c b/target/linux/adm5120/files/arch/mips/adm5120/time.c
new file mode 100644
index 000000000..27393d4fe
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/time.c
@@ -0,0 +1,54 @@
+/*
+ * $Id$
+ *
+ * ADM5120 specific hooks for MIPS CPU Counter/Compare timer
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This file was based on: arch/mips/gt64120/wrppmc/time.c
+ * Original author: Mark.Zhan
+ * Copyright (C) 1996, 1997, 2004 by Ralf Baechle
+ * Copyright (C) 2006, Wind River System Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+
+#include <asm/irq.h>
+#include <asm/cpu.h>
+#include <asm/time.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_irq.h>
+
+void __init adm5120_time_init(void)
+{
+ mips_hpt_frequency = adm5120_speed / 2;
+}
+
+void __init plat_timer_setup(struct irqaction *irq)
+{
+ clear_c0_status(ST0_BEV);
+
+ /* Install ISR for CPU Counter interrupt */
+ setup_irq(ADM5120_IRQ_COUNTER, irq);
+}
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/trxsplit.c b/target/linux/adm5120/files/arch/mips/adm5120/trxsplit.c
new file mode 100644
index 000000000..941f30695
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/adm5120/trxsplit.c
@@ -0,0 +1,208 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/kmod.h>
+#include <linux/root_dev.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/byteorder/generic.h>
+
+#define PFX "trxsplit: "
+
+#define TRX_MAGIC 0x30524448 /* "HDR0" */
+#define TRX_VERSION 1
+#define TRX_MAX_LEN 0x3A0000
+#define TRX_NO_HEADER 1 /* Do not write TRX header */
+#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
+#define TRX_MAX_OFFSET 3
+#define TRX_MIN_KERNEL_SIZE 256*1024
+
+struct trx_header {
+ u32 magic; /* "HDR0" */
+ u32 len; /* Length of file including header */
+ u32 crc32; /* 32-bit CRC from flag_version to end of file */
+ u32 flag_version; /* 0:15 flags, 16:31 version */
+ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
+};
+
+#define BLOCK_LEN_MIN 0x10000
+
+static struct mtd_info *trx_mtd = NULL;
+static unsigned long trx_offset = 0;
+static int trx_nr_parts = 0;
+static struct mtd_partition trx_parts[TRX_MAX_OFFSET];
+static struct trx_header trx_hdr;
+
+static int __init trxsplit_checktrx(struct mtd_info *mtd, unsigned long offset)
+{
+ size_t retlen;
+ int err;
+
+ err = mtd->read(mtd, offset, sizeof(trx_hdr), &retlen, (void *)&trx_hdr);
+ if (err) {
+ printk(KERN_ALERT PFX "unable to read from '%s'\n", mtd->name);
+ goto err_out;
+ }
+
+ if (retlen != sizeof(trx_hdr)) {
+ printk(KERN_ALERT PFX "reading failed on '%s'\n", mtd->name);
+ goto err_out;
+ }
+
+ trx_hdr.magic = le32_to_cpu(trx_hdr.magic);
+ trx_hdr.len = le32_to_cpu(trx_hdr.len);
+ trx_hdr.crc32 = le32_to_cpu(trx_hdr.crc32);
+ trx_hdr.flag_version = le32_to_cpu(trx_hdr.flag_version);
+ trx_hdr.offsets[0] = le32_to_cpu(trx_hdr.offsets[0]);
+ trx_hdr.offsets[1] = le32_to_cpu(trx_hdr.offsets[1]);
+ trx_hdr.offsets[2] = le32_to_cpu(trx_hdr.offsets[2]);
+
+ /* sanity checks */
+ if (trx_hdr.magic != TRX_MAGIC)
+ goto err_out;
+
+ if (trx_hdr.len > mtd->size - offset)
+ goto err_out;
+
+ /* TODO: add crc32 checking too? */
+
+ return 0;
+
+err_out:
+ return -1;
+}
+
+static int __init trxsplit_create_partitions(void)
+{
+ struct mtd_partition *part = trx_parts;
+ int ret = 0;
+ int i;
+
+ if (trx_mtd == NULL)
+ goto out;
+
+ printk(KERN_INFO PFX "creating TRX partitions in '%s' (%d,%d)\n",
+ trx_mtd->name, MTD_BLOCK_MAJOR, trx_mtd->index);
+
+ for (i=0; i<TRX_MAX_OFFSET;i++) {
+ part = &trx_parts[i];
+ if (trx_hdr.offsets[i] == 0)
+ continue;
+ part->offset = trx_offset + trx_hdr.offsets[i];
+ trx_nr_parts++;
+ }
+
+ for (i=0; i<trx_nr_parts-1; i++) {
+ trx_parts[i].size = trx_parts[i+1].offset - trx_parts[i].offset;
+ }
+ trx_parts[i].size = trx_mtd->size - trx_parts[i].offset;
+
+ i=0;
+ part = &trx_parts[i];
+ if (part->size < TRX_MIN_KERNEL_SIZE) {
+ part->name = "loader";
+ i++;
+ }
+
+ part = &trx_parts[i];
+ part->name = "kernel";
+ i++;
+
+ part = &trx_parts[i];
+ part->name = "rootfs";
+
+ ret = add_mtd_partitions(trx_mtd, trx_parts, trx_nr_parts);
+ if (ret) {
+ printk(KERN_ALERT PFX "creating TRX partitions failed\n");
+ }
+
+out:
+ return ret;
+}
+
+static void __init trxsplit_add_mtd(struct mtd_info *mtd)
+{
+ unsigned long offset;
+ unsigned long blocklen;
+ int err;
+
+ if (trx_mtd)
+ return;
+
+ blocklen = mtd->erasesize;
+ if (blocklen < BLOCK_LEN_MIN)
+ blocklen = BLOCK_LEN_MIN;
+
+ printk(KERN_INFO PFX "searching TRX header in '%s'\n", mtd->name);
+
+ err = 0;
+ for (offset=0; offset < mtd->size; offset+=blocklen) {
+ err = trxsplit_checktrx(mtd, offset);
+ if (err == 0)
+ break;
+ }
+
+ if (err) {
+ printk(KERN_ALERT PFX "no TRX header found\n");
+ return;
+ }
+
+ printk(KERN_INFO PFX "TRX header found at 0x%lX\n", offset);
+
+ trx_mtd = mtd;
+ trx_offset = offset;
+}
+
+static void __init trxsplit_remove_mtd(struct mtd_info *mtd)
+{
+ /* nothing to do */
+}
+
+static struct mtd_notifier trxsplit_notifier __initdata = {
+ .add = trxsplit_add_mtd,
+ .remove = trxsplit_remove_mtd,
+};
+
+static void __init trxsplit_find_trx(void)
+{
+ register_mtd_user(&trxsplit_notifier);
+ unregister_mtd_user(&trxsplit_notifier);
+}
+
+static int __init trxsplit_init(void)
+{
+ int ret;
+
+ trxsplit_find_trx();
+
+ ret = trxsplit_create_partitions();
+ return ret;
+}
+
+late_initcall(trxsplit_init);
diff --git a/target/linux/adm5120/files/arch/mips/pci/fixup-adm5120.c b/target/linux/adm5120/files/arch/mips/pci/fixup-adm5120.c
new file mode 100644
index 000000000..59acf75c1
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/pci/fixup-adm5120.c
@@ -0,0 +1,175 @@
+/*
+ * $Id$
+ *
+ * ADM5120 specific PCI fixups
+ *
+ * Copyright (C) ADMtek Incorporated.
+ * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2007 OpenWrt.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/pci_regs.h>
+
+#include <asm/delay.h>
+#include <asm/bootinfo.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_irq.h>
+
+struct adm5120_pci_irq {
+ u8 slot;
+ u8 func;
+ u8 pin;
+ unsigned irq;
+};
+
+#define PCIIRQ(s,f,p,i) { \
+ .slot = (s), \
+ .func = (f), \
+ .pin = (p), \
+ .irq = (i) \
+ }
+
+static struct adm5120_pci_irq default_pci_irqs[] __initdata = {
+ PCIIRQ(2, 0, 1, ADM5120_IRQ_PCI0),
+};
+
+static struct adm5120_pci_irq rb1xx_pci_irqs[] __initdata = {
+ PCIIRQ(1, 0, 1, ADM5120_IRQ_PCI0),
+ PCIIRQ(2, 0, 1, ADM5120_IRQ_PCI1),
+ PCIIRQ(3, 0, 1, ADM5120_IRQ_PCI2)
+};
+
+static struct adm5120_pci_irq cas771_pci_irqs[] __initdata = {
+ PCIIRQ(2, 0, 1, ADM5120_IRQ_PCI0),
+ PCIIRQ(3, 0, 1, ADM5120_IRQ_PCI1),
+ PCIIRQ(3, 2, 3, ADM5120_IRQ_PCI2)
+};
+
+static struct adm5120_pci_irq np28g_pci_irqs[] __initdata = {
+ PCIIRQ(2, 0, 1, ADM5120_IRQ_PCI0),
+ PCIIRQ(3, 0, 1, ADM5120_IRQ_PCI0),
+ PCIIRQ(3, 1, 2, ADM5120_IRQ_PCI1),
+ PCIIRQ(3, 2, 3, ADM5120_IRQ_PCI2)
+};
+
+#define GETMAP(n) do { \
+ nr_irqs = ARRAY_SIZE(n ## _pci_irqs); \
+ p = n ## _pci_irqs; \
+ } while (0)
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct adm5120_pci_irq *p;
+ int nr_irqs;
+ int i;
+ int irq;
+
+ irq = -1;
+ if (slot < 1 || slot > 3) {
+ printk(KERN_ALERT "PCI: slot number %u is not supported\n",
+ slot);
+ goto out;
+ }
+
+ GETMAP(default);
+
+ switch (mips_machtype) {
+ case MACH_ADM5120_RB_111:
+ case MACH_ADM5120_RB_112:
+ case MACH_ADM5120_RB_133:
+ case MACH_ADM5120_RB_133C:
+ case MACH_ADM5120_RB_153:
+ GETMAP(rb1xx);
+ break;
+ case MACH_ADM5120_NP28G:
+ GETMAP(np28g);
+ break;
+ case MACH_ADM5120_P335:
+ case MACH_ADM5120_P334WT:
+ /* using default mapping */
+ break;
+ case MACH_ADM5120_CAS771:
+ GETMAP(cas771);
+ break;
+
+ case MACH_ADM5120_NP27G:
+ case MACH_ADM5120_NP28GHS:
+ case MACH_ADM5120_WP54AG:
+ case MACH_ADM5120_WP54G:
+ case MACH_ADM5120_WP54G_WRT:
+ case MACH_ADM5120_WPP54AG:
+ case MACH_ADM5120_WPP54G:
+ default:
+ printk(KERN_ALERT "PCI: irq map is unknown, using defaults.\n");
+ break;
+ }
+
+ for (i=0; i<nr_irqs; i++, p++) {
+ if ((p->slot == slot) && (PCI_FUNC(dev->devfn) == p->func) &&
+ (p->pin == pin)) {
+ irq = p->irq;
+ break;
+ }
+ }
+
+ if (irq < 0) {
+ printk(KERN_ALERT "PCI: no irq found for %s pin:%u\n",
+ pci_name(dev), pin);
+ } else {
+ printk(KERN_INFO "PCI: mapping irq for %s pin:%u, irq:%d\n",
+ pci_name(dev), pin, irq);
+ }
+
+out:
+ return irq;
+}
+
+static void adm5120_pci_fixup(struct pci_dev *dev)
+{
+ if (dev->devfn != 0)
+ return;
+
+ /* setup COMMAND register */
+ pci_write_config_word(dev, PCI_COMMAND,
+ (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
+
+ /* setup CACHE_LINE_SIZE register */
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4);
+
+ /* setting up BARS */
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_ADM5120,
+ adm5120_pci_fixup);
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
diff --git a/target/linux/adm5120/files/arch/mips/pci/ops-adm5120.c b/target/linux/adm5120/files/arch/mips/pci/ops-adm5120.c
new file mode 100644
index 000000000..4a9bc999c
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/pci/ops-adm5120.c
@@ -0,0 +1,143 @@
+/*
+ * $Id$
+ *
+ * ADM5120 specific PCI operations
+ *
+ * Copyright (C) ADMtek Incorporated.
+ * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2007 OpenWrt.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include <asm/mach-adm5120/adm5120_defs.h>
+
+#define DEBUG 0
+#if DEBUG
+#define DBG(f, ...) printk(f, ## __VA_ARGS__ )
+#else
+#define DBG(f, ...)
+#endif
+
+#define PCI_ENABLE 0x80000000
+
+static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
+
+static inline void write_cfgaddr(u32 addr)
+{
+ *(volatile u32*)KSEG1ADDR(ADM5120_PCICFG_ADDR) = (addr | PCI_ENABLE);
+}
+
+static inline void write_cfgdata(u32 data)
+{
+ *(volatile u32*)KSEG1ADDR(ADM5120_PCICFG_DATA) = data;
+
+}
+
+static inline u32 read_cfgdata(void)
+{
+ return (*(volatile u32*)KSEG1ADDR(ADM5120_PCICFG_DATA));
+}
+
+static inline u32 mkaddr(struct pci_bus *bus, unsigned int devfn, int where)
+{
+ return (((bus->number & 0xFF) << 16) | ((devfn & 0xFF) << 8) | \
+ (where & 0xFC));
+}
+
+static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *val)
+{
+ unsigned long flags;
+ u32 data;
+
+ spin_lock_irqsave(&pci_lock, flags);
+ write_cfgaddr(mkaddr(bus,devfn,where));
+ data = read_cfgdata();
+
+ DBG("PCI: cfg_read %02u.%02u.%01u/%02X:%01d, cfg:0x%08X",
+ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, data);
+
+ switch (size) {
+ case 1:
+ if (where & 1)
+ data >>= 8;
+ if (where & 2)
+ data >>= 16;
+ data &= 0xFF;
+ break;
+ case 2:
+ if (where & 2)
+ data >>= 16;
+ data &= 0xFFFF;
+ break;
+ }
+
+ *val = data;
+ DBG(", 0x%08X returned\n", data);
+ spin_unlock_irqrestore(&pci_lock, flags);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 val)
+{
+ unsigned long flags;
+ u32 data;
+ int s;
+
+ spin_lock_irqsave(&pci_lock, flags);
+ write_cfgaddr(mkaddr(bus,devfn,where));
+ data = read_cfgdata();
+
+ DBG("PCI: cfg_write %02u.%02u.%01u/%02X:%01d, cfg:0x%08X",
+ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, data);
+
+ switch (size) {
+ case 1:
+ s = ((where & 3) << 3);
+ data &= ~(0xFF << s);
+ data |= ((val & 0xFF) << s);
+ break;
+ case 2:
+ s = ((where & 2) << 4);
+ data &= ~(0xFFFF << s);
+ data |= ((val & 0xFFFF) << s);
+ break;
+ case 4:
+ data = val;
+ break;
+ }
+
+ write_cfgdata(data);
+ DBG(", 0x%08X written\n", data);
+ spin_unlock_irqrestore(&pci_lock, flags);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops adm5120_pci_ops = {
+ .read = pci_config_read,
+ .write = pci_config_write,
+};
diff --git a/target/linux/adm5120/files/arch/mips/pci/pci-adm5120.c b/target/linux/adm5120/files/arch/mips/pci/pci-adm5120.c
new file mode 100644
index 000000000..2a6477023
--- /dev/null
+++ b/target/linux/adm5120/files/arch/mips/pci/pci-adm5120.c
@@ -0,0 +1,80 @@
+/*
+ * $Id$
+ *
+ * ADM5120 PCI Host Controller driver
+ *
+ * Copyright (C) ADMtek Incorporated.
+ * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2007 OpenWrt.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_irq.h>
+
+extern struct pci_ops adm5120_pci_ops;
+
+static struct resource pci_io_resource = {
+ .name = "ADM5120 PCI I/O",
+ .start = ADM5120_PCIIO_BASE,
+ .end = ADM5120_PCICFG_ADDR-1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+ .name = "ADM5120 PCI MEM",
+ .start = ADM5120_PCIMEM_BASE,
+ .end = ADM5120_PCIIO_BASE-1,
+ .flags = IORESOURCE_MEM
+};
+
+static struct pci_controller adm5120_controller = {
+ .pci_ops = &adm5120_pci_ops,
+ .io_resource = &pci_io_resource,
+ .mem_resource = &pci_mem_resource,
+};
+
+static int __init adm5120_pci_setup(void)
+{
+ int pci_bios;
+
+ pci_bios = adm5120_has_pci();
+
+ printk("adm5120: system has %sPCI BIOS\n", pci_bios ? "" : "no ");
+ if (pci_bios == 0)
+ return -1;
+
+ /* Avoid ISA compat ranges. */
+ PCIBIOS_MIN_IO = 0x00000000;
+ PCIBIOS_MIN_MEM = 0x00000000;
+
+ /* Set I/O resource limits. */
+ ioport_resource.end = 0x1fffffff;
+ iomem_resource.end = 0xffffffff;
+
+ register_pci_controller(&adm5120_controller);
+ return 0;
+}
+
+arch_initcall(adm5120_pci_setup);