surprise :p
SVN-Revision: 11894
This commit is contained in:
		
							parent
							
								
									3d9c4c9073
								
							
						
					
					
						commit
						f529a37420
					
				
							
								
								
									
										24
									
								
								target/linux/ar71xx/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								target/linux/ar71xx/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2008 OpenWrt.org
 | 
			
		||||
#
 | 
			
		||||
# This is free software, licensed under the GNU General Public License v2.
 | 
			
		||||
# See /LICENSE for more information.
 | 
			
		||||
#
 | 
			
		||||
include $(TOPDIR)/rules.mk
 | 
			
		||||
 | 
			
		||||
ARCH:=mips
 | 
			
		||||
BOARD:=ar71xx
 | 
			
		||||
BOARDNAME:=Atheros AR71xx
 | 
			
		||||
FEATURES:=squashfs tgz broken
 | 
			
		||||
 | 
			
		||||
LINUX_VERSION:=2.6.25.10
 | 
			
		||||
 | 
			
		||||
include $(INCLUDE_DIR)/target.mk
 | 
			
		||||
 | 
			
		||||
#DEFAULT_PACKAGES += kmod-madwifi
 | 
			
		||||
 | 
			
		||||
define Target/Description
 | 
			
		||||
	Build firmware images for Atheros AR71xx based boards
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
$(eval $(call BuildTarget))
 | 
			
		||||
							
								
								
									
										244
									
								
								target/linux/ar71xx/config-default
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								target/linux/ar71xx/config-default
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,244 @@
 | 
			
		||||
CONFIG_32BIT=y
 | 
			
		||||
# CONFIG_64BIT is not set
 | 
			
		||||
# CONFIG_8139TOO is not set
 | 
			
		||||
CONFIG_ADM6996_PHY=y
 | 
			
		||||
CONFIG_AG71XX=y
 | 
			
		||||
# CONFIG_AR71XX_EARLY_SERIAL is not set
 | 
			
		||||
CONFIG_AR71XX_MACH_GENERIC=y
 | 
			
		||||
CONFIG_AR71XX_MACH_RB_4XX=y
 | 
			
		||||
CONFIG_AR71XX_MACH_WP543=y
 | 
			
		||||
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
 | 
			
		||||
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 | 
			
		||||
CONFIG_ARCH_POPULATES_NODE_MAP=y
 | 
			
		||||
# CONFIG_ARCH_SUPPORTS_MSI is not set
 | 
			
		||||
CONFIG_ARCH_SUPPORTS_OPROFILE=y
 | 
			
		||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
 | 
			
		||||
CONFIG_ATHEROS_AR71XX=y
 | 
			
		||||
CONFIG_BASE_SMALL=0
 | 
			
		||||
# CONFIG_BCM47XX is not set
 | 
			
		||||
CONFIG_BITREVERSE=y
 | 
			
		||||
# CONFIG_BROADCOM_PHY is not set
 | 
			
		||||
CONFIG_CEVT_R4K=y
 | 
			
		||||
CONFIG_CLASSIC_RCU=y
 | 
			
		||||
CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,yaffs,jffs2 noinitrd console=ttyS0,115200 init=/etc/preinit"
 | 
			
		||||
CONFIG_CPU_BIG_ENDIAN=y
 | 
			
		||||
CONFIG_CPU_HAS_LLSC=y
 | 
			
		||||
CONFIG_CPU_HAS_PREFETCH=y
 | 
			
		||||
CONFIG_CPU_HAS_SYNC=y
 | 
			
		||||
# CONFIG_CPU_LITTLE_ENDIAN is not set
 | 
			
		||||
# CONFIG_CPU_LOONGSON2 is not set
 | 
			
		||||
CONFIG_CPU_MIPS32=y
 | 
			
		||||
# CONFIG_CPU_MIPS32_R1 is not set
 | 
			
		||||
CONFIG_CPU_MIPS32_R2=y
 | 
			
		||||
# CONFIG_CPU_MIPS64_R1 is not set
 | 
			
		||||
# CONFIG_CPU_MIPS64_R2 is not set
 | 
			
		||||
CONFIG_CPU_MIPSR2=y
 | 
			
		||||
# CONFIG_CPU_NEVADA is not set
 | 
			
		||||
# CONFIG_CPU_R10000 is not set
 | 
			
		||||
# CONFIG_CPU_R3000 is not set
 | 
			
		||||
# CONFIG_CPU_R4300 is not set
 | 
			
		||||
# CONFIG_CPU_R4X00 is not set
 | 
			
		||||
# CONFIG_CPU_R5000 is not set
 | 
			
		||||
# CONFIG_CPU_R5432 is not set
 | 
			
		||||
# CONFIG_CPU_R6000 is not set
 | 
			
		||||
# CONFIG_CPU_R8000 is not set
 | 
			
		||||
# CONFIG_CPU_RM7000 is not set
 | 
			
		||||
# CONFIG_CPU_RM9000 is not set
 | 
			
		||||
# CONFIG_CPU_SB1 is not set
 | 
			
		||||
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
 | 
			
		||||
CONFIG_CPU_SUPPORTS_HIGHMEM=y
 | 
			
		||||
# CONFIG_CPU_TX39XX is not set
 | 
			
		||||
# CONFIG_CPU_TX49XX is not set
 | 
			
		||||
# CONFIG_CPU_VR41XX is not set
 | 
			
		||||
CONFIG_CRYPTO_AEAD=m
 | 
			
		||||
CONFIG_CRYPTO_AUTHENC=m
 | 
			
		||||
CONFIG_CRYPTO_GF128MUL=m
 | 
			
		||||
CONFIG_CSRC_R4K=y
 | 
			
		||||
CONFIG_DEVPORT=y
 | 
			
		||||
# CONFIG_DM9000 is not set
 | 
			
		||||
CONFIG_DMA_NEED_PCI_MAP_STATE=y
 | 
			
		||||
CONFIG_DMA_NONCOHERENT=y
 | 
			
		||||
# CONFIG_E1000E_ENABLED is not set
 | 
			
		||||
CONFIG_EARLY_PRINTK=y
 | 
			
		||||
# CONFIG_FIXED_PHY is not set
 | 
			
		||||
CONFIG_FS_POSIX_ACL=y
 | 
			
		||||
CONFIG_GENERIC_CLOCKEVENTS=y
 | 
			
		||||
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 | 
			
		||||
CONFIG_GENERIC_CMOS_UPDATE=y
 | 
			
		||||
CONFIG_GENERIC_FIND_NEXT_BIT=y
 | 
			
		||||
CONFIG_GENERIC_GPIO=y
 | 
			
		||||
# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
 | 
			
		||||
# CONFIG_GPIO_MCP23S08 is not set
 | 
			
		||||
CONFIG_HAS_DMA=y
 | 
			
		||||
CONFIG_HAS_IOMEM=y
 | 
			
		||||
CONFIG_HAS_IOPORT=y
 | 
			
		||||
CONFIG_HAVE_GPIO_LIB=y
 | 
			
		||||
CONFIG_HAVE_IDE=y
 | 
			
		||||
# CONFIG_HAVE_KPROBES is not set
 | 
			
		||||
# CONFIG_HAVE_KRETPROBES is not set
 | 
			
		||||
CONFIG_HAVE_OPROFILE=y
 | 
			
		||||
CONFIG_HW_HAS_PCI=y
 | 
			
		||||
CONFIG_HW_RANDOM=m
 | 
			
		||||
# CONFIG_I2C is not set
 | 
			
		||||
# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 | 
			
		||||
# CONFIG_IBM_NEW_EMAC_RGMII is not set
 | 
			
		||||
# CONFIG_IBM_NEW_EMAC_TAH is not set
 | 
			
		||||
# CONFIG_IBM_NEW_EMAC_ZMII is not set
 | 
			
		||||
CONFIG_ICPLUS_PHY=y
 | 
			
		||||
# CONFIG_IDE is not set
 | 
			
		||||
CONFIG_INITRAMFS_ROOT_GID=0
 | 
			
		||||
CONFIG_INITRAMFS_ROOT_UID=0
 | 
			
		||||
CONFIG_INITRAMFS_SOURCE="../../root"
 | 
			
		||||
CONFIG_IRQ_CPU=y
 | 
			
		||||
# CONFIG_LEDS_ALIX is not set
 | 
			
		||||
CONFIG_LEDS_GPIO=y
 | 
			
		||||
# CONFIG_LEMOTE_FULONG is not set
 | 
			
		||||
CONFIG_LZO_COMPRESS=m
 | 
			
		||||
CONFIG_LZO_DECOMPRESS=m
 | 
			
		||||
# CONFIG_MACH_ALCHEMY is not set
 | 
			
		||||
# CONFIG_MACH_DECSTATION is not set
 | 
			
		||||
# CONFIG_MACH_JAZZ is not set
 | 
			
		||||
# CONFIG_MACH_VR41XX is not set
 | 
			
		||||
# CONFIG_MDIO_BITBANG is not set
 | 
			
		||||
# CONFIG_MEMSTICK is not set
 | 
			
		||||
CONFIG_MICREL_PHY=y
 | 
			
		||||
CONFIG_MIPS=y
 | 
			
		||||
# CONFIG_MIPS_ATLAS is not set
 | 
			
		||||
# CONFIG_MIPS_COBALT is not set
 | 
			
		||||
CONFIG_MIPS_L1_CACHE_SHIFT=5
 | 
			
		||||
CONFIG_MIPS_MACHINE=y
 | 
			
		||||
# CONFIG_MIPS_MALTA is not set
 | 
			
		||||
CONFIG_MIPS_MT_DISABLED=y
 | 
			
		||||
# CONFIG_MIPS_MT_SMP is not set
 | 
			
		||||
# CONFIG_MIPS_MT_SMTC is not set
 | 
			
		||||
# CONFIG_MIPS_SEAD is not set
 | 
			
		||||
# CONFIG_MIPS_SIM is not set
 | 
			
		||||
CONFIG_MTD=y
 | 
			
		||||
# CONFIG_MTD_ABSENT is not set
 | 
			
		||||
CONFIG_MTD_BLKDEVS=y
 | 
			
		||||
CONFIG_MTD_BLOCK=y
 | 
			
		||||
# CONFIG_MTD_BLOCK2MTD is not set
 | 
			
		||||
# CONFIG_MTD_CFI is not set
 | 
			
		||||
CONFIG_MTD_CFI_I1=y
 | 
			
		||||
CONFIG_MTD_CFI_I2=y
 | 
			
		||||
# CONFIG_MTD_CFI_I4 is not set
 | 
			
		||||
# CONFIG_MTD_CFI_I8 is not set
 | 
			
		||||
CONFIG_MTD_CHAR=y
 | 
			
		||||
# CONFIG_MTD_CMDLINE_PARTS is not set
 | 
			
		||||
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 | 
			
		||||
CONFIG_MTD_CONCAT=y
 | 
			
		||||
# CONFIG_MTD_DEBUG is not set
 | 
			
		||||
# CONFIG_MTD_DOC2000 is not set
 | 
			
		||||
# CONFIG_MTD_DOC2001 is not set
 | 
			
		||||
# CONFIG_MTD_DOC2001PLUS is not set
 | 
			
		||||
# CONFIG_MTD_JEDECPROBE is not set
 | 
			
		||||
CONFIG_MTD_M25P80=y
 | 
			
		||||
CONFIG_MTD_MAP_BANK_WIDTH_1=y
 | 
			
		||||
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
 | 
			
		||||
CONFIG_MTD_MAP_BANK_WIDTH_2=y
 | 
			
		||||
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
 | 
			
		||||
CONFIG_MTD_MAP_BANK_WIDTH_4=y
 | 
			
		||||
# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
 | 
			
		||||
# CONFIG_MTD_MTDRAM is not set
 | 
			
		||||
CONFIG_MTD_NAND=y
 | 
			
		||||
# CONFIG_MTD_NAND_CAFE is not set
 | 
			
		||||
# CONFIG_MTD_NAND_DISKONCHIP is not set
 | 
			
		||||
# CONFIG_MTD_NAND_ECC_SMC is not set
 | 
			
		||||
CONFIG_MTD_NAND_IDS=y
 | 
			
		||||
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
 | 
			
		||||
# CONFIG_MTD_NAND_NANDSIM is not set
 | 
			
		||||
# CONFIG_MTD_NAND_PLATFORM is not set
 | 
			
		||||
CONFIG_MTD_NAND_RB4XX=y
 | 
			
		||||
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
 | 
			
		||||
# CONFIG_MTD_ONENAND is not set
 | 
			
		||||
CONFIG_MTD_PARTITIONS=y
 | 
			
		||||
# CONFIG_MTD_PHRAM is not set
 | 
			
		||||
# CONFIG_MTD_PLATRAM is not set
 | 
			
		||||
# CONFIG_MTD_PMC551 is not set
 | 
			
		||||
# CONFIG_MTD_RAM is not set
 | 
			
		||||
CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2
 | 
			
		||||
CONFIG_MTD_REDBOOT_PARTS=y
 | 
			
		||||
CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 | 
			
		||||
CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 | 
			
		||||
# CONFIG_MTD_ROM is not set
 | 
			
		||||
# CONFIG_MTD_SLRAM is not set
 | 
			
		||||
# CONFIG_NATSEMI is not set
 | 
			
		||||
# CONFIG_NE2K_PCI is not set
 | 
			
		||||
# CONFIG_NET_VENDOR_3COM is not set
 | 
			
		||||
# CONFIG_NO_IOPORT is not set
 | 
			
		||||
# CONFIG_OCF_OCF is not set
 | 
			
		||||
# CONFIG_PAGE_SIZE_16KB is not set
 | 
			
		||||
CONFIG_PAGE_SIZE_4KB=y
 | 
			
		||||
# CONFIG_PAGE_SIZE_64KB is not set
 | 
			
		||||
# CONFIG_PAGE_SIZE_8KB is not set
 | 
			
		||||
CONFIG_PCI=y
 | 
			
		||||
# CONFIG_PCIPCWATCHDOG is not set
 | 
			
		||||
CONFIG_PCI_DOMAINS=y
 | 
			
		||||
CONFIG_PHYLIB=y
 | 
			
		||||
# CONFIG_PMC_MSP is not set
 | 
			
		||||
# CONFIG_PMC_YOSEMITE is not set
 | 
			
		||||
# CONFIG_PNX8550_JBS is not set
 | 
			
		||||
# CONFIG_PNX8550_STB810 is not set
 | 
			
		||||
# CONFIG_QSEMI_PHY is not set
 | 
			
		||||
# CONFIG_R6040 is not set
 | 
			
		||||
# CONFIG_REALTEK_PHY is not set
 | 
			
		||||
# CONFIG_RTC is not set
 | 
			
		||||
CONFIG_RTC_LIB=y
 | 
			
		||||
CONFIG_RWSEM_GENERIC_SPINLOCK=y
 | 
			
		||||
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 | 
			
		||||
CONFIG_SCSI_WAIT_SCAN=m
 | 
			
		||||
# CONFIG_SERIAL_8250_EXTENDED is not set
 | 
			
		||||
CONFIG_SERIAL_8250_NR_UARTS=1
 | 
			
		||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=1
 | 
			
		||||
# CONFIG_SGI_IP22 is not set
 | 
			
		||||
# CONFIG_SGI_IP27 is not set
 | 
			
		||||
# CONFIG_SGI_IP28 is not set
 | 
			
		||||
# CONFIG_SGI_IP32 is not set
 | 
			
		||||
# CONFIG_SIBYTE_BIGSUR is not set
 | 
			
		||||
# CONFIG_SIBYTE_CARMEL is not set
 | 
			
		||||
# CONFIG_SIBYTE_CRHINE is not set
 | 
			
		||||
# CONFIG_SIBYTE_CRHONE is not set
 | 
			
		||||
# CONFIG_SIBYTE_LITTLESUR is not set
 | 
			
		||||
# CONFIG_SIBYTE_RHONE is not set
 | 
			
		||||
# CONFIG_SIBYTE_SENTOSA is not set
 | 
			
		||||
# CONFIG_SIBYTE_SWARM is not set
 | 
			
		||||
CONFIG_SLABINFO=y
 | 
			
		||||
# CONFIG_SMSC_PHY is not set
 | 
			
		||||
# CONFIG_SOFT_WATCHDOG is not set
 | 
			
		||||
# CONFIG_SPARSEMEM_STATIC is not set
 | 
			
		||||
# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 | 
			
		||||
CONFIG_SPI=y
 | 
			
		||||
CONFIG_SPI_AR71XX=y
 | 
			
		||||
CONFIG_SPI_BITBANG=y
 | 
			
		||||
# CONFIG_SPI_GPIO is not set
 | 
			
		||||
CONFIG_SPI_MASTER=y
 | 
			
		||||
# CONFIG_SPI_SPIDEV is not set
 | 
			
		||||
CONFIG_SSB_POSSIBLE=y
 | 
			
		||||
CONFIG_SYSVIPC_SYSCTL=y
 | 
			
		||||
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
 | 
			
		||||
CONFIG_SYS_HAS_CPU_MIPS32_R2=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_TC35815 is not set
 | 
			
		||||
# CONFIG_THERMAL is not set
 | 
			
		||||
CONFIG_TICK_ONESHOT=y
 | 
			
		||||
# CONFIG_TOSHIBA_JMR3927 is not set
 | 
			
		||||
# CONFIG_TOSHIBA_RBTX4927 is not set
 | 
			
		||||
# CONFIG_TOSHIBA_RBTX4938 is not set
 | 
			
		||||
CONFIG_TRAD_SIGNALS=y
 | 
			
		||||
# CONFIG_VGASTATE is not set
 | 
			
		||||
# CONFIG_VIA_RHINE is not set
 | 
			
		||||
CONFIG_VIDEO_V4L2_COMMON=m
 | 
			
		||||
CONFIG_YAFFS_9BYTE_TAGS=y
 | 
			
		||||
CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y
 | 
			
		||||
CONFIG_YAFFS_AUTO_YAFFS2=y
 | 
			
		||||
CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=0
 | 
			
		||||
# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
 | 
			
		||||
# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
 | 
			
		||||
CONFIG_YAFFS_FS=y
 | 
			
		||||
CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 | 
			
		||||
CONFIG_YAFFS_YAFFS1=y
 | 
			
		||||
CONFIG_YAFFS_YAFFS2=y
 | 
			
		||||
CONFIG_ZONE_DMA_FLAG=0
 | 
			
		||||
							
								
								
									
										23
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
if ATHEROS_AR71XX
 | 
			
		||||
 | 
			
		||||
config AR71XX_EARLY_SERIAL
 | 
			
		||||
	bool "Use early serial console"
 | 
			
		||||
	default n
 | 
			
		||||
 | 
			
		||||
menu "Atheros AR71xx machine selection"
 | 
			
		||||
 | 
			
		||||
config AR71XX_MACH_GENERIC
 | 
			
		||||
	bool "Generic AR71xx based machine support"
 | 
			
		||||
	default y
 | 
			
		||||
 | 
			
		||||
config AR71XX_MACH_WP543
 | 
			
		||||
	bool "Compex WP543 board support"
 | 
			
		||||
	default y
 | 
			
		||||
 | 
			
		||||
config AR71XX_MACH_RB_4XX
 | 
			
		||||
	bool "MikroTik RouterBOARD 4xx series support"
 | 
			
		||||
	default y
 | 
			
		||||
 | 
			
		||||
endmenu
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
							
								
								
									
										15
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
#
 | 
			
		||||
# Makefile for the Atheros AR71xx SoC specific parts of the kernel
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
# Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
#
 | 
			
		||||
# This program 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.
 | 
			
		||||
 | 
			
		||||
obj-y	:= prom.o irq.o setup.o platform.o gpio.o ar71xx.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_AR71XX_MACH_GENERIC)	+= mach-generic.o
 | 
			
		||||
obj-$(CONFIG_AR71XX_MACH_RB_4XX)	+= mach-rb-4xx.o
 | 
			
		||||
obj-$(CONFIG_AR71XX_MACH_WP543)		+= mach-wp543.o
 | 
			
		||||
							
								
								
									
										55
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  AR71xx SoC routines
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
 | 
			
		||||
void __iomem *ar71xx_ddr_base;
 | 
			
		||||
void __iomem *ar71xx_pll_base;
 | 
			
		||||
void __iomem *ar71xx_reset_base;
 | 
			
		||||
void __iomem *ar71xx_gpio_base;
 | 
			
		||||
void __iomem *ar71xx_usb_ctrl_base;
 | 
			
		||||
 | 
			
		||||
void ar71xx_device_stop(u32 mask)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	local_irq_save(flags);
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_RESET_MODULE,
 | 
			
		||||
			ar71xx_reset_rr(RESET_REG_RESET_MODULE) | mask);
 | 
			
		||||
	local_irq_restore(flags);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ar71xx_device_stop);
 | 
			
		||||
 | 
			
		||||
void ar71xx_device_start(u32 mask)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	local_irq_save(flags);
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_RESET_MODULE,
 | 
			
		||||
			ar71xx_reset_rr(RESET_REG_RESET_MODULE) & ~mask);
 | 
			
		||||
	local_irq_restore(flags);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ar71xx_device_start);
 | 
			
		||||
 | 
			
		||||
void ar71xx_ddr_flush(u32 reg)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_ddr_wr(reg, 1);
 | 
			
		||||
	while ((ar71xx_ddr_rr(reg) & 0x1));
 | 
			
		||||
 | 
			
		||||
	ar71xx_ddr_wr(reg, 1);
 | 
			
		||||
	while ((ar71xx_ddr_rr(reg) & 0x1));
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ar71xx_ddr_flush);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										135
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,135 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx SoC GPIO API support
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/init.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/ioport.h>
 | 
			
		||||
#include <linux/gpio.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
 | 
			
		||||
static DEFINE_SPINLOCK(ar71xx_gpio_lock);
 | 
			
		||||
 | 
			
		||||
void __ar71xx_gpio_set_value(unsigned gpio, int value)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (value)
 | 
			
		||||
		ar71xx_gpio_wr(GPIO_REG_SET, (1 << gpio));
 | 
			
		||||
	else
 | 
			
		||||
		ar71xx_gpio_wr(GPIO_REG_CLEAR, (1 << gpio));
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__ar71xx_gpio_set_value);
 | 
			
		||||
 | 
			
		||||
int __ar71xx_gpio_get_value(unsigned gpio)
 | 
			
		||||
{
 | 
			
		||||
	return (ar71xx_gpio_rr(GPIO_REG_IN) & (1 << gpio)) ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__ar71xx_gpio_get_value);
 | 
			
		||||
 | 
			
		||||
static int ar71xx_gpio_get_value(struct gpio_chip *chip, unsigned offset)
 | 
			
		||||
{
 | 
			
		||||
	return __ar71xx_gpio_get_value(offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_gpio_set_value(struct gpio_chip *chip,
 | 
			
		||||
				  unsigned offset, int value)
 | 
			
		||||
{
 | 
			
		||||
	__ar71xx_gpio_set_value(offset, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ar71xx_gpio_direction_input(struct gpio_chip *chip,
 | 
			
		||||
				       unsigned offset)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
 | 
			
		||||
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_OE,
 | 
			
		||||
			ar71xx_gpio_rr(GPIO_REG_OE) & ~(1 << offset));
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ar71xx_gpio_direction_output(struct gpio_chip *chip,
 | 
			
		||||
					unsigned offset, int value)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (value)
 | 
			
		||||
		ar71xx_gpio_wr(GPIO_REG_SET, (1 << offset));
 | 
			
		||||
	else
 | 
			
		||||
		ar71xx_gpio_wr(GPIO_REG_CLEAR, (1 << offset));
 | 
			
		||||
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_OE,
 | 
			
		||||
			ar71xx_gpio_rr(GPIO_REG_OE) | (1 << offset));
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gpio_chip ar71xx_gpio_chip = {
 | 
			
		||||
	.label			= "ar71xx",
 | 
			
		||||
	.get			= ar71xx_gpio_get_value,
 | 
			
		||||
	.set			= ar71xx_gpio_set_value,
 | 
			
		||||
	.direction_input	= ar71xx_gpio_direction_input,
 | 
			
		||||
	.direction_output	= ar71xx_gpio_direction_output,
 | 
			
		||||
	.base			= 0,
 | 
			
		||||
	.ngpio			= AR71XX_GPIO_COUNT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void ar71xx_gpio_function_enable(u32 mask)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
 | 
			
		||||
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_FUNC, ar71xx_gpio_rr(GPIO_REG_FUNC) | mask);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ar71xx_gpio_function_disable(u32 mask)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ar71xx_gpio_lock, flags);
 | 
			
		||||
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_FUNC, ar71xx_gpio_rr(GPIO_REG_FUNC) & ~mask);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init ar71xx_gpio_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (!request_mem_region(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
 | 
			
		||||
				"AR71xx GPIO controller"))
 | 
			
		||||
		panic("cannot allocate AR71xx GPIO registers page");
 | 
			
		||||
 | 
			
		||||
	err = gpiochip_add(&ar71xx_gpio_chip);
 | 
			
		||||
	if (err)
 | 
			
		||||
		panic("cannot add AR71xx GPIO chip, error=%d", err);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										285
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/irq.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/irq.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,285 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx SoC specific interrupt handling
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Parts of this file are based on Atheros' 2.6.15 BSP
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/init.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/irq.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/irq_cpu.h>
 | 
			
		||||
#include <asm/mipsregs.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PCI
 | 
			
		||||
