summaryrefslogtreecommitdiffstats
path: root/target/linux/atheros/files-2.6.26/arch/mips
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/atheros/files-2.6.26/arch/mips')
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/Kconfig27
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/Makefile13
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/Makefile11
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/board.c473
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/irq.c174
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/Makefile12
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/board.c414
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/irq.c359
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/pci.c265
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/board.c299
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/prom.c45
-rw-r--r--target/linux/atheros/files-2.6.26/arch/mips/atheros/reset.c162
12 files changed, 2254 insertions, 0 deletions
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/Kconfig b/target/linux/atheros/files-2.6.26/arch/mips/atheros/Kconfig
new file mode 100644
index 000000000..953f0cb5b
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/Kconfig
@@ -0,0 +1,27 @@
+config ATHEROS_AR5312
+ bool "Atheros 5312/2312+ support"
+ depends on ATHEROS
+ default y
+
+config ATHEROS_AR5315
+ bool "Atheros 5315/2315+ support"
+ depends on ATHEROS
+ select DMA_NONCOHERENT
+ select CEVT_R4K
+ select CSRC_R4K
+ select IRQ_CPU
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select GENERIC_GPIO
+ default y
+
+config ATHEROS_AR5315_PCI
+ bool "PCI support"
+ select HW_HAS_PCI
+ select PCI
+ select USB_ARCH_HAS_HCD
+ select USB_ARCH_HAS_OHCI
+ select USB_ARCH_HAS_EHCI
+ depends on ATHEROS_AR5315
+ default n
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/Makefile b/target/linux/atheros/files-2.6.26/arch/mips/atheros/Makefile
new file mode 100644
index 000000000..2c2b991bc
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/Makefile
@@ -0,0 +1,13 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2006 FON Technology, SL.
+# Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+# Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+#
+
+obj-y += board.o prom.o reset.o
+obj-$(CONFIG_ATHEROS_AR5312) += ar5312/
+obj-$(CONFIG_ATHEROS_AR5315) += ar5315/
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/Makefile b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/Makefile
new file mode 100644
index 000000000..6c50d9931
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/Makefile
@@ -0,0 +1,11 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2007 FON Technology, SL.
+# Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
+# Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+#
+
+obj-y := board.o irq.o
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/board.c b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/board.c
new file mode 100644
index 000000000..938db11bc
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/board.c
@@ -0,0 +1,473 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Platform devices for Atheros SoCs
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <ar531x.h>
+#include <linux/leds.h>
+
+#define NO_PHY 0x1f
+
+static int is_5312 = 0;
+static struct platform_device *ar5312_devs[6];
+
+static struct resource ar5312_eth0_res[] = {
+ {
+ .name = "eth0_membase",
+ .flags = IORESOURCE_MEM,
+ .start = KSEG1ADDR(AR531X_ENET0),
+ .end = KSEG1ADDR(AR531X_ENET0 + 0x2000),
+ },
+ {
+ .name = "eth0_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = AR5312_IRQ_ENET0_INTRS,
+ .end = AR5312_IRQ_ENET0_INTRS,
+ },
+};
+static struct ar531x_eth ar5312_eth0_data = {
+ .phy = NO_PHY,
+ .mac = 0,
+ .reset_base = AR531X_RESET,
+ .reset_mac = AR531X_RESET_ENET0,
+ .reset_phy = AR531X_RESET_EPHY0,
+ .phy_base = KSEG1ADDR(AR531X_ENET0),
+};
+
+static struct resource ar5312_eth1_res[] = {
+ {
+ .name = "eth1_membase",
+ .flags = IORESOURCE_MEM,
+ .start = KSEG1ADDR(AR531X_ENET1),
+ .end = KSEG1ADDR(AR531X_ENET1 + 0x2000),
+ },
+ {
+ .name = "eth1_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = AR5312_IRQ_ENET1_INTRS,
+ .end = AR5312_IRQ_ENET1_INTRS,
+ },
+};
+static struct ar531x_eth ar5312_eth1_data = {
+ .phy = NO_PHY,
+ .mac = 1,
+ .reset_base = AR531X_RESET,
+ .reset_mac = AR531X_RESET_ENET1,
+ .reset_phy = AR531X_RESET_EPHY1,
+ .phy_base = KSEG1ADDR(AR531X_ENET1),
+};
+
+static struct platform_device ar5312_eth[] = {
+ {
+ .id = 0,
+ .name = "ar531x-eth",
+ .dev.platform_data = &ar5312_eth0_data,
+ .resource = ar5312_eth0_res,
+ .num_resources = ARRAY_SIZE(ar5312_eth0_res)
+ },
+ {
+ .id = 1,
+ .name = "ar531x-eth",
+ .dev.platform_data = &ar5312_eth1_data,
+ .resource = ar5312_eth1_res,
+ .num_resources = ARRAY_SIZE(ar5312_eth1_res)
+ },
+};
+
+
+/*
+ * AR2312/3 ethernet uses the PHY of ENET0, but the MAC
+ * of ENET1. Atheros calls it 'twisted' for a reason :)
+ */
+static struct resource ar231x_eth0_res[] = {
+ {
+ .name = "eth0_membase",
+ .flags = IORESOURCE_MEM,
+ .start = KSEG1ADDR(AR531X_ENET1),
+ .end = KSEG1ADDR(AR531X_ENET1 + 0x2000),
+ },
+ {
+ .name = "eth0_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = AR5312_IRQ_ENET1_INTRS,
+ .end = AR5312_IRQ_ENET1_INTRS,
+ },
+};
+static struct ar531x_eth ar231x_eth0_data = {
+ .phy = 1,
+ .mac = 1,
+ .reset_base = AR531X_RESET,
+ .reset_mac = AR531X_RESET_ENET1,
+ .reset_phy = AR531X_RESET_EPHY1,
+ .phy_base = KSEG1ADDR(AR531X_ENET0),
+};
+static struct platform_device ar231x_eth0 = {
+ .id = 0,
+ .name = "ar531x-eth",
+ .dev.platform_data = &ar231x_eth0_data,
+ .resource = ar231x_eth0_res,
+ .num_resources = ARRAY_SIZE(ar231x_eth0_res)
+};
+
+
+static struct platform_device ar5312_wmac[] = {
+ {
+ .id = 0,
+ .name = "ar531x-wmac",
+ },
+ {
+ .id = 1,
+ .name = "ar531x-wmac",
+ },
+};
+
+static struct physmap_flash_data ar5312_flash_data = {
+ .width = 2,
+};
+
+static struct resource ar5312_flash_resource = {
+ .start = AR531X_FLASH,
+ .end = AR531X_FLASH + 0x800000 - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ar5312_physmap_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &ar5312_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &ar5312_flash_resource,
+};
+
+#ifdef CONFIG_LEDS_GPIO
+static struct gpio_led ar5312_leds[] = {
+ { .name = "wlan", .gpio = 0, .active_low = 1, },
+};
+
+static const struct gpio_led_platform_data ar5312_led_data = {
+ .num_leds = ARRAY_SIZE(ar5312_leds),
+ .leds = (void *) ar5312_leds,
+};
+
+static struct platform_device ar5312_gpio_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = (void *) &ar5312_led_data,
+ }
+};
+#endif
+
+/*
+ * NB: This mapping size is larger than the actual flash size,
+ * but this shouldn't be a problem here, because the flash
+ * will simply be mapped multiple times.
+ */
+static char __init *ar5312_flash_limit(void)
+{
+ u32 ctl;
+ /*
+ * Configure flash bank 0.
+ * Assume 8M window size. Flash will be aliased if it's smaller
+ */
+ ctl = FLASHCTL_E |
+ FLASHCTL_AC_8M |
+ FLASHCTL_RBLE |
+ (0x01 << FLASHCTL_IDCY_S) |
+ (0x07 << FLASHCTL_WST1_S) |
+ (0x07 << FLASHCTL_WST2_S) |
+ (sysRegRead(AR531X_FLASHCTL0) & FLASHCTL_MW);
+
+ sysRegWrite(AR531X_FLASHCTL0, ctl);
+
+ /* Disable other flash banks */
+ sysRegWrite(AR531X_FLASHCTL1,
+ sysRegRead(AR531X_FLASHCTL1) & ~(FLASHCTL_E | FLASHCTL_AC));
+
+ sysRegWrite(AR531X_FLASHCTL2,
+ sysRegRead(AR531X_FLASHCTL2) & ~(FLASHCTL_E | FLASHCTL_AC));
+
+ return (char *) KSEG1ADDR(AR531X_FLASH + 0x800000);
+}
+
+static struct ar531x_config __init *init_wmac(int unit)
+{
+ struct ar531x_config *config;
+
+ config = (struct ar531x_config *) kzalloc(sizeof(struct ar531x_config), GFP_KERNEL);
+ config->board = board_config;
+ config->radio = radio_config;
+ config->unit = unit;
+ config->tag = (u_int16_t) ((sysRegRead(AR531X_REV) >> AR531X_REV_WMAC_MIN_S) & AR531X_REV_CHIP);
+
+ return config;
+}
+
+int __init ar5312_init_devices(void)
+{
+ struct ar531x_boarddata *bcfg;
+ char *radio, *c;
+ int dev = 0;
+ uint32_t fctl = 0;
+
+ if (!is_5312)
+ return 0;
+
+ /* Locate board/radio config data */
+ ar531x_find_config(ar5312_flash_limit());
+ bcfg = (struct ar531x_boarddata *) board_config;
+
+
+ /*
+ * Chip IDs and hardware detection for some Atheros
+ * models are really broken!
+ *
+ * Atheros uses a disabled WMAC0 and Silicon ID of AR5312
+ * as indication for AR2312, which is otherwise
+ * indistinguishable from the real AR5312.
+ */
+ if (radio_config) {
+ radio = radio_config + AR531X_RADIO_MASK_OFF;
+ if ((*((u32 *) radio) & AR531X_RADIO0_MASK) == 0)
+ bcfg->config |= BD_ISCASPER;
+ } else
+ radio = NULL;
+
+ /* AR2313 has CPU minor rev. 10 */
+ if ((current_cpu_data.processor_id & 0xff) == 0x0a)
+ mips_machtype = MACH_ATHEROS_AR2313;
+
+ /* AR2312 shares the same Silicon ID as AR5312 */
+ else if (bcfg->config & BD_ISCASPER)
+ mips_machtype = MACH_ATHEROS_AR2312;
+
+ /* Everything else is probably AR5312 or compatible */
+ else
+ mips_machtype = MACH_ATHEROS_AR5312;
+
+ ar5312_eth0_data.board_config = board_config;
+ ar5312_eth1_data.board_config = board_config;
+
+ /* fixup flash width */
+ fctl = sysRegRead(AR531X_FLASHCTL) & FLASHCTL_MW;
+ switch (fctl) {
+ case FLASHCTL_MWx16:
+ ar5312_flash_data.width = 2;
+ break;
+ case FLASHCTL_MWx8:
+ default:
+ ar5312_flash_data.width = 1;
+ break;
+ }
+
+ ar5312_devs[dev++] = &ar5312_physmap_flash;
+
+#ifdef CONFIG_LEDS_GPIO
+ ar5312_leds[0].gpio = bcfg->sysLedGpio;
+ ar5312_devs[dev++] = &ar5312_gpio_leds;
+#endif
+
+ if (!memcmp(bcfg->enet0Mac, "\xff\xff\xff\xff\xff\xff", 6))
+ memcpy(bcfg->enet0Mac, bcfg->enet1Mac, 6);
+
+ if (memcmp(bcfg->enet0Mac, bcfg->enet1Mac, 6) == 0) {
+ /* ENET0 and ENET1 have the same mac.
+ * Increment the one from ENET1 */
+ c = bcfg->enet1Mac + 5;
+ while ((c >= (char *) bcfg->enet1Mac) && !(++(*c)))
+ c--;
+ }
+
+ switch(mips_machtype) {
+ case MACH_ATHEROS_AR5312:
+ ar5312_eth0_data.macaddr = bcfg->enet0Mac;
+ ar5312_eth1_data.macaddr = bcfg->enet1Mac;
+ ar5312_devs[dev++] = &ar5312_eth[0];
+ ar5312_devs[dev++] = &ar5312_eth[1];
+ break;
+ case MACH_ATHEROS_AR2312:
+ case MACH_ATHEROS_AR2313:
+ ar231x_eth0_data.macaddr = bcfg->enet0Mac;
+ ar5312_devs[dev++] = &ar231x_eth0;
+ ar5312_flash_data.width = 1;
+ break;
+ }
+
+ if (radio) {
+ if (mips_machtype == MACH_ATHEROS_AR5312) {
+ if (*((u32 *) radio) & AR531X_RADIO0_MASK) {
+ ar5312_wmac[0].dev.platform_data = init_wmac(0);
+ ar5312_devs[dev++] = &ar5312_wmac[0];
+ }
+ }
+ if (*((u32 *) radio) & AR531X_RADIO1_MASK) {
+ ar5312_wmac[1].dev.platform_data = init_wmac(1);
+ ar5312_devs[dev++] = &ar5312_wmac[1];
+ }
+ }
+
+ return platform_add_devices(ar5312_devs, dev);
+}
+
+
+static void ar5312_halt(void)
+{
+ while (1);
+}
+
+static void ar5312_power_off(void)
+{
+ ar5312_halt();
+}
+
+
+static void ar5312_restart(char *command)
+{
+ /* reset the system */
+ for(;;) sysRegWrite(AR531X_RESET, AR531X_RESET_SYSTEM);
+}
+
+
+/*
+ * This table is indexed by bits 5..4 of the CLOCKCTL1 register
+ * to determine the predevisor value.
+ */
+static int __initdata CLOCKCTL1_PREDIVIDE_TABLE[4] = {
+ 1,
+ 2,
+ 4,
+ 5
+};
+
+
+static unsigned int __init ar5312_cpu_frequency(void)
+{
+ unsigned int result;
+ unsigned int predivide_mask, predivide_shift;
+ unsigned int multiplier_mask, multiplier_shift;
+ unsigned int clockCtl1, preDivideSelect, preDivisor, multiplier;
+ unsigned int doubler_mask;
+ unsigned int wisoc_revision;
+
+ /* Trust the bootrom's idea of cpu frequency. */
+ if ((result = sysRegRead(AR5312_SCRATCH)))
+ return result;
+
+ wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> AR531X_REV_MAJ_S;
+ if (wisoc_revision == AR531X_REV_MAJ_AR2313) {
+ predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK;
+ predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT;
+ multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK;
+ multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT;
+ doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK;
+ } else { /* AR5312 and AR2312 */
+ predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK;
+ predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT;
+ multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK;
+ multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT;
+ doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK;
+ }
+
+ /*
+ * Clocking is derived from a fixed 40MHz input clock.
+ *
+ * cpuFreq = InputClock * MULT (where MULT is PLL multiplier)
+ * sysFreq = cpuFreq / 4 (used for APB clock, serial,
+ * flash, Timer, Watchdog Timer)
+ *
+ * cntFreq = cpuFreq / 2 (use for CPU count/compare)
+ *
+ * So, for example, with a PLL multiplier of 5, we have
+ *
+ * cpuFreq = 200MHz
+ * sysFreq = 50MHz
+ * cntFreq = 100MHz
+ *
+ * We compute the CPU frequency, based on PLL settings.
+ */
+
+ clockCtl1 = sysRegRead(AR5312_CLOCKCTL1);
+ preDivideSelect = (clockCtl1 & predivide_mask) >> predivide_shift;
+ preDivisor = CLOCKCTL1_PREDIVIDE_TABLE[preDivideSelect];
+ multiplier = (clockCtl1 & multiplier_mask) >> multiplier_shift;
+
+ if (clockCtl1 & doubler_mask) {
+ multiplier = multiplier << 1;
+ }
+ return (40000000 / preDivisor) * multiplier;
+}
+
+static inline int ar5312_sys_frequency(void)
+{
+ return ar5312_cpu_frequency() / 4;
+}
+
+static void __init ar5312_time_init(void)
+{
+ mips_hpt_frequency = ar5312_cpu_frequency() / 2;
+}
+
+
+void __init ar5312_prom_init(void)
+{
+ u32 memsize, memcfg, bank0AC, bank1AC;
+
+ is_5312 = 1;
+
+ /* Detect memory size */
+ memcfg = sysRegRead(AR531X_MEM_CFG1);
+ bank0AC = (memcfg & MEM_CFG1_AC0) >> MEM_CFG1_AC0_S;
+ bank1AC = (memcfg & MEM_CFG1_AC1) >> MEM_CFG1_AC1_S;
+ memsize = (bank0AC ? (1 << (bank0AC+1)) : 0)
+ + (bank1AC ? (1 << (bank1AC+1)) : 0);
+ memsize <<= 20;
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+
+ /* Initialize it to AR5312 for now. Real detection will be done
+ * in ar5312_init_devices() */
+ mips_machtype = MACH_ATHEROS_AR5312;
+}
+
+void __init ar5312_plat_setup(void)
+{
+ /* Clear any lingering AHB errors */
+ sysRegRead(AR531X_PROCADDR);
+ sysRegRead(AR531X_DMAADDR);
+ sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION);
+
+ board_time_init = ar5312_time_init;
+
+ _machine_restart = ar5312_restart;
+ _machine_halt = ar5312_halt;
+ pm_power_off = ar5312_power_off;
+
+ serial_setup(KSEG1ADDR(AR531X_UART0), ar5312_sys_frequency());
+}
+
+arch_initcall(ar5312_init_devices);
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/irq.c b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/irq.c
new file mode 100644
index 000000000..0cbdc8ed2
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/irq.c
@@ -0,0 +1,174 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Platform devices for Atheros SoCs
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <ar531x.h>
+#include <gpio.h>
+
+/*
+ * Called when an interrupt is received, this function
+ * determines exactly which interrupt it was, and it
+ * invokes the appropriate handler.
+ *
+ * Implicitly, we also define interrupt priority by
+ * choosing which to dispatch first.
+ */
+asmlinkage void ar5312_irq_dispatch(void)
+{
+ int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & CAUSEF_IP2)
+ do_IRQ(AR5312_IRQ_WLAN0_INTRS);
+ else if (pending & CAUSEF_IP3)
+ do_IRQ(AR5312_IRQ_ENET0_INTRS);
+ else if (pending & CAUSEF_IP4)
+ do_IRQ(AR5312_IRQ_ENET1_INTRS);
+ else if (pending & CAUSEF_IP5)
+ do_IRQ(AR5312_IRQ_WLAN1_INTRS);
+ else if (pending & CAUSEF_IP6) {
+ unsigned int ar531x_misc_intrs = sysRegRead(AR531X_ISR) & sysRegRead(AR531X_IMR);
+
+ if (ar531x_misc_intrs & AR531X_ISR_TIMER) {
+ do_IRQ(AR531X_MISC_IRQ_TIMER);
+ (void)sysRegRead(AR531X_TIMER);
+ } else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC)
+ do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
+ else if ((ar531x_misc_intrs & AR531X_ISR_UART0))
+ do_IRQ(AR531X_MISC_IRQ_UART0);
+ else if (ar531x_misc_intrs & AR531X_ISR_WD)
+ do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
+ else
+ do_IRQ(AR531X_MISC_IRQ_NONE);
+ } else if (pending & CAUSEF_IP7) {
+ do_IRQ(AR531X_IRQ_CPU_CLOCK);
+ }
+}
+
+
+/* Enable the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5312_misc_intr_enable(unsigned int irq)
+{
+ unsigned int imr;
+
+ imr = sysRegRead(AR531X_IMR);
+ imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1));
+ sysRegWrite(AR531X_IMR, imr);
+ sysRegRead(AR531X_IMR); /* flush write buffer */
+}
+
+/* Disable the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5312_misc_intr_disable(unsigned int irq)
+{
+ unsigned int imr;
+
+ imr = sysRegRead(AR531X_IMR);
+ imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1));
+ sysRegWrite(AR531X_IMR, imr);
+ sysRegRead(AR531X_IMR); /* flush write buffer */
+}
+
+/* Turn on the specified AR531X_MISC_IRQ interrupt */
+static unsigned int
+ar5312_misc_intr_startup(unsigned int irq)
+{
+ ar5312_misc_intr_enable(irq);
+ return 0;
+}
+
+/* Turn off the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5312_misc_intr_shutdown(unsigned int irq)
+{
+ ar5312_misc_intr_disable(irq);
+}
+
+static void
+ar5312_misc_intr_ack(unsigned int irq)
+{
+ ar5312_misc_intr_disable(irq);
+}
+
+static void
+ar5312_misc_intr_end(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ ar5312_misc_intr_enable(irq);
+}
+
+static struct irq_chip ar5312_misc_intr_controller = {
+ .typename = "AR5312 misc",
+ .startup = ar5312_misc_intr_startup,
+ .shutdown = ar5312_misc_intr_shutdown,
+ .enable = ar5312_misc_intr_enable,
+ .disable = ar5312_misc_intr_disable,
+ .ack = ar5312_misc_intr_ack,
+ .end = ar5312_misc_intr_end,
+};
+
+static irqreturn_t ar5312_ahb_proc_handler(int cpl, void *dev_id)
+{
+ u32 proc1 = sysRegRead(AR531X_PROC1);
+ u32 procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */
+ u32 dma1 = sysRegRead(AR531X_DMA1);
+ u32 dmaAddr = sysRegRead(AR531X_DMAADDR); /* clears error state */
+
+ printk("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n",
+ procAddr, proc1, dmaAddr, dma1);
+
+ machine_restart("AHB error"); /* Catastrophic failure */
+ return IRQ_HANDLED;
+}
+
+
+static struct irqaction ar5312_ahb_proc_interrupt = {
+ .handler = ar5312_ahb_proc_handler,
+ .flags = IRQF_DISABLED,
+ .name = "ar5312_ahb_proc_interrupt",
+};
+
+
+static struct irqaction cascade = {
+ .handler = no_action,
+ .flags = IRQF_DISABLED,
+ .name = "cascade",
+};
+
+void __init ar5312_misc_intr_init(int irq_base)
+{
+ int i;
+
+ for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 1;
+ irq_desc[i].chip = &ar5312_misc_intr_controller;
+ }
+ setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5312_ahb_proc_interrupt);
+ setup_irq(AR5312_IRQ_MISC_INTRS, &cascade);
+}
+
+
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/Makefile b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/Makefile
new file mode 100644
index 000000000..9b900113f
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/Makefile
@@ -0,0 +1,12 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2007 FON Technology, SL.
+# Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
+# Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+#
+
+obj-y := board.o irq.o
+obj-$(CONFIG_ATHEROS_AR5315_PCI) += pci.o
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/board.c b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/board.c
new file mode 100644
index 000000000..6ee75a966
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/board.c
@@ -0,0 +1,414 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Platform devices for Atheros SoCs
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <ar531x.h>
+#include <linux/leds.h>
+#include <asm/gpio.h>
+
+static int is_5315 = 0;
+
+static struct resource ar5315_eth_res[] = {
+ {
+ .name = "eth0_membase",
+ .flags = IORESOURCE_MEM,
+ .start = AR5315_ENET0,
+ .end = AR5315_ENET0 + 0x2000,
+ },
+ {
+ .name = "eth0_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = AR5315_IRQ_ENET0_INTRS,
+ .end = AR5315_IRQ_ENET0_INTRS,
+ },
+};
+
+static struct ar531x_eth ar5315_eth_data = {
+ .phy = 1,
+ .mac = 0,
+ .reset_base = AR5315_RESET,
+ .reset_mac = AR5315_RESET_ENET0,
+ .reset_phy = AR5315_RESET_EPHY0,
+ .phy_base = AR5315_ENET0
+};
+
+static struct platform_device ar5315_eth = {
+ .id = 0,
+ .name = "ar531x-eth",
+ .dev.platform_data = &ar5315_eth_data,
+ .resource = ar5315_eth_res,
+ .num_resources = ARRAY_SIZE(ar5315_eth_res)
+};
+
+static struct platform_device ar5315_wmac = {
+ .id = 0,
+ .name = "ar531x-wmac",
+ /* FIXME: add resources */
+};
+
+static struct resource ar5315_spiflash_res[] = {
+ {
+ .name = "flash_base",
+ .flags = IORESOURCE_MEM,
+ .start = KSEG1ADDR(AR5315_SPI_READ),
+ .end = KSEG1ADDR(AR5315_SPI_READ) + 0x800000,
+ },
+ {
+ .name = "flash_regs",
+ .flags = IORESOURCE_MEM,
+ .start = 0x11300000,
+ .end = 0x11300012,
+ },
+};
+
+static struct platform_device ar5315_spiflash = {
+ .id = 0,
+ .name = "spiflash",
+ .resource = ar5315_spiflash_res,
+ .num_resources = ARRAY_SIZE(ar5315_spiflash_res)
+};
+
+#ifdef CONFIG_LEDS_GPIO
+static struct gpio_led ar5315_leds[8];
+
+static struct gpio_led_platform_data ar5315_led_data = {
+ .num_leds = ARRAY_SIZE(ar5315_leds),
+ .leds = (void *) ar5315_leds,
+};
+
+static struct platform_device ar5315_gpio_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = (void *) &ar5315_led_data,
+ }
+};
+#endif
+
+static struct platform_device ar5315_wdt =
+{
+ .id = 0,
+ .name = "ar2315_wdt",
+};
+
+static __initdata struct platform_device *ar5315_devs[6];
+
+static void *flash_regs;
+
+static inline __u32 spiflash_regread32(int reg)
+{
+ volatile __u32 *data = (__u32 *)(flash_regs + reg);
+
+ return (*data);
+}
+
+static inline void spiflash_regwrite32(int reg, __u32 data)
+{
+ volatile __u32 *addr = (__u32 *)(flash_regs + reg);
+
+ *addr = data;
+}
+
+#define SPI_FLASH_CTL 0x00
+#define SPI_FLASH_OPCODE 0x04
+#define SPI_FLASH_DATA 0x08
+
+static __u8 spiflash_probe(void)
+{
+ __u32 reg;
+
+ do {
+ reg = spiflash_regread32(SPI_FLASH_CTL);
+ } while (reg & SPI_CTL_BUSY);
+
+ spiflash_regwrite32(SPI_FLASH_OPCODE, 0xab);
+
+ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | 4 |
+ (1 << 4) | SPI_CTL_START;
+
+ spiflash_regwrite32(SPI_FLASH_CTL, reg);
+
+ do {
+ reg = spiflash_regread32(SPI_FLASH_CTL);
+ } while (reg & SPI_CTL_BUSY);
+
+ reg = (__u32) spiflash_regread32(SPI_FLASH_DATA);
+ reg &= 0xff;
+
+ return (u8) reg;
+}
+
+
+#define STM_8MBIT_SIGNATURE 0x13
+#define STM_16MBIT_SIGNATURE 0x14
+#define STM_32MBIT_SIGNATURE 0x15
+#define STM_64MBIT_SIGNATURE 0x16
+#define STM_128MBIT_SIGNATURE 0x17
+
+
+static char __init *ar5315_flash_limit(void)
+{
+ u8 sig;
+ u32 flash_size = 0;
+
+ /* probe the flash chip size */
+ flash_regs = ioremap_nocache(ar5315_spiflash_res[1].start, ar5315_spiflash_res[1].end - ar5315_spiflash_res[1].start);
+ sig = spiflash_probe();
+ iounmap(flash_regs);
+
+ switch(sig) {
+ case STM_8MBIT_SIGNATURE:
+ flash_size = 0x00100000;
+ break;
+ case STM_16MBIT_SIGNATURE:
+ flash_size = 0x00200000;
+ break;
+ case STM_32MBIT_SIGNATURE:
+ flash_size = 0x00400000;
+ break;
+ case STM_64MBIT_SIGNATURE:
+ flash_size = 0x00800000;
+ break;
+ case STM_128MBIT_SIGNATURE:
+ flash_size = 0x01000000;
+ break;
+ }
+
+ ar5315_spiflash_res[0].end = ar5315_spiflash_res[0].start + flash_size;
+ return (char *) ar5315_spiflash_res[0].end;
+}
+
+int __init ar5315_init_devices(void)
+{
+ struct ar531x_config *config;
+ struct ar531x_boarddata *bcfg;
+ int dev = 0;
+#ifdef CONFIG_LEDS_GPIO
+ int i;
+ char *tmp;
+#endif
+
+ if (!is_5315)
+ return 0;
+
+ /* Find board configuration */
+ ar531x_find_config(ar5315_flash_limit());
+ bcfg = (struct ar531x_boarddata *) board_config;
+
+ config = (struct ar531x_config *) kzalloc(sizeof(struct ar531x_config), GFP_KERNEL);
+ config->board = board_config;
+ config->radio = radio_config;
+ config->unit = 0;
+ config->tag = (u_int16_t) (sysRegRead(AR5315_SREV) & AR5315_REV_CHIP);
+
+ ar5315_eth_data.board_config = board_config;
+ ar5315_eth_data.macaddr = bcfg->enet0Mac;
+ ar5315_wmac.dev.platform_data = config;
+
+ ar5315_devs[dev++] = &ar5315_eth;
+ ar5315_devs[dev++] = &ar5315_wmac;
+ ar5315_devs[dev++] = &ar5315_spiflash;
+ ar5315_devs[dev++] = &ar5315_wdt;
+
+#ifdef CONFIG_LEDS_GPIO
+ ar5315_led_data.num_leds = 0;
+ for(i = 1; i < 8; i++)
+ {
+ if((i != AR5315_RESET_GPIO) && (i != bcfg->resetConfigGpio))
+ {
+ if(i == bcfg->sysLedGpio)
+ {
+ tmp = kstrdup("wlan", GFP_KERNEL);
+ } else {
+ tmp = kmalloc(6, GFP_KERNEL);
+ if(tmp)
+ sprintf((char*)tmp, "gpio%d", i);
+ }
+ if(tmp)
+ {
+ ar5315_leds[ar5315_led_data.num_leds].name = tmp;
+ ar5315_leds[ar5315_led_data.num_leds].gpio = i;
+ ar5315_leds[ar5315_led_data.num_leds].active_low = 0;
+ ar5315_led_data.num_leds++;
+ } else {
+ printk("failed to alloc led string\n");
+ continue;
+ }
+ }
+ }
+ ar5315_devs[dev++] = &ar5315_gpio_leds;
+#endif
+
+ return platform_add_devices(ar5315_devs, dev);
+}
+
+static void ar5315_halt(void)
+{
+ while (1);
+}
+
+static void ar5315_power_off(void)
+{
+ ar5315_halt();
+}
+
+
+static void ar5315_restart(char *command)
+{
+ void (*mips_reset_vec)(void) = (void *) 0xbfc00000;
+
+ /* reset the system */
+ sysRegWrite(AR5315_COLD_RESET,AR5317_RESET_SYSTEM);
+
+ /* Cold reset does not work on the AR2315/6, use the GPIO reset bits a workaround.
+ * give it some time to attempt a gpio based hardware reset
+ * (atheros reference design workaround) */
+ gpio_direction_output(AR5315_RESET_GPIO, 0);
+ mdelay(100);
+
+ /* Some boards (e.g. Senao EOC-2610) don't implement the reset logic
+ * workaround. Attempt to jump to the mips reset location -
+ * the boot loader itself might be able to recover the system */
+ mips_reset_vec();
+}
+
+
+/*
+ * This table is indexed by bits 5..4 of the CLOCKCTL1 register
+ * to determine the predevisor value.
+ */
+static int __initdata CLOCKCTL1_PREDIVIDE_TABLE[4] = {
+ 1,
+ 2,
+ 4,
+ 5
+};
+
+static int __initdata PLLC_DIVIDE_TABLE[5] = {
+ 2,
+ 3,
+ 4,
+ 6,
+ 3
+};
+
+static unsigned int __init
+ar5315_sys_clk(unsigned int clockCtl)
+{
+ unsigned int pllcCtrl,cpuDiv;
+ unsigned int pllcOut,refdiv,fdiv,divby2;
+ unsigned int clkDiv;
+
+ pllcCtrl = sysRegRead(AR5315_PLLC_CTL);
+ refdiv = (pllcCtrl & PLLC_REF_DIV_M) >> PLLC_REF_DIV_S;
+ refdiv = CLOCKCTL1_PREDIVIDE_TABLE[refdiv];
+ fdiv = (pllcCtrl & PLLC_FDBACK_DIV_M) >> PLLC_FDBACK_DIV_S;
+ divby2 = (pllcCtrl & PLLC_ADD_FDBACK_DIV_M) >> PLLC_ADD_FDBACK_DIV_S;
+ divby2 += 1;
+ pllcOut = (40000000/refdiv)*(2*divby2)*fdiv;
+
+
+ /* clkm input selected */
+ switch(clockCtl & CPUCLK_CLK_SEL_M) {
+ case 0:
+ case 1:
+ clkDiv = PLLC_DIVIDE_TABLE[(pllcCtrl & PLLC_CLKM_DIV_M) >> PLLC_CLKM_DIV_S];
+ break;
+ case 2:
+ clkDiv = PLLC_DIVIDE_TABLE[(pllcCtrl & PLLC_CLKC_DIV_M) >> PLLC_CLKC_DIV_S];
+ break;
+ default:
+ pllcOut = 40000000;
+ clkDiv = 1;
+ break;
+ }
+ cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S;
+ cpuDiv = cpuDiv * 2 ?: 1;
+ return (pllcOut/(clkDiv * cpuDiv));
+}
+
+static inline unsigned int ar5315_cpu_frequency(void)
+{
+ return ar5315_sys_clk(sysRegRead(AR5315_CPUCLK));
+}
+
+static inline unsigned int ar5315_apb_frequency(void)
+{
+ return ar5315_sys_clk(sysRegRead(AR5315_AMBACLK));
+}
+
+static void __init ar5315_time_init(void)
+{
+ mips_hpt_frequency = ar5315_cpu_frequency() / 2;
+}
+
+void __init ar5315_prom_init(void)
+{
+ u32 memsize, memcfg, devid;
+
+ is_5315 = 1;
+ memcfg = sysRegRead(AR5315_MEM_CFG);
+ memsize = 1 + ((memcfg & SDRAM_DATA_WIDTH_M) >> SDRAM_DATA_WIDTH_S);
+ memsize <<= 1 + ((memcfg & SDRAM_COL_WIDTH_M) >> SDRAM_COL_WIDTH_S);
+ memsize <<= 1 + ((memcfg & SDRAM_ROW_WIDTH_M) >> SDRAM_ROW_WIDTH_S);
+ memsize <<= 3;
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+
+ /* Detect the hardware based on the device ID */
+ devid = sysRegRead(AR5315_SREV) & AR5315_REV_CHIP;
+ switch(devid) {
+ case 0x90:
+ case 0x91:
+ mips_machtype = MACH_ATHEROS_AR2317;
+ break;
+ default:
+ mips_machtype = MACH_ATHEROS_AR2315;
+ break;
+ }
+}
+
+void __init ar5315_plat_setup(void)
+{
+ unsigned int config = read_c0_config();
+
+ /* Clear any lingering AHB errors */
+ write_c0_config(config & ~0x3);
+ sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
+ sysRegRead(AR5315_AHB_ERR1);
+ sysRegWrite(AR5315_WDC, WDC_IGNORE_EXPIRATION);
+
+ board_time_init = ar5315_time_init;
+
+ _machine_restart = ar5315_restart;
+ _machine_halt = ar5315_halt;
+ pm_power_off = ar5315_power_off;
+
+ serial_setup(KSEG1ADDR(AR5315_UART0), ar5315_apb_frequency());
+}
+
+arch_initcall(ar5315_init_devices);
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/irq.c b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/irq.c
new file mode 100644
index 000000000..581b1a4a1
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/irq.c
@@ -0,0 +1,359 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Platform devices for Atheros SoCs
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+#include <asm/io.h>
+
+#include <ar531x.h>
+#include <gpio.h>
+
+static u32 gpiointmask = 0, gpiointval = 0;
+
+static inline void ar5315_gpio_irq(void)
+{
+ u32 pend;
+ sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO);
+
+ /* only do one gpio interrupt at a time */
+ pend = (sysRegRead(AR5315_GPIO_DI) ^ gpiointval) & gpiointmask;
+ if (!pend)
+ return;
+
+ do_IRQ(AR531X_GPIO_IRQ_BASE + fls(pend) - 1);
+}
+
+
+/*
+ * Called when an interrupt is received, this function
+ * determines exactly which interrupt it was, and it
+ * invokes the appropriate handler.
+ *
+ * Implicitly, we also define interrupt priority by
+ * choosing which to dispatch first.
+ */
+asmlinkage void ar5315_irq_dispatch(void)
+{
+ int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & CAUSEF_IP3)
+ do_IRQ(AR5315_IRQ_WLAN0_INTRS);
+ else if (pending & CAUSEF_IP4)
+ do_IRQ(AR5315_IRQ_ENET0_INTRS);
+#ifdef CONFIG_PCI
+ else if (pending & CAUSEF_IP5)
+ ar5315_pci_irq(AR5315_IRQ_LCBUS_PCI);
+#endif
+ else if (pending & CAUSEF_IP2) {
+ unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR);
+
+ if (ar531x_misc_intrs & AR5315_ISR_SPI)
+ do_IRQ(AR531X_MISC_IRQ_SPI);
+ else if (ar531x_misc_intrs & AR5315_ISR_TIMER)
+ do_IRQ(AR531X_MISC_IRQ_TIMER);
+ else if (ar531x_misc_intrs & AR5315_ISR_AHB)
+ do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
+ else if (ar531x_misc_intrs & AR5315_ISR_GPIO)
+ ar5315_gpio_irq();
+ else if (ar531x_misc_intrs & AR5315_ISR_UART0)
+ do_IRQ(AR531X_MISC_IRQ_UART0);
+ else if (ar531x_misc_intrs & AR5315_ISR_WD)
+ do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
+ else
+ do_IRQ(AR531X_MISC_IRQ_NONE);
+ } else if (pending & CAUSEF_IP7)
+ do_IRQ(AR531X_IRQ_CPU_CLOCK);
+}
+
+#ifdef CONFIG_PCI
+static inline void pci_abort_irq(void)
+{
+ sysRegWrite(AR5315_PCI_INT_STATUS, AR5315_PCI_ABORT_INT);
+ (void)sysRegRead(AR5315_PCI_INT_STATUS); /* flush write to hardware */
+}
+
+static inline void pci_ack_irq(void)
+{
+ sysRegWrite(AR5315_PCI_INT_STATUS, AR5315_PCI_EXT_INT);
+ (void)sysRegRead(AR5315_PCI_INT_STATUS); /* flush write to hardware */
+}
+
+void ar5315_pci_irq(int irq)
+{
+ if (sysRegRead(AR5315_PCI_INT_STATUS) == AR5315_PCI_ABORT_INT)
+ pci_abort_irq();
+ else {
+ do_IRQ(irq);
+ pci_ack_irq();
+ }
+}
+#endif
+
+static void ar5315_gpio_intr_enable(unsigned int irq)
+{
+ u32 gpio, mask;
+ gpio = irq - AR531X_GPIO_IRQ_BASE;
+ mask = 1 << gpio;
+ gpiointmask |= mask;
+
+ /* reconfigure GPIO line as input */
+ sysRegMask(AR5315_GPIO_CR, AR5315_GPIO_CR_M(gpio), AR5315_GPIO_CR_I(gpio));
+
+ /* Enable interrupt with edge detection */
+ sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(3));
+}
+
+static void ar5315_gpio_intr_disable(unsigned int irq)
+{
+ u32 gpio, mask;
+ gpio = irq - AR531X_GPIO_IRQ_BASE;
+ mask = 1 << gpio;
+
+ gpiointmask &= ~mask;
+
+ /* Disable interrupt with edge detection */
+ sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(0));
+}
+
+/* Turn on the specified AR531X_MISC_IRQ interrupt */
+static unsigned int ar5315_gpio_intr_startup(unsigned int irq)
+{
+ ar5315_gpio_intr_enable(irq);
+ return 0;
+}
+
+/* Turn off the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5315_gpio_intr_shutdown(unsigned int irq)
+{
+ ar5315_gpio_intr_disable(irq);
+}
+
+static void
+ar5315_gpio_intr_ack(unsigned int irq)
+{
+ ar5315_gpio_intr_disable(irq);
+}
+
+static void
+ar5315_gpio_intr_end(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ ar5315_gpio_intr_enable(irq);
+}
+
+static struct irq_chip ar5315_gpio_intr_controller = {
+ .typename = "AR5315 GPIO",
+ .startup = ar5315_gpio_intr_startup,
+ .shutdown = ar5315_gpio_intr_shutdown,
+ .enable = ar5315_gpio_intr_enable,
+ .disable = ar5315_gpio_intr_disable,
+ .ack = ar5315_gpio_intr_ack,
+ .end = ar5315_gpio_intr_end,
+};
+
+
+/* Enable the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5315_misc_intr_enable(unsigned int irq)
+{
+ unsigned int imr;
+
+ imr = sysRegRead(AR5315_IMR);
+ switch(irq)
+ {
+ case AR531X_MISC_IRQ_SPI:
+ imr |= AR5315_ISR_SPI;
+ break;
+
+ case AR531X_MISC_IRQ_TIMER:
+ imr |= AR5315_ISR_TIMER;
+ break;
+
+ case AR531X_MISC_IRQ_AHB_PROC:
+ imr |= AR5315_ISR_AHB;
+ break;
+
+ case AR531X_MISC_IRQ_AHB_DMA:
+ imr |= 0/* ?? */;
+ break;
+
+ case AR531X_MISC_IRQ_GPIO:
+ imr |= AR5315_ISR_GPIO;
+ break;
+
+ case AR531X_MISC_IRQ_UART0:
+ imr |= AR5315_ISR_UART0;
+ break;
+
+
+ case AR531X_MISC_IRQ_WATCHDOG:
+ imr |= AR5315_ISR_WD;
+ break;
+
+ case AR531X_MISC_IRQ_LOCAL:
+ imr |= 0/* ?? */;
+ break;
+
+ }
+ sysRegWrite(AR5315_IMR, imr);
+ imr=sysRegRead(AR5315_IMR); /* flush write buffer */
+}
+
+/* Disable the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5315_misc_intr_disable(unsigned int irq)
+{
+ unsigned int imr;
+
+ imr = sysRegRead(AR5315_IMR);
+ switch(irq)
+ {
+ case AR531X_MISC_IRQ_SPI:
+ imr &= ~AR5315_ISR_SPI;
+ break;
+
+ case AR531X_MISC_IRQ_TIMER:
+ imr &= (~AR5315_ISR_TIMER);
+ break;
+
+ case AR531X_MISC_IRQ_AHB_PROC:
+ imr &= (~AR5315_ISR_AHB);
+ break;
+
+ case AR531X_MISC_IRQ_AHB_DMA:
+ imr &= 0/* ?? */;
+ break;
+
+ case AR531X_MISC_IRQ_GPIO:
+ imr &= ~AR5315_ISR_GPIO;
+ break;
+
+ case AR531X_MISC_IRQ_UART0:
+ imr &= (~AR5315_ISR_UART0);
+ break;
+
+ case AR531X_MISC_IRQ_WATCHDOG:
+ imr &= (~AR5315_ISR_WD);
+ break;
+
+ case AR531X_MISC_IRQ_LOCAL:
+ imr &= ~0/* ?? */;
+ break;
+
+ }
+ sysRegWrite(AR5315_IMR, imr);
+ sysRegRead(AR5315_IMR); /* flush write buffer */
+}
+
+/* Turn on the specified AR531X_MISC_IRQ interrupt */
+static unsigned int
+ar5315_misc_intr_startup(unsigned int irq)
+{
+ ar5315_misc_intr_enable(irq);
+ return 0;
+}
+
+/* Turn off the specified AR531X_MISC_IRQ interrupt */
+static void
+ar5315_misc_intr_shutdown(unsigned int irq)
+{
+ ar5315_misc_intr_disable(irq);
+}
+
+static void
+ar5315_misc_intr_ack(unsigned int irq)
+{
+ ar5315_misc_intr_disable(irq);
+}
+
+static void
+ar5315_misc_intr_end(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ ar5315_misc_intr_enable(irq);
+}
+
+static struct irq_chip ar5315_misc_intr_controller = {
+ .typename = "AR5315 misc",
+ .startup = ar5315_misc_intr_startup,
+ .shutdown = ar5315_misc_intr_shutdown,
+ .enable = ar5315_misc_intr_enable,
+ .disable = ar5315_misc_intr_disable,
+ .ack = ar5315_misc_intr_ack,
+ .end = ar5315_misc_intr_end,
+};
+
+static irqreturn_t ar5315_ahb_proc_handler(int cpl, void *dev_id)
+{
+ sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
+ sysRegRead(AR5315_AHB_ERR1);
+
+ printk("AHB fatal error\n");
+ machine_restart("AHB error"); /* Catastrophic failure */
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction ar5315_ahb_proc_interrupt = {
+ .handler = ar5315_ahb_proc_handler,
+ .flags = IRQF_DISABLED,
+ .name = "ar5315_ahb_proc_interrupt",
+};
+
+
+static struct irqaction cascade = {
+ .handler = no_action,
+ .flags = IRQF_DISABLED,
+ .name = "cascade",
+};
+
+static void ar5315_gpio_intr_init(int irq_base)
+{
+ int i;
+
+ for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 1;
+ irq_desc[i].chip = &ar5315_gpio_intr_controller;
+ }
+ setup_irq(AR531X_MISC_IRQ_GPIO, &cascade);
+ gpiointval = sysRegRead(AR5315_GPIO_DI);
+}
+
+void ar5315_misc_intr_init(int irq_base)
+{
+ int i;
+
+ for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 1;
+ irq_desc[i].chip = &ar5315_misc_intr_controller;
+ }
+ setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5315_ahb_proc_interrupt);
+ setup_irq(AR5315_IRQ_MISC_INTRS, &cascade);
+ ar5315_gpio_intr_init(AR531X_GPIO_IRQ_BASE);
+}
+
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/pci.c b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/pci.c
new file mode 100644
index 000000000..166fa1cf9
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/pci.c
@@ -0,0 +1,265 @@
+/*
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <asm/bootinfo.h>
+#include <asm/paccess.h>
+#include <asm/irq_cpu.h>
+#include <asm/io.h>
+#include "ar531x.h"
+
+#define AR531X_MEM_BASE 0x80800000UL
+#define AR531X_MEM_SIZE 0x00ffffffUL
+#define AR531X_IO_SIZE 0x00007fffUL
+#define IDSEL_SHIFT 13
+
+static spinlock_t ar531x_pci_lock = SPIN_LOCK_UNLOCKED;
+static u32 cfgaddr;
+
+static int config_access(int busno, int dev, int func, int where, int size, u32 ptr, int write)
+{
+ u32 address; /* Address to read from */
+ u32 reg;
+ unsigned long flags;
+ int ret = -1;
+ if ((busno != 0) || ((dev != 0) && (dev != 3)) || (func > 2))
+ return ret;
+
+ spin_lock_irqsave(&ar531x_pci_lock, flags);
+
+ /* Select Configuration access */
+ reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
+ reg |= AR5315_PCIMISC_CFG_SEL;
+ sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
+ (void)sysRegRead(AR5315_PCI_MISC_CONFIG);
+
+ address = (u32)cfgaddr + (1 << (IDSEL_SHIFT + dev)) + (func << 8) + where;
+
+ if (size == 1)
+ address ^= 0x3;
+ else if (size == 2)
+ address ^= 0x2;
+
+ if (write) {
+ if (size == 1)
+ ret = put_dbe(ptr, (u8 *) address);
+ else if (size == 2)
+ ret = put_dbe(ptr, (u16 *) address);
+ else if (size == 4)
+ ret = put_dbe(ptr, (u32 *) address);
+ } else {
+ if (size == 1)
+ ret = get_dbe(*((u32 *)ptr), (u8 *) address);
+ else if (size == 2)
+ ret = get_dbe(*((u32 *)ptr), (u16 *) address);
+ else if (size == 4)
+ ret = get_dbe(*((u32 *)ptr), (u32 *) address);
+ }
+
+ /* Select Memory access */
+ reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
+ reg &= ~AR5315_PCIMISC_CFG_SEL;
+ sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
+ (void)sysRegRead(AR5315_PCI_MISC_CONFIG);
+
+ spin_unlock_irqrestore(&ar531x_pci_lock, flags);
+
+ if (ret) {
+ *((u32 *)ptr) = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int ar531x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * value)
+{
+ return config_access(bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, (u32) value, 0);
+}
+
+static int ar531x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
+{
+ return config_access(bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value, 1);
+}
+
+struct pci_ops ar531x_pci_ops = {
+ .read = ar531x_pci_read,
+ .write = ar531x_pci_write,
+};
+
+static struct resource ar531x_mem_resource = {
+ .name = "AR531x PCI MEM",
+ .start = AR531X_MEM_BASE,
+ .end = AR531X_MEM_BASE + AR531X_MEM_SIZE - AR531X_IO_SIZE - 1 + 0x4000000,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource ar531x_io_resource = {
+ .name = "AR531x PCI I/O",
+ .start = AR531X_MEM_BASE + AR531X_MEM_SIZE - AR531X_IO_SIZE,
+ .end = AR531X_MEM_BASE + AR531X_MEM_SIZE - 1,
+ .flags = IORESOURCE_IO,
+};
+
+struct pci_controller ar531x_pci_controller = {
+ .pci_ops = &ar531x_pci_ops,
+ .mem_resource = &ar531x_mem_resource,
+ .io_resource = &ar531x_io_resource,
+ .mem_offset = 0x00000000UL,
+ .io_offset = 0x00000000UL,
+};
+
+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return AR5315_IRQ_LCBUS_PCI;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ u32 reg;
+
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 5);
+ pci_write_config_word(dev, 0x40, 0);
+
+ /* Clear any pending Abort or external Interrupts
+ * and enable interrupt processing */
+ reg = sysRegRead(AR5315_PCI_INTEN_REG);
+ reg &= ~AR5315_PCI_INT_ENABLE;
+ sysRegWrite(AR5315_PCI_INTEN_REG, reg);
+
+ reg = sysRegRead(AR5315_PCI_INT_STATUS);
+ reg |= (AR5315_PCI_ABORT_INT | AR5315_PCI_EXT_INT);
+ sysRegWrite(AR5315_PCI_INT_STATUS, reg);
+
+ reg = sysRegRead(AR5315_PCI_INT_MASK);
+ reg |= (AR5315_PCI_EXT_INT | AR5315_PCI_ABORT_INT);
+ sysRegWrite(AR5315_PCI_INT_MASK, reg);
+
+ reg = sysRegRead(AR5315_PCI_INTEN_REG);
+ reg |= AR5315_PCI_INT_ENABLE;
+ sysRegWrite(AR5315_PCI_INTEN_REG, reg);
+
+ return 0;
+}
+
+static void ar5315_pci_fixup(struct pci_dev *dev)
+{
+ struct pci_bus *bus = dev->bus;
+
+ if ((PCI_SLOT(dev->devfn) != 3) || (PCI_FUNC(dev->devfn) != 0) || (bus->number != 0))
+ return;
+
+#define _DEV bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)
+ printk("PCI: fixing up device %d,%d,%d\n", _DEV);
+ /* fix up mbars */
+ config_access(_DEV, PCI_BASE_ADDRESS_0, 4, HOST_PCI_MBAR0, 1);
+ config_access(_DEV, PCI_BASE_ADDRESS_1, 4, HOST_PCI_MBAR1, 1);
+ config_access(_DEV, PCI_BASE_ADDRESS_2, 4, HOST_PCI_MBAR2, 1);
+ config_access(_DEV, PCI_COMMAND, 4,
+ PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL|
+ PCI_COMMAND_INVALIDATE|PCI_COMMAND_PARITY|PCI_COMMAND_SERR|
+ PCI_COMMAND_FAST_BACK, 1);
+#undef _DEV
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, ar5315_pci_fixup);
+
+int __init ar5315_pci_init(void)
+{
+ u32 reg;
+
+ if (mips_machtype != MACH_ATHEROS_AR2315)
+ return -ENODEV;
+
+ printk("AR531x PCI init... \n");
+
+ cfgaddr = (u32) ioremap_nocache(0x80000000, 1*1024*1024); /* Remap PCI config space */
+ ar531x_pci_controller.io_map_base =
+ (unsigned long) ioremap_nocache(AR531X_MEM_BASE + AR531X_MEM_SIZE, AR531X_IO_SIZE);
+ set_io_port_base(ar531x_pci_controller.io_map_base); /* PCI I/O space */
+
+ reg = sysRegRead(AR5315_RESET);
+ sysRegWrite(AR5315_RESET, reg | AR5315_RESET_PCIDMA);
+
+ udelay(10*1000);
+
+ sysRegWrite(AR5315_RESET, reg & ~AR5315_RESET_PCIDMA);
+ sysRegRead(AR5315_RESET); /* read after */
+
+ udelay(10*1000);
+
+ reg = sysRegRead(AR5315_ENDIAN_CTL);
+ reg |= AR5315_CONFIG_PCIAHB | AR5315_CONFIG_PCIAHB_BRIDGE;
+
+ sysRegWrite(AR5315_ENDIAN_CTL, reg);
+
+ reg = sysRegRead(AR5315_PCICLK);
+ reg = 4;
+ sysRegWrite(AR5315_PCICLK, reg);
+
+ reg = sysRegRead(AR5315_AHB_ARB_CTL);
+ reg |= (ARB_PCI);
+ sysRegWrite(AR5315_AHB_ARB_CTL, reg);
+
+ reg = sysRegRead(AR5315_IF_CTL);
+ reg &= ~(IF_PCI_CLK_MASK | IF_MASK);
+ reg |= (IF_PCI | IF_PCI_HOST | IF_PCI_INTR | (IF_PCI_CLK_OUTPUT_CLK << IF_PCI_CLK_SHIFT));
+
+ sysRegWrite(AR5315_IF_CTL, reg);
+
+ /* Reset the PCI bus by setting bits 5-4 in PCI_MCFG */
+ reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
+ reg &= ~(AR5315_PCIMISC_RST_MODE);
+ reg |= AR5315_PCIRST_LOW;
+ sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
+
+ /* wait for 100 ms */
+ udelay(100*1000);
+
+ /* Bring the PCI out of reset */
+ reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
+ reg &= ~(AR5315_PCIMISC_RST_MODE);
+ reg |= (AR5315_PCIRST_HIGH | AR5315_PCICACHE_DIS | 0x8);
+ sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
+
+ sysRegWrite(AR5315_PCI_UNCACHE_CFG,
+ 0x1E | /* 1GB uncached */
+ (1 << 5) | /* Enable uncached */
+ (0x2 << 30) /* Base: 0x80000000 */
+ );
+ (void)sysRegRead(AR5315_PCI_UNCACHE_CFG); /* flush */
+
+ udelay(500*1000);
+
+ /* dirty hack - anyone with a datasheet that knows the memory map ? */
+ ioport_resource.start = 0x10000000;
+ ioport_resource.end = 0xffffffff;
+ iomem_resource.start = 0x10000000;
+ iomem_resource.end = 0xffffffff;
+
+ register_pci_controller(&ar531x_pci_controller);
+
+ printk("done\n");
+ return 0;
+}
+
+arch_initcall(ar5315_pci_init);
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/board.c b/target/linux/atheros/files-2.6.26/arch/mips/atheros/board.c
new file mode 100644
index 000000000..4a224933a
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/board.c
@@ -0,0 +1,299 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Platform devices for Atheros SoCs
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/random.h>
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+#include <asm/io.h>
+#include <ar531x.h>
+
+char *board_config = NULL;
+char *radio_config = NULL;
+int broken_boarddata = 0;
+
+extern int early_serial_setup(struct uart_port *port);
+
+static inline bool
+check_radio_magic(unsigned char *addr)
+{
+ addr += 0x7a; /* offset for flash magic */
+ if ((addr[0] == 0x5a) && (addr[1] == 0xa5)) {
+ return 1;
+ }
+ return 0;
+}
+
+static inline bool
+check_board_data(unsigned char *flash_limit, unsigned char *addr, bool broken)
+{
+ /* config magic found */
+ if ( *(int *)addr == 0x35333131)
+ return 1;
+
+ if (!broken)
+ return 0;
+
+ if (check_radio_magic(addr + 0xf8))
+ radio_config = addr + 0xf8;
+ if ((addr < flash_limit + 0x10000) &&
+ check_radio_magic(addr + 0x10000))
+ radio_config = addr + 0x10000;
+
+ if (radio_config) {
+ /* broken board data detected, use radio data to find the offset,
+ * user will fix this */
+ broken_boarddata = 1;
+ return 1;
+ }
+ return 0;
+}
+
+static u8 *find_board_config(char *flash_limit, bool broken)
+{
+ char *addr;
+ int found = 0;
+
+ for (addr = (char *) (flash_limit - 0x1000);
+ addr >= (char *) (flash_limit - 0x30000);
+ addr -= 0x1000) {
+
+ if (check_board_data(flash_limit, addr, broken)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ addr = NULL;
+
+ return addr;
+}
+
+static u8 *find_radio_config(char *flash_limit, char *board_config)
+{
+ int dataFound;
+ char *radio_config;
+
+ /*
+ * Now find the start of Radio Configuration data, using heuristics:
+ * Search forward from Board Configuration data by 0x1000 bytes
+ * at a time until we find non-0xffffffff.
+ */
+ dataFound = 0;
+ for (radio_config = board_config + 0x1000;
+ (radio_config < flash_limit);
+ radio_config += 0x1000) {
+ if ((*(u32 *)radio_config != 0xffffffff) &&
+ check_radio_magic(radio_config)) {
+ dataFound = 1;
+ break;
+ }
+ }
+
+#ifdef CONFIG_ATHEROS_AR5315
+ if (!dataFound) { /* AR2316 relocates radio config to new location */
+ for (radio_config = board_config + 0xf8;
+ (radio_config < flash_limit - 0x1000 + 0xf8);
+ radio_config += 0x1000) {
+ if ((*(u32 *)radio_config != 0xffffffff) &&
+ check_radio_magic(radio_config)) {
+ dataFound = 1;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (!dataFound) {
+ printk("Could not find Radio Configuration data\n");
+ radio_config = 0;
+ }
+
+ return (u8 *) radio_config;
+}
+
+int __init ar531x_find_config(char *flash_limit)
+{
+ struct ar531x_boarddata *bd;
+ unsigned int rcfg_size;
+ char *bcfg, *rcfg;
+
+ /* Copy the board and radio data to RAM, because with the new
+ * spiflash driver, accessing the mapped memory directly is no
+ * longer safe */
+
+ bcfg = find_board_config(flash_limit, false);
+ if (!bcfg)
+ bcfg = find_board_config(flash_limit, true);
+ if (!bcfg) {
+ printk("WARNING: No board configuration data found!\n");
+ return -ENODEV;
+ }
+
+ board_config = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
+ memcpy(board_config, bcfg, 0x100);
+ if (broken_boarddata) {
+ printk("WARNING: broken board data detected\n");
+ bd = (struct ar531x_boarddata *)board_config;
+ if (!memcmp(bd->enet0Mac, "\x00\x00\x00\x00\x00\x00", 6)) {
+ printk("Fixing up empty mac addresses\n");
+ bd->enet0Mac[1] = 0x13;
+ bd->enet0Mac[2] = 0x37;
+ get_random_bytes(bd->enet0Mac + 3, 3);
+ bd->wlan0Mac[1] = 0x13;
+ bd->wlan0Mac[2] = 0x37;
+ get_random_bytes(bd->wlan0Mac + 3, 3);
+ }
+ }
+
+
+ /* Radio config starts 0x100 bytes after board config, regardless
+ * of what the physical layout on the flash chip looks like */
+
+ if (radio_config)
+ rcfg = radio_config;
+ else
+ rcfg = find_radio_config(flash_limit, bcfg);
+
+ if (!rcfg)
+ return -ENODEV;
+
+ radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff);
+ printk("Radio config found at offset 0x%x(0x%x)\n", rcfg - bcfg, radio_config - board_config);
+ rcfg_size = BOARD_CONFIG_BUFSZ - (radio_config - board_config);
+ memcpy(radio_config, rcfg, rcfg_size);
+
+ return 0;
+}
+
+void __init serial_setup(unsigned long mapbase, unsigned int uartclk)
+{
+ struct uart_port s;
+
+ memset(&s, 0, sizeof(s));
+
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ s.iotype = UPIO_MEM;
+ s.irq = AR531X_MISC_IRQ_UART0;
+ s.regshift = 2;
+ s.mapbase = mapbase;
+ s.uartclk = uartclk;
+ s.membase = (void __iomem *)s.mapbase;
+
+ early_serial_setup(&s);
+}
+
+void __init plat_mem_setup(void)
+{
+ DO_AR5312(ar5312_plat_setup();)
+ DO_AR5315(ar5315_plat_setup();)
+
+ /* Disable data watchpoints */
+ write_c0_watchlo0(0);
+}
+
+const char *get_system_type(void)
+{
+ switch (mips_machtype) {
+#ifdef CONFIG_ATHEROS_AR5312
+ case MACH_ATHEROS_AR5312:
+ return "Atheros AR5312";
+
+ case MACH_ATHEROS_AR2312:
+ return "Atheros AR2312";
+
+ case MACH_ATHEROS_AR2313:
+ return "Atheros AR2313";
+#endif
+#ifdef CONFIG_ATHEROS_AR5315
+ case MACH_ATHEROS_AR2315:
+ return "Atheros AR2315";
+ case MACH_ATHEROS_AR2316:
+ return "Atheros AR2316";
+ case MACH_ATHEROS_AR2317:
+ return "Atheros AR2317";
+ case MACH_ATHEROS_AR2318:
+ return "Atheros AR2318";
+#endif
+ }
+ return "Atheros (unknown)";
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
+void __init plat_timer_setup(struct irqaction *irq)
+{
+ unsigned int count;
+
+ /* Usually irq is timer_irqaction (timer_interrupt) */
+ setup_irq(AR531X_IRQ_CPU_CLOCK, irq);
+
+ /* to generate the first CPU timer interrupt */
+ count = read_c0_count();
+ write_c0_compare(count + 1000);
+}
+#endif
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ DO_AR5312(ar5312_irq_dispatch();)
+ DO_AR5315(ar5315_irq_dispatch();)
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
+void (*board_time_init)(void);
+void __init plat_time_init(void) {
+ board_time_init();
+}
+#endif
+
+void __init arch_init_irq(void)
+{
+ clear_c0_status(ST0_IM);
+ mips_cpu_irq_init();
+
+ /* Initialize interrupt controllers */
+ DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);)
+ DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);)
+}
+
+static int __init ar531x_register_gpiodev(void)
+{
+ static struct resource res = {
+ .start = 0xFFFFFFFF,
+ };
+ struct platform_device *pdev;
+
+ printk(KERN_INFO "ar531x: Registering GPIODEV device\n");
+
+ pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
+
+ if (!pdev) {
+ printk(KERN_ERR "ar531x: GPIODEV init failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+device_initcall(ar531x_register_gpiodev);
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/prom.c b/target/linux/atheros/files-2.6.26/arch/mips/atheros/prom.c
new file mode 100644
index 000000000..82617cdd3
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/prom.c
@@ -0,0 +1,45 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright MontaVista Software Inc
+ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Prom setup file for ar531x
+ */
+
+#include <linux/init.h>
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+#include <ar531x.h>
+
+void __init prom_init(void)
+{
+ char **argv;
+
+ mips_machtype = -1;
+
+ DO_AR5312(ar5312_prom_init();)
+ DO_AR5315(ar5315_prom_init();)
+#if 0
+ argv = (char **)fw_arg1;
+ /* RedBoot desired command line is argv[1] */
+ strcat(arcs_cmdline, argv[1]);
+#endif
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
diff --git a/target/linux/atheros/files-2.6.26/arch/mips/atheros/reset.c b/target/linux/atheros/files-2.6.26/arch/mips/atheros/reset.c
new file mode 100644
index 000000000..eb525da20
--- /dev/null
+++ b/target/linux/atheros/files-2.6.26/arch/mips/atheros/reset.c
@@ -0,0 +1,162 @@
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include <ar531x.h>
+
+#define AR531X_RESET_GPIO_IRQ (AR531X_GPIO_IRQ(bcfg->resetConfigGpio))
+
+struct event_t {
+ struct work_struct wq;
+ int set;
+ unsigned long jiffies;
+};
+
+static struct ar531x_boarddata *bcfg;
+static struct timer_list rst_button_timer;
+
+extern struct sock *uevent_sock;
+extern u64 uevent_next_seqnum(void);
+static unsigned long seen;
+
+static inline void add_msg(struct sk_buff *skb, char *msg)
+{
+ char *scratch;
+ scratch = skb_put(skb, strlen(msg) + 1);
+ sprintf(scratch, msg);
+}
+
+static void hotplug_button(struct work_struct *wq)
+{
+ struct sk_buff *skb;
+ struct event_t *event;
+ size_t len;
+ char *scratch, *s;
+ char buf[128];
+
+ event = container_of(wq, struct event_t, wq);
+ if (!uevent_sock)
+ goto done;
+
+ /* allocate message with the maximum possible size */
+ s = event->set ? "pressed" : "released";
+ len = strlen(s) + 2;
+ skb = alloc_skb(len + 2048, GFP_KERNEL);
+ if (!skb)
+ goto done;
+
+ /* add header */
+ scratch = skb_put(skb, len);
+ sprintf(scratch, "%s@",s);
+
+ /* copy keys to our continuous event payload buffer */
+ add_msg(skb, "HOME=/");
+ add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
+ add_msg(skb, "SUBSYSTEM=button");
+ add_msg(skb, "BUTTON=reset");
+ add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
+ sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
+ add_msg(skb, buf);
+ snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
+ add_msg(skb, buf);
+
+ NETLINK_CB(skb).dst_group = 1;
+ netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
+
+done:
+ kfree(event);
+}
+
+static int no_release_workaround = 1;
+
+static void
+reset_button_poll(unsigned long unused)
+{
+ struct event_t *event;
+ int gpio = ~0;
+
+ if(!no_release_workaround)
+ return;
+
+ DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
+ gpio &= 1 << (AR531X_RESET_GPIO_IRQ - AR531X_GPIO_IRQ_BASE);
+ if(gpio)
+ {
+ rst_button_timer.expires = jiffies + (HZ / 4);
+ add_timer(&rst_button_timer);
+ } else {
+ event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
+ if (!event)
+ {
+ printk("Could not alloc hotplug event\n");
+ return;
+ }
+ event->set = 0;
+ event->jiffies = jiffies;
+ INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
+ schedule_work(&event->wq);
+ }
+}
+
+static irqreturn_t button_handler(int irq, void *dev_id)
+{
+ static int pressed = 0;
+ struct event_t *event;
+ u32 gpio = ~0;
+
+ event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
+ if (!event)
+ return IRQ_NONE;
+
+ pressed = !pressed;
+
+ DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
+ gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
+
+ event->set = gpio;
+ if(!event->set)
+ no_release_workaround = 0;
+
+ event->jiffies = jiffies;
+
+ INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
+ schedule_work(&event->wq);
+
+ seen = jiffies;
+ if(event->set && no_release_workaround)
+ mod_timer(&rst_button_timer, jiffies + (HZ / 4));
+
+ return IRQ_HANDLED;
+}
+
+void ar531x_disable_reset_button(void)
+{
+ disable_irq(AR531X_RESET_GPIO_IRQ);
+}
+
+EXPORT_SYMBOL(ar531x_disable_reset_button);
+
+int __init ar531x_init_reset(void)
+{
+ bcfg = (struct ar531x_boarddata *) board_config;
+
+ seen = jiffies;
+
+ init_timer(&rst_button_timer);
+ rst_button_timer.function = reset_button_poll;
+ rst_button_timer.expires = jiffies + HZ / 50;
+ add_timer(&rst_button_timer);
+
+ request_irq(AR531X_RESET_GPIO_IRQ, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
+
+ return 0;
+}
+
+
+
+module_init(ar531x_init_reset);