diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2011-04-12 09:35:27 +0200 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2011-04-12 09:35:27 +0200 |
commit | dd48a4ec3bb4ee6f1cf2e67e4ac8f5f6f93f9a05 (patch) | |
tree | 5b97591f5861c38a32f3d5693ee7b4ef6bd30d63 | |
parent | 3a996498d7c64584f34492604b614e2412ade08e (diff) |
add basic support for Fonera devices (nfsroot) via OpenWrt/FreeWRT kernel patches
-rw-r--r-- | target/config/Config.in | 1 | ||||
-rw-r--r-- | target/linux/config/Config.in.netdevice | 14 | ||||
-rw-r--r-- | target/linux/patches/2.6.37/atheros.patch | 6332 | ||||
-rw-r--r-- | target/mips/sys-available/fon-fon2100 | 8 |
4 files changed, 6355 insertions, 0 deletions
diff --git a/target/config/Config.in b/target/config/Config.in index 7dd6c1947..ff8668b35 100644 --- a/target/config/Config.in +++ b/target/config/Config.in @@ -180,6 +180,7 @@ config ADK_TARGET_CFLAGS config ADK_TARGET_CMDLINE string + default "console=ttyS0,9600" if ADK_TARGET_SYSTEM_FON_FON2100 default "console=ttyS0,38400" if ADK_TARGET_SYSTEM_PCENGINES_WRAP default "console=ttyS0,115200 console=tty0 geodewdt.nowayout=1" if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default "console=ttyS0,115200 console=tty0" if ADK_TARGET_SYSTEM_IBM_X40 diff --git a/target/linux/config/Config.in.netdevice b/target/linux/config/Config.in.netdevice index 6c30397a4..a0ec08247 100644 --- a/target/linux/config/Config.in.netdevice +++ b/target/linux/config/Config.in.netdevice @@ -7,6 +7,9 @@ config ADK_KERNEL_NETDEVICES config ADK_KERNEL_NET_ETHERNET boolean +config ADK_KERNEL_PHYLIB + boolean + config ADK_KERNEL_MII boolean @@ -62,6 +65,17 @@ config ADK_KERNEL_VIA_RHINE default n help +config ADK_KERNEL_AR231X_ETHERNET + boolean + select ADK_KERNEL_NETDEVICES + select ADK_KERNEL_NET_ETHERNET + select ADK_KERNEL_NET_PCI + select ADK_KERNEL_MII + select ADK_KERNEL_PHYLIB + default y if ADK_TARGET_SYSTEM_FON_FON2100 + default n + help + config ADK_KERNEL_KORINA boolean select ADK_KERNEL_NETDEVICES diff --git a/target/linux/patches/2.6.37/atheros.patch b/target/linux/patches/2.6.37/atheros.patch new file mode 100644 index 000000000..ee5184a00 --- /dev/null +++ b/target/linux/patches/2.6.37/atheros.patch @@ -0,0 +1,6332 @@ +diff -Nur linux-2.6.37.orig/arch/mips/Kbuild.platforms linux-2.6.37/arch/mips/Kbuild.platforms +--- linux-2.6.37.orig/arch/mips/Kbuild.platforms 2011-01-05 01:50:19.000000000 +0100 ++++ linux-2.6.37/arch/mips/Kbuild.platforms 2011-04-12 08:12:01.000000000 +0200 +@@ -5,6 +5,7 @@ + platforms += bcm47xx + platforms += bcm63xx + platforms += cavium-octeon ++platforms += ar231x + platforms += cobalt + platforms += dec + platforms += emma +diff -Nur linux-2.6.37.orig/arch/mips/Kconfig linux-2.6.37/arch/mips/Kconfig +--- linux-2.6.37.orig/arch/mips/Kconfig 2011-01-05 01:50:19.000000000 +0100 ++++ linux-2.6.37/arch/mips/Kconfig 2011-04-12 08:12:01.000000000 +0200 +@@ -102,6 +102,20 @@ + help + Support for BCM63XX based boards + ++config ATHEROS_AR231X ++ bool "Atheros 231x/531x SoC support" ++ select CEVT_R4K ++ select CSRC_R4K ++ select DMA_NONCOHERENT ++ select IRQ_CPU ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_BIG_ENDIAN ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select GENERIC_GPIO ++ select SYS_HAS_EARLY_PRINTK ++ help ++ Support for AR231x and AR531x based boards ++ + config MIPS_COBALT + bool "Cobalt Server" + select CEVT_R4K +@@ -716,6 +730,7 @@ + + endchoice + ++source "arch/mips/ar231x/Kconfig" + source "arch/mips/alchemy/Kconfig" + source "arch/mips/bcm63xx/Kconfig" + source "arch/mips/jazz/Kconfig" +diff -Nur linux-2.6.37.orig/arch/mips/ar231x/Kconfig linux-2.6.37/arch/mips/ar231x/Kconfig +--- linux-2.6.37.orig/arch/mips/ar231x/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.37/arch/mips/ar231x/Kconfig 2011-04-12 08:12:33.000000000 +0200 +@@ -0,0 +1,27 @@ ++config ATHEROS_AR5312 ++ bool "Atheros 5312/2312+ support" ++ depends on ATHEROS_AR231X ++ default y ++ ++config ATHEROS_AR2315 ++ bool "Atheros 2315+ support" ++ depends on ATHEROS_AR231X ++ 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_AR2315_PCI ++ bool "PCI support" ++ depends on ATHEROS_AR2315 ++ select HW_HAS_PCI ++ select PCI ++ select USB_ARCH_HAS_HCD ++ select USB_ARCH_HAS_OHCI ++ select USB_ARCH_HAS_EHCI ++ default y +diff -Nur linux-2.6.37.orig/arch/mips/ar231x/Makefile linux-2.6.37/arch/mips/ar231x/Makefile +--- linux-2.6.37.orig/arch/mips/ar231x/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.37/arch/mips/ar231x/Makefile 2011-04-12 08:12:01.000000000 +0200 +@@ -0,0 +1,17 @@ ++# ++# 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-2009 Felix Fietkau <nbd@openwrt.org> ++# ++ ++obj-y += board.o prom.o devices.o ++ ++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++ ++obj-$(CONFIG_ATHEROS_AR5312) += ar5312.o ++obj-$(CONFIG_ATHEROS_AR2315) += ar2315.o ++obj-$(CONFIG_ATHEROS_AR2315_PCI) += pci.o +diff -Nur linux-2.6.37.orig/arch/mips/ar231x/Platform linux-2.6.37/arch/mips/ar231x/Platform +--- linux-2.6.37.orig/arch/mips/ar231x/Platform 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.37/arch/mips/ar231x/Platform 2011-04-12 08:12:01.000000000 +0200 +@@ -0,0 +1,6 @@ ++# ++# Atheros AR5312/AR2312 WiSoC ++# ++platform-$(CONFIG_ATHEROS_AR231X) += ar231x/ ++cflags-$(CONFIG_ATHEROS_AR231X) += -I$(srctree)/arch/mips/include/asm/mach-ar231x ++load-$(CONFIG_ATHEROS_AR231X) += 0xffffffff80041000 +diff -Nur linux-2.6.37.orig/arch/mips/ar231x/ar2315.c linux-2.6.37/arch/mips/ar231x/ar2315.c +--- linux-2.6.37.orig/arch/mips/ar231x/ar2315.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.37/arch/mips/ar231x/ar2315.c 2011-04-12 08:12:01.000000000 +0200 +@@ -0,0 +1,683 @@ ++/* ++ * 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 <generated/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 <linux/leds.h> ++#include <asm/bootinfo.h> ++#include <asm/reboot.h> ++#include <asm/time.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/gpio.h> ++ ++#include <ar231x_platform.h> ++#include <ar2315_regs.h> ++#include <ar231x.h> ++#include "devices.h" ++#include "ar2315.h" ++ ++static u32 gpiointmask = 0, gpiointval = 0; ++ ++static inline void ar2315_gpio_irq(void) ++{ ++ u32 pend; ++ int bit = -1; ++ ++ /* only do one gpio interrupt at a time */ ++ pend = (ar231x_read_reg(AR2315_GPIO_DI) ^ gpiointval) & gpiointmask; ++ ++ if (pend) { ++ bit = fls(pend) - 1; ++ pend &= ~(1 << bit); ++ gpiointval ^= (1 << bit); ++ } ++ ++ if (!pend) ++ ar231x_write_reg(AR2315_ISR, AR2315_ISR_GPIO); ++ ++ /* Enable interrupt with edge detection */ ++ if ((ar231x_read_reg(AR2315_GPIO_CR) & AR2315_GPIO_CR_M(bit)) != AR2315_GPIO_CR_I(bit)) ++ return; ++ ++ if (bit >= 0) ++ do_IRQ(AR531X_GPIO_IRQ_BASE + bit); ++} ++ ++#ifdef CONFIG_ATHEROS_AR2315_PCI ++static inline void pci_abort_irq(void) ++{ ++ ar231x_write_reg(AR2315_PCI_INT_STATUS, AR2315_PCI_ABORT_INT); ++} ++ ++static inline void pci_ack_irq(void) ++{ ++ ar231x_write_reg(AR2315_PCI_INT_STATUS, AR2315_PCI_EXT_INT); ++} ++ ++void ar2315_pci_irq(int irq) ++{ ++ if (ar231x_read_reg(AR2315_PCI_INT_STATUS) == AR2315_PCI_ABORT_INT) ++ pci_abort_irq(); ++ else { ++ do_IRQ(irq); ++ pci_ack_irq(); ++ } ++} ++#endif /* CONFIG_ATHEROS_AR2315_PCI */ ++ ++/* ++ * 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. ++ */ ++static asmlinkage void ++ar2315_irq_dispatch(void) ++{ ++ int pending = read_c0_status() & read_c0_cause(); ++ ++ if (pending & CAUSEF_IP3) ++ do_IRQ(AR2315_IRQ_WLAN0_INTRS); ++ else if (pending & CAUSEF_IP4) ++ do_IRQ(AR2315_IRQ_ENET0_INTRS); ++#ifdef CONFIG_ATHEROS_AR2315_PCI ++ else if (pending & CAUSEF_IP5) ++ ar2315_pci_irq(AR2315_IRQ_LCBUS_PCI); ++#endif ++ else if (pending & CAUSEF_IP2) { ++ unsigned int misc_intr = ar231x_read_reg(AR2315_ISR) & ar231x_read_reg(AR2315_IMR); ++ ++ if (misc_intr & AR2315_ISR_SPI) ++ do_IRQ(AR531X_MISC_IRQ_SPI); ++ else if (misc_intr & AR2315_ISR_TIMER) ++ do_IRQ(AR531X_MISC_IRQ_TIMER); ++ else if (misc_intr & AR2315_ISR_AHB) ++ do_IRQ(AR531X_MISC_IRQ_AHB_PROC); ++ else if (misc_intr & AR2315_ISR_GPIO) ++ ar2315_gpio_irq(); ++ else if (misc_intr & AR2315_ISR_UART0) ++ do_IRQ(AR531X_MISC_IRQ_UART0); ++ else if (misc_intr & AR2315_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); ++} ++ ++static void ar2315_set_gpiointmask(int gpio, int level) ++{ ++ u32 reg; ++ ++ reg = ar231x_read_reg(AR2315_GPIO_INT); ++ reg &= ~(AR2315_GPIO_INT_M | AR2315_GPIO_INT_LVL_M); ++ reg |= gpio | AR2315_GPIO_INT_LVL(level); ++ ar231x_write_reg(AR2315_GPIO_INT, reg); ++} ++ ++static void ar2315_gpio_intr_enable(unsigned int irq) ++{ ++ unsigned int gpio = irq - AR531X_GPIO_IRQ_BASE; ++ ++ /* Enable interrupt with edge detection */ ++ if ((ar231x_read_reg(AR2315_GPIO_CR) & AR2315_GPIO_CR_M(gpio)) != AR2315_GPIO_CR_I(gpio)) ++ return; ++ ++ gpiointmask |= (1 << gpio); ++ ar2315_set_gpiointmask(gpio, 3); ++} ++ ++static unsigned int ar2315_gpio_intr_startup(unsigned int irq) ++{ ++ unsigned int gpio = irq - AR531X_GPIO_IRQ_BASE; ++ ++ /* reconfigure GPIO line as input */ ++ ar231x_mask_reg(AR2315_GPIO_CR, AR2315_GPIO_CR_M(gpio), AR2315_GPIO_CR_I(gpio)); ++ ar2315_gpio_intr_enable(irq); ++ return 0; ++} ++ ++static void ar2315_gpio_intr_disable(unsigned int irq) ++{ ++ unsigned int gpio = irq - AR531X_GPIO_IRQ_BASE; ++ ++ /* Disable interrupt */ ++ gpiointmask &= ~(1 << gpio); ++ ar2315_set_gpiointmask(gpio, 0); ++} ++ ++static void ++ar2315_gpio_intr_end(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) ++ ar2315_gpio_intr_enable(irq); ++} ++ ++static struct irq_chip ar2315_gpio_intr_controller = { ++ .name = "AR2315-GPIO", ++ .startup = ar2315_gpio_intr_startup, ++ .ack = ar2315_gpio_intr_disable, ++ .mask_ack = ar2315_gpio_intr_disable, ++ .mask = ar2315_gpio_intr_disable, ++ .unmask = ar2315_gpio_intr_enable, ++ .end = ar2315_gpio_intr_end, ++}; ++ ++static void ++ar2315_misc_intr_enable(unsigned int irq) ++{ ++ unsigned int imr; ++ ++ imr = ar231x_read_reg(AR2315_IMR); ++ switch(irq) { ++ case AR531X_MISC_IRQ_SPI: ++ imr |= AR2315_ISR_SPI; ++ break; ++ case AR531X_MISC_IRQ_TIMER: ++ imr |= AR2315_ISR_TIMER; ++ break; ++ case AR531X_MISC_IRQ_AHB_PROC: ++ imr |= AR2315_ISR_AHB; ++ break; ++ case AR531X_MISC_IRQ_GPIO: ++ imr |= AR2315_ISR_GPIO; ++ break; ++ case AR531X_MISC_IRQ_UART0: ++ imr |= AR2315_ISR_UART0; ++ break; ++ case AR531X_MISC_IRQ_WATCHDOG: ++ imr |= AR2315_ISR_WD; ++ break; ++ default: ++ break; ++ } ++ ar231x_write_reg(AR2315_IMR, imr); ++} ++ ++static void ++ar2315_misc_intr_disable(unsigned int irq) ++{ ++ unsigned int imr; ++ ++ imr = ar231x_read_reg(AR2315_IMR); ++ switch(irq) { ++ case AR531X_MISC_IRQ_SPI: ++ imr &= ~AR2315_ISR_SPI; ++ break; ++ case AR531X_MISC_IRQ_TIMER: ++ imr &= ~AR2315_ISR_TIMER; ++ break; ++ case AR531X_MISC_IRQ_AHB_PROC: ++ imr &= ~AR2315_ISR_AHB; ++ break; ++ case AR531X_MISC_IRQ_GPIO: ++ imr &= ~AR2315_ISR_GPIO; ++ break; ++ case AR531X_MISC_IRQ_UART0: ++ imr &= ~AR2315_ISR_UART0; ++ break; ++ case AR531X_MISC_IRQ_WATCHDOG: ++ imr &= ~AR2315_ISR_WD; ++ break; ++ default: ++ break; ++ } ++ ar231x_write_reg(AR2315_IMR, imr); ++} ++ ++static void ++ar2315_misc_intr_end(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) ++ ar2315_misc_intr_enable(irq); ++} ++ ++ ++static struct irq_chip ar2315_misc_intr_controller = { ++ .name = "AR2315-MISC", ++ .ack = ar2315_misc_intr_disable, ++ .mask_ack = ar2315_misc_intr_disable, ++ .mask = ar2315_misc_intr_disable, ++ .unmask = ar2315_misc_intr_enable, ++ .end = ar2315_misc_intr_end, ++}; ++ ++static irqreturn_t ar2315_ahb_proc_handler(int cpl, void *dev_id) ++{ ++ ar231x_write_reg(AR2315_AHB_ERR0, AHB_ERROR_DET); ++ ar231x_read_reg(AR2315_AHB_ERR1); ++ ++ printk(KERN_ERR "AHB fatal error\n"); ++ machine_restart("AHB error"); /* Catastrophic failure */ ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction ar2315_ahb_proc_interrupt = { ++ .handler = ar2315_ahb_proc_handler, ++ .flags = IRQF_DISABLED, ++ .name = "ar2315_ahb_proc_interrupt", ++}; ++ ++static struct irqaction cascade = { ++ .handler = no_action, ++ .flags = IRQF_DISABLED, ++ .name = "cascade", ++}; ++ ++void ++ar2315_irq_init(void) ++{ ++ int i; ++ ++ if (!is_2315()) ++ return; ++ ++ ar231x_irq_dispatch = ar2315_irq_dispatch; ++ gpiointval = ar231x_read_reg(AR2315_GPIO_DI); ++ for (i = 0; i < AR531X_MISC_IRQ_COUNT; i++) { ++ int irq = AR531X_MISC_IRQ_BASE + i; ++ set_irq_chip_and_handler(irq, &ar2315_misc_intr_controller, ++ handle_level_irq); ++ } ++ for (i = 0; i < AR531X_GPIO_IRQ_COUNT; i++) { ++ int irq = AR531X_GPIO_IRQ_BASE + i; ++ set_irq_chip_and_handler(irq, &ar2315_gpio_intr_controller, ++ handle_level_irq); ++ } ++ setup_irq(AR531X_MISC_IRQ_GPIO, &cascade); ++ setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar2315_ahb_proc_interrupt); ++ setup_irq(AR2315_IRQ_MISC_INTRS, &cascade); ++} ++ ++const struct ar231x_gpiodev ar2315_gpiodev; ++ ++static u32 ++ar2315_gpio_get_output(void) ++{ ++ u32 reg; ++ reg = ar231x_read_reg(AR2315_GPIO_CR); ++ reg &= ar2315_gpiodev.valid_mask; ++ return reg; ++} ++ ++static u32 ++ar2315_gpio_set_output(u32 mask, u32 val) ++{ ++ u32 reg; ++ ++ reg = ar231x_read_reg(AR2315_GPIO_CR); ++ reg &= ~mask; ++ reg |= val; ++ ar231x_write_reg(AR2315_GPIO_CR, reg); ++ return reg; ++} ++ ++static u32 ++ar2315_gpio_get(void) ++{ ++ u32 reg; ++ reg = ar231x_read_reg(AR2315_GPIO_DI); ++ reg &= ar2315_gpiodev.valid_mask; ++ return reg; ++} ++ ++static u32 ++ar2315_gpio_set(u32 mask, u32 value) ++{ ++ u32 reg; ++ reg = ar231x_read_reg(AR2315_GPIO_DO); ++ reg &= ~mask; ++ reg |= value; ++ ar231x_write_reg(AR2315_GPIO_DO, reg); ++ return reg; ++} ++ ++const struct ar231x_gpiodev ar2315_gpiodev = { ++ .valid_mask = (1 << 22) - 1, ++ .get_output = ar2315_gpio_get_output, ++ .set_output = ar2315_gpio_set_output, ++ .get = ar2315_gpio_get, ++ .set = ar2315_gpio_set, ++}; ++ ++static struct ar231x_eth ar2315_eth_data = { ++ .reset_base = AR2315_RESET, ++ .reset_mac = AR2315_RESET_ENET0, ++ .reset_phy = AR2315_RESET_EPHY0, ++ .phy_base = AR2315_ENET0, ++ .config = &ar231x_board, ++}; ++ ++static struct resource ar2315_spiflash_res[] = { ++ { ++ .name = "flash_base", ++ .flags = IORESOURCE_MEM, ++ .start = KSEG1ADDR(AR2315_SPI_READ), ++ .end = KSEG1ADDR(AR2315_SPI_READ) + 0x1000000 - 1, ++ }, ++ { ++ .name = "flash_regs", ++ .flags = IORESOURCE_MEM, ++ .start = 0x11300000, ++ .end = 0x11300012, ++ }, ++}; ++ ++static struct platform_device ar2315_spiflash = { ++ .id = 0, ++ .name = "spiflash", ++ .resource = ar2315_spiflash_res, ++ .num_resources = ARRAY_SIZE(ar2315_spiflash_res) ++}; ++ ++static struct platform_device ar2315_wdt = { ++ .id = 0, ++ .name = "ar2315_wdt", ++}; ++ ++#define SPI_FLASH_CTL 0x00 ++#define SPI_FLASH_OPCODE 0x04 ++#define SPI_FLASH_DATA 0x08 ++ ++static inline u32 ++spiflash_read_reg(int reg) ++{ ++ return ar231x_read_reg(KSEG1ADDR(AR2315_SPI) + reg); ++} ++ ++static inline void ++spiflash_write_reg(int reg, u32 data) ++{ ++ ar231x_write_reg(KSEG1ADDR(AR2315_SPI) + reg, data); ++} ++ ++static u32 ++spiflash_wait_status(void) ++{ ++ u32 reg; ++ ++ do { ++ reg = spiflash_read_reg(SPI_FLASH_CTL); ++ } while (reg & SPI_CTL_BUSY); ++ ++ return reg; ++} ++ ++static u8 ++spiflash_probe(void) ++{ ++ u32 reg; ++ ++ reg = spiflash_wait_status(); ++ reg &= ~SPI_CTL_TX_RX_CNT_MASK; ++ reg |= (1 << 4) | 4 | SPI_CTL_START; ++ ++ spiflash_write_reg(SPI_FLASH_OPCODE, 0xab); ++ spiflash_write_reg(SPI_FLASH_CTL, reg); ++ ++ reg = spiflash_wait_status(); ++ reg = spiflash_read_reg(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 u8 __init * ++ar2315_flash_limit(void) ++{ ++ u32 flash_size = 0; ++ ++ /* probe the flash chip size */ ++ switch(spiflash_probe()) { ++ 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; ++ } ++ ++ ar2315_spiflash_res[0].end = ar2315_spiflash_res[0].start + ++ flash_size - 1; ++ return (u8 *) ar2315_spiflash_res[0].end + 1; ++} ++ ++#ifdef CONFIG_LEDS_GPIO ++static struct gpio_led ar2315_leds[6]; ++static struct gpio_led_platform_data ar2315_led_data = { ++ .leds = (void *) ar2315_leds, ++}; ++ ++static struct platform_device ar2315_gpio_leds = { ++ .name = "leds-gpio", ++ .id = -1, ++ .dev = { ++ .platform_data = (void *) &ar2315_led_data, ++ } ++}; ++ ++static void __init ++ar2315_init_gpio(void) ++{ ++ static char led_names[6][6]; ++ int i, led = 0; ++ ++ ar2315_led_data.num_leds = 0; ++ for(i = 1; i < 8; i++) ++ { ++ if((i == AR2315_RESET_GPIO) || ++ (i == ar231x_board.config->resetConfigGpio)) ++ continue; ++ ++ if(i == ar231x_board.config->sysLedGpio) ++ strcpy(led_names[led], "wlan"); ++ else ++ sprintf(led_names[led], "gpio%d", i); ++ ++ ar2315_leds[led].name = led_names[led]; ++ ar2315_leds[led].gpio = i; ++ ar2315_leds[led].active_low = 0; ++ led++; ++ } ++ ar2315_led_data.num_leds = led; ++ platform_device_register(&ar2315_gpio_leds); ++} ++#else ++static inline void ar2315_init_gpio(void) ++{ ++} ++#endif ++ ++int __init ++ar2315_init_devices(void) ++{ ++ if (!is_2315()) ++ return 0; ++ ++ /* Find board configuration */ ++ ar231x_find_config(ar2315_flash_limit()); ++ ar2315_eth_data.macaddr = ar231x_board.config->enet0_mac; ++ ++ ar2315_init_gpio(); ++ platform_device_register(&ar2315_wdt); ++ platform_device_register(&ar2315_spiflash); ++ ar231x_add_ethernet(0, AR2315_ENET0, AR2315_IRQ_ENET0_INTRS, ++ &ar2315_eth_data); ++ ar231x_add_wmac(0, AR2315_WLAN0, AR2315_IRQ_WLAN0_INTRS); ++ ++ return 0; ++} ++ ++static void ++ar2315_restart(char *command) ++{ ++ void (*mips_reset_vec)(void) = (void *) 0xbfc00000; ++ ++ local_irq_disable(); ++ ++ /* try reset the system via reset control */ ++ ar231x_write_reg(AR2315_COLD_RESET,AR2317_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(AR2315_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 ++ar2315_sys_clk(unsigned int clockCtl) ++{ ++ unsigned int pllcCtrl,cpuDiv; ++ unsigned int pllcOut,refdiv,fdiv,divby2; ++ unsigned int clkDiv; ++ ++ pllcCtrl = ar231x_read_reg(AR2315_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 ++ar2315_cpu_frequency(void) ++{ ++ return ar2315_sys_clk(ar231x_read_reg(AR2315_CPUCLK)); ++} ++ ++static inline unsigned int ++ar2315_apb_frequency(void) ++{ ++ return ar2315_sys_clk(ar231x_read_reg(AR2315_AMBACLK)); ++} ++ ++void __init ++ar2315_time_init(void) ++{ ++ if (!is_2315()) ++ return; ++ ++ mips_hpt_frequency = ar2315_cpu_frequency() / 2; ++} ++ ++void __init ++ar2315_prom_init(void) ++{ ++ u32 memsize, memcfg, devid; ++ ++ if (!is_2315()) ++ return; ++ ++ memcfg = ar231x_read_reg(AR2315_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 = ar231x_read_reg(AR2315_SREV) & AR2315_REV_CHIP; ++ switch(devid) { ++ case 0x90: ++ case 0x91: ++ ar231x_devtype = DEV_TYPE_AR2317; ++ break; ++ default: ++ ar231x_devtype = DEV_TYPE_AR2315; ++ break; ++ } ++ ar231x_gpiodev = &ar2315_gpiodev; ++ ar231x_board.devid = devid; ++} ++ ++void __init ++ar2315_plat_setup(void) ++{ ++ u32 config; ++ ++ if (!is_2315()) ++ return; ++ ++ /* Clear any lingering AHB errors */ ++ config = read_c0_config(); ++ write_c0_config(config & ~0x3); ++ ar231x_write_reg(AR2315_AHB_ERR0,AHB_ERROR_DET); ++ ar231x_read_reg(AR2315_AHB_ERR1); ++ ar231x_write_reg(AR2315_WDC, AR2315_WDC_IGNORE_EXPIRATION); ++ ++ _machine_restart = ar2315_restart; ++ ar231x_serial_setup(KSEG1ADDR(AR2315_UART0), ar2315_apb_frequency()); ++} +diff -Nur linux-2.6.37.orig/arch/mips/ar231x/ar2315.h linux-2.6.37/arch/mips/ar231x/ar2315.h +--- linux-2.6.37.orig/arch/mips/ar231x/ar2315.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.37/arch/mips/ar231x/ar2315.h 2011-04-12 08:12:01.000000000 +0200 +@@ -0,0 +1,37 @@ ++#ifndef __AR2315_H ++#define __AR2315_H ++ ++#ifdef CONFIG_ATHEROS_AR2315 ++ ++extern void ar2315_irq_init(void); ++extern int ar2315_init_devices(void); ++extern void ar2315_prom_init(void); ++extern void ar2315_plat_setup(void); ++extern void ar2315_time_init(void); ++ ++#else ++ ++static inline void ar2315_irq_init(void) ++{ ++} ++ ++static inline int ar2315_init_devices(void) ++{ ++ return 0; ++} ++ ++static inline void ar2315_prom_init(void) ++{ ++} ++ ++static inline void ar2315_plat_setup(void) ++{ ++} ++ ++static inline void ar2315_time_init(void) ++{ ++} ++ ++#endif ++ ++#endif +diff -Nur linux-2.6.37.orig/arch/mips/ar231x/ar5312.c linux-2.6.37/arch/mips/ar231x/ar5312.c +--- linux-2.6.37.orig/arch/mips/ar231x/ar5312.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.37/arch/mips/ar231x/ar5312.c 2011-04-12 08:12:01.000000000 +0200 +@@ -0,0 +1,549 @@ ++/* ++ * 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-2009 Felix Fietkau <nbd@openwrt.org> ++ */ ++ ++/* ++ * Platform devices for Atheros SoCs ++ */ ++ ++#include <generated/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 <linux/leds.h> ++#include <asm/bootinfo.h> ++#include <asm/reboot.h> ++#include <asm/time.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <gpio.h> ++ ++#include <ar231x_platform.h> ++#include <ar5312_regs.h> ++#include <ar231x.h> ++#include "devices.h" ++#include "ar5312.h" ++ ++static void ++ar5312_misc_irq_dispatch(void) ++{ ++ unsigned int ar231x_misc_intrs = ar231x_read_reg(AR531X_ISR) & ar231x_read_reg(AR531X_IMR); ++ ++ if (ar231x_misc_intrs & AR531X_ISR_TIMER) { ++ do_IRQ(AR531X_MISC_IRQ_TIMER); ++ (void)ar231x_read_reg(AR531X_TIMER); ++ } else if (ar231x_misc_intrs & AR531X_ISR_AHBPROC) ++ do_IRQ(AR531X_MISC_IRQ_AHB_PROC); ++ else if ((ar231x_misc_intrs & AR531X_ISR_UART0)) ++ do_IRQ(AR531X_MISC_IRQ_UART0); ++ else if (ar231x_misc_intrs & AR531X_ISR_WD) ++ do_IRQ(AR531X_MISC_IRQ_WATCHDOG); ++ else ++ do_IRQ(AR531X_MISC_IRQ_NONE); ++} ++ ++static 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) ++ ar5312_misc_irq_dispatch(); ++ 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 = ar231x_read_reg(AR531X_IMR); ++ imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1)); ++ ar231x_write_reg(AR531X_IMR, imr); ++} ++ ++/* Disable the specified AR531X_MISC_IRQ interrupt */ ++static void ++ar5312_misc_intr_disable(unsigned int irq) ++{ ++ unsigned int imr; ++ ++ imr = ar231x_read_reg(AR531X_IMR); ++ imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1)); ++ ar231x_write_reg(AR531X_IMR, imr); ++ ar231x_read_reg(AR531X_IMR); /* flush write buffer */ ++} ++ ++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 = { ++ .name = "AR5312-MISC", ++ .disable = ar5312_misc_intr_disable, ++ .ack = ar5312_misc_intr_disable, ++ .mask_ack = ar5312_misc_intr_disable, ++ .mask = ar5312_misc_intr_disable, ++ .unmask = ar5312_misc_intr_enable, ++ .end = ar5312_misc_intr_end, ++}; ++ ++ ++static irqreturn_t ar5312_ahb_proc_handler(int cpl, void *dev_id) ++{ ++ u32 proc1 = ar231x_read_reg(AR531X_PROC1); ++ u32 procAddr = ar231x_read_reg(AR531X_PROCADDR); /* clears error state */ ++ u32 dma1 = ar231x_read_reg(AR531X_DMA1); ++ u32 dmaAddr = ar231x_read_reg(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_irq_init(void) ++{ ++ int i; ++ ++ if (!is_5312()) ++ return; ++ ++ ar231x_irq_dispatch = ar5312_irq_dispatch; ++ for (i = 0; i < AR531X_MISC_IRQ_COUNT; i++) { ++ int irq = AR531X_MISC_IRQ_BASE + i; ++ set_irq_chip_and_handler(irq, &ar5312_misc_intr_controller, ++ handle_level_irq); ++ } ++ setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5312_ahb_proc_interrupt); ++ setup_irq(AR5312_IRQ_MISC_INTRS, &cascade); ++} ++ ++const struct ar231x_gpiodev ar5312_gpiodev; ++ ++static u32 ++ar5312_gpio_get_output(void) ++{ ++ u32 reg; ++ reg = ~(ar231x_read_reg(AR531X_GPIO_CR)); ++ reg &= ar5312_gpiodev.valid_mask; ++ return reg; ++} ++ ++static u32 ++ar5312_gpio_set_output(u32 mask, u32 val) ++{ ++ u32 reg; ++ ++ reg = ar231x_read_reg(AR531X_GPIO_CR); ++ reg |= mask; ++ reg &= ~val; ++ ar231x_write_reg(AR531X_GPIO_CR, reg); ++ return reg; ++} ++ ++static u32 ++ar5312_gpio_get(void) ++{ ++ u32 reg; ++ reg = ar231x_read_reg(AR531X_GPIO_DI); ++ reg &= ar5312_gpiodev.valid_mask; ++ return reg; ++} ++ ++static u32 ++ar5312_gpio_set(u32 mask, u32 value) ++{ ++ u32 reg; ++ reg = ar231x_read_reg(AR531X_GPIO_DO); ++ reg &= ~mask; ++ reg |= value; ++ ar231x_write_reg(AR531X_GPIO_DO, reg); ++ return reg; ++} ++ ++const struct ar231x_gpiodev ar5312_gpiodev = { ++ .valid_mask = (1 << 8) - 1, ++ .get_output = ar5312_gpio_get_output, ++ .set_output = ar5312_gpio_set_output, ++ .get = ar5312_gpio_get, ++ .set = ar5312_gpio_set, ++}; ++ ++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 ar231x_eth ar5312_eth0_data = { ++ .reset_base = AR531X_RESET, ++ .reset_mac = AR531X_RESET_ENET0, ++ .reset_phy = AR531X_RESET_EPHY0, ++ .phy_base = KSEG1ADDR(AR531X_ENET0), ++ .config = &ar231x_board, ++}; ++ ++static struct ar231x_eth ar5312_eth1_data = { ++ .reset_base = AR531X_RESET, ++ .reset_mac = AR531X_RESET_ENET1, ++ .reset_phy = AR531X_RESET_EPHY1, ++ .phy_base = KSEG1ADDR(AR531X_ENET1), ++ .config = &ar231x_board, ++}; ++ ++static struct platform_device ar5312_physmap_flash = { ++ .name = "physmap-flash", ++ .id = 0, ++ .dev.platform_data = &ar5312_flash_data, ++ .resource = &ar5312_flash_resource, ++ .num_resources = 1, ++}; ++ ++#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) | ++ (ar231x_read_reg(AR531X_FLASHCTL0) & FLASHCTL_MW); ++ ++ ar231x_write_reg(AR531X_FLASHCTL0, ctl); ++ ++ /* Disable other flash banks */ ++ ar231x_write_reg(AR531X_FLASHCTL1, ++ ar231x_read_reg(AR531X_FLASHCTL1) & ~(FLASHCTL_E | FLASHCTL_AC)); |