surprise :p
authorGabor Juhos <juhosg@openwrt.org>
Mon, 21 Jul 2008 17:08:14 +0000 (17:08 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Mon, 21 Jul 2008 17:08:14 +0000 (17:08 +0000)
SVN-Revision: 11894

54 files changed:
target/linux/ar71xx/Makefile [new file with mode: 0644]
target/linux/ar71xx/config-default [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/Makefile [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/irq.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/platform.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/prom.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ar71xx/setup.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c [new file with mode: 0644]
target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c [new file with mode: 0644]
target/linux/ar71xx/files/drivers/net/ag71xx/Kconfig [new file with mode: 0644]
target/linux/ar71xx/files/drivers/net/ag71xx/Makefile [new file with mode: 0644]
target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h [new file with mode: 0644]
target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ethtool.c [new file with mode: 0644]
target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c [new file with mode: 0644]
target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mii.c [new file with mode: 0644]
target/linux/ar71xx/files/drivers/net/phy/micrel.c [new file with mode: 0644]
target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c [new file with mode: 0644]
target/linux/ar71xx/files/drivers/usb/host/ehci-ar71xx.c [new file with mode: 0644]
target/linux/ar71xx/files/drivers/usb/host/ohci-ar71xx.c [new file with mode: 0644]
target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/ar71xx.h [new file with mode: 0644]
target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/cpu-feature-overrides.h [new file with mode: 0644]
target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/gpio.h [new file with mode: 0644]
target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/irq.h [new file with mode: 0644]
target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/mangle-port.h [new file with mode: 0644]
target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/pci.h [new file with mode: 0644]
target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/platform.h [new file with mode: 0644]
target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/war.h [new file with mode: 0644]
target/linux/ar71xx/image/Makefile [new file with mode: 0644]
target/linux/ar71xx/patches/001-ar71xx_core.patch [new file with mode: 0644]
target/linux/ar71xx/patches/002-ar71xx_pci.patch [new file with mode: 0644]
target/linux/ar71xx/patches/003-ar71xx_usb_host.patch [new file with mode: 0644]
target/linux/ar71xx/patches/004-ar71xx_spi_controller.patch [new file with mode: 0644]
target/linux/ar71xx/patches/005-ar71xx_mac_driver.patch [new file with mode: 0644]
target/linux/ar71xx/patches/100-mtd_pm25lv_flash_support.patch [new file with mode: 0644]
target/linux/ar71xx/patches/101-ksz8041_phy_driver.patch [new file with mode: 0644]
target/linux/ar71xx/patches/140-redboot_partition_scan.patch [new file with mode: 0644]
target/linux/ar71xx/patches/200-rb4xx_nand_driver.patch [new file with mode: 0644]
target/linux/ar71xx/patches/900-mips_multi_machine_support.patch [new file with mode: 0644]
target/linux/ar71xx/patches/901-get_c0_compare_irq_function.patch [new file with mode: 0644]
target/linux/ar71xx/patches/902-mips_clocksource_init_war.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/910-m25p80_redboot_partitions.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/920-backport-gpio-is-valid.patch [deleted file]
target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/961-backport_gpio_define_gpio_valid.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/963-backport_gpio_chip_reserve.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/964-backport_gpiolib_fix_off_by_one_errors.patch [new file with mode: 0644]
toolchain/Config.in

diff --git a/target/linux/ar71xx/Makefile b/target/linux/ar71xx/Makefile
new file mode 100644 (file)
index 0000000..849f4c2
--- /dev/null
@@ -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))
diff --git a/target/linux/ar71xx/config-default b/target/linux/ar71xx/config-default
new file mode 100644 (file)
index 0000000..93caf0b
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig b/target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig
new file mode 100644 (file)
index 0000000..274c3ed
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/Makefile b/target/linux/ar71xx/files/arch/mips/ar71xx/Makefile
new file mode 100644 (file)
index 0000000..6e7ab1d
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c b/target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c
new file mode 100644 (file)
index 0000000..c88225c
--- /dev/null
@@ -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);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c b/target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c
new file mode 100644 (file)
index 0000000..03bf38b
--- /dev/null
@@ -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);
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c b/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c
new file mode 100644 (file)
index 0000000..171dd63
--- /dev/null
@@ -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();
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c
new file mode 100644 (file)
index 0000000..4a1200d
--- /dev/null
@@ -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);
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c
new file mode 100644 (file)
index 0000000..7504c34
--- /dev/null
@@ -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);
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c
new file mode 100644 (file)
index 0000000..6f1f39b
--- /dev/null
@@ -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);
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/platform.c b/target/linux/ar71xx/files/arch/mips/ar71xx/platform.c
new file mode 100644 (file)
index 0000000..9c91fa3
--- /dev/null
@@ -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);
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/prom.c b/target/linux/ar71xx/files/arch/mips/ar71xx/prom.c
new file mode 100644 (file)
index 0000000..e21464f
--- /dev/null
@@ -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);
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/setup.c b/target/linux/ar71xx/files/arch/mips/ar71xx/setup.c
new file mode 100644 (file)
index 0000000..3118552
--- /dev/null
@@ -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;
+}
diff --git a/target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c b/target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c
new file mode 100644 (file)
index 0000000..e3e80a9
--- /dev/null
@@ -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);
diff --git a/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c b/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c
new file mode 100644 (file)
index 0000000..c252831
--- /dev/null
@@ -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");
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/Kconfig b/target/linux/ar71xx/files/drivers/net/ag71xx/Kconfig
new file mode 100644 (file)
index 0000000..8105744
--- /dev/null
@@ -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.
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/Makefile b/target/linux/ar71xx/files/drivers/net/ag71xx/Makefile
new file mode 100644 (file)
index 0000000..452ee36
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
new file mode 100644 (file)
index 0000000..e22a7e6
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ethtool.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ethtool.c
new file mode 100644 (file)
index 0000000..9aa7b3a
--- /dev/null
@@ -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,
+};
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c
new file mode 100644 (file)
index 0000000..d4eebda
--- /dev/null
@@ -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);
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mii.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mii.c
new file mode 100644 (file)
index 0000000..65940d2
--- /dev/null
@@ -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);
+}
diff --git a/target/linux/ar71xx/files/drivers/net/phy/micrel.c b/target/linux/ar71xx/files/drivers/net/phy/micrel.c
new file mode 100644 (file)
index 0000000..e651672
--- /dev/null
@@ -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");
diff --git a/target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c b/target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c
new file mode 100644 (file)
index 0000000..98de435
--- /dev/null
@@ -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");
diff --git a/target/linux/ar71xx/files/drivers/usb/host/ehci-ar71xx.c b/target/linux/ar71xx/files/drivers/usb/host/ehci-ar71xx.c
new file mode 100644 (file)
index 0000000..6c7f29f
--- /dev/null
@@ -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");
diff --git a/target/linux/ar71xx/files/drivers/usb/host/ohci-ar71xx.c b/target/linux/ar71xx/files/drivers/usb/host/ohci-ar71xx.c
new file mode 100644 (file)
index 0000000..7af7faf
--- /dev/null
@@ -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");
diff --git a/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/ar71xx.h b/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/ar71xx.h
new file mode 100644 (file)
index 0000000..22fd2e6
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/cpu-feature-overrides.h b/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..d3560e5
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/gpio.h b/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/gpio.h
new file mode 100644 (file)
index 0000000..3477270
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/irq.h b/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/irq.h
new file mode 100644 (file)
index 0000000..fe6cfeb
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/mangle-port.h b/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/mangle-port.h
new file mode 100644 (file)
index 0000000..126d5b3
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/pci.h b/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/pci.h
new file mode 100644 (file)
index 0000000..9cf536d
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/platform.h b/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/platform.h
new file mode 100644 (file)
index 0000000..6c23340
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/war.h b/target/linux/ar71xx/files/include/asm-mips/mach-ar71xx/war.h
new file mode 100644 (file)
index 0000000..1ca6ffd
--- /dev/null
@@ -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 */
diff --git a/target/linux/ar71xx/image/Makefile b/target/linux/ar71xx/image/Makefile
new file mode 100644 (file)
index 0000000..4d86889
--- /dev/null
@@ -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))
diff --git a/target/linux/ar71xx/patches/001-ar71xx_core.patch b/target/linux/ar71xx/patches/001-ar71xx_core.patch
new file mode 100644 (file)
index 0000000..5806206
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/patches/002-ar71xx_pci.patch b/target/linux/ar71xx/patches/002-ar71xx_pci.patch
new file mode 100644 (file)
index 0000000..8ae604a
--- /dev/null
@@ -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.
diff --git a/target/linux/ar71xx/patches/003-ar71xx_usb_host.patch b/target/linux/ar71xx/patches/003-ar71xx_usb_host.patch
new file mode 100644 (file)
index 0000000..33b2475
--- /dev/null
@@ -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) && \
diff --git a/target/linux/ar71xx/patches/004-ar71xx_spi_controller.patch b/target/linux/ar71xx/patches/004-ar71xx_spi_controller.patch
new file mode 100644 (file)
index 0000000..b2d11ff
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/patches/005-ar71xx_mac_driver.patch b/target/linux/ar71xx/patches/005-ar71xx_mac_driver.patch
new file mode 100644 (file)
index 0000000..4a009a9
--- /dev/null
@@ -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/
diff --git a/target/linux/ar71xx/patches/100-mtd_pm25lv_flash_support.patch b/target/linux/ar71xx/patches/100-mtd_pm25lv_flash_support.patch
new file mode 100644 (file)
index 0000000..fb763af
--- /dev/null
@@ -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).
+        */
diff --git a/target/linux/ar71xx/patches/101-ksz8041_phy_driver.patch b/target/linux/ar71xx/patches/101-ksz8041_phy_driver.patch
new file mode 100644 (file)
index 0000000..9b69eca
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/patches/140-redboot_partition_scan.patch b/target/linux/ar71xx/patches/140-redboot_partition_scan.patch
new file mode 100644 (file)
index 0000000..baf8026
--- /dev/null
@@ -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;
diff --git a/target/linux/ar71xx/patches/200-rb4xx_nand_driver.patch b/target/linux/ar71xx/patches/200-rb4xx_nand_driver.patch
new file mode 100644 (file)
index 0000000..d9f6716
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/patches/900-mips_multi_machine_support.patch b/target/linux/ar71xx/patches/900-mips_multi_machine_support.patch
new file mode 100644 (file)
index 0000000..8932ba6
--- /dev/null
@@ -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
diff --git a/target/linux/ar71xx/patches/901-get_c0_compare_irq_function.patch b/target/linux/ar71xx/patches/901-get_c0_compare_irq_function.patch
new file mode 100644 (file)
index 0000000..0cc114d
--- /dev/null
@@ -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)
+ {
diff --git a/target/linux/ar71xx/patches/902-mips_clocksource_init_war.patch b/target/linux/ar71xx/patches/902-mips_clocksource_init_war.patch
new file mode 100644 (file)
index 0000000..0f1bc95
--- /dev/null
@@ -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;
diff --git a/target/linux/generic-2.6/patches-2.6.25/910-m25p80_redboot_partitions.patch b/target/linux/generic-2.6/patches-2.6.25/910-m25p80_redboot_partitions.patch
new file mode 100644 (file)
index 0000000..5f35f00
--- /dev/null
@@ -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;
diff --git a/target/linux/generic-2.6/patches-2.6.25/920-backport-gpio-is-valid.patch b/target/linux/generic-2.6/patches-2.6.25/920-backport-gpio-is-valid.patch
deleted file mode 100644 (file)
index 966270b..0000000
+++ /dev/null
@@ -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;
- /**
diff --git a/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch b/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch
new file mode 100644 (file)
index 0000000..a6822fc
--- /dev/null
@@ -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);
diff --git a/target/linux/generic-2.6/patches-2.6.25/961-backport_gpio_define_gpio_valid.patch b/target/linux/generic-2.6/patches-2.6.25/961-backport_gpio_define_gpio_valid.patch
new file mode 100644 (file)
index 0000000..2e826d4
--- /dev/null
@@ -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.
+  */
diff --git a/target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch b/target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch
new file mode 100644 (file)
index 0000000..0007423
--- /dev/null
@@ -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... */
diff --git a/target/linux/generic-2.6/patches-2.6.25/963-backport_gpio_chip_reserve.patch b/target/linux/generic-2.6/patches-2.6.25/963-backport_gpio_chip_reserve.patch
new file mode 100644 (file)
index 0000000..306fb0a
--- /dev/null
@@ -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);
diff --git a/target/linux/generic-2.6/patches-2.6.25/964-backport_gpiolib_fix_off_by_one_errors.patch b/target/linux/generic-2.6/patches-2.6.25/964-backport_gpiolib_fix_off_by_one_errors.patch
new file mode 100644 (file)
index 0000000..715f9ab
--- /dev/null
@@ -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;
+ }
index 1a465f5e50434819d81a4db64adcfd9eecd78db3..35dbba152ccb5712ba6178d59f8d2586ff7afb52 100644 (file)
@@ -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