diff --git a/target/linux/atheros-2.6/config b/target/linux/atheros-2.6/config index 7bf0289a0..52c4d7a23 100644 --- a/target/linux/atheros-2.6/config +++ b/target/linux/atheros-2.6/config @@ -14,12 +14,8 @@ CONFIG_AIRO=m CONFIG_AIRO_CS=m # CONFIG_AMD8111_ETH is not set # CONFIG_AMIGA_PARTITION is not set -CONFIG_AP51=y # CONFIG_APPLICOM is not set CONFIG_AR2313=y -CONFIG_AR5315=y -CONFIG_AR531X=y -CONFIG_AR531X_COBRA=y CONFIG_ARCH_FLATMEM_ENABLE=y # CONFIG_ARCNET is not set CONFIG_ARPD=y @@ -28,6 +24,9 @@ CONFIG_ASK_IP_FIB_HASH=y # CONFIG_ATALK is not set # CONFIG_ATARI_PARTITION is not set # CONFIG_ATA_OVER_ETH is not set +CONFIG_ATHEROS=y +CONFIG_ATHEROS_AR5312=y +CONFIG_ATHEROS_AR5315=y # CONFIG_ATM is not set CONFIG_ATMEL=m # CONFIG_ATM_AMBASSADOR is not set @@ -689,10 +688,10 @@ CONFIG_MTD_MAP_BANK_WIDTH_4=y # CONFIG_MTD_OTP is not set CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_PHRAM is not set -# CONFIG_MTD_PHYSMAP is not set -# CONFIG_MTD_PHYSMAP_BANKWIDTH is not set -# CONFIG_MTD_PHYSMAP_LEN is not set -# CONFIG_MTD_PHYSMAP_START is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_BANKWIDTH=0 +CONFIG_MTD_PHYSMAP_LEN=0x0 +CONFIG_MTD_PHYSMAP_START=0x0 # CONFIG_MTD_PLATRAM is not set # CONFIG_MTD_RAM is not set CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3 @@ -878,7 +877,6 @@ CONFIG_PCCARD_NONSTATIC=m CONFIG_PCI=y CONFIG_PCI_ATMEL=m CONFIG_PCI_HERMES=m -# CONFIG_PCMCIA is not set # CONFIG_PCMCIA_AHA152X is not set # CONFIG_PCMCIA_DEBUG is not set # CONFIG_PCMCIA_FDOMAIN is not set diff --git a/target/linux/atheros-2.6/config-diff b/target/linux/atheros-2.6/config-diff index 30c500e84..064880a3b 100644 --- a/target/linux/atheros-2.6/config-diff +++ b/target/linux/atheros-2.6/config-diff @@ -1,11 +1,10 @@ CONFIG_32BIT=y # CONFIG_64BIT is not set # CONFIG_64BIT_PHYS_ADDR is not set -CONFIG_AP51=y CONFIG_AR2313=y -CONFIG_AR5315=y -CONFIG_AR531X=y -CONFIG_AR531X_COBRA=y +CONFIG_ATHEROS=y +CONFIG_ATHEROS_AR5312=y +CONFIG_ATHEROS_AR5315=y # CONFIG_ATM is not set CONFIG_BASE_SMALL=0 # CONFIG_BT is not set @@ -43,7 +42,6 @@ CONFIG_DMA_NEED_PCI_MAP_STATE=y CONFIG_DMA_NONCOHERENT=y # CONFIG_FIRMWARE_EDID is not set CONFIG_FS_POSIX_ACL=y -# CONFIG_FUSE_FS is not set CONFIG_GENERIC_FIND_NEXT_BIT=y # CONFIG_GEN_RTC is not set CONFIG_HAVE_STD_PC_SERIAL_PORT=y @@ -138,10 +136,10 @@ CONFIG_MTD_MAP_BANK_WIDTH_4=y # CONFIG_MTD_OTP is not set CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_PHRAM is not set -# CONFIG_MTD_PHYSMAP is not set -# CONFIG_MTD_PHYSMAP_BANKWIDTH is not set -# CONFIG_MTD_PHYSMAP_LEN is not set -# CONFIG_MTD_PHYSMAP_START is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_BANKWIDTH=0 +CONFIG_MTD_PHYSMAP_LEN=0x0 +CONFIG_MTD_PHYSMAP_START=0x0 # CONFIG_MTD_PLATRAM is not set # CONFIG_MTD_RAM is not set CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3 @@ -155,7 +153,6 @@ CONFIG_MTD_SPIFLASH=y CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_64KB is not set # CONFIG_PAGE_SIZE_8KB is not set -# CONFIG_PCMCIA is not set # CONFIG_PCCARD is not set # CONFIG_PMC_YOSEMITE is not set # CONFIG_PNX8550_JBS is not set diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/Kconfig b/target/linux/atheros-2.6/files/arch/mips/atheros/Kconfig new file mode 100644 index 000000000..2170fd710 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/Kconfig @@ -0,0 +1,13 @@ + +config ATHEROS_AR5312 + bool "Atheros 5312/2312+ support" + depends on ATHEROS + default y + +config ATHEROS_AR5315 + bool "Atheros 5315/2315+ support" + depends on ATHEROS + default y + + + diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/Makefile b/target/linux/atheros-2.6/files/arch/mips/atheros/Makefile new file mode 100644 index 000000000..aff65d723 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/Makefile @@ -0,0 +1,22 @@ +# +# 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 +# Copyright (C) 2006 Felix Fietkau +# + +# Makefile for Atheros ar531x boards +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +obj-y += board.o prom.o irq.o +obj-$(CONFIG_ATHEROS_AR5312) += ar5312.o +obj-$(CONFIG_ATHEROS_AR5315) += ar5315.o + diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.c b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.c new file mode 100644 index 000000000..28b9d3f95 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.c @@ -0,0 +1,471 @@ +/* + * 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 + * Copyright (C) 2006 Felix Fietkau + */ + +/* + * Platform devices for Atheros SoCs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ar531x.h" + + +#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */ +#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */ +#define AR531X_IRQ_ENET1_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */ +#define AR531X_IRQ_WLAN1_INTRS MIPS_CPU_IRQ_BASE+5 /* C0_CAUSE: 0x2000 */ +#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ + + +static struct platform_device *ar5312_devs[5]; + +static struct resource ar5312_eth0_res[] = { + { + .name = "eth_membase", + .flags = IORESOURCE_MEM, + .start = KSEG1ADDR(AR531X_ENET0), + .end = KSEG1ADDR(AR531X_ENET0 + 0x2000), + }, + { + .name = "eth_irq", + .flags = IORESOURCE_IRQ, + .start = AR531X_IRQ_ENET0_INTRS, + .end = AR531X_IRQ_ENET0_INTRS, + }, +}; + + +static struct resource ar5312_eth1_res[] = { + { + .name = "eth_membase", + .flags = IORESOURCE_MEM, + .start = KSEG1ADDR(AR531X_ENET1), + .end = KSEG1ADDR(AR531X_ENET1 + 0x2000), + }, + { + .name = "eth_irq", + .flags = IORESOURCE_IRQ, + .start = AR531X_IRQ_ENET1_INTRS, + .end = AR531X_IRQ_ENET1_INTRS, + }, +}; + + +static struct ar531x_eth ar5312_eth0_data = { + .phy = 0x1f, + .mac = 0, + .reset_base = AR531X_RESET, + .reset_mac = AR531X_RESET_ENET0, + .reset_phy = AR531X_RESET_EPHY0, +}; + +static struct ar531x_eth ar5312_eth1_data = { + .phy = 0, + .mac = 1, + .reset_base = AR531X_RESET, + .reset_mac = AR531X_RESET_ENET1, + .reset_phy = AR531X_RESET_EPHY1, +}; + +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) + }, +}; + +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 + 0x400000 - 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, +}; + + +/* + * 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 */ + 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 + 0x400000); +} + +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) +{ + char *radio; + int dev = 0; + + if (mips_machtype != MACH_ATHEROS_AR5312) + return 0; + + ar531x_find_config(ar5312_flash_limit()); + ar5312_eth0_data.board_config = board_config; + ar5312_eth1_data.board_config = board_config; + ar5312_devs[dev++] = &ar5312_physmap_flash; + ar5312_devs[dev++] = &ar5312_eth[0]; + ar5312_devs[dev++] = &ar5312_eth[1]; + + radio = radio_config + AR531X_RADIO_MASK_OFF; + 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); +} + + +/* + * 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(AR531X_IRQ_WLAN0_INTRS); + else if (pending & CAUSEF_IP3) + do_IRQ(AR531X_IRQ_ENET0_INTRS); + else if (pending & CAUSEF_IP4) + do_IRQ(AR531X_IRQ_ENET1_INTRS); + else if (pending & CAUSEF_IP5) + do_IRQ(AR531X_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); + } + else + do_IRQ(AR531X_IRQ_NONE); +} + +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; +} + + +/* 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 = SA_INTERRUPT, + .name = "ar5312_ahb_proc_interrupt", +}; + + +static struct irqaction cascade = { + .handler = no_action, + .flags = SA_INTERRUPT, + .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(AR531X_IRQ_MISC_INTRS, &cascade); +} + + +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-2.6/files/arch/mips/atheros/ar5312.h b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.h new file mode 100644 index 000000000..b6e71b890 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.h @@ -0,0 +1,223 @@ +/* + * 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 Imre Kaloz + * Copyright (C) 2006 Felix Fietkau + */ + +#ifndef AR5312_H +#define AR5312_H + +#include + +/* Address Map */ +#define AR531X_WLAN0 0x18000000 +#define AR531X_WLAN1 0x18500000 +#define AR531X_ENET0 0x18100000 +#define AR531X_ENET1 0x18200000 +#define AR531X_SDRAMCTL 0x18300000 +#define AR531X_FLASHCTL 0x18400000 +#define AR531X_APBBASE 0x1c000000 +#define AR531X_FLASH 0x1e000000 +#define AR531X_UART0 0xbc000003 /* UART MMR */ + +/* + * AR531X_NUM_ENET_MAC defines the number of ethernet MACs that + * should be considered available. The AR5312 supports 2 enet MACS, + * even though many reference boards only actually use 1 of them + * (i.e. Only MAC 0 is actually connected to an enet PHY or PHY switch. + * The AR2312 supports 1 enet MAC. + */ +#define AR531X_NUM_ENET_MAC 2 + +/* + * Need these defines to determine true number of ethernet MACs + */ +#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ +#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ +#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */ +#define AR531X_RADIO_MASK_OFF 0xc8 +#define AR531X_RADIO0_MASK 0x0003 +#define AR531X_RADIO1_MASK 0x000c +#define AR531X_RADIO1_S 2 + +/* + * AR531X_NUM_WMAC defines the number of Wireless MACs that\ + * should be considered available. + */ +#define AR531X_NUM_WMAC 2 + +/* Reset/Timer Block Address Map */ +#define AR531X_RESETTMR (AR531X_APBBASE + 0x3000) +#define AR531X_TIMER (AR531X_RESETTMR + 0x0000) /* countdown timer */ +#define AR531X_WD_CTRL (AR531X_RESETTMR + 0x0008) /* watchdog cntrl */ +#define AR531X_WD_TIMER (AR531X_RESETTMR + 0x000c) /* watchdog timer */ +#define AR531X_ISR (AR531X_RESETTMR + 0x0010) /* Intr Status Reg */ +#define AR531X_IMR (AR531X_RESETTMR + 0x0014) /* Intr Mask Reg */ +#define AR531X_RESET (AR531X_RESETTMR + 0x0020) +#define AR5312_CLOCKCTL1 (AR531X_RESETTMR + 0x0064) +#define AR5312_SCRATCH (AR531X_RESETTMR + 0x006c) +#define AR531X_PROCADDR (AR531X_RESETTMR + 0x0070) +#define AR531X_PROC1 (AR531X_RESETTMR + 0x0074) +#define AR531X_DMAADDR (AR531X_RESETTMR + 0x0078) +#define AR531X_DMA1 (AR531X_RESETTMR + 0x007c) +#define AR531X_ENABLE (AR531X_RESETTMR + 0x0080) /* interface enb */ +#define AR531X_REV (AR531X_RESETTMR + 0x0090) /* revision */ + +/* AR531X_WD_CTRL register bit field definitions */ +#define AR531X_WD_CTRL_IGNORE_EXPIRATION 0x0000 +#define AR531X_WD_CTRL_NMI 0x0001 +#define AR531X_WD_CTRL_RESET 0x0002 + +/* AR531X_ISR register bit field definitions */ +#define AR531X_ISR_NONE 0x0000 +#define AR531X_ISR_TIMER 0x0001 +#define AR531X_ISR_AHBPROC 0x0002 +#define AR531X_ISR_AHBDMA 0x0004 +#define AR531X_ISR_GPIO 0x0008 +#define AR531X_ISR_UART0 0x0010 +#define AR531X_ISR_UART0DMA 0x0020 +#define AR531X_ISR_WD 0x0040 +#define AR531X_ISR_LOCAL 0x0080 + +/* AR531X_RESET register bit field definitions */ +#define AR531X_RESET_SYSTEM 0x00000001 /* cold reset full system */ +#define AR531X_RESET_PROC 0x00000002 /* cold reset MIPS core */ +#define AR531X_RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */ +#define AR531X_RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */ +#define AR531X_RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */ +#define AR531X_RESET_ENET0 0x00000020 /* cold reset ENET0 mac */ +#define AR531X_RESET_ENET1 0x00000040 /* cold reset ENET1 mac */ +#define AR531X_RESET_UART0 0x00000100 /* cold reset UART0 (high speed) */ +#define AR531X_RESET_WLAN1 0x00000200 /* cold reset WLAN MAC/BB */ +#define AR531X_RESET_APB 0x00000400 /* cold reset APB (ar5312) */ +#define AR531X_RESET_WARM_PROC 0x00001000 /* warm reset MIPS core */ +#define AR531X_RESET_WARM_WLAN0_MAC 0x00002000 /* warm reset WLAN0 MAC */ +#define AR531X_RESET_WARM_WLAN0_BB 0x00004000 /* warm reset WLAN0 BaseBand */ +#define AR531X_RESET_NMI 0x00010000 /* send an NMI to the processor */ +#define AR531X_RESET_WARM_WLAN1_MAC 0x00020000 /* warm reset WLAN1 mac */ +#define AR531X_RESET_WARM_WLAN1_BB 0x00040000 /* warm reset WLAN1 baseband */ +#define AR531X_RESET_LOCAL_BUS 0x00080000 /* reset local bus */ +#define AR531X_RESET_WDOG 0x00100000 /* last reset was a watchdog */ + +#define AR531X_RESET_WMAC0_BITS \ + AR531X_RESET_WLAN0 |\ + AR531X_RESET_WARM_WLAN0_MAC |\ + AR531X_RESET_WARM_WLAN0_BB + +#define AR531X_RESERT_WMAC1_BITS \ + AR531X_RESET_WLAN1 |\ + AR531X_RESET_WARM_WLAN1_MAC |\ + AR531X_RESET_WARM_WLAN1_BB + +/* AR5312_CLOCKCTL1 register bit field definitions */ +#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 +#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 +#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 +#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 +#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 + +/* Valid for AR5312 and AR2312 */ +#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 +#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 +#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 +#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 +#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 + +/* Valid for AR2313 */ +#define AR2313_CLOCKCTL1_PREDIVIDE_MASK 0x00003000 +#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT 12 +#define AR2313_CLOCKCTL1_MULTIPLIER_MASK 0x001f0000 +#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT 16 +#define AR2313_CLOCKCTL1_DOUBLER_MASK 0x00000000 + + +/* AR531X_ENABLE register bit field definitions */ +#define AR531X_ENABLE_WLAN0 0x0001 +#define AR531X_ENABLE_ENET0 0x0002 +#define AR531X_ENABLE_ENET1 0x0004 +#define AR531X_ENABLE_UART_AND_WLAN1_PIO 0x0008 /* UART, and WLAN1 PIOs */ +#define AR531X_ENABLE_WLAN1_DMA 0x0010 /* WLAN1 DMAs */ +#define AR531X_ENABLE_WLAN1 \ + (AR531X_ENABLE_UART_AND_WLAN1_PIO | AR531X_ENABLE_WLAN1_DMA) + +/* AR531X_REV register bit field definitions */ +#define AR531X_REV_WMAC_MAJ 0xf000 +#define AR531X_REV_WMAC_MAJ_S 12 +#define AR531X_REV_WMAC_MIN 0x0f00 +#define AR531X_REV_WMAC_MIN_S 8 +#define AR531X_REV_MAJ 0x00f0 +#define AR531X_REV_MAJ_S 4 +#define AR531X_REV_MIN 0x000f +#define AR531X_REV_MIN_S 0 +#define AR531X_REV_CHIP (REV_MAJ|REV_MIN) + +/* Major revision numbers, bits 7..4 of Revision ID register */ +#define AR531X_REV_MAJ_AR5312 0x4 +#define AR531X_REV_MAJ_AR2313 0x5 + +/* Minor revision numbers, bits 3..0 of Revision ID register */ +#define AR5312_REV_MIN_DUAL 0x0 /* Dual WLAN version */ +#define AR5312_REV_MIN_SINGLE 0x1 /* Single WLAN version */ + +/* AR531X_FLASHCTL register bit field definitions */ +#define FLASHCTL_IDCY 0x0000000f /* Idle cycle turn around time */ +#define FLASHCTL_IDCY_S 0 +#define FLASHCTL_WST1 0x000003e0 /* Wait state 1 */ +#define FLASHCTL_WST1_S 5 +#define FLASHCTL_RBLE 0x00000400 /* Read byte lane enable */ +#define FLASHCTL_WST2 0x0000f800 /* Wait state 2 */ +#define FLASHCTL_WST2_S 11 +#define FLASHCTL_AC 0x00070000 /* Flash address check (added) */ +#define FLASHCTL_AC_S 16 +#define FLASHCTL_AC_128K 0x00000000 +#define FLASHCTL_AC_256K 0x00010000 +#define FLASHCTL_AC_512K 0x00020000 +#define FLASHCTL_AC_1M 0x00030000 +#define FLASHCTL_AC_2M 0x00040000 +#define FLASHCTL_AC_4M 0x00050000 +#define FLASHCTL_AC_8M 0x00060000 +#define FLASHCTL_AC_RES 0x00070000 /* 16MB is not supported */ +#define FLASHCTL_E 0x00080000 /* Flash bank enable (added) */ +#define FLASHCTL_BUSERR 0x01000000 /* Bus transfer error status flag */ +#define FLASHCTL_WPERR 0x02000000 /* Write protect error status flag */ +#define FLASHCTL_WP 0x04000000 /* Write protect */ +#define FLASHCTL_BM 0x08000000 /* Burst mode */ +#define FLASHCTL_MW 0x30000000 /* Memory width */ +#define FLASHCTL_MWx8 0x00000000 /* Memory width x8 */ +#define FLASHCTL_MWx16 0x10000000 /* Memory width x16 */ +#define FLASHCTL_MWx32 0x20000000 /* Memory width x32 (not supported) */ +#define FLASHCTL_ATNR 0x00000000 /* Access type == no retry */ +#define FLASHCTL_ATR 0x80000000 /* Access type == retry every */ +#define FLASHCTL_ATR4 0xc0000000 /* Access type == retry every 4 */ + +/* ARM Flash Controller -- 3 flash banks with either x8 or x16 devices. */ +#define AR531X_FLASHCTL0 (AR531X_FLASHCTL + 0x00) +#define AR531X_FLASHCTL1 (AR531X_FLASHCTL + 0x04) +#define AR531X_FLASHCTL2 (AR531X_FLASHCTL + 0x08) + +/* ARM SDRAM Controller -- just enough to determine memory size */ +#define AR531X_MEM_CFG1 (AR531X_SDRAMCTL + 0x04) +#define MEM_CFG1_AC0 0x00000700 /* bank 0: SDRAM addr check (added) */ +#define MEM_CFG1_AC0_S 8 +#define MEM_CFG1_AC1 0x00007000 /* bank 1: SDRAM addr check (added) */ +#define MEM_CFG1_AC1_S 12 + +/* GPIO Address Map */ +#define AR531X_GPIO (AR531X_APBBASE + 0x2000) +#define AR531X_GPIO_DO (AR531X_GPIO + 0x00) /* output register */ +#define AR531X_GPIO_DI (AR531X_GPIO + 0x04) /* intput register */ +#define AR531X_GPIO_CR (AR531X_GPIO + 0x08) /* control register */ + +/* GPIO Control Register bit field definitions */ +#define AR531X_GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ +#define AR531X_GPIO_CR_O(x) (0 << (x)) /* mask for output */ +#define AR531X_GPIO_CR_I(x) (1 << (x)) /* mask for input */ +#define AR531X_GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */ +#define AR531X_GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */ + +#endif + diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.c b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.c new file mode 100644 index 000000000..78b283591 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.c @@ -0,0 +1,529 @@ +/* + * 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 + * Copyright (C) 2006 Felix Fietkau + */ + +/* + * Platform devices for Atheros SoCs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ar531x.h" + +#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */ +#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */ +#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */ +#define AR531X_IRQ_LCBUS_PCI MIPS_CPU_IRQ_BASE+5 /* C0_CAUSE: 0x2000 */ +#define AR531X_IRQ_WLAN0_POLL MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ + +static struct resource ar5315_eth_res[] = { + { + .name = "eth_membase", + .flags = IORESOURCE_MEM, + .start = AR5315_ENET0, + .end = AR5315_ENET0 + 0x2000, + }, + { + .name = "eth_irq", + .flags = IORESOURCE_IRQ, + .start = AR531X_IRQ_ENET0_INTRS, + .end = AR531X_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, +}; + +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) +}; + +static __initdata struct platform_device *ar5315_devs[4]; + + + +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 + + +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; + } + + 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; + int dev = 0; + + if (mips_machtype != MACH_ATHEROS_AR5315) + return 0; + + ar531x_find_config(ar5315_flash_limit()); + + 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) & REV_CHIP); + + ar5315_eth_data.board_config = board_config; + ar5315_wmac.dev.platform_data = config; + + ar5315_devs[dev++] = &ar5315_eth; + ar5315_devs[dev++] = &ar5315_wmac; + ar5315_devs[dev++] = &ar5315_spiflash; + + return platform_add_devices(ar5315_devs, dev); +} + + +/* + * 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(AR531X_IRQ_WLAN0_INTRS); + else if (pending & CAUSEF_IP4) + do_IRQ(AR531X_IRQ_ENET0_INTRS); + else if (pending & CAUSEF_IP2) { + unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR); + + 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) { + sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO); + } 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); + else + do_IRQ(AR531X_IRQ_NONE); +} + +static void ar5315_halt(void) +{ + while (1); +} + +static void ar5315_power_off(void) +{ + ar5315_halt(); +} + + +static void ar5315_restart(char *command) +{ + unsigned int reg; + for(;;) { + + /* 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. + */ + + reg = sysRegRead(AR5315_GPIO_DO); + reg &= ~(1 << AR5315_RESET_GPIO); + sysRegWrite(AR5315_GPIO_DO, reg); + (void)sysRegRead(AR5315_GPIO_DO); /* flush write to hardware */ + } +} + + +/* + * 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; +} + + + +/* 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_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 */ + //printk("enable Interrupt irq 0x%x imr 0x%x \n",irq,imr); + +} + +/* 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_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 = SA_INTERRUPT, + .name = "ar5315_ahb_proc_interrupt", +}; + + +static struct irqaction cascade = { + .handler = no_action, + .flags = SA_INTERRUPT, + .name = "cascade", +}; + +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(AR531X_IRQ_MISC_INTRS, &cascade); +} + +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-2.6/files/arch/mips/atheros/ar5315.h b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.h new file mode 100644 index 000000000..b523f8040 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.h @@ -0,0 +1,678 @@ +/* + * 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 + * Copyright (C) 2006 Felix Fietkau + */ + +#ifndef AR5315_H +#define AR5315_H + +/* + * Address map + */ +#define AR5315_SDRAM0 0x00000000 /* DRAM */ +#define AR5315_SPI_READ 0x08000000 /* SPI FLASH */ +#define AR5315_WLAN0 0xB0000000 /* Wireless MMR */ +#define AR5315_PCI 0xB0100000 /* PCI MMR */ +#define AR5315_SDRAMCTL 0xB0300000 /* SDRAM MMR */ +#define AR5315_LOCAL 0xB0400000 /* LOCAL BUS MMR */ +#define AR5315_ENET0 0xB0500000 /* ETHERNET MMR */ +#define AR5315_DSLBASE 0xB1000000 /* RESET CONTROL MMR */ +#define AR5315_UART0 0xB1100003 /* UART MMR */ +#define AR5315_SPI 0xB1300000 /* SPI FLASH MMR */ +#define AR5315_FLASHBT 0xBfc00000 /* ro boot alias to FLASH */ +#define AR5315_RAM1 0x40000000 /* ram alias */ +#define AR5315_PCIEXT 0x80000000 /* pci external */ +#define AR5315_RAM2 0xc0000000 /* ram alias */ +#define AR5315_RAM3 0xe0000000 /* ram alias */ + +/* + * Reset Register + */ +#define AR5315_COLD_RESET (AR5315_DSLBASE + 0x0000) + +/* Cold Reset */ +#define RESET_COLD_AHB 0x00000001 +#define RESET_COLD_APB 0x00000002 +#define RESET_COLD_CPU 0x00000004 +#define RESET_COLD_CPUWARM 0x00000008 +#define RESET_SYSTEM (RESET_COLD_CPU | RESET_COLD_APB | RESET_COLD_AHB) /* full system */ + +#define AR5317_RESET_SYSTEM 0x00000010 + +/* Warm Reset */ + +#define AR5315_RESET (AR5315_DSLBASE + 0x0004) + +#define AR5315_RESET_WARM_WLAN0_MAC 0x00000001 /* warm reset WLAN0 MAC */ +#define AR5315_RESET_WARM_WLAN0_BB 0x00000002 /* warm reset WLAN0 BaseBand */ +#define AR5315_RESET_MPEGTS_RSVD 0x00000004 /* warm reset MPEG-TS */ +#define AR5315_RESET_PCIDMA 0x00000008 /* warm reset PCI ahb/dma */ +#define AR5315_RESET_MEMCTL 0x00000010 /* warm reset memory controller */ +#define AR5315_RESET_LOCAL 0x00000020 /* warm reset local bus */ +#define AR5315_RESET_I2C_RSVD 0x00000040 /* warm reset I2C bus */ +#define AR5315_RESET_SPI 0x00000080 /* warm reset SPI interface */ +#define AR5315_RESET_UART0 0x00000100 /* warm reset UART0 */ +#define AR5315_RESET_IR_RSVD 0x00000200 /* warm reset IR interface */ +#define AR5315_RESET_EPHY0 0x00000400 /* cold reset ENET0 phy */ +#define AR5315_RESET_ENET0 0x00000800 /* cold reset ENET0 mac */ + +/* + * AHB master arbitration control + */ +#define AR5315_AHB_ARB_CTL (AR5315_DSLBASE + 0x0008) + +#define ARB_CPU 0x00000001 /* CPU, default */ +#define ARB_WLAN 0x00000002 /* WLAN */ +#define ARB_MPEGTS_RSVD 0x00000004 /* MPEG-TS */ +#define ARB_LOCAL 0x00000008 /* LOCAL */ +#define ARB_PCI 0x00000010 /* PCI */ +#define ARB_ETHERNET 0x00000020 /* Ethernet */ +#define ARB_RETRY 0x00000100 /* retry policy, debug only */ + +/* + * Config Register + */ +#define AR5315_ENDIAN_CTL (AR5315_DSLBASE + 0x000c) + +#define CONFIG_AHB 0x00000001 /* EC - AHB bridge endianess */ +#define CONFIG_WLAN 0x00000002 /* WLAN byteswap */ +#define CONFIG_MPEGTS_RSVD 0x00000004 /* MPEG-TS byteswap */ +#define CONFIG_PCI 0x00000008 /* PCI byteswap */ +#define CONFIG_MEMCTL 0x00000010 /* Memory controller endianess */ +#define CONFIG_LOCAL 0x00000020 /* Local bus byteswap */ +#define CONFIG_ETHERNET 0x00000040 /* Ethernet byteswap */ + +#define CONFIG_MERGE 0x00000200 /* CPU write buffer merge */ +#define CONFIG_CPU 0x00000400 /* CPU big endian */ +#define CONFIG_PCIAHB 0x00000800 +#define CONFIG_PCIAHB_BRIDGE 0x00001000 +#define CONFIG_SPI 0x00008000 /* SPI byteswap */ +#define CONFIG_CPU_DRAM 0x00010000 +#define CONFIG_CPU_PCI 0x00020000 +#define CONFIG_CPU_MMR 0x00040000 +#define CONFIG_BIG 0x00000400 + + +/* + * NMI control + */ +#define AR5315_NMI_CTL (AR5315_DSLBASE + 0x0010) + +#define NMI_EN 1 + +/* + * Revision Register - Initial value is 0x3010 (WMAC 3.0, AR531X 1.0). + */ +#define AR5315_SREV (AR5315_DSLBASE + 0x0014) + +#define REV_MAJ 0x00f0 +#define REV_MAJ_S 4 +#define REV_MIN 0x000f +#define REV_MIN_S 0 +#define REV_CHIP (REV_MAJ|REV_MIN) + +/* + * Interface Enable + */ +#define AR5315_IF_CTL (AR5315_DSLBASE + 0x0018) + +#define IF_MASK 0x00000007 +#define IF_DISABLED 0 +#define IF_PCI 1 +#define IF_TS_LOCAL 2 +#define IF_ALL 3 /* only for emulation with separate pins */ +#define IF_LOCAL_HOST 0x00000008 +#define IF_PCI_HOST 0x00000010 +#define IF_PCI_INTR 0x00000020 +#define IF_PCI_CLK_MASK 0x00030000 +#define IF_PCI_CLK_INPUT 0 +#define IF_PCI_CLK_OUTPUT_LOW 1 +#define IF_PCI_CLK_OUTPUT_CLK 2 +#define IF_PCI_CLK_OUTPUT_HIGH 3 +#define IF_PCI_CLK_SHIFT 16 + + +/* Major revision numbers, bits 7..4 of Revision ID register */ +#define REV_MAJ_AR5311 0x01 +#define REV_MAJ_AR5312 0x04 +#define REV_MAJ_AR5315 0x0B + +/* + * APB Interrupt control + */ + +#define AR5315_ISR (AR5315_DSLBASE + 0x0020) +#define AR5315_IMR (AR5315_DSLBASE + 0x0024) +#define AR5315_GISR (AR5315_DSLBASE + 0x0028) + +#define AR5315_ISR_UART0 0x0001 /* high speed UART */ +#define AR5315_ISR_I2C_RSVD 0x0002 /* I2C bus */ +#define AR5315_ISR_SPI 0x0004 /* SPI bus */ +#define AR5315_ISR_AHB 0x0008 /* AHB error */ +#define AR5315_ISR_APB 0x0010 /* APB error */ +#define AR5315_ISR_TIMER 0x0020 /* timer */ +#define AR5315_ISR_GPIO 0x0040 /* GPIO */ +#define AR5315_ISR_WD 0x0080 /* watchdog */ +#define AR5315_ISR_IR_RSVD 0x0100 /* IR */ + +#define AR5315_GISR_MISC 0x0001 +#define AR5315_GISR_WLAN0 0x0002 +#define AR5315_GISR_MPEGTS_RSVD 0x0004 +#define AR5315_GISR_LOCALPCI 0x0008 +#define AR5315_GISR_WMACPOLL 0x0010 +#define AR5315_GISR_TIMER 0x0020 +#define AR5315_GISR_ETHERNET 0x0040 + +/* + * Interrupt routing from IO to the processor IP bits + * Define our inter mask and level + */ +#define AR5315_INTR_MISCIO SR_IBIT3 +#define AR5315_INTR_WLAN0 SR_IBIT4 +#define AR5315_INTR_ENET0 SR_IBIT5 +#define AR5315_INTR_LOCALPCI SR_IBIT6 +#define AR5315_INTR_WMACPOLL SR_IBIT7 +#define AR5315_INTR_COMPARE SR_IBIT8 + +/* + * Timers + */ +#define AR5315_TIMER (AR5315_DSLBASE + 0x0030) +#define AR5315_RELOAD (AR5315_DSLBASE + 0x0034) +#define AR5315_WD (AR5315_DSLBASE + 0x0038) +#define AR5315_WDC (AR5315_DSLBASE + 0x003c) + +#define WDC_RESET 0x00000002 /* reset on watchdog */ +#define WDC_NMI 0x00000001 /* NMI on watchdog */ +#define WDC_IGNORE_EXPIRATION 0x00000000 + +/* + * CPU Performance Counters + */ +#define AR5315_PERFCNT0 (AR5315_DSLBASE + 0x0048) +#define AR5315_PERFCNT1 (AR5315_DSLBASE + 0x004c) + +#define PERF_DATAHIT 0x0001 /* Count Data Cache Hits */ +#define PERF_DATAMISS 0x0002 /* Count Data Cache Misses */ +#define PERF_INSTHIT 0x0004 /* Count Instruction Cache Hits */ +#define PERF_INSTMISS 0x0008 /* Count Instruction Cache Misses */ +#define PERF_ACTIVE 0x0010 /* Count Active Processor Cycles */ +#define PERF_WBHIT 0x0020 /* Count CPU Write Buffer Hits */ +#define PERF_WBMISS 0x0040 /* Count CPU Write Buffer Misses */ + +#define PERF_EB_ARDY 0x0001 /* Count EB_ARdy signal */ +#define PERF_EB_AVALID 0x0002 /* Count EB_AValid signal */ +#define PERF_EB_WDRDY 0x0004 /* Count EB_WDRdy signal */ +#define PERF_EB_RDVAL 0x0008 /* Count EB_RdVal signal */ +#define PERF_VRADDR 0x0010 /* Count valid read address cycles */ +#define PERF_VWADDR 0x0020 /* Count valid write address cycles */ +#define PERF_VWDATA 0x0040 /* Count valid write data cycles */ + +/* + * AHB Error Reporting. + */ +#define AR5315_AHB_ERR0 (AR5315_DSLBASE + 0x0050) /* error */ +#define AR5315_AHB_ERR1 (AR5315_DSLBASE + 0x0054) /* haddr */ +#define AR5315_AHB_ERR2 (AR5315_DSLBASE + 0x0058) /* hwdata */ +#define AR5315_AHB_ERR3 (AR5315_DSLBASE + 0x005c) /* hrdata */ +#define AR5315_AHB_ERR4 (AR5315_DSLBASE + 0x0060) /* status */ + +#define AHB_ERROR_DET 1 /* AHB Error has been detected, */ + /* write 1 to clear all bits in ERR0 */ +#define AHB_ERROR_OVR 2 /* AHB Error overflow has been detected */ +#define AHB_ERROR_WDT 4 /* AHB Error due to wdt instead of hresp */ + +#define PROCERR_HMAST 0x0000000f +#define PROCERR_HMAST_DFLT 0 +#define PROCERR_HMAST_WMAC 1 +#define PROCERR_HMAST_ENET 2 +#define PROCERR_HMAST_PCIENDPT 3 +#define PROCERR_HMAST_LOCAL 4 +#define PROCERR_HMAST_CPU 5 +#define PROCERR_HMAST_PCITGT 6 + +#define PROCERR_HMAST_S 0 +#define PROCERR_HWRITE 0x00000010 +#define PROCERR_HSIZE 0x00000060 +#define PROCERR_HSIZE_S 5 +#define PROCERR_HTRANS 0x00000180 +#define PROCERR_HTRANS_S 7 +#define PROCERR_HBURST 0x00000e00 +#define PROCERR_HBURST_S 9 + + + +/* + * Clock Control + */ +#define AR5315_PLLC_CTL (AR5315_DSLBASE + 0x0064) +#define AR5315_PLLV_CTL (AR5315_DSLBASE + 0x0068) +#define AR5315_CPUCLK (AR5315_DSLBASE + 0x006c) +#define AR5315_AMBACLK (AR5315_DSLBASE + 0x0070) +#define AR5315_SYNCCLK (AR5315_DSLBASE + 0x0074) +#define AR5315_DSL_SLEEP_CTL (AR5315_DSLBASE + 0x0080) +#define AR5315_DSL_SLEEP_DUR (AR5315_DSLBASE + 0x0084) + +/* PLLc Control fields */ +#define PLLC_REF_DIV_M 0x00000003 +#define PLLC_REF_DIV_S 0 +#define PLLC_FDBACK_DIV_M 0x0000007C +#define PLLC_FDBACK_DIV_S 2 +#define PLLC_ADD_FDBACK_DIV_M 0x00000080 +#define PLLC_ADD_FDBACK_DIV_S 7 +#define PLLC_CLKC_DIV_M 0x0001c000 +#define PLLC_CLKC_DIV_S 14 +#define PLLC_CLKM_DIV_M 0x00700000 +#define PLLC_CLKM_DIV_S 20 + +/* CPU CLK Control fields */ +#define CPUCLK_CLK_SEL_M 0x00000003 +#define CPUCLK_CLK_SEL_S 0 +#define CPUCLK_CLK_DIV_M 0x0000000c +#define CPUCLK_CLK_DIV_S 2 + +/* AMBA CLK Control fields */ +#define AMBACLK_CLK_SEL_M 0x00000003 +#define AMBACLK_CLK_SEL_S 0 +#define AMBACLK_CLK_DIV_M 0x0000000c +#define AMBACLK_CLK_DIV_S 2 + +#if defined(COBRA_EMUL) +#define AR5315_AMBA_CLOCK_RATE 20000000 +#define AR5315_CPU_CLOCK_RATE 40000000 +#else +#if defined(DEFAULT_PLL) +#define AR5315_AMBA_CLOCK_RATE 40000000 +#define AR5315_CPU_CLOCK_RATE 40000000 +#else +#define AR5315_AMBA_CLOCK_RATE 92000000 +#define AR5315_CPU_CLOCK_RATE 184000000 +#endif /* ! DEFAULT_PLL */ +#endif /* ! COBRA_EMUL */ + +#define AR5315_UART_CLOCK_RATE AR5315_AMBA_CLOCK_RATE +#define AR5315_SDRAM_CLOCK_RATE AR5315_AMBA_CLOCK_RATE + +/* + * The UART computes baud rate as: + * baud = clock / (16 * divisor) + * where divisor is specified as a High Byte (DLM) and a Low Byte (DLL). + */ +#define DESIRED_BAUD_RATE 38400 + + +#define CLOCKCTL_UART0 0x0010 /* enable UART0 external clock */ + + + /* + * Applicable "PCICFG" bits for WLAN(s). Assoc status and LED mode. + */ +#define ASSOC_STATUS_M 0x00000003 +#define ASSOC_STATUS_NONE 0 +#define ASSOC_STATUS_PENDING 1 +#define ASSOC_STATUS_ASSOCIATED 2 +#define LED_MODE_M 0x0000001c +#define LED_BLINK_THRESHOLD_M 0x000000e0 +#define LED_SLOW_BLINK_MODE 0x00000100 + +/* + * GPIO + */ + +#define AR5315_GPIO_DI (AR5315_DSLBASE + 0x0088) +#define AR5315_GPIO_DO (AR5315_DSLBASE + 0x0090) +#define AR5315_GPIO_CR (AR5315_DSLBASE + 0x0098) +#define AR5315_GPIO_INT (AR5315_DSLBASE + 0x00a0) + +#define AR5315_GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ +#define AR5315_GPIO_CR_O(x) (1 << (x)) /* output */ +#define AR5315_GPIO_CR_I(x) (0 << (x)) /* input */ + +#define AR5315_GPIO_INT_S(x,Y) ((x) << (8 * (Y))) /* interrupt enable */ +#define AR5315_GPIO_INT_M(Y) ((0x3F) << (8 * (Y))) /* mask for int */ +#define AR5315_GPIO_INT_LVL(x,Y) ((x) << (8 * (Y) + 6)) /* interrupt level */ +#define AR5315_GPIO_INT_LVL_M(Y) ((0x3) << (8 * (Y) + 6)) /* mask for int level */ + +#define AR5315_RESET_GPIO 5 +#define AR5315_NUM_GPIO 22 + + +/* + * PCI Clock Control + */ + +#define AR5315_PCICLK (AR5315_DSLBASE + 0x00a4) + +#define PCICLK_INPUT_M 0x3 +#define PCICLK_INPUT_S 0 + +#define PCICLK_PLLC_CLKM 0 +#define PCICLK_PLLC_CLKM1 1 +#define PCICLK_PLLC_CLKC 2 +#define PCICLK_REF_CLK 3 + +#define PCICLK_DIV_M 0xc +#define PCICLK_DIV_S 2 + +#define PCICLK_IN_FREQ 0 +#define PCICLK_IN_FREQ_DIV_6 1 +#define PCICLK_IN_FREQ_DIV_8 2 +#define PCICLK_IN_FREQ_DIV_10 3 + +/* + * Observation Control Register + */ +#define AR5315_OCR (AR5315_DSLBASE + 0x00b0) +#define OCR_GPIO0_IRIN 0x0040 +#define OCR_GPIO1_IROUT 0x0080 +#define OCR_GPIO3_RXCLR 0x0200 + +/* + * General Clock Control + */ + +#define AR5315_MISCCLK (AR5315_DSLBASE + 0x00b4) +#define MISCCLK_PLLBYPASS_EN 0x00000001 +#define MISCCLK_PROCREFCLK 0x00000002 + +/* + * SDRAM Controller + * - No read or write buffers are included. + */ +#define AR5315_MEM_CFG (AR5315_SDRAMCTL + 0x00) +#define AR5315_MEM_CTRL (AR5315_SDRAMCTL + 0x0c) +#define AR5315_MEM_REF (AR5315_SDRAMCTL + 0x10) + +#define SDRAM_DATA_WIDTH_M 0x00006000 +#define SDRAM_DATA_WIDTH_S 13 + +#define SDRAM_COL_WIDTH_M 0x00001E00 +#define SDRAM_COL_WIDTH_S 9 + +#define SDRAM_ROW_WIDTH_M 0x000001E0 +#define SDRAM_ROW_WIDTH_S 5 + +#define SDRAM_BANKADDR_BITS_M 0x00000018 +#define SDRAM_BANKADDR_BITS_S 3 + +/* + * SPI Flash Interface Registers + */ + +#define AR5315_SPI_CTL (AR5315_SPI + 0x00) +#define AR5315_SPI_OPCODE (AR5315_SPI + 0x04) +#define AR5315_SPI_DATA (AR5315_SPI + 0x08) + +#define SPI_CTL_START 0x00000100 +#define SPI_CTL_BUSY 0x00010000 +#define SPI_CTL_TXCNT_MASK 0x0000000f +#define SPI_CTL_RXCNT_MASK 0x000000f0 +#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff +#define SPI_CTL_SIZE_MASK 0x00060000 + +#define SPI_CTL_CLK_SEL_MASK 0x03000000 +#define SPI_OPCODE_MASK 0x000000ff + +/* + * PCI-MAC Configuration registers + */ +#define PCI_MAC_RC (AR5315_PCI + 0x4000) +#define PCI_MAC_SCR (AR5315_PCI + 0x4004) +#define PCI_MAC_INTPEND (AR5315_PCI + 0x4008) +#define PCI_MAC_SFR (AR5315_PCI + 0x400C) +#define PCI_MAC_PCICFG (AR5315_PCI + 0x4010) +#define PCI_MAC_SREV (AR5315_PCI + 0x4020) + +#define PCI_MAC_RC_MAC 0x00000001 +#define PCI_MAC_RC_BB 0x00000002 + +#define PCI_MAC_SCR_SLMODE_M 0x00030000 +#define PCI_MAC_SCR_SLMODE_S 16 +#define PCI_MAC_SCR_SLM_FWAKE 0 +#define PCI_MAC_SCR_SLM_FSLEEP 1 +#define PCI_MAC_SCR_SLM_NORMAL 2 + +#define PCI_MAC_SFR_SLEEP 0x00000001 + +#define PCI_MAC_PCICFG_SPWR_DN 0x00010000 + + +/* + * PCI Bus Interface Registers + */ +#define AR5315_PCI_1MS_REG (AR5315_PCI + 0x0008) +#define AR5315_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ + +#define AR5315_PCI_MISC_CONFIG (AR5315_PCI + 0x000c) +#define AR5315_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */ +#define AR5315_PCIMISC_CFG_SEL 0x00000002 /* mem or config cycles */ +#define AR5315_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */ +#define AR5315_PCIMISC_RST_MODE 0x00000030 +#define AR5315_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */ +#define AR5315_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */ +#define AR5315_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */ +#define AR5315_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */ +#define AR5315_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */ +#define AR5315_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */ +#define AR5315_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */ +#define AR5315_PCICACHE_DIS 0x00001000 /* PCI external access cache disable */ + +#define AR5315_PCI_OUT_TSTAMP (AR5315_PCI + 0x0010) + +#define AR5315_PCI_UNCACHE_CFG (AR5315_PCI + 0x0014) + +#define AR5315_PCI_IN_EN (AR5315_PCI + 0x0100) +#define AR5315_PCI_IN_EN0 0x01 /* Enable chain 0 */ +#define AR5315_PCI_IN_EN1 0x02 /* Enable chain 1 */ +#define AR5315_PCI_IN_EN2 0x04 /* Enable chain 2 */ +#define AR5315_PCI_IN_EN3 0x08 /* Enable chain 3 */ + +#define AR5315_PCI_IN_DIS (AR5315_PCI + 0x0104) +#define AR5315_PCI_IN_DIS0 0x01 /* Disable chain 0 */ +#define AR5315_PCI_IN_DIS1 0x02 /* Disable chain 1 */ +#define AR5315_PCI_IN_DIS2 0x04 /* Disable chain 2 */ +#define AR5315_PCI_IN_DIS3 0x08 /* Disable chain 3 */ + +#define AR5315_PCI_IN_PTR (AR5315_PCI + 0x0200) + +#define AR5315_PCI_OUT_EN (AR5315_PCI + 0x0400) +#define AR5315_PCI_OUT_EN0 0x01 /* Enable chain 0 */ + +#define AR5315_PCI_OUT_DIS (AR5315_PCI + 0x0404) +#define AR5315_PCI_OUT_DIS0 0x01 /* Disable chain 0 */ + +#define AR5315_PCI_OUT_PTR (AR5315_PCI + 0x0408) + +#define AR5315_PCI_INT_STATUS (AR5315_PCI + 0x0500) /* write one to clr */ +#define AR5315_PCI_TXINT 0x00000001 /* Desc In Completed */ +#define AR5315_PCI_TXOK 0x00000002 /* Desc In OK */ +#define AR5315_PCI_TXERR 0x00000004 /* Desc In ERR */ +#define AR5315_PCI_TXEOL 0x00000008 /* Desc In End-of-List */ +#define AR5315_PCI_RXINT 0x00000010 /* Desc Out Completed */ +#define AR5315_PCI_RXOK 0x00000020 /* Desc Out OK */ +#define AR5315_PCI_RXERR 0x00000040 /* Desc Out ERR */ +#define AR5315_PCI_RXEOL 0x00000080 /* Desc Out EOL */ +#define AR5315_PCI_TXOOD 0x00000200 /* Desc In Out-of-Desc */ +#define AR5315_PCI_MASK 0x0000FFFF /* Desc Mask */ +#define AR5315_PCI_EXT_INT 0x02000000 +#define AR5315_PCI_ABORT_INT 0x04000000 + +#define AR5315_PCI_INT_MASK (AR5315_PCI + 0x0504) /* same as INT_STATUS */ + +#define AR5315_PCI_INTEN_REG (AR5315_PCI + 0x0508) +#define AR5315_PCI_INT_DISABLE 0x00 /* disable pci interrupts */ +#define AR5315_PCI_INT_ENABLE 0x01 /* enable pci interrupts */ + +#define AR5315_PCI_HOST_IN_EN (AR5315_PCI + 0x0800) +#define AR5315_PCI_HOST_IN_DIS (AR5315_PCI + 0x0804) +#define AR5315_PCI_HOST_IN_PTR (AR5315_PCI + 0x0810) +#define AR5315_PCI_HOST_OUT_EN (AR5315_PCI + 0x0900) +#define AR5315_PCI_HOST_OUT_DIS (AR5315_PCI + 0x0904) +#define AR5315_PCI_HOST_OUT_PTR (AR5315_PCI + 0x0908) + + +/* + * Local Bus Interface Registers + */ +#define AR5315_LB_CONFIG (AR5315_LOCAL + 0x0000) +#define AR5315_LBCONF_OE 0x00000001 /* =1 OE is low-true */ +#define AR5315_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */ +#define AR5315_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */ +#define AR5315_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */ +#define AR5315_LBCONF_WE 0x00000010 /* =1 Write En is low-true */ +#define AR5315_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */ +#define AR5315_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */ +#define AR5315_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */ +#define AR5315_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */ +#define AR5315_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */ +#define AR5315_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */ +#define AR5315_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */ +#define AR5315_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */ +#define AR5315_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */ +#define AR5315_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */ +#define AR5315_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */ +#define AR5315_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */ +#define AR5315_LBCONF_INT 0x00020000 /* =1 Intr is low true */ +#define AR5315_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */ +#define AR5315_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */ +#define AR5315_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */ +#define AR5315_LBCONF_INT_CTR3 0x000C0000 /* GND drive, Vdd drive */ +#define AR5315_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */ +#define AR5315_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */ +#define AR5315_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */ + +#define AR5315_LB_CLKSEL (AR5315_LOCAL + 0x0004) +#define AR5315_LBCLK_EXT 0x0001 /* use external clk for lb */ + +#define AR5315_LB_1MS (AR5315_LOCAL + 0x0008) +#define AR5315_LB1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ + +#define AR5315_LB_MISCCFG (AR5315_LOCAL + 0x000C) +#define AR5315_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */ +#define AR5315_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */ +#define AR5315_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */ +#define AR5315_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */ +#define AR5315_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */ +#define AR5315_LBM_TIMEOUT_MASK 0x00FFFF80 +#define AR5315_LBM_TIMEOUT_SHFT 7 +#define AR5315_LBM_PORTMUX 0x07000000 + + +#define AR5315_LB_RXTSOFF (AR5315_LOCAL + 0x0010) + +#define AR5315_LB_TX_CHAIN_EN (AR5315_LOCAL + 0x0100) +#define AR5315_LB_TXEN_0 0x01 +#define AR5315_LB_TXEN_1 0x02 +#define AR5315_LB_TXEN_2 0x04 +#define AR5315_LB_TXEN_3 0x08 + +#define AR5315_LB_TX_CHAIN_DIS (AR5315_LOCAL + 0x0104) +#define AR5315_LB_TX_DESC_PTR (AR5315_LOCAL + 0x0200) + +#define AR5315_LB_RX_CHAIN_EN (AR5315_LOCAL + 0x0400) +#define AR5315_LB_RXEN 0x01 + +#define AR5315_LB_RX_CHAIN_DIS (AR5315_LOCAL + 0x0404) +#define AR5315_LB_RX_DESC_PTR (AR5315_LOCAL + 0x0408) + +#define AR5315_LB_INT_STATUS (AR5315_LOCAL + 0x0500) +#define AR5315_INT_TX_DESC 0x0001 +#define AR5315_INT_TX_OK 0x0002 +#define AR5315_INT_TX_ERR 0x0004 +#define AR5315_INT_TX_EOF 0x0008 +#define AR5315_INT_RX_DESC 0x0010 +#define AR5315_INT_RX_OK 0x0020 +#define AR5315_INT_RX_ERR 0x0040 +#define AR5315_INT_RX_EOF 0x0080 +#define AR5315_INT_TX_TRUNC 0x0100 +#define AR5315_INT_TX_STARVE 0x0200 +#define AR5315_INT_LB_TIMEOUT 0x0400 +#define AR5315_INT_LB_ERR 0x0800 +#define AR5315_INT_MBOX_WR 0x1000 +#define AR5315_INT_MBOX_RD 0x2000 + +/* Bit definitions for INT MASK are the same as INT_STATUS */ +#define AR5315_LB_INT_MASK (AR5315_LOCAL + 0x0504) + +#define AR5315_LB_INT_EN (AR5315_LOCAL + 0x0508) +#define AR5315_LB_MBOX (AR5315_LOCAL + 0x0600) + + + +/* + * IR Interface Registers + */ +#define AR5315_IR_PKTDATA (AR5315_IR + 0x0000) + +#define AR5315_IR_PKTLEN (AR5315_IR + 0x07fc) /* 0 - 63 */ + +#define AR5315_IR_CONTROL (AR5315_IR + 0x0800) +#define AR5315_IRCTL_TX 0x00000000 /* use as tranmitter */ +#define AR5315_IRCTL_RX 0x00000001 /* use as receiver */ +#define AR5315_IRCTL_SAMPLECLK_MASK 0x00003ffe /* Sample clk divisor mask */ +#define AR5315_IRCTL_SAMPLECLK_SHFT 1 +#define AR5315_IRCTL_OUTPUTCLK_MASK 0x03ffc000 /* Output clk divisor mask */ +#define AR5315_IRCTL_OUTPUTCLK_SHFT 14 + +#define AR5315_IR_STATUS (AR5315_IR + 0x0804) +#define AR5315_IRSTS_RX 0x00000001 /* receive in progress */ +#define AR5315_IRSTS_TX 0x00000002 /* transmit in progress */ + +#define AR5315_IR_CONFIG (AR5315_IR + 0x0808) +#define AR5315_IRCFG_INVIN 0x00000001 /* invert input polarity */ +#define AR5315_IRCFG_INVOUT 0x00000002 /* invert output polarity */ +#define AR5315_IRCFG_SEQ_START_WIN_SEL 0x00000004 /* 1 => 28, 0 => 7 */ +#define AR5315_IRCFG_SEQ_START_THRESH 0x000000f0 /* */ +#define AR5315_IRCFG_SEQ_END_UNIT_SEL 0x00000100 /* */ +#define AR5315_IRCFG_SEQ_END_UNIT_THRESH 0x00007e00 /* */ +#define AR5315_IRCFG_SEQ_END_WIN_SEL 0x00008000 /* */ +#define AR5315_IRCFG_SEQ_END_WIN_THRESH 0x001f0000 /* */ +#define AR5315_IRCFG_NUM_BACKOFF_WORDS 0x01e00000 /* */ + +/* + * PCI memory constants: Memory area 1 and 2 are the same size - + * (twice the PCI_TLB_PAGE_SIZE). The definition of + * CPU_TO_PCI_MEM_SIZE is coupled with the TLB setup routine + * sysLib.c/sysTlbInit(), in that it assumes that 2 pages of size + * PCI_TLB_PAGE_SIZE are set up in the TLB for each PCI memory space. + */ + +#define CPU_TO_PCI_MEM_BASE1 0xE0000000 +#define CPU_TO_PCI_MEM_SIZE1 (2*PCI_TLB_PAGE_SIZE) + + +/* TLB attributes for PCI transactions */ + +#define PCI_MMU_PAGEMASK 0x00003FFF +#define MMU_PAGE_UNCACHED 0x00000010 +#define MMU_PAGE_DIRTY 0x00000004 +#define MMU_PAGE_VALID 0x00000002 +#define MMU_PAGE_GLOBAL 0x00000001 +#define PCI_MMU_PAGEATTRIB (MMU_PAGE_UNCACHED|MMU_PAGE_DIRTY|\ + MMU_PAGE_VALID|MMU_PAGE_GLOBAL) +#define PCI_MEMORY_SPACE1_VIRT 0xE0000000 /* Used for non-prefet mem */ +#define PCI_MEMORY_SPACE1_PHYS 0x80000000 +#define PCI_TLB_PAGE_SIZE 0x01000000 +#define TLB_HI_MASK 0xFFFFE000 +#define TLB_LO_MASK 0x3FFFFFFF +#define PAGEMASK_SHIFT 11 +#define TLB_LO_SHIFT 6 + +#define PCI_MAX_LATENCY 0xFFF /* Max PCI latency */ + +#define HOST_PCI_DEV_ID 3 +#define HOST_PCI_MBAR0 0x10000000 +#define HOST_PCI_MBAR1 0x20000000 +#define HOST_PCI_MBAR2 0x30000000 + +#define HOST_PCI_SDRAM_BASEADDR HOST_PCI_MBAR1 +#define PCI_DEVICE_MEM_SPACE 0x800000 + +#endif + diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar531x.h b/target/linux/atheros-2.6/files/arch/mips/atheros/ar531x.h new file mode 100644 index 000000000..208b0101a --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar531x.h @@ -0,0 +1,106 @@ +#ifndef __AR531X_H +#define __AR531X_H + +#include +#include "ar5312.h" +#include "ar5315.h" + +#define MIPS_CPU_IRQ_BASE 0x00 +#define AR531X_HIGH_PRIO 0x10 +#define AR531X_MISC_IRQ_BASE 0x20 +#define AR531X_GPIO_IRQ_BASE 0x30 + +/* Software's idea of interrupts handled by "CPU Interrupt Controller" */ +#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 +#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */ + +/* Miscellaneous interrupts, which share IP6 */ +#define AR531X_MISC_IRQ_NONE AR531X_MISC_IRQ_BASE+0 +#define AR531X_MISC_IRQ_TIMER AR531X_MISC_IRQ_BASE+1 +#define AR531X_MISC_IRQ_AHB_PROC AR531X_MISC_IRQ_BASE+2 +#define AR531X_MISC_IRQ_AHB_DMA AR531X_MISC_IRQ_BASE+3 +#define AR531X_MISC_IRQ_GPIO AR531X_MISC_IRQ_BASE+4 +#define AR531X_MISC_IRQ_UART0 AR531X_MISC_IRQ_BASE+5 +#define AR531X_MISC_IRQ_UART0_DMA AR531X_MISC_IRQ_BASE+6 +#define AR531X_MISC_IRQ_WATCHDOG AR531X_MISC_IRQ_BASE+7 +#define AR531X_MISC_IRQ_LOCAL AR531X_MISC_IRQ_BASE+8 +#define AR531X_MISC_IRQ_COUNT 9 + +/* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */ +#define AR531X_GPIO_IRQ_NONE AR531X_MISC_IRQ_BASE+0 +#define AR531X_GPIO_IRQ(n) AR531X_MISC_IRQ_BASE+(n)+1 +#define AR531X_GPIO_IRQ_COUNT 22 + +#define sysRegRead(phys) \ + (*(volatile u32 *)KSEG1ADDR(phys)) + +#define sysRegWrite(phys, val) \ + ((*(volatile u32 *)KSEG1ADDR(phys)) = (val)) + +/* + * This is board-specific data that is stored in a "fixed" location in flash. + * It is shared across operating systems, so it should not be changed lightly. + * The main reason we need it is in order to extract the ethernet MAC + * address(es). + */ +struct ar531x_boarddata { + u32 magic; /* board data is valid */ +#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */ + u16 cksum; /* checksum (starting with BD_REV 2) */ + u16 rev; /* revision of this struct */ +#define BD_REV 4 + char boardName[64]; /* Name of board */ + u16 major; /* Board major number */ + u16 minor; /* Board minor number */ + u32 config; /* Board configuration */ +#define BD_ENET0 0x00000001 /* ENET0 is stuffed */ +#define BD_ENET1 0x00000002 /* ENET1 is stuffed */ +#define BD_UART1 0x00000004 /* UART1 is stuffed */ +#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */ +#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */ +#define BD_SYSLED 0x00000020 /* System LED stuffed */ +#define BD_EXTUARTCLK 0x00000040 /* External UART clock */ +#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */ +#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */ +#define BD_WLAN0 0x00000200 /* Enable WLAN0 */ +#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */ +#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */ +#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */ +#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */ +#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */ +#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */ +#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */ +#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */ + u16 resetConfigGpio; /* Reset factory GPIO pin */ + u16 sysLedGpio; /* System LED GPIO pin */ + + u32 cpuFreq; /* CPU core frequency in Hz */ + u32 sysFreq; /* System frequency in Hz */ + u32 cntFreq; /* Calculated C0_COUNT frequency */ + + u8 wlan0Mac[6]; + u8 enet0Mac[6]; + u8 enet1Mac[6]; + + u16 pciId; /* Pseudo PCIID for common code */ + u16 memCap; /* cap bank1 in MB */ + + /* version 3 */ + u8 wlan1Mac[6]; /* (ar5212) */ +}; + + +extern char *board_config; +extern char *radio_config; +extern void serial_setup(unsigned long mapbase, unsigned int uartclk); +extern int ar531x_find_config(char *flash_limit); + +extern void ar5312_misc_intr_init(int irq_base); +extern void ar5312_irq_dispatch(void); +extern void ar5312_plat_setup(void); + +extern void ar5315_misc_intr_init(int irq_base); +extern asmlinkage void ar5315_irq_dispatch(void); +extern void ar5315_plat_setup(void); + +#endif diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/board.c b/target/linux/atheros-2.6/files/arch/mips/atheros/board.c new file mode 100644 index 000000000..fe94c3ffc --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/board.c @@ -0,0 +1,190 @@ +/* + * 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 + * Copyright (C) 2006 Felix Fietkau + */ + +/* + * Platform devices for Atheros SoCs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ar531x.h" + +char *board_config, *radio_config; + +static u8 *find_board_config(char *flash_limit) +{ + char *addr; + int found = 0; + + for (addr = (char *) (flash_limit - 0x1000); + addr >= (char *) (flash_limit - 0x30000); + addr -= 0x1000) { + + if ( *(int *)addr == 0x35333131) { + /* config magic found */ + found = 1; + break; + } + } + + if (!found) { + printk("WARNING: No board configuration data found!\n"); + addr = NULL; + } + + return addr; +} + +static u8 *find_radio_config(char *flash_limit, char *board_config) +{ + int dataFound; + u32 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 = (u32) board_config + 0x1000; + (radio_config < (u32) flash_limit); + radio_config += 0x1000) { + if (*(int *)radio_config != 0xffffffff) { + dataFound = 1; + break; + } + } + +#ifdef CONFIG_ATHEROS_AR5315 + if (!dataFound) { /* AR2316 relocates radio config to new location */ + for (radio_config = (u32) board_config + 0xf8; + (radio_config < (u32) flash_limit - 0x1000 + 0xf8); + radio_config += 0x1000) { + if (*(int *)radio_config != 0xffffffff) { + 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) +{ + 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); + if (!bcfg) + return -ENODEV; + + board_config = kmalloc(0x1000, GFP_KERNEL); + memcpy(board_config, bcfg, 0x100); + + /* Radio config starts 0x100 bytes after board config, regardless + * of what the physical layout on the flash chip looks like */ + + rcfg = find_radio_config(flash_limit, bcfg); + if (!rcfg) + return -ENODEV; + + printk("Radio config found at offset 0x%x\n", rcfg - bcfg); + radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff); + rcfg_size = 0x1000 - ((rcfg - bcfg) & 0xfff); + 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) +{ + switch(mips_machtype) { +#ifdef CONFIG_ATHEROS_AR5312 + case MACH_ATHEROS_AR5312: + ar5312_plat_setup(); + break; +#endif +#ifdef CONFIG_ATHEROS_AR5315 + case MACH_ATHEROS_AR5315: + ar5315_plat_setup(); + break; +#endif + } + + /* 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\n"; +#endif +#ifdef CONFIG_ATHEROS_AR5315 + case MACH_ATHEROS_AR5315: + return "Atheros AR5315\n"; +#endif + } + return "Atheros (unknown)"; +} + +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); +} + + diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/irq.c b/target/linux/atheros-2.6/files/arch/mips/atheros/irq.c new file mode 100644 index 000000000..99d960b41 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/irq.c @@ -0,0 +1,98 @@ +/* + * 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 + * Copyright (C) 2006 Felix Fietkau + */ + +/* + * Interrupt support for AR531X WiSOC. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ar531x.h" + + +/* ARGSUSED */ +irqreturn_t +spurious_irq_handler(int cpl, void *dev_id) +{ + /* + printk("spurious_irq_handler: %d cause=0x%8.8x status=0x%8.8x\n", + cpl, cause_intrs, status_intrs); + */ + return IRQ_NONE; +} + +/* ARGSUSED */ +irqreturn_t +spurious_misc_handler(int cpl, void *dev_id) +{ + /* + printk("spurious_misc_handler: 0x%x isr=0x%8.8x imr=0x%8.8x\n", + cpl, ar531x_isr, ar531x_imr); + */ + return IRQ_NONE; +} + +static struct irqaction spurious_irq = { + .handler = spurious_irq_handler, + .flags = SA_INTERRUPT, + .name = "spurious_irq", +}; + +static struct irqaction spurious_misc = { + .handler = spurious_misc_handler, + .flags = SA_INTERRUPT, + .name = "spurious_misc", +}; + +asmlinkage void plat_irq_dispatch(void) +{ +#ifdef CONFIG_ATHEROS_AR5312 + if (mips_machtype == MACH_ATHEROS_AR5312) + ar5312_irq_dispatch(); +#endif +#ifdef CONFIG_ATHEROS_AR5315 + if (mips_machtype == MACH_ATHEROS_AR5315) + ar5315_irq_dispatch(); +#endif +} + +void __init arch_init_irq(void) +{ + clear_c0_status(ST0_IM); + mips_cpu_irq_init(0); + + /* Initialize interrupt controllers */ +#ifdef CONFIG_ATHEROS_AR5312 + if (mips_machtype == MACH_ATHEROS_AR5312) + ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE); +#endif +#ifdef CONFIG_ATHEROS_AR5315 + if (mips_machtype == MACH_ATHEROS_AR5315) + ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE); +#endif + + /* Default "spurious interrupt" handlers */ + setup_irq(AR531X_IRQ_NONE, &spurious_irq); + setup_irq(AR531X_MISC_IRQ_NONE, &spurious_misc); +} diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/prom.c b/target/linux/atheros-2.6/files/arch/mips/atheros/prom.c new file mode 100644 index 000000000..6dfa13c77 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/prom.c @@ -0,0 +1,67 @@ +/* + * 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 + * Copyright (C) 2006 Felix Fietkau + */ + +/* + * Prom setup file for ar531x + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ar531x.h" + +void __init prom_init(void) +{ + u32 memsize, memcfg; + + mips_machgroup = MACH_GROUP_ATHEROS; + mips_machtype = -1; + + /* + * Atheros CPUs before the AR2315 are using MIPS 4Kc core, later designs are + * using MIPS 4KEc R2 core. This makes it easy to determine the board at runtime. + */ + + if (current_cpu_data.cputype == CPU_4KEC) { + mips_machtype = MACH_ATHEROS_AR5315; + + 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; + } else { + int bank0AC, bank1AC; + + mips_machtype = MACH_ATHEROS_AR5312; + + 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); + strcpy(arcs_cmdline, "console=ttyS0,9600 rootfstype=squashfs,jffs2"); +} + +void __init prom_free_prom_memory(void) +{ +} diff --git a/target/linux/atheros-2.6/files/drivers/mtd/devices/spiflash.c b/target/linux/atheros-2.6/files/drivers/mtd/devices/spiflash.c new file mode 100644 index 000000000..6e6734d43 --- /dev/null +++ b/target/linux/atheros-2.6/files/drivers/mtd/devices/spiflash.c @@ -0,0 +1,596 @@ + +/* + * MTD driver for the SPI Flash Memory support. + * + * Copyright (c) 2005-2006 Atheros Communications Inc. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz + * Copyright (C) 2006 Felix Fietkau + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +/*=========================================================================== +** !!!! VERY IMPORTANT NOTICE !!!! FLASH DATA STORED IN LITTLE ENDIAN FORMAT +** +** This module contains the Serial Flash access routines for the Atheros SOC. +** The Atheros SOC integrates a SPI flash controller that is used to access +** serial flash parts. The SPI flash controller executes in "Little Endian" +** mode. THEREFORE, all WRITES and READS from the MIPS CPU must be +** BYTESWAPPED! The SPI Flash controller hardware by default performs READ +** ONLY byteswapping when accessed via the SPI Flash Alias memory region +** (Physical Address 0x0800_0000 - 0x0fff_ffff). The data stored in the +** flash sectors is stored in "Little Endian" format. +** +** The spiflash_write() routine performs byteswapping on all write +** operations. +**===========================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "spiflash.h" + +/* debugging */ +/* #define SPIFLASH_DEBUG */ + +#ifndef __BIG_ENDIAN +#error This driver currently only works with big endian CPU. +#endif + +#define MAX_PARTS 32 + +static char module_name[] = "spiflash"; + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define FALSE 0 +#define TRUE 1 + +#define ROOTFS_NAME "rootfs" + +static __u32 spiflash_regread32(int reg); +static void spiflash_regwrite32(int reg, __u32 data); +static __u32 spiflash_sendcmd (int op); + +int __init spiflash_init (void); +void __exit spiflash_exit (void); +static int spiflash_probe_chip (void); +static int spiflash_erase (struct mtd_info *mtd,struct erase_info *instr); +static int spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf); +static int spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf); + +/* Flash configuration table */ +struct flashconfig { + __u32 byte_cnt; + __u32 sector_cnt; + __u32 sector_size; + __u32 cs_addrmask; +} flashconfig_tbl[MAX_FLASH] = + { + { 0, 0, 0, 0}, + { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT, STM_1MB_SECTOR_SIZE, 0x0}, + { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT, STM_2MB_SECTOR_SIZE, 0x0}, + { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT, STM_4MB_SECTOR_SIZE, 0x0}, + { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT, STM_8MB_SECTOR_SIZE, 0x0} + }; + +/* Mapping of generic opcodes to STM serial flash opcodes */ +struct opcodes { + __u16 code; + __s8 tx_cnt; + __s8 rx_cnt; +} stm_opcodes[] = { + {STM_OP_WR_ENABLE, 1, 0}, + {STM_OP_WR_DISABLE, 1, 0}, + {STM_OP_RD_STATUS, 1, 1}, + {STM_OP_WR_STATUS, 1, 0}, + {STM_OP_RD_DATA, 4, 4}, + {STM_OP_FAST_RD_DATA, 1, 0}, + {STM_OP_PAGE_PGRM, 8, 0}, + {STM_OP_SECTOR_ERASE, 4, 0}, + {STM_OP_BULK_ERASE, 1, 0}, + {STM_OP_DEEP_PWRDOWN, 1, 0}, + {STM_OP_RD_SIG, 4, 1} +}; + +/* Driver private data structure */ +struct spiflash_data { + struct mtd_info *mtd; + struct mtd_partition *parsed_parts; /* parsed partitions */ + void *spiflash_readaddr; /* memory mapped data for read */ + void *spiflash_mmraddr; /* memory mapped register space */ + spinlock_t mutex; +}; + +static struct spiflash_data *spidata; + +extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); + +/***************************************************************************************************/ + +static __u32 +spiflash_regread32(int reg) +{ + volatile __u32 *data = (__u32 *)(spidata->spiflash_mmraddr + reg); + + return (*data); +} + +static void +spiflash_regwrite32(int reg, __u32 data) +{ + volatile __u32 *addr = (__u32 *)(spidata->spiflash_mmraddr + reg); + + *addr = data; + return; +} + +static __u32 +spiflash_sendcmd (int op) +{ + __u32 reg; + __u32 mask; + struct opcodes *ptr_opcode; + + ptr_opcode = &stm_opcodes[op]; + + do { + reg = spiflash_regread32(SPI_FLASH_CTL); + } while (reg & SPI_CTL_BUSY); + + spiflash_regwrite32(SPI_FLASH_OPCODE, ptr_opcode->code); + + reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | + (ptr_opcode->rx_cnt << 4) | SPI_CTL_START; + + spiflash_regwrite32(SPI_FLASH_CTL, reg); + + if (ptr_opcode->rx_cnt > 0) { + do { + reg = spiflash_regread32(SPI_FLASH_CTL); + } while (reg & SPI_CTL_BUSY); + + reg = (__u32) spiflash_regread32(SPI_FLASH_DATA); + + switch (ptr_opcode->rx_cnt) { + case 1: + mask = 0x000000ff; + break; + case 2: + mask = 0x0000ffff; + break; + case 3: + mask = 0x00ffffff; + break; + default: + mask = 0xffffffff; + break; + } + + reg &= mask; + } + else { + reg = 0; + } + + return reg; +} + +/* Probe SPI flash device + * Function returns 0 for failure. + * and flashconfig_tbl array index for success. + */ +static int +spiflash_probe_chip (void) +{ + __u32 sig; + int flash_size; + + /* Read the signature on the flash device */ + sig = spiflash_sendcmd(SPI_RD_SIG); + + switch (sig) { + case STM_8MBIT_SIGNATURE: + flash_size = FLASH_1MB; + break; + case STM_16MBIT_SIGNATURE: + flash_size = FLASH_2MB; + break; + case STM_32MBIT_SIGNATURE: + flash_size = FLASH_4MB; + break; + case STM_64MBIT_SIGNATURE: + flash_size = FLASH_8MB; + break; + default: + printk (KERN_WARNING "%s: Read of flash device signature failed!\n", module_name); + return (0); + } + + return (flash_size); +} + + +static int +spiflash_erase (struct mtd_info *mtd,struct erase_info *instr) +{ + struct opcodes *ptr_opcode; + __u32 temp, reg; + int finished = FALSE; + +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len); +#endif + + /* sanity checks */ + if (instr->addr + instr->len > mtd->size) return (-EINVAL); + + ptr_opcode = &stm_opcodes[SPI_SECTOR_ERASE]; + + temp = ((__u32)instr->addr << 8) | (__u32)(ptr_opcode->code); + spin_lock(&spidata->mutex); + spiflash_sendcmd(SPI_WRITE_ENABLE); + do { + schedule(); + reg = spiflash_regread32(SPI_FLASH_CTL); + } while (reg & SPI_CTL_BUSY); + + spiflash_regwrite32(SPI_FLASH_OPCODE, temp); + + reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | SPI_CTL_START; + spiflash_regwrite32(SPI_FLASH_CTL, reg); + + do { + schedule(); + reg = spiflash_sendcmd(SPI_RD_STATUS); + if (!(reg & SPI_STATUS_WIP)) { + finished = TRUE; + } + } while (!finished); + spin_unlock(&spidata->mutex); + + instr->state = MTD_ERASE_DONE; + if (instr->callback) instr->callback (instr); + +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG "%s return\n",__FUNCTION__); +#endif + return (0); +} + +static int +spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf) +{ + u_char *read_addr; + +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) from,(int)len); +#endif + + /* sanity checks */ + if (!len) return (0); + if (from + len > mtd->size) return (-EINVAL); + + + /* we always read len bytes */ + *retlen = len; + + read_addr = (u_char *)(spidata->spiflash_readaddr + from); + spin_lock(&spidata->mutex); + memcpy(buf, read_addr, len); + spin_unlock(&spidata->mutex); + + return (0); +} + +static int +spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf) +{ + int done = FALSE, page_offset, bytes_left, finished; + __u32 xact_len, spi_data = 0, opcode, reg; + +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) to,len); +#endif + + *retlen = 0; + + /* sanity checks */ + if (!len) return (0); + if (to + len > mtd->size) return (-EINVAL); + + opcode = stm_opcodes[SPI_PAGE_PROGRAM].code; + bytes_left = len; + + while (done == FALSE) { + xact_len = MIN(bytes_left, sizeof(__u32)); + + /* 32-bit writes cannot span across a page boundary + * (256 bytes). This types of writes require two page + * program operations to handle it correctly. The STM part + * will write the overflow data to the beginning of the + * current page as opposed to the subsequent page. + */ + page_offset = (to & (STM_PAGE_SIZE - 1)) + xact_len; + + if (page_offset > STM_PAGE_SIZE) { + xact_len -= (page_offset - STM_PAGE_SIZE); + } + + spin_lock(&spidata->mutex); + spiflash_sendcmd(SPI_WRITE_ENABLE); + + do { + schedule(); + reg = spiflash_regread32(SPI_FLASH_CTL); + } while (reg & SPI_CTL_BUSY); + + switch (xact_len) { + case 1: + spi_data = (u32) ((u8) *buf); + break; + case 2: + spi_data = (buf[1] << 8) | buf[0]; + break; + case 3: + spi_data = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + break; + case 4: + spi_data = (buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; + break; + default: + printk("spiflash_write: default case\n"); + break; + } + + spiflash_regwrite32(SPI_FLASH_DATA, spi_data); + opcode = (opcode & SPI_OPCODE_MASK) | ((__u32)to << 8); + spiflash_regwrite32(SPI_FLASH_OPCODE, opcode); + + reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | (xact_len + 4) | SPI_CTL_START; + spiflash_regwrite32(SPI_FLASH_CTL, reg); + finished = FALSE; + + do { + schedule(); + reg = spiflash_sendcmd(SPI_RD_STATUS); + if (!(reg & SPI_STATUS_WIP)) { + finished = TRUE; + } + } while (!finished); + spin_unlock(&spidata->mutex); + + bytes_left -= xact_len; + to += xact_len; + buf += xact_len; + + *retlen += xact_len; + + if (bytes_left == 0) { + done = TRUE; + } + } + + return (0); +} + + +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; +#endif + + +static int spiflash_probe(struct platform_device *pdev) +{ + int result = -1, i, j; + u32 len; + int index, num_parts; + struct mtd_info *mtd; + struct mtd_partition *mtd_parts; + char *buf; + struct mtd_partition *part; + struct squashfs_super_block *sb; + u32 config_start; + + spidata->spiflash_mmraddr = ioremap_nocache(SPI_FLASH_MMR, SPI_FLASH_MMR_SIZE); + + if (!spidata->spiflash_mmraddr) { + printk (KERN_WARNING "%s: Failed to map flash device\n", module_name); + kfree(spidata); + spidata = NULL; + } + + mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd) { + kfree(spidata); + return (-ENXIO); + } + + printk ("MTD driver for SPI flash.\n"); + printk ("%s: Probing for Serial flash ...\n", module_name); + if (!(index = spiflash_probe_chip())) { + printk (KERN_WARNING "%s: Found no serial flash device\n", module_name); + kfree(mtd); + kfree(spidata); + return (-ENXIO); + } + + printk ("%s: Found SPI serial Flash.\n", module_name); + + spidata->spiflash_readaddr = ioremap_nocache(SPI_FLASH_READ, flashconfig_tbl[index].byte_cnt); + if (!spidata->spiflash_readaddr) { + printk (KERN_WARNING "%s: Failed to map flash device\n", module_name); + kfree(mtd); + kfree(spidata); + return (-ENXIO); + } + + mtd->name = module_name; + mtd->type = MTD_NORFLASH; + mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE); + mtd->size = flashconfig_tbl[index].byte_cnt; + mtd->erasesize = flashconfig_tbl[index].sector_size; + mtd->writesize = 1; + mtd->numeraseregions = 0; + mtd->eraseregions = NULL; + mtd->erase = spiflash_erase; + mtd->read = spiflash_read; + mtd->write = spiflash_write; + mtd->owner = THIS_MODULE; + +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG + "mtd->name = %s\n" + "mtd->size = 0x%.8x (%uM)\n" + "mtd->erasesize = 0x%.8x (%uK)\n" + "mtd->numeraseregions = %d\n", + mtd->name, + mtd->size, mtd->size / (1024*1024), + mtd->erasesize, mtd->erasesize / 1024, + mtd->numeraseregions); + + if (mtd->numeraseregions) { + for (result = 0; result < mtd->numeraseregions; result++) { + printk (KERN_DEBUG + "\n\n" + "mtd->eraseregions[%d].offset = 0x%.8x\n" + "mtd->eraseregions[%d].erasesize = 0x%.8x (%uK)\n" + "mtd->eraseregions[%d].numblocks = %d\n", + result,mtd->eraseregions[result].offset, + result,mtd->eraseregions[result].erasesize,mtd->eraseregions[result].erasesize / 1024, + result,mtd->eraseregions[result].numblocks); + } + } +#endif + + /* parse redboot partitions */ + num_parts = parse_mtd_partitions(mtd, part_probe_types, &spidata->parsed_parts, 0); + + mtd_parts = kzalloc(sizeof(struct mtd_partition) * MAX_PARTS, GFP_KERNEL); + buf = kmalloc(mtd->erasesize, GFP_KERNEL); + sb = (struct squashfs_super_block *) buf; + for (i = j = 0; i < num_parts; i++, j++) { + part = &mtd_parts[j]; + memcpy(part, &spidata->parsed_parts[i], sizeof(struct mtd_partition)); + + if (!strcmp(part->name, ROOTFS_NAME)) { + /* create the root device */ + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, i); + + part->size -= mtd->erasesize; + config_start = part->offset + part->size; + + while ((mtd->read(mtd, part->offset, mtd->erasesize, &len, buf) == 0) && + (len == mtd->erasesize) && + (*((u32 *) buf) == SQUASHFS_MAGIC) && + (sb->bytes_used > 0)) { + + /* this is squashfs, allocate another partition starting from the end of filesystem data */ + memcpy(&mtd_parts[j + 1], part, sizeof(struct mtd_partition)); + + len = (u32) sb->bytes_used; + len += (part->offset & 0x000fffff); + len += (mtd->erasesize - 1); + len &= ~(mtd->erasesize - 1); + len -= (part->offset & 0x000fffff); + + if (len + mtd->erasesize > part->size) + break; + + part = &mtd_parts[++j]; + + part->offset += len; + part->size -= len; + + part->name = kmalloc(10, GFP_KERNEL); + sprintf(part->name, "rootfs%d", j - i); + } + } + if (!strcmp(part->name, "RedBoot config")) { + /* add anoterh partition for the board config data */ + memcpy(&mtd_parts[j + 1], part, sizeof(struct mtd_partition)); + j++; + part = &mtd_parts[j]; + part->offset += part->size; + part->size = mtd->erasesize; + + part->name = kmalloc(16, GFP_KERNEL); + sprintf(part->name, "board_config"); + } + } + num_parts += j - i; + kfree(buf); + +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG "Found %d redboot partitions\n", num_parts); +#endif + if (num_parts) { + result = add_mtd_partitions(mtd, mtd_parts, num_parts); + } else { +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG "Did not find any redboot partitions\n"); +#endif + kfree(mtd); + kfree(spidata); + return (-ENXIO); + } + + spidata->mtd = mtd; + + return (result); +} + +static int spiflash_remove (struct platform_device *pdev) +{ + del_mtd_partitions (spidata->mtd); + kfree(spidata->mtd); + + return 0; +} + +struct platform_driver spiflash_driver = { + .driver.name = "spiflash", + .probe = spiflash_probe, + .remove = spiflash_remove, +}; + +int __init +spiflash_init (void) +{ + spidata = kmalloc(sizeof(struct spiflash_data), GFP_KERNEL); + if (!spidata) + return (-ENXIO); + + spin_lock_init(&spidata->mutex); + platform_driver_register(&spiflash_driver); + + return 0; +} + +void __exit +spiflash_exit (void) +{ + kfree(spidata); +} + +module_init (spiflash_init); +module_exit (spiflash_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Atheros Communications Inc"); +MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros SOC"); + diff --git a/target/linux/atheros-2.6/files/drivers/mtd/devices/spiflash.h b/target/linux/atheros-2.6/files/drivers/mtd/devices/spiflash.h new file mode 100644 index 000000000..e543e040f --- /dev/null +++ b/target/linux/atheros-2.6/files/drivers/mtd/devices/spiflash.h @@ -0,0 +1,124 @@ +/* + * SPI Flash Memory support header file. + * + * $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/drivers/mtd/devices/spiflash.h#3 $ + * + * + * Copyright (c) 2005, Atheros Communications Inc. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#define FLASH_1MB 1 +#define FLASH_2MB 2 +#define FLASH_4MB 3 +#define FLASH_8MB 4 +#define MAX_FLASH 5 + +#define STM_PAGE_SIZE 256 + +#define SPI_WRITE_ENABLE 0 +#define SPI_WRITE_DISABLE 1 +#define SPI_RD_STATUS 2 +#define SPI_WR_STATUS 3 +#define SPI_RD_DATA 4 +#define SPI_FAST_RD_DATA 5 +#define SPI_PAGE_PROGRAM 6 +#define SPI_SECTOR_ERASE 7 +#define SPI_BULK_ERASE 8 +#define SPI_DEEP_PWRDOWN 9 +#define SPI_RD_SIG 10 +#define SPI_MAX_OPCODES 11 + +#define SFI_WRITE_BUFFER_SIZE 4 +#define SFI_FLASH_ADDR_MASK 0x00ffffff + +#define STM_8MBIT_SIGNATURE 0x13 +#define STM_M25P80_BYTE_COUNT 1048576 +#define STM_M25P80_SECTOR_COUNT 16 +#define STM_M25P80_SECTOR_SIZE 0x10000 + +#define STM_16MBIT_SIGNATURE 0x14 +#define STM_M25P16_BYTE_COUNT 2097152 +#define STM_M25P16_SECTOR_COUNT 32 +#define STM_M25P16_SECTOR_SIZE 0x10000 + +#define STM_32MBIT_SIGNATURE 0x15 +#define STM_M25P32_BYTE_COUNT 4194304 +#define STM_M25P32_SECTOR_COUNT 64 +#define STM_M25P32_SECTOR_SIZE 0x10000 + +#define STM_64MBIT_SIGNATURE 0x16 +#define STM_M25P64_BYTE_COUNT 8388608 +#define STM_M25P64_SECTOR_COUNT 128 +#define STM_M25P64_SECTOR_SIZE 0x10000 + +#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT +#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT +#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE +#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT +#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT +#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE +#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT +#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT +#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE +#define STM_8MB_BYTE_COUNT STM_M25P64_BYTE_COUNT +#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT +#define STM_8MB_SECTOR_SIZE STM_M25P64_SECTOR_SIZE + +/* + * ST Microelectronics Opcodes for Serial Flash + */ + +#define STM_OP_WR_ENABLE 0x06 /* Write Enable */ +#define STM_OP_WR_DISABLE 0x04 /* Write Disable */ +#define STM_OP_RD_STATUS 0x05 /* Read Status */ +#define STM_OP_WR_STATUS 0x01 /* Write Status */ +#define STM_OP_RD_DATA 0x03 /* Read Data */ +#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */ +#define STM_OP_PAGE_PGRM 0x02 /* Page Program */ +#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */ +#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */ +#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */ +#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */ + +#define STM_STATUS_WIP 0x01 /* Write-In-Progress */ +#define STM_STATUS_WEL 0x02 /* Write Enable Latch */ +#define STM_STATUS_BP0 0x04 /* Block Protect 0 */ +#define STM_STATUS_BP1 0x08 /* Block Protect 1 */ +#define STM_STATUS_BP2 0x10 /* Block Protect 2 */ +#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */ + +/* + * SPI Flash Interface Registers + */ +#define AR531XPLUS_SPI_READ 0x08000000 +#define AR531XPLUS_SPI_MMR 0x11300000 +#define AR531XPLUS_SPI_MMR_SIZE 12 + +#define AR531XPLUS_SPI_CTL 0x00 +#define AR531XPLUS_SPI_OPCODE 0x04 +#define AR531XPLUS_SPI_DATA 0x08 + +#define SPI_FLASH_READ AR531XPLUS_SPI_READ +#define SPI_FLASH_MMR AR531XPLUS_SPI_MMR +#define SPI_FLASH_MMR_SIZE AR531XPLUS_SPI_MMR_SIZE +#define SPI_FLASH_CTL AR531XPLUS_SPI_CTL +#define SPI_FLASH_OPCODE AR531XPLUS_SPI_OPCODE +#define SPI_FLASH_DATA AR531XPLUS_SPI_DATA + +#define SPI_CTL_START 0x00000100 +#define SPI_CTL_BUSY 0x00010000 +#define SPI_CTL_TXCNT_MASK 0x0000000f +#define SPI_CTL_RXCNT_MASK 0x000000f0 +#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff +#define SPI_CTL_SIZE_MASK 0x00060000 + +#define SPI_CTL_CLK_SEL_MASK 0x03000000 +#define SPI_OPCODE_MASK 0x000000ff + +#define SPI_STATUS_WIP STM_STATUS_WIP diff --git a/target/linux/atheros-2.6/files/drivers/net/ar2313/Makefile b/target/linux/atheros-2.6/files/drivers/net/ar2313/Makefile new file mode 100644 index 000000000..9eb63e46b --- /dev/null +++ b/target/linux/atheros-2.6/files/drivers/net/ar2313/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the AR2313 ethernet driver +# + +obj-$(CONFIG_AR2313) += ar2313.o diff --git a/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313.c b/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313.c new file mode 100644 index 000000000..82e9e94d5 --- /dev/null +++ b/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313.c @@ -0,0 +1,1545 @@ +/* + * ar2313.c: Linux driver for the Atheros AR231z Ethernet device. + * + * Copyright (C) 2004 by Sameer Dekate + * Copyright (C) 2006 Imre Kaloz + * Copyright (C) 2006 Felix Fietkau + * + * Thanks to Atheros for providing hardware and documentation + * enabling me to write this driver. + * + * 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. + * + * Additional credits: + * This code is taken from John Taylor's Sibyte driver and then + * modified for the AR2313. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#undef INDEX_DEBUG +#define DEBUG 0 +#define DEBUG_TX 0 +#define DEBUG_RX 0 +#define DEBUG_INT 0 +#define DEBUG_MC 0 +#define DEBUG_ERR 1 + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef SMP_CACHE_BYTES +#define SMP_CACHE_BYTES L1_CACHE_BYTES +#endif + +#ifndef SET_MODULE_OWNER +#define SET_MODULE_OWNER(dev) {do{} while(0);} +#define AR2313_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define AR2313_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define AR2313_MOD_INC_USE_COUNT {do{} while(0);} +#define AR2313_MOD_DEC_USE_COUNT {do{} while(0);} +#endif + +#define PHYSADDR(a) ((_ACAST32_ (a)) & 0x1fffffff) + +static char ifname[5] = "bond"; + +module_param_string(ifname, ifname, 5, 0); + +#define AR2313_MBOX_SET_BIT 0x8 + +#define BOARD_IDX_STATIC 0 +#define BOARD_IDX_OVERFLOW -1 + +#include "ar2313_msg.h" +#include "platform.h" +#include "dma.h" +#include "ar2313.h" + +/* + * New interrupt handler strategy: + * + * An old interrupt handler worked using the traditional method of + * replacing an skbuff with a new one when a packet arrives. However + * the rx rings do not need to contain a static number of buffer + * descriptors, thus it makes sense to move the memory allocation out + * of the main interrupt handler and do it in a bottom half handler + * and only allocate new buffers when the number of buffers in the + * ring is below a certain threshold. In order to avoid starving the + * NIC under heavy load it is however necessary to force allocation + * when hitting a minimum threshold. The strategy for alloction is as + * follows: + * + * RX_LOW_BUF_THRES - allocate buffers in the bottom half + * RX_PANIC_LOW_THRES - we are very low on buffers, allocate + * the buffers in the interrupt handler + * RX_RING_THRES - maximum number of buffers in the rx ring + * + * One advantagous side effect of this allocation approach is that the + * entire rx processing can be done without holding any spin lock + * since the rx rings and registers are totally independent of the tx + * ring and its registers. This of course includes the kmalloc's of + * new skb's. Thus start_xmit can run in parallel with rx processing + * and the memory allocation on SMP systems. + * + * Note that running the skb reallocation in a bottom half opens up + * another can of races which needs to be handled properly. In + * particular it can happen that the interrupt handler tries to run + * the reallocation while the bottom half is either running on another + * CPU or was interrupted on the same CPU. To get around this the + * driver uses bitops to prevent the reallocation routines from being + * reentered. + * + * TX handling can also be done without holding any spin lock, wheee + * this is fun! since tx_csm is only written to by the interrupt + * handler. + */ + +/* + * Threshold values for RX buffer allocation - the low water marks for + * when to start refilling the rings are set to 75% of the ring + * sizes. It seems to make sense to refill the rings entirely from the + * intrrupt handler once it gets below the panic threshold, that way + * we don't risk that the refilling is moved to another CPU when the + * one running the interrupt handler just got the slab code hot in its + * cache. + */ +#define RX_RING_SIZE AR2313_DESCR_ENTRIES +#define RX_PANIC_THRES (RX_RING_SIZE/4) +#define RX_LOW_THRES ((3*RX_RING_SIZE)/4) +#define CRC_LEN 4 +#define RX_OFFSET 2 + +#define AR2313_BUFSIZE (AR2313_MTU + ETH_HLEN + CRC_LEN + RX_OFFSET) + +#ifdef MODULE +MODULE_AUTHOR("Sameer Dekate , Imre Kaloz , Felix Fietkau "); +MODULE_DESCRIPTION("AR2313 Ethernet driver"); +#endif + +#if DEBUG +static char version[] __initdata = + "ar2313.c: v0.03 2006/07/12 sdekate@arubanetworks.com\n"; +#endif /* DEBUG */ + +#define virt_to_phys(x) ((u32)(x) & 0x1fffffff) + +// prototypes +static short armiiread(short phy, short reg); +static void armiiwrite(short phy, short reg, short data); +#ifdef TX_TIMEOUT +static void ar2313_tx_timeout(struct net_device *dev); +#endif +static void ar2313_halt(struct net_device *dev); +static void rx_tasklet_func(unsigned long data); +static void ar2313_multicast_list(struct net_device *dev); + +static int probed __initdata = 0; +static unsigned long ar_eth_base; +static unsigned long ar_dma_base; +static unsigned long ar_int_base; +static unsigned long ar_int_mac_mask; +static unsigned long ar_int_phy_mask; + +#ifndef ERR +#define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args) +#endif + + +int __init ar2313_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct ar2313_private *sp; + struct ar531x_eth *cfg; + struct resource *res; + int version_disp; + char name[64] ; + + if (probed) + return -ENODEV; + probed++; + + version_disp = 0; + sprintf(name, "%s%%d", ifname) ; + dev = alloc_etherdev(sizeof(struct ar2313_private)); + + if (dev == NULL) { + printk(KERN_ERR "ar2313: Unable to allocate net_device structure!\n"); + return -ENOMEM; + } + + SET_MODULE_OWNER(dev); + platform_set_drvdata(pdev, dev); + + sp = dev->priv; + sp->dev = dev; + cfg = pdev->dev.platform_data; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth_membase"); + if (!res) + return -ENODEV; + + sp->link = 0; + ar_eth_base = res->start; + ar_dma_base = ar_eth_base + 0x1000; + ar_int_base = cfg->reset_base; + ar_int_mac_mask = cfg->reset_mac; + ar_int_phy_mask = cfg->reset_phy; + sp->phy = cfg->phy; + + dev->irq = platform_get_irq_byname(pdev, "eth_irq"); + + spin_lock_init(&sp->lock); + + /* initialize func pointers */ + dev->open = &ar2313_open; + dev->stop = &ar2313_close; + dev->hard_start_xmit = &ar2313_start_xmit; + + dev->get_stats = &ar2313_get_stats; + dev->set_multicast_list = &ar2313_multicast_list; +#ifdef TX_TIMEOUT + dev->tx_timeout = ar2313_tx_timeout; + dev->watchdog_timeo = AR2313_TX_TIMEOUT; +#endif + dev->do_ioctl = &ar2313_ioctl; + + // SAMEER: do we need this? + dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA; + + tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long) dev); + tasklet_disable(&sp->rx_tasklet); + + /* display version info if adapter is found */ + if (!version_disp) { + /* set display flag to TRUE so that */ + /* we only display this string ONCE */ + version_disp = 1; +#if DEBUG + printk(version); +#endif /* DEBUG */ + } + +#if 0 + request_region(PHYSADDR(ar_eth_base), ETHERNET_SIZE*ETHERNET_MACS, + "AR2313ENET"); +#endif + + sp->eth_regs = ioremap_nocache(PHYSADDR(ar_eth_base), sizeof(*sp->eth_regs)); + if (!sp->eth_regs) { + printk("Can't remap eth registers\n"); + return(-ENXIO); + } + + sp->dma_regs = ioremap_nocache(PHYSADDR(ar_eth_base + 0x1000), sizeof(*sp->dma_regs)); + dev->base_addr = (unsigned int) sp->dma_regs; + if (!sp->dma_regs) { + printk("Can't remap DMA registers\n"); + return(-ENXIO); + } + + sp->int_regs = ioremap_nocache(PHYSADDR(ar_int_base), 4); + if (!sp->int_regs) { + printk("Can't remap INTERRUPT registers\n"); + return(-ENXIO); + } + + strncpy(sp->name, "Atheros AR2313", sizeof (sp->name) - 1); + sp->name [sizeof (sp->name) - 1] = '\0'; + + { + /* XXX: Will have to rewrite this part later */ + char *configstart; + unsigned char def_mac[6] = {0, 0xaa, 0xbb, 0xcc, 0xdd, 0xee}; + + configstart = (char *) cfg->board_config; + + if (!configstart) { + printk("no valid mac found, using defaults"); + memcpy(dev->dev_addr, def_mac, 6); + } else { + memcpy(dev->dev_addr, ((u8 *)configstart)+102, 6); + } + } + + sp->board_idx = BOARD_IDX_STATIC; + + if (ar2313_init(dev)) { + /* + * ar2313_init() calls ar2313_init_cleanup() on error. + */ + kfree(dev); + return -ENODEV; + } + + if (register_netdev(dev)){ + printk("%s: register_netdev failed\n", __func__); + return -1; + } + + printk("%s: %s: %02x:%02x:%02x:%02x:%02x:%02x, irq %d\n", + dev->name, sp->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], + dev->irq); + + /* start link poll timer */ + ar2313_setup_timer(dev); + + return 0; +} + +#if 0 +static void ar2313_dump_regs(struct net_device *dev) +{ + unsigned int *ptr, i; + struct ar2313_private *sp = (struct ar2313_private *)dev->priv; + + ptr = (unsigned int *)sp->eth_regs; + for(i=0; i< (sizeof(ETHERNET_STRUCT)/ sizeof(unsigned int)); i++, ptr++) { + printk("ENET: %08x = %08x\n", (int)ptr, *ptr); + } + + ptr = (unsigned int *)sp->dma_regs; + for(i=0; i< (sizeof(DMA)/ sizeof(unsigned int)); i++, ptr++) { + printk("DMA: %08x = %08x\n", (int)ptr, *ptr); + } + + ptr = (unsigned int *)sp->int_regs; + for(i=0; i< (sizeof(INTERRUPT)/ sizeof(unsigned int)); i++, ptr++){ + printk("INT: %08x = %08x\n", (int)ptr, *ptr); + } + + for (i = 0; i < AR2313_DESCR_ENTRIES; i++) { + ar2313_descr_t *td = &sp->tx_ring[i]; + printk("Tx desc %2d: %08x %08x %08x %08x\n", i, + td->status, td->devcs, td->addr, td->descr); + } +} +#endif + +#ifdef TX_TIMEOUT +static void +ar2313_tx_timeout(struct net_device *dev) +{ + struct ar2313_private *sp = (struct ar2313_private *)dev->priv; + unsigned long flags; + +#if DEBUG_TX + printk("Tx timeout\n"); +#endif + spin_lock_irqsave(&sp->lock, flags); + ar2313_restart(dev); + spin_unlock_irqrestore(&sp->lock, flags); +} +#endif + +#if DEBUG_MC +static void +printMcList(struct net_device *dev) +{ + struct dev_mc_list *list = dev->mc_list; + int num=0, i; + while(list){ + printk("%d MC ADDR ", num); + for(i=0;idmi_addrlen;i++) { + printk(":%02x", list->dmi_addr[i]); + } + list = list->next; + printk("\n"); + } +} +#endif + +/* + * Set or clear the multicast filter for this adaptor. + * THIS IS ABSOLUTE CRAP, disabled + */ +static void +ar2313_multicast_list(struct net_device *dev) +{ + /* + * Always listen to broadcasts and + * treat IFF bits independently + */ + struct ar2313_private *sp = (struct ar2313_private *)dev->priv; + unsigned int recognise; + + recognise = sp->eth_regs->mac_control; + + if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ + recognise |= MAC_CONTROL_PR; + } else { + recognise &= ~MAC_CONTROL_PR; + } + + if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) { +#if DEBUG_MC + printMcList(dev); + printk("%s: all MULTICAST mc_count %d\n", __FUNCTION__, dev->mc_count); +#endif + recognise |= MAC_CONTROL_PM;/* all multicast */ + } else if (dev->mc_count > 0) { +#if DEBUG_MC + printMcList(dev); + printk("%s: mc_count %d\n", __FUNCTION__, dev->mc_count); +#endif + recognise |= MAC_CONTROL_PM; /* for the time being */ + } +#if DEBUG_MC + printk("%s: setting %08x to %08x\n", __FUNCTION__, (int)sp->eth_regs, recognise); +#endif + + sp->eth_regs->mac_control = recognise; +} + +static void rx_tasklet_cleanup(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + + /* + * Tasklet may be scheduled. Need to get it removed from the list + * since we're about to free the struct. + */ + + sp->unloading = 1; + tasklet_enable(&sp->rx_tasklet); + tasklet_kill(&sp->rx_tasklet); +} + +static int __exit ar2313_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + rx_tasklet_cleanup(dev); + ar2313_init_cleanup(dev); + unregister_netdev(dev); + kfree(dev); + return 0; +} + + +/* + * Restart the AR2313 ethernet controller. + */ +static int ar2313_restart(struct net_device *dev) +{ + /* disable interrupts */ + disable_irq(dev->irq); + + /* stop mac */ + ar2313_halt(dev); + + /* initialize */ + ar2313_init(dev); + + /* enable interrupts */ + enable_irq(dev->irq); + + return 0; +} + +static struct platform_driver ar2313_driver = { + .driver.name = "ar531x-eth", + .probe = ar2313_probe, + .remove = ar2313_remove, +}; + +int __init ar2313_module_init(void) +{ + return platform_driver_register(&ar2313_driver); +} + +void __exit ar2313_module_cleanup(void) +{ + platform_driver_unregister(&ar2313_driver); +} + +module_init(ar2313_module_init); +module_exit(ar2313_module_cleanup); + + +static void ar2313_free_descriptors(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + if (sp->rx_ring != NULL) { + kfree((void*)KSEG0ADDR(sp->rx_ring)); + sp->rx_ring = NULL; + sp->tx_ring = NULL; + } +} + + +static int ar2313_allocate_descriptors(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + int size; + int j; + ar2313_descr_t *space; + + if(sp->rx_ring != NULL){ + printk("%s: already done.\n", __FUNCTION__); + return 0; + } + + size = (sizeof(ar2313_descr_t) * (AR2313_DESCR_ENTRIES * AR2313_QUEUES)); + space = kmalloc(size, GFP_KERNEL); + if (space == NULL) + return 1; + + /* invalidate caches */ + dma_cache_inv((unsigned int)space, size); + + /* now convert pointer to KSEG1 */ + space = (ar2313_descr_t *)KSEG1ADDR(space); + + memset((void *)space, 0, size); + + sp->rx_ring = space; + space += AR2313_DESCR_ENTRIES; + + sp->tx_ring = space; + space += AR2313_DESCR_ENTRIES; + + /* Initialize the transmit Descriptors */ + for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { + ar2313_descr_t *td = &sp->tx_ring[j]; + td->status = 0; + td->devcs = DMA_TX1_CHAINED; + td->addr = 0; + td->descr = K1_TO_PHYS(&sp->tx_ring[(j+1) & (AR2313_DESCR_ENTRIES-1)]); + } + + return 0; +} + + +/* + * Generic cleanup handling data allocated during init. Used when the + * module is unloaded or if an error occurs during initialization + */ +static void ar2313_init_cleanup(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + struct sk_buff *skb; + int j; + + ar2313_free_descriptors(dev); + + if (sp->eth_regs) iounmap((void*)sp->eth_regs); + if (sp->dma_regs) iounmap((void*)sp->dma_regs); + + if (sp->rx_skb) { + for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { + skb = sp->rx_skb[j]; + if (skb) { + sp->rx_skb[j] = NULL; + dev_kfree_skb(skb); + } + } + kfree(sp->rx_skb); + sp->rx_skb = NULL; + } + + if (sp->tx_skb) { + for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { + skb = sp->tx_skb[j]; + if (skb) { + sp->tx_skb[j] = NULL; + dev_kfree_skb(skb); + } + } + kfree(sp->tx_skb); + sp->tx_skb = NULL; + } +} + +static int ar2313_setup_timer(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + + init_timer(&sp->link_timer); + + sp->link_timer.function = ar2313_link_timer_fn; + sp->link_timer.data = (int) dev; + sp->link_timer.expires = jiffies + HZ; + + add_timer(&sp->link_timer); + return 0; + +} + +static void ar2313_link_timer_fn(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct ar2313_private *sp = dev->priv; + + // see if the link status changed + // This was needed to make sure we set the PHY to the + // autonegotiated value of half or full duplex. + ar2313_check_link(dev); + + // Loop faster when we don't have link. + // This was needed to speed up the AP bootstrap time. + if(sp->link == 0) { + mod_timer(&sp->link_timer, jiffies + HZ/2); + } else { + mod_timer(&sp->link_timer, jiffies + LINK_TIMER); + } +} + +static void ar2313_check_link(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + u16 phyData; + + phyData = armiiread(sp->phy, MII_BMSR); + if (sp->phyData != phyData) { + if (phyData & BMSR_LSTATUS) { + /* link is present, ready link partner ability to deterine duplexity */ + int duplex = 0; + u16 reg; + + sp->link = 1; + reg = armiiread(sp->phy, MII_BMCR); + if (reg & BMCR_ANENABLE) { + /* auto neg enabled */ + reg = armiiread(sp->phy, MII_LPA); + duplex = (reg & (LPA_100FULL|LPA_10FULL))? 1:0; + } else { + /* no auto neg, just read duplex config */ + duplex = (reg & BMCR_FULLDPLX)? 1:0; + } + + printk(KERN_INFO "%s: Configuring MAC for %s duplex\n", dev->name, + (duplex)? "full":"half"); + + if (duplex) { + /* full duplex */ + sp->eth_regs->mac_control = ((sp->eth_regs->mac_control | MAC_CONTROL_F) & + ~MAC_CONTROL_DRO); + } else { + /* half duplex */ + sp->eth_regs->mac_control = ((sp->eth_regs->mac_control | MAC_CONTROL_DRO) & + ~MAC_CONTROL_F); + } + } else { + /* no link */ + sp->link = 0; + } + sp->phyData = phyData; + } +} + +static int +ar2313_reset_reg(struct net_device *dev) +{ + struct ar2313_private *sp = (struct ar2313_private *)dev->priv; + unsigned int ethsal, ethsah; + unsigned int flags; + + *sp->int_regs |= ar_int_mac_mask; + mdelay(10); + *sp->int_regs &= ~ar_int_mac_mask; + mdelay(10); + *sp->int_regs |= ar_int_phy_mask; + mdelay(10); + *sp->int_regs &= ~ar_int_phy_mask; + mdelay(10); + + sp->dma_regs->bus_mode = (DMA_BUS_MODE_SWR); + mdelay(10); + sp->dma_regs->bus_mode = ((32 << DMA_BUS_MODE_PBL_SHIFT) | DMA_BUS_MODE_BLE); + + /* enable interrupts */ + sp->dma_regs->intr_ena = (DMA_STATUS_AIS | + DMA_STATUS_NIS | + DMA_STATUS_RI | + DMA_STATUS_TI | + DMA_STATUS_FBE); + sp->dma_regs->xmt_base = K1_TO_PHYS(sp->tx_ring); + sp->dma_regs->rcv_base = K1_TO_PHYS(sp->rx_ring); + sp->dma_regs->control = (DMA_CONTROL_SR | DMA_CONTROL_ST | DMA_CONTROL_SF); + + sp->eth_regs->flow_control = (FLOW_CONTROL_FCE); + sp->eth_regs->vlan_tag = (0x8100); + + /* Enable Ethernet Interface */ + flags = (MAC_CONTROL_TE | /* transmit enable */ + MAC_CONTROL_PM | /* pass mcast */ + MAC_CONTROL_F | /* full duplex */ + MAC_CONTROL_HBD); /* heart beat disabled */ + + if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ + flags |= MAC_CONTROL_PR; + } + sp->eth_regs->mac_control = flags; + + /* Set all Ethernet station address registers to their initial values */ + ethsah = ((((u_int)(dev->dev_addr[5]) << 8) & (u_int)0x0000FF00) | + (((u_int)(dev->dev_addr[4]) << 0) & (u_int)0x000000FF)); + + ethsal = ((((u_int)(dev->dev_addr[3]) << 24) & (u_int)0xFF000000) | + (((u_int)(dev->dev_addr[2]) << 16) & (u_int)0x00FF0000) | + (((u_int)(dev->dev_addr[1]) << 8) & (u_int)0x0000FF00) | + (((u_int)(dev->dev_addr[0]) << 0) & (u_int)0x000000FF) ); + + sp->eth_regs->mac_addr[0] = ethsah; + sp->eth_regs->mac_addr[1] = ethsal; + + mdelay(10); + + return(0); +} + + +static int ar2313_init(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + int ecode=0; + + /* + * Allocate descriptors + */ + if (ar2313_allocate_descriptors(dev)) { + printk("%s: %s: ar2313_allocate_descriptors failed\n", + dev->name, __FUNCTION__); + ecode = -EAGAIN; + goto init_error; + } + + /* + * Get the memory for the skb rings. + */ + if(sp->rx_skb == NULL) { + sp->rx_skb = kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES, GFP_KERNEL); + if (!(sp->rx_skb)) { + printk("%s: %s: rx_skb kmalloc failed\n", + dev->name, __FUNCTION__); + ecode = -EAGAIN; + goto init_error; + } + } + memset(sp->rx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES); + + if(sp->tx_skb == NULL) { + sp->tx_skb = kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES, GFP_KERNEL); + if (!(sp->tx_skb)) { + printk("%s: %s: tx_skb kmalloc failed\n", + dev->name, __FUNCTION__); + ecode = -EAGAIN; + goto init_error; + } + } + memset(sp->tx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES); + + /* + * Set tx_csm before we start receiving interrupts, otherwise + * the interrupt handler might think it is supposed to process + * tx ints before we are up and running, which may cause a null + * pointer access in the int handler. + */ + sp->rx_skbprd = 0; + sp->cur_rx = 0; + sp->tx_prd = 0; + sp->tx_csm = 0; + + /* + * Zero the stats before starting the interface + */ + memset(&sp->stats, 0, sizeof(sp->stats)); + + /* + * We load the ring here as there seem to be no way to tell the + * firmware to wipe the ring without re-initializing it. + */ + ar2313_load_rx_ring(dev, RX_RING_SIZE); + + /* + * Init hardware + */ + ar2313_reset_reg(dev); + + /* + * Get the IRQ + */ + ecode = request_irq(dev->irq, &ar2313_interrupt, IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, dev->name, dev); + if (ecode) { + printk(KERN_WARNING "%s: %s: Requested IRQ %d is busy\n", + dev->name, __FUNCTION__, dev->irq); + goto init_error; + } + + + tasklet_enable(&sp->rx_tasklet); + + return 0; + + init_error: + ar2313_init_cleanup(dev); + return ecode; +} + +/* + * Load the rx ring. + * + * Loading rings is safe without holding the spin lock since this is + * done only before the device is enabled, thus no interrupts are + * generated and by the interrupt handler/tasklet handler. + */ +static void ar2313_load_rx_ring(struct net_device *dev, int nr_bufs) +{ + + struct ar2313_private *sp = ((struct net_device *)dev)->priv; + short i, idx; + + idx = sp->rx_skbprd; + + for (i = 0; i < nr_bufs; i++) { + struct sk_buff *skb; + ar2313_descr_t *rd; + + if (sp->rx_skb[idx]) { +#if DEBUG_RX + printk(KERN_INFO "ar2313 rx refill full\n"); +#endif /* DEBUG */ + break; + } + + // partha: create additional room for the second GRE fragment + skb = alloc_skb(AR2313_BUFSIZE+128, GFP_ATOMIC); + if (!skb) { + printk("\n\n\n\n %s: No memory in system\n\n\n\n", __FUNCTION__); + break; + } + // partha: create additional room in the front for tx pkt capture + skb_reserve(skb, 32); + + /* + * Make sure IP header starts on a fresh cache line. + */ + skb->dev = dev; + skb_reserve(skb, RX_OFFSET); + sp->rx_skb[idx] = skb; + + rd = (ar2313_descr_t *) &sp->rx_ring[idx]; + + /* initialize dma descriptor */ + rd->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) | + DMA_RX1_CHAINED); + rd->addr = virt_to_phys(skb->data); + rd->descr = virt_to_phys(&sp->rx_ring[(idx+1) & (AR2313_DESCR_ENTRIES-1)]); + rd->status = DMA_RX_OWN; + + idx = DSC_NEXT(idx); + } + + if (!i) { +#if DEBUG_ERR + printk(KERN_INFO "Out of memory when allocating standard receive buffers\n"); +#endif /* DEBUG */ + } else { + sp->rx_skbprd = idx; + } + + return; +} + +#define AR2313_MAX_PKTS_PER_CALL 64 + +static int ar2313_rx_int(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + struct sk_buff *skb, *skb_new; + ar2313_descr_t *rxdesc; + unsigned int status; + u32 idx; + int pkts = 0; + int rval; + + idx = sp->cur_rx; + + /* process at most the entire ring and then wait for another interrupt */ + while(1) { + + rxdesc = &sp->rx_ring[idx]; + status = rxdesc->status; + if (status & DMA_RX_OWN) { + /* SiByte owns descriptor or descr not yet filled in */ + rval = 0; + break; + } + + if (++pkts > AR2313_MAX_PKTS_PER_CALL) { + rval = 1; + break; + } + +#if DEBUG_RX + printk("index %d\n", idx); + printk("RX status %08x\n", rxdesc->status); + printk("RX devcs %08x\n", rxdesc->devcs ); + printk("RX addr %08x\n", rxdesc->addr ); + printk("RX descr %08x\n", rxdesc->descr ); +#endif + + if ((status & (DMA_RX_ERROR|DMA_RX_ERR_LENGTH)) && + (!(status & DMA_RX_LONG))){ +#if DEBUG_RX + printk("%s: rx ERROR %08x\n", __FUNCTION__, status); +#endif + sp->stats.rx_errors++; + sp->stats.rx_dropped++; + + /* add statistics counters */ + if (status & DMA_RX_ERR_CRC) sp->stats.rx_crc_errors++; + if (status & DMA_RX_ERR_COL) sp->stats.rx_over_errors++; + if (status & DMA_RX_ERR_LENGTH) + sp->stats.rx_length_errors++; + if (status & DMA_RX_ERR_RUNT) sp->stats.rx_over_errors++; + if (status & DMA_RX_ERR_DESC) sp->stats.rx_over_errors++; + + } else { + /* alloc new buffer. */ + skb_new = dev_alloc_skb(AR2313_BUFSIZE + RX_OFFSET + 128); + if (skb_new != NULL) { + + skb = sp->rx_skb[idx]; + /* set skb */ + skb_put(skb, ((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN); + +#ifdef CONFIG_MERLOT + if ((dev->am_pkt_handler == NULL) || + (dev->am_pkt_handler(skb, dev) == 0)) { +#endif + sp->stats.rx_bytes += skb->len; + skb->protocol = eth_type_trans(skb, dev); + /* pass the packet to upper layers */ + +#ifdef CONFIG_MERLOT + if (dev->asap_netif_rx) + dev->asap_netif_rx(skb); + else +#endif + netif_rx(skb); +#ifdef CONFIG_MERLOT + } +#endif + skb_new->dev = dev; + /* 16 bit align */ + skb_reserve(skb_new, RX_OFFSET+32); + /* reset descriptor's curr_addr */ + rxdesc->addr = virt_to_phys(skb_new->data); + + sp->stats.rx_packets++; + sp->rx_skb[idx] = skb_new; + + } else { + sp->stats.rx_dropped++; + } + } + + rxdesc->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) | + DMA_RX1_CHAINED); + rxdesc->status = DMA_RX_OWN; + + idx = DSC_NEXT(idx); + } + + sp->cur_rx = idx; + + return rval; +} + + +static void ar2313_tx_int(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + u32 idx; + struct sk_buff *skb; + ar2313_descr_t *txdesc; + unsigned int status=0; + + idx = sp->tx_csm; + + while (idx != sp->tx_prd) { + + txdesc = &sp->tx_ring[idx]; + +#if DEBUG_TX + printk("%s: TXINT: csm=%d idx=%d prd=%d status=%x devcs=%x addr=%08x descr=%x\n", + dev->name, sp->tx_csm, idx, sp->tx_prd, + txdesc->status, txdesc->devcs, txdesc->addr, txdesc->descr); +#endif /* DEBUG */ + + if ((status = txdesc->status) & DMA_TX_OWN) { + /* ar2313 dma still owns descr */ + break; + } + /* done with this descriptor */ + dma_unmap_single(NULL, txdesc->addr, txdesc->devcs & DMA_TX1_BSIZE_MASK, DMA_TO_DEVICE); + txdesc->status = 0; + + if (status & DMA_TX_ERROR){ + sp->stats.tx_errors++; + sp->stats.tx_dropped++; + if(status & DMA_TX_ERR_UNDER) + sp->stats.tx_fifo_errors++; + if(status & DMA_TX_ERR_HB) + sp->stats.tx_heartbeat_errors++; + if(status & (DMA_TX_ERR_LOSS | + DMA_TX_ERR_LINK)) + sp->stats.tx_carrier_errors++; + if (status & (DMA_TX_ERR_LATE| + DMA_TX_ERR_COL | + DMA_TX_ERR_JABBER | + DMA_TX_ERR_DEFER)) + sp->stats.tx_aborted_errors++; + } else { + /* transmit OK */ + sp->stats.tx_packets++; + } + + skb = sp->tx_skb[idx]; + sp->tx_skb[idx] = NULL; + idx = DSC_NEXT(idx); + sp->stats.tx_bytes += skb->len; + dev_kfree_skb_irq(skb); + } + + sp->tx_csm = idx; + + return; +} + + +static void +rx_tasklet_func(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct ar2313_private *sp = dev->priv; + + if (sp->unloading) { + return; + } + + if (ar2313_rx_int(dev)) { + tasklet_hi_schedule(&sp->rx_tasklet); + } + else { + unsigned long flags; + spin_lock_irqsave(&sp->lock, flags); + sp->dma_regs->intr_ena |= DMA_STATUS_RI; + spin_unlock_irqrestore(&sp->lock, flags); + } +} + +static void +rx_schedule(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + + sp->dma_regs->intr_ena &= ~DMA_STATUS_RI; + + tasklet_hi_schedule(&sp->rx_tasklet); +} + +static irqreturn_t ar2313_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct ar2313_private *sp = dev->priv; + unsigned int status, enabled; + + /* clear interrupt */ + /* + * Don't clear RI bit if currently disabled. + */ + status = sp->dma_regs->status; + enabled = sp->dma_regs->intr_ena; + sp->dma_regs->status = status & enabled; + + if (status & DMA_STATUS_NIS) { + /* normal status */ + /* + * Don't schedule rx processing if interrupt + * is already disabled. + */ + if (status & enabled & DMA_STATUS_RI) { + /* receive interrupt */ + rx_schedule(dev); + } + if (status & DMA_STATUS_TI) { + /* transmit interrupt */ + ar2313_tx_int(dev); + } + } + + if (status & DMA_STATUS_AIS) { +#if DEBUG_INT + printk("%s: AIS set %08x & %x\n", __FUNCTION__, + status, (DMA_STATUS_FBE | DMA_STATUS_TPS)); +#endif + /* abnormal status */ + if (status & (DMA_STATUS_FBE | DMA_STATUS_TPS)) { + ar2313_restart(dev); + } + } + return IRQ_HANDLED; +} + + +static int ar2313_open(struct net_device *dev) +{ + struct ar2313_private *sp; + + sp = dev->priv; + + dev->mtu = 1500; + netif_start_queue(dev); + + sp->eth_regs->mac_control |= MAC_CONTROL_RE; + + AR2313_MOD_INC_USE_COUNT; + + return 0; +} + +static void ar2313_halt(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + int j; + + tasklet_disable(&sp->rx_tasklet); + + /* kill the MAC */ + sp->eth_regs->mac_control &= ~(MAC_CONTROL_RE | /* disable Receives */ + MAC_CONTROL_TE); /* disable Transmits */ + /* stop dma */ + sp->dma_regs->control = 0; + sp->dma_regs->bus_mode = DMA_BUS_MODE_SWR; + + /* place phy and MAC in reset */ + *sp->int_regs |= (ar_int_mac_mask | ar_int_phy_mask); + + /* free buffers on tx ring */ + for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { + struct sk_buff *skb; + ar2313_descr_t *txdesc; + + txdesc = &sp->tx_ring[j]; + txdesc->descr = 0; + + skb = sp->tx_skb[j]; + if (skb) { + dev_kfree_skb(skb); + sp->tx_skb[j] = NULL; + } + } +} + +/* + * close should do nothing. Here's why. It's called when + * 'ifconfig bond0 down' is run. If it calls free_irq then + * the irq is gone forever ! When bond0 is made 'up' again, + * the ar2313_open () does not call request_irq (). Worse, + * the call to ar2313_halt() generates a WDOG reset due to + * the write to 'sp->int_regs' and the box reboots. + * Commenting this out is good since it allows the + * system to resume when bond0 is made up again. + */ +static int ar2313_close(struct net_device *dev) +{ +#if 0 + /* + * Disable interrupts + */ + disable_irq(dev->irq); + + /* + * Without (or before) releasing irq and stopping hardware, this + * is an absolute non-sense, by the way. It will be reset instantly + * by the first irq. + */ + netif_stop_queue(dev); + + /* stop the MAC and DMA engines */ + ar2313_halt(dev); + + /* release the interrupt */ + free_irq(dev->irq, dev); + +#endif + AR2313_MOD_DEC_USE_COUNT; + return 0; +} + +static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + ar2313_descr_t *td; + u32 idx; + + idx = sp->tx_prd; + td = &sp->tx_ring[idx]; + + if (td->status & DMA_TX_OWN) { +#if DEBUG_TX + printk("%s: No space left to Tx\n", __FUNCTION__); +#endif + /* free skbuf and lie to the caller that we sent it out */ + sp->stats.tx_dropped++; + dev_kfree_skb(skb); + + /* restart transmitter in case locked */ + sp->dma_regs->xmt_poll = 0; + return 0; + } + + /* Setup the transmit descriptor. */ + td->devcs = ((skb->len << DMA_TX1_BSIZE_SHIFT) | + (DMA_TX1_LS|DMA_TX1_IC|DMA_TX1_CHAINED)); + td->addr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); + td->status = DMA_TX_OWN; + + /* kick transmitter last */ + sp->dma_regs->xmt_poll = 0; + +#if DEBUG_TX + printk("index %d\n", idx); + printk("TX status %08x\n", td->status); + printk("TX devcs %08x\n", td->devcs ); + printk("TX addr %08x\n", td->addr ); + printk("TX descr %08x\n", td->descr ); +#endif + + sp->tx_skb[idx] = skb; + idx = DSC_NEXT(idx); + sp->tx_prd = idx; + + //dev->trans_start = jiffies; + + return 0; +} + +static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct ar2313_private *np = dev->priv; + u32 tmp; + + ecmd->supported = + (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); + + ecmd->port = PORT_TP; + /* only supports internal transceiver */ + ecmd->transceiver = XCVR_INTERNAL; + /* not sure what this is for */ + ecmd->phy_address = 1; + + ecmd->advertising = ADVERTISED_MII; + tmp = armiiread(np->phy, MII_ADVERTISE); + if (tmp & ADVERTISE_10HALF) + ecmd->advertising |= ADVERTISED_10baseT_Half; + if (tmp & ADVERTISE_10FULL) + ecmd->advertising |= ADVERTISED_10baseT_Full; + if (tmp & ADVERTISE_100HALF) + ecmd->advertising |= ADVERTISED_100baseT_Half; + if (tmp & ADVERTISE_100FULL) + ecmd->advertising |= ADVERTISED_100baseT_Full; + + tmp = armiiread(np->phy, MII_BMCR); + if (tmp & BMCR_ANENABLE) { + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->autoneg = AUTONEG_ENABLE; + } else { + ecmd->autoneg = AUTONEG_DISABLE; + } + + if (ecmd->autoneg == AUTONEG_ENABLE) { + tmp = armiiread(np->phy, MII_LPA); + if (tmp & (LPA_100FULL|LPA_10FULL)) { + ecmd->duplex = DUPLEX_FULL; + } else { + ecmd->duplex = DUPLEX_HALF; + } + if (tmp & (LPA_100FULL|LPA_100HALF)) { + ecmd->speed = SPEED_100; + } else { + ecmd->speed = SPEED_10; + } + } else { + if (tmp & BMCR_FULLDPLX) { + ecmd->duplex = DUPLEX_FULL; + } else { + ecmd->duplex = DUPLEX_HALF; + } + if (tmp & BMCR_SPEED100) { + ecmd->speed = SPEED_100; + } else { + ecmd->speed = SPEED_10; + } + } + + /* ignore maxtxpkt, maxrxpkt for now */ + + return 0; +} + +static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct ar2313_private *np = dev->priv; + u32 tmp; + + if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + return -EINVAL; + if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) + return -EINVAL; + if (ecmd->port != PORT_TP) + return -EINVAL; + if (ecmd->transceiver != XCVR_INTERNAL) + return -EINVAL; + if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) + return -EINVAL; + /* ignore phy_address, maxtxpkt, maxrxpkt for now */ + + /* WHEW! now lets bang some bits */ + + tmp = armiiread(np->phy, MII_BMCR); + if (ecmd->autoneg == AUTONEG_ENABLE) { + /* turn on autonegotiation */ + tmp |= BMCR_ANENABLE; + printk("%s: Enabling auto-neg\n", dev->name); + } else { + /* turn off auto negotiation, set speed and duplexity */ + tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); + if (ecmd->speed == SPEED_100) + tmp |= BMCR_SPEED100; + if (ecmd->duplex == DUPLEX_FULL) + tmp |= BMCR_FULLDPLX; + printk("%s: Hard coding %d/%s\n", dev->name, + (ecmd->speed == SPEED_100)? 100:10, + (ecmd->duplex == DUPLEX_FULL)? "full":"half"); + } + armiiwrite(np->phy, MII_BMCR, tmp); + np->phyData = 0; + return 0; +} + +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct ar2313_private *np = dev->priv; + u32 cmd; + + if (get_user(cmd, (u32 *)useraddr)) + return -EFAULT; + + switch (cmd) { + /* get settings */ + case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + spin_lock_irq(&np->lock); + netdev_get_ecmd(dev, &ecmd); + spin_unlock_irq(&np->lock); + if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } + /* set settings */ + case ETHTOOL_SSET: { + struct ethtool_cmd ecmd; + int r; + if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) + return -EFAULT; + spin_lock_irq(&np->lock); + r = netdev_set_ecmd(dev, &ecmd); + spin_unlock_irq(&np->lock); + return r; + } + /* restart autonegotiation */ + case ETHTOOL_NWAY_RST: { + int tmp; + int r = -EINVAL; + /* if autoneg is off, it's an error */ + tmp = armiiread(np->phy, MII_BMCR); + if (tmp & BMCR_ANENABLE) { + tmp |= (BMCR_ANRESTART); + armiiwrite(np->phy, MII_BMCR, tmp); + r = 0; + } + return r; + } + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = (armiiread(np->phy, MII_BMSR)&BMSR_LSTATUS) ? 1:0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + +static int ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + + switch (cmd) { + case SIOCDEVPRIVATE: { + struct ar2313_cmd scmd; + + if (copy_from_user(&scmd, ifr->ifr_data, sizeof(scmd))) + return -EFAULT; + +#if DEBUG + printk("%s: ioctl devprivate c=%d a=%x l=%d m=%d d=%x,%x\n", + dev->name, scmd.cmd, + scmd.address, scmd.length, + scmd.mailbox, scmd.data[0], scmd.data[1]); +#endif /* DEBUG */ + + switch (scmd.cmd) { + case AR2313_READ_DATA: + if(scmd.length==4){ + scmd.data[0] = *((u32*)scmd.address); + } else if(scmd.length==2) { + scmd.data[0] = *((u16*)scmd.address); + } else if (scmd.length==1) { + scmd.data[0] = *((u8*)scmd.address); + } else { + return -EOPNOTSUPP; + } + if(copy_to_user(ifr->ifr_data, &scmd, sizeof(scmd))) + return -EFAULT; + break; + + case AR2313_WRITE_DATA: + if(scmd.length==4){ + *((u32*)scmd.address) = scmd.data[0]; + } else if(scmd.length==2) { + *((u16*)scmd.address) = scmd.data[0]; + } else if (scmd.length==1) { + *((u8*)scmd.address) = scmd.data[0]; + } else { + return -EOPNOTSUPP; + } + break; + + case AR2313_GET_VERSION: + // SAMEER: sprintf((char*) &scmd, "%s", ARUBA_VERSION); + if(copy_to_user(ifr->ifr_data, &scmd, sizeof(scmd))) + return -EFAULT; + break; + + default: + return -EOPNOTSUPP; + } + return 0; + } + + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data); + + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + data->phy_id = 1; + /* Fall Through */ + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = armiiread(data->phy_id & 0x1f, + data->reg_num & 0x1f); + return 0; + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + armiiwrite(data->phy_id & 0x1f, + data->reg_num & 0x1f, data->val_in); + return 0; + + case SIOCSIFHWADDR: + if (copy_from_user(dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr))) + return -EFAULT; + return 0; + + case SIOCGIFHWADDR: + if (copy_to_user(ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr))) + return -EFAULT; + return 0; + + default: + break; + } + + return -EOPNOTSUPP; +} + +static struct net_device_stats *ar2313_get_stats(struct net_device *dev) +{ + struct ar2313_private *sp = dev->priv; + return &sp->stats; +} + +static short +armiiread(short phy, short reg) +{ + volatile ETHERNET_STRUCT * ethernet; + + ethernet = (volatile ETHERNET_STRUCT *)(ar_eth_base); /* always MAC 0 */ + ethernet->mii_addr = ((reg << MII_ADDR_REG_SHIFT) | + (phy << MII_ADDR_PHY_SHIFT)); + while (ethernet->mii_addr & MII_ADDR_BUSY); + return (ethernet->mii_data >> MII_DATA_SHIFT); +} + +static void +armiiwrite(short phy, short reg, short data) +{ + volatile ETHERNET_STRUCT * ethernet; + + ethernet = (volatile ETHERNET_STRUCT *)(ar_eth_base); /* always MAC 0 */ + while (ethernet->mii_addr & MII_ADDR_BUSY); + ethernet->mii_data = data << MII_DATA_SHIFT; + ethernet->mii_addr = ((reg << MII_ADDR_REG_SHIFT) | + (phy << MII_ADDR_PHY_SHIFT) | + MII_ADDR_WRITE); +} + diff --git a/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313.h b/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313.h new file mode 100644 index 000000000..3606bd7a2 --- /dev/null +++ b/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313.h @@ -0,0 +1,191 @@ +#ifndef _AR2313_H_ +#define _AR2313_H_ + +#include +#include +#include "platform.h" + +extern unsigned long mips_machtype; + +#undef ETHERNET_BASE +#define ETHERNET_BASE ar_eth_base +#define ETHERNET_SIZE 0x00100000 +#define ETHERNET_MACS 2 + +#undef DMA_BASE +#define DMA_BASE ar_dma_base +#define DMA_SIZE 0x00100000 + + +/* + * probe link timer - 5 secs + */ +#define LINK_TIMER (5*HZ) + +/* + * Interrupt register base address + */ +#define INTERRUPT_BASE PHYS_TO_K1(ar_int_base) + +/* + * Reset Register + */ +#define AR531X_RESET (AR531X_RESETTMR + 0x0020) +#define RESET_SYSTEM 0x00000001 /* cold reset full system */ +#define RESET_PROC 0x00000002 /* cold reset MIPS core */ +#define RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */ +#define RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */ +#define RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */ +#define RESET_ENET0 0x00000020 /* cold reset ENET0 mac */ +#define RESET_ENET1 0x00000040 /* cold reset ENET1 mac */ + +#define IS_DMA_TX_INT(X) (((X) & (DMA_STATUS_TI)) != 0) +#define IS_DMA_RX_INT(X) (((X) & (DMA_STATUS_RI)) != 0) +#define IS_DRIVER_OWNED(X) (((X) & (DMA_TX_OWN)) == 0) + +#ifndef K1_TO_PHYS +// hack +#define K1_TO_PHYS(x) (((unsigned int)(x)) & 0x1FFFFFFF) /* kseg1 to physical */ +#endif + +#ifndef PHYS_TO_K1 +// hack +#define PHYS_TO_K1(x) (((unsigned int)(x)) | 0xA0000000) /* physical to kseg1 */ +#endif + +#define AR2313_TX_TIMEOUT (HZ/4) + +/* + * Rings + */ +#define DSC_RING_ENTRIES_SIZE (AR2313_DESCR_ENTRIES * sizeof(struct desc)) +#define DSC_NEXT(idx) ((idx + 1) & (AR2313_DESCR_ENTRIES - 1)) + +static inline int tx_space (u32 csm, u32 prd) +{ + return (csm - prd - 1) & (AR2313_DESCR_ENTRIES - 1); +} + +#if MAX_SKB_FRAGS +#define TX_RESERVED (MAX_SKB_FRAGS+1) /* +1 for message header */ +#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED) +#else +#define tx_ring_full 0 +#endif + +#define AR2313_MBGET 2 +#define AR2313_MBSET 3 +#define AR2313_PCI_RECONFIG 4 +#define AR2313_PCI_DUMP 5 +#define AR2313_TEST_PANIC 6 +#define AR2313_TEST_NULLPTR 7 +#define AR2313_READ_DATA 8 +#define AR2313_WRITE_DATA 9 +#define AR2313_GET_VERSION 10 +#define AR2313_TEST_HANG 11 +#define AR2313_SYNC 12 + + +struct ar2313_cmd { + u32 cmd; + u32 address; /* virtual address of image */ + u32 length; /* size of image to download */ + u32 mailbox; /* mailbox to get/set */ + u32 data[2]; /* contents of mailbox to read/write */ +}; + + +/* + * Struct private for the Sibyte. + * + * Elements are grouped so variables used by the tx handling goes + * together, and will go into the same cache lines etc. in order to + * avoid cache line contention between the rx and tx handling on SMP. + * + * Frequently accessed variables are put at the beginning of the + * struct to help the compiler generate better/shorter code. + */ +struct ar2313_private +{ + struct net_device *dev; + int version; + u32 mb[2]; + + volatile ETHERNET_STRUCT *eth_regs; + volatile DMA *dma_regs; + volatile u32 *int_regs; + + spinlock_t lock; /* Serialise access to device */ + + /* + * RX and TX descriptors, must be adjacent + */ + ar2313_descr_t *rx_ring; + ar2313_descr_t *tx_ring; + + + struct sk_buff **rx_skb; + struct sk_buff **tx_skb; + + /* + * RX elements + */ + u32 rx_skbprd; + u32 cur_rx; + + /* + * TX elements + */ + u32 tx_prd; + u32 tx_csm; + + /* + * Misc elements + */ + int board_idx; + char name[48]; + struct net_device_stats stats; + struct { + u32 address; + u32 length; + char *mapping; + } desc; + + + struct timer_list link_timer; + unsigned short phy; /* merlot phy = 1, samsung phy = 0x1f */ + unsigned short mac; + unsigned short link; /* 0 - link down, 1 - link up */ + u16 phyData; + + struct tasklet_struct rx_tasklet; + int unloading; +}; + + +/* + * Prototypes + */ +static int ar2313_init(struct net_device *dev); +#ifdef TX_TIMEOUT +static void ar2313_tx_timeout(struct net_device *dev); +#endif +#if 0 +static void ar2313_multicast_list(struct net_device *dev); +#endif +static int ar2313_restart(struct net_device *dev); +#if DEBUG +static void ar2313_dump_regs(struct net_device *dev); +#endif +static void ar2313_load_rx_ring(struct net_device *dev, int bufs); +static irqreturn_t ar2313_interrupt(int irq, void *dev_id); +static int ar2313_open(struct net_device *dev); +static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int ar2313_close(struct net_device *dev); +static int ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static void ar2313_init_cleanup(struct net_device *dev); +static int ar2313_setup_timer(struct net_device *dev); +static void ar2313_link_timer_fn(unsigned long data); +static void ar2313_check_link(struct net_device *dev); +static struct net_device_stats *ar2313_get_stats(struct net_device *dev); +#endif /* _AR2313_H_ */ diff --git a/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313_msg.h b/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313_msg.h new file mode 100644 index 000000000..d10d9eade --- /dev/null +++ b/target/linux/atheros-2.6/files/drivers/net/ar2313/ar2313_msg.h @@ -0,0 +1,17 @@ +#ifndef _AR2313_MSG_H_ +#define _AR2313_MSG_H_ + +#define AR2313_MTU 1692 +#define AR2313_PRIOS 1 +#define AR2313_QUEUES (2*AR2313_PRIOS) + +#define AR2313_DESCR_ENTRIES 64 + +typedef struct { + volatile unsigned int status; // OWN, Device control and status. + volatile unsigned int devcs; // pkt Control bits + Length + volatile unsigned int addr; // Current Address. + volatile unsigned int descr; // Next descriptor in chain. +} ar2313_descr_t; + +#endif /* _AR2313_MSG_H_ */ diff --git a/target/linux/atheros-2.6/files/drivers/net/ar2313/dma.h b/target/linux/atheros-2.6/files/drivers/net/ar2313/dma.h new file mode 100644 index 000000000..2f8c06af5 --- /dev/null +++ b/target/linux/atheros-2.6/files/drivers/net/ar2313/dma.h @@ -0,0 +1,135 @@ +#ifndef __ARUBA_DMA_H__ +#define __ARUBA_DMA_H__ + +/******************************************************************************* + * + * Copyright 2002 Integrated Device Technology, Inc. + * All rights reserved. + * + * DMA register definition. + * + * File : $Id: dma.h,v 1.3 2002/06/06 18:34:03 astichte Exp $ + * + * Author : ryan.holmQVist@idt.com + * Date : 20011005 + * Update : + * $Log: dma.h,v $ + * Revision 1.3 2002/06/06 18:34:03 astichte + * Added XXX_PhysicalAddress and XXX_VirtualAddress + * + * Revision 1.2 2002/06/05 18:30:46 astichte + * Removed IDTField + * + * Revision 1.1 2002/05/29 17:33:21 sysarch + * jba File moved from vcode/include/idt/acacia + * + * + ******************************************************************************/ + +#define AR_BIT(x) (1 << (x)) +#define DMA_RX_ERR_CRC AR_BIT(1) +#define DMA_RX_ERR_DRIB AR_BIT(2) +#define DMA_RX_ERR_MII AR_BIT(3) +#define DMA_RX_EV2 AR_BIT(5) +#define DMA_RX_ERR_COL AR_BIT(6) +#define DMA_RX_LONG AR_BIT(7) +#define DMA_RX_LS AR_BIT(8) /* last descriptor */ +#define DMA_RX_FS AR_BIT(9) /* first descriptor */ +#define DMA_RX_MF AR_BIT(10) /* multicast frame */ +#define DMA_RX_ERR_RUNT AR_BIT(11) /* runt frame */ +#define DMA_RX_ERR_LENGTH AR_BIT(12) /* length error */ +#define DMA_RX_ERR_DESC AR_BIT(14) /* descriptor error */ +#define DMA_RX_ERROR AR_BIT(15) /* error summary */ +#define DMA_RX_LEN_MASK 0x3fff0000 +#define DMA_RX_LEN_SHIFT 16 +#define DMA_RX_FILT AR_BIT(30) +#define DMA_RX_OWN AR_BIT(31) /* desc owned by DMA controller */ + +#define DMA_RX1_BSIZE_MASK 0x000007ff +#define DMA_RX1_BSIZE_SHIFT 0 +#define DMA_RX1_CHAINED AR_BIT(24) +#define DMA_RX1_RER AR_BIT(25) + +#define DMA_TX_ERR_UNDER AR_BIT(1) /* underflow error */ +#define DMA_TX_ERR_DEFER AR_BIT(2) /* excessive deferral */ +#define DMA_TX_COL_MASK 0x78 +#define DMA_TX_COL_SHIFT 3 +#define DMA_TX_ERR_HB AR_BIT(7) /* hearbeat failure */ +#define DMA_TX_ERR_COL AR_BIT(8) /* excessive collisions */ +#define DMA_TX_ERR_LATE AR_BIT(9) /* late collision */ +#define DMA_TX_ERR_LINK AR_BIT(10) /* no carrier */ +#define DMA_TX_ERR_LOSS AR_BIT(11) /* loss of carrier */ +#define DMA_TX_ERR_JABBER AR_BIT(14) /* transmit jabber timeout */ +#define DMA_TX_ERROR AR_BIT(15) /* frame aborted */ +#define DMA_TX_OWN AR_BIT(31) /* descr owned by DMA controller */ + +#define DMA_TX1_BSIZE_MASK 0x000007ff +#define DMA_TX1_BSIZE_SHIFT 0 +#define DMA_TX1_CHAINED AR_BIT(24) /* chained descriptors */ +#define DMA_TX1_TER AR_BIT(25) /* transmit end of ring */ +#define DMA_TX1_FS AR_BIT(29) /* first segment */ +#define DMA_TX1_LS AR_BIT(30) /* last segment */ +#define DMA_TX1_IC AR_BIT(31) /* interrupt on completion */ + +#define RCVPKT_LENGTH(X) (X >> 16) /* Received pkt Length */ + +#define MAC_CONTROL_RE AR_BIT(2) /* receive enable */ +#define MAC_CONTROL_TE AR_BIT(3) /* transmit enable */ +#define MAC_CONTROL_DC AR_BIT(5) /* Deferral check*/ +#define MAC_CONTROL_ASTP AR_BIT(8) /* Auto pad strip */ +#define MAC_CONTROL_DRTY AR_BIT(10) /* Disable retry */ +#define MAC_CONTROL_DBF AR_BIT(11) /* Disable bcast frames */ +#define MAC_CONTROL_LCC AR_BIT(12) /* late collision ctrl */ +#define MAC_CONTROL_HP AR_BIT(13) /* Hash Perfect filtering */ +#define MAC_CONTROL_HASH AR_BIT(14) /* Unicast hash filtering */ +#define MAC_CONTROL_HO AR_BIT(15) /* Hash only filtering */ +#define MAC_CONTROL_PB AR_BIT(16) /* Pass Bad frames */ +#define MAC_CONTROL_IF AR_BIT(17) /* Inverse filtering */ +#define MAC_CONTROL_PR AR_BIT(18) /* promiscuous mode (valid frames only) */ +#define MAC_CONTROL_PM AR_BIT(19) /* pass multicast */ +#define MAC_CONTROL_F AR_BIT(20) /* full-duplex */ +#define MAC_CONTROL_DRO AR_BIT(23) /* Disable Receive Own */ +#define MAC_CONTROL_HBD AR_BIT(28) /* heart-beat disabled (MUST BE SET) */ +#define MAC_CONTROL_BLE AR_BIT(30) /* big endian mode */ +#define MAC_CONTROL_RA AR_BIT(31) /* receive all (valid and invalid frames) */ + +#define MII_ADDR_BUSY AR_BIT(0) +#define MII_ADDR_WRITE AR_BIT(1) +#define MII_ADDR_REG_SHIFT 6 +#define MII_ADDR_PHY_SHIFT 11 +#define MII_DATA_SHIFT 0 + +#define FLOW_CONTROL_FCE AR_BIT(1) + +#define DMA_BUS_MODE_SWR AR_BIT(0) /* software reset */ +#define DMA_BUS_MODE_BLE AR_BIT(7) /* big endian mode */ +#define DMA_BUS_MODE_PBL_SHIFT 8 /* programmable burst length 32 */ +#define DMA_BUS_MODE_DBO AR_BIT(20) /* big-endian descriptors */ + +#define DMA_STATUS_TI AR_BIT(0) /* transmit interrupt */ +#define DMA_STATUS_TPS AR_BIT(1) /* transmit process stopped */ +#define DMA_STATUS_TU AR_BIT(2) /* transmit buffer unavailable */ +#define DMA_STATUS_TJT AR_BIT(3) /* transmit buffer timeout */ +#define DMA_STATUS_UNF AR_BIT(5) /* transmit underflow */ +#define DMA_STATUS_RI AR_BIT(6) /* receive interrupt */ +#define DMA_STATUS_RU AR_BIT(7) /* receive buffer unavailable */ +#define DMA_STATUS_RPS AR_BIT(8) /* receive process stopped */ +#define DMA_STATUS_ETI AR_BIT(10) /* early transmit interrupt */ +#define DMA_STATUS_FBE AR_BIT(13) /* fatal bus interrupt */ +#define DMA_STATUS_ERI AR_BIT(14) /* early receive interrupt */ +#define DMA_STATUS_AIS AR_BIT(15) /* abnormal interrupt summary */ +#define DMA_STATUS_NIS AR_BIT(16) /* normal interrupt summary */ +#define DMA_STATUS_RS_SHIFT 17 /* receive process state */ +#define DMA_STATUS_TS_SHIFT 20 /* transmit process state */ +#define DMA_STATUS_EB_SHIFT 23 /* error bits */ + +#define DMA_CONTROL_SR AR_BIT(1) /* start receive */ +#define DMA_CONTROL_ST AR_BIT(13) /* start transmit */ +#define DMA_CONTROL_SF AR_BIT(21) /* store and forward */ + +#endif // __ARUBA_DMA_H__ + + + + + diff --git a/target/linux/atheros-2.6/files/drivers/net/ar2313/platform.h b/target/linux/atheros-2.6/files/drivers/net/ar2313/platform.h new file mode 100644 index 000000000..67d8f5c08 --- /dev/null +++ b/target/linux/atheros-2.6/files/drivers/net/ar2313/platform.h @@ -0,0 +1,128 @@ +/******************************************************************************** + Title: $Source: platform.h,v $ + + Author: Dan Steinberg + Copyright Integrated Device Technology 2001 + + Purpose: AR2313 Register/Bit Definitions + + Update: + $Log: platform.h,v $ + + Notes: See Merlot architecture spec for complete details. Note, all + addresses are virtual addresses in kseg1 (Uncached, Unmapped). + +********************************************************************************/ + +#ifndef PLATFORM_H +#define PLATFORM_H + +#define BIT(x) (1 << (x)) + +#define RESET_BASE 0xBC003020 +#define RESET_VALUE 0x00000001 + +/******************************************************************** + * Device controller + ********************************************************************/ +typedef struct { + volatile unsigned int flash0; +} DEVICE; + +#define device (*((volatile DEVICE *) DEV_CTL_BASE)) + +// DDRC register +#define DEV_WP (1<<26) + +/******************************************************************** + * DDR controller + ********************************************************************/ +typedef struct { + volatile unsigned int ddrc0; + volatile unsigned int ddrc1; + volatile unsigned int ddrrefresh; +} DDR; + +#define ddr (*((volatile DDR *) DDR_BASE)) + +// DDRC register +#define DDRC_CS(i) ((i&0x3)<<0) +#define DDRC_WE (1<<2) + +/******************************************************************** + * Ethernet interfaces + ********************************************************************/ +#define ETHERNET_BASE 0xB8200000 + +// +// New Combo structure for Both Eth0 AND eth1 +// +typedef struct { + volatile unsigned int mac_control; /* 0x00 */ + volatile unsigned int mac_addr[2]; /* 0x04 - 0x08*/ + volatile unsigned int mcast_table[2]; /* 0x0c - 0x10 */ + volatile unsigned int mii_addr; /* 0x14 */ + volatile unsigned int mii_data; /* 0x18 */ + volatile unsigned int flow_control; /* 0x1c */ + volatile unsigned int vlan_tag; /* 0x20 */ + volatile unsigned int pad[7]; /* 0x24 - 0x3c */ + volatile unsigned int ucast_table[8]; /* 0x40-0x5c */ + +} ETHERNET_STRUCT; + +/******************************************************************** + * Interrupt controller + ********************************************************************/ + +typedef struct { + volatile unsigned int wdog_control; /* 0x08 */ + volatile unsigned int wdog_timer; /* 0x0c */ + volatile unsigned int misc_status; /* 0x10 */ + volatile unsigned int misc_mask; /* 0x14 */ + volatile unsigned int global_status; /* 0x18 */ + volatile unsigned int reserved; /* 0x1c */ + volatile unsigned int reset_control; /* 0x20 */ +} INTERRUPT; + +#define interrupt (*((volatile INTERRUPT *) INTERRUPT_BASE)) + +#define INTERRUPT_MISC_TIMER BIT(0) +#define INTERRUPT_MISC_AHBPROC BIT(1) +#define INTERRUPT_MISC_AHBDMA BIT(2) +#define INTERRUPT_MISC_GPIO BIT(3) +#define INTERRUPT_MISC_UART BIT(4) +#define INTERRUPT_MISC_UARTDMA BIT(5) +#define INTERRUPT_MISC_WATCHDOG BIT(6) +#define INTERRUPT_MISC_LOCAL BIT(7) + +#define INTERRUPT_GLOBAL_ETH BIT(2) +#define INTERRUPT_GLOBAL_WLAN BIT(3) +#define INTERRUPT_GLOBAL_MISC BIT(4) +#define INTERRUPT_GLOBAL_ITIMER BIT(5) + +/******************************************************************** + * DMA controller + ********************************************************************/ +#define DMA_BASE 0xB8201000 + +typedef struct { + volatile unsigned int bus_mode; /* 0x00 (CSR0) */ + volatile unsigned int xmt_poll; /* 0x04 (CSR1) */ + volatile unsigned int rcv_poll; /* 0x08 (CSR2) */ + volatile unsigned int rcv_base; /* 0x0c (CSR3) */ + volatile unsigned int xmt_base; /* 0x10 (CSR4) */ + volatile unsigned int status; /* 0x14 (CSR5) */ + volatile unsigned int control; /* 0x18 (CSR6) */ + volatile unsigned int intr_ena; /* 0x1c (CSR7) */ + volatile unsigned int rcv_missed; /* 0x20 (CSR8) */ + volatile unsigned int reserved[11]; /* 0x24-0x4c (CSR9-19) */ + volatile unsigned int cur_tx_buf_addr; /* 0x50 (CSR20) */ + volatile unsigned int cur_rx_buf_addr; /* 0x50 (CSR21) */ +} DMA; + +#define dma (*((volatile DMA *) DMA_BASE)) + +// macro to convert from virtual to physical address +#define phys_addr(x) (x & 0x1fffffff) + +#endif /* PLATFORM_H */ diff --git a/target/linux/atheros-2.6/files/include/asm-mips/mach-atheros/ar531x_platform.h b/target/linux/atheros-2.6/files/include/asm-mips/mach-atheros/ar531x_platform.h new file mode 100644 index 000000000..377b31a26 --- /dev/null +++ b/target/linux/atheros-2.6/files/include/asm-mips/mach-atheros/ar531x_platform.h @@ -0,0 +1,26 @@ +#ifndef __AR531X_PLATFORM_H +#define __AR531X_PLATFORM_H + +/* + * Board support data. The driver is required to locate + * and fill-in this information before passing a reference to + * this structure as the HAL_BUS_TAG parameter supplied to + * ath_hal_attach. + */ +struct ar531x_config { + const char *board; /* board config data */ + const char *radio; /* radio config data */ + int unit; /* unit number [0, 1] */ + u32 tag; /* used as devid for now */ +}; + +struct ar531x_eth { + int phy; + int mac; + u32 reset_base; + u32 reset_mac; + u32 reset_phy; + char *board_config; +}; + +#endif /* __AR531X_PLATFORM_H */ diff --git a/target/linux/atheros-2.6/patches/100-board.patch b/target/linux/atheros-2.6/patches/100-board.patch index 040a28faf..a137d15d2 100644 --- a/target/linux/atheros-2.6/patches/100-board.patch +++ b/target/linux/atheros-2.6/patches/100-board.patch @@ -1,1926 +1,63 @@ -diff -urN linux.old/arch/mips/ar531x/ar531x.h linux.dev/arch/mips/ar531x/ar531x.h ---- linux.old/arch/mips/ar531x/ar531x.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/arch/mips/ar531x/ar531x.h 2006-12-16 03:51:47.000000000 +0100 -@@ -0,0 +1,734 @@ -+/* -+ * 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 -+ * Copyright (C) 2006 Felix Fietkau -+ */ -+ -+#ifndef AR531X_H -+#define AR531X_H 1 -+ -+/* -+ * Address map -+ */ -+#define AR5315_SDRAM0 0x00000000 /* DRAM */ -+#define AR5315_SPI_READ 0x08000000 /* SPI FLASH */ -+#define AR5315_WLAN0 0xB0000000 /* Wireless MMR */ -+#define AR5315_PCI 0xB0100000 /* PCI MMR */ -+#define AR5315_SDRAMCTL 0xB0300000 /* SDRAM MMR */ -+#define AR5315_LOCAL 0xB0400000 /* LOCAL BUS MMR */ -+#define AR5315_ENET0 0xB0500000 /* ETHERNET MMR */ -+#define AR5315_DSLBASE 0xB1000000 /* RESET CONTROL MMR */ -+#define AR5315_UART0 0xB1100003 /* UART MMR */ -+#define AR5315_SPI 0xB1300000 /* SPI FLASH MMR */ -+#define AR5315_FLASHBT 0xBfc00000 /* ro boot alias to FLASH */ -+#define AR5315_RAM1 0x40000000 /* ram alias */ -+#define AR5315_PCIEXT 0x80000000 /* pci external */ -+#define AR5315_RAM2 0xc0000000 /* ram alias */ -+#define AR5315_RAM3 0xe0000000 /* ram alias */ -+ -+/* -+ * Reset Register -+ */ -+#define AR5315_COLD_RESET (AR5315_DSLBASE + 0x0000) -+ -+/* Cold Reset */ -+#define RESET_COLD_AHB 0x00000001 -+#define RESET_COLD_APB 0x00000002 -+#define RESET_COLD_CPU 0x00000004 -+#define RESET_COLD_CPUWARM 0x00000008 -+#define RESET_SYSTEM (RESET_COLD_CPU | RESET_COLD_APB | RESET_COLD_AHB) /* full system */ -+ -+#define AR5317_RESET_SYSTEM 0x00000010 -+ -+/* Warm Reset */ -+ -+#define AR5315_RESET (AR5315_DSLBASE + 0x0004) -+ -+#define RESET_WARM_WLAN0_MAC 0x00000001 /* warm reset WLAN0 MAC */ -+#define RESET_WARM_WLAN0_BB 0x00000002 /* warm reset WLAN0 BaseBand */ -+#define RESET_MPEGTS_RSVD 0x00000004 /* warm reset MPEG-TS */ -+#define RESET_PCIDMA 0x00000008 /* warm reset PCI ahb/dma */ -+#define RESET_MEMCTL 0x00000010 /* warm reset memory controller */ -+#define RESET_LOCAL 0x00000020 /* warm reset local bus */ -+#define RESET_I2C_RSVD 0x00000040 /* warm reset I2C bus */ -+#define RESET_SPI 0x00000080 /* warm reset SPI interface */ -+#define RESET_UART0 0x00000100 /* warm reset UART0 */ -+#define RESET_IR_RSVD 0x00000200 /* warm reset IR interface */ -+#define RESET_EPHY0 0x00000400 /* cold reset ENET0 phy */ -+#define RESET_ENET0 0x00000800 /* cold reset ENET0 mac */ -+ -+/* -+ * AHB master arbitration control -+ */ -+#define AR5315_AHB_ARB_CTL (AR5315_DSLBASE + 0x0008) -+ -+#define ARB_CPU 0x00000001 /* CPU, default */ -+#define ARB_WLAN 0x00000002 /* WLAN */ -+#define ARB_MPEGTS_RSVD 0x00000004 /* MPEG-TS */ -+#define ARB_LOCAL 0x00000008 /* LOCAL */ -+#define ARB_PCI 0x00000010 /* PCI */ -+#define ARB_ETHERNET 0x00000020 /* Ethernet */ -+#define ARB_RETRY 0x00000100 /* retry policy, debug only */ -+ -+/* -+ * Config Register -+ */ -+#define AR5315_ENDIAN_CTL (AR5315_DSLBASE + 0x000c) -+ -+#define CONFIG_AHB 0x00000001 /* EC - AHB bridge endianess */ -+#define CONFIG_WLAN 0x00000002 /* WLAN byteswap */ -+#define CONFIG_MPEGTS_RSVD 0x00000004 /* MPEG-TS byteswap */ -+#define CONFIG_PCI 0x00000008 /* PCI byteswap */ -+#define CONFIG_MEMCTL 0x00000010 /* Memory controller endianess */ -+#define CONFIG_LOCAL 0x00000020 /* Local bus byteswap */ -+#define CONFIG_ETHERNET 0x00000040 /* Ethernet byteswap */ -+ -+#define CONFIG_MERGE 0x00000200 /* CPU write buffer merge */ -+#define CONFIG_CPU 0x00000400 /* CPU big endian */ -+#define CONFIG_PCIAHB 0x00000800 -+#define CONFIG_PCIAHB_BRIDGE 0x00001000 -+#define CONFIG_SPI 0x00008000 /* SPI byteswap */ -+#define CONFIG_CPU_DRAM 0x00010000 -+#define CONFIG_CPU_PCI 0x00020000 -+#define CONFIG_CPU_MMR 0x00040000 -+#define CONFIG_BIG 0x00000400 -+ -+ -+/* -+ * NMI control -+ */ -+#define AR5315_NMI_CTL (AR5315_DSLBASE + 0x0010) -+ -+#define NMI_EN 1 -+ -+/* -+ * Revision Register - Initial value is 0x3010 (WMAC 3.0, AR531X 1.0). -+ */ -+#define AR5315_SREV (AR5315_DSLBASE + 0x0014) -+ -+#define REV_MAJ 0x00f0 -+#define REV_MAJ_S 4 -+#define REV_MIN 0x000f -+#define REV_MIN_S 0 -+#define REV_CHIP (REV_MAJ|REV_MIN) -+ -+/* -+ * Interface Enable -+ */ -+#define AR5315_IF_CTL (AR5315_DSLBASE + 0x0018) -+ -+#define IF_MASK 0x00000007 -+#define IF_DISABLED 0 -+#define IF_PCI 1 -+#define IF_TS_LOCAL 2 -+#define IF_ALL 3 /* only for emulation with separate pins */ -+#define IF_LOCAL_HOST 0x00000008 -+#define IF_PCI_HOST 0x00000010 -+#define IF_PCI_INTR 0x00000020 -+#define IF_PCI_CLK_MASK 0x00030000 -+#define IF_PCI_CLK_INPUT 0 -+#define IF_PCI_CLK_OUTPUT_LOW 1 -+#define IF_PCI_CLK_OUTPUT_CLK 2 -+#define IF_PCI_CLK_OUTPUT_HIGH 3 -+#define IF_PCI_CLK_SHIFT 16 -+ -+ -+/* Major revision numbers, bits 7..4 of Revision ID register */ -+#define REV_MAJ_AR5311 0x01 -+#define REV_MAJ_AR5312 0x04 -+#define REV_MAJ_AR5315 0x0B -+ -+/* -+ * APB Interrupt control -+ */ -+ -+#define AR5315_ISR (AR5315_DSLBASE + 0x0020) -+#define AR5315_IMR (AR5315_DSLBASE + 0x0024) -+#define AR5315_GISR (AR5315_DSLBASE + 0x0028) -+ -+#define ISR_UART0 0x0001 /* high speed UART */ -+#define ISR_I2C_RSVD 0x0002 /* I2C bus */ -+#define ISR_SPI 0x0004 /* SPI bus */ -+#define ISR_AHB 0x0008 /* AHB error */ -+#define ISR_APB 0x0010 /* APB error */ -+#define ISR_TIMER 0x0020 /* timer */ -+#define ISR_GPIO 0x0040 /* GPIO */ -+#define ISR_WD 0x0080 /* watchdog */ -+#define ISR_IR_RSVD 0x0100 /* IR */ -+ -+#define IMR_UART0 ISR_UART0 -+#define IMR_I2C_RSVD ISR_I2C_RSVD -+#define IMR_SPI ISR_SPI -+#define IMR_AHB ISR_AHB -+#define IMR_APB ISR_APB -+#define IMR_TIMER ISR_TIMER -+#define IMR_GPIO ISR_GPIO -+#define IMR_WD ISR_WD -+#define IMR_IR_RSVD ISR_IR_RSVD -+ -+#define GISR_MISC 0x0001 -+#define GISR_WLAN0 0x0002 -+#define GISR_MPEGTS_RSVD 0x0004 -+#define GISR_LOCALPCI 0x0008 -+#define GISR_WMACPOLL 0x0010 -+#define GISR_TIMER 0x0020 -+#define GISR_ETHERNET 0x0040 -+ -+/* -+ * Interrupt routing from IO to the processor IP bits -+ * Define our inter mask and level -+ */ -+#define AR5315_INTR_MISCIO SR_IBIT3 -+#define AR5315_INTR_WLAN0 SR_IBIT4 -+#define AR5315_INTR_ENET0 SR_IBIT5 -+#define AR5315_INTR_LOCALPCI SR_IBIT6 -+#define AR5315_INTR_WMACPOLL SR_IBIT7 -+#define AR5315_INTR_COMPARE SR_IBIT8 -+ -+/* -+ * Timers -+ */ -+#define AR5315_TIMER (AR5315_DSLBASE + 0x0030) -+#define AR5315_RELOAD (AR5315_DSLBASE + 0x0034) -+#define AR5315_WD (AR5315_DSLBASE + 0x0038) -+#define AR5315_WDC (AR5315_DSLBASE + 0x003c) -+ -+#define WDC_RESET 0x00000002 /* reset on watchdog */ -+#define WDC_NMI 0x00000001 /* NMI on watchdog */ -+#define WDC_IGNORE_EXPIRATION 0x00000000 -+ -+/* -+ * Interface Debug -+ */ -+#define AR531X_FLASHDBG (AR531X_RESETTMR + 0x0040) -+#define AR531X_MIIDBG (AR531X_RESETTMR + 0x0044) -+ -+ -+/* -+ * CPU Performance Counters -+ */ -+#define AR5315_PERFCNT0 (AR5315_DSLBASE + 0x0048) -+#define AR5315_PERFCNT1 (AR5315_DSLBASE + 0x004c) -+ -+#define PERF_DATAHIT 0x0001 /* Count Data Cache Hits */ -+#define PERF_DATAMISS 0x0002 /* Count Data Cache Misses */ -+#define PERF_INSTHIT 0x0004 /* Count Instruction Cache Hits */ -+#define PERF_INSTMISS 0x0008 /* Count Instruction Cache Misses */ -+#define PERF_ACTIVE 0x0010 /* Count Active Processor Cycles */ -+#define PERF_WBHIT 0x0020 /* Count CPU Write Buffer Hits */ -+#define PERF_WBMISS 0x0040 /* Count CPU Write Buffer Misses */ -+ -+#define PERF_EB_ARDY 0x0001 /* Count EB_ARdy signal */ -+#define PERF_EB_AVALID 0x0002 /* Count EB_AValid signal */ -+#define PERF_EB_WDRDY 0x0004 /* Count EB_WDRdy signal */ -+#define PERF_EB_RDVAL 0x0008 /* Count EB_RdVal signal */ -+#define PERF_VRADDR 0x0010 /* Count valid read address cycles */ -+#define PERF_VWADDR 0x0020 /* Count valid write address cycles */ -+#define PERF_VWDATA 0x0040 /* Count valid write data cycles */ -+ -+/* -+ * AHB Error Reporting. -+ */ -+#define AR5315_AHB_ERR0 (AR5315_DSLBASE + 0x0050) /* error */ -+#define AR5315_AHB_ERR1 (AR5315_DSLBASE + 0x0054) /* haddr */ -+#define AR5315_AHB_ERR2 (AR5315_DSLBASE + 0x0058) /* hwdata */ -+#define AR5315_AHB_ERR3 (AR5315_DSLBASE + 0x005c) /* hrdata */ -+#define AR5315_AHB_ERR4 (AR5315_DSLBASE + 0x0060) /* status */ -+ -+#define AHB_ERROR_DET 1 /* AHB Error has been detected, */ -+ /* write 1 to clear all bits in ERR0 */ -+#define AHB_ERROR_OVR 2 /* AHB Error overflow has been detected */ -+#define AHB_ERROR_WDT 4 /* AHB Error due to wdt instead of hresp */ -+ -+#define PROCERR_HMAST 0x0000000f -+#define PROCERR_HMAST_DFLT 0 -+#define PROCERR_HMAST_WMAC 1 -+#define PROCERR_HMAST_ENET 2 -+#define PROCERR_HMAST_PCIENDPT 3 -+#define PROCERR_HMAST_LOCAL 4 -+#define PROCERR_HMAST_CPU 5 -+#define PROCERR_HMAST_PCITGT 6 -+ -+#define PROCERR_HMAST_S 0 -+#define PROCERR_HWRITE 0x00000010 -+#define PROCERR_HSIZE 0x00000060 -+#define PROCERR_HSIZE_S 5 -+#define PROCERR_HTRANS 0x00000180 -+#define PROCERR_HTRANS_S 7 -+#define PROCERR_HBURST 0x00000e00 -+#define PROCERR_HBURST_S 9 -+ -+ -+ -+/* -+ * Clock Control -+ */ -+#define AR5315_PLLC_CTL (AR5315_DSLBASE + 0x0064) -+#define AR5315_PLLV_CTL (AR5315_DSLBASE + 0x0068) -+#define AR5315_CPUCLK (AR5315_DSLBASE + 0x006c) -+#define AR5315_AMBACLK (AR5315_DSLBASE + 0x0070) -+#define AR5315_SYNCCLK (AR5315_DSLBASE + 0x0074) -+#define AR5315_DSL_SLEEP_CTL (AR5315_DSLBASE + 0x0080) -+#define AR5315_DSL_SLEEP_DUR (AR5315_DSLBASE + 0x0084) -+ -+/* PLLc Control fields */ -+#define PLLC_REF_DIV_M 0x00000003 -+#define PLLC_REF_DIV_S 0 -+#define PLLC_FDBACK_DIV_M 0x0000007C -+#define PLLC_FDBACK_DIV_S 2 -+#define PLLC_ADD_FDBACK_DIV_M 0x00000080 -+#define PLLC_ADD_FDBACK_DIV_S 7 -+#define PLLC_CLKC_DIV_M 0x0001c000 -+#define PLLC_CLKC_DIV_S 14 -+#define PLLC_CLKM_DIV_M 0x00700000 -+#define PLLC_CLKM_DIV_S 20 -+ -+/* CPU CLK Control fields */ -+#define CPUCLK_CLK_SEL_M 0x00000003 -+#define CPUCLK_CLK_SEL_S 0 -+#define CPUCLK_CLK_DIV_M 0x0000000c -+#define CPUCLK_CLK_DIV_S 2 -+ -+/* AMBA CLK Control fields */ -+#define AMBACLK_CLK_SEL_M 0x00000003 -+#define AMBACLK_CLK_SEL_S 0 -+#define AMBACLK_CLK_DIV_M 0x0000000c -+#define AMBACLK_CLK_DIV_S 2 -+ -+#if defined(COBRA_EMUL) -+#define AR5315_AMBA_CLOCK_RATE 20000000 -+#define AR5315_CPU_CLOCK_RATE 40000000 -+#else -+#if defined(DEFAULT_PLL) -+#define AR5315_AMBA_CLOCK_RATE 40000000 -+#define AR5315_CPU_CLOCK_RATE 40000000 -+#else -+#define AR5315_AMBA_CLOCK_RATE 92000000 -+#define AR5315_CPU_CLOCK_RATE 184000000 -+#endif /* ! DEFAULT_PLL */ -+#endif /* ! COBRA_EMUL */ -+ -+#define AR5315_UART_CLOCK_RATE AR5315_AMBA_CLOCK_RATE -+#define AR5315_SDRAM_CLOCK_RATE AR5315_AMBA_CLOCK_RATE -+ -+/* -+ * The UART computes baud rate as: -+ * baud = clock / (16 * divisor) -+ * where divisor is specified as a High Byte (DLM) and a Low Byte (DLL). -+ */ -+#define DESIRED_BAUD_RATE 38400 -+ -+/* -+ * The WATCHDOG value is computed as -+ * 10 seconds * AR531X_WATCHDOG_CLOCK_RATE -+ */ -+#define DESIRED_WATCHDOG_SECONDS 10 -+#define AR531X_WATCHDOG_TIME \ -+ (DESIRED_WATCHDOG_SECONDS * AR531X_WATCHDOG_CLOCK_RATE) -+ -+ -+#define CLOCKCTL_UART0 0x0010 /* enable UART0 external clock */ -+ -+ -+ /* -+ * Applicable "PCICFG" bits for WLAN(s). Assoc status and LED mode. -+ */ -+#define AR531X_PCICFG (AR531X_RESETTMR + 0x00b0) -+#define ASSOC_STATUS_M 0x00000003 -+#define ASSOC_STATUS_NONE 0 -+#define ASSOC_STATUS_PENDING 1 -+#define ASSOC_STATUS_ASSOCIATED 2 -+#define LED_MODE_M 0x0000001c -+#define LED_BLINK_THRESHOLD_M 0x000000e0 -+#define LED_SLOW_BLINK_MODE 0x00000100 -+ -+/* -+ * GPIO -+ */ -+ -+#define AR5315_GPIO_DI (AR5315_DSLBASE + 0x0088) -+#define AR5315_GPIO_DO (AR5315_DSLBASE + 0x0090) -+#define AR5315_GPIO_CR (AR5315_DSLBASE + 0x0098) -+#define AR5315_GPIO_INT (AR5315_DSLBASE + 0x00a0) -+ -+#define GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ -+#define GPIO_CR_O(x) (1 << (x)) /* output */ -+#define GPIO_CR_I(x) (0 << (x)) /* input */ -+ -+#define GPIO_INT(x,Y) ((x) << (8 * (Y))) /* interrupt enable */ -+#define GPIO_INT_M(Y) ((0x3F) << (8 * (Y))) /* mask for int */ -+#define GPIO_INT_LVL(x,Y) ((x) << (8 * (Y) + 6)) /* interrupt level */ -+#define GPIO_INT_LVL_M(Y) ((0x3) << (8 * (Y) + 6)) /* mask for int level */ -+ -+#define AR5315_RESET_GPIO 5 -+#define AR5315_NUM_GPIO 22 -+ -+ -+/* -+ * PCI Clock Control -+ */ -+ -+#define AR5315_PCICLK (AR5315_DSLBASE + 0x00a4) -+ -+#define PCICLK_INPUT_M 0x3 -+#define PCICLK_INPUT_S 0 -+ -+#define PCICLK_PLLC_CLKM 0 -+#define PCICLK_PLLC_CLKM1 1 -+#define PCICLK_PLLC_CLKC 2 -+#define PCICLK_REF_CLK 3 -+ -+#define PCICLK_DIV_M 0xc -+#define PCICLK_DIV_S 2 -+ -+#define PCICLK_IN_FREQ 0 -+#define PCICLK_IN_FREQ_DIV_6 1 -+#define PCICLK_IN_FREQ_DIV_8 2 -+#define PCICLK_IN_FREQ_DIV_10 3 -+ -+/* -+ * Observation Control Register -+ */ -+#define AR5315_OCR (AR5315_DSLBASE + 0x00b0) -+#define OCR_GPIO0_IRIN 0x0040 -+#define OCR_GPIO1_IROUT 0x0080 -+#define OCR_GPIO3_RXCLR 0x0200 -+ -+/* -+ * General Clock Control -+ */ -+ -+#define AR5315_MISCCLK (AR5315_DSLBASE + 0x00b4) -+#define MISCCLK_PLLBYPASS_EN 0x00000001 -+#define MISCCLK_PROCREFCLK 0x00000002 -+ -+/* -+ * SDRAM Controller -+ * - No read or write buffers are included. -+ */ -+#define AR5315_MEM_CFG (AR5315_SDRAMCTL + 0x00) -+#define AR5315_MEM_CTRL (AR5315_SDRAMCTL + 0x0c) -+#define AR5315_MEM_REF (AR5315_SDRAMCTL + 0x10) -+ -+#define SDRAM_DATA_WIDTH_M 0x00006000 -+#define SDRAM_DATA_WIDTH_S 13 -+ -+#define SDRAM_COL_WIDTH_M 0x00001E00 -+#define SDRAM_COL_WIDTH_S 9 -+ -+#define SDRAM_ROW_WIDTH_M 0x000001E0 -+#define SDRAM_ROW_WIDTH_S 5 -+ -+#define SDRAM_BANKADDR_BITS_M 0x00000018 -+#define SDRAM_BANKADDR_BITS_S 3 -+ -+ -+/* -+ * SDRAM Memory Refresh (MEM_REF) value is computed as: -+ * MEMCTL_SREFR = (Tr * hclk_freq) / R -+ * where Tr is max. time of refresh of any single row -+ * R is number of rows in the DRAM -+ * For most 133MHz SDRAM parts, Tr=64ms, R=4096 or 8192 -+ */ -+#if defined(COBRA_EMUL) -+#define AR5315_SDRAM_MEMORY_REFRESH_VALUE 0x96 -+#else -+#if defined(DEFAULT_PLL) -+#define AR5315_SDRAM_MEMORY_REFRESH_VALUE 0x200 -+#else -+#define AR5315_SDRAM_MEMORY_REFRESH_VALUE 0x61a -+#endif /* ! DEFAULT_PLL */ -+#endif -+ -+#define AR5315_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */ -+#define AR5315_SDRAM_DATA_WIDTH 16 -+#define AR5315_SDRAM_COL_WIDTH 8 -+#define AR5315_SDRAM_ROW_WIDTH 12 -+ -+/* -+ * SPI Flash Interface Registers -+ */ -+ -+#define AR5315_SPI_CTL (AR5315_SPI + 0x00) -+#define AR5315_SPI_OPCODE (AR5315_SPI + 0x04) -+#define AR5315_SPI_DATA (AR5315_SPI + 0x08) -+ -+#define SPI_CTL_START 0x00000100 -+#define SPI_CTL_BUSY 0x00010000 -+#define SPI_CTL_TXCNT_MASK 0x0000000f -+#define SPI_CTL_RXCNT_MASK 0x000000f0 -+#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff -+#define SPI_CTL_SIZE_MASK 0x00060000 -+ -+#define SPI_CTL_CLK_SEL_MASK 0x03000000 -+#define SPI_OPCODE_MASK 0x000000ff -+ -+/* -+ * PCI-MAC Configuration registers -+ */ -+#define PCI_MAC_RC (AR5315_PCI + 0x4000) -+#define PCI_MAC_SCR (AR5315_PCI + 0x4004) -+#define PCI_MAC_INTPEND (AR5315_PCI + 0x4008) -+#define PCI_MAC_SFR (AR5315_PCI + 0x400C) -+#define PCI_MAC_PCICFG (AR5315_PCI + 0x4010) -+#define PCI_MAC_SREV (AR5315_PCI + 0x4020) -+ -+#define PCI_MAC_RC_MAC 0x00000001 -+#define PCI_MAC_RC_BB 0x00000002 -+ -+#define PCI_MAC_SCR_SLMODE_M 0x00030000 -+#define PCI_MAC_SCR_SLMODE_S 16 -+#define PCI_MAC_SCR_SLM_FWAKE 0 -+#define PCI_MAC_SCR_SLM_FSLEEP 1 -+#define PCI_MAC_SCR_SLM_NORMAL 2 -+ -+#define PCI_MAC_SFR_SLEEP 0x00000001 -+ -+#define PCI_MAC_PCICFG_SPWR_DN 0x00010000 -+ -+ -+ -+ -+/* -+ * PCI Bus Interface Registers -+ */ -+#define AR5315_PCI_1MS_REG (AR5315_PCI + 0x0008) -+#define AR5315_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ -+ -+#define AR5315_PCI_MISC_CONFIG (AR5315_PCI + 0x000c) -+#define AR5315_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */ -+#define AR5315_PCIMISC_CFG_SEL 0x00000002 /* mem or config cycles */ -+#define AR5315_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */ -+#define AR5315_PCIMISC_RST_MODE 0x00000030 -+#define AR5315_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */ -+#define AR5315_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */ -+#define AR5315_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */ -+#define AR5315_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */ -+#define AR5315_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */ -+#define AR5315_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */ -+#define AR5315_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */ -+#define AR5315_PCICACHE_DIS 0x00001000 /* PCI external access cache disable */ -+ -+#define AR5315_PCI_OUT_TSTAMP (AR5315_PCI + 0x0010) -+ -+#define AR5315_PCI_UNCACHE_CFG (AR5315_PCI + 0x0014) -+ -+#define AR5315_PCI_IN_EN (AR5315_PCI + 0x0100) -+#define AR5315_PCI_IN_EN0 0x01 /* Enable chain 0 */ -+#define AR5315_PCI_IN_EN1 0x02 /* Enable chain 1 */ -+#define AR5315_PCI_IN_EN2 0x04 /* Enable chain 2 */ -+#define AR5315_PCI_IN_EN3 0x08 /* Enable chain 3 */ -+ -+#define AR5315_PCI_IN_DIS (AR5315_PCI + 0x0104) -+#define AR5315_PCI_IN_DIS0 0x01 /* Disable chain 0 */ -+#define AR5315_PCI_IN_DIS1 0x02 /* Disable chain 1 */ -+#define AR5315_PCI_IN_DIS2 0x04 /* Disable chain 2 */ -+#define AR5315_PCI_IN_DIS3 0x08 /* Disable chain 3 */ -+ -+#define AR5315_PCI_IN_PTR (AR5315_PCI + 0x0200) -+ -+#define AR5315_PCI_OUT_EN (AR5315_PCI + 0x0400) -+#define AR5315_PCI_OUT_EN0 0x01 /* Enable chain 0 */ -+ -+#define AR5315_PCI_OUT_DIS (AR5315_PCI + 0x0404) -+#define AR5315_PCI_OUT_DIS0 0x01 /* Disable chain 0 */ -+ -+#define AR5315_PCI_OUT_PTR (AR5315_PCI + 0x0408) -+ -+#define AR5315_PCI_INT_STATUS (AR5315_PCI + 0x0500) /* write one to clr */ -+#define AR5315_PCI_TXINT 0x00000001 /* Desc In Completed */ -+#define AR5315_PCI_TXOK 0x00000002 /* Desc In OK */ -+#define AR5315_PCI_TXERR 0x00000004 /* Desc In ERR */ -+#define AR5315_PCI_TXEOL 0x00000008 /* Desc In End-of-List */ -+#define AR5315_PCI_RXINT 0x00000010 /* Desc Out Completed */ -+#define AR5315_PCI_RXOK 0x00000020 /* Desc Out OK */ -+#define AR5315_PCI_RXERR 0x00000040 /* Desc Out ERR */ -+#define AR5315_PCI_RXEOL 0x00000080 /* Desc Out EOL */ -+#define AR5315_PCI_TXOOD 0x00000200 /* Desc In Out-of-Desc */ -+#define AR5315_PCI_MASK 0x0000FFFF /* Desc Mask */ -+#define AR5315_PCI_EXT_INT 0x02000000 -+#define AR5315_PCI_ABORT_INT 0x04000000 -+ -+#define AR5315_PCI_INT_MASK (AR5315_PCI + 0x0504) /* same as INT_STATUS */ -+ -+#define AR5315_PCI_INTEN_REG (AR5315_PCI + 0x0508) -+#define AR5315_PCI_INT_DISABLE 0x00 /* disable pci interrupts */ -+#define AR5315_PCI_INT_ENABLE 0x01 /* enable pci interrupts */ -+ -+#define AR5315_PCI_HOST_IN_EN (AR5315_PCI + 0x0800) -+#define AR5315_PCI_HOST_IN_DIS (AR5315_PCI + 0x0804) -+#define AR5315_PCI_HOST_IN_PTR (AR5315_PCI + 0x0810) -+#define AR5315_PCI_HOST_OUT_EN (AR5315_PCI + 0x0900) -+#define AR5315_PCI_HOST_OUT_DIS (AR5315_PCI + 0x0904) -+#define AR5315_PCI_HOST_OUT_PTR (AR5315_PCI + 0x0908) -+ -+ -+/* -+ * Local Bus Interface Registers -+ */ -+#define AR5315_LB_CONFIG (AR5315_LOCAL + 0x0000) -+#define AR5315_LBCONF_OE 0x00000001 /* =1 OE is low-true */ -+#define AR5315_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */ -+#define AR5315_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */ -+#define AR5315_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */ -+#define AR5315_LBCONF_WE 0x00000010 /* =1 Write En is low-true */ -+#define AR5315_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */ -+#define AR5315_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */ -+#define AR5315_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */ -+#define AR5315_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */ -+#define AR5315_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */ -+#define AR5315_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */ -+#define AR5315_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */ -+#define AR5315_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */ -+#define AR5315_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */ -+#define AR5315_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */ -+#define AR5315_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */ -+#define AR5315_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */ -+#define AR5315_LBCONF_INT 0x00020000 /* =1 Intr is low true */ -+#define AR5315_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */ -+#define AR5315_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */ -+#define AR5315_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */ -+#define AR5315_LBCONF_INT_CTR3 0x000C0000 /* GND drive, Vdd drive */ -+#define AR5315_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */ -+#define AR5315_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */ -+#define AR5315_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */ -+ -+#define AR5315_LB_CLKSEL (AR5315_LOCAL + 0x0004) -+#define AR5315_LBCLK_EXT 0x0001 /* use external clk for lb */ -+ -+#define AR5315_LB_1MS (AR5315_LOCAL + 0x0008) -+#define AR5315_LB1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ -+ -+#define AR5315_LB_MISCCFG (AR5315_LOCAL + 0x000C) -+#define AR5315_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */ -+#define AR5315_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */ -+#define AR5315_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */ -+#define AR5315_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */ -+#define AR5315_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */ -+#define AR5315_LBM_TIMEOUT_MASK 0x00FFFF80 -+#define AR5315_LBM_TIMEOUT_SHFT 7 -+#define AR5315_LBM_PORTMUX 0x07000000 -+ -+ -+#define AR5315_LB_RXTSOFF (AR5315_LOCAL + 0x0010) -+ -+#define AR5315_LB_TX_CHAIN_EN (AR5315_LOCAL + 0x0100) -+#define AR5315_LB_TXEN_0 0x01 -+#define AR5315_LB_TXEN_1 0x02 -+#define AR5315_LB_TXEN_2 0x04 -+#define AR5315_LB_TXEN_3 0x08 -+ -+#define AR5315_LB_TX_CHAIN_DIS (AR5315_LOCAL + 0x0104) -+#define AR5315_LB_TX_DESC_PTR (AR5315_LOCAL + 0x0200) -+ -+#define AR5315_LB_RX_CHAIN_EN (AR5315_LOCAL + 0x0400) -+#define AR5315_LB_RXEN 0x01 -+ -+#define AR5315_LB_RX_CHAIN_DIS (AR5315_LOCAL + 0x0404) -+#define AR5315_LB_RX_DESC_PTR (AR5315_LOCAL + 0x0408) -+ -+#define AR5315_LB_INT_STATUS (AR5315_LOCAL + 0x0500) -+#define AR5315_INT_TX_DESC 0x0001 -+#define AR5315_INT_TX_OK 0x0002 -+#define AR5315_INT_TX_ERR 0x0004 -+#define AR5315_INT_TX_EOF 0x0008 -+#define AR5315_INT_RX_DESC 0x0010 -+#define AR5315_INT_RX_OK 0x0020 -+#define AR5315_INT_RX_ERR 0x0040 -+#define AR5315_INT_RX_EOF 0x0080 -+#define AR5315_INT_TX_TRUNC 0x0100 -+#define AR5315_INT_TX_STARVE 0x0200 -+#define AR5315_INT_LB_TIMEOUT 0x0400 -+#define AR5315_INT_LB_ERR 0x0800 -+#define AR5315_INT_MBOX_WR 0x1000 -+#define AR5315_INT_MBOX_RD 0x2000 -+ -+/* Bit definitions for INT MASK are the same as INT_STATUS */ -+#define AR5315_LB_INT_MASK (AR5315_LOCAL + 0x0504) -+ -+#define AR5315_LB_INT_EN (AR5315_LOCAL + 0x0508) -+#define AR5315_LB_MBOX (AR5315_LOCAL + 0x0600) -+ -+ -+ -+/* -+ * IR Interface Registers -+ */ -+#define AR5315_IR_PKTDATA (AR5315_IR + 0x0000) -+ -+#define AR5315_IR_PKTLEN (AR5315_IR + 0x07fc) /* 0 - 63 */ -+ -+#define AR5315_IR_CONTROL (AR5315_IR + 0x0800) -+#define AR5315_IRCTL_TX 0x00000000 /* use as tranmitter */ -+#define AR5315_IRCTL_RX 0x00000001 /* use as receiver */ -+#define AR5315_IRCTL_SAMPLECLK_MASK 0x00003ffe /* Sample clk divisor mask */ -+#define AR5315_IRCTL_SAMPLECLK_SHFT 1 -+#define AR5315_IRCTL_OUTPUTCLK_MASK 0x03ffc000 /* Output clk divisor mask */ -+#define AR5315_IRCTL_OUTPUTCLK_SHFT 14 -+ -+#define AR5315_IR_STATUS (AR5315_IR + 0x0804) -+#define AR5315_IRSTS_RX 0x00000001 /* receive in progress */ -+#define AR5315_IRSTS_TX 0x00000002 /* transmit in progress */ -+ -+#define AR5315_IR_CONFIG (AR5315_IR + 0x0808) -+#define AR5315_IRCFG_INVIN 0x00000001 /* invert input polarity */ -+#define AR5315_IRCFG_INVOUT 0x00000002 /* invert output polarity */ -+#define AR5315_IRCFG_SEQ_START_WIN_SEL 0x00000004 /* 1 => 28, 0 => 7 */ -+#define AR5315_IRCFG_SEQ_START_THRESH 0x000000f0 /* */ -+#define AR5315_IRCFG_SEQ_END_UNIT_SEL 0x00000100 /* */ -+#define AR5315_IRCFG_SEQ_END_UNIT_THRESH 0x00007e00 /* */ -+#define AR5315_IRCFG_SEQ_END_WIN_SEL 0x00008000 /* */ -+#define AR5315_IRCFG_SEQ_END_WIN_THRESH 0x001f0000 /* */ -+#define AR5315_IRCFG_NUM_BACKOFF_WORDS 0x01e00000 /* */ -+ -+/* -+ * PCI memory constants: Memory area 1 and 2 are the same size - -+ * (twice the PCI_TLB_PAGE_SIZE). The definition of -+ * CPU_TO_PCI_MEM_SIZE is coupled with the TLB setup routine -+ * sysLib.c/sysTlbInit(), in that it assumes that 2 pages of size -+ * PCI_TLB_PAGE_SIZE are set up in the TLB for each PCI memory space. -+ */ -+ -+#define CPU_TO_PCI_MEM_BASE1 0xE0000000 -+#define CPU_TO_PCI_MEM_SIZE1 (2*PCI_TLB_PAGE_SIZE) -+ -+ -+/* TLB attributes for PCI transactions */ -+ -+#define PCI_MMU_PAGEMASK 0x00003FFF -+#define MMU_PAGE_UNCACHED 0x00000010 -+#define MMU_PAGE_DIRTY 0x00000004 -+#define MMU_PAGE_VALID 0x00000002 -+#define MMU_PAGE_GLOBAL 0x00000001 -+#define PCI_MMU_PAGEATTRIB (MMU_PAGE_UNCACHED|MMU_PAGE_DIRTY|\ -+ MMU_PAGE_VALID|MMU_PAGE_GLOBAL) -+#define PCI_MEMORY_SPACE1_VIRT 0xE0000000 /* Used for non-prefet mem */ -+#define PCI_MEMORY_SPACE1_PHYS 0x80000000 -+#define PCI_TLB_PAGE_SIZE 0x01000000 -+#define TLB_HI_MASK 0xFFFFE000 -+#define TLB_LO_MASK 0x3FFFFFFF -+#define PAGEMASK_SHIFT 11 -+#define TLB_LO_SHIFT 6 -+ -+#define PCI_MAX_LATENCY 0xFFF /* Max PCI latency */ -+ -+#define HOST_PCI_DEV_ID 3 -+#define HOST_PCI_MBAR0 0x10000000 -+#define HOST_PCI_MBAR1 0x20000000 -+#define HOST_PCI_MBAR2 0x30000000 -+ -+#define HOST_PCI_SDRAM_BASEADDR HOST_PCI_MBAR1 -+#define PCI_DEVICE_MEM_SPACE 0x800000 -+ -+#define sysRegRead(phys) \ -+ (*(volatile u32 *)KSEG1ADDR(phys)) -+ -+#define sysRegWrite(phys, val) \ -+ ((*(volatile u32 *)KSEG1ADDR(phys)) = (val)) -+ -+#endif -diff -urN linux.old/arch/mips/ar531x/ar531xlnx.h linux.dev/arch/mips/ar531x/ar531xlnx.h ---- linux.old/arch/mips/ar531x/ar531xlnx.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/arch/mips/ar531x/ar531xlnx.h 2006-12-16 04:49:36.000000000 +0100 -@@ -0,0 +1,74 @@ -+/* -+ * 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 -+ * Copyright (C) 2006 Felix Fietkau -+ */ -+ -+/* -+ * This file contains definitions needed in order to compile -+ * AR531X products for linux. Definitions that are largely -+ * AR531X-specific and independent of operating system belong -+ * in ar531x.h rather than this file. -+ */ -+#ifndef _AR531XLNX_H -+#define _AR531XLNX_H -+ -+#include "ar531x.h" -+ -+/* -+ * Board support data. The driver is required to locate -+ * and fill-in this information before passing a reference to -+ * this structure as the HAL_BUS_TAG parameter supplied to -+ * ath_hal_attach. -+ */ -+struct ar531x_config { -+ const char *board; /* board config data */ -+ const char *radio; /* radio config data */ -+ int unit; /* unit number [0, 1] */ -+ u32 tag; /* used as devid for now */ -+}; -+ -+#define MIPS_CPU_IRQ_BASE 0x00 -+#define AR531X_HIGH_PRIO 0x10 -+#define AR531X_MISC_IRQ_BASE 0x20 -+#define AR531X_GPIO_IRQ_BASE 0x30 -+ -+/* Software's idea of interrupts handled by "CPU Interrupt Controller" */ -+#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 -+#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */ -+#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */ -+#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */ -+#define AR531X_IRQ_LCBUS_PCI MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ -+#define AR531X_IRQ_WLAN0_POLL MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ -+#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */ -+ -+/* Miscellaneous interrupts, which share IP6 */ -+#define AR531X_MISC_IRQ_NONE AR531X_MISC_IRQ_BASE+0 -+#define AR531X_MISC_IRQ_TIMER AR531X_MISC_IRQ_BASE+1 -+#define AR531X_MISC_IRQ_AHB_PROC AR531X_MISC_IRQ_BASE+2 -+#define AR531X_MISC_IRQ_AHB_DMA AR531X_MISC_IRQ_BASE+3 -+#define AR531X_MISC_IRQ_GPIO AR531X_MISC_IRQ_BASE+4 -+#define AR531X_MISC_IRQ_UART0 AR531X_MISC_IRQ_BASE+5 -+#define AR531X_MISC_IRQ_UART0_DMA AR531X_MISC_IRQ_BASE+6 -+#define AR531X_MISC_IRQ_WATCHDOG AR531X_MISC_IRQ_BASE+7 -+#define AR531X_MISC_IRQ_LOCAL AR531X_MISC_IRQ_BASE+8 -+#define AR531X_MISC_IRQ_COUNT 9 -+ -+/* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */ -+#define AR531X_GPIO_IRQ_NONE AR531X_MISC_IRQ_BASE+0 -+#define AR531X_GPIO_IRQ(n) AR531X_MISC_IRQ_BASE+(n)+1 -+#define AR531X_GPIO_IRQ_COUNT 22 -+ -+extern struct ar531x_boarddata *ar531x_board_configuration; -+extern char *ar531x_radio_configuration; -+extern char *enet_mac_address_get(int MACUnit); -+ -+#define A_DATA_CACHE_INVAL(start, length) \ -+ dma_cache_inv((UINT32)(start),(length)) -+ -+#endif /* _AR531XLNX_H */ -diff -urN linux.old/arch/mips/ar531x/devices.c linux.dev/arch/mips/ar531x/devices.c ---- linux.old/arch/mips/ar531x/devices.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/arch/mips/ar531x/devices.c 2006-12-16 04:46:43.000000000 +0100 -@@ -0,0 +1,281 @@ -+/* -+ * 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 -+ * Copyright (C) 2006 Felix Fietkau -+ */ -+ -+/* -+ * Platform devices for AR531x SoC. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ar531xlnx.h" -+ -+static struct resource ar531x_eth_res[] = { -+ { -+ .name = "eth_membase", -+ .flags = IORESOURCE_MEM, -+ .start = 0xb0500000, -+ .end = 0xb0502000, -+ }, -+ { -+ .name = "eth_irq", -+ .flags = IORESOURCE_IRQ, -+ .start = 4, -+ .end = 4, -+ }, -+}; -+ -+static struct ar531x_eth ar531x_eth_data = { -+ .phy = 1, -+ .mac = 0, -+ .reset_base = 0x11000004, -+ .reset_mac = 0x800, -+ .reset_phy = 0x400, -+}; -+ -+static struct platform_device ar531x_eth = { -+ .id = 0, -+ .name = "ar531x-eth", -+ .dev.platform_data = &ar531x_eth_data, -+ .resource = ar531x_eth_res, -+ .num_resources = ARRAY_SIZE(ar531x_eth_res) -+}; -+ -+static struct platform_device ar531x_wmac = { -+ .id = 0, -+ .name = "ar531x-wmac", -+ /* FIXME: add resources */ -+}; -+ -+static struct resource ar531x_spiflash_res[] = { -+ { -+ .name = "flash_base", -+ .flags = IORESOURCE_MEM, -+ .start = 0xa8000000, -+ .end = 0xa8400000, -+ }, -+ { -+ .name = "flash_regs", -+ .flags = IORESOURCE_MEM, -+ .start = 0x11300000, -+ .end = 0x11300012, -+ }, -+}; -+ -+static struct platform_device ar531x_spiflash = { -+ .id = 0, -+ .name = "spiflash", -+ .resource = ar531x_spiflash_res, -+ .num_resources = ARRAY_SIZE(ar531x_spiflash_res) -+}; -+ -+static __initdata struct platform_device *ar531x_devs[] = { -+ &ar531x_eth, -+ &ar531x_wmac, -+ &ar531x_spiflash -+}; -+ -+ -+ -+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; -+} -+ -+static u8 *find_board_config(void) -+{ -+ char *addr; -+ int found = 0; -+ -+ for (addr = (char *) (ar531x_spiflash_res[0].end - 0x1000); -+ addr >= (char *) (ar531x_spiflash_res[0].end - 0x30000); -+ addr -= 0x1000) { -+ -+ if ( *(int *)addr == 0x35333131) { -+ /* config magic found */ -+ found = 1; -+ break; -+ } -+ } -+ -+ if (!found) { -+ printk("WARNING: No board configuration data found!\n"); -+ addr = NULL; -+ } -+ -+ return addr; -+} -+ -+static void *find_radio_config(char *board_config) -+{ -+ int dataFound; -+ u32 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 = (u32) board_config + 0x1000; -+ (radio_config < (u32) ar531x_spiflash_res[0].end); -+ radio_config += 0x1000) { -+ if (*(int *)radio_config != 0xffffffff) { -+ dataFound = 1; -+ break; -+ } -+ } -+ -+ if (!dataFound) { /* AR2316 relocates radio config to new location */ -+ for (radio_config = (u32) board_config + 0xf8; -+ (radio_config < (u32) ar531x_spiflash_res[0].end - 0x1000 + 0xf8); -+ radio_config += 0x1000) { -+ if (*(int *)radio_config != 0xffffffff) { -+ dataFound = 1; -+ break; -+ } -+ } -+ } -+ -+ if (!dataFound) { -+ printk("Could not find Radio Configuration data\n"); -+ radio_config = 0; -+ } -+ -+ return (u8 *) radio_config; -+} -+ -+ -+#define STM_8MBIT_SIGNATURE 0x13 -+#define STM_16MBIT_SIGNATURE 0x14 -+#define STM_32MBIT_SIGNATURE 0x15 -+#define STM_64MBIT_SIGNATURE 0x16 -+ -+ -+static void __init ar531x_init_flash(void) -+{ -+ u8 sig; -+ u32 flash_size = 0; -+ unsigned int rcfg_size; -+ char *bcfg, *rcfg, *board_config, *radio_config; -+ struct ar531x_config *config; -+ -+ /* probe the flash chip size */ -+ flash_regs = ioremap_nocache(ar531x_spiflash_res[1].start, ar531x_spiflash_res[1].end - ar531x_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; -+ } -+ -+ if (!flash_size) -+ return; -+ -+ ar531x_spiflash_res[0].end = ar531x_spiflash_res[0].start + flash_size; -+ -+ /* 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(); -+ if (!bcfg) -+ return; -+ -+ board_config = kmalloc(0x1000, GFP_KERNEL); -+ memcpy(board_config, bcfg, 0x100); -+ ar531x_eth_data.board_config = board_config; -+ -+ /* Radio config starts 0x100 bytes after board config, regardless -+ * of what the physical layout on the flash chip looks like */ -+ -+ rcfg = find_radio_config(bcfg); -+ if (!rcfg) -+ return; -+ printk("Radio config found at offset 0x%x\n", rcfg - bcfg); -+ radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff); -+ rcfg_size = 0x1000 - ((rcfg - bcfg) & 0xfff); -+ memcpy(radio_config, rcfg, rcfg_size); -+ -+ 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) & REV_CHIP); -+ ar531x_wmac.dev.platform_data = config; -+} -+ -+static int __init ar531x_register_devices(void) -+{ -+ ar531x_init_flash(); -+ return platform_add_devices(ar531x_devs, ARRAY_SIZE(ar531x_devs)); -+} -+ -+ -+arch_initcall(ar531x_register_devices); -diff -urN linux.old/arch/mips/ar531x/gpio.c linux.dev/arch/mips/ar531x/gpio.c ---- linux.old/arch/mips/ar531x/gpio.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/arch/mips/ar531x/gpio.c 2006-12-16 04:49:20.000000000 +0100 -@@ -0,0 +1,127 @@ -+/* -+ * 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 -+ * Copyright (C) 2006 Felix Fietkau -+ */ -+ -+/* -+ * Support for GPIO -- General Purpose Input/Output Pins -+ * XXX: should be rewritten -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "ar531xlnx.h" -+ -+/* GPIO Interrupt Support */ -+ -+/* Turn on the specified AR531X_GPIO_IRQ interrupt */ -+static unsigned int -+ar531x_gpio_intr_startup(unsigned int irq) -+{ -+ ar531x_gpio_intr_enable(irq); -+ -+ return 0; -+} -+ -+/* Turn off the specified AR531X_GPIO_IRQ interrupt */ -+static void -+ar531x_gpio_intr_shutdown(unsigned int irq) -+{ -+ ar531x_gpio_intr_disable(irq); -+} -+ -+u32 gpioIntMask = 0; -+ -+static void ar531x_gpio_intr_set_enabled(unsigned int gpio, int enabled) -+{ -+ u32 reg; -+ int intnum = 0; -+ int intlevel = 2; -+ -+ reg = sysRegRead(AR5315_GPIO_CR); -+ reg &= ~(GPIO_CR_M(gpio)); -+ reg |= GPIO_CR_I(gpio); -+ sysRegWrite(AR5315_GPIO_CR, reg); -+ (void)sysRegRead(AR5315_GPIO_CR); /* flush write to hardware */ -+ -+ reg = sysRegRead(AR5315_GPIO_INT); -+ -+ reg &= ~(GPIO_INT_M(intnum)); -+ reg &= ~(GPIO_INT_LVL_M(intnum)); -+ -+ if (enabled) { -+ reg |= GPIO_INT_LVL(intlevel, intnum); -+ reg |= GPIO_INT(gpio, intnum); -+ } -+ -+ sysRegWrite(AR5315_GPIO_INT, reg); -+ (void)sysRegRead(AR5315_GPIO_INT); /* flush write to hardware */ -+} -+ -+ -+/* Enable the specified AR531X_GPIO_IRQ interrupt */ -+static void -+ar531x_gpio_intr_enable(unsigned int irq) -+{ -+ int gpio = irq - AR531X_GPIO_IRQ_BASE; -+ -+ gpioIntMask |= (1< -+ * Copyright (C) 2006 Felix Fietkau -+ */ -+ -+/* -+ * Interrupt support for AR531X WiSOC. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ar531xlnx.h" -+#include -+ -+extern int setup_irq(unsigned int irq, struct irqaction *irqaction); -+ -+static void ar531x_misc_intr_enable(unsigned int irq); -+static void ar531x_misc_intr_disable(unsigned int irq); -+ -+ -+/* Turn on the specified AR531X_MISC_IRQ interrupt */ -+static unsigned int -+ar531x_misc_intr_startup(unsigned int irq) -+{ -+ ar531x_misc_intr_enable(irq); -+ return 0; -+} -+ -+/* Turn off the specified AR531X_MISC_IRQ interrupt */ -+static void -+ar531x_misc_intr_shutdown(unsigned int irq) -+{ -+ ar531x_misc_intr_disable(irq); -+} -+ -+/* Enable the specified AR531X_MISC_IRQ interrupt */ -+static void -+ar531x_misc_intr_enable(unsigned int irq) -+{ -+ unsigned int imr; -+ -+ imr = sysRegRead(AR5315_IMR); -+ switch(irq) -+ { -+ case AR531X_MISC_IRQ_TIMER: -+ imr |= IMR_TIMER; -+ break; -+ -+ case AR531X_MISC_IRQ_AHB_PROC: -+ imr |= IMR_AHB; -+ break; -+ -+ case AR531X_MISC_IRQ_AHB_DMA: -+ imr |= 0/* ?? */; -+ break; -+ -+ case AR531X_MISC_IRQ_GPIO: -+ imr |= IMR_GPIO; -+ break; -+ -+ case AR531X_MISC_IRQ_UART0: -+ imr |= IMR_UART0; -+ break; -+ -+ -+ case AR531X_MISC_IRQ_WATCHDOG: -+ imr |= IMR_WD; -+ break; -+ -+ case AR531X_MISC_IRQ_LOCAL: -+ imr |= 0/* ?? */; -+ break; -+ -+ } -+ sysRegWrite(AR5315_IMR, imr); -+ imr=sysRegRead(AR5315_IMR); /* flush write buffer */ -+ //printk("enable Interrupt irq 0x%x imr 0x%x \n",irq,imr); -+ -+} -+ -+/* Disable the specified AR531X_MISC_IRQ interrupt */ -+static void -+ar531x_misc_intr_disable(unsigned int irq) -+{ -+ unsigned int imr; -+ -+ imr = sysRegRead(AR5315_IMR); -+ switch(irq) -+ { -+ case AR531X_MISC_IRQ_TIMER: -+ imr &= (~IMR_TIMER); -+ break; -+ -+ case AR531X_MISC_IRQ_AHB_PROC: -+ imr &= (~IMR_AHB); -+ break; -+ -+ case AR531X_MISC_IRQ_AHB_DMA: -+ imr &= 0/* ?? */; -+ break; -+ -+ case AR531X_MISC_IRQ_GPIO: -+ imr &= ~IMR_GPIO; -+ break; -+ -+ case AR531X_MISC_IRQ_UART0: -+ imr &= (~IMR_UART0); -+ break; -+ -+ case AR531X_MISC_IRQ_WATCHDOG: -+ imr &= (~IMR_WD); -+ break; -+ -+ case AR531X_MISC_IRQ_LOCAL: -+ imr &= ~0/* ?? */; -+ break; -+ -+ } -+ sysRegWrite(AR5315_IMR, imr); -+ sysRegRead(AR5315_IMR); /* flush write buffer */ -+} -+ -+static void -+ar531x_misc_intr_ack(unsigned int irq) -+{ -+ ar531x_misc_intr_disable(irq); -+} -+ -+static void -+ar531x_misc_intr_end(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) -+ ar531x_misc_intr_enable(irq); -+} -+ -+struct irq_chip ar531x_misc_intr_controller = { -+ .typename = "AR531X MISC", -+ .startup = ar531x_misc_intr_startup, -+ .shutdown = ar531x_misc_intr_shutdown, -+ .enable = ar531x_misc_intr_enable, -+ .disable = ar531x_misc_intr_disable, -+ .ack = ar531x_misc_intr_ack, -+ .end = ar531x_misc_intr_end, -+}; -+ -+/* -+ * Determine interrupt source among interrupts that use IP6 -+ */ -+void -+ar531x_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 = &ar531x_misc_intr_controller; -+ } -+} -+ -+/* ARGSUSED */ -+irqreturn_t -+spurious_irq_handler(int cpl, void *dev_id) -+{ -+ /* -+ printk("spurious_irq_handler: %d cause=0x%8.8x status=0x%8.8x\n", -+ cpl, cause_intrs, status_intrs); -+ */ -+ return IRQ_NONE; -+} -+ -+/* ARGSUSED */ -+irqreturn_t -+spurious_misc_handler(int cpl, void *dev_id) -+{ -+ /* -+ printk("spurious_misc_handler: 0x%x isr=0x%8.8x imr=0x%8.8x\n", -+ cpl, ar531x_isr, ar531x_imr); -+ */ -+ return IRQ_NONE; -+} -+ -+irqreturn_t -+ar531x_ahb_proc_handler(int cpl, void *dev_id) -+{ -+ u32 procAddr = -1; -+ u32 proc1 = -1; -+ u32 dmaAddr = -1; -+ u32 dma1 = -1; -+ sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET); -+ sysRegRead(AR5315_AHB_ERR1); -+ -+ 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 cascade = { -+ .handler = no_action, -+ .flags = SA_INTERRUPT, -+ .name = "cascade", -+}; -+ -+static struct irqaction spurious_irq = { -+ .handler = spurious_irq_handler, -+ .flags = SA_INTERRUPT, -+ .name = "spurious_irq", -+}; -+ -+static struct irqaction spurious_misc = { -+ .handler = spurious_misc_handler, -+ .flags = SA_INTERRUPT, -+ .name = "spurious_misc", -+}; -+ -+static struct irqaction ar531x_ahb_proc_interrupt = { -+ .handler = ar531x_ahb_proc_handler, -+ .flags = SA_INTERRUPT, -+ .name = "ar531x_ahb_proc_interrupt", -+}; -+ -+/* -+ * 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 plat_irq_dispatch(void) -+{ -+ int pending = read_c0_status() & read_c0_cause(); -+ -+ if (pending & CAUSEF_IP3) -+ do_IRQ(AR531X_IRQ_WLAN0_INTRS); -+ else if (pending & CAUSEF_IP4) -+ do_IRQ(AR531X_IRQ_ENET0_INTRS); -+ else if (pending & CAUSEF_IP2) { -+ unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR); -+ -+ if (ar531x_misc_intrs & ISR_TIMER) -+ do_IRQ(AR531X_MISC_IRQ_TIMER); -+ else if (ar531x_misc_intrs & ISR_AHB) -+ do_IRQ(AR531X_MISC_IRQ_AHB_PROC); -+ else if (ar531x_misc_intrs & ISR_GPIO) { -+#if 0 -+ int i; -+ u32 gpioIntPending; -+ -+ gpioIntPending = sysRegRead(AR5315_GPIO_DI) & gpioIntMask; -+ for (i=0; i -+# Copyright (C) 2006 Felix Fietkau -+# -+ -+# Makefile for Atheros ar531x boards -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (ie not a .c file). -+# -+obj-y := setup.o prom.o irq.o devices.o -diff -urN linux.old/arch/mips/ar531x/prom.c linux.dev/arch/mips/ar531x/prom.c ---- linux.old/arch/mips/ar531x/prom.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/arch/mips/ar531x/prom.c 2006-12-16 04:50:30.000000000 +0100 -@@ -0,0 +1,50 @@ -+/* -+ * 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 -+ * Copyright (C) 2006 Felix Fietkau -+ */ -+ -+/* -+ * Prom setup file for ar531x -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "ar531xlnx.h" -+ -+void __init prom_init(void) -+{ -+ u32 memsize, memcfg; -+ -+ mips_machgroup = MACH_GROUP_AR531X; -+ mips_machtype = MACH_ATHEROS_AP51; -+ -+ 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); -+ -+ strcpy(arcs_cmdline, "console=ttyS0,9600 rootfstype=squashfs,jffs2"); -+} -+ -+void __init prom_free_prom_memory(void) -+{ -+} -+ -+ -diff -urN linux.old/arch/mips/ar531x/setup.c linux.dev/arch/mips/ar531x/setup.c ---- linux.old/arch/mips/ar531x/setup.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/arch/mips/ar531x/setup.c 2006-12-16 03:51:47.000000000 +0100 -@@ -0,0 +1,198 @@ -+/* -+ * 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 -+ * Copyright (C) 2006 Felix Fietkau -+ */ -+ -+/* -+ * Initialization for ar531x SOC. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ar531xlnx.h" -+ -+void -+ar531x_restart(char *command) -+{ -+ for(;;) { -+ /* -+ ** Cold reset does not work,work around is to use the GPIO reset bit. -+ */ -+ unsigned int reg; -+ -+ /* AR2317 reset */ -+ sysRegWrite(AR5315_COLD_RESET,AR5317_RESET_SYSTEM); -+ -+ reg = sysRegRead(AR5315_GPIO_DO); -+ reg &= ~(1 << AR5315_RESET_GPIO); -+ sysRegWrite(AR5315_GPIO_DO, reg); -+ (void)sysRegRead(AR5315_GPIO_DO); /* flush write to hardware */ -+ } -+} -+ -+void -+ar531x_halt(void) -+{ -+ printk(KERN_NOTICE "\n** You can safely turn off the power\n"); -+ while (1); -+} -+ -+void -+ar531x_power_off(void) -+{ -+ ar531x_halt(); -+} -+ -+char *get_system_type(void) -+{ -+ return "Atheros AR5315"; -+} -+ -+/* -+ * 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 -+ar531x_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 ar531x_cpu_frequency(void) -+{ -+ return ar531x_sys_clk(sysRegRead(AR5315_CPUCLK)); -+} -+ -+static inline unsigned int ar531x_apb_frequency(void) -+{ -+ return ar531x_sys_clk(sysRegRead(AR5315_AMBACLK)); -+} -+ -+ -+void __init serial_setup(void) -+{ -+ struct uart_port s; -+ -+ memset(&s, 0, sizeof(s)); -+ -+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; -+ s.iotype = UPIO_MEM; -+ s.uartclk = AR5315_UART_CLOCK_RATE; -+ s.irq = AR531X_MISC_IRQ_UART0; -+ s.regshift = 2; -+ s.mapbase = KSEG1ADDR(AR5315_UART0); -+ s.membase = (void __iomem *)s.mapbase; -+ -+ early_serial_setup(&s); -+} -+ -+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); -+} -+ -+static void __init -+ar531x_time_init(void) -+{ -+ mips_hpt_frequency = ar531x_cpu_frequency() / 2; -+} -+ -+void __init plat_mem_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); -+ -+ /* Disable data watchpoints */ -+ write_c0_watchlo0(0); -+ -+ board_time_init = ar531x_time_init; -+ -+ _machine_restart = ar531x_restart; -+ _machine_halt = ar531x_halt; -+ pm_power_off = ar531x_power_off; -+ -+ serial_setup(); -+} -+ -+EXPORT_SYMBOL(get_system_type); diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig ---- linux.old/arch/mips/Kconfig 2006-11-29 22:57:37.000000000 +0100 -+++ linux.dev/arch/mips/Kconfig 2006-12-16 03:51:47.000000000 +0100 -@@ -145,6 +145,19 @@ +--- linux.old/arch/mips/Kconfig 2007-02-02 23:55:52.912446784 +0100 ++++ linux.dev/arch/mips/Kconfig 2007-02-03 21:50:25.262027104 +0100 +@@ -145,6 +145,16 @@ note that a kernel built with this option selected will not be able to run on normal units. -+config AR531X -+ bool 'Atheros AR531x/AR231x WiSoC (EXPERIMENTAL)' ++config ATHEROS ++ bool "Atheros SoC support (EXPERIMENTAL)" + depends on EXPERIMENTAL + select DMA_NONCOHERENT + select IRQ_CPU + select SYS_HAS_CPU_MIPS32_R1 + select HAVE_STD_PC_SERIAL_PORT -+ select AR531X_COBRA -+ select AR5315 -+ select AP51 + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_32BIT_KERNEL + config MIPS_COBALT bool "Cobalt Server" select DMA_NONCOHERENT -@@ -864,6 +877,18 @@ - config MIPS_DISABLE_OBSOLETE_IDE - bool +@@ -766,6 +776,7 @@ -+config AR531X_COBRA -+ bool -+ -+config AR5315 -+ bool -+ -+config AR5317 -+ bool -+ -+config AP51 -+ bool -+ - # - # Endianess selection. Suffiently obscure so many users don't know what to - # answer,so we try hard to limit the available choices. Also the use of a + endchoice + ++source "arch/mips/atheros/Kconfig" + source "arch/mips/ddb5xxx/Kconfig" + source "arch/mips/gt64120/ev64120/Kconfig" + source "arch/mips/jazz/Kconfig" diff -urN linux.old/arch/mips/Makefile linux.dev/arch/mips/Makefile ---- linux.old/arch/mips/Makefile 2006-12-14 23:53:29.000000000 +0100 -+++ linux.dev/arch/mips/Makefile 2006-12-16 04:45:48.000000000 +0100 +--- linux.old/arch/mips/Makefile 2007-02-02 23:55:52.913446632 +0100 ++++ linux.dev/arch/mips/Makefile 2007-02-03 17:40:29.193776000 +0100 @@ -267,6 +267,13 @@ load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000 # +# Atheros AR5312/AR2312 WiSoC +# -+core-$(CONFIG_AR531X) += arch/mips/ar531x/ -+cflags-$(CONFIG_AR531X) += -Iinclude/asm-mips/mach-atheros -+load-$(CONFIG_AR531X) += 0xffffffff80041000 ++core-$(CONFIG_ATHEROS) += arch/mips/atheros/ ++cflags-$(CONFIG_ATHEROS) += -Iinclude/asm-mips/mach-atheros ++load-$(CONFIG_ATHEROS) += 0xffffffff80041000 + +# # Cobalt Server # core-$(CONFIG_MIPS_COBALT) += arch/mips/cobalt/ diff -urN linux.old/include/asm-mips/bootinfo.h linux.dev/include/asm-mips/bootinfo.h ---- linux.old/include/asm-mips/bootinfo.h 2006-11-29 22:57:37.000000000 +0100 -+++ linux.dev/include/asm-mips/bootinfo.h 2006-12-16 03:51:47.000000000 +0100 -@@ -212,6 +212,19 @@ +--- linux.old/include/asm-mips/bootinfo.h 2007-02-02 23:55:52.913446632 +0100 ++++ linux.dev/include/asm-mips/bootinfo.h 2007-02-03 17:51:02.531494032 +0100 +@@ -212,6 +212,13 @@ #define MACH_GROUP_NEC_EMMA2RH 25 /* NEC EMMA2RH (was 23) */ #define MACH_NEC_MARKEINS 0 /* NEC EMMA2RH Mark-eins */ +/* -+ * Valid machtype for group AR531X ++ * Valid machtype for group ATHEROS + */ -+#define MACH_GROUP_AR531X 23 -+#define MACH_ATHEROS_UNUSED 0 -+#define MACH_ATHEROS_AP30 1 /* AP30 */ -+#define MACH_ATHEROS_AP33 2 /* AP33 */ -+#define MACH_ATHEROS_AP38 3 /* AP38 */ -+#define MACH_ATHEROS_AP43 4 /* AP43 */ -+#define MACH_ATHEROS_AP48 5 /* AP48 */ -+#define MACH_ATHEROS_PB32 6 /* PB32 */ -+#define MACH_ATHEROS_AP51 7 /* AP51 */ ++#define MACH_GROUP_ATHEROS 26 ++#define MACH_ATHEROS_AR5312 0 /* Atheros AR5312, AR2312/3/4 */ ++#define MACH_ATHEROS_AR5315 1 /* Atheros AR2315/6/7/8 */ + #define CL_SIZE COMMAND_LINE_SIZE const char *get_system_type(void); -diff -urN linux.old/include/asm-mips/mach-atheros/ar531x_platform.h linux.dev/include/asm-mips/mach-atheros/ar531x_platform.h ---- linux.old/include/asm-mips/mach-atheros/ar531x_platform.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/include/asm-mips/mach-atheros/ar531x_platform.h 2006-12-16 04:27:21.000000000 +0100 -@@ -0,0 +1,14 @@ -+#ifndef __AR531X_PLATFORM_H -+#define __AR531X_PLATFORM_H -+ -+struct ar531x_eth { -+ int phy; -+ int mac; -+ u32 reset_base; -+ u32 reset_mac; -+ u32 reset_phy; -+ char *board_config; -+}; -+ -+#endif /* __AR531X_PLATFORM_H */ -+ + diff --git a/target/linux/atheros-2.6/patches/110-spiflash.patch b/target/linux/atheros-2.6/patches/110-spiflash.patch index a8fc4af8e..e6461ff06 100644 --- a/target/linux/atheros-2.6/patches/110-spiflash.patch +++ b/target/linux/atheros-2.6/patches/110-spiflash.patch @@ -1,750 +1,23 @@ diff -urN linux.old/drivers/mtd/devices/Kconfig linux.dev/drivers/mtd/devices/Kconfig ---- linux.old/drivers/mtd/devices/Kconfig 2006-11-29 22:57:37.000000000 +0100 -+++ linux.dev/drivers/mtd/devices/Kconfig 2006-12-15 00:03:11.000000000 +0100 +--- linux.old/drivers/mtd/devices/Kconfig 2007-02-04 04:30:26.145338240 +0100 ++++ linux.dev/drivers/mtd/devices/Kconfig 2007-02-02 23:48:28.748969000 +0100 @@ -68,6 +68,10 @@ used for program and data storage. Set up your spi devices with the right board-specific platform data. +config MTD_SPIFLASH + tristate "Atheros AR2315/6/7 SPI Flash support" -+ depends on MTD && AR531X_COBRA ++ depends on MTD && ATHEROS_AR5315 + config MTD_SLRAM tristate "Uncached system RAM" depends on MTD diff -urN linux.old/drivers/mtd/devices/Makefile linux.dev/drivers/mtd/devices/Makefile ---- linux.old/drivers/mtd/devices/Makefile 2006-11-29 22:57:37.000000000 +0100 -+++ linux.dev/drivers/mtd/devices/Makefile 2006-12-15 00:03:11.000000000 +0100 +--- linux.old/drivers/mtd/devices/Makefile 2007-02-04 04:30:26.146338088 +0100 ++++ linux.dev/drivers/mtd/devices/Makefile 2007-02-02 23:48:28.749969000 +0100 @@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o +obj-$(CONFIG_MTD_SPIFLASH) += spiflash.o -diff -urN linux.old/drivers/mtd/devices/spiflash.c linux.dev/drivers/mtd/devices/spiflash.c ---- linux.old/drivers/mtd/devices/spiflash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/mtd/devices/spiflash.c 2006-12-15 08:26:11.000000000 +0100 -@@ -0,0 +1,595 @@ -+ -+/* -+ * MTD driver for the SPI Flash Memory support. -+ * -+ * Copyright (c) 2005-2006 Atheros Communications Inc. -+ * Copyright (C) 2006 FON Technology, SL. -+ * Copyright (C) 2006 Imre Kaloz -+ * Copyright (C) 2006 Felix Fietkau -+ * -+ * This code is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+/*=========================================================================== -+** !!!! VERY IMPORTANT NOTICE !!!! FLASH DATA STORED IN LITTLE ENDIAN FORMAT -+** -+** This module contains the Serial Flash access routines for the Atheros SOC. -+** The Atheros SOC integrates a SPI flash controller that is used to access -+** serial flash parts. The SPI flash controller executes in "Little Endian" -+** mode. THEREFORE, all WRITES and READS from the MIPS CPU must be -+** BYTESWAPPED! The SPI Flash controller hardware by default performs READ -+** ONLY byteswapping when accessed via the SPI Flash Alias memory region -+** (Physical Address 0x0800_0000 - 0x0fff_ffff). The data stored in the -+** flash sectors is stored in "Little Endian" format. -+** -+** The spiflash_write() routine performs byteswapping on all write -+** operations. -+**===========================================================================*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "spiflash.h" -+ -+/* debugging */ -+/* #define SPIFLASH_DEBUG */ -+ -+#ifndef __BIG_ENDIAN -+#error This driver currently only works with big endian CPU. -+#endif -+ -+#define MAX_PARTS 32 -+ -+static char module_name[] = "spiflash"; -+ -+#define MIN(a,b) ((a) < (b) ? (a) : (b)) -+#define FALSE 0 -+#define TRUE 1 -+ -+#define ROOTFS_NAME "rootfs" -+ -+static __u32 spiflash_regread32(int reg); -+static void spiflash_regwrite32(int reg, __u32 data); -+static __u32 spiflash_sendcmd (int op); -+ -+static void __init spidata_init(void); -+int __init spiflash_init (void); -+void __exit spiflash_exit (void); -+static int spiflash_probe (void); -+static int spiflash_erase (struct mtd_info *mtd,struct erase_info *instr); -+static int spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf); -+static int spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf); -+ -+/* Flash configuration table */ -+struct flashconfig { -+ __u32 byte_cnt; -+ __u32 sector_cnt; -+ __u32 sector_size; -+ __u32 cs_addrmask; -+} flashconfig_tbl[MAX_FLASH] = -+ { -+ { 0, 0, 0, 0}, -+ { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT, STM_1MB_SECTOR_SIZE, 0x0}, -+ { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT, STM_2MB_SECTOR_SIZE, 0x0}, -+ { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT, STM_4MB_SECTOR_SIZE, 0x0}, -+ { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT, STM_8MB_SECTOR_SIZE, 0x0} -+ }; -+ -+/* Mapping of generic opcodes to STM serial flash opcodes */ -+struct opcodes { -+ __u16 code; -+ __s8 tx_cnt; -+ __s8 rx_cnt; -+} stm_opcodes[] = { -+ {STM_OP_WR_ENABLE, 1, 0}, -+ {STM_OP_WR_DISABLE, 1, 0}, -+ {STM_OP_RD_STATUS, 1, 1}, -+ {STM_OP_WR_STATUS, 1, 0}, -+ {STM_OP_RD_DATA, 4, 4}, -+ {STM_OP_FAST_RD_DATA, 1, 0}, -+ {STM_OP_PAGE_PGRM, 8, 0}, -+ {STM_OP_SECTOR_ERASE, 4, 0}, -+ {STM_OP_BULK_ERASE, 1, 0}, -+ {STM_OP_DEEP_PWRDOWN, 1, 0}, -+ {STM_OP_RD_SIG, 4, 1} -+}; -+ -+/* Driver private data structure */ -+struct spiflash_data { -+ struct mtd_info *mtd; -+ struct mtd_partition *parsed_parts; /* parsed partitions */ -+ void *spiflash_readaddr; /* memory mapped data for read */ -+ void *spiflash_mmraddr; /* memory mapped register space */ -+ spinlock_t mutex; -+}; -+ -+static struct spiflash_data *spidata; -+ -+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -+ -+/***************************************************************************************************/ -+ -+static __u32 -+spiflash_regread32(int reg) -+{ -+ volatile __u32 *data = (__u32 *)(spidata->spiflash_mmraddr + reg); -+ -+ return (*data); -+} -+ -+static void -+spiflash_regwrite32(int reg, __u32 data) -+{ -+ volatile __u32 *addr = (__u32 *)(spidata->spiflash_mmraddr + reg); -+ -+ *addr = data; -+ return; -+} -+ -+static __u32 -+spiflash_sendcmd (int op) -+{ -+ __u32 reg; -+ __u32 mask; -+ struct opcodes *ptr_opcode; -+ -+ ptr_opcode = &stm_opcodes[op]; -+ -+ do { -+ reg = spiflash_regread32(SPI_FLASH_CTL); -+ } while (reg & SPI_CTL_BUSY); -+ -+ spiflash_regwrite32(SPI_FLASH_OPCODE, ptr_opcode->code); -+ -+ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | -+ (ptr_opcode->rx_cnt << 4) | SPI_CTL_START; -+ -+ spiflash_regwrite32(SPI_FLASH_CTL, reg); -+ -+ if (ptr_opcode->rx_cnt > 0) { -+ do { -+ reg = spiflash_regread32(SPI_FLASH_CTL); -+ } while (reg & SPI_CTL_BUSY); -+ -+ reg = (__u32) spiflash_regread32(SPI_FLASH_DATA); -+ -+ switch (ptr_opcode->rx_cnt) { -+ case 1: -+ mask = 0x000000ff; -+ break; -+ case 2: -+ mask = 0x0000ffff; -+ break; -+ case 3: -+ mask = 0x00ffffff; -+ break; -+ default: -+ mask = 0xffffffff; -+ break; -+ } -+ -+ reg &= mask; -+ } -+ else { -+ reg = 0; -+ } -+ -+ return reg; -+} -+ -+/* Probe SPI flash device -+ * Function returns 0 for failure. -+ * and flashconfig_tbl array index for success. -+ */ -+static int -+spiflash_probe (void) -+{ -+ __u32 sig; -+ int flash_size; -+ -+ if (!spidata) -+ spidata_init(); -+ -+ if (!spidata) /* init failed */ -+ return 0; -+ -+ /* Read the signature on the flash device */ -+ sig = spiflash_sendcmd(SPI_RD_SIG); -+ -+ switch (sig) { -+ case STM_8MBIT_SIGNATURE: -+ flash_size = FLASH_1MB; -+ break; -+ case STM_16MBIT_SIGNATURE: -+ flash_size = FLASH_2MB; -+ break; -+ case STM_32MBIT_SIGNATURE: -+ flash_size = FLASH_4MB; -+ break; -+ case STM_64MBIT_SIGNATURE: -+ flash_size = FLASH_8MB; -+ break; -+ default: -+ printk (KERN_WARNING "%s: Read of flash device signature failed!\n", module_name); -+ return (0); -+ } -+ -+ return (flash_size); -+} -+ -+ -+static int -+spiflash_erase (struct mtd_info *mtd,struct erase_info *instr) -+{ -+ struct opcodes *ptr_opcode; -+ __u32 temp, reg; -+ int finished = FALSE; -+ -+#ifdef SPIFLASH_DEBUG -+ printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len); -+#endif -+ -+ /* sanity checks */ -+ if (instr->addr + instr->len > mtd->size) return (-EINVAL); -+ -+ ptr_opcode = &stm_opcodes[SPI_SECTOR_ERASE]; -+ -+ temp = ((__u32)instr->addr << 8) | (__u32)(ptr_opcode->code); -+ spin_lock(&spidata->mutex); -+ spiflash_sendcmd(SPI_WRITE_ENABLE); -+ do { -+ schedule(); -+ reg = spiflash_regread32(SPI_FLASH_CTL); -+ } while (reg & SPI_CTL_BUSY); -+ -+ spiflash_regwrite32(SPI_FLASH_OPCODE, temp); -+ -+ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | SPI_CTL_START; -+ spiflash_regwrite32(SPI_FLASH_CTL, reg); -+ -+ do { -+ schedule(); -+ reg = spiflash_sendcmd(SPI_RD_STATUS); -+ if (!(reg & SPI_STATUS_WIP)) { -+ finished = TRUE; -+ } -+ } while (!finished); -+ spin_unlock(&spidata->mutex); -+ -+ instr->state = MTD_ERASE_DONE; -+ if (instr->callback) instr->callback (instr); -+ -+#ifdef SPIFLASH_DEBUG -+ printk (KERN_DEBUG "%s return\n",__FUNCTION__); -+#endif -+ return (0); -+} -+ -+static int -+spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf) -+{ -+ u_char *read_addr; -+ -+#ifdef SPIFLASH_DEBUG -+ printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) from,(int)len); -+#endif -+ -+ /* sanity checks */ -+ if (!len) return (0); -+ if (from + len > mtd->size) return (-EINVAL); -+ -+ -+ /* we always read len bytes */ -+ *retlen = len; -+ -+ read_addr = (u_char *)(spidata->spiflash_readaddr + from); -+ spin_lock(&spidata->mutex); -+ memcpy(buf, read_addr, len); -+ spin_unlock(&spidata->mutex); -+ -+ return (0); -+} -+ -+static int -+spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf) -+{ -+ int done = FALSE, page_offset, bytes_left, finished; -+ __u32 xact_len, spi_data = 0, opcode, reg; -+ -+#ifdef SPIFLASH_DEBUG -+ printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) to,len); -+#endif -+ -+ *retlen = 0; -+ -+ /* sanity checks */ -+ if (!len) return (0); -+ if (to + len > mtd->size) return (-EINVAL); -+ -+ opcode = stm_opcodes[SPI_PAGE_PROGRAM].code; -+ bytes_left = len; -+ -+ while (done == FALSE) { -+ xact_len = MIN(bytes_left, sizeof(__u32)); -+ -+ /* 32-bit writes cannot span across a page boundary -+ * (256 bytes). This types of writes require two page -+ * program operations to handle it correctly. The STM part -+ * will write the overflow data to the beginning of the -+ * current page as opposed to the subsequent page. -+ */ -+ page_offset = (to & (STM_PAGE_SIZE - 1)) + xact_len; -+ -+ if (page_offset > STM_PAGE_SIZE) { -+ xact_len -= (page_offset - STM_PAGE_SIZE); -+ } -+ -+ spin_lock(&spidata->mutex); -+ spiflash_sendcmd(SPI_WRITE_ENABLE); -+ -+ do { -+ schedule(); -+ reg = spiflash_regread32(SPI_FLASH_CTL); -+ } while (reg & SPI_CTL_BUSY); -+ -+ switch (xact_len) { -+ case 1: -+ spi_data = (u32) ((u8) *buf); -+ break; -+ case 2: -+ spi_data = (buf[1] << 8) | buf[0]; -+ break; -+ case 3: -+ spi_data = (buf[2] << 16) | (buf[1] << 8) | buf[0]; -+ break; -+ case 4: -+ spi_data = (buf[3] << 24) | (buf[2] << 16) | -+ (buf[1] << 8) | buf[0]; -+ break; -+ default: -+ printk("spiflash_write: default case\n"); -+ break; -+ } -+ -+ spiflash_regwrite32(SPI_FLASH_DATA, spi_data); -+ opcode = (opcode & SPI_OPCODE_MASK) | ((__u32)to << 8); -+ spiflash_regwrite32(SPI_FLASH_OPCODE, opcode); -+ -+ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | (xact_len + 4) | SPI_CTL_START; -+ spiflash_regwrite32(SPI_FLASH_CTL, reg); -+ finished = FALSE; -+ -+ do { -+ schedule(); -+ reg = spiflash_sendcmd(SPI_RD_STATUS); -+ if (!(reg & SPI_STATUS_WIP)) { -+ finished = TRUE; -+ } -+ } while (!finished); -+ spin_unlock(&spidata->mutex); -+ -+ bytes_left -= xact_len; -+ to += xact_len; -+ buf += xact_len; -+ -+ *retlen += xact_len; -+ -+ if (bytes_left == 0) { -+ done = TRUE; -+ } -+ } -+ -+ return (0); -+} -+ -+static void __init spidata_init(void) -+{ -+ if (spidata) -+ return; -+ -+ spidata = kmalloc(sizeof(struct spiflash_data), GFP_KERNEL); -+ spin_lock_init(&spidata->mutex); -+ -+ if (!spidata) -+ return; -+ -+ spidata->spiflash_mmraddr = ioremap_nocache(SPI_FLASH_MMR, SPI_FLASH_MMR_SIZE); -+ -+ if (!spidata->spiflash_mmraddr) { -+ printk (KERN_WARNING "%s: Failed to map flash device\n", module_name); -+ kfree(spidata); -+ spidata = NULL; -+ } -+} -+ -+#ifdef CONFIG_MTD_PARTITIONS -+static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; -+#endif -+ -+int __init -+spiflash_init (void) -+{ -+ int result = -1, i, j; -+ u32 len; -+ int index, num_parts; -+ struct mtd_info *mtd; -+ struct mtd_partition *mtd_parts; -+ char *buf; -+ struct mtd_partition *part; -+ struct squashfs_super_block *sb; -+ u32 config_start; -+ -+ spidata_init(); -+ -+ if (!spidata) -+ return (-ENXIO); -+ -+ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); -+ if (!mtd) { -+ kfree(spidata); -+ return (-ENXIO); -+ } -+ -+ printk ("MTD driver for SPI flash.\n"); -+ printk ("%s: Probing for Serial flash ...\n", module_name); -+ if (!(index = spiflash_probe ())) { -+ printk (KERN_WARNING "%s: Found no serial flash device\n", module_name); -+ kfree(mtd); -+ kfree(spidata); -+ return (-ENXIO); -+ } -+ -+ printk ("%s: Found SPI serial Flash.\n", module_name); -+ -+ spidata->spiflash_readaddr = ioremap_nocache(SPI_FLASH_READ, flashconfig_tbl[index].byte_cnt); -+ if (!spidata->spiflash_readaddr) { -+ printk (KERN_WARNING "%s: Failed to map flash device\n", module_name); -+ kfree(mtd); -+ kfree(spidata); -+ return (-ENXIO); -+ } -+ -+ mtd->name = module_name; -+ mtd->type = MTD_NORFLASH; -+ mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE); -+ mtd->size = flashconfig_tbl[index].byte_cnt; -+ mtd->erasesize = flashconfig_tbl[index].sector_size; -+ mtd->writesize = 1; -+ mtd->numeraseregions = 0; -+ mtd->eraseregions = NULL; -+ mtd->erase = spiflash_erase; -+ mtd->read = spiflash_read; -+ mtd->write = spiflash_write; -+ mtd->owner = THIS_MODULE; -+ -+#ifdef SPIFLASH_DEBUG -+ printk (KERN_DEBUG -+ "mtd->name = %s\n" -+ "mtd->size = 0x%.8x (%uM)\n" -+ "mtd->erasesize = 0x%.8x (%uK)\n" -+ "mtd->numeraseregions = %d\n", -+ mtd->name, -+ mtd->size, mtd->size / (1024*1024), -+ mtd->erasesize, mtd->erasesize / 1024, -+ mtd->numeraseregions); -+ -+ if (mtd->numeraseregions) { -+ for (result = 0; result < mtd->numeraseregions; result++) { -+ printk (KERN_DEBUG -+ "\n\n" -+ "mtd->eraseregions[%d].offset = 0x%.8x\n" -+ "mtd->eraseregions[%d].erasesize = 0x%.8x (%uK)\n" -+ "mtd->eraseregions[%d].numblocks = %d\n", -+ result,mtd->eraseregions[result].offset, -+ result,mtd->eraseregions[result].erasesize,mtd->eraseregions[result].erasesize / 1024, -+ result,mtd->eraseregions[result].numblocks); -+ } -+ } -+#endif -+ -+ /* parse redboot partitions */ -+ num_parts = parse_mtd_partitions(mtd, part_probe_types, &spidata->parsed_parts, 0); -+ -+ mtd_parts = kzalloc(sizeof(struct mtd_partition) * MAX_PARTS, GFP_KERNEL); -+ buf = kmalloc(mtd->erasesize, GFP_KERNEL); -+ sb = (struct squashfs_super_block *) buf; -+ for (i = j = 0; i < num_parts; i++, j++) { -+ part = &mtd_parts[j]; -+ memcpy(part, &spidata->parsed_parts[i], sizeof(struct mtd_partition)); -+ -+ if (!strcmp(part->name, ROOTFS_NAME)) { -+ /* create the root device */ -+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, i); -+ -+ part->size -= mtd->erasesize; -+ config_start = part->offset + part->size; -+ -+ while ((mtd->read(mtd, part->offset, mtd->erasesize, &len, buf) == 0) && -+ (len == mtd->erasesize) && -+ (*((u32 *) buf) == SQUASHFS_MAGIC) && -+ (sb->bytes_used > 0)) { -+ -+ /* this is squashfs, allocate another partition starting from the end of filesystem data */ -+ memcpy(&mtd_parts[j + 1], part, sizeof(struct mtd_partition)); -+ -+ len = (u32) sb->bytes_used; -+ len += (part->offset & 0x000fffff); -+ len += (mtd->erasesize - 1); -+ len &= ~(mtd->erasesize - 1); -+ len -= (part->offset & 0x000fffff); -+ -+ if (len + mtd->erasesize > part->size) -+ break; -+ -+ part = &mtd_parts[++j]; -+ -+ part->offset += len; -+ part->size -= len; -+ -+ part->name = kmalloc(10, GFP_KERNEL); -+ sprintf(part->name, "rootfs%d", j - i); -+ } -+ } -+ if (!strcmp(part->name, "RedBoot config")) { -+ /* add anoterh partition for the board config data */ -+ memcpy(&mtd_parts[j + 1], part, sizeof(struct mtd_partition)); -+ j++; -+ part = &mtd_parts[j]; -+ part->offset += part->size; -+ part->size = mtd->erasesize; -+ -+ part->name = kmalloc(16, GFP_KERNEL); -+ sprintf(part->name, "board_config"); -+ } -+ } -+ num_parts += j - i; -+ kfree(buf); -+ -+#ifdef SPIFLASH_DEBUG -+ printk (KERN_DEBUG "Found %d redboot partitions\n", num_parts); -+#endif -+ if (num_parts) { -+ result = add_mtd_partitions(mtd, mtd_parts, num_parts); -+ } else { -+#ifdef SPIFLASH_DEBUG -+ printk (KERN_DEBUG "Did not find any redboot partitions\n"); -+#endif -+ kfree(mtd); -+ kfree(spidata); -+ return (-ENXIO); -+ } -+ -+ spidata->mtd = mtd; -+ -+ return (result); -+} -+ -+void __exit -+spiflash_exit (void) -+{ -+ if (spidata && spidata->parsed_parts) { -+ del_mtd_partitions (spidata->mtd); -+ kfree(spidata->mtd); -+ kfree(spidata); -+ } -+} -+ -+module_init (spiflash_init); -+module_exit (spiflash_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Atheros Communications Inc"); -+MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros SOC"); -+ -diff -urN linux.old/drivers/mtd/devices/spiflash.h linux.dev/drivers/mtd/devices/spiflash.h ---- linux.old/drivers/mtd/devices/spiflash.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/mtd/devices/spiflash.h 2006-12-15 06:59:43.000000000 +0100 -@@ -0,0 +1,124 @@ -+/* -+ * SPI Flash Memory support header file. -+ * -+ * $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/drivers/mtd/devices/spiflash.h#3 $ -+ * -+ * -+ * Copyright (c) 2005, Atheros Communications Inc. -+ * Copyright (C) 2006 FON Technology, SL. -+ * Copyright (C) 2006 Imre Kaloz -+ * -+ * This code is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+#define FLASH_1MB 1 -+#define FLASH_2MB 2 -+#define FLASH_4MB 3 -+#define FLASH_8MB 4 -+#define MAX_FLASH 5 -+ -+#define STM_PAGE_SIZE 256 -+ -+#define SPI_WRITE_ENABLE 0 -+#define SPI_WRITE_DISABLE 1 -+#define SPI_RD_STATUS 2 -+#define SPI_WR_STATUS 3 -+#define SPI_RD_DATA 4 -+#define SPI_FAST_RD_DATA 5 -+#define SPI_PAGE_PROGRAM 6 -+#define SPI_SECTOR_ERASE 7 -+#define SPI_BULK_ERASE 8 -+#define SPI_DEEP_PWRDOWN 9 -+#define SPI_RD_SIG 10 -+#define SPI_MAX_OPCODES 11 -+ -+#define SFI_WRITE_BUFFER_SIZE 4 -+#define SFI_FLASH_ADDR_MASK 0x00ffffff -+ -+#define STM_8MBIT_SIGNATURE 0x13 -+#define STM_M25P80_BYTE_COUNT 1048576 -+#define STM_M25P80_SECTOR_COUNT 16 -+#define STM_M25P80_SECTOR_SIZE 0x10000 -+ -+#define STM_16MBIT_SIGNATURE 0x14 -+#define STM_M25P16_BYTE_COUNT 2097152 -+#define STM_M25P16_SECTOR_COUNT 32 -+#define STM_M25P16_SECTOR_SIZE 0x10000 -+ -+#define STM_32MBIT_SIGNATURE 0x15 -+#define STM_M25P32_BYTE_COUNT 4194304 -+#define STM_M25P32_SECTOR_COUNT 64 -+#define STM_M25P32_SECTOR_SIZE 0x10000 -+ -+#define STM_64MBIT_SIGNATURE 0x16 -+#define STM_M25P64_BYTE_COUNT 8388608 -+#define STM_M25P64_SECTOR_COUNT 128 -+#define STM_M25P64_SECTOR_SIZE 0x10000 -+ -+#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT -+#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT -+#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE -+#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT -+#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT -+#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE -+#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT -+#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT -+#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE -+#define STM_8MB_BYTE_COUNT STM_M25P64_BYTE_COUNT -+#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT -+#define STM_8MB_SECTOR_SIZE STM_M25P64_SECTOR_SIZE -+ -+/* -+ * ST Microelectronics Opcodes for Serial Flash -+ */ -+ -+#define STM_OP_WR_ENABLE 0x06 /* Write Enable */ -+#define STM_OP_WR_DISABLE 0x04 /* Write Disable */ -+#define STM_OP_RD_STATUS 0x05 /* Read Status */ -+#define STM_OP_WR_STATUS 0x01 /* Write Status */ -+#define STM_OP_RD_DATA 0x03 /* Read Data */ -+#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */ -+#define STM_OP_PAGE_PGRM 0x02 /* Page Program */ -+#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */ -+#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */ -+#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */ -+#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */ -+ -+#define STM_STATUS_WIP 0x01 /* Write-In-Progress */ -+#define STM_STATUS_WEL 0x02 /* Write Enable Latch */ -+#define STM_STATUS_BP0 0x04 /* Block Protect 0 */ -+#define STM_STATUS_BP1 0x08 /* Block Protect 1 */ -+#define STM_STATUS_BP2 0x10 /* Block Protect 2 */ -+#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */ -+ -+/* -+ * SPI Flash Interface Registers -+ */ -+#define AR531XPLUS_SPI_READ 0x08000000 -+#define AR531XPLUS_SPI_MMR 0x11300000 -+#define AR531XPLUS_SPI_MMR_SIZE 12 -+ -+#define AR531XPLUS_SPI_CTL 0x00 -+#define AR531XPLUS_SPI_OPCODE 0x04 -+#define AR531XPLUS_SPI_DATA 0x08 -+ -+#define SPI_FLASH_READ AR531XPLUS_SPI_READ -+#define SPI_FLASH_MMR AR531XPLUS_SPI_MMR -+#define SPI_FLASH_MMR_SIZE AR531XPLUS_SPI_MMR_SIZE -+#define SPI_FLASH_CTL AR531XPLUS_SPI_CTL -+#define SPI_FLASH_OPCODE AR531XPLUS_SPI_OPCODE -+#define SPI_FLASH_DATA AR531XPLUS_SPI_DATA -+ -+#define SPI_CTL_START 0x00000100 -+#define SPI_CTL_BUSY 0x00010000 -+#define SPI_CTL_TXCNT_MASK 0x0000000f -+#define SPI_CTL_RXCNT_MASK 0x000000f0 -+#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff -+#define SPI_CTL_SIZE_MASK 0x00060000 -+ -+#define SPI_CTL_CLK_SEL_MASK 0x03000000 -+#define SPI_OPCODE_MASK 0x000000ff -+ -+#define SPI_STATUS_WIP STM_STATUS_WIP diff --git a/target/linux/atheros-2.6/patches/120-enable_wireless_for_ahb.patch b/target/linux/atheros-2.6/patches/120-enable_wireless_for_ahb.patch index 616f39458..a959cba9c 100644 --- a/target/linux/atheros-2.6/patches/120-enable_wireless_for_ahb.patch +++ b/target/linux/atheros-2.6/patches/120-enable_wireless_for_ahb.patch @@ -6,7 +6,7 @@ diff -urN linux.old/drivers/net/wireless/Kconfig linux.dev/drivers/net/wireless/ config NET_WIRELESS bool - depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) -+ depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA || AR531X) ++ depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA || ATHEROS) default y endmenu diff --git a/target/linux/atheros-2.6/patches/130-ar2313_ethernet.patch b/target/linux/atheros-2.6/patches/130-ar2313_ethernet.patch index 704054335..960c736ae 100644 --- a/target/linux/atheros-2.6/patches/130-ar2313_ethernet.patch +++ b/target/linux/atheros-2.6/patches/130-ar2313_ethernet.patch @@ -1,2048 +1,3 @@ -diff -urN linux.old/drivers/net/ar2313/ar2313.c linux.eth/drivers/net/ar2313/ar2313.c ---- linux.old/drivers/net/ar2313/ar2313.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.eth/drivers/net/ar2313/ar2313.c 2006-12-16 04:30:44.000000000 +0100 -@@ -0,0 +1,1545 @@ -+/* -+ * ar2313.c: Linux driver for the Atheros AR231z Ethernet device. -+ * -+ * Copyright (C) 2004 by Sameer Dekate -+ * Copyright (C) 2006 Imre Kaloz -+ * Copyright (C) 2006 Felix Fietkau -+ * -+ * Thanks to Atheros for providing hardware and documentation -+ * enabling me to write this driver. -+ * -+ * 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. -+ * -+ * Additional credits: -+ * This code is taken from John Taylor's Sibyte driver and then -+ * modified for the AR2313. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#undef INDEX_DEBUG -+#define DEBUG 0 -+#define DEBUG_TX 0 -+#define DEBUG_RX 0 -+#define DEBUG_INT 0 -+#define DEBUG_MC 0 -+#define DEBUG_ERR 1 -+ -+#ifndef min -+#define min(a,b) (((a)<(b))?(a):(b)) -+#endif -+ -+#ifndef SMP_CACHE_BYTES -+#define SMP_CACHE_BYTES L1_CACHE_BYTES -+#endif -+ -+#ifndef SET_MODULE_OWNER -+#define SET_MODULE_OWNER(dev) {do{} while(0);} -+#define AR2313_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -+#define AR2313_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -+#else -+#define AR2313_MOD_INC_USE_COUNT {do{} while(0);} -+#define AR2313_MOD_DEC_USE_COUNT {do{} while(0);} -+#endif -+ -+#define PHYSADDR(a) ((_ACAST32_ (a)) & 0x1fffffff) -+ -+static char ifname[5] = "bond"; -+ -+module_param_string(ifname, ifname, 5, 0); -+ -+#define AR2313_MBOX_SET_BIT 0x8 -+ -+#define BOARD_IDX_STATIC 0 -+#define BOARD_IDX_OVERFLOW -1 -+ -+#include "ar2313_msg.h" -+#include "platform.h" -+#include "dma.h" -+#include "ar2313.h" -+ -+/* -+ * New interrupt handler strategy: -+ * -+ * An old interrupt handler worked using the traditional method of -+ * replacing an skbuff with a new one when a packet arrives. However -+ * the rx rings do not need to contain a static number of buffer -+ * descriptors, thus it makes sense to move the memory allocation out -+ * of the main interrupt handler and do it in a bottom half handler -+ * and only allocate new buffers when the number of buffers in the -+ * ring is below a certain threshold. In order to avoid starving the -+ * NIC under heavy load it is however necessary to force allocation -+ * when hitting a minimum threshold. The strategy for alloction is as -+ * follows: -+ * -+ * RX_LOW_BUF_THRES - allocate buffers in the bottom half -+ * RX_PANIC_LOW_THRES - we are very low on buffers, allocate -+ * the buffers in the interrupt handler -+ * RX_RING_THRES - maximum number of buffers in the rx ring -+ * -+ * One advantagous side effect of this allocation approach is that the -+ * entire rx processing can be done without holding any spin lock -+ * since the rx rings and registers are totally independent of the tx -+ * ring and its registers. This of course includes the kmalloc's of -+ * new skb's. Thus start_xmit can run in parallel with rx processing -+ * and the memory allocation on SMP systems. -+ * -+ * Note that running the skb reallocation in a bottom half opens up -+ * another can of races which needs to be handled properly. In -+ * particular it can happen that the interrupt handler tries to run -+ * the reallocation while the bottom half is either running on another -+ * CPU or was interrupted on the same CPU. To get around this the -+ * driver uses bitops to prevent the reallocation routines from being -+ * reentered. -+ * -+ * TX handling can also be done without holding any spin lock, wheee -+ * this is fun! since tx_csm is only written to by the interrupt -+ * handler. -+ */ -+ -+/* -+ * Threshold values for RX buffer allocation - the low water marks for -+ * when to start refilling the rings are set to 75% of the ring -+ * sizes. It seems to make sense to refill the rings entirely from the -+ * intrrupt handler once it gets below the panic threshold, that way -+ * we don't risk that the refilling is moved to another CPU when the -+ * one running the interrupt handler just got the slab code hot in its -+ * cache. -+ */ -+#define RX_RING_SIZE AR2313_DESCR_ENTRIES -+#define RX_PANIC_THRES (RX_RING_SIZE/4) -+#define RX_LOW_THRES ((3*RX_RING_SIZE)/4) -+#define CRC_LEN 4 -+#define RX_OFFSET 2 -+ -+#define AR2313_BUFSIZE (AR2313_MTU + ETH_HLEN + CRC_LEN + RX_OFFSET) -+ -+#ifdef MODULE -+MODULE_AUTHOR("Sameer Dekate , Imre Kaloz , Felix Fietkau "); -+MODULE_DESCRIPTION("AR2313 Ethernet driver"); -+#endif -+ -+#if DEBUG -+static char version[] __initdata = -+ "ar2313.c: v0.03 2006/07/12 sdekate@arubanetworks.com\n"; -+#endif /* DEBUG */ -+ -+#define virt_to_phys(x) ((u32)(x) & 0x1fffffff) -+ -+// prototypes -+static short armiiread(short phy, short reg); -+static void armiiwrite(short phy, short reg, short data); -+#ifdef TX_TIMEOUT -+static void ar2313_tx_timeout(struct net_device *dev); -+#endif -+static void ar2313_halt(struct net_device *dev); -+static void rx_tasklet_func(unsigned long data); -+static void ar2313_multicast_list(struct net_device *dev); -+ -+static int probed __initdata = 0; -+static unsigned long ar_eth_base; -+static unsigned long ar_dma_base; -+static unsigned long ar_int_base; -+static unsigned long ar_int_mac_mask; -+static unsigned long ar_int_phy_mask; -+ -+#ifndef ERR -+#define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args) -+#endif -+ -+ -+int __init ar2313_probe(struct platform_device *pdev) -+{ -+ struct net_device *dev; -+ struct ar2313_private *sp; -+ struct ar531x_eth *cfg; -+ struct resource *res; -+ int version_disp; -+ char name[64] ; -+ -+ if (probed) -+ return -ENODEV; -+ probed++; -+ -+ version_disp = 0; -+ sprintf(name, "%s%%d", ifname) ; -+ dev = alloc_etherdev(sizeof(struct ar2313_private)); -+ -+ if (dev == NULL) { -+ printk(KERN_ERR "ar2313: Unable to allocate net_device structure!\n"); -+ return -ENOMEM; -+ } -+ -+ SET_MODULE_OWNER(dev); -+ platform_set_drvdata(pdev, dev); -+ -+ sp = dev->priv; -+ sp->dev = dev; -+ cfg = pdev->dev.platform_data; -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth_membase"); -+ if (!res) -+ return -ENODEV; -+ -+ sp->link = 0; -+ ar_eth_base = res->start; -+ ar_dma_base = ar_eth_base + 0x1000; -+ ar_int_base = cfg->reset_base; -+ ar_int_mac_mask = cfg->reset_mac; -+ ar_int_phy_mask = cfg->reset_phy; -+ sp->phy = cfg->phy; -+ -+ dev->irq = platform_get_irq_byname(pdev, "eth_irq"); -+ -+ spin_lock_init(&sp->lock); -+ -+ /* initialize func pointers */ -+ dev->open = &ar2313_open; -+ dev->stop = &ar2313_close; -+ dev->hard_start_xmit = &ar2313_start_xmit; -+ -+ dev->get_stats = &ar2313_get_stats; -+ dev->set_multicast_list = &ar2313_multicast_list; -+#ifdef TX_TIMEOUT -+ dev->tx_timeout = ar2313_tx_timeout; -+ dev->watchdog_timeo = AR2313_TX_TIMEOUT; -+#endif -+ dev->do_ioctl = &ar2313_ioctl; -+ -+ // SAMEER: do we need this? -+ dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA; -+ -+ tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long) dev); -+ tasklet_disable(&sp->rx_tasklet); -+ -+ /* display version info if adapter is found */ -+ if (!version_disp) { -+ /* set display flag to TRUE so that */ -+ /* we only display this string ONCE */ -+ version_disp = 1; -+#if DEBUG -+ printk(version); -+#endif /* DEBUG */ -+ } -+ -+#if 0 -+ request_region(PHYSADDR(ar_eth_base), ETHERNET_SIZE*ETHERNET_MACS, -+ "AR2313ENET"); -+#endif -+ -+ sp->eth_regs = ioremap_nocache(PHYSADDR(ar_eth_base), sizeof(*sp->eth_regs)); -+ if (!sp->eth_regs) { -+ printk("Can't remap eth registers\n"); -+ return(-ENXIO); -+ } -+ -+ sp->dma_regs = ioremap_nocache(PHYSADDR(ar_eth_base + 0x1000), sizeof(*sp->dma_regs)); -+ dev->base_addr = (unsigned int) sp->dma_regs; -+ if (!sp->dma_regs) { -+ printk("Can't remap DMA registers\n"); -+ return(-ENXIO); -+ } -+ -+ sp->int_regs = ioremap_nocache(PHYSADDR(ar_int_base), 4); -+ if (!sp->int_regs) { -+ printk("Can't remap INTERRUPT registers\n"); -+ return(-ENXIO); -+ } -+ -+ strncpy(sp->name, "Atheros AR2313", sizeof (sp->name) - 1); -+ sp->name [sizeof (sp->name) - 1] = '\0'; -+ -+ { -+ /* XXX: Will have to rewrite this part later */ -+ char *configstart; -+ unsigned char def_mac[6] = {0, 0xaa, 0xbb, 0xcc, 0xdd, 0xee}; -+ -+ configstart = (char *) cfg->board_config; -+ -+ if (!configstart) { -+ printk("no valid mac found, using defaults"); -+ memcpy(dev->dev_addr, def_mac, 6); -+ } else { -+ memcpy(dev->dev_addr, ((u8 *)configstart)+102, 6); -+ } -+ } -+ -+ sp->board_idx = BOARD_IDX_STATIC; -+ -+ if (ar2313_init(dev)) { -+ /* -+ * ar2313_init() calls ar2313_init_cleanup() on error. -+ */ -+ kfree(dev); -+ return -ENODEV; -+ } -+ -+ if (register_netdev(dev)){ -+ printk("%s: register_netdev failed\n", __func__); -+ return -1; -+ } -+ -+ printk("%s: %s: %02x:%02x:%02x:%02x:%02x:%02x, irq %d\n", -+ dev->name, sp->name, -+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], -+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], -+ dev->irq); -+ -+ /* start link poll timer */ -+ ar2313_setup_timer(dev); -+ -+ return 0; -+} -+ -+#if 0 -+static void ar2313_dump_regs(struct net_device *dev) -+{ -+ unsigned int *ptr, i; -+ struct ar2313_private *sp = (struct ar2313_private *)dev->priv; -+ -+ ptr = (unsigned int *)sp->eth_regs; -+ for(i=0; i< (sizeof(ETHERNET_STRUCT)/ sizeof(unsigned int)); i++, ptr++) { -+ printk("ENET: %08x = %08x\n", (int)ptr, *ptr); -+ } -+ -+ ptr = (unsigned int *)sp->dma_regs; -+ for(i=0; i< (sizeof(DMA)/ sizeof(unsigned int)); i++, ptr++) { -+ printk("DMA: %08x = %08x\n", (int)ptr, *ptr); -+ } -+ -+ ptr = (unsigned int *)sp->int_regs; -+ for(i=0; i< (sizeof(INTERRUPT)/ sizeof(unsigned int)); i++, ptr++){ -+ printk("INT: %08x = %08x\n", (int)ptr, *ptr); -+ } -+ -+ for (i = 0; i < AR2313_DESCR_ENTRIES; i++) { -+ ar2313_descr_t *td = &sp->tx_ring[i]; -+ printk("Tx desc %2d: %08x %08x %08x %08x\n", i, -+ td->status, td->devcs, td->addr, td->descr); -+ } -+} -+#endif -+ -+#ifdef TX_TIMEOUT -+static void -+ar2313_tx_timeout(struct net_device *dev) -+{ -+ struct ar2313_private *sp = (struct ar2313_private *)dev->priv; -+ unsigned long flags; -+ -+#if DEBUG_TX -+ printk("Tx timeout\n"); -+#endif -+ spin_lock_irqsave(&sp->lock, flags); -+ ar2313_restart(dev); -+ spin_unlock_irqrestore(&sp->lock, flags); -+} -+#endif -+ -+#if DEBUG_MC -+static void -+printMcList(struct net_device *dev) -+{ -+ struct dev_mc_list *list = dev->mc_list; -+ int num=0, i; -+ while(list){ -+ printk("%d MC ADDR ", num); -+ for(i=0;idmi_addrlen;i++) { -+ printk(":%02x", list->dmi_addr[i]); -+ } -+ list = list->next; -+ printk("\n"); -+ } -+} -+#endif -+ -+/* -+ * Set or clear the multicast filter for this adaptor. -+ * THIS IS ABSOLUTE CRAP, disabled -+ */ -+static void -+ar2313_multicast_list(struct net_device *dev) -+{ -+ /* -+ * Always listen to broadcasts and -+ * treat IFF bits independently -+ */ -+ struct ar2313_private *sp = (struct ar2313_private *)dev->priv; -+ unsigned int recognise; -+ -+ recognise = sp->eth_regs->mac_control; -+ -+ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ -+ recognise |= MAC_CONTROL_PR; -+ } else { -+ recognise &= ~MAC_CONTROL_PR; -+ } -+ -+ if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) { -+#if DEBUG_MC -+ printMcList(dev); -+ printk("%s: all MULTICAST mc_count %d\n", __FUNCTION__, dev->mc_count); -+#endif -+ recognise |= MAC_CONTROL_PM;/* all multicast */ -+ } else if (dev->mc_count > 0) { -+#if DEBUG_MC -+ printMcList(dev); -+ printk("%s: mc_count %d\n", __FUNCTION__, dev->mc_count); -+#endif -+ recognise |= MAC_CONTROL_PM; /* for the time being */ -+ } -+#if DEBUG_MC -+ printk("%s: setting %08x to %08x\n", __FUNCTION__, (int)sp->eth_regs, recognise); -+#endif -+ -+ sp->eth_regs->mac_control = recognise; -+} -+ -+static void rx_tasklet_cleanup(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ -+ /* -+ * Tasklet may be scheduled. Need to get it removed from the list -+ * since we're about to free the struct. -+ */ -+ -+ sp->unloading = 1; -+ tasklet_enable(&sp->rx_tasklet); -+ tasklet_kill(&sp->rx_tasklet); -+} -+ -+static int __exit ar2313_remove(struct platform_device *pdev) -+{ -+ struct net_device *dev = platform_get_drvdata(pdev); -+ rx_tasklet_cleanup(dev); -+ ar2313_init_cleanup(dev); -+ unregister_netdev(dev); -+ kfree(dev); -+ return 0; -+} -+ -+ -+/* -+ * Restart the AR2313 ethernet controller. -+ */ -+static int ar2313_restart(struct net_device *dev) -+{ -+ /* disable interrupts */ -+ disable_irq(dev->irq); -+ -+ /* stop mac */ -+ ar2313_halt(dev); -+ -+ /* initialize */ -+ ar2313_init(dev); -+ -+ /* enable interrupts */ -+ enable_irq(dev->irq); -+ -+ return 0; -+} -+ -+static struct platform_driver ar2313_driver = { -+ .driver.name = "ar531x-eth", -+ .probe = ar2313_probe, -+ .remove = ar2313_remove, -+}; -+ -+int __init ar2313_module_init(void) -+{ -+ return platform_driver_register(&ar2313_driver); -+} -+ -+void __exit ar2313_module_cleanup(void) -+{ -+ platform_driver_unregister(&ar2313_driver); -+} -+ -+module_init(ar2313_module_init); -+module_exit(ar2313_module_cleanup); -+ -+ -+static void ar2313_free_descriptors(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ if (sp->rx_ring != NULL) { -+ kfree((void*)KSEG0ADDR(sp->rx_ring)); -+ sp->rx_ring = NULL; -+ sp->tx_ring = NULL; -+ } -+} -+ -+ -+static int ar2313_allocate_descriptors(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ int size; -+ int j; -+ ar2313_descr_t *space; -+ -+ if(sp->rx_ring != NULL){ -+ printk("%s: already done.\n", __FUNCTION__); -+ return 0; -+ } -+ -+ size = (sizeof(ar2313_descr_t) * (AR2313_DESCR_ENTRIES * AR2313_QUEUES)); -+ space = kmalloc(size, GFP_KERNEL); -+ if (space == NULL) -+ return 1; -+ -+ /* invalidate caches */ -+ dma_cache_inv((unsigned int)space, size); -+ -+ /* now convert pointer to KSEG1 */ -+ space = (ar2313_descr_t *)KSEG1ADDR(space); -+ -+ memset((void *)space, 0, size); -+ -+ sp->rx_ring = space; -+ space += AR2313_DESCR_ENTRIES; -+ -+ sp->tx_ring = space; -+ space += AR2313_DESCR_ENTRIES; -+ -+ /* Initialize the transmit Descriptors */ -+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { -+ ar2313_descr_t *td = &sp->tx_ring[j]; -+ td->status = 0; -+ td->devcs = DMA_TX1_CHAINED; -+ td->addr = 0; -+ td->descr = K1_TO_PHYS(&sp->tx_ring[(j+1) & (AR2313_DESCR_ENTRIES-1)]); -+ } -+ -+ return 0; -+} -+ -+ -+/* -+ * Generic cleanup handling data allocated during init. Used when the -+ * module is unloaded or if an error occurs during initialization -+ */ -+static void ar2313_init_cleanup(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ struct sk_buff *skb; -+ int j; -+ -+ ar2313_free_descriptors(dev); -+ -+ if (sp->eth_regs) iounmap((void*)sp->eth_regs); -+ if (sp->dma_regs) iounmap((void*)sp->dma_regs); -+ -+ if (sp->rx_skb) { -+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { -+ skb = sp->rx_skb[j]; -+ if (skb) { -+ sp->rx_skb[j] = NULL; -+ dev_kfree_skb(skb); -+ } -+ } -+ kfree(sp->rx_skb); -+ sp->rx_skb = NULL; -+ } -+ -+ if (sp->tx_skb) { -+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { -+ skb = sp->tx_skb[j]; -+ if (skb) { -+ sp->tx_skb[j] = NULL; -+ dev_kfree_skb(skb); -+ } -+ } -+ kfree(sp->tx_skb); -+ sp->tx_skb = NULL; -+ } -+} -+ -+static int ar2313_setup_timer(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ -+ init_timer(&sp->link_timer); -+ -+ sp->link_timer.function = ar2313_link_timer_fn; -+ sp->link_timer.data = (int) dev; -+ sp->link_timer.expires = jiffies + HZ; -+ -+ add_timer(&sp->link_timer); -+ return 0; -+ -+} -+ -+static void ar2313_link_timer_fn(unsigned long data) -+{ -+ struct net_device *dev = (struct net_device *) data; -+ struct ar2313_private *sp = dev->priv; -+ -+ // see if the link status changed -+ // This was needed to make sure we set the PHY to the -+ // autonegotiated value of half or full duplex. -+ ar2313_check_link(dev); -+ -+ // Loop faster when we don't have link. -+ // This was needed to speed up the AP bootstrap time. -+ if(sp->link == 0) { -+ mod_timer(&sp->link_timer, jiffies + HZ/2); -+ } else { -+ mod_timer(&sp->link_timer, jiffies + LINK_TIMER); -+ } -+} -+ -+static void ar2313_check_link(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ u16 phyData; -+ -+ phyData = armiiread(sp->phy, MII_BMSR); -+ if (sp->phyData != phyData) { -+ if (phyData & BMSR_LSTATUS) { -+ /* link is present, ready link partner ability to deterine duplexity */ -+ int duplex = 0; -+ u16 reg; -+ -+ sp->link = 1; -+ reg = armiiread(sp->phy, MII_BMCR); -+ if (reg & BMCR_ANENABLE) { -+ /* auto neg enabled */ -+ reg = armiiread(sp->phy, MII_LPA); -+ duplex = (reg & (LPA_100FULL|LPA_10FULL))? 1:0; -+ } else { -+ /* no auto neg, just read duplex config */ -+ duplex = (reg & BMCR_FULLDPLX)? 1:0; -+ } -+ -+ printk(KERN_INFO "%s: Configuring MAC for %s duplex\n", dev->name, -+ (duplex)? "full":"half"); -+ -+ if (duplex) { -+ /* full duplex */ -+ sp->eth_regs->mac_control = ((sp->eth_regs->mac_control | MAC_CONTROL_F) & -+ ~MAC_CONTROL_DRO); -+ } else { -+ /* half duplex */ -+ sp->eth_regs->mac_control = ((sp->eth_regs->mac_control | MAC_CONTROL_DRO) & -+ ~MAC_CONTROL_F); -+ } -+ } else { -+ /* no link */ -+ sp->link = 0; -+ } -+ sp->phyData = phyData; -+ } -+} -+ -+static int -+ar2313_reset_reg(struct net_device *dev) -+{ -+ struct ar2313_private *sp = (struct ar2313_private *)dev->priv; -+ unsigned int ethsal, ethsah; -+ unsigned int flags; -+ -+ *sp->int_regs |= ar_int_mac_mask; -+ mdelay(10); -+ *sp->int_regs &= ~ar_int_mac_mask; -+ mdelay(10); -+ *sp->int_regs |= ar_int_phy_mask; -+ mdelay(10); -+ *sp->int_regs &= ~ar_int_phy_mask; -+ mdelay(10); -+ -+ sp->dma_regs->bus_mode = (DMA_BUS_MODE_SWR); -+ mdelay(10); -+ sp->dma_regs->bus_mode = ((32 << DMA_BUS_MODE_PBL_SHIFT) | DMA_BUS_MODE_BLE); -+ -+ /* enable interrupts */ -+ sp->dma_regs->intr_ena = (DMA_STATUS_AIS | -+ DMA_STATUS_NIS | -+ DMA_STATUS_RI | -+ DMA_STATUS_TI | -+ DMA_STATUS_FBE); -+ sp->dma_regs->xmt_base = K1_TO_PHYS(sp->tx_ring); -+ sp->dma_regs->rcv_base = K1_TO_PHYS(sp->rx_ring); -+ sp->dma_regs->control = (DMA_CONTROL_SR | DMA_CONTROL_ST | DMA_CONTROL_SF); -+ -+ sp->eth_regs->flow_control = (FLOW_CONTROL_FCE); -+ sp->eth_regs->vlan_tag = (0x8100); -+ -+ /* Enable Ethernet Interface */ -+ flags = (MAC_CONTROL_TE | /* transmit enable */ -+ MAC_CONTROL_PM | /* pass mcast */ -+ MAC_CONTROL_F | /* full duplex */ -+ MAC_CONTROL_HBD); /* heart beat disabled */ -+ -+ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ -+ flags |= MAC_CONTROL_PR; -+ } -+ sp->eth_regs->mac_control = flags; -+ -+ /* Set all Ethernet station address registers to their initial values */ -+ ethsah = ((((u_int)(dev->dev_addr[5]) << 8) & (u_int)0x0000FF00) | -+ (((u_int)(dev->dev_addr[4]) << 0) & (u_int)0x000000FF)); -+ -+ ethsal = ((((u_int)(dev->dev_addr[3]) << 24) & (u_int)0xFF000000) | -+ (((u_int)(dev->dev_addr[2]) << 16) & (u_int)0x00FF0000) | -+ (((u_int)(dev->dev_addr[1]) << 8) & (u_int)0x0000FF00) | -+ (((u_int)(dev->dev_addr[0]) << 0) & (u_int)0x000000FF) ); -+ -+ sp->eth_regs->mac_addr[0] = ethsah; -+ sp->eth_regs->mac_addr[1] = ethsal; -+ -+ mdelay(10); -+ -+ return(0); -+} -+ -+ -+static int ar2313_init(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ int ecode=0; -+ -+ /* -+ * Allocate descriptors -+ */ -+ if (ar2313_allocate_descriptors(dev)) { -+ printk("%s: %s: ar2313_allocate_descriptors failed\n", -+ dev->name, __FUNCTION__); -+ ecode = -EAGAIN; -+ goto init_error; -+ } -+ -+ /* -+ * Get the memory for the skb rings. -+ */ -+ if(sp->rx_skb == NULL) { -+ sp->rx_skb = kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES, GFP_KERNEL); -+ if (!(sp->rx_skb)) { -+ printk("%s: %s: rx_skb kmalloc failed\n", -+ dev->name, __FUNCTION__); -+ ecode = -EAGAIN; -+ goto init_error; -+ } -+ } -+ memset(sp->rx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES); -+ -+ if(sp->tx_skb == NULL) { -+ sp->tx_skb = kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES, GFP_KERNEL); -+ if (!(sp->tx_skb)) { -+ printk("%s: %s: tx_skb kmalloc failed\n", -+ dev->name, __FUNCTION__); -+ ecode = -EAGAIN; -+ goto init_error; -+ } -+ } -+ memset(sp->tx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES); -+ -+ /* -+ * Set tx_csm before we start receiving interrupts, otherwise -+ * the interrupt handler might think it is supposed to process -+ * tx ints before we are up and running, which may cause a null -+ * pointer access in the int handler. -+ */ -+ sp->rx_skbprd = 0; -+ sp->cur_rx = 0; -+ sp->tx_prd = 0; -+ sp->tx_csm = 0; -+ -+ /* -+ * Zero the stats before starting the interface -+ */ -+ memset(&sp->stats, 0, sizeof(sp->stats)); -+ -+ /* -+ * We load the ring here as there seem to be no way to tell the -+ * firmware to wipe the ring without re-initializing it. -+ */ -+ ar2313_load_rx_ring(dev, RX_RING_SIZE); -+ -+ /* -+ * Init hardware -+ */ -+ ar2313_reset_reg(dev); -+ -+ /* -+ * Get the IRQ -+ */ -+ ecode = request_irq(dev->irq, &ar2313_interrupt, IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, dev->name, dev); -+ if (ecode) { -+ printk(KERN_WARNING "%s: %s: Requested IRQ %d is busy\n", -+ dev->name, __FUNCTION__, dev->irq); -+ goto init_error; -+ } -+ -+ -+ tasklet_enable(&sp->rx_tasklet); -+ -+ return 0; -+ -+ init_error: -+ ar2313_init_cleanup(dev); -+ return ecode; -+} -+ -+/* -+ * Load the rx ring. -+ * -+ * Loading rings is safe without holding the spin lock since this is -+ * done only before the device is enabled, thus no interrupts are -+ * generated and by the interrupt handler/tasklet handler. -+ */ -+static void ar2313_load_rx_ring(struct net_device *dev, int nr_bufs) -+{ -+ -+ struct ar2313_private *sp = ((struct net_device *)dev)->priv; -+ short i, idx; -+ -+ idx = sp->rx_skbprd; -+ -+ for (i = 0; i < nr_bufs; i++) { -+ struct sk_buff *skb; -+ ar2313_descr_t *rd; -+ -+ if (sp->rx_skb[idx]) { -+#if DEBUG_RX -+ printk(KERN_INFO "ar2313 rx refill full\n"); -+#endif /* DEBUG */ -+ break; -+ } -+ -+ // partha: create additional room for the second GRE fragment -+ skb = alloc_skb(AR2313_BUFSIZE+128, GFP_ATOMIC); -+ if (!skb) { -+ printk("\n\n\n\n %s: No memory in system\n\n\n\n", __FUNCTION__); -+ break; -+ } -+ // partha: create additional room in the front for tx pkt capture -+ skb_reserve(skb, 32); -+ -+ /* -+ * Make sure IP header starts on a fresh cache line. -+ */ -+ skb->dev = dev; -+ skb_reserve(skb, RX_OFFSET); -+ sp->rx_skb[idx] = skb; -+ -+ rd = (ar2313_descr_t *) &sp->rx_ring[idx]; -+ -+ /* initialize dma descriptor */ -+ rd->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) | -+ DMA_RX1_CHAINED); -+ rd->addr = virt_to_phys(skb->data); -+ rd->descr = virt_to_phys(&sp->rx_ring[(idx+1) & (AR2313_DESCR_ENTRIES-1)]); -+ rd->status = DMA_RX_OWN; -+ -+ idx = DSC_NEXT(idx); -+ } -+ -+ if (!i) { -+#if DEBUG_ERR -+ printk(KERN_INFO "Out of memory when allocating standard receive buffers\n"); -+#endif /* DEBUG */ -+ } else { -+ sp->rx_skbprd = idx; -+ } -+ -+ return; -+} -+ -+#define AR2313_MAX_PKTS_PER_CALL 64 -+ -+static int ar2313_rx_int(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ struct sk_buff *skb, *skb_new; -+ ar2313_descr_t *rxdesc; -+ unsigned int status; -+ u32 idx; -+ int pkts = 0; -+ int rval; -+ -+ idx = sp->cur_rx; -+ -+ /* process at most the entire ring and then wait for another interrupt */ -+ while(1) { -+ -+ rxdesc = &sp->rx_ring[idx]; -+ status = rxdesc->status; -+ if (status & DMA_RX_OWN) { -+ /* SiByte owns descriptor or descr not yet filled in */ -+ rval = 0; -+ break; -+ } -+ -+ if (++pkts > AR2313_MAX_PKTS_PER_CALL) { -+ rval = 1; -+ break; -+ } -+ -+#if DEBUG_RX -+ printk("index %d\n", idx); -+ printk("RX status %08x\n", rxdesc->status); -+ printk("RX devcs %08x\n", rxdesc->devcs ); -+ printk("RX addr %08x\n", rxdesc->addr ); -+ printk("RX descr %08x\n", rxdesc->descr ); -+#endif -+ -+ if ((status & (DMA_RX_ERROR|DMA_RX_ERR_LENGTH)) && -+ (!(status & DMA_RX_LONG))){ -+#if DEBUG_RX -+ printk("%s: rx ERROR %08x\n", __FUNCTION__, status); -+#endif -+ sp->stats.rx_errors++; -+ sp->stats.rx_dropped++; -+ -+ /* add statistics counters */ -+ if (status & DMA_RX_ERR_CRC) sp->stats.rx_crc_errors++; -+ if (status & DMA_RX_ERR_COL) sp->stats.rx_over_errors++; -+ if (status & DMA_RX_ERR_LENGTH) -+ sp->stats.rx_length_errors++; -+ if (status & DMA_RX_ERR_RUNT) sp->stats.rx_over_errors++; -+ if (status & DMA_RX_ERR_DESC) sp->stats.rx_over_errors++; -+ -+ } else { -+ /* alloc new buffer. */ -+ skb_new = dev_alloc_skb(AR2313_BUFSIZE + RX_OFFSET + 128); -+ if (skb_new != NULL) { -+ -+ skb = sp->rx_skb[idx]; -+ /* set skb */ -+ skb_put(skb, ((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN); -+ -+#ifdef CONFIG_MERLOT -+ if ((dev->am_pkt_handler == NULL) || -+ (dev->am_pkt_handler(skb, dev) == 0)) { -+#endif -+ sp->stats.rx_bytes += skb->len; -+ skb->protocol = eth_type_trans(skb, dev); -+ /* pass the packet to upper layers */ -+ -+#ifdef CONFIG_MERLOT -+ if (dev->asap_netif_rx) -+ dev->asap_netif_rx(skb); -+ else -+#endif -+ netif_rx(skb); -+#ifdef CONFIG_MERLOT -+ } -+#endif -+ skb_new->dev = dev; -+ /* 16 bit align */ -+ skb_reserve(skb_new, RX_OFFSET+32); -+ /* reset descriptor's curr_addr */ -+ rxdesc->addr = virt_to_phys(skb_new->data); -+ -+ sp->stats.rx_packets++; -+ sp->rx_skb[idx] = skb_new; -+ -+ } else { -+ sp->stats.rx_dropped++; -+ } -+ } -+ -+ rxdesc->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) | -+ DMA_RX1_CHAINED); -+ rxdesc->status = DMA_RX_OWN; -+ -+ idx = DSC_NEXT(idx); -+ } -+ -+ sp->cur_rx = idx; -+ -+ return rval; -+} -+ -+ -+static void ar2313_tx_int(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ u32 idx; -+ struct sk_buff *skb; -+ ar2313_descr_t *txdesc; -+ unsigned int status=0; -+ -+ idx = sp->tx_csm; -+ -+ while (idx != sp->tx_prd) { -+ -+ txdesc = &sp->tx_ring[idx]; -+ -+#if DEBUG_TX -+ printk("%s: TXINT: csm=%d idx=%d prd=%d status=%x devcs=%x addr=%08x descr=%x\n", -+ dev->name, sp->tx_csm, idx, sp->tx_prd, -+ txdesc->status, txdesc->devcs, txdesc->addr, txdesc->descr); -+#endif /* DEBUG */ -+ -+ if ((status = txdesc->status) & DMA_TX_OWN) { -+ /* ar2313 dma still owns descr */ -+ break; -+ } -+ /* done with this descriptor */ -+ dma_unmap_single(NULL, txdesc->addr, txdesc->devcs & DMA_TX1_BSIZE_MASK, DMA_TO_DEVICE); -+ txdesc->status = 0; -+ -+ if (status & DMA_TX_ERROR){ -+ sp->stats.tx_errors++; -+ sp->stats.tx_dropped++; -+ if(status & DMA_TX_ERR_UNDER) -+ sp->stats.tx_fifo_errors++; -+ if(status & DMA_TX_ERR_HB) -+ sp->stats.tx_heartbeat_errors++; -+ if(status & (DMA_TX_ERR_LOSS | -+ DMA_TX_ERR_LINK)) -+ sp->stats.tx_carrier_errors++; -+ if (status & (DMA_TX_ERR_LATE| -+ DMA_TX_ERR_COL | -+ DMA_TX_ERR_JABBER | -+ DMA_TX_ERR_DEFER)) -+ sp->stats.tx_aborted_errors++; -+ } else { -+ /* transmit OK */ -+ sp->stats.tx_packets++; -+ } -+ -+ skb = sp->tx_skb[idx]; -+ sp->tx_skb[idx] = NULL; -+ idx = DSC_NEXT(idx); -+ sp->stats.tx_bytes += skb->len; -+ dev_kfree_skb_irq(skb); -+ } -+ -+ sp->tx_csm = idx; -+ -+ return; -+} -+ -+ -+static void -+rx_tasklet_func(unsigned long data) -+{ -+ struct net_device *dev = (struct net_device *) data; -+ struct ar2313_private *sp = dev->priv; -+ -+ if (sp->unloading) { -+ return; -+ } -+ -+ if (ar2313_rx_int(dev)) { -+ tasklet_hi_schedule(&sp->rx_tasklet); -+ } -+ else { -+ unsigned long flags; -+ spin_lock_irqsave(&sp->lock, flags); -+ sp->dma_regs->intr_ena |= DMA_STATUS_RI; -+ spin_unlock_irqrestore(&sp->lock, flags); -+ } -+} -+ -+static void -+rx_schedule(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ -+ sp->dma_regs->intr_ena &= ~DMA_STATUS_RI; -+ -+ tasklet_hi_schedule(&sp->rx_tasklet); -+} -+ -+static irqreturn_t ar2313_interrupt(int irq, void *dev_id) -+{ -+ struct net_device *dev = (struct net_device *)dev_id; -+ struct ar2313_private *sp = dev->priv; -+ unsigned int status, enabled; -+ -+ /* clear interrupt */ -+ /* -+ * Don't clear RI bit if currently disabled. -+ */ -+ status = sp->dma_regs->status; -+ enabled = sp->dma_regs->intr_ena; -+ sp->dma_regs->status = status & enabled; -+ -+ if (status & DMA_STATUS_NIS) { -+ /* normal status */ -+ /* -+ * Don't schedule rx processing if interrupt -+ * is already disabled. -+ */ -+ if (status & enabled & DMA_STATUS_RI) { -+ /* receive interrupt */ -+ rx_schedule(dev); -+ } -+ if (status & DMA_STATUS_TI) { -+ /* transmit interrupt */ -+ ar2313_tx_int(dev); -+ } -+ } -+ -+ if (status & DMA_STATUS_AIS) { -+#if DEBUG_INT -+ printk("%s: AIS set %08x & %x\n", __FUNCTION__, -+ status, (DMA_STATUS_FBE | DMA_STATUS_TPS)); -+#endif -+ /* abnormal status */ -+ if (status & (DMA_STATUS_FBE | DMA_STATUS_TPS)) { -+ ar2313_restart(dev); -+ } -+ } -+ return IRQ_HANDLED; -+} -+ -+ -+static int ar2313_open(struct net_device *dev) -+{ -+ struct ar2313_private *sp; -+ -+ sp = dev->priv; -+ -+ dev->mtu = 1500; -+ netif_start_queue(dev); -+ -+ sp->eth_regs->mac_control |= MAC_CONTROL_RE; -+ -+ AR2313_MOD_INC_USE_COUNT; -+ -+ return 0; -+} -+ -+static void ar2313_halt(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ int j; -+ -+ tasklet_disable(&sp->rx_tasklet); -+ -+ /* kill the MAC */ -+ sp->eth_regs->mac_control &= ~(MAC_CONTROL_RE | /* disable Receives */ -+ MAC_CONTROL_TE); /* disable Transmits */ -+ /* stop dma */ -+ sp->dma_regs->control = 0; -+ sp->dma_regs->bus_mode = DMA_BUS_MODE_SWR; -+ -+ /* place phy and MAC in reset */ -+ *sp->int_regs |= (ar_int_mac_mask | ar_int_phy_mask); -+ -+ /* free buffers on tx ring */ -+ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) { -+ struct sk_buff *skb; -+ ar2313_descr_t *txdesc; -+ -+ txdesc = &sp->tx_ring[j]; -+ txdesc->descr = 0; -+ -+ skb = sp->tx_skb[j]; -+ if (skb) { -+ dev_kfree_skb(skb); -+ sp->tx_skb[j] = NULL; -+ } -+ } -+} -+ -+/* -+ * close should do nothing. Here's why. It's called when -+ * 'ifconfig bond0 down' is run. If it calls free_irq then -+ * the irq is gone forever ! When bond0 is made 'up' again, -+ * the ar2313_open () does not call request_irq (). Worse, -+ * the call to ar2313_halt() generates a WDOG reset due to -+ * the write to 'sp->int_regs' and the box reboots. -+ * Commenting this out is good since it allows the -+ * system to resume when bond0 is made up again. -+ */ -+static int ar2313_close(struct net_device *dev) -+{ -+#if 0 -+ /* -+ * Disable interrupts -+ */ -+ disable_irq(dev->irq); -+ -+ /* -+ * Without (or before) releasing irq and stopping hardware, this -+ * is an absolute non-sense, by the way. It will be reset instantly -+ * by the first irq. -+ */ -+ netif_stop_queue(dev); -+ -+ /* stop the MAC and DMA engines */ -+ ar2313_halt(dev); -+ -+ /* release the interrupt */ -+ free_irq(dev->irq, dev); -+ -+#endif -+ AR2313_MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ ar2313_descr_t *td; -+ u32 idx; -+ -+ idx = sp->tx_prd; -+ td = &sp->tx_ring[idx]; -+ -+ if (td->status & DMA_TX_OWN) { -+#if DEBUG_TX -+ printk("%s: No space left to Tx\n", __FUNCTION__); -+#endif -+ /* free skbuf and lie to the caller that we sent it out */ -+ sp->stats.tx_dropped++; -+ dev_kfree_skb(skb); -+ -+ /* restart transmitter in case locked */ -+ sp->dma_regs->xmt_poll = 0; -+ return 0; -+ } -+ -+ /* Setup the transmit descriptor. */ -+ td->devcs = ((skb->len << DMA_TX1_BSIZE_SHIFT) | -+ (DMA_TX1_LS|DMA_TX1_IC|DMA_TX1_CHAINED)); -+ td->addr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); -+ td->status = DMA_TX_OWN; -+ -+ /* kick transmitter last */ -+ sp->dma_regs->xmt_poll = 0; -+ -+#if DEBUG_TX -+ printk("index %d\n", idx); -+ printk("TX status %08x\n", td->status); -+ printk("TX devcs %08x\n", td->devcs ); -+ printk("TX addr %08x\n", td->addr ); -+ printk("TX descr %08x\n", td->descr ); -+#endif -+ -+ sp->tx_skb[idx] = skb; -+ idx = DSC_NEXT(idx); -+ sp->tx_prd = idx; -+ -+ //dev->trans_start = jiffies; -+ -+ return 0; -+} -+ -+static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) -+{ -+ struct ar2313_private *np = dev->priv; -+ u32 tmp; -+ -+ ecmd->supported = -+ (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | -+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | -+ SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); -+ -+ ecmd->port = PORT_TP; -+ /* only supports internal transceiver */ -+ ecmd->transceiver = XCVR_INTERNAL; -+ /* not sure what this is for */ -+ ecmd->phy_address = 1; -+ -+ ecmd->advertising = ADVERTISED_MII; -+ tmp = armiiread(np->phy, MII_ADVERTISE); -+ if (tmp & ADVERTISE_10HALF) -+ ecmd->advertising |= ADVERTISED_10baseT_Half; -+ if (tmp & ADVERTISE_10FULL) -+ ecmd->advertising |= ADVERTISED_10baseT_Full; -+ if (tmp & ADVERTISE_100HALF) -+ ecmd->advertising |= ADVERTISED_100baseT_Half; -+ if (tmp & ADVERTISE_100FULL) -+ ecmd->advertising |= ADVERTISED_100baseT_Full; -+ -+ tmp = armiiread(np->phy, MII_BMCR); -+ if (tmp & BMCR_ANENABLE) { -+ ecmd->advertising |= ADVERTISED_Autoneg; -+ ecmd->autoneg = AUTONEG_ENABLE; -+ } else { -+ ecmd->autoneg = AUTONEG_DISABLE; -+ } -+ -+ if (ecmd->autoneg == AUTONEG_ENABLE) { -+ tmp = armiiread(np->phy, MII_LPA); -+ if (tmp & (LPA_100FULL|LPA_10FULL)) { -+ ecmd->duplex = DUPLEX_FULL; -+ } else { -+ ecmd->duplex = DUPLEX_HALF; -+ } -+ if (tmp & (LPA_100FULL|LPA_100HALF)) { -+ ecmd->speed = SPEED_100; -+ } else { -+ ecmd->speed = SPEED_10; -+ } -+ } else { -+ if (tmp & BMCR_FULLDPLX) { -+ ecmd->duplex = DUPLEX_FULL; -+ } else { -+ ecmd->duplex = DUPLEX_HALF; -+ } -+ if (tmp & BMCR_SPEED100) { -+ ecmd->speed = SPEED_100; -+ } else { -+ ecmd->speed = SPEED_10; -+ } -+ } -+ -+ /* ignore maxtxpkt, maxrxpkt for now */ -+ -+ return 0; -+} -+ -+static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) -+{ -+ struct ar2313_private *np = dev->priv; -+ u32 tmp; -+ -+ if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) -+ return -EINVAL; -+ if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) -+ return -EINVAL; -+ if (ecmd->port != PORT_TP) -+ return -EINVAL; -+ if (ecmd->transceiver != XCVR_INTERNAL) -+ return -EINVAL; -+ if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) -+ return -EINVAL; -+ /* ignore phy_address, maxtxpkt, maxrxpkt for now */ -+ -+ /* WHEW! now lets bang some bits */ -+ -+ tmp = armiiread(np->phy, MII_BMCR); -+ if (ecmd->autoneg == AUTONEG_ENABLE) { -+ /* turn on autonegotiation */ -+ tmp |= BMCR_ANENABLE; -+ printk("%s: Enabling auto-neg\n", dev->name); -+ } else { -+ /* turn off auto negotiation, set speed and duplexity */ -+ tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); -+ if (ecmd->speed == SPEED_100) -+ tmp |= BMCR_SPEED100; -+ if (ecmd->duplex == DUPLEX_FULL) -+ tmp |= BMCR_FULLDPLX; -+ printk("%s: Hard coding %d/%s\n", dev->name, -+ (ecmd->speed == SPEED_100)? 100:10, -+ (ecmd->duplex == DUPLEX_FULL)? "full":"half"); -+ } -+ armiiwrite(np->phy, MII_BMCR, tmp); -+ np->phyData = 0; -+ return 0; -+} -+ -+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) -+{ -+ struct ar2313_private *np = dev->priv; -+ u32 cmd; -+ -+ if (get_user(cmd, (u32 *)useraddr)) -+ return -EFAULT; -+ -+ switch (cmd) { -+ /* get settings */ -+ case ETHTOOL_GSET: { -+ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; -+ spin_lock_irq(&np->lock); -+ netdev_get_ecmd(dev, &ecmd); -+ spin_unlock_irq(&np->lock); -+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) -+ return -EFAULT; -+ return 0; -+ } -+ /* set settings */ -+ case ETHTOOL_SSET: { -+ struct ethtool_cmd ecmd; -+ int r; -+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) -+ return -EFAULT; -+ spin_lock_irq(&np->lock); -+ r = netdev_set_ecmd(dev, &ecmd); -+ spin_unlock_irq(&np->lock); -+ return r; -+ } -+ /* restart autonegotiation */ -+ case ETHTOOL_NWAY_RST: { -+ int tmp; -+ int r = -EINVAL; -+ /* if autoneg is off, it's an error */ -+ tmp = armiiread(np->phy, MII_BMCR); -+ if (tmp & BMCR_ANENABLE) { -+ tmp |= (BMCR_ANRESTART); -+ armiiwrite(np->phy, MII_BMCR, tmp); -+ r = 0; -+ } -+ return r; -+ } -+ /* get link status */ -+ case ETHTOOL_GLINK: { -+ struct ethtool_value edata = {ETHTOOL_GLINK}; -+ edata.data = (armiiread(np->phy, MII_BMSR)&BMSR_LSTATUS) ? 1:0; -+ if (copy_to_user(useraddr, &edata, sizeof(edata))) -+ return -EFAULT; -+ return 0; -+ } -+ } -+ -+ return -EOPNOTSUPP; -+} -+ -+static int ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -+{ -+ struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; -+ -+ switch (cmd) { -+ case SIOCDEVPRIVATE: { -+ struct ar2313_cmd scmd; -+ -+ if (copy_from_user(&scmd, ifr->ifr_data, sizeof(scmd))) -+ return -EFAULT; -+ -+#if DEBUG -+ printk("%s: ioctl devprivate c=%d a=%x l=%d m=%d d=%x,%x\n", -+ dev->name, scmd.cmd, -+ scmd.address, scmd.length, -+ scmd.mailbox, scmd.data[0], scmd.data[1]); -+#endif /* DEBUG */ -+ -+ switch (scmd.cmd) { -+ case AR2313_READ_DATA: -+ if(scmd.length==4){ -+ scmd.data[0] = *((u32*)scmd.address); -+ } else if(scmd.length==2) { -+ scmd.data[0] = *((u16*)scmd.address); -+ } else if (scmd.length==1) { -+ scmd.data[0] = *((u8*)scmd.address); -+ } else { -+ return -EOPNOTSUPP; -+ } -+ if(copy_to_user(ifr->ifr_data, &scmd, sizeof(scmd))) -+ return -EFAULT; -+ break; -+ -+ case AR2313_WRITE_DATA: -+ if(scmd.length==4){ -+ *((u32*)scmd.address) = scmd.data[0]; -+ } else if(scmd.length==2) { -+ *((u16*)scmd.address) = scmd.data[0]; -+ } else if (scmd.length==1) { -+ *((u8*)scmd.address) = scmd.data[0]; -+ } else { -+ return -EOPNOTSUPP; -+ } -+ break; -+ -+ case AR2313_GET_VERSION: -+ // SAMEER: sprintf((char*) &scmd, "%s", ARUBA_VERSION); -+ if(copy_to_user(ifr->ifr_data, &scmd, sizeof(scmd))) -+ return -EFAULT; -+ break; -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ return 0; -+ } -+ -+ case SIOCETHTOOL: -+ return netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data); -+ -+ case SIOCGMIIPHY: /* Get address of MII PHY in use. */ -+ data->phy_id = 1; -+ /* Fall Through */ -+ -+ case SIOCGMIIREG: /* Read MII PHY register. */ -+ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ -+ data->val_out = armiiread(data->phy_id & 0x1f, -+ data->reg_num & 0x1f); -+ return 0; -+ case SIOCSMIIREG: /* Write MII PHY register. */ -+ case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ armiiwrite(data->phy_id & 0x1f, -+ data->reg_num & 0x1f, data->val_in); -+ return 0; -+ -+ case SIOCSIFHWADDR: -+ if (copy_from_user(dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr))) -+ return -EFAULT; -+ return 0; -+ -+ case SIOCGIFHWADDR: -+ if (copy_to_user(ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr))) -+ return -EFAULT; -+ return 0; -+ -+ default: -+ break; -+ } -+ -+ return -EOPNOTSUPP; -+} -+ -+static struct net_device_stats *ar2313_get_stats(struct net_device *dev) -+{ -+ struct ar2313_private *sp = dev->priv; -+ return &sp->stats; -+} -+ -+static short -+armiiread(short phy, short reg) -+{ -+ volatile ETHERNET_STRUCT * ethernet; -+ -+ ethernet = (volatile ETHERNET_STRUCT *)KSEG1ADDR(ar_eth_base); /* always MAC 0 */ -+ ethernet->mii_addr = ((reg << MII_ADDR_REG_SHIFT) | -+ (phy << MII_ADDR_PHY_SHIFT)); -+ while (ethernet->mii_addr & MII_ADDR_BUSY); -+ return (ethernet->mii_data >> MII_DATA_SHIFT); -+} -+ -+static void -+armiiwrite(short phy, short reg, short data) -+{ -+ volatile ETHERNET_STRUCT * ethernet; -+ -+ ethernet = (volatile ETHERNET_STRUCT *)KSEG1ADDR(ar_eth_base); /* always MAC 0 */ -+ while (ethernet->mii_addr & MII_ADDR_BUSY); -+ ethernet->mii_data = data << MII_DATA_SHIFT; -+ ethernet->mii_addr = ((reg << MII_ADDR_REG_SHIFT) | -+ (phy << MII_ADDR_PHY_SHIFT) | -+ MII_ADDR_WRITE); -+} -+ -diff -urN linux.old/drivers/net/ar2313/ar2313.h linux.eth/drivers/net/ar2313/ar2313.h ---- linux.old/drivers/net/ar2313/ar2313.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.eth/drivers/net/ar2313/ar2313.h 2006-12-16 04:30:11.000000000 +0100 -@@ -0,0 +1,191 @@ -+#ifndef _AR2313_H_ -+#define _AR2313_H_ -+ -+#include -+#include -+#include "platform.h" -+ -+extern unsigned long mips_machtype; -+ -+#undef ETHERNET_BASE -+#define ETHERNET_BASE ar_eth_base -+#define ETHERNET_SIZE 0x00100000 -+#define ETHERNET_MACS 2 -+ -+#undef DMA_BASE -+#define DMA_BASE ar_dma_base -+#define DMA_SIZE 0x00100000 -+ -+ -+/* -+ * probe link timer - 5 secs -+ */ -+#define LINK_TIMER (5*HZ) -+ -+/* -+ * Interrupt register base address -+ */ -+#define INTERRUPT_BASE PHYS_TO_K1(ar_int_base) -+ -+/* -+ * Reset Register -+ */ -+#define AR531X_RESET (AR531X_RESETTMR + 0x0020) -+#define RESET_SYSTEM 0x00000001 /* cold reset full system */ -+#define RESET_PROC 0x00000002 /* cold reset MIPS core */ -+#define RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */ -+#define RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */ -+#define RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */ -+#define RESET_ENET0 0x00000020 /* cold reset ENET0 mac */ -+#define RESET_ENET1 0x00000040 /* cold reset ENET1 mac */ -+ -+#define IS_DMA_TX_INT(X) (((X) & (DMA_STATUS_TI)) != 0) -+#define IS_DMA_RX_INT(X) (((X) & (DMA_STATUS_RI)) != 0) -+#define IS_DRIVER_OWNED(X) (((X) & (DMA_TX_OWN)) == 0) -+ -+#ifndef K1_TO_PHYS -+// hack -+#define K1_TO_PHYS(x) (((unsigned int)(x)) & 0x1FFFFFFF) /* kseg1 to physical */ -+#endif -+ -+#ifndef PHYS_TO_K1 -+// hack -+#define PHYS_TO_K1(x) (((unsigned int)(x)) | 0xA0000000) /* physical to kseg1 */ -+#endif -+ -+#define AR2313_TX_TIMEOUT (HZ/4) -+ -+/* -+ * Rings -+ */ -+#define DSC_RING_ENTRIES_SIZE (AR2313_DESCR_ENTRIES * sizeof(struct desc)) -+#define DSC_NEXT(idx) ((idx + 1) & (AR2313_DESCR_ENTRIES - 1)) -+ -+static inline int tx_space (u32 csm, u32 prd) -+{ -+ return (csm - prd - 1) & (AR2313_DESCR_ENTRIES - 1); -+} -+ -+#if MAX_SKB_FRAGS -+#define TX_RESERVED (MAX_SKB_FRAGS+1) /* +1 for message header */ -+#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED) -+#else -+#define tx_ring_full 0 -+#endif -+ -+#define AR2313_MBGET 2 -+#define AR2313_MBSET 3 -+#define AR2313_PCI_RECONFIG 4 -+#define AR2313_PCI_DUMP 5 -+#define AR2313_TEST_PANIC 6 -+#define AR2313_TEST_NULLPTR 7 -+#define AR2313_READ_DATA 8 -+#define AR2313_WRITE_DATA 9 -+#define AR2313_GET_VERSION 10 -+#define AR2313_TEST_HANG 11 -+#define AR2313_SYNC 12 -+ -+ -+struct ar2313_cmd { -+ u32 cmd; -+ u32 address; /* virtual address of image */ -+ u32 length; /* size of image to download */ -+ u32 mailbox; /* mailbox to get/set */ -+ u32 data[2]; /* contents of mailbox to read/write */ -+}; -+ -+ -+/* -+ * Struct private for the Sibyte. -+ * -+ * Elements are grouped so variables used by the tx handling goes -+ * together, and will go into the same cache lines etc. in order to -+ * avoid cache line contention between the rx and tx handling on SMP. -+ * -+ * Frequently accessed variables are put at the beginning of the -+ * struct to help the compiler generate better/shorter code. -+ */ -+struct ar2313_private -+{ -+ struct net_device *dev; -+ int version; -+ u32 mb[2]; -+ -+ volatile ETHERNET_STRUCT *eth_regs; -+ volatile DMA *dma_regs; -+ volatile u32 *int_regs; -+ -+ spinlock_t lock; /* Serialise access to device */ -+ -+ /* -+ * RX and TX descriptors, must be adjacent -+ */ -+ ar2313_descr_t *rx_ring; -+ ar2313_descr_t *tx_ring; -+ -+ -+ struct sk_buff **rx_skb; -+ struct sk_buff **tx_skb; -+ -+ /* -+ * RX elements -+ */ -+ u32 rx_skbprd; -+ u32 cur_rx; -+ -+ /* -+ * TX elements -+ */ -+ u32 tx_prd; -+ u32 tx_csm; -+ -+ /* -+ * Misc elements -+ */ -+ int board_idx; -+ char name[48]; -+ struct net_device_stats stats; -+ struct { -+ u32 address; -+ u32 length; -+ char *mapping; -+ } desc; -+ -+ -+ struct timer_list link_timer; -+ unsigned short phy; /* merlot phy = 1, samsung phy = 0x1f */ -+ unsigned short mac; -+ unsigned short link; /* 0 - link down, 1 - link up */ -+ u16 phyData; -+ -+ struct tasklet_struct rx_tasklet; -+ int unloading; -+}; -+ -+ -+/* -+ * Prototypes -+ */ -+static int ar2313_init(struct net_device *dev); -+#ifdef TX_TIMEOUT -+static void ar2313_tx_timeout(struct net_device *dev); -+#endif -+#if 0 -+static void ar2313_multicast_list(struct net_device *dev); -+#endif -+static int ar2313_restart(struct net_device *dev); -+#if DEBUG -+static void ar2313_dump_regs(struct net_device *dev); -+#endif -+static void ar2313_load_rx_ring(struct net_device *dev, int bufs); -+static irqreturn_t ar2313_interrupt(int irq, void *dev_id); -+static int ar2313_open(struct net_device *dev); -+static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev); -+static int ar2313_close(struct net_device *dev); -+static int ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -+static void ar2313_init_cleanup(struct net_device *dev); -+static int ar2313_setup_timer(struct net_device *dev); -+static void ar2313_link_timer_fn(unsigned long data); -+static void ar2313_check_link(struct net_device *dev); -+static struct net_device_stats *ar2313_get_stats(struct net_device *dev); -+#endif /* _AR2313_H_ */ -diff -urN linux.old/drivers/net/ar2313/ar2313_msg.h linux.eth/drivers/net/ar2313/ar2313_msg.h ---- linux.old/drivers/net/ar2313/ar2313_msg.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.eth/drivers/net/ar2313/ar2313_msg.h 2006-12-16 04:30:11.000000000 +0100 -@@ -0,0 +1,17 @@ -+#ifndef _AR2313_MSG_H_ -+#define _AR2313_MSG_H_ -+ -+#define AR2313_MTU 1692 -+#define AR2313_PRIOS 1 -+#define AR2313_QUEUES (2*AR2313_PRIOS) -+ -+#define AR2313_DESCR_ENTRIES 64 -+ -+typedef struct { -+ volatile unsigned int status; // OWN, Device control and status. -+ volatile unsigned int devcs; // pkt Control bits + Length -+ volatile unsigned int addr; // Current Address. -+ volatile unsigned int descr; // Next descriptor in chain. -+} ar2313_descr_t; -+ -+#endif /* _AR2313_MSG_H_ */ -diff -urN linux.old/drivers/net/ar2313/dma.h linux.eth/drivers/net/ar2313/dma.h ---- linux.old/drivers/net/ar2313/dma.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.eth/drivers/net/ar2313/dma.h 2006-12-16 04:30:11.000000000 +0100 -@@ -0,0 +1,135 @@ -+#ifndef __ARUBA_DMA_H__ -+#define __ARUBA_DMA_H__ -+ -+/******************************************************************************* -+ * -+ * Copyright 2002 Integrated Device Technology, Inc. -+ * All rights reserved. -+ * -+ * DMA register definition. -+ * -+ * File : $Id: dma.h,v 1.3 2002/06/06 18:34:03 astichte Exp $ -+ * -+ * Author : ryan.holmQVist@idt.com -+ * Date : 20011005 -+ * Update : -+ * $Log: dma.h,v $ -+ * Revision 1.3 2002/06/06 18:34:03 astichte -+ * Added XXX_PhysicalAddress and XXX_VirtualAddress -+ * -+ * Revision 1.2 2002/06/05 18:30:46 astichte -+ * Removed IDTField -+ * -+ * Revision 1.1 2002/05/29 17:33:21 sysarch -+ * jba File moved from vcode/include/idt/acacia -+ * -+ * -+ ******************************************************************************/ -+ -+#define AR_BIT(x) (1 << (x)) -+#define DMA_RX_ERR_CRC AR_BIT(1) -+#define DMA_RX_ERR_DRIB AR_BIT(2) -+#define DMA_RX_ERR_MII AR_BIT(3) -+#define DMA_RX_EV2 AR_BIT(5) -+#define DMA_RX_ERR_COL AR_BIT(6) -+#define DMA_RX_LONG AR_BIT(7) -+#define DMA_RX_LS AR_BIT(8) /* last descriptor */ -+#define DMA_RX_FS AR_BIT(9) /* first descriptor */ -+#define DMA_RX_MF AR_BIT(10) /* multicast frame */ -+#define DMA_RX_ERR_RUNT AR_BIT(11) /* runt frame */ -+#define DMA_RX_ERR_LENGTH AR_BIT(12) /* length error */ -+#define DMA_RX_ERR_DESC AR_BIT(14) /* descriptor error */ -+#define DMA_RX_ERROR AR_BIT(15) /* error summary */ -+#define DMA_RX_LEN_MASK 0x3fff0000 -+#define DMA_RX_LEN_SHIFT 16 -+#define DMA_RX_FILT AR_BIT(30) -+#define DMA_RX_OWN AR_BIT(31) /* desc owned by DMA controller */ -+ -+#define DMA_RX1_BSIZE_MASK 0x000007ff -+#define DMA_RX1_BSIZE_SHIFT 0 -+#define DMA_RX1_CHAINED AR_BIT(24) -+#define DMA_RX1_RER AR_BIT(25) -+ -+#define DMA_TX_ERR_UNDER AR_BIT(1) /* underflow error */ -+#define DMA_TX_ERR_DEFER AR_BIT(2) /* excessive deferral */ -+#define DMA_TX_COL_MASK 0x78 -+#define DMA_TX_COL_SHIFT 3 -+#define DMA_TX_ERR_HB AR_BIT(7) /* hearbeat failure */ -+#define DMA_TX_ERR_COL AR_BIT(8) /* excessive collisions */ -+#define DMA_TX_ERR_LATE AR_BIT(9) /* late collision */ -+#define DMA_TX_ERR_LINK AR_BIT(10) /* no carrier */ -+#define DMA_TX_ERR_LOSS AR_BIT(11) /* loss of carrier */ -+#define DMA_TX_ERR_JABBER AR_BIT(14) /* transmit jabber timeout */ -+#define DMA_TX_ERROR AR_BIT(15) /* frame aborted */ -+#define DMA_TX_OWN AR_BIT(31) /* descr owned by DMA controller */ -+ -+#define DMA_TX1_BSIZE_MASK 0x000007ff -+#define DMA_TX1_BSIZE_SHIFT 0 -+#define DMA_TX1_CHAINED AR_BIT(24) /* chained descriptors */ -+#define DMA_TX1_TER AR_BIT(25) /* transmit end of ring */ -+#define DMA_TX1_FS AR_BIT(29) /* first segment */ -+#define DMA_TX1_LS AR_BIT(30) /* last segment */ -+#define DMA_TX1_IC AR_BIT(31) /* interrupt on completion */ -+ -+#define RCVPKT_LENGTH(X) (X >> 16) /* Received pkt Length */ -+ -+#define MAC_CONTROL_RE AR_BIT(2) /* receive enable */ -+#define MAC_CONTROL_TE AR_BIT(3) /* transmit enable */ -+#define MAC_CONTROL_DC AR_BIT(5) /* Deferral check*/ -+#define MAC_CONTROL_ASTP AR_BIT(8) /* Auto pad strip */ -+#define MAC_CONTROL_DRTY AR_BIT(10) /* Disable retry */ -+#define MAC_CONTROL_DBF AR_BIT(11) /* Disable bcast frames */ -+#define MAC_CONTROL_LCC AR_BIT(12) /* late collision ctrl */ -+#define MAC_CONTROL_HP AR_BIT(13) /* Hash Perfect filtering */ -+#define MAC_CONTROL_HASH AR_BIT(14) /* Unicast hash filtering */ -+#define MAC_CONTROL_HO AR_BIT(15) /* Hash only filtering */ -+#define MAC_CONTROL_PB AR_BIT(16) /* Pass Bad frames */ -+#define MAC_CONTROL_IF AR_BIT(17) /* Inverse filtering */ -+#define MAC_CONTROL_PR AR_BIT(18) /* promiscuous mode (valid frames only) */ -+#define MAC_CONTROL_PM AR_BIT(19) /* pass multicast */ -+#define MAC_CONTROL_F AR_BIT(20) /* full-duplex */ -+#define MAC_CONTROL_DRO AR_BIT(23) /* Disable Receive Own */ -+#define MAC_CONTROL_HBD AR_BIT(28) /* heart-beat disabled (MUST BE SET) */ -+#define MAC_CONTROL_BLE AR_BIT(30) /* big endian mode */ -+#define MAC_CONTROL_RA AR_BIT(31) /* receive all (valid and invalid frames) */ -+ -+#define MII_ADDR_BUSY AR_BIT(0) -+#define MII_ADDR_WRITE AR_BIT(1) -+#define MII_ADDR_REG_SHIFT 6 -+#define MII_ADDR_PHY_SHIFT 11 -+#define MII_DATA_SHIFT 0 -+ -+#define FLOW_CONTROL_FCE AR_BIT(1) -+ -+#define DMA_BUS_MODE_SWR AR_BIT(0) /* software reset */ -+#define DMA_BUS_MODE_BLE AR_BIT(7) /* big endian mode */ -+#define DMA_BUS_MODE_PBL_SHIFT 8 /* programmable burst length 32 */ -+#define DMA_BUS_MODE_DBO AR_BIT(20) /* big-endian descriptors */ -+ -+#define DMA_STATUS_TI AR_BIT(0) /* transmit interrupt */ -+#define DMA_STATUS_TPS AR_BIT(1) /* transmit process stopped */ -+#define DMA_STATUS_TU AR_BIT(2) /* transmit buffer unavailable */ -+#define DMA_STATUS_TJT AR_BIT(3) /* transmit buffer timeout */ -+#define DMA_STATUS_UNF AR_BIT(5) /* transmit underflow */ -+#define DMA_STATUS_RI AR_BIT(6) /* receive interrupt */ -+#define DMA_STATUS_RU AR_BIT(7) /* receive buffer unavailable */ -+#define DMA_STATUS_RPS AR_BIT(8) /* receive process stopped */ -+#define DMA_STATUS_ETI AR_BIT(10) /* early transmit interrupt */ -+#define DMA_STATUS_FBE AR_BIT(13) /* fatal bus interrupt */ -+#define DMA_STATUS_ERI AR_BIT(14) /* early receive interrupt */ -+#define DMA_STATUS_AIS AR_BIT(15) /* abnormal interrupt summary */ -+#define DMA_STATUS_NIS AR_BIT(16) /* normal interrupt summary */ -+#define DMA_STATUS_RS_SHIFT 17 /* receive process state */ -+#define DMA_STATUS_TS_SHIFT 20 /* transmit process state */ -+#define DMA_STATUS_EB_SHIFT 23 /* error bits */ -+ -+#define DMA_CONTROL_SR AR_BIT(1) /* start receive */ -+#define DMA_CONTROL_ST AR_BIT(13) /* start transmit */ -+#define DMA_CONTROL_SF AR_BIT(21) /* store and forward */ -+ -+#endif // __ARUBA_DMA_H__ -+ -+ -+ -+ -+ -diff -urN linux.old/drivers/net/ar2313/Makefile linux.eth/drivers/net/ar2313/Makefile ---- linux.old/drivers/net/ar2313/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux.eth/drivers/net/ar2313/Makefile 2006-12-16 04:30:11.000000000 +0100 -@@ -0,0 +1,5 @@ -+# -+# Makefile for the AR2313 ethernet driver -+# -+ -+obj-$(CONFIG_AR2313) += ar2313.o -diff -urN linux.old/drivers/net/ar2313/platform.h linux.eth/drivers/net/ar2313/platform.h ---- linux.old/drivers/net/ar2313/platform.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.eth/drivers/net/ar2313/platform.h 2006-12-16 04:30:11.000000000 +0100 -@@ -0,0 +1,128 @@ -+/******************************************************************************** -+ Title: $Source: platform.h,v $ -+ -+ Author: Dan Steinberg -+ Copyright Integrated Device Technology 2001 -+ -+ Purpose: AR2313 Register/Bit Definitions -+ -+ Update: -+ $Log: platform.h,v $ -+ -+ Notes: See Merlot architecture spec for complete details. Note, all -+ addresses are virtual addresses in kseg1 (Uncached, Unmapped). -+ -+********************************************************************************/ -+ -+#ifndef PLATFORM_H -+#define PLATFORM_H -+ -+#define BIT(x) (1 << (x)) -+ -+#define RESET_BASE 0xBC003020 -+#define RESET_VALUE 0x00000001 -+ -+/******************************************************************** -+ * Device controller -+ ********************************************************************/ -+typedef struct { -+ volatile unsigned int flash0; -+} DEVICE; -+ -+#define device (*((volatile DEVICE *) DEV_CTL_BASE)) -+ -+// DDRC register -+#define DEV_WP (1<<26) -+ -+/******************************************************************** -+ * DDR controller -+ ********************************************************************/ -+typedef struct { -+ volatile unsigned int ddrc0; -+ volatile unsigned int ddrc1; -+ volatile unsigned int ddrrefresh; -+} DDR; -+ -+#define ddr (*((volatile DDR *) DDR_BASE)) -+ -+// DDRC register -+#define DDRC_CS(i) ((i&0x3)<<0) -+#define DDRC_WE (1<<2) -+ -+/******************************************************************** -+ * Ethernet interfaces -+ ********************************************************************/ -+#define ETHERNET_BASE 0xB8200000 -+ -+// -+// New Combo structure for Both Eth0 AND eth1 -+// -+typedef struct { -+ volatile unsigned int mac_control; /* 0x00 */ -+ volatile unsigned int mac_addr[2]; /* 0x04 - 0x08*/ -+ volatile unsigned int mcast_table[2]; /* 0x0c - 0x10 */ -+ volatile unsigned int mii_addr; /* 0x14 */ -+ volatile unsigned int mii_data; /* 0x18 */ -+ volatile unsigned int flow_control; /* 0x1c */ -+ volatile unsigned int vlan_tag; /* 0x20 */ -+ volatile unsigned int pad[7]; /* 0x24 - 0x3c */ -+ volatile unsigned int ucast_table[8]; /* 0x40-0x5c */ -+ -+} ETHERNET_STRUCT; -+ -+/******************************************************************** -+ * Interrupt controller -+ ********************************************************************/ -+ -+typedef struct { -+ volatile unsigned int wdog_control; /* 0x08 */ -+ volatile unsigned int wdog_timer; /* 0x0c */ -+ volatile unsigned int misc_status; /* 0x10 */ -+ volatile unsigned int misc_mask; /* 0x14 */ -+ volatile unsigned int global_status; /* 0x18 */ -+ volatile unsigned int reserved; /* 0x1c */ -+ volatile unsigned int reset_control; /* 0x20 */ -+} INTERRUPT; -+ -+#define interrupt (*((volatile INTERRUPT *) INTERRUPT_BASE)) -+ -+#define INTERRUPT_MISC_TIMER BIT(0) -+#define INTERRUPT_MISC_AHBPROC BIT(1) -+#define INTERRUPT_MISC_AHBDMA BIT(2) -+#define INTERRUPT_MISC_GPIO BIT(3) -+#define INTERRUPT_MISC_UART BIT(4) -+#define INTERRUPT_MISC_UARTDMA BIT(5) -+#define INTERRUPT_MISC_WATCHDOG BIT(6) -+#define INTERRUPT_MISC_LOCAL BIT(7) -+ -+#define INTERRUPT_GLOBAL_ETH BIT(2) -+#define INTERRUPT_GLOBAL_WLAN BIT(3) -+#define INTERRUPT_GLOBAL_MISC BIT(4) -+#define INTERRUPT_GLOBAL_ITIMER BIT(5) -+ -+/******************************************************************** -+ * DMA controller -+ ********************************************************************/ -+#define DMA_BASE 0xB8201000 -+ -+typedef struct { -+ volatile unsigned int bus_mode; /* 0x00 (CSR0) */ -+ volatile unsigned int xmt_poll; /* 0x04 (CSR1) */ -+ volatile unsigned int rcv_poll; /* 0x08 (CSR2) */ -+ volatile unsigned int rcv_base; /* 0x0c (CSR3) */ -+ volatile unsigned int xmt_base; /* 0x10 (CSR4) */ -+ volatile unsigned int status; /* 0x14 (CSR5) */ -+ volatile unsigned int control; /* 0x18 (CSR6) */ -+ volatile unsigned int intr_ena; /* 0x1c (CSR7) */ -+ volatile unsigned int rcv_missed; /* 0x20 (CSR8) */ -+ volatile unsigned int reserved[11]; /* 0x24-0x4c (CSR9-19) */ -+ volatile unsigned int cur_tx_buf_addr; /* 0x50 (CSR20) */ -+ volatile unsigned int cur_rx_buf_addr; /* 0x50 (CSR21) */ -+} DMA; -+ -+#define dma (*((volatile DMA *) DMA_BASE)) -+ -+// macro to convert from virtual to physical address -+#define phys_addr(x) (x & 0x1fffffff) -+ -+#endif /* PLATFORM_H */ diff -urN linux.old/drivers/net/Kconfig linux.eth/drivers/net/Kconfig --- linux.old/drivers/net/Kconfig 2006-12-14 23:53:29.000000000 +0100 +++ linux.eth/drivers/net/Kconfig 2006-12-16 04:30:11.000000000 +0100 @@ -2052,7 +7,7 @@ diff -urN linux.old/drivers/net/Kconfig linux.eth/drivers/net/Kconfig +config AR2313 + tristate "AR2313 Ethernet support" -+ depends on NET_ETHERNET && AR531X ++ depends on NET_ETHERNET && ATHEROS + help + Support for the AR231x/531x ethernet controller +