diff -urN linux-mips/arch/mips/ar531x/ar531xdbg_io.c mips-linux-2.4.25/arch/mips/ar531x/ar531xdbg_io.c --- linux-mips/arch/mips/ar531x/ar531xdbg_io.c 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531xdbg_io.c 2005-12-30 17:26:30.606883840 +0000 @@ -0,0 +1,234 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * Basic support for polled character input/output + * using the AR531X's serial port. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar531xlnx.h" + +#if CONFIG_EARLY_PRINTK_HACK || CONFIG_KGDB +/* base addr of uart and clock timing */ +#if CONFIG_AR5315 +#define BASE AR5315_UART0 +#else +#define BASE AR531X_UART0 +#endif + +/* distance in bytes between two serial registers */ +#define REG_OFFSET 4 + +/* + * 0 - we need to do serial init + * 1 - skip serial init + */ +static int serialPortInitialized = 0; + +/* + * * the default baud rate *if* we do serial init + * */ +#define BAUD_DEFAULT UART16550_BAUD_9600 + +/* === END OF CONFIG === */ + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +/* register offset */ +#define OFS_RCV_BUFFER (0*REG_OFFSET) +#define OFS_TRANS_HOLD (0*REG_OFFSET) +#define OFS_SEND_BUFFER (0*REG_OFFSET) +#define OFS_INTR_ENABLE (1*REG_OFFSET) +#define OFS_INTR_ID (2*REG_OFFSET) +#define OFS_DATA_FORMAT (3*REG_OFFSET) +#define OFS_LINE_CONTROL (3*REG_OFFSET) +#define OFS_MODEM_CONTROL (4*REG_OFFSET) +#define OFS_RS232_OUTPUT (4*REG_OFFSET) +#define OFS_LINE_STATUS (5*REG_OFFSET) +#define OFS_MODEM_STATUS (6*REG_OFFSET) +#define OFS_RS232_INPUT (6*REG_OFFSET) +#define OFS_SCRATCH_PAD (7*REG_OFFSET) + +#define OFS_DIVISOR_LSB (0*REG_OFFSET) +#define OFS_DIVISOR_MSB (1*REG_OFFSET) + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile u8*)(BASE + y))) +#define UART16550_WRITE(y, z) ((*((volatile u8*)(BASE + y))) = z) + +void +debugPortInit(u32 baud, u8 data, u8 parity, u8 stop) +{ + /* Pull UART out of reset */ +#if CONFIG_AR5315 + sysRegWrite(AR5315_RESET, + sysRegRead(AR5315_RESET) & ~(RESET_UART0)); +#else + sysRegWrite(AR531X_RESET, + sysRegRead(AR531X_RESET) & ~(AR531X_RESET_UART0)); +#endif + + /* disable interrupts */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + u32 divisor; +#if CONFIG_AR5315 + u32 uart_clock_rate = ar531x_apb_frequency(); +#else + u32 uart_clock_rate = ar531x_cpu_frequency() / 4; +#endif + u32 base_baud = uart_clock_rate / 16; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = base_baud / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + +u8 +getDebugChar(void) +{ + if (!serialPortInitialized) { + serialPortInitialized = 1; + debugPortInit(BAUD_DEFAULT, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + +#if CONFIG_KGDB +/* + * Peek at the most recently received character. + * Don't wait for a new character to be received. + */ +u8 +peekDebugChar(void) +{ + return UART16550_READ(OFS_RCV_BUFFER); +} + +static int kgdbInitialized = 0; + +void +kgdbInit(void) +{ +#if CONFIG_AR5315 + sysRegWrite(AR5315_WDC, WDC_IGNORE_EXPIRATION); +#else + sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION); +#endif + + if (!kgdbInitialized) { + printk("Setting debug traps - please connect the remote debugger.\n"); + set_debug_traps(); + kgdbInitialized = 1; + } + breakpoint(); +} + +int +kgdbEnabled(void) +{ + return kgdbInitialized; +} + +#define DEBUG_CHAR '\001'; + +int +kgdbInterrupt(void) +{ + if (!kgdbInitialized) { + return 0; + } + + /* + * Try to avoid swallowing too much input: Only consume + * a character if nothing new has arrived. Yes, there's + * still a small hole here, and we may lose an input + * character now and then. + */ + if (UART16550_READ(OFS_LINE_STATUS) & 1) { + return 0; + } else { + return UART16550_READ(OFS_RCV_BUFFER) == DEBUG_CHAR; + } +} +#endif + + +void +putDebugChar(char byte) +{ + if (!serialPortInitialized) { + serialPortInitialized = 1; + debugPortInit(BAUD_DEFAULT, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + } +#endif /* CONFIG_EARLY_PRINTK_HACK || CONFIG_KGDB */ diff -urN linux-mips/arch/mips/ar531x/ar531xgpio.c mips-linux-2.4.25/arch/mips/ar531x/ar531xgpio.c --- linux-mips/arch/mips/ar531x/ar531xgpio.c 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531xgpio.c 2005-12-30 17:26:30.606883840 +0000 @@ -0,0 +1,147 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * Support for GPIO -- General Purpose Input/Output Pins + */ + +#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; + +/* Enable the specified AR531X_GPIO_IRQ interrupt */ +void +ar531x_gpio_intr_enable(unsigned int irq) +{ + u32 reg; + int gpio; + +#ifndef CONFIG_AR5315 + gpio = irq - AR531X_GPIO_IRQ_BASE; + gpioIntMask |= gpio; + + reg = sysRegRead(AR531X_GPIO_CR); + reg &= ~(GPIO_CR_M(gpio) | GPIO_CR_UART(gpio) | GPIO_CR_INT(gpio)); + reg |= GPIO_CR_I(gpio); + reg |= GPIO_CR_INT(gpio); + + sysRegWrite(AR531X_GPIO_CR, reg); + (void)sysRegRead(AR531X_GPIO_CR); /* flush to hardware */ +#endif +} + +/* Disable the specified AR531X_GPIO_IRQ interrupt */ +void +ar531x_gpio_intr_disable(unsigned int irq) +{ + u32 reg; + int gpio; + +#ifndef CONFIG_AR5315 + gpio = irq - AR531X_GPIO_IRQ_BASE; + reg = sysRegRead(AR531X_GPIO_CR); + reg &= ~(GPIO_CR_M(gpio) | GPIO_CR_UART(gpio) | GPIO_CR_INT(gpio)); + reg |= GPIO_CR_I(gpio); + /* No GPIO_CR_INT bit */ + + sysRegWrite(AR531X_GPIO_CR, reg); + (void)sysRegRead(AR531X_GPIO_CR); /* flush to hardware */ + + gpioIntMask &= ~gpio; +#endif +} + +static void +ar531x_gpio_intr_ack(unsigned int irq) +{ + ar531x_gpio_intr_disable(irq); +} + +static void +ar531x_gpio_intr_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + ar531x_gpio_intr_enable(irq); +} + +static void +ar531x_gpio_intr_set_affinity(unsigned int irq, unsigned long mask) +{ + /* Only 1 CPU; ignore affinity request */ +} + +int ar531x_gpio_irq_base; + +struct hw_interrupt_type ar531x_gpio_intr_controller = { + "AR531X GPIO", + ar531x_gpio_intr_startup, + ar531x_gpio_intr_shutdown, + ar531x_gpio_intr_enable, + ar531x_gpio_intr_disable, + ar531x_gpio_intr_ack, + ar531x_gpio_intr_end, + ar531x_gpio_intr_set_affinity, +}; + +void +ar531x_gpio_intr_init(int irq_base) +{ + int i; + + for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &ar531x_gpio_intr_controller; + } + + ar531x_gpio_irq_base = irq_base; +} + +/* ARGSUSED */ +void +spurious_gpio_handler(int cpl, void *dev_id, struct pt_regs *regs) +{ + u32 gpioDataIn; +#if CONFIG_AR5315 + gpioDataIn = sysRegRead(AR5315_GPIO_DI) & gpioIntMask; +#else + gpioDataIn = sysRegRead(AR531X_GPIO_DI) & gpioIntMask; +#endif + + printk("spurious_gpio_handler: 0x%x di=0x%8.8x gpioIntMask=0x%8.8x\n", + cpl, gpioDataIn, gpioIntMask); +} + +struct irqaction spurious_gpio = + {spurious_gpio_handler, SA_INTERRUPT, 0, "spurious_gpio", + NULL, NULL}; + diff -urN linux-mips/arch/mips/ar531x/ar531x.h mips-linux-2.4.25/arch/mips/ar531x/ar531x.h --- linux-mips/arch/mips/ar531x/ar531x.h 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531x.h 2005-12-30 17:26:30.605883992 +0000 @@ -0,0 +1,1018 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +#ifndef AR531X_H +#define AR531X_H 1 + +#ifndef CONFIG_AR5315 + +#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 GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ +#define GPIO_CR_O(x) (0 << (x)) /* mask for output */ +#define GPIO_CR_I(x) (1 << (x)) /* mask for input */ +#define GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */ +#define GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */ + + +typedef unsigned int AR531X_REG; + +#define sysRegRead(phys) \ + (*(volatile AR531X_REG *)PHYS_TO_K1(phys)) + +#define sysRegWrite(phys, val) \ + ((*(volatile AR531X_REG *)PHYS_TO_K1(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) */ +}; + +#else + +/* + * 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 */ + +/* 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 + +#if defined(AR5315) + +#define AR5315_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */ +#define AR5315_SDRAM_DATA_WIDTH 16 /* bits */ +#define AR5315_SDRAM_COL_WIDTH 8 +#define AR5315_SDRAM_ROW_WIDTH 12 + +#else + +#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 + +#endif /* ! AR5315 */ + +/* + * 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 + + +typedef unsigned int AR531X_REG; + +#define sysRegRead(phys) \ + (*(volatile AR531X_REG *)PHYS_TO_K1(phys)) + +#define sysRegWrite(phys, val) \ + ((*(volatile AR531X_REG *)PHYS_TO_K1(phys)) = (val)) +#endif + +#endif diff -urN linux-mips/arch/mips/ar531x/ar531xintr.S mips-linux-2.4.25/arch/mips/ar531x/ar531xintr.S --- linux-mips/arch/mips/ar531x/ar531xintr.S 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531xintr.S 2005-12-30 17:26:31.000823952 +0000 @@ -0,0 +1,30 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +#include +#include +#include +#include + +/* + * Glue code to save registers and get us to the interrupt dispatcher + */ + .text + .set noat + .align 5 +NESTED(ar531x_interrupt_receive, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + + move a0, sp + jal ar531x_irq_dispatch + + j ret_from_irq + + END(ar531x_interrupt_receive) diff -urN linux-mips/arch/mips/ar531x/ar531xirq.c mips-linux-2.4.25/arch/mips/ar531x/ar531xirq.c --- linux-mips/arch/mips/ar531x/ar531xirq.c 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531xirq.c 2005-12-30 17:26:31.000823952 +0000 @@ -0,0 +1,442 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * 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; + +#if CONFIG_AR5315 + 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_ISR_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); + +#else + imr = sysRegRead(AR531X_IMR); + imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1)); + sysRegWrite(AR531X_IMR, imr); + sysRegRead(AR531X_IMR); /* flush write buffer */ +#endif +} + +/* Disable the specified AR531X_MISC_IRQ interrupt */ +static void +ar531x_misc_intr_disable(unsigned int irq) +{ + unsigned int imr; + +#if CONFIG_AR5315 + 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_ISR_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 */ +#else + imr = sysRegRead(AR531X_IMR); + imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1)); + sysRegWrite(AR531X_IMR, imr); + sysRegRead(AR531X_IMR); /* flush write buffer */ +#endif +} + +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); +} + +static void +ar531x_misc_intr_set_affinity(unsigned int irq, unsigned long mask) +{ + /* Only 1 CPU; ignore affinity request */ +} + +struct hw_interrupt_type ar531x_misc_intr_controller = { + "AR531X MISC", + ar531x_misc_intr_startup, + ar531x_misc_intr_shutdown, + ar531x_misc_intr_enable, + ar531x_misc_intr_disable, + ar531x_misc_intr_ack, + ar531x_misc_intr_end, + ar531x_misc_intr_set_affinity, +}; + +int ar531x_misc_irq_base; + +/* + * 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].handler = &ar531x_misc_intr_controller; + } + + ar531x_misc_irq_base = irq_base; +} + +/* ARGSUSED */ +void +spurious_irq_handler(int cpl, void *dev_id, struct pt_regs *regs) +{ + /* + printk("spurious_irq_handler: %d cause=0x%8.8x status=0x%8.8x\n", + cpl, cause_intrs, status_intrs); + */ +} + +/* ARGSUSED */ +void +spurious_misc_handler(int cpl, void *dev_id, struct pt_regs *regs) +{ + /* + printk("spurious_misc_handler: 0x%x isr=0x%8.8x imr=0x%8.8x\n", + cpl, ar531x_isr, ar531x_imr); + */ +} + +void +ar531x_timer_handler(int cpl, void *dev_id, struct pt_regs *regs) +{ +#if CONFIG_AR5315 + (void)sysRegRead(AR5315_TIMER); /* clear interrupt */ +#else + (void)sysRegRead(AR531X_TIMER); /* clear interrupt */ +#endif +} + +void +ar531x_ahb_proc_handler(int cpl, void *dev_id, struct pt_regs *regs) +{ + u32 procAddr; + u32 proc1; + u32 dmaAddr; + u32 dma1; +#if CONFIG_AR5315 + sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET); + sysRegRead(AR5315_AHB_ERR1); +#else + proc1 = sysRegRead(AR531X_PROC1); + procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */ + dma1 = sysRegRead(AR531X_DMA1); + dmaAddr = sysRegRead(AR531X_DMAADDR); /* clears error state */ +#endif + + 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 */ +} + +static struct irqaction cascade = + {no_action, SA_INTERRUPT, 0, "cascade", + NULL, NULL}; + +static struct irqaction spurious_irq = + {spurious_irq_handler, SA_INTERRUPT, 0, "spurious_irq", + NULL, NULL}; + +static struct irqaction spurious_misc = + {spurious_misc_handler, SA_INTERRUPT, 0, "spurious_misc", + NULL, NULL}; + +static struct irqaction ar531x_timer_interrupt = + {ar531x_timer_handler, SA_INTERRUPT, 0, "ar531x_timer_interrupt", + NULL, NULL}; + +static struct irqaction ar531x_ahb_proc_interrupt = + {ar531x_ahb_proc_handler, SA_INTERRUPT, 0, "ar531x_ahb_proc_interrupt", + NULL, NULL}; + +extern asmlinkage void ar531x_interrupt_receive(void); + +/* + * 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. + */ +extern void dump_uart(void *); + +#if CONFIG_AR5315 + +void +ar531x_irq_dispatch(struct pt_regs *regs) +{ + int cause_intrs = regs->cp0_cause; + int status_intrs = regs->cp0_status; + int pending = cause_intrs & status_intrs; + + if (pending & CAUSEF_IP3) { + do_IRQ(AR531X_IRQ_WLAN0_INTRS, regs); + } + else if (pending & CAUSEF_IP4) { + do_IRQ(AR531X_IRQ_ENET0_INTRS, regs); + } + else if (pending & CAUSEF_IP2) { + AR531X_REG ar531x_isr = sysRegRead(AR5315_ISR); + AR531X_REG ar531x_imr = sysRegRead(AR5315_IMR); + unsigned int ar531x_misc_intrs = ar531x_isr & ar531x_imr; + + if (ar531x_misc_intrs & ISR_TIMER) + do_IRQ(AR531X_MISC_IRQ_TIMER, regs); + else if (ar531x_misc_intrs & ISR_AHB) + do_IRQ(AR531X_MISC_IRQ_AHB_PROC, regs); + else if (ar531x_misc_intrs & ISR_GPIO) + { + int i; + u32 gpioIntPending; + + gpioIntPending = sysRegRead(AR5315_GPIO_DI) & gpioIntMask; + for (i=0; icp0_epc); + } +#endif /* CONFIG_KGDB */ + } + else if (ar531x_misc_intrs & ISR_WD) + do_IRQ(AR531X_MISC_IRQ_WATCHDOG, regs); + else + do_IRQ(AR531X_MISC_IRQ_NONE, regs); + } else if (pending & CAUSEF_IP7) { + do_IRQ(AR531X_IRQ_CPU_CLOCK, regs); + } + else { + do_IRQ(AR531X_IRQ_NONE, regs); + } +} + +#else + +void +ar531x_irq_dispatch(struct pt_regs *regs) +{ + int cause_intrs = regs->cp0_cause; + int status_intrs = regs->cp0_status; + int pending = cause_intrs & status_intrs; + + if (pending & CAUSEF_IP2) { + do_IRQ(AR531X_IRQ_WLAN0_INTRS, regs); + } + else if (pending & CAUSEF_IP3) { + do_IRQ(AR531X_IRQ_ENET0_INTRS, regs); + } + else if (pending & CAUSEF_IP4) { + do_IRQ(AR531X_IRQ_ENET1_INTRS, regs); + } + else if (pending & CAUSEF_IP5) { + do_IRQ(AR531X_IRQ_WLAN1_INTRS, regs); + } + else if (pending & CAUSEF_IP6) { + AR531X_REG ar531x_isr = sysRegRead(AR531X_ISR); + AR531X_REG ar531x_imr = sysRegRead(AR531X_IMR); + unsigned int ar531x_misc_intrs = ar531x_isr & ar531x_imr; + + if (ar531x_misc_intrs & AR531X_ISR_TIMER) + do_IRQ(AR531X_MISC_IRQ_TIMER, regs); + else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC) + do_IRQ(AR531X_MISC_IRQ_AHB_PROC, regs); + else if (ar531x_misc_intrs & AR531X_ISR_AHBDMA) + do_IRQ(AR531X_MISC_IRQ_AHB_DMA, regs); + else if (ar531x_misc_intrs & AR531X_ISR_GPIO) + { + int i; + u32 gpioIntPending; + + gpioIntPending = sysRegRead(AR531X_GPIO_DI) & gpioIntMask; + for (i=0; icp0_epc); + } +#endif /* CONFIG_KGDB */ + } + else if (ar531x_misc_intrs & AR531X_ISR_WD) + do_IRQ(AR531X_MISC_IRQ_WATCHDOG, regs); + else if (ar531x_misc_intrs & AR531X_ISR_LOCAL) + do_IRQ(AR531X_MISC_IRQ_LOCAL, regs); + else + do_IRQ(AR531X_MISC_IRQ_NONE, regs); + } else if (pending & CAUSEF_IP7) { + do_IRQ(AR531X_IRQ_CPU_CLOCK, regs); + } else + do_IRQ(AR531X_IRQ_NONE, regs); +} + +#endif + +void __init init_IRQ(void) +{ + init_generic_irq(); + set_except_vector(0, ar531x_interrupt_receive); + + /* Initialize interrupt controllers */ + mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); + ar531x_misc_intr_init(AR531X_MISC_IRQ_BASE); + ar531x_gpio_intr_init(AR531X_GPIO_IRQ_BASE); + setup_irq(AR531X_IRQ_MISC_INTRS, &cascade); + /* + * AR531X_IRQ_CPU_CLOCK is setup by ar531x_timer_setup. + */ + + /* Default "spurious interrupt" handlers */ + setup_irq(AR531X_IRQ_NONE, &spurious_irq); + setup_irq(AR531X_MISC_IRQ_NONE, &spurious_misc); + setup_irq(AR531X_GPIO_IRQ_NONE, &spurious_gpio); +#ifndef CONFIG_AR5315 + setup_irq(AR531X_MISC_IRQ_TIMER, &ar531x_timer_interrupt); +#endif + setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar531x_ahb_proc_interrupt); + setup_irq(AR531X_MISC_IRQ_GPIO, &cascade); + +#ifdef CONFIG_KGDB +#if CONFIG_EARLY_STOP + kgdbInit(); +#endif +#endif +} diff -urN linux-mips/arch/mips/ar531x/ar531xksyms.c mips-linux-2.4.25/arch/mips/ar531x/ar531xksyms.c --- linux-mips/arch/mips/ar531x/ar531xksyms.c 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531xksyms.c 2005-12-30 17:26:31.001823800 +0000 @@ -0,0 +1,17 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +#include +#include "asm/atheros/ar531xbsp.h" + +#ifdef CONFIG_KGDB +EXPORT_SYMBOL(kgdbInit); +EXPORT_SYMBOL(kgdbEnabled); +#endif +EXPORT_SYMBOL(ar531x_sys_frequency); +EXPORT_SYMBOL(get_system_type); diff -urN linux-mips/arch/mips/ar531x/ar531xlnx.h mips-linux-2.4.25/arch/mips/ar531x/ar531xlnx.h --- linux-mips/arch/mips/ar531x/ar531xlnx.h 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531xlnx.h 2005-12-30 17:26:31.001823800 +0000 @@ -0,0 +1,135 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * 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. + */ +#include "ar531x.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" */ +#if CONFIG_AR5315 +#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 */ +#else +#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 +#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 */ +#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */ +#endif +/* 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 +#ifdef CONFIG_AR5315 +#define AR531X_GPIO_IRQ_COUNT 2 +#else +#define AR531X_GPIO_IRQ_COUNT 9 +#endif + +#define PHYS_TO_K1(physaddr) KSEG1ADDR(physaddr) +#define PHYS_TO_K0(physaddr) KSEG0ADDR(physaddr) +#define UNMAPPED_TO_PHYS(vaddr) PHYSADDR(vaddr) +#define IS_UNMAPPED_VADDR(vaddr) \ + ((KSEGX(vaddr) == KSEG0) || (KSEGX(vaddr) == KSEG1)) + +/* IOCTL commands for /proc/ar531x */ +#define AR531X_CTRL_DO_BREAKPOINT 1 +#define AR531X_CTRL_DO_MADWIFI 2 + +/* + * Definitions for operating system portability. + * These are vxWorks-->Linux translations. + */ +#define LOCAL static +#define BOOL int +#define TRUE 1 +#define FALSE 0 +#define UINT8 u8 +#define UINT16 u16 +#define UINT32 u32 +#define PRINTF printk +#if /* DEBUG */ 1 +#define DEBUG_PRINTF printk +#define INLINE +#else +DEBUG_PRINTF while (0) printk +#define INLINE inline +#endif +#define sysUDelay(usecs) udelay(usecs) +#define sysMsDelay(msecs) mdelay(msecs) +typedef volatile UINT8 *VIRT_ADDR; +#define MALLOC(sz) kmalloc(sz, GFP_KERNEL) +#define MALLOC_NOSLEEP(sz) kmalloc(sz, GFP_ATOMIC) +#define FREE(ptr) kfree((void *)ptr) +#define BSP_BUG() do { printk("kernel BSP BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) +#define BSP_BUG_ON(condition) do { if (unlikely((condition)!=0)) BSP_BUG(); } while(0) +#define ASSERT(x) BSP_BUG_ON(!(x)) + +extern struct ar531x_boarddata *ar531x_board_configuration; +extern char *ar531x_radio_configuration; +extern char *enet_mac_address_get(int MACUnit); + +extern void kgdbInit(void); +extern int kgdbEnabled(void); +extern void breakpoint(void); +extern int kgdbInterrupt(void); +extern unsigned int ar531x_cpu_frequency(void); +extern unsigned int ar531x_sys_frequency(void); + +/* GPIO support */ +extern struct irqaction spurious_gpio; +extern unsigned int gpioIntMask; +extern void ar531x_gpio_intr_init(int irq_base); +extern void ar531x_gpio_ctrl_output(int gpio); +extern void ar531x_gpio_ctrl_input(int gpio); +extern void ar531x_gpio_set(int gpio, int val); +extern int ar531x_gpio_get(int gpio); +extern void ar531x_gpio_intr_enable(unsigned int irq); +extern void ar531x_gpio_intr_disable(unsigned int irq); + +/* Watchdog Timer support */ +extern int watchdog_start(unsigned int milliseconds); +extern int watchdog_stop(void); +extern int watchdog_is_enabled(void); +extern unsigned int watchdog_min_timer_reached(void); +extern void watchdog_notify_alive(void); + +#define A_DATA_CACHE_INVAL(start, length) \ + dma_cache_inv((UINT32)(start),(length)) + +#define sysWbFlush() mb() + +#define intDisable(x) cli() +#define intEnable(x) sti() diff -urN linux-mips/arch/mips/ar531x/ar531xprom.c mips-linux-2.4.25/arch/mips/ar531x/ar531xprom.c --- linux-mips/arch/mips/ar531x/ar531xprom.c 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531xprom.c 2005-12-30 17:26:31.001823800 +0000 @@ -0,0 +1,88 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * Prom setup file for ar531x + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ar531xlnx.h" + +#define COMMAND_LINE_SIZE 512 + +char arcs_cmdline[COMMAND_LINE_SIZE]; + +void __init prom_init(int argc, char *argv[]) +{ + int i; + unsigned int memcfg1; + int bank0AC, bank1AC; + int memsz_in_mb; + strcpy(arcs_cmdline, "console=ttyS0,9600"); + for (i=0; i> MEM_CFG1_AC0_S; + bank1AC = (memcfg1 & MEM_CFG1_AC1) >> MEM_CFG1_AC1_S; + memsz_in_mb = (bank0AC ? (1 << (bank0AC+1)) : 0) + + (bank1AC ? (1 << (bank1AC+1)) : 0); +#endif + + /* + * By default, use all available memory. You can override this + * to use, say, 8MB by specifying "mem=8M" as an argument on the + * linux bootup command line. + */ + add_memory_region(0, memsz_in_mb << 20, BOOT_MEM_RAM); +} + +void __init prom_free_prom_memory(void) +{ +} diff -urN linux-mips/arch/mips/ar531x/ar531xsetup.c mips-linux-2.4.25/arch/mips/ar531x/ar531xsetup.c --- linux-mips/arch/mips/ar531x/ar531xsetup.c 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/ar531xsetup.c 2005-12-30 17:26:31.002823648 +0000 @@ -0,0 +1,406 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * Initialization for ar531x SOC. + */ + +#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(;;) { +#if CONFIG_AR5315 + /* + ** Cold reset does not work,work around is to use the GPIO reset bit. + */ + unsigned int reg; + reg = sysRegRead(AR5315_GPIO_DO); + reg &= ~(1 << AR5315_RESET_GPIO); + sysRegWrite(AR5315_GPIO_DO, reg); + (void)sysRegRead(AR5315_GPIO_DO); /* flush write to hardware */ + +#else + sysRegWrite(AR531X_RESET, AR531X_RESET_SYSTEM); +#endif + } +} + +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(); +} + +const char * +get_system_type(void) +{ +#if CONFIG_AR5315 + return "Atheros AR5315"; +#else + return "Atheros AR531X"; +#endif +} + +/* + * This table is indexed by bits 5..4 of the CLOCKCTL1 register + * to determine the predevisor value. + */ +static int CLOCKCTL1_PREDIVIDE_TABLE[4] = { + 1, + 2, + 4, + 5 +}; + +#if CONFIG_AR5315 +static int PLLC_DIVIDE_TABLE[5] = { + 2, + 3, + 4, + 6, + 3 +}; + +unsigned int +ar531x_cpu_frequency(void) +{ + static unsigned int ar531x_calculated_cpu_freq=0; + unsigned int clockCtl,pllcCtrl,cpuDiv; + unsigned int pllcOut,refdiv,fdiv,divby2; + + if(ar531x_calculated_cpu_freq) + return ar531x_calculated_cpu_freq; + + + 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; + + clockCtl = sysRegRead(AR5315_CPUCLK); + + /* clkm input selected */ + if((clockCtl & CPUCLK_CLK_SEL_M) == 0 || (clockCtl & CPUCLK_CLK_SEL_M) == 1 ) { + unsigned int clkMdiv; + clkMdiv = (pllcCtrl & PLLC_CLKM_DIV_M) >> PLLC_CLKM_DIV_S; + clkMdiv = PLLC_DIVIDE_TABLE[clkMdiv]; + + cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S; + if(cpuDiv) cpuDiv *= 2; + else cpuDiv=1; + + ar531x_calculated_cpu_freq= (pllcOut/(clkMdiv * cpuDiv)) ; + + return ar531x_calculated_cpu_freq; + } + + /* clkc input selected */ + if((clockCtl & CPUCLK_CLK_SEL_M) == 2 ) { + unsigned int clkCdiv; + clkCdiv = (pllcCtrl & PLLC_CLKC_DIV_M) >> PLLC_CLKC_DIV_S; + clkCdiv = PLLC_DIVIDE_TABLE[clkCdiv]; + + cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S; + if(cpuDiv) cpuDiv *= 2; + else cpuDiv=1; + + ar531x_calculated_cpu_freq= (pllcOut/(clkCdiv * cpuDiv)) ; + + return ar531x_calculated_cpu_freq; + } else { /* ref_clk selected */ + + cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S; + if(cpuDiv) cpuDiv *= 2; + else cpuDiv=1; + + ar531x_calculated_cpu_freq= (40000000/(cpuDiv)) ; + return ar531x_calculated_cpu_freq; + } +} + +unsigned int +ar531x_apb_frequency(void) +{ + static unsigned int ar531x_calculated_cpu_freq=0; + unsigned int clockCtl,pllcCtrl,cpuDiv; + unsigned int pllcOut,refdiv,fdiv,divby2; + + if(ar531x_calculated_cpu_freq) + return ar531x_calculated_cpu_freq; + + + 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; + + clockCtl = sysRegRead(AR5315_AMBACLK); + + /* clkm input selected */ + if((clockCtl & CPUCLK_CLK_SEL_M) == 0 || (clockCtl & CPUCLK_CLK_SEL_M) == 1 ) { + unsigned int clkMdiv; + clkMdiv = (pllcCtrl & PLLC_CLKM_DIV_M) >> PLLC_CLKM_DIV_S; + clkMdiv = PLLC_DIVIDE_TABLE[clkMdiv]; + + cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S; + if(cpuDiv) cpuDiv *= 2; + else cpuDiv=1; + + ar531x_calculated_cpu_freq= (pllcOut/(clkMdiv * cpuDiv)) ; + + return ar531x_calculated_cpu_freq; + } + + /* clkc input selected */ + if((clockCtl & CPUCLK_CLK_SEL_M) == 2 ) { + unsigned int clkCdiv; + clkCdiv = (pllcCtrl & PLLC_CLKC_DIV_M) >> PLLC_CLKC_DIV_S; + clkCdiv = PLLC_DIVIDE_TABLE[clkCdiv]; + + cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S; + if(cpuDiv) cpuDiv *= 2; + else cpuDiv=1; + + ar531x_calculated_cpu_freq= (pllcOut/(clkCdiv * cpuDiv)) ; + + return ar531x_calculated_cpu_freq; + } else { /* ref_clk selected */ + + cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S; + if(cpuDiv) cpuDiv *= 2; + else cpuDiv=1; + + ar531x_calculated_cpu_freq= (40000000/(cpuDiv)) ; + return ar531x_calculated_cpu_freq; + } +} + +#else +unsigned int +ar531x_cpu_frequency(void) +{ + static unsigned int ar531x_calculated_cpu_freq; + unsigned int clockctl1_predivide_mask; + unsigned int clockctl1_predivide_shift; + unsigned int clockctl1_multiplier_mask; + unsigned int clockctl1_multiplier_shift; + unsigned int clockctl1_doubler_mask; + int wisoc_revision; + + /* + * Trust the bootrom's idea of cpu frequency. + */ + ar531x_calculated_cpu_freq = sysRegRead(AR5312_SCRATCH); + if (ar531x_calculated_cpu_freq) + return ar531x_calculated_cpu_freq; + + wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> AR531X_REV_MAJ_S; + + if (wisoc_revision == AR531X_REV_MAJ_AR2313) { + clockctl1_predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK; + clockctl1_predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT; + clockctl1_multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK; + clockctl1_multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT; + clockctl1_doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK; + } else { /* AR5312 and AR2312 */ + clockctl1_predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK; + clockctl1_predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT; + clockctl1_multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK; + clockctl1_multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT; + clockctl1_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 + * cpuFrez = 200MHz + * sysFreq = 50MHz + * cntFreq = 100MHz + * + * We compute the CPU frequency, based on PLL settings. + */ + if (ar531x_calculated_cpu_freq == 0) { + unsigned int clockCtl1 = sysRegRead(AR5312_CLOCKCTL1); + + int preDivideSelect = (clockCtl1 & clockctl1_predivide_mask) >> + clockctl1_predivide_shift; + + int preDivisor = CLOCKCTL1_PREDIVIDE_TABLE[preDivideSelect]; + + int multiplier = (clockCtl1 & clockctl1_multiplier_mask) >> + clockctl1_multiplier_shift; + + if (clockCtl1 & clockctl1_doubler_mask) { + multiplier = multiplier << 1; + } + + ar531x_calculated_cpu_freq = (40000000 / preDivisor) * multiplier; + } + + return ar531x_calculated_cpu_freq; +} +#endif + +unsigned int +ar531x_sys_frequency(void) +{ + static unsigned int ar531x_calculated_sys_freq = 0; + + if (ar531x_calculated_sys_freq == 0) { + ar531x_calculated_sys_freq = ar531x_cpu_frequency() / 4; + } + + return ar531x_calculated_sys_freq; +} + +static void __init +flash_setup(void) +{ + UINT32 flash_ctl; +#ifndef CONFIG_AR5315 + /* Configure flash bank 0 */ + flash_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, flash_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)); +#endif +} + + + +void __init +serial_setup(void) +{ + struct serial_struct s; + + memset(&s, 0, sizeof(s)); + + s.flags = STD_COM_FLAGS; + s.io_type = SERIAL_IO_MEM; +#if CONFIG_AR5315 + s.baud_base = ar531x_apb_frequency()/16; +#else + s.baud_base = ar531x_sys_frequency()/16; +#endif + s.irq = AR531X_MISC_IRQ_UART0; + s.iomem_reg_shift = 2; +#if CONFIG_AR5315 + s.iomem_base = (u8 *)AR5315_UART0; +#else + s.iomem_base = (u8 *)AR531X_UART0; +#endif + + if (early_serial_setup(&s) != 0) + printk(KERN_ERR "early_serial_setup failed\n"); +} + +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); +static void __init +ar531x_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); +} + +extern void (*board_time_init)(void); + +static void __init +ar531x_time_init(void) +{ + mips_hpt_frequency = ar531x_cpu_frequency() / 2; +} + +void __init +ar531x_setup(void) +{ + /* Clear any lingering AHB errors */ +#if CONFIG_AR5315 + unsigned int config = read_c0_config(); + write_c0_config(config & ~0x3); + sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET); + sysRegRead(AR5315_AHB_ERR1); + sysRegWrite(AR5315_WDC, WDC_IGNORE_EXPIRATION); +#else + sysRegRead(AR531X_PROCADDR); + sysRegRead(AR531X_DMAADDR); + + sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION); + +#endif + + /* Disable data watchpoints */ + write_c0_watchlo0(0); + + board_time_init = ar531x_time_init; + board_timer_setup = ar531x_timer_setup; + + _machine_restart = ar531x_restart; + _machine_halt = ar531x_halt; + _machine_power_off = ar531x_power_off; + + flash_setup(); + serial_setup(); +} diff -urN linux-mips/arch/mips/ar531x/Makefile mips-linux-2.4.25/arch/mips/ar531x/Makefile --- linux-mips/arch/mips/ar531x/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/Makefile 2005-12-30 17:26:29.912989328 +0000 @@ -0,0 +1,33 @@ +# +# 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 © 2003 Atheros Communications, Inc., All Rights Reserved. +# + +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o + +O_TARGET:= ar531x.o + +export-objs = ar531xksyms.o + +obj-y := ar531xdbg_io.o \ + ar531xsetup.o \ + ar531xprom.o \ + ar531xirq.o \ + ar531xintr.o \ + ar531xgpio.o \ + ar531xksyms.o + +include $(TOPDIR)/Rules.make diff -urN linux-mips/arch/mips/ar531x/README mips-linux-2.4.25/arch/mips/ar531x/README --- linux-mips/arch/mips/ar531x/README 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/README 2005-12-30 17:26:30.478903296 +0000 @@ -0,0 +1,68 @@ +Basic information for the AR531X Board Support Package + +This directory contains the "LBSP" -- Linux Board Support Package -- +for Linux on the Atheros AR531X Wireless System-On-a-Chip. It is intended +primarily as a building block for wireless products. At this time, the +AR531X Linux BSP is experimental code, and is actively UNDER CONSTRUCTION. + +Some components that are supported by this LBSP along with a standard 2.4 +Linux MIPS kernel include + R4Kc CPU + instruction and data caches + SDRAM + flash (Macronix, AMD, STS, etc.) + 16550 serial port + ethernet MACs + ethernet PHY or PHY Switch (RealTek, Kendin, Marvell) + General-Purpose I/O pins + kernel debugging with kgdb + +This LBSP code does NOT include drivers for the wireless components of the +chip/boards! Drivers for those components may be distributed separately. +In particular, the MADWiFi project under SourceForge supports (not yet!) +wireless functions on the AR531X chipset. See + http://www.sourceforge.net/projects/madwifi + +Files included in this BSP: +ae531xlnx.c - Linux-specific portions of the ethernet driver +ae531xmac.c - OS-independent AR531X ethernet MAC code +ae531xmac.h - OS-independent AR531X ethernet MAC software definitions +ae531xreg.h - OS-independent AR531X ethernet MAC hardware definitions +ar531x.h - OS-independent AR531X system hardware definitions +ar531xlnx.h - Linux-specific AR531X system definitions and externs +defconfig-ar531x - Default Linux configuration file +intr_recv.S - Linux interrupt "glue" code +ar531xirq.c - Linux Interrupt Request management +Makefile - Linux makefile +mvPhy.c - OS-independent ethernet PHY code for Marvell Switch +mvPhy.h - OS-independent ethernet PHY definitions for Marvell Switch +ar531xprom.c - Linux prom "glue" code +ar531xsetup.c - Linux startup code +ar531xdbg_io.c - Support for kgdb-based debugging and for EARLY_PRINTK_HACK +ar531xproc.c - Pseudo-device driver for /proc/ar531x device +ar531xgpio.c - Support for General Purpose I/O pins +ar531xwmacsl.c - Wireless MAC Support Layer + +Additional files, distributed with the BSP: +README - This file +README.BUILD - Instructions for building a linux kernel from source +README.EXECUTE - Instructions for testing your linux kernel +README.RAMDISK - Instructions for building a root ramdisk image + +ramdisk.gz - A binary ramdisk image, suitable for use with AR531X. +DIFFS - Directory that contains "patch" files (See README.BUILD) + + +There are several ways to boot a vmlinux image on an AR531X board: + -You can boot in over ethernet from the vxWorks bootrom, which is preloaded + on all Atheros boards + -You can use an ICE (e.g. VisionICE) to load the vmlinux image. You will + need appropriate register initialization (e.g. AP30.ini file) + -You can use the eCos RedBoot bootrom loader. This is a full-featured + bootrom which as been ported to AR531x. It can boot vmlinux over ethernet + or from flash. Source code is available from Atheros. + +Please send comments, corrections, complaints, criticisms, suggestions, +enhancements, requests, or any other reasonable communications regarding +this effort, to "linux@atheros.com". Your email will be received by a +couple of engineers, and redirected as appropriate. diff -urN linux-mips/arch/mips/ar531x/README.BUILD mips-linux-2.4.25/arch/mips/ar531x/README.BUILD --- linux-mips/arch/mips/ar531x/README.BUILD 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/README.BUILD 2005-12-30 17:26:30.478903296 +0000 @@ -0,0 +1,47 @@ + How to BUILD a linux kernel for an AR531X system + +It is expected that you will build Linux on an existing Linux system, which +has all of the standard Linux tools. + +01) Obtain a MIPS BigEndian ELF gcc-compatible toolchain. For example, + if you're cross-compiling on a x86 Linux system, you could use: + ftp://ftp.mips.com/pub/tools/software/sde-for-linux/sdelinux-5.01-4eb.i386.rpm + +02) Obtain the latest working MIPS Linux kernel + cvs -d :pserver:cvs@ftp.linux-mips.org:/home/cvs login (password "cvs") + cvs -d :pserver:cvs@ftp.linux-mips.org:/home/cvs co -r linux_2_4 linux + + Now "cd linux". The remainder of these instructions assume + that you are in the linux directory. + +03) Place the contents of this directory at arch/mips/ar531x. + +04) Use the patch command to patch generic linux files according + to the DIFFS directory + for i in arch/mips/ar531x/DIFFS/*.diff + do + patch -p1 < $i + done + NOTE: This version of the AR531X Linux BSP was tested with + MIPS Linux 2.4.22 as of 11/14/03. If you use a different + (e.g. more recent) version of Linux source, you may need to + resolve some minor patch and compilation issues. + +05) Set up a RAMDISK image. + See the instructions in README.RAMDISK. + +06) Set up a linux configuration using ar531x/defconfig-ar531x. + cp arch/mips/ar531x/defconfig-ar531x .config + make oldconfig (answer all questions that are asked) + NOTE: For development/debug purposes, you may want to + enable CONFIG_RUNTIME_DEBUG and CONFIG_KGDB. + +07) Make dependencies. + make dep + +08) Build the linux kernel + make + +09) The linux image you just built is in vmlinux. + See instructions in README.EXECUTE to run your vmlinux + image on an AP531X-based board. diff -urN linux-mips/arch/mips/ar531x/README.EXECUTE mips-linux-2.4.25/arch/mips/ar531x/README.EXECUTE --- linux-mips/arch/mips/ar531x/README.EXECUTE 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/README.EXECUTE 2005-12-30 17:26:30.479903144 +0000 @@ -0,0 +1,23 @@ + How to EXECUTE a linux image on an AR531X system + +There are currently three ways to run you vmlinux image: + 1) Load it using the vxWorks bootrom that is supplied with the board. + You can load it over ethernet or from the TFFS file system, if you + have sufficient flash to store the image. + 2) Load it using an ICE (e.g. VisionICE). + 3) Use a bootrom loader, such as eCos RedBoot. + +After you have booted linux: + By default, the root filesystem on ramdisk is read-only. + To make it writable, use "mount -o remount w /". + + The user-level commands are slightly non-standard, as they + are based on "busybox". + + The "wget" command is included. You can use wget to fetch + files from any ftp server. So, for instance, you can fetch + a kernel module and then "insmod" it. + +Note that the standard source-level kernel debugger, kgdb, works well +over the serial line with this port. We use kgdb and the kgdb_demux perl +script -- available over the www -- for debugging. diff -urN linux-mips/arch/mips/ar531x/README.VERSION mips-linux-2.4.25/arch/mips/ar531x/README.VERSION --- linux-mips/arch/mips/ar531x/README.VERSION 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/arch/mips/ar531x/README.VERSION 2005-12-30 17:26:30.479903144 +0000 @@ -0,0 +1 @@ +Source release last modified: 12/16/03 diff -urN linux-mips/arch/mips/config-shared.in mips-linux-2.4.25/arch/mips/config-shared.in --- linux-mips/arch/mips/config-shared.in 2005-12-24 15:11:15.963885864 +0000 +++ mips-linux-2.4.25/arch/mips/config-shared.in 2005-12-30 17:26:31.611731080 +0000 @@ -34,6 +34,7 @@ dep_bool 'Support for Alchemy PB1550 board' CONFIG_MIPS_PB1550 $CONFIG_MIPS32 dep_bool 'Support for Alchemy PB1200 board' CONFIG_MIPS_PB1200 $CONFIG_MIPS32 dep_bool 'Support for Alchemy Hydrogen3 board' CONFIG_MIPS_HYDROGEN3 $CONFIG_MIPS32 +dep_bool 'Support for Atheros AR5312/AR2312 WiSoC (EXPERIMENTAL)' CONFIG_AR531X $CONFIG_AR531X $CONFIG_EXPERIMENTAL dep_bool 'Support for MyCable XXS1500 board' CONFIG_MIPS_XXS1500 $CONFIG_MIPS32 dep_bool 'Support for 4G Systems MTX-1 board' CONFIG_MIPS_MTX1 $CONFIG_MIPS32 dep_bool 'Support for Cogent CSB250 board' CONFIG_COGENT_CSB250 $CONFIG_MIPS32 @@ -238,6 +239,63 @@ define_bool CONFIG_PC_KEYB y define_bool CONFIG_OLD_TIME_C y fi +if [ "$CONFIG_AR531X" = "y" ]; then + define_bool CONFIG_IRQ_CPU y + define_bool CONFIG_CPU_R4X00 y + define_bool CONFIG_SERIAL y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_AR5312 + define_bool CONFIG_NONCOHERENT_IO y + bool 'Enable early printk hack' CONFIG_EARLY_PRINTK_HACK + define_bool CONFIG_SCSI n + mainmenu_option next_comment + comment 'Board selection' + choice 'Board type' \ + "UNKNOWN CONFIG_APUNKNOWN \ + AP30 CONFIG_AP30 \ + AP31 CONFIG_AP31 \ + AP33 CONFIG_AP33 \ + AP38 CONFIG_AP38 \ + AP43 CONFIG_AP43 \ + AP48 CONFIG_AP48 \ + AP51 CONFIG_AP51 \ + AP30-ASK CONFIG_AP30ASK" AP30 + if [ "$CONFIG_AP30" = "y" -o "$CONFIG_AP30ASK" = "y" ]; then + define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 2 + fi + if [ "$CONFIG_AP33" = "y" ]; then + define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 + fi + if [ "$CONFIG_AP38" = "y" ]; then + define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 + fi + if [ "$CONFIG_AP43" = "y" ]; then + define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 + fi + if [ "$CONFIG_AP48" = "y" ]; then + define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 + fi + if [ "$CONFIG_AP51" = "y" ]; then + define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1 + define_bool CONFIG_MTD_REDBOOT_PARTS y + define_bool CONFIG_AR5315 y + define_bool CONFIG_MTD_SPIFLASH y + define_bool CONFIG_MTD_CFI n + define_bool CONFIG_MTD_JEDECPROBE n + define_bool CONFIG_MTD_CFI_INTELEXT n + define_bool CONFIG_MTD_CFI_AMDSTD n + define_bool CONFIG_MTD_OBSOLETE_CHIPS n + define_bool CONFIG_MTD_AMDSTD n + define_bool CONFIG_MTD_JEDEC n + define_bool CONFIG_MTD_PHYSMAP n + fi + mainmenu_option next_comment + comment 'Flash Selection' + choice 'Flash Size' \ + "2MB CONFIG_FLASH_2MB \ + 4MB CONFIG_FLASH_4MB" 2MB +fi if [ "$CONFIG_CASIO_E55" = "y" ]; then define_bool CONFIG_IRQ_CPU y define_bool CONFIG_NEW_TIME_C y diff -urN linux-mips/arch/mips/kernel/setup.c mips-linux-2.4.25/arch/mips/kernel/setup.c --- linux-mips/arch/mips/kernel/setup.c 2005-12-24 15:11:16.188851664 +0000 +++ mips-linux-2.4.25/arch/mips/kernel/setup.c 2005-12-30 17:26:33.536438480 +0000 @@ -496,6 +496,7 @@ void hp_setup(void); void au1x00_setup(void); void frame_info_init(void); + void ar531x_setup(void); frame_info_init(); #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE) @@ -693,6 +694,12 @@ pmc_yosemite_setup(); break; #endif + +#ifdef CONFIG_AR531X + case MACH_GROUP_AR531X: + ar531x_setup(); + break; +#endif default: panic("Unsupported architecture"); } diff -urN linux-mips/arch/mips/Makefile mips-linux-2.4.25/arch/mips/Makefile --- linux-mips/arch/mips/Makefile 2005-12-24 15:11:15.903894984 +0000 +++ mips-linux-2.4.25/arch/mips/Makefile 2005-12-30 17:26:29.911989480 +0000 @@ -701,6 +701,17 @@ LOADADDR += 0x80020000 endif +ifdef CONFIG_AR531X +SUBDIRS += arch/mips/ar531x +LIBS += arch/mips/ar531x/ar531x.o +ifdef CONFIG_AP51 +LOADADDR += 0x80041000 +else +LOADADDR += 0x80002000 +endif + +endif + # # Choosing incompatible machines durings configuration will result in # error messages during linking. Select a default linkscript if diff -urN linux-mips/ath_version.mk mips-linux-2.4.25/ath_version.mk --- linux-mips/ath_version.mk 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/ath_version.mk 2005-12-30 17:27:00.579327336 +0000 @@ -0,0 +1 @@ +EXTRAVERSION=-LSDK-5.0.0-RC5 diff -urN linux-mips/drivers/char/serial.c mips-linux-2.4.25/drivers/char/serial.c --- linux-mips/drivers/char/serial.c 2005-12-24 15:11:21.796999096 +0000 +++ mips-linux-2.4.25/drivers/char/serial.c 2005-12-30 17:27:10.815771160 +0000 @@ -3441,7 +3441,7 @@ static _INLINE_ void show_serial_version(void) { - printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name, + printk(KERN_INFO "%s version %s%s (%s) with%s\n", serial_name, serial_version, LOCAL_VERSTRING, serial_revdate, serial_options); } @@ -5567,7 +5567,7 @@ printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a %s\n", state->line + SERIAL_DEV_OFFSET, (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", - state->iomem_base, state->irq, + (void *)state->iomem_base, state->irq, uart_config[state->type].name); } else { diff -urN linux-mips/drivers/mtd/chips/cfi_cmdset_0002.c mips-linux-2.4.25/drivers/mtd/chips/cfi_cmdset_0002.c --- linux-mips/drivers/mtd/chips/cfi_cmdset_0002.c 2005-12-24 15:11:25.102496584 +0000 +++ mips-linux-2.4.25/drivers/mtd/chips/cfi_cmdset_0002.c 2005-12-30 17:27:21.333172272 +0000 @@ -511,7 +511,7 @@ or tells us why it failed. */ dq6 = CMD(1<<6); dq5 = CMD(1<<5); - timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */ + timeo = jiffies + (HZ/1000) + 1; /* setting timeout to 1ms for now */ oldstatus = cfi_read(map, adr); status = cfi_read(map, adr); @@ -536,16 +536,18 @@ if( (status & dq5) == dq5 ) { /* When DQ5 raises, we must check once again if DQ6 is toggling. If not, the erase has been - completed OK. If not, reset chip. */ + completed OK. But if so, reset chip. */ oldstatus = cfi_read(map, adr); status = cfi_read(map, adr); if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) { +#if 0 printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" ); +#endif } else { /* DQ5 is active so we can do a reset and stop the erase */ cfi_write(map, CMD(0xF0), chip->start); - printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" ); + printk(KERN_WARNING "Internal flash device timeout pt A occurred or write operation was performed while flash was programming. timeout=%d\n",chip->word_write_time ); } } else { printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword."); @@ -959,7 +961,7 @@ { /* DQ5 is active so we can do a reset and stop the erase */ cfi_write(map, CMD(0xF0), chip->start); - printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" ); + printk( KERN_WARNING "Internal flash device timeout pt B occured or write operation was performed while flash was erasing\n" ); } } else diff -urN linux-mips/drivers/mtd/chips/cfi_probe.c mips-linux-2.4.25/drivers/mtd/chips/cfi_probe.c --- linux-mips/drivers/mtd/chips/cfi_probe.c 2005-12-24 15:11:25.103496432 +0000 +++ mips-linux-2.4.25/drivers/mtd/chips/cfi_probe.c 2005-12-30 17:27:21.507145824 +0000 @@ -51,7 +51,7 @@ struct flchip *chips, struct cfi_private *cfi) { int i; - + if ((base + 0) >= map->size) { printk(KERN_NOTICE "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n", @@ -221,12 +221,10 @@ static void print_cfi_ident(struct cfi_ident *cfip) { -#if 0 if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') { printk("Invalid CFI ident structure.\n"); return; } -#endif printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID)); if (cfip->P_ADR) printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR); diff -urN linux-mips/drivers/mtd/chips/jedec_probe.c mips-linux-2.4.25/drivers/mtd/chips/jedec_probe.c --- linux-mips/drivers/mtd/chips/jedec_probe.c 2005-12-24 15:11:25.126492936 +0000 +++ mips-linux-2.4.25/drivers/mtd/chips/jedec_probe.c 2005-12-30 17:27:21.532142024 +0000 @@ -104,6 +104,7 @@ #define SST29LE512 0x003d #define SST39LF800 0x2781 #define SST39LF160 0x2782 +#define SST39LF1601 0x234b #define SST39LF512 0x00D4 #define SST39LF010 0x00D5 #define SST39LF020 0x00D6 @@ -113,6 +114,8 @@ #define SST49LF030A 0x001C #define SST49LF040A 0x0051 #define SST49LF080A 0x005B +#define SST39VF3201 0x235B +#define SST39VF3202 0x235A /* Toshiba */ #define TC58FVT160 0x00C2 @@ -900,7 +903,43 @@ NumEraseRegions: 1, regions: {ERASEINFO(0x01000,256), } - } + }, { + mfr_id: MANUFACTURER_SST, + dev_id: SST39LF160, + name: "SST 39LF160", + DevSize: SIZE_2MiB, + CmdSet: P_ID_AMD_STD, + NumEraseRegions: 1, + regions: {ERASEINFO(0x01000,512), + } + }, { + mfr_id: MANUFACTURER_SST, + dev_id: SST39LF1601, + name: "SST 39LF1601", + DevSize: SIZE_2MiB, + CmdSet: P_ID_AMD_STD, + NumEraseRegions: 1, + regions: {ERASEINFO(0x01000,512), + } + }, { + mfr_id: MANUFACTURER_SST, + dev_id: SST39VF3201, + name: "SST 39VF3201", + DevSize: SIZE_4MiB, + CmdSet: P_ID_AMD_STD, + NumEraseRegions: 1, + regions: {ERASEINFO(0x01000,1024), + } + }, { + mfr_id: MANUFACTURER_SST, + dev_id: SST39VF3202, + name: "SST 39VF3202", + DevSize: SIZE_4MiB, + CmdSet: P_ID_AMD_STD, + NumEraseRegions: 1, + regions: {ERASEINFO(0x01000,1024), + } + } }; @@ -967,6 +1006,35 @@ p_cfi->cfiq->DevSize = jedec_table[index].DevSize; p_cfi->cfi_mode = CFI_MODE_JEDEC; + /* + * Add the following code to set the flash timing parameters. + * Maybe this is done in a table somwehere else? I can't find it. + */ + + + switch(jedec_table[index].dev_id) { + case SST39VF3201: + case SST39VF3202: + p_cfi->cfiq->WordWriteTimeoutTyp = 3; /* 8 us */ + p_cfi->cfiq->WordWriteTimeoutMax = 4; /* 16 us */ + p_cfi->cfiq->BlockEraseTimeoutTyp = 15; /* Actually 18ms, max 25 */ + p_cfi->cfiq->BlockEraseTimeoutMax = 15; /* Actually 25ms */ + p_cfi->cfiq->ChipEraseTimeoutTyp = 16; /* Max is 50ms, typical is 40ms */ + p_cfi->cfiq->ChipEraseTimeoutMax = 16; + break; + case SST39LF160: + case SST39LF1601: + p_cfi->cfiq->WordWriteTimeoutTyp = 4; /* 14 us */ + p_cfi->cfiq->WordWriteTimeoutMax = 5; /* 20 us */ + p_cfi->cfiq->BlockEraseTimeoutTyp = 15; /* Actually 18ms, max 25 */ + p_cfi->cfiq->BlockEraseTimeoutMax = 15; /* Actually 25ms */ + p_cfi->cfiq->ChipEraseTimeoutTyp = 17; /* Max is 70ms, typical is 40ms */ + p_cfi->cfiq->ChipEraseTimeoutMax = 17; + break; + } + + + for (i=0; icfiq->EraseRegionInfo[i] = jedec_table[index].regions[i]; } diff -urN linux-mips/drivers/mtd/Config.in mips-linux-2.4.25/drivers/mtd/Config.in --- linux-mips/drivers/mtd/Config.in 2005-12-24 15:11:25.091498256 +0000 +++ mips-linux-2.4.25/drivers/mtd/Config.in 2005-12-30 17:27:21.182195224 +0000 @@ -14,6 +14,9 @@ dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS + if [ "$CONFIG_MTD_END_RESERVED" != "" ]; then + define_int CONFIG_MTD_END_RESERVED $CONFIG_MTD_END_RESERVED + fi dep_tristate ' Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS diff -urN linux-mips/drivers/mtd/devices/Makefile mips-linux-2.4.25/drivers/mtd/devices/Makefile --- linux-mips/drivers/mtd/devices/Makefile 2005-12-24 15:11:25.128492632 +0000 +++ mips-linux-2.4.25/drivers/mtd/devices/Makefile 2005-12-30 17:27:21.561137616 +0000 @@ -22,5 +22,6 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o +obj-$(CONFIG_MTD_SPIFLASH) += spiflash.o include $(TOPDIR)/Rules.make diff -urN linux-mips/drivers/mtd/devices/spiflash.c mips-linux-2.4.25/drivers/mtd/devices/spiflash.c --- linux-mips/drivers/mtd/devices/spiflash.c 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/drivers/mtd/devices/spiflash.c 2005-12-30 17:27:21.652123784 +0000 @@ -0,0 +1,506 @@ + +/* + * MTD driver for the SPI Flash Memory support. + * + * $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/drivers/mtd/devices/spiflash.c#3 $ + * + * + * Copyright (c) 2005-2006 Atheros Communications Inc. + * + * 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 "spiflash.h" + +/* debugging */ +/* #define SPIFLASH_DEBUG */ + +#ifndef __BIG_ENDIAN +#error This driver currently only works with big endian CPU. +#endif + +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 (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} + }; + +/* 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 */ +}; + +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; + + /* 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; + 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); + spiflash_sendcmd(SPI_WRITE_ENABLE); + do { + 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 { + reg = spiflash_sendcmd(SPI_RD_STATUS); + if (!(reg & SPI_STATUS_WIP)) { + finished = TRUE; + } + } while (!finished); + + 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); + memcpy(buf, read_addr, len); + + 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); + } + + spiflash_sendcmd(SPI_WRITE_ENABLE); + + do { + reg = spiflash_regread32(SPI_FLASH_CTL); + } while (reg & SPI_CTL_BUSY); + + switch (xact_len) { + case 1: + (__u8)spi_data = *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 { + udelay(1); + reg = spiflash_sendcmd(SPI_RD_STATUS); + if (!(reg & SPI_STATUS_WIP)) { + finished = TRUE; + } + } while (!finished); + + bytes_left -= xact_len; + to += xact_len; + buf += xact_len; + + *retlen += xact_len; + + if (bytes_left == 0) { + done = TRUE; + } + } + + return (0); +} + + +int __init +spiflash_init (void) +{ + int result, i; + int index, num_parts; + struct mtd_info *mtd; + struct mtd_partition *mtd_parts; + + spidata = kmalloc(sizeof(struct spiflash_data), GFP_KERNEL); + if (!spidata) + return (-ENXIO); + + 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); + return (-ENXIO); + } + + mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd) { + kfree(spidata); + return (-ENXIO); + } + + memset (mtd,0,sizeof (*mtd)); + + 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); + printk ("%d: size\n", flashconfig_tbl[index].byte_cnt); + + 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->numeraseregions = 0; + mtd->eraseregions = NULL; + mtd->module = THIS_MODULE; + mtd->erase = spiflash_erase; + mtd->read = spiflash_read; + mtd->write = spiflash_write; + +#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 + +#ifndef CONFIG_BLK_DEV_INITRD + /* parse redboot partitions */ + num_parts = parse_redboot_partitions(mtd, &spidata->parsed_parts); + +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG "Found %d redboot partitions\n", num_parts); +#endif + + if (num_parts) { + result = add_mtd_partitions(mtd, spidata->parsed_parts, num_parts); + /* Find root partition */ + mtd_parts = spidata->parsed_parts; + for (i=0; i < num_parts; i++) { + if (!strcmp(mtd_parts[i].name, ROOTFS_NAME)) { + /* Create root device */ + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, i); + break; + } + } + } else { +#ifdef SPIFLASH_DEBUG + printk (KERN_DEBUG "Did not find any redboot partitions\n"); +#endif + kfree(mtd); + kfree(spidata); + return (-ENXIO); + } +#endif + + 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-mips/drivers/mtd/devices/spiflash.h mips-linux-2.4.25/drivers/mtd/devices/spiflash.h --- linux-mips/drivers/mtd/devices/spiflash.h 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/drivers/mtd/devices/spiflash.h 2005-12-30 17:27:21.652123784 +0000 @@ -0,0 +1,113 @@ +/* + * 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. + * + * 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 MAX_FLASH 4 + +#define STM_PAGE_SIZE 256 + +#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_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 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 + +/* + * 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 0x1fc00000 +#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 -urN linux-mips/drivers/mtd/maps/Config.in mips-linux-2.4.25/drivers/mtd/maps/Config.in --- linux-mips/drivers/mtd/maps/Config.in 2005-12-24 15:11:25.158488072 +0000 +++ mips-linux-2.4.25/drivers/mtd/maps/Config.in 2005-12-30 17:27:21.660122568 +0000 @@ -9,7 +9,14 @@ dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then hex ' Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000 - hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000 + if [ "$CONFIG_FLASH_2MB" = "y" ]; then + define_hex CONFIG_MTD_PHYSMAP_LEN 200000 + fi + if [ "$CONFIG_FLASH_4MB" = "y" ]; then + define_hex CONFIG_MTD_PHYSMAP_LEN 400000 + fi + +# hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000 int ' Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2 fi diff -urN linux-mips/drivers/mtd/maps/physmap.c mips-linux-2.4.25/drivers/mtd/maps/physmap.c --- linux-mips/drivers/mtd/maps/physmap.c 2005-12-24 15:11:25.217479104 +0000 +++ mips-linux-2.4.25/drivers/mtd/maps/physmap.c 2005-12-30 17:27:22.044064200 +0000 @@ -80,12 +80,25 @@ }; #ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS +#if defined(CONFIG_MTD_CMDLINE_PARTS) || defined(CONFIG_MTD_REDBOOT_PARTS) static struct mtd_partition *mtd_parts = 0; static int mtd_parts_nb = 0; #else static struct mtd_partition physmap_partitions[] = { /* Put your own partition definitions here */ + { + name: "rootfs", +#ifdef CONFIG_FLASH_2MB + size: 0x000e0000, + offset: 0x000f0000, +#endif +#ifdef CONFIG_FLASH_4MB + size: 0x002dd000, + offset: 0x00100000, +#endif + + /* Allow file system to be mounted for writing */ + } #if 0 { name: "bootROM", @@ -138,6 +151,22 @@ add_mtd_device(mymtd); #ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_REDBOOT_PARTS + { + extern int parse_redboot_partitions(struct mtd_info *master, + struct mtd_partition **pparts); + + struct mtd_partition *rb_parts = 0; + int rb_parts_nb = 0; + + rb_parts_nb = parse_redboot_partitions(mymtd, &rb_parts); + if (rb_parts_nb > 0) { + printk(KERN_NOTICE + "Using redboot flash partitioning"); + add_mtd_partitions (mymtd, rb_parts, rb_parts_nb); + } + } +#endif #ifdef CONFIG_MTD_CMDLINE_PARTS mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, "phys"); @@ -147,7 +176,8 @@ "Using command line partition definition\n"); add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb); } -#else +#endif +#if !defined(CONFIG_MTD_CMDLINE_PARTS) && !defined(CONFIG_MTD_REDBOOT_PARTS) if (NUM_PARTITIONS != 0) { printk(KERN_NOTICE diff -urN linux-mips/drivers/mtd/redboot.c mips-linux-2.4.25/drivers/mtd/redboot.c --- linux-mips/drivers/mtd/redboot.c 2005-12-24 15:11:25.249474240 +0000 +++ mips-linux-2.4.25/drivers/mtd/redboot.c 2005-12-30 17:27:22.517992152 +0000 @@ -51,8 +51,14 @@ return -ENOMEM; /* Read the start of the last erase block */ - ret = master->read(master, master->size - master->erasesize, + { + u_int32_t part_table_start = master->size - master->erasesize; +#if defined(CONFIG_MTD_END_RESERVED) + part_table_start -= CONFIG_MTD_END_RESERVED; +#endif + ret = master->read(master, part_table_start, PAGE_SIZE, &retlen, (void *)buf); + } if (ret) goto out; diff -urN linux-mips/drivers/net/Config.in mips-linux-2.4.25/drivers/net/Config.in --- linux-mips/drivers/net/Config.in 2005-12-24 15:11:25.725401888 +0000 +++ mips-linux-2.4.25/drivers/net/Config.in 2005-12-30 17:27:22.684966768 +0000 @@ -24,6 +24,18 @@ comment 'Ethernet (10 or 100Mbit)' bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then + define_bool CONFIG_VENETDEV n + tristate ' BUILT-IN ATHEROS ENET DRIVER' CONFIG_NET_ATHEROS_ETHER + if [ "$CONFIG_AP38" = "y" -o "$CONFIG_AP48" = "y" ]; then + define_bool CONFIG_KENDIN_ENET_PHY y + elif [ "$CONFIG_AP30ASK" = "y" ]; then + define_bool CONFIG_KENDIN_KS8995XA_ENET_PHY y + bool 'Multiple Ethernet address hack ' CONFIG_ASK_MULT_MAC_HACK + elif [ "$CONFIG_AP51" = "y" ]; then + define_bool CONFIG_ICPLUS_ENET_PHY y + else + define_bool CONFIG_MARVELL_ENET_PHY y + fi if [ "$CONFIG_ARM" = "y" ]; then dep_bool ' ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110 tristate ' Cirrus Logic CS8900A support' CONFIG_ARM_CIRRUS diff -urN linux-mips/drivers/net/Makefile mips-linux-2.4.25/drivers/net/Makefile --- linux-mips/drivers/net/Makefile 2005-12-24 15:11:25.726401736 +0000 +++ mips-linux-2.4.25/drivers/net/Makefile 2005-12-30 17:27:22.709962968 +0000 @@ -31,6 +31,10 @@ obj-y += e1000/e1000.o endif +ifeq ($(CONFIG_NET_ATHEROS_ETHER),y) + obj-y += ath/ae531x.o +endif + ifeq ($(CONFIG_BONDING),y) obj-y += bonding/bonding.o endif @@ -53,8 +57,13 @@ subdir-$(CONFIG_SKFP) += skfp subdir-$(CONFIG_E100) += e100 subdir-$(CONFIG_E1000) += e1000 +subdir-$(CONFIG_NET_ATHEROS_ETHER) += ath subdir-$(CONFIG_BONDING) += bonding +ifeq ($(CONFIG_ATHAP33),y) +subdir-$(CONFIG_ATHAP33) += athap33 +endif + # # link order important here # @@ -242,6 +251,10 @@ obj-$(CONFIG_R8169) += r8169.o obj-$(CONFIG_AMD8111_ETH) += amd8111e.o mii.o +ifeq ($(CONFIG_ATHAP33),y) +obj-$(CONFIG_ATHAP33) += athap33/ath_ap_mips.o +endif + # non-drivers/net drivers who want mii lib obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o obj-$(CONFIG_USB_USBNET) += mii.o diff -urN linux-mips/fs/jffs2/nodelist.h mips-linux-2.4.25/fs/jffs2/nodelist.h --- linux-mips/fs/jffs2/nodelist.h 2005-12-24 15:11:50.407649616 +0000 +++ mips-linux-2.4.25/fs/jffs2/nodelist.h 2005-12-30 17:27:51.289618200 +0000 @@ -31,7 +31,7 @@ * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * - * $Id: nodelist.h,v 1.46.2.5 2003/11/02 13:54:20 dwmw2 Exp $ + * $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/fs/jffs2/nodelist.h#3 $ * */ @@ -222,8 +222,8 @@ #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */ #define ALLOC_GC 2 /* Space requested for GC. Give it or die */ -#define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */ -#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */ +#define JFFS2_RESERVED_BLOCKS_BASE 2 /* Number of free blocks there must be before we... */ +#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem write */ #define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem deletion */ #define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */ #define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */ diff -urN linux-mips/fs/partitions/Config.in mips-linux-2.4.25/fs/partitions/Config.in --- linux-mips/fs/partitions/Config.in 2005-12-24 15:11:52.366351848 +0000 +++ mips-linux-2.4.25/fs/partitions/Config.in 2005-12-30 17:27:52.279467720 +0000 @@ -39,7 +39,7 @@ fi if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \ "$CONFIG_MAC" != "y" -a "$CONFIG_SGI_IP22" != "y" -a \ - "$CONFIG_SGI_IP27" != "y" ]; then + "$CONFIG_SGI_IP27" != "y" -a "$CONFIG_AR531X" != "y" ]; then define_bool CONFIG_MSDOS_PARTITION y fi if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_AFFS_FS" = "y" ]; then diff -urN linux-mips/include/asm-mips/atheros/ar531xbsp.h mips-linux-2.4.25/include/asm-mips/atheros/ar531xbsp.h --- linux-mips/include/asm-mips/atheros/ar531xbsp.h 1970-01-01 01:00:00.000000000 +0100 +++ mips-linux-2.4.25/include/asm-mips/atheros/ar531xbsp.h 2005-12-30 17:28:01.523062480 +0000 @@ -0,0 +1,17 @@ +#ifndef __ASM_ATHEROS_BSP_SUPPORT_H +#define __ASM_ATHEROS_BSP_SUPPORT_H +/* + * These are definitions and functions provided by the bsp to support the + * AR5312 WiSoC running LSDK. For different BSP implementations, different + * BSP functions will be needed. + */ + +extern unsigned int ar531x_sys_frequency(void); +extern const char* get_system_type(void); + +#ifdef CONFIG_KGDB +extern void kgdbInit(void); +extern int kgdbEnabled(void); +#endif + +#endif /* __ASM_ATHEROS_BSP_SUPPORT_H */ diff -urN linux-mips/include/asm-mips/bootinfo.h mips-linux-2.4.25/include/asm-mips/bootinfo.h --- linux-mips/include/asm-mips/bootinfo.h 2005-12-24 15:12:00.645093288 +0000 +++ mips-linux-2.4.25/include/asm-mips/bootinfo.h 2005-12-30 17:28:01.534060808 +0000 @@ -37,6 +37,7 @@ #define MACH_GROUP_HP_LJ 20 /* Hewlett Packard LaserJet */ #define MACH_GROUP_LASAT 21 #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */ +#define MACH_GROUP_AR531X 23 /* Atheros AR531X */ /* * Valid machtype values for group unknown (low order halfword of mips_machtype) @@ -198,6 +199,17 @@ */ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */ +/* + * Valid machtype for group MACH_GROUP_AR5312 + */ +#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 CL_SIZE (256) const char *get_system_type(void); diff -urN linux-mips/include/asm-mips/page.h mips-linux-2.4.25/include/asm-mips/page.h --- linux-mips/include/asm-mips/page.h 2005-12-24 15:12:01.097024584 +0000 +++ mips-linux-2.4.25/include/asm-mips/page.h 2005-12-30 17:28:01.898005480 +0000 @@ -13,7 +13,6 @@ #include #include -#ifdef __KERNEL__ /* * PAGE_SHIFT determines the page size @@ -30,6 +29,7 @@ #define PAGE_SIZE (1L << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) +#ifdef __KERNEL__ #ifndef __ASSEMBLY__ #include diff -urN linux-mips/include/asm-mips/serial.h mips-linux-2.4.25/include/asm-mips/serial.h --- linux-mips/include/asm-mips/serial.h 2005-12-24 15:12:01.130019568 +0000 +++ mips-linux-2.4.25/include/asm-mips/serial.h 2005-12-30 17:28:02.143968088 +0000 @@ -410,6 +410,11 @@ #define DDB5477_SERIAL_PORT_DEFNS #endif +#if defined(CONFIG_AR531X) +#undef RS_TABLE_SIZE +#define RS_TABLE_SIZE 1 +#endif + #define SERIAL_PORT_DFNS \ ATLAS_SERIAL_PORT_DEFNS \ AU1000_SERIAL_PORT_DEFNS \ diff -urN linux-mips/kernel/printk.c mips-linux-2.4.25/kernel/printk.c --- linux-mips/kernel/printk.c 2005-12-24 15:12:09.361768152 +0000 +++ mips-linux-2.4.25/kernel/printk.c 2005-12-30 17:28:11.943478336 +0000 @@ -383,6 +383,18 @@ _call_console_drivers(start_print, end, msg_level); } +#if CONFIG_EARLY_PRINTK_HACK +void putDebugChar(char byte); +static void emit_log_char(char c) +{ + if (c == '\n') { + putDebugChar('\r'); + putDebugChar('\n'); + } else { + putDebugChar(c); + } +} +#else static void emit_log_char(char c) { LOG_BUF(log_end) = c; @@ -394,6 +406,7 @@ if (logged_chars < LOG_BUF_LEN) logged_chars++; } +#endif /* * This is printk. It can be called from any context. We want it to work. @@ -696,3 +709,4 @@ tty->driver.write(tty, 0, msg, strlen(msg)); return; } + diff -urN linux-mips-orig/drivers/net/ath/ae531x.h linux-mips-new/drivers/net/ath/ae531x.h --- linux-mips-orig/drivers/net/ath/ae531x.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ae531x.h 2005-12-31 12:33:57.672538976 +0000 @@ -0,0 +1,43 @@ +#ifndef __AE531X_H +#define __AE531X_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar531xlnx.h" +#include "ae531xreg.h" +#include "ae531xmac.h" + +extern void *ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBuffp, + int *rxBuffSizep); +extern void ae531x_swptr_free(VIRT_ADDR desc); +extern BOOL ae531x_twisted_enet(void); +extern void ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, + UINT16 data); +extern UINT16 ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg); +extern void ae531x_unitLinkGained(int ethUnit); +extern void ae531x_unitLinkLost(int ethUnit); +extern void ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data); +extern void ae531x_MACReset(ae531x_MAC_t *MACInfo); +extern void ae531x_DisableComm(ae531x_MAC_t *MACInfo); +extern void ae531x_FreeQueues(ae531x_MAC_t *MACInfo); +extern void ae531x_reset(ae531x_MAC_t *MACInfo); +extern int ae531x_AllocateQueues(ae531x_MAC_t *MACInfo); +extern void ae531x_EnableComm(ae531x_MAC_t *MACInfo); +extern void ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo); +extern void ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo); +extern void ae531x_DmaReset(ae531x_MAC_t *MACInfo); +extern void ae531x_BeginResetMode(ae531x_MAC_t *MACInfo); +extern void ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 data); +extern void ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); +extern BOOL ae531x_IsInResetMode(ae531x_MAC_t *MACInfo); +extern UINT32 ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg); +extern void ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); + +#endif /* __AE531X_H */ diff -urN linux-mips-orig/drivers/net/ath/ae531xlnx.c linux-mips-new/drivers/net/ath/ae531xlnx.c --- linux-mips-orig/drivers/net/ath/ae531xlnx.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ae531xlnx.c 2005-12-31 12:33:57.673538824 +0000 @@ -0,0 +1,1303 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * Ethernet driver for Atheros' ae531x ethernet MAC. + * This is a fairly generic driver, but it's intended + * for use in typical Atheros products. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar531xlnx.h" +#include "ae531xreg.h" +#include "ae531xmac.h" +#include "ae531x.h" + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#ifdef DEBUG +void my_mvPhyShow(int ethUnit); +#endif + +static struct ar531x_boarddata *ar531x_boardConfig=NULL; + +static char *radioConfig=NULL; + +#define AE531X_LAN_PORT 0 +#define AE531X_DEV_PER_MAC 1 + +/* + * ae531x_MAC_state contains driver-specific linux-specific per-MAC information. + * The OSinfo member of ae531x_MAC_t points to one of these. + */ +typedef struct ae531x_MAC_state { + int irq; + struct tq_struct restart_task; + struct net_device_stats stats; + struct ae531x_dev_sw_state *dev_sw_state[AE531X_DEV_PER_MAC]; + int primary_dev; + ae531x_MAC_t MACInfo; /* hardware state */ +} ae531x_MAC_state_t; + +/* + * ae531x_dev_sw_state contains driver-specific linux-specific per-device + * information. The net_device priv member points to one of these, and + * this structure contains a pointer to the associated MAC information. + */ + +typedef struct ae531x_dev_sw_state { + int enetUnit; /* system unit number "eth%d" */ + int unit_on_MAC; /* MAC-relative unit number */ + struct net_device *dev; + ae531x_MAC_state_t *MAC_state; /* underlying MAC hw/sw state */ +} ae531x_dev_sw_state_t; + +/* + * Driver-independent linux-specific per-ethernet device software information. + */ +static struct net_device *ae531x_MAC_dev[AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC]; + +/* Driver-dependent per-MAC information */ +static ae531x_MAC_state_t per_MAC_info[AR531X_NUM_ENET_MAC]; + +/* + * Receive buffers need enough room to hold the following: + * 1) a max MTU-sized packet. + * 2) space for an ethernet header + * 3) room at the beginning of the receive buffer in order + * to facilitate cooperating drivers that need to PREpend + * data. + * 4) Depending on configuration, we may need some additional + * room at the END of the rx buffer for phy-supplied + * trailers (if any). (c.f. CONFIG_VENETDEV) + * + * The DMA engine insists on 32-bit aligned RX buffers. + * TBDXXX: With current code, the IP stack ends up looking + * at misaligned headers with word operations. The misaligned + * reads are software-emulated via handle_adel_int. We'd + * rather align the buffers on a 16-bit boundary, but the + * DMA engine doesn't permit it??? + */ +#define ETH_MAX_MTU 1518 +#define AE531X_RX_BUF_SIZE \ + (((RXBUFF_RESERVE + ETH_HLEN + ETH_MAX_MTU + PHY_TRAILER_SIZE) + 3) & ~3) + +/* Forward references to local functions */ +static void ae531x_TxReap(ae531x_MAC_state_t *MAC_state); +static int ae531x_phy_poll(void *data); +static int ae531x_MAC_stop(struct net_device *dev); +static int ae531x_MAC_open(struct net_device *dev); + +/******************************************************************************* +* ae531x_MAC_poll checks for received packets, and sends data +* up the stack. +*/ +int +ae531x_MAC_poll(struct net_device *dev, int *budget) +{ + struct sk_buff *skb; + struct sk_buff *newskb; + char *rxBufp; + int unused_length; + VIRT_ADDR rxDesc; + int length; + ae531x_dev_sw_state_t *dev_sw_state; + ae531x_MAC_state_t *MAC_state; + ae531x_MAC_t *MACInfo; + u32 cmdsts; + int rx_limit; + int rx_received; + int rxDescCount; + struct net_device *rxdev; + int early_stop; + int retval; +#ifdef DEBUG + static int rxDescCountMax = 0; +#endif + + ARRIVE(); + + dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; + MAC_state = dev_sw_state->MAC_state; + MACInfo = &MAC_state->MACInfo; + rx_limit = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev->quota; + rx_received = 0; + + rxDescCount = 0; + + early_stop = 0; + do { + ae531x_AckIntr(MACInfo, DmaIntRxCompleted); + + for(;!early_stop;) { + rxDesc = MACInfo->rxQueue.curDescAddr; + cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(rxDesc)); + + AE531X_PRINT(AE531X_DEBUG_RX, + ("examine rxDesc %p with cmdsts=0x%x\n", + (void *)rxDesc, cmdsts)); + + if (cmdsts & DescOwnByDma) { + /* There's nothing left to process in the RX ring */ + goto rx_all_done; + } + + rxDescCount++; + + AE531X_CONSUME_DESC((&MACInfo->rxQueue)); + + A_DATA_CACHE_INVAL(rxDesc, AE531X_DESC_SIZE); + + /* Process a packet */ + length = AE531X_DESC_STATUS_RX_SIZE(cmdsts) - ETH_CRC_LEN; + if ( (cmdsts & (DescRxFirst |DescRxLast | DescRxErrors)) == + (DescRxFirst | DescRxLast) ) { + /* Descriptor status indicates "NO errors" */ + skb = AE531X_DESC_SWPTR_GET(rxDesc); + + /* + * Allocate a replacement skb. + * We want to get another buffer ready for Rx ASAP. + */ + newskb = (struct sk_buff *)ae531x_rxbuf_alloc(MACInfo, &rxBufp, &unused_length); + if(newskb == NULL ) { + /* + * Give this descriptor back to the DMA engine, + * and drop the received packet. + */ + MAC_state->stats.rx_dropped++; + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("Can't allocate new skb\n")); + } else { + AE531X_DESC_BUFPTR_SET(rxDesc, virt_to_bus(rxBufp)); + AE531X_DESC_SWPTR_SET(rxDesc, newskb); + } + + AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma); + rxDesc = NULL; /* sanity -- cannot use rxDesc now */ + sysWbFlush(); + + if (newskb == NULL) { + retval = 1; + goto rx_no_skbs; + } else { + /* Sync data cache w.r.t. DMA */ + A_DATA_CACHE_INVAL(skb->data, length); + + rxdev = dev_sw_state->dev; + + if (rxdev == NULL) { + /* + * We received a packet for a virtual enet device + * that is no longer up. Ignore it. + */ + kfree_skb(skb); + continue; + } + + /* Advance data pointer to show that there's data here */ + skb_put(skb, length); + skb->protocol = eth_type_trans(skb, rxdev); + skb->dev = rxdev; + rxdev->last_rx = jiffies; + rxdev->quota--; + + if (rx_limit-- < 0) { + early_stop=1; + /* We've done enough for now -- more later */ + AE531X_PRINT(AE531X_DEBUG_RX_STOP, + ("Enet%d RX early stop. Quota=%d rxDescCount=%d budget=%d\n", + MACInfo->unit, dev->quota, rxDescCount, *budget)); + } + rx_received++; + + /* Send the data up the stack */ + AE531X_PRINT(AE531X_DEBUG_RX, + ("Send data up stack: skb=%p data=%p length=%d\n", + (void *)skb, (void *)skb->data, length)); + + netif_receive_skb(skb); + + MAC_state->stats.rx_packets++; + MAC_state->stats.rx_bytes += length; + } + } else { + /* Descriptor status indicates ERRORS */ + MAC_state->stats.rx_errors++; + + if (cmdsts & (DescRxRunt | DescRxLateColl)) { + MAC_state->stats.collisions++; + } + + if (cmdsts & DescRxLengthError) { + MAC_state->stats.rx_length_errors++; + } + + if (cmdsts & DescRxCrc) { + MAC_state->stats.rx_crc_errors++; + } + + if (cmdsts & DescRxDribbling) { + MAC_state->stats.rx_frame_errors++; + } + + AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma); + + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("Bad receive. rxDesc=%p cmdsts=0x%8.8x\n", + (void *)rxDesc, cmdsts)); + } + } + } while ((!early_stop) && + ae531x_ReadDmaReg(MACInfo, DmaStatus) & DmaIntRxCompleted); + +rx_all_done: + AE531X_PRINT(AE531X_DEBUG_RX, + ("rx done (%d)\n", rxDescCount)); + *budget -= rxDescCount; + + if (!early_stop) { + netif_rx_complete(dev); + + ae531x_SetDmaReg(MACInfo, DmaIntrEnb, + DmaIeRxCompleted | DmaIeRxNoBuffer); + ae531x_WriteDmaReg(MACInfo, DmaRxPollDemand, 0); + } + + retval = early_stop; + +rx_no_skbs: + + LEAVE(); + +#ifdef DEBUG + if (rxDescCount > rxDescCountMax) { + printk("max rx %d\n", rxDescCount); + rxDescCountMax = rxDescCount; + } +#endif + + return retval; +} + +/******************************************************************************* +* ae531x_restart stops all ethernet devices associated with a physical MAC, +* then shuts down the MAC. Then it re-opens all devices that were in use. +* TBDXXX: needs testing! +*/ +static void +ae531x_restart(void *data) +{ + ae531x_MAC_t *MACInfo = (ae531x_MAC_t *)data; + ae531x_MAC_state_t *MAC_state = (ae531x_MAC_state_t *)MACInfo->OSinfo; + struct net_device *saved_dev[AE531X_DEV_PER_MAC]; + int i; + + for (i=0; idev_sw_state[i]->dev) != NULL) { + ae531x_MAC_stop(saved_dev[i]); + } + } + + for (i=0; iOSinfo; + for(;;) { + /* Clear any unhandled intr causes. */ + ae531x_WriteDmaReg(MACInfo, DmaStatus, UnhandledIntrMask); + + regIsr = ae531x_ReadDmaReg(MACInfo, DmaStatus); + regImr = ae531x_ReadDmaReg(MACInfo, DmaIntrEnb); + pendIntrs = regIsr & regImr; + + AE531X_PRINT(AE531X_DEBUG_INT, + ("ethmac%d: intIsr=0x%8.8x intImr=0x%8.8x pendIntrs=0x%8.8x\n", + MACInfo->unit, regIsr, regImr, pendIntrs )); + + if ((pendIntrs & DmaAllIntCauseMask) == 0) + break; + + if ((pendIntrs & DmaIntRxCompleted) || + (pendIntrs & DmaIntRxNoBuffer)) { + if (netif_rx_schedule_prep(MAC_state->dev_sw_state[MAC_state->primary_dev]->dev)) { + ae531x_ClearDmaReg(MACInfo, + DmaIntrEnb, + DmaIeRxCompleted | DmaIeRxNoBuffer); + ae531x_AckIntr(MACInfo, + DmaIntRxCompleted | DmaIntRxNoBuffer); + (void)ae531x_ReadDmaReg(MACInfo, DmaIntrEnb); + __netif_rx_schedule(MAC_state->dev_sw_state[MAC_state->primary_dev]->dev); + } else { +#if 0 + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("%s: Interrupt (0x%8.8x/0x%8.8x) while in poll. regs@%p, pc=%p, ra=%p\n", + __FILE__, + regIsr, + ae531x_ReadDmaReg(MACInfo, DmaIntrEnb), + (void *)regs, + (void *)regs->cp0_epc, + (void *)regs->regs[31])); +#endif + ae531x_AckIntr(MACInfo, + DmaIntRxCompleted | DmaIntRxNoBuffer); + } + } + + if (pendIntrs & + (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow)) { + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("ethmac%d: TX Error Intr (0x%x)\n", + MACInfo->unit, pendIntrs)); + ae531x_AckIntr(MACInfo, + (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow)); + } + + if (pendIntrs & DmaIntBusError) { + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("ethmac%d: DMA Bus Error Intr (0x%x)\n", + MACInfo->unit, pendIntrs)); + ae531x_AckIntr(MACInfo, DmaIntBusError); + /* Reset the chip, if it's not already being done */ + if (ae531x_IsInResetMode(MACInfo)) { + goto intr_done; + } + ae531x_BeginResetMode(MACInfo); + schedule_task(&MAC_state->restart_task); + } + + if (pendIntrs & DmaIntRxStopped) { + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("ethmac%d: RX Stopped Intr (0x%x)\n", + MACInfo->unit, pendIntrs)); + ae531x_AckIntr(MACInfo, DmaIntRxStopped); + } + } + + intr_done: + LEAVE(); +} + +/******************************************************************************* +* ae531x_MAC_get_stats returns statistics for a specified device +*/ +static struct net_device_stats* +ae531x_MAC_get_stats(struct net_device *dev) +{ + ae531x_dev_sw_state_t *dev_sw_state; + ae531x_MAC_state_t *MAC_state; + + ARRIVE(); + dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; + MAC_state = dev_sw_state->MAC_state; + + LEAVE(); + return &MAC_state->stats; +} + +#define AE531X_PHY_POLL_SECONDS 2 + +#if CONFIG_AR5315 + +/******************************************************************************* +* ae531x_getMACInfo returns the MACInfo of the interface given by unit +*/ +ae531x_MAC_t *ae531x_getMAcInfo(int ethUnit) +{ + int i,j; + for(i=0;ienetUnit == ethUnit) + return (&(per_MAC_info[i].MACInfo)); + } + } + } + return NULL; +} + + +#endif + +/******************************************************************************* +* ae531x_phy_poll periodically checks for changes in phy status +* (e.g. dropped link). +*/ +static int +ae531x_phy_poll(void *data) +{ + ae531x_dev_sw_state_t *dev_sw_state = (ae531x_dev_sw_state_t *)data; + ae531x_MAC_t *MACInfo = &dev_sw_state->MAC_state->MACInfo; + int unit = dev_sw_state->enetUnit; + + while(dev_sw_state->dev!=NULL) { + if (MACInfo->port_is_up) { + phyCheckStatusChange(unit); + } + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(AE531X_PHY_POLL_SECONDS * HZ); + } + + return 0; +} + + +static char invalid_enet_MAC_addr[] = {0, 0, 0, 0, 0, 0}; + +/* + * Fetch a pointer to an ethernet's MAC address + * in the Board Configuration data (in flash). + */ +char * +ae531x_enet_mac_address_get(int MACUnit) +{ + /* XXX: Hack for poorly configured boards. + * Cannot setup bridging properly (brctl) when both enet + * interfaces share the same MAC address. + * + */ + +#ifdef CONFIG_ASK_MULT_MAC_HACK + static u8 enet0Mac[6] = {0x00, 0x0d, 0x0b, 0x13, 0x6b, 0x16}; + static u8 enet1Mac[6] = {0x00, 0x0d, 0x0b, 0x13, 0x6b, 0x17}; +#endif + + if (!ar531x_boardConfig) + return invalid_enet_MAC_addr; + if (MACUnit == 0) { +#ifndef CONFIG_ASK_MULT_MAC_HACK + return ar531x_boardConfig->enet0Mac; +#else + return enet0Mac; +#endif + } + if (MACUnit == 1) { +#ifndef CONFIG_ASK_MULT_MAC_HACK + return ar531x_boardConfig->enet1Mac; +#else + return enet1Mac; +#endif + } + printk("Invalid ethernet MAC unit number (%d)!\n", MACUnit); + return invalid_enet_MAC_addr; +} + + + +/******************************************************************************* +* ae531x_MAC_open is the standard Linux open function. It puts +* hardware into a known good state, allocates queues, starts +* the phy polling task, and arranges for interrupts to be handled. +*/ +static int +ae531x_MAC_open(struct net_device *dev) +{ + ae531x_dev_sw_state_t *dev_sw_state; + ae531x_MAC_state_t *MAC_state; + ae531x_MAC_t *MACInfo; + u8 *MACAddr; + int rv; + struct tq_struct *restart_task; + pid_t phy_poll_pid; + ARRIVE(); + + dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; + dev_sw_state->dev = dev; + MAC_state = dev_sw_state->MAC_state; + MACInfo = &MAC_state->MACInfo; + + restart_task = &MAC_state->restart_task; + restart_task->routine = ae531x_restart; + restart_task->data = (void *)MACInfo; + + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ae531x_MAC_open eth%d ethmac%d macBase=0x%x dmaBase=0x%x irq=0x%x\n", + dev_sw_state->enetUnit, + MACInfo->unit, + MACInfo->macBase, + MACInfo->dmaBase, + MAC_state->irq)); + + /* Default MAC address */ + MACAddr = ae531x_enet_mac_address_get(MACInfo->unit); + memcpy(dev->dev_addr, MACAddr, dev->addr_len ); + + if (!MACInfo->port_is_up) { + /* Bring MAC and PHY out of reset */ + ae531x_reset(MACInfo); + + /* Attach interrupt handler */ + rv = request_irq(MAC_state->irq, ae531x_MAC_intr, SA_INTERRUPT, + "ae531x_MAC_intr", (void *)MACInfo); + if (rv < 0) { + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("request_irq(0x%x) failed (%d)\n", + MAC_state->irq, rv)); + goto open_failure; + } + + /* Initialize PHY */ + AE531X_PRINT(AE531X_DEBUG_RESET, ("\n --- phyBase: %08x\n", MACInfo->phyBase)); + phySetup(MACInfo->unit, MACInfo->phyBase); + + /* Start thread to poll for phy link status changes */ + phy_poll_pid = kernel_thread(ae531x_phy_poll, dev_sw_state, 0); + if (phy_poll_pid < 0) { + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("ethmac%d unable to start Phy Poll thread\n", + MACInfo->unit)); + } + + /* Allocate RX/TX Queues */ + if (ae531x_AllocateQueues(MACInfo) < 0) { + AE531X_PRINT(AE531X_DEBUG_RESET, ("Queue allocation failed")); + free_irq(MAC_state->irq, (void *)MACInfo); + goto open_failure; + } + + /* Initialize DMA and descriptors */ + ae531x_DmaReset(MACInfo); + + /* Initialize MAC */ + ae531x_MACReset(MACInfo); + + /* Enable Receive/Transmit */ + ae531x_EnableComm(MACInfo); + + MAC_state->primary_dev = dev_sw_state->unit_on_MAC; + MACInfo->port_is_up = TRUE; + } + + dev->trans_start = jiffies; + SET_MODULE_OWNER(dev); + + LEAVE(); + return 0; + +open_failure: + LEAVE(); + return -1; +} + +/* + * Shut down MAC hardware. + */ +static void +ae531x_MAC_shutdown(ae531x_MAC_state_t *MAC_state) +{ + ae531x_MAC_t *MACInfo; + + MACInfo = &MAC_state->MACInfo; + MACInfo->port_is_up = FALSE; + + /* Disable Receive/Transmit */ + ae531x_DisableComm(MACInfo); + + /* Disable Interrupts */ + ae531x_DmaIntDisable(MACInfo); + sysWbFlush(); + free_irq(MAC_state->irq, (void *)MACInfo); + + /* Free Transmit & Receive skb's/descriptors */ + ae531x_TxReap(MAC_state); /* one last time */ + ae531x_FreeQueues(MACInfo); +} + +/******************************************************************************* +* ae531x_MAC_stop is the standard Linux stop function. It undoes +* everything set up by ae531x_MAC_open. +*/ +static int +ae531x_MAC_stop(struct net_device *dev) +{ + ae531x_dev_sw_state_t *dev_sw_state; + ae531x_MAC_state_t *MAC_state; + ae531x_MAC_t *MACInfo; + int i; + + ARRIVE(); + + dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; + MAC_state = dev_sw_state->MAC_state; + MACInfo = &MAC_state->MACInfo; + + for (i=0; idev_sw_state[i]->dev) && + (MAC_state->dev_sw_state[i]->dev != dev_sw_state->dev)) { + break; + } + } + + if (i < AE531X_DEV_PER_MAC) { + /* Physical MAC is still in use */ + if (MAC_state->primary_dev == dev_sw_state->unit_on_MAC) { + /* + * If the primary_dev is being stopped + * then we need to assign a new one. + */ + MAC_state->primary_dev = i; + } + } else { + /* Physical MAC is no longer in use */ + ae531x_MAC_shutdown(MAC_state); + } + + dev_sw_state->dev = NULL; + LEAVE(); + return 0; +} + +/******************************************************************************* +* ae531x_rxbuf_alloc - Allocate an skb to be associated with an RX descriptor. +* +* RETURNS: A pointer to the skb. Also returns a pointer to the underlying +* buffer and the size of that buffer. +*/ +void * +ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBuffp, int *rxBuffSizep) +{ + int buf_size; + struct sk_buff *skb; + char *rxBuff; + int rxBuffSize; + + buf_size = AE531X_RX_BUF_SIZE; + + skb = dev_alloc_skb(buf_size); + if (skb) { + /* skb->dev = dev; */ + skb_reserve(skb, RXBUFF_RESERVE); + + rxBuffSize = skb_tailroom(skb); + rxBuff = skb->tail; + + *rxBuffp = rxBuff; + *rxBuffSizep = rxBuffSize; + } + + return skb; +} + +/******************************************************************************* +* ae531x_swptr_free - Free the skb, if any, associated with a descriptor. +*/ +void +ae531x_swptr_free(VIRT_ADDR desc) +{ + struct sk_buff *skb; + + skb = (struct sk_buff *)AE531X_DESC_SWPTR_GET(desc); + if (skb) { + AE531X_DESC_SWPTR_SET(desc, NULL); + kfree_skb(skb); + } +} + +/******************************************************************************* +* +* ae531x_TxReap - the driver Tx completion routine. +* +* This routine reaps sk_buffs which have already been transmitted. +* +*/ +static void +ae531x_TxReap(ae531x_MAC_state_t *MAC_state) +{ + AE531X_QUEUE *txq; + VIRT_ADDR txDesc; + UINT32 cmdsts; + struct sk_buff *skb; + int reaped; + ae531x_MAC_t *MACInfo; + static int aeUselessReap = 0; +#ifdef DEBUG + static int aeMaxReap = 0; +#endif + ARRIVE(); + + MACInfo = &MAC_state->MACInfo; + txq = &MACInfo->txQueue; + reaped = 0; + + while (1) { + + txDesc = AE531X_QUEUE_ELE_NEXT_GET(txq, txq->reapDescAddr); + if (txDesc == txq->curDescAddr) { + break; + } + + cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(txDesc)); + if (cmdsts & DescOwnByDma) { + break; + } + + /* Release sk_buff associated with completed transmit */ + skb = (struct sk_buff *)AE531X_DESC_SWPTR_GET(txDesc); + if (skb) { + kfree_skb(skb); + AE531X_DESC_SWPTR_SET(txDesc, NULL); + } + + /* Update statistics according to completed transmit desc */ + if (cmdsts & DescTxErrors) { + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("enetmac%d Tx prior error: 0x%8.8x <0x%8.8x> 0x%8.8x\n", + MACInfo->unit, + cmdsts, + DescTxErrors, + (int)txDesc)); +#ifdef DEBUG + //my_mvPhyShow(MACInfo->unit); + printk ("ae531xMacControl: 0x%08x\tMacFlowControl: 0x%08x\n", + ae531x_ReadMacReg(MACInfo, MacControl), + ae531x_ReadMacReg(MACInfo, MacFlowControl)); +#endif + MAC_state->stats.tx_errors++; + if (cmdsts & (DescTxLateCollision | DescTxExcCollisions)) { + MAC_state->stats.tx_aborted_errors++; + } + if (cmdsts & (DescTxLostCarrier | DescTxNoCarrier)) { + MAC_state->stats.tx_carrier_errors++; + } + } else { + MAC_state->stats.tx_bytes += AE531X_DESC_STATUS_RX_SIZE(cmdsts); + MAC_state->stats.tx_packets++; + } + + MAC_state->stats.collisions += + ((cmdsts & DescTxCollMask) >> DescTxCollShift); + + txq->reapDescAddr = txDesc; + reaped++; + } + + if (reaped > 0) { + int i; + +#ifdef DEBUG + if (reaped > aeMaxReap) { + aeMaxReap = reaped; + printk("max reaped = %d\n", reaped); + } +#endif + AE531X_PRINT(AE531X_DEBUG_TX_REAP, + ("reaped %d\n", reaped)); + + /* + * Re-start transmit queues for all ethernet devices + * associated with this MAC. + */ + for (i=0; idev_sw_state[i]->dev) + netif_start_queue(MAC_state->dev_sw_state[i]->dev); + } + } else { + aeUselessReap++; + } + + LEAVE(); +} + + +/******************************************************************************* +* ae531x_MAC_start_xmit sends a packet. +*/ +static int +ae531x_MAC_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + ae531x_dev_sw_state_t *dev_sw_state; + ae531x_MAC_state_t *MAC_state; + ae531x_MAC_t *MACInfo; + u32 buf; + u32 ctrlen; + u32 length; + int mtu; + int max_buf_size; + VIRT_ADDR txDesc; + + ARRIVE(); + + dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; + MAC_state = dev_sw_state->MAC_state; + MACInfo = &MAC_state->MACInfo; + + length = skb->len; + + /* Check if this port is up, else toss packet */ + if (!MACInfo->port_is_up) { + buf = virt_to_bus(skb->data); + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("eth%d Tx Down, dropping buf=0x%8.8x, length=0x%8.8x, skb=%p\n", + dev_sw_state->enetUnit, buf, length, (void *)skb)); + + MAC_state->stats.tx_dropped++; + MAC_state->stats.tx_carrier_errors++; + goto dropFrame; + } + + if (ae531x_IsInResetMode(MACInfo)) { + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("eth%d Tx: In Chip reset - drop frame\n", + dev_sw_state->enetUnit)); + + MAC_state->stats.tx_dropped++; + MAC_state->stats.tx_aborted_errors++; + goto dropFrame; + } + + /* Check if we can transport this packet */ + length = max((u32)60, length); /* total length */ + mtu = dev->mtu; + max_buf_size = mtu + ETH_HLEN; + if (length > max_buf_size) { + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("eth%d Tx: length %d too long. mtu=%d, trailer=%d\n", + dev_sw_state->enetUnit, length, mtu, PHY_TRAILER_SIZE)); + + MAC_state->stats.tx_errors++; + MAC_state->stats.tx_aborted_errors++; + + goto dropFrame; + } + + /* Reap any old, completed Tx descriptors */ + ae531x_TxReap(MAC_state); + + txDesc = MACInfo->txQueue.curDescAddr; + if (txDesc == MACInfo->txQueue.reapDescAddr) { + int i; + + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("eth%d Tx: cannot get txDesc\n", + dev_sw_state->enetUnit)); + + MAC_state->stats.tx_dropped++; + MAC_state->stats.tx_fifo_errors++; + + /* + * Stop transmit queues for any ethernet devices + * associated with this MAC. + */ +#if 0 /* XXX: no way to recover from queue stop until ae531x_MAC_tx_timeout() + * is rewritten to avoid calls to shedule(). + */ + for (i=0; idev_sw_state[i]->dev) + netif_stop_queue(MAC_state->dev_sw_state[i]->dev); + } +#endif + goto dropFrame; + } + + /* We won't fail now; so consume this descriptor */ + AE531X_CONSUME_DESC((&MACInfo->txQueue)); + + /* Update the descriptor */ + buf = virt_to_bus(skb->data); + AE531X_DESC_BUFPTR_SET(txDesc, buf); + AE531X_DESC_SWPTR_SET(txDesc, skb); + ctrlen = AE531X_DESC_CTRLEN_GET(txDesc); + ctrlen = (ctrlen & (DescEndOfRing)) | + DescTxFirst | + DescTxLast | + DescTxIntEnable; + + ctrlen |= ((length << DescSize1Shift) & DescSize1Mask); + + AE531X_DESC_CTRLEN_SET(txDesc, ctrlen); + AE531X_DESC_STATUS_SET(txDesc, DescOwnByDma); + + /* Alert DMA engine to resume Tx */ + ae531x_WriteDmaReg(MACInfo, DmaTxPollDemand, 0); + sysWbFlush(); + + AE531X_PRINT(AE531X_DEBUG_TX, + ("eth%d Tx: Desc=0x%8.8x, L=0x%8.8x, D=0x%8.8x, d=0x%8.8x, length=0x%8.8x\n", + dev_sw_state->enetUnit, + (UINT32)txDesc, + AE531X_DESC_CTRLEN_GET(txDesc), + buf, + AE531X_DESC_LNKBUF_GET(txDesc), + length)); + + /* Tell upper layers to keep it coming */ + dev->trans_start = jiffies; + + LEAVE(); + + return 0; + +dropFrame: + kfree_skb(skb); + LEAVE(); + return 0; +} + + +/******************************************************************************* +* ae531x_MAC_tx_timeout handles transmit timeouts +*/ +static void +ae531x_MAC_tx_timeout(struct net_device *dev) +{ + ae531x_dev_sw_state_t *dev_sw_state; + ae531x_MAC_state_t *MAC_state; + ae531x_MAC_t *MACInfo; + + ARRIVE(); + + dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; + MAC_state = dev_sw_state->MAC_state; + MACInfo = &MAC_state->MACInfo; + + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("enet%d: Tx timeout\n", dev_sw_state->enetUnit)); + + ae531x_restart(MACInfo); + + LEAVE(); +} + + +/******************************************************************************* +* ae531x_MAC_do_ioctl is a placeholder for future ioctls. +*/ +static int +ae531x_MAC_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + int rv; + ae531x_MAC_t *MACInfo; + struct ioctl_data { + u32 unit; + u32 addr; + u32 data; + } *req; + ae531x_dev_sw_state_t *dev_sw_state; + ae531x_MAC_state_t *MAC_state; + + ARRIVE(); + + dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; + MAC_state = dev_sw_state->MAC_state; + MACInfo = &MAC_state->MACInfo; + + req = (struct ioctl_data *)ifr->ifr_data; + + switch( cmd ) { + default: + AE531X_PRINT(AE531X_DEBUG_ERROR, + ("Unsupported ioctl: 0x%x\n", cmd)); + rv = -EOPNOTSUPP; + } + + LEAVE(); + return rv; +} + +static void +ae531x_MAC_setup_fntable(struct net_device *dev) +{ + ARRIVE(); + + dev->get_stats = ae531x_MAC_get_stats; + dev->open = ae531x_MAC_open; + dev->stop = ae531x_MAC_stop; + dev->hard_start_xmit = ae531x_MAC_start_xmit; + dev->do_ioctl = ae531x_MAC_do_ioctl; + dev->poll = ae531x_MAC_poll; + dev->weight = 16; +#if 0 /* XXX: currently, ae531x_MAC_tx_timeout() will call functions + * that in turn call schedule(). this is BAD, since the + * timeout call runs at interrupt time. until ae531x_MAC_tx_timeout + * is rewritten to avoid schedule() calls, we do not use it. + */ + dev->tx_timeout = ae531x_MAC_tx_timeout; +#else + dev->tx_timeout = NULL; +#endif + dev->features = NETIF_F_HW_CSUM |\ + NETIF_F_HIGHDMA; + + LEAVE(); +} + +static void +ar5312EepromRead(char *EepromAddr, u_int16_t id, unsigned int off, + unsigned int nbytes, char *data) +{ + int i; + + for (i=0; i>8) & + (AR531X_REV_MAJ | AR531X_REV_MIN))); + switch (devid) { + case AR5212_AR5312_REV2: + case AR5212_AR5312_REV7: + /* Need to determine if we have a 5312 or a 2312 since they + have the same Silicon Rev ID*/ + ar5312EepromRead(radioConfig,0,2*AR531X_RADIO_MASK_OFF,2, + (char *) &radioMask); + if ((radioMask & AR531X_RADIO0_MASK) != 0) { + return 2; + } + return 1; + case AR5212_AR2313_REV8: + return 1; + } + + /* default to 1 */ + return 1; +} + +BOOL +ae531x_twisted_enet(void) +{ + int wisoc_revision; + + wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> AR531X_REV_MAJ_S; + if ( (wisoc_revision == AR531X_REV_MAJ_AR2313) || + /* next clause is used to determine AR2312, based on number of MACs. + * must do this since revision is same for 5312 and 2312. + */ + (wisoc_revision == AR531X_REV_MAJ_AR5312 && ae531x_get_numMACs() == 1) ) { + return TRUE; + } else { + return FALSE; + } +} + +int +ae531x_get_board_config(void) +{ + int dataFound; + char *bd_config; + + /* + * Find start of Board Configuration data, using heuristics: + * Search back from the (aliased) end of flash by 0x1000 bytes + * at a time until we find the string "5311", which marks the + * start of Board Configuration. Give up if we've searched + * more than 500KB. + */ + dataFound = 0; + for (bd_config = (char *)0xbffff000; + bd_config > (char *)0xbff80000; + bd_config -= 0x1000) + { + if ( *(int *)bd_config == AR531X_BD_MAGIC) { + dataFound = 1; + break; + } + } + + if (!dataFound) { + printk("Could not find Board Configuration Data\n"); + bd_config = NULL; + } + + ar531x_boardConfig = (struct ar531x_boarddata *) bd_config; + + return(dataFound); +} + +int +ae531x_get_radio_config(void) +{ + int dataFound; + char *radio_config; + + /* + * Now find the start of Radio Configuration data, using heuristics: + * Search forward from Board Configuration data by 0x1000 bytes + * at a time until we find non-0xffffffff. + */ + dataFound = 0; + for (radio_config = ((char *) ar531x_boardConfig) + 0x1000; + radio_config < (char *)0xbffff000; + radio_config += 0x1000) + { + if (*(int *)radio_config != 0xffffffff) { + dataFound = 1; + break; + } + } + + if (!dataFound) { /* AR2316 relocates radio config to new location */ + dataFound = 0; + for (radio_config = ((char *) ar531x_boardConfig) + 0xf8; + radio_config < (char *)0xbffff0f8; + radio_config += 0x1000) + { + if (*(int *)radio_config != 0xffffffff) { + dataFound = 1; + break; + } + } + } + + if (!dataFound) { + printk("Could not find Radio Configuration data\n"); + radio_config = NULL; + } + radioConfig = radio_config; + return(dataFound); +} + +static int __init +ae531x_MAC_setup(void) +{ + int next_dev, i; + struct net_device *dev; + ae531x_dev_sw_state_t *dev_sw_state; + ae531x_MAC_state_t *MAC_state; + ae531x_MAC_t *MACInfo; + char *addr; + + ARRIVE(); + + MOD_INC_USE_COUNT; + for (i=0;i=0; + i++, next_dev--){ + + /* if MAC is bogus in config data, skip */ + addr = ae531x_enet_mac_address_get(next_dev); + if((*(u32 *)addr == 0xffffffff) && (*(u16 *)(addr+4)==0xffff)){ + /* bogus MAC config data */ + continue; + } + + dev = ae531x_MAC_dev[next_dev] = + init_etherdev(NULL, sizeof(ae531x_dev_sw_state_t)); + + if (dev == NULL) { + LEAVE(); + return -1; + } + + ae531x_MAC_setup_fntable(dev); + + dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; + dev_sw_state->enetUnit = next_dev; + dev_sw_state->unit_on_MAC = 0; + MAC_state = &per_MAC_info[next_dev]; + dev_sw_state->MAC_state = MAC_state; + MAC_state->dev_sw_state[AE531X_LAN_PORT] = dev_sw_state; + MAC_state->primary_dev = -1; + + /* Initialize per-MAC information */ + MACInfo = &MAC_state->MACInfo; + + MACInfo->unit = next_dev; + + if (MACInfo->unit == 0) { + MACInfo->macBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_MAC_OFFSET); + MACInfo->dmaBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_DMA_OFFSET); + MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET); + MAC_state->irq = AR531X_IRQ_ENET0_INTRS; + } else { +#ifndef CONFIG_AR5315 + MACInfo->macBase = (u32) (PHYS_TO_K1(AR531X_ENET1)+AE531X_MAC_OFFSET); + MACInfo->dmaBase = (u32) (PHYS_TO_K1(AR531X_ENET1)+AE531X_DMA_OFFSET); + if (ae531x_twisted_enet()) { + MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET); + } else { + MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_PHY_OFFSET); + } + MAC_state->irq = AR531X_IRQ_ENET1_INTRS; +#endif + } + + MACInfo->OSinfo = (void *)MAC_state; + + } + + LEAVE(); + return 0; +} +module_init(ae531x_MAC_setup); + +/******************************************************************************* +* ae531x_MAC_unload is the module unload function +*/ +static void __exit +ae531x_MAC_unload(void) +{ + int i; + + for (i=0;ipriv)->dev) != NULL) + ae531x_MAC_stop(ae531x_MAC_dev[i]); + ae531x_MAC_dev[i] = NULL; + } + } + MOD_DEC_USE_COUNT; +} + +MODULE_AUTHOR("Atheros Communications, Inc."); +MODULE_DESCRIPTION("Support for Atheros WiSoC Ethernet device"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Atheros"); +#endif +module_exit(ae531x_MAC_unload); diff -urN linux-mips-orig/drivers/net/ath/ae531xmac.c linux-mips-new/drivers/net/ath/ae531xmac.c --- linux-mips-orig/drivers/net/ath/ae531xmac.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ae531xmac.c 2005-12-31 12:33:57.673538824 +0000 @@ -0,0 +1,951 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + + +/* + * Ethernet driver for Atheros' ae531x ethernet MAC. + */ + +#if linux +#include +#include +#include +#include +#include +#include +#include + +#include "ar531xlnx.h" +#endif /* linux */ + +#include "ae531xreg.h" +#include "ae531xmac.h" + +#ifdef DEBUG +int ae531x_MAC_debug = AE531X_DEBUG_ERROR; +#else +int ae531x_MAC_debug = 0; +#endif + +extern char *ae531x_enet_mac_address_get(int); + +/* Forward references to local functions */ +static void ae531x_QueueDestroy(AE531X_QUEUE *q); + + +/****************************************************************************** +* +* ae531x_ReadMacReg - read AE MAC register +* +* RETURNS: register value +*/ +UINT32 +ae531x_ReadMacReg(ae531x_MAC_t *MACInfo, UINT32 reg) +{ + UINT32 addr = MACInfo->macBase+reg; + UINT32 data; + + data = RegRead(addr); + return data; +} + + +/****************************************************************************** +* +* ae531x_WriteMacReg - write AE MAC register +* +* RETURNS: N/A +*/ +void +ae531x_WriteMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data) +{ + UINT32 addr = MACInfo->macBase+reg; + + RegWrite(data, addr); +} + + +/****************************************************************************** +* +* ae531x_SetMacReg - set bits in AE MAC register +* +* RETURNS: N/A +*/ +void +ae531x_SetMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val) +{ + UINT32 addr = MACInfo->macBase+reg; + UINT32 data = RegRead(addr); + + data |= val; + RegWrite(data, addr); +} + + +/****************************************************************************** +* +* ae531x_ClearMacReg - clear bits in AE MAC register +* +* RETURNS: N/A +*/ +void +ae531x_ClearMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val) +{ + UINT32 addr = MACInfo->macBase+reg; + UINT32 data = RegRead(addr); + + data &= ~val; + RegWrite(data, addr); +} + + +/****************************************************************************** +* +* ae531x_ReadDmaReg - read AE DMA register +* +* RETURNS: register value +*/ +UINT32 +ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg) +{ + UINT32 addr = MACInfo->dmaBase+reg; + UINT32 data = RegRead(addr); + + return data; +} + + +/****************************************************************************** +* +* ae531x_WriteDmaReg - write AE DMA register +* +* RETURNS: N/A +*/ +void +ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data) +{ + UINT32 addr = MACInfo->dmaBase+reg; + + RegWrite(data, addr); +} + + +/****************************************************************************** + * + * ae531x_AckIntr - clear interrupt bits in the status register. + * Note: Interrupt bits are *cleared* by writing a 1. + */ +void +ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 data) +{ + ae531x_WriteDmaReg(MACInfo, DmaStatus, data); +} + + +/****************************************************************************** +* +* ae531x_SetDmaReg - set bits in an AE DMA register +* +* RETURNS: N/A +*/ +void +ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val) +{ + UINT32 addr = MACInfo->dmaBase+reg; + UINT32 data = RegRead(addr); + + data |= val; + RegWrite(data, addr); +} + + +/****************************************************************************** +* +* ae531x_ClearDmaReg - clear bits in an AE DMA register +* +* RETURNS: N/A +*/ +void +ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val) +{ + UINT32 addr = MACInfo->dmaBase+reg; + UINT32 data = RegRead(addr); + + data &= ~val; + RegWrite(data, addr); +} + + +/****************************************************************************** +* +* ae531x_ReadMiiReg - read PHY registers via AE MAC Mii addr/data registers +* +* RETURNS: register value +*/ +UINT32 +ae531x_ReadMiiReg(UINT32 phyBase, UINT32 reg) +{ + UINT32 data; + UINT32 addr = phyBase+reg; + + data = RegRead(addr); + return data; +} + + +/****************************************************************************** +* +* ae531x_WriteMiiReg - write PHY registers via AE MAC Mii addr/data registers +* +* RETURNS: N/A +*/ +void +ae531x_WriteMiiReg(UINT32 phyBase, UINT32 reg, UINT32 data) +{ + UINT32 addr = phyBase+reg; + + RegWrite(data, addr); +} + + +/****************************************************************************** +* +* ae531x_MiiRead - read AE Mii register +* +* RETURNS: register value +*/ +UINT16 +ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg) +{ + UINT32 addr; + UINT16 data; + + addr = ((phyAddr << MiiDevShift) & MiiDevMask) | ((reg << MiiRegShift) & MiiRegMask); + + ae531x_WriteMiiReg(phyBase, MacMiiAddr, addr ); + do { + /* nop */ + } while ((ae531x_ReadMiiReg(phyBase, MacMiiAddr ) & MiiBusy) == MiiBusy); + + data = ae531x_ReadMiiReg(phyBase, MacMiiData) & 0xFFFF; + + return data; +} + + +/****************************************************************************** +* +* ae531x_MiiWrite - write AE Mii register +* +* RETURNS: N/A +*/ +void +ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, UINT16 data) +{ + UINT32 addr; + + ae531x_WriteMiiReg(phyBase, MacMiiData, data ); + + addr = ((phyAddr << MiiDevShift) & MiiDevMask) | + ((reg << MiiRegShift) & MiiRegMask) | MiiWrite; + ae531x_WriteMiiReg(phyBase, MacMiiAddr, addr ); + + do { + /* nop */ + } while ((ae531x_ReadMiiReg(phyBase, MacMiiAddr ) & MiiBusy) == MiiBusy); +} + + +/******************************************************************************* +* ae531x_BeginResetMode - enter a special "reset mode" in which +* -no interrupts are expected from the device +* -the device will not transmit nor receive +* -attempts to send or receive will return with an error and +* -the device will be reset at the next convenient opportunity. +*/ +void +ae531x_BeginResetMode(ae531x_MAC_t *MACInfo) +{ + /* Set the reset flag */ + MACInfo->aeProcessRst = 1; +} + + +/******************************************************************************* +* ae531x_EndResetMode - exit the special "reset mode" entered +* earlier via a call to ae531x_BeginResetMode. +*/ +void +ae531x_EndResetMode(ae531x_MAC_t *MACInfo) +{ + MACInfo->aeProcessRst = 0; +} + + +/******************************************************************************* +* ae531x_IsInResetMode - determine whether or not the device is +* currently in "reset mode" (i.e. that a device reset is pending) +*/ +BOOL +ae531x_IsInResetMode(ae531x_MAC_t *MACInfo) +{ + return MACInfo->aeProcessRst; +} + + +/****************************************************************************** +* +* ae531x_DmaRxStart - Start Rx +* +* RETURNS: N/A +*/ +static void +ae531x_DmaRxStart(ae531x_MAC_t *MACInfo) +{ + ae531x_SetDmaReg(MACInfo, DmaControl, DmaRxStart); + sysWbFlush(); +} + + +/****************************************************************************** +* +* ae531x_DmaRxStop - Stop Rx +* +* RETURNS: N/A +*/ +void +ae531x_DmaRxStop(ae531x_MAC_t *MACInfo) +{ + ae531x_ClearDmaReg(MACInfo, DmaControl, DmaRxStart); + sysWbFlush(); +} + + +/****************************************************************************** +* +* ae531x_DmaTxStart - Start Tx +* +* RETURNS: N/A +*/ +void +ae531x_DmaTxStart(ae531x_MAC_t *MACInfo) +{ + ae531x_SetDmaReg(MACInfo, DmaControl, DmaTxStart); + sysWbFlush(); +} + + +/****************************************************************************** +* +* ae531x_DmaTxStop - Stop Tx +* +* RETURNS: N/A +*/ +void +ae531x_DmaTxStop(ae531x_MAC_t *MACInfo) +{ + ae531x_ClearDmaReg(MACInfo, DmaControl, DmaTxStart); + sysWbFlush(); +} + + +/****************************************************************************** +* +* ae531x_DmaIntEnable - Enable DMA interrupts +* +* RETURNS: N/A +*/ +void +ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo) +{ + ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntEnable); +} + + +/****************************************************************************** +* +* ae531x_DmaIntDisable - Disable DMA interrupts +* +* RETURNS: N/A +*/ +void +ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo) +{ + ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable); +} + + +/****************************************************************************** +* +* ae531x_DmaIntClear - Clear DMA interrupts +* +* RETURNS: N/A +*/ +static void +ae531x_DmaIntClear(ae531x_MAC_t *MACInfo) +{ + /* clear all interrupt requests */ + ae531x_WriteDmaReg(MACInfo, DmaStatus, + ae531x_ReadDmaReg(MACInfo, DmaStatus)); +} + + +/****************************************************************************** +* Initialize generic queue data +*/ +void +ae531x_QueueInit(AE531X_QUEUE *q, char *pMem, int count) +{ + ARRIVE(); + q->firstDescAddr = pMem; + q->lastDescAddr = (VIRT_ADDR)((UINT32)q->firstDescAddr + + (count - 1) * AE531X_QUEUE_ELE_SIZE); + q->curDescAddr = q->firstDescAddr; + q->count = count; + LEAVE(); +} + + +/****************************************************************************** +* ae531x_TxQueueCreate - create a circular queue of descriptors for Transmit +*/ +static int +ae531x_TxQueueCreate(ae531x_MAC_t *MACInfo, + AE531X_QUEUE *q, + char *pMem, + int count) +{ + int i; + VIRT_ADDR descAddr; + + ARRIVE(); + + ae531x_QueueInit(q, pMem, count); + q->reapDescAddr = q->lastDescAddr; + + /* Initialize Tx buffer descriptors. */ + for (i=0, descAddr=q->firstDescAddr; + ilastDescAddr, + DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr)); + + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d Txbuf begin = %x, end = %x\n", + MACInfo->unit, + (UINT32)q->firstDescAddr, + (UINT32)q->lastDescAddr)); + + LEAVE(); + return 0; +} + + +/****************************************************************************** +* ae531x_RxQueueCreate - create a circular queue of Rx descriptors +*/ +int +ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo, + AE531X_QUEUE *q, + char *pMem, + int count) +{ + int i; + VIRT_ADDR descAddr; + + ARRIVE(); + + ae531x_QueueInit(q, pMem, count); + q->reapDescAddr = NULL; + + + /* Initialize Rx buffer descriptors */ + for (i=0, descAddr=q->firstDescAddr; + iunit)); + ae531x_QueueDestroy(q); + return -1; + } + AE531X_DESC_SWPTR_SET(descAddr, swptr); + + AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma); + AE531X_DESC_CTRLEN_SET(descAddr, rxBufferSize); + AE531X_DESC_BUFPTR_SET(descAddr, virt_to_bus(rxBuffer)); + AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0); + } /* for each desc */ + + /* Make the queue circular */ + AE531X_DESC_CTRLEN_SET(q->lastDescAddr, + DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr)); + + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d Rxbuf begin = %x, end = %x\n", + MACInfo->unit, + (UINT32)q->firstDescAddr, + (UINT32)q->lastDescAddr)); + + LEAVE(); + return 0; +} + + +/****************************************************************************** +* ae531x_QueueDestroy -- Free all buffers and descriptors associated +* with a queue. +*/ +static void +ae531x_QueueDestroy(AE531X_QUEUE *q) +{ + int i; + int count; + VIRT_ADDR descAddr; + + ARRIVE(); + + count = q->count; + + for (i=0, descAddr=q->firstDescAddr; + itxQueue); +} + +static void +ae531x_RxQueueDestroy(ae531x_MAC_t *MACInfo) +{ + ae531x_QueueDestroy(&MACInfo->rxQueue); +} + + +/****************************************************************************** +* ae531x_AllocateQueues - Allocate receive and transmit queues +*/ +int +ae531x_AllocateQueues(ae531x_MAC_t *MACInfo) +{ + size_t QMemSize; + char *pTxBuf = NULL; + char *pRxBuf = NULL; + + ARRIVE(); + + MACInfo->txDescCount = AE531X_TX_DESC_COUNT_DEFAULT; + QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->txDescCount; + pTxBuf = MALLOC(QMemSize); + if (pTxBuf == NULL) { + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d Failed to allocate TX queue\n", MACInfo->unit)); + goto AllocQFail; + } + + if (ae531x_TxQueueCreate(MACInfo, &MACInfo->txQueue, pTxBuf, + MACInfo->txDescCount) < 0) + { + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d Failed to create TX queue\n", MACInfo->unit)); + goto AllocQFail; + } + + MACInfo->rxDescCount = AE531X_RX_DESC_COUNT_DEFAULT; + QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->rxDescCount; + pRxBuf = MALLOC(QMemSize); + if (pRxBuf == NULL) { + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d Failed to allocate RX queue\n", MACInfo->unit)); + goto AllocQFail; + } + + if (ae531x_RxQueueCreate(MACInfo, &MACInfo->rxQueue, pRxBuf, + MACInfo->rxDescCount) < 0) + { + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d Failed to create RX queue\n", MACInfo->unit)); + goto AllocQFail; + } + + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d Memory setup complete.\n", MACInfo->unit)); + + LEAVE(); + return 0; + +AllocQFail: + MACInfo->txDescCount = 0; /* sanity */ + MACInfo->rxDescCount = 0; /* sanity */ + + if (pTxBuf) { + FREE(pTxBuf); + } + if (pRxBuf) { + FREE(pRxBuf); + } + + LEAVE(); + return -1; +} + + +/****************************************************************************** +* +* ae531x_FreeQueues - Free Transmit & Receive queues +*/ +void +ae531x_FreeQueues(ae531x_MAC_t *MACInfo) +{ + ae531x_TxQueueDestroy(MACInfo); + FREE(MACInfo->txQueue.firstDescAddr); + + ae531x_RxQueueDestroy(MACInfo); + FREE(MACInfo->rxQueue.firstDescAddr); +} + +/****************************************************************************** +* +* ae531x_DmaReset - Reset DMA and TLI controllers +* +* RETURNS: N/A +*/ +void +ae531x_DmaReset(ae531x_MAC_t *MACInfo) +{ + int i; + UINT32 descAddr; + + ARRIVE(); + + /* Disable device interrupts prior to any errors during stop */ + intDisable(MACInfo->ilevel); + + /* Disable MAC rx and tx */ + ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable)); + + udelay(1); + + /* Reset dma controller */ + + ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaResetOn); + + /* Delay 2 usec */ + sysUDelay(2); + + /* Flush the rx queue */ + descAddr = (UINT32)MACInfo->rxQueue.firstDescAddr; + MACInfo->rxQueue.curDescAddr = MACInfo->rxQueue.firstDescAddr; + for (i=0; + i<(MACInfo->rxDescCount); + i++, descAddr += AE531X_QUEUE_ELE_SIZE) { + AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma); + } + + /* Flush the tx queue */ + descAddr = (UINT32)MACInfo->txQueue.firstDescAddr; + MACInfo->txQueue.curDescAddr = MACInfo->txQueue.firstDescAddr; + MACInfo->txQueue.reapDescAddr = MACInfo->txQueue.lastDescAddr; + for (i=0; + i<(MACInfo->txDescCount); + i++, descAddr += AE531X_QUEUE_ELE_SIZE) { + AE531X_DESC_STATUS_SET (descAddr, 0); + } + + /* Set init register values */ + ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaBusModeInit); + + /* Install the first Tx and Rx queues on the device */ + ae531x_WriteDmaReg(MACInfo, DmaRxBaseAddr, + virt_to_bus(MACInfo->rxQueue.firstDescAddr)); + ae531x_WriteDmaReg(MACInfo, DmaTxBaseAddr, + virt_to_bus(MACInfo->txQueue.firstDescAddr)); + + + ae531x_WriteDmaReg(MACInfo, DmaControl, DmaStoreAndForward); + + ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable); + + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d: DMA RESET!\n", MACInfo->unit)); + + /* Turn on device interrupts -- enable most errors */ + ae531x_DmaIntClear(MACInfo); /* clear interrupt requests */ + ae531x_DmaIntEnable(MACInfo); /* enable interrupts */ + + ae531x_EndResetMode(MACInfo); + + intEnable(MACInfo->ilevel); + + LEAVE(); +} + + +/****************************************************************************** +* +* ae531x_MACAddressSet - Set the ethernet address +* +* Sets the ethernet address according to settings in flash. +* +* RETURNS: void +*/ +static void +ae531x_MACAddressSet(ae531x_MAC_t *MACInfo) +{ + unsigned int data; + UINT8 *macAddr; + + ARRIVE(); + + macAddr = ae531x_enet_mac_address_get(MACInfo->unit); + + /* set our MAC address */ + data = (macAddr[5]<<8) | macAddr[4]; + ae531x_WriteMacReg(MACInfo, MacAddrHigh, data ); + + data = (macAddr[3]<<24) | (macAddr[2]<<16) | (macAddr[1]<<8) | macAddr[0]; + ae531x_WriteMacReg(MACInfo, MacAddrLow, data ); + + AE531X_PRINT(AE531X_DEBUG_RESET, + ("ethmac%d Verify MAC address %8.8X %8.8X \n", + MACInfo->unit, + ae531x_ReadMacReg(MACInfo, MacAddrLow), + ae531x_ReadMacReg(MACInfo, MacAddrHigh))); + + AE531X_PRINT(AE531X_DEBUG_RESET, + (" sb = %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + 0xff&macAddr[0], + 0xff&macAddr[1], + 0xff&macAddr[2], + 0xff&macAddr[3], + 0xff&macAddr[4], + 0xff&macAddr[5])); + LEAVE(); +} + + +/****************************************************************************** +* +* ae_SetMACFromPhy - read Phy settings and update Mac +* with current duplex and speed. +* +* RETURNS: +*/ +static void +ae531x_SetMACFromPhy(ae531x_MAC_t *MACInfo) +{ + UINT32 macCtl; + BOOL fullDuplex; + UINT32 timeout; + + ARRIVE(); + + timeout = jiffies+(HZ/1000)*AE531X_NEGOT_TIMEOUT; + + /* Get duplex mode from Phy */ + while (((fullDuplex = phyIsFullDuplex(MACInfo->unit)) == -1) && + (jiffies <= timeout)); + + /* Flag is set for full duplex mode, else cleared */ + macCtl = ae531x_ReadMacReg(MACInfo, MacControl); + + if (fullDuplex) { + /* set values of control registers */ + macCtl &= ~MacDisableRxOwn; + macCtl |= MacFullDuplex; + ae531x_WriteMacReg(MACInfo, MacControl, macCtl); + ae531x_WriteMacReg(MACInfo, MacFlowControl, MacFlowControlInitFdx); + } else { + /* set values of control registers */ + ae531x_WriteMacReg(MACInfo, MacFlowControl, MacFlowControlInitHdx); + macCtl |= MacDisableRxOwn; + macCtl &= ~MacFullDuplex; + ae531x_WriteMacReg(MACInfo, MacControl, macCtl); + } + + LEAVE(); +} + + +/****************************************************************************** +* ae531x_MACReset -- sets MAC address and duplex. +*/ +void +ae531x_MACReset(ae531x_MAC_t *MACInfo) +{ + ae531x_MACAddressSet(MACInfo); +#ifndef CONFIG_AR5315 + ae531x_SetMACFromPhy(MACInfo); +#endif +} + + +/****************************************************************************** +* ae531x_EnableComm -- enable Transmit and Receive +*/ +void +ae531x_EnableComm(ae531x_MAC_t *MACInfo) +{ + ae531x_SetMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable)); + ae531x_DmaRxStart(MACInfo); /* start receiver */ + ae531x_DmaTxStart(MACInfo); /* start transmitter */ +} + + +/****************************************************************************** +* ae531x_DisableComm -- disable Transmit and Receive +*/ +void +ae531x_DisableComm(ae531x_MAC_t *MACInfo) +{ + ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable)); +} + + +/****************************************************************************** +* ae531x_reset -- Cold reset ethernet interface +*/ +void +ae531x_reset(ae531x_MAC_t *MACInfo) +{ + UINT32 mask = 0; + UINT32 regtmp; +#ifndef CONFIG_AR5315 + + if (MACInfo->unit == 0) { + mask = AR531X_RESET_ENET0 | AR531X_RESET_EPHY0; + } else { + mask = AR531X_RESET_ENET1 | AR531X_RESET_EPHY1; + } + + /* Put into reset */ + regtmp = sysRegRead(AR531X_RESET); + sysRegWrite(AR531X_RESET, regtmp | mask); + sysMsDelay(15); + + /* Pull out of reset */ + regtmp = sysRegRead(AR531X_RESET); + sysRegWrite(AR531X_RESET, regtmp & ~mask); + sysUDelay(25); + + /* Enable */ + if (MACInfo->unit == 0) { + mask = AR531X_ENABLE_ENET0; + } else { + mask = AR531X_ENABLE_ENET1; + } + regtmp = sysRegRead(AR531X_ENABLE); + sysRegWrite(AR531X_ENABLE, regtmp | mask); +#else + if (MACInfo->unit == 0) { + mask = AR531X_RESET_ENET0 | AR531X_RESET_EPHY0; + } + /* Enable Arbitration for Ethernet bus */ + regtmp = sysRegRead(AR531XPLUS_AHB_ARB_CTL); + regtmp |= ARB_ETHERNET; + sysRegWrite(AR531XPLUS_AHB_ARB_CTL, regtmp); + + /* Put into reset */ + regtmp = sysRegRead(AR531X_RESET); + sysRegWrite(AR531X_RESET, regtmp | mask); + sysMsDelay(10); + + /* Pull out of reset */ + regtmp = sysRegRead(AR531X_RESET); + sysRegWrite(AR531X_RESET, regtmp & ~mask); + sysMsDelay(10); + + regtmp = sysRegRead(AR531XPLUS_IF_CTL); + regtmp |= IF_TS_LOCAL; + sysRegWrite(AR531XPLUS_IF_CTL, regtmp); +#endif +} + + +/****************************************************************************** +* ae531x_unitLinkLost -- Called from PHY layer to notify the MAC layer +* that there are no longer any live links associated with a MAC. +*/ +void +ae531x_unitLinkLost(int ethUnit) +{ + AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE, + ("enetmac%d link down\n", ethUnit)); +} + + +/****************************************************************************** +* ae531x_unitLinkGained -- Called from PHY layer to notify the MAC layer +* that there are 1 or more live links associated with a MAC. +*/ +void +ae531x_unitLinkGained(int ethUnit) +{ +#if CONFIG_AR5315 +#define AE531X_POLL_MILLI_SECONDS 200 + ae531x_MAC_t *MACInfo = ae531x_getMAcInfo(ethUnit); + while(!MACInfo || !MACInfo->port_is_up) + { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((AE531X_POLL_MILLI_SECONDS * HZ)/1000); + MACInfo = ae531x_getMAcInfo(ethUnit); + } + ae531x_SetMACFromPhy(MACInfo); +#endif + AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE, + ("enet%d link up\n", ethUnit)); +} + +/****************************************************************************** +* ae531x_ethMacDefault -- Called from PHY layer to determine the default +* ethernet MAC. On some "twisted" platforms, the only usable MAC is 1, +* while on others the usable MAC is 0. Future boards may allow both MACs +* to be used; in this case, return -1 to indicate that there IS NO default +* MAC. +*/ +int +ae531x_ethMacDefault(void) +{ + if (ae531x_twisted_enet()) + return 1; + + return 0; + +} diff -urN linux-mips-orig/drivers/net/ath/ae531xmac.h linux-mips-new/drivers/net/ath/ae531xmac.h --- linux-mips-orig/drivers/net/ath/ae531xmac.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ae531xmac.h 2005-12-31 12:33:57.674538672 +0000 @@ -0,0 +1,229 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * See README to understand the decomposition of the ethernet driver. + * + * This file contains OS-independent pure software definitions for + * ethernet support on the AR531X platform. + */ + +#ifndef _AE531XMAC_H_ +#define _AE531XMAC_H_ + +#include +#include + +/* + * DEBUG switches to control verbosity. + * Just modify the value of ae531x_MAC_debug. + */ +#define AE531X_DEBUG_ALL 0xffffffff +#define AE531X_DEBUG_ERROR 0x00000001 /* Unusual conditions and Errors */ +#define AE531X_DEBUG_ARRIVE 0x00000002 /* Arrive into a function */ +#define AE531X_DEBUG_LEAVE 0x00000004 /* Leave a function */ +#define AE531X_DEBUG_RESET 0x00000008 /* Reset */ +#define AE531X_DEBUG_TX 0x00000010 /* Transmit */ +#define AE531X_DEBUG_TX_REAP 0x00000020 /* Transmit Descriptor Reaping */ +#define AE531X_DEBUG_RX 0x00000040 /* Receive */ +#define AE531X_DEBUG_RX_STOP 0x00000080 /* Receive Early Stop */ +#define AE531X_DEBUG_INT 0x00000100 /* Interrupts */ +#define AE531X_DEBUG_LINK_CHANGE 0x00000200 /* PHY Link status changed */ + +#define AE531X_NEGOT_TIMEOUT 500 /* ms to wait for autonegotiation */ + +extern int ae531x_MAC_debug; + +#define AE531X_PRINT(FLG, X) \ +{ \ + if (ae531x_MAC_debug & (FLG)) { \ + DEBUG_PRINTF("%s#%d:%s ", \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + DEBUG_PRINTF X; \ + } \ +} + +#define ARRIVE() AE531X_PRINT(AE531X_DEBUG_ARRIVE, ("Arrive{\n")) +#define LEAVE() AE531X_PRINT(AE531X_DEBUG_LEAVE, ("}Leave\n")) + +#define RegRead(addr) \ + (*(volatile unsigned int *)(addr)) + +#define RegWrite(val,addr) \ + ((*(volatile unsigned int *)(addr)) = (val)) + +/***************************************************************** + * Phy code is broken out into a separate layer, so that different + * PHY hardware can easily be supported. + * + * These functions are provided by the PHY layer for use by the MAC layer. + * phySetup -- Set phy hardware appropriately for a MAC unit + * + * phyCheckStatusChange -- Look for dropped/initiated links on any + * phy port associated with a MAC unit + * + * phyIsSpeed100 -- Determines whether or not a PHY is up and + * running at 100Mbit + * + * phyIsFullDuplex -- Determines whether or not a PHY is up and + * running in Full Duplex mode + * + */ +#if CONFIG_MARVELL_ENET_PHY +/* + * Mapping of generic phy APIs to Marvell Ethernet Switch phy functions. + */ +#include "mvPhy.h" +#define phySetup(ethUnit, phyBase) mv_phySetup((ethUnit), (phyBase)) +#define phyCheckStatusChange(ethUnit) mv_phyCheckStatusChange(ethUnit) +#define phyIsSpeed100(ethUnit) mv_phyIsSpeed100(ethUnit) +#define phyIsFullDuplex(ethUnit) mv_phyIsFullDuplex(ethUnit) + +#if CONFIG_VENETDEV +#define PHY_TRAILER_SIZE MV_PHY_TRAILER_SIZE +extern void mv_phyDetermineSource(char *data, int len, int *pFromLAN); +extern void mv_phySetDestinationPort(char *data, int len, int fromLAN); +#define phyDetermineSource(data, len, pFromLAN) mv_phyDetermineSource((data), (len), (pFromLAN)) +#define phySetDestinationPort(data, len, fromLAN) mv_phySetDestinationPort((data), (len), (fromLAN)) +#else +#define PHY_TRAILER_SIZE 0 +#endif +#endif /* CONFIG_MARVELL_ENET_PHY */ + +#if CONFIG_KENDIN_ENET_PHY || CONFIG_REALTEK_ENET_PHY || CONFIG_KENDIN_KS8995XA_ENET_PHY +/* + * Mapping of generic phy APIs to Kendin KS8721B and RealTek RTL8201BL phys. + */ +#include "rtPhy.h" +#define phySetup(ethUnit, phyBase) rt_phySetup((ethUnit), (phyBase)) +#define phyCheckStatusChange(ethUnit) rt_phyCheckStatusChange(ethUnit) +#define phyIsSpeed100(ethUnit) rt_phyIsSpeed100(ethUnit) +#define phyIsFullDuplex(ethUnit) rt_phyIsFullDuplex(ethUnit) +#endif + +#if CONFIG_ICPLUS_ENET_PHY +/* + * Mapping of generic phy APIs to Icplus phys. + */ +#include "ipPhy.h" +#define phySetup(ethUnit, phyBase) ip_phySetup((ethUnit), (phyBase)) +#define phyCheckStatusChange(ethUnit) ip_phyCheckStatusChange(ethUnit) +#define phyIsSpeed100(ethUnit) ip_phyIsSpeed100(ethUnit) +#define phyIsFullDuplex(ethUnit) ip_phyIsFullDuplex(ethUnit) +#endif + +#if !defined(PHY_TRAILER_SIZE) +#define PHY_TRAILER_SIZE 0 +#endif + +/***************************************************************** + * MAC-independent interface to be used by PHY code + * + * These functions are provided by the MAC layer for use by the PHY layer. + */ +#define phyRegRead ae531x_MiiRead +#define phyRegWrite ae531x_MiiWrite +#define phyLinkLost(ethUnit) ae531x_unitLinkLost(ethUnit) +#define phyLinkGained(ethUnit) ae531x_unitLinkGained(ethUnit) +#define phyEthMacDefault() ae531x_ethMacDefault() + +void ae531x_unitLinkLost(int unit); +void ae531x_unitLinkGained(int unit); +int ae531x_ethMacDefault(void); + + +/* + * RXBUFF_RESERVE enables building header on WLAN-side in place + * NB: Divisible by 2 but NOT 4. Otherwise handle_adel_int() will + * be used by the ip layer for misaligned word accesses and + * performance will suffer - a lot. + */ +#define ETH_CRC_LEN 4 +#define RXBUFF_RESERVE 98 +// #define RXBUFF_RESERVE 98 + +/***************************************************************** + * Descriptor queue + */ +typedef struct ae531x_queue { + VIRT_ADDR firstDescAddr; /* descriptor array address */ + VIRT_ADDR lastDescAddr; /* last descriptor address */ + VIRT_ADDR curDescAddr; /* current descriptor address */ + VIRT_ADDR reapDescAddr; /* current tail of tx descriptors reaped */ + UINT16 count; /* number of elements */ +} AE531X_QUEUE; + +/* Given a descriptor, return the next one in a circular list */ +#define AE531X_QUEUE_ELE_NEXT_GET(q, descAddr) \ + ((descAddr) == (q)->lastDescAddr) ? (q)->firstDescAddr : \ + (VIRT_ADDR)((UINT32)(descAddr) + AE531X_QUEUE_ELE_SIZE) + +/* Move the "current descriptor" forward to the next one */ +#define AE531X_CONSUME_DESC(q) \ + q->curDescAddr = AE531X_QUEUE_ELE_NEXT_GET(q, q->curDescAddr) + +/***************************************************************** + * Per-ethernet-MAC OS-independent information + */ +typedef struct ae531x_MAC_s { + u32 unit; /* MAC unit ID */ + u32 macBase; /* MAC base address */ + u32 dmaBase; /* DMA base address */ + u32 phyBase; /* PHY base address */ + AE531X_QUEUE txQueue; /* Transmit descriptor queue */ + AE531X_QUEUE rxQueue; /* Receive descriptor queue */ + UINT16 txDescCount; /* Transmit descriptor count */ + UINT16 rxDescCount; /* Receive descriptor count */ + BOOL aeProcessRst; /* flag to indicate reset in progress */ + BOOL port_is_up; /* flag to indicate port is up */ + void *OSinfo; /* OS-dependent data */ +} ae531x_MAC_t; + +#define AE531X_TX_DESC_COUNT_DEFAULT 128 /* Transmit descriptors */ +#define AE531X_RX_DESC_COUNT_DEFAULT 128 /* Receive descriptors */ + + +/***************************************************************** + * Interfaces exported by the OS-independent MAC layer + */ +void ae531x_BeginResetMode(ae531x_MAC_t *MACInfo); +void ae531x_EndResetMode(ae531x_MAC_t *MACInfo); +BOOL ae531x_IsInResetMode(ae531x_MAC_t *MACInfo); +int ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo, AE531X_QUEUE *q, + char *pMem, int count); +int ae531x_QueueDelete(struct ae531x_queue *q); +void ae531x_DmaReset(ae531x_MAC_t *MACInfo); +void ae531x_MACReset(ae531x_MAC_t *MACInfo); +void ae531x_EnableComm(ae531x_MAC_t *MACInfo); +void ae531x_DisableComm(ae531x_MAC_t *MACInfo); +void ae531x_reset(ae531x_MAC_t *MACInfo); +int ae531x_AllocateQueues(ae531x_MAC_t *MACInfo); +void ae531x_FreeQueues(ae531x_MAC_t *MACInfo); +void ae531x_QueueInit(AE531X_QUEUE *q, char *pMem, int count); +UINT32 ae531x_ReadMacReg(ae531x_MAC_t *MACInfo, UINT32 reg); +void ae531x_WriteMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data); +void ae531x_SetMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); +void ae531x_ClearMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); +void ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); +void ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val); +UINT32 ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg); +void ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data); +UINT32 ae531x_ReadMiiReg(UINT32 phyBase, UINT32 reg); +void ae531x_WriteMiiReg(UINT32 phyBase, UINT32 reg, UINT32 data); +UINT16 ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg); +void ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, UINT16 data); +void ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo); +void ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo); +void ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 val); +void *ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBptr, int *rxBSize); +void ae531x_swptr_free(VIRT_ADDR txDesc); +BOOL ae531x_twisted_enet(void); + +#endif /* _AE531XMAC_H_ */ diff -urN linux-mips-orig/drivers/net/ath/ae531xreg.h linux-mips-new/drivers/net/ath/ae531xreg.h --- linux-mips-orig/drivers/net/ath/ae531xreg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ae531xreg.h 2005-12-31 12:33:57.675538520 +0000 @@ -0,0 +1,439 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * See README to understand the decomposition of the ethernet driver. + * + * Register definitions for Atheros AR531X Ethernet MAC. + */ + +#ifndef _AE531XREG_H_ +#define _AE531XREG_H_ + +#define AE531X_MAC_OFFSET 0x0000 +#define AE531X_PHY_OFFSET 0x0000 /* Same as MAC offset */ +#define AE531X_DMA_OFFSET 0x1000 + +/***********************************************************/ +/* MAC110 registers, base address is BAR+AE531X_MAC_OFFSET */ +/***********************************************************/ +#define MacControl 0x00 /* control */ +#define MacAddrHigh 0x04 /* address high */ +#define MacAddrLow 0x08 /* address low */ +#define MacMultiHashHigh 0x0C /* multicast hash table high */ +#define MacMultiHashLow 0x10 /* multicast hash table low */ +#define MacMiiAddr 0x14 /* MII address */ +#define MacMiiData 0x18 /* MII data */ +#define MacFlowControl 0x1C /* Flow control */ +#define MacVlan1Tag 0x4C /* VLAN1 tag */ +#define MacVlan2Tag 0x50 /* VLAN2 tag */ + + +/***************************************************************/ +/* DMA engine registers, base address is BAR+AE531X_DMA_OFFSET */ +/***************************************************************/ +#define DmaBusMode 0x00 /* CSR0 - Bus Mode */ +#define DmaTxPollDemand 0x04 /* CSR1 - Transmit Poll Demand */ +#define DmaRxPollDemand 0x08 /* CSR2 - Receive Poll Demand */ +#define DmaRxBaseAddr 0x0C /* CSR3 - Receive list base address */ +#define DmaTxBaseAddr 0x10 /* CSR4 - Transmit list base address */ +#define DmaStatus 0x14 /* CSR5 - Dma status */ +#define DmaControl 0x18 /* CSR6 - Dma control */ +#define DmaIntrEnb 0x1C /* CSR7 - Interrupt enable */ +#define DmaOverflowCnt 0x20 /* CSR8 - Missed Frame and Buff Overflow counter */ +#define DmaTxCurrAddr 0x50 /* CSR20 - Current host transmit buffer address */ +#define DmaRxCurrAddr 0x54 /* CSR21 - Current host receive buffer address */ + +/**********************************************************/ +/* MAC Control register layout */ +/**********************************************************/ +#define MacFilterOff 0x80000000 /* Receive all incoming packets RW */ +#define MacFilterOn 0 /* Receive filtered packets only 0 */ +#define MacBigEndian 0x40000000 /* Big endian mode RW */ +#define MacLittleEndian 0 /* Little endian 0 */ +#define MacHeartBeatOff 0x10000000 /* Heartbeat signal qual disable RW*/ +#define MacHeartBeatOn 0 /* Heartbeat signal qual enable 0 */ +#define MacSelectSrl 0x08000000 /* Select SRL port RW */ +#define MacSelectMii 0 /* Select MII port 0 */ +#define MacDisableRxOwn 0x00800000 /* Disable receive own packets RW */ +#define MacEnableRxOwn 0 /* Enable receive own packets 0 */ +#define MacLoopbackExt 0x00400000 /* External loopback RW */ +#define MacLoopbackInt 0x00200000 /* Internal loopback */ +#define MacLoopbackOff 0 /* Normal mode 00 */ +#define MacFullDuplex 0x00100000 /* Full duplex mode RW */ +#define MacHalfDuplex 0 /* Half duplex mode 0 */ +#define MacMulticastFilterOff 0x00080000 /* Pass all multicast packets RW */ +#define MacMulticastFilterOn 0 /* Pass filtered mcast packets 0 */ +#define MacPromiscuousModeOn 0x00040000 /* Receive all valid packets RW 1 */ +#define MacPromiscuousModeOff 0 /* Receive filtered packets only */ +#define MacFilterInverse 0x00020000 /* Inverse filtering RW */ +#define MacFilterNormal 0 /* Normal filtering 0 */ +#define MacBadFramesEnable 0x00010000 /* Pass bad frames RW */ +#define MacBadFramesDisable 0 /* Do not pass bad frames 0 */ +#define MacPerfectFilterOff 0x00008000 /* Hash filtering only RW */ +#define MacPerfectFilterOn 0 /* Both perfect and hash filtering 0 */ +#define MacHashFilterOn 0x00002000 /* perform hash filtering RW */ +#define MacHashFilterOff 0 /* perfect filtering only 0 */ +#define MacLateCollisionOn 0x00001000 /* Enable late collision control RW */ +#define MacLateCollisionOff 0 /* Disable late collision control 0 */ +#define MacBroadcastDisable 0x00000800 /* Disable reception of bcast frames RW */ +#define MacBroadcastEnable 0 /* Enable broadcast frames 0 */ +#define MacRetryDisable 0x00000400 /* Disable retransmission RW */ +#define MacRetryEnable 0 /* Enable retransmission 0 */ +#define MacPadStripEnable 0x00000100 /* Pad stripping enable RW */ +#define MacPadStripDisable 0 /* Pad stripping disable 0 */ +#define MacBackoff 0 /* Backoff Limit RW 00 */ +#define MacDeferralCheckEnable 0x00000020 /* Deferral check enable RW */ +#define MacDeferralCheckDisable 0 /* Deferral check disable 0 */ +#define MacTxEnable 0x00000008 /* Transmitter enable RW */ +#define MacTxDisable 0 /* Transmitter disable 0 */ +#define MacRxEnable 0x00000004 /* Receiver enable RW */ +#define MacRxDisable 0 /* Receiver disable 0 */ + + +/**********************************************************/ +/* MII address register layout */ +/**********************************************************/ +#define MiiDevMask 0x0000F800 /* MII device address */ +#define MiiDevShift 11 +#define MiiRegMask 0x000007C0 /* MII register */ +#define MiiRegShift 6 +#define MiiWrite 0x00000002 /* Write to register */ +#define MiiRead 0 /* Read from register */ +#define MiiBusy 0x00000001 /* MII interface is busy */ + +/**********************************************************/ +/* MII Data register layout */ +/**********************************************************/ +#define MiiDataMask 0x0000FFFF /* MII Data */ + +/**********************************************************/ +/* MAC flow control register layout */ +/**********************************************************/ +#define MacPauseTimeMask 0xFFFF0000 /* PAUSE TIME field in ctrl frame */ +#define MacPauseTimeShift 15 +#define MacControlFrameEnable 0x00000004 /* Enable pass ctrl frames to host */ +#define MacControlFrameDisable 0 /* Do not pass ctrl frames to host */ +#define MacFlowControlEnable 0x00000002 /* Enable flow control */ +#define MacFlowControlDisable 0 /* Disable flow control */ +#define MacSendPauseFrame 0x00000001 /* send pause frame */ + +/**********************************************************/ +/* DMA bus mode register layout */ +/**********************************************************/ +#define DmaRxAlign16 0x01000000 /* Force all rx buffers to align on odd hw bndry */ +#define DmaBigEndianDes 0x00100000 /* Big endian data buffer descriptors RW */ +#define DmaLittleEndianDesc 0 /* Little endian data descriptors */ +#define DmaBurstLength32 0x00002000 /* Dma burst length 32 RW */ +#define DmaBurstLength16 0x00001000 /* Dma burst length 16 */ +#define DmaBurstLength8 0x00000800 /* Dma burst length 8 */ +#define DmaBurstLength4 0x00000400 /* Dma burst length 4 */ +#define DmaBurstLength2 0x00000200 /* Dma burst length 2 */ +#define DmaBurstLength1 0x00000100 /* Dma burst length 1 */ +#define DmaBurstLength0 0x00000000 /* Dma burst length 0 */ +#define DmaBigEndianData 0x00000080 /* Big endian data buffers RW */ +#define DmaLittleEndianData 0 /* Little endian data buffers 0 */ +#define DmaDescriptorSkip16 0x00000040 /* number of dwords to skip RW */ +#define DmaDescriptorSkip8 0x00000020 /* between two unchained descriptors */ +#define DmaDescriptorSkip4 0x00000010 +#define DmaDescriptorSkip2 0x00000008 +#define DmaDescriptorSkip1 0x00000004 +#define DmaDescriptorSkip0 0 +#define DmaReceivePriorityOff 0x00000002 /* equal rx and tx priorities RW */ +#define DmaReceivePriorityOn 0 /* Rx has prioryty over Tx 0 */ +#define DmaResetOn 0x00000001 /* Reset DMA engine RW */ +#define DmaResetOff 0 + +/**********************************************************/ +/* DMA Status register layout */ +/**********************************************************/ +#define DmaRxAbort 0x01000000 /* receiver bus abort R 0 */ +#define DmaTxAbort 0x00800000 /* transmitter bus abort R 0 */ +#define DmaTxState 0x00700000 /* Transmit process state R 000 */ +#define DmaTxStopped 0x00000000 /* Stopped */ +#define DmaTxFetching 0x00100000 /* Running - fetching the descriptor */ +#define DmaTxWaiting 0x00200000 /* Running - waiting for end of transmission */ +#define DmaTxReading 0x00300000 /* Running - reading the data from memory */ +#define DmaTxSuspended 0x00600000 /* Suspended */ +#define DmaTxClosing 0x00700000 /* Running - closing descriptor */ +#define DmaRxState 0x000E0000 /* Receive process state 000 */ +#define DmaRxStopped 0x00000000 /* Stopped */ +#define DmaRxFetching 0x00020000 /* Running - fetching the descriptor */ +#define DmaRxChecking 0x00040000 /* Running - checking for end of packet */ +#define DmaRxWaiting 0x00060000 /* Running - waiting for packet */ +#define DmaRxSuspended 0x00080000 /* Suspended */ +#define DmaRxClosing 0x000A0000 /* Running - closing descriptor */ +#define DmaRxFlushing 0x000C0000 /* Running - flushing the current frame */ +#define DmaRxQueuing 0x000E0000 /* Running - queuing the recieve frame into host memory */ +#define DmaIntNormal 0x00010000 /* Normal interrupt summary RW 0 */ +#define DmaIntAbnormal 0x00008000 /* Abnormal interrupt summary RW 0 */ +#define DmaIntEarlyRx 0x00004000 /* Early receive interrupt (Normal) RW 0 */ +#define DmaIntBusError 0x00002000 /* Fatal bus error (Abnormal) RW 0 */ +#define DmaIntEarlyTx 0x00000400 /* Early transmit interrupt RW 0 */ +#define DmaIntRxStopped 0x00000100 /* Receive process stopped (Abnormal) RW 0 */ +#define DmaIntRxNoBuffer 0x00000080 /* Receive buffer unavailable (Abnormal) RW 0*/ +#define DmaIntRxCompleted 0x00000040 /* Completion of frame reception(Normal) RW 0*/ +#define DmaIntTxUnderflow 0x00000020 /* Transmit underflow (Abnormal) RW 0 */ +#define DmaIntTxJabber 0x00000008 /* Transmit Jabber Timeout (Abnormal) RW 0 */ +#define DmaIntTxNoBuffer 0x00000004 /* Transmit buffer unavailable (Normal) RW 0*/ +#define DmaIntTxStopped 0x00000002 /* Transmit process stopped (Abnormal) RW 0 */ +#define DmaIntTxCompleted 0x00000001 /* Transmit completed (Normal) RW 0 */ + +/**********************************************************/ +/* DMA control register layout */ +/**********************************************************/ +#define DmaStoreAndForward 0x00000000 /* Store and forward RW 0 */ +#define DmaTxThreshCtl256 0x0000c000 /* Non-SF threshold is 256 words */ +#define DmaTxThreshCtl128 0x00008000 /* Non-SF threshold is 128 words */ +#define DmaTxThreshCtl064 0x00004000 /* Non-SF threshold is 64 words */ +#define DmaTxThreshCtl032 0x00000000 /* Non-SF threshold is 32 words */ +#define DmaTxStart 0x00002000 /* Start/Stop transmission RW 0 */ +#define DmaTxSecondFrame 0x00000004 /* Operate on second frame RW 0 */ +#define DmaRxStart 0x00000002 /* Start/Stop reception RW 0 */ + +/**********************************************************/ +/* DMA interrupt enable register layout */ +/**********************************************************/ +#define DmaIeNormal DmaIntNormal /* Normal interrupt enable RW 0 */ +#define DmaIeAbnormal DmaIntAbnormal /* Abnormal interrupt enable RW 0 */ +#define DmaIeEarlyRx DmaIntEarlyRx /* Early receive interrupt enable RW 0 */ +#define DmaIeBusError DmaIntBusError /* Fatal bus error enable RW 0 */ +#define DmaIeEarlyTx DmaIntEarlyTx /* Early transmit interrupt enable RW 0 */ +#define DmaIeRxStopped DmaIntRxStopped /* Receive process stopped enable RW 0 */ +#define DmaIeRxNoBuffer DmaIntRxNoBuffer /* Receive buffer unavailable enable RW 0 */ +#define DmaIeRxCompleted DmaIntRxCompleted /* Completion of frame reception enable RW 0 */ +#define DmaIeTxUnderflow DmaIntTxUnderflow /* Transmit underflow enable RW 0 */ +#define DmaIeTxJabber DmaIntTxJabber /* Transmit jabber timeout RW 0 */ +#define DmaIeTxNoBuffer DmaIntTxNoBuffer /* Transmit buffer unavailable enable RW 0 */ +#define DmaIeTxStopped DmaIntTxStopped /* Transmit process stopped enable RW 0 */ +#define DmaIeTxCompleted DmaIntTxCompleted /* Transmit completed enable RW 0 */ + +/****************************************************************/ +/* DMA Missed Frame and Buffer Overflow Counter register layout */ +/****************************************************************/ +#define DmaRxBufferMissedFrame 0xffff0000 /* cleared on read */ +#define DmaMissedFrameShift 16 +#define DmaRxBufferOverflowCnt 0x0000ffff /* cleared on read */ +#define DmaMissedFrameCountMask 0x0000ffff + +/**********************************************************/ +/* DMA Engine descriptor layout */ +/**********************************************************/ +/* status word of DMA descriptor */ +#define DescOwnByDma 0x80000000 /* Descriptor is owned by DMA engine */ +#define DescFrameLengthMask 0x3FFF0000 /* Receive descriptor frame length */ +#define DescFrameLengthShift 16 +#define DescError 0x00008000 /* Error summary bit OR of following bits */ +#define DescRxTruncated 0x00004000 /* Rx - no more descs for receive frame */ +#define DescRxLengthError 0x00001000 /* Rx - frame size not matching with length field */ +#define DescRxRunt 0x00000800 /* Rx - runt frame, damaged by a + collision or term before 64 bytes */ +#define DescRxMulticast 0x00000400 /* Rx - received frame is multicast */ +#define DescRxFirst 0x00000200 /* Rx - first descriptor of the frame */ +#define DescRxLast 0x00000100 /* Rx - last descriptor of the frame */ +#define DescRxLongFrame 0x00000080 /* Rx - frame is longer than 1518 bytes */ +#define DescRxLateColl 0x00000040 /* Rx - frame was damaged by a late collision */ +#define DescRxFrameEther 0x00000020 /* Rx - Frame type Ethernet 802.3*/ +#define DescRxMiiError 0x00000008 /* Rx - error reported by MII interface */ +#define DescRxDribbling 0x00000004 /* Rx - frame contains noninteger multiple of 8 bits */ +#define DescRxCrc 0x00000002 /* Rx - CRC error */ +#define DescTxTimeout 0x00004000 /* Tx - Transmit jabber timeout */ +#define DescTxLostCarrier 0x00000800 /* Tx - carrier lost during tramsmission */ +#define DescTxNoCarrier 0x00000400 /* Tx - no carrier signal from tranceiver */ +#define DescTxLateCollision 0x00000200 /* Tx - transmission aborted due to collision */ +#define DescTxExcCollisions 0x00000100 /* Tx - transmission aborted after 16 collisions */ +#define DescTxHeartbeatFail 0x00000080 /* Tx - heartbeat collision check failure */ +#define DescTxCollMask 0x00000078 /* Tx - Collision count */ +#define DescTxCollShift 3 +#define DescTxExcDeferral 0x00000004 /* Tx - excessive deferral */ +#define DescTxUnderflow 0x00000002 /* Tx - late data arrival from memory */ +#define DescTxDeferred 0x00000001 /* Tx - frame transmision deferred */ + +/* length word of DMA descriptor */ +#define DescTxIntEnable 0x80000000 /* Tx - interrupt on completion */ +#define DescTxLast 0x40000000 /* Tx - Last segment of the frame */ +#define DescTxFirst 0x20000000 /* Tx - First segment of the frame */ +#define DescTxDisableCrc 0x04000000 /* Tx - Add CRC disabled (first segment only) */ +#define DescEndOfRing 0x02000000 /* End of descriptors ring */ +#define DescChain 0x01000000 /* Second buffer address is chain address */ +#define DescTxDisablePadd 0x00800000 /* disable padding */ +#define DescSize2Mask 0x003FF800 /* Buffer 2 size */ +#define DescSize2Shift 11 +#define DescSize1Mask 0x000007FF /* Buffer 1 size */ +#define DescSize1Shift 0 + +/**********************************************************/ +/* Initial register values */ +/**********************************************************/ +/* Full-duplex mode with perfect filter on */ +#define MacControlInitFdx \ + ( MacFilterOn \ + | MacLittleEndian \ + | MacHeartBeatOn \ + | MacSelectMii \ + | MacEnableRxOwn \ + | MacLoopbackOff \ + | MacFullDuplex \ + | MacMulticastFilterOn \ + | MacPromiscuousModeOff \ + | MacFilterNormal \ + | MacBadFramesDisable \ + | MacPerfectFilterOn \ + | MacHashFilterOff \ + | MacLateCollisionOff \ + | MacBroadcastEnable \ + | MacRetryEnable \ + | MacPadStripDisable \ + | MacDeferralCheckDisable \ + | MacTxEnable \ + | MacRxEnable) + +/* Full-duplex mode */ +#define MacFlowControlInitFdx \ + ( MacControlFrameDisable \ + | MacFlowControlEnable) + +/* Half-duplex mode with perfect filter on */ +#define MacControlInitHdx \ + ( MacFilterOn \ + | MacLittleEndian \ + | MacHeartBeatOn \ + | MacSelectMii \ + | MacDisableRxOwn \ + | MacLoopbackOff \ + | MacHalfDuplex \ + | MacMulticastFilterOn \ + | MacPromiscuousModeOff \ + | MacFilterNormal \ + | MacBadFramesDisable \ + | MacPerfectFilterOn \ + | MacHashFilterOff \ + | MacLateCollisionOff \ + | MacBroadcastEnable \ + | MacRetryEnable \ + | MacPadStripDisable \ + | MacDeferralCheckDisable \ + | MacTxEnable \ + | MacRxEnable) + +/* Half-duplex mode */ +#define MacFlowControlInitHdx \ + ( MacControlFrameDisable \ + | MacFlowControlDisable) + +/* Bus Mode Rx odd half word align */ +#define DmaBusModeInit \ + ( DmaLittleEndianDesc \ + | DmaRxAlign16 \ + | DmaBurstLength32 \ + | DmaBigEndianData \ + | DmaDescriptorSkip1 \ + | DmaReceivePriorityOn \ + | DmaResetOff) + +#define DmaControlInit (DmaStoreAndForward) + +/* Interrupt groups */ +#define DmaIntEnable \ + ( DmaIeNormal \ + | DmaIeAbnormal \ + | DmaIntBusError \ + | DmaIntRxStopped \ + | DmaIntRxNoBuffer \ + | DmaIntRxCompleted \ + | DmaIntTxUnderflow \ + | DmaIntTxStopped) + +#define DmaIntDisable 0 + +#define DmaAllIntCauseMask \ + ( DmaIeNormal \ + | DmaIeAbnormal \ + | DmaIntEarlyRx \ + | DmaIntBusError \ + | DmaIntEarlyTx \ + | DmaIntRxStopped \ + | DmaIntRxNoBuffer \ + | DmaIntRxCompleted \ + | DmaIntTxUnderflow \ + | DmaIntTxJabber \ + | DmaIntTxNoBuffer \ + | DmaIntTxStopped \ + | DmaIntTxCompleted) + +#define UnhandledIntrMask \ + (DmaAllIntCauseMask \ + & ~(DmaIntRxNoBuffer \ + | DmaIntTxStopped \ + | DmaIntTxJabber \ + | DmaIntTxUnderflow \ + | DmaIntBusError \ + | DmaIntRxCompleted )) + +#define DescRxErrors \ + (DescRxTruncated \ + | DescRxRunt \ + | DescRxLateColl \ + | DescRxMiiError \ + | DescRxCrc) + +#define DescTxErrors \ + ( DescTxTimeout \ + | DescTxLateCollision \ + | DescTxExcCollisions \ + | DescTxExcDeferral \ + | DescTxUnderflow) + +/**********************************************************/ +/* Descriptor Layout */ +/**********************************************************/ +#define AE531X_DESC_STATUS 0x00 /* Status offset */ +#define AE531X_DESC_CTRLEN 0x04 /* Control and Length offset */ +#define AE531X_DESC_BUFPTR 0x08 /* Buffer pointer offset */ +#define AE531X_DESC_LNKBUF 0x0c /* Link field offset, or ptr to 2nd buf */ +#define AE531X_DESC_SWPTR 0x10 /* OS-Dependent software pointer */ + +#define AE531X_DESC_SIZE 0x10 /* 4 words, 16 bytes */ +#define AE531X_QUEUE_ELE_SIZE 0x14 /* with software pointer extension */ + +/* Accessors to the dma descriptor fields */ +#define AE531X_DESC_STATUS_GET(ptr) \ + *(volatile UINT32 *)((UINT32)(ptr) + AE531X_DESC_STATUS) + +#define AE531X_DESC_STATUS_SET(ptr, val) \ + AE531X_DESC_STATUS_GET(ptr) = (val) + +#define AE531X_DESC_CTRLEN_GET(ptr) \ + *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_CTRLEN) + +#define AE531X_DESC_CTRLEN_SET(ptr, val) \ + AE531X_DESC_CTRLEN_GET(ptr) = (val) + +#define AE531X_DESC_BUFPTR_GET(ptr) \ + *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_BUFPTR) + +#define AE531X_DESC_BUFPTR_SET(ptr,val) \ + AE531X_DESC_BUFPTR_GET(ptr) = (UINT32)(val) + +#define AE531X_DESC_LNKBUF_GET(ptr) \ + *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_LNKBUF) + +#define AE531X_DESC_LNKBUF_SET(ptr, val) \ + AE531X_DESC_LNKBUF_GET(ptr) = (val) + +#define AE531X_DESC_SWPTR_GET(ptr) \ + (void *)(*(volatile UINT32 *) ((UINT32)ptr + AE531X_DESC_SWPTR)) + +#define AE531X_DESC_SWPTR_SET(ptr,val) \ + AE531X_DESC_SWPTR_GET(ptr) = (void *)(val) + +/* Get size of Rx data from desc, in bytes */ +#define AE531X_DESC_STATUS_RX_SIZE(x) \ + (((x) & DescFrameLengthMask) >> DescFrameLengthShift) + +#endif /* _AE531XREG_H_ */ diff -urN linux-mips-orig/drivers/net/ath/ar531x.h linux-mips-new/drivers/net/ath/ar531x.h --- linux-mips-orig/drivers/net/ath/ar531x.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ar531x.h 2005-12-31 12:33:57.676538368 +0000 @@ -0,0 +1,1124 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +#ifndef AR531X_H +#define AR531X_H 1 + + +#ifndef CONFIG_AR5315 + +#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 + +/* + * 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 GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ +#define GPIO_CR_O(x) (0 << (x)) /* mask for output */ +#define GPIO_CR_I(x) (1 << (x)) /* mask for input */ +#define GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */ +#define GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */ + + +typedef unsigned int AR531X_REG; + +#define sysRegRead(phys) \ + (*(volatile AR531X_REG *)PHYS_TO_K1(phys)) + +#define sysRegWrite(phys, val) \ + ((*(volatile AR531X_REG *)PHYS_TO_K1(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) */ +}; + +#else + +/* + * Add support for Cobra + * + * AR531XPLUSreg.h Register definitions for Atheros AR5311 and AR5312 chipsets. + * - WLAN registers are listed in + * hal/ar5211/ar5211Reg.h + * hal/ar5212/ar5212Reg.h + * - Ethernet registers are listed in ar531xenet.h + * - Standard UART is 16550 compatible. + */ + + +/* + * Address map + */ +#define AR531XPLUS_SDRAM0 0x00000000 /* DRAM */ +#define AR531XPLUS_SPI_READ 0x08000000 /* SPI FLASH */ +#define AR531XPLUS_WLAN0 0xB0000000 /* Wireless MMR */ +#define AR531XPLUS_PCI 0xB0100000 /* PCI MMR */ +#define AR531XPLUS_SDRAMCTL 0xB0300000 /* SDRAM MMR */ +#define AR531XPLUS_LOCAL 0xB0400000 /* LOCAL BUS MMR */ +#define AR531XPLUS_ENET0 0xB0500000 /* ETHERNET MMR */ +#define AR531XPLUS_DSLBASE 0xB1000000 /* RESET CONTROL MMR */ +#define AR531XPLUS_UART0 0xB1100003 /* UART MMR */ +#define AR531XPLUS_SPI 0xB1300000 /* SPI FLASH MMR */ +#define AR531XPLUS_FLASHBT 0xBfc00000 /* ro boot alias to FLASH */ +#define AR531XPLUS_RAM1 0x40000000 /* ram alias */ +#define AR531XPLUS_PCIEXT 0x80000000 /* pci external */ +#define AR531XPLUS_RAM2 0xc0000000 /* ram alias */ +#define AR531XPLUS_RAM3 0xe0000000 /* ram alias */ + +#define AR531X_ENET0 AR531XPLUS_ENET0 +#define AR531X_ENET1 0 +/* + * Reset Register + */ +#define AR531XPLUS_COLD_RESET (AR531XPLUS_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 */ + +/* Warm Reset */ + +#define AR531XPLUS_RESET (AR531XPLUS_DSLBASE + 0x0004) +#define AR531X_RESET AR531XPLUS_RESET + +#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 */ + +#define AR531X_RESET_ENET0 RESET_ENET0 +#define AR531X_RESET_EPHY0 RESET_EPHY0 +#define AR531X_RESET_ENET1 0 +#define AR531X_RESET_EPHY1 0 + +/* + * AHB master arbitration control + */ +#define AR531XPLUS_AHB_ARB_CTL (AR531XPLUS_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 AR531XPLUS_ENDIAN_CTL (AR531XPLUS_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 AR531XPLUS_NMI_CTL (AR531XPLUS_DSLBASE + 0x0010) + +#define NMI_EN 1 + +/* + * Revision Register - Initial value is 0x3010 (WMAC 3.0, AR531X 1.0). + */ +#define AR531XPLUS_SREV (AR531XPLUS_DSLBASE + 0x0014) + +#define AR531X_REV AR531XPLUS_SREV + +#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) + +#define AR531X_REV_MAJ REV_MAJ +#define AR531X_REV_MAJ_S REV_MAJ_S +#define AR531X_REV_MIN REV_MIN +#define AR531X_REV_MIN_S REV_MIN_S +#define REV_CHIP (REV_MAJ|REV_MIN) +/* + * 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 + +/* Major revision numbers, bits 7..4 of Revision ID register */ +#define AR531X_REV_MAJ_AR5312 0x4 +#define AR531X_REV_MAJ_AR2313 0x5 + +/* + * 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 1 + +/* + * Interface Enable + */ +#define AR531XPLUS_IF_CTL (AR531XPLUS_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 AR531XPLUS_ISR (AR531XPLUS_DSLBASE + 0x0020) +#define AR531XPLUS_IMR (AR531XPLUS_DSLBASE + 0x0024) +#define AR531XPLUS_GISR (AR531XPLUS_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 AR531XPLUS_INTR_MISCIO SR_IBIT3 +#define AR531XPLUS_INTR_WLAN0 SR_IBIT4 +#define AR531XPLUS_INTR_ENET0 SR_IBIT5 +#define AR531XPLUS_INTR_LOCALPCI SR_IBIT6 +#define AR531XPLUS_INTR_WMACPOLL SR_IBIT7 +#define AR531XPLUS_INTR_COMPARE SR_IBIT8 + +/* + * Timers + */ +#define AR531XPLUS_TIMER (AR531XPLUS_DSLBASE + 0x0030) +#define AR531XPLUS_RELOAD (AR531XPLUS_DSLBASE + 0x0034) +#define AR531XPLUS_WD (AR531XPLUS_DSLBASE + 0x0038) +#define AR531XPLUS_WDC (AR531XPLUS_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 AR531XPLUS_PERFCNT0 (AR531XPLUS_DSLBASE + 0x0048) +#define AR531XPLUS_PERFCNT1 (AR531XPLUS_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 AR531XPLUS_AHB_ERR0 (AR531XPLUS_DSLBASE + 0x0050) /* error */ +#define AR531XPLUS_AHB_ERR1 (AR531XPLUS_DSLBASE + 0x0054) /* haddr */ +#define AR531XPLUS_AHB_ERR2 (AR531XPLUS_DSLBASE + 0x0058) /* hwdata */ +#define AR531XPLUS_AHB_ERR3 (AR531XPLUS_DSLBASE + 0x005c) /* hrdata */ +#define AR531XPLUS_AHB_ERR4 (AR531XPLUS_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 AR531XPLUS_PLLC_CTL (AR531XPLUS_DSLBASE + 0x0064) +#define AR531XPLUS_PLLV_CTL (AR531XPLUS_DSLBASE + 0x0068) +#define AR531XPLUS_CPUCLK (AR531XPLUS_DSLBASE + 0x006c) +#define AR531XPLUS_AMBACLK (AR531XPLUS_DSLBASE + 0x0070) +#define AR531XPLUS_SYNCCLK (AR531XPLUS_DSLBASE + 0x0074) +#define AR531XPLUS_DSL_SLEEP_CTL (AR531XPLUS_DSLBASE + 0x0080) +#define AR531XPLUS_DSL_SLEEP_DUR (AR531XPLUS_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 AR531XPLUS_AMBA_CLOCK_RATE 20000000 +#define AR531XPLUS_CPU_CLOCK_RATE 40000000 +#else +#if defined(DEFAULT_PLL) +#define AR531XPLUS_AMBA_CLOCK_RATE 40000000 +#define AR531XPLUS_CPU_CLOCK_RATE 40000000 +#else +#define AR531XPLUS_AMBA_CLOCK_RATE 92000000 +#define AR531XPLUS_CPU_CLOCK_RATE 184000000 +#endif /* ! DEFAULT_PLL */ +#endif /* ! COBRA_EMUL */ + +#define AR531XPLUS_UART_CLOCK_RATE AR531XPLUS_AMBA_CLOCK_RATE +#define AR531XPLUS_SDRAM_CLOCK_RATE AR531XPLUS_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 AR531XPLUS_GPIO_DI (AR531XPLUS_DSLBASE + 0x0088) +#define AR531XPLUS_GPIO_DO (AR531XPLUS_DSLBASE + 0x0090) +#define AR531XPLUS_GPIO_CR (AR531XPLUS_DSLBASE + 0x0098) +#define AR531XPLUS_GPIO_INT (AR531XPLUS_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 AR531XPLUS_RESET_GPIO 5 +#define AR531XPLUS_NUM_GPIO 22 + + +/* + * PCI Clock Control + */ + +#define AR531XPLUS_PCICLK (AR531XPLUS_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 AR531XPLUS_OCR (AR531XPLUS_DSLBASE + 0x00b0) +#define OCR_GPIO0_IRIN 0x0040 +#define OCR_GPIO1_IROUT 0x0080 +#define OCR_GPIO3_RXCLR 0x0200 + +/* + * General Clock Control + */ + +#define AR531XPLUS_MISCCLK (AR531XPLUS_DSLBASE + 0x00b4) +#define MISCCLK_PLLBYPASS_EN 0x00000001 +#define MISCCLK_PROCREFCLK 0x00000002 + +/* + * SDRAM Controller + * - No read or write buffers are included. + */ +#define AR531XPLUS_MEM_CFG (AR531XPLUS_SDRAMCTL + 0x00) +#define AR531XPLUS_MEM_CTRL (AR531XPLUS_SDRAMCTL + 0x0c) +#define AR531XPLUS_MEM_REF (AR531XPLUS_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 AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x96 +#else +#if defined(DEFAULT_PLL) +#define AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x200 +#else +#define AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x61a +#endif /* ! DEFAULT_PLL */ +#endif + +#if defined(AR531XPLUS) + +#define AR531XPLUS_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */ +#define AR531XPLUS_SDRAM_DATA_WIDTH 16 /* bits */ +#define AR531XPLUS_SDRAM_COL_WIDTH 8 +#define AR531XPLUS_SDRAM_ROW_WIDTH 12 + +#else + +#define AR531XPLUS_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */ +#define AR531XPLUS_SDRAM_DATA_WIDTH 16 +#define AR531XPLUS_SDRAM_COL_WIDTH 8 +#define AR531XPLUS_SDRAM_ROW_WIDTH 12 + +#endif /* ! AR531XPLUS */ + +/* + * SPI Flash Interface Registers + */ + +#define AR531XPLUS_SPI_CTL (AR531XPLUS_SPI + 0x00) +#define AR531XPLUS_SPI_OPCODE (AR531XPLUS_SPI + 0x04) +#define AR531XPLUS_SPI_DATA (AR531XPLUS_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 (AR531XPLUS_PCI + 0x4000) +#define PCI_MAC_SCR (AR531XPLUS_PCI + 0x4004) +#define PCI_MAC_INTPEND (AR531XPLUS_PCI + 0x4008) +#define PCI_MAC_SFR (AR531XPLUS_PCI + 0x400C) +#define PCI_MAC_PCICFG (AR531XPLUS_PCI + 0x4010) +#define PCI_MAC_SREV (AR531XPLUS_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 AR531XPLUS_PCI_1MS_REG (AR531XPLUS_PCI + 0x0008) +#define AR531XPLUS_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ + +#define AR531XPLUS_PCI_MISC_CONFIG (AR531XPLUS_PCI + 0x000c) +#define AR531XPLUS_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */ +#define AR531XPLUS_PCIMISC_CFG_SEL 0x00000002 /* mem or config cycles */ +#define AR531XPLUS_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */ +#define AR531XPLUS_PCIMISC_RST_MODE 0x00000030 +#define AR531XPLUS_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */ +#define AR531XPLUS_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */ +#define AR531XPLUS_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */ +#define AR531XPLUS_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */ +#define AR531XPLUS_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */ +#define AR531XPLUS_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */ +#define AR531XPLUS_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */ +#define AR531XPLUS_PCICACHE_DIS 0x00001000 /* PCI external access cache disable */ + +#define AR531XPLUS_PCI_OUT_TSTAMP (AR531XPLUS_PCI + 0x0010) + +#define AR531XPLUS_PCI_UNCACHE_CFG (AR531XPLUS_PCI + 0x0014) + +#define AR531XPLUS_PCI_IN_EN (AR531XPLUS_PCI + 0x0100) +#define AR531XPLUS_PCI_IN_EN0 0x01 /* Enable chain 0 */ +#define AR531XPLUS_PCI_IN_EN1 0x02 /* Enable chain 1 */ +#define AR531XPLUS_PCI_IN_EN2 0x04 /* Enable chain 2 */ +#define AR531XPLUS_PCI_IN_EN3 0x08 /* Enable chain 3 */ + +#define AR531XPLUS_PCI_IN_DIS (AR531XPLUS_PCI + 0x0104) +#define AR531XPLUS_PCI_IN_DIS0 0x01 /* Disable chain 0 */ +#define AR531XPLUS_PCI_IN_DIS1 0x02 /* Disable chain 1 */ +#define AR531XPLUS_PCI_IN_DIS2 0x04 /* Disable chain 2 */ +#define AR531XPLUS_PCI_IN_DIS3 0x08 /* Disable chain 3 */ + +#define AR531XPLUS_PCI_IN_PTR (AR531XPLUS_PCI + 0x0200) + +#define AR531XPLUS_PCI_OUT_EN (AR531XPLUS_PCI + 0x0400) +#define AR531XPLUS_PCI_OUT_EN0 0x01 /* Enable chain 0 */ + +#define AR531XPLUS_PCI_OUT_DIS (AR531XPLUS_PCI + 0x0404) +#define AR531XPLUS_PCI_OUT_DIS0 0x01 /* Disable chain 0 */ + +#define AR531XPLUS_PCI_OUT_PTR (AR531XPLUS_PCI + 0x0408) + +#define AR531XPLUS_PCI_INT_STATUS (AR531XPLUS_PCI + 0x0500) /* write one to clr */ +#define AR531XPLUS_PCI_TXINT 0x00000001 /* Desc In Completed */ +#define AR531XPLUS_PCI_TXOK 0x00000002 /* Desc In OK */ +#define AR531XPLUS_PCI_TXERR 0x00000004 /* Desc In ERR */ +#define AR531XPLUS_PCI_TXEOL 0x00000008 /* Desc In End-of-List */ +#define AR531XPLUS_PCI_RXINT 0x00000010 /* Desc Out Completed */ +#define AR531XPLUS_PCI_RXOK 0x00000020 /* Desc Out OK */ +#define AR531XPLUS_PCI_RXERR 0x00000040 /* Desc Out ERR */ +#define AR531XPLUS_PCI_RXEOL 0x00000080 /* Desc Out EOL */ +#define AR531XPLUS_PCI_TXOOD 0x00000200 /* Desc In Out-of-Desc */ +#define AR531XPLUS_PCI_MASK 0x0000FFFF /* Desc Mask */ +#define AR531XPLUS_PCI_EXT_INT 0x02000000 +#define AR531XPLUS_PCI_ABORT_INT 0x04000000 + +#define AR531XPLUS_PCI_INT_MASK (AR531XPLUS_PCI + 0x0504) /* same as INT_STATUS */ + +#define AR531XPLUS_PCI_INTEN_REG (AR531XPLUS_PCI + 0x0508) +#define AR531XPLUS_PCI_INT_DISABLE 0x00 /* disable pci interrupts */ +#define AR531XPLUS_PCI_INT_ENABLE 0x01 /* enable pci interrupts */ + +#define AR531XPLUS_PCI_HOST_IN_EN (AR531XPLUS_PCI + 0x0800) +#define AR531XPLUS_PCI_HOST_IN_DIS (AR531XPLUS_PCI + 0x0804) +#define AR531XPLUS_PCI_HOST_IN_PTR (AR531XPLUS_PCI + 0x0810) +#define AR531XPLUS_PCI_HOST_OUT_EN (AR531XPLUS_PCI + 0x0900) +#define AR531XPLUS_PCI_HOST_OUT_DIS (AR531XPLUS_PCI + 0x0904) +#define AR531XPLUS_PCI_HOST_OUT_PTR (AR531XPLUS_PCI + 0x0908) + + +/* + * Local Bus Interface Registers + */ +#define AR531XPLUS_LB_CONFIG (AR531XPLUS_LOCAL + 0x0000) +#define AR531XPLUS_LBCONF_OE 0x00000001 /* =1 OE is low-true */ +#define AR531XPLUS_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */ +#define AR531XPLUS_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */ +#define AR531XPLUS_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */ +#define AR531XPLUS_LBCONF_WE 0x00000010 /* =1 Write En is low-true */ +#define AR531XPLUS_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */ +#define AR531XPLUS_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */ +#define AR531XPLUS_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */ +#define AR531XPLUS_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */ +#define AR531XPLUS_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */ +#define AR531XPLUS_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */ +#define AR531XPLUS_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */ +#define AR531XPLUS_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */ +#define AR531XPLUS_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */ +#define AR531XPLUS_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */ +#define AR531XPLUS_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */ +#define AR531XPLUS_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */ +#define AR531XPLUS_LBCONF_INT 0x00020000 /* =1 Intr is low true */ +#define AR531XPLUS_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */ +#define AR531XPLUS_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */ +#define AR531XPLUS_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */ +#define AR531XPLUS_LBCONF_INT_CTR3 0x000C0000 /* GND drive, Vdd drive */ +#define AR531XPLUS_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */ +#define AR531XPLUS_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */ +#define AR531XPLUS_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */ + +#define AR531XPLUS_LB_CLKSEL (AR531XPLUS_LOCAL + 0x0004) +#define AR531XPLUS_LBCLK_EXT 0x0001 /* use external clk for lb */ + +#define AR531XPLUS_LB_1MS (AR531XPLUS_LOCAL + 0x0008) +#define AR531XPLUS_LB1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ + +#define AR531XPLUS_LB_MISCCFG (AR531XPLUS_LOCAL + 0x000C) +#define AR531XPLUS_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */ +#define AR531XPLUS_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */ +#define AR531XPLUS_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */ +#define AR531XPLUS_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */ +#define AR531XPLUS_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */ +#define AR531XPLUS_LBM_TIMEOUT_MASK 0x00FFFF80 +#define AR531XPLUS_LBM_TIMEOUT_SHFT 7 +#define AR531XPLUS_LBM_PORTMUX 0x07000000 + + +#define AR531XPLUS_LB_RXTSOFF (AR531XPLUS_LOCAL + 0x0010) + +#define AR531XPLUS_LB_TX_CHAIN_EN (AR531XPLUS_LOCAL + 0x0100) +#define AR531XPLUS_LB_TXEN_0 0x01 +#define AR531XPLUS_LB_TXEN_1 0x02 +#define AR531XPLUS_LB_TXEN_2 0x04 +#define AR531XPLUS_LB_TXEN_3 0x08 + +#define AR531XPLUS_LB_TX_CHAIN_DIS (AR531XPLUS_LOCAL + 0x0104) +#define AR531XPLUS_LB_TX_DESC_PTR (AR531XPLUS_LOCAL + 0x0200) + +#define AR531XPLUS_LB_RX_CHAIN_EN (AR531XPLUS_LOCAL + 0x0400) +#define AR531XPLUS_LB_RXEN 0x01 + +#define AR531XPLUS_LB_RX_CHAIN_DIS (AR531XPLUS_LOCAL + 0x0404) +#define AR531XPLUS_LB_RX_DESC_PTR (AR531XPLUS_LOCAL + 0x0408) + +#define AR531XPLUS_LB_INT_STATUS (AR531XPLUS_LOCAL + 0x0500) +#define AR531XPLUS_INT_TX_DESC 0x0001 +#define AR531XPLUS_INT_TX_OK 0x0002 +#define AR531XPLUS_INT_TX_ERR 0x0004 +#define AR531XPLUS_INT_TX_EOF 0x0008 +#define AR531XPLUS_INT_RX_DESC 0x0010 +#define AR531XPLUS_INT_RX_OK 0x0020 +#define AR531XPLUS_INT_RX_ERR 0x0040 +#define AR531XPLUS_INT_RX_EOF 0x0080 +#define AR531XPLUS_INT_TX_TRUNC 0x0100 +#define AR531XPLUS_INT_TX_STARVE 0x0200 +#define AR531XPLUS_INT_LB_TIMEOUT 0x0400 +#define AR531XPLUS_INT_LB_ERR 0x0800 +#define AR531XPLUS_INT_MBOX_WR 0x1000 +#define AR531XPLUS_INT_MBOX_RD 0x2000 + +/* Bit definitions for INT MASK are the same as INT_STATUS */ +#define AR531XPLUS_LB_INT_MASK (AR531XPLUS_LOCAL + 0x0504) + +#define AR531XPLUS_LB_INT_EN (AR531XPLUS_LOCAL + 0x0508) +#define AR531XPLUS_LB_MBOX (AR531XPLUS_LOCAL + 0x0600) + + + +/* + * IR Interface Registers + */ +#define AR531XPLUS_IR_PKTDATA (AR531XPLUS_IR + 0x0000) + +#define AR531XPLUS_IR_PKTLEN (AR531XPLUS_IR + 0x07fc) /* 0 - 63 */ + +#define AR531XPLUS_IR_CONTROL (AR531XPLUS_IR + 0x0800) +#define AR531XPLUS_IRCTL_TX 0x00000000 /* use as tranmitter */ +#define AR531XPLUS_IRCTL_RX 0x00000001 /* use as receiver */ +#define AR531XPLUS_IRCTL_SAMPLECLK_MASK 0x00003ffe /* Sample clk divisor mask */ +#define AR531XPLUS_IRCTL_SAMPLECLK_SHFT 1 +#define AR531XPLUS_IRCTL_OUTPUTCLK_MASK 0x03ffc000 /* Output clk divisor mask */ +#define AR531XPLUS_IRCTL_OUTPUTCLK_SHFT 14 + +#define AR531XPLUS_IR_STATUS (AR531XPLUS_IR + 0x0804) +#define AR531XPLUS_IRSTS_RX 0x00000001 /* receive in progress */ +#define AR531XPLUS_IRSTS_TX 0x00000002 /* transmit in progress */ + +#define AR531XPLUS_IR_CONFIG (AR531XPLUS_IR + 0x0808) +#define AR531XPLUS_IRCFG_INVIN 0x00000001 /* invert input polarity */ +#define AR531XPLUS_IRCFG_INVOUT 0x00000002 /* invert output polarity */ +#define AR531XPLUS_IRCFG_SEQ_START_WIN_SEL 0x00000004 /* 1 => 28, 0 => 7 */ +#define AR531XPLUS_IRCFG_SEQ_START_THRESH 0x000000f0 /* */ +#define AR531XPLUS_IRCFG_SEQ_END_UNIT_SEL 0x00000100 /* */ +#define AR531XPLUS_IRCFG_SEQ_END_UNIT_THRESH 0x00007e00 /* */ +#define AR531XPLUS_IRCFG_SEQ_END_WIN_SEL 0x00008000 /* */ +#define AR531XPLUS_IRCFG_SEQ_END_WIN_THRESH 0x001f0000 /* */ +#define AR531XPLUS_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 + + +typedef unsigned int AR531X_REG; + +#define sysRegRead(phys) \ + (*(volatile AR531X_REG *)PHYS_TO_K1(phys)) + +#define sysRegWrite(phys, val) \ + ((*(volatile AR531X_REG *)PHYS_TO_K1(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) */ +}; + +#endif + +#endif /* AR531X_H */ diff -urN linux-mips-orig/drivers/net/ath/ar531xlnx.h linux-mips-new/drivers/net/ath/ar531xlnx.h --- linux-mips-orig/drivers/net/ath/ar531xlnx.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ar531xlnx.h 2005-12-31 12:33:57.676538368 +0000 @@ -0,0 +1,137 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * 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" + +#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" */ +#if CONFIG_AR5315 +#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 */ +#else +#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 +#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 */ +#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */ +#endif + +/* Miscellaneous interrupts, which share IP6 or IP2 */ +#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 9 + +#define PHYS_TO_K1(physaddr) KSEG1ADDR(physaddr) +#define PHYS_TO_K0(physaddr) KSEG0ADDR(physaddr) +#define UNMAPPED_TO_PHYS(vaddr) PHYSADDR(vaddr) +#define IS_UNMAPPED_VADDR(vaddr) \ + ((KSEGX(vaddr) == KSEG0) || (KSEGX(vaddr) == KSEG1)) + +/* IOCTL commands for /proc/ar531x */ +#define AR531X_CTRL_DO_BREAKPOINT 1 +#define AR531X_CTRL_DO_MADWIFI 2 + +/* + * Definitions for operating system portability. + * These are vxWorks-->Linux translations. + */ +#define LOCAL static +#define BOOL int +#define TRUE 1 +#define FALSE 0 +#define UINT8 u8 +#define UINT16 u16 +#define UINT32 u32 +#define PRINTF printk +#if /* DEBUG */ 1 +#define DEBUG_PRINTF printk +#define printf printk +#define INLINE +#else +DEBUG_PRINTF while (0) printk +#define INLINE inline +#endif +#define sysUDelay(usecs) udelay(usecs) +#define sysMsDelay(msecs) mdelay(msecs) +typedef volatile UINT8 *VIRT_ADDR; +#define MALLOC(sz) kmalloc(sz, GFP_KERNEL) +#define MALLOC_NOSLEEP(sz) kmalloc(sz, GFP_ATOMIC) +#define FREE(ptr) kfree((void *)ptr) +#define BSP_BUG() do { printk("kernel BSP BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) +#define BSP_BUG_ON(condition) do { if (unlikely((condition)!=0)) BSP_BUG(); } while(0) +#define ASSERT(x) BSP_BUG_ON(!(x)) + +extern struct ar531x_boarddata *ar531x_board_configuration; +extern char *ar531x_radio_configuration; +extern char *enet_mac_address_get(int MACUnit); + +extern void kgdbInit(void); +extern int kgdbEnabled(void); +extern void breakpoint(void); +extern int kgdbInterrupt(void); +extern unsigned int ar531x_cpu_frequency(void); +extern unsigned int ar531x_sys_frequency(void); + +/* GPIO support */ +extern struct irqaction spurious_gpio; +extern unsigned int gpioIntMask; +extern void ar531x_gpio_intr_init(int irq_base); +extern void ar531x_gpio_ctrl_output(int gpio); +extern void ar531x_gpio_ctrl_input(int gpio); +extern void ar531x_gpio_set(int gpio, int val); +extern int ar531x_gpio_get(int gpio); +extern void ar531x_gpio_intr_enable(unsigned int irq); +extern void ar531x_gpio_intr_disable(unsigned int irq); + +/* Watchdog Timer support */ +extern int watchdog_start(unsigned int milliseconds); +extern int watchdog_stop(void); +extern int watchdog_is_enabled(void); +extern unsigned int watchdog_min_timer_reached(void); +extern void watchdog_notify_alive(void); + +#define A_DATA_CACHE_INVAL(start, length) \ + dma_cache_inv((UINT32)(start),(length)) + +#define sysWbFlush() mb() + +#define intDisable(x) cli() +#define intEnable(x) sti() + +#endif /* __AR531XLNX_H */ diff -urN linux-mips-orig/drivers/net/ath/ipPhy.c linux-mips-new/drivers/net/ath/ipPhy.c --- linux-mips-orig/drivers/net/ath/ipPhy.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ipPhy.c 2005-12-31 12:33:57.677538216 +0000 @@ -0,0 +1,833 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * Manage the ICPLUS ethernet PHY. + * + * All definitions in this file are operating system independent! + */ + +#if defined(linux) +#include +#include +#include +#include +#include + +#include "ar531xlnx.h" +#endif + +#include "ae531xmac.h" +#include "ae531xreg.h" +#include "ipPhy.h" + +/* PHY selections and access functions */ + +typedef enum { + PHY_SRCPORT_INFO, + PHY_PORTINFO_SIZE, +} PHY_CAP_TYPE; + +typedef enum { + PHY_SRCPORT_NONE, + PHY_SRCPORT_VLANTAG, + PHY_SRCPORT_TRAILER, +} PHY_SRCPORT_TYPE; + +#ifdef DEBUG +#define DRV_DEBUG 1 +#endif +#define DRV_DEBUG 1 + +#if DRV_DEBUG +#define DRV_DEBUG_PHYERROR 0x00000001 +#define DRV_DEBUG_PHYCHANGE 0x00000002 +#define DRV_DEBUG_PHYSETUP 0x00000004 + +int ipPhyDebug = DRV_DEBUG_PHYERROR; + +#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \ +{ \ + if (ipPhyDebug & (FLG)) { \ + logMsg(X0, X1, X2, X3, X4, X5, X6); \ + } \ +} + +#define DRV_MSG(x,a,b,c,d,e,f) \ + logMsg(x,a,b,c,d,e,f) + +#define DRV_PRINT(FLG, X) \ +{ \ + if (ipPhyDebug & (FLG)) { \ + printf X; \ + } \ +} + +#else /* !DRV_DEBUG */ +#define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6) +#define DRV_MSG(x,a,b,c,d,e,f) +#define DRV_PRINT(DBG_SW,X) +#endif + +#define IP_LAN_PORT_VLAN 1 +#define IP_WAN_PORT_VLAN 2 + +#define ENET_UNIT_DEFAULT 0 + +/* + * Track per-PHY port information. + */ +typedef struct { + BOOL isEnetPort; /* normal enet port */ + BOOL isPhyAlive; /* last known state of link */ + int ethUnit; /* MAC associated with this phy port */ + UINT32 phyBase; + UINT32 phyAddr; /* PHY registers associated with this phy port */ + UINT32 VLANTableSetting; /* Value to be written to VLAN table */ +} ipPhyInfo_t; + +/* + * Per-PHY information, indexed by PHY unit number. + */ +ipPhyInfo_t ipPhyInfo[] = { + /* + * On AP30/AR5312, all PHYs are associated with MAC0. + * AP30/AR5312's MAC1 isn't used for anything. + * CONFIG_VENETDEV==1 (router) configuration: + * Ports 0,1,2, and 3 are "LAN ports" + * Port 4 is a WAN port + * Port 5 connects to MAC0 in the AR5312 + * CONFIG_VENETDEV==0 (bridge) configuration: + * Ports 0,1,2,3,4 are "LAN ports" + * Port 5 connects to the MAC0 in the AR5312 + */ + {TRUE, /* phy port 0 -- LAN port 0 */ + FALSE, + ENET_UNIT_DEFAULT, + (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET), + IP_PHY0_ADDR, + IP_LAN_PORT_VLAN + }, + + {TRUE, /* phy port 1 -- LAN port 1 */ + FALSE, + ENET_UNIT_DEFAULT, + (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET), + IP_PHY1_ADDR, + IP_LAN_PORT_VLAN + }, + + {TRUE, /* phy port 2 -- LAN port 2 */ + FALSE, + ENET_UNIT_DEFAULT, + (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET), + IP_PHY2_ADDR, + IP_LAN_PORT_VLAN + }, + + {TRUE, /* phy port 3 -- LAN port 3 */ + FALSE, + ENET_UNIT_DEFAULT, + (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET), + IP_PHY3_ADDR, + IP_LAN_PORT_VLAN + }, + + {TRUE, /* phy port 4 -- WAN port or LAN port 4 */ + FALSE, + ENET_UNIT_DEFAULT, + (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET), + IP_PHY4_ADDR, + IP_LAN_PORT_VLAN /* Send to all ports */ + }, + + {FALSE, /* phy port 5 -- CPU port (no RJ45 connector) */ + TRUE, + ENET_UNIT_DEFAULT, + (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET), + 0x00, + IP_LAN_PORT_VLAN /* Send to all ports */ + }, +}; + +#define IP_GLOBALREGBASE ((UINT32) (PHYS_TO_K1(AR531X_ENET0))) + +#define IP_PHY_MAX (sizeof(ipPhyInfo) / sizeof(ipPhyInfo[0])) + +/* Range of valid PHY IDs is [MIN..MAX] */ +#define IP_ID_MIN 0 +#define IP_ID_MAX (IP_PHY_MAX-1) + +/* Convenience macros to access myPhyInfo */ +#define IP_IS_ENET_PORT(phyUnit) (ipPhyInfo[phyUnit].isEnetPort) +#define IP_IS_PHY_ALIVE(phyUnit) (ipPhyInfo[phyUnit].isPhyAlive) +#define IP_ETHUNIT(phyUnit) (ipPhyInfo[phyUnit].ethUnit) +#define IP_PHYBASE(phyUnit) (ipPhyInfo[phyUnit].phyBase) +#define IP_PHYADDR(phyUnit) (ipPhyInfo[phyUnit].phyAddr) +#define IP_VLAN_TABLE_SETTING(phyUnit) (ipPhyInfo[phyUnit].VLANTableSetting) + + +#define IP_IS_ETHUNIT(phyUnit, ethUnit) \ + (IP_IS_ENET_PORT(phyUnit) && \ + IP_ETHUNIT(phyUnit) == (ethUnit)) + +/* Forward references */ +BOOL ip_phyIsLinkAlive(int phyUnit); +LOCAL void ip_VLANInit(int ethUnit); +LOCAL void ip_verifyReady(int ethUnit); +#if DEBUG +void ip_phyShow(int phyUnit); +void ip_phySet(int phyUnit, UINT32 regnum, UINT32 value); +void ip_globalSet(UINT32 phyAddr, UINT32 regnum, UINT32 value); +#endif + +/****************************************************************************** +* +* ip_phyIsLinkAlive - test to see if the specified link is alive +* +* RETURNS: +* TRUE --> link is alive +* FALSE --> link is down +*/ +BOOL +ip_phyIsLinkAlive(int phyUnit) +{ + UINT16 phyHwStatus; + UINT32 phyBase; + UINT32 phyAddr; + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS); + + if (phyHwStatus & IP_STATUS_LINK_PASS) { + return TRUE; + } else { + return FALSE; + } +} + +/****************************************************************************** +* +* ip_VLANInit - initialize "port-based VLANs" for the specified enet unit. +*/ +LOCAL void +ip_VLANInit(int ethUnit) +{ + int phyUnit; + UINT32 phyBase; + UINT32 phyReg; + + phyBase = IP_GLOBALREGBASE; + + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (IP_ETHUNIT(phyUnit) != ethUnit) { + continue; + } + phyRegWrite(phyBase, IP_GLOBAL_PHY29_ADDR, + IP_GLOBAL_PHY29_24_REG + ((phyUnit == 5) ? (phyUnit + 1) : phyUnit), + IP_VLAN_TABLE_SETTING(phyUnit)); + + /* Send all packets to all ports */ + phyReg = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG); + phyReg = phyReg | ((1 << phyUnit) << IP_VLAN1_OUTPUT_PORT_MASK_S); + phyRegWrite(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG, phyReg); + } + phyReg = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG); + phyReg = phyReg | TAG_VLAN_ENABLE; + phyReg = phyReg & ~VID_INDX_SEL_M; + phyRegWrite(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG, phyReg); + +} + + +LOCAL void +ip_verifyReady(int ethUnit) +{ + int phyUnit; + UINT32 phyBase = 0; + UINT32 phyAddr; + UINT16 phyID1; + UINT16 phyID2; + + /* + * The first read to the Phy port registers always fails and + * returns 0. So get things started with a bogus read. + */ + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyID1 = phyRegRead(phyBase, phyAddr, IP_PHY_ID1); /* returns 0 */ + break; + } + + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + /*******************/ + /* Verify phy port */ + /*******************/ + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyID1 = phyRegRead(phyBase, phyAddr, IP_PHY_ID1); + if (phyID1 != IP_PHY_ID1_EXPECTATION) { + DRV_PRINT(DRV_DEBUG_PHYERROR, + ("Invalid PHY ID1 for enet%d port%d. Expected 0x%04x, read 0x%04x\n", + ethUnit, + phyUnit, + IP_PHY_ID1_EXPECTATION, + phyID1)); + return; + } + + phyID2 = phyRegRead(phyBase, phyAddr, IP_PHY_ID2); + if ((phyID2 & IP_OUI_LSB_MASK) != IP_OUI_LSB_EXPECTATION) { + DRV_PRINT(DRV_DEBUG_PHYERROR, + ("Invalid PHY ID2 for enet%d port %d. Expected 0x%04x, read 0x%04x\n", + ethUnit, + phyUnit, + IP_OUI_LSB_EXPECTATION, + phyID2)); + return; + } + + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("Found PHY enet%d port%d: model 0x%x revision 0x%x\n", + ethUnit, + phyUnit, + (phyID2 & IP_MODEL_NUM_MASK) >> IP_MODEL_NUM_SHIFT, + (phyID2 & IP_REV_NUM_MASK) >> IP_REV_NUM_SHIFT)); + + } +} + + +/****************************************************************************** +* +* ip_phySetup - reset and setup the PHY associated with +* the specified MAC unit number. +* +* Resets the associated PHY port. +* +* RETURNS: +* TRUE --> associated PHY is alive +* FALSE --> no LINKs on this ethernet unit +*/ + +BOOL +ip_phySetup(int ethUnit, UINT32 _phyBase) +{ + int phyUnit; + UINT16 phyHwStatus; + UINT16 timeout; + int liveLinks = 0; + UINT32 phyBase = 0; + BOOL foundPhy = FALSE; + UINT32 phyAddr; + + /* Reset PHYs*/ + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyRegWrite(phyBase, phyAddr, IP_PHY_CONTROL, + IP_CTRL_SOFTWARE_RESET); + } + /* + * After the phy is reset, it takes a little while before + * it can respond properly. + */ + sysMsDelay(300); + /* Verify that the switch is what we think it is, and that it's ready */ + ip_verifyReady(ethUnit); + + /* See if there's any configuration data for this enet */ + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (IP_ETHUNIT(phyUnit) != ethUnit) { + continue; + } + + phyBase = IP_PHYBASE(phyUnit); + foundPhy = TRUE; + break; + } + + if (!foundPhy) { + return FALSE; /* No PHY's configured for this ethUnit */ + } + +#ifdef COBRA_TODO + /* Initialize global switch settings */ + + /* Initialize the aging time */ + + /* Set the learning properties */ +#endif + + /* start auto negogiation on each phy */ + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyRegWrite(phyBase, phyAddr, IP_AUTONEG_ADVERT, + IP_ADVERTISE_ALL); + phyRegWrite(phyBase, phyAddr, IP_PHY_CONTROL, + IP_CTRL_AUTONEGOTIATION_ENABLE | IP_CTRL_START_AUTONEGOTIATION); + } + + /* + * Wait up to .75 seconds for ALL associated PHYs to finish + * autonegotiation. The only way we get out of here sooner is + * if ALL PHYs are connected AND finish autonegotiation. + */ + timeout=5; + for (phyUnit=0; (phyUnit < IP_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + for (;;) { + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS); + + if (IP_AUTONEG_DONE(phyHwStatus)) { + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("Port %d, Neg Success\n", phyUnit)); + break; + } + if (timeout == 0) { + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("Port %d, Negogiation timeout\n", phyUnit)); + break; + } + if (--timeout == 0) { + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("Port %d, Negogiation timeout\n", phyUnit)); + break; + } + + sysMsDelay(150); + } + } + + /* + * All PHYs have had adequate time to autonegotiate. + * Now initialize software status. + * + * It's possible that some ports may take a bit longer + * to autonegotiate; but we can't wait forever. They'll + * get noticed by mv_phyCheckStatusChange during regular + * polling activities. + */ + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + if (ip_phyIsLinkAlive(phyUnit)) { + liveLinks++; + IP_IS_PHY_ALIVE(phyUnit) = TRUE; + } else { + IP_IS_PHY_ALIVE(phyUnit) = FALSE; + } + + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("eth%d: Phy Status=%4.4x\n", + ethUnit, + phyRegRead(IP_PHYBASE(phyUnit), + IP_PHYADDR(phyUnit), + IP_PHY_STATUS))); + } +#if 0 + /* XXX Divy. Disable WAN/LAN seggregation. See bug 17866 */ + ip_VLANInit(ethUnit); +#endif + return (liveLinks > 0); +} + +/****************************************************************************** +* +* ip_phyIsDuplexFull - Determines whether the phy ports associated with the +* specified device are FULL or HALF duplex. +* +* RETURNS: +* 1 --> FULL +* 0 --> HALF +*/ +int +ip_phyIsFullDuplex(int ethUnit) +{ + int phyUnit; + UINT32 phyBase; + UINT32 phyAddr; + UINT16 phyHwStatus; + + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + if (ip_phyIsLinkAlive(phyUnit)) { + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, IP_LINK_PARTNER_ABILITY); + printk("ipPhy.c: phyHwStatus 0x%x\n",phyHwStatus); + if ((phyHwStatus & IP_LINK_100BASETX_FULL_DUPLEX) || + (phyHwStatus & IP_LINK_10BASETX_FULL_DUPLEX)) { + return TRUE; + } + } + return -1; + } + + return FALSE; + +} + + +/****************************************************************************** +* +* ip_phyIsSpeed100 - Determines the speed of phy ports associated with the +* specified device. +* +* RETURNS: +* TRUE --> 100Mbit +* FALSE --> 10Mbit +*/ + +BOOL +ip_phyIsSpeed100(int ethUnit) +{ + int phyUnit; + UINT16 phyHwStatus; + UINT32 phyBase; + UINT32 phyAddr; + + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + if (ip_phyIsLinkAlive(phyUnit)) { + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, IP_LINK_PARTNER_ABILITY); + + if (phyHwStatus & IP_LINK_100BASETX) { + return TRUE; + } + } + } + + return FALSE; +} + +/***************************************************************************** +* +* ip_phyCheckStatusChange -- checks for significant changes in PHY state. +* +* A "significant change" is: +* dropped link (e.g. ethernet cable unplugged) OR +* autonegotiation completed + link (e.g. ethernet cable plugged in) +* +* When a PHY is plugged in, phyLinkGained is called. +* When a PHY is unplugged, phyLinkLost is called. +*/ + +void +ip_phyCheckStatusChange(int ethUnit) +{ + + int phyUnit; + UINT16 phyHwStatus; + ipPhyInfo_t *lastStatus; + int linkCount = 0; + int lostLinks = 0; + int gainedLinks = 0; + UINT32 phyBase; + UINT32 phyAddr; + + for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { + if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + lastStatus = &ipPhyInfo[phyUnit]; + phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS); + + if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */ + /* See if we've lost link */ + if (phyHwStatus & IP_STATUS_LINK_PASS) { + linkCount++; + } else { + lostLinks++; +#ifdef COBRA_TODO + mv_flushATUDB(phyUnit); +#endif + DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d down\n", + ethUnit, phyUnit)); + lastStatus->isPhyAlive = FALSE; + } + } else { /* last known link status was DEAD */ + /* Check for AutoNegotiation complete */ + if (IP_AUTONEG_DONE(phyHwStatus)) { + gainedLinks++; + linkCount++; + DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d up\n", + ethUnit, phyUnit)); + lastStatus->isPhyAlive = TRUE; + } + } + } + + if (linkCount == 0) { + if (lostLinks) { + /* We just lost the last link for this MAC */ + phyLinkLost(ethUnit); + } + } else { + if (gainedLinks == linkCount) { + /* We just gained our first link(s) for this MAC */ + phyLinkGained(ethUnit); + } + } + +} + +#if DEBUG + +/* Define the registers of interest for a phyShow command */ +typedef struct ipRegisterTableEntry_s { + UINT32 regNum; + char *regIdString; +} ipRegisterTableEntry_t; + +ipRegisterTableEntry_t ipPhyRegisterTable[] = { + {IP_PHY_CONTROL, "PHY Control "}, + {IP_PHY_STATUS, "PHY Status "}, + {IP_PHY_ID1, "PHY Identifier 1 "}, + {IP_PHY_ID2, "PHY Identifier 2 "}, + {IP_AUTONEG_ADVERT, "Auto-Negotiation Advertisement "}, + {IP_LINK_PARTNER_ABILITY, "Link Partner Ability "}, + {IP_AUTONEG_EXPANSION, "Auto-Negotiation Expansion "}, +}; +int ipPhyNumRegs = sizeof(ipPhyRegisterTable) / sizeof(ipPhyRegisterTable[0]); + + +ipRegisterTableEntry_t ipPhy29GlobalRegisterTable[] = { + {IP_GLOBAL_PHY29_18_REG, "29_18_REG "}, + {IP_GLOBAL_PHY29_19_REG, "29_19_REG "}, + {IP_GLOBAL_PHY29_20_REG, "29_20_REG "}, + {IP_GLOBAL_PHY29_21_REG, "29_21_REG "}, + {IP_GLOBAL_PHY29_22_REG, "29_22_REG "}, + {IP_GLOBAL_PHY29_23_REG, "29_23_REG "}, + {IP_GLOBAL_PHY29_24_REG, "29_24_REG "}, + {IP_GLOBAL_PHY29_25_REG, "29_25_REG "}, + {IP_GLOBAL_PHY29_26_REG, "29_26_REG "}, + {IP_GLOBAL_PHY29_27_REG, "29_27_REG "}, + {IP_GLOBAL_PHY29_28_REG, "29_28_REG "}, + {IP_GLOBAL_PHY29_29_REG, "29_29_REG "}, + {IP_GLOBAL_PHY29_30_REG, "29_30_REG "}, + {IP_GLOBAL_PHY29_31_REG, "29_31_REG "}, +}; +int ipPhy29GlobalNumRegs = + sizeof(ipPhy29GlobalRegisterTable) / sizeof(ipPhy29GlobalRegisterTable[0]); + + +ipRegisterTableEntry_t ipPhy30GlobalRegisterTable[] = { + {IP_GLOBAL_PHY30_0_REG, "30_0_REG "}, + {IP_GLOBAL_PHY30_1_REG, "30_1_REG "}, + {IP_GLOBAL_PHY30_2_REG, "30_2_REG "}, + {IP_GLOBAL_PHY30_3_REG, "30_3_REG "}, + {IP_GLOBAL_PHY30_4_REG, "30_4_REG "}, + {IP_GLOBAL_PHY30_5_REG, "30_5_REG "}, + {IP_GLOBAL_PHY30_6_REG, "30_6_REG "}, + {IP_GLOBAL_PHY30_7_REG, "30_7_REG "}, + {IP_GLOBAL_PHY30_8_REG, "30_8_REG "}, + {IP_GLOBAL_PHY30_9_REG, "30_9_REG "}, + {IP_GLOBAL_PHY30_10_REG, "30_10_REG "}, + {IP_GLOBAL_PHY30_11_REG, "30_11_REG "}, + {IP_GLOBAL_PHY30_12_REG, "30_12_REG "}, + {IP_GLOBAL_PHY30_13_REG, "30_13_REG "}, + {IP_GLOBAL_PHY30_16_REG, "30_16_REG "}, + {IP_GLOBAL_PHY30_17_REG, "30_17_REG "}, + {IP_GLOBAL_PHY30_18_REG, "30_18_REG "}, + {IP_GLOBAL_PHY30_20_REG, "30_20_REG "}, + {IP_GLOBAL_PHY30_21_REG, "30_21_REG "}, + {IP_GLOBAL_PHY30_22_REG, "30_22_REG "}, + {IP_GLOBAL_PHY30_23_REG, "30_23_REG "}, + {IP_GLOBAL_PHY30_24_REG, "30_24_REG "}, + {IP_GLOBAL_PHY30_25_REG, "30_25_REG "}, + {IP_GLOBAL_PHY30_26_REG, "30_26_REG "}, + {IP_GLOBAL_PHY30_27_REG, "30_27_REG "}, + {IP_GLOBAL_PHY30_28_REG, "30_28_REG "}, + {IP_GLOBAL_PHY30_29_REG, "30_29_REG "}, + {IP_GLOBAL_PHY30_30_REG, "30_30_REG "}, + {IP_GLOBAL_PHY30_31_REG, "30_31_REG "}, +}; +int ipPhy30GlobalNumRegs = + sizeof(ipPhy30GlobalRegisterTable) / sizeof(ipPhy30GlobalRegisterTable[0]); + +ipRegisterTableEntry_t ipPhy31GlobalRegisterTable[] = { + {IP_GLOBAL_PHY31_0_REG, "31_0_REG "}, + {IP_GLOBAL_PHY31_1_REG, "31_1_REG "}, + {IP_GLOBAL_PHY31_2_REG, "31_2_REG "}, + {IP_GLOBAL_PHY31_3_REG, "31_3_REG "}, + {IP_GLOBAL_PHY31_4_REG, "31_4_REG "}, + {IP_GLOBAL_PHY31_5_REG, "31_5_REG "}, + {IP_GLOBAL_PHY31_6_REG, "31_6_REG "}, +}; + +int ipPhy31GlobalNumRegs = + sizeof(ipPhy31GlobalRegisterTable) / sizeof(ipPhy31GlobalRegisterTable[0]); + + +/***************************************************************************** +* +* ip_phyShow - Dump the state of a PHY. +* There are two sets of registers for each phy port: +* "phy registers" and +* "switch port registers" +* We dump 'em all, plus the switch global registers. +*/ +void +ip_phyShow(int phyUnit) +{ + int i; + UINT16 value; + UINT32 phyBase; + UINT32 phyAddr; + + if (!ip_validPhyId(phyUnit)) { + return; + } + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + printf("PHY state for PHY%d (enet%d, phyBase 0x%8x, phyAddr 0x%x)\n", + phyUnit, + IP_ETHUNIT(phyUnit), + IP_PHYBASE(phyUnit), + IP_PHYADDR(phyUnit)); + + printf("PHY Registers:\n"); + for (i=0; i < ipPhyNumRegs; i++) { + + value = phyRegRead(phyBase, phyAddr, ipPhyRegisterTable[i].regNum); + + printf("Reg %02d (0x%02x) %s = 0x%08x\n", + ipPhyRegisterTable[i].regNum, + ipPhyRegisterTable[i].regNum, + ipPhyRegisterTable[i].regIdString, + value); + } + + phyBase = IP_GLOBALREGBASE; + + printf("Switch Global Registers:\n"); + printf("Phy29 Registers:\n"); + for (i=0; i < ipPhy29GlobalNumRegs; i++) { + + value = phyRegRead(phyBase, IP_GLOBAL_PHY29_ADDR, + ipPhy29GlobalRegisterTable[i].regNum); + + printf("Reg %02d (0x%02x) %s = 0x%08x\n", + ipPhy29GlobalRegisterTable[i].regNum, + ipPhy29GlobalRegisterTable[i].regNum, + ipPhy29GlobalRegisterTable[i].regIdString, + value); + } + + printf("Phy30 Registers:\n"); + for (i=0; i < ipPhy30GlobalNumRegs; i++) { + + value = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR, + ipPhy30GlobalRegisterTable[i].regNum); + + printf("Reg %02d (0x%02x) %s = 0x%08x\n", + ipPhy30GlobalRegisterTable[i].regNum, + ipPhy30GlobalRegisterTable[i].regNum, + ipPhy30GlobalRegisterTable[i].regIdString, + value); + } + printf("Phy31 Registers:\n"); + for (i=0; i < ipPhy31GlobalNumRegs; i++) { + + value = phyRegRead(phyBase, IP_GLOBAL_PHY31_ADDR, + ipPhy31GlobalRegisterTable[i].regNum); + + printf("Reg %02d (0x%02x) %s = 0x%08x\n", + ipPhy31GlobalRegisterTable[i].regNum, + ipPhy31GlobalRegisterTable[i].regNum, + ipPhy31GlobalRegisterTable[i].regIdString, + value); + } +} + +/***************************************************************************** +* +* ip_phySet - Modify the value of a PHY register (debug only). +*/ +void +ip_phySet(int phyUnit, UINT32 regnum, UINT32 value) +{ + UINT32 phyBase; + UINT32 phyAddr; + + if (ip_validPhyId(phyUnit)) { + + phyBase = IP_PHYBASE(phyUnit); + phyAddr = IP_PHYADDR(phyUnit); + + phyRegWrite(phyBase, phyAddr, regnum, value); + } +} + +/***************************************************************************** +* +* ip_globalSet - Modify the value of a global register +* (debug only). +*/ +void +ip_globalSet(UINT32 phyAddr, UINT32 regnum, UINT32 value) +{ + UINT32 phyBase; + + phyBase = IP_GLOBALREGBASE; + + phyRegWrite(phyBase, phyAddr, regnum, value); +} + + +#endif diff -urN linux-mips-orig/drivers/net/ath/ipPhy.h linux-mips-new/drivers/net/ath/ipPhy.h --- linux-mips-orig/drivers/net/ath/ipPhy.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/ipPhy.h 2005-12-31 12:33:57.678538064 +0000 @@ -0,0 +1,172 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * icPhy.h - definitions for the ethernet PHY. + * This code supports a simple 1-port ethernet phy, ICPLUS, + * All definitions in this file are operating system independent! + */ + +#ifndef IPPHY_H +#define IPPHY_H + +/*****************/ +/* PHY Registers */ +/*****************/ +#define IP_PHY_CONTROL 0 +#define IP_PHY_STATUS 1 +#define IP_PHY_ID1 2 +#define IP_PHY_ID2 3 +#define IP_AUTONEG_ADVERT 4 +#define IP_LINK_PARTNER_ABILITY 5 +#define IP_AUTONEG_EXPANSION 6 + + +/* IP_PHY_CONTROL fields */ +#define IP_CTRL_SOFTWARE_RESET 0x8000 +#define IP_CTRL_SPEED_100 0x2000 +#define IP_CTRL_AUTONEGOTIATION_ENABLE 0x1000 +#define IP_CTRL_START_AUTONEGOTIATION 0x0200 +#define IP_CTRL_SPEED_FULL_DUPLEX 0x0100 + +/* Phy status fields */ +#define IP_STATUS_AUTO_NEG_DONE 0x0020 +#define IP_STATUS_LINK_PASS 0x0004 + +#define IP_AUTONEG_DONE(ip_phy_status) \ + (((ip_phy_status) & \ + (IP_STATUS_AUTO_NEG_DONE)) == \ + (IP_STATUS_AUTO_NEG_DONE)) + +/* ICPLUS_PHY_ID1 fields */ +#define IP_PHY_ID1_EXPECTATION 0x0243 /* OUI >> 6 */ + +/* ICPLUS_PHY_ID2 fields */ +#define IP_OUI_LSB_MASK 0xfc00 +#define IP_OUI_LSB_EXPECTATION 0x0c00 +#define IP_OUI_LSB_SHIFT 10 +#define IP_MODEL_NUM_MASK 0x03f0 +#define IP_MODEL_NUM_SHIFT 4 +#define IP_REV_NUM_MASK 0x000f +#define IP_REV_NUM_SHIFT 0 + +/* Link Partner ability */ +#define IP_LINK_100BASETX_FULL_DUPLEX 0x0100 +#define IP_LINK_100BASETX 0x0080 +#define IP_LINK_10BASETX_FULL_DUPLEX 0x0040 +#define IP_LINK_10BASETX 0x0020 + +/* Advertisement register. */ +#define IP_ADVERTISE_100FULL 0x0100 +#define IP_ADVERTISE_100HALF 0x0080 +#define IP_ADVERTISE_10FULL 0x0040 +#define IP_ADVERTISE_10HALF 0x0020 + +#define IP_ADVERTISE_ALL (IP_ADVERTISE_10HALF | IP_ADVERTISE_10FULL | \ + IP_ADVERTISE_100HALF | IP_ADVERTISE_100FULL) + + +#define IP_VLAN_TAG_VALID 0x81 +#define IP_VLAN_TAG_SIZE 4 +#define IP_VLAN_TAG_OFFSET 12 /* After DA & SA */ +#define IP_SPECIAL_TAG_VALID 0x81 + +/****************************/ +/* Global Control Registers */ +/****************************/ +/* IP Global register doesn't have names based on functionality + * hence has to live with this names for now */ +#define IP_GLOBAL_PHY29_18_REG 18 +#define IP_GLOBAL_PHY29_19_REG 19 +#define IP_GLOBAL_PHY29_20_REG 20 +#define IP_GLOBAL_PHY29_21_REG 21 +#define IP_GLOBAL_PHY29_22_REG 22 +#define IP_GLOBAL_PHY29_23_REG 23 +#define IP_GLOBAL_PHY29_24_REG 24 +#define IP_GLOBAL_PHY29_25_REG 25 +#define IP_GLOBAL_PHY29_26_REG 26 +#define IP_GLOBAL_PHY29_27_REG 27 +#define IP_GLOBAL_PHY29_28_REG 28 +#define IP_GLOBAL_PHY29_29_REG 29 +#define IP_GLOBAL_PHY29_30_REG 30 +#define IP_GLOBAL_PHY29_31_REG 31 + + +#define IP_GLOBAL_PHY30_0_REG 0 +#define IP_GLOBAL_PHY30_1_REG 1 +#define IP_GLOBAL_PHY30_2_REG 2 +#define IP_GLOBAL_PHY30_3_REG 3 +#define IP_GLOBAL_PHY30_4_REG 4 +#define IP_GLOBAL_PHY30_5_REG 5 +#define IP_GLOBAL_PHY30_6_REG 6 +#define IP_GLOBAL_PHY30_7_REG 7 +#define IP_GLOBAL_PHY30_8_REG 8 +#define IP_GLOBAL_PHY30_9_REG 9 +#define IP_GLOBAL_PHY30_10_REG 10 +#define IP_GLOBAL_PHY30_11_REG 11 +#define IP_GLOBAL_PHY30_12_REG 12 +#define IP_GLOBAL_PHY30_13_REG 13 +#define IP_GLOBAL_PHY30_16_REG 16 +#define IP_GLOBAL_PHY30_17_REG 17 +#define IP_GLOBAL_PHY30_18_REG 18 +#define IP_GLOBAL_PHY30_20_REG 20 +#define IP_GLOBAL_PHY30_21_REG 21 +#define IP_GLOBAL_PHY30_22_REG 22 +#define IP_GLOBAL_PHY30_23_REG 23 +#define IP_GLOBAL_PHY30_24_REG 24 +#define IP_GLOBAL_PHY30_25_REG 25 +#define IP_GLOBAL_PHY30_26_REG 26 +#define IP_GLOBAL_PHY30_27_REG 27 +#define IP_GLOBAL_PHY30_28_REG 28 +#define IP_GLOBAL_PHY30_29_REG 29 +#define IP_GLOBAL_PHY30_30_REG 30 +#define IP_GLOBAL_PHY30_31_REG 31 + +#define IP_GLOBAL_PHY31_0_REG 0 +#define IP_GLOBAL_PHY31_1_REG 1 +#define IP_GLOBAL_PHY31_2_REG 2 +#define IP_GLOBAL_PHY31_3_REG 3 +#define IP_GLOBAL_PHY31_4_REG 4 +#define IP_GLOBAL_PHY31_5_REG 5 +#define IP_GLOBAL_PHY31_6_REG 6 + +#define IP_GLOBAL_PHY29_31_REG 31 + + +#define IP_VLAN0_OUTPUT_PORT_MASK_S 0 +#define IP_VLAN1_OUTPUT_PORT_MASK_S 8 +#define IP_VLAN2_OUTPUT_PORT_MASK_S 0 +#define IP_VLAN3_OUTPUT_PORT_MASK_S 8 + +/* Masks and shifts for 29.23 register */ +#define IP_PORTX_ADD_TAG_S 11 +#define IP_PORTX_REMOVE_TAG_S 6 +#define IP_PORT5_ADD_TAG_S 1 +#define IP_PORT5_REMOVE_TAG_S 0 + +/* + * 30.9 Definitions + */ +#define TAG_VLAN_ENABLE 0x0080 +#define VID_INDX_SEL_M 0x0070 +#define VID_INDX_SEL_S 4 + + +/* PHY Addresses */ +#define IP_PHY0_ADDR 0 +#define IP_PHY1_ADDR 1 +#define IP_PHY2_ADDR 2 +#define IP_PHY3_ADDR 3 +#define IP_PHY4_ADDR 4 + +#define IP_GLOBAL_PHY29_ADDR 29 +#define IP_GLOBAL_PHY30_ADDR 30 +#define IP_GLOBAL_PHY31_ADDR 31 + + +#endif diff -urN linux-mips-orig/drivers/net/ath/kendSwitchPhy.c linux-mips-new/drivers/net/ath/kendSwitchPhy.c --- linux-mips-orig/drivers/net/ath/kendSwitchPhy.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/kendSwitchPhy.c 2005-12-31 12:33:57.678538064 +0000 @@ -0,0 +1,286 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * Manage the ethernet PHY. + * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL, + * and compatible PHYs, such as the Kendin KS8721B. + * All definitions in this file are operating system independent! + */ + +#if defined(linux) +#include +#include +#include +#include +#include + +#include "ar531xlnx.h" +#endif + +#if defined(__ECOS) +#include "ae531xecos.h" +#endif + + +#include "ae531xmac.h" +#include "ae531xreg.h" +#include "rtPhy.h" + +#define RT_MAX_PORTS 5 /* max addressable ports per MIIM */ + +#if /* DEBUG */ 1 +#define RT_DEBUG_ERROR 0x00000001 +#define RT_DEBUG_PHYSETUP 0x00000002 +#define RT_DEBUG_PHYCHANGE 0x00000004 + +/* XXX: must hardcode this since same MIIM for all ethUnits */ +const UINT32 phyBase = 0xb8100000; + +int rtPhyDebug = RT_DEBUG_ERROR; + +#define RT_PRINT(FLG, X) \ +{ \ + if (rtPhyDebug & (FLG)) { \ + DEBUG_PRINTF X; \ + } \ +} +#else +#define RT_PRINT(FLG, X) +#endif + +/* + * Track per-PHY state. + */ +static BOOL rtPhyAlive[RT_MAX_PORTS]; + + +/****************************************************************************** +* +* rt_phySetup - reset and setup the PHY associated with +* the specified MAC unit number. +* +* Resets the associated PHY port. +* +* RETURNS: +* TRUE --> associated PHY is alive +* FALSE --> no LINKs on this ethernet unit +*/ + +BOOL +rt_phySetup(int ethUnit, UINT32 phyBaseIgnored) +{ + BOOL linkAlive = FALSE; + + /* Reset phy */ + if (ethUnit == 0) { + int i; + for (i=1; i<5; i++) { + phyRegWrite(phyBase, i, GEN_ctl, AUTONEGENA); + sysMsDelay(200); + if (phyRegRead(phyBase, i, GEN_sts) & (AUTOCMPLT | LINK)) { + rtPhyAlive[i] = TRUE; + } + else { + rtPhyAlive[i] = FALSE; + } + } + } + else { + phyRegWrite(phyBase, 5, GEN_ctl, AUTONEGENA); + sysMsDelay(200); + if (phyRegRead(phyBase, 5, GEN_sts) & (AUTOCMPLT | LINK)) { + rtPhyAlive[5] = TRUE; + } + else { + rtPhyAlive[5] = FALSE; + } + } + + return linkAlive; +} + +/****************************************************************************** +* +* rt_phyIsDuplexFull - Determines whether the phy ports associated with the +* specified device are FULL or HALF duplex. +* +* RETURNS: +* 1 --> FULL +* 0 --> HALF +*/ +int +rt_phyIsFullDuplex(int ethUnit) +{ + UINT16 phyLpa = 0; + + if (ethUnit == 0) { + int i; + /* 4 ports connected. If any are half-duplex report half. */ + for (i=1; i<5; i++) { + phyLpa = phyRegRead(phyBase, i, AN_lpa); + if ( (!(phyLpa & (LPA_TXFD | LPA_10FD))) && + (phyLpa & (LPA_TX | LPA_10)) ) { + return 0; + } + } + return 1; + } + else { + phyLpa = phyRegRead(phyBase, 5, AN_lpa); + if (phyLpa & (LPA_TXFD | LPA_10FD) ) { + return 1; + } + else { + return 0; + } + } +} + +/****************************************************************************** +* +* rt_phyIsSpeed100 - Determines the speed of phy ports associated with the +* specified device. +* +* RETURNS: +* TRUE --> 100Mbit +* FALSE --> 10Mbit +*/ +BOOL +rt_phyIsSpeed100(int ethUnit) +{ + UINT16 phyLpa; + + if (ethUnit == 0) { + int i; + /* 4 ports connected. If any are not 100 report 10. */ + for (i=1; i<5; i++) { + phyLpa = phyRegRead(phyBase, i, AN_lpa); + if ( (!(phyLpa & (LPA_TXFD | LPA_TX))) && + (phyLpa & (LPA_10FD | LPA_10)) ) { + printk("10\n"); + return FALSE; + } + } + printk("100\n"); + return TRUE; + } + else { + phyLpa = phyRegRead(phyBase, 5, AN_lpa); + if (phyLpa & (LPA_TXFD | LPA_TX) ) { + printk("100\n"); + return TRUE; + } + else { + printk("10\n"); + return FALSE; + } + } +} + +/***************************************************************************** +* +* rt_phyCheckStatusChange -- checks for significant changes in PHY state. +* +* A "significant change" is: +* dropped link (e.g. ethernet cable unplugged) OR +* autonegotiation completed + link (e.g. ethernet cable plugged in) +* +* When a PHY is plugged in, phyLinkGained is called. +* When a PHY is unplugged, phyLinkLost is called. +*/ +void +rt_phyCheckStatusChange(int ethUnit) +{ + UINT16 phyHwStatus; + int i, loopLower, loopUpper; + + if (ethUnit == 0) { + loopLower = 1; + loopUpper = 4; + } + else { + loopLower = 5; + loopUpper = 5; + } + + for (i=loopLower; i<=loopUpper; i++) { + phyHwStatus = phyRegRead(phyBase, i, GEN_sts); + + if (rtPhyAlive[i]) { /* last known status was ALIVE */ + /* See if we've lost link */ + if (!(phyHwStatus & LINK)) { + RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link down\n", ethUnit)); + rtPhyAlive[i] = FALSE; + phyLinkLost(ethUnit); + } + } else { /* last known status was DEAD */ + /* Check for AN complete */ + if ((phyHwStatus & (AUTOCMPLT | LINK)) == (AUTOCMPLT | LINK)) { + RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link up\n", ethUnit)); + rtPhyAlive[i] = TRUE; + phyLinkGained(ethUnit); + } + } + } +} + +#if DEBUG + +/* Define the PHY registers of interest for a phyShow command */ +struct rtRegisterTable_s { + UINT32 regNum; + char *regIdString; +} rtRegisterTable[] = +{ + {GEN_ctl, "Basic Mode Control (GEN_ctl) "}, + {GEN_sts, "Basic Mode Status (GEN_sts) "}, + {GEN_id_hi, "PHY Identifier 1 (GET_id_hi) "}, + {GEN_id_lo, "PHY Identifier 2 (GET_id_lo) "}, + {AN_adv, "Auto-Neg Advertisement (AN_adv) "}, + {AN_lpa, "Auto-Neg Link Partner Ability "}, + {AN_exp, "Auto-Neg Expansion "}, +}; + +int rtNumRegs = sizeof(rtRegisterTable) / sizeof(rtRegisterTable[0]); + +/* + * Dump the state of a PHY. + */ +void +rt_phyShow(int phyUnit) +{ + int i; + UINT16 value; + int j, loopLower, loopUpper; + + printf("PHY state for ethphy%d\n", phyUnit); + + if (phyUnit == 0) { + loopLower = 1; + loopUpper = 4; + } + else { + loopLower = 5; + loopUpper = 5; + } + + for (j=loopLower; j<=loopUpper; j++) { + printk("PHY port %d:\n", j); + for (i=0; i link is alive +* FALSE --> link is down +*/ +BOOL +mv_phyIsLinkAlive(int phyUnit) +{ + UINT16 phyHwStatus; + UINT32 phyBase; + UINT32 phyAddr; + + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); + + if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) { + return TRUE; + } else { + return FALSE; + } +} + +/****************************************************************************** +* +* mv_VLANInit - initialize "port-based VLANs" for the specified enet unit. +*/ +LOCAL void +mv_VLANInit(int ethUnit) +{ + int phyUnit; + UINT32 phyBase; + UINT32 switchPortAddr; + + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (MV_ETHUNIT(phyUnit) != ethUnit) { + continue; + } + + phyBase = MV_PHYBASE(phyUnit); + switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); + + phyRegWrite(phyBase, switchPortAddr, MV_PORT_BASED_VLAN_MAP, + MV_VLAN_TABLE_SETTING(phyUnit)); + } +} + +#define phyPortConfigured(phyUnit) TRUE /* TBDFREEDOM2 */ + +/****************************************************************************** +* +* mv_enableConfiguredPorts - enable whichever PHY ports are supposed +* to be enabled according to administrative configuration. +*/ +LOCAL void +mv_enableConfiguredPorts(int ethUnit) +{ + int phyUnit; + UINT32 phyBase; + UINT32 switchPortAddr; + UINT16 portControl; + UINT16 portAssociationVector; + + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (MV_ETHUNIT(phyUnit) != ethUnit) { + continue; + } + + phyBase = MV_PHYBASE(phyUnit); + switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); + + if (phyPortConfigured(phyUnit)) { + + portControl = MV_PORT_CONTROL_PORT_STATE_FORWARDING; +#if CONFIG_VENETDEV + if (!MV_IS_ENET_PORT(phyUnit)) { /* CPU port */ + portControl |= MV_PORT_CONTROL_INGRESS_TRAILER + | MV_PORT_CONTROL_EGRESS_MODE; + } +#endif + phyRegWrite(phyBase, switchPortAddr, MV_PORT_CONTROL, portControl); + + portAssociationVector = 1 << phyUnit; + + phyRegWrite(phyBase, switchPortAddr, + MV_PORT_ASSOCIATION_VECTOR, portAssociationVector); + } + } +} + +/****************************************************************************** +* +* mv_verifyReady - validates that we're dealing with the device +* we think we're dealing with, and that it's ready. +*/ +LOCAL void +mv_verifyReady(int ethUnit) +{ + int phyUnit; + UINT16 globalStatus; + UINT32 phyBase = 0; + UINT32 phyAddr; + UINT32 switchPortAddr; + UINT16 phyID1; + UINT16 phyID2; + UINT16 switchID; + + /* + * The first read to the Phy port registers always fails and + * returns 0. So get things started with a bogus read. + */ + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + (void)phyRegRead(phyBase, phyAddr, MV_PHY_ID1); /* returns 0 */ + break; + } + + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + /*******************/ + /* Verify phy port */ + /*******************/ + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + phyID1 = phyRegRead(phyBase, phyAddr, MV_PHY_ID1); + if (phyID1 != MV_PHY_ID1_EXPECTATION) { + MV_PRINT(MV_DEBUG_PHYSETUP, + ("Invalid PHY ID1 for ethmac%d port%d. Expected 0x%04x, read 0x%04x\n", + ethUnit, + phyUnit, + MV_PHY_ID1_EXPECTATION, + phyID1)); + return; + } + + phyID2 = phyRegRead(phyBase, phyAddr, MV_PHY_ID2); + if ((phyID2 & MV_OUI_LSB_MASK) != MV_OUI_LSB_EXPECTATION) { + MV_PRINT(MV_DEBUG_PHYSETUP, + ("Invalid PHY ID2 for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n", + ethUnit, + phyUnit, + MV_OUI_LSB_EXPECTATION, + phyID2)); + return; + } + + MV_PRINT(MV_DEBUG_PHYSETUP, + ("Found PHY ethmac%d port%d: model 0x%x revision 0x%x\n", + ethUnit, + phyUnit, + (phyID2 & MV_MODEL_NUM_MASK) >> MV_MODEL_NUM_SHIFT, + (phyID2 & MV_REV_NUM_MASK) >> MV_REV_NUM_SHIFT)); + + + /**********************/ + /* Verify switch port */ + /**********************/ + switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); + + switchID = phyRegRead(phyBase, switchPortAddr, MV_SWITCH_ID); + if ((switchID & MV_SWITCH_ID_DEV_MASK) != + MV_SWITCH_ID_DEV_EXPECTATION) { + + MV_PRINT(MV_DEBUG_PHYSETUP, + ("Invalid switch ID for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n", + ethUnit, + phyUnit, + MV_SWITCH_ID_DEV_EXPECTATION, + switchID)); + return; + } + + MV_PRINT(MV_DEBUG_PHYSETUP, + ("Found PHY switch for enet %d port %d deviceID 0x%x revision 0x%x\n", + ethUnit, + phyUnit, + (switchID & MV_SWITCH_ID_DEV_MASK) >> MV_SWITCH_ID_DEV_SHIFT, + (switchID & MV_SWITCH_ID_REV_MASK) >> MV_SWITCH_ID_REV_SHIFT)) + } + + /*******************************/ + /* Verify that switch is ready */ + /*******************************/ + if (phyBase) { + globalStatus = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, + MV_SWITCH_GLOBAL_STATUS); + + if (!(globalStatus & MV_SWITCH_STATUS_READY_MASK)) { + MV_PRINT(MV_DEBUG_PHYSETUP, + ("PHY switch for ethmac%d NOT ready!\n", + ethUnit)); + } + } else { + MV_PRINT(MV_DEBUG_PHYSETUP, + ("No ports configured for ethmac%d\n", ethUnit)); + } +} + +/****************************************************************************** +* +* mv_phySetup - reset and setup the PHY switch. +* +* Resets each PHY port. +* +* RETURNS: +* TRUE --> at least 1 PHY with LINK +* FALSE --> no LINKs on this ethernet unit +*/ +BOOL +mv_phySetup(int ethUnit, UINT32 phyBase) +{ + int phyUnit; + int liveLinks = 0; + BOOL foundPhy = FALSE; + UINT32 phyAddr; + UINT16 atuControl; + + /* + * Allow platform-specific code to determine the default Ethernet MAC + * at run-time. If phyEthMacDefault returns a negative value, use the + * static mvPhyInfo table "as is". But if phyEthMacDefault returns a + * non-negative value, use it as the default ethernet unit. + */ + { + int ethMacDefault = phyEthMacDefault(); + + if (ethMacDefault >= 0) { + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + MV_ETHUNIT(phyUnit)=ethMacDefault; + } + } + } + + /* + * See if there's any configuration data for this enet, + * and set up phyBase in table. + */ + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (MV_ETHUNIT(phyUnit) != ethUnit) { + continue; + } + + MV_PHYBASE(phyUnit) = phyBase; + foundPhy = TRUE; + } + + if (!foundPhy) { + return FALSE; /* No PHY's configured for this ethUnit */ + } + + /* Verify that the switch is what we think it is, and that it's ready */ + mv_verifyReady(ethUnit); + + /* Initialize global switch settings */ + atuControl = MV_ATUCTRL_AGE_TIME_DEFAULT << MV_ATUCTRL_AGE_TIME_SHIFT; + atuControl |= MV_ATUCTRL_ATU_SIZE_DEFAULT << MV_ATUCTRL_ATU_SIZE_SHIFT; + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_CONTROL, atuControl); + + /* Reset PHYs and start autonegoation on each. */ + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (MV_ETHUNIT(phyUnit) != ethUnit) { + continue; + } + + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + phyRegWrite(phyBase, phyAddr, MV_PHY_CONTROL, + MV_CTRL_SOFTWARE_RESET | MV_CTRL_AUTONEGOTIATION_ENABLE); + } + +#if 0 /* Don't wait -- we'll detect shortly after the link comes up */ +{ + int timeout; + UINT16 phyHwStatus; + + /* + * Wait 5 seconds for ALL associated PHYs to finish autonegotiation. + */ + timeout=50; + for (phyUnit=0; (phyUnit < MV_PHY_MAX) && (timeout > 0); phyUnit++) { + if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + for (;;) { + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); + + if (MV_AUTONEG_DONE(phyHwStatus)) { + break; + } + + if (--timeout == 0) { + break; + } + + sysMsDelay(100); + } + } +} +#endif + + /* + * All PHYs have had adequate time to autonegotiate. + * Now initialize software status. + * + * It's possible that some ports may take a bit longer + * to autonegotiate; but we can't wait forever. They'll + * get noticed by mv_phyCheckStatusChange during regular + * polling activities. + */ + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + if (mv_phyIsLinkAlive(phyUnit)) { + liveLinks++; + MV_IS_PHY_ALIVE(phyUnit) = TRUE; + } else { + MV_IS_PHY_ALIVE(phyUnit) = FALSE; + } + + MV_PRINT(MV_DEBUG_PHYSETUP, + ("ethmac%d: Phy Status=%4.4x\n", + ethUnit, + phyRegRead(MV_PHYBASE(phyUnit), + MV_PHYADDR(phyUnit), + MV_PHY_SPECIFIC_STATUS))); + } + + mv_VLANInit(ethUnit); + + mv_enableConfiguredPorts(ethUnit); + + return (liveLinks > 0); +} + + +/****************************************************************************** +* +* mv_phyIsDuplexFull - Determines whether the phy ports associated with the +* specified device are FULL or HALF duplex. +* +* RETURNS: +* 1 --> at least one associated PHY in FULL DUPLEX +* 0 --> all half duplex +* -1 --> No links +*/ +int +mv_phyIsFullDuplex(int ethUnit) +{ + int phyUnit; + UINT32 phyBase; + UINT32 phyAddr; + UINT16 phyHwStatus; + int oneIsReady=0; + + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + if (mv_phyIsLinkAlive(phyUnit)) { + oneIsReady = 1; + + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); + + if (phyHwStatus & MV_STATUS_RESOLVED_DUPLEX_FULL) { + return 1; + } + } + } + if (oneIsReady) + return 0; + else + return -1; +} + +/****************************************************************************** +* +* mv_phyIsSpeed100 - Determines the speed of a phy port +* +* RETURNS: +* TRUE --> PHY operating at 100 Mbit +* FALSE --> link down, or not operating at 100 Mbit +*/ +BOOL +mv_phyIsSpeed100(int phyUnit) +{ + UINT16 phyHwStatus; + UINT32 phyBase; + UINT32 phyAddr; + + if (MV_IS_ENET_PORT(phyUnit)) { + if (mv_phyIsLinkAlive(phyUnit)) { + + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); + + if (phyHwStatus & MV_STATUS_RESOLVED_SPEED_100) { + return TRUE; + } + } + } + + return FALSE; +} + +#if CONFIG_VENETDEV +/****************************************************************************** +* +* mv_phyDetermineSource - Examine a received frame's Egress Trailer +* to determine whether it came from a LAN or WAN port. +* +* RETURNS: +* Sets *pFromLAN: 1-->LAN, 0-->WAN +* Modifies *pLen to remove PHY trailer from frame +*/ +void +mv_phyDetermineSource(char *data, int len, int *pFromLAN) +{ + unsigned char *phyTrailer; + unsigned char incomingPort; + + phyTrailer = &data[len - MV_PHY_TRAILER_SIZE]; + ASSERT(phyTrailer[0] == MV_EGRESS_TRAILER_VALID); + + incomingPort = phyTrailer[1]; + if (MV_IS_LAN_PORT(incomingPort)) { + *pFromLAN = 1; + } else { + ASSERT(MV_IS_WAN_PORT(incomingPort)); + *pFromLAN = 0; + } +} + + +/****************************************************************************** +* +* mv_phySetDestinationPort - Set the Ingress Trailer to force the +* frame to be sent to LAN or WAN, as specified. +* +*/ +void +mv_phySetDestinationPort(char *data, int len, int fromLAN) +{ + char *phyTrailer; + + phyTrailer = &data[len]; + if (fromLAN) { + /* LAN ports: Use default settings, as per mvPhyInfo */ + phyTrailer[0] = 0x00; + phyTrailer[1] = 0x00; + } else { + /* WAN port: Direct to WAN port */ + phyTrailer[0] = MV_INGRESS_TRAILER_OVERRIDE; + phyTrailer[1] = 1 << MV_WAN_PORT; + } + phyTrailer[2] = 0x00; + phyTrailer[3] = 0x00; +} +#endif + + +/***************************************************************************** +* +* Validate that the specified PHY unit number is a valid PHY ID. +* Print a message if it is invalid. +* RETURNS +* TRUE --> valid +* FALSE --> invalid +*/ +LOCAL BOOL +mv_validPhyId(int phyUnit) +{ + if ((phyUnit >= MV_ID_MIN) && (phyUnit <= MV_ID_MAX)) { + return TRUE; + } else { + PRINTF("PHY unit number must be in the range [%d..%d]\n", + MV_ID_MIN, MV_ID_MAX); + return FALSE; + } +} + + +/***************************************************************************** +* +* mv_waitWhileATUBusy - spins until the ATU completes +* its previous operation. +*/ +LOCAL void +mv_waitWhileATUBusy(UINT32 phyBase) +{ + BOOL isBusy; + UINT16 ATUOperation; + + do { + + ATUOperation = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, + MV_ATU_OPERATION); + + isBusy = (ATUOperation & MV_ATU_BUSY_MASK) == MV_ATU_IS_BUSY; + + } while(isBusy); +} + +/***************************************************************************** +* +* mv_flushATUDB - flushes ALL entries in the Address Translation Unit +* DataBase associated with phyUnit. [Since we use a single DB for +* all PHYs, this flushes the entire shared DataBase.] +* +* The current implementation flushes even more than absolutely needed -- +* it flushes all entries for all phyUnits on the same ethernet as the +* specified phyUnit. +* +* It is called only when a link failure is detected on a port that was +* previously working. In other words, when the cable is unplugged. +*/ +void +mv_flushATUDB(int phyUnit) +{ + UINT32 phyBase; + + if (!mv_validPhyId(phyUnit)) { + PRINTF("Invalid port number: %d\n", phyUnit); + return; + } + + phyBase = MV_PHYBASE(phyUnit); + + /* Wait for previous operation (if any) to complete */ + mv_waitWhileATUBusy(phyBase); + + /* Tell hardware to flush all entries */ + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION, + MV_ATU_OP_FLUSH_ALL | MV_ATU_IS_BUSY); + + mv_waitWhileATUBusy(phyBase); +} + +/***************************************************************************** +* +* mv_phyCheckStatusChange -- checks for significant changes in PHY state. +* +* A "significant change" is: +* dropped link (e.g. ethernet cable unplugged) OR +* autonegotiation completed + link (e.g. ethernet cable plugged in) +*/ +void +mv_phyCheckStatusChange(int ethUnit) +{ + int phyUnit; + UINT16 phyHwStatus; + mvPhyInfo_t *lastStatus; + int linkCount = 0; + int lostLinks = 0; + int gainedLinks = 0; + UINT32 phyBase; + UINT32 phyAddr; + + for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { + if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + lastStatus = &mvPhyInfo[phyUnit]; + phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); + + if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */ + /* See if we've lost link */ + if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) { + linkCount++; + } else { + lostLinks++; + mv_flushATUDB(phyUnit); + MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d down\n", + ethUnit, phyUnit)); + lastStatus->isPhyAlive = FALSE; + } + } else { /* last known link status was DEAD */ + /* Check for AutoNegotiation complete */ + if (MV_AUTONEG_DONE(phyHwStatus)) { + gainedLinks++; + linkCount++; + MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d up\n", + ethUnit, phyUnit)); + lastStatus->isPhyAlive = TRUE; + } + } + } + + if (linkCount == 0) { + if (lostLinks) { + /* We just lost the last link for this MAC */ + phyLinkLost(ethUnit); + } + } else { + if (gainedLinks == linkCount) { + /* We just gained our first link(s) for this MAC */ + phyLinkGained(ethUnit); + } + } +} + +#if DEBUG + +/* Define the registers of interest for a phyShow command */ +typedef struct mvRegisterTableEntry_s { + UINT32 regNum; + char *regIdString; +} mvRegisterTableEntry_t; + +mvRegisterTableEntry_t mvPhyRegisterTable[] = { + {MV_PHY_CONTROL, "PHY Control "}, + {MV_PHY_STATUS, "PHY Status "}, + {MV_PHY_ID1, "PHY Identifier 1 "}, + {MV_PHY_ID2, "PHY Identifier 2 "}, + {MV_AUTONEG_ADVERT, "Auto-Negotiation Advertisement "}, + {MV_LINK_PARTNER_ABILITY, "Link Partner Ability "}, + {MV_AUTONEG_EXPANSION, "Auto-Negotiation Expansion "}, + {MV_NEXT_PAGE_TRANSMIT, "Next Page Transmit "}, + {MV_LINK_PARTNER_NEXT_PAGE, "Link Partner Next Page "}, + {MV_PHY_SPECIFIC_CONTROL_1, "PHY-Specific Control Register 1 "}, + {MV_PHY_SPECIFIC_STATUS, "PHY-Specific Status "}, + {MV_PHY_INTERRUPT_ENABLE, "PHY Interrupt Enable "}, + {MV_PHY_INTERRUPT_STATUS, "PHY Interrupt Status "}, + {MV_PHY_INTERRUPT_PORT_SUMMARY, "PHY Interrupt Port Summary "}, + {MV_RECEIVE_ERROR_COUNTER, "Receive Error Counter "}, + {MV_LED_PARALLEL_SELECT, "LED Parallel Select "}, + {MV_LED_STREAM_SELECT_LEDS, "LED Stream Select "}, + {MV_PHY_LED_CONTROL, "PHY LED Control "}, + {MV_PHY_MANUAL_LED_OVERRIDE, "PHY Manual LED Override "}, + {MV_VCT_CONTROL, "VCT Control "}, + {MV_VCT_STATUS, "VCT Status "}, + {MV_PHY_SPECIFIC_CONTROL_2, "PHY-Specific Control Register 2 "}, +}; +int mvPhyNumRegs = sizeof(mvPhyRegisterTable) / sizeof(mvPhyRegisterTable[0]); + + +mvRegisterTableEntry_t mvSwitchPortRegisterTable[] = { + {MV_PORT_STATUS, "Port Status "}, + {MV_SWITCH_ID, "Switch ID "}, + {MV_PORT_CONTROL, "Port Control "}, + {MV_PORT_BASED_VLAN_MAP, "Port-Based VLAN Map "}, + {MV_PORT_ASSOCIATION_VECTOR, "Port Association Vector "}, + {MV_RX_COUNTER, "RX Counter "}, + {MV_TX_COUNTER, "TX Counter "}, +}; +int mvSwitchPortNumRegs = + sizeof(mvSwitchPortRegisterTable) / sizeof(mvSwitchPortRegisterTable[0]); + + +mvRegisterTableEntry_t mvSwitchGlobalRegisterTable[] = { + {MV_SWITCH_GLOBAL_STATUS, "Switch Global Status "}, + {MV_SWITCH_MAC_ADDR0, "Switch MAC Addr 0 & 1 "}, + {MV_SWITCH_MAC_ADDR2, "Switch MAC Addr 2 & 3 "}, + {MV_SWITCH_MAC_ADDR4, "Switch MAC Addr 4 & 5 "}, + {MV_SWITCH_GLOBAL_CONTROL, "Switch Global Control "}, + {MV_ATU_CONTROL, "ATU Control "}, + {MV_ATU_OPERATION, "ATU Operation "}, + {MV_ATU_DATA, "ATU Data "}, + {MV_ATU_MAC_ADDR0, "ATU MAC Addr 0 & 1 "}, + {MV_ATU_MAC_ADDR2, "ATU MAC Addr 2 & 3 "}, + {MV_ATU_MAC_ADDR4, "ATU MAC Addr 4 & 5 "}, +}; +int mvSwitchGlobalNumRegs = + sizeof(mvSwitchGlobalRegisterTable) / sizeof(mvSwitchGlobalRegisterTable[0]); + +void my_mvPhyShow(int ethUnit) +{ + int phyUnit; + for (phyUnit=0; (phyUnit < MV_PHY_MAX); phyUnit++) { + if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + mv_phyShow(phyUnit); + } +} + +/***************************************************************************** +* +* mv_phyShow - Dump the state of a PHY. +* There are two sets of registers for each phy port: +* "phy registers" and +* "switch port registers" +* We dump 'em all, plus the switch global registers. +*/ +void +mv_phyShow(int phyUnit) +{ + int i; + UINT16 value; + UINT32 phyBase; + UINT32 phyAddr; + UINT32 switchPortAddr; + + if (!mv_validPhyId(phyUnit)) { + return; + } + + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); + + printk("PHY state for PHY%d (ethmac%d, phyBase 0x%8x, phyAddr 0x%x, switchAddr 0x%x)\n", + phyUnit, + MV_ETHUNIT(phyUnit), + MV_PHYBASE(phyUnit), + MV_PHYADDR(phyUnit), + MV_SWITCH_PORT_ADDR(phyUnit)); + + printk("PHY Registers:\n"); + for (i=0; i < mvPhyNumRegs; i++) { + + value = phyRegRead(phyBase, phyAddr, mvPhyRegisterTable[i].regNum); + + printk("Reg %02d (0x%02x) %s = 0x%08x\n", + mvPhyRegisterTable[i].regNum, + mvPhyRegisterTable[i].regNum, + mvPhyRegisterTable[i].regIdString, + value); + } + + printk("Switch Port Registers:\n"); + for (i=0; i < mvSwitchPortNumRegs; i++) { + + value = phyRegRead(phyBase, switchPortAddr, + mvSwitchPortRegisterTable[i].regNum); + + printk("Reg %02d (0x%02x) %s = 0x%08x\n", + mvSwitchPortRegisterTable[i].regNum, + mvSwitchPortRegisterTable[i].regNum, + mvSwitchPortRegisterTable[i].regIdString, + value); + } + + printk("Switch Global Registers:\n"); + for (i=0; i < mvSwitchGlobalNumRegs; i++) { + + value = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, + mvSwitchGlobalRegisterTable[i].regNum); + + printk("Reg %02d (0x%02x) %s = 0x%08x\n", + mvSwitchGlobalRegisterTable[i].regNum, + mvSwitchGlobalRegisterTable[i].regNum, + mvSwitchGlobalRegisterTable[i].regIdString, + value); + } +} + +/***************************************************************************** +* +* mv_phySet - Modify the value of a PHY register (debug only). +*/ +void +mv_phySet(int phyUnit, UINT32 regnum, UINT32 value) +{ + UINT32 phyBase; + UINT32 phyAddr; + + if (mv_validPhyId(phyUnit)) { + + phyBase = MV_PHYBASE(phyUnit); + phyAddr = MV_PHYADDR(phyUnit); + + phyRegWrite(phyBase, phyAddr, regnum, value); + } +} + + +/***************************************************************************** +* +* mv_switchPortSet - Modify the value of a switch port register (debug only). +*/ +void +mv_switchPortSet(int phyUnit, UINT32 regnum, UINT32 value) +{ + UINT32 phyBase; + UINT32 switchPortAddr; + + if (mv_validPhyId(phyUnit)) { + + phyBase = MV_PHYBASE(phyUnit); + switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); + + phyRegWrite(phyBase, switchPortAddr, regnum, value); + } +} + +/***************************************************************************** +* +* mv_switchGlobalSet - Modify the value of a switch global register +* (debug only). +*/ +void +mv_switchGlobalSet(int phyUnit, UINT32 regnum, UINT32 value) +{ + UINT32 phyBase; + + if (mv_validPhyId(phyUnit)) { + + phyBase = MV_PHYBASE(phyUnit); + + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, regnum, value); + } +} + +/***************************************************************************** +* +* mv_showATUDB - Dump the contents of the Address Translation Unit DataBase +* for the PHY switch associated with the specified phy. +*/ +void +mv_showATUDB(int phyUnit) +{ + UINT32 phyBase; + UINT16 ATUData; + UINT16 ATUMac0; + UINT16 ATUMac2; + UINT16 ATUMac4; + int portVec; + int entryState; + + if (!mv_validPhyId(phyUnit)) { + printk("Invalid port number: %d\n", phyUnit); + return; + } + + phyBase = MV_PHYBASE(phyUnit); + + /* Wait for previous operation (if any) to complete */ + mv_waitWhileATUBusy(phyBase); + + /* Initialize ATU MAC to all 1's */ + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR0, 0xffff); + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR2, 0xffff); + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR4, 0xffff); + + printk(" MAC ADDRESS EntryState PortVector\n"); + + for(;;) { + /* Tell hardware to get next MAC info */ + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION, + MV_ATU_OP_GET_NEXT | MV_ATU_IS_BUSY); + + mv_waitWhileATUBusy(phyBase); + + ATUData = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_DATA); + entryState = (ATUData & MV_ENTRYSTATE_MASK) >> MV_ENTRYSTATE_SHIFT; + + if (entryState == 0) { + /* We've hit the end of the list */ + break; + } + + ATUMac0 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR0); + ATUMac2 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR2); + ATUMac4 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR4); + + portVec = (ATUData & MV_PORTVEC_MASK) >> MV_PORTVEC_SHIFT; + + printk("%02x:%02x:%02x:%02x:%02x:%02x 0x%02x 0x%02x\n", + ATUMac0 >> 8, /* MAC byte 0 */ + ATUMac0 & 0xff, /* MAC byte 1 */ + ATUMac2 >> 8, /* MAC byte 2 */ + ATUMac2 & 0xff, /* MAC byte 3 */ + ATUMac4 >> 8, /* MAC byte 4 */ + ATUMac4 & 0xff, /* MAC byte 5 */ + entryState, + portVec); + } +} + +LOCAL BOOL countingGoodFrames; + +/***************************************************************************** +* +* mv_countGoodFrames - starts counting GOOD RX/TX frames per port +*/ +void +mv_countGoodFrames(int phyUnit) +{ + UINT32 phyBase; + UINT16 globalControl; + + if (mv_validPhyId(phyUnit)) { + /* + * Guarantee that counters are cleared by + * forcing CtrMode to toggle and end on GOODFRAMES. + */ + + phyBase = MV_PHYBASE(phyUnit); + + /* Read current Switch Global Control Register */ + globalControl = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, + MV_SWITCH_GLOBAL_CONTROL); + + /* Set CtrMode to count BAD frames */ + globalControl = ((globalControl & ~MV_CTRMODE_MASK) | + MV_CTRMODE_BADFRAMES); + + /* Push new value out to hardware */ + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, + MV_SWITCH_GLOBAL_CONTROL, globalControl); + + /* Now toggle CtrMode to count GOOD frames */ + globalControl = ((globalControl & ~MV_CTRMODE_MASK) | + MV_CTRMODE_GOODFRAMES); + + /* Push new value out to hardware */ + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, + MV_SWITCH_GLOBAL_CONTROL, globalControl); + + countingGoodFrames = TRUE; + } +} + +/***************************************************************************** +* +* mv_countBadFrames - starts counting BAD RX/TX frames per port +*/ +void +mv_countBadFrames(int phyUnit) +{ + UINT32 phyBase; + UINT16 globalControl; + + if (mv_validPhyId(phyUnit)) { + /* + * Guarantee that counters are cleared by + * forcing CtrMode to toggle and end on BADFRAMES. + */ + + phyBase = MV_PHYBASE(phyUnit); + + /* Read current Switch Global Control Register */ + globalControl = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, + MV_SWITCH_GLOBAL_CONTROL); + + /* Set CtrMode to count GOOD frames */ + globalControl = ((globalControl & ~MV_CTRMODE_MASK) | + MV_CTRMODE_GOODFRAMES); + + /* Push new value out to hardware */ + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, + MV_SWITCH_GLOBAL_CONTROL, globalControl); + + /* Now toggle CtrMode to count BAD frames */ + globalControl = ((globalControl & ~MV_CTRMODE_MASK) | + MV_CTRMODE_BADFRAMES); + + /* Push new value out to hardware */ + phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, + MV_SWITCH_GLOBAL_CONTROL, globalControl); + + countingGoodFrames = FALSE; + } +} + +/***************************************************************************** +* +* mv_showFrameCounts - shows current GOOD/BAD Frame counts +*/ +void +mv_showFrameCounts(int phyUnit) +{ + UINT16 rxCounter; + UINT16 txCounter; + UINT32 phyBase; + UINT32 switchPortAddr; + + if (!mv_validPhyId(phyUnit)) { + return; + } + + phyBase = MV_PHYBASE(phyUnit); + switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit); + + rxCounter = phyRegRead(phyBase, switchPortAddr, MV_RX_COUNTER); + + txCounter = phyRegRead(phyBase, switchPortAddr, MV_TX_COUNTER); + + printk("port%d %s frames: receive: %05d transmit: %05d\n", + phyUnit, + (countingGoodFrames ? "good" : "error"), + rxCounter, + txCounter); +} +#endif diff -urN linux-mips-orig/drivers/net/ath/mvPhy.h linux-mips-new/drivers/net/ath/mvPhy.h --- linux-mips-orig/drivers/net/ath/mvPhy.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/mvPhy.h 2005-12-31 12:33:57.727530616 +0000 @@ -0,0 +1,162 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * mvPhy.h - definitions for the ethernet PHY -- Marvell 88E6060 + * All definitions in this file are operating system independent! + */ + +#ifndef MVPHY_H +#define MVPHY_H + +/*****************/ +/* PHY Registers */ +/*****************/ +#define MV_PHY_CONTROL 0 +#define MV_PHY_STATUS 1 +#define MV_PHY_ID1 2 +#define MV_PHY_ID2 3 +#define MV_AUTONEG_ADVERT 4 +#define MV_LINK_PARTNER_ABILITY 5 +#define MV_AUTONEG_EXPANSION 6 +#define MV_NEXT_PAGE_TRANSMIT 7 +#define MV_LINK_PARTNER_NEXT_PAGE 8 +#define MV_PHY_SPECIFIC_CONTROL_1 16 +#define MV_PHY_SPECIFIC_STATUS 17 +#define MV_PHY_INTERRUPT_ENABLE 18 +#define MV_PHY_INTERRUPT_STATUS 19 +#define MV_PHY_INTERRUPT_PORT_SUMMARY 20 +#define MV_RECEIVE_ERROR_COUNTER 21 +#define MV_LED_PARALLEL_SELECT 22 +#define MV_LED_STREAM_SELECT_LEDS 23 +#define MV_PHY_LED_CONTROL 24 +#define MV_PHY_MANUAL_LED_OVERRIDE 25 + +#define MV_VCT_CONTROL 26 +#define MV_VCT_STATUS 27 +#define MV_PHY_SPECIFIC_CONTROL_2 28 + +/* MV_PHY_CONTROL fields */ +#define MV_CTRL_SOFTWARE_RESET 0x8000 +#define MV_CTRL_AUTONEGOTIATION_ENABLE 0x1000 +#define MV_CTRL_FULL_DUPLEX 0x0100 +#define MV_CTRL_100_MBPS 0x2000 + +/* MV_PHY_ID1 fields */ +#define MV_PHY_ID1_EXPECTATION 0x0141 /* OUI >> 6 */ + +/* MV_PHY_ID2 fields */ +#define MV_OUI_LSB_MASK 0xfc00 +#define MV_OUI_LSB_EXPECTATION 0x0c00 +#define MV_OUI_LSB_SHIFT 10 +#define MV_MODEL_NUM_MASK 0x03f0 +#define MV_MODEL_NUM_SHIFT 4 +#define MV_REV_NUM_MASK 0x000f +#define MV_REV_NUM_SHIFT 0 + +/* MV_PHY_SPECIFIC_STATUS fields */ +#define MV_STATUS_RESOLVED_SPEED_100 0x4000 +#define MV_STATUS_RESOLVED_DUPLEX_FULL 0x2000 +#define MV_STATUS_RESOLVED 0x0800 +#define MV_STATUS_REAL_TIME_LINK_UP 0x0400 + +/* Check if autonegotiation is complete and link is up */ +#define MV_AUTONEG_DONE(mv_phy_specific_status) \ + (((mv_phy_specific_status) & \ + (MV_STATUS_RESOLVED | MV_STATUS_REAL_TIME_LINK_UP)) == \ + (MV_STATUS_RESOLVED | MV_STATUS_REAL_TIME_LINK_UP)) + + +/*************************/ +/* Switch Port Registers */ +/*************************/ +#define MV_PORT_STATUS 0 +#define MV_SWITCH_ID 3 +#define MV_PORT_CONTROL 4 +#define MV_PORT_BASED_VLAN_MAP 6 +#define MV_PORT_ASSOCIATION_VECTOR 11 +#define MV_RX_COUNTER 16 +#define MV_TX_COUNTER 17 + +/* MV_SWITCH_ID fields */ +#define MV_SWITCH_ID_DEV_MASK 0xfff0 +#define MV_SWITCH_ID_DEV_EXPECTATION 0x0600 +#define MV_SWITCH_ID_DEV_SHIFT 4 +#define MV_SWITCH_ID_REV_MASK 0x000f +#define MV_SWITCH_ID_REV_SHIFT 0 + +/* MV_PORT_CONTROL fields */ +#define MV_PORT_CONTROL_PORT_STATE_MASK 0x0003 +#define MV_PORT_CONTROL_PORT_STATE_DISABLED 0x0000 +#define MV_PORT_CONTROL_PORT_STATE_FORWARDING 0x0003 + +#define MV_PORT_CONTROL_EGRESS_MODE 0x0100 /* Receive */ +#define MV_PORT_CONTROL_INGRESS_TRAILER 0x4000 /* Transmit */ + +#define MV_EGRESS_TRAILER_VALID 0x80 +#define MV_INGRESS_TRAILER_OVERRIDE 0x80 + +#define MV_PHY_TRAILER_SIZE 4 + + +/***************************/ +/* Switch Global Registers */ +/***************************/ +#define MV_SWITCH_GLOBAL_STATUS 0 +#define MV_SWITCH_MAC_ADDR0 1 +#define MV_SWITCH_MAC_ADDR2 2 +#define MV_SWITCH_MAC_ADDR4 3 +#define MV_SWITCH_GLOBAL_CONTROL 4 +#define MV_ATU_CONTROL 10 +#define MV_ATU_OPERATION 11 +#define MV_ATU_DATA 12 +#define MV_ATU_MAC_ADDR0 13 +#define MV_ATU_MAC_ADDR2 14 +#define MV_ATU_MAC_ADDR4 15 + +/* MV_SWITCH_GLOBAL_STATUS fields */ +#define MV_SWITCH_STATUS_READY_MASK 0x0800 + +/* MV_SWITCH_GLOBAL_CONTROL fields */ +#define MV_CTRMODE_MASK 0x0100 +#define MV_CTRMODE_GOODFRAMES 0x0000 +#define MV_CTRMODE_BADFRAMES 0x0100 + +/* MV_ATU_CONTROL fields */ +#define MV_ATUCTRL_ATU_SIZE_MASK 0x3000 +#define MV_ATUCTRL_ATU_SIZE_SHIFT 12 +#define MV_ATUCTRL_ATU_SIZE_DEFAULT 2 /* 1024 entry database */ +#define MV_ATUCTRL_AGE_TIME_MASK 0x0ff0 +#define MV_ATUCTRL_AGE_TIME_SHIFT 4 +#define MV_ATUCTRL_AGE_TIME_DEFAULT 19 /* 19 * 16 = 304 seconds */ + +/* MV_ATU_OPERATION fields */ +#define MV_ATU_BUSY_MASK 0x8000 +#define MV_ATU_IS_BUSY 0x8000 +#define MV_ATU_IS_FREE 0x0000 +#define MV_ATU_OP_MASK 0x7000 +#define MV_ATU_OP_FLUSH_ALL 0x1000 +#define MV_ATU_OP_GET_NEXT 0x4000 + +/* MV_ATU_DATA fields */ +#define MV_ENTRYPRI_MASK 0xc000 +#define MV_ENTRYPRI_SHIFT 14 +#define MV_PORTVEC_MASK 0x03f0 +#define MV_PORTVEC_SHIFT 4 +#define MV_ENTRYSTATE_MASK 0x000f +#define MV_ENTRYSTATE_SHIFT 0 + +/* PHY Address for the switch itself */ +#define MV_SWITCH_GLOBAL_ADDR 0x1f + +BOOL mv_phySetup(int ethUnit, UINT32 phyBase); +void mv_phyCheckStatusChange(int ethUnit); +BOOL mv_phyIsSpeed100(int ethUnit); +int mv_phyIsFullDuplex(int ethUnit); + +#endif /* MVPHY_H */ diff -urN linux-mips-orig/drivers/net/ath/rtPhy.c linux-mips-new/drivers/net/ath/rtPhy.c --- linux-mips-orig/drivers/net/ath/rtPhy.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-mips-new/drivers/net/ath/rtPhy.c 2005-12-31 12:33:57.727530616 +0000 @@ -0,0 +1,272 @@ +/* + * 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 © 2003 Atheros Communications, Inc., All Rights Reserved. + */ + +/* + * Manage the ethernet PHY. + * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL, + * and compatible PHYs, such as the Kendin KS8721B. + * All definitions in this file are operating system independent! + */ + +#if defined(linux) +#include +#include +#include +#include +#include + +#include "ar531xlnx.h" +#endif + +#if defined(__ECOS) +#include "ae531xecos.h" +#endif + + +#include "ae531xmac.h" +#include "ae531xreg.h" +#include "rtPhy.h" + +#if /* DEBUG */ 1 +#define RT_DEBUG_ERROR 0x00000001 +#define RT_DEBUG_PHYSETUP 0x00000002 +#define RT_DEBUG_PHYCHANGE 0x00000004 + +int rtPhyDebug = RT_DEBUG_ERROR; + +#define RT_PRINT(FLG, X) \ +{ \ + if (rtPhyDebug & (FLG)) { \ + DEBUG_PRINTF X; \ + } \ +} +#else +#define RT_PRINT(FLG, X) +#endif + +/* + * Track per-PHY port information. + */ +typedef struct { + BOOL phyAlive; /* last known state of link */ + UINT32 phyBase; + UINT32 phyAddr; +} rtPhyInfo_t; + +#define ETH_PHY_ADDR 1 + +/* + * This table defines the mapping from phy units to + * per-PHY information. + * + * This table is somewhat board-dependent. + */ +rtPhyInfo_t rtPhyInfo[] = { + {phyAlive: FALSE, /* PHY 0 */ + phyBase: 0, /* filled in by rt_phySetup */ + phyAddr: ETH_PHY_ADDR}, + + {phyAlive: FALSE, /* PHY 1 */ + phyBase: 0, /* filled in by rt_phySetup */ + phyAddr: ETH_PHY_ADDR} +}; + +/* Convert from phy unit# to (phyBase, phyAddr) pair */ +#define RT_PHYBASE(phyUnit) (rtPhyInfo[phyUnit].phyBase) +#define RT_PHYADDR(phyUnit) (rtPhyInfo[phyUnit].phyAddr) + + +/****************************************************************************** +* +* rt_phySetup - reset and setup the PHY associated with +* the specified MAC unit number. +* +* Resets the associated PHY port. +* +* RETURNS: +* TRUE --> associated PHY is alive +* FALSE --> no LINKs on this ethernet unit +*/ + +BOOL +rt_phySetup(int ethUnit, UINT32 phyBase) +{ + BOOL linkAlive = FALSE; + UINT32 phyAddr; + + RT_PHYBASE(ethUnit) = phyBase; + + phyAddr = RT_PHYADDR(ethUnit); + + /* Reset phy */ + phyRegWrite(phyBase, phyAddr, GEN_ctl, PHY_SW_RST | AUTONEGENA); + + sysMsDelay(1500); + + return linkAlive; +} + +/****************************************************************************** +* +* rt_phyIsDuplexFull - Determines whether the phy ports associated with the +* specified device are FULL or HALF duplex. +* +* RETURNS: +* 1 --> FULL +* 0 --> HALF +*/ +int +rt_phyIsFullDuplex(int ethUnit) +{ + UINT16 phyCtl; + UINT32 phyBase; + UINT32 phyAddr; + + phyBase = RT_PHYBASE(ethUnit); + phyAddr = RT_PHYADDR(ethUnit); + + phyCtl = phyRegRead(phyBase, phyAddr, GEN_ctl); + + if (phyCtl & DUPLEX) { + return 1; + } else { + return 0; + } +} + +/****************************************************************************** +* +* rt_phyIsSpeed100 - Determines the speed of phy ports associated with the +* specified device. +* +* RETURNS: +* TRUE --> 100Mbit +* FALSE --> 10Mbit +*/ +BOOL +rt_phyIsSpeed100(int phyUnit) +{ + UINT16 phyLpa; + UINT32 phyBase; + UINT32 phyAddr; + + phyBase = RT_PHYBASE(phyUnit); + phyAddr = RT_PHYADDR(phyUnit); + + phyLpa = phyRegRead(phyBase, phyAddr, AN_lpa); + + if (phyLpa & (LPA_TXFD | LPA_TX)) { + return TRUE; + } else { + return FALSE; + } +} + +/***************************************************************************** +* +* rt_phyCheckStatusChange -- checks for significant changes in PHY state. +* +* A "significant change" is: +* dropped link (e.g. ethernet cable unplugged) OR +* autonegotiation completed + link (e.g. ethernet cable plugged in) +* +* On AR5311, there is a 1-to-1 mapping of ethernet units to PHYs. +* When a PHY is plugged in, phyLinkGained is called. +* When a PHY is unplugged, phyLinkLost is called. +*/ +void +rt_phyCheckStatusChange(int ethUnit) +{ + UINT16 phyHwStatus; + rtPhyInfo_t *lastStatus = &rtPhyInfo[ethUnit]; + UINT32 phyBase; + UINT32 phyAddr; + + phyBase = RT_PHYBASE(ethUnit); + phyAddr = RT_PHYADDR(ethUnit); + + phyHwStatus = phyRegRead(phyBase, phyAddr, GEN_sts); + + if (lastStatus->phyAlive) { /* last known status was ALIVE */ + /* See if we've lost link */ + if (!(phyHwStatus & LINK)) { + RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link down\n", ethUnit)); + lastStatus->phyAlive = FALSE; + phyLinkLost(ethUnit); + } + } else { /* last known status was DEAD */ + /* Check for AN complete */ + if ((phyHwStatus & (AUTOCMPLT | LINK)) == (AUTOCMPLT | LINK)) { + RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link up\n", ethUnit)); + lastStatus->phyAlive = TRUE; + phyLinkGained(ethUnit); + } + } +} + +#if DEBUG + +/* Define the PHY registers of interest for a phyShow command */ +struct rtRegisterTable_s { + UINT32 regNum; + char *regIdString; +} rtRegisterTable[] = +{ + {GEN_ctl, "Basic Mode Control (GEN_ctl) "}, + {GEN_sts, "Basic Mode Status (GEN_sts) "}, + {GEN_id_hi, "PHY Identifier 1 (GET_id_hi) "}, + {GEN_id_lo, "PHY Identifier 2 (GET_id_lo) "}, + {AN_adv, "Auto-Neg Advertisement (AN_adv) "}, + {AN_lpa, "Auto-Neg Link Partner Ability "}, + {AN_exp, "Auto-Neg Expansion "}, +}; + +int rtNumRegs = sizeof(rtRegisterTable) / sizeof(rtRegisterTable[0]); + +/* + * Dump the state of a PHY. + */ +void +rt_phyShow(int phyUnit) +{ + int i; + UINT16 value; + UINT32 phyBase; + UINT32 phyAddr; + + phyBase = RT_PHYBASE(phyUnit); + phyAddr = RT_PHYADDR(phyUnit); + + printf("PHY state for ethphy%d\n", phyUnit); + + for (i=0; i