atheros: add support for linux kernel v3.8
This builds and boots. Because of the function pointer indirection (e.g. mtd_info's read function pointer is assigned to spiflash_read), it is difficult for me to understand where the calls are coming from (could be anywhere, conditionally pointing at spiflash versions), so I punted and used the renamed function pointers (_erase, _read, _write). If someone knows better what to do, please fix. Cleaned up other sundry kernel tracking issues like get_phy_id and __devinit,etc. [juhosg: don't switch to that yet] Signed-off-by: Russell Senior <russell@personaltelco.net> Signed-off-by: Gabor Juhos <juhosg@openwrt.org> SVN-Revision: 35727
This commit is contained in:
		
							
								
								
									
										124
									
								
								target/linux/atheros/config-3.8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								target/linux/atheros/config-3.8
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | |||||||
|  | CONFIG_ADM6996_PHY=y | ||||||
|  | CONFIG_AR8216_PHY=y | ||||||
|  | CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y | ||||||
|  | CONFIG_ARCH_DISCARD_MEMBLOCK=y | ||||||
|  | CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y | ||||||
|  | CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y | ||||||
|  | CONFIG_ARCH_HIBERNATION_POSSIBLE=y | ||||||
|  | CONFIG_ARCH_REQUIRE_GPIOLIB=y | ||||||
|  | CONFIG_ARCH_SUSPEND_POSSIBLE=y | ||||||
|  | CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y | ||||||
|  | CONFIG_ATHEROS_AR2315=y | ||||||
|  | CONFIG_ATHEROS_AR2315_PCI=y | ||||||
|  | CONFIG_ATHEROS_AR231X=y | ||||||
|  | CONFIG_ATHEROS_AR5312=y | ||||||
|  | CONFIG_ATHEROS_WDT=y | ||||||
|  | CONFIG_CC_OPTIMIZE_FOR_SIZE=y | ||||||
|  | CONFIG_CEVT_R4K=y | ||||||
|  | CONFIG_CEVT_R4K_LIB=y | ||||||
|  | CONFIG_CMDLINE="console=ttyS0,9600 rootfstype=squashfs,jffs2" | ||||||
|  | CONFIG_CMDLINE_BOOL=y | ||||||
|  | # CONFIG_CMDLINE_OVERRIDE is not set | ||||||
|  | CONFIG_CPU_BIG_ENDIAN=y | ||||||
|  | CONFIG_CPU_GENERIC_DUMP_TLB=y | ||||||
|  | CONFIG_CPU_HAS_PREFETCH=y | ||||||
|  | CONFIG_CPU_HAS_SYNC=y | ||||||
|  | CONFIG_CPU_MIPS32=y | ||||||
|  | CONFIG_CPU_MIPS32_R1=y | ||||||
|  | CONFIG_CPU_MIPSR1=y | ||||||
|  | CONFIG_CPU_R4K_CACHE_TLB=y | ||||||
|  | CONFIG_CPU_R4K_FPU=y | ||||||
|  | CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y | ||||||
|  | CONFIG_CPU_SUPPORTS_HIGHMEM=y | ||||||
|  | CONFIG_CSRC_R4K=y | ||||||
|  | CONFIG_CSRC_R4K_LIB=y | ||||||
|  | CONFIG_DECOMPRESS_LZMA=y | ||||||
|  | CONFIG_DMA_NONCOHERENT=y | ||||||
|  | CONFIG_EARLY_PRINTK=y | ||||||
|  | CONFIG_ETHERNET_PACKET_MANGLE=y | ||||||
|  | CONFIG_GENERIC_ATOMIC64=y | ||||||
|  | CONFIG_GENERIC_CLOCKEVENTS=y | ||||||
|  | CONFIG_GENERIC_CLOCKEVENTS_BUILD=y | ||||||
|  | CONFIG_GENERIC_CMOS_UPDATE=y | ||||||
|  | CONFIG_GENERIC_GPIO=y | ||||||
|  | CONFIG_GENERIC_IO=y | ||||||
|  | CONFIG_GENERIC_IRQ_SHOW=y | ||||||
|  | CONFIG_GENERIC_PCI_IOMAP=y | ||||||
|  | CONFIG_GENERIC_SMP_IDLE_THREAD=y | ||||||
|  | CONFIG_GPIOLIB=y | ||||||
|  | CONFIG_GPIO_SYSFS=y | ||||||
|  | # CONFIG_HAMRADIO is not set | ||||||
|  | CONFIG_HARDWARE_WATCHPOINTS=y | ||||||
|  | CONFIG_HAS_DMA=y | ||||||
|  | CONFIG_HAS_IOMEM=y | ||||||
|  | CONFIG_HAS_IOPORT=y | ||||||
|  | CONFIG_HAVE_ARCH_JUMP_LABEL=y | ||||||
|  | CONFIG_HAVE_ARCH_KGDB=y | ||||||
|  | CONFIG_HAVE_C_RECORDMCOUNT=y | ||||||
|  | CONFIG_HAVE_DEBUG_KMEMLEAK=y | ||||||
|  | CONFIG_HAVE_DMA_API_DEBUG=y | ||||||
|  | CONFIG_HAVE_DMA_ATTRS=y | ||||||
|  | CONFIG_HAVE_DYNAMIC_FTRACE=y | ||||||
|  | CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y | ||||||
|  | CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y | ||||||
|  | CONFIG_HAVE_FUNCTION_TRACER=y | ||||||
|  | CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y | ||||||
|  | CONFIG_HAVE_GENERIC_DMA_COHERENT=y | ||||||
|  | CONFIG_HAVE_GENERIC_HARDIRQS=y | ||||||
|  | CONFIG_HAVE_IDE=y | ||||||
|  | CONFIG_HAVE_IRQ_WORK=y | ||||||
|  | CONFIG_HAVE_MEMBLOCK=y | ||||||
|  | CONFIG_HAVE_MEMBLOCK_NODE_MAP=y | ||||||
|  | CONFIG_HAVE_MOD_ARCH_SPECIFIC=y | ||||||
|  | CONFIG_HAVE_OPROFILE=y | ||||||
|  | CONFIG_HAVE_PERF_EVENTS=y | ||||||
|  | CONFIG_HW_HAS_PCI=y | ||||||
|  | CONFIG_HW_RANDOM=y | ||||||
|  | CONFIG_IMAGE_CMDLINE_HACK=y | ||||||
|  | CONFIG_INITRAMFS_SOURCE="" | ||||||
|  | CONFIG_IP17XX_PHY=y | ||||||
|  | CONFIG_IRQ_CPU=y | ||||||
|  | CONFIG_IRQ_FORCED_THREADING=y | ||||||
|  | CONFIG_LEDS_GPIO=y | ||||||
|  | CONFIG_MDIO_BOARDINFO=y | ||||||
|  | CONFIG_MIPS=y | ||||||
|  | CONFIG_MIPS_L1_CACHE_SHIFT=5 | ||||||
|  | # CONFIG_MIPS_MACHINE is not set | ||||||
|  | CONFIG_MIPS_MT_DISABLED=y | ||||||
|  | # CONFIG_MIPS_SEAD3 is not set | ||||||
|  | CONFIG_MODULES_USE_ELF_REL=y | ||||||
|  | CONFIG_MTD_AR2315=y | ||||||
|  | CONFIG_MTD_CFI_ADV_OPTIONS=y | ||||||
|  | # CONFIG_MTD_CFI_GEOMETRY is not set | ||||||
|  | # CONFIG_MTD_CFI_INTELEXT is not set | ||||||
|  | CONFIG_MTD_MYLOADER_PARTS=y | ||||||
|  | CONFIG_MTD_PHYSMAP=y | ||||||
|  | CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3 | ||||||
|  | CONFIG_MTD_REDBOOT_PARTS=y | ||||||
|  | CONFIG_MVSWITCH_PHY=y | ||||||
|  | CONFIG_NEED_DMA_MAP_STATE=y | ||||||
|  | CONFIG_NEED_PER_CPU_KM=y | ||||||
|  | CONFIG_NET_VENDOR_AR231X=y | ||||||
|  | CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y | ||||||
|  | CONFIG_PAGEFLAGS_EXTENDED=y | ||||||
|  | CONFIG_PCI=y | ||||||
|  | CONFIG_PCI_DISABLE_COMMON_QUIRKS=y | ||||||
|  | CONFIG_PCI_DOMAINS=y | ||||||
|  | CONFIG_PERF_USE_VMALLOC=y | ||||||
|  | CONFIG_PHYLIB=y | ||||||
|  | # CONFIG_PREEMPT_RCU is not set | ||||||
|  | # CONFIG_SCSI_DMA is not set | ||||||
|  | CONFIG_SERIAL_8250_NR_UARTS=1 | ||||||
|  | CONFIG_SERIAL_8250_RUNTIME_UARTS=1 | ||||||
|  | # CONFIG_SWAP is not set | ||||||
|  | CONFIG_SWCONFIG=y | ||||||
|  | CONFIG_SYS_HAS_CPU_MIPS32_R1=y | ||||||
|  | CONFIG_SYS_HAS_EARLY_PRINTK=y | ||||||
|  | CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y | ||||||
|  | CONFIG_SYS_SUPPORTS_ARBIT_HZ=y | ||||||
|  | CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y | ||||||
|  | CONFIG_TICK_CPU_ACCOUNTING=y | ||||||
|  | CONFIG_UIDGID_CONVERTED=y | ||||||
|  | CONFIG_USB_ARCH_HAS_XHCI=y | ||||||
|  | CONFIG_USB_SUPPORT=y | ||||||
|  | CONFIG_ZONE_DMA_FLAG=0 | ||||||
| @@ -0,0 +1,39 @@ | |||||||
|  | Fix the usage of get_c0_compare_int: override cp0_compare_irq if the returned | ||||||
|  | value is in the MIPS CPU IRQ range to ensure that c0_compare_int_usable() | ||||||
|  | still works. | ||||||
|  |  | ||||||
|  | Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||||
|  |  | ||||||
|  | --- a/arch/mips/kernel/cevt-r4k.c | ||||||
|  | +++ b/arch/mips/kernel/cevt-r4k.c | ||||||
|  | @@ -168,20 +168,23 @@ int __cpuinit r4k_clockevent_init(void) | ||||||
|  |  	struct clock_event_device *cd; | ||||||
|  |  	unsigned int irq; | ||||||
|  |   | ||||||
|  | -	if (!cpu_has_counter || !mips_hpt_frequency) | ||||||
|  | -		return -ENXIO; | ||||||
|  | - | ||||||
|  | -	if (!c0_compare_int_usable()) | ||||||
|  | -		return -ENXIO; | ||||||
|  | - | ||||||
|  |  	/* | ||||||
|  |  	 * With vectored interrupts things are getting platform specific. | ||||||
|  |  	 * get_c0_compare_int is a hook to allow a platform to return the | ||||||
|  |  	 * interrupt number of it's liking. | ||||||
|  |  	 */ | ||||||
|  |  	irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; | ||||||
|  | -	if (get_c0_compare_int) | ||||||
|  | +	if (get_c0_compare_int) { | ||||||
|  |  		irq = get_c0_compare_int(); | ||||||
|  | +		if ((irq >= MIPS_CPU_IRQ_BASE) && (irq < MIPS_CPU_IRQ_BASE + 8)) | ||||||
|  | +			cp0_compare_irq = irq - MIPS_CPU_IRQ_BASE; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (!cpu_has_counter || !mips_hpt_frequency) | ||||||
|  | +		return -ENXIO; | ||||||
|  | + | ||||||
|  | +	if (!c0_compare_int_usable()) | ||||||
|  | +		return -ENXIO; | ||||||
|  |   | ||||||
|  |  	cd = &per_cpu(mips_clockevent_device, cpu); | ||||||
|  |   | ||||||
							
								
								
									
										3160
									
								
								target/linux/atheros/patches-3.8/100-board.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3160
									
								
								target/linux/atheros/patches-3.8/100-board.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | --- /dev/null | ||||||
|  | +++ b/arch/mips/ar231x/early_printk.c | ||||||
|  | @@ -0,0 +1,44 @@ | ||||||
|  | +/* | ||||||
|  | + * 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) 2010 Gabor Juhos <juhosg@openwrt.org> | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/mm.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/serial_reg.h> | ||||||
|  | +#include <asm/addrspace.h> | ||||||
|  | + | ||||||
|  | +#include <asm/mach-ar231x/ar2315_regs.h> | ||||||
|  | +#include <asm/mach-ar231x/ar5312_regs.h> | ||||||
|  | +#include "devices.h" | ||||||
|  | + | ||||||
|  | +static inline void prom_uart_wr(void __iomem *base, unsigned reg, | ||||||
|  | +				unsigned char ch) | ||||||
|  | +{ | ||||||
|  | +	__raw_writeb(ch, base + 4 * reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline unsigned char prom_uart_rr(void __iomem *base, unsigned reg) | ||||||
|  | +{ | ||||||
|  | +	return __raw_readb(base + 4 * reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void prom_putchar(unsigned char ch) | ||||||
|  | +{ | ||||||
|  | +	static void __iomem *base; | ||||||
|  | + | ||||||
|  | +	if (unlikely(base == NULL)) { | ||||||
|  | +		if (is_2315()) | ||||||
|  | +			base = (void __iomem *)(KSEG1ADDR(AR2315_UART0)); | ||||||
|  | +		else | ||||||
|  | +			base = (void __iomem *)(KSEG1ADDR(AR531X_UART0)); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0); | ||||||
|  | +	prom_uart_wr(base, UART_TX, ch); | ||||||
|  | +	while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | --- a/arch/mips/ar231x/Makefile | ||||||
|  | +++ b/arch/mips/ar231x/Makefile | ||||||
|  | @@ -9,5 +9,8 @@ | ||||||
|  |  # | ||||||
|  |   | ||||||
|  |  obj-y += board.o prom.o devices.o | ||||||
|  | + | ||||||
|  | +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||||||
|  | + | ||||||
|  |  obj-$(CONFIG_ATHEROS_AR5312) += ar5312.o | ||||||
|  |  obj-$(CONFIG_ATHEROS_AR2315) += ar2315.o | ||||||
|  | --- a/arch/mips/Kconfig | ||||||
|  | +++ b/arch/mips/Kconfig | ||||||
|  | @@ -130,6 +130,7 @@ config ATHEROS_AR231X | ||||||
|  |  	select SYS_SUPPORTS_BIG_ENDIAN | ||||||
|  |  	select SYS_SUPPORTS_32BIT_KERNEL | ||||||
|  |  	select ARCH_REQUIRE_GPIOLIB | ||||||
|  | +	select SYS_HAS_EARLY_PRINTK | ||||||
|  |  	help | ||||||
|  |  	  Support for AR231x and AR531x based boards | ||||||
|  |   | ||||||
							
								
								
									
										294
									
								
								target/linux/atheros/patches-3.8/105-ar2315_pci.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								target/linux/atheros/patches-3.8/105-ar2315_pci.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,294 @@ | |||||||
|  | --- a/arch/mips/ar231x/Makefile | ||||||
|  | +++ b/arch/mips/ar231x/Makefile | ||||||
|  | @@ -14,3 +14,4 @@ obj-$(CONFIG_EARLY_PRINTK) += early_prin | ||||||
|  |   | ||||||
|  |  obj-$(CONFIG_ATHEROS_AR5312) += ar5312.o | ||||||
|  |  obj-$(CONFIG_ATHEROS_AR2315) += ar2315.o | ||||||
|  | +obj-$(CONFIG_ATHEROS_AR2315_PCI) += pci.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/arch/mips/ar231x/pci.c | ||||||
|  | @@ -0,0 +1,230 @@ | ||||||
|  | +/* | ||||||
|  | + * This program is free software; you can redistribute it and/or | ||||||
|  | + * modify it under the terms of the GNU General Public License | ||||||
|  | + * as published by the Free Software Foundation; either version 2 | ||||||
|  | + * of the License, or (at your option) any later version. | ||||||
|  | + * | ||||||
|  | + * This program is distributed in the hope that it will be useful, | ||||||
|  | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | + * GNU General Public License for more details. | ||||||
|  | + * | ||||||
|  | + * You should have received a copy of the GNU General Public License | ||||||
|  | + * along with this program; if not, write to the Free Software | ||||||
|  | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/types.h> | ||||||
|  | +#include <linux/pci.h> | ||||||
|  | +#include <linux/kernel.h> | ||||||
|  | +#include <linux/init.h> | ||||||
|  | +#include <linux/mm.h> | ||||||
|  | +#include <linux/spinlock.h> | ||||||
|  | +#include <linux/delay.h> | ||||||
|  | +#include <linux/irq.h> | ||||||
|  | +#include <asm/bootinfo.h> | ||||||
|  | +#include <asm/paccess.h> | ||||||
|  | +#include <asm/irq_cpu.h> | ||||||
|  | +#include <asm/io.h> | ||||||
|  | +#include <ar231x_platform.h> | ||||||
|  | +#include <ar231x.h> | ||||||
|  | +#include <ar2315_regs.h> | ||||||
|  | +#include "devices.h" | ||||||
|  | + | ||||||
|  | +#define AR531X_MEM_BASE    0x80800000UL | ||||||
|  | +#define AR531X_MEM_SIZE    0x00ffffffUL | ||||||
|  | +#define AR531X_IO_SIZE     0x00007fffUL | ||||||
|  | + | ||||||
|  | +static unsigned long configspace; | ||||||
|  | + | ||||||
|  | +static int config_access(int devfn, int where, int size, u32 *ptr, bool write) | ||||||
|  | +{ | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	int func = PCI_FUNC(devfn); | ||||||
|  | +	int dev = PCI_SLOT(devfn); | ||||||
|  | +	u32 value = 0; | ||||||
|  | +	int err = 0; | ||||||
|  | +	u32 addr; | ||||||
|  | + | ||||||
|  | +	if (((dev != 0) && (dev != 3)) || (func > 2)) | ||||||
|  | +		return PCIBIOS_DEVICE_NOT_FOUND; | ||||||
|  | + | ||||||
|  | +	/* Select Configuration access */ | ||||||
|  | +	local_irq_save(flags); | ||||||
|  | +	ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, 0, AR2315_PCIMISC_CFG_SEL); | ||||||
|  | +	mb(); | ||||||
|  | + | ||||||
|  | +	addr = (u32) configspace + (1 << (13 + dev)) + (func << 8) + where; | ||||||
|  | +	if (size == 1) | ||||||
|  | +		addr ^= 0x3; | ||||||
|  | +	else if (size == 2) | ||||||
|  | +		addr ^= 0x2; | ||||||
|  | + | ||||||
|  | +	if (write) { | ||||||
|  | +		value = *ptr; | ||||||
|  | +		if (size == 1) | ||||||
|  | +			err = put_dbe(value, (u8 *) addr); | ||||||
|  | +		else if (size == 2) | ||||||
|  | +			err = put_dbe(value, (u16 *) addr); | ||||||
|  | +		else if (size == 4) | ||||||
|  | +			err = put_dbe(value, (u32 *) addr); | ||||||
|  | +	} else { | ||||||
|  | +		if (size == 1) | ||||||
|  | +			err = get_dbe(value, (u8 *) addr); | ||||||
|  | +		else if (size == 2) | ||||||
|  | +			err = get_dbe(value, (u16 *) addr); | ||||||
|  | +		else if (size == 4) | ||||||
|  | +			err = get_dbe(value, (u32 *) addr); | ||||||
|  | +		if (err) | ||||||
|  | +			*ptr = 0xffffffff; | ||||||
|  | +		else | ||||||
|  | +			*ptr = value; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* Select Memory access */ | ||||||
|  | +	ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_CFG_SEL, 0); | ||||||
|  | +	local_irq_restore(flags); | ||||||
|  | + | ||||||
|  | +	return (err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ar231x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * value) | ||||||
|  | +{ | ||||||
|  | +	return config_access(devfn, where, size, value, 0); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ar231x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) | ||||||
|  | +{ | ||||||
|  | +	return config_access(devfn, where, size, &value, 1); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +struct pci_ops ar231x_pci_ops = { | ||||||
|  | +	.read	= ar231x_pci_read, | ||||||
|  | +	.write	= ar231x_pci_write, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static struct resource ar231x_mem_resource = { | ||||||
|  | +	.name	= "AR531x PCI MEM", | ||||||
|  | +	.start	= AR531X_MEM_BASE, | ||||||
|  | +	.end	= AR531X_MEM_BASE + AR531X_MEM_SIZE - AR531X_IO_SIZE - 1 + 0x4000000, | ||||||
|  | +	.flags	= IORESOURCE_MEM, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static struct resource ar231x_io_resource = { | ||||||
|  | +	.name	= "AR531x PCI I/O", | ||||||
|  | +	.start	= AR531X_MEM_BASE + AR531X_MEM_SIZE - AR531X_IO_SIZE, | ||||||
|  | +	.end	= AR531X_MEM_BASE + AR531X_MEM_SIZE - 1, | ||||||
|  | +	.flags	= IORESOURCE_IO, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct pci_controller ar231x_pci_controller = { | ||||||
|  | +	.pci_ops		= &ar231x_pci_ops, | ||||||
|  | +	.mem_resource	= &ar231x_mem_resource, | ||||||
|  | +	.io_resource	= &ar231x_io_resource, | ||||||
|  | +	.mem_offset     = 0x00000000UL, | ||||||
|  | +	.io_offset      = 0x00000000UL, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||||||
|  | +{ | ||||||
|  | +	return AR2315_IRQ_LCBUS_PCI; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +int pcibios_plat_dev_init(struct pci_dev *dev) | ||||||
|  | +{ | ||||||
|  | +	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 5); | ||||||
|  | +	pci_write_config_word(dev, 0x40, 0); | ||||||
|  | + | ||||||
|  | +	/* Clear any pending Abort or external Interrupts | ||||||
|  | +	 * and enable interrupt processing */ | ||||||
|  | +	ar231x_mask_reg(AR2315_PCI_INTEN_REG, AR2315_PCI_INT_ENABLE, 0); | ||||||
|  | +	ar231x_write_reg(AR2315_PCI_INT_STATUS, (AR2315_PCI_ABORT_INT | AR2315_PCI_EXT_INT)); | ||||||
|  | +	ar231x_write_reg(AR2315_PCI_INT_MASK, (AR2315_PCI_ABORT_INT | AR2315_PCI_EXT_INT)); | ||||||
|  | +	ar231x_mask_reg(AR2315_PCI_INTEN_REG, 0, AR2315_PCI_INT_ENABLE); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +ar2315_pci_fixup(struct pci_dev *dev) | ||||||
|  | +{ | ||||||
|  | +	unsigned int devfn = dev->devfn; | ||||||
|  | + | ||||||
|  | +	if (dev->bus->number != 0) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	/* Only fix up the PCI host settings */ | ||||||
|  | +	if ((PCI_SLOT(devfn) != 3) || (PCI_FUNC(devfn) != 0)) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	/* Fix up MBARs */ | ||||||
|  | +	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, HOST_PCI_MBAR0); | ||||||
|  | +	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, HOST_PCI_MBAR1); | ||||||
|  | +	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, HOST_PCI_MBAR2); | ||||||
|  | +	pci_write_config_dword(dev, PCI_COMMAND, | ||||||
|  | +		PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL | | ||||||
|  | +		PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | | ||||||
|  | +		PCI_COMMAND_FAST_BACK); | ||||||
|  | +} | ||||||
|  | +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, ar2315_pci_fixup); | ||||||
|  | + | ||||||
|  | +static int __init | ||||||
|  | +ar2315_pci_init(void) | ||||||
|  | +{ | ||||||
|  | +	u32 reg; | ||||||
|  | + | ||||||
|  | +	if (ar231x_devtype != DEV_TYPE_AR2315) | ||||||
|  | +		return -ENODEV; | ||||||
|  | + | ||||||
|  | +	configspace = (unsigned long) ioremap_nocache(AR2315_PCIEXT, 1*1024*1024); /* Remap PCI config space */ | ||||||
|  | +	ar231x_pci_controller.io_map_base = | ||||||
|  | +		(unsigned long) ioremap_nocache(AR531X_MEM_BASE + AR531X_MEM_SIZE, AR531X_IO_SIZE); | ||||||
|  | +	set_io_port_base(ar231x_pci_controller.io_map_base); /* PCI I/O space */ | ||||||
|  | + | ||||||
|  | +	reg = ar231x_mask_reg(AR2315_RESET, 0, AR2315_RESET_PCIDMA); | ||||||
|  | +	msleep(10); | ||||||
|  | + | ||||||
|  | +	reg &= ~AR2315_RESET_PCIDMA; | ||||||
|  | +	ar231x_write_reg(AR2315_RESET, reg); | ||||||
|  | +	msleep(10); | ||||||
|  | + | ||||||
|  | +	ar231x_mask_reg(AR2315_ENDIAN_CTL, 0, | ||||||
|  | +		AR2315_CONFIG_PCIAHB | AR2315_CONFIG_PCIAHB_BRIDGE); | ||||||
|  | + | ||||||
|  | +	ar231x_write_reg(AR2315_PCICLK, AR2315_PCICLK_PLLC_CLKM | | ||||||
|  | +		(AR2315_PCICLK_IN_FREQ_DIV_6 << AR2315_PCICLK_DIV_S)); | ||||||
|  | +	ar231x_mask_reg(AR2315_AHB_ARB_CTL, 0, AR2315_ARB_PCI); | ||||||
|  | +	ar231x_mask_reg(AR2315_IF_CTL, AR2315_IF_PCI_CLK_MASK | AR2315_IF_MASK, | ||||||
|  | +		AR2315_IF_PCI | AR2315_IF_PCI_HOST | AR2315_IF_PCI_INTR | | ||||||
|  | +		 (AR2315_IF_PCI_CLK_OUTPUT_CLK << AR2315_IF_PCI_CLK_SHIFT)); | ||||||
|  | + | ||||||
|  | +	/* Reset the PCI bus by setting bits 5-4 in PCI_MCFG */ | ||||||
|  | +	ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_RST_MODE, | ||||||
|  | +		AR2315_PCIRST_LOW); | ||||||
|  | +	msleep(100); | ||||||
|  | + | ||||||
|  | +	/* Bring the PCI out of reset */ | ||||||
|  | +	ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_RST_MODE, | ||||||
|  | +		AR2315_PCIRST_HIGH | AR2315_PCICACHE_DIS | 0x8); | ||||||
|  | + | ||||||
|  | +	ar231x_write_reg(AR2315_PCI_UNCACHE_CFG, | ||||||
|  | +			0x1E | /* 1GB uncached */ | ||||||
|  | +			(1 << 5) | /* Enable uncached */ | ||||||
|  | +			(0x2 << 30) /* Base: 0x80000000 */ | ||||||
|  | +	); | ||||||
|  | +	ar231x_read_reg(AR2315_PCI_UNCACHE_CFG); | ||||||
|  | + | ||||||
|  | +	msleep(500); | ||||||
|  | + | ||||||
|  | +	/* dirty hack - anyone with a datasheet that knows the memory map ? */ | ||||||
|  | +	ioport_resource.start = 0x10000000; | ||||||
|  | +	ioport_resource.end = 0xffffffff; | ||||||
|  | +	iomem_resource.start = 0x10000000; | ||||||
|  | +	iomem_resource.end = 0xffffffff; | ||||||
|  | + | ||||||
|  | +	register_pci_controller(&ar231x_pci_controller); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +arch_initcall(ar2315_pci_init); | ||||||
|  | --- a/arch/mips/ar231x/Kconfig | ||||||
|  | +++ b/arch/mips/ar231x/Kconfig | ||||||
|  | @@ -14,3 +14,10 @@ config ATHEROS_AR2315 | ||||||
|  |  	select SYS_SUPPORTS_32BIT_KERNEL | ||||||
|  |  	select SYS_SUPPORTS_BIG_ENDIAN | ||||||
|  |  	default y | ||||||
|  | + | ||||||
|  | +config ATHEROS_AR2315_PCI | ||||||
|  | +	bool "PCI support" | ||||||
|  | +	depends on ATHEROS_AR2315 | ||||||
|  | +	select HW_HAS_PCI | ||||||
|  | +	select PCI | ||||||
|  | +	default y | ||||||
|  | --- a/arch/mips/ar231x/ar2315.c | ||||||
|  | +++ b/arch/mips/ar231x/ar2315.c | ||||||
|  | @@ -64,6 +64,27 @@ static inline void ar2315_gpio_irq(void) | ||||||
|  |  		do_IRQ(AR531X_GPIO_IRQ_BASE + bit); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +#ifdef CONFIG_ATHEROS_AR2315_PCI | ||||||
|  | +static inline void pci_abort_irq(void) | ||||||
|  | +{ | ||||||
|  | +	ar231x_write_reg(AR2315_PCI_INT_STATUS, AR2315_PCI_ABORT_INT); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void pci_ack_irq(void) | ||||||
|  | +{ | ||||||
|  | +	ar231x_write_reg(AR2315_PCI_INT_STATUS, AR2315_PCI_EXT_INT); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void ar2315_pci_irq(int irq) | ||||||
|  | +{ | ||||||
|  | +	if (ar231x_read_reg(AR2315_PCI_INT_STATUS) == AR2315_PCI_ABORT_INT) | ||||||
|  | +		pci_abort_irq(); | ||||||
|  | +	else { | ||||||
|  | +		do_IRQ(irq); | ||||||
|  | +		pci_ack_irq(); | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | +#endif /* CONFIG_ATHEROS_AR2315_PCI */ | ||||||
|  |   | ||||||
|  |  /* | ||||||
|  |   * Called when an interrupt is received, this function | ||||||
|  | @@ -82,6 +103,10 @@ ar2315_irq_dispatch(void) | ||||||
|  |  		do_IRQ(AR2315_IRQ_WLAN0_INTRS); | ||||||
|  |  	else if (pending & CAUSEF_IP4) | ||||||
|  |  		do_IRQ(AR2315_IRQ_ENET0_INTRS); | ||||||
|  | +#ifdef CONFIG_ATHEROS_AR2315_PCI | ||||||
|  | +	else if (pending & CAUSEF_IP5) | ||||||
|  | +		ar2315_pci_irq(AR2315_IRQ_LCBUS_PCI); | ||||||
|  | +#endif | ||||||
|  |  	else if (pending & CAUSEF_IP2) { | ||||||
|  |  		unsigned int misc_intr = ar231x_read_reg(AR2315_ISR) & ar231x_read_reg(AR2315_IMR); | ||||||
|  |   | ||||||
							
								
								
									
										1619
									
								
								target/linux/atheros/patches-3.8/110-ar2313_ethernet.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1619
									
								
								target/linux/atheros/patches-3.8/110-ar2313_ethernet.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										662
									
								
								target/linux/atheros/patches-3.8/120-spiflash.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										662
									
								
								target/linux/atheros/patches-3.8/120-spiflash.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,662 @@ | |||||||
|  | --- a/drivers/mtd/devices/Kconfig | ||||||
|  | +++ b/drivers/mtd/devices/Kconfig | ||||||
|  | @@ -136,6 +136,10 @@ config MTD_BCM47XXSFLASH | ||||||
|  |  	  registered by bcma as platform devices. This enables driver for | ||||||
|  |  	  serial flash memories (only read-only mode is implemented). | ||||||
|  |   | ||||||
|  | +config MTD_AR2315 | ||||||
|  | +	tristate "Atheros AR2315+ SPI Flash support" | ||||||
|  | +	depends on ATHEROS_AR2315 | ||||||
|  | + | ||||||
|  |  config MTD_SLRAM | ||||||
|  |  	tristate "Uncached system RAM" | ||||||
|  |  	help | ||||||
|  | --- a/drivers/mtd/devices/Makefile | ||||||
|  | +++ b/drivers/mtd/devices/Makefile | ||||||
|  | @@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataf | ||||||
|  |  obj-$(CONFIG_MTD_M25P80)	+= m25p80.o | ||||||
|  |  obj-$(CONFIG_MTD_SPEAR_SMI)	+= spear_smi.o | ||||||
|  |  obj-$(CONFIG_MTD_SST25L)	+= sst25l.o | ||||||
|  | +obj-$(CONFIG_MTD_AR2315)	+= ar2315.o | ||||||
|  |  obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o | ||||||
|  |   | ||||||
|  | -CFLAGS_docg3.o			+= -I$(src) | ||||||
|  | \ No newline at end of file | ||||||
|  | +CFLAGS_docg3.o			+= -I$(src) | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/mtd/devices/ar2315.c | ||||||
|  | @@ -0,0 +1,515 @@ | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | + * MTD driver for the SPI Flash Memory support on Atheros AR2315 | ||||||
|  | + * | ||||||
|  | + * Copyright (c) 2005-2006 Atheros Communications Inc. | ||||||
|  | + * Copyright (C) 2006-2007 FON Technology, SL. | ||||||
|  | + * Copyright (C) 2006-2007 Imre Kaloz <kaloz@openwrt.org> | ||||||
|  | + * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org> | ||||||
|  | + * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com> | ||||||
|  | + * | ||||||
|  | + * 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. | ||||||
|  | + * | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#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/platform_device.h> | ||||||
|  | +#include <linux/sched.h> | ||||||
|  | +#include <linux/root_dev.h> | ||||||
|  | +#include <linux/delay.h> | ||||||
|  | +#include <asm/delay.h> | ||||||
|  | +#include <asm/io.h> | ||||||
|  | + | ||||||
|  | +#include <ar2315_spiflash.h> | ||||||
|  | +#include <ar231x_platform.h> | ||||||
|  | +#include <ar231x.h> | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +#define SPIFLASH "spiflash: " | ||||||
|  | +#define busy_wait(_priv, _condition, _wait) do { \ | ||||||
|  | +	while (_condition) { \ | ||||||
|  | +		spin_unlock_bh(&_priv->lock); \ | ||||||
|  | +		if (_wait > 1) \ | ||||||
|  | +			msleep(_wait); \ | ||||||
|  | +		else if ((_wait == 1) && need_resched()) \ | ||||||
|  | +			schedule(); \ | ||||||
|  | +		else \ | ||||||
|  | +			udelay(1); \ | ||||||
|  | +		spin_lock_bh(&_priv->lock); \ | ||||||
|  | +	} \ | ||||||
|  | +} while (0) | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	FLASH_NONE, | ||||||
|  | +	FLASH_1MB, | ||||||
|  | +	FLASH_2MB, | ||||||
|  | +	FLASH_4MB, | ||||||
|  | +	FLASH_8MB, | ||||||
|  | +	FLASH_16MB, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* Flash configuration table */ | ||||||
|  | +struct flashconfig { | ||||||
|  | +	u32 byte_cnt; | ||||||
|  | +	u32 sector_cnt; | ||||||
|  | +	u32 sector_size; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +const struct flashconfig flashconfig_tbl[] = { | ||||||
|  | +	[FLASH_NONE] = { 0, 0, 0}, | ||||||
|  | +	[FLASH_1MB]  = { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT, STM_1MB_SECTOR_SIZE}, | ||||||
|  | +	[FLASH_2MB]  = { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT, STM_2MB_SECTOR_SIZE}, | ||||||
|  | +	[FLASH_4MB]  = { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT, STM_4MB_SECTOR_SIZE}, | ||||||
|  | +	[FLASH_8MB]  = { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT, STM_8MB_SECTOR_SIZE}, | ||||||
|  | +	[FLASH_16MB] = { STM_16MB_BYTE_COUNT, STM_16MB_SECTOR_COUNT, STM_16MB_SECTOR_SIZE} | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* Mapping of generic opcodes to STM serial flash opcodes */ | ||||||
|  | +enum { | ||||||
|  | +	SPI_WRITE_ENABLE, | ||||||
|  | +	SPI_WRITE_DISABLE, | ||||||
|  | +	SPI_RD_STATUS, | ||||||
|  | +	SPI_WR_STATUS, | ||||||
|  | +	SPI_RD_DATA, | ||||||
|  | +	SPI_FAST_RD_DATA, | ||||||
|  | +	SPI_PAGE_PROGRAM, | ||||||
|  | +	SPI_SECTOR_ERASE, | ||||||
|  | +	SPI_BULK_ERASE, | ||||||
|  | +	SPI_DEEP_PWRDOWN, | ||||||
|  | +	SPI_RD_SIG, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct opcodes { | ||||||
|  | +    __u16 code; | ||||||
|  | +    __s8 tx_cnt; | ||||||
|  | +    __s8 rx_cnt; | ||||||
|  | +}; | ||||||
|  | +const struct opcodes stm_opcodes[] = { | ||||||
|  | +	[SPI_WRITE_ENABLE] = {STM_OP_WR_ENABLE, 1, 0}, | ||||||
|  | +	[SPI_WRITE_DISABLE] = {STM_OP_WR_DISABLE, 1, 0}, | ||||||
|  | +	[SPI_RD_STATUS] = {STM_OP_RD_STATUS, 1, 1}, | ||||||
|  | +	[SPI_WR_STATUS] = {STM_OP_WR_STATUS, 1, 0}, | ||||||
|  | +	[SPI_RD_DATA] = {STM_OP_RD_DATA, 4, 4}, | ||||||
|  | +	[SPI_FAST_RD_DATA] = {STM_OP_FAST_RD_DATA, 5, 0}, | ||||||
|  | +	[SPI_PAGE_PROGRAM] = {STM_OP_PAGE_PGRM, 8, 0}, | ||||||
|  | +	[SPI_SECTOR_ERASE] = {STM_OP_SECTOR_ERASE, 4, 0}, | ||||||
|  | +	[SPI_BULK_ERASE] = {STM_OP_BULK_ERASE, 1, 0}, | ||||||
|  | +	[SPI_DEEP_PWRDOWN] = {STM_OP_DEEP_PWRDOWN, 1, 0}, | ||||||
|  | +	[SPI_RD_SIG] = {STM_OP_RD_SIG, 4, 1}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* Driver private data structure */ | ||||||
|  | +struct spiflash_priv { | ||||||
|  | +	struct mtd_info mtd; | ||||||
|  | +	void *readaddr; /* memory mapped data for read  */ | ||||||
|  | +	void *mmraddr;  /* memory mapped register space */ | ||||||
|  | +	wait_queue_head_t wq; | ||||||
|  | +	spinlock_t lock; | ||||||
|  | +	int state; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define to_spiflash(_mtd) container_of(_mtd, struct spiflash_priv, mtd) | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	FL_READY, | ||||||
|  | +	FL_READING, | ||||||
|  | +	FL_ERASING, | ||||||
|  | +	FL_WRITING | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/***************************************************************************************************/ | ||||||
|  | + | ||||||
|  | +static u32 | ||||||
|  | +spiflash_read_reg(struct spiflash_priv *priv, int reg) | ||||||
|  | +{ | ||||||
|  | +	return ar231x_read_reg((u32) priv->mmraddr + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +spiflash_write_reg(struct spiflash_priv *priv, int reg, u32 data) | ||||||
|  | +{ | ||||||
|  | +	ar231x_write_reg((u32) priv->mmraddr + reg, data); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static u32 | ||||||
|  | +spiflash_wait_busy(struct spiflash_priv *priv) | ||||||
|  | +{ | ||||||
|  | +	u32 reg; | ||||||
|  | + | ||||||
|  | +	busy_wait(priv, (reg = spiflash_read_reg(priv, SPI_FLASH_CTL)) & | ||||||
|  | +		SPI_CTL_BUSY, 0); | ||||||
|  | +	return reg; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static u32 | ||||||
|  | +spiflash_sendcmd (struct spiflash_priv *priv, int opcode, u32 addr) | ||||||
|  | +{ | ||||||
|  | +	const struct opcodes *op; | ||||||
|  | +	u32 reg, mask; | ||||||
|  | + | ||||||
|  | +	op = &stm_opcodes[opcode]; | ||||||
|  | +	reg = spiflash_wait_busy(priv); | ||||||
|  | +	spiflash_write_reg(priv, SPI_FLASH_OPCODE, | ||||||
|  | +		((u32) op->code) | (addr << 8)); | ||||||
|  | + | ||||||
|  | +	reg &= ~SPI_CTL_TX_RX_CNT_MASK; | ||||||
|  | +	reg |= SPI_CTL_START | op->tx_cnt | (op->rx_cnt << 4); | ||||||
|  | + | ||||||
|  | +	spiflash_write_reg(priv, SPI_FLASH_CTL, reg); | ||||||
|  | +	spiflash_wait_busy(priv); | ||||||
|  | + | ||||||
|  | +	if (!op->rx_cnt) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	reg = spiflash_read_reg(priv, SPI_FLASH_DATA); | ||||||
|  | + | ||||||
|  | +	switch (op->rx_cnt) { | ||||||
|  | +	case 1: | ||||||
|  | +		mask = 0x000000ff; | ||||||
|  | +		break; | ||||||
|  | +	case 2: | ||||||
|  | +		mask = 0x0000ffff; | ||||||
|  | +		break; | ||||||
|  | +	case 3: | ||||||
|  | +		mask = 0x00ffffff; | ||||||
|  | +		break; | ||||||
|  | +	default: | ||||||
|  | +		mask = 0xffffffff; | ||||||
|  | +		break; | ||||||
|  | +	} | ||||||
|  | +	reg &= mask; | ||||||
|  | + | ||||||
|  | +	return reg; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | + * Probe SPI flash device | ||||||
|  | + * Function returns 0 for failure. | ||||||
|  | + * and flashconfig_tbl array index for success. | ||||||
|  | + */ | ||||||
|  | +static int | ||||||
|  | +spiflash_probe_chip (struct spiflash_priv *priv) | ||||||
|  | +{ | ||||||
|  | +	u32 sig; | ||||||
|  | +	int flash_size; | ||||||
|  | + | ||||||
|  | +	/* Read the signature on the flash device */ | ||||||
|  | +	spin_lock_bh(&priv->lock); | ||||||
|  | +	sig = spiflash_sendcmd(priv, SPI_RD_SIG, 0); | ||||||
|  | +	spin_unlock_bh(&priv->lock); | ||||||
|  | + | ||||||
|  | +	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; | ||||||
|  | +	case STM_128MBIT_SIGNATURE: | ||||||
|  | +		flash_size = FLASH_16MB; | ||||||
|  | +		break; | ||||||
|  | +	default: | ||||||
|  | +		printk (KERN_WARNING SPIFLASH "Read of flash device signature failed!\n"); | ||||||
|  | +		return 0; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return flash_size; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +/* wait until the flash chip is ready and grab a lock */ | ||||||
|  | +static int spiflash_wait_ready(struct spiflash_priv *priv, int state) | ||||||
|  | +{ | ||||||
|  | +	DECLARE_WAITQUEUE(wait, current); | ||||||
|  | + | ||||||
|  | +retry: | ||||||
|  | +	spin_lock_bh(&priv->lock); | ||||||
|  | +	if (priv->state != FL_READY) { | ||||||
|  | +		set_current_state(TASK_UNINTERRUPTIBLE); | ||||||
|  | +		add_wait_queue(&priv->wq, &wait); | ||||||
|  | +		spin_unlock_bh(&priv->lock); | ||||||
|  | +		schedule(); | ||||||
|  | +		remove_wait_queue(&priv->wq, &wait); | ||||||
|  | + | ||||||
|  | +		if(signal_pending(current)) | ||||||
|  | +			return 0; | ||||||
|  | + | ||||||
|  | +		goto retry; | ||||||
|  | +	} | ||||||
|  | +	priv->state = state; | ||||||
|  | + | ||||||
|  | +	return 1; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void spiflash_done(struct spiflash_priv *priv) | ||||||
|  | +{ | ||||||
|  | +	priv->state = FL_READY; | ||||||
|  | +	spin_unlock_bh(&priv->lock); | ||||||
|  | +	wake_up(&priv->wq); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +spiflash_wait_complete(struct spiflash_priv *priv, unsigned int timeout) | ||||||
|  | +{ | ||||||
|  | +	busy_wait(priv, spiflash_sendcmd(priv, SPI_RD_STATUS, 0) & | ||||||
|  | +		SPI_STATUS_WIP, timeout); | ||||||
|  | +	spiflash_done(priv); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +spiflash_erase (struct mtd_info *mtd, struct erase_info *instr) | ||||||
|  | +{ | ||||||
|  | +	struct spiflash_priv *priv = to_spiflash(mtd); | ||||||
|  | +	const struct opcodes *op; | ||||||
|  | +	u32 temp, reg; | ||||||
|  | + | ||||||
|  | +	if (instr->addr + instr->len > mtd->size) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	if (!spiflash_wait_ready(priv, FL_ERASING)) | ||||||
|  | +		return -EINTR; | ||||||
|  | + | ||||||
|  | +	spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0); | ||||||
|  | +	reg = spiflash_wait_busy(priv); | ||||||
|  | + | ||||||
|  | +	op = &stm_opcodes[SPI_SECTOR_ERASE]; | ||||||
|  | +	temp = ((u32)instr->addr << 8) | (u32)(op->code); | ||||||
|  | +	spiflash_write_reg(priv, SPI_FLASH_OPCODE, temp); | ||||||
|  | + | ||||||
|  | +	reg &= ~SPI_CTL_TX_RX_CNT_MASK; | ||||||
|  | +	reg |= op->tx_cnt | SPI_CTL_START; | ||||||
|  | +	spiflash_write_reg(priv, SPI_FLASH_CTL, reg); | ||||||
|  | + | ||||||
|  | +	spiflash_wait_complete(priv, 20); | ||||||
|  | + | ||||||
|  | +	instr->state = MTD_ERASE_DONE; | ||||||
|  | +	mtd_erase_callback(instr); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +spiflash_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) | ||||||
|  | +{ | ||||||
|  | +	struct spiflash_priv *priv = to_spiflash(mtd); | ||||||
|  | +	u8 *read_addr; | ||||||
|  | + | ||||||
|  | +	if (!len) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	if (from + len > mtd->size) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	*retlen = len; | ||||||
|  | + | ||||||
|  | +	if (!spiflash_wait_ready(priv, FL_READING)) | ||||||
|  | +		return -EINTR; | ||||||
|  | + | ||||||
|  | +	read_addr = (u8 *)(priv->readaddr + from); | ||||||
|  | +	memcpy_fromio(buf, read_addr, len); | ||||||
|  | +	spiflash_done(priv); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +spiflash_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u8 *buf) | ||||||
|  | +{ | ||||||
|  | +	struct spiflash_priv *priv = to_spiflash(mtd); | ||||||
|  | +	u32 opcode, bytes_left; | ||||||
|  | + | ||||||
|  | +	*retlen = 0; | ||||||
|  | + | ||||||
|  | +	if (!len) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	if (to + len > mtd->size) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	bytes_left = len; | ||||||
|  | + | ||||||
|  | +	do { | ||||||
|  | +		u32 read_len, reg, page_offset, spi_data = 0; | ||||||
|  | + | ||||||
|  | +		read_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)) + read_len; | ||||||
|  | + | ||||||
|  | +		if (page_offset > STM_PAGE_SIZE) | ||||||
|  | +			read_len -= (page_offset - STM_PAGE_SIZE); | ||||||
|  | + | ||||||
|  | +		if (!spiflash_wait_ready(priv, FL_WRITING)) | ||||||
|  | +			return -EINTR; | ||||||
|  | + | ||||||
|  | +		spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0); | ||||||
|  | +		spi_data = 0; | ||||||
|  | +		switch (read_len) { | ||||||
|  | +		case 4: | ||||||
|  | +			spi_data |= buf[3] << 24; | ||||||
|  | +			/* fall through */ | ||||||
|  | +		case 3: | ||||||
|  | +			spi_data |= buf[2] << 16; | ||||||
|  | +			/* fall through */ | ||||||
|  | +		case 2: | ||||||
|  | +			spi_data |= buf[1] << 8; | ||||||
|  | +			/* fall through */ | ||||||
|  | +		case 1: | ||||||
|  | +			spi_data |= buf[0] & 0xff; | ||||||
|  | +			break; | ||||||
|  | +		default: | ||||||
|  | +			break; | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		spiflash_write_reg(priv, SPI_FLASH_DATA, spi_data); | ||||||
|  | +		opcode = stm_opcodes[SPI_PAGE_PROGRAM].code | | ||||||
|  | +			(to & 0x00ffffff) << 8; | ||||||
|  | +		spiflash_write_reg(priv, SPI_FLASH_OPCODE, opcode); | ||||||
|  | + | ||||||
|  | +		reg = spiflash_read_reg(priv, SPI_FLASH_CTL); | ||||||
|  | +		reg &= ~SPI_CTL_TX_RX_CNT_MASK; | ||||||
|  | +		reg |= (read_len + 4) | SPI_CTL_START; | ||||||
|  | +		spiflash_write_reg(priv, SPI_FLASH_CTL, reg); | ||||||
|  | + | ||||||
|  | +		spiflash_wait_complete(priv, 1); | ||||||
|  | + | ||||||
|  | +		bytes_left -= read_len; | ||||||
|  | +		to += read_len; | ||||||
|  | +		buf += read_len; | ||||||
|  | + | ||||||
|  | +		*retlen += read_len; | ||||||
|  | +	} while (bytes_left != 0); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS | ||||||
|  | +static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "MyLoader", NULL }; | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +spiflash_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct spiflash_priv *priv; | ||||||
|  | +	struct mtd_info *mtd; | ||||||
|  | +	int index; | ||||||
|  | +	int result = 0; | ||||||
|  | + | ||||||
|  | +	priv = kzalloc(sizeof(struct spiflash_priv), GFP_KERNEL); | ||||||
|  | +	spin_lock_init(&priv->lock); | ||||||
|  | +	init_waitqueue_head(&priv->wq); | ||||||
|  | +	priv->state = FL_READY; | ||||||
|  | +	mtd = &priv->mtd; | ||||||
|  | + | ||||||
|  | +	priv->mmraddr = ioremap_nocache(SPI_FLASH_MMR, SPI_FLASH_MMR_SIZE); | ||||||
|  | +	if (!priv->mmraddr) { | ||||||
|  | +		printk(KERN_WARNING SPIFLASH "Failed to map flash device\n"); | ||||||
|  | +		goto error; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	index = spiflash_probe_chip(priv); | ||||||
|  | +	if (!index) { | ||||||
|  | +		printk (KERN_WARNING SPIFLASH "Found no serial flash device\n"); | ||||||
|  | +		goto error; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	priv->readaddr = ioremap_nocache(SPI_FLASH_READ, flashconfig_tbl[index].byte_cnt); | ||||||
|  | +	if (!priv->readaddr) { | ||||||
|  | +		printk (KERN_WARNING SPIFLASH "Failed to map flash device\n"); | ||||||
|  | +		goto error; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	platform_set_drvdata(pdev, priv); | ||||||
|  | +	mtd->name = "spiflash"; | ||||||
|  | +	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; | ||||||
|  | + | ||||||
|  | +#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS | ||||||
|  | +	/* parse redboot partitions */ | ||||||
|  | + | ||||||
|  | +	result = mtd_device_parse_register(mtd, part_probe_types, | ||||||
|  | +			NULL, NULL, 0); | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|  | +	return result; | ||||||
|  | + | ||||||
|  | +error: | ||||||
|  | +	if (priv->mmraddr) | ||||||
|  | +		iounmap(priv->mmraddr); | ||||||
|  | +	kfree(priv); | ||||||
|  | +	return -ENXIO; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +spiflash_remove (struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct spiflash_priv *priv = platform_get_drvdata(pdev); | ||||||
|  | +	struct mtd_info *mtd = &priv->mtd; | ||||||
|  | + | ||||||
|  | +	mtd_device_unregister(mtd); | ||||||
|  | +	iounmap(priv->mmraddr); | ||||||
|  | +	iounmap(priv->readaddr); | ||||||
|  | +	kfree(priv); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +struct platform_driver spiflash_driver = { | ||||||
|  | +	.driver.name = "spiflash", | ||||||
|  | +	.probe = spiflash_probe, | ||||||
|  | +	.remove = spiflash_remove, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +int __init | ||||||
|  | +spiflash_init (void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_register(&spiflash_driver); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void __exit | ||||||
|  | +spiflash_exit (void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_unregister(&spiflash_driver); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +module_init (spiflash_init); | ||||||
|  | +module_exit (spiflash_exit); | ||||||
|  | + | ||||||
|  | +MODULE_LICENSE("GPL"); | ||||||
|  | +MODULE_AUTHOR("OpenWrt.org, Atheros Communications Inc"); | ||||||
|  | +MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros SOC"); | ||||||
|  | + | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/arch/mips/include/asm/mach-ar231x/ar2315_spiflash.h | ||||||
|  | @@ -0,0 +1,116 @@ | ||||||
|  | +/* | ||||||
|  | + * SPI Flash Memory support header file. | ||||||
|  | + * | ||||||
|  | + * Copyright (c) 2005, Atheros Communications Inc. | ||||||
|  | + * Copyright (C) 2006 FON Technology, SL. | ||||||
|  | + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> | ||||||
|  | + * Copyright (C) 2006-2009 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. | ||||||
|  | + * | ||||||
|  | + */ | ||||||
|  | +#ifndef __AR2315_SPIFLASH_H | ||||||
|  | +#define __AR2315_SPIFLASH_H | ||||||
|  | + | ||||||
|  | +#define STM_PAGE_SIZE           256 | ||||||
|  | + | ||||||
|  | +#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_128MBIT_SIGNATURE   0x17 | ||||||
|  | +#define STM_M25P128_BYTE_COUNT   16777216 | ||||||
|  | +#define STM_M25P128_SECTOR_COUNT 256 | ||||||
|  | +#define STM_M25P128_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 | ||||||
|  | +#define STM_16MB_BYTE_COUNT   STM_M25P128_BYTE_COUNT | ||||||
|  | +#define STM_16MB_SECTOR_COUNT STM_M25P128_SECTOR_COUNT | ||||||
|  | +#define STM_16MB_SECTOR_SIZE  STM_M25P128_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 | ||||||
|  | + | ||||||
|  | +#endif | ||||||
							
								
								
									
										227
									
								
								target/linux/atheros/patches-3.8/130-watchdog.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								target/linux/atheros/patches-3.8/130-watchdog.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | |||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/watchdog/ar2315-wtd.c | ||||||
|  | @@ -0,0 +1,199 @@ | ||||||
|  | +/* | ||||||
|  | + * This program is free software; you can redistribute it and/or modify | ||||||
|  | + * it under the terms of the GNU General Public License as published by | ||||||
|  | + * the Free Software Foundation; either version 2 of the License, or | ||||||
|  | + * (at your option) any later version. | ||||||
|  | + * | ||||||
|  | + * This program is distributed in the hope that it will be useful, | ||||||
|  | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | + * GNU General Public License for more details. | ||||||
|  | + * | ||||||
|  | + * You should have received a copy of the GNU General Public License | ||||||
|  | + * along with this program; if not, write to the Free Software | ||||||
|  | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||||
|  | + * | ||||||
|  | + * Copyright (C) 2008 John Crispin <blogic@openwrt.org> | ||||||
|  | + * Based on EP93xx and ifxmips wdt driver | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/interrupt.h> | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/moduleparam.h> | ||||||
|  | +#include <linux/types.h> | ||||||
|  | +#include <linux/miscdevice.h> | ||||||
|  | +#include <linux/watchdog.h> | ||||||
|  | +#include <linux/fs.h> | ||||||
|  | +#include <linux/ioport.h> | ||||||
|  | +#include <linux/notifier.h> | ||||||
|  | +#include <linux/reboot.h> | ||||||
|  | +#include <linux/init.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | + | ||||||
|  | +#include <asm/io.h> | ||||||
|  | +#include <asm/uaccess.h> | ||||||
|  | +#include <asm/addrspace.h> | ||||||
|  | +#include <ar231x_platform.h> | ||||||
|  | +#include <ar2315_regs.h> | ||||||
|  | +#include <ar231x.h> | ||||||
|  | + | ||||||
|  | +#define CLOCK_RATE 40000000 | ||||||
|  | +#define HEARTBEAT(x) (x < 1 || x > 90)?(20):(x) | ||||||
|  | + | ||||||
|  | +static int wdt_timeout = 20; | ||||||
|  | +static int started = 0; | ||||||
|  | +static int in_use = 0; | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +ar2315_wdt_enable(void) | ||||||
|  | +{ | ||||||
|  | +	ar231x_write_reg(AR2315_WD, wdt_timeout * CLOCK_RATE); | ||||||
|  | +	ar231x_write_reg(AR2315_ISR, 0x80); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static ssize_t | ||||||
|  | +ar2315_wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) | ||||||
|  | +{ | ||||||
|  | +	if(len) | ||||||
|  | +		ar2315_wdt_enable(); | ||||||
|  | +	return len; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +ar2315_wdt_open(struct inode *inode, struct file *file) | ||||||
|  | +{ | ||||||
|  | +	if(in_use) | ||||||
|  | +		return -EBUSY; | ||||||
|  | +	ar2315_wdt_enable(); | ||||||
|  | +	in_use = started = 1; | ||||||
|  | +	return nonseekable_open(inode, file); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +ar2315_wdt_release(struct inode *inode, struct file *file) | ||||||
|  | +{ | ||||||
|  | +	in_use = 0; | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static irqreturn_t | ||||||
|  | +ar2315_wdt_interrupt(int irq, void *dev_id) | ||||||
|  | +{ | ||||||
|  | +	if(started) | ||||||
|  | +	{ | ||||||
|  | +		printk(KERN_CRIT "watchdog expired, rebooting system\n"); | ||||||
|  | +		emergency_restart(); | ||||||
|  | +	} else { | ||||||
|  | +		ar231x_write_reg(AR2315_WDC, 0); | ||||||
|  | +		ar231x_write_reg(AR2315_WD, 0); | ||||||
|  | +		ar231x_write_reg(AR2315_ISR, 0x80); | ||||||
|  | +	} | ||||||
|  | +	return IRQ_HANDLED; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct watchdog_info ident = { | ||||||
|  | +	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | ||||||
|  | +	.identity = "ar2315 Watchdog", | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static long | ||||||
|  | +ar2315_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||||||
|  | +{ | ||||||
|  | +	int new_wdt_timeout; | ||||||
|  | +	int ret = -ENOIOCTLCMD; | ||||||
|  | + | ||||||
|  | +	switch(cmd) | ||||||
|  | +	{ | ||||||
|  | +		case WDIOC_GETSUPPORT: | ||||||
|  | +			ret = copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)) ? -EFAULT : 0; | ||||||
|  | +			break; | ||||||
|  | + | ||||||
|  | +		case WDIOC_KEEPALIVE: | ||||||
|  | +			ar2315_wdt_enable(); | ||||||
|  | +			ret = 0; | ||||||
|  | +			break; | ||||||
|  | + | ||||||
|  | +		case WDIOC_SETTIMEOUT: | ||||||
|  | +			if((ret = get_user(new_wdt_timeout, (int __user *)arg))) | ||||||
|  | +				break; | ||||||
|  | +			wdt_timeout = HEARTBEAT(new_wdt_timeout); | ||||||
|  | +			ar2315_wdt_enable(); | ||||||
|  | +			break; | ||||||
|  | + | ||||||
|  | +		case WDIOC_GETTIMEOUT: | ||||||
|  | +			ret = put_user(wdt_timeout, (int __user *)arg); | ||||||
|  | +			break; | ||||||
|  | +	} | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct file_operations ar2315_wdt_fops = { | ||||||
|  | +	.owner		= THIS_MODULE, | ||||||
|  | +	.llseek		= no_llseek, | ||||||
|  | +	.write		= ar2315_wdt_write, | ||||||
|  | +	.unlocked_ioctl	= ar2315_wdt_ioctl, | ||||||
|  | +	.open		= ar2315_wdt_open, | ||||||
|  | +	.release	= ar2315_wdt_release, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static struct miscdevice ar2315_wdt_miscdev = { | ||||||
|  | +	.minor	= WATCHDOG_MINOR, | ||||||
|  | +	.name	= "watchdog", | ||||||
|  | +	.fops	= &ar2315_wdt_fops, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +ar2315_wdt_probe(struct platform_device *dev) | ||||||
|  | +{ | ||||||
|  | +	int ret = 0; | ||||||
|  | + | ||||||
|  | +	ar2315_wdt_enable(); | ||||||
|  | +	ret = request_irq(AR531X_MISC_IRQ_WATCHDOG, ar2315_wdt_interrupt, IRQF_DISABLED, "ar2315_wdt", NULL); | ||||||
|  | +	if(ret) | ||||||
|  | +	{ | ||||||
|  | +		printk(KERN_ERR "ar2315wdt: failed to register inetrrupt\n"); | ||||||
|  | +		goto out; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	ret = misc_register(&ar2315_wdt_miscdev); | ||||||
|  | +	if(ret) | ||||||
|  | +		printk(KERN_ERR "ar2315wdt: failed to register miscdev\n"); | ||||||
|  | + | ||||||
|  | +out: | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +ar2315_wdt_remove(struct platform_device *dev) | ||||||
|  | +{ | ||||||
|  | +	misc_deregister(&ar2315_wdt_miscdev); | ||||||
|  | +	free_irq(AR531X_MISC_IRQ_WATCHDOG, NULL); | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct platform_driver ar2315_wdt_driver = { | ||||||
|  | +	.probe = ar2315_wdt_probe, | ||||||
|  | +	.remove = ar2315_wdt_remove, | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = "ar2315_wdt", | ||||||
|  | +		.owner = THIS_MODULE, | ||||||
|  | +	}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int __init | ||||||
|  | +init_ar2315_wdt(void) | ||||||
|  | +{ | ||||||
|  | +	int ret = platform_driver_register(&ar2315_wdt_driver); | ||||||
|  | +	if(ret) | ||||||
|  | +		printk(KERN_INFO "ar2315_wdt: error registering platfom driver!"); | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void __exit | ||||||
|  | +exit_ar2315_wdt(void) | ||||||
|  | +{ | ||||||
|  | +	platform_driver_unregister(&ar2315_wdt_driver); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +module_init(init_ar2315_wdt); | ||||||
|  | +module_exit(exit_ar2315_wdt); | ||||||
|  | --- a/drivers/watchdog/Kconfig | ||||||
|  | +++ b/drivers/watchdog/Kconfig | ||||||
|  | @@ -1064,6 +1064,12 @@ config LANTIQ_WDT | ||||||
|  |  	help | ||||||
|  |  	  Hardware driver for the Lantiq SoC Watchdog Timer. | ||||||
|  |   | ||||||
|  | +config ATHEROS_WDT | ||||||
|  | +	tristate "Atheros wisoc Watchdog Timer" | ||||||
|  | +	depends on ATHEROS_AR231X | ||||||
|  | +	help | ||||||
|  | +	  Hardware driver for the Atheros wisoc Watchdog Timer. | ||||||
|  | + | ||||||
|  |  # PARISC Architecture | ||||||
|  |   | ||||||
|  |  # POWERPC Architecture | ||||||
|  | --- a/drivers/watchdog/Makefile | ||||||
|  | +++ b/drivers/watchdog/Makefile | ||||||
|  | @@ -128,6 +128,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o | ||||||
|  |  obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o | ||||||
|  |  obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o | ||||||
|  |  obj-$(CONFIG_AR7_WDT) += ar7_wdt.o | ||||||
|  | +obj-$(CONFIG_ATHEROS_WDT) += ar2315-wtd.o | ||||||
|  |  obj-$(CONFIG_TXX9_WDT) += txx9wdt.o | ||||||
|  |  obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o | ||||||
|  |  octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o | ||||||
| @@ -0,0 +1,60 @@ | |||||||
|  | --- a/drivers/mtd/redboot.c | ||||||
|  | +++ b/drivers/mtd/redboot.c | ||||||
|  | @@ -30,6 +30,8 @@ | ||||||
|  |  #include <linux/mtd/partitions.h> | ||||||
|  |  #include <linux/module.h> | ||||||
|  |   | ||||||
|  | +#define BOARD_CONFIG_PART		"boardconfig" | ||||||
|  | + | ||||||
|  |  struct fis_image_desc { | ||||||
|  |      unsigned char name[16];      // Null terminated name | ||||||
|  |      uint32_t	  flash_base;    // Address within FLASH of image | ||||||
|  | @@ -60,6 +62,7 @@ static int parse_redboot_partitions(stru | ||||||
|  |  				    struct mtd_partition **pparts, | ||||||
|  |  				    struct mtd_part_parser_data *data) | ||||||
|  |  { | ||||||
|  | +	unsigned long max_offset = 0; | ||||||
|  |  	int nrparts = 0; | ||||||
|  |  	struct fis_image_desc *buf; | ||||||
|  |  	struct mtd_partition *parts; | ||||||
|  | @@ -227,14 +230,14 @@ static int parse_redboot_partitions(stru | ||||||
|  |  		} | ||||||
|  |  	} | ||||||
|  |  #endif | ||||||
|  | -	parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL); | ||||||
|  | +	parts = kzalloc(sizeof(*parts) * (nrparts + 1) + nulllen + namelen + sizeof(BOARD_CONFIG_PART), GFP_KERNEL); | ||||||
|  |   | ||||||
|  |  	if (!parts) { | ||||||
|  |  		ret = -ENOMEM; | ||||||
|  |  		goto out; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	nullname = (char *)&parts[nrparts]; | ||||||
|  | +	nullname = (char *)&parts[nrparts + 1]; | ||||||
|  |  #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED | ||||||
|  |  	if (nulllen > 0) { | ||||||
|  |  		strcpy(nullname, nullstring); | ||||||
|  | @@ -253,6 +256,8 @@ static int parse_redboot_partitions(stru | ||||||
|  |  	} | ||||||
|  |  #endif | ||||||
|  |  	for ( ; i<nrparts; i++) { | ||||||
|  | +		if(max_offset < buf[i].flash_base + buf[i].size) | ||||||
|  | +			max_offset = buf[i].flash_base + buf[i].size; | ||||||
|  |  		parts[i].size = fl->img->size; | ||||||
|  |  		parts[i].offset = fl->img->flash_base; | ||||||
|  |  		parts[i].name = names; | ||||||
|  | @@ -286,6 +291,14 @@ static int parse_redboot_partitions(stru | ||||||
|  |  		fl = fl->next; | ||||||
|  |  		kfree(tmp_fl); | ||||||
|  |  	} | ||||||
|  | +	if(master->size - max_offset >= master->erasesize) | ||||||
|  | +	{ | ||||||
|  | +		parts[nrparts].size = master->size - max_offset; | ||||||
|  | +		parts[nrparts].offset = max_offset; | ||||||
|  | +		parts[nrparts].name = names; | ||||||
|  | +		strcpy(names, BOARD_CONFIG_PART); | ||||||
|  | +		nrparts++; | ||||||
|  | +	} | ||||||
|  |  	ret = nrparts; | ||||||
|  |  	*pparts = parts; | ||||||
|  |   out: | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | --- a/drivers/mtd/redboot.c | ||||||
|  | +++ b/drivers/mtd/redboot.c | ||||||
|  | @@ -79,6 +79,11 @@ static int parse_redboot_partitions(stru | ||||||
|  |  	static char nullstring[] = "unallocated"; | ||||||
|  |  #endif | ||||||
|  |   | ||||||
|  | +	buf = vmalloc(master->erasesize); | ||||||
|  | +	if (!buf) | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +		 | ||||||
|  | + restart: | ||||||
|  |  	if ( directory < 0 ) { | ||||||
|  |  		offset = master->size + directory * master->erasesize; | ||||||
|  |  		while (mtd_can_have_bb(master) && | ||||||
|  | @@ -86,6 +91,7 @@ static int parse_redboot_partitions(stru | ||||||
|  |  			if (!offset) { | ||||||
|  |  			nogood: | ||||||
|  |  				printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n"); | ||||||
|  | +				vfree(buf); | ||||||
|  |  				return -EIO; | ||||||
|  |  			} | ||||||
|  |  			offset -= master->erasesize; | ||||||
|  | @@ -99,10 +105,6 @@ static int parse_redboot_partitions(stru | ||||||
|  |  				goto nogood; | ||||||
|  |  		} | ||||||
|  |  	} | ||||||
|  | -	buf = vmalloc(master->erasesize); | ||||||
|  | - | ||||||
|  | -	if (!buf) | ||||||
|  | -		return -ENOMEM; | ||||||
|  |   | ||||||
|  |  	printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n", | ||||||
|  |  	       master->name, offset); | ||||||
|  | @@ -175,6 +177,11 @@ static int parse_redboot_partitions(stru | ||||||
|  |  	} | ||||||
|  |  	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; | ||||||
| @@ -0,0 +1,72 @@ | |||||||
|  | --- a/drivers/mtd/redboot.c | ||||||
|  | +++ b/drivers/mtd/redboot.c | ||||||
|  | @@ -58,6 +58,22 @@ static inline int redboot_checksum(struc | ||||||
|  |  	return 1; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static uint32_t mtd_get_offset_erasesize(struct mtd_info *mtd, uint64_t offset) | ||||||
|  | +{ | ||||||
|  | +	struct mtd_erase_region_info *regions = mtd->eraseregions; | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < mtd->numeraseregions; i++) { | ||||||
|  | +		if (regions[i].offset + | ||||||
|  | +		    regions[i].numblocks * regions[i].erasesize <= offset) | ||||||
|  | +			continue; | ||||||
|  | + | ||||||
|  | +		return regions[i].erasesize; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return mtd->erasesize; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static int parse_redboot_partitions(struct mtd_info *master, | ||||||
|  |  				    struct mtd_partition **pparts, | ||||||
|  |  				    struct mtd_part_parser_data *data) | ||||||
|  | @@ -74,6 +90,7 @@ static int parse_redboot_partitions(stru | ||||||
|  |  	int namelen = 0; | ||||||
|  |  	int nulllen = 0; | ||||||
|  |  	int numslots; | ||||||
|  | +	int first_slot; | ||||||
|  |  	unsigned long offset; | ||||||
|  |  #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED | ||||||
|  |  	static char nullstring[] = "unallocated"; | ||||||
|  | @@ -188,7 +205,10 @@ static int parse_redboot_partitions(stru | ||||||
|  |  		goto out; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	for (i = 0; i < numslots; i++) { | ||||||
|  | +	first_slot = (buf[i].flash_base & (master->erasesize - 1)) / | ||||||
|  | +		     sizeof(struct fis_image_desc); | ||||||
|  | + | ||||||
|  | +	for (i = first_slot; i < first_slot + numslots; i++) { | ||||||
|  |  		struct fis_list *new_fl, **prev; | ||||||
|  |   | ||||||
|  |  		if (buf[i].name[0] == 0xff) { | ||||||
|  | @@ -263,12 +283,13 @@ static int parse_redboot_partitions(stru | ||||||
|  |  	} | ||||||
|  |  #endif | ||||||
|  |  	for ( ; i<nrparts; i++) { | ||||||
|  | -		if(max_offset < buf[i].flash_base + buf[i].size) | ||||||
|  | -			max_offset = buf[i].flash_base + buf[i].size; | ||||||
|  |  		parts[i].size = fl->img->size; | ||||||
|  |  		parts[i].offset = fl->img->flash_base; | ||||||
|  |  		parts[i].name = names; | ||||||
|  |   | ||||||
|  | +		if (max_offset < parts[i].offset + parts[i].size) | ||||||
|  | +			max_offset = parts[i].offset + parts[i].size; | ||||||
|  | + | ||||||
|  |  		strcpy(names, fl->img->name); | ||||||
|  |  #ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY | ||||||
|  |  		if (!memcmp(names, "RedBoot", 8) || | ||||||
|  | @@ -298,7 +319,9 @@ static int parse_redboot_partitions(stru | ||||||
|  |  		fl = fl->next; | ||||||
|  |  		kfree(tmp_fl); | ||||||
|  |  	} | ||||||
|  | -	if(master->size - max_offset >= master->erasesize) | ||||||
|  | + | ||||||
|  | +	if (master->size - max_offset >= | ||||||
|  | +	    mtd_get_offset_erasesize(master, max_offset)) | ||||||
|  |  	{ | ||||||
|  |  		parts[nrparts].size = master->size - max_offset; | ||||||
|  |  		parts[nrparts].offset = max_offset; | ||||||
							
								
								
									
										72
									
								
								target/linux/atheros/patches-3.8/210-reset_button.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								target/linux/atheros/patches-3.8/210-reset_button.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | --- a/arch/mips/ar231x/Makefile | ||||||
|  | +++ b/arch/mips/ar231x/Makefile | ||||||
|  | @@ -8,7 +8,7 @@ | ||||||
|  |  # Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org> | ||||||
|  |  # | ||||||
|  |   | ||||||
|  | -obj-y += board.o prom.o devices.o | ||||||
|  | +obj-y += board.o prom.o devices.o reset.o | ||||||
|  |   | ||||||
|  |  obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||||||
|  |   | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/arch/mips/ar231x/reset.c | ||||||
|  | @@ -0,0 +1,58 @@ | ||||||
|  | +#include <linux/init.h> | ||||||
|  | +#include <linux/slab.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/gpio_keys.h> | ||||||
|  | +#include <linux/input.h> | ||||||
|  | +#include <ar231x_platform.h> | ||||||
|  | +#include <ar231x.h> | ||||||
|  | +#include "devices.h" | ||||||
|  | + | ||||||
|  | +static int __init | ||||||
|  | +ar231x_init_reset(void) | ||||||
|  | +{ | ||||||
|  | +	struct platform_device *pdev; | ||||||
|  | +	struct gpio_keys_platform_data pdata; | ||||||
|  | +	struct gpio_keys_button *p; | ||||||
|  | +	int err; | ||||||
|  | + | ||||||
|  | +	if (ar231x_board.config->resetConfigGpio == 0xffff) | ||||||
|  | +		return -ENODEV; | ||||||
|  | + | ||||||
|  | +	p = kzalloc(sizeof(*p), GFP_KERNEL); | ||||||
|  | +	if (!p) | ||||||
|  | +		goto err; | ||||||
|  | + | ||||||
|  | +	p->desc = "reset"; | ||||||
|  | +	p->type = EV_KEY; | ||||||
|  | +	p->code = KEY_RESTART; | ||||||
|  | +	p->debounce_interval = 60; | ||||||
|  | +	p->gpio = ar231x_board.config->resetConfigGpio; | ||||||
|  | + | ||||||
|  | +	memset(&pdata, 0, sizeof(pdata)); | ||||||
|  | +	pdata.poll_interval = 20; | ||||||
|  | +	pdata.buttons = p; | ||||||
|  | +	pdata.nbuttons = 1; | ||||||
|  | + | ||||||
|  | +	pdev = platform_device_alloc("gpio-keys-polled", 0); | ||||||
|  | +	if (!pdev) | ||||||
|  | +		goto err_free; | ||||||
|  | + | ||||||
|  | +	err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); | ||||||
|  | +	if (err) | ||||||
|  | +		goto err_put_pdev; | ||||||
|  | + | ||||||
|  | +	err = platform_device_add(pdev); | ||||||
|  | +	if (err) | ||||||
|  | +		goto err_put_pdev; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | + | ||||||
|  | +err_put_pdev: | ||||||
|  | +	platform_device_put(pdev); | ||||||
|  | +err_free: | ||||||
|  | +	kfree(p); | ||||||
|  | +err: | ||||||
|  | +	return -ENOMEM; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +module_init(ar231x_init_reset); | ||||||
| @@ -0,0 +1,86 @@ | |||||||
|  | --- a/drivers/net/ethernet/ar231x/ar231x.c | ||||||
|  | +++ b/drivers/net/ethernet/ar231x/ar231x.c | ||||||
|  | @@ -150,6 +150,7 @@ static int ar231x_mdiobus_write(struct m | ||||||
|  |  static int ar231x_mdiobus_reset(struct mii_bus *bus); | ||||||
|  |  static int ar231x_mdiobus_probe (struct net_device *dev); | ||||||
|  |  static void ar231x_adjust_link(struct net_device *dev); | ||||||
|  | +static bool no_phy = false; | ||||||
|  |   | ||||||
|  |  #ifndef ERR | ||||||
|  |  #define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args) | ||||||
|  | @@ -182,6 +183,30 @@ static const struct net_device_ops ar231 | ||||||
|  |  #endif | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | +static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) | ||||||
|  | +{ | ||||||
|  | +	int phy_reg; | ||||||
|  | + | ||||||
|  | +	/* Grab the bits from PHYIR1, and put them | ||||||
|  | +	 * in the upper half */ | ||||||
|  | +	phy_reg = mdiobus_read(bus, addr, MII_PHYSID1); | ||||||
|  | + | ||||||
|  | +	if (phy_reg < 0) | ||||||
|  | +		return -EIO; | ||||||
|  | + | ||||||
|  | +	*phy_id = (phy_reg & 0xffff) << 16; | ||||||
|  | + | ||||||
|  | +	/* Grab the bits from PHYIR2, and put them in the lower half */ | ||||||
|  | +	phy_reg = mdiobus_read(bus, addr, MII_PHYSID2); | ||||||
|  | + | ||||||
|  | +	if (phy_reg < 0) | ||||||
|  | +		return -EIO; | ||||||
|  | + | ||||||
|  | +	*phy_id |= (phy_reg & 0xffff); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  int ar231x_probe(struct platform_device *pdev) | ||||||
|  |  { | ||||||
|  |  	struct net_device *dev; | ||||||
|  | @@ -299,6 +324,21 @@ int ar231x_probe(struct platform_device | ||||||
|  |   | ||||||
|  |  	mdiobus_register(sp->mii_bus); | ||||||
|  |   | ||||||
|  | +	/* Workaround for Micrel switch, which is only available on | ||||||
|  | +	 * one PHY and cannot be configured through MDIO */ | ||||||
|  | +	if (!no_phy) { | ||||||
|  | +		u32 phy_id = 0; | ||||||
|  | +		get_phy_id(sp->mii_bus, 1, &phy_id); | ||||||
|  | +		if (phy_id == 0x00221450) | ||||||
|  | +			no_phy = true; | ||||||
|  | +	} | ||||||
|  | +	if (no_phy) { | ||||||
|  | +		sp->link = 1; | ||||||
|  | +		netif_carrier_on(dev); | ||||||
|  | +		return 0; | ||||||
|  | +	} | ||||||
|  | +	no_phy = true; | ||||||
|  | + | ||||||
|  |  	if (ar231x_mdiobus_probe(dev) != 0) { | ||||||
|  |  		printk(KERN_ERR "%s: mdiobus_probe failed\n", dev->name); | ||||||
|  |  		rx_tasklet_cleanup(dev); | ||||||
|  | @@ -355,8 +395,10 @@ static int ar231x_remove(struct platform | ||||||
|  |  	rx_tasklet_cleanup(dev); | ||||||
|  |  	ar231x_init_cleanup(dev); | ||||||
|  |  	unregister_netdev(dev); | ||||||
|  | -	mdiobus_unregister(sp->mii_bus); | ||||||
|  | -	mdiobus_free(sp->mii_bus); | ||||||
|  | +	if (sp->mii_bus) { | ||||||
|  | +		mdiobus_unregister(sp->mii_bus); | ||||||
|  | +		mdiobus_free(sp->mii_bus); | ||||||
|  | +	} | ||||||
|  |  	kfree(dev); | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  | @@ -1132,6 +1174,9 @@ static int ar231x_ioctl(struct net_devic | ||||||
|  |  	struct ar231x_private *sp = netdev_priv(dev); | ||||||
|  |  	int ret; | ||||||
|  |   | ||||||
|  | +	if (!sp->phy_dev) | ||||||
|  | +		return -ENODEV; | ||||||
|  | + | ||||||
|  |  	switch (cmd) { | ||||||
|  |   | ||||||
|  |  	case SIOCETHTOOL: | ||||||
		Reference in New Issue
	
	Block a user
	 Gabor Juhos
					Gabor Juhos