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