static void ar71xx_pci_irq_dispatch(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 pending;
 | 
			
		||||
 | 
			
		||||
	pending = ar71xx_reset_rr(RESET_REG_PCI_INT_STATUS) &
 | 
			
		||||
	    ar71xx_reset_rr(RESET_REG_PCI_INT_ENABLE);
 | 
			
		||||
 | 
			
		||||
	if (pending & PCI_INT_DEV0)
 | 
			
		||||
		do_IRQ(AR71XX_PCI_IRQ_DEV0);
 | 
			
		||||
 | 
			
		||||
	else if (pending & PCI_INT_DEV1)
 | 
			
		||||
		do_IRQ(AR71XX_PCI_IRQ_DEV1);
 | 
			
		||||
 | 
			
		||||
	else if (pending & PCI_INT_DEV2)
 | 
			
		||||
		do_IRQ(AR71XX_PCI_IRQ_DEV2);
 | 
			
		||||
 | 
			
		||||
	else
 | 
			
		||||
		spurious_interrupt();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_pci_irq_unmask(unsigned int irq)
 | 
			
		||||
{
 | 
			
		||||
	irq -= AR71XX_PCI_IRQ_BASE;
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_PCI_INT_ENABLE,
 | 
			
		||||
		ar71xx_reset_rr(RESET_REG_PCI_INT_ENABLE) | (1 << irq));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_pci_irq_mask(unsigned int irq)
 | 
			
		||||
{
 | 
			
		||||
	irq -= AR71XX_PCI_IRQ_BASE;
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_PCI_INT_ENABLE,
 | 
			
		||||
		ar71xx_reset_rr(RESET_REG_PCI_INT_ENABLE) & ~(1 << irq));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct irq_chip ar71xx_pci_irq_chip = {
 | 
			
		||||
	.name		= "AR71XX PCI ",
 | 
			
		||||
	.mask		= ar71xx_pci_irq_mask,
 | 
			
		||||
	.unmask		= ar71xx_pci_irq_unmask,
 | 
			
		||||
	.mask_ack	= ar71xx_pci_irq_mask,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct irqaction ar71xx_pci_irqaction = {
 | 
			
		||||
	.handler	= no_action,
 | 
			
		||||
	.name		= "cascade [AR71XX PCI]",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init ar71xx_pci_irq_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_PCI_INT_ENABLE, 0);
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_PCI_INT_STATUS, 0);
 | 
			
		||||
 | 
			
		||||
	for (i = AR71XX_PCI_IRQ_BASE;
 | 
			
		||||
	     i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) {
 | 
			
		||||
		irq_desc[i].status = IRQ_DISABLED;
 | 
			
		||||
		set_irq_chip_and_handler(i, &ar71xx_pci_irq_chip,
 | 
			
		||||
					 handle_level_irq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setup_irq(AR71XX_CPU_IRQ_PCI, &ar71xx_pci_irqaction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_PCI */
 | 
			
		||||
 | 
			
		||||
static void ar71xx_gpio_irq_dispatch(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 pending;
 | 
			
		||||
 | 
			
		||||
	pending = ar71xx_gpio_rr(GPIO_REG_INT_PENDING)
 | 
			
		||||
		& ar71xx_gpio_rr(GPIO_REG_INT_ENABLE);
 | 
			
		||||
 | 
			
		||||
	if (pending)
 | 
			
		||||
		do_IRQ(AR71XX_GPIO_IRQ_BASE + fls(pending) - 1);
 | 
			
		||||
	else
 | 
			
		||||
		spurious_interrupt();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_gpio_irq_unmask(unsigned int irq)
 | 
			
		||||
{
 | 
			
		||||
	irq -= AR71XX_GPIO_IRQ_BASE;
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_INT_ENABLE,
 | 
			
		||||
			ar71xx_gpio_rr(GPIO_REG_INT_ENABLE) | (1 << irq));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_gpio_irq_mask(unsigned int irq)
 | 
			
		||||
{
 | 
			
		||||
	irq -= AR71XX_GPIO_IRQ_BASE;
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_INT_ENABLE,
 | 
			
		||||
			ar71xx_gpio_rr(GPIO_REG_INT_ENABLE) & ~(1 << irq));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
static int ar71xx_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: implement */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define ar71xx_gpio_irq_set_type	NULL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct irq_chip ar71xx_gpio_irq_chip = {
 | 
			
		||||
	.name		= "AR71XX GPIO",
 | 
			
		||||
	.unmask		= ar71xx_gpio_irq_unmask,
 | 
			
		||||
	.mask		= ar71xx_gpio_irq_mask,
 | 
			
		||||
	.mask_ack	= ar71xx_gpio_irq_mask,
 | 
			
		||||
	.set_type	= ar71xx_gpio_irq_set_type,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct irqaction ar71xx_gpio_irqaction = {
 | 
			
		||||
	.handler	= no_action,
 | 
			
		||||
	.name		= "cascade [AR71XX GPIO]",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define GPIO_IRQ_INIT_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED)
 | 
			
		||||
#define GPIO_INT_ALL	0xffff
 | 
			
		||||
 | 
			
		||||
static void __init ar71xx_gpio_irq_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_INT_ENABLE, 0);
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_INT_PENDING, 0);
 | 
			
		||||
 | 
			
		||||
	/* setup type of all GPIO interrupts to level sensitive */
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_INT_TYPE, GPIO_INT_ALL);
 | 
			
		||||
 | 
			
		||||
	/* setup polarity of all GPIO interrupts to active high */
 | 
			
		||||
	ar71xx_gpio_wr(GPIO_REG_INT_POLARITY, GPIO_INT_ALL);
 | 
			
		||||
 | 
			
		||||
	for (i = AR71XX_GPIO_IRQ_BASE;
 | 
			
		||||
	     i < AR71XX_GPIO_IRQ_BASE + AR71XX_GPIO_IRQ_COUNT; i++) {
 | 
			
		||||
		irq_desc[i].status = GPIO_IRQ_INIT_STATUS;
 | 
			
		||||
		set_irq_chip_and_handler(i, &ar71xx_gpio_irq_chip,
 | 
			
		||||
					 handle_level_irq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setup_irq(AR71XX_MISC_IRQ_GPIO, &ar71xx_gpio_irqaction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_misc_irq_dispatch(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 pending;
 | 
			
		||||
 | 
			
		||||
	pending = ar71xx_reset_rr(RESET_REG_MISC_INT_STATUS)
 | 
			
		||||
	    & ar71xx_reset_rr(RESET_REG_MISC_INT_ENABLE);
 | 
			
		||||
 | 
			
		||||
	if (pending & MISC_INT_UART)
 | 
			
		||||
		do_IRQ(AR71XX_MISC_IRQ_UART);
 | 
			
		||||
 | 
			
		||||
	else if (pending & MISC_INT_DMA)
 | 
			
		||||
		do_IRQ(AR71XX_MISC_IRQ_DMA);
 | 
			
		||||
 | 
			
		||||
	else if (pending & MISC_INT_PERFC)
 | 
			
		||||
		do_IRQ(AR71XX_MISC_IRQ_PERFC);
 | 
			
		||||
 | 
			
		||||
	else if (pending & MISC_INT_TIMER)
 | 
			
		||||
		do_IRQ(AR71XX_MISC_IRQ_TIMER);
 | 
			
		||||
 | 
			
		||||
	else if (pending & MISC_INT_OHCI)
 | 
			
		||||
		do_IRQ(AR71XX_MISC_IRQ_OHCI);
 | 
			
		||||
 | 
			
		||||
	else if (pending & MISC_INT_ERROR)
 | 
			
		||||
		do_IRQ(AR71XX_MISC_IRQ_ERROR);
 | 
			
		||||
 | 
			
		||||
	else if (pending & MISC_INT_GPIO)
 | 
			
		||||
		ar71xx_gpio_irq_dispatch();
 | 
			
		||||
 | 
			
		||||
	else if (pending & MISC_INT_WDOG)
 | 
			
		||||
		do_IRQ(AR71XX_MISC_IRQ_WDOG);
 | 
			
		||||
 | 
			
		||||
	else
 | 
			
		||||
		spurious_interrupt();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_misc_irq_unmask(unsigned int irq)
 | 
			
		||||
{
 | 
			
		||||
	irq -= AR71XX_MISC_IRQ_BASE;
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_MISC_INT_ENABLE,
 | 
			
		||||
		ar71xx_reset_rr(RESET_REG_MISC_INT_ENABLE) | (1 << irq));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_misc_irq_mask(unsigned int irq)
 | 
			
		||||
{
 | 
			
		||||
	irq -= AR71XX_MISC_IRQ_BASE;
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_MISC_INT_ENABLE,
 | 
			
		||||
		ar71xx_reset_rr(RESET_REG_MISC_INT_ENABLE) & ~(1 << irq));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct irq_chip ar71xx_misc_irq_chip = {
 | 
			
		||||
	.name		= "AR71XX MISC",
 | 
			
		||||
	.unmask		= ar71xx_misc_irq_unmask,
 | 
			
		||||
	.mask		= ar71xx_misc_irq_mask,
 | 
			
		||||
	.mask_ack	= ar71xx_misc_irq_mask,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct irqaction ar71xx_misc_irqaction = {
 | 
			
		||||
	.handler	= no_action,
 | 
			
		||||
	.name		= "cascade [AR71XX MISC]",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init ar71xx_misc_irq_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_MISC_INT_ENABLE, 0);
 | 
			
		||||
	ar71xx_reset_wr(RESET_REG_MISC_INT_STATUS, 0);
 | 
			
		||||
 | 
			
		||||
	for (i = AR71XX_MISC_IRQ_BASE;
 | 
			
		||||
	     i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) {
 | 
			
		||||
		irq_desc[i].status = IRQ_DISABLED;
 | 
			
		||||
		set_irq_chip_and_handler(i, &ar71xx_misc_irq_chip,
 | 
			
		||||
					 handle_level_irq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setup_irq(AR71XX_CPU_IRQ_MISC, &ar71xx_misc_irqaction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
asmlinkage void plat_irq_dispatch(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long pending;
 | 
			
		||||
 | 
			
		||||
	pending = read_c0_status() & read_c0_cause() & ST0_IM;
 | 
			
		||||
 | 
			
		||||
	if (pending & STATUSF_IP7)
 | 
			
		||||
		do_IRQ(AR71XX_CPU_IRQ_TIMER);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PCI
 | 
			
		||||
	else if (pending & STATUSF_IP2)
 | 
			
		||||
		ar71xx_pci_irq_dispatch();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	else if (pending & STATUSF_IP4)
 | 
			
		||||
		do_IRQ(AR71XX_CPU_IRQ_GE0);
 | 
			
		||||
 | 
			
		||||
	else if (pending & STATUSF_IP5)
 | 
			
		||||
		do_IRQ(AR71XX_CPU_IRQ_GE1);
 | 
			
		||||
 | 
			
		||||
	else if (pending & STATUSF_IP3)
 | 
			
		||||
		do_IRQ(AR71XX_CPU_IRQ_USB);
 | 
			
		||||
 | 
			
		||||
	else if (pending & STATUSF_IP6)
 | 
			
		||||
		ar71xx_misc_irq_dispatch();
 | 
			
		||||
 | 
			
		||||
	else
 | 
			
		||||
		spurious_interrupt();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init arch_init_irq(void)
 | 
			
		||||
{
 | 
			
		||||
	mips_cpu_irq_init();
 | 
			
		||||
 | 
			
		||||
	ar71xx_misc_irq_init();
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PCI
 | 
			
		||||
	ar71xx_pci_irq_init();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	ar71xx_gpio_irq_init();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Generic AR71xx machine setup
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/init.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/spi/spi.h>
 | 
			
		||||
#include <linux/spi/flash.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mips_machine.h>
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
#include <asm/mach-ar71xx/pci.h>
 | 
			
		||||
#include <asm/mach-ar71xx/platform.h>
 | 
			
		||||
 | 
			
		||||
static struct spi_board_info ar71xx_generic_spi_info[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.bus_num	= 0,
 | 
			
		||||
		.chip_select	= 0,
 | 
			
		||||
		.max_speed_hz	= 25000000,
 | 
			
		||||
		.modalias	= "m25p80",
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct ar71xx_pci_irq ar71xx_generic_pci_irqs[] __initdata = {
 | 
			
		||||
	{
 | 
			
		||||
		.slot	= 0,
 | 
			
		||||
		.pin	= 1,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV0,
 | 
			
		||||
	}, {
 | 
			
		||||
		.slot	= 1,
 | 
			
		||||
		.pin	= 1,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV1,
 | 
			
		||||
	}, {
 | 
			
		||||
		.slot	= 2,
 | 
			
		||||
		.pin	= 1,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV2,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init ar71xx_generic_init(void)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_add_device_spi(NULL, ar71xx_generic_spi_info,
 | 
			
		||||
				ARRAY_SIZE(ar71xx_generic_spi_info));
 | 
			
		||||
 | 
			
		||||
	ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x001f0000);
 | 
			
		||||
	ar71xx_add_device_eth(1, PHY_INTERFACE_MODE_RMII, 0xffffffff);
 | 
			
		||||
 | 
			
		||||
	ar71xx_add_device_usb();
 | 
			
		||||
 | 
			
		||||
	ar71xx_pci_init(ARRAY_SIZE(ar71xx_generic_pci_irqs),
 | 
			
		||||
			ar71xx_generic_pci_irqs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MIPS_MACHINE(MACH_AR71XX_GENERIC, "Generic AR71xx board", ar71xx_generic_init);
 | 
			
		||||
							
								
								
									
										192
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,192 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  MikroTik RouterBOARD 4xx series support
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/platform_device.h>
 | 
			
		||||
#include <linux/irq.h>
 | 
			
		||||
#include <linux/mmc/host.h>
 | 
			
		||||
#include <linux/spi/spi.h>
 | 
			
		||||
#include <linux/spi/flash.h>
 | 
			
		||||
#include <linux/spi/mmc_spi.h>
 | 
			
		||||
#include <linux/leds.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mips_machine.h>
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
#include <asm/mach-ar71xx/pci.h>
 | 
			
		||||
#include <asm/mach-ar71xx/platform.h>
 | 
			
		||||
 | 
			
		||||
#define RB4XX_GPIO_USER_LED	4
 | 
			
		||||
 | 
			
		||||
static struct gpio_led rb4xx_leds_gpio[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.name		= "rb4xx:yellow:user",
 | 
			
		||||
		.gpio		= RB4XX_GPIO_USER_LED,
 | 
			
		||||
		.active_low	= 0,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct gpio_led_platform_data rb4xx_leds_gpio_data = {
 | 
			
		||||
	.leds		= rb4xx_leds_gpio,
 | 
			
		||||
	.num_leds	= ARRAY_SIZE(rb4xx_leds_gpio),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct platform_device rb4xx_leds_gpio_device = {
 | 
			
		||||
	.name	= "leds-gpio",
 | 
			
		||||
	.id	= -1,
 | 
			
		||||
	.dev = {
 | 
			
		||||
		.platform_data = &rb4xx_leds_gpio_data,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct platform_device rb4xx_nand_device = {
 | 
			
		||||
	.name	= "rb4xx-nand",
 | 
			
		||||
	.id	= -1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct ar71xx_pci_irq rb4xx_pci_irqs[] __initdata = {
 | 
			
		||||
	{
 | 
			
		||||
		.slot	= 1,
 | 
			
		||||
		.pin	= 1,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV0,
 | 
			
		||||
	}, {
 | 
			
		||||
		.slot	= 1,
 | 
			
		||||
		.pin	= 2,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV1,
 | 
			
		||||
	}, {
 | 
			
		||||
		.slot	= 2,
 | 
			
		||||
		.pin	= 1,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV1,
 | 
			
		||||
	}, {
 | 
			
		||||
		.slot	= 3,
 | 
			
		||||
		.pin	= 1,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV2,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
/*
 | 
			
		||||
 * SPI device support is experimental
 | 
			
		||||
 */
 | 
			
		||||
static struct flash_platform_data rb4xx_flash_data = {
 | 
			
		||||
	.type	= "pm25lv512",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct spi_board_info rb4xx_spi_info[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.bus_num	= 0,
 | 
			
		||||
		.chip_select	= 0,
 | 
			
		||||
		.max_speed_hz	= 25000000,
 | 
			
		||||
		.modalias	= "m25p80",
 | 
			
		||||
		.platform_data	= &rb4xx_flash_data,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct mmc_spi_platform_data rb433_mmc_data = {
 | 
			
		||||
	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct spi_board_info rb433_spi_info[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.bus_num	= 0,
 | 
			
		||||
		.chip_select	= 0,
 | 
			
		||||
		.max_speed_hz	= 25000000,
 | 
			
		||||
		.modalias	= "m25p80",
 | 
			
		||||
		.platform_data	= &rb433_flash_data,
 | 
			
		||||
	}, {
 | 
			
		||||
		.bus_num	= 0,
 | 
			
		||||
		.chip_select	= 2,
 | 
			
		||||
		.max_speed_hz	= 25000000,
 | 
			
		||||
		.modalias	= "mmc_spi",
 | 
			
		||||
		.platform_data	= &rb433_mmc_data,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static u32 rb433_spi_get_ioc_base(u8 chip_select, int cs_high, int is_on)
 | 
			
		||||
{
 | 
			
		||||
	u32 ret;
 | 
			
		||||
 | 
			
		||||
	if (is_on == AR71XX_SPI_CS_INACTIVE) {
 | 
			
		||||
		ret = SPI_IOC_CS0 | SPI_IOC_CS1;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (cs_high) {
 | 
			
		||||
			ret = SPI_IOC_CS0 | SPI_IOC_CS1;
 | 
			
		||||
		} else {
 | 
			
		||||
			if ((chip_select ^ 2) == 0)
 | 
			
		||||
				ret = SPI_IOC_CS1 ^ (SPI_IOC_CS0 | SPI_IOC_CS1);
 | 
			
		||||
			else
 | 
			
		||||
				ret = SPI_IOC_CS0 ^ (SPI_IOC_CS0 | SPI_IOC_CS1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ar71xx_spi_platform_data rb433_spi_data = {
 | 
			
		||||
	.bus_num		= 0,
 | 
			
		||||
	.num_chipselect		= 3,
 | 
			
		||||
	.get_ioc_base		= rb433_spi_get_ioc_base,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void rb4xx_add_device_spi(void)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_add_device_spi(NULL, rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rb433_add_device_spi(void)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_add_device_spi(&rb433_spi_data, rb433_spi_info,
 | 
			
		||||
				ARRAY_SIZE(rb433_spi_info));
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline void rb4xx_add_device_spi(void) {}
 | 
			
		||||
static inline void rb433_add_device_spi(void) {}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void __init rb411_setup(void)
 | 
			
		||||
{
 | 
			
		||||
	rb4xx_add_device_spi();
 | 
			
		||||
 | 
			
		||||
	ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x00000001);
 | 
			
		||||
 | 
			
		||||
	platform_device_register(&rb4xx_leds_gpio_device);
 | 
			
		||||
	platform_device_register(&rb4xx_nand_device);
 | 
			
		||||
 | 
			
		||||
	ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MIPS_MACHINE(MACH_AR71XX_RB_411, "MikroTik RouterBOARD 411/A/AH", rb411_setup);
 | 
			
		||||
 | 
			
		||||
static void __init rb433_setup(void)
 | 
			
		||||
{
 | 
			
		||||
	rb433_add_device_spi();
 | 
			
		||||
 | 
			
		||||
	ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x00000001);
 | 
			
		||||
	ar71xx_add_device_eth(1, PHY_INTERFACE_MODE_RMII, 0xffffffff);
 | 
			
		||||
 | 
			
		||||
	platform_device_register(&rb4xx_leds_gpio_device);
 | 
			
		||||
	platform_device_register(&rb4xx_nand_device);
 | 
			
		||||
 | 
			
		||||
	ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MIPS_MACHINE(MACH_AR71XX_RB_433, "MikroTik RouterBOARD 433/AH", rb433_setup);
 | 
			
		||||
 | 
			
		||||
static void __init rb450_setup(void)
 | 
			
		||||
{
 | 
			
		||||
	rb4xx_add_device_spi();
 | 
			
		||||
 | 
			
		||||
	ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x00000001);
 | 
			
		||||
	ar71xx_add_device_eth(1, PHY_INTERFACE_MODE_RMII, 0xffffffff);
 | 
			
		||||
 | 
			
		||||
	platform_device_register(&rb4xx_leds_gpio_device);
 | 
			
		||||
	platform_device_register(&rb4xx_nand_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MIPS_MACHINE(MACH_AR71XX_RB_450, "MikroTik RouterBOARD 450", rb450_setup);
 | 
			
		||||
							
								
								
									
										56
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Compex WP543 board support
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/platform_device.h>
 | 
			
		||||
#include <linux/spi/spi.h>
 | 
			
		||||
#include <linux/spi/flash.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mips_machine.h>
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
#include <asm/mach-ar71xx/pci.h>
 | 
			
		||||
#include <asm/mach-ar71xx/platform.h>
 | 
			
		||||
 | 
			
		||||
static struct flash_platform_data wp543_flash_data = {
 | 
			
		||||
	/* TODO: add partition map */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct spi_board_info wp543_spi_info[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.bus_num	= 0,
 | 
			
		||||
		.chip_select	= 0,
 | 
			
		||||
		.max_speed_hz	= 25000000,
 | 
			
		||||
		.modalias	= "m25p80",
 | 
			
		||||
		.platform_data	= &wp543_flash_data,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct ar71xx_pci_irq wp543_pci_irqs[] __initdata = {
 | 
			
		||||
	{
 | 
			
		||||
		.slot	= 1,
 | 
			
		||||
		.pin	= 1,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV0,
 | 
			
		||||
	}, {
 | 
			
		||||
		.slot	= 1,
 | 
			
		||||
		.pin	= 2,
 | 
			
		||||
		.irq	= AR71XX_PCI_IRQ_DEV1,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init wp543_setup(void)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_add_device_spi(NULL, wp543_spi_info, ARRAY_SIZE(wp543_spi_info));
 | 
			
		||||
 | 
			
		||||
	ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x00000001);
 | 
			
		||||
 | 
			
		||||
	ar71xx_pci_init(ARRAY_SIZE(wp543_pci_irqs), wp543_pci_irqs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MIPS_MACHINE(MACH_AR71XX_WP543, "Compex WP543", wp543_setup);
 | 
			
		||||
							
								
								
									
										301
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/platform.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/platform.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,301 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx SoC platform devices
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Parts of this file are based on Atheros' 2.6.15 BSP
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/init.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/dma-mapping.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/serial_8250.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mips_machine.h>
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
#include <asm/mach-ar71xx/platform.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * OHCI (USB full speed host controller)
 | 
			
		||||
 */
 | 
			
		||||
static struct resource ar71xx_usb_ohci_resources[] = {
 | 
			
		||||
	[0] = {
 | 
			
		||||
		.start	= AR71XX_OHCI_BASE,
 | 
			
		||||
		.end	= AR71XX_OHCI_BASE + AR71XX_OHCI_SIZE - 1,
 | 
			
		||||
		.flags	= IORESOURCE_MEM,
 | 
			
		||||
	},
 | 
			
		||||
	[1] = {
 | 
			
		||||
		.start	= AR71XX_MISC_IRQ_OHCI,
 | 
			
		||||
		.end	= AR71XX_MISC_IRQ_OHCI,
 | 
			
		||||
		.flags	= IORESOURCE_IRQ,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static u64 ar71xx_ohci_dmamask = DMA_BIT_MASK(32);
 | 
			
		||||
static struct platform_device ar71xx_usb_ohci_device = {
 | 
			
		||||
	.name		= "ar71xx-ohci",
 | 
			
		||||
	.id		= 0,
 | 
			
		||||
	.resource	= ar71xx_usb_ohci_resources,
 | 
			
		||||
	.num_resources	= ARRAY_SIZE(ar71xx_usb_ohci_resources),
 | 
			
		||||
	.dev = {
 | 
			
		||||
		.dma_mask		= &ar71xx_ohci_dmamask,
 | 
			
		||||
		.coherent_dma_mask	= DMA_BIT_MASK(32),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * EHCI (USB full speed host controller)
 | 
			
		||||
 */
 | 
			
		||||
static struct resource ar71xx_usb_ehci_resources[] = {
 | 
			
		||||
	[0] = {
 | 
			
		||||
		.start	= AR71XX_EHCI_BASE,
 | 
			
		||||
		.end	= AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1,
 | 
			
		||||
		.flags	= IORESOURCE_MEM,
 | 
			
		||||
	},
 | 
			
		||||
	[1] = {
 | 
			
		||||
		.start	= AR71XX_CPU_IRQ_USB,
 | 
			
		||||
		.end	= AR71XX_CPU_IRQ_USB,
 | 
			
		||||
		.flags	= IORESOURCE_IRQ,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static u64 ar71xx_ehci_dmamask = DMA_BIT_MASK(32);
 | 
			
		||||
static struct platform_device ar71xx_usb_ehci_device = {
 | 
			
		||||
	.name		= "ar71xx-ehci",
 | 
			
		||||
	.id		= 0,
 | 
			
		||||
	.resource	= ar71xx_usb_ehci_resources,
 | 
			
		||||
	.num_resources	= ARRAY_SIZE(ar71xx_usb_ehci_resources),
 | 
			
		||||
	.dev = {
 | 
			
		||||
		.dma_mask		= &ar71xx_ehci_dmamask,
 | 
			
		||||
		.coherent_dma_mask	= DMA_BIT_MASK(32),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define AR71XX_USB_RESET_MASK \
 | 
			
		||||
	(RESET_MODULE_USB_HOST | RESET_MODULE_USB_PHY \
 | 
			
		||||
	| RESET_MODULE_USB_OHCI_DLL)
 | 
			
		||||
 | 
			
		||||
void __init ar71xx_add_device_usb(void)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_device_stop(AR71XX_USB_RESET_MASK);
 | 
			
		||||
	mdelay(1000);
 | 
			
		||||
	ar71xx_device_start(AR71XX_USB_RESET_MASK);
 | 
			
		||||
 | 
			
		||||
	/* Turning on the Buff and Desc swap bits */
 | 
			
		||||
	ar71xx_usb_ctrl_wr(USB_CTRL_REG_CONFIG, 0xf0000);
 | 
			
		||||
 | 
			
		||||
	/* WAR for HW bug. Here it adjusts the duration between two SOFS */
 | 
			
		||||
	ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x20c00);
 | 
			
		||||
 | 
			
		||||
	mdelay(900);
 | 
			
		||||
 | 
			
		||||
	platform_device_register(&ar71xx_usb_ohci_device);
 | 
			
		||||
	platform_device_register(&ar71xx_usb_ehci_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_AR71XX_EARLY_SERIAL
 | 
			
		||||
static void __init ar71xx_add_device_uart(void) {};
 | 
			
		||||
#else
 | 
			
		||||
static struct resource ar71xx_uart_resources[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.start	= AR71XX_UART_BASE,
 | 
			
		||||
		.end	= AR71XX_UART_BASE + AR71XX_UART_SIZE - 1,
 | 
			
		||||
		.flags	= IORESOURCE_MEM,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define AR71XX_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP)
 | 
			
		||||
static struct plat_serial8250_port ar71xx_uart_data[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.mapbase	= AR71XX_UART_BASE,
 | 
			
		||||
		.irq		= AR71XX_MISC_IRQ_UART,
 | 
			
		||||
		.flags		= AR71XX_UART_FLAGS,
 | 
			
		||||
		.iotype		= UPIO_MEM32,
 | 
			
		||||
		.regshift	= 2,
 | 
			
		||||
	}, {
 | 
			
		||||
		/* terminating entry */
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct platform_device ar71xx_uart_device = {
 | 
			
		||||
	.name		= "serial8250",
 | 
			
		||||
	.id		= PLAT8250_DEV_PLATFORM,
 | 
			
		||||
	.resource	= ar71xx_uart_resources,
 | 
			
		||||
	.num_resources	= ARRAY_SIZE(ar71xx_uart_resources),
 | 
			
		||||
	.dev = {
 | 
			
		||||
		.platform_data	= ar71xx_uart_data
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init ar71xx_add_device_uart(void)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_uart_data[0].uartclk = ar71xx_ahb_freq;
 | 
			
		||||
	platform_device_register(&ar71xx_uart_device);
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_AR71XX_EARLY_SERIAL */
 | 
			
		||||
 | 
			
		||||
static struct resource ar71xx_eth0_resources[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.name	= "mac_base",
 | 
			
		||||
		.flags	= IORESOURCE_MEM,
 | 
			
		||||
		.start	= AR71XX_GE0_BASE,
 | 
			
		||||
		.end	= AR71XX_GE0_BASE + AR71XX_GE0_SIZE - 1,
 | 
			
		||||
	}, {
 | 
			
		||||
		.name	= "mii_ctrl",
 | 
			
		||||
		.flags	= IORESOURCE_MEM,
 | 
			
		||||
		.start	= AR71XX_MII_BASE + MII_REG_MII0_CTRL,
 | 
			
		||||
		.end	= AR71XX_MII_BASE + MII_REG_MII0_CTRL + 3,
 | 
			
		||||
	}, {
 | 
			
		||||
		.name	= "mac_irq",
 | 
			
		||||
		.flags	= IORESOURCE_IRQ,
 | 
			
		||||
		.start	= AR71XX_CPU_IRQ_GE0,
 | 
			
		||||
		.end	= AR71XX_CPU_IRQ_GE0,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct ag71xx_platform_data ar71xx_eth0_data = {
 | 
			
		||||
	.reset_bit	= RESET_MODULE_GE0_MAC,
 | 
			
		||||
	.flush_reg	= DDR_REG_FLUSH_GE0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct platform_device ar71xx_eth0_device = {
 | 
			
		||||
	.name		= "ag71xx",
 | 
			
		||||
	.id		= 0,
 | 
			
		||||
	.resource	= ar71xx_eth0_resources,
 | 
			
		||||
	.num_resources	= ARRAY_SIZE(ar71xx_eth0_resources),
 | 
			
		||||
	.dev = {
 | 
			
		||||
		.platform_data = &ar71xx_eth0_data,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct resource ar71xx_eth1_resources[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.name	= "mac_base",
 | 
			
		||||
		.flags	= IORESOURCE_MEM,
 | 
			
		||||
		.start	= AR71XX_GE1_BASE,
 | 
			
		||||
		.end	= AR71XX_GE1_BASE + AR71XX_GE1_SIZE - 1,
 | 
			
		||||
	}, {
 | 
			
		||||
		.name	= "mii_ctrl",
 | 
			
		||||
		.flags	= IORESOURCE_MEM,
 | 
			
		||||
		.start	= AR71XX_MII_BASE + MII_REG_MII1_CTRL,
 | 
			
		||||
		.end	= AR71XX_MII_BASE + MII_REG_MII1_CTRL + 3,
 | 
			
		||||
	}, {
 | 
			
		||||
		.name	= "mac_irq",
 | 
			
		||||
		.flags	= IORESOURCE_IRQ,
 | 
			
		||||
		.start	= AR71XX_CPU_IRQ_GE1,
 | 
			
		||||
		.end	= AR71XX_CPU_IRQ_GE1,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct ag71xx_platform_data ar71xx_eth1_data = {
 | 
			
		||||
	.reset_bit	= RESET_MODULE_GE1_MAC,
 | 
			
		||||
	.flush_reg	= DDR_REG_FLUSH_GE1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct platform_device ar71xx_eth1_device = {
 | 
			
		||||
	.name		= "ag71xx",
 | 
			
		||||
	.id		= 1,
 | 
			
		||||
	.resource	= ar71xx_eth1_resources,
 | 
			
		||||
	.num_resources	= ARRAY_SIZE(ar71xx_eth1_resources),
 | 
			
		||||
	.dev = {
 | 
			
		||||
		.platform_data = &ar71xx_eth1_data,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void __init ar71xx_add_device_eth(unsigned int id, phy_interface_t phy_if_mode,
 | 
			
		||||
				u32 phy_mask)
 | 
			
		||||
{
 | 
			
		||||
	struct platform_device *pdev;
 | 
			
		||||
 | 
			
		||||
	switch (id) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		switch (phy_if_mode) {
 | 
			
		||||
		case PHY_INTERFACE_MODE_MII:
 | 
			
		||||
			ar71xx_eth0_data.mii_if = MII0_CTRL_IF_MII;
 | 
			
		||||
			break;
 | 
			
		||||
		case PHY_INTERFACE_MODE_GMII:
 | 
			
		||||
			ar71xx_eth0_data.mii_if = MII0_CTRL_IF_GMII;
 | 
			
		||||
			break;
 | 
			
		||||
		case PHY_INTERFACE_MODE_RGMII:
 | 
			
		||||
			ar71xx_eth0_data.mii_if = MII0_CTRL_IF_RGMII;
 | 
			
		||||
			break;
 | 
			
		||||
		case PHY_INTERFACE_MODE_RMII:
 | 
			
		||||
			ar71xx_eth0_data.mii_if = MII0_CTRL_IF_RMII;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			BUG();
 | 
			
		||||
		}
 | 
			
		||||
		ar71xx_eth0_data.phy_if_mode = phy_if_mode;
 | 
			
		||||
		ar71xx_eth0_data.phy_mask = phy_mask;
 | 
			
		||||
		pdev = &ar71xx_eth0_device;
 | 
			
		||||
		break;
 | 
			
		||||
	case 1:
 | 
			
		||||
		switch (phy_if_mode) {
 | 
			
		||||
		case PHY_INTERFACE_MODE_RMII:
 | 
			
		||||
			ar71xx_eth1_data.mii_if = MII1_CTRL_IF_RMII;
 | 
			
		||||
			break;
 | 
			
		||||
		case PHY_INTERFACE_MODE_RGMII:
 | 
			
		||||
			ar71xx_eth1_data.mii_if = MII1_CTRL_IF_RGMII;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			BUG();
 | 
			
		||||
		}
 | 
			
		||||
		ar71xx_eth1_data.phy_if_mode = phy_if_mode;
 | 
			
		||||
		ar71xx_eth1_data.phy_mask = phy_mask;
 | 
			
		||||
		pdev = &ar71xx_eth1_device;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		pdev = NULL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pdev)
 | 
			
		||||
		platform_device_register(pdev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct resource ar71xx_spi_resources[] = {
 | 
			
		||||
	[0] = {
 | 
			
		||||
		.start	= AR71XX_SPI_BASE,
 | 
			
		||||
		.end	= AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
 | 
			
		||||
		.flags	= IORESOURCE_MEM,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct platform_device ar71xx_spi_device = {
 | 
			
		||||
	.name		= "ar71xx-spi",
 | 
			
		||||
	.id		= -1,
 | 
			
		||||
	.resource	= ar71xx_spi_resources,
 | 
			
		||||
	.num_resources	= ARRAY_SIZE(ar71xx_spi_resources),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void __init ar71xx_add_device_spi(struct ar71xx_spi_platform_data *pdata,
 | 
			
		||||
				struct spi_board_info const *info,
 | 
			
		||||
				unsigned n)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_gpio_function_enable(GPIO_FUNC_SPI_EN);
 | 
			
		||||
 | 
			
		||||
	spi_register_board_info(info, n);
 | 
			
		||||
	ar71xx_spi_device.dev.platform_data = pdata;
 | 
			
		||||
	platform_device_register(&ar71xx_spi_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init ar71xx_machine_setup(void)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_print_cmdline();
 | 
			
		||||
 | 
			
		||||
	ar71xx_gpio_init();
 | 
			
		||||
 | 
			
		||||
	ar71xx_add_device_uart();
 | 
			
		||||
 | 
			
		||||
	mips_machine_setup();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
arch_initcall(ar71xx_machine_setup);
 | 
			
		||||
							
								
								
									
										126
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/prom.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/prom.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx SoC specific prom routines
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/init.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/serial_reg.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/bootinfo.h>
 | 
			
		||||
#include <asm/addrspace.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
 | 
			
		||||
struct board_rec {
 | 
			
		||||
	char		*name;
 | 
			
		||||
	unsigned long	mach_type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int prom_argc __initdata;
 | 
			
		||||
static char **prom_argv __initdata;
 | 
			
		||||
static char **prom_envp __initdata;
 | 
			
		||||
 | 
			
		||||
static struct board_rec boards[] __initdata = {
 | 
			
		||||
	{
 | 
			
		||||
		.name		= "411",
 | 
			
		||||
		.mach_type	= MACH_AR71XX_RB_411,
 | 
			
		||||
	}, {
 | 
			
		||||
		.name		= "433",
 | 
			
		||||
		.mach_type	= MACH_AR71XX_RB_433,
 | 
			
		||||
	}, {
 | 
			
		||||
		.name		= "450",
 | 
			
		||||
		.mach_type	= MACH_AR71XX_RB_450,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
char *(*prom_getenv)(const char *envname) __initdata;
 | 
			
		||||
 | 
			
		||||
static __init char *dummy_getenv(const char *envname)
 | 
			
		||||
{
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __init routerboot_printargs(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < prom_argc; i++)
 | 
			
		||||
		printk(KERN_DEBUG "prom: routerboot envp[%d]: %s\n",
 | 
			
		||||
				i, prom_envp[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static __init char *routerboot_getenv(const char *envname)
 | 
			
		||||
{
 | 
			
		||||
	char **env;
 | 
			
		||||
	int i = strlen(envname);
 | 
			
		||||
 | 
			
		||||
	for (env = prom_envp; *env != NULL; env++)
 | 
			
		||||
		if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
 | 
			
		||||
			return *env + i + 1;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static __init unsigned long find_board_byname(char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(boards); i++)
 | 
			
		||||
		if (strcmp(name, boards[i].name) == 0)
 | 
			
		||||
			return boards[i].mach_type;
 | 
			
		||||
 | 
			
		||||
	return MACH_AR71XX_GENERIC;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init prom_init(void)
 | 
			
		||||
{
 | 
			
		||||
	char *board;
 | 
			
		||||
 | 
			
		||||
	printk(KERN_DEBUG "prom: fw_arg0=%08x, fw_arg1=%08x, "
 | 
			
		||||
			"fw_arg2=%08x, fw_arg3=%08x\n",
 | 
			
		||||
			(unsigned int)fw_arg0, (unsigned int)fw_arg1,
 | 
			
		||||
			(unsigned int)fw_arg2, (unsigned int)fw_arg3);
 | 
			
		||||
 | 
			
		||||
	prom_getenv = dummy_getenv;
 | 
			
		||||
 | 
			
		||||
	if ((fw_arg0 == 7) && (fw_arg2 == 0)) {
 | 
			
		||||
		prom_argc = fw_arg0;
 | 
			
		||||
		prom_envp = (char **)fw_arg1;
 | 
			
		||||
		prom_getenv = routerboot_getenv;
 | 
			
		||||
		routerboot_printargs();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	board = prom_getenv("board");
 | 
			
		||||
	if (board)
 | 
			
		||||
		mips_machtype = find_board_byname(board);
 | 
			
		||||
	else
 | 
			
		||||
		mips_machtype = MACH_AR71XX_GENERIC;
 | 
			
		||||
 | 
			
		||||
	ar71xx_print_cmdline();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init prom_free_prom_memory(void)
 | 
			
		||||
{
 | 
			
		||||
	/* We do not have to prom memory to free */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define UART_READ(r) \
 | 
			
		||||
	__raw_readl((void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4 * (r)))
 | 
			
		||||
 | 
			
		||||
#define UART_WRITE(r, v) \
 | 
			
		||||
	__raw_writel((v), (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4*(r)))
 | 
			
		||||
 | 
			
		||||
void prom_putchar(unsigned char ch)
 | 
			
		||||
{
 | 
			
		||||
	while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
 | 
			
		||||
	UART_WRITE(UART_TX, ch);
 | 
			
		||||
	while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										226
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/setup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								target/linux/ar71xx/files/arch/mips/ar71xx/setup.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,226 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx SoC specific setup
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Parts of this file are based on Atheros' 2.6.15 BSP
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/init.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/pci.h>
 | 
			
		||||
#include <linux/serial_8250.h>
 | 
			
		||||
#include <linux/bootmem.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/bootinfo.h>
 | 
			
		||||
#include <asm/traps.h>
 | 
			
		||||
#include <asm/time.h>		/* for mips_hpt_frequency */
 | 
			
		||||
#include <asm/reboot.h>		/* for _machine_{restart,halt} */
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
#include <asm/mach-ar71xx/pci.h>
 | 
			
		||||
#include <asm/mach-ar71xx/platform.h>
 | 
			
		||||
 | 
			
		||||
#define AR71XX_SYS_TYPE_LEN	64
 | 
			
		||||
#define AR71XX_BASE_FREQ	40000000
 | 
			
		||||
 | 
			
		||||
#define AR71XX_MEM_SIZE_MIN	0x0200000
 | 
			
		||||
#define AR71XX_MEM_SIZE_MAX	0x8000000
 | 
			
		||||
 | 
			
		||||
u32 ar71xx_cpu_freq;
 | 
			
		||||
EXPORT_SYMBOL_GPL(ar71xx_cpu_freq);
 | 
			
		||||
 | 
			
		||||
u32 ar71xx_ahb_freq;
 | 
			
		||||
EXPORT_SYMBOL_GPL(ar71xx_ahb_freq);
 | 
			
		||||
 | 
			
		||||
u32 ar71xx_ddr_freq;
 | 
			
		||||
EXPORT_SYMBOL_GPL(ar71xx_ddr_freq);
 | 
			
		||||
 | 
			
		||||
int (*ar71xx_pci_bios_init)(unsigned nr_irqs,
 | 
			
		||||
			     struct ar71xx_pci_irq *map) __initdata;
 | 
			
		||||
 | 
			
		||||
int (*ar71xx_pci_be_handler)(int is_fixup);
 | 
			
		||||
 | 
			
		||||
static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN];
 | 
			
		||||
 | 
			
		||||
static void ar71xx_restart(char *command)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_device_stop(RESET_MODULE_FULL_CHIP);
 | 
			
		||||
	for (;;)
 | 
			
		||||
		if (cpu_wait)
 | 
			
		||||
			cpu_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_halt(void)
 | 
			
		||||
{
 | 
			
		||||
	while (1)
 | 
			
		||||
		cpu_wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ar71xx_be_handler(struct pt_regs *regs, int is_fixup)
 | 
			
		||||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
	if (ar71xx_pci_be_handler)
 | 
			
		||||
		err = ar71xx_pci_be_handler(is_fixup);
 | 
			
		||||
 | 
			
		||||
	return (is_fixup && !err) ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int __init ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map)
 | 
			
		||||
{
 | 
			
		||||
	if (!ar71xx_pci_bios_init)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return ar71xx_pci_bios_init(nr_irqs, map);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __init ar71xx_detect_mem_size(void)
 | 
			
		||||
{
 | 
			
		||||
	volatile u8 *p;
 | 
			
		||||
	u8 memsave;
 | 
			
		||||
	u32 size;
 | 
			
		||||
 | 
			
		||||
	p = (volatile u8 *) KSEG1ADDR(0);
 | 
			
		||||
	memsave = *p;
 | 
			
		||||
	for (size = AR71XX_MEM_SIZE_MIN;
 | 
			
		||||
	     size <= (AR71XX_MEM_SIZE_MAX >> 1); size <<= 1) {
 | 
			
		||||
		volatile u8 *r;
 | 
			
		||||
 | 
			
		||||
		r = (p + size);
 | 
			
		||||
		*p = 0x55;
 | 
			
		||||
		if (*r == 0x55) {
 | 
			
		||||
			/* Mirrored data found, try another pattern */
 | 
			
		||||
			*p = 0xAA;
 | 
			
		||||
			if (*r == 0xAA) {
 | 
			
		||||
				/* Mirrored data found again, stop detection */
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	*p = memsave;
 | 
			
		||||
 | 
			
		||||
	add_memory_region(0, size, BOOT_MEM_RAM);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __init ar71xx_detect_sys_type(void)
 | 
			
		||||
{
 | 
			
		||||
	char *chip;
 | 
			
		||||
	u32 id;
 | 
			
		||||
	u32 rev;
 | 
			
		||||
 | 
			
		||||
	id = ar71xx_reset_rr(RESET_REG_REV_ID) & REV_ID_MASK;
 | 
			
		||||
	rev = (id >> REV_ID_REVISION_SHIFT) & REV_ID_REVISION_MASK;
 | 
			
		||||
	switch (id & REV_ID_CHIP_MASK) {
 | 
			
		||||
	case REV_ID_CHIP_AR7130:
 | 
			
		||||
		chip = "7130";
 | 
			
		||||
		break;
 | 
			
		||||
	case REV_ID_CHIP_AR7141:
 | 
			
		||||
		chip = "7141";
 | 
			
		||||
		break;
 | 
			
		||||
	case REV_ID_CHIP_AR7161:
 | 
			
		||||
		chip = "7161";
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		chip = "71xx";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sprintf(ar71xx_sys_type, "Atheros AR%s rev %u (id:0x%02x)",
 | 
			
		||||
		chip, rev, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __init ar71xx_detect_sys_frequency(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 pll;
 | 
			
		||||
	u32 freq;
 | 
			
		||||
	u32 div;
 | 
			
		||||
 | 
			
		||||
	pll = ar71xx_pll_rr(PLL_REG_CPU_PLL_CFG);
 | 
			
		||||
 | 
			
		||||
	div = ((pll >> PLL_DIV_SHIFT) & PLL_DIV_MASK) + 1;
 | 
			
		||||
	freq = div * AR71XX_BASE_FREQ;
 | 
			
		||||
 | 
			
		||||
	div = ((pll >> CPU_DIV_SHIFT) & CPU_DIV_MASK) + 1;
 | 
			
		||||
	ar71xx_cpu_freq = freq / div;
 | 
			
		||||
 | 
			
		||||
	div = ((pll >> DDR_DIV_SHIFT) & DDR_DIV_MASK) + 1;
 | 
			
		||||
	ar71xx_ddr_freq = freq / div;
 | 
			
		||||
 | 
			
		||||
	div = (((pll >> AHB_DIV_SHIFT) & AHB_DIV_MASK) + 1) * 2;
 | 
			
		||||
	ar71xx_ahb_freq = ar71xx_cpu_freq / div;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_AR71XX_EARLY_SERIAL
 | 
			
		||||
static void __init ar71xx_early_serial_setup(void)
 | 
			
		||||
{
 | 
			
		||||
	struct uart_port p;
 | 
			
		||||
 | 
			
		||||
	memset(&p, 0, sizeof(p));
 | 
			
		||||
 | 
			
		||||
	p.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP;
 | 
			
		||||
	p.iotype	= UPIO_MEM32;
 | 
			
		||||
	p.uartclk	= ar71xx_ahb_freq;
 | 
			
		||||
	p.irq		= AR71XX_MISC_IRQ_UART;
 | 
			
		||||
	p.regshift	= 2;
 | 
			
		||||
	p.mapbase	= AR71XX_UART_BASE;
 | 
			
		||||
 | 
			
		||||
	early_serial_setup(&p);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline void ar71xx_early_serial_setup(void) {};
 | 
			
		||||
#endif /* CONFIG_AR71XX_EARLY_SERIAL */
 | 
			
		||||
 | 
			
		||||
const char *get_system_type(void)
 | 
			
		||||
{
 | 
			
		||||
	return ar71xx_sys_type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int __cpuinit get_c0_compare_irq(void)
 | 
			
		||||
{
 | 
			
		||||
	return CP0_LEGACY_COMPARE_IRQ;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init plat_mem_setup(void)
 | 
			
		||||
{
 | 
			
		||||
	set_io_port_base(KSEG1);
 | 
			
		||||
 | 
			
		||||
	ar71xx_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
 | 
			
		||||
						AR71XX_DDR_CTRL_SIZE);
 | 
			
		||||
 | 
			
		||||
	ar71xx_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
 | 
			
		||||
						AR71XX_PLL_SIZE);
 | 
			
		||||
 | 
			
		||||
	ar71xx_reset_base = ioremap_nocache(AR71XX_RESET_BASE,
 | 
			
		||||
						AR71XX_RESET_SIZE);
 | 
			
		||||
 | 
			
		||||
	ar71xx_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
 | 
			
		||||
 | 
			
		||||
	ar71xx_usb_ctrl_base = ioremap_nocache(AR71XX_USB_CTRL_BASE,
 | 
			
		||||
						AR71XX_USB_CTRL_SIZE);
 | 
			
		||||
 | 
			
		||||
	ar71xx_detect_mem_size();
 | 
			
		||||
	ar71xx_detect_sys_type();
 | 
			
		||||
	ar71xx_detect_sys_frequency();
 | 
			
		||||
 | 
			
		||||
	_machine_restart = ar71xx_restart;
 | 
			
		||||
	_machine_halt = ar71xx_halt;
 | 
			
		||||
	pm_power_off = ar71xx_halt;
 | 
			
		||||
 | 
			
		||||
	board_be_handler = ar71xx_be_handler;
 | 
			
		||||
 | 
			
		||||
	ar71xx_print_cmdline();
 | 
			
		||||
 | 
			
		||||
	ar71xx_early_serial_setup();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init plat_time_init(void)
 | 
			
		||||
{
 | 
			
		||||
	mips_hpt_frequency = ar71xx_cpu_freq / 2;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										346
									
								
								target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,346 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx PCI host controller driver
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Parts of this file are based on Atheros' 2.6.15 BSP
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/resource.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/bitops.h>
 | 
			
		||||
#include <linux/pci.h>
 | 
			
		||||
#include <linux/pci_regs.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
#include <asm/mach-ar71xx/pci.h>
 | 
			
		||||
 | 
			
		||||
#undef DEBUG
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
#define DBG(fmt, args...)	printk(KERN_DEBUG fmt, ## args)
 | 
			
		||||
#else
 | 
			
		||||
#define DBG(fmt, args...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define AR71XX_PCI_DELAY	100 /* msecs */
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
#define PCI_IDSEL_BASE	PCI_IDSEL_ADL_START
 | 
			
		||||
#else
 | 
			
		||||
#define PCI_IDSEL_BASE	0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static unsigned ar71xx_pci_nr_irqs;
 | 
			
		||||
static struct ar71xx_pci_irq *ar71xx_pci_irq_map __initdata;
 | 
			
		||||
static void __iomem *ar71xx_pcicfg_base;
 | 
			
		||||
 | 
			
		||||
static DEFINE_SPINLOCK(ar71xx_pci_lock);
 | 
			
		||||
 | 
			
		||||
static inline void ar71xx_pci_delay(void)
 | 
			
		||||
{
 | 
			
		||||
	mdelay(AR71XX_PCI_DELAY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_pcicfg_rr(unsigned int reg)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(ar71xx_pcicfg_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ar71xx_pcicfg_wr(unsigned int reg, u32 val)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(val, ar71xx_pcicfg_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Byte lane enable bits */
 | 
			
		||||
static u8 ble_table[4][4] = {
 | 
			
		||||
	{0xf, 0xe, 0xd, 0xc},
 | 
			
		||||
	{0xc, 0x9, 0x3, 0x1},
 | 
			
		||||
	{0x0, 0x0, 0x0, 0x0},
 | 
			
		||||
	{0x0, 0x0, 0x0, 0x0},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_pci_get_ble(int where, int size, int local)
 | 
			
		||||
{
 | 
			
		||||
	u32 t;
 | 
			
		||||
 | 
			
		||||
	t = ble_table[size][where & 3];
 | 
			
		||||
	t <<= (local) ? 20 : 4;
 | 
			
		||||
	return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn,
 | 
			
		||||
					int where)
 | 
			
		||||
{
 | 
			
		||||
	u32 ret;
 | 
			
		||||
 | 
			
		||||
	if (!bus->number) {
 | 
			
		||||
		/* type 0 */
 | 
			
		||||
		ret = (1 << (PCI_IDSEL_BASE + PCI_SLOT(devfn)))
 | 
			
		||||
		    | (PCI_FUNC(devfn) << 8) | (where & ~3);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* type 1 */
 | 
			
		||||
		ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11)
 | 
			
		||||
		    | (PCI_FUNC(devfn) << 8) | (where & ~3) | 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __ar71xx_pci_be_handler(int is_fixup)
 | 
			
		||||
{
 | 
			
		||||
	u32 pci_err;
 | 
			
		||||
	u32 ahb_err;
 | 
			
		||||
 | 
			
		||||
	pci_err = ar71xx_pcicfg_rr(PCI_REG_PCI_ERR) & 3;
 | 
			
		||||
	if (pci_err) {
 | 
			
		||||
		if (!is_fixup)
 | 
			
		||||
			printk(KERN_ALERT "PCI error %d at PCI addr 0x%x\n",
 | 
			
		||||
				pci_err,
 | 
			
		||||
				ar71xx_pcicfg_rr(PCI_REG_PCI_ERR_ADDR));
 | 
			
		||||
 | 
			
		||||
		ar71xx_pcicfg_wr(PCI_REG_PCI_ERR, pci_err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ahb_err = ar71xx_pcicfg_rr(PCI_REG_AHB_ERR) & 1;
 | 
			
		||||
	if (ahb_err) {
 | 
			
		||||
		if (!is_fixup)
 | 
			
		||||
			printk(KERN_ALERT "AHB error at AHB address 0x%x\n",
 | 
			
		||||
				ar71xx_pcicfg_rr(PCI_REG_AHB_ERR_ADDR));
 | 
			
		||||
 | 
			
		||||
		ar71xx_pcicfg_wr(PCI_REG_AHB_ERR, ahb_err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ((ahb_err | pci_err) ? 1 : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus,
 | 
			
		||||
			unsigned int devfn, int where, int size, u32 cmd)
 | 
			
		||||
{
 | 
			
		||||
	u32 addr;
 | 
			
		||||
 | 
			
		||||
	addr = ar71xx_pci_bus_addr(bus, devfn, where);
 | 
			
		||||
 | 
			
		||||
	DBG("PCI: set cfgaddr: %02x:%02x.%01x/%02x:%01d, addr=%08x\n",
 | 
			
		||||
		bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
 | 
			
		||||
		where, size, addr);
 | 
			
		||||
 | 
			
		||||
	ar71xx_pcicfg_wr(PCI_REG_CFG_AD, addr);
 | 
			
		||||
	ar71xx_pcicfg_wr(PCI_REG_CFG_CBE,
 | 
			
		||||
			cmd | ar71xx_pci_get_ble(where, size, 0));
 | 
			
		||||
 | 
			
		||||
	return __ar71xx_pci_be_handler(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
 | 
			
		||||
				  int where, int size, u32 *value)
 | 
			
		||||
{
 | 
			
		||||
	static u32 mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0};
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	u32 data;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = PCIBIOS_SUCCESSFUL;
 | 
			
		||||
 | 
			
		||||
	DBG("PCI: read config: %02x:%02x.%01x/%02x:%01d\n", bus->number,
 | 
			
		||||
			PCI_SLOT(devfn), PCI_FUNC(devfn), where, size);
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ar71xx_pci_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (bus->number == 0 && devfn == 0) {
 | 
			
		||||
		u32 t;
 | 
			
		||||
 | 
			
		||||
		t = PCI_CRP_CMD_READ | (where & ~3);
 | 
			
		||||
 | 
			
		||||
		ar71xx_pcicfg_wr(PCI_REG_CRP_AD_CBE, t);
 | 
			
		||||
		data = ar71xx_pcicfg_rr(PCI_REG_CRP_RDDATA);
 | 
			
		||||
 | 
			
		||||
		DBG("PCI: rd local cfg, ad_cbe:%08x, data:%08x\n", t, data);
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		int err;
 | 
			
		||||
 | 
			
		||||
		err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
 | 
			
		||||
						PCI_CFG_CMD_READ);
 | 
			
		||||
 | 
			
		||||
		if (err == 0) {
 | 
			
		||||
			data = ar71xx_pcicfg_rr(PCI_REG_CFG_RDDATA);
 | 
			
		||||
		} else {
 | 
			
		||||
			ret = PCIBIOS_DEVICE_NOT_FOUND;
 | 
			
		||||
			data = ~0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
 | 
			
		||||
 | 
			
		||||
	DBG("PCI: read config: data=%08x raw=%08x\n",
 | 
			
		||||
		(data >> (8 * (where & 3))) & mask[size & 7], data);
 | 
			
		||||
 | 
			
		||||
	*value = (data >> (8 * (where & 3))) & mask[size & 7];
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
 | 
			
		||||
				   int where, int size, u32 value)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	DBG("PCI: write config: %02x:%02x.%01x/%02x:%01d value=%08x\n",
 | 
			
		||||
		bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
 | 
			
		||||
		where, size, value);
 | 
			
		||||
 | 
			
		||||
	value = value << (8 * (where & 3));
 | 
			
		||||
	ret = PCIBIOS_SUCCESSFUL;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ar71xx_pci_lock, flags);
 | 
			
		||||
	if (bus->number == 0 && devfn == 0) {
 | 
			
		||||
		u32 t;
 | 
			
		||||
 | 
			
		||||
		t = PCI_CRP_CMD_WRITE | (where & ~3);
 | 
			
		||||
		t |= ar71xx_pci_get_ble(where, size, 1);
 | 
			
		||||
 | 
			
		||||
		DBG("PCI: wr local cfg, ad_cbe:%08x, value:%08x\n", t, value);
 | 
			
		||||
 | 
			
		||||
		ar71xx_pcicfg_wr(PCI_REG_CRP_AD_CBE, t);
 | 
			
		||||
		ar71xx_pcicfg_wr(PCI_REG_CRP_WRDATA, value);
 | 
			
		||||
	} else {
 | 
			
		||||
		int err;
 | 
			
		||||
 | 
			
		||||
		err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
 | 
			
		||||
						PCI_CFG_CMD_WRITE);
 | 
			
		||||
 | 
			
		||||
		if (err == 0)
 | 
			
		||||
			ar71xx_pcicfg_wr(PCI_REG_CFG_WRDATA, value);
 | 
			
		||||
		else
 | 
			
		||||
			ret = PCIBIOS_DEVICE_NOT_FOUND;
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_pci_fixup(struct pci_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	u32 t;
 | 
			
		||||
 | 
			
		||||
	if (dev->bus->number != 0 || dev->devfn != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	DBG("PCI: fixup host controller %s (%04x:%04x)\n", pci_name(dev),
 | 
			
		||||
		dev->vendor, dev->device);
 | 
			
		||||
 | 
			
		||||
	/* setup COMMAND register */
 | 
			
		||||
	t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
 | 
			
		||||
	  | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
 | 
			
		||||
 | 
			
		||||
	pci_write_config_word(dev, PCI_COMMAND, t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ar71xx_pci_fixup);
 | 
			
		||||
 | 
			
		||||
int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
 | 
			
		||||
{
 | 
			
		||||
	int irq = -1;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	slot -= PCI_IDSEL_ADL_START - PCI_IDSEL_BASE;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ar71xx_pci_nr_irqs; i++) {
 | 
			
		||||
		struct ar71xx_pci_irq *entry;
 | 
			
		||||
 | 
			
		||||
		entry = &ar71xx_pci_irq_map[i];
 | 
			
		||||
		if (entry->slot == slot && entry->pin == pin) {
 | 
			
		||||
			irq = entry->irq;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (irq < 0) {
 | 
			
		||||
		printk(KERN_ALERT "PCI: no irq found for pin%u@%s\n",
 | 
			
		||||
				pin, pci_name((struct pci_dev *)dev));
 | 
			
		||||
	} else {
 | 
			
		||||
		printk(KERN_INFO "PCI: mapping irq %d to pin%u@%s\n",
 | 
			
		||||
				irq, pin, pci_name((struct pci_dev *)dev));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return irq;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pcibios_plat_dev_init(struct pci_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct pci_ops ar71xx_pci_ops = {
 | 
			
		||||
	.read	= ar71xx_pci_read_config,
 | 
			
		||||
	.write	= ar71xx_pci_write_config,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct resource ar71xx_pci_io_resource = {
 | 
			
		||||
	.name		= "PCI IO space",
 | 
			
		||||
	.start		= 0,
 | 
			
		||||
	.end		= 0,
 | 
			
		||||
	.flags		= IORESOURCE_IO,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct resource ar71xx_pci_mem_resource = {
 | 
			
		||||
	.name		= "PCI memory space",
 | 
			
		||||
	.start		= AR71XX_PCI_MEM_BASE,
 | 
			
		||||
	.end		= AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1,
 | 
			
		||||
	.flags		= IORESOURCE_MEM
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct pci_controller ar71xx_pci_controller = {
 | 
			
		||||
	.pci_ops	= &ar71xx_pci_ops,
 | 
			
		||||
	.mem_resource	= &ar71xx_pci_mem_resource,
 | 
			
		||||
	.io_resource	= &ar71xx_pci_io_resource,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init __ar71xx_pci_bios_init(unsigned nr_irqs,
 | 
			
		||||
					 struct ar71xx_pci_irq *map)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_device_stop(RESET_MODULE_PCI_BUS | RESET_MODULE_PCI_CORE);
 | 
			
		||||
	ar71xx_pci_delay();
 | 
			
		||||
 | 
			
		||||
	ar71xx_device_start(RESET_MODULE_PCI_BUS | RESET_MODULE_PCI_CORE);
 | 
			
		||||
	ar71xx_pci_delay();
 | 
			
		||||
 | 
			
		||||
	ar71xx_pcicfg_base = ioremap_nocache(AR71XX_PCI_CFG_BASE,
 | 
			
		||||
						AR71XX_PCI_CFG_SIZE);
 | 
			
		||||
 | 
			
		||||
	ar71xx_ddr_wr(DDR_REG_PCI_WIN0, PCI_WIN0_OFFS);
 | 
			
		||||
	ar71xx_ddr_wr(DDR_REG_PCI_WIN1, PCI_WIN1_OFFS);
 | 
			
		||||
	ar71xx_ddr_wr(DDR_REG_PCI_WIN2, PCI_WIN2_OFFS);
 | 
			
		||||
	ar71xx_ddr_wr(DDR_REG_PCI_WIN3, PCI_WIN3_OFFS);
 | 
			
		||||
	ar71xx_ddr_wr(DDR_REG_PCI_WIN4, PCI_WIN4_OFFS);
 | 
			
		||||
	ar71xx_ddr_wr(DDR_REG_PCI_WIN5, PCI_WIN5_OFFS);
 | 
			
		||||
	ar71xx_ddr_wr(DDR_REG_PCI_WIN6, PCI_WIN6_OFFS);
 | 
			
		||||
	ar71xx_ddr_wr(DDR_REG_PCI_WIN7, PCI_WIN7_OFFS);
 | 
			
		||||
 | 
			
		||||
	ar71xx_pci_delay();
 | 
			
		||||
 | 
			
		||||
	/* clear bus errors */
 | 
			
		||||
	(void)__ar71xx_pci_be_handler(1);
 | 
			
		||||
 | 
			
		||||
	ar71xx_pci_nr_irqs = nr_irqs;
 | 
			
		||||
	ar71xx_pci_irq_map = map;
 | 
			
		||||
	ar71xx_pci_be_handler = __ar71xx_pci_be_handler;
 | 
			
		||||
 | 
			
		||||
	register_pci_controller(&ar71xx_pci_controller);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init __ar71xx_pci_init(void)
 | 
			
		||||
{
 | 
			
		||||
	ar71xx_pci_bios_init = __ar71xx_pci_bios_init;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
pure_initcall(__ar71xx_pci_init);
 | 
			
		||||
							
								
								
									
										507
									
								
								target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										507
									
								
								target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,507 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  NAND flash driver for the MikroTik RouterBoard 4xx series
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This file was based on the driver for Linux 2.6.22 published by
 | 
			
		||||
 *  MikroTik for their RouterBoard 4xx series devices.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/init.h>
 | 
			
		||||
#include <linux/mtd/nand.h>
 | 
			
		||||
#include <linux/mtd/mtd.h>
 | 
			
		||||
#include <linux/mtd/partitions.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/gpio.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
 | 
			
		||||
#define DRV_NAME        "rb4xx-nand"
 | 
			
		||||
#define DRV_VERSION     "0.1.9"
 | 
			
		||||
#define DRV_DESC        "NAND flash driver for RouterBoard 4xx series"
 | 
			
		||||
 | 
			
		||||
#define USE_FAST_READ	1
 | 
			
		||||
#define USE_FAST_WRITE	1
 | 
			
		||||
#undef RB4XX_NAND_DEBUG
 | 
			
		||||
 | 
			
		||||
#ifdef RB4XX_NAND_DEBUG
 | 
			
		||||
#define DBG(fmt, arg...)	printk(KERN_DEBUG DRV_NAME ": " fmt, ## arg)
 | 
			
		||||
#else
 | 
			
		||||
#define DBG(fmt, arg...)	do {} while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define RB4XX_NAND_GPIO_RDY	5
 | 
			
		||||
#define RB4XX_FLASH_HZ		33333334
 | 
			
		||||
#define RB4XX_NAND_HZ		33333334
 | 
			
		||||
 | 
			
		||||
#define SPI_CTRL_FASTEST	0x40
 | 
			
		||||
#define SPI_CTRL_SAFE		0x43	/* 25 MHz for AHB 200 MHz */
 | 
			
		||||
#define SBIT_IOC_BASE		SPI_IOC_CS1
 | 
			
		||||
#define SBIT_IOC_DO_SHIFT	0
 | 
			
		||||
#define SBIT_IOC_DO		(1u << SBIT_IOC_DO_SHIFT)
 | 
			
		||||
#define SBIT_IOC_DO2_SHIFT	18
 | 
			
		||||
#define SBIT_IOC_DO2		(1u << SBIT_IOC_DO2_SHIFT)
 | 
			
		||||
 | 
			
		||||
#define CPLD_CMD_WRITE_MULT	0x08	/* send cmd, n x send data, read data */
 | 
			
		||||
#define CPLD_CMD_WRITE_CFG	0x09	/* send cmd, n x send cfg */
 | 
			
		||||
#define CPLD_CMD_READ_MULT	0x0a	/* send cmd, send idle, n x read data */
 | 
			
		||||
#define CPLD_CMD_READ_FAST	0x0b	/* send cmd, 4 x idle, n x read data */
 | 
			
		||||
 | 
			
		||||
#define CFG_BIT_nCE	0x80
 | 
			
		||||
#define CFG_BIT_CLE	0x40
 | 
			
		||||
#define CFG_BIT_ALE	0x20
 | 
			
		||||
#define CFG_BIT_FAN	0x10
 | 
			
		||||
#define CFG_BIT_nLED4	0x08
 | 
			
		||||
#define CFG_BIT_nLED3	0x04
 | 
			
		||||
#define CFG_BIT_nLED2	0x02
 | 
			
		||||
#define CFG_BIT_nLED1	0x01
 | 
			
		||||
 | 
			
		||||
#define CFG_BIT_nLEDS \
 | 
			
		||||
	(CFG_BIT_nLED1 | CFG_BIT_nLED2 | CFG_BIT_nLED3 | CFG_BIT_nLED4)
 | 
			
		||||
 | 
			
		||||
struct rb4xx_nand_info {
 | 
			
		||||
	struct nand_chip	chip;
 | 
			
		||||
	struct mtd_info		mtd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
 | 
			
		||||
 * will not be able to find the kernel that we load.
 | 
			
		||||
 */
 | 
			
		||||
static struct nand_ecclayout rb4xx_nand_ecclayout = {
 | 
			
		||||
	.eccbytes	= 6,
 | 
			
		||||
	.eccpos		= { 8, 9, 10, 13, 14, 15 },
 | 
			
		||||
	.oobavail	= 9,
 | 
			
		||||
	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct mtd_partition rb4xx_nand_partitions[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.name	= "kernel",
 | 
			
		||||
		.offset	= (256 * 1024),
 | 
			
		||||
		.size	= (4 * 1024 * 1024) - (256 * 1024),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.name	= "rootfs",
 | 
			
		||||
		.offset	= MTDPART_OFS_NXTBLK,
 | 
			
		||||
		.size	= MTDPART_SIZ_FULL,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.name	= "booter",
 | 
			
		||||
		.offset	= 0,
 | 
			
		||||
		.size	= (256 * 1024),
 | 
			
		||||
		.mask_flags = MTD_WRITEABLE,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if USE_FAST_READ
 | 
			
		||||
#define SPI_NDATA_BASE	0x00800000
 | 
			
		||||
static unsigned spi_ctrl_fread = SPI_CTRL_SAFE;
 | 
			
		||||
static unsigned spi_ctrl_flash = SPI_CTRL_SAFE;
 | 
			
		||||
extern unsigned mips_hpt_frequency;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline unsigned rb4xx_spi_rreg(unsigned r)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl((void * __iomem)(KSEG1ADDR(AR71XX_SPI_BASE) + r));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void rb4xx_spi_wreg(unsigned r, unsigned v)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(v, (void * __iomem)(KSEG1ADDR(AR71XX_SPI_BASE) + r));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void do_spi_clk(int bit)
 | 
			
		||||
{
 | 
			
		||||
	unsigned bval = SBIT_IOC_BASE | (bit & 1);
 | 
			
		||||
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_IOC, bval);
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void do_spi_byte(uint8_t byte)
 | 
			
		||||
{
 | 
			
		||||
	do_spi_clk(byte >> 7);
 | 
			
		||||
	do_spi_clk(byte >> 6);
 | 
			
		||||
	do_spi_clk(byte >> 5);
 | 
			
		||||
	do_spi_clk(byte >> 4);
 | 
			
		||||
	do_spi_clk(byte >> 3);
 | 
			
		||||
	do_spi_clk(byte >> 2);
 | 
			
		||||
	do_spi_clk(byte >> 1);
 | 
			
		||||
	do_spi_clk(byte);
 | 
			
		||||
 | 
			
		||||
	DBG("spi_byte sent 0x%02x got 0x%x\n",
 | 
			
		||||
					byte, rb4xx_spi_rreg(SPI_REG_RDS));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if USE_FAST_WRITE
 | 
			
		||||
static inline void do_spi_clk_fast(int bit1, int bit2)
 | 
			
		||||
{
 | 
			
		||||
	unsigned bval = (SBIT_IOC_BASE |
 | 
			
		||||
			((bit1 << SBIT_IOC_DO_SHIFT) & SBIT_IOC_DO) |
 | 
			
		||||
			((bit2 << SBIT_IOC_DO2_SHIFT) & SBIT_IOC_DO2));
 | 
			
		||||
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_IOC, bval);
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void do_spi_byte_fast(uint8_t byte)
 | 
			
		||||
{
 | 
			
		||||
	do_spi_clk_fast(byte >> 7, byte >> 6);
 | 
			
		||||
	do_spi_clk_fast(byte >> 5, byte >> 4);
 | 
			
		||||
	do_spi_clk_fast(byte >> 3, byte >> 2);
 | 
			
		||||
	do_spi_clk_fast(byte >> 1, byte >> 0);
 | 
			
		||||
 | 
			
		||||
	DBG("spi_byte_fast sent 0x%02x got 0x%x\n",
 | 
			
		||||
					byte, rb4xx_spi_rreg(SPI_REG_RDS));
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline void do_spi_byte_fast(uint8_t byte)
 | 
			
		||||
{
 | 
			
		||||
	do_spi_byte(byte);
 | 
			
		||||
}
 | 
			
		||||
#endif /* USE_FAST_WRITE */
 | 
			
		||||
 | 
			
		||||
static int do_spi_cmd(unsigned cmd, unsigned sendCnt, const uint8_t *sendData,
 | 
			
		||||
		unsigned recvCnt, uint8_t *recvData,
 | 
			
		||||
		const uint8_t *verifyData, int fastWrite)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i;
 | 
			
		||||
 | 
			
		||||
	DBG("SPI cmd 0x%x send %u recv %u\n", cmd, sendCnt, recvCnt);
 | 
			
		||||
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_FS, SPI_FS_GPIO);
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_CTRL, SPI_CTRL_FASTEST);
 | 
			
		||||
 | 
			
		||||
	do_spi_byte(cmd);
 | 
			
		||||
#if 0
 | 
			
		||||
	if (cmd == CPLD_CMD_READ_FAST) {
 | 
			
		||||
		do_spi_byte(0x80);
 | 
			
		||||
		do_spi_byte(0);
 | 
			
		||||
		do_spi_byte(0);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	for (i = 0; i < sendCnt; ++i) {
 | 
			
		||||
		if (fastWrite)
 | 
			
		||||
			do_spi_byte_fast(sendData[i]);
 | 
			
		||||
		else
 | 
			
		||||
			do_spi_byte(sendData[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < recvCnt; ++i) {
 | 
			
		||||
		if (fastWrite)
 | 
			
		||||
			do_spi_byte_fast(0);
 | 
			
		||||
		else
 | 
			
		||||
			do_spi_byte(0);
 | 
			
		||||
 | 
			
		||||
		if (recvData) {
 | 
			
		||||
			recvData[i] = rb4xx_spi_rreg(SPI_REG_RDS) & 0xff;
 | 
			
		||||
		} else if (verifyData) {
 | 
			
		||||
			if (verifyData[i] != (rb4xx_spi_rreg(SPI_REG_RDS)
 | 
			
		||||
							 & 0xff))
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_IOC, SBIT_IOC_BASE | SPI_IOC_CS0);
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_CTRL, spi_ctrl_flash);
 | 
			
		||||
	rb4xx_spi_wreg(SPI_REG_FS, 0);
 | 
			
		||||
 | 
			
		||||
	return i == recvCnt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int got_write = 1;
 | 
			
		||||
 | 
			
		||||
static void rb4xx_nand_write_data(const uint8_t *byte, unsigned cnt)
 | 
			
		||||
{
 | 
			
		||||
	do_spi_cmd(CPLD_CMD_WRITE_MULT, cnt, byte, 1, NULL, NULL, 1);
 | 
			
		||||
	got_write = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rb4xx_nand_write_byte(uint8_t byte)
 | 
			
		||||
{
 | 
			
		||||
	rb4xx_nand_write_data(&byte, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if USE_FAST_READ
 | 
			
		||||
static uint8_t *rb4xx_nand_read_getaddr(unsigned cnt)
 | 
			
		||||
{
 | 
			
		||||
	static unsigned nboffset = 0x100000;
 | 
			
		||||
	unsigned addr;
 | 
			
		||||
 | 
			
		||||
	if (got_write) {
 | 
			
		||||
		nboffset = (nboffset + 31) & ~31;
 | 
			
		||||
		if (nboffset >= 0x100000)	/* 1MB */
 | 
			
		||||
			nboffset = 0;
 | 
			
		||||
 | 
			
		||||
		got_write = 0;
 | 
			
		||||
		rb4xx_spi_wreg(SPI_REG_FS, SPI_FS_GPIO);
 | 
			
		||||
		rb4xx_spi_wreg(SPI_REG_CTRL, spi_ctrl_fread);
 | 
			
		||||
		rb4xx_spi_wreg(SPI_REG_FS, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addr = KSEG1ADDR(AR71XX_SPI_BASE + SPI_NDATA_BASE) + nboffset;
 | 
			
		||||
	DBG("rb4xx_nand_read_getaddr 0x%x cnt 0x%x\n", addr, cnt);
 | 
			
		||||
 | 
			
		||||
	nboffset += cnt;
 | 
			
		||||
	return (uint8_t *)addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt)
 | 
			
		||||
{
 | 
			
		||||
	unsigned size32 = cnt & ~31;
 | 
			
		||||
	unsigned remain = cnt & 31;
 | 
			
		||||
 | 
			
		||||
	if (size32) {
 | 
			
		||||
		uint8_t *addr = rb4xx_nand_read_getaddr(size32);
 | 
			
		||||
		memcpy(buf, (void *)addr, size32);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (remain) {
 | 
			
		||||
		do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain,
 | 
			
		||||
			   buf + size32, NULL, 0);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rb4xx_nand_verify_data(const uint8_t *buf, unsigned cnt)
 | 
			
		||||
{
 | 
			
		||||
	unsigned size32 = cnt & ~31;
 | 
			
		||||
	unsigned remain = cnt & 31;
 | 
			
		||||
 | 
			
		||||
	if (size32) {
 | 
			
		||||
		uint8_t *addr = rb4xx_nand_read_getaddr(size32);
 | 
			
		||||
		if (memcmp(buf, (void *)addr, size32) != 0)
 | 
			
		||||
			return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (remain) {
 | 
			
		||||
		return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain,
 | 
			
		||||
				  NULL, buf + size32, 0);
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
#else /* USE_FAST_READ */
 | 
			
		||||
static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt)
 | 
			
		||||
{
 | 
			
		||||
	do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, cnt, buf, NULL, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rb4xx_nand_verify_data(const uint8_t *buf, unsigned cnt)
 | 
			
		||||
{
 | 
			
		||||
	return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, cnt, NULL, buf, 0);
 | 
			
		||||
}
 | 
			
		||||
#endif /* USE_FAST_READ */
 | 
			
		||||
 | 
			
		||||
static void rb4xx_nand_write_cfg(uint8_t byte)
 | 
			
		||||
{
 | 
			
		||||
	do_spi_cmd(CPLD_CMD_WRITE_CFG, 1, &byte, 0, NULL, NULL, 0);
 | 
			
		||||
	got_write = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rb4xx_nand_dev_ready(struct mtd_info *mtd)
 | 
			
		||||
{
 | 
			
		||||
	return gpio_get_value(RB4XX_NAND_GPIO_RDY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rb4xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 | 
			
		||||
				unsigned int ctrl)
 | 
			
		||||
{
 | 
			
		||||
	if (ctrl & NAND_CTRL_CHANGE) {
 | 
			
		||||
		uint8_t cfg = CFG_BIT_nLEDS;
 | 
			
		||||
 | 
			
		||||
		cfg |= (ctrl & NAND_CLE) ? CFG_BIT_CLE : 0;
 | 
			
		||||
		cfg |= (ctrl & NAND_ALE) ? CFG_BIT_ALE : 0;
 | 
			
		||||
		cfg |= (ctrl & NAND_NCE) ? 0 : CFG_BIT_nCE;
 | 
			
		||||
 | 
			
		||||
		rb4xx_nand_write_cfg(cfg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cmd != NAND_CMD_NONE)
 | 
			
		||||
		rb4xx_nand_write_byte(cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t rb4xx_nand_read_byte(struct mtd_info *mtd)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t byte = 0;
 | 
			
		||||
 | 
			
		||||
	rb4xx_nand_read_data(&byte, 1);
 | 
			
		||||
	return byte;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rb4xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 | 
			
		||||
				int len)
 | 
			
		||||
{
 | 
			
		||||
	rb4xx_nand_write_data(buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rb4xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf,
 | 
			
		||||
				int len)
 | 
			
		||||
{
 | 
			
		||||
	rb4xx_nand_read_data(buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rb4xx_nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf,
 | 
			
		||||
				int len)
 | 
			
		||||
{
 | 
			
		||||
	if (!rb4xx_nand_verify_data(buf, len))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned get_spi_ctrl(unsigned hz_max, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	unsigned div;
 | 
			
		||||
 | 
			
		||||
	div = (ar71xx_ahb_freq - 1) / (2 * hz_max);
 | 
			
		||||
	/*
 | 
			
		||||
	 * CPU has a bug at (div == 0) - first bit read is random
 | 
			
		||||
	 */
 | 
			
		||||
	if (div == 0)
 | 
			
		||||
		++div;
 | 
			
		||||
 | 
			
		||||
	if (name) {
 | 
			
		||||
		unsigned ahb_khz = (ar71xx_ahb_freq + 500) / 1000;
 | 
			
		||||
		unsigned div_real = 2 * (div + 1);
 | 
			
		||||
		printk(KERN_INFO "%s SPI clock %u kHz (AHB %u kHz / %u)\n",
 | 
			
		||||
		       name,
 | 
			
		||||
		       ahb_khz / div_real,
 | 
			
		||||
		       ahb_khz, div_real);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return SPI_CTRL_FASTEST + div;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init rb4xx_nand_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct rb4xx_nand_info	*info;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
 | 
			
		||||
 | 
			
		||||
	ret = gpio_request(RB4XX_NAND_GPIO_RDY, "NAND RDY");
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		printk(KERN_ERR "rb4xx-nand: gpio request failed\n");
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = gpio_direction_input(RB4XX_NAND_GPIO_RDY);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		printk(KERN_ERR "rb4xx-nand: unable to set input mode "
 | 
			
		||||
					"on gpio%d\n", RB4XX_NAND_GPIO_RDY);
 | 
			
		||||
		goto err_free_gpio;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info = kzalloc(sizeof(*info), GFP_KERNEL);
 | 
			
		||||
	if (!info) {
 | 
			
		||||
		printk(KERN_ERR "rb4xx-nand: no memory for private data\n");
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto err_free_gpio;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if USE_FAST_READ
 | 
			
		||||
	spi_ctrl_fread = get_spi_ctrl(RB4XX_NAND_HZ, "NAND");
 | 
			
		||||
#endif
 | 
			
		||||
	spi_ctrl_flash = get_spi_ctrl(RB4XX_FLASH_HZ, "FLASH");
 | 
			
		||||
 | 
			
		||||
	rb4xx_nand_write_cfg(CFG_BIT_nLEDS | CFG_BIT_nCE);
 | 
			
		||||
 | 
			
		||||
	info->chip.priv	= &info;
 | 
			
		||||
	info->mtd.priv	= &info->chip;
 | 
			
		||||
	info->mtd.owner	= THIS_MODULE;
 | 
			
		||||
 | 
			
		||||
	info->chip.cmd_ctrl	= rb4xx_nand_cmd_ctrl;
 | 
			
		||||
	info->chip.dev_ready	= rb4xx_nand_dev_ready;
 | 
			
		||||
	info->chip.read_byte	= rb4xx_nand_read_byte;
 | 
			
		||||
	info->chip.write_buf	= rb4xx_nand_write_buf;
 | 
			
		||||
	info->chip.read_buf	= rb4xx_nand_read_buf;
 | 
			
		||||
	info->chip.verify_buf	= rb4xx_nand_verify_buf;
 | 
			
		||||
 | 
			
		||||
	info->chip.chip_delay	= 25;
 | 
			
		||||
	info->chip.ecc.mode	= NAND_ECC_SOFT;
 | 
			
		||||
	info->chip.options	|= NAND_NO_AUTOINCR;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, info);
 | 
			
		||||
 | 
			
		||||
	ret = nand_scan_ident(&info->mtd, 1);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		ret = -ENXIO;
 | 
			
		||||
		goto err_free_info;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (info->mtd.writesize == 512)
 | 
			
		||||
		info->chip.ecc.layout = &rb4xx_nand_ecclayout;
 | 
			
		||||
 | 
			
		||||
	ret = nand_scan_tail(&info->mtd);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
		goto err_set_drvdata;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MTD_PARTITIONS
 | 
			
		||||
	ret = add_mtd_partitions(&info->mtd, rb4xx_nand_partitions,
 | 
			
		||||
				ARRAY_SIZE(rb4xx_nand_partitions));
 | 
			
		||||
#else
 | 
			
		||||
	ret = add_mtd_device(&info->mtd);
 | 
			
		||||
#endif
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto err_release_nand;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_release_nand:
 | 
			
		||||
	nand_release(&info->mtd);
 | 
			
		||||
err_set_drvdata:
 | 
			
		||||
	platform_set_drvdata(pdev, NULL);
 | 
			
		||||
err_free_info:
 | 
			
		||||
	kfree(info);
 | 
			
		||||
err_free_gpio:
 | 
			
		||||
	gpio_free(RB4XX_NAND_GPIO_RDY);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __devexit rb4xx_nand_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct rb4xx_nand_info *info = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	nand_release(&info->mtd);
 | 
			
		||||
	platform_set_drvdata(pdev, NULL);
 | 
			
		||||
	kfree(info);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver rb4xx_nand_driver = {
 | 
			
		||||
	.probe	= rb4xx_nand_probe,
 | 
			
		||||
	.remove	= __devexit_p(rb4xx_nand_remove),
 | 
			
		||||
	.driver	= {
 | 
			
		||||
		.name	= DRV_NAME,
 | 
			
		||||
		.owner	= THIS_MODULE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init rb4xx_nand_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return platform_driver_register(&rb4xx_nand_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit rb4xx_nand_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	platform_driver_unregister(&rb4xx_nand_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module_init(rb4xx_nand_init);
 | 
			
		||||
module_exit(rb4xx_nand_exit);
 | 
			
		||||
 | 
			
		||||
MODULE_DESCRIPTION(DRV_DESC);
 | 
			
		||||
MODULE_VERSION(DRV_VERSION);
 | 
			
		||||
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
 | 
			
		||||
MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
 | 
			
		||||
MODULE_LICENSE("GPL v2");
 | 
			
		||||
							
								
								
									
										7
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/Kconfig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
config AG71XX
 | 
			
		||||
	tristate "Atheros AR71xx built-in ethernet mac support"
 | 
			
		||||
	depends on ATHEROS_AR71XX
 | 
			
		||||
	select PHYLIB
 | 
			
		||||
	help
 | 
			
		||||
	  If you wish to compile a kernel for AR71xx/91xx and enable
 | 
			
		||||
	  ethernet support, then you should always answer Y to this.
 | 
			
		||||
							
								
								
									
										7
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
#
 | 
			
		||||
# Makefile for the Atheros AR71xx built-in ethernet macs
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_AG71XX)	+= ag71xx.o
 | 
			
		||||
 | 
			
		||||
ag71xx-objs	:= ag71xx_main.o ag71xx_mii.o ag71xx_ethtool.o
 | 
			
		||||
							
								
								
									
										281
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,281 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx built-in ethernet mac driver
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Based on Atheros' AG7100 driver
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 __AG71XX_H
 | 
			
		||||
#define __AG71XX_H
 | 
			
		||||
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/ethtool.h>
 | 
			
		||||
#include <linux/etherdevice.h>
 | 
			
		||||
#include <linux/phy.h>
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/dma-mapping.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/bitops.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
#include <asm/mach-ar71xx/platform.h>
 | 
			
		||||
 | 
			
		||||
#define ETH_FCS_LEN	4
 | 
			
		||||
 | 
			
		||||
#define AG71XX_DRV_NAME		"ag71xx"
 | 
			
		||||
#define AG71XX_DRV_VERSION	"0.3.9"
 | 
			
		||||
 | 
			
		||||
#define AG71XX_NAPI_TX		1
 | 
			
		||||
 | 
			
		||||
#define AG71XX_NAPI_WEIGHT	64
 | 
			
		||||
 | 
			
		||||
#define AG71XX_INT_ERR	(AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
 | 
			
		||||
#define AG71XX_INT_TX	(AG71XX_INT_TX_PS)
 | 
			
		||||
#define AG71XX_INT_RX	(AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
 | 
			
		||||
 | 
			
		||||
#ifdef AG71XX_NAPI_TX
 | 
			
		||||
#define AG71XX_INT_POLL	(AG71XX_INT_RX | AG71XX_INT_TX)
 | 
			
		||||
#define AG71XX_INT_INIT	(AG71XX_INT_ERR | AG71XX_INT_POLL)
 | 
			
		||||
#else
 | 
			
		||||
#define AG71XX_INT_POLL	(AG71XX_INT_RX)
 | 
			
		||||
#define AG71XX_INT_INIT	(AG71XX_INT_ERR | AG71XX_INT_POLL | AG71XX_INT_TX)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define AG71XX_TX_FIFO_LEN	2048
 | 
			
		||||
#define AG71XX_TX_MTU_LEN	1536
 | 
			
		||||
#define AG71XX_RX_PKT_RESERVE	64
 | 
			
		||||
#define AG71XX_RX_PKT_SIZE	\
 | 
			
		||||
	(AG71XX_RX_PKT_RESERVE + ETH_HLEN + ETH_FRAME_LEN + ETH_FCS_LEN)
 | 
			
		||||
 | 
			
		||||
#define AG71XX_TX_RING_SIZE	64
 | 
			
		||||
#define AG71XX_TX_THRES_STOP	(AG71XX_TX_RING_SIZE - 4)
 | 
			
		||||
#define AG71XX_TX_THRES_WAKEUP	\
 | 
			
		||||
		(AG71XX_TX_RING_SIZE - (AG71XX_TX_RING_SIZE / 4))
 | 
			
		||||
 | 
			
		||||
#define AG71XX_RX_RING_SIZE	128
 | 
			
		||||
 | 
			
		||||
#undef DEBUG
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
#define DBG(fmt, args...)	printk(KERN_DEBUG fmt, ## args)
 | 
			
		||||
#else
 | 
			
		||||
#define DBG(fmt, args...)	do {} while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define ag71xx_assert(_cond)						\
 | 
			
		||||
do {									\
 | 
			
		||||
	if (_cond)							\
 | 
			
		||||
		break;							\
 | 
			
		||||
	printk("%s,%d: assertion failed\n", __FILE__, __LINE__);	\
 | 
			
		||||
	BUG();								\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
struct ag71xx_desc {
 | 
			
		||||
	u32	data;
 | 
			
		||||
	u32	ctrl;
 | 
			
		||||
#define DESC_EMPTY	BIT(31)
 | 
			
		||||
#define DESC_MORE	BIT(24)
 | 
			
		||||
#define DESC_PKTLEN_M	0x1fff
 | 
			
		||||
	u32	next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ag71xx_buf {
 | 
			
		||||
	struct sk_buff	*skb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ag71xx_ring {
 | 
			
		||||
	struct ag71xx_buf	*buf;
 | 
			
		||||
	struct ag71xx_desc	*descs;
 | 
			
		||||
	dma_addr_t		descs_dma;
 | 
			
		||||
	unsigned int		curr;
 | 
			
		||||
	unsigned int		dirty;
 | 
			
		||||
	unsigned int		size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ag71xx {
 | 
			
		||||
	void __iomem		*mac_base;
 | 
			
		||||
	void __iomem		*mii_ctrl;
 | 
			
		||||
 | 
			
		||||
	spinlock_t		lock;
 | 
			
		||||
	struct platform_device	*pdev;
 | 
			
		||||
	struct net_device	*dev;
 | 
			
		||||
	struct napi_struct	napi;
 | 
			
		||||
 | 
			
		||||
	struct ag71xx_ring	rx_ring;
 | 
			
		||||
	struct ag71xx_ring	tx_ring;
 | 
			
		||||
 | 
			
		||||
	struct phy_device	*phy_dev;
 | 
			
		||||
	struct mii_bus		mii_bus;
 | 
			
		||||
 | 
			
		||||
	unsigned int		link;
 | 
			
		||||
	unsigned int		speed;
 | 
			
		||||
	int 			duplex;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct ethtool_ops ag71xx_ethtool_ops;
 | 
			
		||||
 | 
			
		||||
extern int ag71xx_mdio_init(struct ag71xx *ag, int id);
 | 
			
		||||
extern void ag71xx_mdio_cleanup(struct ag71xx *ag);
 | 
			
		||||
extern int ag71xx_mii_peek(struct ag71xx *ag);
 | 
			
		||||
extern void ag71xx_mii_ctrl_set_if(struct ag71xx *ag, unsigned int mii_if);
 | 
			
		||||
extern void ag71xx_mii_ctrl_set_speed(struct ag71xx *ag, unsigned int speed);
 | 
			
		||||
extern void ag71xx_link_update(struct ag71xx *ag);
 | 
			
		||||
 | 
			
		||||
static inline struct ag71xx_platform_data *ag71xx_get_pdata(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	return ag->pdev->dev.platform_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ag71xx_wr(struct ag71xx *ag, unsigned reg, u32 value)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(value, ag->mac_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ag71xx_rr(struct ag71xx *ag, unsigned reg)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(ag->mac_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ag71xx_sb(struct ag71xx *ag, unsigned reg, u32 mask)
 | 
			
		||||
{
 | 
			
		||||
	void __iomem *r = ag->mac_base + reg;
 | 
			
		||||
 | 
			
		||||
	__raw_writel(__raw_readl(r) | mask, r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ag71xx_cb(struct ag71xx *ag, unsigned reg, u32 mask)
 | 
			
		||||
{
 | 
			
		||||
	void __iomem *r = ag->mac_base + reg;
 | 
			
		||||
 | 
			
		||||
	__raw_writel(__raw_readl(r) & ~mask, r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int ag71xx_desc_empty(struct ag71xx_desc *desc)
 | 
			
		||||
{
 | 
			
		||||
	return ((desc->ctrl & DESC_EMPTY) != 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc)
 | 
			
		||||
{
 | 
			
		||||
	return (desc->ctrl & DESC_PKTLEN_M);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Register offsets */
 | 
			
		||||
#define AG71XX_REG_MAC_CFG1	0x0000
 | 
			
		||||
#define AG71XX_REG_MAC_CFG2	0x0004
 | 
			
		||||
#define AG71XX_REG_MAC_IPG	0x0008
 | 
			
		||||
#define AG71XX_REG_MAC_HDX	0x000c
 | 
			
		||||
#define AG71XX_REG_MAC_MFL	0x0010
 | 
			
		||||
#define AG71XX_REG_MII_CFG	0x0020
 | 
			
		||||
#define AG71XX_REG_MII_CMD	0x0024
 | 
			
		||||
#define AG71XX_REG_MII_ADDR	0x0028
 | 
			
		||||
#define AG71XX_REG_MII_CTRL	0x002c
 | 
			
		||||
#define AG71XX_REG_MII_STATUS	0x0030
 | 
			
		||||
#define AG71XX_REG_MII_IND	0x0034
 | 
			
		||||
#define AG71XX_REG_MAC_IFCTL	0x0038
 | 
			
		||||
#define AG71XX_REG_MAC_ADDR1	0x0040
 | 
			
		||||
#define AG71XX_REG_MAC_ADDR2	0x0044
 | 
			
		||||
#define AG71XX_REG_FIFO_CFG0	0x0048
 | 
			
		||||
#define AG71XX_REG_FIFO_CFG1	0x004c
 | 
			
		||||
#define AG71XX_REG_FIFO_CFG2	0x0050
 | 
			
		||||
#define AG71XX_REG_FIFO_CFG3	0x0054
 | 
			
		||||
#define AG71XX_REG_FIFO_CFG4	0x0058
 | 
			
		||||
#define AG71XX_REG_FIFO_CFG5	0x005c
 | 
			
		||||
#define AG71XX_REG_FIFO_RAM0	0x0060
 | 
			
		||||
#define AG71XX_REG_FIFO_RAM1	0x0064
 | 
			
		||||
#define AG71XX_REG_FIFO_RAM2	0x0068
 | 
			
		||||
#define AG71XX_REG_FIFO_RAM3	0x006c
 | 
			
		||||
#define AG71XX_REG_FIFO_RAM4	0x0070
 | 
			
		||||
#define AG71XX_REG_FIFO_RAM5	0x0074
 | 
			
		||||
#define AG71XX_REG_FIFO_RAM6	0x0078
 | 
			
		||||
#define AG71XX_REG_FIFO_RAM7	0x007c
 | 
			
		||||
 | 
			
		||||
#define AG71XX_REG_TX_CTRL	0x0180
 | 
			
		||||
#define AG71XX_REG_TX_DESC	0x0184
 | 
			
		||||
#define AG71XX_REG_TX_STATUS	0x0188
 | 
			
		||||
#define AG71XX_REG_RX_CTRL	0x018c
 | 
			
		||||
#define AG71XX_REG_RX_DESC	0x0190
 | 
			
		||||
#define AG71XX_REG_RX_STATUS	0x0194
 | 
			
		||||
#define AG71XX_REG_INT_ENABLE	0x0198
 | 
			
		||||
#define AG71XX_REG_INT_STATUS	0x019c
 | 
			
		||||
 | 
			
		||||
#define MAC_CFG1_TXE		BIT(0)
 | 
			
		||||
#define MAC_CFG1_STX		BIT(1)
 | 
			
		||||
#define MAC_CFG1_RXE		BIT(2)
 | 
			
		||||
#define MAC_CFG1_SRX		BIT(3)
 | 
			
		||||
#define MAC_CFG1_LB		BIT(8)
 | 
			
		||||
#define MAC_CFG1_SR		BIT(31)
 | 
			
		||||
 | 
			
		||||
#define MAC_CFG2_FDX		BIT(0)
 | 
			
		||||
#define MAC_CFG2_CRC_EN		BIT(1)
 | 
			
		||||
#define MAC_CFG2_PAD_CRC_EN	BIT(2)
 | 
			
		||||
#define MAC_CFG2_LEN_CHECK	BIT(4)
 | 
			
		||||
#define MAC_CFG2_HUGE_FRAME_EN	BIT(5)
 | 
			
		||||
#define MAC_CFG2_IF_1000	BIT(9)
 | 
			
		||||
#define MAC_CFG2_IF_10_100	BIT(8)
 | 
			
		||||
 | 
			
		||||
#define AG71XX_INT_TX_PS	BIT(0)
 | 
			
		||||
#define AG71XX_INT_TX_UR	BIT(1)
 | 
			
		||||
#define AG71XX_INT_TX_BE	BIT(3)
 | 
			
		||||
#define AG71XX_INT_RX_PR	BIT(4)
 | 
			
		||||
#define AG71XX_INT_RX_OF	BIT(6)
 | 
			
		||||
#define AG71XX_INT_RX_BE	BIT(7)
 | 
			
		||||
 | 
			
		||||
#define MAC_IFCTL_SPEED		BIT(16)
 | 
			
		||||
 | 
			
		||||
#define MII_CFG_CLK_DIV_4	0
 | 
			
		||||
#define MII_CFG_CLK_DIV_6	2
 | 
			
		||||
#define MII_CFG_CLK_DIV_8	3
 | 
			
		||||
#define MII_CFG_CLK_DIV_10	4
 | 
			
		||||
#define MII_CFG_CLK_DIV_14	5
 | 
			
		||||
#define MII_CFG_CLK_DIV_20	6
 | 
			
		||||
#define MII_CFG_CLK_DIV_28	7
 | 
			
		||||
 | 
			
		||||
#define MII_CMD_WRITE		0x0
 | 
			
		||||
#define MII_CMD_READ		0x1
 | 
			
		||||
#define MII_ADDR_S		8
 | 
			
		||||
#define MII_IND_BUSY		BIT(0)
 | 
			
		||||
#define MII_IND_INVALID		BIT(2)
 | 
			
		||||
 | 
			
		||||
#define TX_CTRL_TXE		BIT(0)
 | 
			
		||||
 | 
			
		||||
#define TX_STATUS_PS		BIT(0)
 | 
			
		||||
#define TX_STATUS_UR		BIT(1)
 | 
			
		||||
#define TX_STATUS_BE		BIT(3)
 | 
			
		||||
 | 
			
		||||
#define RX_CTRL_RXE		BIT(0)
 | 
			
		||||
 | 
			
		||||
#define RX_STATUS_PR		BIT(0)
 | 
			
		||||
#define RX_STATUS_OF		BIT(1)
 | 
			
		||||
#define RX_STATUS_BE		BIT(3)
 | 
			
		||||
 | 
			
		||||
#define FIFO_CFG5_BYTE_PER_CLK	BIT(19)
 | 
			
		||||
 | 
			
		||||
#define MII_CTRL_SPEED_S	4
 | 
			
		||||
#define MII_CTRL_SPEED_M	3
 | 
			
		||||
#define MII_CTRL_SPEED_10	0
 | 
			
		||||
#define MII_CTRL_SPEED_100	1
 | 
			
		||||
#define MII_CTRL_SPEED_1000	2
 | 
			
		||||
 | 
			
		||||
static inline void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
 | 
			
		||||
{
 | 
			
		||||
	ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
 | 
			
		||||
{
 | 
			
		||||
	ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _AG71XX_H */
 | 
			
		||||
@ -0,0 +1,55 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx built-in ethernet mac driver
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Based on Atheros' AG7100 driver
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 "ag71xx.h"
 | 
			
		||||
 | 
			
		||||
static int ag71xx_ethtool_get_settings(struct net_device *dev,
 | 
			
		||||
				       struct ethtool_cmd *cmd)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
	struct phy_device *phydev = ag->phy_dev;
 | 
			
		||||
 | 
			
		||||
	if (!phydev)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	return phy_ethtool_gset(phydev, cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_ethtool_set_settings(struct net_device *dev,
 | 
			
		||||
				       struct ethtool_cmd *cmd)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
	struct phy_device *phydev = ag->phy_dev;
 | 
			
		||||
 | 
			
		||||
	if (!phydev)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	return phy_ethtool_sset(phydev, cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_ethtool_get_drvinfo(struct net_device *dev,
 | 
			
		||||
				       struct ethtool_drvinfo *info)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
 | 
			
		||||
	strcpy(info->driver, ag->pdev->dev.driver->name);
 | 
			
		||||
	strcpy(info->version, AG71XX_DRV_VERSION);
 | 
			
		||||
	strcpy(info->bus_info, ag->pdev->dev.bus_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ethtool_ops ag71xx_ethtool_ops = {
 | 
			
		||||
	.set_settings	= ag71xx_ethtool_set_settings,
 | 
			
		||||
	.get_settings	= ag71xx_ethtool_get_settings,
 | 
			
		||||
	.get_drvinfo	= ag71xx_ethtool_get_drvinfo,
 | 
			
		||||
	.get_link	= ethtool_op_get_link,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										855
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										855
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,855 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx built-in ethernet mac driver
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Based on Atheros' AG7100 driver
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 "ag71xx.h"
 | 
			
		||||
 | 
			
		||||
static void ag71xx_dump_regs(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	DBG("%s: mac_cfg1=%08x, mac_cfg2=%08x, ipg=%08x, hdx=%08x, mfl=%08x\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_CFG1),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_IPG),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_HDX),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_MFL));
 | 
			
		||||
	DBG("%s: mii_cfg=%08x, mii_cmd=%08x, mii_addr=%08x\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MII_CFG),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MII_CMD),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MII_ADDR));
 | 
			
		||||
	DBG("%s: mii_ctrl=%08x, mii_status=%08x, mii_ind=%08x\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MII_CTRL),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MII_STATUS),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MII_IND));
 | 
			
		||||
	DBG("%s: mac_ifctl=%08x, mac_addr1=%08x, mac_addr2=%08x\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_ADDR1),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_ADDR2));
 | 
			
		||||
	DBG("%s: fifo_cfg0=%08x, fifo_cfg1=%08x, fifo_cfg2=%08x\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
 | 
			
		||||
	DBG("%s: fifo_cfg3=%08x, fifo_cfg3=%08x, fifo_cfg5=%08x\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_ring_free(struct ag71xx_ring *ring)
 | 
			
		||||
{
 | 
			
		||||
	kfree(ring->buf);
 | 
			
		||||
 | 
			
		||||
	if (ring->descs)
 | 
			
		||||
		dma_free_coherent(NULL, ring->size * sizeof(*ring->descs),
 | 
			
		||||
				  ring->descs, ring->descs_dma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	ring->descs = dma_alloc_coherent(NULL, size * sizeof(*ring->descs),
 | 
			
		||||
					 &ring->descs_dma,
 | 
			
		||||
					 GFP_ATOMIC);
 | 
			
		||||
	if (!ring->descs) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ring->size = size;
 | 
			
		||||
 | 
			
		||||
	ring->buf = kzalloc(size * sizeof(*ring->buf), GFP_KERNEL);
 | 
			
		||||
	if (!ring->buf) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_ring_tx_clean(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx_ring *ring = &ag->tx_ring;
 | 
			
		||||
	struct net_device *dev = ag->dev;
 | 
			
		||||
 | 
			
		||||
	while (ring->curr != ring->dirty) {
 | 
			
		||||
		u32 i = ring->dirty % AG71XX_TX_RING_SIZE;
 | 
			
		||||
 | 
			
		||||
		if (!ag71xx_desc_empty(&ring->descs[i])) {
 | 
			
		||||
			ring->descs[i].ctrl = 0;
 | 
			
		||||
			dev->stats.tx_errors++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (ring->buf[i].skb)
 | 
			
		||||
			dev_kfree_skb_any(ring->buf[i].skb);
 | 
			
		||||
 | 
			
		||||
		ring->buf[i].skb = NULL;
 | 
			
		||||
 | 
			
		||||
		ring->dirty++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* flush descriptors */
 | 
			
		||||
	wmb();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_ring_tx_init(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx_ring *ring = &ag->tx_ring;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < AG71XX_TX_RING_SIZE; i++) {
 | 
			
		||||
		ring->descs[i].next = (u32) (ring->descs_dma +
 | 
			
		||||
			sizeof(*ring->descs) * ((i + 1) % AG71XX_TX_RING_SIZE));
 | 
			
		||||
 | 
			
		||||
		ring->descs[i].ctrl = DESC_EMPTY;
 | 
			
		||||
		ring->buf[i].skb = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* flush descriptors */
 | 
			
		||||
	wmb();
 | 
			
		||||
 | 
			
		||||
	ring->curr = 0;
 | 
			
		||||
	ring->dirty = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_ring_rx_clean(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx_ring *ring = &ag->rx_ring;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!ring->buf)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < AG71XX_RX_RING_SIZE; i++)
 | 
			
		||||
		if (ring->buf[i].skb)
 | 
			
		||||
			kfree_skb(ring->buf[i].skb);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_ring_rx_init(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx_ring *ring = &ag->rx_ring;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = 0;
 | 
			
		||||
	for (i = 0; i < AG71XX_RX_RING_SIZE; i++)
 | 
			
		||||
		ring->descs[i].next = (u32) (ring->descs_dma +
 | 
			
		||||
			sizeof(*ring->descs) * ((i + 1) % AG71XX_RX_RING_SIZE));
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
 | 
			
		||||
		struct sk_buff *skb;
 | 
			
		||||
 | 
			
		||||
		skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE);
 | 
			
		||||
		if (!skb) {
 | 
			
		||||
			ret = -ENOMEM;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		skb->dev = ag->dev;
 | 
			
		||||
		skb_reserve(skb, AG71XX_RX_PKT_RESERVE);
 | 
			
		||||
 | 
			
		||||
		ring->buf[i].skb = skb;
 | 
			
		||||
		ring->descs[i].data = virt_to_phys(skb->data);
 | 
			
		||||
		ring->descs[i].ctrl = DESC_EMPTY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* flush descriptors */
 | 
			
		||||
	wmb();
 | 
			
		||||
 | 
			
		||||
	ring->curr = 0;
 | 
			
		||||
	ring->dirty = 0;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_ring_rx_refill(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx_ring *ring = &ag->rx_ring;
 | 
			
		||||
	unsigned int count;
 | 
			
		||||
 | 
			
		||||
	count = 0;
 | 
			
		||||
	for (; ring->curr - ring->dirty > 0; ring->dirty++) {
 | 
			
		||||
		unsigned int i;
 | 
			
		||||
 | 
			
		||||
		i = ring->dirty % AG71XX_RX_RING_SIZE;
 | 
			
		||||
 | 
			
		||||
		if (ring->buf[i].skb == NULL) {
 | 
			
		||||
			struct sk_buff *skb;
 | 
			
		||||
 | 
			
		||||
			skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE);
 | 
			
		||||
			if (skb == NULL) {
 | 
			
		||||
				printk(KERN_ERR "%s: no memory for skb\n",
 | 
			
		||||
					ag->dev->name);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			skb_reserve(skb, AG71XX_RX_PKT_RESERVE);
 | 
			
		||||
			skb->dev = ag->dev;
 | 
			
		||||
			ring->buf[i].skb = skb;
 | 
			
		||||
			ring->descs[i].data = virt_to_phys(skb->data);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ring->descs[i].ctrl = DESC_EMPTY;
 | 
			
		||||
		count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* flush descriptors */
 | 
			
		||||
	wmb();
 | 
			
		||||
 | 
			
		||||
	DBG("%s: %u rx descriptors refilled\n", ag->dev->name, count);
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_rings_init(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = ag71xx_ring_alloc(&ag->tx_ring, AG71XX_TX_RING_SIZE);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ag71xx_ring_tx_init(ag);
 | 
			
		||||
 | 
			
		||||
	ret = ag71xx_ring_alloc(&ag->rx_ring, AG71XX_RX_RING_SIZE);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = ag71xx_ring_rx_init(ag);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_rings_cleanup(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	ag71xx_ring_rx_clean(ag);
 | 
			
		||||
	ag71xx_ring_free(&ag->rx_ring);
 | 
			
		||||
 | 
			
		||||
	ag71xx_ring_tx_clean(ag);
 | 
			
		||||
	ag71xx_ring_free(&ag->tx_ring);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
 | 
			
		||||
{
 | 
			
		||||
	u32 t;
 | 
			
		||||
 | 
			
		||||
	t = (((u32) mac[0]) << 24) | (((u32) mac[1]) << 16)
 | 
			
		||||
	  | (((u32) mac[2]) << 8) | ((u32) mac[2]);
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
 | 
			
		||||
 | 
			
		||||
	t = (((u32) mac[4]) << 24) | (((u32) mac[5]) << 16);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MAC_CFG1_INIT	(MAC_CFG1_RXE | MAC_CFG1_TXE | MAC_CFG1_SRX \
 | 
			
		||||
			| MAC_CFG1_STX)
 | 
			
		||||
 | 
			
		||||
static void ag71xx_hw_init(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
 | 
			
		||||
 | 
			
		||||
	ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
 | 
			
		||||
	udelay(20);
 | 
			
		||||
 | 
			
		||||
	ar71xx_device_stop(pdata->reset_bit);
 | 
			
		||||
	mdelay(100);
 | 
			
		||||
	ar71xx_device_start(pdata->reset_bit);
 | 
			
		||||
	mdelay(100);
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT);
 | 
			
		||||
 | 
			
		||||
	/* TODO: set max packet size */
 | 
			
		||||
 | 
			
		||||
	ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
 | 
			
		||||
		  MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, 0x00001f00);
 | 
			
		||||
 | 
			
		||||
	ag71xx_mii_ctrl_set_if(ag, pdata->mii_if);
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MII_CFG, MII_CFG_CLK_DIV_28);
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, 0x0000ffff);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, 0x0007ffef);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_hw_start(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	/* start RX engine */
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
 | 
			
		||||
 | 
			
		||||
	/* enable interrupts */
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_hw_stop(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	/* stop RX and TX */
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
 | 
			
		||||
 | 
			
		||||
	/* disable all interrupts */
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_open(struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = ag71xx_rings_init(ag);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto err;
 | 
			
		||||
 | 
			
		||||
	napi_enable(&ag->napi);
 | 
			
		||||
 | 
			
		||||
	netif_carrier_off(dev);
 | 
			
		||||
	if (ag->phy_dev) {
 | 
			
		||||
		phy_start(ag->phy_dev);
 | 
			
		||||
	} else {
 | 
			
		||||
		ag->duplex = DUPLEX_FULL;
 | 
			
		||||
		ag->speed = SPEED_100;
 | 
			
		||||
		ag->link = 1;
 | 
			
		||||
		ag71xx_link_update(ag);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
 | 
			
		||||
 | 
			
		||||
	ag71xx_hw_set_macaddr(ag, dev->dev_addr);
 | 
			
		||||
 | 
			
		||||
	ag71xx_hw_start(ag);
 | 
			
		||||
 | 
			
		||||
	netif_start_queue(dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	ag71xx_rings_cleanup(ag);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_stop(struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ag->lock, flags);
 | 
			
		||||
 | 
			
		||||
	netif_stop_queue(dev);
 | 
			
		||||
 | 
			
		||||
	ag71xx_hw_stop(ag);
 | 
			
		||||
 | 
			
		||||
	netif_carrier_off(dev);
 | 
			
		||||
	if (ag->phy_dev) {
 | 
			
		||||
		phy_stop(ag->phy_dev);
 | 
			
		||||
	} else {
 | 
			
		||||
		ag->duplex = -1;
 | 
			
		||||
		ag->link = 0;
 | 
			
		||||
		ag->speed = 0;
 | 
			
		||||
		ag71xx_link_update(ag);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	napi_disable(&ag->napi);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&ag->lock, flags);
 | 
			
		||||
 | 
			
		||||
	ag71xx_rings_cleanup(ag);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
 | 
			
		||||
	struct ag71xx_ring *ring = &ag->tx_ring;
 | 
			
		||||
	struct ag71xx_desc *desc;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	i = ring->curr % AG71XX_TX_RING_SIZE;
 | 
			
		||||
	desc = &ring->descs[i];
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ag->lock, flags);
 | 
			
		||||
	ar71xx_ddr_flush(pdata->flush_reg);
 | 
			
		||||
	spin_unlock_irqrestore(&ag->lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (!ag71xx_desc_empty(desc))
 | 
			
		||||
		goto err_drop;
 | 
			
		||||
 | 
			
		||||
	if (skb->len <= 0) {
 | 
			
		||||
		DBG("%s: packet len is too small\n", ag->dev->name);
 | 
			
		||||
		goto err_drop;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dma_cache_wback_inv((unsigned long)skb->data, skb->len);
 | 
			
		||||
 | 
			
		||||
	ring->buf[i].skb = skb;
 | 
			
		||||
 | 
			
		||||
	/* setup descriptor fields */
 | 
			
		||||
	desc->data = virt_to_phys(skb->data);
 | 
			
		||||
	desc->ctrl = (skb->len & DESC_PKTLEN_M);
 | 
			
		||||
 | 
			
		||||
	/* flush descriptor */
 | 
			
		||||
	wmb();
 | 
			
		||||
 | 
			
		||||
	ring->curr++;
 | 
			
		||||
	if (ring->curr == (ring->dirty + AG71XX_TX_THRES_STOP)) {
 | 
			
		||||
		DBG("%s: tx queue full\n", ag->dev->name);
 | 
			
		||||
		netif_stop_queue(dev);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DBG("%s: packet injected into TX queue\n", ag->dev->name);
 | 
			
		||||
 | 
			
		||||
	/* enable TX engine */
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
 | 
			
		||||
 | 
			
		||||
	dev->trans_start = jiffies;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_drop:
 | 
			
		||||
	dev->stats.tx_dropped++;
 | 
			
		||||
 | 
			
		||||
	dev_kfree_skb(skb);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 | 
			
		||||
{
 | 
			
		||||
	struct mii_ioctl_data *data = (struct mii_ioctl_data *) &ifr->ifr_data;
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
	case SIOCETHTOOL:
 | 
			
		||||
		if (ag->phy_dev == NULL)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		spin_lock_irq(&ag->lock);
 | 
			
		||||
		ret = phy_ethtool_ioctl(ag->phy_dev, (void *) ifr->ifr_data);
 | 
			
		||||
		spin_unlock_irq(&ag->lock);
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	case SIOCGMIIPHY:
 | 
			
		||||
	case SIOCGMIIREG:
 | 
			
		||||
	case SIOCSMIIREG:
 | 
			
		||||
		if (ag->phy_dev == NULL)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		return phy_mii_ioctl(ag->phy_dev, data, cmd);
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -EOPNOTSUPP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_tx_packets(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
 | 
			
		||||
	struct ag71xx_ring *ring = &ag->tx_ring;
 | 
			
		||||
	unsigned int sent;
 | 
			
		||||
 | 
			
		||||
	DBG("%s: processing TX ring\n", ag->dev->name);
 | 
			
		||||
 | 
			
		||||
#ifdef AG71XX_NAPI_TX
 | 
			
		||||
	ar71xx_ddr_flush(pdata->flush_reg);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	sent = 0;
 | 
			
		||||
	while (ring->dirty != ring->curr) {
 | 
			
		||||
		unsigned int i = ring->dirty % AG71XX_TX_RING_SIZE;
 | 
			
		||||
		struct ag71xx_desc *desc = &ring->descs[i];
 | 
			
		||||
		struct sk_buff *skb = ring->buf[i].skb;
 | 
			
		||||
 | 
			
		||||
		if (!ag71xx_desc_empty(desc))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
 | 
			
		||||
 | 
			
		||||
		ag->dev->stats.tx_bytes += skb->len;
 | 
			
		||||
		ag->dev->stats.tx_packets++;
 | 
			
		||||
 | 
			
		||||
		dev_kfree_skb_any(skb);
 | 
			
		||||
		ring->buf[i].skb = NULL;
 | 
			
		||||
 | 
			
		||||
		ring->dirty++;
 | 
			
		||||
		sent++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DBG("%s: %d packets sent out\n", ag->dev->name, sent);
 | 
			
		||||
 | 
			
		||||
	if ((ring->curr - ring->dirty) < AG71XX_TX_THRES_WAKEUP)
 | 
			
		||||
		netif_wake_queue(ag->dev);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_rx_packets(struct ag71xx *ag, int limit)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *dev = ag->dev;
 | 
			
		||||
	struct ag71xx_ring *ring = &ag->rx_ring;
 | 
			
		||||
#ifndef AG71XX_NAPI_TX
 | 
			
		||||
	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
#endif
 | 
			
		||||
	int done = 0;
 | 
			
		||||
 | 
			
		||||
#ifndef AG71XX_NAPI_TX
 | 
			
		||||
	spin_lock_irqsave(&ag->lock, flags);
 | 
			
		||||
	ar71xx_ddr_flush(pdata->flush_reg);
 | 
			
		||||
	spin_unlock_irqrestore(&ag->lock, flags);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	DBG("%s: rx packets, limit=%d, curr=%u, dirty=%u\n",
 | 
			
		||||
			dev->name, limit, ring->curr, ring->dirty);
 | 
			
		||||
 | 
			
		||||
	while (done < limit) {
 | 
			
		||||
		unsigned int i = ring->curr % AG71XX_RX_RING_SIZE;
 | 
			
		||||
		struct ag71xx_desc *desc = &ring->descs[i];
 | 
			
		||||
		struct sk_buff *skb;
 | 
			
		||||
		int pktlen;
 | 
			
		||||
 | 
			
		||||
		if (ag71xx_desc_empty(desc))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if ((ring->dirty + AG71XX_RX_RING_SIZE) == ring->curr) {
 | 
			
		||||
			ag71xx_assert(0);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		skb = ring->buf[i].skb;
 | 
			
		||||
		pktlen = ag71xx_desc_pktlen(desc);
 | 
			
		||||
		pktlen -= ETH_FCS_LEN;
 | 
			
		||||
 | 
			
		||||
		/* TODO: move it into the refill function */
 | 
			
		||||
		dma_cache_wback_inv((unsigned long)skb->data, pktlen);
 | 
			
		||||
		skb_put(skb, pktlen);
 | 
			
		||||
 | 
			
		||||
		skb->dev = dev;
 | 
			
		||||
		skb->protocol = eth_type_trans(skb, dev);
 | 
			
		||||
		skb->ip_summed = CHECKSUM_UNNECESSARY;
 | 
			
		||||
 | 
			
		||||
		netif_receive_skb(skb);
 | 
			
		||||
 | 
			
		||||
		dev->last_rx = jiffies;
 | 
			
		||||
		dev->stats.rx_packets++;
 | 
			
		||||
		dev->stats.rx_bytes += pktlen;
 | 
			
		||||
 | 
			
		||||
		ring->buf[i].skb = NULL;
 | 
			
		||||
		done++;
 | 
			
		||||
 | 
			
		||||
		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
 | 
			
		||||
 | 
			
		||||
		ring->curr++;
 | 
			
		||||
		if ((ring->curr - ring->dirty) > (AG71XX_RX_RING_SIZE / 4))
 | 
			
		||||
			ag71xx_ring_rx_refill(ag);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ag71xx_ring_rx_refill(ag);
 | 
			
		||||
 | 
			
		||||
	DBG("%s: rx finish, curr=%u, dirty=%u, done=%d\n",
 | 
			
		||||
		dev->name, ring->curr, ring->dirty, done);
 | 
			
		||||
 | 
			
		||||
	return done;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_poll(struct napi_struct *napi, int limit)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = container_of(napi, struct ag71xx, napi);
 | 
			
		||||
#ifdef AG71XX_NAPI_TX
 | 
			
		||||
	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
 | 
			
		||||
#endif
 | 
			
		||||
	struct net_device *dev = ag->dev;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	u32 status;
 | 
			
		||||
	int done;
 | 
			
		||||
 | 
			
		||||
#ifdef AG71XX_NAPI_TX
 | 
			
		||||
	ar71xx_ddr_flush(pdata->flush_reg);
 | 
			
		||||
	ag71xx_tx_packets(ag);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	DBG("%s: processing RX ring\n", dev->name);
 | 
			
		||||
	done = ag71xx_rx_packets(ag, limit);
 | 
			
		||||
 | 
			
		||||
	/* TODO: add OOM handler */
 | 
			
		||||
 | 
			
		||||
	status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS);
 | 
			
		||||
	status &= AG71XX_INT_POLL;
 | 
			
		||||
 | 
			
		||||
	if ((done < limit) && (!status)) {
 | 
			
		||||
		DBG("%s: disable polling mode, done=%d, status=%x\n",
 | 
			
		||||
			dev->name, done, status);
 | 
			
		||||
 | 
			
		||||
		netif_rx_complete(dev, napi);
 | 
			
		||||
 | 
			
		||||
		/* enable interrupts */
 | 
			
		||||
		spin_lock_irqsave(&ag->lock, flags);
 | 
			
		||||
		ag71xx_int_enable(ag, AG71XX_INT_POLL);
 | 
			
		||||
		spin_unlock_irqrestore(&ag->lock, flags);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (status & AG71XX_INT_RX_OF) {
 | 
			
		||||
		printk(KERN_ALERT "%s: rx owerflow, restarting dma\n",
 | 
			
		||||
			dev->name);
 | 
			
		||||
 | 
			
		||||
		/* ack interrupt */
 | 
			
		||||
		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF);
 | 
			
		||||
		/* restart RX */
 | 
			
		||||
		ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DBG("%s: stay in polling mode, done=%d, status=%x\n",
 | 
			
		||||
			dev->name, done, status);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static irqreturn_t ag71xx_interrupt(int irq, void *dev_id)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *dev = dev_id;
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
	u32 status;
 | 
			
		||||
 | 
			
		||||
	status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS);
 | 
			
		||||
	status &= ag71xx_rr(ag, AG71XX_REG_INT_ENABLE);
 | 
			
		||||
 | 
			
		||||
	if (unlikely(!status))
 | 
			
		||||
		return IRQ_NONE;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(status & AG71XX_INT_ERR)) {
 | 
			
		||||
		if (status & AG71XX_INT_TX_BE) {
 | 
			
		||||
			ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE);
 | 
			
		||||
			dev_err(&dev->dev, "TX BUS error\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (status & AG71XX_INT_RX_BE) {
 | 
			
		||||
			ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE);
 | 
			
		||||
			dev_err(&dev->dev, "RX BUS error\n");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
	if (unlikely(status & AG71XX_INT_TX_UR)) {
 | 
			
		||||
		ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_UR);
 | 
			
		||||
		DBG("%s: TX underrun\n", dev->name);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef AG71XX_NAPI_TX
 | 
			
		||||
	if (likely(status & AG71XX_INT_TX_PS))
 | 
			
		||||
		ag71xx_tx_packets(ag);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (likely(status & AG71XX_INT_POLL)) {
 | 
			
		||||
		ag71xx_int_disable(ag, AG71XX_INT_POLL);
 | 
			
		||||
		DBG("%s: enable polling mode\n", dev->name);
 | 
			
		||||
		netif_rx_schedule(dev, &ag->napi);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return IRQ_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_set_multicast_list(struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init ag71xx_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	static u8 default_mac[ETH_ALEN] = {0x00, 0xba, 0xdb, 0xad, 0xba, 0xd0};
 | 
			
		||||
	struct net_device *dev;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	struct ag71xx *ag;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (!pdev->dev.platform_data) {
 | 
			
		||||
		dev_err(&pdev->dev, "no platform data specified\n");
 | 
			
		||||
		err = -ENXIO;
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev = alloc_etherdev(sizeof(*ag));
 | 
			
		||||
	if (!dev) {
 | 
			
		||||
		dev_err(&pdev->dev, "alloc_etherdev failed\n");
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SET_NETDEV_DEV(dev, &pdev->dev);
 | 
			
		||||
 | 
			
		||||
	ag = netdev_priv(dev);
 | 
			
		||||
	ag->pdev = pdev;
 | 
			
		||||
	ag->dev = dev;
 | 
			
		||||
	spin_lock_init(&ag->lock);
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac_base");
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		dev_err(&pdev->dev, "no mac_base resource found\n");
 | 
			
		||||
		err = -ENXIO;
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ag->mac_base = ioremap_nocache(res->start, res->end - res->start + 1);
 | 
			
		||||
	if (!ag->mac_base) {
 | 
			
		||||
		dev_err(&pdev->dev, "unable to ioremap mac_base\n");
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err_free_dev;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mii_ctrl");
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		dev_err(&pdev->dev, "no mii_ctrl resource found\n");
 | 
			
		||||
		err = -ENXIO;
 | 
			
		||||
		goto err_unmap_base;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ag->mii_ctrl = ioremap_nocache(res->start, res->end - res->start + 1);
 | 
			
		||||
	if (!ag->mii_ctrl) {
 | 
			
		||||
		dev_err(&pdev->dev, "unable to ioremap mii_ctrl\n");
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err_unmap_base;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev->irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	err = request_irq(dev->irq, ag71xx_interrupt,
 | 
			
		||||
			  IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
 | 
			
		||||
			  dev->name, dev);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dev_err(&pdev->dev, "unable to request IRQ %d\n", dev->irq);
 | 
			
		||||
		goto err_unmap_mii_ctrl;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev->base_addr = (unsigned long)ag->mac_base;
 | 
			
		||||
	dev->open = ag71xx_open;
 | 
			
		||||
	dev->stop = ag71xx_stop;
 | 
			
		||||
	dev->hard_start_xmit = ag71xx_hard_start_xmit;
 | 
			
		||||
	dev->set_multicast_list = ag71xx_set_multicast_list;
 | 
			
		||||
	dev->do_ioctl = ag71xx_do_ioctl;
 | 
			
		||||
	dev->ethtool_ops = &ag71xx_ethtool_ops;
 | 
			
		||||
 | 
			
		||||
	netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
 | 
			
		||||
 | 
			
		||||
	memcpy(dev->dev_addr, default_mac, ETH_ALEN);
 | 
			
		||||
	dev->dev_addr[5] += pdev->id & 0xff;
 | 
			
		||||
 | 
			
		||||
	err = register_netdev(dev);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dev_err(&pdev->dev, "unable to register net device\n");
 | 
			
		||||
		goto err_free_irq;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO "%s: Atheros AG71xx at 0x%08lx, irq %d\n",
 | 
			
		||||
	       dev->name, dev->base_addr, dev->irq);
 | 
			
		||||
 | 
			
		||||
	ag71xx_dump_regs(ag);
 | 
			
		||||
 | 
			
		||||
	ag71xx_hw_init(ag);
 | 
			
		||||
 | 
			
		||||
	ag71xx_dump_regs(ag);
 | 
			
		||||
 | 
			
		||||
	err = ag71xx_mdio_init(ag, pdev->id);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err_unregister_netdev;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_unregister_netdev:
 | 
			
		||||
	unregister_netdev(dev);
 | 
			
		||||
err_free_irq:
 | 
			
		||||
	free_irq(dev->irq, dev);
 | 
			
		||||
err_unmap_mii_ctrl:
 | 
			
		||||
	iounmap(ag->mii_ctrl);
 | 
			
		||||
err_unmap_base:
 | 
			
		||||
	iounmap(ag->mac_base);
 | 
			
		||||
err_free_dev:
 | 
			
		||||
	kfree(dev);
 | 
			
		||||
err_out:
 | 
			
		||||
	platform_set_drvdata(pdev, NULL);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __exit ag71xx_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *dev = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	if (dev) {
 | 
			
		||||
		struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
 | 
			
		||||
		if (ag->phy_dev)
 | 
			
		||||
			phy_disconnect(ag->phy_dev);
 | 
			
		||||
		ag71xx_mdio_cleanup(ag);
 | 
			
		||||
		unregister_netdev(dev);
 | 
			
		||||
		free_irq(dev->irq, dev);
 | 
			
		||||
		iounmap(ag->mii_ctrl);
 | 
			
		||||
		iounmap(ag->mac_base);
 | 
			
		||||
		kfree(dev);
 | 
			
		||||
		platform_set_drvdata(pdev, NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver ag71xx_driver = {
 | 
			
		||||
	.probe		= ag71xx_probe,
 | 
			
		||||
	.remove		= __exit_p(ag71xx_remove),
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name	= AG71XX_DRV_NAME,
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init ag71xx_module_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return platform_driver_register(&ag71xx_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit ag71xx_module_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	platform_driver_unregister(&ag71xx_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module_init(ag71xx_module_init);
 | 
			
		||||
module_exit(ag71xx_module_exit);
 | 
			
		||||
 | 
			
		||||
MODULE_VERSION(AG71XX_DRV_VERSION);
 | 
			
		||||
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
 | 
			
		||||
MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
 | 
			
		||||
MODULE_LICENSE("GPL v2");
 | 
			
		||||
MODULE_ALIAS("platform:" AG71XX_DRV_NAME);
 | 
			
		||||
							
								
								
									
										436
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mii.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mii.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,436 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx built-in ethernet mac driver
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Based on Atheros' AG7100 driver
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 "ag71xx.h"
 | 
			
		||||
 | 
			
		||||
#define AG71XX_MII_RETRY	1000
 | 
			
		||||
#define AG71XX_MII_DELAY	5
 | 
			
		||||
 | 
			
		||||
static inline void ag71xx_mii_ctrl_wr(struct ag71xx *ag, u32 value)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(value, ag->mii_ctrl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ag71xx_mii_ctrl_rr(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(ag->mii_ctrl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ag71xx_mii_ctrl_set_if(struct ag71xx *ag, unsigned int mii_if)
 | 
			
		||||
{
 | 
			
		||||
	u32 t;
 | 
			
		||||
 | 
			
		||||
	t = ag71xx_mii_ctrl_rr(ag);
 | 
			
		||||
	t &= ~(0x3);
 | 
			
		||||
	t |= (mii_if & 0x3);
 | 
			
		||||
	ag71xx_mii_ctrl_wr(ag, t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ag71xx_mii_ctrl_set_speed(struct ag71xx *ag, unsigned int speed)
 | 
			
		||||
{
 | 
			
		||||
	u32 t;
 | 
			
		||||
 | 
			
		||||
	t = ag71xx_mii_ctrl_rr(ag);
 | 
			
		||||
	t &= ~(0x3 << 4);
 | 
			
		||||
	t |= (speed & 0x3) << 4;
 | 
			
		||||
	ag71xx_mii_ctrl_wr(ag, t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_mii_read(struct ag71xx *ag, int addr, int reg)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MII_ADDR,
 | 
			
		||||
			((addr & 0xff) << MII_ADDR_S) | (reg & 0xff));
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_READ);
 | 
			
		||||
 | 
			
		||||
	i = AG71XX_MII_RETRY;
 | 
			
		||||
	while (ag71xx_rr(ag, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
 | 
			
		||||
		if (i-- == 0) {
 | 
			
		||||
			printk(KERN_ERR "%s: mii_read timed out\n",
 | 
			
		||||
				ag->dev->name);
 | 
			
		||||
			ret = 0xffff;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		udelay(AG71XX_MII_DELAY);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = ag71xx_rr(ag, AG71XX_REG_MII_STATUS) & 0xffff;
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
 | 
			
		||||
 | 
			
		||||
	DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_mii_write(struct ag71xx *ag, int addr, int reg, u16 val)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MII_ADDR,
 | 
			
		||||
			((addr & 0xff) << MII_ADDR_S) | (reg & 0xff));
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MII_CTRL, val);
 | 
			
		||||
 | 
			
		||||
	i = AG71XX_MII_RETRY;
 | 
			
		||||
	while (ag71xx_rr(ag, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
 | 
			
		||||
		if (i-- == 0) {
 | 
			
		||||
			printk(KERN_ERR "%s: mii_write timed out\n",
 | 
			
		||||
				ag->dev->name);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		udelay(AG71XX_MII_DELAY);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ag71xx_mii_peek(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	int cnt;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	cnt = 0;
 | 
			
		||||
	for (i = 0; i < PHY_MAX_ADDR; i++) {
 | 
			
		||||
		u16 bmsr, id1, id2, bmcr, advert, lpa;
 | 
			
		||||
 | 
			
		||||
		bmsr = ag71xx_mii_read(ag, i, MII_BMSR);
 | 
			
		||||
		bmcr = ag71xx_mii_read(ag, i, MII_BMCR);
 | 
			
		||||
		id1 = ag71xx_mii_read(ag, i, MII_PHYSID1);
 | 
			
		||||
		id2 = ag71xx_mii_read(ag, i, MII_PHYSID2);
 | 
			
		||||
		advert = ag71xx_mii_read(ag, i, MII_ADVERTISE);
 | 
			
		||||
		lpa = ag71xx_mii_read(ag, i, MII_LPA);
 | 
			
		||||
		DBG("%s: phy%02d bmsr=%04x, bmcr=%04x, "
 | 
			
		||||
			"id=%04x.%04x, advertise=%04x, lpa=%04x\n",
 | 
			
		||||
			ag->dev->name, i,
 | 
			
		||||
			bmsr, bmcr, id1, id2, advert, lpa);
 | 
			
		||||
 | 
			
		||||
		if ((bmsr | bmcr | id1 | id2 | advert | lpa) != 0)
 | 
			
		||||
			cnt++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cnt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define PLL_SEC_CONFIG		0x18050004
 | 
			
		||||
#define PLL_ETH0_INT_CLOCK	0x18050010
 | 
			
		||||
#define PLL_ETH1_INT_CLOCK	0x18050014
 | 
			
		||||
#define PLL_ETH_EXT_CLOCK	0x18050018
 | 
			
		||||
 | 
			
		||||
#define ag7100_pll_shift(_ag)   (((_ag)->pdev->id) ? 19 : 17)
 | 
			
		||||
#define ag7100_pll_offset(_ag)	(((_ag)->pdev->id) ? PLL_ETH1_INT_CLOCK \
 | 
			
		||||
						   : PLL_ETH0_INT_CLOCK)
 | 
			
		||||
 | 
			
		||||
static void ag71xx_set_pll(struct ag71xx *ag, u32 pll_val)
 | 
			
		||||
{
 | 
			
		||||
	void __iomem *pll_reg = ioremap_nocache(ag7100_pll_offset(ag), 4);
 | 
			
		||||
	void __iomem *pll_cfg = ioremap_nocache(PLL_SEC_CONFIG, 4);
 | 
			
		||||
	u32 s;
 | 
			
		||||
	u32 t;
 | 
			
		||||
 | 
			
		||||
	s = ag7100_pll_shift(ag);
 | 
			
		||||
 | 
			
		||||
	t = __raw_readl(pll_cfg);
 | 
			
		||||
	t &= ~(3 << s);
 | 
			
		||||
	t |=  (2 << s);
 | 
			
		||||
	__raw_writel(t, pll_cfg);
 | 
			
		||||
	udelay(100);
 | 
			
		||||
 | 
			
		||||
	__raw_writel(pll_val, pll_reg);
 | 
			
		||||
 | 
			
		||||
	t |= (3 << s);
 | 
			
		||||
	__raw_writel(t, pll_cfg);
 | 
			
		||||
	udelay(100);
 | 
			
		||||
 | 
			
		||||
	t &= ~(3 << s);
 | 
			
		||||
	__raw_writel(t, pll_cfg);
 | 
			
		||||
	udelay(100);
 | 
			
		||||
	DBG("%s: pll_reg %#x: %#x\n", ag->dev->name,
 | 
			
		||||
			(unsigned int)pll_reg, __raw_readl(pll_reg));
 | 
			
		||||
 | 
			
		||||
	iounmap(pll_cfg);
 | 
			
		||||
	iounmap(pll_reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned char *ag71xx_speed_str(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	switch (ag->speed) {
 | 
			
		||||
	case SPEED_1000:
 | 
			
		||||
		return "1000";
 | 
			
		||||
	case SPEED_100:
 | 
			
		||||
		return "100";
 | 
			
		||||
	case SPEED_10:
 | 
			
		||||
		return "10";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "?";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 1
 | 
			
		||||
#define PLL_VAL_1000	0x00110000
 | 
			
		||||
#define PLL_VAL_100	0x00001099
 | 
			
		||||
#define PLL_VAL_10	0x00991099
 | 
			
		||||
#else
 | 
			
		||||
#define PLL_VAL_1000	0x01111000
 | 
			
		||||
#define PLL_VAL_100	0x09991000
 | 
			
		||||
#define PLL_VAL_10	0x09991999
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void ag71xx_link_update(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	u32 cfg2;
 | 
			
		||||
	u32 ifctl;
 | 
			
		||||
	u32 pll;
 | 
			
		||||
	u32 fifo5;
 | 
			
		||||
	u32 mii_speed;
 | 
			
		||||
 | 
			
		||||
	if (!ag->link) {
 | 
			
		||||
		netif_carrier_off(ag->dev);
 | 
			
		||||
		printk(KERN_INFO "%s: link down\n", ag->dev->name);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
 | 
			
		||||
	cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
 | 
			
		||||
	cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0;
 | 
			
		||||
 | 
			
		||||
	ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
 | 
			
		||||
	ifctl &= ~(MAC_IFCTL_SPEED);
 | 
			
		||||
 | 
			
		||||
	fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
 | 
			
		||||
	fifo5 &= ~FIFO_CFG5_BYTE_PER_CLK;
 | 
			
		||||
 | 
			
		||||
	switch (ag->speed) {
 | 
			
		||||
	case SPEED_1000:
 | 
			
		||||
		mii_speed =  MII_CTRL_SPEED_1000;
 | 
			
		||||
		cfg2 |= MAC_CFG2_IF_1000;
 | 
			
		||||
		pll = PLL_VAL_1000;
 | 
			
		||||
		fifo5 |= FIFO_CFG5_BYTE_PER_CLK;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPEED_100:
 | 
			
		||||
		mii_speed = MII_CTRL_SPEED_100;
 | 
			
		||||
		cfg2 |= MAC_CFG2_IF_10_100;
 | 
			
		||||
		ifctl |= MAC_IFCTL_SPEED;
 | 
			
		||||
		pll = PLL_VAL_100;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPEED_10:
 | 
			
		||||
		mii_speed = MII_CTRL_SPEED_10;
 | 
			
		||||
		cfg2 |= MAC_CFG2_IF_10_100;
 | 
			
		||||
		pll = PLL_VAL_10;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		BUG();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff);
 | 
			
		||||
	ag71xx_set_pll(ag, pll);
 | 
			
		||||
	ag71xx_mii_ctrl_set_speed(ag, mii_speed);
 | 
			
		||||
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
 | 
			
		||||
	ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
 | 
			
		||||
 | 
			
		||||
	netif_carrier_on(ag->dev);
 | 
			
		||||
	printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_speed_str(ag),
 | 
			
		||||
		(DUPLEX_FULL == ag->duplex) ? "Full" : "Half");
 | 
			
		||||
 | 
			
		||||
	DBG("%s: fifo1=%#x, fifo2=%#x, fifo3=%#x, fifo4=%#x, fifo5=%#x\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
 | 
			
		||||
 | 
			
		||||
	DBG("%s: mac_cfg2=%#x, ifctl=%#x, mii_ctrl=%#x\n",
 | 
			
		||||
		ag->dev->name,
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
 | 
			
		||||
		ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
 | 
			
		||||
		ag71xx_mii_ctrl_rr(ag));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ag71xx_link_adjust(struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = netdev_priv(dev);
 | 
			
		||||
	struct phy_device *phydev = ag->phy_dev;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int status_change = 0;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ag->lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (phydev->link) {
 | 
			
		||||
		if (ag->duplex != phydev->duplex
 | 
			
		||||
		    || ag->speed != phydev->speed) {
 | 
			
		||||
			status_change = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (phydev->link != ag->link) {
 | 
			
		||||
		if (phydev->link)
 | 
			
		||||
			netif_schedule(dev);
 | 
			
		||||
 | 
			
		||||
		status_change = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ag->link = phydev->link;
 | 
			
		||||
	ag->duplex = phydev->duplex;
 | 
			
		||||
	ag->speed = phydev->speed;
 | 
			
		||||
 | 
			
		||||
	if (status_change)
 | 
			
		||||
		ag71xx_link_update(ag);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&ag->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_mdio_read(struct mii_bus *bus, int addr, int reg)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = bus->priv;
 | 
			
		||||
 | 
			
		||||
	return ag71xx_mii_read(ag, addr, reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
 | 
			
		||||
{
 | 
			
		||||
	struct ag71xx *ag = bus->priv;
 | 
			
		||||
 | 
			
		||||
	ag71xx_mii_write(ag, addr, reg, val);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_mdio_reset(struct mii_bus *bus)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ag71xx_mdio_probe(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *dev = ag->dev;
 | 
			
		||||
	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
 | 
			
		||||
	struct phy_device *phydev = NULL;
 | 
			
		||||
	int phy_count = 0;
 | 
			
		||||
	int phy_addr;
 | 
			
		||||
 | 
			
		||||
	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
 | 
			
		||||
		if (!(pdata->phy_mask & (1 << phy_addr)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (ag->mii_bus.phy_map[phy_addr] == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		DBG("%s: PHY found at %s, uid=%08x\n",
 | 
			
		||||
			dev->name,
 | 
			
		||||
			ag->mii_bus.phy_map[phy_addr]->dev.bus_id,
 | 
			
		||||
			ag->mii_bus.phy_map[phy_addr]->phy_id);
 | 
			
		||||
 | 
			
		||||
		if (phydev == NULL)
 | 
			
		||||
			phydev = ag->mii_bus.phy_map[phy_addr];
 | 
			
		||||
 | 
			
		||||
		phy_count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (phy_count) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		printk(KERN_ERR "%s: no PHY found\n", dev->name);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	case 1:
 | 
			
		||||
		ag->phy_dev = phy_connect(dev, phydev->dev.bus_id,
 | 
			
		||||
			&ag71xx_link_adjust, 0, pdata->phy_if_mode);
 | 
			
		||||
 | 
			
		||||
		if (IS_ERR(ag->phy_dev)) {
 | 
			
		||||
			printk(KERN_ERR "%s: could not connect to PHY at %s\n",
 | 
			
		||||
				dev->name, phydev->dev.bus_id);
 | 
			
		||||
			return PTR_ERR(ag->phy_dev);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* mask with MAC supported features */
 | 
			
		||||
		phydev->supported &= (SUPPORTED_10baseT_Half
 | 
			
		||||
			| SUPPORTED_10baseT_Full
 | 
			
		||||
			| SUPPORTED_100baseT_Half
 | 
			
		||||
			| SUPPORTED_100baseT_Full
 | 
			
		||||
			| SUPPORTED_Autoneg
 | 
			
		||||
			| SUPPORTED_MII
 | 
			
		||||
			| SUPPORTED_TP);
 | 
			
		||||
 | 
			
		||||
		phydev->advertising = phydev->supported;
 | 
			
		||||
 | 
			
		||||
		printk(KERN_DEBUG "%s: connected to PHY at %s "
 | 
			
		||||
			"[uid=%08x, driver=%s]\n",
 | 
			
		||||
			dev->name, phydev->dev.bus_id,
 | 
			
		||||
			phydev->phy_id, phydev->drv->name);
 | 
			
		||||
 | 
			
		||||
		ag->link = 0;
 | 
			
		||||
		ag->speed = 0;
 | 
			
		||||
		ag->duplex = -1;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		ag->phy_dev = NULL;
 | 
			
		||||
		printk(KERN_DEBUG "%s: connected to multiple PHYs (%d)\n",
 | 
			
		||||
			dev->name, phy_count);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ag71xx_mdio_init(struct ag71xx *ag, int id)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	ag->mii_bus.name = "ag71xx_mii";
 | 
			
		||||
	ag->mii_bus.read = ag71xx_mdio_read;
 | 
			
		||||
	ag->mii_bus.write = ag71xx_mdio_write;
 | 
			
		||||
	ag->mii_bus.reset = ag71xx_mdio_reset;
 | 
			
		||||
	ag->mii_bus.id = id;
 | 
			
		||||
	ag->mii_bus.priv = ag;
 | 
			
		||||
	ag->mii_bus.dev = &ag->dev->dev;
 | 
			
		||||
 | 
			
		||||
	ag->mii_bus.irq = kmalloc(sizeof(*ag->mii_bus.irq) * PHY_MAX_ADDR,
 | 
			
		||||
				  GFP_KERNEL);
 | 
			
		||||
	if (!ag->mii_bus.irq) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < PHY_MAX_ADDR; i++)
 | 
			
		||||
		ag->mii_bus.irq[i] = PHY_POLL;
 | 
			
		||||
 | 
			
		||||
	err = mdiobus_register(&ag->mii_bus);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err_free_irqs;
 | 
			
		||||
 | 
			
		||||
	err = ag71xx_mdio_probe(ag);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err_unregister_bus;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_unregister_bus:
 | 
			
		||||
	mdiobus_unregister(&ag->mii_bus);
 | 
			
		||||
err_free_irqs:
 | 
			
		||||
	kfree(ag->mii_bus.irq);
 | 
			
		||||
err_out:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ag71xx_mdio_cleanup(struct ag71xx *ag)
 | 
			
		||||
{
 | 
			
		||||
	mdiobus_unregister(&ag->mii_bus);
 | 
			
		||||
	kfree(ag->mii_bus.irq);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								target/linux/ar71xx/files/drivers/net/phy/micrel.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								target/linux/ar71xx/files/drivers/net/phy/micrel.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Driver for Micrel/Kendin PHYs
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (c) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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/delay.h>
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/phy.h>
 | 
			
		||||
 | 
			
		||||
#define KSZ_REG_INT_CTRL	0x1b
 | 
			
		||||
 | 
			
		||||
#define KSZ_INT_LU_EN	(1 << 8)	/* enable Link Up interrupt */
 | 
			
		||||
#define KSZ_INT_RF_EN	(1 << 9)	/* enable Remote Fault interrupt */
 | 
			
		||||
#define KSZ_INT_LD_EN	(1 << 10)	/* enable Link Down interrupt */
 | 
			
		||||
 | 
			
		||||
#define KSZ_INT_INIT	(KSZ_INT_LU_EN | KSZ_INT_LD_EN)
 | 
			
		||||
 | 
			
		||||
static int ksz8041_ack_interrupt(struct phy_device *phydev)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = phy_read(phydev, KSZ_REG_INT_CTRL);
 | 
			
		||||
 | 
			
		||||
	return (err < 0) ? err : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ksz8041_config_intr(struct phy_device *phydev)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 | 
			
		||||
		err = phy_write(phydev, KSZ_REG_INT_CTRL,
 | 
			
		||||
				KSZ_INT_INIT);
 | 
			
		||||
	else
 | 
			
		||||
		err = phy_write(phydev, KSZ_REG_INT_CTRL, 0);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct phy_driver ksz8041_phy_driver = {
 | 
			
		||||
	.phy_id		= 0x00221512,
 | 
			
		||||
	.name		= "Micrel/Kendin KSZ8041",
 | 
			
		||||
	.phy_id_mask	= 0x001fffff,
 | 
			
		||||
	.features	= PHY_BASIC_FEATURES,
 | 
			
		||||
	.flags		= PHY_HAS_INTERRUPT,
 | 
			
		||||
	.config_aneg	= genphy_config_aneg,
 | 
			
		||||
	.read_status	= genphy_read_status,
 | 
			
		||||
	.ack_interrupt	= ksz8041_ack_interrupt,
 | 
			
		||||
	.config_intr	= ksz8041_config_intr,
 | 
			
		||||
	.driver	= {
 | 
			
		||||
		.owner	= THIS_MODULE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init micrel_phy_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = phy_driver_register(&ksz8041_phy_driver);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit micrel_phy_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	phy_driver_unregister(&ksz8041_phy_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module_init(micrel_phy_init);
 | 
			
		||||
module_exit(micrel_phy_exit);
 | 
			
		||||
 | 
			
		||||
MODULE_DESCRIPTION("Micrel/Kendin PHY driver");
 | 
			
		||||
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
 | 
			
		||||
MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
 | 
			
		||||
MODULE_LICENSE("GPL v2");
 | 
			
		||||
							
								
								
									
										240
									
								
								target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,240 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Atheros AR71xx SPI Controller driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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/init.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
#include <linux/workqueue.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/spi/spi.h>
 | 
			
		||||
#include <linux/spi/spi_bitbang.h>
 | 
			
		||||
#include <linux/bitops.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
#include <asm/mach-ar71xx/platform.h>
 | 
			
		||||
 | 
			
		||||
#define DRV_DESC	"Atheros AR71xx SPI Controller driver"
 | 
			
		||||
#define DRV_VERSION	"0.2.2"
 | 
			
		||||
#define DRV_NAME	"ar71xx-spi"
 | 
			
		||||
 | 
			
		||||
#undef PER_BIT_READ
 | 
			
		||||
 | 
			
		||||
struct ar71xx_spi {
 | 
			
		||||
	struct	spi_bitbang 	bitbang;
 | 
			
		||||
	u32			ioc_base;
 | 
			
		||||
	u32			reg_ctrl;
 | 
			
		||||
 | 
			
		||||
	void __iomem 		*base;
 | 
			
		||||
 | 
			
		||||
	struct platform_device	*pdev;
 | 
			
		||||
	u32			(*get_ioc_base)(u8 chip_select, int cs_high,
 | 
			
		||||
						int is_on);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_spi_rr(struct ar71xx_spi *sp, unsigned reg)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(sp->base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ar71xx_spi_wr(struct ar71xx_spi *sp, unsigned reg, u32 val)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(val, sp->base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct ar71xx_spi *spidev_to_sp(struct spi_device *spi)
 | 
			
		||||
{
 | 
			
		||||
	return spi_master_get_devdata(spi->master);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u32 ar71xx_spi_get_ioc_base(u8 chip_select, int cs_high, int is_on)
 | 
			
		||||
{
 | 
			
		||||
	u32 ret;
 | 
			
		||||
 | 
			
		||||
	if (is_on == AR71XX_SPI_CS_INACTIVE)
 | 
			
		||||
		ret = SPI_IOC_CS_ALL;
 | 
			
		||||
	else
 | 
			
		||||
		ret = SPI_IOC_CS_ALL & ~SPI_IOC_CS(chip_select);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_spi_chipselect(struct spi_device *spi, int value)
 | 
			
		||||
{
 | 
			
		||||
	struct ar71xx_spi *sp = spidev_to_sp(spi);
 | 
			
		||||
	void __iomem *base = sp->base;
 | 
			
		||||
	u32 ioc_base;
 | 
			
		||||
 | 
			
		||||
	switch (value) {
 | 
			
		||||
	case BITBANG_CS_INACTIVE:
 | 
			
		||||
		ioc_base = sp->get_ioc_base(spi->chip_select,
 | 
			
		||||
					(spi->mode & SPI_CS_HIGH) != 0,
 | 
			
		||||
					AR71XX_SPI_CS_INACTIVE);
 | 
			
		||||
 | 
			
		||||
		__raw_writel(ioc_base, base + SPI_REG_IOC);
 | 
			
		||||
		__raw_writel(sp->reg_ctrl, base + SPI_REG_CTRL);
 | 
			
		||||
		__raw_writel(0, base + SPI_REG_FS);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case BITBANG_CS_ACTIVE:
 | 
			
		||||
		ioc_base = sp->get_ioc_base(spi->chip_select,
 | 
			
		||||
					(spi->mode & SPI_CS_HIGH) != 0,
 | 
			
		||||
					AR71XX_SPI_CS_ACTIVE);
 | 
			
		||||
 | 
			
		||||
		__raw_writel(SPI_FS_GPIO, base + SPI_REG_FS);
 | 
			
		||||
		/* TODO: setup speed */
 | 
			
		||||
		__raw_writel(0x43, base + SPI_REG_CTRL);
 | 
			
		||||
		__raw_writel(ioc_base, base + SPI_REG_IOC);
 | 
			
		||||
		sp->ioc_base = ioc_base;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u32 ar71xx_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
 | 
			
		||||
					u32 word, u8 bits)
 | 
			
		||||
{
 | 
			
		||||
	struct ar71xx_spi *sp = spidev_to_sp(spi);
 | 
			
		||||
	void __iomem *base = sp->base;
 | 
			
		||||
	u32 ioc = sp->ioc_base;
 | 
			
		||||
	u32 ret;
 | 
			
		||||
 | 
			
		||||
	/* clock starts at inactive polarity */
 | 
			
		||||
	for (word <<= (32 - bits); likely(bits); bits--) {
 | 
			
		||||
		u32 out;
 | 
			
		||||
 | 
			
		||||
		if (word & (1 << 31))
 | 
			
		||||
			out = ioc | SPI_IOC_DO;
 | 
			
		||||
		else
 | 
			
		||||
			out = ioc & ~SPI_IOC_DO;
 | 
			
		||||
 | 
			
		||||
		/* setup MSB (to slave) on trailing edge */
 | 
			
		||||
		__raw_writel(out, base + SPI_REG_IOC);
 | 
			
		||||
 | 
			
		||||
		__raw_writel(out | SPI_IOC_CLK, base + SPI_REG_IOC);
 | 
			
		||||
 | 
			
		||||
		word <<= 1;
 | 
			
		||||
 | 
			
		||||
#ifdef PER_BIT_READ
 | 
			
		||||
		/* sample MSB (from slave) on leading edge */
 | 
			
		||||
		ret = __raw_readl(base + SPI_REG_RDS);
 | 
			
		||||
		__raw_writel(out, base + SPI_REG_IOC);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifndef PER_BIT_READ
 | 
			
		||||
	ret = __raw_readl(base + SPI_REG_RDS);
 | 
			
		||||
#endif
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ar71xx_spi_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct spi_master *master;
 | 
			
		||||
	struct ar71xx_spi *sp;
 | 
			
		||||
	struct ar71xx_spi_platform_data *pdata;
 | 
			
		||||
	struct resource	*r;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	master = spi_alloc_master(&pdev->dev, sizeof(*sp));
 | 
			
		||||
	if (master == NULL) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to allocate spi master\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sp = spi_master_get_devdata(master);
 | 
			
		||||
	platform_set_drvdata(pdev, sp);
 | 
			
		||||
 | 
			
		||||
	pdata = pdev->dev.platform_data;
 | 
			
		||||
 | 
			
		||||
	sp->bitbang.master = spi_master_get(master);
 | 
			
		||||
	sp->bitbang.chipselect = ar71xx_spi_chipselect;
 | 
			
		||||
	sp->bitbang.txrx_word[SPI_MODE_0] = ar71xx_spi_txrx_mode0;
 | 
			
		||||
 | 
			
		||||
	sp->get_ioc_base = ar71xx_spi_get_ioc_base;
 | 
			
		||||
	if (pdata) {
 | 
			
		||||
		sp->bitbang.master->bus_num = pdata->bus_num;
 | 
			
		||||
		sp->bitbang.master->num_chipselect = pdata->num_chipselect;
 | 
			
		||||
		if (pdata->get_ioc_base)
 | 
			
		||||
			sp->get_ioc_base = pdata->get_ioc_base;
 | 
			
		||||
	} else {
 | 
			
		||||
		sp->bitbang.master->bus_num = 0;
 | 
			
		||||
		sp->bitbang.master->num_chipselect = 3;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
			
		||||
	if (r == NULL) {
 | 
			
		||||
		ret = -ENOENT;
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sp->base = ioremap_nocache(r->start, r->end - r->start + 1);
 | 
			
		||||
	if (!sp->base) {
 | 
			
		||||
		ret = -ENXIO;
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sp->reg_ctrl = ar71xx_spi_rr(sp, SPI_REG_IOC);
 | 
			
		||||
 | 
			
		||||
	ret = spi_bitbang_start(&sp->bitbang);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	iounmap(sp->base);
 | 
			
		||||
err1:
 | 
			
		||||
	platform_set_drvdata(pdev, NULL);
 | 
			
		||||
	spi_master_put(sp->bitbang.master);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ar71xx_spi_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct ar71xx_spi *sp = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	spi_bitbang_stop(&sp->bitbang);
 | 
			
		||||
	iounmap(sp->base);
 | 
			
		||||
	platform_set_drvdata(pdev, NULL);
 | 
			
		||||
	spi_master_put(sp->bitbang.master);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver ar71xx_spi_drv = {
 | 
			
		||||
	.probe		= ar71xx_spi_probe,
 | 
			
		||||
	.remove		= ar71xx_spi_remove,
 | 
			
		||||
	.driver		= {
 | 
			
		||||
		.name	= DRV_NAME,
 | 
			
		||||
		.owner	= THIS_MODULE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init ar71xx_spi_init(void)
 | 
			
		||||
{
 | 
			
		||||
	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
 | 
			
		||||
	return platform_driver_register(&ar71xx_spi_drv);
 | 
			
		||||
}
 | 
			
		||||
module_init(ar71xx_spi_init);
 | 
			
		||||
 | 
			
		||||
static void __exit ar71xx_spi_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	platform_driver_unregister(&ar71xx_spi_drv);
 | 
			
		||||
}
 | 
			
		||||
module_exit(ar71xx_spi_exit);
 | 
			
		||||
 | 
			
		||||
MODULE_ALIAS("platform:" DRV_NAME);
 | 
			
		||||
MODULE_DESCRIPTION(DRV_DESC);
 | 
			
		||||
MODULE_VERSION(DRV_VERSION);
 | 
			
		||||
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
 | 
			
		||||
MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
 | 
			
		||||
MODULE_LICENSE("GPL v2");
 | 
			
		||||
							
								
								
									
										193
									
								
								target/linux/ar71xx/files/drivers/usb/host/ehci-ar71xx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								target/linux/ar71xx/files/drivers/usb/host/ehci-ar71xx.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,193 @@
 | 
			
		||||
/*
 | 
			
		||||
 * EHCI HCD (Host Controller Driver) for USB.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2007 Atheros Communications, Inc.
 | 
			
		||||
 * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 * Bus Glue for Atheros AR71xx built-in EHCI controller
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
 | 
			
		||||
extern int usb_disabled(void);
 | 
			
		||||
 | 
			
		||||
static void ar71xx_start_ehci(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_stop_ehci(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * TODO: implement
 | 
			
		||||
	 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int usb_ehci_ar71xx_probe(const struct hc_driver *driver,
 | 
			
		||||
			  struct usb_hcd **hcd_out,
 | 
			
		||||
			  struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_hcd *hcd;
 | 
			
		||||
	struct ehci_hcd *ehci;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	int irq;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
 | 
			
		||||
			pdev->dev.bus_id);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
	irq = res->start;
 | 
			
		||||
 | 
			
		||||
	hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
 | 
			
		||||
	if (!hcd)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "no base address specified for %s\n",
 | 
			
		||||
			pdev->dev.bus_id);
 | 
			
		||||
		ret = -ENODEV;
 | 
			
		||||
		goto err_put_hcd;
 | 
			
		||||
	}
 | 
			
		||||
	hcd->rsrc_start	= res->start;
 | 
			
		||||
	hcd->rsrc_len	= res->end - res->start + 1;
 | 
			
		||||
 | 
			
		||||
	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "controller already in use\n");
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto err_put_hcd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 | 
			
		||||
	if (!hcd->regs) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "error mapping memory\n");
 | 
			
		||||
		ret = -EFAULT;
 | 
			
		||||
		goto err_release_region;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ar71xx_start_ehci(pdev);
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
	ehci		= hcd_to_ehci(hcd);
 | 
			
		||||
	ehci->caps	= hcd->regs;
 | 
			
		||||
	ehci->regs	= hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
 | 
			
		||||
	ehci->hcs_params = readl(&ehci->caps->hcs_params);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto err_stop_ehc;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_stop_ehc:
 | 
			
		||||
	ar71xx_stop_ehci(pdev);
 | 
			
		||||
	iounmap(hcd->regs);
 | 
			
		||||
 | 
			
		||||
err_release_region:
 | 
			
		||||
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 | 
			
		||||
err_put_hcd:
 | 
			
		||||
	usb_put_hcd(hcd);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* may be called without controller electrically present */
 | 
			
		||||
/* may be called with controller, bus, and devices active */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * usb_ehci_ar71xx_remove - shutdown processing for AR71xx-based HCDs
 | 
			
		||||
 * @dev: USB Host Controller being removed
 | 
			
		||||
 * Context: !in_interrupt()
 | 
			
		||||
 *
 | 
			
		||||
 * Reverses the effect of usb_hcd_ar71xx_probe(), first invoking
 | 
			
		||||
 * the HCD's stop() method.  It is always called from a thread
 | 
			
		||||
 * context, normally "rmmod", "apmd", or something similar.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void usb_ehci_ar71xx_remove(struct usb_hcd *hcd,
 | 
			
		||||
				   struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	usb_remove_hcd(hcd);
 | 
			
		||||
	ar71xx_stop_ehci(pdev);
 | 
			
		||||
	iounmap(hcd->regs);
 | 
			
		||||
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 | 
			
		||||
	usb_put_hcd(hcd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct hc_driver ehci_ar71xx_hc_driver = {
 | 
			
		||||
	.description	= hcd_name,
 | 
			
		||||
	.product_desc	= "Atheros AR71xx built-in EHCI controller",
 | 
			
		||||
	.hcd_priv_size	= sizeof(struct ehci_hcd),
 | 
			
		||||
	/*
 | 
			
		||||
	 * generic hardware linkage
 | 
			
		||||
	 */
 | 
			
		||||
	.irq		= ehci_irq,
 | 
			
		||||
	.flags		= HCD_MEMORY | HCD_USB2,
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * basic lifecycle operations
 | 
			
		||||
	 */
 | 
			
		||||
	.reset		= ehci_init,
 | 
			
		||||
	.start		= ehci_run,
 | 
			
		||||
	.stop		= ehci_stop,
 | 
			
		||||
	.shutdown	= ehci_shutdown,
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * managing i/o requests and associated device resources
 | 
			
		||||
	 */
 | 
			
		||||
	.urb_enqueue		= ehci_urb_enqueue,
 | 
			
		||||
	.urb_dequeue		= ehci_urb_dequeue,
 | 
			
		||||
	.endpoint_disable	= ehci_endpoint_disable,
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * scheduling support
 | 
			
		||||
	 */
 | 
			
		||||
	.get_frame_number = ehci_get_frame,
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * root hub support
 | 
			
		||||
	 */
 | 
			
		||||
	.hub_status_data	= ehci_hub_status_data,
 | 
			
		||||
	.hub_control		= ehci_hub_control,
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
	.hub_suspend		= ehci_hub_suspend,
 | 
			
		||||
	.hub_resume		= ehci_hub_resume,
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int ehci_hcd_ar71xx_drv_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_hcd *hcd = NULL;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = -ENODEV;
 | 
			
		||||
	if (!usb_disabled())
 | 
			
		||||
		ret = usb_ehci_ar71xx_probe(&ehci_ar71xx_hc_driver, &hcd, pdev);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ehci_hcd_ar71xx_drv_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	usb_ehci_ar71xx_remove(hcd, pdev);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver ehci_hcd_ar71xx_driver = {
 | 
			
		||||
	.probe		= ehci_hcd_ar71xx_drv_probe,
 | 
			
		||||
	.remove		= ehci_hcd_ar71xx_drv_remove,
 | 
			
		||||
	.shutdown	= usb_hcd_platform_shutdown,
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name	= "ar71xx-ehci",
 | 
			
		||||
		.bus	= &platform_bus_type
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MODULE_ALIAS("ar71xx-ehci");
 | 
			
		||||
							
								
								
									
										200
									
								
								target/linux/ar71xx/files/drivers/usb/host/ohci-ar71xx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								target/linux/ar71xx/files/drivers/usb/host/ohci-ar71xx.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,200 @@
 | 
			
		||||
/*
 | 
			
		||||
 * OHCI HCD (Host Controller Driver) for USB.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2007 Atheros Communications, Inc.
 | 
			
		||||
 * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 * Bus Glue for Atheros AR71xx built-in OHCI controller
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
 | 
			
		||||
extern int usb_disabled(void);
 | 
			
		||||
 | 
			
		||||
static void ar71xx_start_ohci(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ar71xx_stop_ohci(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * TODO: implement
 | 
			
		||||
	 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int usb_hcd_ar71xx_probe(const struct hc_driver *driver,
 | 
			
		||||
			 struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_hcd *hcd;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	int irq;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
 | 
			
		||||
			pdev->dev.bus_id);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
	irq = res->start;
 | 
			
		||||
 | 
			
		||||
	hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
 | 
			
		||||
	if (!hcd)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "no base address specified for %s\n",
 | 
			
		||||
			pdev->dev.bus_id);
 | 
			
		||||
		ret = -ENODEV;
 | 
			
		||||
		goto err_put_hcd;
 | 
			
		||||
	}
 | 
			
		||||
	hcd->rsrc_start	= res->start;
 | 
			
		||||
	hcd->rsrc_len	= res->end - res->start + 1;
 | 
			
		||||
 | 
			
		||||
	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "controller already in use\n");
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto err_put_hcd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 | 
			
		||||
	if (!hcd->regs) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "error mapping memory\n");
 | 
			
		||||
		ret = -EFAULT;
 | 
			
		||||
		goto err_release_region;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ar71xx_start_ohci(pdev);
 | 
			
		||||
	ohci_hcd_init(hcd_to_ohci(hcd));
 | 
			
		||||
 | 
			
		||||
	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto err_stop_hcd;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_stop_hcd:
 | 
			
		||||
	ar71xx_stop_ohci(pdev);
 | 
			
		||||
	iounmap(hcd->regs);
 | 
			
		||||
err_release_region:
 | 
			
		||||
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 | 
			
		||||
err_put_hcd:
 | 
			
		||||
	usb_put_hcd(hcd);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* may be called without controller electrically present */
 | 
			
		||||
/* may be called with controller, bus, and devices active */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * usb_hcd_ar71xx_remove - shutdown processing for AR71xx HCDs
 | 
			
		||||
 * @dev: USB Host Controller being removed
 | 
			
		||||
 * Context: !in_interrupt()
 | 
			
		||||
 *
 | 
			
		||||
 * Reverses the effect of usb_hcd_ar71xx_probe(), first invoking
 | 
			
		||||
 * the HCD's stop() method.  It is always called from a thread
 | 
			
		||||
 * context, normally "rmmod", "apmd", or something similar.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void usb_hcd_ar71xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	usb_remove_hcd(hcd);
 | 
			
		||||
	ar71xx_stop_ohci(pdev);
 | 
			
		||||
	iounmap(hcd->regs);
 | 
			
		||||
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 | 
			
		||||
	usb_put_hcd(hcd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __devinit ohci_ar71xx_start(struct usb_hcd *hcd)
 | 
			
		||||
{
 | 
			
		||||
	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = ohci_init(ohci);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = ohci_run(ohci);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		goto err;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	ohci_stop(hcd);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct hc_driver ohci_ar71xx_hc_driver = {
 | 
			
		||||
	.description	= hcd_name,
 | 
			
		||||
	.product_desc	= "Atheros AR71xx built-in OHCI controller",
 | 
			
		||||
	.hcd_priv_size	= sizeof(struct ohci_hcd),
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * generic hardware linkage
 | 
			
		||||
	 */
 | 
			
		||||
	.irq		= ohci_irq,
 | 
			
		||||
	.flags		= HCD_USB11 | HCD_MEMORY,
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * basic lifecycle operations
 | 
			
		||||
	 */
 | 
			
		||||
	.start		= ohci_ar71xx_start,
 | 
			
		||||
	.stop		= ohci_stop,
 | 
			
		||||
	.shutdown	= ohci_shutdown,
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * managing i/o requests and associated device resources
 | 
			
		||||
	 */
 | 
			
		||||
	.urb_enqueue		= ohci_urb_enqueue,
 | 
			
		||||
	.urb_dequeue		= ohci_urb_dequeue,
 | 
			
		||||
	.endpoint_disable	= ohci_endpoint_disable,
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * scheduling support
 | 
			
		||||
	 */
 | 
			
		||||
	.get_frame_number	= ohci_get_frame,
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * root hub support
 | 
			
		||||
	 */
 | 
			
		||||
	.hub_status_data	= ohci_hub_status_data,
 | 
			
		||||
	.hub_control		= ohci_hub_control,
 | 
			
		||||
	.start_port_reset	= ohci_start_port_reset,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int ohci_hcd_ar71xx_drv_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = -ENODEV;
 | 
			
		||||
	if (!usb_disabled())
 | 
			
		||||
		ret = usb_hcd_ar71xx_probe(&ohci_ar71xx_hc_driver, pdev);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ohci_hcd_ar71xx_drv_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	usb_hcd_ar71xx_remove(hcd, pdev);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver ohci_hcd_ar71xx_driver = {
 | 
			
		||||
	.probe		= ohci_hcd_ar71xx_drv_probe,
 | 
			
		||||
	.remove		= ohci_hcd_ar71xx_drv_remove,
 | 
			
		||||
	.shutdown	= usb_hcd_platform_shutdown,
 | 
			
		||||
	.driver		= {
 | 
			
		||||
		.name	= "ar71xx-ohci",
 | 
			
		||||
		.owner	= THIS_MODULE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MODULE_ALIAS("ar71xx-ohci");
 | 
			
		||||
							
								
								
									
										375
									
								
								target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/ar71xx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/ar71xx.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,375 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx SoC specific definitions
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  Parts of this file are based on Atheros' 2.6.15 BSP
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 __ASM_MACH_AR71XX_H
 | 
			
		||||
#define __ASM_MACH_AR71XX_H
 | 
			
		||||
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/bitops.h>
 | 
			
		||||
 | 
			
		||||
#ifndef __ASSEMBLER__
 | 
			
		||||
 | 
			
		||||
#define AR71XX_PCI_MEM_BASE	0x10000000
 | 
			
		||||
#define AR71XX_PCI_MEM_SIZE	0x08000000
 | 
			
		||||
#define AR71XX_APB_BASE		0x18000000
 | 
			
		||||
#define AR71XX_GE0_BASE		0x19000000
 | 
			
		||||
#define AR71XX_GE0_SIZE		0x01000000
 | 
			
		||||
#define AR71XX_GE1_BASE		0x1a000000
 | 
			
		||||
#define AR71XX_GE1_SIZE		0x01000000
 | 
			
		||||
#define AR71XX_EHCI_BASE	0x1b000000
 | 
			
		||||
#define AR71XX_EHCI_SIZE	0x01000000
 | 
			
		||||
#define AR71XX_OHCI_BASE	0x1c000000
 | 
			
		||||
#define AR71XX_OHCI_SIZE	0x01000000
 | 
			
		||||
#define AR71XX_SPI_BASE		0x1f000000
 | 
			
		||||
#define AR71XX_SPI_SIZE		0x01000000
 | 
			
		||||
 | 
			
		||||
#define AR71XX_DDR_CTRL_BASE	(AR71XX_APB_BASE + 0x00000000)
 | 
			
		||||
#define AR71XX_DDR_CTRL_SIZE	0x10000
 | 
			
		||||
#define AR71XX_CPU_BASE		(AR71XX_APB_BASE + 0x00010000)
 | 
			
		||||
#define AR71XX_UART_BASE	(AR71XX_APB_BASE + 0x00020000)
 | 
			
		||||
#define AR71XX_UART_SIZE	0x10000
 | 
			
		||||
#define AR71XX_USB_CTRL_BASE	(AR71XX_APB_BASE + 0x00030000)
 | 
			
		||||
#define AR71XX_USB_CTRL_SIZE	0x10000
 | 
			
		||||
#define AR71XX_GPIO_BASE	(AR71XX_APB_BASE + 0x00040000)
 | 
			
		||||
#define AR71XX_GPIO_SIZE	0x10000
 | 
			
		||||
#define AR71XX_PLL_BASE		(AR71XX_APB_BASE + 0x00050000)
 | 
			
		||||
#define AR71XX_PLL_SIZE		0x10000
 | 
			
		||||
#define AR71XX_RESET_BASE	(AR71XX_APB_BASE + 0x00060000)
 | 
			
		||||
#define AR71XX_RESET_SIZE	0x10000
 | 
			
		||||
#define AR71XX_MII_BASE		(AR71XX_APB_BASE + 0x00070000)
 | 
			
		||||
#define AR71XX_MII_SIZE		0x10000
 | 
			
		||||
#define AR71XX_SLIC_BASE	(AR71XX_APB_BASE + 0x00090000)
 | 
			
		||||
#define AR71XX_SLIC_SIZE	0x10000
 | 
			
		||||
#define AR71XX_DMA_BASE		(AR71XX_APB_BASE + 0x000A0000)
 | 
			
		||||
#define AR71XX_DMA_SIZE		0x10000
 | 
			
		||||
#define AR71XX_STEREO_BASE	(AR71XX_APB_BASE + 0x000B0000)
 | 
			
		||||
#define AR71XX_STEREO_SIZE	0x10000
 | 
			
		||||
 | 
			
		||||
#define AR71XX_CPU_IRQ_BASE	0
 | 
			
		||||
#define AR71XX_MISC_IRQ_BASE	8
 | 
			
		||||
#define AR71XX_MISC_IRQ_COUNT	8
 | 
			
		||||
#define AR71XX_GPIO_IRQ_BASE	16
 | 
			
		||||
#define AR71XX_GPIO_IRQ_COUNT	16
 | 
			
		||||
#define AR71XX_PCI_IRQ_BASE     32
 | 
			
		||||
#define AR71XX_PCI_IRQ_COUNT	4
 | 
			
		||||
 | 
			
		||||
#define AR71XX_CPU_IRQ_PCI	(AR71XX_CPU_IRQ_BASE + 2)
 | 
			
		||||
#define AR71XX_CPU_IRQ_USB	(AR71XX_CPU_IRQ_BASE + 3)
 | 
			
		||||
#define AR71XX_CPU_IRQ_GE0	(AR71XX_CPU_IRQ_BASE + 4)
 | 
			
		||||
#define AR71XX_CPU_IRQ_GE1	(AR71XX_CPU_IRQ_BASE + 5)
 | 
			
		||||
#define AR71XX_CPU_IRQ_MISC	(AR71XX_CPU_IRQ_BASE + 6)
 | 
			
		||||
#define AR71XX_CPU_IRQ_TIMER	(AR71XX_CPU_IRQ_BASE + 7)
 | 
			
		||||
 | 
			
		||||
#define AR71XX_MISC_IRQ_TIMER	(AR71XX_MISC_IRQ_BASE + 0)
 | 
			
		||||
#define AR71XX_MISC_IRQ_ERROR	(AR71XX_MISC_IRQ_BASE + 1)
 | 
			
		||||
#define AR71XX_MISC_IRQ_GPIO	(AR71XX_MISC_IRQ_BASE + 2)
 | 
			
		||||
#define AR71XX_MISC_IRQ_UART	(AR71XX_MISC_IRQ_BASE + 3)
 | 
			
		||||
#define AR71XX_MISC_IRQ_WDOG	(AR71XX_MISC_IRQ_BASE + 4)
 | 
			
		||||
#define AR71XX_MISC_IRQ_PERFC	(AR71XX_MISC_IRQ_BASE + 5)
 | 
			
		||||
#define AR71XX_MISC_IRQ_OHCI	(AR71XX_MISC_IRQ_BASE + 6)
 | 
			
		||||
#define AR71XX_MISC_IRQ_DMA	(AR71XX_MISC_IRQ_BASE + 7)
 | 
			
		||||
 | 
			
		||||
#define AR71XX_GPIO_IRQ(_x)	(AR71XX_GPIO_IRQ_BASE + (_x))
 | 
			
		||||
 | 
			
		||||
#define AR71XX_PCI_IRQ_DEV0	(AR71XX_PCI_IRQ_BASE + 0)
 | 
			
		||||
#define AR71XX_PCI_IRQ_DEV1	(AR71XX_PCI_IRQ_BASE + 1)
 | 
			
		||||
#define AR71XX_PCI_IRQ_DEV2	(AR71XX_PCI_IRQ_BASE + 2)
 | 
			
		||||
#define AR71XX_PCI_IRQ_CORE	(AR71XX_PCI_IRQ_BASE + 3)
 | 
			
		||||
 | 
			
		||||
extern u32 ar71xx_ahb_freq;
 | 
			
		||||
extern u32 ar71xx_cpu_freq;
 | 
			
		||||
extern u32 ar71xx_ddr_freq;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * PLL block
 | 
			
		||||
 */
 | 
			
		||||
#define PLL_REG_CPU_PLL_CFG	0x00
 | 
			
		||||
#define PLL_REG_SEC_PLL_CFG	0x04
 | 
			
		||||
#define PLL_REG_CPU_CLK_CTRL	0x08
 | 
			
		||||
#define PLL_REG_ETH_INT0_CLK	0x10
 | 
			
		||||
#define PLL_REG_ETH_INT1_CLK	0x14
 | 
			
		||||
#define PLL_REG_ETH_EXT_CLK	0x18
 | 
			
		||||
#define PLL_REG_PCI_CLK		0x1c
 | 
			
		||||
 | 
			
		||||
#define PLL_DIV_SHIFT		3
 | 
			
		||||
#define PLL_DIV_MASK		0x1f
 | 
			
		||||
#define CPU_DIV_SHIFT		16
 | 
			
		||||
#define CPU_DIV_MASK		0x3
 | 
			
		||||
#define DDR_DIV_SHIFT		18
 | 
			
		||||
#define DDR_DIV_MASK		0x3
 | 
			
		||||
#define AHB_DIV_SHIFT		20
 | 
			
		||||
#define AHB_DIV_MASK		0x7
 | 
			
		||||
 | 
			
		||||
extern void __iomem *ar71xx_pll_base;
 | 
			
		||||
 | 
			
		||||
static inline void ar71xx_pll_wr(unsigned reg, u32 val)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(val, ar71xx_pll_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_pll_rr(unsigned reg)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(ar71xx_pll_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * USB_CONFIG block
 | 
			
		||||
 */
 | 
			
		||||
#define USB_CTRL_REG_FLADJ	0x00
 | 
			
		||||
#define USB_CTRL_REG_CONFIG	0x04
 | 
			
		||||
 | 
			
		||||
extern void __iomem *ar71xx_usb_ctrl_base;
 | 
			
		||||
 | 
			
		||||
static inline void ar71xx_usb_ctrl_wr(unsigned reg, u32 val)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(val, ar71xx_usb_ctrl_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_usb_ctrl_rr(unsigned reg)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(ar71xx_usb_ctrl_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern void ar71xx_add_device_usb(void) __init;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * GPIO block
 | 
			
		||||
 */
 | 
			
		||||
#define GPIO_REG_OE		0x00
 | 
			
		||||
#define GPIO_REG_IN		0x04
 | 
			
		||||
#define GPIO_REG_OUT		0x08
 | 
			
		||||
#define GPIO_REG_SET		0x0c
 | 
			
		||||
#define GPIO_REG_CLEAR		0x10
 | 
			
		||||
#define GPIO_REG_INT_MODE	0x14
 | 
			
		||||
#define GPIO_REG_INT_TYPE	0x18
 | 
			
		||||
#define GPIO_REG_INT_POLARITY	0x1c
 | 
			
		||||
#define GPIO_REG_INT_PENDING	0x20
 | 
			
		||||
#define GPIO_REG_INT_ENABLE	0x24
 | 
			
		||||
#define GPIO_REG_FUNC		0x28
 | 
			
		||||
 | 
			
		||||
#define GPIO_FUNC_STEREO_EN	BIT(17)
 | 
			
		||||
#define GPIO_FUNC_SLIC_EN	BIT(16)
 | 
			
		||||
#define GPIO_FUNC_SPI_CS1_EN	BIT(15)
 | 
			
		||||
#define GPIO_FUNC_SPI_CS0_EN	BIT(14)
 | 
			
		||||
#define GPIO_FUNC_SPI_EN	BIT(13)
 | 
			
		||||
#define GPIO_FUNC_UART_EN	BIT(8)
 | 
			
		||||
#define GPIO_FUNC_USB_OC_EN	BIT(4)
 | 
			
		||||
#define GPIO_FUNC_USB_CLK_EN	BIT(0)
 | 
			
		||||
 | 
			
		||||
#define AR71XX_GPIO_COUNT	16
 | 
			
		||||
 | 
			
		||||
extern void __iomem *ar71xx_gpio_base;
 | 
			
		||||
 | 
			
		||||
static inline void ar71xx_gpio_wr(unsigned reg, u32 value)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(value, ar71xx_gpio_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_gpio_rr(unsigned reg)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(ar71xx_gpio_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern void ar71xx_gpio_init(void) __init;
 | 
			
		||||
extern void ar71xx_gpio_function_enable(u32 mask);
 | 
			
		||||
extern void ar71xx_gpio_function_disable(u32 mask);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DDR_CTRL block
 | 
			
		||||
 */
 | 
			
		||||
#define DDR_REG_PCI_WIN0	0x7c
 | 
			
		||||
#define DDR_REG_PCI_WIN1	0x80
 | 
			
		||||
#define DDR_REG_PCI_WIN2	0x84
 | 
			
		||||
#define DDR_REG_PCI_WIN3	0x88
 | 
			
		||||
#define DDR_REG_PCI_WIN4	0x8c
 | 
			
		||||
#define DDR_REG_PCI_WIN5	0x90
 | 
			
		||||
#define DDR_REG_PCI_WIN6	0x94
 | 
			
		||||
#define DDR_REG_PCI_WIN7	0x98
 | 
			
		||||
#define DDR_REG_FLUSH_GE0	0x9c
 | 
			
		||||
#define DDR_REG_FLUSH_GE1	0xa0
 | 
			
		||||
#define DDR_REG_FLUSH_USB	0xa4
 | 
			
		||||
#define DDR_REG_FLUSH_PCI	0xa8
 | 
			
		||||
 | 
			
		||||
#define PCI_WIN0_OFFS	0x10000000
 | 
			
		||||
#define PCI_WIN1_OFFS	0x11000000
 | 
			
		||||
#define PCI_WIN2_OFFS	0x12000000
 | 
			
		||||
#define PCI_WIN3_OFFS	0x13000000
 | 
			
		||||
#define PCI_WIN4_OFFS	0x14000000
 | 
			
		||||
#define PCI_WIN5_OFFS	0x15000000
 | 
			
		||||
#define PCI_WIN6_OFFS	0x16000000
 | 
			
		||||
#define PCI_WIN7_OFFS	0x07000000
 | 
			
		||||
 | 
			
		||||
extern void __iomem *ar71xx_ddr_base;
 | 
			
		||||
 | 
			
		||||
static inline void ar71xx_ddr_wr(unsigned reg, u32 val)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(val, ar71xx_ddr_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_ddr_rr(unsigned reg)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(ar71xx_ddr_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern void ar71xx_ddr_flush(u32 reg);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * PCI block
 | 
			
		||||
 */
 | 
			
		||||
#define AR71XX_PCI_CFG_BASE	(AR71XX_PCI_MEM_BASE + PCI_WIN7_OFFS + 0x10000)
 | 
			
		||||
#define AR71XX_PCI_CFG_SIZE	0x100
 | 
			
		||||
 | 
			
		||||
#define PCI_REG_CRP_AD_CBE	0x00
 | 
			
		||||
#define PCI_REG_CRP_WRDATA	0x04
 | 
			
		||||
#define PCI_REG_CRP_RDDATA	0x08
 | 
			
		||||
#define PCI_REG_CFG_AD		0x0c
 | 
			
		||||
#define PCI_REG_CFG_CBE		0x10
 | 
			
		||||
#define PCI_REG_CFG_WRDATA	0x14
 | 
			
		||||
#define PCI_REG_CFG_RDDATA	0x18
 | 
			
		||||
#define PCI_REG_PCI_ERR		0x1c
 | 
			
		||||
#define PCI_REG_PCI_ERR_ADDR	0x20
 | 
			
		||||
#define PCI_REG_AHB_ERR		0x24
 | 
			
		||||
#define PCI_REG_AHB_ERR_ADDR	0x28
 | 
			
		||||
 | 
			
		||||
#define PCI_CRP_CMD_WRITE	0x00010000
 | 
			
		||||
#define PCI_CRP_CMD_READ	0x00000000
 | 
			
		||||
#define PCI_CFG_CMD_READ	0x0000000a
 | 
			
		||||
#define PCI_CFG_CMD_WRITE	0x0000000b
 | 
			
		||||
 | 
			
		||||
#define PCI_IDSEL_ADL_START	17
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * RESET block
 | 
			
		||||
 */
 | 
			
		||||
#define RESET_REG_TIMER			0x00
 | 
			
		||||
#define RESET_REG_TIMER_RELOAD		0x04
 | 
			
		||||
#define RESET_REG_WDOG_CTRL		0x08
 | 
			
		||||
#define RESET_REG_WDOG			0x0c
 | 
			
		||||
#define RESET_REG_MISC_INT_STATUS	0x10
 | 
			
		||||
#define RESET_REG_MISC_INT_ENABLE	0x14
 | 
			
		||||
#define RESET_REG_PCI_INT_STATUS	0x18
 | 
			
		||||
#define RESET_REG_PCI_INT_ENABLE	0x1c
 | 
			
		||||
#define RESET_REG_GLOBAL_INT_STATUS	0x20
 | 
			
		||||
#define RESET_REG_RESET_MODULE		0x24
 | 
			
		||||
#define RESET_REG_PERFC_CTRL		0x2c
 | 
			
		||||
#define RESET_REG_PERFC0		0x30
 | 
			
		||||
#define RESET_REG_PERFC1		0x34
 | 
			
		||||
#define RESET_REG_REV_ID		0x90
 | 
			
		||||
 | 
			
		||||
#define MISC_INT_DMA			BIT(7)
 | 
			
		||||
#define MISC_INT_OHCI			BIT(6)
 | 
			
		||||
#define MISC_INT_PERFC			BIT(5)
 | 
			
		||||
#define MISC_INT_WDOG			BIT(4)
 | 
			
		||||
#define MISC_INT_UART			BIT(3)
 | 
			
		||||
#define MISC_INT_GPIO			BIT(2)
 | 
			
		||||
#define MISC_INT_ERROR			BIT(1)
 | 
			
		||||
#define MISC_INT_TIMER			BIT(0)
 | 
			
		||||
 | 
			
		||||
#define PCI_INT_CORE			BIT(4)
 | 
			
		||||
#define PCI_INT_DEV2			BIT(2)
 | 
			
		||||
#define PCI_INT_DEV1			BIT(1)
 | 
			
		||||
#define PCI_INT_DEV0			BIT(0)
 | 
			
		||||
 | 
			
		||||
#define RESET_MODULE_EXTERNAL		BIT(28)
 | 
			
		||||
#define RESET_MODULE_FULL_CHIP		BIT(24)
 | 
			
		||||
#define RESET_MODULE_CPU_NMI		BIT(21)
 | 
			
		||||
#define RESET_MODULE_CPU_COLD		BIT(20)
 | 
			
		||||
#define RESET_MODULE_DMA		BIT(19)
 | 
			
		||||
#define RESET_MODULE_SLIC		BIT(18)
 | 
			
		||||
#define RESET_MODULE_STEREO		BIT(17)
 | 
			
		||||
#define RESET_MODULE_DDR		BIT(16)
 | 
			
		||||
#define RESET_MODULE_GE1_MAC		BIT(13)
 | 
			
		||||
#define RESET_MODULE_GE1_PHY		BIT(12)
 | 
			
		||||
#define RESET_MODULE_USBSUS_OVERRIDE	BIT(10)
 | 
			
		||||
#define RESET_MODULE_GE0_MAC		BIT(9)
 | 
			
		||||
#define RESET_MODULE_GE0_PHY		BIT(8)
 | 
			
		||||
#define RESET_MODULE_USB_OHCI_DLL	BIT(6)
 | 
			
		||||
#define RESET_MODULE_USB_HOST		BIT(5)
 | 
			
		||||
#define RESET_MODULE_USB_PHY		BIT(4)
 | 
			
		||||
#define RESET_MODULE_PCI_BUS		BIT(1)
 | 
			
		||||
#define RESET_MODULE_PCI_CORE		BIT(0)
 | 
			
		||||
 | 
			
		||||
#define REV_ID_MASK		0xff
 | 
			
		||||
#define REV_ID_CHIP_MASK	0xf3
 | 
			
		||||
#define REV_ID_CHIP_AR7130	0xa0
 | 
			
		||||
#define REV_ID_CHIP_AR7141	0xa1
 | 
			
		||||
#define REV_ID_CHIP_AR7161	0xa2
 | 
			
		||||
 | 
			
		||||
#define REV_ID_REVISION_MASK	0x3
 | 
			
		||||
#define REV_ID_REVISION_SHIFT	2
 | 
			
		||||
 | 
			
		||||
extern void __iomem *ar71xx_reset_base;
 | 
			
		||||
 | 
			
		||||
static inline void ar71xx_reset_wr(unsigned reg, u32 val)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writel(val, ar71xx_reset_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ar71xx_reset_rr(unsigned reg)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readl(ar71xx_reset_base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern void ar71xx_device_stop(u32 mask);
 | 
			
		||||
extern void ar71xx_device_start(u32 mask);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SPI block
 | 
			
		||||
 */
 | 
			
		||||
#define SPI_REG_FS		0x00	/* Function Select */
 | 
			
		||||
#define SPI_REG_CTRL		0x04	/* SPI Control */
 | 
			
		||||
#define SPI_REG_IOC		0x08	/* SPI I/O Control */
 | 
			
		||||
#define SPI_REG_RDS		0x0c	/* Read Data Shift */
 | 
			
		||||
 | 
			
		||||
#define SPI_FS_GPIO		BIT(0)	/* Enable GPIO mode */
 | 
			
		||||
 | 
			
		||||
#define SPI_CTRL_RD		BIT(6)	/* Remap Disable */
 | 
			
		||||
#define SPI_CTRL_DIV_MASK	0x3f
 | 
			
		||||
 | 
			
		||||
#define SPI_IOC_DO		BIT(0)	/* Data Out pin */
 | 
			
		||||
#define SPI_IOC_CLK		BIT(8)	/* CLK pin */
 | 
			
		||||
#define SPI_IOC_CS(n)		BIT(16 + (n))
 | 
			
		||||
#define SPI_IOC_CS0		SPI_IOC_CS(0)
 | 
			
		||||
#define SPI_IOC_CS1		SPI_IOC_CS(1)
 | 
			
		||||
#define SPI_IOC_CS2		SPI_IOC_CS(2)
 | 
			
		||||
#define SPI_IOC_CS_ALL		(SPI_IOC_CS0 | SPI_IOC_CS1 | SPI_IOC_CS2)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * MII_CTRL block
 | 
			
		||||
 */
 | 
			
		||||
#define MII_REG_MII0_CTRL	0x00
 | 
			
		||||
#define MII_REG_MII1_CTRL	0x04
 | 
			
		||||
 | 
			
		||||
#define MII0_CTRL_IF_GMII	0
 | 
			
		||||
#define MII0_CTRL_IF_MII	1
 | 
			
		||||
#define MII0_CTRL_IF_RGMII	2
 | 
			
		||||
#define MII0_CTRL_IF_RMII	3
 | 
			
		||||
 | 
			
		||||
#define MII1_CTRL_IF_RGMII	0
 | 
			
		||||
#define MII1_CTRL_IF_RMII	1
 | 
			
		||||
 | 
			
		||||
#include <asm/bootinfo.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
 | 
			
		||||
#define ar71xx_print_cmdline() do {					\
 | 
			
		||||
		printk(KERN_DEBUG "%s:%d arcs_cmdline:'%s'\n",		\
 | 
			
		||||
			__FUNCTION__, __LINE__, arcs_cmdline);		\
 | 
			
		||||
		printk(KERN_DEBUG "%s:%d boot_command_line:'%s'\n",	\
 | 
			
		||||
			__FUNCTION__, __LINE__,	boot_command_line);	\
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
#endif /* __ASSEMBLER__ */
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_MACH_AR71XX_H */
 | 
			
		||||
@ -0,0 +1,56 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx specific CPU feature overrides
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This file was derived from: include/asm-mips/cpu-features.h
 | 
			
		||||
 *	Copyright (C) 2003, 2004 Ralf Baechle
 | 
			
		||||
 *	Copyright (C) 2004 Maciej W. Rozycki
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H
 | 
			
		||||
#define __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H
 | 
			
		||||
 | 
			
		||||
#define cpu_has_tlb		1
 | 
			
		||||
#define cpu_has_4kex		1
 | 
			
		||||
#define cpu_has_3k_cache	0
 | 
			
		||||
#define cpu_has_4k_cache	1
 | 
			
		||||
#define cpu_has_tx39_cache	0
 | 
			
		||||
#define cpu_has_sb1_cache	0
 | 
			
		||||
#define cpu_has_fpu		0
 | 
			
		||||
#define cpu_has_32fpr		0
 | 
			
		||||
#define cpu_has_counter		1
 | 
			
		||||
#define cpu_has_watch		1
 | 
			
		||||
#define cpu_has_divec		1
 | 
			
		||||
 | 
			
		||||
#define cpu_has_prefetch	1
 | 
			
		||||
#define cpu_has_ejtag		1
 | 
			
		||||
#define cpu_has_llsc		1
 | 
			
		||||
 | 
			
		||||
#define cpu_has_mips16		1
 | 
			
		||||
#define cpu_has_mdmx		0
 | 
			
		||||
#define cpu_has_mips3d		0
 | 
			
		||||
#define cpu_has_smartmips	0
 | 
			
		||||
 | 
			
		||||
#define cpu_has_mips32r1	1
 | 
			
		||||
#define cpu_has_mips32r2	1
 | 
			
		||||
#define cpu_has_mips64r1	0
 | 
			
		||||
#define cpu_has_mips64r2	0
 | 
			
		||||
 | 
			
		||||
#define cpu_has_dsp		0
 | 
			
		||||
#define cpu_has_mipsmt		0
 | 
			
		||||
 | 
			
		||||
#define cpu_has_64bits		0
 | 
			
		||||
#define cpu_has_64bit_zero_reg	0
 | 
			
		||||
#define cpu_has_64bit_gp_regs	0
 | 
			
		||||
#define cpu_has_64bit_addresses	0
 | 
			
		||||
 | 
			
		||||
#define cpu_dcache_line_size()	32
 | 
			
		||||
#define cpu_icache_line_size()	32
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H */
 | 
			
		||||
@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx GPIO API definitions
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 __ASM_MACH_AR71XX_GPIO_H
 | 
			
		||||
#define __ASM_MACH_AR71XX_GPIO_H
 | 
			
		||||
 | 
			
		||||
#define ARCH_NR_GPIOS	64
 | 
			
		||||
#include <asm-generic/gpio.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-ar71xx/ar71xx.h>
 | 
			
		||||
 | 
			
		||||
extern void __ar71xx_gpio_set_value(unsigned gpio, int value);
 | 
			
		||||
extern int __ar71xx_gpio_get_value(unsigned gpio);
 | 
			
		||||
 | 
			
		||||
static inline int gpio_to_irq(unsigned gpio)
 | 
			
		||||
{
 | 
			
		||||
	return AR71XX_GPIO_IRQ(gpio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int irq_to_gpio(unsigned irq)
 | 
			
		||||
{
 | 
			
		||||
	return irq - AR71XX_GPIO_IRQ_BASE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int gpio_get_value(unsigned gpio)
 | 
			
		||||
{
 | 
			
		||||
	if (gpio < AR71XX_GPIO_COUNT)
 | 
			
		||||
		return __ar71xx_gpio_get_value(gpio);
 | 
			
		||||
 | 
			
		||||
	return __gpio_get_value(gpio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void gpio_set_value(unsigned gpio, int value)
 | 
			
		||||
{
 | 
			
		||||
	if (gpio < AR71XX_GPIO_COUNT)
 | 
			
		||||
		__ar71xx_gpio_set_value(gpio, value);
 | 
			
		||||
	else
 | 
			
		||||
		__gpio_set_value(gpio, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define gpio_cansleep	__gpio_cansleep
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_MACH_AR71XX_GPIO_H */
 | 
			
		||||
							
								
								
									
										17
									
								
								target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/irq.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/irq.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 __ASM_MACH_AR71XX_IRQ_H
 | 
			
		||||
#define __ASM_MACH_AR71XX_IRQ_H
 | 
			
		||||
 | 
			
		||||
#define MIPS_CPU_IRQ_BASE	0
 | 
			
		||||
#define NR_IRQS			36
 | 
			
		||||
 | 
			
		||||
#include_next <irq.h>
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_MACH_AR71XX_IRQ_H */
 | 
			
		||||
@ -0,0 +1,45 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This file was derived from: inlude/asm-mips/mach-generic/mangle-port.h
 | 
			
		||||
 * 	Copyright (C) 2003, 2004 Ralf Baechle
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 __ASM_MACH_AR71XX_MANGLE_PORT_H
 | 
			
		||||
#define __ASM_MACH_AR71XX_MANGLE_PORT_H
 | 
			
		||||
 | 
			
		||||
#define __swizzle_addr_b(port)	((port) ^ 3)
 | 
			
		||||
#define __swizzle_addr_w(port)	((port) ^ 2)
 | 
			
		||||
#define __swizzle_addr_l(port)	(port)
 | 
			
		||||
#define __swizzle_addr_q(port)	(port)
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_SWAP_IO_SPACE)
 | 
			
		||||
 | 
			
		||||
# define ioswabb(a, x)           (x)
 | 
			
		||||
# define __mem_ioswabb(a, x)     (x)
 | 
			
		||||
# define ioswabw(a, x)           le16_to_cpu(x)
 | 
			
		||||
# define __mem_ioswabw(a, x)     (x)
 | 
			
		||||
# define ioswabl(a, x)           le32_to_cpu(x)
 | 
			
		||||
# define __mem_ioswabl(a, x)     (x)
 | 
			
		||||
# define ioswabq(a, x)           le64_to_cpu(x)
 | 
			
		||||
# define __mem_ioswabq(a, x)     (x)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
# define ioswabb(a, x)           (x)
 | 
			
		||||
# define __mem_ioswabb(a, x)     (x)
 | 
			
		||||
# define ioswabw(a, x)           (x)
 | 
			
		||||
# define __mem_ioswabw(a, x)     cpu_to_le16(x)
 | 
			
		||||
# define ioswabl(a, x)           (x)
 | 
			
		||||
# define __mem_ioswabl(a, x)     cpu_to_le32(x)
 | 
			
		||||
# define ioswabq(a, x)           (x)
 | 
			
		||||
# define __mem_ioswabq(a, x)     cpu_to_le64(x)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_MACH_AR71XX_MANGLE_PORT_H */
 | 
			
		||||
							
								
								
									
										28
									
								
								target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/pci.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/pci.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx SoC specific PCI definitions
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 __ASM_MACH_AR71XX_PCI_H
 | 
			
		||||
#define __ASM_MACH_AR71XX_PCI_H
 | 
			
		||||
 | 
			
		||||
struct ar71xx_pci_irq {
 | 
			
		||||
	int	irq;
 | 
			
		||||
	u8	slot;
 | 
			
		||||
	u8	pin;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern int (*ar71xx_pci_be_handler)(int is_fixup);
 | 
			
		||||
extern int (*ar71xx_pci_bios_init)(unsigned nr_irqs,
 | 
			
		||||
				    struct ar71xx_pci_irq *map) __initdata;
 | 
			
		||||
 | 
			
		||||
extern int ar71xx_pci_init(unsigned nr_irqs,
 | 
			
		||||
			   struct ar71xx_pci_irq *map) __init;
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_MACH_AR71XX_PCI_H */
 | 
			
		||||
@ -0,0 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Atheros AR71xx SoC specific platform definitions
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program 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 __ASM_MACH_AR71XX_PLATFORM_H
 | 
			
		||||
#define __ASM_MACH_AR71XX_PLATFORM_H
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/phy.h>
 | 
			
		||||
#include <linux/spi/spi.h>
 | 
			
		||||
 | 
			
		||||
struct ag71xx_platform_data {
 | 
			
		||||
	u32		reset_bit;
 | 
			
		||||
	u32		flush_reg;
 | 
			
		||||
	u32		phy_mask;
 | 
			
		||||
	phy_interface_t	phy_if_mode;
 | 
			
		||||
	u32		mii_if;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ar71xx_spi_platform_data {
 | 
			
		||||
	unsigned	bus_num;
 | 
			
		||||
	unsigned	num_chipselect;
 | 
			
		||||
	u32		(*get_ioc_base)(u8 chip_select, int cs_high, int is_on);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define AR71XX_SPI_CS_INACTIVE	0
 | 
			
		||||
#define AR71XX_SPI_CS_ACTIVE	1
 | 
			
		||||
 | 
			
		||||
extern void ar71xx_add_device_spi(struct ar71xx_spi_platform_data *pdata,
 | 
			
		||||
				struct spi_board_info const *info,
 | 
			
		||||
				unsigned n) __init;
 | 
			
		||||
extern void ar71xx_add_device_eth(unsigned int id, phy_interface_t phy_if_mode,
 | 
			
		||||
				u32 phy_mask) __init;
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_MACH_AR71XX_PLATFORM_H */
 | 
			
		||||
							
								
								
									
										25
									
								
								target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/war.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/war.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
 | 
			
		||||
 */
 | 
			
		||||
#ifndef __ASM_MACH_AR71XX_WAR_H
 | 
			
		||||
#define __ASM_MACH_AR71XX_WAR_H
 | 
			
		||||
 | 
			
		||||
#define R4600_V1_INDEX_ICACHEOP_WAR	0
 | 
			
		||||
#define R4600_V1_HIT_CACHEOP_WAR	0
 | 
			
		||||
#define R4600_V2_HIT_CACHEOP_WAR	0
 | 
			
		||||
#define R5432_CP0_INTERRUPT_WAR		0
 | 
			
		||||
#define BCM1250_M3_WAR			0
 | 
			
		||||
#define SIBYTE_1956_WAR			0
 | 
			
		||||
#define MIPS4K_ICACHE_REFILL_WAR	0
 | 
			
		||||
#define MIPS_CACHE_SYNC_WAR		0
 | 
			
		||||
#define TX49XX_ICACHE_INDEX_INV_WAR	0
 | 
			
		||||
#define RM9000_CDEX_SMP_WAR		0
 | 
			
		||||
#define ICACHE_REFILLS_WORKAROUND_WAR	0
 | 
			
		||||
#define R10000_LLSC_WAR			0
 | 
			
		||||
#define MIPS34K_MISSED_ITLB_WAR		0
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_MACH_AR71XX_WAR_H */
 | 
			
		||||
							
								
								
									
										28
									
								
								target/linux/ar71xx/image/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								target/linux/ar71xx/image/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
# 
 | 
			
		||||
# Copyright (C) 2008 OpenWrt.org
 | 
			
		||||
#
 | 
			
		||||
# This is free software, licensed under the GNU General Public License v2.
 | 
			
		||||
# See /LICENSE for more information.
 | 
			
		||||
#
 | 
			
		||||
include $(TOPDIR)/rules.mk
 | 
			
		||||
include $(INCLUDE_DIR)/image.mk
 | 
			
		||||
 | 
			
		||||
define Image/BuildKernel
 | 
			
		||||
	cp $(KDIR)/vmlinux.elf $(BIN_DIR)/openwrt-$(BOARD)-vmlinux.elf
 | 
			
		||||
	gzip -9 -c $(KDIR)/vmlinux > $(KDIR)/vmlinux.bin.gz
 | 
			
		||||
	$(STAGING_DIR_HOST)/bin/lzma e $(KDIR)/vmlinux $(KDIR)/vmlinux.bin.l7
 | 
			
		||||
	dd if=$(KDIR)/vmlinux.bin.l7 of=$(BIN_DIR)/openwrt-$(BOARD)-vmlinux.lzma bs=65536 conv=sync
 | 
			
		||||
	dd if=$(KDIR)/vmlinux.bin.gz of=$(BIN_DIR)/openwrt-$(BOARD)-vmlinux.gz bs=65536 conv=sync
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
define Image/Build/squashfs
 | 
			
		||||
    $(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
define Image/Build
 | 
			
		||||
	$(call Image/Build/$(1))
 | 
			
		||||
	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-root.$(1) bs=128k conv=sync
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
$(eval $(call BuildImage))
 | 
			
		||||
							
								
								
									
										61
									
								
								target/linux/ar71xx/patches/001-ar71xx_core.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								target/linux/ar71xx/patches/001-ar71xx_core.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
--- a/arch/mips/Makefile
 | 
			
		||||
+++ b/arch/mips/Makefile
 | 
			
		||||
@@ -593,6 +593,13 @@
 | 
			
		||||
 cflags-$(CONFIG_TOSHIBA_RBTX4938) += -Iinclude/asm-mips/mach-tx49xx
 | 
			
		||||
 load-$(CONFIG_TOSHIBA_RBTX4938) += 0xffffffff80100000
 | 
			
		||||
 
 | 
			
		||||
+#
 | 
			
		||||
+# Atheros AR71xx
 | 
			
		||||
+#
 | 
			
		||||
+core-$(CONFIG_ATHEROS_AR71XX)	+= arch/mips/ar71xx/
 | 
			
		||||
+cflags-$(CONFIG_ATHEROS_AR71XX)	+= -Iinclude/asm-mips/mach-ar71xx
 | 
			
		||||
+load-$(CONFIG_ATHEROS_AR71XX)	+= 0xffffffff80060000
 | 
			
		||||
+
 | 
			
		||||
 # temporary until string.h is fixed
 | 
			
		||||
 cflags-y += -ffreestanding
 | 
			
		||||
 
 | 
			
		||||
--- a/include/asm-mips/bootinfo.h
 | 
			
		||||
+++ b/include/asm-mips/bootinfo.h
 | 
			
		||||
@@ -79,6 +79,15 @@
 | 
			
		||||
 #define  MACH_LASAT_200		1	/* Masquerade PRO/SP200 */
 | 
			
		||||
 
 | 
			
		||||
 /*
 | 
			
		||||
+ * Valid machtype for Atheros AR71xx based boards
 | 
			
		||||
+ */
 | 
			
		||||
+#define MACH_AR71XX_GENERIC	0
 | 
			
		||||
+#define MACH_AR71XX_WP543	1	/* Compex WP543 */
 | 
			
		||||
+#define MACH_AR71XX_RB_411	2	/* MikroTik RouterBOARD 411 */
 | 
			
		||||
+#define MACH_AR71XX_RB_433	3	/* MikroTik RouterBOARD 433/433AH */
 | 
			
		||||
+#define MACH_AR71XX_RB_450	4	/* MikroTik RouterBOARD 450 */
 | 
			
		||||
+
 | 
			
		||||
+/*
 | 
			
		||||
  * Valid machtype for group NEC EMMA2RH
 | 
			
		||||
  */
 | 
			
		||||
 #define  MACH_NEC_MARKEINS	0	/* NEC EMMA2RH Mark-eins	*/
 | 
			
		||||
--- a/arch/mips/Kconfig
 | 
			
		||||
+++ b/arch/mips/Kconfig
 | 
			
		||||
@@ -21,6 +21,24 @@
 | 
			
		||||
 config MACH_ALCHEMY
 | 
			
		||||
 	bool "Alchemy processor based machines"
 | 
			
		||||
 
 | 
			
		||||
+config ATHEROS_AR71XX
 | 
			
		||||
+	bool "Atheros AR71xx based boards"
 | 
			
		||||
+	select CEVT_R4K
 | 
			
		||||
+	select CSRC_R4K
 | 
			
		||||
+	select DMA_NONCOHERENT
 | 
			
		||||
+	select HW_HAS_PCI
 | 
			
		||||
+	select IRQ_CPU
 | 
			
		||||
+	select GENERIC_GPIO
 | 
			
		||||
+	select HAVE_GPIO_LIB
 | 
			
		||||
+	select SYS_HAS_CPU_MIPS32_R1
 | 
			
		||||
+	select SYS_HAS_CPU_MIPS32_R2
 | 
			
		||||
+	select SYS_SUPPORTS_32BIT_KERNEL
 | 
			
		||||
+	select SYS_SUPPORTS_BIG_ENDIAN
 | 
			
		||||
+	select SYS_HAS_EARLY_PRINTK
 | 
			
		||||
+	select MIPS_MACHINE
 | 
			
		||||
+	help
 | 
			
		||||
+	  Support for Atheros AR71xx based boards.
 | 
			
		||||
+
 | 
			
		||||
 config BASLER_EXCITE
 | 
			
		||||
 	bool "Basler eXcite smart camera"
 | 
			
		||||
 	select CEVT_R4K
 | 
			
		||||
							
								
								
									
										10
									
								
								target/linux/ar71xx/patches/002-ar71xx_pci.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								target/linux/ar71xx/patches/002-ar71xx_pci.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
--- a/arch/mips/pci/Makefile
 | 
			
		||||
+++ b/arch/mips/pci/Makefile
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
 obj-$(CONFIG_PCI_VR41XX)	+= ops-vr41xx.o pci-vr41xx.o
 | 
			
		||||
 obj-$(CONFIG_NEC_CMBVR4133)	+= fixup-vr4133.o
 | 
			
		||||
 obj-$(CONFIG_MARKEINS)		+= ops-emma2rh.o pci-emma2rh.o fixup-emma2rh.o
 | 
			
		||||
+obj-$(CONFIG_ATHEROS_AR71XX)	+= pci-ar71xx.o
 | 
			
		||||
 
 | 
			
		||||
 #
 | 
			
		||||
 # These are still pretty much in the old state, watch, go blind.
 | 
			
		||||
							
								
								
									
										60
									
								
								target/linux/ar71xx/patches/003-ar71xx_usb_host.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								target/linux/ar71xx/patches/003-ar71xx_usb_host.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
			
		||||
--- a/drivers/usb/host/Kconfig
 | 
			
		||||
+++ b/drivers/usb/host/Kconfig
 | 
			
		||||
@@ -260,3 +260,15 @@
 | 
			
		||||
 	  To compile this driver as a module, choose M here: the
 | 
			
		||||
 	  module will be called r8a66597-hcd.
 | 
			
		||||
 
 | 
			
		||||
+config USB_OHCI_AR71XX
 | 
			
		||||
+	bool "USB OHCI support for Atheros AR71xx"
 | 
			
		||||
+	depends on ATHEROS_AR71XX && USB_OHCI_HCD
 | 
			
		||||
+	help
 | 
			
		||||
+	  Support for Atheros AR71xx built-in OHCI controller
 | 
			
		||||
+
 | 
			
		||||
+config USB_EHCI_AR71XX
 | 
			
		||||
+	bool "USB EHCI support for AR71xx"
 | 
			
		||||
+	depends on ATHEROS_AR71XX && USB_EHCI_HCD
 | 
			
		||||
+	help
 | 
			
		||||
+	  Support for Atheros AR71xx built-in EHCI controller
 | 
			
		||||
+
 | 
			
		||||
--- a/drivers/usb/host/ehci-hcd.c
 | 
			
		||||
+++ b/drivers/usb/host/ehci-hcd.c
 | 
			
		||||
@@ -1043,6 +1043,11 @@
 | 
			
		||||
 #define	PLATFORM_DRIVER		ixp4xx_ehci_driver
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+#ifdef CONFIG_USB_EHCI_AR71XX
 | 
			
		||||
+#include "ehci-ar71xx.c"
 | 
			
		||||
+#define PLATFORM_DRIVER		ehci_hcd_ar71xx_driver
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
 | 
			
		||||
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
 | 
			
		||||
 #error "missing bus glue for ehci-hcd"
 | 
			
		||||
--- a/drivers/usb/host/ohci.h
 | 
			
		||||
+++ b/drivers/usb/host/ohci.h
 | 
			
		||||
@@ -538,6 +538,11 @@
 | 
			
		||||
 #define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+#if defined(CONFIG_ATHEROS_AR71XX)
 | 
			
		||||
+#define readl_be(addr)		__raw_readl(addr)
 | 
			
		||||
+#define writel_be(val, addr)	__raw_writel(addr, val)
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
 static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
 | 
			
		||||
 					__hc32 __iomem * regs)
 | 
			
		||||
 {
 | 
			
		||||
--- a/drivers/usb/host/ohci-hcd.c
 | 
			
		||||
+++ b/drivers/usb/host/ohci-hcd.c
 | 
			
		||||
@@ -1057,6 +1057,11 @@
 | 
			
		||||
 #define PLATFORM_DRIVER		ohci_hcd_sm501_driver
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+#ifdef CONFIG_USB_OHCI_AR71XX
 | 
			
		||||
+#include "ohci-ar71xx.c"
 | 
			
		||||
+#define PLATFORM_DRIVER		ohci_hcd_ar71xx_driver
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
 #if	!defined(PCI_DRIVER) &&		\
 | 
			
		||||
 	!defined(PLATFORM_DRIVER) &&	\
 | 
			
		||||
 	!defined(OF_PLATFORM_DRIVER) &&	\
 | 
			
		||||
							
								
								
									
										26
									
								
								target/linux/ar71xx/patches/004-ar71xx_spi_controller.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								target/linux/ar71xx/patches/004-ar71xx_spi_controller.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
--- a/drivers/spi/Kconfig
 | 
			
		||||
+++ b/drivers/spi/Kconfig
 | 
			
		||||
@@ -52,6 +52,13 @@
 | 
			
		||||
 comment "SPI Master Controller Drivers"
 | 
			
		||||
 	depends on SPI_MASTER
 | 
			
		||||
 
 | 
			
		||||
+config SPI_AR71XX
 | 
			
		||||
+	tristate "Atheros AR71xx SPI Controller"
 | 
			
		||||
+	depends on SPI_MASTER && ATHEROS_AR71XX
 | 
			
		||||
+	select SPI_BITBANG
 | 
			
		||||
+	help
 | 
			
		||||
+	  This is the SPI contoller driver for Atheros AR71xx.
 | 
			
		||||
+
 | 
			
		||||
 config SPI_ATMEL
 | 
			
		||||
 	tristate "Atmel SPI Controller"
 | 
			
		||||
 	depends on (ARCH_AT91 || AVR32) && SPI_MASTER
 | 
			
		||||
--- a/drivers/spi/Makefile
 | 
			
		||||
+++ b/drivers/spi/Makefile
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
 obj-$(CONFIG_SPI_MASTER)		+= spi.o
 | 
			
		||||
 
 | 
			
		||||
 # SPI master controller drivers (bus)
 | 
			
		||||
+obj-$(CONFIG_SPI_AR71XX)		+= ar71xx_spi.o
 | 
			
		||||
 obj-$(CONFIG_SPI_ATMEL)			+= atmel_spi.o
 | 
			
		||||
 obj-$(CONFIG_SPI_BFIN)			+= spi_bfin5xx.o
 | 
			
		||||
 obj-$(CONFIG_SPI_BITBANG)		+= spi_bitbang.o
 | 
			
		||||
							
								
								
									
										21
									
								
								target/linux/ar71xx/patches/005-ar71xx_mac_driver.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								target/linux/ar71xx/patches/005-ar71xx_mac_driver.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
--- a/drivers/net/Kconfig
 | 
			
		||||
+++ b/drivers/net/Kconfig
 | 
			
		||||
@@ -2067,6 +2067,8 @@
 | 
			
		||||
 
 | 
			
		||||
 	  The safe and default value for this is N.
 | 
			
		||||
 
 | 
			
		||||
+source drivers/net/ag71xx/Kconfig
 | 
			
		||||
+
 | 
			
		||||
 config DL2K
 | 
			
		||||
 	tristate "DL2000/TC902x-based Gigabit Ethernet support"
 | 
			
		||||
 	depends on PCI
 | 
			
		||||
--- a/drivers/net/Makefile
 | 
			
		||||
+++ b/drivers/net/Makefile
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 # Makefile for the Linux network (ethercard) device drivers.
 | 
			
		||||
 #
 | 
			
		||||
 
 | 
			
		||||
+obj-$(CONFIG_AG71XX) += ag71xx/
 | 
			
		||||
 obj-$(CONFIG_E1000) += e1000/
 | 
			
		||||
 obj-$(CONFIG_E1000E) += e1000e/
 | 
			
		||||
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
 | 
			
		||||
@ -0,0 +1,13 @@
 | 
			
		||||
--- a/drivers/mtd/devices/m25p80.c
 | 
			
		||||
+++ b/drivers/mtd/devices/m25p80.c
 | 
			
		||||
@@ -441,6 +441,10 @@
 | 
			
		||||
 	{ "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, },
 | 
			
		||||
 	{ "at26df321",  0x1f4701, 64 * 1024, 64, SECT_4K, },
 | 
			
		||||
 
 | 
			
		||||
+	/* PMC -- pm25x "blocks" are 32K, sectors are 4K */
 | 
			
		||||
+	{ "pm25lv512",         0, 32 * 1024, 2, SECT_4K },
 | 
			
		||||
+	{ "pm25lv010",         0, 32 * 1024, 4, SECT_4K },
 | 
			
		||||
+
 | 
			
		||||
 	/* Spansion -- single (large) sector size only, at least
 | 
			
		||||
 	 * for the chips listed here (without boot sectors).
 | 
			
		||||
 	 */
 | 
			
		||||
							
								
								
									
										23
									
								
								target/linux/ar71xx/patches/101-ksz8041_phy_driver.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								target/linux/ar71xx/patches/101-ksz8041_phy_driver.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -76,6 +76,11 @@
 | 
			
		||||
 	---help---
 | 
			
		||||
 	  Currently supports the Marvell 88E6060 switch.
 | 
			
		||||
 
 | 
			
		||||
+config MICREL_PHY
 | 
			
		||||
+	tristate "Drivers for Micrel/Kendin PHYs"
 | 
			
		||||
+	---help---
 | 
			
		||||
+	  Currently has a driver for the KSZ8041
 | 
			
		||||
+
 | 
			
		||||
 config FIXED_PHY
 | 
			
		||||
 	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
 | 
			
		||||
 	depends on PHYLIB=y
 | 
			
		||||
--- a/drivers/net/phy/Makefile
 | 
			
		||||
+++ b/drivers/net/phy/Makefile
 | 
			
		||||
@@ -15,5 +15,6 @@
 | 
			
		||||
 obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
 | 
			
		||||
 obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
 | 
			
		||||
 obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
 | 
			
		||||
+obj-$(CONFIG_MICREL_PHY)	+= micrel.o
 | 
			
		||||
 obj-$(CONFIG_FIXED_PHY)		+= fixed.o
 | 
			
		||||
 obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
 | 
			
		||||
							
								
								
									
										54
									
								
								target/linux/ar71xx/patches/140-redboot_partition_scan.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								target/linux/ar71xx/patches/140-redboot_partition_scan.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
			
		||||
--- a/drivers/mtd/redboot.c
 | 
			
		||||
+++ b/drivers/mtd/redboot.c
 | 
			
		||||
@@ -59,31 +59,32 @@
 | 
			
		||||
 	static char nullstring[] = "unallocated";
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+	buf = vmalloc(master->erasesize);
 | 
			
		||||
+	if (!buf)
 | 
			
		||||
+		return -ENOMEM;
 | 
			
		||||
+
 | 
			
		||||
+ restart:
 | 
			
		||||
 	if ( directory < 0 ) {
 | 
			
		||||
 		offset = master->size + directory * master->erasesize;
 | 
			
		||||
-		while (master->block_isbad && 
 | 
			
		||||
+		while (master->block_isbad &&
 | 
			
		||||
 		       master->block_isbad(master, offset)) {
 | 
			
		||||
 			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;
 | 
			
		||||
 		}
 | 
			
		||||
 	} else {
 | 
			
		||||
 		offset = directory * master->erasesize;
 | 
			
		||||
-		while (master->block_isbad && 
 | 
			
		||||
+		while (master->block_isbad &&
 | 
			
		||||
 		       master->block_isbad(master, offset)) {
 | 
			
		||||
 			offset += master->erasesize;
 | 
			
		||||
 			if (offset == master->size)
 | 
			
		||||
 				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);
 | 
			
		||||
 
 | 
			
		||||
@@ -155,6 +156,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;
 | 
			
		||||
							
								
								
									
										21
									
								
								target/linux/ar71xx/patches/200-rb4xx_nand_driver.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								target/linux/ar71xx/patches/200-rb4xx_nand_driver.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
--- a/drivers/mtd/nand/Kconfig
 | 
			
		||||
+++ b/drivers/mtd/nand/Kconfig
 | 
			
		||||
@@ -330,4 +330,8 @@
 | 
			
		||||
 	  Enabling this option will enable you to use this to control
 | 
			
		||||
 	  external NAND devices.
 | 
			
		||||
 
 | 
			
		||||
+config MTD_NAND_RB4XX
 | 
			
		||||
+	tristate "NAND flash driver for RouterBoard 4xx series"
 | 
			
		||||
+	depends on MTD_NAND && ATHEROS_AR71XX
 | 
			
		||||
+
 | 
			
		||||
 endif # MTD_NAND
 | 
			
		||||
--- a/drivers/mtd/nand/Makefile
 | 
			
		||||
+++ b/drivers/mtd/nand/Makefile
 | 
			
		||||
@@ -28,6 +28,7 @@
 | 
			
		||||
 obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
 | 
			
		||||
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)	+= excite_nandflash.o
 | 
			
		||||
 obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 | 
			
		||||
+obj-$(CONFIG_MTD_NAND_RB4XX)		+= rb4xx_nand.o
 | 
			
		||||
 obj-$(CONFIG_MTD_ALAUDA)		+= alauda.o
 | 
			
		||||
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 | 
			
		||||
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
 | 
			
		||||
							
								
								
									
										143
									
								
								target/linux/ar71xx/patches/900-mips_multi_machine_support.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								target/linux/ar71xx/patches/900-mips_multi_machine_support.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,143 @@
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/include/asm-mips/mips_machine.h
 | 
			
		||||
@@ -0,0 +1,49 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
+ *
 | 
			
		||||
+ *  This program 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 __ASM_MIPS_MACHINE_H
 | 
			
		||||
+#define __ASM_MIPS_MACHINE_H
 | 
			
		||||
+
 | 
			
		||||
+#include <linux/init.h>
 | 
			
		||||
+#include <linux/list.h>
 | 
			
		||||
+
 | 
			
		||||
+#include <asm/bootinfo.h>
 | 
			
		||||
+
 | 
			
		||||
+#define MIPS_MACHINE_NAME_LEN	64
 | 
			
		||||
+
 | 
			
		||||
+struct mips_machine {
 | 
			
		||||
+	unsigned long		mach_type;
 | 
			
		||||
+	void			(*mach_setup)(void);
 | 
			
		||||
+	unsigned char		mach_name[MIPS_MACHINE_NAME_LEN];
 | 
			
		||||
+	struct list_head	list;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+void mips_machine_register(struct mips_machine *) __init;
 | 
			
		||||
+void mips_machine_setup(void) __init;
 | 
			
		||||
+
 | 
			
		||||
+extern unsigned char mips_machine_name[MIPS_MACHINE_NAME_LEN];
 | 
			
		||||
+
 | 
			
		||||
+#define MIPS_MACHINE(_type, _name, _setup) 			\
 | 
			
		||||
+static struct mips_machine machine_##_type __initdata =		\
 | 
			
		||||
+{								\
 | 
			
		||||
+	.mach_type	= _type,				\
 | 
			
		||||
+	.mach_name	= _name,				\
 | 
			
		||||
+	.mach_setup	= _setup,				\
 | 
			
		||||
+};								\
 | 
			
		||||
+								\
 | 
			
		||||
+static int __init register_machine_##_type(void)		\
 | 
			
		||||
+{								\
 | 
			
		||||
+	mips_machine_register(&machine_##_type);		\
 | 
			
		||||
+	return 0;						\
 | 
			
		||||
+}								\
 | 
			
		||||
+								\
 | 
			
		||||
+pure_initcall(register_machine_##_type)
 | 
			
		||||
+
 | 
			
		||||
+#endif /* __ASM_MIPS_MACHINE_H */
 | 
			
		||||
+
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/arch/mips/kernel/mips_machine.c
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
 | 
			
		||||
+ *
 | 
			
		||||
+ *  This program 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 <asm/mips_machine.h>
 | 
			
		||||
+#include <asm/bootinfo.h>
 | 
			
		||||
+
 | 
			
		||||
+static struct list_head mips_machines __initdata =
 | 
			
		||||
+		LIST_HEAD_INIT(mips_machines);
 | 
			
		||||
+
 | 
			
		||||
+unsigned char mips_machine_name[MIPS_MACHINE_NAME_LEN] = "Unknown";
 | 
			
		||||
+
 | 
			
		||||
+static struct mips_machine * __init mips_machine_find(unsigned long machtype)
 | 
			
		||||
+{
 | 
			
		||||
+	struct list_head *this;
 | 
			
		||||
+
 | 
			
		||||
+	list_for_each(this, &mips_machines) {
 | 
			
		||||
+		struct mips_machine *mach;
 | 
			
		||||
+
 | 
			
		||||
+		mach = list_entry(this, struct mips_machine, list);
 | 
			
		||||
+		if (mach->mach_type == machtype)
 | 
			
		||||
+			return mach;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return NULL;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+void __init mips_machine_register(struct mips_machine *mach)
 | 
			
		||||
+{
 | 
			
		||||
+	list_add_tail(&mach->list, &mips_machines);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+void __init mips_machine_setup(void)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mips_machine *mach;
 | 
			
		||||
+
 | 
			
		||||
+	mach = mips_machine_find(mips_machtype);
 | 
			
		||||
+	if (!mach) {
 | 
			
		||||
+		printk(KERN_ALERT "MIPS: no machine registered for "
 | 
			
		||||
+			"machtype %lu\n", mips_machtype);
 | 
			
		||||
+		return;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (mach->mach_name[0])
 | 
			
		||||
+		strncpy(mips_machine_name, mach->mach_name,
 | 
			
		||||
+			MIPS_MACHINE_NAME_LEN);
 | 
			
		||||
+
 | 
			
		||||
+	printk(KERN_INFO "MIPS: machine is %s\n", mips_machine_name);
 | 
			
		||||
+
 | 
			
		||||
+	if (mach->mach_setup)
 | 
			
		||||
+		mach->mach_setup();
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
--- a/arch/mips/kernel/Makefile
 | 
			
		||||
+++ b/arch/mips/kernel/Makefile
 | 
			
		||||
@@ -79,6 +79,7 @@
 | 
			
		||||
 
 | 
			
		||||
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 | 
			
		||||
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 | 
			
		||||
+obj-$(CONFIG_MIPS_MACHINE)	+= mips_machine.o
 | 
			
		||||
 
 | 
			
		||||
 CFLAGS_cpu-bugs64.o	= $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
 | 
			
		||||
 
 | 
			
		||||
--- a/arch/mips/Kconfig
 | 
			
		||||
+++ b/arch/mips/Kconfig
 | 
			
		||||
@@ -700,6 +700,7 @@
 | 
			
		||||
 
 | 
			
		||||
 endchoice
 | 
			
		||||
 
 | 
			
		||||
+source "arch/mips/ar71xx/Kconfig"
 | 
			
		||||
 source "arch/mips/au1000/Kconfig"
 | 
			
		||||
 source "arch/mips/basler/excite/Kconfig"
 | 
			
		||||
 source "arch/mips/jazz/Kconfig"
 | 
			
		||||
@@ -857,6 +858,9 @@
 | 
			
		||||
 config MIPS_DISABLE_OBSOLETE_IDE
 | 
			
		||||
 	bool
 | 
			
		||||
 
 | 
			
		||||
+config MIPS_MACHINE
 | 
			
		||||
+	def_bool n
 | 
			
		||||
+
 | 
			
		||||
 config NO_IOPORT
 | 
			
		||||
 	def_bool n
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,29 @@
 | 
			
		||||
--- a/arch/mips/kernel/traps.c
 | 
			
		||||
+++ b/arch/mips/kernel/traps.c
 | 
			
		||||
@@ -42,6 +42,7 @@
 | 
			
		||||
 #include <asm/mmu_context.h>
 | 
			
		||||
 #include <asm/types.h>
 | 
			
		||||
 #include <asm/stacktrace.h>
 | 
			
		||||
+#include <asm/time.h>
 | 
			
		||||
 
 | 
			
		||||
 extern asmlinkage void handle_int(void);
 | 
			
		||||
 extern asmlinkage void handle_tlbm(void);
 | 
			
		||||
@@ -1379,6 +1380,8 @@
 | 
			
		||||
 	 */
 | 
			
		||||
 	if (cpu_has_mips_r2) {
 | 
			
		||||
 		cp0_compare_irq = (read_c0_intctl() >> 29) & 7;
 | 
			
		||||
+		if (get_c0_compare_irq)
 | 
			
		||||
+			cp0_compare_irq = get_c0_compare_irq();
 | 
			
		||||
 		cp0_perfcount_irq = (read_c0_intctl() >> 26) & 7;
 | 
			
		||||
 		if (cp0_perfcount_irq == cp0_compare_irq)
 | 
			
		||||
 			cp0_perfcount_irq = -1;
 | 
			
		||||
--- a/include/asm-mips/time.h
 | 
			
		||||
+++ b/include/asm-mips/time.h
 | 
			
		||||
@@ -53,6 +53,7 @@
 | 
			
		||||
 #ifdef CONFIG_CEVT_R4K
 | 
			
		||||
 extern int mips_clockevent_init(void);
 | 
			
		||||
 extern unsigned int __weak get_c0_compare_int(void);
 | 
			
		||||
+extern unsigned int __weak get_c0_compare_irq(void);
 | 
			
		||||
 #else
 | 
			
		||||
 static inline int mips_clockevent_init(void)
 | 
			
		||||
 {
 | 
			
		||||
@ -0,0 +1,45 @@
 | 
			
		||||
--- a/include/asm-mips/hazards.h
 | 
			
		||||
+++ b/include/asm-mips/hazards.h
 | 
			
		||||
@@ -64,7 +64,7 @@
 | 
			
		||||
 	_ehb
 | 
			
		||||
 	)
 | 
			
		||||
 ASMMACRO(back_to_back_c0_hazard,
 | 
			
		||||
-	 _ehb
 | 
			
		||||
+	 _ssnop; _ssnop; _ssnop; _ehb
 | 
			
		||||
 	)
 | 
			
		||||
 /*
 | 
			
		||||
  * gcc has a tradition of misscompiling the previous construct using the
 | 
			
		||||
--- a/arch/mips/kernel/cevt-r4k.c
 | 
			
		||||
+++ b/arch/mips/kernel/cevt-r4k.c
 | 
			
		||||
@@ -187,7 +187,7 @@
 | 
			
		||||
 	 */
 | 
			
		||||
 	if (c0_compare_int_pending()) {
 | 
			
		||||
 		write_c0_compare(read_c0_count());
 | 
			
		||||
-		irq_disable_hazard();
 | 
			
		||||
+		back_to_back_c0_hazard();		
 | 
			
		||||
 		if (c0_compare_int_pending())
 | 
			
		||||
 			return 0;
 | 
			
		||||
 	}
 | 
			
		||||
@@ -196,7 +196,7 @@
 | 
			
		||||
 		cnt = read_c0_count();
 | 
			
		||||
 		cnt += delta;
 | 
			
		||||
 		write_c0_compare(cnt);
 | 
			
		||||
-		irq_disable_hazard();
 | 
			
		||||
+		back_to_back_c0_hazard();		
 | 
			
		||||
 		if ((int)(read_c0_count() - cnt) < 0)
 | 
			
		||||
 		    break;
 | 
			
		||||
 		/* increase delta if the timer was already expired */
 | 
			
		||||
@@ -205,11 +205,12 @@
 | 
			
		||||
 	while ((int)(read_c0_count() - cnt) <= 0)
 | 
			
		||||
 		;	/* Wait for expiry  */
 | 
			
		||||
 
 | 
			
		||||
+	back_to_back_c0_hazard();
 | 
			
		||||
 	if (!c0_compare_int_pending())
 | 
			
		||||
 		return 0;
 | 
			
		||||
 
 | 
			
		||||
 	write_c0_compare(read_c0_count());
 | 
			
		||||
-	irq_disable_hazard();
 | 
			
		||||
+	back_to_back_c0_hazard();		
 | 
			
		||||
 	if (c0_compare_int_pending())
 | 
			
		||||
 		return 0;
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,17 @@
 | 
			
		||||
diff -Nur a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
 | 
			
		||||
--- a/drivers/mtd/devices/m25p80.c	2008-07-06 14:36:59.000000000 +0200
 | 
			
		||||
+++ b/drivers/mtd/devices/m25p80.c	2008-07-06 15:17:48.000000000 +0200
 | 
			
		||||
@@ -631,12 +631,10 @@
 | 
			
		||||
 		struct mtd_partition	*parts = NULL;
 | 
			
		||||
 		int			nr_parts = 0;
 | 
			
		||||
 
 | 
			
		||||
-#ifdef CONFIG_MTD_CMDLINE_PARTS
 | 
			
		||||
-		static const char *part_probes[] = { "cmdlinepart", NULL, };
 | 
			
		||||
+		static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL, };
 | 
			
		||||
 
 | 
			
		||||
 		nr_parts = parse_mtd_partitions(&flash->mtd,
 | 
			
		||||
 				part_probes, &parts, 0);
 | 
			
		||||
-#endif
 | 
			
		||||
 
 | 
			
		||||
 		if (nr_parts <= 0 && data && data->parts) {
 | 
			
		||||
 			parts = data->parts;
 | 
			
		||||
@ -1,18 +0,0 @@
 | 
			
		||||
Backport gpio_is_valid() for gpiolib from linux-2.6.26
 | 
			
		||||
Index: linux-2.6.25.10/include/asm-generic/gpio.h
 | 
			
		||||
===================================================================
 | 
			
		||||
--- linux-2.6.25.10.orig/include/asm-generic/gpio.h	2008-07-03 05:46:47.000000000 +0200
 | 
			
		||||
+++ linux-2.6.25.10/include/asm-generic/gpio.h	2008-07-20 20:32:12.000000000 +0200
 | 
			
		||||
@@ -16,6 +16,12 @@
 | 
			
		||||
 #define ARCH_NR_GPIOS		256
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+static inline int gpio_is_valid(int number)
 | 
			
		||||
+{
 | 
			
		||||
+	/* only some non-negative numbers are valid */
 | 
			
		||||
+	return ((unsigned)number) < ARCH_NR_GPIOS;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 struct seq_file;
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
@ -0,0 +1,93 @@
 | 
			
		||||
From: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
 | 
			
		||||
Date: Mon, 28 Apr 2008 09:14:44 +0000 (-0700)
 | 
			
		||||
Subject: gpiolib: better rmmod infrastructure
 | 
			
		||||
X-Git-Tag: v2.6.26-rc1~851
 | 
			
		||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=438d8908b379b6322fc3b28d45c9ebdddf58bc20
 | 
			
		||||
 | 
			
		||||
gpiolib: better rmmod infrastructure
 | 
			
		||||
 | 
			
		||||
As long as one or more GPIOs on a gpio chip are used its driver should not be
 | 
			
		||||
unloaded.  The existing mechanism (gpiochip_remove failure) doesn't address
 | 
			
		||||
that, since rmmod can no longer be made to fail by having the cleanup code
 | 
			
		||||
report errors.  Module usecounts are the solution.
 | 
			
		||||
 | 
			
		||||
Assuming standard "initialize struct to zero" policies, this change won't
 | 
			
		||||
affect SOC platform drivers.  However, drivers for external chips (on I2C and
 | 
			
		||||
SPI busses) should be updated if they can be built as modules.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
 | 
			
		||||
[ gpio_ensure_requested() needs to update module usecounts too ]
 | 
			
		||||
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
 | 
			
		||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
 | 
			
		||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
 | 
			
		||||
index d8db2f8..eb75d12 100644
 | 
			
		||||
--- a/drivers/gpio/gpiolib.c
 | 
			
		||||
+++ b/drivers/gpio/gpiolib.c
 | 
			
		||||
@@ -68,6 +68,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc)
 | 
			
		||||
 	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
 | 
			
		||||
 		pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
 | 
			
		||||
 		desc_set_label(desc, "[auto]");
 | 
			
		||||
+		if (!try_module_get(desc->chip->owner))
 | 
			
		||||
+			pr_err("GPIO-%d: module can't be gotten \n",
 | 
			
		||||
+					(int)(desc - gpio_desc));
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -177,6 +180,9 @@ int gpio_request(unsigned gpio, const char *label)
 | 
			
		||||
 	if (desc->chip == NULL)
 | 
			
		||||
 		goto done;
 | 
			
		||||
 
 | 
			
		||||
+	if (!try_module_get(desc->chip->owner))
 | 
			
		||||
+		goto done;
 | 
			
		||||
+
 | 
			
		||||
 	/* NOTE:  gpio_request() can be called in early boot,
 | 
			
		||||
 	 * before IRQs are enabled.
 | 
			
		||||
 	 */
 | 
			
		||||
@@ -184,8 +190,10 @@ int gpio_request(unsigned gpio, const char *label)
 | 
			
		||||
 	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
 | 
			
		||||
 		desc_set_label(desc, label ? : "?");
 | 
			
		||||
 		status = 0;
 | 
			
		||||
-	} else
 | 
			
		||||
+	} else {
 | 
			
		||||
 		status = -EBUSY;
 | 
			
		||||
+		module_put(desc->chip->owner);
 | 
			
		||||
+	}
 | 
			
		||||
 
 | 
			
		||||
 done:
 | 
			
		||||
 	if (status)
 | 
			
		||||
@@ -209,9 +217,10 @@ void gpio_free(unsigned gpio)
 | 
			
		||||
 	spin_lock_irqsave(&gpio_lock, flags);
 | 
			
		||||
 
 | 
			
		||||
 	desc = &gpio_desc[gpio];
 | 
			
		||||
-	if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags))
 | 
			
		||||
+	if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
 | 
			
		||||
 		desc_set_label(desc, NULL);
 | 
			
		||||
-	else
 | 
			
		||||
+		module_put(desc->chip->owner);
 | 
			
		||||
+	} else
 | 
			
		||||
 		WARN_ON(extra_checks);
 | 
			
		||||
 
 | 
			
		||||
 	spin_unlock_irqrestore(&gpio_lock, flags);
 | 
			
		||||
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
 | 
			
		||||
index f29a502..7e77b6f 100644
 | 
			
		||||
--- a/include/asm-generic/gpio.h
 | 
			
		||||
+++ b/include/asm-generic/gpio.h
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
 struct seq_file;
 | 
			
		||||
+struct module;
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
  * struct gpio_chip - abstract a GPIO controller
 | 
			
		||||
@@ -48,6 +49,7 @@ struct seq_file;
 | 
			
		||||
  */
 | 
			
		||||
 struct gpio_chip {
 | 
			
		||||
 	char			*label;
 | 
			
		||||
+	struct module		*owner;
 | 
			
		||||
 
 | 
			
		||||
 	int			(*direction_input)(struct gpio_chip *chip,
 | 
			
		||||
 						unsigned offset);
 | 
			
		||||
@ -0,0 +1,136 @@
 | 
			
		||||
From: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
 | 
			
		||||
Date: Mon, 28 Apr 2008 09:14:46 +0000 (-0700)
 | 
			
		||||
Subject: gpio: define gpio_is_valid()
 | 
			
		||||
X-Git-Tag: v2.6.26-rc1~849
 | 
			
		||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=e6de1808f8ebfeb7e49f3c5a30cb8f2032beb287
 | 
			
		||||
 | 
			
		||||
gpio: define gpio_is_valid()
 | 
			
		||||
 | 
			
		||||
Introduce a gpio_is_valid() predicate; use it in gpiolib.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
 | 
			
		||||
    [ use inline function; follow the gpio_* naming convention;
 | 
			
		||||
      work without gpiolib; all programming interfaces need docs ]
 | 
			
		||||
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
 | 
			
		||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
 | 
			
		||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
 | 
			
		||||
index 5463009..c35ca9e 100644
 | 
			
		||||
--- a/Documentation/gpio.txt
 | 
			
		||||
+++ b/Documentation/gpio.txt
 | 
			
		||||
@@ -107,6 +107,16 @@ type of GPIO controller, and on one particular board 80-95 with an FPGA.
 | 
			
		||||
 The numbers need not be contiguous; either of those platforms could also
 | 
			
		||||
 use numbers 2000-2063 to identify GPIOs in a bank of I2C GPIO expanders.
 | 
			
		||||
 
 | 
			
		||||
+If you want to initialize a structure with an invalid GPIO number, use
 | 
			
		||||
+some negative number (perhaps "-EINVAL"); that will never be valid.  To
 | 
			
		||||
+test if a number could reference a GPIO, you may use this predicate:
 | 
			
		||||
+
 | 
			
		||||
+	int gpio_is_valid(int number);
 | 
			
		||||
+
 | 
			
		||||
+A number that's not valid will be rejected by calls which may request
 | 
			
		||||
+or free GPIOs (see below).  Other numbers may also be rejected; for
 | 
			
		||||
+example, a number might be valid but unused on a given board.
 | 
			
		||||
+
 | 
			
		||||
 Whether a platform supports multiple GPIO controllers is currently a
 | 
			
		||||
 platform-specific implementation issue.
 | 
			
		||||
 
 | 
			
		||||
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
 | 
			
		||||
index eb75d12..623fcd9 100644
 | 
			
		||||
--- a/drivers/gpio/gpiolib.c
 | 
			
		||||
+++ b/drivers/gpio/gpiolib.c
 | 
			
		||||
@@ -99,7 +99,7 @@ int gpiochip_add(struct gpio_chip *chip)
 | 
			
		||||
 	 * dynamic allocation.  We don't currently support that.
 | 
			
		||||
 	 */
 | 
			
		||||
 
 | 
			
		||||
-	if (chip->base < 0 || (chip->base  + chip->ngpio) >= ARCH_NR_GPIOS) {
 | 
			
		||||
+	if (chip->base < 0 || !gpio_is_valid(chip->base  + chip->ngpio)) {
 | 
			
		||||
 		status = -EINVAL;
 | 
			
		||||
 		goto fail;
 | 
			
		||||
 	}
 | 
			
		||||
@@ -174,7 +174,7 @@ int gpio_request(unsigned gpio, const char *label)
 | 
			
		||||
 
 | 
			
		||||
 	spin_lock_irqsave(&gpio_lock, flags);
 | 
			
		||||
 
 | 
			
		||||
-	if (gpio >= ARCH_NR_GPIOS)
 | 
			
		||||
+	if (!gpio_is_valid(gpio))
 | 
			
		||||
 		goto done;
 | 
			
		||||
 	desc = &gpio_desc[gpio];
 | 
			
		||||
 	if (desc->chip == NULL)
 | 
			
		||||
@@ -209,7 +209,7 @@ void gpio_free(unsigned gpio)
 | 
			
		||||
 	unsigned long		flags;
 | 
			
		||||
 	struct gpio_desc	*desc;
 | 
			
		||||
 
 | 
			
		||||
-	if (gpio >= ARCH_NR_GPIOS) {
 | 
			
		||||
+	if (!gpio_is_valid(gpio)) {
 | 
			
		||||
 		WARN_ON(extra_checks);
 | 
			
		||||
 		return;
 | 
			
		||||
 	}
 | 
			
		||||
@@ -245,7 +245,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
 | 
			
		||||
 {
 | 
			
		||||
 	unsigned gpio = chip->base + offset;
 | 
			
		||||
 
 | 
			
		||||
-	if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip)
 | 
			
		||||
+	if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip)
 | 
			
		||||
 		return NULL;
 | 
			
		||||
 	if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
 | 
			
		||||
 		return NULL;
 | 
			
		||||
@@ -276,7 +276,7 @@ int gpio_direction_input(unsigned gpio)
 | 
			
		||||
 
 | 
			
		||||
 	spin_lock_irqsave(&gpio_lock, flags);
 | 
			
		||||
 
 | 
			
		||||
-	if (gpio >= ARCH_NR_GPIOS)
 | 
			
		||||
+	if (!gpio_is_valid(gpio))
 | 
			
		||||
 		goto fail;
 | 
			
		||||
 	chip = desc->chip;
 | 
			
		||||
 	if (!chip || !chip->get || !chip->direction_input)
 | 
			
		||||
@@ -314,7 +314,7 @@ int gpio_direction_output(unsigned gpio, int value)
 | 
			
		||||
 
 | 
			
		||||
 	spin_lock_irqsave(&gpio_lock, flags);
 | 
			
		||||
 
 | 
			
		||||
-	if (gpio >= ARCH_NR_GPIOS)
 | 
			
		||||
+	if (!gpio_is_valid(gpio))
 | 
			
		||||
 		goto fail;
 | 
			
		||||
 	chip = desc->chip;
 | 
			
		||||
 	if (!chip || !chip->set || !chip->direction_output)
 | 
			
		||||
@@ -531,7 +531,7 @@ static int gpiolib_show(struct seq_file *s, void *unused)
 | 
			
		||||
 
 | 
			
		||||
 	/* REVISIT this isn't locked against gpio_chip removal ... */
 | 
			
		||||
 
 | 
			
		||||
-	for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
 | 
			
		||||
+	for (gpio = 0; gpio_is_valid(gpio); gpio++) {
 | 
			
		||||
 		if (chip == gpio_desc[gpio].chip)
 | 
			
		||||
 			continue;
 | 
			
		||||
 		chip = gpio_desc[gpio].chip;
 | 
			
		||||
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
 | 
			
		||||
index 7e77b6f..464c5b3 100644
 | 
			
		||||
--- a/include/asm-generic/gpio.h
 | 
			
		||||
+++ b/include/asm-generic/gpio.h
 | 
			
		||||
@@ -16,6 +16,12 @@
 | 
			
		||||
 #define ARCH_NR_GPIOS		256
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+static inline int gpio_is_valid(int number)
 | 
			
		||||
+{
 | 
			
		||||
+	/* only some non-negative numbers are valid */
 | 
			
		||||
+	return ((unsigned)number) < ARCH_NR_GPIOS;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 struct seq_file;
 | 
			
		||||
 struct module;
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +105,12 @@ extern int __gpio_cansleep(unsigned gpio);
 | 
			
		||||
 
 | 
			
		||||
 #else
 | 
			
		||||
 
 | 
			
		||||
+static inline int gpio_is_valid(int number)
 | 
			
		||||
+{
 | 
			
		||||
+	/* only non-negative numbers are valid */
 | 
			
		||||
+	return number >= 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* platforms that don't directly support access to GPIOs through I2C, SPI,
 | 
			
		||||
  * or other blocking infrastructure can use these wrappers.
 | 
			
		||||
  */
 | 
			
		||||
@ -0,0 +1,118 @@
 | 
			
		||||
From: Anton Vorontsov <avorontsov@ru.mvista.com>
 | 
			
		||||
Date: Mon, 28 Apr 2008 09:14:46 +0000 (-0700)
 | 
			
		||||
Subject: gpiolib: dynamic gpio number allocation
 | 
			
		||||
X-Git-Tag: v2.6.26-rc1~848
 | 
			
		||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=8d0aab2f16c4fa170f32e7a74a52cd0122bbafef
 | 
			
		||||
 | 
			
		||||
gpiolib: dynamic gpio number allocation
 | 
			
		||||
 | 
			
		||||
If gpio_chip->base is negative during registration, gpiolib performs dynamic
 | 
			
		||||
base allocation.  This is useful for devices that aren't always present, such
 | 
			
		||||
as GPIOs on hotplugged devices rather than mainboards.  (This behavior was
 | 
			
		||||
previously specified but not implemented.)
 | 
			
		||||
 | 
			
		||||
To avoid using any numbers that may have been explicitly assigned but not yet
 | 
			
		||||
registered, this dynamic allocation assigns GPIO numbers from the biggest
 | 
			
		||||
number on down, instead of from the smallest on up.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
 | 
			
		||||
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
 | 
			
		||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
 | 
			
		||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
 | 
			
		||||
index 623fcd9..2ba6127 100644
 | 
			
		||||
--- a/drivers/gpio/gpiolib.c
 | 
			
		||||
+++ b/drivers/gpio/gpiolib.c
 | 
			
		||||
@@ -80,6 +80,33 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
 | 
			
		||||
 	return gpio_desc[gpio].chip;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
 | 
			
		||||
+static int gpiochip_find_base(int ngpio)
 | 
			
		||||
+{
 | 
			
		||||
+	int i;
 | 
			
		||||
+	int spare = 0;
 | 
			
		||||
+	int base = -ENOSPC;
 | 
			
		||||
+
 | 
			
		||||
+	for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
 | 
			
		||||
+		struct gpio_chip *chip = gpio_desc[i].chip;
 | 
			
		||||
+
 | 
			
		||||
+		if (!chip) {
 | 
			
		||||
+			spare++;
 | 
			
		||||
+			if (spare == ngpio) {
 | 
			
		||||
+				base = i;
 | 
			
		||||
+				break;
 | 
			
		||||
+			}
 | 
			
		||||
+		} else {
 | 
			
		||||
+			spare = 0;
 | 
			
		||||
+			i -= chip->ngpio - 1;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (gpio_is_valid(base))
 | 
			
		||||
+		pr_debug("%s: found new base at %d\n", __func__, base);
 | 
			
		||||
+	return base;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /**
 | 
			
		||||
  * gpiochip_add() - register a gpio_chip
 | 
			
		||||
  * @chip: the chip to register, with chip->base initialized
 | 
			
		||||
@@ -88,38 +115,49 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
 | 
			
		||||
  * Returns a negative errno if the chip can't be registered, such as
 | 
			
		||||
  * because the chip->base is invalid or already associated with a
 | 
			
		||||
  * different chip.  Otherwise it returns zero as a success code.
 | 
			
		||||
+ *
 | 
			
		||||
+ * If chip->base is negative, this requests dynamic assignment of
 | 
			
		||||
+ * a range of valid GPIOs.
 | 
			
		||||
  */
 | 
			
		||||
 int gpiochip_add(struct gpio_chip *chip)
 | 
			
		||||
 {
 | 
			
		||||
 	unsigned long	flags;
 | 
			
		||||
 	int		status = 0;
 | 
			
		||||
 	unsigned	id;
 | 
			
		||||
+	int		base = chip->base;
 | 
			
		||||
 
 | 
			
		||||
-	/* NOTE chip->base negative is reserved to mean a request for
 | 
			
		||||
-	 * dynamic allocation.  We don't currently support that.
 | 
			
		||||
-	 */
 | 
			
		||||
-
 | 
			
		||||
-	if (chip->base < 0 || !gpio_is_valid(chip->base  + chip->ngpio)) {
 | 
			
		||||
+	if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio))
 | 
			
		||||
+			&& base >= 0) {
 | 
			
		||||
 		status = -EINVAL;
 | 
			
		||||
 		goto fail;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	spin_lock_irqsave(&gpio_lock, flags);
 | 
			
		||||
 
 | 
			
		||||
+	if (base < 0) {
 | 
			
		||||
+		base = gpiochip_find_base(chip->ngpio);
 | 
			
		||||
+		if (base < 0) {
 | 
			
		||||
+			status = base;
 | 
			
		||||
+			goto fail_unlock;
 | 
			
		||||
+		}
 | 
			
		||||
+		chip->base = base;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
 	/* these GPIO numbers must not be managed by another gpio_chip */
 | 
			
		||||
-	for (id = chip->base; id < chip->base + chip->ngpio; id++) {
 | 
			
		||||
+	for (id = base; id < base + chip->ngpio; id++) {
 | 
			
		||||
 		if (gpio_desc[id].chip != NULL) {
 | 
			
		||||
 			status = -EBUSY;
 | 
			
		||||
 			break;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 	if (status == 0) {
 | 
			
		||||
-		for (id = chip->base; id < chip->base + chip->ngpio; id++) {
 | 
			
		||||
+		for (id = base; id < base + chip->ngpio; id++) {
 | 
			
		||||
 			gpio_desc[id].chip = chip;
 | 
			
		||||
 			gpio_desc[id].flags = 0;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+fail_unlock:
 | 
			
		||||
 	spin_unlock_irqrestore(&gpio_lock, flags);
 | 
			
		||||
 fail:
 | 
			
		||||
 	/* failures here can mean systems won't boot... */
 | 
			
		||||
@ -0,0 +1,116 @@
 | 
			
		||||
From: Anton Vorontsov <avorontsov@ru.mvista.com>
 | 
			
		||||
Date: Mon, 28 Apr 2008 09:14:47 +0000 (-0700)
 | 
			
		||||
Subject: gpiochip_reserve()
 | 
			
		||||
X-Git-Tag: v2.6.26-rc1~847
 | 
			
		||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=169b6a7a6e91e1ea32136681b475cbaf2074bf35
 | 
			
		||||
 | 
			
		||||
gpiochip_reserve()
 | 
			
		||||
 | 
			
		||||
Add a new function gpiochip_reserve() to reserve ranges of gpios that platform
 | 
			
		||||
code has pre-allocated.  That is, this marks gpio numbers which will be
 | 
			
		||||
claimed by drivers that haven't yet been loaded, and thus are not available
 | 
			
		||||
for dynamic gpio number allocation.
 | 
			
		||||
 | 
			
		||||
[akpm@linux-foundation.org: remove unneeded __must_check]
 | 
			
		||||
[david-b@pacbell.net: don't export gpiochip_reserve (section fix)]
 | 
			
		||||
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
 | 
			
		||||
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
 | 
			
		||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
 | 
			
		||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
 | 
			
		||||
index 2ba6127..24c62b8 100644
 | 
			
		||||
--- a/drivers/gpio/gpiolib.c
 | 
			
		||||
+++ b/drivers/gpio/gpiolib.c
 | 
			
		||||
@@ -43,6 +43,7 @@ struct gpio_desc {
 | 
			
		||||
 /* flag symbols are bit numbers */
 | 
			
		||||
 #define FLAG_REQUESTED	0
 | 
			
		||||
 #define FLAG_IS_OUT	1
 | 
			
		||||
+#define FLAG_RESERVED	2
 | 
			
		||||
 
 | 
			
		||||
 #ifdef CONFIG_DEBUG_FS
 | 
			
		||||
 	const char		*label;
 | 
			
		||||
@@ -88,9 +89,10 @@ static int gpiochip_find_base(int ngpio)
 | 
			
		||||
 	int base = -ENOSPC;
 | 
			
		||||
 
 | 
			
		||||
 	for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
 | 
			
		||||
-		struct gpio_chip *chip = gpio_desc[i].chip;
 | 
			
		||||
+		struct gpio_desc *desc = &gpio_desc[i];
 | 
			
		||||
+		struct gpio_chip *chip = desc->chip;
 | 
			
		||||
 
 | 
			
		||||
-		if (!chip) {
 | 
			
		||||
+		if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) {
 | 
			
		||||
 			spare++;
 | 
			
		||||
 			if (spare == ngpio) {
 | 
			
		||||
 				base = i;
 | 
			
		||||
@@ -98,7 +100,8 @@ static int gpiochip_find_base(int ngpio)
 | 
			
		||||
 			}
 | 
			
		||||
 		} else {
 | 
			
		||||
 			spare = 0;
 | 
			
		||||
-			i -= chip->ngpio - 1;
 | 
			
		||||
+			if (chip)
 | 
			
		||||
+				i -= chip->ngpio - 1;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
@@ -108,6 +111,47 @@ static int gpiochip_find_base(int ngpio)
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
+ * gpiochip_reserve() - reserve range of gpios to use with platform code only
 | 
			
		||||
+ * @start: starting gpio number
 | 
			
		||||
+ * @ngpio: number of gpios to reserve
 | 
			
		||||
+ * Context: platform init, potentially before irqs or kmalloc will work
 | 
			
		||||
+ *
 | 
			
		||||
+ * Returns a negative errno if any gpio within the range is already reserved
 | 
			
		||||
+ * or registered, else returns zero as a success code.  Use this function
 | 
			
		||||
+ * to mark a range of gpios as unavailable for dynamic gpio number allocation,
 | 
			
		||||
+ * for example because its driver support is not yet loaded.
 | 
			
		||||
+ */
 | 
			
		||||
+int __init gpiochip_reserve(int start, int ngpio)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = 0;
 | 
			
		||||
+	unsigned long flags;
 | 
			
		||||
+	int i;
 | 
			
		||||
+
 | 
			
		||||
+	if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio))
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+
 | 
			
		||||
+	spin_lock_irqsave(&gpio_lock, flags);
 | 
			
		||||
+
 | 
			
		||||
+	for (i = start; i < start + ngpio; i++) {
 | 
			
		||||
+		struct gpio_desc *desc = &gpio_desc[i];
 | 
			
		||||
+
 | 
			
		||||
+		if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) {
 | 
			
		||||
+			ret = -EBUSY;
 | 
			
		||||
+			goto err;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		set_bit(FLAG_RESERVED, &desc->flags);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	pr_debug("%s: reserved gpios from %d to %d\n",
 | 
			
		||||
+		 __func__, start, start + ngpio - 1);
 | 
			
		||||
+err:
 | 
			
		||||
+	spin_unlock_irqrestore(&gpio_lock, flags);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+/**
 | 
			
		||||
  * gpiochip_add() - register a gpio_chip
 | 
			
		||||
  * @chip: the chip to register, with chip->base initialized
 | 
			
		||||
  * Context: potentially before irqs or kmalloc will work
 | 
			
		||||
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
 | 
			
		||||
index 464c5b3..ecf675a 100644
 | 
			
		||||
--- a/include/asm-generic/gpio.h
 | 
			
		||||
+++ b/include/asm-generic/gpio.h
 | 
			
		||||
@@ -74,6 +74,7 @@ struct gpio_chip {
 | 
			
		||||
 
 | 
			
		||||
 extern const char *gpiochip_is_requested(struct gpio_chip *chip,
 | 
			
		||||
 			unsigned offset);
 | 
			
		||||
+extern int __init __must_check gpiochip_reserve(int start, int ngpio);
 | 
			
		||||
 
 | 
			
		||||
 /* add/remove chips */
 | 
			
		||||
 extern int gpiochip_add(struct gpio_chip *chip);
 | 
			
		||||
@ -0,0 +1,48 @@
 | 
			
		||||
From: Trent Piepho <xyzzy@speakeasy.org>
 | 
			
		||||
Date: Fri, 23 May 2008 20:04:44 +0000 (-0700)
 | 
			
		||||
Subject: gpiolib: fix off by one errors
 | 
			
		||||
X-Git-Tag: v2.6.26-rc4~31
 | 
			
		||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=bff5fda972dc23bd1806a47c2098ae173585d013
 | 
			
		||||
 | 
			
		||||
gpiolib: fix off by one errors
 | 
			
		||||
 | 
			
		||||
The last gpio belonging to a chip is chip->base + chip->ngpios - 1.  Some
 | 
			
		||||
places in the code, but not all, forgot the critical minus one.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
 | 
			
		||||
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
 | 
			
		||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
 | 
			
		||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
 | 
			
		||||
index 7f138c6..beaf6b3 100644
 | 
			
		||||
--- a/drivers/gpio/gpiolib.c
 | 
			
		||||
+++ b/drivers/gpio/gpiolib.c
 | 
			
		||||
@@ -127,7 +127,7 @@ int __init gpiochip_reserve(int start, int ngpio)
 | 
			
		||||
 	unsigned long flags;
 | 
			
		||||
 	int i;
 | 
			
		||||
 
 | 
			
		||||
-	if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio))
 | 
			
		||||
+	if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
 | 
			
		||||
 		return -EINVAL;
 | 
			
		||||
 
 | 
			
		||||
 	spin_lock_irqsave(&gpio_lock, flags);
 | 
			
		||||
@@ -170,7 +170,7 @@ int gpiochip_add(struct gpio_chip *chip)
 | 
			
		||||
 	unsigned	id;
 | 
			
		||||
 	int		base = chip->base;
 | 
			
		||||
 
 | 
			
		||||
-	if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio))
 | 
			
		||||
+	if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
 | 
			
		||||
 			&& base >= 0) {
 | 
			
		||||
 		status = -EINVAL;
 | 
			
		||||
 		goto fail;
 | 
			
		||||
@@ -207,7 +207,7 @@ fail:
 | 
			
		||||
 	/* failures here can mean systems won't boot... */
 | 
			
		||||
 	if (status)
 | 
			
		||||
 		pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
 | 
			
		||||
-			chip->base, chip->base + chip->ngpio,
 | 
			
		||||
+			chip->base, chip->base + chip->ngpio - 1,
 | 
			
		||||
 			chip->label ? : "generic");
 | 
			
		||||
 	return status;
 | 
			
		||||
 }
 | 
			
		||||
@ -83,6 +83,7 @@ config TARGET_OPTIMIZATION
 | 
			
		||||
	default "-O2 -pipe -march=i686 -funit-at-a-time" if TARGET_x86_mediacenter
 | 
			
		||||
	default "-O2 -pipe -march=i486 -funit-at-a-time" if TARGET_x86
 | 
			
		||||
	default "-Os -pipe -march=i486 -funit-at-a-time" if TARGET_rdc
 | 
			
		||||
	default "-Os -pipe -mips32r2 -mtune=mips32r2 -funit-at-a-time" if TARGET_ar71xx
 | 
			
		||||
	default "-Os -pipe -mips32 -mtune=mips32 -funit-at-a-time" if mipsel || mips
 | 
			
		||||
	default "-Os -pipe -march=armv5te -mtune=xscale -funit-at-a-time" if TARGET_ixp4xx || TARGET_iop32x || TARGET_pxa || TARGET_orion
 | 
			
		||||
	default "-Os -pipe -march=armv4t -mtune=arm9tdmi -funit-at-a-time" if TARGET_storm
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user