diff options
Diffstat (limited to 'target/linux')
22 files changed, 10337 insertions, 10629 deletions
diff --git a/target/linux/Config.in b/target/linux/Config.in index cf4890059..1b78cecb5 100644 --- a/target/linux/Config.in +++ b/target/linux/Config.in @@ -20,5 +20,7 @@ source target/linux/config/Config.in.misc source target/linux/config/Config.in.mips source target/linux/config/Config.in.lib source target/linux/config/Config.in.pm +source target/linux/config/Config.in.serial +source target/linux/config/Config.in.spi source target/linux/config/Config.in.kvm source target/linux/config/Config.in.debug diff --git a/target/linux/config/Config.in.block b/target/linux/config/Config.in.block index 7e7d6cd9c..fe4c0a9c8 100644 --- a/target/linux/config/Config.in.block +++ b/target/linux/config/Config.in.block @@ -62,6 +62,9 @@ config ADK_KERNEL_MMC config ADK_KERNEL_MMC_BLOCK boolean +config ADK_KERNEL_SCSI_SYM53C8XX_2 + boolean + config ADK_KERNEL_MMC_AT91 boolean select ADK_KERNEL_BLOCK @@ -121,14 +124,16 @@ config ADK_KERNEL_ATA_PIIX select ADK_KERNEL_ATA_BMDMA select ADK_KERNEL_BLK_DEV select ADK_KERNEL_BLK_DEV_SD - default y if ADK_TARGET_SYSTEM_QEMU_MIPS64 - default y if ADK_TARGET_SYSTEM_QEMU_MIPS64EL + default y if ADK_TARGET_SYSTEM_QEMU_I686 default y if ADK_TARGET_SYSTEM_QEMU_MIPS default y if ADK_TARGET_SYSTEM_QEMU_MIPSEL - default y if ADK_TARGET_SYSTEM_QEMU_X86 + default y if ADK_TARGET_SYSTEM_QEMU_PPC + default y if ADK_TARGET_SYSTEM_QEMU_SPARC default y if ADK_TARGET_SYSTEM_QEMU_X86_64 default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default n config ADK_KERNEL_SATA_AHCI @@ -150,6 +155,8 @@ config ADK_KPACKAGE_KMOD_SATA_AHCI select ADK_KERNEL_BLK_DEV_SD depends on !ADK_KERNEL_SATA_AHCI depends on ADK_TARGET_WITH_SATA + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default n help Enables support for AHCI Serial ATA. @@ -274,8 +281,7 @@ config ADK_KPACKAGE_KMOD_BLK_DEV_MD tristate depends on !ADK_KERNEL_BLK_DEV_MD select ADK_KERNEL_MD - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX help config ADK_KERNEL_MD_RAID0 @@ -310,8 +316,7 @@ config ADK_KPACKAGE_KMOD_BLK_DEV_DM prompt "kmod-blk-dev-dm................... Device Mapper support" select ADK_KERNEL_MD depends on !ADK_KERNEL_BLK_DEV_DM - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX tristate help Device-mapper is a low level volume manager. It works by allowing @@ -359,8 +364,7 @@ config ADK_KPACKAGE_KMOD_BLK_DEV_DRBD tristate select ADK_KERNEL_BLK_DEV select ADK_KERNEL_CONNECTOR - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX help DRBD - http://www.drbd.org diff --git a/target/linux/config/Config.in.cpu b/target/linux/config/Config.in.cpu index 64d9e9f3f..5be6dacfc 100644 --- a/target/linux/config/Config.in.cpu +++ b/target/linux/config/Config.in.cpu @@ -11,3 +11,24 @@ config ADK_KERNEL_MTRR boolean default y if ADK_TARGET_CPU_WITH_MTRR default n + +# hyper threading +config ADK_KERNEL_PM_SLEEP_SMP + boolean + default y if ADK_TARGET_CPU_WITH_HT + default n + +config ADK_KERNEL_SMP + boolean + default y if ADK_TARGET_CPU_WITH_HT + default n + +config ADK_KERNEL_X86_HT + boolean + default y if ADK_TARGET_CPU_WITH_HT + default n + +config ADK_KERNEL_USE_GENERIC_SMP_HELPERS + boolean + default y if ADK_TARGET_CPU_WITH_HT + default n diff --git a/target/linux/config/Config.in.debug b/target/linux/config/Config.in.debug index 891a00c6e..0aed48de9 100644 --- a/target/linux/config/Config.in.debug +++ b/target/linux/config/Config.in.debug @@ -60,8 +60,7 @@ config ADK_KPACKAGE_KMOD_OPROFILE prompt "kernel support for oprofile" tristate select ADK_KERNEL_PROFILING - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help use oprofile package to make use of the kernel support. diff --git a/target/linux/config/Config.in.flash b/target/linux/config/Config.in.flash index 4d9bf6828..fb4f22221 100644 --- a/target/linux/config/Config.in.flash +++ b/target/linux/config/Config.in.flash @@ -1,5 +1,8 @@ config ADK_KERNEL_MTD boolean + +config ADK_KERNEL_MTD_MTDRAM + boolean config ADK_KERNEL_MTD_NAND boolean @@ -43,8 +46,7 @@ config ADK_KERNEL_MTD_CFI_ADV_OPTIONS config ADK_KERNEL_MTD_NAND_RB4XX boolean - default y if ADK_TARGET_SYSTEM_MIKROTIK_RB411 - default y if ADK_TARGET_SYSTEM_MIKROTIK_RB433 + default y if ADK_TARGET_SYSTEM_MIKROTIK_RB4XX default n config ADK_KERNEL_MTD_AR7_PARTS diff --git a/target/linux/config/Config.in.fs b/target/linux/config/Config.in.fs index ee2adc39f..60b331755 100644 --- a/target/linux/config/Config.in.fs +++ b/target/linux/config/Config.in.fs @@ -190,8 +190,7 @@ config ADK_KPACKAGE_KMOD_XFS_FS tristate select ADK_KERNEL_EXPORTFS depends on !ADK_KERNEL_XFS_FS - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help XFS is a high performance journaling filesystem which originated diff --git a/target/linux/config/Config.in.graphics b/target/linux/config/Config.in.graphics index 667593de9..61e124098 100644 --- a/target/linux/config/Config.in.graphics +++ b/target/linux/config/Config.in.graphics @@ -3,6 +3,7 @@ config ADK_KERNEL_VT default y if ADK_HARDWARE_QEMU default y if ADK_TARGET_WITH_VGA default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default n config ADK_KERNEL_VT_CONSOLE @@ -10,6 +11,7 @@ config ADK_KERNEL_VT_CONSOLE default y if ADK_HARDWARE_QEMU default y if ADK_TARGET_WITH_VGA default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default n config ADK_KERNEL_FONTS @@ -46,6 +48,17 @@ config ADK_KERNEL_AGP_INTEL menu "Graphic devices support" depends on ADK_TARGET_WITH_VGA +config ADK_KERNEL_FB_CIRRUS + prompt "................................ Framebuffer support for QEMU Emulator" + tristate + select ADK_KERNEL_FB + select ADK_KERNEL_FRAMEBUFFER_CONSOLE + default y if ADK_TARGET_SYSTEM_QEMU_I686 + default n + depends on ADK_TARGET_SYSTEM_QEMU_I686 + help + Framebuffer support for Qemu Emulator. + config ADK_KERNEL_FB_GEODE_LX prompt "................................ Framebuffer support for ALIX boards with VGA" tristate @@ -71,7 +84,7 @@ config ADK_KERNEL_FB_SM7XX Framebuffer support for Lemote Yeelong. config ADK_HARDWARE_GRAPHICS_INTEL_I915 - prompt "................................ Support for Intel graphic cards (AGP/DRM/KMS)" + prompt "............................ Support for Intel graphic cards (AGP/DRM/KMS/NM10)" boolean select ADK_KERNEL_FB select ADK_KERNEL_DRM @@ -83,7 +96,7 @@ config ADK_HARDWARE_GRAPHICS_INTEL_I915 default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 default n - depends on ADK_TARGET_SYSTEM_IBM_X40 || ADK_NATIVE_SYSTEM_IBM_X40 + depends on ADK_TARGET_SYSTEM_IBM_X40 || ADK_NATIVE_SYSTEM_IBM_X40 || ADK_TARGET_SYSTEM_INTEL_ATOM || ADK_NATIVE_SYSTEM_INTEL_ATOM help AGP/DRM/KMS support for Intel chipset i915. diff --git a/target/linux/config/Config.in.input b/target/linux/config/Config.in.input index 4a18af573..07fc751a5 100644 --- a/target/linux/config/Config.in.input +++ b/target/linux/config/Config.in.input @@ -3,45 +3,60 @@ depends on ADK_TARGET_WITH_USB || ADK_TARGET_WITH_INPUT config ADK_KERNEL_INPUT boolean + default y if ADK_TARGET_SYSTEM_QEMU_I686 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default y if ADK_TARGET_SYSTEM_SHUTTLE_SA76G2 default n config ADK_KERNEL_INPUT_KEYBOARD boolean + default y if ADK_TARGET_SYSTEM_QEMU_I686 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default y if ADK_TARGET_SYSTEM_SHUTTLE_SA76G2 default n config ADK_KERNEL_KEYBOARD_ATKBD boolean + default y if ADK_TARGET_SYSTEM_QEMU_I686 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default y if ADK_TARGET_SYSTEM_SHUTTLE_SA76G2 default n config ADK_KERNEL_INPUT_MOUSE boolean + default y if ADK_TARGET_SYSTEM_QEMU_I686 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default y if ADK_TARGET_SYSTEM_SHUTTLE_SA76G2 default n config ADK_KERNEL_INPUT_MOUSEDEV boolean + default y if ADK_TARGET_SYSTEM_QEMU_I686 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default y if ADK_TARGET_SYSTEM_SHUTTLE_SA76G2 default n @@ -61,8 +76,7 @@ config ADK_KPACKAGE_KMOD_USB_HID select ADK_KERNEL_INPUT select ADK_KERNEL_HID select ADK_PACKAGE_KMOD_USB_CONTROLLER - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX depends on ADK_TARGET_WITH_USB default n diff --git a/target/linux/config/Config.in.kernel b/target/linux/config/Config.in.kernel index 0400d8db6..1791a624a 100644 --- a/target/linux/config/Config.in.kernel +++ b/target/linux/config/Config.in.kernel @@ -3,21 +3,21 @@ config ADK_KERNEL_EXPERIMENTAL config ADK_KERNEL_ETRAX_MTD_SIZE hex - depends on ADK_TARGET_SYSTEM_FOXBOARD_LX416 || ADK_TARGET_SYSTEM_FOXBOARD_LX832 - default "0x00400000" if ADK_TARGET_SYSTEM_FOXBOARD_LX416 - default "0x00800000" if ADK_TARGET_SYSTEM_FOXBOARD_LX832 + depends on ADK_TARGET_SYSTEM_FOXBOARD_LX + default "0x00400000" if ADK_TARGET_FOXBOARD_MODEL_LX416 + default "0x00800000" if ADK_TARGET_FOXBOARD_MODEL_LX832 config ADK_KERNEL_ETRAX_DRAM_SIZE int - depends on ADK_TARGET_SYSTEM_FOXBOARD_LX416 || ADK_TARGET_SYSTEM_FOXBOARD_LX832 - default "16" if ADK_TARGET_SYSTEM_FOXBOARD_LX416 - default "32" if ADK_TARGET_SYSTEM_FOXBOARD_LX832 + depends on ADK_TARGET_SYSTEM_FOXBOARD_LX + default "16" if ADK_TARGET_FOXBOARD_MODEL_LX416 + default "32" if ADK_TARGET_FOXBOARD_MODEL_LX832 config ADK_KERNEL_ETRAX_DEF_R_SDRAM_TIMING hex - depends on ADK_TARGET_SYSTEM_FOXBOARD_LX416 || ADK_TARGET_SYSTEM_FOXBOARD_LX832 - default "0x80608002" if ADK_TARGET_SYSTEM_FOXBOARD_LX416 - default "0x80008002" if ADK_TARGET_SYSTEM_FOXBOARD_LX832 + depends on ADK_TARGET_SYSTEM_FOXBOARD_LX + default "0x80608002" if ADK_TARGET_FOXBOARD_MODEL_LX416 + default "0x80008002" if ADK_TARGET_FOXBOARD_MODEL_LX832 config ADK_KERNEL_BLK_DEV_INITRD boolean @@ -85,3 +85,6 @@ config ADK_KERNEL_NFS_COMMON config ADK_KERNEL_SUNRPC boolean + +config ADK_KERNEL_PCI + boolean diff --git a/target/linux/config/Config.in.misc b/target/linux/config/Config.in.misc index e7891a465..2a2b3e860 100644 --- a/target/linux/config/Config.in.misc +++ b/target/linux/config/Config.in.misc @@ -15,6 +15,12 @@ config ADK_KERNEL_RTC_INTF_DEV menu "Miscellaneous devices support" +config ADK_KERNEL_KEXEC + prompt ".................................. Add KEXEC syscall" + boolean + help + You need also kexec-tools to benefit from it. + config ADK_KERNEL_RTC_DRV_AT91SAM9 prompt ".................................. RTC support for AT91SAM9 (Fox G20)" boolean diff --git a/target/linux/config/Config.in.netdevice b/target/linux/config/Config.in.netdevice index 14820b810..2eea73b4a 100644 --- a/target/linux/config/Config.in.netdevice +++ b/target/linux/config/Config.in.netdevice @@ -22,6 +22,16 @@ config ADK_KERNEL_NETDEV_1000 config ADK_KERNEL_VIA_RHINE_MMIO boolean +config ADK_KERNEL_SMC91X + boolean + select ADK_KERNEL_NETDEVICES + select ADK_KERNEL_NET_ETHERNET + select ADK_KERNEL_NET_PCI + select ADK_KERNEL_MII + default y if ADK_TARGET_QEMU_ARM_MODEL_VERSATILE + default n + help + config ADK_KERNEL_CPMAC boolean select ADK_KERNEL_NETDEVICES @@ -42,6 +52,17 @@ config ADK_KERNEL_MACB default n help +config ADK_KERNEL_PCNET32 + boolean + select ADK_KERNEL_NETDEVICES + select ADK_KERNEL_NET_ETHERNET + select ADK_KERNEL_NET_PCI + select ADK_KERNEL_MII + default y if ADK_TARGET_SYSTEM_QEMU_MIPSEL + default y if ADK_TARGET_SYSTEM_QEMU_MIPS + default n + help + config ADK_KERNEL_NATSEMI boolean select ADK_KERNEL_NETDEVICES @@ -87,6 +108,16 @@ config ADK_KERNEL_AR231X_ETHERNET default n help +config ADK_KERNEL_NE2K_PCI + boolean + select ADK_KERNEL_NETDEVICES + select ADK_KERNEL_NET_ETHERNET + select ADK_KERNEL_NET_PCI + select ADK_KERNEL_MII + default y if ADK_TARGET_SYSTEM_QEMU_PPC + default n + help + config ADK_KERNEL_KORINA boolean select ADK_KERNEL_NETDEVICES @@ -104,8 +135,7 @@ config ADK_KERNEL_AG71XX select ADK_KERNEL_NET_PCI select ADK_KERNEL_MII select ADK_KERNEL_NETDEV_1000 - default y if ADK_TARGET_SYSTEM_MIKROTIK_RB411 - default y if ADK_TARGET_SYSTEM_MIKROTIK_RB433 + default y if ADK_TARGET_SYSTEM_MIKROTIK_RB4XX default n help @@ -126,7 +156,7 @@ config ADK_KERNEL_E1000 select ADK_KERNEL_NETDEV_1000 default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 - default y if ADK_TARGET_SYSTEM_QEMU_X86 + default y if ADK_TARGET_SYSTEM_QEMU_I686 default y if ADK_TARGET_SYSTEM_QEMU_X86_64 default n help @@ -145,6 +175,8 @@ config ADK_KERNEL_R8169 select ADK_KERNEL_NETDEVICES select ADK_KERNEL_NET_ETHERNET select ADK_KERNEL_NETDEV_1000 + select ADK_KERNEL_MII + select ADK_KPACKAGE_KMOD_FW_LOADER default y if ADK_TARGET_SYSTEM_OVH_RPS default n help @@ -237,6 +269,8 @@ config ADK_KPACKAGE_KMOD_R8169 select ADK_KERNEL_NETDEVICES select ADK_KERNEL_NET_ETHERNET select ADK_KERNEL_NETDEV_1000 + select ADK_KERNEL_MII + select ADK_KPACKAGE_KMOD_FW_LOADER depends on !ADK_KERNEL_R8169 default n help @@ -244,6 +278,7 @@ config ADK_KPACKAGE_KMOD_R8169 endmenu config ADK_KERNEL_WIRELESS + select ADK_KERNEL_NETDEVICES boolean config ADK_KERNEL_WIRELESS_EXT @@ -373,8 +408,9 @@ config ADK_KPACKAGE_KMOD_RTL8187 prompt "kmod-rtl8187................. Realtek RTL8187/RTL8187B wireless cards" tristate depends on ADK_TARGET_WITH_USB - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX + select ADK_KPACKAGE_KMOD_MAC80211 + select ADK_KPACKAGE_KMOD_EEPROM_93CX6 default n help Driver for Realtek RTL8187/RTL8187B wireless chips. @@ -389,8 +425,6 @@ config ADK_KPACKAGE_KMOD_P54_USB select ADK_KPACKAGE_KMOD_MAC80211 select ADK_KPACKAGE_KMOD_CRC_CCITT depends on ADK_PACKAGE_KMOD_USB_CONTROLLER - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 default n help Driver for Prism54 USB adaptors. diff --git a/target/linux/config/Config.in.network b/target/linux/config/Config.in.network index 6e4267857..2ec253111 100644 --- a/target/linux/config/Config.in.network +++ b/target/linux/config/Config.in.network @@ -158,7 +158,7 @@ config ADK_KPACKAGE_KMOD_NET_IPGRE config ADK_KPACKAGE_KMOD_IPV6 prompt "kmod-ipv6......................... IPv6 support" tristate - default n + default m help This is complemental support for the IP version 6. You will still be able to do traditional IPv4 networking as well. diff --git a/target/linux/config/Config.in.pm b/target/linux/config/Config.in.pm index 5ffd8aca9..7d7dc1f8f 100644 --- a/target/linux/config/Config.in.pm +++ b/target/linux/config/Config.in.pm @@ -23,7 +23,7 @@ config ADK_KERNEL_ACPI_DOCK boolean menu "Power Management support" -depends on ADK_TARGET_WITH_ACPI +depends on ADK_TARGET_WITH_ACPI || ADK_TARGET_SYSTEM_LEMOTE_YEELONG config ADK_HARDWARE_ACPI prompt "Enable ACPI support" @@ -36,6 +36,8 @@ config ADK_HARDWARE_ACPI select ADK_KERNEL_ACPI_BUTTON select ADK_KERNEL_ACPI_FAN select ADK_KERNEL_ACPI_DOCK + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 default n @@ -46,8 +48,12 @@ config ADK_KERNEL_SUSPEND prompt "Enable Suspend-to-RAM support" boolean select ADK_KERNEL_PM + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG + default y if ADK_NATIVE_SYSTEM_LEMOTE_YEELONG default n help Enable Suspend-to-RAM support. @@ -58,8 +64,12 @@ config ADK_KERNEL_HIBERNATION select ADK_KERNEL_PM select ADK_KERNEL_SWAP select BUSYBOX_SWAPONOFF + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG + default y if ADK_NATIVE_SYSTEM_LEMOTE_YEELONG default n help Enable Suspend-to-Disk support. diff --git a/target/linux/config/Config.in.sensors b/target/linux/config/Config.in.sensors new file mode 100644 index 000000000..941913bbd --- /dev/null +++ b/target/linux/config/Config.in.sensors @@ -0,0 +1,25 @@ +menu "Sensors" + +config ADK_KERNEL_HWMON + boolean + +config ADK_KPACKAGE_KMOD_CORETEMP + prompt "kmod-coretemp..................... Coretemp" + boolean + select ADK_KERNEL_I2C + select ADK_KERNEL_I2C_CHARDEV + select ADK_KERNEL_HWMON + select ADK_KERNEL_EXPERIMENTAL + default n + help + Coretemp module + +config ADK_KPACKAGE_KMOD_IT87 + prompt "kmod-it87......................... it87" + boolean + default n + help + Module for IT87 smbus chipsets + +endmenu + diff --git a/target/linux/config/Config.in.serial b/target/linux/config/Config.in.serial new file mode 100644 index 000000000..adc25312d --- /dev/null +++ b/target/linux/config/Config.in.serial @@ -0,0 +1,15 @@ +config ADK_KERNEL_SERIAL_PXA + boolean + default y if ADK_TARGET_QEMU_ARM_MODEL_SPITZ + +config ADK_KERNEL_SERIAL_PXA_CONSOLE + boolean + default y if ADK_TARGET_QEMU_ARM_MODEL_SPITZ + +config ADK_KERNEL_SERIAL_AMBA_PL011 + boolean + default y if ADK_TARGET_QEMU_ARM_MODEL_VERSATILE + +config ADK_KERNEL_SERIAL_AMBA_PL011_CONSOLE + boolean + default y if ADK_TARGET_QEMU_ARM_MODEL_VERSATILE diff --git a/target/linux/config/Config.in.spi b/target/linux/config/Config.in.spi new file mode 100644 index 000000000..73db5e86d --- /dev/null +++ b/target/linux/config/Config.in.spi @@ -0,0 +1,18 @@ +config ADK_KERNEL_SPI + boolean + +config ADK_KERNEL_SPI_AR71XX + select ADK_KERNEL_SPI + boolean + +config ADK_KERNEL_SPI_RB4XX + select ADK_KERNEL_SPI + boolean + +config ADK_KERNEL_SPI_RB4XX_CPLD + select ADK_KERNEL_SPI + boolean + +config ADK_KERNEL_SPI_PXA2XX + select ADK_KERNEL_SPI + boolean diff --git a/target/linux/config/Config.in.systems b/target/linux/config/Config.in.systems index 8750ac281..3e64caddc 100644 --- a/target/linux/config/Config.in.systems +++ b/target/linux/config/Config.in.systems @@ -1,3 +1,10 @@ +# page size +config ADK_KERNEL_PAGE_SIZE_4KB + boolean + +config ADK_KERNEL_PAGE_SIZE_16KB + boolean + # mips systems config ADK_KERNEL_ATHEROS_AR231X boolean @@ -28,6 +35,18 @@ config ADK_KERNEL_LEMOTE_MACH2F boolean # arm systems +config ADK_KERNEL_ARCH_VERSATILE + boolean + +config ADK_KERNEL_ARCH_PXA + boolean + +config ADK_KERNEL_PXA_SHARPSL + boolean + +config ADK_KERNEL_MACH_SPITZ + boolean + config ADK_KERNEL_ARCH_AT91 boolean @@ -37,6 +56,7 @@ config ADK_KERNEL_ARCH_AT91SAM9G20 config ADK_KERNEL_MACH_ACMENETUSFOXG20 boolean +# endianesss and ABI config ADK_KERNEL_AEABI boolean @@ -45,3 +65,7 @@ config ADK_KERNEL_CPU_BIG_ENDIAN config ADK_KERNEL_CPU_LITTLE_ENDIAN boolean + +# cris systems +config ADK_KERNEL_ETRAXFS + boolean diff --git a/target/linux/config/Config.in.usb b/target/linux/config/Config.in.usb index 2bc8d73db..057fa1ffc 100644 --- a/target/linux/config/Config.in.usb +++ b/target/linux/config/Config.in.usb @@ -30,14 +30,16 @@ config ADK_KPACKAGE_KMOD_USB tristate select ADK_KERNEL_NLS depends on !ADK_KERNEL_USB - #depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D2 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D13 default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default y if ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 + default y if ADK_TARGET_SYSTEM_FOXBOARD_LX default n help Universal Serial Bus (USB) is a specification for a serial bus @@ -75,10 +77,11 @@ config ADK_KPACKAGE_KMOD_USB_UHCI_HCD depends on ADK_KPACKAGE_KMOD_USB depends on !ADK_KERNEL_USB_UHCI_HCD depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default n help @@ -97,12 +100,13 @@ config ADK_KPACKAGE_KMOD_USB_OHCI_HCD select ADK_PACKAGE_KMOD_USB_CONTROLLER depends on ADK_KPACKAGE_KMOD_USB #depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D2 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D13 default y if ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default n help The Open Host Controller Interface (OHCI) is a standard for accessing @@ -120,8 +124,7 @@ config ADK_KPACKAGE_KMOD_USB_ISP116X_HCD select ADK_PACKAGE_KMOD_USB_CONTROLLER depends on ADK_KPACKAGE_KMOD_USB depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help The ISP1160 and ISP1161 chips are USB host controllers. Enable this @@ -135,8 +138,7 @@ config ADK_KPACKAGE_KMOD_USB_SL811_HCD select ADK_PACKAGE_KMOD_USB_CONTROLLER depends on ADK_KPACKAGE_KMOD_USB depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help The SL811HS is a single-port USB controller that supports either @@ -151,12 +153,13 @@ config ADK_KPACKAGE_KMOD_USB_EHCI_HCD select ADK_PACKAGE_KMOD_USB_CONTROLLER depends on !ADK_KERNEL_USB_EHCI_HCD depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX depends on ADK_KPACKAGE_KMOD_USB default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D2 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D13 + default y if ADK_TARGET_SYSTEM_INTEL_ATOM + default y if ADK_NATIVE_SYSTEM_INTEL_ATOM default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG @@ -183,6 +186,7 @@ config ADK_KPACKAGE_KMOD_USB_EHCI_HCD config ADK_PACKAGE_KMOD_USB_CONTROLLER tristate default y if ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 + default y if ADK_TARGET_SYSTEM_FOXBOARD_LX default n config ADK_KPACKAGE_KMOD_USB_ACM diff --git a/target/linux/patches/2.6.39/cris-etrax.patch b/target/linux/patches/2.6.39/cris-etrax.patch new file mode 100644 index 000000000..a80d9a8b8 --- /dev/null +++ b/target/linux/patches/2.6.39/cris-etrax.patch @@ -0,0 +1,12 @@ +diff -Nur linux-2.6.39.orig/arch/cris/arch-v32/drivers/i2c.h linux-2.6.39/arch/cris/arch-v32/drivers/i2c.h +--- linux-2.6.39.orig/arch/cris/arch-v32/drivers/i2c.h 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/arch/cris/arch-v32/drivers/i2c.h 2011-08-24 19:15:05.000000000 +0200 +@@ -2,7 +2,7 @@ + #include <linux/init.h> + + /* High level I2C actions */ +-int __init i2c_init(void); ++static int __init i2c_init(void); + int i2c_write(unsigned char theSlave, void *data, size_t nbytes); + int i2c_read(unsigned char theSlave, void *data, size_t nbytes); + int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); diff --git a/target/linux/patches/2.6.39/cris.patch b/target/linux/patches/2.6.39/cris.patch index f58391a5d..2d56de399 100644 --- a/target/linux/patches/2.6.39/cris.patch +++ b/target/linux/patches/2.6.39/cris.patch @@ -1,6 +1,6 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c --- linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c 2011-07-28 16:16:35.633425525 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c 2011-08-25 07:43:00.179230147 +0200 @@ -113,7 +113,7 @@ /* If no partition-table was found, we use this default-set. */ @@ -146,443 +146,9 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c linux-2.6. return err; } -diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c.orig linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c.orig ---- linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c.orig 2011-05-19 06:06:34.000000000 +0200 -@@ -0,0 +1,430 @@ -+/* -+ * Physical mapping layer for MTD using the Axis partitiontable format -+ * -+ * Copyright (c) 2001, 2002 Axis Communications AB -+ * -+ * This file is under the GPL. -+ * -+ * First partition is always sector 0 regardless of if we find a partitiontable -+ * or not. In the start of the next sector, there can be a partitiontable that -+ * tells us what other partitions to define. If there isn't, we use a default -+ * partition split defined below. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/slab.h> -+ -+#include <linux/mtd/concat.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/mtdram.h> -+#include <linux/mtd/partitions.h> -+ -+#include <asm/axisflashmap.h> -+#include <asm/mmu.h> -+#include <arch/sv_addr_ag.h> -+ -+#ifdef CONFIG_CRIS_LOW_MAP -+#define FLASH_UNCACHED_ADDR KSEG_8 -+#define FLASH_CACHED_ADDR KSEG_5 -+#else -+#define FLASH_UNCACHED_ADDR KSEG_E -+#define FLASH_CACHED_ADDR KSEG_F -+#endif -+ -+#if CONFIG_ETRAX_FLASH_BUSWIDTH==1 -+#define flash_data __u8 -+#elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 -+#define flash_data __u16 -+#elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 -+#define flash_data __u32 -+#endif -+ -+/* From head.S */ -+extern unsigned long romfs_start, romfs_length, romfs_in_flash; -+ -+/* The master mtd for the entire flash. */ -+struct mtd_info* axisflash_mtd = NULL; -+ -+/* Map driver functions. */ -+ -+static map_word flash_read(struct map_info *map, unsigned long ofs) -+{ -+ map_word tmp; -+ tmp.x[0] = *(flash_data *)(map->map_priv_1 + ofs); -+ return tmp; -+} -+ -+static void flash_copy_from(struct map_info *map, void *to, -+ unsigned long from, ssize_t len) -+{ -+ memcpy(to, (void *)(map->map_priv_1 + from), len); -+} -+ -+static void flash_write(struct map_info *map, map_word d, unsigned long adr) -+{ -+ *(flash_data *)(map->map_priv_1 + adr) = (flash_data)d.x[0]; -+} -+ -+/* -+ * The map for chip select e0. -+ * -+ * We run into tricky coherence situations if we mix cached with uncached -+ * accesses to we only use the uncached version here. -+ * -+ * The size field is the total size where the flash chips may be mapped on the -+ * chip select. MTD probes should find all devices there and it does not matter -+ * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD -+ * probes will ignore them. -+ * -+ * The start address in map_priv_1 is in virtual memory so we cannot use -+ * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start -+ * address of cse0. -+ */ -+static struct map_info map_cse0 = { -+ .name = "cse0", -+ .size = MEM_CSE0_SIZE, -+ .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH, -+ .read = flash_read, -+ .copy_from = flash_copy_from, -+ .write = flash_write, -+ .map_priv_1 = FLASH_UNCACHED_ADDR -+}; -+ -+/* -+ * The map for chip select e1. -+ * -+ * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong -+ * address, but there isn't. -+ */ -+static struct map_info map_cse1 = { -+ .name = "cse1", -+ .size = MEM_CSE1_SIZE, -+ .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH, -+ .read = flash_read, -+ .copy_from = flash_copy_from, -+ .write = flash_write, -+ .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE -+}; -+ -+/* If no partition-table was found, we use this default-set. */ -+#define MAX_PARTITIONS 7 -+#define NUM_DEFAULT_PARTITIONS 3 -+ -+/* -+ * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the -+ * size of one flash block and "filesystem"-partition needs 5 blocks to be able -+ * to use JFFS. -+ */ -+static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { -+ { -+ .name = "boot firmware", -+ .size = CONFIG_ETRAX_PTABLE_SECTOR, -+ .offset = 0 -+ }, -+ { -+ .name = "kernel", -+ .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), -+ .offset = CONFIG_ETRAX_PTABLE_SECTOR -+ }, -+ { -+ .name = "filesystem", -+ .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR, -+ .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) -+ } -+}; -+ -+/* Initialize the ones normally used. */ -+static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { -+ { -+ .name = "part0", -+ .size = CONFIG_ETRAX_PTABLE_SECTOR, -+ .offset = 0 -+ }, -+ { -+ .name = "part1", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part2", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part3", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part4", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part5", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part6", -+ .size = 0, -+ .offset = 0 -+ }, -+}; -+ -+#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE -+/* Main flash device */ -+static struct mtd_partition main_partition = { -+ .name = "main", -+ .size = 0, -+ .offset = 0 -+}; -+#endif -+ -+/* -+ * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash -+ * chips in that order (because the amd_flash-driver is faster). -+ */ -+static struct mtd_info *probe_cs(struct map_info *map_cs) -+{ -+ struct mtd_info *mtd_cs = NULL; -+ -+ printk(KERN_INFO -+ "%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n", -+ map_cs->name, map_cs->size, map_cs->map_priv_1); -+ -+#ifdef CONFIG_MTD_CFI -+ mtd_cs = do_map_probe("cfi_probe", map_cs); -+#endif -+#ifdef CONFIG_MTD_JEDECPROBE -+ if (!mtd_cs) -+ mtd_cs = do_map_probe("jedec_probe", map_cs); -+#endif -+ -+ return mtd_cs; -+} -+ -+/* -+ * Probe each chip select individually for flash chips. If there are chips on -+ * both cse0 and cse1, the mtd_info structs will be concatenated to one struct -+ * so that MTD partitions can cross chip boundries. -+ * -+ * The only known restriction to how you can mount your chips is that each -+ * chip select must hold similar flash chips. But you need external hardware -+ * to do that anyway and you can put totally different chips on cse0 and cse1 -+ * so it isn't really much of a restriction. -+ */ -+static struct mtd_info *flash_probe(void) -+{ -+ struct mtd_info *mtd_cse0; -+ struct mtd_info *mtd_cse1; -+ struct mtd_info *mtd_cse; -+ -+ mtd_cse0 = probe_cs(&map_cse0); -+ mtd_cse1 = probe_cs(&map_cse1); -+ -+ if (!mtd_cse0 && !mtd_cse1) { -+ /* No chip found. */ -+ return NULL; -+ } -+ -+ if (mtd_cse0 && mtd_cse1) { -+ struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 }; -+ -+ /* Since the concatenation layer adds a small overhead we -+ * could try to figure out if the chips in cse0 and cse1 are -+ * identical and reprobe the whole cse0+cse1 window. But since -+ * flash chips are slow, the overhead is relatively small. -+ * So we use the MTD concatenation layer instead of further -+ * complicating the probing procedure. -+ */ -+ mtd_cse = mtd_concat_create(mtds, ARRAY_SIZE(mtds), -+ "cse0+cse1"); -+ if (!mtd_cse) { -+ printk(KERN_ERR "%s and %s: Concatenation failed!\n", -+ map_cse0.name, map_cse1.name); -+ -+ /* The best we can do now is to only use what we found -+ * at cse0. -+ */ -+ mtd_cse = mtd_cse0; -+ map_destroy(mtd_cse1); -+ } -+ } else { -+ mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1; -+ } -+ -+ return mtd_cse; -+} -+ -+/* -+ * Probe the flash chip(s) and, if it succeeds, read the partition-table -+ * and register the partitions with MTD. -+ */ -+static int __init init_axis_flash(void) -+{ -+ struct mtd_info *mymtd; -+ int err = 0; -+ int pidx = 0; -+ struct partitiontable_head *ptable_head = NULL; -+ struct partitiontable_entry *ptable; -+ int use_default_ptable = 1; /* Until proven otherwise. */ -+ const char pmsg[] = " /dev/flash%d at 0x%08x, size 0x%08x\n"; -+ -+ if (!(mymtd = flash_probe())) { -+ /* There's no reason to use this module if no flash chip can -+ * be identified. Make sure that's understood. -+ */ -+ printk(KERN_INFO "axisflashmap: Found no flash chip.\n"); -+ } else { -+ printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n", -+ mymtd->name, mymtd->size); -+ axisflash_mtd = mymtd; -+ } -+ -+ if (mymtd) { -+ mymtd->owner = THIS_MODULE; -+ ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + -+ CONFIG_ETRAX_PTABLE_SECTOR + -+ PARTITION_TABLE_OFFSET); -+ } -+ pidx++; /* First partition is always set to the default. */ -+ -+ if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC) -+ && (ptable_head->size < -+ (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + -+ PARTITIONTABLE_END_MARKER_SIZE)) -+ && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + -+ ptable_head->size - -+ PARTITIONTABLE_END_MARKER_SIZE) -+ == PARTITIONTABLE_END_MARKER)) { -+ /* Looks like a start, sane length and end of a -+ * partition table, lets check csum etc. -+ */ -+ int ptable_ok = 0; -+ struct partitiontable_entry *max_addr = -+ (struct partitiontable_entry *) -+ ((unsigned long)ptable_head + sizeof(*ptable_head) + -+ ptable_head->size); -+ unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; -+ unsigned char *p; -+ unsigned long csum = 0; -+ -+ ptable = (struct partitiontable_entry *) -+ ((unsigned long)ptable_head + sizeof(*ptable_head)); -+ -+ /* Lets be PARANOID, and check the checksum. */ -+ p = (unsigned char*) ptable; -+ -+ while (p <= (unsigned char*)max_addr) { -+ csum += *p++; -+ csum += *p++; -+ csum += *p++; -+ csum += *p++; -+ } -+ ptable_ok = (csum == ptable_head->checksum); -+ -+ /* Read the entries and use/show the info. */ -+ printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n", -+ (ptable_ok ? " valid" : "n invalid"), ptable_head, -+ max_addr); -+ -+ /* We have found a working bootblock. Now read the -+ * partition table. Scan the table. It ends when -+ * there is 0xffffffff, that is, empty flash. -+ */ -+ while (ptable_ok -+ && ptable->offset != 0xffffffff -+ && ptable < max_addr -+ && pidx < MAX_PARTITIONS) { -+ -+ axis_partitions[pidx].offset = offset + ptable->offset; -+ axis_partitions[pidx].size = ptable->size; -+ -+ printk(pmsg, pidx, axis_partitions[pidx].offset, -+ axis_partitions[pidx].size); -+ pidx++; -+ ptable++; -+ } -+ use_default_ptable = !ptable_ok; -+ } -+ -+ if (romfs_in_flash) { -+ /* Add an overlapping device for the root partition (romfs). */ -+ -+ axis_partitions[pidx].name = "romfs"; -+ axis_partitions[pidx].size = romfs_length; -+ axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; -+ axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; -+ -+ printk(KERN_INFO -+ " Adding readonly flash partition for romfs image:\n"); -+ printk(pmsg, pidx, axis_partitions[pidx].offset, -+ axis_partitions[pidx].size); -+ pidx++; -+ } -+ -+#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE -+ if (mymtd) { -+ main_partition.size = mymtd->size; -+ err = add_mtd_partitions(mymtd, &main_partition, 1); -+ if (err) -+ panic("axisflashmap: Could not initialize " -+ "partition for whole main mtd device!\n"); -+ } -+#endif -+ -+ if (mymtd) { -+ if (use_default_ptable) { -+ printk(KERN_INFO " Using default partition table.\n"); -+ err = add_mtd_partitions(mymtd, axis_default_partitions, -+ NUM_DEFAULT_PARTITIONS); -+ } else { -+ err = add_mtd_partitions(mymtd, axis_partitions, pidx); -+ } -+ -+ if (err) -+ panic("axisflashmap could not add MTD partitions!\n"); -+ } -+ -+ if (!romfs_in_flash) { -+ /* Create an RAM device for the root partition (romfs). */ -+ -+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0) -+ /* No use trying to boot this kernel from RAM. Panic! */ -+ printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM " -+ "device due to kernel (mis)configuration!\n"); -+ panic("This kernel cannot boot from RAM!\n"); -+#else -+ struct mtd_info *mtd_ram; -+ -+ mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); -+ if (!mtd_ram) -+ panic("axisflashmap couldn't allocate memory for " -+ "mtd_info!\n"); -+ -+ printk(KERN_INFO " Adding RAM partition for romfs image:\n"); -+ printk(pmsg, pidx, (unsigned)romfs_start, -+ (unsigned)romfs_length); -+ -+ err = mtdram_init_device(mtd_ram, -+ (void *)romfs_start, -+ romfs_length, -+ "romfs"); -+ if (err) -+ panic("axisflashmap could not initialize MTD RAM " -+ "device!\n"); -+#endif -+ } -+ return err; -+} -+ -+/* This adds the above to the kernels init-call chain. */ -+module_init(init_axis_flash); -+ -+EXPORT_SYMBOL(axisflash_mtd); diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/ds1302.c linux-2.6.39/arch/cris/arch-v10/drivers/ds1302.c --- linux-2.6.39.orig/arch/cris/arch-v10/drivers/ds1302.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/drivers/ds1302.c 2011-07-28 16:16:35.863415658 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/drivers/ds1302.c 2011-08-25 07:43:00.339229517 +0200 @@ -22,6 +22,7 @@ #include <linux/mutex.h> #include <linux/bcd.h> @@ -617,7 +183,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/ds1302.c linux-2.6.39/arc } diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/gpio.c linux-2.6.39/arch/cris/arch-v10/drivers/gpio.c --- linux-2.6.39.orig/arch/cris/arch-v10/drivers/gpio.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/drivers/gpio.c 2011-07-28 16:16:36.023425394 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/drivers/gpio.c 2011-08-25 07:43:00.588029746 +0200 @@ -20,6 +20,7 @@ #include <linux/poll.h> #include <linux/init.h> @@ -653,7 +219,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/gpio.c linux-2.6.39/arch/ CRIS_LED_NETWORK_SET(0); diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/lib/hw_settings.S linux-2.6.39/arch/cris/arch-v10/lib/hw_settings.S --- linux-2.6.39.orig/arch/cris/arch-v10/lib/hw_settings.S 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/lib/hw_settings.S 2011-07-28 16:16:36.163758404 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/lib/hw_settings.S 2011-08-25 07:43:00.799228984 +0200 @@ -58,3 +58,5 @@ .dword R_PORT_PB_SET .dword PB_SET_VALUE @@ -662,7 +228,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/lib/hw_settings.S linux-2.6.39/ar + .dword 0xdeadc0de diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/mm/init.c linux-2.6.39/arch/cris/arch-v10/mm/init.c --- linux-2.6.39.orig/arch/cris/arch-v10/mm/init.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/mm/init.c 2011-07-28 16:16:36.313421347 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/mm/init.c 2011-08-25 07:43:01.069229695 +0200 @@ -184,6 +184,9 @@ free_area_init_node(0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); @@ -675,7 +241,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/mm/init.c linux-2.6.39/arch/cris/ * is called before any driver is initialized. diff -Nur linux-2.6.39.orig/arch/cris/boot/compressed/Makefile linux-2.6.39/arch/cris/boot/compressed/Makefile --- linux-2.6.39.orig/arch/cris/boot/compressed/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/boot/compressed/Makefile 2011-07-28 16:16:36.453421314 +0200 ++++ linux-2.6.39/arch/cris/boot/compressed/Makefile 2011-08-25 07:43:01.847994855 +0200 @@ -18,7 +18,7 @@ OBJECTS-$(CONFIG_ETRAX_ARCH_V32) = $(obj)/head_v32.o OBJECTS-$(CONFIG_ETRAX_ARCH_V10) = $(obj)/head_v10.o @@ -687,7 +253,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/boot/compressed/Makefile linux-2.6.39/arch cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@ diff -Nur linux-2.6.39.orig/arch/cris/boot/Makefile linux-2.6.39/arch/cris/boot/Makefile --- linux-2.6.39.orig/arch/cris/boot/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/boot/Makefile 2011-07-28 16:16:36.573671907 +0200 ++++ linux-2.6.39/arch/cris/boot/Makefile 2011-08-25 07:43:01.989240448 +0200 @@ -5,7 +5,7 @@ objcopyflags-$(CONFIG_ETRAX_ARCH_V10) += -R .note -R .comment objcopyflags-$(CONFIG_ETRAX_ARCH_V32) += --remove-section=.bss --remove-section=.note.gnu.build-id @@ -707,7 +273,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/boot/Makefile linux-2.6.39/arch/cris/boot/ @cp $< $@ diff -Nur linux-2.6.39.orig/arch/cris/Kconfig linux-2.6.39/arch/cris/Kconfig --- linux-2.6.39.orig/arch/cris/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/Kconfig 2011-07-28 16:16:36.713417234 +0200 ++++ linux-2.6.39/arch/cris/Kconfig 2011-08-25 07:43:57.197980003 +0200 @@ -168,6 +168,12 @@ help Size of DRAM (decimal in MB) typically 2, 8 or 16. @@ -730,7 +296,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/Kconfig linux-2.6.39/arch/cris/Kconfig select MTD_PARTITIONS select MTD_COMPLEX_MAPPINGS help -@@ -660,6 +666,11 @@ +@@ -660,6 +666,13 @@ source "drivers/ide/Kconfig" @@ -739,10 +305,12 @@ diff -Nur linux-2.6.39.orig/arch/cris/Kconfig linux-2.6.39/arch/cris/Kconfig + +source "drivers/media/Kconfig" + ++source "drivers/misc/Kconfig" ++ source "drivers/net/Kconfig" source "drivers/i2c/Kconfig" -@@ -675,6 +686,8 @@ +@@ -675,6 +688,8 @@ source "fs/Kconfig" @@ -751,703 +319,9 @@ diff -Nur linux-2.6.39.orig/arch/cris/Kconfig linux-2.6.39/arch/cris/Kconfig source "drivers/usb/Kconfig" source "drivers/uwb/Kconfig" -diff -Nur linux-2.6.39.orig/arch/cris/Kconfig.orig linux-2.6.39/arch/cris/Kconfig.orig ---- linux-2.6.39.orig/arch/cris/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/cris/Kconfig.orig 2011-05-19 06:06:34.000000000 +0200 -@@ -0,0 +1,690 @@ -+config MMU -+ bool -+ default y -+ -+config ZONE_DMA -+ bool -+ default y -+ -+config RWSEM_GENERIC_SPINLOCK -+ bool -+ default y -+ -+config RWSEM_XCHGADD_ALGORITHM -+ bool -+ -+config GENERIC_CMOS_UPDATE -+ def_bool y -+ -+config ARCH_USES_GETTIMEOFFSET -+ def_bool n -+ -+config GENERIC_IOMAP -+ bool -+ default y -+ -+config ARCH_HAS_ILOG2_U32 -+ bool -+ default n -+ -+config ARCH_HAS_ILOG2_U64 -+ bool -+ default n -+ -+config GENERIC_FIND_NEXT_BIT -+ bool -+ default y -+ -+config GENERIC_HWEIGHT -+ bool -+ default y -+ -+config GENERIC_CALIBRATE_DELAY -+ bool -+ default y -+ -+config NO_IOPORT -+ def_bool y -+ -+config FORCE_MAX_ZONEORDER -+ int -+ default 6 -+ -+config CRIS -+ bool -+ default y -+ select HAVE_IDE -+ select HAVE_GENERIC_HARDIRQS -+ select GENERIC_IRQ_SHOW -+ -+config HZ -+ int -+ default 100 -+ -+source "init/Kconfig" -+ -+source "kernel/Kconfig.freezer" -+ -+menu "General setup" -+ -+source "fs/Kconfig.binfmt" -+ -+config ETRAX_CMDLINE -+ string "Kernel command line" -+ default "root=/dev/mtdblock3" -+ help -+ Pass additional commands to the kernel. -+ -+config ETRAX_WATCHDOG -+ bool "Enable ETRAX watchdog" -+ help -+ Enable the built-in watchdog timer support on ETRAX based embedded -+ network computers. -+ -+config ETRAX_WATCHDOG_NICE_DOGGY -+ bool "Disable watchdog during Oops printouts" -+ depends on ETRAX_WATCHDOG -+ help -+ By enabling this you make sure that the watchdog does not bite while -+ printing oopses. Recommended for development systems but not for -+ production releases. -+ -+config ETRAX_FAST_TIMER -+ bool "Enable ETRAX fast timer API" -+ help -+ This options enables the API to a fast timer implementation using -+ timer1 to get sub jiffie resolution timers (primarily one-shot -+ timers). -+ This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled. -+ -+config ETRAX_KMALLOCED_MODULES -+ bool "Enable module allocation with kmalloc" -+ help -+ Enable module allocation with kmalloc instead of vmalloc. -+ -+config OOM_REBOOT -+ bool "Enable reboot at out of memory" -+ -+source "kernel/Kconfig.preempt" -+ -+source mm/Kconfig -+ -+endmenu -+ -+menu "Hardware setup" -+ -+choice -+ prompt "Processor type" -+ default ETRAX100LX -+ -+config ETRAX100LX -+ bool "ETRAX-100LX-v1" -+ select ARCH_USES_GETTIMEOFFSET -+ help -+ Support version 1 of the ETRAX 100LX. -+ -+config ETRAX100LX_V2 -+ bool "ETRAX-100LX-v2" -+ select ARCH_USES_GETTIMEOFFSET -+ help -+ Support version 2 of the ETRAX 100LX. -+ -+config SVINTO_SIM -+ bool "ETRAX-100LX-for-xsim-simulator" -+ select ARCH_USES_GETTIMEOFFSET -+ help -+ Support the xsim ETRAX Simulator. -+ -+config ETRAXFS -+ bool "ETRAX-FS-V32" -+ help -+ Support CRIS V32. -+ -+config CRIS_MACH_ARTPEC3 -+ bool "ARTPEC-3" -+ help -+ Support Axis ARTPEC-3. -+ -+endchoice -+ -+config ETRAX_VCS_SIM -+ bool "VCS Simulator" -+ help -+ Setup hardware to be run in the VCS simulator. -+ -+config ETRAX_ARCH_V10 -+ bool -+ default y if ETRAX100LX || ETRAX100LX_V2 -+ default n if !(ETRAX100LX || ETRAX100LX_V2) -+ -+config ETRAX_ARCH_V32 -+ bool -+ default y if (ETRAXFS || CRIS_MACH_ARTPEC3) -+ default n if !(ETRAXFS || CRIS_MACH_ARTPEC3) -+ -+config ETRAX_DRAM_SIZE -+ int "DRAM size (dec, in MB)" -+ default "8" -+ help -+ Size of DRAM (decimal in MB) typically 2, 8 or 16. -+ -+config ETRAX_VMEM_SIZE -+ int "Video memory size (dec, in MB)" -+ depends on ETRAX_ARCH_V32 && !ETRAXFS -+ default 8 if !ETRAXFS -+ help -+ Size of Video accessible memory (decimal, in MB). -+ -+config ETRAX_FLASH_BUSWIDTH -+ int "Buswidth of NOR flash in bytes" -+ default "2" -+ help -+ Width in bytes of the NOR Flash bus (1, 2 or 4). Is usually 2. -+ -+config ETRAX_NANDFLASH_BUSWIDTH -+ int "Buswidth of NAND flash in bytes" -+ default "1" -+ help -+ Width in bytes of the NAND flash (1 or 2). -+ -+config ETRAX_FLASH1_SIZE -+ int "FLASH1 size (dec, in MB. 0 = Unknown)" -+ default "0" -+ -+choice -+ prompt "Product debug-port" -+ default ETRAX_DEBUG_PORT0 -+ -+config ETRAX_DEBUG_PORT0 -+ bool "Serial-0" -+ help -+ Choose a serial port for the ETRAX debug console. Default to -+ port 0. -+ -+config ETRAX_DEBUG_PORT1 -+ bool "Serial-1" -+ help -+ Use serial port 1 for the console. -+ -+config ETRAX_DEBUG_PORT2 -+ bool "Serial-2" -+ help -+ Use serial port 2 for the console. -+ -+config ETRAX_DEBUG_PORT3 -+ bool "Serial-3" -+ help -+ Use serial port 3 for the console. -+ -+config ETRAX_DEBUG_PORT_NULL -+ bool "disabled" -+ help -+ Disable serial-port debugging. -+ -+endchoice -+ -+choice -+ prompt "Kernel GDB port" -+ depends on ETRAX_KGDB -+ default ETRAX_KGDB_PORT0 -+ help -+ Choose a serial port for kernel debugging. NOTE: This port should -+ not be enabled under Drivers for built-in interfaces (as it has its -+ own initialization code) and should not be the same as the debug port. -+ -+config ETRAX_KGDB_PORT0 -+ bool "Serial-0" -+ help -+ Use serial port 0 for kernel debugging. -+ -+config ETRAX_KGDB_PORT1 -+ bool "Serial-1" -+ help -+ Use serial port 1 for kernel debugging. -+ -+config ETRAX_KGDB_PORT2 -+ bool "Serial-2" -+ help -+ Use serial port 2 for kernel debugging. -+ -+config ETRAX_KGDB_PORT3 -+ bool "Serial-3" -+ help -+ Use serial port 3 for kernel debugging. -+ -+endchoice -+ -+source arch/cris/arch-v10/Kconfig -+source arch/cris/arch-v32/Kconfig -+ -+endmenu -+ -+source "net/Kconfig" -+ -+# bring in ETRAX built-in drivers -+menu "Drivers for built-in interfaces" -+source arch/cris/arch-v10/drivers/Kconfig -+source arch/cris/arch-v32/drivers/Kconfig -+ -+config ETRAX_AXISFLASHMAP -+ bool "Axis flash-map support" -+ select MTD -+ select MTD_CFI -+ select MTD_CFI_AMDSTD -+ select MTD_JEDECPROBE if ETRAX_ARCH_V32 -+ select MTD_CHAR -+ select MTD_BLOCK -+ select MTD_PARTITIONS -+ select MTD_COMPLEX_MAPPINGS -+ help -+ This option enables MTD mapping of flash devices. Needed to use -+ flash memories. If unsure, say Y. -+ -+config ETRAX_RTC -+ bool "Real Time Clock support" -+ depends on ETRAX_I2C -+ help -+ Enables drivers for the Real-Time Clock battery-backed chips on -+ some products. The kernel reads the time when booting, and -+ the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a -+ rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc -+ device. You can check the time with cat /proc/rtc, but -+ normal time reading should be done using libc function time and -+ friends. -+ -+choice -+ prompt "RTC chip" -+ depends on ETRAX_RTC -+ default ETRAX_DS1302 -+ -+config ETRAX_DS1302 -+ depends on ETRAX_ARCH_V10 -+ bool "DS1302" -+ help -+ Enables the driver for the DS1302 Real-Time Clock battery-backed -+ chip on some products. -+ -+config ETRAX_PCF8563 -+ bool "PCF8563" -+ help -+ Enables the driver for the PCF8563 Real-Time Clock battery-backed -+ chip on some products. -+ -+endchoice -+ -+config ETRAX_SYNCHRONOUS_SERIAL -+ bool "Synchronous serial-port support" -+ help -+ Select this to enable the synchronous serial port driver. -+ -+config ETRAX_SYNCHRONOUS_SERIAL_PORT0 -+ bool "Synchronous serial port 0 enabled" -+ depends on ETRAX_SYNCHRONOUS_SERIAL -+ help -+ Enabled synchronous serial port 0. -+ -+config ETRAX_SYNCHRONOUS_SERIAL0_DMA -+ bool "Enable DMA on synchronous serial port 0." -+ depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0 -+ help -+ A synchronous serial port can run in manual or DMA mode. -+ Selecting this option will make it run in DMA mode. -+ -+config ETRAX_SYNCHRONOUS_SERIAL_PORT1 -+ bool "Synchronous serial port 1 enabled" -+ depends on ETRAX_SYNCHRONOUS_SERIAL && (ETRAXFS || ETRAX_ARCH_V10) -+ help -+ Enabled synchronous serial port 1. -+ -+config ETRAX_SYNCHRONOUS_SERIAL1_DMA -+ bool "Enable DMA on synchronous serial port 1." -+ depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1 -+ help -+ A synchronous serial port can run in manual or DMA mode. -+ Selecting this option will make it run in DMA mode. -+ -+choice -+ prompt "Network LED behavior" -+ depends on ETRAX_ETHERNET -+ default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY -+ -+config ETRAX_NETWORK_LED_ON_WHEN_LINK -+ bool "LED_on_when_link" -+ help -+ Selecting LED_on_when_link will light the LED when there is a -+ connection and will flash off when there is activity. -+ -+ Selecting LED_on_when_activity will light the LED only when -+ there is activity. -+ -+ This setting will also affect the behaviour of other activity LEDs -+ e.g. Bluetooth. -+ -+config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY -+ bool "LED_on_when_activity" -+ help -+ Selecting LED_on_when_link will light the LED when there is a -+ connection and will flash off when there is activity. -+ -+ Selecting LED_on_when_activity will light the LED only when -+ there is activity. -+ -+ This setting will also affect the behaviour of other activity LEDs -+ e.g. Bluetooth. -+ -+endchoice -+ -+choice -+ prompt "Ser0 DMA out channel" -+ depends on ETRAX_SERIAL_PORT0 -+ default ETRAX_SERIAL_PORT0_DMA6_OUT if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT0_NO_DMA_OUT if ETRAX_ARCH_V10 -+ -+config ETRAX_SERIAL_PORT0_NO_DMA_OUT -+ bool "Ser0 uses no DMA for output" -+ help -+ Do not use DMA for ser0 output. -+ -+config ETRAX_SERIAL_PORT0_DMA6_OUT -+ bool "Ser0 uses DMA6 for output" -+ depends on ETRAXFS -+ help -+ Enables the DMA6 output channel for ser0 (ttyS0). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT0_DMA0_OUT -+ bool "Ser0 uses DMA0 for output" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA0 output channel for ser0 (ttyS0). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser0 DMA in channel " -+ depends on ETRAX_SERIAL_PORT0 -+ default ETRAX_SERIAL_PORT0_NO_DMA_IN if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT0_DMA7_IN if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser0. -+ -+config ETRAX_SERIAL_PORT0_NO_DMA_IN -+ bool "Ser0 uses no DMA for input" -+ help -+ Do not use DMA for ser0 input. -+ -+config ETRAX_SERIAL_PORT0_DMA7_IN -+ bool "Ser0 uses DMA7 for input" -+ depends on ETRAXFS -+ help -+ Enables the DMA7 input channel for ser0 (ttyS0). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT0_DMA1_IN -+ bool "Ser0 uses DMA1 for input" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA1 input channel for ser0 (ttyS0). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser1 DMA in channel " -+ depends on ETRAX_SERIAL_PORT1 -+ default ETRAX_SERIAL_PORT1_NO_DMA_IN if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT1_DMA9_IN if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser1. -+ -+config ETRAX_SERIAL_PORT1_NO_DMA_IN -+ bool "Ser1 uses no DMA for input" -+ help -+ Do not use DMA for ser1 input. -+ -+config ETRAX_SERIAL_PORT1_DMA5_IN -+ bool "Ser1 uses DMA5 for input" -+ depends on ETRAX_ARCH_V32 -+ help -+ Enables the DMA5 input channel for ser1 (ttyS1). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want this on, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT1_DMA9_IN -+ depends on ETRAX_ARCH_V10 -+ bool "Ser1 uses DMA9 for input" -+ -+endchoice -+ -+ -+choice -+ prompt "Ser1 DMA out channel" -+ depends on ETRAX_SERIAL_PORT1 -+ default ETRAX_SERIAL_PORT1_NO_DMA_OUT if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT1_DMA8_OUT if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser1. -+ -+config ETRAX_SERIAL_PORT1_NO_DMA_OUT -+ bool "Ser1 uses no DMA for output" -+ help -+ Do not use DMA for ser1 output. -+ -+config ETRAX_SERIAL_PORT1_DMA8_OUT -+ depends on ETRAX_ARCH_V10 -+ bool "Ser1 uses DMA8 for output" -+ -+config ETRAX_SERIAL_PORT1_DMA4_OUT -+ depends on ETRAX_ARCH_V32 -+ bool "Ser1 uses DMA4 for output" -+ help -+ Enables the DMA4 output channel for ser1 (ttyS1). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want this on, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser2 DMA out channel" -+ depends on ETRAX_SERIAL_PORT2 -+ default ETRAX_SERIAL_PORT2_NO_DMA_OUT if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT2_DMA2_OUT if ETRAX_ARCH_V10 -+ -+config ETRAX_SERIAL_PORT2_NO_DMA_OUT -+ bool "Ser2 uses no DMA for output" -+ help -+ Do not use DMA for ser2 output. -+ -+config ETRAX_SERIAL_PORT2_DMA2_OUT -+ bool "Ser2 uses DMA2 for output" -+ depends on ETRAXFS || ETRAX_ARCH_V10 -+ help -+ Enables the DMA2 output channel for ser2 (ttyS2). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT2_DMA6_OUT -+ bool "Ser2 uses DMA6 for output" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA6 output channel for ser2 (ttyS2). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser2 DMA in channel" -+ depends on ETRAX_SERIAL_PORT2 -+ default ETRAX_SERIAL_PORT2_NO_DMA_IN if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT2_DMA3_IN if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser2. -+ -+config ETRAX_SERIAL_PORT2_NO_DMA_IN -+ bool "Ser2 uses no DMA for input" -+ help -+ Do not use DMA for ser2 input. -+ -+config ETRAX_SERIAL_PORT2_DMA3_IN -+ bool "Ser2 uses DMA3 for input" -+ depends on ETRAXFS || ETRAX_ARCH_V10 -+ help -+ Enables the DMA3 input channel for ser2 (ttyS2). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT2_DMA7_IN -+ bool "Ser2 uses DMA7 for input" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA7 input channel for ser2 (ttyS2). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser3 DMA in channel" -+ depends on ETRAX_SERIAL_PORT3 -+ default ETRAX_SERIAL_PORT3_NO_DMA_IN if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT3_DMA5_IN if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser3. -+ -+config ETRAX_SERIAL_PORT3_NO_DMA_IN -+ bool "Ser3 uses no DMA for input" -+ help -+ Do not use DMA for ser3 input. -+ -+config ETRAX_SERIAL_PORT3_DMA5_IN -+ depends on ETRAX_ARCH_V10 -+ bool "DMA 5" -+ -+config ETRAX_SERIAL_PORT3_DMA9_IN -+ bool "Ser3 uses DMA9 for input" -+ depends on ETRAXFS -+ help -+ Enables the DMA9 input channel for ser3 (ttyS3). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT3_DMA3_IN -+ bool "Ser3 uses DMA3 for input" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA3 input channel for ser3 (ttyS3). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser3 DMA out channel" -+ depends on ETRAX_SERIAL_PORT3 -+ default ETRAX_SERIAL_PORT3_NO_DMA_OUT if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT3_DMA4_OUT if ETRAX_ARCH_V10 -+ -+config ETRAX_SERIAL_PORT3_NO_DMA_OUT -+ bool "Ser3 uses no DMA for output" -+ help -+ Do not use DMA for ser3 output. -+ -+config ETRAX_SERIAL_PORT3_DMA4_OUT -+ depends on ETRAX_ARCH_V10 -+ bool "DMA 4" -+ -+config ETRAX_SERIAL_PORT3_DMA8_OUT -+ bool "Ser3 uses DMA8 for output" -+ depends on ETRAXFS -+ help -+ Enables the DMA8 output channel for ser3 (ttyS3). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT3_DMA2_OUT -+ bool "Ser3 uses DMA2 for output" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA2 output channel for ser3 (ttyS3). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+endmenu -+ -+source "drivers/base/Kconfig" -+ -+# standard linux drivers -+source "drivers/mtd/Kconfig" -+ -+source "drivers/parport/Kconfig" -+ -+source "drivers/pnp/Kconfig" -+ -+source "drivers/block/Kconfig" -+ -+source "drivers/ide/Kconfig" -+ -+source "drivers/net/Kconfig" -+ -+source "drivers/i2c/Kconfig" -+ -+source "drivers/rtc/Kconfig" -+ -+# -+# input before char - char/joystick depends on it. As does USB. -+# -+source "drivers/input/Kconfig" -+ -+source "drivers/char/Kconfig" -+ -+source "fs/Kconfig" -+ -+source "drivers/usb/Kconfig" -+ -+source "drivers/uwb/Kconfig" -+ -+source "drivers/staging/Kconfig" -+ -+source "arch/cris/Kconfig.debug" -+ -+source "security/Kconfig" -+ -+source "crypto/Kconfig" -+ -+source "lib/Kconfig" diff -Nur linux-2.6.39.orig/arch/cris/Makefile linux-2.6.39/arch/cris/Makefile --- linux-2.6.39.orig/arch/cris/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/Makefile 2011-07-28 16:16:36.883415879 +0200 ++++ linux-2.6.39/arch/cris/Makefile 2011-08-25 07:43:02.329230084 +0200 @@ -40,10 +40,10 @@ LD = $(CROSS_COMPILE)ld -mcrislinux @@ -1463,7 +337,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/Makefile linux-2.6.39/arch/cris/Makefile ifdef CONFIG_FRAME_POINTER diff -Nur linux-2.6.39.orig/arch/cris/mm/init.c linux-2.6.39/arch/cris/mm/init.c --- linux-2.6.39.orig/arch/cris/mm/init.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/mm/init.c 2011-07-28 16:16:37.013424379 +0200 ++++ linux-2.6.39/arch/cris/mm/init.c 2011-08-25 07:43:02.489240456 +0200 @@ -16,6 +16,7 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -1485,7 +359,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/mm/init.c linux-2.6.39/arch/cris/mm/init.c +#endif diff -Nur linux-2.6.39.orig/drivers/net/cris/eth_v10.c linux-2.6.39/drivers/net/cris/eth_v10.c --- linux-2.6.39.orig/drivers/net/cris/eth_v10.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/net/cris/eth_v10.c 2011-07-28 16:16:37.184155914 +0200 ++++ linux-2.6.39/drivers/net/cris/eth_v10.c 2011-08-25 07:43:02.627979938 +0200 @@ -1714,7 +1714,7 @@ static void e100_netpoll(struct net_device* netdev) @@ -1495,1762 +369,9 @@ diff -Nur linux-2.6.39.orig/drivers/net/cris/eth_v10.c linux-2.6.39/drivers/net/ } #endif -diff -Nur linux-2.6.39.orig/drivers/net/cris/eth_v10.c.orig linux-2.6.39/drivers/net/cris/eth_v10.c.orig ---- linux-2.6.39.orig/drivers/net/cris/eth_v10.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/cris/eth_v10.c.orig 2011-05-19 06:06:34.000000000 +0200 -@@ -0,0 +1,1749 @@ -+/* -+ * e100net.c: A network driver for the ETRAX 100LX network controller. -+ * -+ * Copyright (c) 1998-2002 Axis Communications AB. -+ * -+ * The outline of this driver comes from skeleton.c. -+ * -+ */ -+ -+ -+#include <linux/module.h> -+ -+#include <linux/kernel.h> -+#include <linux/delay.h> -+#include <linux/types.h> -+#include <linux/fcntl.h> -+#include <linux/interrupt.h> -+#include <linux/ptrace.h> -+#include <linux/ioport.h> -+#include <linux/in.h> -+#include <linux/string.h> -+#include <linux/spinlock.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/bitops.h> -+ -+#include <linux/if.h> -+#include <linux/mii.h> -+#include <linux/netdevice.h> -+#include <linux/etherdevice.h> -+#include <linux/skbuff.h> -+#include <linux/ethtool.h> -+ -+#include <arch/svinto.h>/* DMA and register descriptions */ -+#include <asm/io.h> /* CRIS_LED_* I/O functions */ -+#include <asm/irq.h> -+#include <asm/dma.h> -+#include <asm/system.h> -+#include <asm/ethernet.h> -+#include <asm/cache.h> -+#include <arch/io_interface_mux.h> -+ -+//#define ETHDEBUG -+#define D(x) -+ -+/* -+ * The name of the card. Is used for messages and in the requests for -+ * io regions, irqs and dma channels -+ */ -+ -+static const char* cardname = "ETRAX 100LX built-in ethernet controller"; -+ -+/* A default ethernet address. Highlevel SW will set the real one later */ -+ -+static struct sockaddr default_mac = { -+ 0, -+ { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 } -+}; -+ -+/* Information that need to be kept for each board. */ -+struct net_local { -+ struct mii_if_info mii_if; -+ -+ /* Tx control lock. This protects the transmit buffer ring -+ * state along with the "tx full" state of the driver. This -+ * means all netif_queue flow control actions are protected -+ * by this lock as well. -+ */ -+ spinlock_t lock; -+ -+ spinlock_t led_lock; /* Protect LED state */ -+ spinlock_t transceiver_lock; /* Protect transceiver state. */ -+}; -+ -+typedef struct etrax_eth_descr -+{ -+ etrax_dma_descr descr; -+ struct sk_buff* skb; -+} etrax_eth_descr; -+ -+/* Some transceivers requires special handling */ -+struct transceiver_ops -+{ -+ unsigned int oui; -+ void (*check_speed)(struct net_device* dev); -+ void (*check_duplex)(struct net_device* dev); -+}; -+ -+/* Duplex settings */ -+enum duplex -+{ -+ half, -+ full, -+ autoneg -+}; -+ -+/* Dma descriptors etc. */ -+ -+#define MAX_MEDIA_DATA_SIZE 1522 -+ -+#define MIN_PACKET_LEN 46 -+#define ETHER_HEAD_LEN 14 -+ -+/* -+** MDIO constants. -+*/ -+#define MDIO_START 0x1 -+#define MDIO_READ 0x2 -+#define MDIO_WRITE 0x1 -+#define MDIO_PREAMBLE 0xfffffffful -+ -+/* Broadcom specific */ -+#define MDIO_AUX_CTRL_STATUS_REG 0x18 -+#define MDIO_BC_FULL_DUPLEX_IND 0x1 -+#define MDIO_BC_SPEED 0x2 -+ -+/* TDK specific */ -+#define MDIO_TDK_DIAGNOSTIC_REG 18 -+#define MDIO_TDK_DIAGNOSTIC_RATE 0x400 -+#define MDIO_TDK_DIAGNOSTIC_DPLX 0x800 -+ -+/*Intel LXT972A specific*/ -+#define MDIO_INT_STATUS_REG_2 0x0011 -+#define MDIO_INT_FULL_DUPLEX_IND (1 << 9) -+#define MDIO_INT_SPEED (1 << 14) -+ -+/* Network flash constants */ -+#define NET_FLASH_TIME (HZ/50) /* 20 ms */ -+#define NET_FLASH_PAUSE (HZ/100) /* 10 ms */ -+#define NET_LINK_UP_CHECK_INTERVAL (2*HZ) /* 2 s */ -+#define NET_DUPLEX_CHECK_INTERVAL (2*HZ) /* 2 s */ -+ -+#define NO_NETWORK_ACTIVITY 0 -+#define NETWORK_ACTIVITY 1 -+ -+#define NBR_OF_RX_DESC 32 -+#define NBR_OF_TX_DESC 16 -+ -+/* Large packets are sent directly to upper layers while small packets are */ -+/* copied (to reduce memory waste). The following constant decides the breakpoint */ -+#define RX_COPYBREAK 256 -+ -+/* Due to a chip bug we need to flush the cache when descriptors are returned */ -+/* to the DMA. To decrease performance impact we return descriptors in chunks. */ -+/* The following constant determines the number of descriptors to return. */ -+#define RX_QUEUE_THRESHOLD NBR_OF_RX_DESC/2 -+ -+#define GET_BIT(bit,val) (((val) >> (bit)) & 0x01) -+ -+/* Define some macros to access ETRAX 100 registers */ -+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ -+ IO_FIELD_(reg##_, field##_, val) -+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ -+ IO_STATE_(reg##_, field##_, _##val) -+ -+static etrax_eth_descr *myNextRxDesc; /* Points to the next descriptor to -+ to be processed */ -+static etrax_eth_descr *myLastRxDesc; /* The last processed descriptor */ -+ -+static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32))); -+ -+static etrax_eth_descr* myFirstTxDesc; /* First packet not yet sent */ -+static etrax_eth_descr* myLastTxDesc; /* End of send queue */ -+static etrax_eth_descr* myNextTxDesc; /* Next descriptor to use */ -+static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32))); -+ -+static unsigned int network_rec_config_shadow = 0; -+ -+static unsigned int network_tr_ctrl_shadow = 0; -+ -+/* Network speed indication. */ -+static DEFINE_TIMER(speed_timer, NULL, 0, 0); -+static DEFINE_TIMER(clear_led_timer, NULL, 0, 0); -+static int current_speed; /* Speed read from transceiver */ -+static int current_speed_selection; /* Speed selected by user */ -+static unsigned long led_next_time; -+static int led_active; -+static int rx_queue_len; -+ -+/* Duplex */ -+static DEFINE_TIMER(duplex_timer, NULL, 0, 0); -+static int full_duplex; -+static enum duplex current_duplex; -+ -+/* Index to functions, as function prototypes. */ -+ -+static int etrax_ethernet_init(void); -+ -+static int e100_open(struct net_device *dev); -+static int e100_set_mac_address(struct net_device *dev, void *addr); -+static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); -+static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id); -+static irqreturn_t e100nw_interrupt(int irq, void *dev_id); -+static void e100_rx(struct net_device *dev); -+static int e100_close(struct net_device *dev); -+static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -+static int e100_set_config(struct net_device* dev, struct ifmap* map); -+static void e100_tx_timeout(struct net_device *dev); -+static struct net_device_stats *e100_get_stats(struct net_device *dev); -+static void set_multicast_list(struct net_device *dev); -+static void e100_hardware_send_packet(struct net_local* np, char *buf, int length); -+static void update_rx_stats(struct net_device_stats *); -+static void update_tx_stats(struct net_device_stats *); -+static int e100_probe_transceiver(struct net_device* dev); -+ -+static void e100_check_speed(unsigned long priv); -+static void e100_set_speed(struct net_device* dev, unsigned long speed); -+static void e100_check_duplex(unsigned long priv); -+static void e100_set_duplex(struct net_device* dev, enum duplex); -+static void e100_negotiate(struct net_device* dev); -+ -+static int e100_get_mdio_reg(struct net_device *dev, int phy_id, int location); -+static void e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value); -+ -+static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd); -+static void e100_send_mdio_bit(unsigned char bit); -+static unsigned char e100_receive_mdio_bit(void); -+static void e100_reset_transceiver(struct net_device* net); -+ -+static void e100_clear_network_leds(unsigned long dummy); -+static void e100_set_network_leds(int active); -+ -+static const struct ethtool_ops e100_ethtool_ops; -+#if defined(CONFIG_ETRAX_NO_PHY) -+static void dummy_check_speed(struct net_device* dev); -+static void dummy_check_duplex(struct net_device* dev); -+#else -+static void broadcom_check_speed(struct net_device* dev); -+static void broadcom_check_duplex(struct net_device* dev); -+static void tdk_check_speed(struct net_device* dev); -+static void tdk_check_duplex(struct net_device* dev); -+static void intel_check_speed(struct net_device* dev); -+static void intel_check_duplex(struct net_device* dev); -+static void generic_check_speed(struct net_device* dev); -+static void generic_check_duplex(struct net_device* dev); -+#endif -+#ifdef CONFIG_NET_POLL_CONTROLLER -+static void e100_netpoll(struct net_device* dev); -+#endif -+ -+static int autoneg_normal = 1; -+ -+struct transceiver_ops transceivers[] = -+{ -+#if defined(CONFIG_ETRAX_NO_PHY) -+ {0x0000, dummy_check_speed, dummy_check_duplex} /* Dummy */ -+#else -+ {0x1018, broadcom_check_speed, broadcom_check_duplex}, /* Broadcom */ -+ {0xC039, tdk_check_speed, tdk_check_duplex}, /* TDK 2120 */ -+ {0x039C, tdk_check_speed, tdk_check_duplex}, /* TDK 2120C */ -+ {0x04de, intel_check_speed, intel_check_duplex}, /* Intel LXT972A*/ -+ {0x0000, generic_check_speed, generic_check_duplex} /* Generic, must be last */ -+#endif -+}; -+ -+struct transceiver_ops* transceiver = &transceivers[0]; -+ -+static const struct net_device_ops e100_netdev_ops = { -+ .ndo_open = e100_open, -+ .ndo_stop = e100_close, -+ .ndo_start_xmit = e100_send_packet, -+ .ndo_tx_timeout = e100_tx_timeout, -+ .ndo_get_stats = e100_get_stats, -+ .ndo_set_multicast_list = set_multicast_list, -+ .ndo_do_ioctl = e100_ioctl, -+ .ndo_set_mac_address = e100_set_mac_address, -+ .ndo_validate_addr = eth_validate_addr, -+ .ndo_change_mtu = eth_change_mtu, -+ .ndo_set_config = e100_set_config, -+#ifdef CONFIG_NET_POLL_CONTROLLER -+ .ndo_poll_controller = e100_netpoll, -+#endif -+}; -+ -+#define tx_done(dev) (*R_DMA_CH0_CMD == 0) -+ -+/* -+ * Check for a network adaptor of this type, and return '0' if one exists. -+ * If dev->base_addr == 0, probe all likely locations. -+ * If dev->base_addr == 1, always return failure. -+ * If dev->base_addr == 2, allocate space for the device and return success -+ * (detachable devices only). -+ */ -+ -+static int __init -+etrax_ethernet_init(void) -+{ -+ struct net_device *dev; -+ struct net_local* np; -+ int i, err; -+ -+ printk(KERN_INFO -+ "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 1998-2007 Axis Communications AB\n"); -+ -+ if (cris_request_io_interface(if_eth, cardname)) { -+ printk(KERN_CRIT "etrax_ethernet_init failed to get IO interface\n"); -+ return -EBUSY; -+ } -+ -+ dev = alloc_etherdev(sizeof(struct net_local)); -+ if (!dev) -+ return -ENOMEM; -+ -+ np = netdev_priv(dev); -+ -+ /* we do our own locking */ -+ dev->features |= NETIF_F_LLTX; -+ -+ dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ -+ -+ /* now setup our etrax specific stuff */ -+ -+ dev->irq = NETWORK_DMA_RX_IRQ_NBR; /* we really use DMATX as well... */ -+ dev->dma = NETWORK_RX_DMA_NBR; -+ -+ /* fill in our handlers so the network layer can talk to us in the future */ -+ -+ dev->ethtool_ops = &e100_ethtool_ops; -+ dev->netdev_ops = &e100_netdev_ops; -+ -+ spin_lock_init(&np->lock); -+ spin_lock_init(&np->led_lock); -+ spin_lock_init(&np->transceiver_lock); -+ -+ /* Initialise the list of Etrax DMA-descriptors */ -+ -+ /* Initialise receive descriptors */ -+ -+ for (i = 0; i < NBR_OF_RX_DESC; i++) { -+ /* Allocate two extra cachelines to make sure that buffer used -+ * by DMA does not share cacheline with any other data (to -+ * avoid cache bug) -+ */ -+ RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); -+ if (!RxDescList[i].skb) -+ return -ENOMEM; -+ RxDescList[i].descr.ctrl = 0; -+ RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE; -+ RxDescList[i].descr.next = virt_to_phys(&RxDescList[i + 1]); -+ RxDescList[i].descr.buf = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data)); -+ RxDescList[i].descr.status = 0; -+ RxDescList[i].descr.hw_len = 0; -+ prepare_rx_descriptor(&RxDescList[i].descr); -+ } -+ -+ RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl = d_eol; -+ RxDescList[NBR_OF_RX_DESC - 1].descr.next = virt_to_phys(&RxDescList[0]); -+ rx_queue_len = 0; -+ -+ /* Initialize transmit descriptors */ -+ for (i = 0; i < NBR_OF_TX_DESC; i++) { -+ TxDescList[i].descr.ctrl = 0; -+ TxDescList[i].descr.sw_len = 0; -+ TxDescList[i].descr.next = virt_to_phys(&TxDescList[i + 1].descr); -+ TxDescList[i].descr.buf = 0; -+ TxDescList[i].descr.status = 0; -+ TxDescList[i].descr.hw_len = 0; -+ TxDescList[i].skb = 0; -+ } -+ -+ TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl = d_eol; -+ TxDescList[NBR_OF_TX_DESC - 1].descr.next = virt_to_phys(&TxDescList[0].descr); -+ -+ /* Initialise initial pointers */ -+ -+ myNextRxDesc = &RxDescList[0]; -+ myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; -+ myFirstTxDesc = &TxDescList[0]; -+ myNextTxDesc = &TxDescList[0]; -+ myLastTxDesc = &TxDescList[NBR_OF_TX_DESC - 1]; -+ -+ /* Register device */ -+ err = register_netdev(dev); -+ if (err) { -+ free_netdev(dev); -+ return err; -+ } -+ -+ /* set the default MAC address */ -+ -+ e100_set_mac_address(dev, &default_mac); -+ -+ /* Initialize speed indicator stuff. */ -+ -+ current_speed = 10; -+ current_speed_selection = 0; /* Auto */ -+ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; -+ speed_timer.data = (unsigned long)dev; -+ speed_timer.function = e100_check_speed; -+ -+ clear_led_timer.function = e100_clear_network_leds; -+ clear_led_timer.data = (unsigned long)dev; -+ -+ full_duplex = 0; -+ current_duplex = autoneg; -+ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; -+ duplex_timer.data = (unsigned long)dev; -+ duplex_timer.function = e100_check_duplex; -+ -+ /* Initialize mii interface */ -+ np->mii_if.phy_id_mask = 0x1f; -+ np->mii_if.reg_num_mask = 0x1f; -+ np->mii_if.dev = dev; -+ np->mii_if.mdio_read = e100_get_mdio_reg; -+ np->mii_if.mdio_write = e100_set_mdio_reg; -+ -+ /* Initialize group address registers to make sure that no */ -+ /* unwanted addresses are matched */ -+ *R_NETWORK_GA_0 = 0x00000000; -+ *R_NETWORK_GA_1 = 0x00000000; -+ -+ /* Initialize next time the led can flash */ -+ led_next_time = jiffies; -+ return 0; -+} -+ -+/* set MAC address of the interface. called from the core after a -+ * SIOCSIFADDR ioctl, and from the bootup above. -+ */ -+ -+static int -+e100_set_mac_address(struct net_device *dev, void *p) -+{ -+ struct net_local *np = netdev_priv(dev); -+ struct sockaddr *addr = p; -+ -+ spin_lock(&np->lock); /* preemption protection */ -+ -+ /* remember it */ -+ -+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); -+ -+ /* Write it to the hardware. -+ * Note the way the address is wrapped: -+ * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24); -+ * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8); -+ */ -+ -+ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | -+ (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24); -+ *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8); -+ *R_NETWORK_SA_2 = 0; -+ -+ /* show it in the log as well */ -+ -+ printk(KERN_INFO "%s: changed MAC to %pM\n", dev->name, dev->dev_addr); -+ -+ spin_unlock(&np->lock); -+ -+ return 0; -+} -+ -+/* -+ * Open/initialize the board. This is called (in the current kernel) -+ * sometime after booting when the 'ifconfig' program is run. -+ * -+ * This routine should set everything up anew at each open, even -+ * registers that "should" only need to be set once at boot, so that -+ * there is non-reboot way to recover if something goes wrong. -+ */ -+ -+static int -+e100_open(struct net_device *dev) -+{ -+ unsigned long flags; -+ -+ /* enable the MDIO output pin */ -+ -+ *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); -+ -+ *R_IRQ_MASK0_CLR = -+ IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | -+ IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | -+ IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); -+ -+ /* clear dma0 and 1 eop and descr irq masks */ -+ *R_IRQ_MASK2_CLR = -+ IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); -+ -+ /* Reset and wait for the DMA channels */ -+ -+ RESET_DMA(NETWORK_TX_DMA_NBR); -+ RESET_DMA(NETWORK_RX_DMA_NBR); -+ WAIT_DMA(NETWORK_TX_DMA_NBR); -+ WAIT_DMA(NETWORK_RX_DMA_NBR); -+ -+ /* Initialise the etrax network controller */ -+ -+ /* allocate the irq corresponding to the receiving DMA */ -+ -+ if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, -+ IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) { -+ goto grace_exit0; -+ } -+ -+ /* allocate the irq corresponding to the transmitting DMA */ -+ -+ if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0, -+ cardname, (void *)dev)) { -+ goto grace_exit1; -+ } -+ -+ /* allocate the irq corresponding to the network errors etc */ -+ -+ if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0, -+ cardname, (void *)dev)) { -+ goto grace_exit2; -+ } -+ -+ /* -+ * Always allocate the DMA channels after the IRQ, -+ * and clean up on failure. -+ */ -+ -+ if (cris_request_dma(NETWORK_TX_DMA_NBR, -+ cardname, -+ DMA_VERBOSE_ON_ERROR, -+ dma_eth)) { -+ goto grace_exit3; -+ } -+ -+ if (cris_request_dma(NETWORK_RX_DMA_NBR, -+ cardname, -+ DMA_VERBOSE_ON_ERROR, -+ dma_eth)) { -+ goto grace_exit4; -+ } -+ -+ /* give the HW an idea of what MAC address we want */ -+ -+ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | -+ (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24); -+ *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8); -+ *R_NETWORK_SA_2 = 0; -+ -+#if 0 -+ /* use promiscuous mode for testing */ -+ *R_NETWORK_GA_0 = 0xffffffff; -+ *R_NETWORK_GA_1 = 0xffffffff; -+ -+ *R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */ -+#else -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, max_size, size1522); -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive); -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable); -+ SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+#endif -+ -+ *R_NETWORK_GEN_CONFIG = -+ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | -+ IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); -+ -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, delay, none); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cancel, dont); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cd, enable); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, retry, enable); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, pad, enable); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable); -+ *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; -+ -+ local_irq_save(flags); -+ -+ /* enable the irq's for ethernet DMA */ -+ -+ *R_IRQ_MASK2_SET = -+ IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) | -+ IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); -+ -+ *R_IRQ_MASK0_SET = -+ IO_STATE(R_IRQ_MASK0_SET, overrun, set) | -+ IO_STATE(R_IRQ_MASK0_SET, underrun, set) | -+ IO_STATE(R_IRQ_MASK0_SET, excessive_col, set); -+ -+ /* make sure the irqs are cleared */ -+ -+ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); -+ *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); -+ -+ /* make sure the rec and transmit error counters are cleared */ -+ -+ (void)*R_REC_COUNTERS; /* dummy read */ -+ (void)*R_TR_COUNTERS; /* dummy read */ -+ -+ /* start the receiving DMA channel so we can receive packets from now on */ -+ -+ *R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc); -+ *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start); -+ -+ /* Set up transmit DMA channel so it can be restarted later */ -+ -+ *R_DMA_CH0_FIRST = 0; -+ *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); -+ netif_start_queue(dev); -+ -+ local_irq_restore(flags); -+ -+ /* Probe for transceiver */ -+ if (e100_probe_transceiver(dev)) -+ goto grace_exit5; -+ -+ /* Start duplex/speed timers */ -+ add_timer(&speed_timer); -+ add_timer(&duplex_timer); -+ -+ /* We are now ready to accept transmit requeusts from -+ * the queueing layer of the networking. -+ */ -+ netif_carrier_on(dev); -+ -+ return 0; -+ -+grace_exit5: -+ cris_free_dma(NETWORK_RX_DMA_NBR, cardname); -+grace_exit4: -+ cris_free_dma(NETWORK_TX_DMA_NBR, cardname); -+grace_exit3: -+ free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); -+grace_exit2: -+ free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); -+grace_exit1: -+ free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); -+grace_exit0: -+ return -EAGAIN; -+} -+ -+#if defined(CONFIG_ETRAX_NO_PHY) -+static void -+dummy_check_speed(struct net_device* dev) -+{ -+ current_speed = 100; -+} -+#else -+static void -+generic_check_speed(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE); -+ if ((data & ADVERTISE_100FULL) || -+ (data & ADVERTISE_100HALF)) -+ current_speed = 100; -+ else -+ current_speed = 10; -+} -+ -+static void -+tdk_check_speed(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_TDK_DIAGNOSTIC_REG); -+ current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10); -+} -+ -+static void -+broadcom_check_speed(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_AUX_CTRL_STATUS_REG); -+ current_speed = (data & MDIO_BC_SPEED ? 100 : 10); -+} -+ -+static void -+intel_check_speed(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_INT_STATUS_REG_2); -+ current_speed = (data & MDIO_INT_SPEED ? 100 : 10); -+} -+#endif -+static void -+e100_check_speed(unsigned long priv) -+{ -+ struct net_device* dev = (struct net_device*)priv; -+ struct net_local *np = netdev_priv(dev); -+ static int led_initiated = 0; -+ unsigned long data; -+ int old_speed = current_speed; -+ -+ spin_lock(&np->transceiver_lock); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMSR); -+ if (!(data & BMSR_LSTATUS)) { -+ current_speed = 0; -+ } else { -+ transceiver->check_speed(dev); -+ } -+ -+ spin_lock(&np->led_lock); -+ if ((old_speed != current_speed) || !led_initiated) { -+ led_initiated = 1; -+ e100_set_network_leds(NO_NETWORK_ACTIVITY); -+ if (current_speed) -+ netif_carrier_on(dev); -+ else -+ netif_carrier_off(dev); -+ } -+ spin_unlock(&np->led_lock); -+ -+ /* Reinitialize the timer. */ -+ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; -+ add_timer(&speed_timer); -+ -+ spin_unlock(&np->transceiver_lock); -+} -+ -+static void -+e100_negotiate(struct net_device* dev) -+{ -+ struct net_local *np = netdev_priv(dev); -+ unsigned short data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MII_ADVERTISE); -+ -+ /* Discard old speed and duplex settings */ -+ data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL | -+ ADVERTISE_10HALF | ADVERTISE_10FULL); -+ -+ switch (current_speed_selection) { -+ case 10: -+ if (current_duplex == full) -+ data |= ADVERTISE_10FULL; -+ else if (current_duplex == half) -+ data |= ADVERTISE_10HALF; -+ else -+ data |= ADVERTISE_10HALF | ADVERTISE_10FULL; -+ break; -+ -+ case 100: -+ if (current_duplex == full) -+ data |= ADVERTISE_100FULL; -+ else if (current_duplex == half) -+ data |= ADVERTISE_100HALF; -+ else -+ data |= ADVERTISE_100HALF | ADVERTISE_100FULL; -+ break; -+ -+ case 0: /* Auto */ -+ if (current_duplex == full) -+ data |= ADVERTISE_100FULL | ADVERTISE_10FULL; -+ else if (current_duplex == half) -+ data |= ADVERTISE_100HALF | ADVERTISE_10HALF; -+ else -+ data |= ADVERTISE_10HALF | ADVERTISE_10FULL | -+ ADVERTISE_100HALF | ADVERTISE_100FULL; -+ break; -+ -+ default: /* assume autoneg speed and duplex */ -+ data |= ADVERTISE_10HALF | ADVERTISE_10FULL | -+ ADVERTISE_100HALF | ADVERTISE_100FULL; -+ break; -+ } -+ -+ e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE, data); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR); -+ if (autoneg_normal) { -+ /* Renegotiate with link partner */ -+ data |= BMCR_ANENABLE | BMCR_ANRESTART; -+ } else { -+ /* Don't negotiate speed or duplex */ -+ data &= ~(BMCR_ANENABLE | BMCR_ANRESTART); -+ -+ /* Set speed and duplex static */ -+ if (current_speed_selection == 10) -+ data &= ~BMCR_SPEED100; -+ else -+ data |= BMCR_SPEED100; -+ -+ if (current_duplex != full) -+ data &= ~BMCR_FULLDPLX; -+ else -+ data |= BMCR_FULLDPLX; -+ } -+ e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR, data); -+} -+ -+static void -+e100_set_speed(struct net_device* dev, unsigned long speed) -+{ -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->transceiver_lock); -+ if (speed != current_speed_selection) { -+ current_speed_selection = speed; -+ e100_negotiate(dev); -+ } -+ spin_unlock(&np->transceiver_lock); -+} -+ -+static void -+e100_check_duplex(unsigned long priv) -+{ -+ struct net_device *dev = (struct net_device *)priv; -+ struct net_local *np = netdev_priv(dev); -+ int old_duplex; -+ -+ spin_lock(&np->transceiver_lock); -+ old_duplex = full_duplex; -+ transceiver->check_duplex(dev); -+ if (old_duplex != full_duplex) { -+ /* Duplex changed */ -+ SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } -+ -+ /* Reinitialize the timer. */ -+ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; -+ add_timer(&duplex_timer); -+ np->mii_if.full_duplex = full_duplex; -+ spin_unlock(&np->transceiver_lock); -+} -+#if defined(CONFIG_ETRAX_NO_PHY) -+static void -+dummy_check_duplex(struct net_device* dev) -+{ -+ full_duplex = 1; -+} -+#else -+static void -+generic_check_duplex(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE); -+ if ((data & ADVERTISE_10FULL) || -+ (data & ADVERTISE_100FULL)) -+ full_duplex = 1; -+ else -+ full_duplex = 0; -+} -+ -+static void -+tdk_check_duplex(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_TDK_DIAGNOSTIC_REG); -+ full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0; -+} -+ -+static void -+broadcom_check_duplex(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_AUX_CTRL_STATUS_REG); -+ full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0; -+} -+ -+static void -+intel_check_duplex(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_INT_STATUS_REG_2); -+ full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0; -+} -+#endif -+static void -+e100_set_duplex(struct net_device* dev, enum duplex new_duplex) -+{ -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->transceiver_lock); -+ if (new_duplex != current_duplex) { -+ current_duplex = new_duplex; -+ e100_negotiate(dev); -+ } -+ spin_unlock(&np->transceiver_lock); -+} -+ -+static int -+e100_probe_transceiver(struct net_device* dev) -+{ -+ int ret = 0; -+ -+#if !defined(CONFIG_ETRAX_NO_PHY) -+ unsigned int phyid_high; -+ unsigned int phyid_low; -+ unsigned int oui; -+ struct transceiver_ops* ops = NULL; -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->transceiver_lock); -+ -+ /* Probe MDIO physical address */ -+ for (np->mii_if.phy_id = 0; np->mii_if.phy_id <= 31; -+ np->mii_if.phy_id++) { -+ if (e100_get_mdio_reg(dev, -+ np->mii_if.phy_id, MII_BMSR) != 0xffff) -+ break; -+ } -+ if (np->mii_if.phy_id == 32) { -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ /* Get manufacturer */ -+ phyid_high = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID1); -+ phyid_low = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID2); -+ oui = (phyid_high << 6) | (phyid_low >> 10); -+ -+ for (ops = &transceivers[0]; ops->oui; ops++) { -+ if (ops->oui == oui) -+ break; -+ } -+ transceiver = ops; -+out: -+ spin_unlock(&np->transceiver_lock); -+#endif -+ return ret; -+} -+ -+static int -+e100_get_mdio_reg(struct net_device *dev, int phy_id, int location) -+{ -+ unsigned short cmd; /* Data to be sent on MDIO port */ -+ int data; /* Data read from MDIO */ -+ int bitCounter; -+ -+ /* Start of frame, OP Code, Physical Address, Register Address */ -+ cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (phy_id << 7) | -+ (location << 2); -+ -+ e100_send_mdio_cmd(cmd, 0); -+ -+ data = 0; -+ -+ /* Data... */ -+ for (bitCounter=15; bitCounter>=0 ; bitCounter--) { -+ data |= (e100_receive_mdio_bit() << bitCounter); -+ } -+ -+ return data; -+} -+ -+static void -+e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value) -+{ -+ int bitCounter; -+ unsigned short cmd; -+ -+ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (phy_id << 7) | -+ (location << 2); -+ -+ e100_send_mdio_cmd(cmd, 1); -+ -+ /* Data... */ -+ for (bitCounter=15; bitCounter>=0 ; bitCounter--) { -+ e100_send_mdio_bit(GET_BIT(bitCounter, value)); -+ } -+ -+} -+ -+static void -+e100_send_mdio_cmd(unsigned short cmd, int write_cmd) -+{ -+ int bitCounter; -+ unsigned char data = 0x2; -+ -+ /* Preamble */ -+ for (bitCounter = 31; bitCounter>= 0; bitCounter--) -+ e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE)); -+ -+ for (bitCounter = 15; bitCounter >= 2; bitCounter--) -+ e100_send_mdio_bit(GET_BIT(bitCounter, cmd)); -+ -+ /* Turnaround */ -+ for (bitCounter = 1; bitCounter >= 0 ; bitCounter--) -+ if (write_cmd) -+ e100_send_mdio_bit(GET_BIT(bitCounter, data)); -+ else -+ e100_receive_mdio_bit(); -+} -+ -+static void -+e100_send_mdio_bit(unsigned char bit) -+{ -+ *R_NETWORK_MGM_CTRL = -+ IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | -+ IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); -+ udelay(1); -+ *R_NETWORK_MGM_CTRL = -+ IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | -+ IO_MASK(R_NETWORK_MGM_CTRL, mdck) | -+ IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); -+ udelay(1); -+} -+ -+static unsigned char -+e100_receive_mdio_bit() -+{ -+ unsigned char bit; -+ *R_NETWORK_MGM_CTRL = 0; -+ bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT); -+ udelay(1); -+ *R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck); -+ udelay(1); -+ return bit; -+} -+ -+static void -+e100_reset_transceiver(struct net_device* dev) -+{ -+ struct net_local *np = netdev_priv(dev); -+ unsigned short cmd; -+ unsigned short data; -+ int bitCounter; -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR); -+ -+ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (np->mii_if.phy_id << 7) | (MII_BMCR << 2); -+ -+ e100_send_mdio_cmd(cmd, 1); -+ -+ data |= 0x8000; -+ -+ for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) { -+ e100_send_mdio_bit(GET_BIT(bitCounter, data)); -+ } -+} -+ -+/* Called by upper layers if they decide it took too long to complete -+ * sending a packet - we need to reset and stuff. -+ */ -+ -+static void -+e100_tx_timeout(struct net_device *dev) -+{ -+ struct net_local *np = netdev_priv(dev); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&np->lock, flags); -+ -+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, -+ tx_done(dev) ? "IRQ problem" : "network cable problem"); -+ -+ /* remember we got an error */ -+ -+ dev->stats.tx_errors++; -+ -+ /* reset the TX DMA in case it has hung on something */ -+ -+ RESET_DMA(NETWORK_TX_DMA_NBR); -+ WAIT_DMA(NETWORK_TX_DMA_NBR); -+ -+ /* Reset the transceiver. */ -+ -+ e100_reset_transceiver(dev); -+ -+ /* and get rid of the packets that never got an interrupt */ -+ while (myFirstTxDesc != myNextTxDesc) { -+ dev_kfree_skb(myFirstTxDesc->skb); -+ myFirstTxDesc->skb = 0; -+ myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); -+ } -+ -+ /* Set up transmit DMA channel so it can be restarted later */ -+ *R_DMA_CH0_FIRST = 0; -+ *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); -+ -+ /* tell the upper layers we're ok again */ -+ -+ netif_wake_queue(dev); -+ spin_unlock_irqrestore(&np->lock, flags); -+} -+ -+ -+/* This will only be invoked if the driver is _not_ in XOFF state. -+ * What this means is that we need not check it, and that this -+ * invariant will hold if we make sure that the netif_*_queue() -+ * calls are done at the proper times. -+ */ -+ -+static int -+e100_send_packet(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct net_local *np = netdev_priv(dev); -+ unsigned char *buf = skb->data; -+ unsigned long flags; -+ -+#ifdef ETHDEBUG -+ printk("send packet len %d\n", length); -+#endif -+ spin_lock_irqsave(&np->lock, flags); /* protect from tx_interrupt and ourself */ -+ -+ myNextTxDesc->skb = skb; -+ -+ dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ -+ -+ e100_hardware_send_packet(np, buf, skb->len); -+ -+ myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next); -+ -+ /* Stop queue if full */ -+ if (myNextTxDesc == myFirstTxDesc) { -+ netif_stop_queue(dev); -+ } -+ -+ spin_unlock_irqrestore(&np->lock, flags); -+ -+ return NETDEV_TX_OK; -+} -+ -+/* -+ * The typical workload of the driver: -+ * Handle the network interface interrupts. -+ */ -+ -+static irqreturn_t -+e100rxtx_interrupt(int irq, void *dev_id) -+{ -+ struct net_device *dev = (struct net_device *)dev_id; -+ struct net_local *np = netdev_priv(dev); -+ unsigned long irqbits; -+ -+ /* -+ * Note that both rx and tx interrupts are blocked at this point, -+ * regardless of which got us here. -+ */ -+ -+ irqbits = *R_IRQ_MASK2_RD; -+ -+ /* Handle received packets */ -+ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { -+ /* acknowledge the eop interrupt */ -+ -+ *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); -+ -+ /* check if one or more complete packets were indeed received */ -+ -+ while ((*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) && -+ (myNextRxDesc != myLastRxDesc)) { -+ /* Take out the buffer and give it to the OS, then -+ * allocate a new buffer to put a packet in. -+ */ -+ e100_rx(dev); -+ dev->stats.rx_packets++; -+ /* restart/continue on the channel, for safety */ -+ *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart); -+ /* clear dma channel 1 eop/descr irq bits */ -+ *R_DMA_CH1_CLR_INTR = -+ IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | -+ IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do); -+ -+ /* now, we might have gotten another packet -+ so we have to loop back and check if so */ -+ } -+ } -+ -+ /* Report any packets that have been sent */ -+ while (virt_to_phys(myFirstTxDesc) != *R_DMA_CH0_FIRST && -+ (netif_queue_stopped(dev) || myFirstTxDesc != myNextTxDesc)) { -+ dev->stats.tx_bytes += myFirstTxDesc->skb->len; -+ dev->stats.tx_packets++; -+ -+ /* dma is ready with the transmission of the data in tx_skb, so now -+ we can release the skb memory */ -+ dev_kfree_skb_irq(myFirstTxDesc->skb); -+ myFirstTxDesc->skb = 0; -+ myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); -+ /* Wake up queue. */ -+ netif_wake_queue(dev); -+ } -+ -+ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { -+ /* acknowledge the eop interrupt. */ -+ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t -+e100nw_interrupt(int irq, void *dev_id) -+{ -+ struct net_device *dev = (struct net_device *)dev_id; -+ unsigned long irqbits = *R_IRQ_MASK0_RD; -+ -+ /* check for underrun irq */ -+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); -+ *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop); -+ dev->stats.tx_errors++; -+ D(printk("ethernet receiver underrun!\n")); -+ } -+ -+ /* check for overrun irq */ -+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { -+ update_rx_stats(&dev->stats); /* this will ack the irq */ -+ D(printk("ethernet receiver overrun!\n")); -+ } -+ /* check for excessive collision irq */ -+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); -+ *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop); -+ dev->stats.tx_errors++; -+ D(printk("ethernet excessive collisions!\n")); -+ } -+ return IRQ_HANDLED; -+} -+ -+/* We have a good packet(s), get it/them out of the buffers. */ -+static void -+e100_rx(struct net_device *dev) -+{ -+ struct sk_buff *skb; -+ int length = 0; -+ struct net_local *np = netdev_priv(dev); -+ unsigned char *skb_data_ptr; -+#ifdef ETHDEBUG -+ int i; -+#endif -+ etrax_eth_descr *prevRxDesc; /* The descriptor right before myNextRxDesc */ -+ spin_lock(&np->led_lock); -+ if (!led_active && time_after(jiffies, led_next_time)) { -+ /* light the network leds depending on the current speed. */ -+ e100_set_network_leds(NETWORK_ACTIVITY); -+ -+ /* Set the earliest time we may clear the LED */ -+ led_next_time = jiffies + NET_FLASH_TIME; -+ led_active = 1; -+ mod_timer(&clear_led_timer, jiffies + HZ/10); -+ } -+ spin_unlock(&np->led_lock); -+ -+ length = myNextRxDesc->descr.hw_len - 4; -+ dev->stats.rx_bytes += length; -+ -+#ifdef ETHDEBUG -+ printk("Got a packet of length %d:\n", length); -+ /* dump the first bytes in the packet */ -+ skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf); -+ for (i = 0; i < 8; i++) { -+ printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, -+ skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], -+ skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]); -+ skb_data_ptr += 8; -+ } -+#endif -+ -+ if (length < RX_COPYBREAK) { -+ /* Small packet, copy data */ -+ skb = dev_alloc_skb(length - ETHER_HEAD_LEN); -+ if (!skb) { -+ dev->stats.rx_errors++; -+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); -+ goto update_nextrxdesc; -+ } -+ -+ skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ -+ skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ -+ -+#ifdef ETHDEBUG -+ printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", -+ skb->head, skb->data, skb_tail_pointer(skb), -+ skb_end_pointer(skb)); -+ printk("copying packet to 0x%x.\n", skb_data_ptr); -+#endif -+ -+ memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length); -+ } -+ else { -+ /* Large packet, send directly to upper layers and allocate new -+ * memory (aligned to cache line boundary to avoid bug). -+ * Before sending the skb to upper layers we must make sure -+ * that skb->data points to the aligned start of the packet. -+ */ -+ int align; -+ struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); -+ if (!new_skb) { -+ dev->stats.rx_errors++; -+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); -+ goto update_nextrxdesc; -+ } -+ skb = myNextRxDesc->skb; -+ align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data; -+ skb_put(skb, length + align); -+ skb_pull(skb, align); /* Remove alignment bytes */ -+ myNextRxDesc->skb = new_skb; -+ myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data)); -+ } -+ -+ skb->protocol = eth_type_trans(skb, dev); -+ -+ /* Send the packet to the upper layers */ -+ netif_rx(skb); -+ -+ update_nextrxdesc: -+ /* Prepare for next packet */ -+ myNextRxDesc->descr.status = 0; -+ prevRxDesc = myNextRxDesc; -+ myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next); -+ -+ rx_queue_len++; -+ -+ /* Check if descriptors should be returned */ -+ if (rx_queue_len == RX_QUEUE_THRESHOLD) { -+ flush_etrax_cache(); -+ prevRxDesc->descr.ctrl |= d_eol; -+ myLastRxDesc->descr.ctrl &= ~d_eol; -+ myLastRxDesc = prevRxDesc; -+ rx_queue_len = 0; -+ } -+} -+ -+/* The inverse routine to net_open(). */ -+static int -+e100_close(struct net_device *dev) -+{ -+ printk(KERN_INFO "Closing %s.\n", dev->name); -+ -+ netif_stop_queue(dev); -+ -+ *R_IRQ_MASK0_CLR = -+ IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | -+ IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | -+ IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); -+ -+ *R_IRQ_MASK2_CLR = -+ IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); -+ -+ /* Stop the receiver and the transmitter */ -+ -+ RESET_DMA(NETWORK_TX_DMA_NBR); -+ RESET_DMA(NETWORK_RX_DMA_NBR); -+ -+ /* Flush the Tx and disable Rx here. */ -+ -+ free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); -+ free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); -+ free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); -+ -+ cris_free_dma(NETWORK_TX_DMA_NBR, cardname); -+ cris_free_dma(NETWORK_RX_DMA_NBR, cardname); -+ -+ /* Update the statistics here. */ -+ -+ update_rx_stats(&dev->stats); -+ update_tx_stats(&dev->stats); -+ -+ /* Stop speed/duplex timers */ -+ del_timer(&speed_timer); -+ del_timer(&duplex_timer); -+ -+ return 0; -+} -+ -+static int -+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -+{ -+ struct mii_ioctl_data *data = if_mii(ifr); -+ struct net_local *np = netdev_priv(dev); -+ int rc = 0; -+ int old_autoneg; -+ -+ spin_lock(&np->lock); /* Preempt protection */ -+ switch (cmd) { -+ /* The ioctls below should be considered obsolete but are */ -+ /* still present for compatibility with old scripts/apps */ -+ case SET_ETH_SPEED_10: /* 10 Mbps */ -+ e100_set_speed(dev, 10); -+ break; -+ case SET_ETH_SPEED_100: /* 100 Mbps */ -+ e100_set_speed(dev, 100); -+ break; -+ case SET_ETH_SPEED_AUTO: /* Auto-negotiate speed */ -+ e100_set_speed(dev, 0); -+ break; -+ case SET_ETH_DUPLEX_HALF: /* Half duplex */ -+ e100_set_duplex(dev, half); -+ break; -+ case SET_ETH_DUPLEX_FULL: /* Full duplex */ -+ e100_set_duplex(dev, full); -+ break; -+ case SET_ETH_DUPLEX_AUTO: /* Auto-negotiate duplex */ -+ e100_set_duplex(dev, autoneg); -+ break; -+ case SET_ETH_AUTONEG: -+ old_autoneg = autoneg_normal; -+ autoneg_normal = *(int*)data; -+ if (autoneg_normal != old_autoneg) -+ e100_negotiate(dev); -+ break; -+ default: -+ rc = generic_mii_ioctl(&np->mii_if, if_mii(ifr), -+ cmd, NULL); -+ break; -+ } -+ spin_unlock(&np->lock); -+ return rc; -+} -+ -+static int e100_get_settings(struct net_device *dev, -+ struct ethtool_cmd *cmd) -+{ -+ struct net_local *np = netdev_priv(dev); -+ int err; -+ -+ spin_lock_irq(&np->lock); -+ err = mii_ethtool_gset(&np->mii_if, cmd); -+ spin_unlock_irq(&np->lock); -+ -+ /* The PHY may support 1000baseT, but the Etrax100 does not. */ -+ cmd->supported &= ~(SUPPORTED_1000baseT_Half -+ | SUPPORTED_1000baseT_Full); -+ return err; -+} -+ -+static int e100_set_settings(struct net_device *dev, -+ struct ethtool_cmd *ecmd) -+{ -+ if (ecmd->autoneg == AUTONEG_ENABLE) { -+ e100_set_duplex(dev, autoneg); -+ e100_set_speed(dev, 0); -+ } else { -+ e100_set_duplex(dev, ecmd->duplex == DUPLEX_HALF ? half : full); -+ e100_set_speed(dev, ecmd->speed == SPEED_10 ? 10: 100); -+ } -+ -+ return 0; -+} -+ -+static void e100_get_drvinfo(struct net_device *dev, -+ struct ethtool_drvinfo *info) -+{ -+ strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1); -+ strncpy(info->version, "$Revision: 1.31 $", sizeof(info->version) - 1); -+ strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1); -+ strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1); -+} -+ -+static int e100_nway_reset(struct net_device *dev) -+{ -+ if (current_duplex == autoneg && current_speed_selection == 0) -+ e100_negotiate(dev); -+ return 0; -+} -+ -+static const struct ethtool_ops e100_ethtool_ops = { -+ .get_settings = e100_get_settings, -+ .set_settings = e100_set_settings, -+ .get_drvinfo = e100_get_drvinfo, -+ .nway_reset = e100_nway_reset, -+ .get_link = ethtool_op_get_link, -+}; -+ -+static int -+e100_set_config(struct net_device *dev, struct ifmap *map) -+{ -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->lock); /* Preempt protection */ -+ -+ switch(map->port) { -+ case IF_PORT_UNKNOWN: -+ /* Use autoneg */ -+ e100_set_speed(dev, 0); -+ e100_set_duplex(dev, autoneg); -+ break; -+ case IF_PORT_10BASET: -+ e100_set_speed(dev, 10); -+ e100_set_duplex(dev, autoneg); -+ break; -+ case IF_PORT_100BASET: -+ case IF_PORT_100BASETX: -+ e100_set_speed(dev, 100); -+ e100_set_duplex(dev, autoneg); -+ break; -+ case IF_PORT_100BASEFX: -+ case IF_PORT_10BASE2: -+ case IF_PORT_AUI: -+ spin_unlock(&np->lock); -+ return -EOPNOTSUPP; -+ break; -+ default: -+ printk(KERN_ERR "%s: Invalid media selected", dev->name); -+ spin_unlock(&np->lock); -+ return -EINVAL; -+ } -+ spin_unlock(&np->lock); -+ return 0; -+} -+ -+static void -+update_rx_stats(struct net_device_stats *es) -+{ -+ unsigned long r = *R_REC_COUNTERS; -+ /* update stats relevant to reception errors */ -+ es->rx_fifo_errors += IO_EXTRACT(R_REC_COUNTERS, congestion, r); -+ es->rx_crc_errors += IO_EXTRACT(R_REC_COUNTERS, crc_error, r); -+ es->rx_frame_errors += IO_EXTRACT(R_REC_COUNTERS, alignment_error, r); -+ es->rx_length_errors += IO_EXTRACT(R_REC_COUNTERS, oversize, r); -+} -+ -+static void -+update_tx_stats(struct net_device_stats *es) -+{ -+ unsigned long r = *R_TR_COUNTERS; -+ /* update stats relevant to transmission errors */ -+ es->collisions += -+ IO_EXTRACT(R_TR_COUNTERS, single_col, r) + -+ IO_EXTRACT(R_TR_COUNTERS, multiple_col, r); -+} -+ -+/* -+ * Get the current statistics. -+ * This may be called with the card open or closed. -+ */ -+static struct net_device_stats * -+e100_get_stats(struct net_device *dev) -+{ -+ struct net_local *lp = netdev_priv(dev); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&lp->lock, flags); -+ -+ update_rx_stats(&dev->stats); -+ update_tx_stats(&dev->stats); -+ -+ spin_unlock_irqrestore(&lp->lock, flags); -+ return &dev->stats; -+} -+ -+/* -+ * Set or clear the multicast filter for this adaptor. -+ * num_addrs == -1 Promiscuous mode, receive all packets -+ * num_addrs == 0 Normal mode, clear multicast list -+ * num_addrs > 0 Multicast mode, receive normal and MC packets, -+ * and do best-effort filtering. -+ */ -+static void -+set_multicast_list(struct net_device *dev) -+{ -+ struct net_local *lp = netdev_priv(dev); -+ int num_addr = netdev_mc_count(dev); -+ unsigned long int lo_bits; -+ unsigned long int hi_bits; -+ -+ spin_lock(&lp->lock); -+ if (dev->flags & IFF_PROMISC) { -+ /* promiscuous mode */ -+ lo_bits = 0xfffffffful; -+ hi_bits = 0xfffffffful; -+ -+ /* Enable individual receive */ -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } else if (dev->flags & IFF_ALLMULTI) { -+ /* enable all multicasts */ -+ lo_bits = 0xfffffffful; -+ hi_bits = 0xfffffffful; -+ -+ /* Disable individual receive */ -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } else if (num_addr == 0) { -+ /* Normal, clear the mc list */ -+ lo_bits = 0x00000000ul; -+ hi_bits = 0x00000000ul; -+ -+ /* Disable individual receive */ -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } else { -+ /* MC mode, receive normal and MC packets */ -+ char hash_ix; -+ struct netdev_hw_addr *ha; -+ char *baddr; -+ -+ lo_bits = 0x00000000ul; -+ hi_bits = 0x00000000ul; -+ netdev_for_each_mc_addr(ha, dev) { -+ /* Calculate the hash index for the GA registers */ -+ -+ hash_ix = 0; -+ baddr = ha->addr; -+ hash_ix ^= (*baddr) & 0x3f; -+ hash_ix ^= ((*baddr) >> 6) & 0x03; -+ ++baddr; -+ hash_ix ^= ((*baddr) << 2) & 0x03c; -+ hash_ix ^= ((*baddr) >> 4) & 0xf; -+ ++baddr; -+ hash_ix ^= ((*baddr) << 4) & 0x30; -+ hash_ix ^= ((*baddr) >> 2) & 0x3f; -+ ++baddr; -+ hash_ix ^= (*baddr) & 0x3f; -+ hash_ix ^= ((*baddr) >> 6) & 0x03; -+ ++baddr; -+ hash_ix ^= ((*baddr) << 2) & 0x03c; -+ hash_ix ^= ((*baddr) >> 4) & 0xf; -+ ++baddr; -+ hash_ix ^= ((*baddr) << 4) & 0x30; -+ hash_ix ^= ((*baddr) >> 2) & 0x3f; -+ -+ hash_ix &= 0x3f; -+ -+ if (hash_ix >= 32) { -+ hi_bits |= (1 << (hash_ix-32)); -+ } else { -+ lo_bits |= (1 << hash_ix); -+ } -+ } -+ /* Disable individual receive */ -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } -+ *R_NETWORK_GA_0 = lo_bits; -+ *R_NETWORK_GA_1 = hi_bits; -+ spin_unlock(&lp->lock); -+} -+ -+void -+e100_hardware_send_packet(struct net_local *np, char *buf, int length) -+{ -+ D(printk("e100 send pack, buf 0x%x len %d\n", buf, length)); -+ -+ spin_lock(&np->led_lock); -+ if (!led_active && time_after(jiffies, led_next_time)) { -+ /* light the network leds depending on the current speed. */ -+ e100_set_network_leds(NETWORK_ACTIVITY); -+ -+ /* Set the earliest time we may clear the LED */ -+ led_next_time = jiffies + NET_FLASH_TIME; -+ led_active = 1; -+ mod_timer(&clear_led_timer, jiffies + HZ/10); -+ } -+ spin_unlock(&np->led_lock); -+ -+ /* configure the tx dma descriptor */ -+ myNextTxDesc->descr.sw_len = length; -+ myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait; -+ myNextTxDesc->descr.buf = virt_to_phys(buf); -+ -+ /* Move end of list */ -+ myLastTxDesc->descr.ctrl &= ~d_eol; -+ myLastTxDesc = myNextTxDesc; -+ -+ /* Restart DMA channel */ -+ *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart); -+} -+ -+static void -+e100_clear_network_leds(unsigned long dummy) -+{ -+ struct net_device *dev = (struct net_device *)dummy; -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->led_lock); -+ -+ if (led_active && time_after(jiffies, led_next_time)) { -+ e100_set_network_leds(NO_NETWORK_ACTIVITY); -+ -+ /* Set the earliest time we may set the LED */ -+ led_next_time = jiffies + NET_FLASH_PAUSE; -+ led_active = 0; -+ } -+ -+ spin_unlock(&np->led_lock); -+} -+ -+static void -+e100_set_network_leds(int active) -+{ -+#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) -+ int light_leds = (active == NO_NETWORK_ACTIVITY); -+#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) -+ int light_leds = (active == NETWORK_ACTIVITY); -+#else -+#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" -+#endif -+ -+ if (!current_speed) { -+ /* Make LED red, link is down */ -+ CRIS_LED_NETWORK_SET(CRIS_LED_OFF); -+ } else if (light_leds) { -+ if (current_speed == 10) { -+ CRIS_LED_NETWORK_SET(CRIS_LED_ORANGE); -+ } else { -+ CRIS_LED_NETWORK_SET(CRIS_LED_GREEN); -+ } -+ } else { -+ CRIS_LED_NETWORK_SET(CRIS_LED_OFF); -+ } -+} -+ -+#ifdef CONFIG_NET_POLL_CONTROLLER -+static void -+e100_netpoll(struct net_device* netdev) -+{ -+ e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL); -+} -+#endif -+ -+static int -+etrax_init_module(void) -+{ -+ return etrax_ethernet_init(); -+} -+ -+static int __init -+e100_boot_setup(char* str) -+{ -+ struct sockaddr sa = {0}; -+ int i; -+ -+ /* Parse the colon separated Ethernet station address */ -+ for (i = 0; i < ETH_ALEN; i++) { -+ unsigned int tmp; -+ if (sscanf(str + 3*i, "%2x", &tmp) != 1) { -+ printk(KERN_WARNING "Malformed station address"); -+ return 0; -+ } -+ sa.sa_data[i] = (char)tmp; -+ } -+ -+ default_mac = sa; -+ return 1; -+} -+ -+__setup("etrax100_eth=", e100_boot_setup); -+ -+module_init(etrax_init_module); diff -Nur linux-2.6.39.orig/drivers/tty/serial/crisv10.c linux-2.6.39/drivers/tty/serial/crisv10.c --- linux-2.6.39.orig/drivers/tty/serial/crisv10.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/tty/serial/crisv10.c 2011-07-28 16:27:57.623883501 +0200 ++++ linux-2.6.39/drivers/tty/serial/crisv10.c 2011-08-25 07:43:02.637980323 +0200 @@ -26,6 +26,7 @@ #include <linux/kernel.h> #include <linux/mutex.h> @@ -3292,4585 +413,9 @@ diff -Nur linux-2.6.39.orig/drivers/tty/serial/crisv10.c linux-2.6.39/drivers/tt return 0; } -diff -Nur linux-2.6.39.orig/drivers/tty/serial/crisv10.c.orig linux-2.6.39/drivers/tty/serial/crisv10.c.orig ---- linux-2.6.39.orig/drivers/tty/serial/crisv10.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/tty/serial/crisv10.c.orig 2011-05-19 06:06:34.000000000 +0200 -@@ -0,0 +1,4572 @@ -+/* -+ * Serial port driver for the ETRAX 100LX chip -+ * -+ * Copyright (C) 1998-2007 Axis Communications AB -+ * -+ * Many, many authors. Based once upon a time on serial.c for 16x50. -+ * -+ */ -+ -+static char *serial_version = "$Revision: 1.25 $"; -+ -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <linux/signal.h> -+#include <linux/sched.h> -+#include <linux/timer.h> -+#include <linux/interrupt.h> -+#include <linux/tty.h> -+#include <linux/tty_flip.h> -+#include <linux/major.h> -+#include <linux/string.h> -+#include <linux/fcntl.h> -+#include <linux/mm.h> -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/mutex.h> -+#include <linux/bitops.h> -+#include <linux/seq_file.h> -+#include <linux/delay.h> -+#include <linux/module.h> -+#include <linux/uaccess.h> -+#include <linux/io.h> -+ -+#include <asm/irq.h> -+#include <asm/dma.h> -+#include <asm/system.h> -+ -+#include <arch/svinto.h> -+ -+/* non-arch dependent serial structures are in linux/serial.h */ -+#include <linux/serial.h> -+/* while we keep our own stuff (struct e100_serial) in a local .h file */ -+#include "crisv10.h" -+#include <asm/fasttimer.h> -+#include <arch/io_interface_mux.h> -+ -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+#ifndef CONFIG_ETRAX_FAST_TIMER -+#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER" -+#endif -+#endif -+ -+#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \ -+ (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0) -+#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" -+#endif -+ -+#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G" -+#endif -+ -+/* -+ * All of the compatibilty code so we can compile serial.c against -+ * older kernels is hidden in serial_compat.h -+ */ -+#if defined(LOCAL_HEADERS) -+#include "serial_compat.h" -+#endif -+ -+struct tty_driver *serial_driver; -+ -+/* number of characters left in xmit buffer before we ask for more */ -+#define WAKEUP_CHARS 256 -+ -+//#define SERIAL_DEBUG_INTR -+//#define SERIAL_DEBUG_OPEN -+//#define SERIAL_DEBUG_FLOW -+//#define SERIAL_DEBUG_DATA -+//#define SERIAL_DEBUG_THROTTLE -+//#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins */ -+//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */ -+ -+/* Enable this to use serial interrupts to handle when you -+ expect the first received event on the serial port to -+ be an error, break or similar. Used to be able to flash IRMA -+ from eLinux */ -+#define SERIAL_HANDLE_EARLY_ERRORS -+ -+/* Currently 16 descriptors x 128 bytes = 2048 bytes */ -+#define SERIAL_DESCR_BUF_SIZE 256 -+ -+#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */ -+#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE -+ -+/* We don't want to load the system with massive fast timer interrupt -+ * on high baudrates so limit it to 250 us (4kHz) */ -+#define MIN_FLUSH_TIME_USEC 250 -+ -+/* Add an x here to log a lot of timer stuff */ -+#define TIMERD(x) -+/* Debug details of interrupt handling */ -+#define DINTR1(x) /* irq on/off, errors */ -+#define DINTR2(x) /* tx and rx */ -+/* Debug flip buffer stuff */ -+#define DFLIP(x) -+/* Debug flow control and overview of data flow */ -+#define DFLOW(x) -+#define DBAUD(x) -+#define DLOG_INT_TRIG(x) -+ -+//#define DEBUG_LOG_INCLUDED -+#ifndef DEBUG_LOG_INCLUDED -+#define DEBUG_LOG(line, string, value) -+#else -+struct debug_log_info -+{ -+ unsigned long time; -+ unsigned long timer_data; -+// int line; -+ const char *string; -+ int value; -+}; -+#define DEBUG_LOG_SIZE 4096 -+ -+struct debug_log_info debug_log[DEBUG_LOG_SIZE]; -+int debug_log_pos = 0; -+ -+#define DEBUG_LOG(_line, _string, _value) do { \ -+ if ((_line) == SERIAL_DEBUG_LINE) {\ -+ debug_log_func(_line, _string, _value); \ -+ }\ -+}while(0) -+ -+void debug_log_func(int line, const char *string, int value) -+{ -+ if (debug_log_pos < DEBUG_LOG_SIZE) { -+ debug_log[debug_log_pos].time = jiffies; -+ debug_log[debug_log_pos].timer_data = *R_TIMER_DATA; -+// debug_log[debug_log_pos].line = line; -+ debug_log[debug_log_pos].string = string; -+ debug_log[debug_log_pos].value = value; -+ debug_log_pos++; -+ } -+ /*printk(string, value);*/ -+} -+#endif -+ -+#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS -+/* Default number of timer ticks before flushing rx fifo -+ * When using "little data, low latency applications: use 0 -+ * When using "much data applications (PPP)" use ~5 -+ */ -+#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 -+#endif -+ -+unsigned long timer_data_to_ns(unsigned long timer_data); -+ -+static void change_speed(struct e100_serial *info); -+static void rs_throttle(struct tty_struct * tty); -+static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -+static int rs_write(struct tty_struct *tty, -+ const unsigned char *buf, int count); -+#ifdef CONFIG_ETRAX_RS485 -+static int e100_write_rs485(struct tty_struct *tty, -+ const unsigned char *buf, int count); -+#endif -+static int get_lsr_info(struct e100_serial *info, unsigned int *value); -+ -+ -+#define DEF_BAUD 115200 /* 115.2 kbit/s */ -+#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -+#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */ -+/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ -+#define DEF_TX 0x80 /* or SERIAL_CTRL_B */ -+ -+/* offsets from R_SERIALx_CTRL */ -+ -+#define REG_DATA 0 -+#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */ -+#define REG_TR_DATA 0 -+#define REG_STATUS 1 -+#define REG_TR_CTRL 1 -+#define REG_REC_CTRL 2 -+#define REG_BAUD 3 -+#define REG_XOFF 4 /* this is a 32 bit register */ -+ -+/* The bitfields are the same for all serial ports */ -+#define SER_RXD_MASK IO_MASK(R_SERIAL0_STATUS, rxd) -+#define SER_DATA_AVAIL_MASK IO_MASK(R_SERIAL0_STATUS, data_avail) -+#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err) -+#define SER_PAR_ERR_MASK IO_MASK(R_SERIAL0_STATUS, par_err) -+#define SER_OVERRUN_MASK IO_MASK(R_SERIAL0_STATUS, overrun) -+ -+#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK) -+ -+/* Values for info->errorcode */ -+#define ERRCODE_SET_BREAK (TTY_BREAK) -+#define ERRCODE_INSERT 0x100 -+#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK) -+ -+#define FORCE_EOP(info) *R_SET_EOP = 1U << info->iseteop; -+ -+/* -+ * General note regarding the use of IO_* macros in this file: -+ * -+ * We will use the bits defined for DMA channel 6 when using various -+ * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are -+ * the same for all channels (which of course they are). -+ * -+ * We will also use the bits defined for serial port 0 when writing commands -+ * to the different ports, as these bits too are the same for all ports. -+ */ -+ -+ -+/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */ -+static const unsigned long e100_ser_int_mask = 0 -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready) -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready) -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready) -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready) -+#endif -+; -+unsigned long r_alt_ser_baudrate_shadow = 0; -+ -+/* this is the data for the four serial ports in the etrax100 */ -+/* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ -+/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ -+ -+static struct e100_serial rs_table[] = { -+ { .baud = DEF_BAUD, -+ .ioport = (unsigned char *)R_SERIAL0_CTRL, -+ .irq = 1U << 12, /* uses DMA 6 and 7 */ -+ .oclrintradr = R_DMA_CH6_CLR_INTR, -+ .ofirstadr = R_DMA_CH6_FIRST, -+ .ocmdadr = R_DMA_CH6_CMD, -+ .ostatusadr = R_DMA_CH6_STATUS, -+ .iclrintradr = R_DMA_CH7_CLR_INTR, -+ .ifirstadr = R_DMA_CH7_FIRST, -+ .icmdadr = R_DMA_CH7_CMD, -+ .idescradr = R_DMA_CH7_DESCR, -+ .flags = STD_FLAGS, -+ .rx_ctrl = DEF_RX, -+ .tx_ctrl = DEF_TX, -+ .iseteop = 2, -+ .dma_owner = dma_ser0, -+ .io_if = if_serial_0, -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+ .enabled = 1, -+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT -+ .dma_out_enabled = 1, -+ .dma_out_nbr = SER0_TX_DMA_NBR, -+ .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR, -+ .dma_out_irq_flags = IRQF_DISABLED, -+ .dma_out_irq_description = "serial 0 dma tr", -+#else -+ .dma_out_enabled = 0, -+ .dma_out_nbr = UINT_MAX, -+ .dma_out_irq_nbr = 0, -+ .dma_out_irq_flags = 0, -+ .dma_out_irq_description = NULL, -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN -+ .dma_in_enabled = 1, -+ .dma_in_nbr = SER0_RX_DMA_NBR, -+ .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR, -+ .dma_in_irq_flags = IRQF_DISABLED, -+ .dma_in_irq_description = "serial 0 dma rec", -+#else -+ .dma_in_enabled = 0, -+ .dma_in_nbr = UINT_MAX, -+ .dma_in_irq_nbr = 0, -+ .dma_in_irq_flags = 0, -+ .dma_in_irq_description = NULL, -+#endif -+#else -+ .enabled = 0, -+ .io_if_description = NULL, -+ .dma_out_enabled = 0, -+ .dma_in_enabled = 0 -+#endif -+ -+}, /* ttyS0 */ -+#ifndef CONFIG_SVINTO_SIM -+ { .baud = DEF_BAUD, -+ .ioport = (unsigned char *)R_SERIAL1_CTRL, -+ .irq = 1U << 16, /* uses DMA 8 and 9 */ -+ .oclrintradr = R_DMA_CH8_CLR_INTR, -+ .ofirstadr = R_DMA_CH8_FIRST, -+ .ocmdadr = R_DMA_CH8_CMD, -+ .ostatusadr = R_DMA_CH8_STATUS, -+ .iclrintradr = R_DMA_CH9_CLR_INTR, -+ .ifirstadr = R_DMA_CH9_FIRST, -+ .icmdadr = R_DMA_CH9_CMD, -+ .idescradr = R_DMA_CH9_DESCR, -+ .flags = STD_FLAGS, -+ .rx_ctrl = DEF_RX, -+ .tx_ctrl = DEF_TX, -+ .iseteop = 3, -+ .dma_owner = dma_ser1, -+ .io_if = if_serial_1, -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+ .enabled = 1, -+ .io_if_description = "ser1", -+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT -+ .dma_out_enabled = 1, -+ .dma_out_nbr = SER1_TX_DMA_NBR, -+ .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR, -+ .dma_out_irq_flags = IRQF_DISABLED, -+ .dma_out_irq_description = "serial 1 dma tr", -+#else -+ .dma_out_enabled = 0, -+ .dma_out_nbr = UINT_MAX, -+ .dma_out_irq_nbr = 0, -+ .dma_out_irq_flags = 0, -+ .dma_out_irq_description = NULL, -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN -+ .dma_in_enabled = 1, -+ .dma_in_nbr = SER1_RX_DMA_NBR, -+ .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR, -+ .dma_in_irq_flags = IRQF_DISABLED, -+ .dma_in_irq_description = "serial 1 dma rec", -+#else -+ .dma_in_enabled = 0, -+ .dma_in_enabled = 0, -+ .dma_in_nbr = UINT_MAX, -+ .dma_in_irq_nbr = 0, -+ .dma_in_irq_flags = 0, -+ .dma_in_irq_description = NULL, -+#endif -+#else -+ .enabled = 0, -+ .io_if_description = NULL, -+ .dma_in_irq_nbr = 0, -+ .dma_out_enabled = 0, -+ .dma_in_enabled = 0 -+#endif -+}, /* ttyS1 */ -+ -+ { .baud = DEF_BAUD, -+ .ioport = (unsigned char *)R_SERIAL2_CTRL, -+ .irq = 1U << 4, /* uses DMA 2 and 3 */ -+ .oclrintradr = R_DMA_CH2_CLR_INTR, -+ .ofirstadr = R_DMA_CH2_FIRST, -+ .ocmdadr = R_DMA_CH2_CMD, -+ .ostatusadr = R_DMA_CH2_STATUS, -+ .iclrintradr = R_DMA_CH3_CLR_INTR, -+ .ifirstadr = R_DMA_CH3_FIRST, -+ .icmdadr = R_DMA_CH3_CMD, -+ .idescradr = R_DMA_CH3_DESCR, -+ .flags = STD_FLAGS, -+ .rx_ctrl = DEF_RX, -+ .tx_ctrl = DEF_TX, -+ .iseteop = 0, -+ .dma_owner = dma_ser2, -+ .io_if = if_serial_2, -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+ .enabled = 1, -+ .io_if_description = "ser2", -+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT -+ .dma_out_enabled = 1, -+ .dma_out_nbr = SER2_TX_DMA_NBR, -+ .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR, -+ .dma_out_irq_flags = IRQF_DISABLED, -+ .dma_out_irq_description = "serial 2 dma tr", -+#else -+ .dma_out_enabled = 0, -+ .dma_out_nbr = UINT_MAX, -+ .dma_out_irq_nbr = 0, -+ .dma_out_irq_flags = 0, -+ .dma_out_irq_description = NULL, -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN -+ .dma_in_enabled = 1, -+ .dma_in_nbr = SER2_RX_DMA_NBR, -+ .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR, -+ .dma_in_irq_flags = IRQF_DISABLED, -+ .dma_in_irq_description = "serial 2 dma rec", -+#else -+ .dma_in_enabled = 0, -+ .dma_in_nbr = UINT_MAX, -+ .dma_in_irq_nbr = 0, -+ .dma_in_irq_flags = 0, -+ .dma_in_irq_description = NULL, -+#endif -+#else -+ .enabled = 0, -+ .io_if_description = NULL, -+ .dma_out_enabled = 0, -+ .dma_in_enabled = 0 -+#endif -+ }, /* ttyS2 */ -+ -+ { .baud = DEF_BAUD, -+ .ioport = (unsigned char *)R_SERIAL3_CTRL, -+ .irq = 1U << 8, /* uses DMA 4 and 5 */ -+ .oclrintradr = R_DMA_CH4_CLR_INTR, -+ .ofirstadr = R_DMA_CH4_FIRST, -+ .ocmdadr = R_DMA_CH4_CMD, -+ .ostatusadr = R_DMA_CH4_STATUS, -+ .iclrintradr = R_DMA_CH5_CLR_INTR, -+ .ifirstadr = R_DMA_CH5_FIRST, -+ .icmdadr = R_DMA_CH5_CMD, -+ .idescradr = R_DMA_CH5_DESCR, -+ .flags = STD_FLAGS, -+ .rx_ctrl = DEF_RX, -+ .tx_ctrl = DEF_TX, -+ .iseteop = 1, -+ .dma_owner = dma_ser3, -+ .io_if = if_serial_3, -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+ .enabled = 1, -+ .io_if_description = "ser3", -+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT -+ .dma_out_enabled = 1, -+ .dma_out_nbr = SER3_TX_DMA_NBR, -+ .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR, -+ .dma_out_irq_flags = IRQF_DISABLED, -+ .dma_out_irq_description = "serial 3 dma tr", -+#else -+ .dma_out_enabled = 0, -+ .dma_out_nbr = UINT_MAX, -+ .dma_out_irq_nbr = 0, -+ .dma_out_irq_flags = 0, -+ .dma_out_irq_description = NULL, -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN -+ .dma_in_enabled = 1, -+ .dma_in_nbr = SER3_RX_DMA_NBR, -+ .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR, -+ .dma_in_irq_flags = IRQF_DISABLED, -+ .dma_in_irq_description = "serial 3 dma rec", -+#else -+ .dma_in_enabled = 0, -+ .dma_in_nbr = UINT_MAX, -+ .dma_in_irq_nbr = 0, -+ .dma_in_irq_flags = 0, -+ .dma_in_irq_description = NULL -+#endif -+#else -+ .enabled = 0, -+ .io_if_description = NULL, -+ .dma_out_enabled = 0, -+ .dma_in_enabled = 0 -+#endif -+ } /* ttyS3 */ -+#endif -+}; -+ -+ -+#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) -+ -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+static struct fast_timer fast_timers[NR_PORTS]; -+#endif -+ -+#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY -+#define PROCSTAT(x) x -+struct ser_statistics_type { -+ int overrun_cnt; -+ int early_errors_cnt; -+ int ser_ints_ok_cnt; -+ int errors_cnt; -+ unsigned long int processing_flip; -+ unsigned long processing_flip_still_room; -+ unsigned long int timeout_flush_cnt; -+ int rx_dma_ints; -+ int tx_dma_ints; -+ int rx_tot; -+ int tx_tot; -+}; -+ -+static struct ser_statistics_type ser_stat[NR_PORTS]; -+ -+#else -+ -+#define PROCSTAT(x) -+ -+#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */ -+ -+/* RS-485 */ -+#if defined(CONFIG_ETRAX_RS485) -+#ifdef CONFIG_ETRAX_FAST_TIMER -+static struct fast_timer fast_timers_rs485[NR_PORTS]; -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PA) -+static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT; -+#endif -+#endif -+ -+/* Info and macros needed for each ports extra control/status signals. */ -+#define E100_STRUCT_PORT(line, pinname) \ -+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ -+ (R_PORT_PA_DATA): ( \ -+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ -+ (R_PORT_PB_DATA):&dummy_ser[line])) -+ -+#define E100_STRUCT_SHADOW(line, pinname) \ -+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ -+ (&port_pa_data_shadow): ( \ -+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ -+ (&port_pb_data_shadow):&dummy_ser[line])) -+#define E100_STRUCT_MASK(line, pinname) \ -+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ -+ (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \ -+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ -+ (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK)) -+ -+#define DUMMY_DTR_MASK 1 -+#define DUMMY_RI_MASK 2 -+#define DUMMY_DSR_MASK 4 -+#define DUMMY_CD_MASK 8 -+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF}; -+ -+/* If not all status pins are used or disabled, use mixed mode */ -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+ -+#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT) -+ -+#if SER0_PA_BITSUM != -4 -+# if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT) -+ -+#if SER0_PB_BITSUM != -4 -+# if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#endif /* PORT0 */ -+ -+ -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+ -+#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT) -+ -+#if SER1_PA_BITSUM != -4 -+# if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT) -+ -+#if SER1_PB_BITSUM != -4 -+# if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#endif /* PORT1 */ -+ -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+ -+#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT) -+ -+#if SER2_PA_BITSUM != -4 -+# if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT) -+ -+#if SER2_PB_BITSUM != -4 -+# if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#endif /* PORT2 */ -+ -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+ -+#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT) -+ -+#if SER3_PA_BITSUM != -4 -+# if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT) -+ -+#if SER3_PB_BITSUM != -4 -+# if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#endif /* PORT3 */ -+ -+ -+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \ -+ defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \ -+ defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \ -+ defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED) -+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED -+#endif -+ -+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED -+/* The pins can be mixed on PA and PB */ -+#define CONTROL_PINS_PORT_NOT_USED(line) \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK -+ -+ -+struct control_pins -+{ -+ volatile unsigned char *dtr_port; -+ unsigned char *dtr_shadow; -+ volatile unsigned char *ri_port; -+ unsigned char *ri_shadow; -+ volatile unsigned char *dsr_port; -+ unsigned char *dsr_shadow; -+ volatile unsigned char *cd_port; -+ unsigned char *cd_shadow; -+ -+ unsigned char dtr_mask; -+ unsigned char ri_mask; -+ unsigned char dsr_mask; -+ unsigned char cd_mask; -+}; -+ -+static const struct control_pins e100_modem_pins[NR_PORTS] = -+{ -+ /* Ser 0 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+ E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR), -+ E100_STRUCT_PORT(0,RI), E100_STRUCT_SHADOW(0,RI), -+ E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR), -+ E100_STRUCT_PORT(0,CD), E100_STRUCT_SHADOW(0,CD), -+ E100_STRUCT_MASK(0,DTR), -+ E100_STRUCT_MASK(0,RI), -+ E100_STRUCT_MASK(0,DSR), -+ E100_STRUCT_MASK(0,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(0) -+#endif -+ }, -+ -+ /* Ser 1 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+ E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR), -+ E100_STRUCT_PORT(1,RI), E100_STRUCT_SHADOW(1,RI), -+ E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR), -+ E100_STRUCT_PORT(1,CD), E100_STRUCT_SHADOW(1,CD), -+ E100_STRUCT_MASK(1,DTR), -+ E100_STRUCT_MASK(1,RI), -+ E100_STRUCT_MASK(1,DSR), -+ E100_STRUCT_MASK(1,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(1) -+#endif -+ }, -+ -+ /* Ser 2 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+ E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR), -+ E100_STRUCT_PORT(2,RI), E100_STRUCT_SHADOW(2,RI), -+ E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR), -+ E100_STRUCT_PORT(2,CD), E100_STRUCT_SHADOW(2,CD), -+ E100_STRUCT_MASK(2,DTR), -+ E100_STRUCT_MASK(2,RI), -+ E100_STRUCT_MASK(2,DSR), -+ E100_STRUCT_MASK(2,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(2) -+#endif -+ }, -+ -+ /* Ser 3 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+ E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR), -+ E100_STRUCT_PORT(3,RI), E100_STRUCT_SHADOW(3,RI), -+ E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR), -+ E100_STRUCT_PORT(3,CD), E100_STRUCT_SHADOW(3,CD), -+ E100_STRUCT_MASK(3,DTR), -+ E100_STRUCT_MASK(3,RI), -+ E100_STRUCT_MASK(3,DSR), -+ E100_STRUCT_MASK(3,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(3) -+#endif -+ } -+}; -+#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ -+ -+/* All pins are on either PA or PB for each serial port */ -+#define CONTROL_PINS_PORT_NOT_USED(line) \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK -+ -+ -+struct control_pins -+{ -+ volatile unsigned char *port; -+ unsigned char *shadow; -+ -+ unsigned char dtr_mask; -+ unsigned char ri_mask; -+ unsigned char dsr_mask; -+ unsigned char cd_mask; -+}; -+ -+#define dtr_port port -+#define dtr_shadow shadow -+#define ri_port port -+#define ri_shadow shadow -+#define dsr_port port -+#define dsr_shadow shadow -+#define cd_port port -+#define cd_shadow shadow -+ -+static const struct control_pins e100_modem_pins[NR_PORTS] = -+{ -+ /* Ser 0 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+ E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR), -+ E100_STRUCT_MASK(0,DTR), -+ E100_STRUCT_MASK(0,RI), -+ E100_STRUCT_MASK(0,DSR), -+ E100_STRUCT_MASK(0,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(0) -+#endif -+ }, -+ -+ /* Ser 1 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+ E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR), -+ E100_STRUCT_MASK(1,DTR), -+ E100_STRUCT_MASK(1,RI), -+ E100_STRUCT_MASK(1,DSR), -+ E100_STRUCT_MASK(1,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(1) -+#endif -+ }, -+ -+ /* Ser 2 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+ E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR), -+ E100_STRUCT_MASK(2,DTR), -+ E100_STRUCT_MASK(2,RI), -+ E100_STRUCT_MASK(2,DSR), -+ E100_STRUCT_MASK(2,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(2) -+#endif -+ }, -+ -+ /* Ser 3 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+ E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR), -+ E100_STRUCT_MASK(3,DTR), -+ E100_STRUCT_MASK(3,RI), -+ E100_STRUCT_MASK(3,DSR), -+ E100_STRUCT_MASK(3,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(3) -+#endif -+ } -+}; -+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ -+ -+#define E100_RTS_MASK 0x20 -+#define E100_CTS_MASK 0x40 -+ -+/* All serial port signals are active low: -+ * active = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level -+ * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level -+ * -+ * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip -+ */ -+ -+/* Output */ -+#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK) -+/* Input */ -+#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK) -+ -+/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */ -+/* Is an output */ -+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask) -+ -+/* Normally inputs */ -+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask) -+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask) -+ -+/* Input */ -+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) -+ -+ -+/* -+ * tmp_buf is used as a temporary buffer by serial_write. We need to -+ * lock it in case the memcpy_fromfs blocks while swapping in a page, -+ * and some other program tries to do a serial write at the same time. -+ * Since the lock will only come under contention when the system is -+ * swapping and available memory is low, it makes sense to share one -+ * buffer across all the serial ports, since it significantly saves -+ * memory if large numbers of serial ports are open. -+ */ -+static unsigned char *tmp_buf; -+static DEFINE_MUTEX(tmp_buf_mutex); -+ -+/* Calculate the chartime depending on baudrate, numbor of bits etc. */ -+static void update_char_time(struct e100_serial * info) -+{ -+ tcflag_t cflags = info->port.tty->termios->c_cflag; -+ int bits; -+ -+ /* calc. number of bits / data byte */ -+ /* databits + startbit and 1 stopbit */ -+ if ((cflags & CSIZE) == CS7) -+ bits = 9; -+ else -+ bits = 10; -+ -+ if (cflags & CSTOPB) /* 2 stopbits ? */ -+ bits++; -+ -+ if (cflags & PARENB) /* parity bit ? */ -+ bits++; -+ -+ /* calc timeout */ -+ info->char_time_usec = ((bits * 1000000) / info->baud) + 1; -+ info->flush_time_usec = 4*info->char_time_usec; -+ if (info->flush_time_usec < MIN_FLUSH_TIME_USEC) -+ info->flush_time_usec = MIN_FLUSH_TIME_USEC; -+ -+} -+ -+/* -+ * This function maps from the Bxxxx defines in asm/termbits.h into real -+ * baud rates. -+ */ -+ -+static int -+cflag_to_baud(unsigned int cflag) -+{ -+ static int baud_table[] = { -+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, -+ 4800, 9600, 19200, 38400 }; -+ -+ static int ext_baud_table[] = { -+ 0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000, -+ 0, 0, 0, 0, 0, 0, 0, 0 }; -+ -+ if (cflag & CBAUDEX) -+ return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; -+ else -+ return baud_table[cflag & CBAUD]; -+} -+ -+/* and this maps to an etrax100 hardware baud constant */ -+ -+static unsigned char -+cflag_to_etrax_baud(unsigned int cflag) -+{ -+ char retval; -+ -+ static char baud_table[] = { -+ -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 }; -+ -+ static char ext_baud_table[] = { -+ -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 }; -+ -+ if (cflag & CBAUDEX) -+ retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; -+ else -+ retval = baud_table[cflag & CBAUD]; -+ -+ if (retval < 0) { -+ printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag); -+ retval = 5; /* choose default 9600 instead */ -+ } -+ -+ return retval | (retval << 4); /* choose same for both TX and RX */ -+} -+ -+ -+/* Various static support functions */ -+ -+/* Functions to set or clear DTR/RTS on the requested line */ -+/* It is complicated by the fact that RTS is a serial port register, while -+ * DTR might not be implemented in the HW at all, and if it is, it can be on -+ * any general port. -+ */ -+ -+ -+static inline void -+e100_dtr(struct e100_serial *info, int set) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ unsigned char mask = e100_modem_pins[info->line].dtr_mask; -+ -+#ifdef SERIAL_DEBUG_IO -+ printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); -+ printk("ser%i shadow before 0x%02X get: %i\n", -+ info->line, *e100_modem_pins[info->line].dtr_shadow, -+ E100_DTR_GET(info)); -+#endif -+ /* DTR is active low */ -+ { -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ *e100_modem_pins[info->line].dtr_shadow &= ~mask; -+ *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); -+ *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow; -+ local_irq_restore(flags); -+ } -+ -+#ifdef SERIAL_DEBUG_IO -+ printk("ser%i shadow after 0x%02X get: %i\n", -+ info->line, *e100_modem_pins[info->line].dtr_shadow, -+ E100_DTR_GET(info)); -+#endif -+#endif -+} -+ -+/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive -+ * 0=0V , 1=3.3V -+ */ -+static inline void -+e100_rts(struct e100_serial *info, int set) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ unsigned long flags; -+ local_irq_save(flags); -+ info->rx_ctrl &= ~E100_RTS_MASK; -+ info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ -+ info->ioport[REG_REC_CTRL] = info->rx_ctrl; -+ local_irq_restore(flags); -+#ifdef SERIAL_DEBUG_IO -+ printk("ser%i rts %i\n", info->line, set); -+#endif -+#endif -+} -+ -+ -+/* If this behaves as a modem, RI and CD is an output */ -+static inline void -+e100_ri_out(struct e100_serial *info, int set) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ /* RI is active low */ -+ { -+ unsigned char mask = e100_modem_pins[info->line].ri_mask; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ *e100_modem_pins[info->line].ri_shadow &= ~mask; -+ *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); -+ *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; -+ local_irq_restore(flags); -+ } -+#endif -+} -+static inline void -+e100_cd_out(struct e100_serial *info, int set) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ /* CD is active low */ -+ { -+ unsigned char mask = e100_modem_pins[info->line].cd_mask; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ *e100_modem_pins[info->line].cd_shadow &= ~mask; -+ *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); -+ *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; -+ local_irq_restore(flags); -+ } -+#endif -+} -+ -+static inline void -+e100_disable_rx(struct e100_serial *info) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ /* disable the receiver */ -+ info->ioport[REG_REC_CTRL] = -+ (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -+#endif -+} -+ -+static inline void -+e100_enable_rx(struct e100_serial *info) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ /* enable the receiver */ -+ info->ioport[REG_REC_CTRL] = -+ (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -+#endif -+} -+ -+/* the rx DMA uses both the dma_descr and the dma_eop interrupts */ -+ -+static inline void -+e100_disable_rxdma_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("rxdma_irq(%d): 0\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line)); -+ *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3); -+} -+ -+static inline void -+e100_enable_rxdma_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("rxdma_irq(%d): 1\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line)); -+ *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3); -+} -+ -+/* the tx DMA uses only dma_descr interrupt */ -+ -+static void e100_disable_txdma_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("txdma_irq(%d): 0\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line)); -+ *R_IRQ_MASK2_CLR = info->irq; -+} -+ -+static void e100_enable_txdma_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("txdma_irq(%d): 1\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line)); -+ *R_IRQ_MASK2_SET = info->irq; -+} -+ -+static void e100_disable_txdma_channel(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ /* Disable output DMA channel for the serial port in question -+ * ( set to something other than serialX) -+ */ -+ local_irq_save(flags); -+ DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line)); -+ if (info->line == 0) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) == -+ IO_STATE(R_GEN_CONFIG, dma6, serial0)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); -+ } -+ } else if (info->line == 1) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) == -+ IO_STATE(R_GEN_CONFIG, dma8, serial1)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); -+ } -+ } else if (info->line == 2) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) == -+ IO_STATE(R_GEN_CONFIG, dma2, serial2)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); -+ } -+ } else if (info->line == 3) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) == -+ IO_STATE(R_GEN_CONFIG, dma4, serial3)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); -+ } -+ } -+ *R_GEN_CONFIG = genconfig_shadow; -+ local_irq_restore(flags); -+} -+ -+ -+static void e100_enable_txdma_channel(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line)); -+ /* Enable output DMA channel for the serial port in question */ -+ if (info->line == 0) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0); -+ } else if (info->line == 1) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1); -+ } else if (info->line == 2) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2); -+ } else if (info->line == 3) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3); -+ } -+ *R_GEN_CONFIG = genconfig_shadow; -+ local_irq_restore(flags); -+} -+ -+static void e100_disable_rxdma_channel(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ /* Disable input DMA channel for the serial port in question -+ * ( set to something other than serialX) -+ */ -+ local_irq_save(flags); -+ if (info->line == 0) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) == -+ IO_STATE(R_GEN_CONFIG, dma7, serial0)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused); -+ } -+ } else if (info->line == 1) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) == -+ IO_STATE(R_GEN_CONFIG, dma9, serial1)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb); -+ } -+ } else if (info->line == 2) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) == -+ IO_STATE(R_GEN_CONFIG, dma3, serial2)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0); -+ } -+ } else if (info->line == 3) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) == -+ IO_STATE(R_GEN_CONFIG, dma5, serial3)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1); -+ } -+ } -+ *R_GEN_CONFIG = genconfig_shadow; -+ local_irq_restore(flags); -+} -+ -+ -+static void e100_enable_rxdma_channel(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ /* Enable input DMA channel for the serial port in question */ -+ if (info->line == 0) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0); -+ } else if (info->line == 1) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1); -+ } else if (info->line == 2) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2); -+ } else if (info->line == 3) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3); -+ } -+ *R_GEN_CONFIG = genconfig_shadow; -+ local_irq_restore(flags); -+} -+ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+/* in order to detect and fix errors on the first byte -+ we have to use the serial interrupts as well. */ -+ -+static inline void -+e100_disable_serial_data_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("ser_irq(%d): 0\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line)); -+ *R_IRQ_MASK1_CLR = (1U << (8+2*info->line)); -+} -+ -+static inline void -+e100_enable_serial_data_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("ser_irq(%d): 1\n",info->line); -+ printk("**** %d = %d\n", -+ (8+2*info->line), -+ (1U << (8+2*info->line))); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line)); -+ *R_IRQ_MASK1_SET = (1U << (8+2*info->line)); -+} -+#endif -+ -+static inline void -+e100_disable_serial_tx_ready_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("ser_tx_irq(%d): 0\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line)); -+ *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line)); -+} -+ -+static inline void -+e100_enable_serial_tx_ready_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("ser_tx_irq(%d): 1\n",info->line); -+ printk("**** %d = %d\n", -+ (8+1+2*info->line), -+ (1U << (8+1+2*info->line))); -+#endif -+ DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line)); -+ *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line)); -+} -+ -+static inline void e100_enable_rx_irq(struct e100_serial *info) -+{ -+ if (info->uses_dma_in) -+ e100_enable_rxdma_irq(info); -+ else -+ e100_enable_serial_data_irq(info); -+} -+static inline void e100_disable_rx_irq(struct e100_serial *info) -+{ -+ if (info->uses_dma_in) -+ e100_disable_rxdma_irq(info); -+ else -+ e100_disable_serial_data_irq(info); -+} -+ -+#if defined(CONFIG_ETRAX_RS485) -+/* Enable RS-485 mode on selected port. This is UGLY. */ -+static int -+e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ -+#if defined(CONFIG_ETRAX_RS485_ON_PA) -+ *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ rs485_port_g_bit, 1); -+#endif -+#if defined(CONFIG_ETRAX_RS485_LTC1387) -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1); -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1); -+#endif -+ -+ info->rs485 = *r; -+ -+ /* Maximum delay before RTS equal to 1000 */ -+ if (info->rs485.delay_rts_before_send >= 1000) -+ info->rs485.delay_rts_before_send = 1000; -+ -+/* printk("rts: on send = %i, after = %i, enabled = %i", -+ info->rs485.rts_on_send, -+ info->rs485.rts_after_sent, -+ info->rs485.enabled -+ ); -+*/ -+ return 0; -+} -+ -+static int -+e100_write_rs485(struct tty_struct *tty, -+ const unsigned char *buf, int count) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ int old_value = (info->rs485.flags) & SER_RS485_ENABLED; -+ -+ /* rs485 is always implicitly enabled if we're using the ioctl() -+ * but it doesn't have to be set in the serial_rs485 -+ * (to be backward compatible with old apps) -+ * So we store, set and restore it. -+ */ -+ info->rs485.flags |= SER_RS485_ENABLED; -+ /* rs_write now deals with RS485 if enabled */ -+ count = rs_write(tty, buf, count); -+ if (!old_value) -+ info->rs485.flags &= ~(SER_RS485_ENABLED); -+ return count; -+} -+ -+#ifdef CONFIG_ETRAX_FAST_TIMER -+/* Timer function to toggle RTS when using FAST_TIMER */ -+static void rs485_toggle_rts_timer_function(unsigned long data) -+{ -+ struct e100_serial *info = (struct e100_serial *)data; -+ -+ fast_timers_rs485[info->line].function = NULL; -+ e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); -+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) -+ e100_enable_rx(info); -+ e100_enable_rx_irq(info); -+#endif -+} -+#endif -+#endif /* CONFIG_ETRAX_RS485 */ -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_stop() and rs_start() -+ * -+ * This routines are called before setting or resetting tty->stopped. -+ * They enable or disable transmitter using the XOFF registers, as necessary. -+ * ------------------------------------------------------------ -+ */ -+ -+static void -+rs_stop(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ if (info) { -+ unsigned long flags; -+ unsigned long xoff; -+ -+ local_irq_save(flags); -+ DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n", -+ CIRC_CNT(info->xmit.head, -+ info->xmit.tail,SERIAL_XMIT_SIZE))); -+ -+ xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, -+ STOP_CHAR(info->port.tty)); -+ xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); -+ if (tty->termios->c_iflag & IXON ) { -+ xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); -+ } -+ -+ *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; -+ local_irq_restore(flags); -+ } -+} -+ -+static void -+rs_start(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ if (info) { -+ unsigned long flags; -+ unsigned long xoff; -+ -+ local_irq_save(flags); -+ DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n", -+ CIRC_CNT(info->xmit.head, -+ info->xmit.tail,SERIAL_XMIT_SIZE))); -+ xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty)); -+ xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); -+ if (tty->termios->c_iflag & IXON ) { -+ xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); -+ } -+ -+ *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; -+ if (!info->uses_dma_out && -+ info->xmit.head != info->xmit.tail && info->xmit.buf) -+ e100_enable_serial_tx_ready_irq(info); -+ -+ local_irq_restore(flags); -+ } -+} -+ -+/* -+ * ---------------------------------------------------------------------- -+ * -+ * Here starts the interrupt handling routines. All of the following -+ * subroutines are declared as inline and are folded into -+ * rs_interrupt(). They were separated out for readability's sake. -+ * -+ * Note: rs_interrupt() is a "fast" interrupt, which means that it -+ * runs with interrupts turned off. People who may want to modify -+ * rs_interrupt() should try to keep the interrupt handler as fast as -+ * possible. After you are done making modifications, it is not a bad -+ * idea to do: -+ * -+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c -+ * -+ * and look at the resulting assemble code in serial.s. -+ * -+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 -+ * ----------------------------------------------------------------------- -+ */ -+ -+/* -+ * This routine is used by the interrupt handler to schedule -+ * processing in the software interrupt portion of the driver. -+ */ -+static void rs_sched_event(struct e100_serial *info, int event) -+{ -+ if (info->event & (1 << event)) -+ return; -+ info->event |= 1 << event; -+ schedule_work(&info->work); -+} -+ -+/* The output DMA channel is free - use it to send as many chars as possible -+ * NOTES: -+ * We don't pay attention to info->x_char, which means if the TTY wants to -+ * use XON/XOFF it will set info->x_char but we won't send any X char! -+ * -+ * To implement this, we'd just start a DMA send of 1 byte pointing at a -+ * buffer containing the X char, and skip updating xmit. We'd also have to -+ * check if the last sent char was the X char when we enter this function -+ * the next time, to avoid updating xmit with the sent X value. -+ */ -+ -+static void -+transmit_chars_dma(struct e100_serial *info) -+{ -+ unsigned int c, sentl; -+ struct etrax_dma_descr *descr; -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* This will output too little if tail is not 0 always since -+ * we don't reloop to send the other part. Anyway this SHOULD be a -+ * no-op - transmit_chars_dma would never really be called during sim -+ * since rs_write does not write into the xmit buffer then. -+ */ -+ if (info->xmit.tail) -+ printk("Error in serial.c:transmit_chars-dma(), tail!=0\n"); -+ if (info->xmit.head != info->xmit.tail) { -+ SIMCOUT(info->xmit.buf + info->xmit.tail, -+ CIRC_CNT(info->xmit.head, -+ info->xmit.tail, -+ SERIAL_XMIT_SIZE)); -+ info->xmit.head = info->xmit.tail; /* move back head */ -+ info->tr_running = 0; -+ } -+ return; -+#endif -+ /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ -+ *info->oclrintradr = -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); -+ -+#ifdef SERIAL_DEBUG_INTR -+ if (info->line == SERIAL_DEBUG_LINE) -+ printk("tc\n"); -+#endif -+ if (!info->tr_running) { -+ /* weirdo... we shouldn't get here! */ -+ printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n"); -+ return; -+ } -+ -+ descr = &info->tr_descr; -+ -+ /* first get the amount of bytes sent during the last DMA transfer, -+ and update xmit accordingly */ -+ -+ /* if the stop bit was not set, all data has been sent */ -+ if (!(descr->status & d_stop)) { -+ sentl = descr->sw_len; -+ } else -+ /* otherwise we find the amount of data sent here */ -+ sentl = descr->hw_len; -+ -+ DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl)); -+ -+ /* update stats */ -+ info->icount.tx += sentl; -+ -+ /* update xmit buffer */ -+ info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1); -+ -+ /* if there is only a few chars left in the buf, wake up the blocked -+ write if any */ -+ if (CIRC_CNT(info->xmit.head, -+ info->xmit.tail, -+ SERIAL_XMIT_SIZE) < WAKEUP_CHARS) -+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); -+ -+ /* find out the largest amount of consecutive bytes we want to send now */ -+ -+ c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -+ -+ /* Don't send all in one DMA transfer - divide it so we wake up -+ * application before all is sent -+ */ -+ -+ if (c >= 4*WAKEUP_CHARS) -+ c = c/2; -+ -+ if (c <= 0) { -+ /* our job here is done, don't schedule any new DMA transfer */ -+ info->tr_running = 0; -+ -+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) -+ if (info->rs485.flags & SER_RS485_ENABLED) { -+ /* Set a short timer to toggle RTS */ -+ start_one_shot_timer(&fast_timers_rs485[info->line], -+ rs485_toggle_rts_timer_function, -+ (unsigned long)info, -+ info->char_time_usec*2, -+ "RS-485"); -+ } -+#endif /* RS485 */ -+ return; -+ } -+ -+ /* ok we can schedule a dma send of c chars starting at info->xmit.tail */ -+ /* set up the descriptor correctly for output */ -+ DFLOW(DEBUG_LOG(info->line, "TX %i\n", c)); -+ descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */ -+ descr->sw_len = c; -+ descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail); -+ descr->status = 0; -+ -+ *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */ -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); -+ -+ /* DMA is now running (hopefully) */ -+} /* transmit_chars_dma */ -+ -+static void -+start_transmit(struct e100_serial *info) -+{ -+#if 0 -+ if (info->line == SERIAL_DEBUG_LINE) -+ printk("x\n"); -+#endif -+ -+ info->tr_descr.sw_len = 0; -+ info->tr_descr.hw_len = 0; -+ info->tr_descr.status = 0; -+ info->tr_running = 1; -+ if (info->uses_dma_out) -+ transmit_chars_dma(info); -+ else -+ e100_enable_serial_tx_ready_irq(info); -+} /* start_transmit */ -+ -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+static int serial_fast_timer_started = 0; -+static int serial_fast_timer_expired = 0; -+static void flush_timeout_function(unsigned long data); -+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\ -+ unsigned long timer_flags; \ -+ local_irq_save(timer_flags); \ -+ if (fast_timers[info->line].function == NULL) { \ -+ serial_fast_timer_started++; \ -+ TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \ -+ TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \ -+ start_one_shot_timer(&fast_timers[info->line], \ -+ flush_timeout_function, \ -+ (unsigned long)info, \ -+ (usec), \ -+ string); \ -+ } \ -+ else { \ -+ TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \ -+ } \ -+ local_irq_restore(timer_flags); \ -+} -+#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec) -+ -+#else -+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) -+#define START_FLUSH_FAST_TIMER(info, string) -+#endif -+ -+static struct etrax_recv_buffer * -+alloc_recv_buffer(unsigned int size) -+{ -+ struct etrax_recv_buffer *buffer; -+ -+ if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) -+ return NULL; -+ -+ buffer->next = NULL; -+ buffer->length = 0; -+ buffer->error = TTY_NORMAL; -+ -+ return buffer; -+} -+ -+static void -+append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ if (!info->first_recv_buffer) -+ info->first_recv_buffer = buffer; -+ else -+ info->last_recv_buffer->next = buffer; -+ -+ info->last_recv_buffer = buffer; -+ -+ info->recv_cnt += buffer->length; -+ if (info->recv_cnt > info->max_recv_cnt) -+ info->max_recv_cnt = info->recv_cnt; -+ -+ local_irq_restore(flags); -+} -+ -+static int -+add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) -+{ -+ struct etrax_recv_buffer *buffer; -+ if (info->uses_dma_in) { -+ if (!(buffer = alloc_recv_buffer(4))) -+ return 0; -+ -+ buffer->length = 1; -+ buffer->error = flag; -+ buffer->buffer[0] = data; -+ -+ append_recv_buffer(info, buffer); -+ -+ info->icount.rx++; -+ } else { -+ struct tty_struct *tty = info->port.tty; -+ tty_insert_flip_char(tty, data, flag); -+ info->icount.rx++; -+ } -+ -+ return 1; -+} -+ -+static unsigned int handle_descr_data(struct e100_serial *info, -+ struct etrax_dma_descr *descr, -+ unsigned int recvl) -+{ -+ struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; -+ -+ if (info->recv_cnt + recvl > 65536) { -+ printk(KERN_CRIT -+ "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl); -+ return 0; -+ } -+ -+ buffer->length = recvl; -+ -+ if (info->errorcode == ERRCODE_SET_BREAK) -+ buffer->error = TTY_BREAK; -+ info->errorcode = 0; -+ -+ append_recv_buffer(info, buffer); -+ -+ if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) -+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__); -+ -+ descr->buf = virt_to_phys(buffer->buffer); -+ -+ return recvl; -+} -+ -+static unsigned int handle_all_descr_data(struct e100_serial *info) -+{ -+ struct etrax_dma_descr *descr; -+ unsigned int recvl; -+ unsigned int ret = 0; -+ -+ while (1) -+ { -+ descr = &info->rec_descr[info->cur_rec_descr]; -+ -+ if (descr == phys_to_virt(*info->idescradr)) -+ break; -+ -+ if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS) -+ info->cur_rec_descr = 0; -+ -+ /* find out how many bytes were read */ -+ -+ /* if the eop bit was not set, all data has been received */ -+ if (!(descr->status & d_eop)) { -+ recvl = descr->sw_len; -+ } else { -+ /* otherwise we find the amount of data received here */ -+ recvl = descr->hw_len; -+ } -+ -+ /* Reset the status information */ -+ descr->status = 0; -+ -+ DFLOW( DEBUG_LOG(info->line, "RX %lu\n", recvl); -+ if (info->port.tty->stopped) { -+ unsigned char *buf = phys_to_virt(descr->buf); -+ DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]); -+ DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]); -+ DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]); -+ } -+ ); -+ -+ /* update stats */ -+ info->icount.rx += recvl; -+ -+ ret += handle_descr_data(info, descr, recvl); -+ } -+ -+ return ret; -+} -+ -+static void receive_chars_dma(struct e100_serial *info) -+{ -+ struct tty_struct *tty; -+ unsigned char rstat; -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* No receive in the simulator. Will probably be when the rest of -+ * the serial interface works, and this piece will just be removed. -+ */ -+ return; -+#endif -+ -+ /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ -+ *info->iclrintradr = -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); -+ -+ tty = info->port.tty; -+ if (!tty) /* Something wrong... */ -+ return; -+ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+ if (info->uses_dma_in) -+ e100_enable_serial_data_irq(info); -+#endif -+ -+ if (info->errorcode == ERRCODE_INSERT_BREAK) -+ add_char_and_flag(info, '\0', TTY_BREAK); -+ -+ handle_all_descr_data(info); -+ -+ /* Read the status register to detect errors */ -+ rstat = info->ioport[REG_STATUS]; -+ if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { -+ DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat)); -+ } -+ -+ if (rstat & SER_ERROR_MASK) { -+ /* If we got an error, we must reset it by reading the -+ * data_in field -+ */ -+ unsigned char data = info->ioport[REG_DATA]; -+ -+ PROCSTAT(ser_stat[info->line].errors_cnt++); -+ DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", -+ ((rstat & SER_ERROR_MASK) << 8) | data); -+ -+ if (rstat & SER_PAR_ERR_MASK) -+ add_char_and_flag(info, data, TTY_PARITY); -+ else if (rstat & SER_OVERRUN_MASK) -+ add_char_and_flag(info, data, TTY_OVERRUN); -+ else if (rstat & SER_FRAMING_ERR_MASK) -+ add_char_and_flag(info, data, TTY_FRAME); -+ } -+ -+ START_FLUSH_FAST_TIMER(info, "receive_chars"); -+ -+ /* Restart the receiving DMA */ -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); -+} -+ -+static int start_recv_dma(struct e100_serial *info) -+{ -+ struct etrax_dma_descr *descr = info->rec_descr; -+ struct etrax_recv_buffer *buffer; -+ int i; -+ -+ /* Set up the receiving descriptors */ -+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { -+ if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) -+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__); -+ -+ descr[i].ctrl = d_int; -+ descr[i].buf = virt_to_phys(buffer->buffer); -+ descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; -+ descr[i].hw_len = 0; -+ descr[i].status = 0; -+ descr[i].next = virt_to_phys(&descr[i+1]); -+ } -+ -+ /* Link the last descriptor to the first */ -+ descr[i-1].next = virt_to_phys(&descr[0]); -+ -+ /* Start with the first descriptor in the list */ -+ info->cur_rec_descr = 0; -+ -+ /* Start the DMA */ -+ *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]); -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); -+ -+ /* Input DMA should be running now */ -+ return 1; -+} -+ -+static void -+start_receive(struct e100_serial *info) -+{ -+#ifdef CONFIG_SVINTO_SIM -+ /* No receive in the simulator. Will probably be when the rest of -+ * the serial interface works, and this piece will just be removed. -+ */ -+ return; -+#endif -+ if (info->uses_dma_in) { -+ /* reset the input dma channel to be sure it works */ -+ -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == -+ IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); -+ -+ start_recv_dma(info); -+ } -+} -+ -+ -+/* the bits in the MASK2 register are laid out like this: -+ DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR -+ where I is the input channel and O is the output channel for the port. -+ info->irq is the bit number for the DMAO_DESCR so to check the others we -+ shift info->irq to the left. -+*/ -+ -+/* dma output channel interrupt handler -+ this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or -+ DMA8(ser1) when they have finished a descriptor with the intr flag set. -+*/ -+ -+static irqreturn_t -+tr_interrupt(int irq, void *dev_id) -+{ -+ struct e100_serial *info; -+ unsigned long ireg; -+ int i; -+ int handled = 0; -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* No receive in the simulator. Will probably be when the rest of -+ * the serial interface works, and this piece will just be removed. -+ */ -+ { -+ const char *s = "What? tr_interrupt in simulator??\n"; -+ SIMCOUT(s,strlen(s)); -+ } -+ return IRQ_HANDLED; -+#endif -+ -+ /* find out the line that caused this irq and get it from rs_table */ -+ -+ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ info = rs_table + i; -+ if (!info->enabled || !info->uses_dma_out) -+ continue; -+ /* check for dma_descr (don't need to check for dma_eop in output dma for serial */ -+ if (ireg & info->irq) { -+ handled = 1; -+ /* we can send a new dma bunch. make it so. */ -+ DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i)); -+ /* Read jiffies_usec first, -+ * we want this time to be as late as possible -+ */ -+ PROCSTAT(ser_stat[info->line].tx_dma_ints++); -+ info->last_tx_active_usec = GET_JIFFIES_USEC(); -+ info->last_tx_active = jiffies; -+ transmit_chars_dma(info); -+ } -+ -+ /* FIXME: here we should really check for a change in the -+ status lines and if so call status_handle(info) */ -+ } -+ return IRQ_RETVAL(handled); -+} /* tr_interrupt */ -+ -+/* dma input channel interrupt handler */ -+ -+static irqreturn_t -+rec_interrupt(int irq, void *dev_id) -+{ -+ struct e100_serial *info; -+ unsigned long ireg; -+ int i; -+ int handled = 0; -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* No receive in the simulator. Will probably be when the rest of -+ * the serial interface works, and this piece will just be removed. -+ */ -+ { -+ const char *s = "What? rec_interrupt in simulator??\n"; -+ SIMCOUT(s,strlen(s)); -+ } -+ return IRQ_HANDLED; -+#endif -+ -+ /* find out the line that caused this irq and get it from rs_table */ -+ -+ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ info = rs_table + i; -+ if (!info->enabled || !info->uses_dma_in) -+ continue; -+ /* check for both dma_eop and dma_descr for the input dma channel */ -+ if (ireg & ((info->irq << 2) | (info->irq << 3))) { -+ handled = 1; -+ /* we have received something */ -+ receive_chars_dma(info); -+ } -+ -+ /* FIXME: here we should really check for a change in the -+ status lines and if so call status_handle(info) */ -+ } -+ return IRQ_RETVAL(handled); -+} /* rec_interrupt */ -+ -+static int force_eop_if_needed(struct e100_serial *info) -+{ -+ /* We check data_avail bit to determine if data has -+ * arrived since last time -+ */ -+ unsigned char rstat = info->ioport[REG_STATUS]; -+ -+ /* error or datavail? */ -+ if (rstat & SER_ERROR_MASK) { -+ /* Some error has occurred. If there has been valid data, an -+ * EOP interrupt will be made automatically. If no data, the -+ * normal ser_interrupt should be enabled and handle it. -+ * So do nothing! -+ */ -+ DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n", -+ rstat | (info->line << 8)); -+ return 0; -+ } -+ -+ if (rstat & SER_DATA_AVAIL_MASK) { -+ /* Ok data, no error, count it */ -+ TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", -+ rstat | (info->line << 8))); -+ /* Read data to clear status flags */ -+ (void)info->ioport[REG_DATA]; -+ -+ info->forced_eop = 0; -+ START_FLUSH_FAST_TIMER(info, "magic"); -+ return 0; -+ } -+ -+ /* hit the timeout, force an EOP for the input -+ * dma channel if we haven't already -+ */ -+ if (!info->forced_eop) { -+ info->forced_eop = 1; -+ PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); -+ TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line)); -+ FORCE_EOP(info); -+ } -+ -+ return 1; -+} -+ -+static void flush_to_flip_buffer(struct e100_serial *info) -+{ -+ struct tty_struct *tty; -+ struct etrax_recv_buffer *buffer; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ tty = info->port.tty; -+ -+ if (!tty) { -+ local_irq_restore(flags); -+ return; -+ } -+ -+ while ((buffer = info->first_recv_buffer) != NULL) { -+ unsigned int count = buffer->length; -+ -+ tty_insert_flip_string(tty, buffer->buffer, count); -+ info->recv_cnt -= count; -+ -+ if (count == buffer->length) { -+ info->first_recv_buffer = buffer->next; -+ kfree(buffer); -+ } else { -+ buffer->length -= count; -+ memmove(buffer->buffer, buffer->buffer + count, buffer->length); -+ buffer->error = TTY_NORMAL; -+ } -+ } -+ -+ if (!info->first_recv_buffer) -+ info->last_recv_buffer = NULL; -+ -+ local_irq_restore(flags); -+ -+ /* This includes a check for low-latency */ -+ tty_flip_buffer_push(tty); -+} -+ -+static void check_flush_timeout(struct e100_serial *info) -+{ -+ /* Flip what we've got (if we can) */ -+ flush_to_flip_buffer(info); -+ -+ /* We might need to flip later, but not to fast -+ * since the system is busy processing input... */ -+ if (info->first_recv_buffer) -+ START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000); -+ -+ /* Force eop last, since data might have come while we're processing -+ * and if we started the slow timer above, we won't start a fast -+ * below. -+ */ -+ force_eop_if_needed(info); -+} -+ -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+static void flush_timeout_function(unsigned long data) -+{ -+ struct e100_serial *info = (struct e100_serial *)data; -+ -+ fast_timers[info->line].function = NULL; -+ serial_fast_timer_expired++; -+ TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); -+ TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired)); -+ check_flush_timeout(info); -+} -+ -+#else -+ -+/* dma fifo/buffer timeout handler -+ forces an end-of-packet for the dma input channel if no chars -+ have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s. -+*/ -+ -+static struct timer_list flush_timer; -+ -+static void -+timed_flush_handler(unsigned long ptr) -+{ -+ struct e100_serial *info; -+ int i; -+ -+#ifdef CONFIG_SVINTO_SIM -+ return; -+#endif -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ info = rs_table + i; -+ if (info->uses_dma_in) -+ check_flush_timeout(info); -+ } -+ -+ /* restart flush timer */ -+ mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); -+} -+#endif -+ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+ -+/* If there is an error (ie break) when the DMA is running and -+ * there are no bytes in the fifo the DMA is stopped and we get no -+ * eop interrupt. Thus we have to monitor the first bytes on a DMA -+ * transfer, and if it is without error we can turn the serial -+ * interrupts off. -+ */ -+ -+/* -+BREAK handling on ETRAX 100: -+ETRAX will generate interrupt although there is no stop bit between the -+characters. -+ -+Depending on how long the break sequence is, the end of the breaksequence -+will look differently: -+| indicates start/end of a character. -+ -+B= Break character (0x00) with framing error. -+E= Error byte with parity error received after B characters. -+F= "Faked" valid byte received immediately after B characters. -+V= Valid byte -+ -+1. -+ B BL ___________________________ V -+.._|__________|__________| |valid data | -+ -+Multiple frame errors with data == 0x00 (B), -+the timing matches up "perfectly" so no extra ending char is detected. -+The RXD pin is 1 in the last interrupt, in that case -+we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really -+know if another byte will come and this really is case 2. below -+(e.g F=0xFF or 0xFE) -+If RXD pin is 0 we can expect another character (see 2. below). -+ -+ -+2. -+ -+ B B E or F__________________..__ V -+.._|__________|__________|______ | |valid data -+ "valid" or -+ parity error -+ -+Multiple frame errors with data == 0x00 (B), -+but the part of the break trigs is interpreted as a start bit (and possibly -+some 0 bits followed by a number of 1 bits and a stop bit). -+Depending on parity settings etc. this last character can be either -+a fake "valid" char (F) or have a parity error (E). -+ -+If the character is valid it will be put in the buffer, -+we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt -+will set the flags so the tty will handle it, -+if it's an error byte it will not be put in the buffer -+and we set info->errorcode = ERRCODE_INSERT_BREAK. -+ -+To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp -+of the last faulty char (B) and compares it with the current time: -+If the time elapsed time is less then 2*char_time_usec we will assume -+it's a faked F char and not a Valid char and set -+info->errorcode = ERRCODE_SET_BREAK. -+ -+Flaws in the above solution: -+~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+We use the timer to distinguish a F character from a V character, -+if a V character is to close after the break we might make the wrong decision. -+ -+TODO: The break will be delayed until an F or V character is received. -+ -+*/ -+ -+static -+struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) -+{ -+ unsigned long data_read; -+ struct tty_struct *tty = info->port.tty; -+ -+ if (!tty) { -+ printk("!NO TTY!\n"); -+ return info; -+ } -+ -+ /* Read data and status at the same time */ -+ data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); -+more_data: -+ if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) { -+ DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); -+ } -+ DINTR2(DEBUG_LOG(info->line, "ser_rx %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read))); -+ -+ if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) | -+ IO_MASK(R_SERIAL0_READ, par_err) | -+ IO_MASK(R_SERIAL0_READ, overrun) )) { -+ /* An error */ -+ info->last_rx_active_usec = GET_JIFFIES_USEC(); -+ info->last_rx_active = jiffies; -+ DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read)); -+ DLOG_INT_TRIG( -+ if (!log_int_trig1_pos) { -+ log_int_trig1_pos = log_int_pos; -+ log_int(rdpc(), 0, 0); -+ } -+ ); -+ -+ -+ if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) && -+ (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) { -+ /* Most likely a break, but we get interrupts over and -+ * over again. -+ */ -+ -+ if (!info->break_detected_cnt) { -+ DEBUG_LOG(info->line, "#BRK start\n", 0); -+ } -+ if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) { -+ /* The RX pin is high now, so the break -+ * must be over, but.... -+ * we can't really know if we will get another -+ * last byte ending the break or not. -+ * And we don't know if the byte (if any) will -+ * have an error or look valid. -+ */ -+ DEBUG_LOG(info->line, "# BL BRK\n", 0); -+ info->errorcode = ERRCODE_INSERT_BREAK; -+ } -+ info->break_detected_cnt++; -+ } else { -+ /* The error does not look like a break, but could be -+ * the end of one -+ */ -+ if (info->break_detected_cnt) { -+ DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); -+ info->errorcode = ERRCODE_INSERT_BREAK; -+ } else { -+ unsigned char data = IO_EXTRACT(R_SERIAL0_READ, -+ data_in, data_read); -+ char flag = TTY_NORMAL; -+ if (info->errorcode == ERRCODE_INSERT_BREAK) { -+ struct tty_struct *tty = info->port.tty; -+ tty_insert_flip_char(tty, 0, flag); -+ info->icount.rx++; -+ } -+ -+ if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) { -+ info->icount.parity++; -+ flag = TTY_PARITY; -+ } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) { -+ info->icount.overrun++; -+ flag = TTY_OVERRUN; -+ } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) { -+ info->icount.frame++; -+ flag = TTY_FRAME; -+ } -+ tty_insert_flip_char(tty, data, flag); -+ info->errorcode = 0; -+ } -+ info->break_detected_cnt = 0; -+ } -+ } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { -+ /* No error */ -+ DLOG_INT_TRIG( -+ if (!log_int_trig1_pos) { -+ if (log_int_pos >= log_int_size) { -+ log_int_pos = 0; -+ } -+ log_int_trig0_pos = log_int_pos; -+ log_int(rdpc(), 0, 0); -+ } -+ ); -+ tty_insert_flip_char(tty, -+ IO_EXTRACT(R_SERIAL0_READ, data_in, data_read), -+ TTY_NORMAL); -+ } else { -+ DEBUG_LOG(info->line, "ser_rx int but no data_avail %08lX\n", data_read); -+ } -+ -+ -+ info->icount.rx++; -+ data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); -+ if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { -+ DEBUG_LOG(info->line, "ser_rx %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)); -+ goto more_data; -+ } -+ -+ tty_flip_buffer_push(info->port.tty); -+ return info; -+} -+ -+static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) -+{ -+ unsigned char rstat; -+ -+#ifdef SERIAL_DEBUG_INTR -+ printk("Interrupt from serport %d\n", i); -+#endif -+/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ -+ if (!info->uses_dma_in) { -+ return handle_ser_rx_interrupt_no_dma(info); -+ } -+ /* DMA is used */ -+ rstat = info->ioport[REG_STATUS]; -+ if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { -+ DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); -+ } -+ -+ if (rstat & SER_ERROR_MASK) { -+ unsigned char data; -+ -+ info->last_rx_active_usec = GET_JIFFIES_USEC(); -+ info->last_rx_active = jiffies; -+ /* If we got an error, we must reset it by reading the -+ * data_in field -+ */ -+ data = info->ioport[REG_DATA]; -+ DINTR1(DEBUG_LOG(info->line, "ser_rx! %c\n", data)); -+ DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat)); -+ if (!data && (rstat & SER_FRAMING_ERR_MASK)) { -+ /* Most likely a break, but we get interrupts over and -+ * over again. -+ */ -+ -+ if (!info->break_detected_cnt) { -+ DEBUG_LOG(info->line, "#BRK start\n", 0); -+ } -+ if (rstat & SER_RXD_MASK) { -+ /* The RX pin is high now, so the break -+ * must be over, but.... -+ * we can't really know if we will get another -+ * last byte ending the break or not. -+ * And we don't know if the byte (if any) will -+ * have an error or look valid. -+ */ -+ DEBUG_LOG(info->line, "# BL BRK\n", 0); -+ info->errorcode = ERRCODE_INSERT_BREAK; -+ } -+ info->break_detected_cnt++; -+ } else { -+ /* The error does not look like a break, but could be -+ * the end of one -+ */ -+ if (info->break_detected_cnt) { -+ DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); -+ info->errorcode = ERRCODE_INSERT_BREAK; -+ } else { -+ if (info->errorcode == ERRCODE_INSERT_BREAK) { -+ info->icount.brk++; -+ add_char_and_flag(info, '\0', TTY_BREAK); -+ } -+ -+ if (rstat & SER_PAR_ERR_MASK) { -+ info->icount.parity++; -+ add_char_and_flag(info, data, TTY_PARITY); -+ } else if (rstat & SER_OVERRUN_MASK) { -+ info->icount.overrun++; -+ add_char_and_flag(info, data, TTY_OVERRUN); -+ } else if (rstat & SER_FRAMING_ERR_MASK) { -+ info->icount.frame++; -+ add_char_and_flag(info, data, TTY_FRAME); -+ } -+ -+ info->errorcode = 0; -+ } -+ info->break_detected_cnt = 0; -+ DEBUG_LOG(info->line, "#iERR s d %04X\n", -+ ((rstat & SER_ERROR_MASK) << 8) | data); -+ } -+ PROCSTAT(ser_stat[info->line].early_errors_cnt++); -+ } else { /* It was a valid byte, now let the DMA do the rest */ -+ unsigned long curr_time_u = GET_JIFFIES_USEC(); -+ unsigned long curr_time = jiffies; -+ -+ if (info->break_detected_cnt) { -+ /* Detect if this character is a new valid char or the -+ * last char in a break sequence: If LSBits are 0 and -+ * MSBits are high AND the time is close to the -+ * previous interrupt we should discard it. -+ */ -+ long elapsed_usec = -+ (curr_time - info->last_rx_active) * (1000000/HZ) + -+ curr_time_u - info->last_rx_active_usec; -+ if (elapsed_usec < 2*info->char_time_usec) { -+ DEBUG_LOG(info->line, "FBRK %i\n", info->line); -+ /* Report as BREAK (error) and let -+ * receive_chars_dma() handle it -+ */ -+ info->errorcode = ERRCODE_SET_BREAK; -+ } else { -+ DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line); -+ } -+ DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt); -+ } -+ -+#ifdef SERIAL_DEBUG_INTR -+ printk("** OK, disabling ser_interrupts\n"); -+#endif -+ e100_disable_serial_data_irq(info); -+ DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line)); -+ info->break_detected_cnt = 0; -+ -+ PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); -+ } -+ /* Restarting the DMA never hurts */ -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); -+ START_FLUSH_FAST_TIMER(info, "ser_int"); -+ return info; -+} /* handle_ser_rx_interrupt */ -+ -+static void handle_ser_tx_interrupt(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ if (info->x_char) { -+ unsigned char rstat; -+ DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char)); -+ local_irq_save(flags); -+ rstat = info->ioport[REG_STATUS]; -+ DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); -+ -+ info->ioport[REG_TR_DATA] = info->x_char; -+ info->icount.tx++; -+ info->x_char = 0; -+ /* We must enable since it is disabled in ser_interrupt */ -+ e100_enable_serial_tx_ready_irq(info); -+ local_irq_restore(flags); -+ return; -+ } -+ if (info->uses_dma_out) { -+ unsigned char rstat; -+ int i; -+ /* We only use normal tx interrupt when sending x_char */ -+ DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0)); -+ local_irq_save(flags); -+ rstat = info->ioport[REG_STATUS]; -+ DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); -+ e100_disable_serial_tx_ready_irq(info); -+ if (info->port.tty->stopped) -+ rs_stop(info->port.tty); -+ /* Enable the DMA channel and tell it to continue */ -+ e100_enable_txdma_channel(info); -+ /* Wait 12 cycles before doing the DMA command */ -+ for(i = 6; i > 0; i--) -+ nop(); -+ -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue); -+ local_irq_restore(flags); -+ return; -+ } -+ /* Normal char-by-char interrupt */ -+ if (info->xmit.head == info->xmit.tail -+ || info->port.tty->stopped -+ || info->port.tty->hw_stopped) { -+ DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", -+ info->port.tty->stopped)); -+ e100_disable_serial_tx_ready_irq(info); -+ info->tr_running = 0; -+ return; -+ } -+ DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail])); -+ /* Send a byte, rs485 timing is critical so turn of ints */ -+ local_irq_save(flags); -+ info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail]; -+ info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); -+ info->icount.tx++; -+ if (info->xmit.head == info->xmit.tail) { -+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) -+ if (info->rs485.flags & SER_RS485_ENABLED) { -+ /* Set a short timer to toggle RTS */ -+ start_one_shot_timer(&fast_timers_rs485[info->line], -+ rs485_toggle_rts_timer_function, -+ (unsigned long)info, -+ info->char_time_usec*2, -+ "RS-485"); -+ } -+#endif /* RS485 */ -+ info->last_tx_active_usec = GET_JIFFIES_USEC(); -+ info->last_tx_active = jiffies; -+ e100_disable_serial_tx_ready_irq(info); -+ info->tr_running = 0; -+ DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0)); -+ } else { -+ /* We must enable since it is disabled in ser_interrupt */ -+ e100_enable_serial_tx_ready_irq(info); -+ } -+ local_irq_restore(flags); -+ -+ if (CIRC_CNT(info->xmit.head, -+ info->xmit.tail, -+ SERIAL_XMIT_SIZE) < WAKEUP_CHARS) -+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); -+ -+} /* handle_ser_tx_interrupt */ -+ -+/* result of time measurements: -+ * RX duration 54-60 us when doing something, otherwise 6-9 us -+ * ser_int duration: just sending: 8-15 us normally, up to 73 us -+ */ -+static irqreturn_t -+ser_interrupt(int irq, void *dev_id) -+{ -+ static volatile int tx_started = 0; -+ struct e100_serial *info; -+ int i; -+ unsigned long flags; -+ unsigned long irq_mask1_rd; -+ unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */ -+ int handled = 0; -+ static volatile unsigned long reentered_ready_mask = 0; -+ -+ local_irq_save(flags); -+ irq_mask1_rd = *R_IRQ_MASK1_RD; -+ /* First handle all rx interrupts with ints disabled */ -+ info = rs_table; -+ irq_mask1_rd &= e100_ser_int_mask; -+ for (i = 0; i < NR_PORTS; i++) { -+ /* Which line caused the data irq? */ -+ if (irq_mask1_rd & data_mask) { -+ handled = 1; -+ handle_ser_rx_interrupt(info); -+ } -+ info += 1; -+ data_mask <<= 2; -+ } -+ /* Handle tx interrupts with interrupts enabled so we -+ * can take care of new data interrupts while transmitting -+ * We protect the tx part with the tx_started flag. -+ * We disable the tr_ready interrupts we are about to handle and -+ * unblock the serial interrupt so new serial interrupts may come. -+ * -+ * If we get a new interrupt: -+ * - it migth be due to synchronous serial ports. -+ * - serial irq will be blocked by general irq handler. -+ * - async data will be handled above (sync will be ignored). -+ * - tx_started flag will prevent us from trying to send again and -+ * we will exit fast - no need to unblock serial irq. -+ * - Next (sync) serial interrupt handler will be runned with -+ * disabled interrupt due to restore_flags() at end of function, -+ * so sync handler will not be preempted or reentered. -+ */ -+ if (!tx_started) { -+ unsigned long ready_mask; -+ unsigned long -+ tx_started = 1; -+ /* Only the tr_ready interrupts left */ -+ irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser1_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser2_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser3_ready)); -+ while (irq_mask1_rd) { -+ /* Disable those we are about to handle */ -+ *R_IRQ_MASK1_CLR = irq_mask1_rd; -+ /* Unblock the serial interrupt */ -+ *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); -+ -+ local_irq_enable(); -+ ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */ -+ info = rs_table; -+ for (i = 0; i < NR_PORTS; i++) { -+ /* Which line caused the ready irq? */ -+ if (irq_mask1_rd & ready_mask) { -+ handled = 1; -+ handle_ser_tx_interrupt(info); -+ } -+ info += 1; -+ ready_mask <<= 2; -+ } -+ /* handle_ser_tx_interrupt enables tr_ready interrupts */ -+ local_irq_disable(); -+ /* Handle reentered TX interrupt */ -+ irq_mask1_rd = reentered_ready_mask; -+ } -+ local_irq_disable(); -+ tx_started = 0; -+ } else { -+ unsigned long ready_mask; -+ ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser1_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser2_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser3_ready)); -+ if (ready_mask) { -+ reentered_ready_mask |= ready_mask; -+ /* Disable those we are about to handle */ -+ *R_IRQ_MASK1_CLR = ready_mask; -+ DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask)); -+ } -+ } -+ -+ local_irq_restore(flags); -+ return IRQ_RETVAL(handled); -+} /* ser_interrupt */ -+#endif -+ -+/* -+ * ------------------------------------------------------------------- -+ * Here ends the serial interrupt routines. -+ * ------------------------------------------------------------------- -+ */ -+ -+/* -+ * This routine is used to handle the "bottom half" processing for the -+ * serial driver, known also the "software interrupt" processing. -+ * This processing is done at the kernel interrupt level, after the -+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This -+ * is where time-consuming activities which can not be done in the -+ * interrupt driver proper are done; the interrupt driver schedules -+ * them using rs_sched_event(), and they get done here. -+ */ -+static void -+do_softint(struct work_struct *work) -+{ -+ struct e100_serial *info; -+ struct tty_struct *tty; -+ -+ info = container_of(work, struct e100_serial, work); -+ -+ tty = info->port.tty; -+ if (!tty) -+ return; -+ -+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) -+ tty_wakeup(tty); -+} -+ -+static int -+startup(struct e100_serial * info) -+{ -+ unsigned long flags; -+ unsigned long xmit_page; -+ int i; -+ -+ xmit_page = get_zeroed_page(GFP_KERNEL); -+ if (!xmit_page) -+ return -ENOMEM; -+ -+ local_irq_save(flags); -+ -+ /* if it was already initialized, skip this */ -+ -+ if (info->flags & ASYNC_INITIALIZED) { -+ local_irq_restore(flags); -+ free_page(xmit_page); -+ return 0; -+ } -+ -+ if (info->xmit.buf) -+ free_page(xmit_page); -+ else -+ info->xmit.buf = (unsigned char *) xmit_page; -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf); -+#endif -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* Bits and pieces collected from below. Better to have them -+ in one ifdef:ed clause than to mix in a lot of ifdefs, -+ right? */ -+ if (info->port.tty) -+ clear_bit(TTY_IO_ERROR, &info->port.tty->flags); -+ -+ info->xmit.head = info->xmit.tail = 0; -+ info->first_recv_buffer = info->last_recv_buffer = NULL; -+ info->recv_cnt = info->max_recv_cnt = 0; -+ -+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) -+ info->rec_descr[i].buf = NULL; -+ -+ /* No real action in the simulator, but may set info important -+ to ioctl. */ -+ change_speed(info); -+#else -+ -+ /* -+ * Clear the FIFO buffers and disable them -+ * (they will be reenabled in change_speed()) -+ */ -+ -+ /* -+ * Reset the DMA channels and make sure their interrupts are cleared -+ */ -+ -+ if (info->dma_in_enabled) { -+ info->uses_dma_in = 1; -+ e100_enable_rxdma_channel(info); -+ -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ -+ /* Wait until reset cycle is complete */ -+ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == -+ IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); -+ -+ /* Make sure the irqs are cleared */ -+ *info->iclrintradr = -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); -+ } else { -+ e100_disable_rxdma_channel(info); -+ } -+ -+ if (info->dma_out_enabled) { -+ info->uses_dma_out = 1; -+ e100_enable_txdma_channel(info); -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ -+ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == -+ IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); -+ -+ /* Make sure the irqs are cleared */ -+ *info->oclrintradr = -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); -+ } else { -+ e100_disable_txdma_channel(info); -+ } -+ -+ if (info->port.tty) -+ clear_bit(TTY_IO_ERROR, &info->port.tty->flags); -+ -+ info->xmit.head = info->xmit.tail = 0; -+ info->first_recv_buffer = info->last_recv_buffer = NULL; -+ info->recv_cnt = info->max_recv_cnt = 0; -+ -+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) -+ info->rec_descr[i].buf = 0; -+ -+ /* -+ * and set the speed and other flags of the serial port -+ * this will start the rx/tx as well -+ */ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+ e100_enable_serial_data_irq(info); -+#endif -+ change_speed(info); -+ -+ /* dummy read to reset any serial errors */ -+ -+ (void)info->ioport[REG_DATA]; -+ -+ /* enable the interrupts */ -+ if (info->uses_dma_out) -+ e100_enable_txdma_irq(info); -+ -+ e100_enable_rx_irq(info); -+ -+ info->tr_running = 0; /* to be sure we don't lock up the transmitter */ -+ -+ /* setup the dma input descriptor and start dma */ -+ -+ start_receive(info); -+ -+ /* for safety, make sure the descriptors last result is 0 bytes written */ -+ -+ info->tr_descr.sw_len = 0; -+ info->tr_descr.hw_len = 0; -+ info->tr_descr.status = 0; -+ -+ /* enable RTS/DTR last */ -+ -+ e100_rts(info, 1); -+ e100_dtr(info, 1); -+ -+#endif /* CONFIG_SVINTO_SIM */ -+ -+ info->flags |= ASYNC_INITIALIZED; -+ -+ local_irq_restore(flags); -+ return 0; -+} -+ -+/* -+ * This routine will shutdown a serial port; interrupts are disabled, and -+ * DTR is dropped if the hangup on close termio flag is on. -+ */ -+static void -+shutdown(struct e100_serial * info) -+{ -+ unsigned long flags; -+ struct etrax_dma_descr *descr = info->rec_descr; -+ struct etrax_recv_buffer *buffer; -+ int i; -+ -+#ifndef CONFIG_SVINTO_SIM -+ /* shut down the transmitter and receiver */ -+ DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line)); -+ e100_disable_rx(info); -+ info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); -+ -+ /* disable interrupts, reset dma channels */ -+ if (info->uses_dma_in) { -+ e100_disable_rxdma_irq(info); -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ info->uses_dma_in = 0; -+ } else { -+ e100_disable_serial_data_irq(info); -+ } -+ -+ if (info->uses_dma_out) { -+ e100_disable_txdma_irq(info); -+ info->tr_running = 0; -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ info->uses_dma_out = 0; -+ } else { -+ e100_disable_serial_tx_ready_irq(info); -+ info->tr_running = 0; -+ } -+ -+#endif /* CONFIG_SVINTO_SIM */ -+ -+ if (!(info->flags & ASYNC_INITIALIZED)) -+ return; -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("Shutting down serial port %d (irq %d)....\n", info->line, -+ info->irq); -+#endif -+ -+ local_irq_save(flags); -+ -+ if (info->xmit.buf) { -+ free_page((unsigned long)info->xmit.buf); -+ info->xmit.buf = NULL; -+ } -+ -+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) -+ if (descr[i].buf) { -+ buffer = phys_to_virt(descr[i].buf) - sizeof *buffer; -+ kfree(buffer); -+ descr[i].buf = 0; -+ } -+ -+ if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { -+ /* hang up DTR and RTS if HUPCL is enabled */ -+ e100_dtr(info, 0); -+ e100_rts(info, 0); /* could check CRTSCTS before doing this */ -+ } -+ -+ if (info->port.tty) -+ set_bit(TTY_IO_ERROR, &info->port.tty->flags); -+ -+ info->flags &= ~ASYNC_INITIALIZED; -+ local_irq_restore(flags); -+} -+ -+ -+/* change baud rate and other assorted parameters */ -+ -+static void -+change_speed(struct e100_serial *info) -+{ -+ unsigned int cflag; -+ unsigned long xoff; -+ unsigned long flags; -+ /* first some safety checks */ -+ -+ if (!info->port.tty || !info->port.tty->termios) -+ return; -+ if (!info->ioport) -+ return; -+ -+ cflag = info->port.tty->termios->c_cflag; -+ -+ /* possibly, the tx/rx should be disabled first to do this safely */ -+ -+ /* change baud-rate and write it to the hardware */ -+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { -+ /* Special baudrate */ -+ u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ -+ unsigned long alt_source = -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) | -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); -+ /* R_ALT_SER_BAUDRATE selects the source */ -+ DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n", -+ (unsigned long)info->baud_base, info->custom_divisor)); -+ if (info->baud_base == SERIAL_PRESCALE_BASE) { -+ /* 0, 2-65535 (0=65536) */ -+ u16 divisor = info->custom_divisor; -+ /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */ -+ /* baudrate is 3.125MHz/custom_divisor */ -+ alt_source = -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) | -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale); -+ alt_source = 0x11; -+ DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor)); -+ *R_SERIAL_PRESCALE = divisor; -+ info->baud = SERIAL_PRESCALE_BASE/divisor; -+ } -+#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED -+ else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 && -+ info->custom_divisor == 1) || -+ (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ && -+ info->custom_divisor == 8)) { -+ /* ext_clk selected */ -+ alt_source = -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) | -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern); -+ DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8)); -+ info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8; -+ } -+#endif -+ else -+ { -+ /* Bad baudbase, we don't support using timer0 -+ * for baudrate. -+ */ -+ printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n", -+ (unsigned long)info->baud_base, info->custom_divisor); -+ } -+ r_alt_ser_baudrate_shadow &= ~mask; -+ r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); -+ *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; -+ } else { -+ /* Normal baudrate */ -+ /* Make sure we use normal baudrate */ -+ u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ -+ unsigned long alt_source = -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) | -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); -+ r_alt_ser_baudrate_shadow &= ~mask; -+ r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); -+#ifndef CONFIG_SVINTO_SIM -+ *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; -+#endif /* CONFIG_SVINTO_SIM */ -+ -+ info->baud = cflag_to_baud(cflag); -+#ifndef CONFIG_SVINTO_SIM -+ info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); -+#endif /* CONFIG_SVINTO_SIM */ -+ } -+ -+#ifndef CONFIG_SVINTO_SIM -+ /* start with default settings and then fill in changes */ -+ local_irq_save(flags); -+ /* 8 bit, no/even parity */ -+ info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) | -+ IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) | -+ IO_MASK(R_SERIAL0_REC_CTRL, rec_par)); -+ -+ /* 8 bit, no/even parity, 1 stop bit, no cts */ -+ info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) | -+ IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) | -+ IO_MASK(R_SERIAL0_TR_CTRL, tr_par) | -+ IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) | -+ IO_MASK(R_SERIAL0_TR_CTRL, auto_cts)); -+ -+ if ((cflag & CSIZE) == CS7) { -+ /* set 7 bit mode */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); -+ } -+ -+ if (cflag & CSTOPB) { -+ /* set 2 stop bit mode */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits); -+ } -+ -+ if (cflag & PARENB) { -+ /* enable parity */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); -+ } -+ -+ if (cflag & CMSPAR) { -+ /* enable stick parity, PARODD mean Mark which matches ETRAX */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick); -+ } -+ if (cflag & PARODD) { -+ /* set odd parity (or Mark if CMSPAR) */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); -+ } -+ -+ if (cflag & CRTSCTS) { -+ /* enable automatic CTS handling */ -+ DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0)); -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active); -+ } -+ -+ /* make sure the tx and rx are enabled */ -+ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); -+ -+ /* actually write the control regs to the hardware */ -+ -+ info->ioport[REG_TR_CTRL] = info->tx_ctrl; -+ info->ioport[REG_REC_CTRL] = info->rx_ctrl; -+ xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); -+ xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); -+ if (info->port.tty->termios->c_iflag & IXON ) { -+ DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", -+ STOP_CHAR(info->port.tty))); -+ xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); -+ } -+ -+ *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; -+ local_irq_restore(flags); -+#endif /* !CONFIG_SVINTO_SIM */ -+ -+ update_char_time(info); -+ -+} /* change_speed */ -+ -+/* start transmitting chars NOW */ -+ -+static void -+rs_flush_chars(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ if (info->tr_running || -+ info->xmit.head == info->xmit.tail || -+ tty->stopped || -+ tty->hw_stopped || -+ !info->xmit.buf) -+ return; -+ -+#ifdef SERIAL_DEBUG_FLOW -+ printk("rs_flush_chars\n"); -+#endif -+ -+ /* this protection might not exactly be necessary here */ -+ -+ local_irq_save(flags); -+ start_transmit(info); -+ local_irq_restore(flags); -+} -+ -+static int rs_raw_write(struct tty_struct *tty, -+ const unsigned char *buf, int count) -+{ -+ int c, ret = 0; -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ /* first some sanity checks */ -+ -+ if (!tty || !info->xmit.buf || !tmp_buf) -+ return 0; -+ -+#ifdef SERIAL_DEBUG_DATA -+ if (info->line == SERIAL_DEBUG_LINE) -+ printk("rs_raw_write (%d), status %d\n", -+ count, info->ioport[REG_STATUS]); -+#endif -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* Really simple. The output is here and now. */ -+ SIMCOUT(buf, count); -+ return count; -+#endif -+ local_save_flags(flags); -+ DFLOW(DEBUG_LOG(info->line, "write count %i ", count)); -+ DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty))); -+ -+ -+ /* The local_irq_disable/restore_flags pairs below are needed -+ * because the DMA interrupt handler moves the info->xmit values. -+ * the memcpy needs to be in the critical region unfortunately, -+ * because we need to read xmit values, memcpy, write xmit values -+ * in one atomic operation... this could perhaps be avoided by -+ * more clever design. -+ */ -+ local_irq_disable(); -+ while (count) { -+ c = CIRC_SPACE_TO_END(info->xmit.head, -+ info->xmit.tail, -+ SERIAL_XMIT_SIZE); -+ -+ if (count < c) -+ c = count; -+ if (c <= 0) -+ break; -+ -+ memcpy(info->xmit.buf + info->xmit.head, buf, c); -+ info->xmit.head = (info->xmit.head + c) & -+ (SERIAL_XMIT_SIZE-1); -+ buf += c; -+ count -= c; -+ ret += c; -+ } -+ local_irq_restore(flags); -+ -+ /* enable transmitter if not running, unless the tty is stopped -+ * this does not need IRQ protection since if tr_running == 0 -+ * the IRQ's are not running anyway for this port. -+ */ -+ DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret)); -+ -+ if (info->xmit.head != info->xmit.tail && -+ !tty->stopped && -+ !tty->hw_stopped && -+ !info->tr_running) { -+ start_transmit(info); -+ } -+ -+ return ret; -+} /* raw_raw_write() */ -+ -+static int -+rs_write(struct tty_struct *tty, -+ const unsigned char *buf, int count) -+{ -+#if defined(CONFIG_ETRAX_RS485) -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ -+ if (info->rs485.flags & SER_RS485_ENABLED) -+ { -+ /* If we are in RS-485 mode, we need to toggle RTS and disable -+ * the receiver before initiating a DMA transfer -+ */ -+#ifdef CONFIG_ETRAX_FAST_TIMER -+ /* Abort any started timer */ -+ fast_timers_rs485[info->line].function = NULL; -+ del_fast_timer(&fast_timers_rs485[info->line]); -+#endif -+ e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND)); -+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) -+ e100_disable_rx(info); -+ e100_enable_rx_irq(info); -+#endif -+ if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) && -+ (info->rs485.delay_rts_before_send > 0)) -+ msleep(info->rs485.delay_rts_before_send); -+ } -+#endif /* CONFIG_ETRAX_RS485 */ -+ -+ count = rs_raw_write(tty, buf, count); -+ -+#if defined(CONFIG_ETRAX_RS485) -+ if (info->rs485.flags & SER_RS485_ENABLED) -+ { -+ unsigned int val; -+ /* If we are in RS-485 mode the following has to be done: -+ * wait until DMA is ready -+ * wait on transmit shift register -+ * toggle RTS -+ * enable the receiver -+ */ -+ -+ /* Sleep until all sent */ -+ tty_wait_until_sent(tty, 0); -+#ifdef CONFIG_ETRAX_FAST_TIMER -+ /* Now sleep a little more so that shift register is empty */ -+ schedule_usleep(info->char_time_usec * 2); -+#endif -+ /* wait on transmit shift register */ -+ do{ -+ get_lsr_info(info, &val); -+ }while (!(val & TIOCSER_TEMT)); -+ -+ e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); -+ -+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) -+ e100_enable_rx(info); -+ e100_enable_rxdma_irq(info); -+#endif -+ } -+#endif /* CONFIG_ETRAX_RS485 */ -+ -+ return count; -+} /* rs_write */ -+ -+ -+/* how much space is available in the xmit buffer? */ -+ -+static int -+rs_write_room(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ -+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -+} -+ -+/* How many chars are in the xmit buffer? -+ * This does not include any chars in the transmitter FIFO. -+ * Use wait_until_sent for waiting for FIFO drain. -+ */ -+ -+static int -+rs_chars_in_buffer(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ -+ return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -+} -+ -+/* discard everything in the xmit buffer */ -+ -+static void -+rs_flush_buffer(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ info->xmit.head = info->xmit.tail = 0; -+ local_irq_restore(flags); -+ -+ tty_wakeup(tty); -+} -+ -+/* -+ * This function is used to send a high-priority XON/XOFF character to -+ * the device -+ * -+ * Since we use DMA we don't check for info->x_char in transmit_chars_dma(), -+ * but we do it in handle_ser_tx_interrupt(). -+ * We disable DMA channel and enable tx ready interrupt and write the -+ * character when possible. -+ */ -+static void rs_send_xchar(struct tty_struct *tty, char ch) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ local_irq_save(flags); -+ if (info->uses_dma_out) { -+ /* Put the DMA on hold and disable the channel */ -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold); -+ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) != -+ IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold)); -+ e100_disable_txdma_channel(info); -+ } -+ -+ /* Must make sure transmitter is not stopped before we can transmit */ -+ if (tty->stopped) -+ rs_start(tty); -+ -+ /* Enable manual transmit interrupt and send from there */ -+ DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch)); -+ info->x_char = ch; -+ e100_enable_serial_tx_ready_irq(info); -+ local_irq_restore(flags); -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_throttle() -+ * -+ * This routine is called by the upper-layer tty layer to signal that -+ * incoming characters should be throttled. -+ * ------------------------------------------------------------ -+ */ -+static void -+rs_throttle(struct tty_struct * tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+#ifdef SERIAL_DEBUG_THROTTLE -+ char buf[64]; -+ -+ printk("throttle %s: %lu....\n", tty_name(tty, buf), -+ (unsigned long)tty->ldisc.chars_in_buffer(tty)); -+#endif -+ DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty))); -+ -+ /* Do RTS before XOFF since XOFF might take some time */ -+ if (tty->termios->c_cflag & CRTSCTS) { -+ /* Turn off RTS line */ -+ e100_rts(info, 0); -+ } -+ if (I_IXOFF(tty)) -+ rs_send_xchar(tty, STOP_CHAR(tty)); -+ -+} -+ -+static void -+rs_unthrottle(struct tty_struct * tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+#ifdef SERIAL_DEBUG_THROTTLE -+ char buf[64]; -+ -+ printk("unthrottle %s: %lu....\n", tty_name(tty, buf), -+ (unsigned long)tty->ldisc.chars_in_buffer(tty)); -+#endif -+ DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty))); -+ DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count)); -+ /* Do RTS before XOFF since XOFF might take some time */ -+ if (tty->termios->c_cflag & CRTSCTS) { -+ /* Assert RTS line */ -+ e100_rts(info, 1); -+ } -+ -+ if (I_IXOFF(tty)) { -+ if (info->x_char) -+ info->x_char = 0; -+ else -+ rs_send_xchar(tty, START_CHAR(tty)); -+ } -+ -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_ioctl() and friends -+ * ------------------------------------------------------------ -+ */ -+ -+static int -+get_serial_info(struct e100_serial * info, -+ struct serial_struct * retinfo) -+{ -+ struct serial_struct tmp; -+ -+ /* this is all probably wrong, there are a lot of fields -+ * here that we don't have in e100_serial and maybe we -+ * should set them to something else than 0. -+ */ -+ -+ if (!retinfo) -+ return -EFAULT; -+ memset(&tmp, 0, sizeof(tmp)); -+ tmp.type = info->type; -+ tmp.line = info->line; -+ tmp.port = (int)info->ioport; -+ tmp.irq = info->irq; -+ tmp.flags = info->flags; -+ tmp.baud_base = info->baud_base; -+ tmp.close_delay = info->close_delay; -+ tmp.closing_wait = info->closing_wait; -+ tmp.custom_divisor = info->custom_divisor; -+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int -+set_serial_info(struct e100_serial *info, -+ struct serial_struct *new_info) -+{ -+ struct serial_struct new_serial; -+ struct e100_serial old_info; -+ int retval = 0; -+ -+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) -+ return -EFAULT; -+ -+ old_info = *info; -+ -+ if (!capable(CAP_SYS_ADMIN)) { -+ if ((new_serial.type != info->type) || -+ (new_serial.close_delay != info->close_delay) || -+ ((new_serial.flags & ~ASYNC_USR_MASK) != -+ (info->flags & ~ASYNC_USR_MASK))) -+ return -EPERM; -+ info->flags = ((info->flags & ~ASYNC_USR_MASK) | -+ (new_serial.flags & ASYNC_USR_MASK)); -+ goto check_and_exit; -+ } -+ -+ if (info->count > 1) -+ return -EBUSY; -+ -+ /* -+ * OK, past this point, all the error checking has been done. -+ * At this point, we start making changes..... -+ */ -+ -+ info->baud_base = new_serial.baud_base; -+ info->flags = ((info->flags & ~ASYNC_FLAGS) | -+ (new_serial.flags & ASYNC_FLAGS)); -+ info->custom_divisor = new_serial.custom_divisor; -+ info->type = new_serial.type; -+ info->close_delay = new_serial.close_delay; -+ info->closing_wait = new_serial.closing_wait; -+ info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -+ -+ check_and_exit: -+ if (info->flags & ASYNC_INITIALIZED) { -+ change_speed(info); -+ } else -+ retval = startup(info); -+ return retval; -+} -+ -+/* -+ * get_lsr_info - get line status register info -+ * -+ * Purpose: Let user call ioctl() to get info when the UART physically -+ * is emptied. On bus types like RS485, the transmitter must -+ * release the bus after transmitting. This must be done when -+ * the transmit shift register is empty, not be done when the -+ * transmit holding register is empty. This functionality -+ * allows an RS485 driver to be written in user space. -+ */ -+static int -+get_lsr_info(struct e100_serial * info, unsigned int *value) -+{ -+ unsigned int result = TIOCSER_TEMT; -+#ifndef CONFIG_SVINTO_SIM -+ unsigned long curr_time = jiffies; -+ unsigned long curr_time_usec = GET_JIFFIES_USEC(); -+ unsigned long elapsed_usec = -+ (curr_time - info->last_tx_active) * 1000000/HZ + -+ curr_time_usec - info->last_tx_active_usec; -+ -+ if (info->xmit.head != info->xmit.tail || -+ elapsed_usec < 2*info->char_time_usec) { -+ result = 0; -+ } -+#endif -+ -+ if (copy_to_user(value, &result, sizeof(int))) -+ return -EFAULT; -+ return 0; -+} -+ -+#ifdef SERIAL_DEBUG_IO -+struct state_str -+{ -+ int state; -+ const char *str; -+}; -+ -+const struct state_str control_state_str[] = { -+ {TIOCM_DTR, "DTR" }, -+ {TIOCM_RTS, "RTS"}, -+ {TIOCM_ST, "ST?" }, -+ {TIOCM_SR, "SR?" }, -+ {TIOCM_CTS, "CTS" }, -+ {TIOCM_CD, "CD" }, -+ {TIOCM_RI, "RI" }, -+ {TIOCM_DSR, "DSR" }, -+ {0, NULL } -+}; -+ -+char *get_control_state_str(int MLines, char *s) -+{ -+ int i = 0; -+ -+ s[0]='\0'; -+ while (control_state_str[i].str != NULL) { -+ if (MLines & control_state_str[i].state) { -+ if (s[0] != '\0') { -+ strcat(s, ", "); -+ } -+ strcat(s, control_state_str[i].str); -+ } -+ i++; -+ } -+ return s; -+} -+#endif -+ -+static int -+rs_break(struct tty_struct *tty, int break_state) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ if (!info->ioport) -+ return -EIO; -+ -+ local_irq_save(flags); -+ if (break_state == -1) { -+ /* Go to manual mode and set the txd pin to 0 */ -+ /* Clear bit 7 (txd) and 6 (tr_enable) */ -+ info->tx_ctrl &= 0x3F; -+ } else { -+ /* Set bit 7 (txd) and 6 (tr_enable) */ -+ info->tx_ctrl |= (0x80 | 0x40); -+ } -+ info->ioport[REG_TR_CTRL] = info->tx_ctrl; -+ local_irq_restore(flags); -+ return 0; -+} -+ -+static int -+rs_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ if (clear & TIOCM_RTS) -+ e100_rts(info, 0); -+ if (clear & TIOCM_DTR) -+ e100_dtr(info, 0); -+ /* Handle FEMALE behaviour */ -+ if (clear & TIOCM_RI) -+ e100_ri_out(info, 0); -+ if (clear & TIOCM_CD) -+ e100_cd_out(info, 0); -+ -+ if (set & TIOCM_RTS) -+ e100_rts(info, 1); -+ if (set & TIOCM_DTR) -+ e100_dtr(info, 1); -+ /* Handle FEMALE behaviour */ -+ if (set & TIOCM_RI) -+ e100_ri_out(info, 1); -+ if (set & TIOCM_CD) -+ e100_cd_out(info, 1); -+ -+ local_irq_restore(flags); -+ return 0; -+} -+ -+static int -+rs_tiocmget(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned int result; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ result = -+ (!E100_RTS_GET(info) ? TIOCM_RTS : 0) -+ | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) -+ | (!E100_RI_GET(info) ? TIOCM_RNG : 0) -+ | (!E100_DSR_GET(info) ? TIOCM_DSR : 0) -+ | (!E100_CD_GET(info) ? TIOCM_CAR : 0) -+ | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); -+ -+ local_irq_restore(flags); -+ -+#ifdef SERIAL_DEBUG_IO -+ printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n", -+ info->line, result, result); -+ { -+ char s[100]; -+ -+ get_control_state_str(result, s); -+ printk(KERN_DEBUG "state: %s\n", s); -+ } -+#endif -+ return result; -+ -+} -+ -+ -+static int -+rs_ioctl(struct tty_struct *tty, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ -+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && -+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && -+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { -+ if (tty->flags & (1 << TTY_IO_ERROR)) -+ return -EIO; -+ } -+ -+ switch (cmd) { -+ case TIOCGSERIAL: -+ return get_serial_info(info, -+ (struct serial_struct *) arg); -+ case TIOCSSERIAL: -+ return set_serial_info(info, -+ (struct serial_struct *) arg); -+ case TIOCSERGETLSR: /* Get line status register */ -+ return get_lsr_info(info, (unsigned int *) arg); -+ -+ case TIOCSERGSTRUCT: -+ if (copy_to_user((struct e100_serial *) arg, -+ info, sizeof(struct e100_serial))) -+ return -EFAULT; -+ return 0; -+ -+#if defined(CONFIG_ETRAX_RS485) -+ case TIOCSERSETRS485: -+ { -+ /* In this ioctl we still use the old structure -+ * rs485_control for backward compatibility -+ * (if we use serial_rs485, then old user-level code -+ * wouldn't work anymore...). -+ * The use of this ioctl is deprecated: use TIOCSRS485 -+ * instead.*/ -+ struct rs485_control rs485ctrl; -+ struct serial_rs485 rs485data; -+ printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n"); -+ if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg, -+ sizeof(rs485ctrl))) -+ return -EFAULT; -+ -+ rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send; -+ rs485data.flags = 0; -+ if (rs485data.delay_rts_before_send != 0) -+ rs485data.flags |= SER_RS485_RTS_BEFORE_SEND; -+ else -+ rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND); -+ -+ if (rs485ctrl.enabled) -+ rs485data.flags |= SER_RS485_ENABLED; -+ else -+ rs485data.flags &= ~(SER_RS485_ENABLED); -+ -+ if (rs485ctrl.rts_on_send) -+ rs485data.flags |= SER_RS485_RTS_ON_SEND; -+ else -+ rs485data.flags &= ~(SER_RS485_RTS_ON_SEND); -+ -+ if (rs485ctrl.rts_after_sent) -+ rs485data.flags |= SER_RS485_RTS_AFTER_SEND; -+ else -+ rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND); -+ -+ return e100_enable_rs485(tty, &rs485data); -+ } -+ -+ case TIOCSRS485: -+ { -+ /* This is the new version of TIOCSRS485, with new -+ * data structure serial_rs485 */ -+ struct serial_rs485 rs485data; -+ if (copy_from_user(&rs485data, (struct rs485_control *)arg, -+ sizeof(rs485data))) -+ return -EFAULT; -+ -+ return e100_enable_rs485(tty, &rs485data); -+ } -+ -+ case TIOCGRS485: -+ { -+ struct serial_rs485 *rs485data = -+ &(((struct e100_serial *)tty->driver_data)->rs485); -+ /* This is the ioctl to get RS485 data from user-space */ -+ if (copy_to_user((struct serial_rs485 *) arg, -+ rs485data, -+ sizeof(struct serial_rs485))) -+ return -EFAULT; -+ break; -+ } -+ -+ case TIOCSERWRRS485: -+ { -+ struct rs485_write rs485wr; -+ if (copy_from_user(&rs485wr, (struct rs485_write *)arg, -+ sizeof(rs485wr))) -+ return -EFAULT; -+ -+ return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size); -+ } -+#endif -+ -+ default: -+ return -ENOIOCTLCMD; -+ } -+ return 0; -+} -+ -+static void -+rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ -+ change_speed(info); -+ -+ /* Handle turning off CRTSCTS */ -+ if ((old_termios->c_cflag & CRTSCTS) && -+ !(tty->termios->c_cflag & CRTSCTS)) { -+ tty->hw_stopped = 0; -+ rs_start(tty); -+ } -+ -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_close() -+ * -+ * This routine is called when the serial port gets closed. First, we -+ * wait for the last remaining data to be sent. Then, we unlink its -+ * S structure from the interrupt chain if necessary, and we free -+ * that IRQ if nothing is left in the chain. -+ * ------------------------------------------------------------ -+ */ -+static void -+rs_close(struct tty_struct *tty, struct file * filp) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ if (!info) -+ return; -+ -+ /* interrupts are disabled for this entire function */ -+ -+ local_irq_save(flags); -+ -+ if (tty_hung_up_p(filp)) { -+ local_irq_restore(flags); -+ return; -+ } -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("[%d] rs_close ttyS%d, count = %d\n", current->pid, -+ info->line, info->count); -+#endif -+ if ((tty->count == 1) && (info->count != 1)) { -+ /* -+ * Uh, oh. tty->count is 1, which means that the tty -+ * structure will be freed. Info->count should always -+ * be one in these conditions. If it's greater than -+ * one, we've got real problems, since it means the -+ * serial port won't be shutdown. -+ */ -+ printk(KERN_CRIT -+ "rs_close: bad serial port count; tty->count is 1, " -+ "info->count is %d\n", info->count); -+ info->count = 1; -+ } -+ if (--info->count < 0) { -+ printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n", -+ info->line, info->count); -+ info->count = 0; -+ } -+ if (info->count) { -+ local_irq_restore(flags); -+ return; -+ } -+ info->flags |= ASYNC_CLOSING; -+ /* -+ * Save the termios structure, since this port may have -+ * separate termios for callout and dialin. -+ */ -+ if (info->flags & ASYNC_NORMAL_ACTIVE) -+ info->normal_termios = *tty->termios; -+ /* -+ * Now we wait for the transmit buffer to clear; and we notify -+ * the line discipline to only process XON/XOFF characters. -+ */ -+ tty->closing = 1; -+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) -+ tty_wait_until_sent(tty, info->closing_wait); -+ /* -+ * At this point we stop accepting input. To do this, we -+ * disable the serial receiver and the DMA receive interrupt. -+ */ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+ e100_disable_serial_data_irq(info); -+#endif -+ -+#ifndef CONFIG_SVINTO_SIM -+ e100_disable_rx(info); -+ e100_disable_rx_irq(info); -+ -+ if (info->flags & ASYNC_INITIALIZED) { -+ /* -+ * Before we drop DTR, make sure the UART transmitter -+ * has completely drained; this is especially -+ * important as we have a transmit FIFO! -+ */ -+ rs_wait_until_sent(tty, HZ); -+ } -+#endif -+ -+ shutdown(info); -+ rs_flush_buffer(tty); -+ tty_ldisc_flush(tty); -+ tty->closing = 0; -+ info->event = 0; -+ info->port.tty = NULL; -+ if (info->blocked_open) { -+ if (info->close_delay) -+ schedule_timeout_interruptible(info->close_delay); -+ wake_up_interruptible(&info->open_wait); -+ } -+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); -+ wake_up_interruptible(&info->close_wait); -+ local_irq_restore(flags); -+ -+ /* port closed */ -+ -+#if defined(CONFIG_ETRAX_RS485) -+ if (info->rs485.flags & SER_RS485_ENABLED) { -+ info->rs485.flags &= ~(SER_RS485_ENABLED); -+#if defined(CONFIG_ETRAX_RS485_ON_PA) -+ *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ rs485_port_g_bit, 0); -+#endif -+#if defined(CONFIG_ETRAX_RS485_LTC1387) -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0); -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0); -+#endif -+ } -+#endif -+ -+ /* -+ * Release any allocated DMA irq's. -+ */ -+ if (info->dma_in_enabled) { -+ free_irq(info->dma_in_irq_nbr, info); -+ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description); -+ info->uses_dma_in = 0; -+#ifdef SERIAL_DEBUG_OPEN -+ printk(KERN_DEBUG "DMA irq '%s' freed\n", -+ info->dma_in_irq_description); -+#endif -+ } -+ if (info->dma_out_enabled) { -+ free_irq(info->dma_out_irq_nbr, info); -+ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description); -+ info->uses_dma_out = 0; -+#ifdef SERIAL_DEBUG_OPEN -+ printk(KERN_DEBUG "DMA irq '%s' freed\n", -+ info->dma_out_irq_description); -+#endif -+ } -+} -+ -+/* -+ * rs_wait_until_sent() --- wait until the transmitter is empty -+ */ -+static void rs_wait_until_sent(struct tty_struct *tty, int timeout) -+{ -+ unsigned long orig_jiffies; -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long curr_time = jiffies; -+ unsigned long curr_time_usec = GET_JIFFIES_USEC(); -+ long elapsed_usec = -+ (curr_time - info->last_tx_active) * (1000000/HZ) + -+ curr_time_usec - info->last_tx_active_usec; -+ -+ /* -+ * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO -+ * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k) -+ */ -+ orig_jiffies = jiffies; -+ while (info->xmit.head != info->xmit.tail || /* More in send queue */ -+ (*info->ostatusadr & 0x007f) || /* more in FIFO */ -+ (elapsed_usec < 2*info->char_time_usec)) { -+ schedule_timeout_interruptible(1); -+ if (signal_pending(current)) -+ break; -+ if (timeout && time_after(jiffies, orig_jiffies + timeout)) -+ break; -+ curr_time = jiffies; -+ curr_time_usec = GET_JIFFIES_USEC(); -+ elapsed_usec = -+ (curr_time - info->last_tx_active) * (1000000/HZ) + -+ curr_time_usec - info->last_tx_active_usec; -+ } -+ set_current_state(TASK_RUNNING); -+} -+ -+/* -+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled. -+ */ -+void -+rs_hangup(struct tty_struct *tty) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ -+ rs_flush_buffer(tty); -+ shutdown(info); -+ info->event = 0; -+ info->count = 0; -+ info->flags &= ~ASYNC_NORMAL_ACTIVE; -+ info->port.tty = NULL; -+ wake_up_interruptible(&info->open_wait); -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_open() and friends -+ * ------------------------------------------------------------ -+ */ -+static int -+block_til_ready(struct tty_struct *tty, struct file * filp, -+ struct e100_serial *info) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int retval; -+ int do_clocal = 0, extra_count = 0; -+ -+ /* -+ * If the device is in the middle of being closed, then block -+ * until it's done, and then try again. -+ */ -+ if (tty_hung_up_p(filp) || -+ (info->flags & ASYNC_CLOSING)) { -+ wait_event_interruptible_tty(info->close_wait, -+ !(info->flags & ASYNC_CLOSING)); -+#ifdef SERIAL_DO_RESTART -+ if (info->flags & ASYNC_HUP_NOTIFY) -+ return -EAGAIN; -+ else -+ return -ERESTARTSYS; -+#else -+ return -EAGAIN; -+#endif -+ } -+ -+ /* -+ * If non-blocking mode is set, or the port is not enabled, -+ * then make the check up front and then exit. -+ */ -+ if ((filp->f_flags & O_NONBLOCK) || -+ (tty->flags & (1 << TTY_IO_ERROR))) { -+ info->flags |= ASYNC_NORMAL_ACTIVE; -+ return 0; -+ } -+ -+ if (tty->termios->c_cflag & CLOCAL) { -+ do_clocal = 1; -+ } -+ -+ /* -+ * Block waiting for the carrier detect and the line to become -+ * free (i.e., not in use by the callout). While we are in -+ * this loop, info->count is dropped by one, so that -+ * rs_close() knows when to free things. We restore it upon -+ * exit, either normal or abnormal. -+ */ -+ retval = 0; -+ add_wait_queue(&info->open_wait, &wait); -+#ifdef SERIAL_DEBUG_OPEN -+ printk("block_til_ready before block: ttyS%d, count = %d\n", -+ info->line, info->count); -+#endif -+ local_irq_save(flags); -+ if (!tty_hung_up_p(filp)) { -+ extra_count++; -+ info->count--; -+ } -+ local_irq_restore(flags); -+ info->blocked_open++; -+ while (1) { -+ local_irq_save(flags); -+ /* assert RTS and DTR */ -+ e100_rts(info, 1); -+ e100_dtr(info, 1); -+ local_irq_restore(flags); -+ set_current_state(TASK_INTERRUPTIBLE); -+ if (tty_hung_up_p(filp) || -+ !(info->flags & ASYNC_INITIALIZED)) { -+#ifdef SERIAL_DO_RESTART -+ if (info->flags & ASYNC_HUP_NOTIFY) -+ retval = -EAGAIN; -+ else -+ retval = -ERESTARTSYS; -+#else -+ retval = -EAGAIN; -+#endif -+ break; -+ } -+ if (!(info->flags & ASYNC_CLOSING) && do_clocal) -+ /* && (do_clocal || DCD_IS_ASSERTED) */ -+ break; -+ if (signal_pending(current)) { -+ retval = -ERESTARTSYS; -+ break; -+ } -+#ifdef SERIAL_DEBUG_OPEN -+ printk("block_til_ready blocking: ttyS%d, count = %d\n", -+ info->line, info->count); -+#endif -+ tty_unlock(); -+ schedule(); -+ tty_lock(); -+ } -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&info->open_wait, &wait); -+ if (extra_count) -+ info->count++; -+ info->blocked_open--; -+#ifdef SERIAL_DEBUG_OPEN -+ printk("block_til_ready after blocking: ttyS%d, count = %d\n", -+ info->line, info->count); -+#endif -+ if (retval) -+ return retval; -+ info->flags |= ASYNC_NORMAL_ACTIVE; -+ return 0; -+} -+ -+static void -+deinit_port(struct e100_serial *info) -+{ -+ if (info->dma_out_enabled) { -+ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description); -+ free_irq(info->dma_out_irq_nbr, info); -+ } -+ if (info->dma_in_enabled) { -+ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description); -+ free_irq(info->dma_in_irq_nbr, info); -+ } -+} -+ -+/* -+ * This routine is called whenever a serial port is opened. -+ * It performs the serial-specific initialization for the tty structure. -+ */ -+static int -+rs_open(struct tty_struct *tty, struct file * filp) -+{ -+ struct e100_serial *info; -+ int retval, line; -+ unsigned long page; -+ int allocated_resources = 0; -+ -+ /* find which port we want to open */ -+ line = tty->index; -+ -+ if (line < 0 || line >= NR_PORTS) -+ return -ENODEV; -+ -+ /* find the corresponding e100_serial struct in the table */ -+ info = rs_table + line; -+ -+ /* don't allow the opening of ports that are not enabled in the HW config */ -+ if (!info->enabled) -+ return -ENODEV; -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, -+ info->count); -+#endif -+ -+ info->count++; -+ tty->driver_data = info; -+ info->port.tty = tty; -+ -+ info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -+ -+ if (!tmp_buf) { -+ page = get_zeroed_page(GFP_KERNEL); -+ if (!page) { -+ return -ENOMEM; -+ } -+ if (tmp_buf) -+ free_page(page); -+ else -+ tmp_buf = (unsigned char *) page; -+ } -+ -+ /* -+ * If the port is in the middle of closing, bail out now -+ */ -+ if (tty_hung_up_p(filp) || -+ (info->flags & ASYNC_CLOSING)) { -+ wait_event_interruptible_tty(info->close_wait, -+ !(info->flags & ASYNC_CLOSING)); -+#ifdef SERIAL_DO_RESTART -+ return ((info->flags & ASYNC_HUP_NOTIFY) ? -+ -EAGAIN : -ERESTARTSYS); -+#else -+ return -EAGAIN; -+#endif -+ } -+ -+ /* -+ * If DMA is enabled try to allocate the irq's. -+ */ -+ if (info->count == 1) { -+ allocated_resources = 1; -+ if (info->dma_in_enabled) { -+ if (request_irq(info->dma_in_irq_nbr, -+ rec_interrupt, -+ info->dma_in_irq_flags, -+ info->dma_in_irq_description, -+ info)) { -+ printk(KERN_WARNING "DMA irq '%s' busy; " -+ "falling back to non-DMA mode\n", -+ info->dma_in_irq_description); -+ /* Make sure we never try to use DMA in */ -+ /* for the port again. */ -+ info->dma_in_enabled = 0; -+ } else if (cris_request_dma(info->dma_in_nbr, -+ info->dma_in_irq_description, -+ DMA_VERBOSE_ON_ERROR, -+ info->dma_owner)) { -+ free_irq(info->dma_in_irq_nbr, info); -+ printk(KERN_WARNING "DMA '%s' busy; " -+ "falling back to non-DMA mode\n", -+ info->dma_in_irq_description); -+ /* Make sure we never try to use DMA in */ -+ /* for the port again. */ -+ info->dma_in_enabled = 0; -+ } -+#ifdef SERIAL_DEBUG_OPEN -+ else -+ printk(KERN_DEBUG "DMA irq '%s' allocated\n", -+ info->dma_in_irq_description); -+#endif -+ } -+ if (info->dma_out_enabled) { -+ if (request_irq(info->dma_out_irq_nbr, -+ tr_interrupt, -+ info->dma_out_irq_flags, -+ info->dma_out_irq_description, -+ info)) { -+ printk(KERN_WARNING "DMA irq '%s' busy; " -+ "falling back to non-DMA mode\n", -+ info->dma_out_irq_description); -+ /* Make sure we never try to use DMA out */ -+ /* for the port again. */ -+ info->dma_out_enabled = 0; -+ } else if (cris_request_dma(info->dma_out_nbr, -+ info->dma_out_irq_description, -+ DMA_VERBOSE_ON_ERROR, -+ info->dma_owner)) { -+ free_irq(info->dma_out_irq_nbr, info); -+ printk(KERN_WARNING "DMA '%s' busy; " -+ "falling back to non-DMA mode\n", -+ info->dma_out_irq_description); -+ /* Make sure we never try to use DMA out */ -+ /* for the port again. */ -+ info->dma_out_enabled = 0; -+ } -+#ifdef SERIAL_DEBUG_OPEN -+ else -+ printk(KERN_DEBUG "DMA irq '%s' allocated\n", -+ info->dma_out_irq_description); -+#endif -+ } -+ } -+ -+ /* -+ * Start up the serial port -+ */ -+ -+ retval = startup(info); -+ if (retval) { -+ if (allocated_resources) -+ deinit_port(info); -+ -+ /* FIXME Decrease count info->count here too? */ -+ return retval; -+ } -+ -+ -+ retval = block_til_ready(tty, filp, info); -+ if (retval) { -+#ifdef SERIAL_DEBUG_OPEN -+ printk("rs_open returning after block_til_ready with %d\n", -+ retval); -+#endif -+ if (allocated_resources) -+ deinit_port(info); -+ -+ return retval; -+ } -+ -+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { -+ *tty->termios = info->normal_termios; -+ change_speed(info); -+ } -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("rs_open ttyS%d successful...\n", info->line); -+#endif -+ DLOG_INT_TRIG( log_int_pos = 0); -+ -+ DFLIP( if (info->line == SERIAL_DEBUG_LINE) { -+ info->icount.rx = 0; -+ } ); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PROC_FS -+/* -+ * /proc fs routines.... -+ */ -+ -+static void seq_line_info(struct seq_file *m, struct e100_serial *info) -+{ -+ unsigned long tmp; -+ -+ seq_printf(m, "%d: uart:E100 port:%lX irq:%d", -+ info->line, (unsigned long)info->ioport, info->irq); -+ -+ if (!info->ioport || (info->type == PORT_UNKNOWN)) { -+ seq_printf(m, "\n"); -+ return; -+ } -+ -+ seq_printf(m, " baud:%d", info->baud); -+ seq_printf(m, " tx:%lu rx:%lu", -+ (unsigned long)info->icount.tx, -+ (unsigned long)info->icount.rx); -+ tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -+ if (tmp) -+ seq_printf(m, " tx_pend:%lu/%lu", -+ (unsigned long)tmp, -+ (unsigned long)SERIAL_XMIT_SIZE); -+ -+ seq_printf(m, " rx_pend:%lu/%lu", -+ (unsigned long)info->recv_cnt, -+ (unsigned long)info->max_recv_cnt); -+ -+#if 1 -+ if (info->port.tty) { -+ if (info->port.tty->stopped) -+ seq_printf(m, " stopped:%i", -+ (int)info->port.tty->stopped); -+ if (info->port.tty->hw_stopped) -+ seq_printf(m, " hw_stopped:%i", -+ (int)info->port.tty->hw_stopped); -+ } -+ -+ { -+ unsigned char rstat = info->ioport[REG_STATUS]; -+ if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect)) -+ seq_printf(m, " xoff_detect:1"); -+ } -+ -+#endif -+ -+ if (info->icount.frame) -+ seq_printf(m, " fe:%lu", (unsigned long)info->icount.frame); -+ -+ if (info->icount.parity) -+ seq_printf(m, " pe:%lu", (unsigned long)info->icount.parity); -+ -+ if (info->icount.brk) -+ seq_printf(m, " brk:%lu", (unsigned long)info->icount.brk); -+ -+ if (info->icount.overrun) -+ seq_printf(m, " oe:%lu", (unsigned long)info->icount.overrun); -+ -+ /* -+ * Last thing is the RS-232 status lines -+ */ -+ if (!E100_RTS_GET(info)) -+ seq_puts(m, "|RTS"); -+ if (!E100_CTS_GET(info)) -+ seq_puts(m, "|CTS"); -+ if (!E100_DTR_GET(info)) -+ seq_puts(m, "|DTR"); -+ if (!E100_DSR_GET(info)) -+ seq_puts(m, "|DSR"); -+ if (!E100_CD_GET(info)) -+ seq_puts(m, "|CD"); -+ if (!E100_RI_GET(info)) -+ seq_puts(m, "|RI"); -+ seq_puts(m, "\n"); -+} -+ -+ -+static int crisv10_proc_show(struct seq_file *m, void *v) -+{ -+ int i; -+ -+ seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ if (!rs_table[i].enabled) -+ continue; -+ seq_line_info(m, &rs_table[i]); -+ } -+#ifdef DEBUG_LOG_INCLUDED -+ for (i = 0; i < debug_log_pos; i++) { -+ seq_printf(m, "%-4i %lu.%lu ", -+ i, debug_log[i].time, -+ timer_data_to_ns(debug_log[i].timer_data)); -+ seq_printf(m, debug_log[i].string, debug_log[i].value); -+ } -+ seq_printf(m, "debug_log %i/%i\n", i, DEBUG_LOG_SIZE); -+ debug_log_pos = 0; -+#endif -+ return 0; -+} -+ -+static int crisv10_proc_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, crisv10_proc_show, NULL); -+} -+ -+static const struct file_operations crisv10_proc_fops = { -+ .owner = THIS_MODULE, -+ .open = crisv10_proc_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+#endif -+ -+ -+/* Finally, routines used to initialize the serial driver. */ -+ -+static void show_serial_version(void) -+{ -+ printk(KERN_INFO -+ "ETRAX 100LX serial-driver %s, " -+ "(c) 2000-2004 Axis Communications AB\r\n", -+ &serial_version[11]); /* "$Revision: x.yy" */ -+} -+ -+/* rs_init inits the driver at boot (using the module_init chain) */ -+ -+static const struct tty_operations rs_ops = { -+ .open = rs_open, -+ .close = rs_close, -+ .write = rs_write, -+ .flush_chars = rs_flush_chars, -+ .write_room = rs_write_room, -+ .chars_in_buffer = rs_chars_in_buffer, -+ .flush_buffer = rs_flush_buffer, -+ .ioctl = rs_ioctl, -+ .throttle = rs_throttle, -+ .unthrottle = rs_unthrottle, -+ .set_termios = rs_set_termios, -+ .stop = rs_stop, -+ .start = rs_start, -+ .hangup = rs_hangup, -+ .break_ctl = rs_break, -+ .send_xchar = rs_send_xchar, -+ .wait_until_sent = rs_wait_until_sent, -+ .tiocmget = rs_tiocmget, -+ .tiocmset = rs_tiocmset, -+#ifdef CONFIG_PROC_FS -+ .proc_fops = &crisv10_proc_fops, -+#endif -+}; -+ -+static int __init rs_init(void) -+{ -+ int i; -+ struct e100_serial *info; -+ struct tty_driver *driver = alloc_tty_driver(NR_PORTS); -+ -+ if (!driver) -+ return -ENOMEM; -+ -+ show_serial_version(); -+ -+ /* Setup the timed flush handler system */ -+ -+#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) -+ setup_timer(&flush_timer, timed_flush_handler, 0); -+ mod_timer(&flush_timer, jiffies + 5); -+#endif -+ -+#if defined(CONFIG_ETRAX_RS485) -+#if defined(CONFIG_ETRAX_RS485_ON_PA) -+ if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit, -+ rs485_pa_bit)) { -+ printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " -+ "RS485 pin\n"); -+ put_tty_driver(driver); -+ return -EBUSY; -+ } -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+ if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit, -+ rs485_port_g_bit)) { -+ printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " -+ "RS485 pin\n"); -+ put_tty_driver(driver); -+ return -EBUSY; -+ } -+#endif -+#endif -+ -+ /* Initialize the tty_driver structure */ -+ -+ driver->driver_name = "serial"; -+ driver->name = "ttyS"; -+ driver->major = TTY_MAJOR; -+ driver->minor_start = 64; -+ driver->type = TTY_DRIVER_TYPE_SERIAL; -+ driver->subtype = SERIAL_TYPE_NORMAL; -+ driver->init_termios = tty_std_termios; -+ driver->init_termios.c_cflag = -+ B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ -+ driver->init_termios.c_ispeed = 115200; -+ driver->init_termios.c_ospeed = 115200; -+ driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; -+ -+ tty_set_operations(driver, &rs_ops); -+ serial_driver = driver; -+ if (tty_register_driver(driver)) -+ panic("Couldn't register serial driver\n"); -+ /* do some initializing for the separate ports */ -+ -+ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { -+ if (info->enabled) { -+ if (cris_request_io_interface(info->io_if, -+ info->io_if_description)) { -+ printk(KERN_CRIT "ETRAX100LX async serial: " -+ "Could not allocate IO pins for " -+ "%s, port %d\n", -+ info->io_if_description, i); -+ info->enabled = 0; -+ } -+ } -+ info->uses_dma_in = 0; -+ info->uses_dma_out = 0; -+ info->line = i; -+ info->port.tty = NULL; -+ info->type = PORT_ETRAX; -+ info->tr_running = 0; -+ info->forced_eop = 0; -+ info->baud_base = DEF_BAUD_BASE; -+ info->custom_divisor = 0; -+ info->flags = 0; -+ info->close_delay = 5*HZ/10; -+ info->closing_wait = 30*HZ; -+ info->x_char = 0; -+ info->event = 0; -+ info->count = 0; -+ info->blocked_open = 0; -+ info->normal_termios = driver->init_termios; -+ init_waitqueue_head(&info->open_wait); -+ init_waitqueue_head(&info->close_wait); -+ info->xmit.buf = NULL; -+ info->xmit.tail = info->xmit.head = 0; -+ info->first_recv_buffer = info->last_recv_buffer = NULL; -+ info->recv_cnt = info->max_recv_cnt = 0; -+ info->last_tx_active_usec = 0; -+ info->last_tx_active = 0; -+ -+#if defined(CONFIG_ETRAX_RS485) -+ /* Set sane defaults */ -+ info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND); -+ info->rs485.flags |= SER_RS485_RTS_AFTER_SEND; -+ info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND); -+ info->rs485.delay_rts_before_send = 0; -+ info->rs485.flags &= ~(SER_RS485_ENABLED); -+#endif -+ INIT_WORK(&info->work, do_softint); -+ -+ if (info->enabled) { -+ printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n", -+ serial_driver->name, info->line, info->ioport); -+ } -+ } -+#ifdef CONFIG_ETRAX_FAST_TIMER -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+ memset(fast_timers, 0, sizeof(fast_timers)); -+#endif -+#ifdef CONFIG_ETRAX_RS485 -+ memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485)); -+#endif -+ fast_timer_init(); -+#endif -+ -+#ifndef CONFIG_SVINTO_SIM -+#ifndef CONFIG_ETRAX_KGDB -+ /* Not needed in simulator. May only complicate stuff. */ -+ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ -+ -+ if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, -+ IRQF_SHARED | IRQF_DISABLED, "serial ", driver)) -+ panic("%s: Failed to request irq8", __func__); -+ -+#endif -+#endif /* CONFIG_SVINTO_SIM */ -+ -+ return 0; -+} -+ -+/* this makes sure that rs_init is called during kernel boot */ -+ -+module_init(rs_init); diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-cris-dbg.h linux-2.6.39/drivers/usb/host/hc-cris-dbg.h --- linux-2.6.39.orig/drivers/usb/host/hc-cris-dbg.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/usb/host/hc-cris-dbg.h 2011-07-28 16:16:37.503543830 +0200 ++++ linux-2.6.39/drivers/usb/host/hc-cris-dbg.h 2011-08-25 07:43:02.837990398 +0200 @@ -0,0 +1,146 @@ + +/* macros for debug output */ @@ -8020,7 +565,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-cris-dbg.h linux-2.6.39/drivers/ + }) diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-crisv10.c linux-2.6.39/drivers/usb/host/hc-crisv10.c --- linux-2.6.39.orig/drivers/usb/host/hc-crisv10.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/usb/host/hc-crisv10.c 2011-07-28 16:16:37.633441816 +0200 ++++ linux-2.6.39/drivers/usb/host/hc-crisv10.c 2011-08-25 07:43:02.897981683 +0200 @@ -0,0 +1,4801 @@ +/* + * @@ -12825,7 +5370,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-crisv10.c linux-2.6.39/drivers/u +module_exit(module_hcd_exit); diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-crisv10.h linux-2.6.39/drivers/usb/host/hc-crisv10.h --- linux-2.6.39.orig/drivers/usb/host/hc-crisv10.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/usb/host/hc-crisv10.h 2011-07-28 16:16:37.757174124 +0200 ++++ linux-2.6.39/drivers/usb/host/hc-crisv10.h 2011-08-25 07:43:03.100480030 +0200 @@ -0,0 +1,331 @@ +#ifndef __LINUX_ETRAX_USB_H +#define __LINUX_ETRAX_USB_H @@ -13160,7 +5705,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-crisv10.h linux-2.6.39/drivers/u +#endif diff -Nur linux-2.6.39.orig/drivers/usb/host/Makefile linux-2.6.39/drivers/usb/host/Makefile --- linux-2.6.39.orig/drivers/usb/host/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/usb/host/Makefile 2011-07-28 16:16:37.863421513 +0200 ++++ linux-2.6.39/drivers/usb/host/Makefile 2011-08-25 07:43:03.209057611 +0200 @@ -32,6 +32,7 @@ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o @@ -13171,7 +5716,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/Makefile linux-2.6.39/drivers/usb/h obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o diff -Nur linux-2.6.39.orig/drivers/usb/Makefile linux-2.6.39/drivers/usb/Makefile --- linux-2.6.39.orig/drivers/usb/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/usb/Makefile 2011-07-28 16:16:37.993659487 +0200 ++++ linux-2.6.39/drivers/usb/Makefile 2011-08-25 07:43:03.380490677 +0200 @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_HWA_HCD) += host/ @@ -13182,7 +5727,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/Makefile linux-2.6.39/drivers/usb/Makefi obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ diff -Nur linux-2.6.39.orig/lib/klist.c linux-2.6.39/lib/klist.c --- linux-2.6.39.orig/lib/klist.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/lib/klist.c 2011-07-28 16:16:38.103425277 +0200 ++++ linux-2.6.39/lib/klist.c 2011-08-25 07:43:03.558483154 +0200 @@ -60,7 +60,7 @@ { knode->n_klist = klist; diff --git a/target/linux/patches/2.6.39/mips-malta.patch b/target/linux/patches/2.6.39/mips-malta.patch new file mode 100644 index 000000000..cc8789dca --- /dev/null +++ b/target/linux/patches/2.6.39/mips-malta.patch @@ -0,0 +1,135 @@ +http://lkml.indiana.edu/hypermail/linux/kernel/1105.3/02199.html + +diff -Nur linux-2.6.39.orig/arch/mips/include/asm/smp-ops.h linux-2.6.39/arch/mips/include/asm/smp-ops.h +--- linux-2.6.39.orig/arch/mips/include/asm/smp-ops.h 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/smp-ops.h 2011-08-29 04:39:03.360480881 +0200 +@@ -56,8 +56,43 @@ + + #endif /* !CONFIG_SMP */ + +-extern struct plat_smp_ops up_smp_ops; +-extern struct plat_smp_ops cmp_smp_ops; +-extern struct plat_smp_ops vsmp_smp_ops; ++static inline int register_up_smp_ops(void) ++{ ++#ifdef CONFIG_SMP_UP ++ extern struct plat_smp_ops up_smp_ops; ++ ++ register_smp_ops(&up_smp_ops); ++ ++ return 0; ++#else ++ return -ENODEV; ++#endif ++} ++ ++static inline int register_cmp_smp_ops(void) ++{ ++#ifdef CONFIG_MIPS_CMP ++ extern struct plat_smp_ops cmp_smp_ops; ++ ++ register_smp_ops(&cmp_smp_ops); ++ ++ return 0; ++#else ++ return -ENODEV; ++#endif ++} ++ ++static inline int register_vsmp_smp_ops(void) ++{ ++#ifdef CONFIG_MIPS_MT_SMP ++ extern struct plat_smp_ops vsmp_smp_ops; ++ ++ register_smp_ops(&vsmp_smp_ops); ++ ++ return 0; ++#else ++ return -ENODEV; ++#endif ++} + + #endif /* __ASM_SMP_OPS_H */ +diff -Nur linux-2.6.39.orig/arch/mips/mipssim/sim_setup.c linux-2.6.39/arch/mips/mipssim/sim_setup.c +--- linux-2.6.39.orig/arch/mips/mipssim/sim_setup.c 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/arch/mips/mipssim/sim_setup.c 2011-08-29 04:39:03.390480572 +0200 +@@ -59,18 +59,17 @@ + + prom_meminit(); + +-#ifdef CONFIG_MIPS_MT_SMP +- if (cpu_has_mipsmt) +- register_smp_ops(&vsmp_smp_ops); +- else +- register_smp_ops(&up_smp_ops); +-#endif ++ if (cpu_has_mipsmt) { ++ if (!register_vsmp_smp_ops()) ++ return; ++ + #ifdef CONFIG_MIPS_MT_SMTC +- if (cpu_has_mipsmt) + register_smp_ops(&ssmtc_smp_ops); +- else +- register_smp_ops(&up_smp_ops); ++ return; + #endif ++ } ++ ++ register_up_smp_ops(); + } + + static void __init serial_init(void) +diff -Nur linux-2.6.39.orig/arch/mips/mti-malta/malta-init.c linux-2.6.39/arch/mips/mti-malta/malta-init.c +--- linux-2.6.39.orig/arch/mips/mti-malta/malta-init.c 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/arch/mips/mti-malta/malta-init.c 2011-08-29 04:39:03.700480601 +0200 +@@ -29,6 +29,7 @@ + #include <asm/system.h> + #include <asm/cacheflush.h> + #include <asm/traps.h> ++#include <asm/smp-ops.h> + + #include <asm/gcmpregs.h> + #include <asm/mips-boards/prom.h> +@@ -358,15 +359,14 @@ + #ifdef CONFIG_SERIAL_8250_CONSOLE + console_config(); + #endif +-#ifdef CONFIG_MIPS_CMP + /* Early detection of CMP support */ + if (gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ)) +- register_smp_ops(&cmp_smp_ops); +- else +-#endif +-#ifdef CONFIG_MIPS_MT_SMP +- register_smp_ops(&vsmp_smp_ops); +-#endif ++ if (!register_cmp_smp_ops()) ++ return; ++ ++ if (!register_vsmp_smp_ops()) ++ return; ++ + #ifdef CONFIG_MIPS_MT_SMTC + register_smp_ops(&msmtc_smp_ops); + #endif +diff -Nur linux-2.6.39.orig/arch/mips/pmc-sierra/msp71xx/msp_setup.c linux-2.6.39/arch/mips/pmc-sierra/msp71xx/msp_setup.c +--- linux-2.6.39.orig/arch/mips/pmc-sierra/msp71xx/msp_setup.c 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/arch/mips/pmc-sierra/msp71xx/msp_setup.c 2011-08-29 04:39:03.790480302 +0200 +@@ -228,13 +228,11 @@ + */ + msp_serial_setup(); + +-#ifdef CONFIG_MIPS_MT_SMP +- register_smp_ops(&vsmp_smp_ops); +-#endif +- ++ if (register_vsmp_smp_ops()) { + #ifdef CONFIG_MIPS_MT_SMTC +- register_smp_ops(&msp_smtc_smp_ops); ++ register_smp_ops(&msp_smtc_smp_ops); + #endif ++ } + + #ifdef CONFIG_PMCTWILED + /* diff --git a/target/linux/patches/2.6.39/rb4xx.patch b/target/linux/patches/2.6.39/rb4xx.patch index 1739221bf..4f2e1cd84 100644 --- a/target/linux/patches/2.6.39/rb4xx.patch +++ b/target/linux/patches/2.6.39/rb4xx.patch @@ -1,6 +1,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/Kconfig linux-2.6.39/arch/mips/Kconfig --- linux-2.6.39.orig/arch/mips/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/mips/Kconfig 2011-05-27 14:36:50.000000000 +0200 ++++ linux-2.6.39/arch/mips/Kconfig 2011-08-24 18:17:24.000000000 +0200 @@ -84,6 +84,23 @@ help Support for the Atheros AR71XX/AR724X/AR913X SoCs. @@ -25,17 +25,27 @@ diff -Nur linux-2.6.39.orig/arch/mips/Kconfig linux-2.6.39/arch/mips/Kconfig config BCM47XX bool "Broadcom BCM47XX based boards" select CEVT_R4K -@@ -740,6 +757,7 @@ +@@ -739,6 +756,7 @@ + endchoice source "arch/mips/alchemy/Kconfig" - source "arch/mips/ath79/Kconfig" +source "arch/mips/ar71xx/Kconfig" + source "arch/mips/ath79/Kconfig" source "arch/mips/bcm63xx/Kconfig" source "arch/mips/jazz/Kconfig" - source "arch/mips/jz4740/Kconfig" +@@ -907,6 +925,9 @@ + config MIPS_DISABLE_OBSOLETE_IDE + bool + ++config MYLOADER ++ bool ++ + config SYNC_R4K + bool + diff -Nur linux-2.6.39.orig/arch/mips/Makefile linux-2.6.39/arch/mips/Makefile --- linux-2.6.39.orig/arch/mips/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/mips/Makefile 2011-05-27 14:36:50.000000000 +0200 ++++ linux-2.6.39/arch/mips/Makefile 2011-08-24 18:17:24.000000000 +0200 @@ -158,6 +158,13 @@ endif cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 @@ -50,18 +60,27 @@ diff -Nur linux-2.6.39.orig/arch/mips/Makefile linux-2.6.39/arch/mips/Makefile cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,) cflags-$(CONFIG_CPU_DADDI_WORKAROUNDS) += $(call cc-option,-mno-daddi,) +@@ -174,6 +181,7 @@ + # + libs-$(CONFIG_ARC) += arch/mips/fw/arc/ + libs-$(CONFIG_CFE) += arch/mips/fw/cfe/ ++libs-$(CONFIG_MYLOADER) += arch/mips/fw/myloader/ + libs-$(CONFIG_SNIPROM) += arch/mips/fw/sni/ + libs-y += arch/mips/fw/lib/ + diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71xx/Kconfig --- linux-2.6.39.orig/arch/mips/ar71xx/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/Kconfig 2011-05-27 14:36:50.000000000 +0200 -@@ -0,0 +1,264 @@ ++++ linux-2.6.39/arch/mips/ar71xx/Kconfig 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,420 @@ +if ATHEROS_AR71XX + +menu "Atheros AR71xx machine selection" + +config AR71XX_MACH_AP81 + bool "Atheros AP81 board support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_DEV_USB @@ -69,7 +88,38 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_AP83 + bool "Atheros AP83 board support" -+ select AR71XX_DEV_AR913X_WMAC ++ select SOC_AR913X ++ select AR71XX_DEV_AR9XXX_WMAC ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ select AR71XX_DEV_USB ++ default n ++ ++config AR71XX_MACH_AP96 ++ bool "Atheros AP96 board support" ++ select SOC_AR71XX ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_AP94_PCI if PCI ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ select AR71XX_DEV_USB ++ default n ++ ++config AR71XX_MACH_AP121 ++ bool "Atheros AP121 board support" ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ select AR71XX_DEV_USB ++ select AR71XX_DEV_AR9XXX_WMAC ++ select SOC_AR933X ++ default n ++ ++config AR71XX_MACH_DB120 ++ bool "Atheros DB120 board support" ++ select SOC_AR934X ++ select AR71XX_DEV_AR9XXX_WMAC ++ select AR71XX_DEV_DB120_PCI if PCI + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_DEV_USB @@ -77,7 +127,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_DIR_600_A1 + bool "D-Link DIR-600 rev. A1 support" -+ select AR71XX_DEV_AP91_ETH ++ select SOC_AR724X + select AR71XX_DEV_AP91_PCI if PCI + select AR71XX_DEV_M25P80 + select AR71XX_DEV_GPIO_BUTTONS @@ -87,8 +137,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_DIR_615_C1 + bool "D-Link DIR-615 rev. C1 support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_NVRAM @@ -96,6 +147,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_DIR_825_B1 + bool "D-Link DIR-825 rev. B1 board support" ++ select SOC_AR71XX + select AR71XX_DEV_M25P80 + select AR71XX_DEV_AP94_PCI if PCI + select AR71XX_DEV_GPIO_BUTTONS @@ -103,8 +155,28 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + select AR71XX_DEV_USB + default n + ++config AR71XX_MACH_JA76PF ++ bool "jjPlus JA76PF board support" ++ select SOC_AR71XX ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_PB42_PCI if PCI ++ select AR71XX_DEV_LEDS_GPIO ++ select AR71XX_DEV_USB ++ default n ++ ++config AR71XX_MACH_JWAP003 ++ bool "jjPlus JWAP003 board support" ++ select SOC_AR71XX ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_PB42_PCI if PCI ++ select AR71XX_DEV_USB ++ default n ++ +config AR71XX_MACH_PB42 + bool "Atheros PB42 board support" ++ select SOC_AR71XX + select AR71XX_DEV_M25P80 + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_PB42_PCI if PCI @@ -112,6 +184,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_PB44 + bool "Atheros PB44 board support" ++ select SOC_AR71XX + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_PB42_PCI if PCI + select AR71XX_DEV_LEDS_GPIO @@ -120,6 +193,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_PB92 + bool "Atheros PB92 board support" ++ select SOC_AR724X + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_PB9X_PCI if PCI + select AR71XX_DEV_LEDS_GPIO @@ -128,22 +202,35 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_AW_NR580 + bool "AzureWave AW-NR580 board support" ++ select SOC_AR71XX + select AR71XX_DEV_M25P80 + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_PB42_PCI if PCI + select AR71XX_DEV_LEDS_GPIO + default n + ++config AR71XX_MACH_WZR_HP_AG300H ++ bool "Buffalo WZR-HP-AG300H board support" ++ select SOC_AR71XX ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ select AR71XX_DEV_USB ++ default n ++ +config AR71XX_MACH_WZR_HP_G300NH + bool "Buffalo WZR-HP-G300NH board support" -+ select AR71XX_DEV_AR913X_WMAC ++ select SOC_AR913X ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_DEV_USB -+ default y ++ select RTL8366_SMI ++ default n + +config AR71XX_MACH_WP543 + bool "Compex WP543/WPJ543 board support" ++ select SOC_AR71XX + select MYLOADER + select AR71XX_DEV_M25P80 + select AR71XX_DEV_GPIO_BUTTONS @@ -154,8 +241,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_WRT160NL + bool "Linksys WRT160NL board support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_DEV_USB @@ -164,6 +252,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_WRT400N + bool "Linksys WRT400N board support" ++ select SOC_AR71XX + select AR71XX_DEV_AP94_PCI if PCI + select AR71XX_DEV_M25P80 + select AR71XX_DEV_GPIO_BUTTONS @@ -172,6 +261,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_RB4XX + bool "MikroTik RouterBOARD 4xx series support" ++ select SOC_AR71XX + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_DEV_USB @@ -179,11 +269,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_RB750 + bool "MikroTik RouterBOARD 750 support" -+ select AR71XX_DEV_AP91_ETH ++ select SOC_AR724X + default n + +config AR71XX_MACH_WNDR3700 + bool "NETGEAR WNDR3700 board support" ++ select SOC_AR71XX + select AR71XX_DEV_M25P80 + select AR71XX_DEV_AP94_PCI if PCI + select AR71XX_DEV_GPIO_BUTTONS @@ -193,16 +284,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_WNR2000 + bool "NETGEAR WNR2000 board support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + default n + +config AR71XX_MACH_MZK_W04NU + bool "Planex MZK-W04NU board support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_DEV_USB @@ -210,24 +303,54 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_MZK_W300NH + bool "Planex MZK-W300NH board support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + default n + +config AR71XX_MACH_NBG460N + bool "Zyxel NBG460N/550N/550NH board support" ++ select SOC_AR913X ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_AR9XXX_WMAC ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ default n ++ ++config AR71XX_MACH_TL_MR3X20 ++ bool "TP-LINK TL-MR3220/3420 support" ++ select SOC_AR724X ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_AP91_PCI if PCI ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ select AR71XX_DEV_USB ++ default n ++ ++config AR71XX_MACH_TL_WA901ND ++ bool "TP-LINK TL-WA901ND support" ++ select SOC_AR724X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AP91_PCI if PCI + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + default n -+ ++ ++config AR71XX_MACH_TL_WA901ND_V2 ++ bool "TP-LINK TL-WA901ND v2 support" ++ select SOC_AR913X ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_AR9XXX_WMAC ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ default n ++ +config AR71XX_MACH_TL_WR741ND + bool "TP-LINK TL-WR741ND support" ++ select SOC_AR724X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AP91_ETH + select AR71XX_DEV_AP91_PCI if PCI + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO @@ -235,6 +358,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_TL_WR841N_V1 + bool "TP-LINK TL-WR841N v1 support" ++ select SOC_AR71XX + select AR71XX_DEV_M25P80 + select AR71XX_DEV_PB42_PCI if PCI + select AR71XX_DEV_DSA @@ -244,8 +368,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_TL_WR941ND + bool "TP-LINK TL-WR941ND support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_DSA + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO @@ -253,8 +378,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_TL_WR1043ND + bool "TP-LINK TL-WR1043ND support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_DEV_USB @@ -262,8 +388,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_TEW_632BRP + bool "TRENDnet TEW-632BRP support" ++ select SOC_AR913X + select AR71XX_DEV_M25P80 -+ select AR71XX_DEV_AR913X_WMAC ++ select AR71XX_DEV_AR9XXX_WMAC + select AR71XX_DEV_GPIO_BUTTONS + select AR71XX_DEV_LEDS_GPIO + select AR71XX_NVRAM @@ -271,6 +398,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + +config AR71XX_MACH_UBNT + bool "Ubiquiti AR71xx based boards support" ++ select SOC_AR71XX ++ select SOC_AR724X + select AR71XX_DEV_M25P80 + select AR71XX_DEV_AP91_PCI if PCI + select AR71XX_DEV_GPIO_BUTTONS @@ -279,21 +408,59 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 + select AR71XX_DEV_USB + default n + ++config AR71XX_MACH_EAP7660D ++ bool "Senao EAP7660D support" ++ select SOC_AR71XX ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ default n ++ ++config AR71XX_MACH_ZCN_1523H ++ bool "Zcomax ZCN-1523H support" ++ select SOC_AR724X ++ select AR71XX_DEV_M25P80 ++ select AR71XX_DEV_AP91_PCI if PCI ++ select AR71XX_DEV_GPIO_BUTTONS ++ select AR71XX_DEV_LEDS_GPIO ++ default n ++ +endmenu + ++config SOC_AR71XX ++ bool ++ select USB_ARCH_HAS_EHCI ++ select USB_ARCH_HAS_OHCI ++ ++config SOC_AR724X ++ bool ++ select USB_ARCH_HAS_EHCI ++ select USB_ARCH_HAS_OHCI ++ ++config SOC_AR913X ++ bool ++ select USB_ARCH_HAS_EHCI ++ ++config SOC_AR934X ++ bool ++ select USB_ARCH_HAS_EHCI ++ +config AR71XX_DEV_M25P80 + def_bool n + +config AR71XX_DEV_AP91_PCI ++ select AR71XX_PCI_ATH9K_FIXUP + def_bool n + -+config AR71XX_DEV_AP91_ETH ++config AR71XX_DEV_AP94_PCI ++ select AR71XX_PCI_ATH9K_FIXUP + def_bool n + -+config AR71XX_DEV_AP94_PCI ++config AR71XX_DEV_AR9XXX_WMAC + def_bool n + -+config AR71XX_DEV_AR913X_WMAC ++config AR71XX_DEV_DB120_PCI ++ select AR71XX_PCI_ATH9K_FIXUP + def_bool n + +config AR71XX_DEV_DSA @@ -317,11 +484,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Kconfig linux-2.6.39/arch/mips/ar71 +config AR71XX_NVRAM + def_bool n + ++config AR71XX_PCI_ATH9K_FIXUP ++ def_bool n ++ ++config SOC_AR933X ++ bool ++ select USB_ARCH_HAS_EHCI ++ +endif diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Makefile linux-2.6.39/arch/mips/ar71xx/Makefile --- linux-2.6.39.orig/arch/mips/ar71xx/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/Makefile 2011-05-27 14:36:50.000000000 +0200 -@@ -0,0 +1,54 @@ ++++ linux-2.6.39/arch/mips/ar71xx/Makefile 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,67 @@ +# +# Makefile for the Atheros AR71xx SoC specific parts of the kernel +# @@ -337,10 +511,10 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Makefile linux-2.6.39/arch/mips/ar7 +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_PCI) += pci.o + -+obj-$(CONFIG_AR71XX_DEV_AP91_ETH) += dev-ap91-eth.o +obj-$(CONFIG_AR71XX_DEV_AP91_PCI) += dev-ap91-pci.o +obj-$(CONFIG_AR71XX_DEV_AP94_PCI) += dev-ap94-pci.o -+obj-$(CONFIG_AR71XX_DEV_AR913X_WMAC) += dev-ar913x-wmac.o ++obj-$(CONFIG_AR71XX_DEV_AR9XXX_WMAC) += dev-ar9xxx-wmac.o ++obj-$(CONFIG_AR71XX_DEV_DB120_PCI) += dev-db120-pci.o +obj-$(CONFIG_AR71XX_DEV_DSA) += dev-dsa.o +obj-$(CONFIG_AR71XX_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o +obj-$(CONFIG_AR71XX_DEV_LEDS_GPIO) += dev-leds-gpio.o @@ -350,13 +524,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Makefile linux-2.6.39/arch/mips/ar7 +obj-$(CONFIG_AR71XX_DEV_USB) += dev-usb.o + +obj-$(CONFIG_AR71XX_NVRAM) += nvram.o ++obj-$(CONFIG_AR71XX_PCI_ATH9K_FIXUP) += pci-ath9k-fixup.o + ++obj-$(CONFIG_AR71XX_MACH_AP121) += mach-ap121.o +obj-$(CONFIG_AR71XX_MACH_AP81) += mach-ap81.o +obj-$(CONFIG_AR71XX_MACH_AP83) += mach-ap83.o ++obj-$(CONFIG_AR71XX_MACH_AP96) += mach-ap96.o +obj-$(CONFIG_AR71XX_MACH_AW_NR580) += mach-aw-nr580.o ++obj-$(CONFIG_AR71XX_MACH_DB120) += mach-db120.o +obj-$(CONFIG_AR71XX_MACH_DIR_600_A1) += mach-dir-600-a1.o +obj-$(CONFIG_AR71XX_MACH_DIR_615_C1) += mach-dir-615-c1.o +obj-$(CONFIG_AR71XX_MACH_DIR_825_B1) += mach-dir-825-b1.o ++obj-$(CONFIG_AR71XX_MACH_EAP7660D) += mach-eap7660d.o ++obj-$(CONFIG_AR71XX_MACH_JA76PF) += mach-ja76pf.o ++obj-$(CONFIG_AR71XX_MACH_JWAP003) += mach-jwap003.o +obj-$(CONFIG_AR71XX_MACH_MZK_W04NU) += mach-mzk-w04nu.o +obj-$(CONFIG_AR71XX_MACH_MZK_W300NH) += mach-mzk-w300nh.o +obj-$(CONFIG_AR71XX_MACH_NBG460N) += mach-nbg460n.o @@ -366,6 +547,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Makefile linux-2.6.39/arch/mips/ar7 +obj-$(CONFIG_AR71XX_MACH_RB4XX) += mach-rb4xx.o +obj-$(CONFIG_AR71XX_MACH_RB750) += mach-rb750.o +obj-$(CONFIG_AR71XX_MACH_TEW_632BRP) += mach-tew-632brp.o ++obj-$(CONFIG_AR71XX_MACH_TL_MR3X20) += mach-tl-mr3x20.o ++obj-$(CONFIG_AR71XX_MACH_TL_WA901ND) += mach-tl-wa901nd.o ++obj-$(CONFIG_AR71XX_MACH_TL_WA901ND_V2) += mach-tl-wa901nd-v2.o +obj-$(CONFIG_AR71XX_MACH_TL_WR741ND) += mach-tl-wr741nd.o +obj-$(CONFIG_AR71XX_MACH_TL_WR841N_V1) += mach-tl-wr841n.o +obj-$(CONFIG_AR71XX_MACH_TL_WR941ND) += mach-tl-wr941nd.o @@ -376,10 +560,13 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/Makefile linux-2.6.39/arch/mips/ar7 +obj-$(CONFIG_AR71XX_MACH_WP543) += mach-wp543.o +obj-$(CONFIG_AR71XX_MACH_WRT160NL) += mach-wrt160nl.o +obj-$(CONFIG_AR71XX_MACH_WRT400N) += mach-wrt400n.o ++obj-$(CONFIG_AR71XX_MACH_WZR_HP_G300NH) += mach-wzr-hp-g300nh.o ++obj-$(CONFIG_AR71XX_MACH_WZR_HP_AG300H) += mach-wzr-hp-ag300h.o ++obj-$(CONFIG_AR71XX_MACH_ZCN_1523H) += mach-zcn-1523h.o diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.39/arch/mips/ar71xx/ar71xx.c --- linux-2.6.39.orig/arch/mips/ar71xx/ar71xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/ar71xx.c 2011-05-27 14:36:50.000000000 +0200 -@@ -0,0 +1,177 @@ ++++ linux-2.6.39/arch/mips/ar71xx/ar71xx.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,230 @@ +/* + * AR71xx SoC routines + * @@ -395,10 +582,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.39/arch/mips/ar7 +#include <linux/module.h> +#include <linux/types.h> +#include <linux/mutex.h> ++#include <linux/spinlock.h> + +#include <asm/mach-ar71xx/ar71xx.h> + +static DEFINE_MUTEX(ar71xx_flash_mutex); ++static DEFINE_SPINLOCK(ar71xx_device_lock); + +void __iomem *ar71xx_ddr_base; +EXPORT_SYMBOL_GPL(ar71xx_ddr_base); @@ -425,30 +614,47 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.39/arch/mips/ar7 + case AR71XX_SOC_AR7130: + case AR71XX_SOC_AR7141: + case AR71XX_SOC_AR7161: -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE); + ar71xx_reset_wr(AR71XX_RESET_REG_RESET_MODULE, t | mask); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: + mask_inv = mask & RESET_MODULE_USB_OHCI_DLL_7240; -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE); + t |= mask; + t &= ~mask_inv; + ar71xx_reset_wr(AR724X_RESET_REG_RESET_MODULE, t); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + case AR71XX_SOC_AR9130: + case AR71XX_SOC_AR9132: -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE); + ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, t | mask); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); ++ break; ++ ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ spin_lock_irqsave(&ar71xx_device_lock, flags); ++ t = ar71xx_reset_rr(AR933X_RESET_REG_RESET_MODULE); ++ ar71xx_reset_wr(AR933X_RESET_REG_RESET_MODULE, t | mask); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); ++ break; ++ ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ spin_lock_irqsave(&ar71xx_device_lock, flags); ++ t = ar71xx_reset_rr(AR934X_RESET_REG_RESET_MODULE); ++ ar71xx_reset_wr(AR934X_RESET_REG_RESET_MODULE, t | mask); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + default: @@ -467,30 +673,47 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.39/arch/mips/ar7 + case AR71XX_SOC_AR7130: + case AR71XX_SOC_AR7141: + case AR71XX_SOC_AR7161: -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE); + ar71xx_reset_wr(AR71XX_RESET_REG_RESET_MODULE, t & ~mask); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: + mask_inv = mask & RESET_MODULE_USB_OHCI_DLL_7240; -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE); + t &= ~mask; + t |= mask_inv; + ar71xx_reset_wr(AR724X_RESET_REG_RESET_MODULE, t); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + case AR71XX_SOC_AR9130: + case AR71XX_SOC_AR9132: -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE); + ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, t & ~mask); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); ++ break; ++ ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ spin_lock_irqsave(&ar71xx_device_lock, flags); ++ t = ar71xx_reset_rr(AR933X_RESET_REG_RESET_MODULE); ++ ar71xx_reset_wr(AR933X_RESET_REG_RESET_MODULE, t & ~mask); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); ++ break; ++ ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ spin_lock_irqsave(&ar71xx_device_lock, flags); ++ t = ar71xx_reset_rr(AR934X_RESET_REG_RESET_MODULE); ++ ar71xx_reset_wr(AR934X_RESET_REG_RESET_MODULE, t & ~mask); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + default: @@ -508,24 +731,39 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.39/arch/mips/ar7 + case AR71XX_SOC_AR7130: + case AR71XX_SOC_AR7141: + case AR71XX_SOC_AR7161: -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + case AR71XX_SOC_AR9130: + case AR71XX_SOC_AR9132: -+ local_irq_save(flags); ++ spin_lock_irqsave(&ar71xx_device_lock, flags); + t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); ++ break; ++ ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ spin_lock_irqsave(&ar71xx_device_lock, flags); ++ t = ar71xx_reset_rr(AR933X_RESET_REG_RESET_MODULE); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); ++ break; ++ ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ spin_lock_irqsave(&ar71xx_device_lock, flags); ++ t = ar71xx_reset_rr(AR934X_RESET_REG_RESET_MODULE); ++ spin_unlock_irqrestore(&ar71xx_device_lock, flags); + break; + + default: @@ -539,10 +777,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.39/arch/mips/ar7 +void ar71xx_ddr_flush(u32 reg) +{ + ar71xx_ddr_wr(reg, 1); -+ while ((ar71xx_ddr_rr(reg) & 0x1)); ++ while ((ar71xx_ddr_rr(reg) & 0x1)) ++ ; + + ar71xx_ddr_wr(reg, 1); -+ while ((ar71xx_ddr_rr(reg) & 0x1)); ++ while ((ar71xx_ddr_rr(reg) & 0x1)) ++ ; +} +EXPORT_SYMBOL_GPL(ar71xx_ddr_flush); + @@ -557,111 +797,10 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.39/arch/mips/ar7 + mutex_unlock(&ar71xx_flash_mutex); +} +EXPORT_SYMBOL_GPL(ar71xx_flash_release); -diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-eth.c linux-2.6.39/arch/mips/ar71xx/dev-ap91-eth.c ---- linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-eth.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-ap91-eth.c 2011-05-27 14:36:50.000000000 +0200 -@@ -0,0 +1,70 @@ -+/* -+ * Atheros AP91 reference board ethernet initialization -+ * -+ * Copyright (C) 2010 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 "devices.h" -+#include "dev-dsa.h" -+#include "dev-ap91-eth.h" -+ -+static struct dsa_chip_data ap91_dsa_chip = { -+ .port_names[0] = "cpu", -+ .port_names[1] = "lan1", -+ .port_names[2] = "lan2", -+ .port_names[3] = "lan3", -+ .port_names[4] = "lan4", -+}; -+ -+static struct dsa_platform_data ap91_dsa_data = { -+ .nr_chips = 1, -+ .chip = &ap91_dsa_chip, -+}; -+ -+static void ap91_eth_set_port_name(unsigned port, const char *name) -+{ -+ if (port < 1 || port > 5) -+ return; -+ -+ if (name) -+ ap91_dsa_chip.port_names[port] = (char *) name; -+} -+ -+void __init ap91_eth_init(u8 *mac_addr, const char *port_names[]) -+{ -+ if (mac_addr) -+ ar71xx_set_mac_base(mac_addr); -+ -+ if (port_names) { -+ int i; -+ -+ for (i = 0; i < AP91_ETH_NUM_PORT_NAMES; i++) -+ ap91_eth_set_port_name(i + 1, port_names[i]); -+ } -+ -+ /* WAN port */ -+ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; -+ ar71xx_eth0_data.speed = SPEED_100; -+ ar71xx_eth0_data.duplex = DUPLEX_FULL; -+ ar71xx_eth0_data.fifo_cfg1 = 0x0fff0000; -+ ar71xx_eth0_data.fifo_cfg2 = 0x00001fff; -+ ar71xx_eth0_data.fifo_cfg3 = 0x008001ff; -+ -+ /* LAN ports */ -+ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; -+ ar71xx_eth1_data.speed = SPEED_1000; -+ ar71xx_eth1_data.duplex = DUPLEX_FULL; -+ ar71xx_eth1_data.fifo_cfg1 = 0x0fff0000; -+ ar71xx_eth1_data.fifo_cfg2 = 0x00001fff; -+ ar71xx_eth1_data.fifo_cfg3 = 0x008001ff; -+ -+ ar71xx_add_device_mdio(0x0); -+ ar71xx_add_device_eth(1); -+ ar71xx_add_device_eth(0); -+ -+ ar71xx_add_device_dsa(1, &ap91_dsa_data); -+} -diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-eth.h linux-2.6.39/arch/mips/ar71xx/dev-ap91-eth.h ---- linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-eth.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-ap91-eth.h 2011-05-27 14:36:50.000000000 +0200 -@@ -0,0 +1,23 @@ -+/* -+ * Atheros AP91 reference board ethernet initialization -+ * -+ * Copyright (C) 2010 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 _AR71XX_DEV_AP91_ETH_H -+#define _AR71XX_DEV_AP91_ETH_H -+ -+#define AP91_ETH_NUM_PORT_NAMES 4 -+ -+#if defined(CONFIG_AR71XX_DEV_AP91_ETH) -+void ap91_eth_init(u8 *mac_addr, const char *port_names[]) __init; -+#else -+static inline void ap91_eth_init(u8 *mac_addr) { } -+#endif -+ -+#endif /* _AR71XX_DEV_AP91_ETH_H */ -+ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.c linux-2.6.39/arch/mips/ar71xx/dev-ap91-pci.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-ap91-pci.c 2011-05-27 14:36:50.000000000 +0200 -@@ -0,0 +1,114 @@ ++++ linux-2.6.39/arch/mips/ar71xx/dev-ap91-pci.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,71 @@ +/* + * Atheros AP91 reference board PCI initialization + * @@ -680,10 +819,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.c linux-2.6.39/arch/mi +#include <asm/mach-ar71xx/pci.h> + +#include "dev-ap91-pci.h" ++#include "pci-ath9k-fixup.h" + -+static struct ath9k_platform_data ap91_wmac_data; ++static struct ath9k_platform_data ap91_wmac_data = { ++ .led_pin = -1, ++}; +static char ap91_wmac_mac[6]; -+static int ap91_pci_fixup_enabled; + +static struct ar71xx_pci_irq ap91_pci_irqs[] __initdata = { + { @@ -695,7 +836,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.c linux-2.6.39/arch/mi + +static int ap91_pci_plat_dev_init(struct pci_dev *dev) +{ -+ switch(PCI_SLOT(dev->devfn)) { ++ switch (PCI_SLOT(dev->devfn)) { + case 0: + dev->dev.platform_data = &ap91_wmac_data; + break; @@ -704,61 +845,16 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.c linux-2.6.39/arch/mi + return 0; +} + -+static void ap91_pci_fixup(struct pci_dev *dev) ++__init void ap91_pci_setup_wmac_led_pin(int pin) +{ -+ void __iomem *mem; -+ u16 *cal_data; -+ u16 cmd; -+ u32 val; -+ -+ if (!ap91_pci_fixup_enabled) -+ return; -+ -+ printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev)); -+ -+ cal_data = ap91_wmac_data.eeprom_data; -+ if (*cal_data != 0xa55a) { -+ printk(KERN_ERR "PCI: no calibration data found for %s\n", -+ pci_name(dev)); -+ return; -+ } -+ -+ mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000); -+ if (!mem) { -+ printk(KERN_ERR "PCI: ioremap error for device %s\n", -+ pci_name(dev)); -+ return; -+ } -+ -+ /* Setup the PCI device to allow access to the internal registers */ -+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0xffff); -+ pci_read_config_word(dev, PCI_COMMAND, &cmd); -+ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; -+ pci_write_config_word(dev, PCI_COMMAND, cmd); -+ -+ /* set pointer to first reg address */ -+ cal_data += 3; -+ while (*cal_data != 0xffff) { -+ u32 reg; -+ reg = *cal_data++; -+ val = *cal_data++; -+ val |= (*cal_data++) << 16; -+ -+ __raw_writel(val, mem + reg); -+ udelay(100); -+ } -+ -+ pci_read_config_dword(dev, PCI_VENDOR_ID, &val); -+ dev->vendor = val & 0xffff; -+ dev->device = (val >> 16) & 0xffff; -+ -+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &val); -+ dev->revision = val & 0xff; -+ dev->class = val >> 8; /* upper 3 bytes */ ++ ap91_wmac_data.led_pin = pin; ++} + -+ iounmap(mem); ++__init void ap91_pci_setup_wmac_gpio(u32 mask, u32 val) ++{ ++ ap91_wmac_data.gpio_mask = mask; ++ ap91_wmac_data.gpio_val = val; +} -+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ap91_pci_fixup); + +void __init ap91_pci_init(u8 *cal_data, u8 *mac_addr) +{ @@ -774,12 +870,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.c linux-2.6.39/arch/mi + ar71xx_pci_plat_dev_init = ap91_pci_plat_dev_init; + ar71xx_pci_init(ARRAY_SIZE(ap91_pci_irqs), ap91_pci_irqs); + -+ ap91_pci_fixup_enabled = 1; ++ pci_enable_ath9k_fixup(0, ap91_wmac_data.eeprom_data); +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.h linux-2.6.39/arch/mips/ar71xx/dev-ap91-pci.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-ap91-pci.h 2011-05-27 14:36:50.000000000 +0200 -@@ -0,0 +1,21 @@ ++++ linux-2.6.39/arch/mips/ar71xx/dev-ap91-pci.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,25 @@ +/* + * Atheros AP91 reference board PCI initialization + * @@ -795,16 +891,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap91-pci.h linux-2.6.39/arch/mi + +#if defined(CONFIG_AR71XX_DEV_AP91_PCI) +void ap91_pci_init(u8 *cal_data, u8 *mac_addr) __init; ++void ap91_pci_setup_wmac_led_pin(int pin) __init; ++void ap91_pci_setup_wmac_gpio(u32 mask, u32 val) __init; +#else +static inline void ap91_pci_init(u8 *cal_data, u8 *mac_addr) { } ++static inline void ap91_pci_setup_wmac_led_pin(int pin) { } ++static inline void ap91_pci_setup_wmac_gpio(u32 mask, u32 gpio) { } +#endif + +#endif /* _AR71XX_DEV_AP91_PCI_H */ + diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap94-pci.c linux-2.6.39/arch/mips/ar71xx/dev-ap94-pci.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-ap94-pci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-ap94-pci.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,159 @@ ++++ linux-2.6.39/arch/mips/ar71xx/dev-ap94-pci.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,109 @@ +/* + * Atheros AP94 reference board PCI initialization + * @@ -823,28 +923,32 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap94-pci.c linux-2.6.39/arch/mi +#include <asm/mach-ar71xx/pci.h> + +#include "dev-ap94-pci.h" ++#include "pci-ath9k-fixup.h" + -+static struct ath9k_platform_data ap94_wmac0_data; -+static struct ath9k_platform_data ap94_wmac1_data; ++static struct ath9k_platform_data ap94_wmac0_data = { ++ .led_pin = -1, ++}; ++static struct ath9k_platform_data ap94_wmac1_data = { ++ .led_pin = -1, ++}; +static char ap94_wmac0_mac[6]; +static char ap94_wmac1_mac[6]; -+static int ap94_pci_fixup_enabled; + +static struct ar71xx_pci_irq ap94_pci_irqs[] __initdata = { -+ { -+ .slot = 0, -+ .pin = 1, -+ .irq = AR71XX_PCI_IRQ_DEV0, -+ }, { -+ .slot = 1, -+ .pin = 1, -+ .irq = AR71XX_PCI_IRQ_DEV1, -+ } ++ { ++ .slot = 0, ++ .pin = 1, ++ .irq = AR71XX_PCI_IRQ_DEV0, ++ }, { ++ .slot = 1, ++ .pin = 1, ++ .irq = AR71XX_PCI_IRQ_DEV1, ++ } +}; + +static int ap94_pci_plat_dev_init(struct pci_dev *dev) +{ -+ switch(PCI_SLOT(dev->devfn)) { ++ switch (PCI_SLOT(dev->devfn)) { + case 17: + dev->dev.platform_data = &ap94_wmac0_data; + break; @@ -857,85 +961,30 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap94-pci.c linux-2.6.39/arch/mi + return 0; +} + -+static void ap94_pci_fixup(struct pci_dev *dev) ++__init void ap94_pci_setup_wmac_led_pin(unsigned wmac, int pin) +{ -+ void __iomem *mem; -+ u16 *cal_data; -+ u16 cmd; -+ u32 bar0; -+ u32 val; -+ -+ if (!ap94_pci_fixup_enabled) -+ return; -+ -+ switch (PCI_SLOT(dev->devfn)) { -+ case 17: -+ cal_data = ap94_wmac0_data.eeprom_data; ++ switch (wmac) { ++ case 0: ++ ap94_wmac0_data.led_pin = pin; + break; -+ case 18: -+ cal_data = ap94_wmac1_data.eeprom_data; ++ case 1: ++ ap94_wmac1_data.led_pin = pin; + break; -+ default: -+ return; -+ } -+ -+ if (*cal_data != 0xa55a) { -+ printk(KERN_ERR "PCI: no calibration data found for %s\n", -+ pci_name(dev)); -+ return; + } -+ -+ mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000); -+ if (!mem) { -+ printk(KERN_ERR "PCI: ioremap error for device %s\n", -+ pci_name(dev)); -+ return; -+ } -+ -+ printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev)); -+ -+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0); -+ -+ /* Setup the PCI device to allow access to the internal registers */ -+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, AR71XX_PCI_MEM_BASE); -+ pci_read_config_word(dev, PCI_COMMAND, &cmd); -+ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; -+ pci_write_config_word(dev, PCI_COMMAND, cmd); -+ -+ /* set pointer to first reg address */ -+ cal_data += 3; -+ while (*cal_data != 0xffff) { -+ u32 reg; -+ reg = *cal_data++; -+ val = *cal_data++; -+ val |= (*cal_data++) << 16; -+ -+ __raw_writel(val, mem + reg); -+ udelay(100); -+ } -+ -+ pci_read_config_dword(dev, PCI_VENDOR_ID, &val); -+ dev->vendor = val & 0xffff; -+ dev->device = (val >> 16) & 0xffff; -+ -+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &val); -+ dev->revision = val & 0xff; -+ dev->class = val >> 8; /* upper 3 bytes */ -+ -+ pci_read_config_word(dev, PCI_COMMAND, &cmd); -+ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); -+ pci_write_config_word(dev, PCI_COMMAND, cmd); -+ -+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0); -+ -+ iounmap(mem); +} -+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ap94_pci_fixup); + -+void __init ap94_pci_enable_quirk_wndr3700(void) ++__init void ap94_pci_setup_wmac_gpio(unsigned wmac, u32 mask, u32 val) +{ -+ ap94_wmac0_data.quirk_wndr3700 = 1; -+ ap94_wmac1_data.quirk_wndr3700 = 1; ++ switch (wmac) { ++ case 0: ++ ap94_wmac0_data.gpio_mask = mask; ++ ap94_wmac0_data.gpio_val = val; ++ break; ++ case 1: ++ ap94_wmac1_data.gpio_mask = mask; ++ ap94_wmac1_data.gpio_val = val; ++ break; ++ } +} + +void __init ap94_pci_init(u8 *cal_data0, u8 *mac_addr0, @@ -962,12 +1011,13 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap94-pci.c linux-2.6.39/arch/mi + ar71xx_pci_plat_dev_init = ap94_pci_plat_dev_init; + ar71xx_pci_init(ARRAY_SIZE(ap94_pci_irqs), ap94_pci_irqs); + -+ ap94_pci_fixup_enabled = 1; ++ pci_enable_ath9k_fixup(17, ap94_wmac0_data.eeprom_data); ++ pci_enable_ath9k_fixup(18, ap94_wmac1_data.eeprom_data); +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap94-pci.h linux-2.6.39/arch/mips/ar71xx/dev-ap94-pci.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-ap94-pci.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-ap94-pci.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,28 @@ ++++ linux-2.6.39/arch/mips/ar71xx/dev-ap94-pci.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,31 @@ +/* + * Atheros AP94 reference board PCI initialization + * @@ -985,28 +1035,32 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ap94-pci.h linux-2.6.39/arch/mi +void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0, + u8 *cal_data1, u8 *mac_addr1) __init; + -+void ap94_pci_enable_quirk_wndr3700(void) __init; ++void ap94_pci_setup_wmac_led_pin(unsigned wmac, int pin) __init; ++void ap94_pci_setup_wmac_gpio(unsigned wmac, u32 mask, u32 val) __init; + +#else +static inline void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0, + u8 *cal_data1, u8 *mac_addr1) {} + -+static inline void ap94_pci_enable_quirk_wndr3700(void) {} ++static inline void ap94_pci_setup_wmac_led_pin(unsigned wmac, int pin) {} ++static inline void ap94_pci_setup_wmac_gpio(unsigned wmac, ++ u32 mask, u32 val) {} +#endif + +#endif /* _AR71XX_DEV_AP94_PCI_H */ + -diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ar913x-wmac.c linux-2.6.39/arch/mips/ar71xx/dev-ar913x-wmac.c ---- linux-2.6.39.orig/arch/mips/ar71xx/dev-ar913x-wmac.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-ar913x-wmac.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,68 @@ +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ar9xxx-wmac.c linux-2.6.39/arch/mips/ar71xx/dev-ar9xxx-wmac.c +--- linux-2.6.39.orig/arch/mips/ar71xx/dev-ar9xxx-wmac.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/dev-ar9xxx-wmac.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,154 @@ +/* -+ * Atheros AR913x SoC built-in WMAC device support ++ * Atheros AR9XXX SoCs built-in WMAC device support + * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2009 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 ++ * Parts of this file are based on Atheros 2.6.15/2.6.31 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 @@ -1022,15 +1076,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ar913x-wmac.c linux-2.6.39/arch + +#include <asm/mach-ar71xx/ar71xx.h> + -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" + -+static struct ath9k_platform_data ar913x_wmac_data; -+static char ar913x_wmac_mac[6]; ++#define MHZ_25 (25 * 1000 * 1000) + -+static struct resource ar913x_wmac_resources[] = { ++static struct ath9k_platform_data ar9xxx_wmac_data = { ++ .led_pin = -1, ++}; ++static char ar9xxx_wmac_mac[6]; ++ ++static struct resource ar9xxx_wmac_resources[] = { + { -+ .start = AR91XX_WMAC_BASE, -+ .end = AR91XX_WMAC_BASE + AR91XX_WMAC_SIZE - 1, ++ /* .start and .end fields are filled dynamically */ + .flags = IORESOURCE_MEM, + }, { + .start = AR71XX_CPU_IRQ_IP2, @@ -1039,61 +1096,205 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ar913x-wmac.c linux-2.6.39/arch + }, +}; + -+static struct platform_device ar913x_wmac_device = { ++static struct platform_device ar9xxx_wmac_device = { + .name = "ath9k", + .id = -1, -+ .resource = ar913x_wmac_resources, -+ .num_resources = ARRAY_SIZE(ar913x_wmac_resources), ++ .resource = ar9xxx_wmac_resources, ++ .num_resources = ARRAY_SIZE(ar9xxx_wmac_resources), + .dev = { -+ .platform_data = &ar913x_wmac_data, ++ .platform_data = &ar9xxx_wmac_data, + }, +}; + -+void __init ar913x_add_device_wmac(u8 *cal_data, u8 *mac_addr) ++static void ar913x_wmac_init(void) +{ -+ if (cal_data) -+ memcpy(ar913x_wmac_data.eeprom_data, cal_data, -+ sizeof(ar913x_wmac_data.eeprom_data)); -+ -+ if (mac_addr) { -+ memcpy(ar913x_wmac_mac, mac_addr, sizeof(ar913x_wmac_mac)); -+ ar913x_wmac_data.macaddr = ar913x_wmac_mac; -+ } -+ + ar71xx_device_stop(RESET_MODULE_AMBA2WMAC); + mdelay(10); + + ar71xx_device_start(RESET_MODULE_AMBA2WMAC); + mdelay(10); + -+ platform_device_register(&ar913x_wmac_device); ++ ar9xxx_wmac_resources[0].start = AR91XX_WMAC_BASE; ++ ar9xxx_wmac_resources[0].end = AR91XX_WMAC_BASE + AR91XX_WMAC_SIZE - 1; +} -diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ar913x-wmac.h linux-2.6.39/arch/mips/ar71xx/dev-ar913x-wmac.h ---- linux-2.6.39.orig/arch/mips/ar71xx/dev-ar913x-wmac.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-ar913x-wmac.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,19 @@ ++ ++static int ar933x_r1_get_wmac_revision(void) ++{ ++ return ar71xx_soc_rev; ++} ++ ++static int ar933x_wmac_reset(void) ++{ ++ unsigned retries = 0; ++ ++ ar71xx_device_stop(AR933X_RESET_WMAC); ++ ar71xx_device_start(AR933X_RESET_WMAC); ++ ++ while (1) { ++ u32 bootstrap; ++ ++ bootstrap = ar71xx_reset_rr(AR933X_RESET_REG_BOOTSTRAP); ++ if ((bootstrap & AR933X_BOOTSTRAP_EEPBUSY) == 0) ++ return 0; ++ ++ if (retries > 20) ++ break; ++ ++ udelay(10000); ++ retries++; ++ } ++ ++ pr_err("ar93xx: WMAC reset timed out"); ++ return -ETIMEDOUT; ++} ++ ++static void ar933x_wmac_init(void) ++{ ++ ar9xxx_wmac_device.name = "ar933x_wmac"; ++ ar9xxx_wmac_resources[0].start = AR933X_WMAC_BASE; ++ ar9xxx_wmac_resources[0].end = AR933X_WMAC_BASE + AR933X_WMAC_SIZE - 1; ++ if (ar71xx_ref_freq == MHZ_25) ++ ar9xxx_wmac_data.is_clk_25mhz = true; ++ ++ if (ar71xx_soc_rev == 1) ++ ar9xxx_wmac_data.get_mac_revision = ar933x_r1_get_wmac_revision; ++ ++ ar9xxx_wmac_data.external_reset = ar933x_wmac_reset; ++ ++ ar933x_wmac_reset(); ++} ++ ++static void ar934x_wmac_init(void) ++{ ++ ar9xxx_wmac_device.name = "ar934x_wmac"; ++ ar9xxx_wmac_resources[0].start = AR934X_WMAC_BASE; ++ ar9xxx_wmac_resources[0].end = AR934X_WMAC_BASE + AR934X_WMAC_SIZE - 1; ++ if (ar71xx_ref_freq == MHZ_25) ++ ar9xxx_wmac_data.is_clk_25mhz = true; ++} ++ ++void __init ar9xxx_add_device_wmac(u8 *cal_data, u8 *mac_addr) ++{ ++ switch (ar71xx_soc) { ++ case AR71XX_SOC_AR9130: ++ case AR71XX_SOC_AR9132: ++ ar913x_wmac_init(); ++ break; ++ ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ ar933x_wmac_init(); ++ break; ++ ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ ar934x_wmac_init(); ++ break; ++ ++ default: ++ BUG(); ++ } ++ ++ if (cal_data) ++ memcpy(ar9xxx_wmac_data.eeprom_data, cal_data, ++ sizeof(ar9xxx_wmac_data.eeprom_data)); ++ ++ if (mac_addr) { ++ memcpy(ar9xxx_wmac_mac, mac_addr, sizeof(ar9xxx_wmac_mac)); ++ ar9xxx_wmac_data.macaddr = ar9xxx_wmac_mac; ++ } ++ ++ platform_device_register(&ar9xxx_wmac_device); ++} +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-ar9xxx-wmac.h linux-2.6.39/arch/mips/ar71xx/dev-ar9xxx-wmac.h +--- linux-2.6.39.orig/arch/mips/ar71xx/dev-ar9xxx-wmac.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/dev-ar9xxx-wmac.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,20 @@ +/* -+ * Atheros AR913x SoC built-in WMAC device support ++ * Atheros AR9XXX SoCs built-in WMAC device support + * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2009 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 ++ * Parts of this file are based on Atheros 2.6.15/2.6.31 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 _AR71XX_DEV_AR9XXX_WMAC_H ++#define _AR71XX_DEV_AR9XXX_WMAC_H ++ ++void ar9xxx_add_device_wmac(u8 *cal_data, u8 *mac_addr) __init; ++ ++#endif /* _AR71XX_DEV_AR9XXX_WMAC_H */ +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-db120-pci.c linux-2.6.39/arch/mips/ar71xx/dev-db120-pci.c +--- linux-2.6.39.orig/arch/mips/ar71xx/dev-db120-pci.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/dev-db120-pci.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,31 @@ ++/* ++ * Atheros db120 reference board PCI initialization ++ * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> ++ * ++ * Parts of this file are based on Atheros linux 2.6.31 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/pci.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++#include <asm/mach-ar71xx/pci.h> ++ ++#include "dev-db120-pci.h" ++ ++static struct ar71xx_pci_irq db120_pci_irqs[] __initdata = { ++ { ++ .slot = 0, ++ .pin = 1, ++ .irq = AR71XX_PCI_IRQ_DEV0, ++ } ++}; ++ ++void __init db120_pci_init(void) ++{ ++ ar71xx_pci_init(ARRAY_SIZE(db120_pci_irqs), db120_pci_irqs); ++} +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-db120-pci.h linux-2.6.39/arch/mips/ar71xx/dev-db120-pci.h +--- linux-2.6.39.orig/arch/mips/ar71xx/dev-db120-pci.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/dev-db120-pci.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,22 @@ ++/* ++ * Atheros DB120 reference board PCI initialization ++ * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> ++ * ++ * Parts of this file are based on Atheros linux 2.6.31 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 _AR71XX_DEV_AR913X_WMAC_H -+#define _AR71XX_DEV_AR913X_WMAC_H ++#ifndef _AR71XX_DEV_DB120_PCI_H ++#define _AR71XX_DEV_DB120_PCI_H + -+void ar913x_add_device_wmac(u8 *cal_data, u8 *mac_addr) __init; ++#if defined(CONFIG_AR71XX_DEV_DB120_PCI) ++void db120_pci_init(void); ++#else ++static inline void db120_pci_init(void) { } ++#endif + -+#endif /* _AR71XX_DEV_AR913X_WMAC_H */ ++#endif /* _AR71XX_DEV_DB120_PCI_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-dsa.c linux-2.6.39/arch/mips/ar71xx/dev-dsa.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-dsa.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-dsa.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-dsa.c 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,50 @@ +/* + * Atheros AR71xx DSA switch device support @@ -1147,7 +1348,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-dsa.c linux-2.6.39/arch/mips/ar +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-dsa.h linux-2.6.39/arch/mips/ar71xx/dev-dsa.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-dsa.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-dsa.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-dsa.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,20 @@ +/* + * Atheros AR71xx DSA switch device support @@ -1171,7 +1372,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-dsa.h linux-2.6.39/arch/mips/ar +#endif /* _AR71XX_DEV_DSA_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.c linux-2.6.39/arch/mips/ar71xx/dev-gpio-buttons.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-gpio-buttons.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-gpio-buttons.c 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,58 @@ +/* + * Atheros AR71xx GPIO button support @@ -1185,18 +1386,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.c linux-2.6.39/arc + */ + +#include "linux/init.h" ++#include "linux/slab.h" +#include <linux/platform_device.h> + +#include "dev-gpio-buttons.h" + -+void __init ar71xx_add_device_gpio_buttons(int id, -+ unsigned poll_interval, -+ unsigned nbuttons, -+ struct gpio_button *buttons) ++void __init ar71xx_register_gpio_keys_polled(int id, ++ unsigned poll_interval, ++ unsigned nbuttons, ++ struct gpio_keys_button *buttons) +{ + struct platform_device *pdev; -+ struct gpio_buttons_platform_data pdata; -+ struct gpio_button *p; ++ struct gpio_keys_platform_data pdata; ++ struct gpio_keys_button *p; + int err; + + p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL); @@ -1205,7 +1407,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.c linux-2.6.39/arc + + memcpy(p, buttons, nbuttons * sizeof(*p)); + -+ pdev = platform_device_alloc("gpio-buttons", id); ++ pdev = platform_device_alloc("gpio-keys-polled", id); + if (!pdev) + goto err_free_buttons; + @@ -1218,7 +1420,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.c linux-2.6.39/arc + if (err) + goto err_put_pdev; + -+ + err = platform_device_add(pdev); + if (err) + goto err_put_pdev; @@ -1233,8 +1434,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.c linux-2.6.39/arc +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.h linux-2.6.39/arch/mips/ar71xx/dev-gpio-buttons.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-gpio-buttons.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,25 @@ ++++ linux-2.6.39/arch/mips/ar71xx/dev-gpio-buttons.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,23 @@ +/* + * Atheros AR71xx GPIO button support + * @@ -1250,19 +1451,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-gpio-buttons.h linux-2.6.39/arc +#define _AR71XX_DEV_GPIO_BUTTONS_H + +#include <linux/input.h> -+#include <linux/gpio_buttons.h> ++#include <linux/gpio_keys.h> + -+#include <asm/mach-ar71xx/platform.h> -+ -+void ar71xx_add_device_gpio_buttons(int id, -+ unsigned poll_interval, -+ unsigned nbuttons, -+ struct gpio_button *buttons) __init; ++void ar71xx_register_gpio_keys_polled(int id, ++ unsigned poll_interval, ++ unsigned nbuttons, ++ struct gpio_keys_button *buttons); + +#endif /* _AR71XX_DEV_GPIO_BUTTONS_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-leds-gpio.c linux-2.6.39/arch/mips/ar71xx/dev-leds-gpio.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-leds-gpio.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-leds-gpio.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-leds-gpio.c 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,57 @@ +/* + * Atheros AR71xx GPIO LED device support @@ -1278,8 +1477,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-leds-gpio.c linux-2.6.39/arch/m + */ + +#include <linux/init.h> -+#include <linux/platform_device.h> +#include <linux/slab.h> ++#include <linux/platform_device.h> + +#include "dev-leds-gpio.h" + @@ -1323,7 +1522,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-leds-gpio.c linux-2.6.39/arch/m +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-leds-gpio.h linux-2.6.39/arch/mips/ar71xx/dev-leds-gpio.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-leds-gpio.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-leds-gpio.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-leds-gpio.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,21 @@ +/* + * Atheros AR71xx GPIO LED device support @@ -1348,7 +1547,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-leds-gpio.h linux-2.6.39/arch/m +#endif /* _AR71XX_DEV_LEDS_GPIO_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-m25p80.c linux-2.6.39/arch/mips/ar71xx/dev-m25p80.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-m25p80.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-m25p80.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-m25p80.c 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> @@ -1382,7 +1581,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-m25p80.c linux-2.6.39/arch/mips +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-m25p80.h linux-2.6.39/arch/mips/ar71xx/dev-m25p80.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-m25p80.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-m25p80.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-m25p80.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> @@ -1402,7 +1601,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-m25p80.h linux-2.6.39/arch/mips +#endif /* _AR71XX_DEV_M25P80_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-pb42-pci.c linux-2.6.39/arch/mips/ar71xx/dev-pb42-pci.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-pb42-pci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-pb42-pci.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-pb42-pci.c 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,40 @@ +/* + * Atheros PB42 reference board PCI initialization @@ -1446,7 +1645,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-pb42-pci.c linux-2.6.39/arch/mi +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-pb42-pci.h linux-2.6.39/arch/mips/ar71xx/dev-pb42-pci.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-pb42-pci.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-pb42-pci.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-pb42-pci.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,21 @@ +/* + * Atheros PB42 reference board PCI initialization @@ -1471,7 +1670,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-pb42-pci.h linux-2.6.39/arch/mi +#endif /* _AR71XX_DEV_PB42_PCI_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-pb9x-pci.c linux-2.6.39/arch/mips/ar71xx/dev-pb9x-pci.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-pb9x-pci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-pb9x-pci.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-pb9x-pci.c 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,33 @@ +/* + * Atheros PB9x reference board PCI initialization @@ -1508,7 +1707,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-pb9x-pci.c linux-2.6.39/arch/mi +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-pb9x-pci.h linux-2.6.39/arch/mips/ar71xx/dev-pb9x-pci.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-pb9x-pci.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-pb9x-pci.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-pb9x-pci.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,22 @@ +/* + * Atheros PB9x reference board PCI initialization @@ -1534,8 +1733,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-pb9x-pci.h linux-2.6.39/arch/mi +#endif /* _AR71XX_DEV_PB9X_PCI_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.c linux-2.6.39/arch/mips/ar71xx/dev-usb.c --- linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-usb.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,181 @@ ++++ linux-2.6.39/arch/mips/ar71xx/dev-usb.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,199 @@ +/* + * Atheros AR71xx USB host device support + * @@ -1602,7 +1801,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.c linux-2.6.39/arch/mips/ar +}; + +/* -+ * EHCI (USB full speed host controller) ++ * EHCI (USB high/full speed host controller) + */ +static struct resource ar71xx_ehci_resources[] = { + [0] = { @@ -1666,16 +1865,26 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.c linux-2.6.39/arch/mips/ar + /* WAR for HW bug. Here it adjusts the duration between two SOFS */ + ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x3); + -+ if (ar71xx_soc == AR71XX_SOC_AR7241 || ar71xx_soc == AR71XX_SOC_AR7242) { -+ ar71xx_ehci_data.is_ar91xx = 1; -+ ar71xx_ehci_device.resource = ar7240_ohci_resources; -+ ar71xx_ehci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources); -+ platform_device_register(&ar71xx_ehci_device); -+ } else { -+ ar71xx_ohci_device.resource = ar7240_ohci_resources; -+ ar71xx_ohci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources); -+ platform_device_register(&ar71xx_ohci_device); -+ } ++ ar71xx_ohci_device.resource = ar7240_ohci_resources; ++ ar71xx_ohci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources); ++ platform_device_register(&ar71xx_ohci_device); ++} ++ ++static void __init ar7241_usb_setup(void) ++{ ++ ar71xx_device_start(AR724X_RESET_USBSUS_OVERRIDE); ++ mdelay(10); ++ ++ ar71xx_device_start(AR724X_RESET_USB_HOST); ++ mdelay(10); ++ ++ ar71xx_device_start(AR724X_RESET_USB_PHY); ++ mdelay(10); ++ ++ ar71xx_ehci_data.is_ar91xx = 1; ++ ar71xx_ehci_device.resource = ar7240_ohci_resources; ++ ar71xx_ehci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources); ++ platform_device_register(&ar71xx_ehci_device); +} + +static void __init ar91xx_usb_setup(void) @@ -1697,9 +1906,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.c linux-2.6.39/arch/mips/ar +{ + switch (ar71xx_soc) { + case AR71XX_SOC_AR7240: ++ ar7240_usb_setup(); ++ break; ++ + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: -+ ar7240_usb_setup(); ++ ar7241_usb_setup(); + break; + + case AR71XX_SOC_AR7130: @@ -1710,6 +1922,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.c linux-2.6.39/arch/mips/ar + + case AR71XX_SOC_AR9130: + case AR71XX_SOC_AR9132: ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: + ar91xx_usb_setup(); + break; + @@ -1719,7 +1936,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.c linux-2.6.39/arch/mips/ar +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.h linux-2.6.39/arch/mips/ar71xx/dev-usb.h --- linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/dev-usb.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/dev-usb.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,17 @@ +/* + * Atheros AR71xx USB host device support @@ -1740,15 +1957,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/dev-usb.h linux-2.6.39/arch/mips/ar +#endif /* _AR71XX_DEV_USB_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar71xx/devices.c --- linux-2.6.39.orig/arch/mips/ar71xx/devices.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/devices.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,575 @@ ++++ linux-2.6.39/arch/mips/ar71xx/devices.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,765 @@ +/* + * Atheros AR71xx SoC platform devices + * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2009 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 ++ * Parts of this file are based on Atheros 2.6.15 BSP ++ * Parts of this file are based on Atheros 2.6.31 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 @@ -1763,10 +1982,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar +#include <linux/serial_8250.h> + +#include <asm/mach-ar71xx/ar71xx.h> ++#include <asm/mach-ar71xx/ar933x_uart_platform.h> + +#include "devices.h" + -+static u8 ar71xx_mac_base[ETH_ALEN] __initdata; ++unsigned char ar71xx_mac_base[ETH_ALEN] __initdata; + +static struct resource ar71xx_uart_resources[] = { + { @@ -1799,10 +2019,65 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + }, +}; + ++static struct resource ar933x_uart_resources[] = { ++ { ++ .start = AR933X_UART_BASE, ++ .end = AR933X_UART_BASE + AR71XX_UART_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = AR71XX_MISC_IRQ_UART, ++ .end = AR71XX_MISC_IRQ_UART, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct ar933x_uart_platform_data ar933x_uart_data; ++static struct platform_device ar933x_uart_device = { ++ .name = "ar933x-uart", ++ .id = -1, ++ .resource = ar933x_uart_resources, ++ .num_resources = ARRAY_SIZE(ar933x_uart_resources), ++ .dev = { ++ .platform_data = &ar933x_uart_data, ++ }, ++}; ++ +void __init ar71xx_add_device_uart(void) +{ -+ ar71xx_uart_data[0].uartclk = ar71xx_ahb_freq; -+ platform_device_register(&ar71xx_uart_device); ++ struct platform_device *pdev; ++ ++ switch (ar71xx_soc) { ++ case AR71XX_SOC_AR7130: ++ case AR71XX_SOC_AR7141: ++ case AR71XX_SOC_AR7161: ++ case AR71XX_SOC_AR7240: ++ case AR71XX_SOC_AR7241: ++ case AR71XX_SOC_AR7242: ++ case AR71XX_SOC_AR9130: ++ case AR71XX_SOC_AR9132: ++ pdev = &ar71xx_uart_device; ++ ar71xx_uart_data[0].uartclk = ar71xx_ahb_freq; ++ break; ++ ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ pdev = &ar933x_uart_device; ++ ar933x_uart_data.uartclk = ar71xx_ref_freq; ++ break; ++ ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ pdev = &ar71xx_uart_device; ++ ar71xx_uart_data[0].uartclk = ar71xx_ref_freq; ++ break; ++ ++ default: ++ BUG(); ++ } ++ ++ platform_device_register(pdev); +} + +static struct resource ar71xx_mdio_resources[] = { @@ -1826,23 +2101,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + }, +}; + -+void __init ar71xx_add_device_mdio(u32 phy_mask) -+{ -+ switch (ar71xx_soc) { -+ case AR71XX_SOC_AR7240: -+ case AR71XX_SOC_AR7241: -+ case AR71XX_SOC_AR7242: -+ ar71xx_mdio_data.is_ar7240 = 1; -+ break; -+ default: -+ break; -+ } -+ -+ ar71xx_mdio_data.phy_mask = phy_mask; -+ -+ platform_device_register(&ar71xx_mdio_device); -+} -+ +static void ar71xx_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift) +{ + void __iomem *base; @@ -1872,6 +2130,37 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + iounmap(base); +} + ++void __init ar71xx_add_device_mdio(u32 phy_mask) ++{ ++ switch (ar71xx_soc) { ++ case AR71XX_SOC_AR7240: ++ ar71xx_mdio_data.is_ar7240 = 1; ++ break; ++ case AR71XX_SOC_AR7241: ++ ar71xx_mdio_data.is_ar7240 = 1; ++ ar71xx_mdio_resources[0].start = AR71XX_GE1_BASE; ++ ar71xx_mdio_resources[0].end = AR71XX_GE1_BASE + 0x200 - 1; ++ break; ++ case AR71XX_SOC_AR7242: ++ ar71xx_set_pll(AR71XX_PLL_REG_SEC_CONFIG, ++ AR7242_PLL_REG_ETH0_INT_CLOCK, 0x62000000, ++ AR71XX_ETH0_PLL_SHIFT); ++ break; ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ ar71xx_mdio_data.is_ar7240 = 1; ++ ar71xx_mdio_resources[0].start = AR71XX_GE1_BASE; ++ ar71xx_mdio_resources[0].end = AR71XX_GE1_BASE + 0x200 - 1; ++ break; ++ default: ++ break; ++ } ++ ++ ar71xx_mdio_data.phy_mask = phy_mask; ++ ++ platform_device_register(&ar71xx_mdio_device); ++} ++ +struct ar71xx_eth_pll_data ar71xx_eth0_pll_data; +struct ar71xx_eth_pll_data ar71xx_eth1_pll_data; + @@ -1934,6 +2223,14 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + /* TODO */ +} + ++static void ar7242_set_pll_ge0(int speed) ++{ ++ u32 val = ar71xx_get_eth_pll(0, speed); ++ ++ ar71xx_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR7242_PLL_REG_ETH0_INT_CLOCK, ++ val, AR71XX_ETH0_PLL_SHIFT); ++} ++ +static void ar91xx_set_pll_ge0(int speed) +{ + u32 val = ar71xx_get_eth_pll(0, speed); @@ -1950,6 +2247,16 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + val, AR91XX_ETH1_PLL_SHIFT); +} + ++static void ar933x_set_pll_ge0(int speed) ++{ ++ /* TODO */ ++} ++ ++static void ar933x_set_pll_ge1(int speed) ++{ ++ /* TODO */ ++} ++ +static void ar71xx_ddr_flush_ge0(void) +{ + ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_GE0); @@ -1980,6 +2287,16 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE1); +} + ++static void ar933x_ddr_flush_ge0(void) ++{ ++ ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_GE0); ++} ++ ++static void ar933x_ddr_flush_ge1(void) ++{ ++ ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_GE1); ++} ++ +static struct resource ar71xx_eth0_resources[] = { + { + .name = "mac_base", @@ -2054,10 +2371,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar +#define AR724X_PLL_VAL_100 0x00001099 +#define AR724X_PLL_VAL_10 0x00991099 + ++#define AR7242_PLL_VAL_1000 0x1c000000 ++#define AR7242_PLL_VAL_100 0x00000101 ++#define AR7242_PLL_VAL_10 0x00001616 ++ +#define AR91XX_PLL_VAL_1000 0x1a000000 +#define AR91XX_PLL_VAL_100 0x13000a44 +#define AR91XX_PLL_VAL_10 0x00441099 + ++#define AR933X_PLL_VAL_1000 0x00110000 ++#define AR933X_PLL_VAL_100 0x00001099 ++#define AR933X_PLL_VAL_10 0x00991099 ++ +static void __init ar71xx_init_eth_pll_data(unsigned int id) +{ + struct ar71xx_eth_pll_data *pll_data; @@ -2085,18 +2410,31 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: -+ case AR71XX_SOC_AR7242: + pll_10 = AR724X_PLL_VAL_10; + pll_100 = AR724X_PLL_VAL_100; + pll_1000 = AR724X_PLL_VAL_1000; + break; + ++ case AR71XX_SOC_AR7242: ++ pll_10 = AR7242_PLL_VAL_10; ++ pll_100 = AR7242_PLL_VAL_100; ++ pll_1000 = AR7242_PLL_VAL_1000; ++ break; ++ + case AR71XX_SOC_AR9130: + case AR71XX_SOC_AR9132: + pll_10 = AR91XX_PLL_VAL_10; + pll_100 = AR91XX_PLL_VAL_100; + pll_1000 = AR91XX_PLL_VAL_1000; + break; ++ ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ pll_10 = AR933X_PLL_VAL_10; ++ pll_100 = AR933X_PLL_VAL_100; ++ pll_1000 = AR933X_PLL_VAL_1000; ++ break; ++ + default: + BUG(); + } @@ -2180,17 +2518,47 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + pdata->has_gbit = 1; + break; + -+ case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: ++ ar71xx_eth0_data.reset_bit |= AR724X_RESET_GE0_MDIO | ++ RESET_MODULE_GE0_PHY; ++ ar71xx_eth1_data.reset_bit |= AR724X_RESET_GE1_MDIO | ++ RESET_MODULE_GE1_PHY; ++ pdata->ddr_flush = id ? ar724x_ddr_flush_ge1 ++ : ar724x_ddr_flush_ge0; ++ pdata->set_pll = id ? ar724x_set_pll_ge1 ++ : ar7242_set_pll_ge0; ++ pdata->has_gbit = 1; ++ pdata->is_ar724x = 1; ++ ++ if (!pdata->fifo_cfg1) ++ pdata->fifo_cfg1 = 0x0010ffff; ++ if (!pdata->fifo_cfg2) ++ pdata->fifo_cfg2 = 0x015500aa; ++ if (!pdata->fifo_cfg3) ++ pdata->fifo_cfg3 = 0x01f00140; ++ break; ++ ++ case AR71XX_SOC_AR7241: + ar71xx_eth0_data.reset_bit |= AR724X_RESET_GE0_MDIO; + ar71xx_eth1_data.reset_bit |= AR724X_RESET_GE1_MDIO; + /* fall through */ + case AR71XX_SOC_AR7240: ++ ar71xx_eth0_data.reset_bit |= RESET_MODULE_GE0_PHY; ++ ar71xx_eth1_data.reset_bit |= RESET_MODULE_GE1_PHY; + pdata->ddr_flush = id ? ar724x_ddr_flush_ge1 + : ar724x_ddr_flush_ge0; + pdata->set_pll = id ? ar724x_set_pll_ge1 + : ar724x_set_pll_ge0; + pdata->is_ar724x = 1; ++ if (ar71xx_soc == AR71XX_SOC_AR7240) ++ pdata->is_ar7240 = 1; ++ ++ if (!pdata->fifo_cfg1) ++ pdata->fifo_cfg1 = 0x0010ffff; ++ if (!pdata->fifo_cfg2) ++ pdata->fifo_cfg2 = 0x015500aa; ++ if (!pdata->fifo_cfg3) ++ pdata->fifo_cfg3 = 0x01f00140; + break; + + case AR71XX_SOC_AR9130: @@ -2210,6 +2578,27 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + pdata->has_gbit = 1; + break; + ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ ar71xx_eth0_data.reset_bit = AR933X_RESET_GE0_MAC | ++ AR933X_RESET_GE0_MDIO; ++ ar71xx_eth1_data.reset_bit = AR933X_RESET_GE1_MAC | ++ AR933X_RESET_GE1_MDIO; ++ pdata->ddr_flush = id ? ar933x_ddr_flush_ge1 ++ : ar933x_ddr_flush_ge0; ++ pdata->set_pll = id ? ar933x_set_pll_ge1 ++ : ar933x_set_pll_ge0; ++ pdata->has_gbit = 1; ++ pdata->is_ar724x = 1; ++ ++ if (!pdata->fifo_cfg1) ++ pdata->fifo_cfg1 = 0x0010ffff; ++ if (!pdata->fifo_cfg2) ++ pdata->fifo_cfg2 = 0x015500aa; ++ if (!pdata->fifo_cfg3) ++ pdata->fifo_cfg3 = 0x01f00140; ++ break; ++ + default: + BUG(); + } @@ -2227,10 +2616,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + break; + } + -+ if (is_valid_ether_addr(ar71xx_mac_base)) { -+ memcpy(pdata->mac_addr, ar71xx_mac_base, ETH_ALEN); -+ pdata->mac_addr[5] += ar71xx_eth_instance; -+ } else { ++ if (!is_valid_ether_addr(pdata->mac_addr)) { + random_ether_addr(pdata->mac_addr); + printk(KERN_DEBUG + "ar71xx: using random MAC address for eth%d\n", @@ -2317,10 +2703,31 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.c linux-2.6.39/arch/mips/ar + return 1; +} +__setup("kmac=", ar71xx_kmac_setup); ++ ++void __init ar71xx_init_mac(unsigned char *dst, const unsigned char *src, ++ unsigned offset) ++{ ++ u32 t; ++ ++ if (!is_valid_ether_addr(src)) { ++ memset(dst, '\0', ETH_ALEN); ++ return; ++ } ++ ++ t = (((u32) src[3]) << 16) + (((u32) src[4]) << 8) + ((u32) src[5]); ++ t += offset; ++ ++ dst[0] = src[0]; ++ dst[1] = src[1]; ++ dst[2] = src[2]; ++ dst[3] = (t >> 16) & 0xff; ++ dst[4] = (t >> 8) & 0xff; ++ dst[5] = t & 0xff; ++} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.h linux-2.6.39/arch/mips/ar71xx/devices.h --- linux-2.6.39.orig/arch/mips/ar71xx/devices.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/devices.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,48 @@ ++++ linux-2.6.39/arch/mips/ar71xx/devices.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,50 @@ +/* + * Atheros AR71xx SoC device definitions + * @@ -2343,8 +2750,10 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.h linux-2.6.39/arch/mips/ar + struct spi_board_info const *info, + unsigned n) __init; + -+void ar71xx_set_mac_base(unsigned char *mac) __init; ++extern unsigned char ar71xx_mac_base[] __initdata; +void ar71xx_parse_mac_addr(char *mac_str) __init; ++void ar71xx_init_mac(unsigned char *dst, const unsigned char *src, ++ unsigned offset) __init; + +struct ar71xx_eth_pll_data { + u32 pll_10; @@ -2371,12 +2780,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/devices.h linux-2.6.39/arch/mips/ar +#endif /* __AR71XX_DEVICES_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/early_printk.c linux-2.6.39/arch/mips/ar71xx/early_printk.c --- linux-2.6.39.orig/arch/mips/ar71xx/early_printk.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/early_printk.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,30 @@ ++++ linux-2.6.39/arch/mips/ar71xx/early_printk.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,96 @@ +/* -+ * Atheros AR71xx SoC early printk support ++ * Atheros AR7xxx/AR9xxx SoC early printk support + * -+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2008-2011 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 @@ -2384,33 +2793,99 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/early_printk.c linux-2.6.39/arch/mi + * by the Free Software Foundation. + */ + ++#include <linux/errno.h> +#include <linux/io.h> +#include <linux/serial_reg.h> +#include <asm/addrspace.h> + +#include <asm/mach-ar71xx/ar71xx.h> ++#include <asm/mach-ar71xx/ar933x_uart.h> + -+#define UART_READ(r) \ -+ __raw_readl((void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4 * (r))) ++static void (*_prom_putchar) (unsigned char); + -+#define UART_WRITE(r, v) \ -+ __raw_writel((v), (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4*(r))) ++static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val) ++{ ++ u32 t; + -+void prom_putchar(unsigned char ch) ++ do { ++ t = __raw_readl(reg); ++ if ((t & mask) == val) ++ break; ++ } while (1); ++} ++ ++static void prom_putchar_ar71xx(unsigned char ch) ++{ ++ void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE)); ++ ++ prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE); ++ __raw_writel(ch, base + UART_TX * 4); ++ prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE); ++} ++ ++static void prom_putchar_ar933x(unsigned char ch) ++{ ++ void __iomem *base = (void __iomem *)(KSEG1ADDR(AR933X_UART_BASE)); ++ ++ prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR, ++ AR933X_UART_DATA_TX_CSR); ++ __raw_writel(AR933X_UART_DATA_TX_CSR | ch, base + AR933X_UART_DATA_REG); ++ prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR, ++ AR933X_UART_DATA_TX_CSR); ++} ++ ++static void prom_putchar_dummy(unsigned char ch) ++{ ++ /* nothing to do */ ++} ++ ++static void prom_putchar_init(void) +{ -+ while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0); -+ UART_WRITE(UART_TX, ch); -+ while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0); ++ void __iomem *base; ++ u32 id; ++ ++ base = (void __iomem *)(KSEG1ADDR(AR71XX_RESET_BASE)); ++ id = __raw_readl(base + AR71XX_RESET_REG_REV_ID); ++ id &= REV_ID_MAJOR_MASK; ++ ++ switch (id) { ++ case REV_ID_MAJOR_AR71XX: ++ case REV_ID_MAJOR_AR7240: ++ case REV_ID_MAJOR_AR7241: ++ case REV_ID_MAJOR_AR7242: ++ case REV_ID_MAJOR_AR913X: ++ case REV_ID_MAJOR_AR9341: ++ case REV_ID_MAJOR_AR9342: ++ case REV_ID_MAJOR_AR9344: ++ _prom_putchar = prom_putchar_ar71xx; ++ break; ++ ++ case REV_ID_MAJOR_AR9330: ++ case REV_ID_MAJOR_AR9331: ++ _prom_putchar = prom_putchar_ar933x; ++ break; ++ ++ default: ++ _prom_putchar = prom_putchar_dummy; ++ break; ++ } +} + ++void prom_putchar(unsigned char ch) ++{ ++ if (!_prom_putchar) ++ prom_putchar_init(); ++ ++ _prom_putchar(ch); ++} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/gpio.c linux-2.6.39/arch/mips/ar71xx/gpio.c --- linux-2.6.39.orig/arch/mips/ar71xx/gpio.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/gpio.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,182 @@ ++++ linux-2.6.39/arch/mips/ar71xx/gpio.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,193 @@ +/* -+ * Atheros AR71xx SoC GPIO API support ++ * Atheros AR7XXX/AR9XXX SoC GPIO API support + * -+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2008-2011 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 @@ -2581,6 +3056,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/gpio.c linux-2.6.39/arch/mips/ar71x + ar71xx_gpio_chip.ngpio = AR91XX_GPIO_COUNT; + break; + ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ ar71xx_gpio_chip.ngpio = AR933X_GPIO_COUNT; ++ break; ++ ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ ar71xx_gpio_chip.ngpio = AR934X_GPIO_COUNT; ++ break; ++ + default: + BUG(); + } @@ -2591,15 +3077,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/gpio.c linux-2.6.39/arch/mips/ar71x +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx/irq.c --- linux-2.6.39.orig/arch/mips/ar71xx/irq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/irq.c 2011-06-01 13:50:58.000000000 +0200 -@@ -0,0 +1,293 @@ ++++ linux-2.6.39/arch/mips/ar71xx/irq.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,377 @@ +/* + * Atheros AR71xx SoC specific interrupt handling + * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2010 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 ++ * Parts of this file are based on Atheros 2.6.15 BSP ++ * Parts of this file are based on Atheros 2.6.31 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 @@ -2616,8 +3104,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + +#include <asm/mach-ar71xx/ar71xx.h> + -+static int ip2_flush_reg; -+ +static void ar71xx_gpio_irq_dispatch(void) +{ + void __iomem *base = ar71xx_gpio_base; @@ -2634,13 +3120,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + +static void ar71xx_gpio_irq_unmask(struct irq_data *d) +{ ++ unsigned int irq = d->irq - AR71XX_GPIO_IRQ_BASE; + void __iomem *base = ar71xx_gpio_base; + u32 t; + -+ d->irq -= AR71XX_GPIO_IRQ_BASE; -+ + t = __raw_readl(base + GPIO_REG_INT_ENABLE); -+ __raw_writel(t | (1 << d->irq), base + GPIO_REG_INT_ENABLE); ++ __raw_writel(t | (1 << irq), base + GPIO_REG_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + GPIO_REG_INT_ENABLE); @@ -2648,34 +3133,22 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + +static void ar71xx_gpio_irq_mask(struct irq_data *d) +{ ++ unsigned int irq = d->irq - AR71XX_GPIO_IRQ_BASE; + void __iomem *base = ar71xx_gpio_base; + u32 t; + -+ d->irq -= AR71XX_GPIO_IRQ_BASE; -+ + t = __raw_readl(base + GPIO_REG_INT_ENABLE); -+ __raw_writel(t & ~(1 << d->irq), base + GPIO_REG_INT_ENABLE); ++ __raw_writel(t & ~(1 << irq), base + GPIO_REG_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + GPIO_REG_INT_ENABLE); +} + -+#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 -+ +static struct irq_chip ar71xx_gpio_irq_chip = { + .name = "AR71XX GPIO", -+ .irq_unmask = ar71xx_gpio_irq_unmask, -+ .irq_mask = ar71xx_gpio_irq_mask, ++ .irq_unmask = ar71xx_gpio_irq_unmask, ++ .irq_mask = ar71xx_gpio_irq_mask, + .irq_mask_ack = ar71xx_gpio_irq_mask, -+ .irq_set_type = ar71xx_gpio_irq_set_type, +}; + +static struct irqaction ar71xx_gpio_irqaction = { @@ -2683,7 +3156,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + .name = "cascade [AR71XX GPIO]", +}; + -+#define GPIO_IRQ_INIT_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH) +#define GPIO_INT_ALL 0xffff + +static void __init ar71xx_gpio_irq_init(void) @@ -2701,10 +3173,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + __raw_writel(GPIO_INT_ALL, base + GPIO_REG_INT_POLARITY); + + for (i = AR71XX_GPIO_IRQ_BASE; -+ i < AR71XX_GPIO_IRQ_BASE + AR71XX_GPIO_IRQ_COUNT; i++) { ++ i < AR71XX_GPIO_IRQ_BASE + AR71XX_GPIO_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &ar71xx_gpio_irq_chip, + handle_level_irq); -+ } + + setup_irq(AR71XX_MISC_IRQ_GPIO, &ar71xx_gpio_irqaction); +} @@ -2740,19 +3211,33 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + else if (pending & MISC_INT_WDOG) + do_IRQ(AR71XX_MISC_IRQ_WDOG); + ++ else if (pending & MISC_INT_TIMER2) ++ do_IRQ(AR71XX_MISC_IRQ_TIMER2); ++ ++ else if (pending & MISC_INT_TIMER3) ++ do_IRQ(AR71XX_MISC_IRQ_TIMER3); ++ ++ else if (pending & MISC_INT_TIMER4) ++ do_IRQ(AR71XX_MISC_IRQ_TIMER4); ++ ++ else if (pending & MISC_INT_DDR_PERF) ++ do_IRQ(AR71XX_MISC_IRQ_DDR_PERF); ++ ++ else if (pending & MISC_INT_ENET_LINK) ++ do_IRQ(AR71XX_MISC_IRQ_ENET_LINK); ++ + else + spurious_interrupt(); +} + +static void ar71xx_misc_irq_unmask(struct irq_data *d) +{ ++ unsigned int irq = d->irq - AR71XX_MISC_IRQ_BASE; + void __iomem *base = ar71xx_reset_base; + u32 t; + -+ d->irq -= AR71XX_MISC_IRQ_BASE; -+ + t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); -+ __raw_writel(t | (1 << d->irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); ++ __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); @@ -2760,25 +3245,23 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + +static void ar71xx_misc_irq_mask(struct irq_data *d) +{ ++ unsigned int irq = d->irq - AR71XX_MISC_IRQ_BASE; + void __iomem *base = ar71xx_reset_base; + u32 t; + -+ d->irq -= AR71XX_MISC_IRQ_BASE; -+ + t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); -+ __raw_writel(t & ~(1 << d->irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); ++ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); +} + -+static void ar724x_misc_irq_ack(unsigned int irq) ++static void ar724x_misc_irq_ack(struct irq_data *d) +{ ++ unsigned int irq = d->irq - AR71XX_MISC_IRQ_BASE; + void __iomem *base = ar71xx_reset_base; + u32 t; + -+ irq -= AR71XX_MISC_IRQ_BASE; -+ + t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); + __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); + @@ -2788,8 +3271,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + +static struct irq_chip ar71xx_misc_irq_chip = { + .name = "AR71XX MISC", -+ .irq_unmask = ar71xx_misc_irq_unmask, -+ .irq_mask = ar71xx_misc_irq_mask, ++ .irq_unmask = ar71xx_misc_irq_unmask, ++ .irq_mask = ar71xx_misc_irq_mask, +}; + +static struct irqaction ar71xx_misc_irqaction = { @@ -2809,6 +3292,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: + ar71xx_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; + break; + default: @@ -2817,14 +3305,82 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + } + + for (i = AR71XX_MISC_IRQ_BASE; -+ i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) { ++ i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &ar71xx_misc_irq_chip, + handle_level_irq); -+ } + + setup_irq(AR71XX_CPU_IRQ_MISC, &ar71xx_misc_irqaction); +} + ++/* ++ * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for ++ * these devices typically allocate coherent DMA memory, however the ++ * DMA controller may still have some unsynchronized data in the FIFO. ++ * Issue a flush in the handlers to ensure that the driver sees ++ * the update. ++ */ ++static void ar71xx_ip2_handler(void) ++{ ++ ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_PCI); ++ do_IRQ(AR71XX_CPU_IRQ_IP2); ++} ++ ++static void ar724x_ip2_handler(void) ++{ ++ ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_PCIE); ++ do_IRQ(AR71XX_CPU_IRQ_IP2); ++} ++ ++static void ar913x_ip2_handler(void) ++{ ++ ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_WMAC); ++ do_IRQ(AR71XX_CPU_IRQ_IP2); ++} ++ ++static void ar933x_ip2_handler(void) ++{ ++ ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_WMAC); ++ do_IRQ(AR71XX_CPU_IRQ_IP2); ++} ++ ++static void ar934x_ip2_handler(void) ++{ ++ ar71xx_ddr_flush(AR934X_DDR_REG_FLUSH_PCIE); ++ do_IRQ(AR71XX_CPU_IRQ_IP2); ++} ++ ++static void ar71xx_ip3_handler(void) ++{ ++ ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_USB); ++ do_IRQ(AR71XX_CPU_IRQ_USB); ++} ++ ++static void ar724x_ip3_handler(void) ++{ ++ ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_USB); ++ do_IRQ(AR71XX_CPU_IRQ_USB); ++} ++ ++static void ar913x_ip3_handler(void) ++{ ++ ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_USB); ++ do_IRQ(AR71XX_CPU_IRQ_USB); ++} ++ ++static void ar933x_ip3_handler(void) ++{ ++ ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_USB); ++ do_IRQ(AR71XX_CPU_IRQ_USB); ++} ++ ++static void ar934x_ip3_handler(void) ++{ ++ do_IRQ(AR71XX_CPU_IRQ_USB); ++} ++ ++static void (*ip2_handler)(void); ++static void (*ip3_handler)(void); ++ +asmlinkage void plat_irq_dispatch(void) +{ + unsigned long pending; @@ -2834,17 +3390,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + if (pending & STATUSF_IP7) + do_IRQ(AR71XX_CPU_IRQ_TIMER); + -+ else if (pending & STATUSF_IP2) { -+ /* -+ * This IRQ is meant for a PCI device. Drivers for PCI devices -+ * typically allocate coherent DMA memory for the descriptor -+ * ring, however the DMA controller may still have some -+ * unsynchronized data in the FIFO. -+ * Issue a flush here to ensure that the driver sees the update. -+ */ -+ ar71xx_ddr_flush(ip2_flush_reg); -+ do_IRQ(AR71XX_CPU_IRQ_IP2); -+ } ++ else if (pending & STATUSF_IP2) ++ ip2_handler(); + + else if (pending & STATUSF_IP4) + do_IRQ(AR71XX_CPU_IRQ_GE0); @@ -2853,31 +3400,54 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + do_IRQ(AR71XX_CPU_IRQ_GE1); + + else if (pending & STATUSF_IP3) -+ do_IRQ(AR71XX_CPU_IRQ_USB); ++ ip3_handler(); + + else if (pending & STATUSF_IP6) + ar71xx_misc_irq_dispatch(); + -+ else -+ spurious_interrupt(); ++ spurious_interrupt(); +} + +void __init arch_init_irq(void) +{ -+ switch(ar71xx_soc) { ++ switch (ar71xx_soc) { ++ case AR71XX_SOC_AR7130: ++ case AR71XX_SOC_AR7141: ++ case AR71XX_SOC_AR7161: ++ ip2_handler = ar71xx_ip2_handler; ++ ip3_handler = ar71xx_ip3_handler; ++ break; ++ + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: -+ ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE; ++ ip2_handler = ar724x_ip2_handler; ++ ip3_handler = ar724x_ip3_handler; + break; ++ + case AR71XX_SOC_AR9130: + case AR71XX_SOC_AR9132: -+ ip2_flush_reg = AR91XX_DDR_REG_FLUSH_WMAC; ++ ip2_handler = ar913x_ip2_handler; ++ ip3_handler = ar913x_ip3_handler; + break; -+ default: -+ ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI; ++ ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ ip2_handler = ar933x_ip2_handler; ++ ip3_handler = ar933x_ip3_handler; ++ break; ++ ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ ip2_handler = ar934x_ip2_handler; ++ ip3_handler = ar934x_ip3_handler; + break; ++ ++ default: ++ BUG(); + } ++ + mips_cpu_irq_init(); + + ar71xx_misc_irq_init(); @@ -2886,10 +3456,259 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/irq.c linux-2.6.39/arch/mips/ar71xx + + ar71xx_gpio_irq_init(); +} +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap121.c linux-2.6.39/arch/mips/ar71xx/mach-ap121.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-ap121.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-ap121.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,245 @@ ++/* ++ * Atheros AP121 board support ++ * ++ * Copyright (C) 2011 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 <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/spi/flash.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-ar9xxx-wmac.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++#include "dev-m25p80.h" ++#include "dev-usb.h" ++ ++#define AP121_GPIO_LED_WLAN 0 ++#define AP121_GPIO_LED_USB 1 ++ ++#define AP121_GPIO_BTN_JUMPSTART 11 ++#define AP121_GPIO_BTN_RESET 12 ++ ++#define AP121_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define AP121_KEYS_DEBOUNCE_INTERVAL (3 * AP121_KEYS_POLL_INTERVAL) ++ ++#define AP121_MAC0_OFFSET 0x0000 ++#define AP121_MAC1_OFFSET 0x0006 ++#define AP121_CALDATA_OFFSET 0x1000 ++#define AP121_WMAC_MAC_OFFSET 0x1002 ++ ++#define AP121_MINI_GPIO_LED_WLAN 0 ++#define AP121_MINI_GPIO_BTN_JUMPSTART 12 ++#define AP121_MINI_GPIO_BTN_RESET 11 ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition ap121_parts[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, ++ { ++ .name = "rootfs", ++ .offset = 0x010000, ++ .size = 0x130000, ++ }, ++ { ++ .name = "uImage", ++ .offset = 0x140000, ++ .size = 0x0a0000, ++ }, ++ { ++ .name = "NVRAM", ++ .offset = 0x1e0000, ++ .size = 0x010000, ++ }, ++ { ++ .name = "ART", ++ .offset = 0x1f0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, ++}; ++#define ap121_nr_parts ARRAY_SIZE(ap121_parts) ++ ++static struct mtd_partition ap121_mini_parts[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = 0x040000, ++ .mask_flags = MTD_WRITEABLE, ++ }, ++ { ++ .name = "u-boot-env", ++ .offset = 0x040000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, ++ { ++ .name = "rootfs", ++ .offset = 0x050000, ++ .size = 0x2b0000, ++ }, ++ { ++ .name = "uImage", ++ .offset = 0x300000, ++ .size = 0x0e0000, ++ }, ++ { ++ .name = "NVRAM", ++ .offset = 0x3e0000, ++ .size = 0x010000, ++ }, ++ { ++ .name = "ART", ++ .offset = 0x3f0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, ++}; ++ ++#define ap121_mini_nr_parts ARRAY_SIZE(ap121_parts) ++ ++#else ++#define ap121_parts NULL ++#define ap121_nr_parts 0 ++#define ap121_mini_parts NULL ++#define ap121_mini_nr_parts 0 ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct flash_platform_data ap121_flash_data = { ++ .parts = ap121_parts, ++ .nr_parts = ap121_nr_parts, ++}; ++ ++static struct gpio_led ap121_leds_gpio[] __initdata = { ++ { ++ .name = "ap121:green:usb", ++ .gpio = AP121_GPIO_LED_USB, ++ .active_low = 0, ++ }, ++ { ++ .name = "ap121:green:wlan", ++ .gpio = AP121_GPIO_LED_WLAN, ++ .active_low = 0, ++ }, ++}; ++ ++static struct gpio_keys_button ap121_gpio_keys[] __initdata = { ++ { ++ .desc = "jumpstart button", ++ .type = EV_KEY, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = AP121_GPIO_BTN_JUMPSTART, ++ .active_low = 1, ++ }, ++ { ++ .desc = "reset button", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = AP121_GPIO_BTN_RESET, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_led ap121_mini_leds_gpio[] __initdata = { ++ { ++ .name = "ap121:green:wlan", ++ .gpio = AP121_MINI_GPIO_LED_WLAN, ++ .active_low = 0, ++ }, ++}; ++ ++static struct gpio_keys_button ap121_mini_gpio_keys[] __initdata = { ++ { ++ .desc = "jumpstart button", ++ .type = EV_KEY, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = AP121_MINI_GPIO_BTN_JUMPSTART, ++ .active_low = 1, ++ }, ++ { ++ .desc = "reset button", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = AP121_MINI_GPIO_BTN_RESET, ++ .active_low = 1, ++ } ++}; ++ ++static void __init ap121_common_setup(void) ++{ ++ u8 *art = (u8 *) KSEG1ADDR(0x1fff0000); ++ ++ ar71xx_add_device_m25p80(&ap121_flash_data); ++ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, art + AP121_MAC0_OFFSET, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, art + AP121_MAC1_OFFSET, 0); ++ ++ /* WAN port */ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth0_data.speed = SPEED_100; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = BIT(4); ++ ++ /* LAN ports */ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.speed = SPEED_1000; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ar71xx_eth1_data.has_ar7240_switch = 1; ++ ++ ar71xx_add_device_mdio(0x0); ++ ar71xx_add_device_eth(1); ++ ar71xx_add_device_eth(0); ++ ++ ar9xxx_add_device_wmac(art + AP121_CALDATA_OFFSET, ++ art + AP121_WMAC_MAC_OFFSET); ++} ++ ++static void __init ap121_setup(void) ++{ ++ ap121_flash_data.parts = ap121_parts; ++ ap121_flash_data.nr_parts = ap121_nr_parts; ++ ++ ap121_common_setup(); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap121_leds_gpio), ++ ap121_leds_gpio); ++ ar71xx_register_gpio_keys_polled(-1, AP121_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(ap121_gpio_keys), ++ ap121_gpio_keys); ++ ++ ar71xx_add_device_usb(); ++} ++ ++static void __init ap121_mini_setup(void) ++{ ++ ap121_flash_data.parts = ap121_mini_parts; ++ ap121_flash_data.nr_parts = ap121_mini_nr_parts; ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap121_mini_leds_gpio), ++ ap121_mini_leds_gpio); ++ ar71xx_register_gpio_keys_polled(-1, AP121_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(ap121_mini_gpio_keys), ++ ap121_mini_gpio_keys); ++ ++ ap121_common_setup(); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_AP121, "AP121", "Atheros AP121", ++ ap121_setup); ++ ++MIPS_MACHINE(AR71XX_MACH_AP121_MINI, "AP121-MINI", "Atheros AP121-MINI", ++ ap121_mini_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.39/arch/mips/ar71xx/mach-ap81.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-ap81.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,140 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-ap81.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,142 @@ +/* + * Atheros AP81 board support + * @@ -2909,7 +3728,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.39/arch/mips/ +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-usb.h" @@ -2922,7 +3741,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.39/arch/mips/ +#define AP81_GPIO_BTN_SW4 12 +#define AP81_GPIO_BTN_SW1 21 + -+#define AP81_BUTTONS_POLL_INTERVAL 20 ++#define AP81_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define AP81_KEYS_DEBOUNCE_INTERVAL (3 * AP81_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition ap81_partitions[] = { @@ -2931,19 +3751,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.39/arch/mips/ + .offset = 0, + .size = 0x040000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "u-boot-env", + .offset = 0x040000, + .size = 0x010000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x050000, + .size = 0x500000, -+ } , { ++ }, { + .name = "uImage", + .offset = 0x550000, + .size = 0x100000, -+ } , { ++ }, { + .name = "ART", + .offset = 0x650000, + .size = 0x1b0000, @@ -2954,8 +3774,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.39/arch/mips/ + +static struct flash_platform_data ap81_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = ap81_partitions, -+ .nr_parts = ARRAY_SIZE(ap81_partitions), ++ .parts = ap81_partitions, ++ .nr_parts = ARRAY_SIZE(ap81_partitions), +#endif +}; + @@ -2979,19 +3799,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.39/arch/mips/ + } +}; + -+static struct gpio_button ap81_gpio_buttons[] __initdata = { ++static struct gpio_keys_button ap81_gpio_keys[] __initdata = { + { + .desc = "sw1", + .type = EV_KEY, + .code = BTN_0, -+ .threshold = 3, ++ .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL, + .gpio = AP81_GPIO_BTN_SW1, + .active_low = 1, -+ } , { ++ }, { + .desc = "sw4", + .type = EV_KEY, + .code = BTN_1, -+ .threshold = 3, ++ .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL, + .gpio = AP81_GPIO_BTN_SW4, + .active_low = 1, + } @@ -3001,14 +3821,15 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.39/arch/mips/ +{ + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(eeprom); + ar71xx_add_device_mdio(0x0); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, eeprom, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ar71xx_eth0_data.has_ar8216 = 1; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, eeprom, 1); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.phy_mask = 0x10; + @@ -3022,18 +3843,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.39/arch/mips/ + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap81_leds_gpio), + ap81_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, AP81_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(ap81_gpio_buttons), -+ ap81_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, AP81_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(ap81_gpio_keys), ++ ap81_gpio_keys); + -+ ar913x_add_device_wmac(eeprom, NULL); ++ ar9xxx_add_device_wmac(eeprom, NULL); +} + +MIPS_MACHINE(AR71XX_MACH_AP81, "AP81", "Atheros AP81", ap81_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ar71xx/mach-ap83.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-ap83.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,266 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-ap83.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,267 @@ +/* + * Atheros AP83 board support + * @@ -3058,7 +3879,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ + +#include "machtype.h" +#include "devices.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-usb.h" @@ -3074,7 +3895,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ +#define AP83_050_GPIO_VSC7385_MOSI 16 +#define AP83_050_GPIO_VSC7385_SCK 17 + -+#define AP83_BUTTONS_POLL_INTERVAL 20 ++#define AP83_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define AP83_KEYS_DEBOUNCE_INTERVAL (3 * AP83_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition ap83_flash_partitions[] = { @@ -3083,25 +3905,25 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ + .offset = 0, + .size = 0x040000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "u-boot-env", + .offset = 0x040000, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x060000, + .size = 0x140000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x1a0000, + .size = 0x650000, -+ } , { ++ }, { + .name = "art", + .offset = 0x7f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x060000, + .size = 0x790000, @@ -3112,8 +3934,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ +static struct ar91xx_flash_platform_data ap83_flash_data = { + .width = 2, +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = ap83_flash_partitions, -+ .nr_parts = ARRAY_SIZE(ap83_flash_partitions), ++ .parts = ap83_flash_partitions, ++ .nr_parts = ARRAY_SIZE(ap83_flash_partitions), +#endif +}; + @@ -3151,19 +3973,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ + }, +}; + -+static struct gpio_button ap83_gpio_buttons[] __initdata = { ++static struct gpio_keys_button ap83_gpio_keys[] __initdata = { + { + .desc = "soft_reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = AP83_KEYS_DEBOUNCE_INTERVAL, + .gpio = AP83_GPIO_BTN_RESET, + .active_low = 1, -+ } , { ++ }, { + .desc = "jumpstart", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = AP83_KEYS_DEBOUNCE_INTERVAL, + .gpio = AP83_GPIO_BTN_JUMPSTART, + .active_low = 1, + } @@ -3232,15 +4054,15 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ +{ + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(eeprom); -+ + ar71xx_add_device_mdio(0xfffffffe); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, eeprom, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.phy_mask = 0x1; + + ar71xx_add_device_eth(0); + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, eeprom, 1); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth1_data.speed = SPEED_1000; + ar71xx_eth1_data.duplex = DUPLEX_FULL; @@ -3252,13 +4074,13 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap83_leds_gpio), + ap83_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, AP83_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(ap83_gpio_buttons), -+ ap83_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, AP83_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(ap83_gpio_keys), ++ ap83_gpio_keys); + + ar71xx_add_device_usb(); + -+ ar913x_add_device_wmac(eeprom, NULL); ++ ar9xxx_add_device_wmac(eeprom, NULL); + + platform_device_register(&ap83_flash_device); + @@ -3267,7 +4089,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ + +static void __init ap83_040_setup(void) +{ -+ ap83_flash_data.is_shared=1; ++ ap83_flash_data.is_shared = 1; + ap83_generic_setup(); + platform_device_register(&ap83_040_spi_device); +} @@ -3300,10 +4122,194 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.39/arch/mips/ +} + +MIPS_MACHINE(AR71XX_MACH_AP83, "AP83", "Atheros AP83", ap83_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ap96.c linux-2.6.39/arch/mips/ar71xx/mach-ap96.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-ap96.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-ap96.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,180 @@ ++/* ++ * Atheros AP96 board support ++ * ++ * Copyright (C) 2009 Marco Porsch ++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2010 Atheros Communications ++ * ++ * 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/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/delay.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-m25p80.h" ++#include "dev-ap94-pci.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++#include "dev-usb.h" ++ ++#define AP96_GPIO_LED_12_GREEN 0 ++#define AP96_GPIO_LED_3_GREEN 1 ++#define AP96_GPIO_LED_2_GREEN 2 ++#define AP96_GPIO_LED_WPS_GREEN 4 ++#define AP96_GPIO_LED_5_GREEN 5 ++#define AP96_GPIO_LED_4_ORANGE 6 ++ ++/* Reset button - next to the power connector */ ++#define AP96_GPIO_BTN_RESET 3 ++/* WPS button - next to a led on right */ ++#define AP96_GPIO_BTN_WPS 8 ++ ++#define AP96_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define AP96_KEYS_DEBOUNCE_INTERVAL (3 * AP96_KEYS_POLL_INTERVAL) ++ ++#define AP96_WMAC0_MAC_OFFSET 0x120c ++#define AP96_WMAC1_MAC_OFFSET 0x520c ++#define AP96_CALDATA0_OFFSET 0x1000 ++#define AP96_CALDATA1_OFFSET 0x5000 ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition ap96_partitions[] = { ++ { ++ .name = "uboot", ++ .offset = 0, ++ .size = 0x030000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "env", ++ .offset = 0x030000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "rootfs", ++ .offset = 0x040000, ++ .size = 0x600000, ++ }, { ++ .name = "uImage", ++ .offset = 0x640000, ++ .size = 0x1b0000, ++ }, { ++ .name = "caldata", ++ .offset = 0x7f0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ } ++}; ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct flash_platform_data ap96_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .parts = ap96_partitions, ++ .nr_parts = ARRAY_SIZE(ap96_partitions), ++#endif ++}; ++ ++/* ++ * AP96 has 12 unlabeled leds in the front; these are numbered from 1 to 12 ++ * below (from left to right on the board). Led 1 seems to be on whenever the ++ * board is powered. Led 11 shows LAN link activity actity. Led 3 is orange; ++ * others are green. ++ * ++ * In addition, there is one led next to a button on the right side for WPS. ++ */ ++static struct gpio_led ap96_leds_gpio[] __initdata = { ++ { ++ .name = "ap96:green:led2", ++ .gpio = AP96_GPIO_LED_2_GREEN, ++ .active_low = 1, ++ }, { ++ .name = "ap96:green:led3", ++ .gpio = AP96_GPIO_LED_3_GREEN, ++ .active_low = 1, ++ }, { ++ .name = "ap96:orange:led4", ++ .gpio = AP96_GPIO_LED_4_ORANGE, ++ .active_low = 1, ++ }, { ++ .name = "ap96:green:led5", ++ .gpio = AP96_GPIO_LED_5_GREEN, ++ .active_low = 1, ++ }, { ++ .name = "ap96:green:led12", ++ .gpio = AP96_GPIO_LED_12_GREEN, ++ .active_low = 1, ++ }, { /* next to a button on right */ ++ .name = "ap96:green:wps", ++ .gpio = AP96_GPIO_LED_WPS_GREEN, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_keys_button ap96_gpio_keys[] __initdata = { ++ { ++ .desc = "reset", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = AP96_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = AP96_GPIO_BTN_RESET, ++ .active_low = 1, ++ }, { ++ .desc = "wps", ++ .type = EV_KEY, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = AP96_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = AP96_GPIO_BTN_WPS, ++ .active_low = 1, ++ } ++}; ++ ++#define AP96_WAN_PHYMASK 0x10 ++#define AP96_LAN_PHYMASK 0x0f ++ ++static void __init ap96_setup(void) ++{ ++ u8 *art = (u8 *) KSEG1ADDR(0x1fff0000); ++ ++ ar71xx_add_device_mdio(~(AP96_WAN_PHYMASK | AP96_LAN_PHYMASK)); ++ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, art, 0); ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; ++ ar71xx_eth0_data.phy_mask = AP96_LAN_PHYMASK; ++ ar71xx_eth0_data.speed = SPEED_1000; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ++ ar71xx_add_device_eth(0); ++ ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, art, 1); ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; ++ ar71xx_eth1_data.phy_mask = AP96_WAN_PHYMASK; ++ ++ ar71xx_eth1_pll_data.pll_1000 = 0x1f000000; ++ ++ ar71xx_add_device_eth(1); ++ ++ ar71xx_add_device_usb(); ++ ++ ar71xx_add_device_m25p80(&ap96_flash_data); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap96_leds_gpio), ++ ap96_leds_gpio); ++ ++ ar71xx_register_gpio_keys_polled(-1, AP96_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(ap96_gpio_keys), ++ ap96_gpio_keys); ++ ++ ap94_pci_init(art + AP96_CALDATA0_OFFSET, ++ art + AP96_WMAC0_MAC_OFFSET, ++ art + AP96_CALDATA1_OFFSET, ++ art + AP96_WMAC1_MAC_OFFSET); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_AP96, "AP96", "Atheros AP96", ap96_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-aw-nr580.c linux-2.6.39/arch/mips/ar71xx/mach-aw-nr580.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-aw-nr580.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-aw-nr580.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,101 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-aw-nr580.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,102 @@ +/* + * AzureWave AW-NR580 board support + * @@ -3337,7 +4343,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-aw-nr580.c linux-2.6.39/arch/m +#define AW_NR580_GPIO_BTN_WPS 3 +#define AW_NR580_GPIO_BTN_RESET 11 + -+#define AW_NR580_BUTTONS_POLL_INTERVAL 20 ++#define AW_NR580_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define AW_NR580_KEYS_DEBOUNCE_INTERVAL (3 * AW_NR580_KEYS_POLL_INTERVAL) + +static struct gpio_led aw_nr580_leds_gpio[] __initdata = { + { @@ -3363,19 +4370,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-aw-nr580.c linux-2.6.39/arch/m + } +}; + -+static struct gpio_button aw_nr580_gpio_buttons[] __initdata = { ++static struct gpio_keys_button aw_nr580_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = AW_NR580_KEYS_DEBOUNCE_INTERVAL, + .gpio = AW_NR580_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = AW_NR580_KEYS_DEBOUNCE_INTERVAL, + .gpio = AW_NR580_GPIO_BTN_WPS, + .active_low = 1, + } @@ -3398,17 +4405,155 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-aw-nr580.c linux-2.6.39/arch/m + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(aw_nr580_leds_gpio), + aw_nr580_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, AW_NR580_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(aw_nr580_gpio_buttons), -+ aw_nr580_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, AW_NR580_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(aw_nr580_gpio_keys), ++ aw_nr580_gpio_keys); +} + +MIPS_MACHINE(AR71XX_MACH_AW_NR580, "AW-NR580", "AzureWave AW-NR580", + aw_nr580_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-db120.c linux-2.6.39/arch/mips/ar71xx/mach-db120.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-db120.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-db120.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,134 @@ ++/* ++ * Atheros DB120 board (WASP SoC) support ++ * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> ++ * ++ * 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/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-m25p80.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++#include "dev-usb.h" ++#include "dev-ar9xxx-wmac.h" ++#include "dev-db120-pci.h" ++ ++#define DB120_GPIO_LED_USB 11 ++#define DB120_GPIO_LED_WLAN_5G 12 ++#define DB120_GPIO_LED_WLAN_2G 13 ++#define DB120_GPIO_LED_STATUS 14 ++#define DB120_GPIO_LED_WPS 15 ++ ++#define DB120_GPIO_BTN_SW1 16 ++ ++#define DB120_CALDATA_OFFSET 0x1000 ++#define DB120_WMAC_MAC_OFFSET 0x1002 ++ ++#define DB120_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define DB120_KEYS_DEBOUNCE_INTERVAL (3 * DB120_KEYS_POLL_INTERVAL) ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition db120_partitions[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = 0x040000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "u-boot-env", ++ .offset = 0x040000, ++ .size = 0x010000, ++ }, { ++ .name = "rootfs", ++ .offset = 0x050000, ++ .size = 0x630000, ++ }, { ++ .name = "uImage", ++ .offset = 0x680000, ++ .size = 0x160000, ++ }, { ++ .name = "NVRAM", ++ .offset = 0x7E0000, ++ .size = 0x010000, ++ }, { ++ .name = "ART", ++ .offset = 0x7F0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ } ++}; ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct flash_platform_data db120_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .parts = db120_partitions, ++ .nr_parts = ARRAY_SIZE(db120_partitions), ++#endif ++}; ++ ++static struct gpio_led db120_leds_gpio[] __initdata = { ++ { ++ .name = "db120:green:status", ++ .gpio = DB120_GPIO_LED_STATUS, ++ .active_low = 1, ++ }, { ++ .name = "db120:green:wps", ++ .gpio = DB120_GPIO_LED_WPS, ++ .active_low = 1, ++ }, { ++ .name = "db120:green:wlan-5g", ++ .gpio = DB120_GPIO_LED_WLAN_5G, ++ .active_low = 1, ++ }, { ++ .name = "db120:green:wlan-2g", ++ .gpio = DB120_GPIO_LED_WLAN_2G, ++ .active_low = 1, ++ }, { ++ .name = "db120:green:usb", ++ .gpio = DB120_GPIO_LED_USB, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_keys_button db120_gpio_keys[] __initdata = { ++ { ++ .desc = "sw1", ++ .type = EV_KEY, ++ .code = BTN_0, ++ .debounce_interval = DB120_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = DB120_GPIO_BTN_SW1, ++ .active_low = 1, ++ } ++}; ++ ++static void __init db120_setup(void) ++{ ++ u8 *art = (u8 *) KSEG1ADDR(0x1fff0000); ++ ++ ar71xx_add_device_usb(); ++ ++ ar71xx_add_device_m25p80(&db120_flash_data); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(db120_leds_gpio), ++ db120_leds_gpio); ++ ++ ar71xx_register_gpio_keys_polled(-1, DB120_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(db120_gpio_keys), ++ db120_gpio_keys); ++ ++ ar9xxx_add_device_wmac(art + DB120_CALDATA_OFFSET, ++ art + DB120_WMAC_MAC_OFFSET); ++ ++ db120_pci_init(); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_DB120, "DB120", "Atheros DB120", db120_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.39/arch/mips/ar71xx/mach-dir-600-a1.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-600-a1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-dir-600-a1.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,138 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-dir-600-a1.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,159 @@ +/* + * D-Link DIR-600 rev. A1 board support + * @@ -3427,7 +4572,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.39/arch +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ap91-eth.h" +#include "dev-ap91-pci.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" @@ -3440,7 +4584,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.39/arch +#define DIR_600_A1_GPIO_BTN_RESET 8 +#define DIR_600_A1_GPIO_BTN_WPS 12 + -+#define DIR_600_A1_BUTTONS_POLL_INTERVAL 20 ++#define DIR_600_A1_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define DIR_600_A1_KEYS_DEBOUNCE_INTERVAL (3 * DIR_600_A1_KEYS_POLL_INTERVAL) + +#define DIR_600_A1_NVRAM_ADDR 0x1f030000 +#define DIR_600_A1_NVRAM_SIZE 0x10000 @@ -3484,8 +4629,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.39/arch + +static struct flash_platform_data dir_600_a1_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = dir_600_a1_partitions, -+ .nr_parts = ARRAY_SIZE(dir_600_a1_partitions), ++ .parts = dir_600_a1_partitions, ++ .nr_parts = ARRAY_SIZE(dir_600_a1_partitions), +#endif +}; + @@ -3503,19 +4648,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.39/arch + } +}; + -+static struct gpio_button dir_600_a1_gpio_buttons[] __initdata = { ++static struct gpio_keys_button dir_600_a1_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = DIR_600_A1_KEYS_DEBOUNCE_INTERVAL, + .gpio = DIR_600_A1_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = DIR_600_A1_KEYS_DEBOUNCE_INTERVAL, + .gpio = DIR_600_A1_GPIO_BTN_WPS, + .active_low = 1, + } @@ -3529,19 +4674,40 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.39/arch + u8 *mac = NULL; + + if (nvram_parse_mac_addr(nvram, DIR_600_A1_NVRAM_SIZE, -+ "lan_mac=", mac_buff) == 0) ++ "lan_mac=", mac_buff) == 0) { ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac_buff, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac_buff, 1); + mac = mac_buff; ++ } + + ar71xx_add_device_m25p80(&dir_600_a1_flash_data); + + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir_600_a1_leds_gpio), + dir_600_a1_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, DIR_600_A1_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(dir_600_a1_gpio_buttons), -+ dir_600_a1_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, DIR_600_A1_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(dir_600_a1_gpio_keys), ++ dir_600_a1_gpio_keys); ++ ++ ar71xx_eth1_data.has_ar7240_switch = 1; ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); ++ ++ /* WAN port */ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth0_data.speed = SPEED_100; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = BIT(4); ++ ++ /* LAN ports */ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.speed = SPEED_1000; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ++ ar71xx_add_device_mdio(0x0); ++ ar71xx_add_device_eth(1); ++ ar71xx_add_device_eth(0); + -+ ap91_eth_init(mac, NULL); + ap91_pci_init(ee, mac); +} + @@ -3549,8 +4715,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.39/arch + dir_600_a1_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch/mips/ar71xx/mach-dir-615-c1.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-dir-615-c1.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,173 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-dir-615-c1.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,175 @@ +/* + * D-Link DIR-615 rev C1 board support + * @@ -3570,7 +4736,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "nvram.h" @@ -3588,7 +4754,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch +#define DIR_615C1_GPIO_BTN_WPS 12 +#define DIR_615C1_GPIO_BTN_RESET 21 + -+#define DIR_615C1_BUTTONS_POLL_INTERVAL 20 ++#define DIR_615C1_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define DIR_615C1_KEYS_DEBOUNCE_INTERVAL (3 * DIR_615C1_KEYS_POLL_INTERVAL) + +#define DIR_615C1_CONFIG_ADDR 0x1f020000 +#define DIR_615C1_CONFIG_SIZE 0x10000 @@ -3600,24 +4767,24 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch + .offset = 0, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "config", + .offset = 0x020000, + .size = 0x010000, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x030000, -+ .size = 0x0d0000, -+ } , { ++ .size = 0x0e0000, ++ }, { + .name = "rootfs", -+ .offset = 0x100000, -+ .size = 0x2f0000, -+ } , { ++ .offset = 0x110000, ++ .size = 0x2e0000, ++ }, { + .name = "art", + .offset = 0x3f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x030000, + .size = 0x3c0000, @@ -3627,8 +4794,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch + +static struct flash_platform_data dir_615c1_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = dir_615c1_partitions, -+ .nr_parts = ARRAY_SIZE(dir_615c1_partitions), ++ .parts = dir_615c1_partitions, ++ .nr_parts = ARRAY_SIZE(dir_615c1_partitions), +#endif +}; + @@ -3649,13 +4816,13 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch + .name = "dir-615c1:green:wancpu", + .gpio = DIR_615C1_GPIO_LED_GREEN_WANCPU, + .active_low = 1, -+ }, { ++ }, { + .name = "dir-615c1:green:wlan", + .gpio = DIR_615C1_GPIO_LED_GREEN_WLAN, + .active_low = 1, -+ }, { -+ .name = "dir-615c1:green:status", -+ .gpio = DIR_615C1_GPIO_LED_GREEN_STATUS, ++ }, { ++ .name = "dir-615c1:green:status", ++ .gpio = DIR_615C1_GPIO_LED_GREEN_STATUS, + .active_low = 1, + }, { + .name = "dir-615c1:orange:wan", @@ -3665,18 +4832,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch + +}; + -+static struct gpio_button dir_615c1_gpio_buttons[] __initdata = { ++static struct gpio_keys_button dir_615c1_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = DIR_615C1_KEYS_DEBOUNCE_INTERVAL, + .gpio = DIR_615C1_GPIO_BTN_RESET, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = DIR_615C1_KEYS_DEBOUNCE_INTERVAL, + .gpio = DIR_615C1_GPIO_BTN_WPS, + } +}; @@ -3694,8 +4861,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch + u8 *wlan_mac = NULL; + + if (nvram_parse_mac_addr(config, DIR_615C1_CONFIG_SIZE, -+ "lan_mac=", mac) == 0) { -+ ar71xx_set_mac_base(mac); ++ "lan_mac=", mac) == 0) { ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); + wlan_mac = mac; + } + @@ -3715,19 +4883,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.39/arch + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir_615c1_leds_gpio), + dir_615c1_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, DIR_615C1_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(dir_615c1_gpio_buttons), -+ dir_615c1_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, DIR_615C1_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(dir_615c1_gpio_keys), ++ dir_615c1_gpio_keys); + -+ ar913x_add_device_wmac(eeprom, wlan_mac); ++ ar9xxx_add_device_wmac(eeprom, wlan_mac); +} + +MIPS_MACHINE(AR71XX_MACH_DIR_615_C1, "DIR-615-C1", "D-Link DIR-615 rev. C1", + dir_615c1_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch/mips/ar71xx/mach-dir-825-b1.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-dir-825-b1.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,192 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-dir-825-b1.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,198 @@ +/* + * D-Link DIR-825 rev. B1 board support + * @@ -3744,7 +4912,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/delay.h> -+#include <linux/rtl8366s.h> ++#include <linux/rtl8366.h> + +#include <asm/mach-ar71xx/ar71xx.h> + @@ -3759,17 +4927,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch +#define DIR825B1_GPIO_LED_BLUE_USB 0 +#define DIR825B1_GPIO_LED_ORANGE_POWER 1 +#define DIR825B1_GPIO_LED_BLUE_POWER 2 -+#define DIR825B1_GPIO_LED_BLUE_POWERSAVE 4 ++#define DIR825B1_GPIO_LED_BLUE_WPS 4 +#define DIR825B1_GPIO_LED_ORANGE_PLANET 6 +#define DIR825B1_GPIO_LED_BLUE_PLANET 11 + +#define DIR825B1_GPIO_BTN_RESET 3 -+#define DIR825B1_GPIO_BTN_POWERSAVE 8 ++#define DIR825B1_GPIO_BTN_WPS 8 + +#define DIR825B1_GPIO_RTL8366_SDA 5 +#define DIR825B1_GPIO_RTL8366_SCK 7 + -+#define DIR825B1_BUTTONS_POLL_INTERVAL 20 ++#define DIR825B1_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define DIR825B1_KEYS_DEBOUNCE_INTERVAL (3 * DIR825B1_KEYS_POLL_INTERVAL) + +#define DIR825B1_CAL_LOCATION_0 0x1f661000 +#define DIR825B1_CAL_LOCATION_1 0x1f665000 @@ -3784,21 +4953,21 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch + .offset = 0, + .size = 0x040000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "config", + .offset = 0x040000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x050000, + .size = 0x610000, -+ } , { ++ }, { + .name = "caldata", + .offset = 0x660000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "unknown", + .offset = 0x670000, + .size = 0x190000, @@ -3809,8 +4978,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch + +static struct flash_platform_data dir825b1_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = dir825b1_partitions, -+ .nr_parts = ARRAY_SIZE(dir825b1_partitions), ++ .parts = dir825b1_partitions, ++ .nr_parts = ARRAY_SIZE(dir825b1_partitions), +#endif +}; + @@ -3828,8 +4997,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch + .gpio = DIR825B1_GPIO_LED_BLUE_POWER, + .active_low = 1, + }, { -+ .name = "dir825b1:blue:powersave", -+ .gpio = DIR825B1_GPIO_LED_BLUE_POWERSAVE, ++ .name = "dir825b1:blue:wps", ++ .gpio = DIR825B1_GPIO_LED_BLUE_WPS, + .active_low = 1, + }, { + .name = "dir825b1:orange:planet", @@ -3842,27 +5011,33 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch + } +}; + -+static struct gpio_button dir825b1_gpio_buttons[] __initdata = { ++static struct gpio_keys_button dir825b1_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = DIR825B1_KEYS_DEBOUNCE_INTERVAL, + .gpio = DIR825B1_GPIO_BTN_RESET, + .active_low = 1, -+ } , { -+ .desc = "powersave", ++ }, { ++ .desc = "wps", + .type = EV_KEY, -+ .code = BTN_1, -+ .threshold = 3, -+ .gpio = DIR825B1_GPIO_BTN_POWERSAVE, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = DIR825B1_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = DIR825B1_GPIO_BTN_WPS, + .active_low = 1, + } +}; + -+static struct rtl8366s_platform_data dir825b1_rtl8366s_data = { -+ .gpio_sda = DIR825B1_GPIO_RTL8366_SDA, -+ .gpio_sck = DIR825B1_GPIO_RTL8366_SCK, ++static struct rtl8366_initval dir825b1_rtl8366s_initvals[] = { ++ { .reg = 0x06, .val = 0x0108 }, ++}; ++ ++static struct rtl8366_platform_data dir825b1_rtl8366s_data = { ++ .gpio_sda = DIR825B1_GPIO_RTL8366_SDA, ++ .gpio_sck = DIR825B1_GPIO_RTL8366_SCK, ++ .num_initvals = ARRAY_SIZE(dir825b1_rtl8366s_initvals), ++ .initvals = dir825b1_rtl8366s_initvals, +}; + +static struct platform_device dir825b1_rtl8366s_device = { @@ -3875,22 +5050,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch + +static void __init dir825b1_setup(void) +{ -+ u8 mac[6], i; -+ -+ memcpy(mac, (u8*)KSEG1ADDR(DIR825B1_MAC_LOCATION_1), 6); -+ for(i = 5; i >= 3; i--) -+ if(++mac[i] != 0x00) break; -+ -+ ar71xx_set_mac_base(mac); ++ u8 *mac = (u8 *) KSEG1ADDR(DIR825B1_MAC_LOCATION_1); + + ar71xx_add_device_mdio(0x0); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 1); + ar71xx_eth0_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev; + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.speed = SPEED_1000; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ar71xx_eth0_pll_data.pll_1000 = 0x11110000; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 2); + ar71xx_eth1_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev; + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth1_data.phy_mask = 0x10; @@ -3904,14 +5075,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir825b1_leds_gpio), + dir825b1_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, DIR825B1_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(dir825b1_gpio_buttons), -+ dir825b1_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, DIR825B1_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(dir825b1_gpio_keys), ++ dir825b1_gpio_keys); + + ar71xx_add_device_usb(); + + platform_device_register(&dir825b1_rtl8366s_device); + ++ ap94_pci_setup_wmac_led_pin(0, 5); ++ ap94_pci_setup_wmac_led_pin(1, 5); ++ + ap94_pci_init((u8 *) KSEG1ADDR(DIR825B1_CAL_LOCATION_0), + (u8 *) KSEG1ADDR(DIR825B1_MAC_LOCATION_0), + (u8 *) KSEG1ADDR(DIR825B1_CAL_LOCATION_1), @@ -3920,10 +5094,387 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.39/arch + +MIPS_MACHINE(AR71XX_MACH_DIR_825_B1, "DIR-825-B1", "D-Link DIR-825 rev. B1", + dir825b1_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-eap7660d.c linux-2.6.39/arch/mips/ar71xx/mach-eap7660d.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-eap7660d.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-eap7660d.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,180 @@ ++/* ++ * Senao EAP7660D board support ++ * ++ * Copyright (C) 2010 Daniel Golle <daniel.golle@gmail.com> ++ * 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/pci.h> ++#include <linux/ath5k_platform.h> ++#include <linux/delay.h> ++#include <asm/mach-ar71xx/ar71xx.h> ++#include <asm/mach-ar71xx/pci.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++#include "dev-m25p80.h" ++ ++#define EAP7660D_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define EAP7660D_KEYS_DEBOUNCE_INTERVAL (3 * EAP7660D_KEYS_POLL_INTERVAL) ++ ++#define EAP7660D_GPIO_DS4 7 ++#define EAP7660D_GPIO_DS5 2 ++#define EAP7660D_GPIO_DS7 0 ++#define EAP7660D_GPIO_DS8 4 ++#define EAP7660D_GPIO_SW1 3 ++#define EAP7660D_GPIO_SW3 8 ++#define EAP7660D_PHYMASK BIT(20) ++#define EAP7660D_BOARDCONFIG 0x1F7F0000 ++#define EAP7660D_GBIC_MAC_OFFSET 0x1000 ++#define EAP7660D_WMAC0_MAC_OFFSET 0x1010 ++#define EAP7660D_WMAC1_MAC_OFFSET 0x1016 ++#define EAP7660D_WMAC0_CALDATA_OFFSET 0x2000 ++#define EAP7660D_WMAC1_CALDATA_OFFSET 0x3000 ++ ++static struct ath5k_platform_data eap7660d_wmac0_data; ++static struct ath5k_platform_data eap7660d_wmac1_data; ++static char eap7660d_wmac0_mac[6]; ++static char eap7660d_wmac1_mac[6]; ++static u16 eap7660d_wmac0_eeprom[ATH5K_PLAT_EEP_MAX_WORDS]; ++static u16 eap7660d_wmac1_eeprom[ATH5K_PLAT_EEP_MAX_WORDS]; ++ ++#ifdef CONFIG_PCI ++static struct ar71xx_pci_irq eap7660d_pci_irqs[] __initdata = { ++ { ++ .slot = 0, ++ .pin = 1, ++ .irq = AR71XX_PCI_IRQ_DEV0, ++ }, { ++ .slot = 1, ++ .pin = 1, ++ .irq = AR71XX_PCI_IRQ_DEV1, ++ } ++}; ++ ++static int eap7660d_pci_plat_dev_init(struct pci_dev *dev) ++{ ++ switch (PCI_SLOT(dev->devfn)) { ++ case 17: ++ dev->dev.platform_data = &eap7660d_wmac0_data; ++ break; ++ ++ case 18: ++ dev->dev.platform_data = &eap7660d_wmac1_data; ++ break; ++ } ++ ++ return 0; ++} ++ ++void __init eap7660d_pci_init(u8 *cal_data0, u8 *mac_addr0, ++ u8 *cal_data1, u8 *mac_addr1) ++{ ++ if (cal_data0 && *cal_data0 == 0xa55a) { ++ memcpy(eap7660d_wmac0_eeprom, cal_data0, ++ ATH5K_PLAT_EEP_MAX_WORDS); ++ eap7660d_wmac0_data.eeprom_data = eap7660d_wmac0_eeprom; ++ } ++ ++ if (cal_data1 && *cal_data1 == 0xa55a) { ++ memcpy(eap7660d_wmac1_eeprom, cal_data1, ++ ATH5K_PLAT_EEP_MAX_WORDS); ++ eap7660d_wmac1_data.eeprom_data = eap7660d_wmac1_eeprom; ++ } ++ ++ if (mac_addr0) { ++ memcpy(eap7660d_wmac0_mac, mac_addr0, ++ sizeof(eap7660d_wmac0_mac)); ++ eap7660d_wmac0_data.macaddr = eap7660d_wmac0_mac; ++ } ++ ++ if (mac_addr1) { ++ memcpy(eap7660d_wmac1_mac, mac_addr1, ++ sizeof(eap7660d_wmac1_mac)); ++ eap7660d_wmac1_data.macaddr = eap7660d_wmac1_mac; ++ } ++ ++ ar71xx_pci_plat_dev_init = eap7660d_pci_plat_dev_init; ++ ar71xx_pci_init(ARRAY_SIZE(eap7660d_pci_irqs), eap7660d_pci_irqs); ++} ++#else ++static inline void eap7660d_pci_init(u8 *cal_data0, u8 *mac_addr0, ++ u8 *cal_data1, u8 *mac_addr1) ++{ ++} ++#endif /* CONFIG_PCI */ ++ ++static struct gpio_led eap7660d_leds_gpio[] __initdata = { ++ { ++ .name = "eap7660d:green:ds8", ++ .gpio = EAP7660D_GPIO_DS8, ++ .active_low = 0, ++ }, ++ { ++ .name = "eap7660d:green:ds5", ++ .gpio = EAP7660D_GPIO_DS5, ++ .active_low = 0, ++ }, ++ { ++ .name = "eap7660d:green:ds7", ++ .gpio = EAP7660D_GPIO_DS7, ++ .active_low = 0, ++ }, ++ { ++ .name = "eap7660d:green:ds4", ++ .gpio = EAP7660D_GPIO_DS4, ++ .active_low = 0, ++ } ++}; ++ ++static struct gpio_keys_button eap7660d_gpio_keys[] __initdata = { ++ { ++ .desc = "reset", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = EAP7660D_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = EAP7660D_GPIO_SW1, ++ .active_low = 1, ++ }, ++ { ++ .desc = "wps", ++ .type = EV_KEY, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = EAP7660D_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = EAP7660D_GPIO_SW3, ++ .active_low = 1, ++ } ++}; ++ ++static void __init eap7660d_setup(void) ++{ ++ u8 *boardconfig = (u8 *) KSEG1ADDR(EAP7660D_BOARDCONFIG); ++ ++ ar71xx_add_device_mdio(~EAP7660D_PHYMASK); ++ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ++ boardconfig + EAP7660D_GBIC_MAC_OFFSET, 0); ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; ++ ar71xx_eth0_data.phy_mask = EAP7660D_PHYMASK; ++ ar71xx_add_device_eth(0); ++ ar71xx_add_device_m25p80(NULL); ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(eap7660d_leds_gpio), ++ eap7660d_leds_gpio); ++ ar71xx_register_gpio_keys_polled(-1, EAP7660D_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(eap7660d_gpio_keys), ++ eap7660d_gpio_keys); ++ eap7660d_pci_init(boardconfig + EAP7660D_WMAC0_CALDATA_OFFSET, ++ boardconfig + EAP7660D_WMAC0_MAC_OFFSET, ++ boardconfig + EAP7660D_WMAC1_CALDATA_OFFSET, ++ boardconfig + EAP7660D_WMAC1_MAC_OFFSET); ++}; ++ ++MIPS_MACHINE(AR71XX_MACH_EAP7660D, "EAP7660D", "Senao EAP7660D", ++ eap7660d_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ja76pf.c linux-2.6.39/arch/mips/ar71xx/mach-ja76pf.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-ja76pf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-ja76pf.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,102 @@ ++/* ++ * jjPlus JA76PF board support ++ */ ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++#include <linux/platform_device.h> ++#include <linux/i2c.h> ++#include <linux/i2c-gpio.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-m25p80.h" ++#include "dev-gpio-buttons.h" ++#include "dev-pb42-pci.h" ++#include "dev-usb.h" ++#include "dev-leds-gpio.h" ++ ++#define JA76PF_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define JA76PF_KEYS_DEBOUNCE_INTERVAL (3 * JA76PF_KEYS_POLL_INTERVAL) ++ ++#define JA76PF_GPIO_I2C_SCL 0 ++#define JA76PF_GPIO_I2C_SDA 1 ++#define JA76PF_GPIO_LED_1 5 ++#define JA76PF_GPIO_LED_2 4 ++#define JA76PF_GPIO_LED_3 3 ++#define JA76PF_GPIO_BTN_RESET 11 ++ ++static struct gpio_led ja76pf_leds_gpio[] __initdata = { ++ { ++ .name = "ja76pf:green:led1", ++ .gpio = JA76PF_GPIO_LED_1, ++ .active_low = 1, ++ }, { ++ .name = "ja76pf:green:led2", ++ .gpio = JA76PF_GPIO_LED_2, ++ .active_low = 1, ++ }, { ++ .name = "ja76pf:green:led3", ++ .gpio = JA76PF_GPIO_LED_3, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_keys_button ja76pf_gpio_keys[] __initdata = { ++ { ++ .desc = "reset", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = JA76PF_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = JA76PF_GPIO_BTN_RESET, ++ .active_low = 1, ++ } ++}; ++ ++static struct i2c_gpio_platform_data ja76pf_i2c_gpio_data = { ++ .sda_pin = JA76PF_GPIO_I2C_SDA, ++ .scl_pin = JA76PF_GPIO_I2C_SCL, ++}; ++ ++static struct platform_device ja76pf_i2c_gpio_device = { ++ .name = "i2c-gpio", ++ .id = 0, ++ .dev = { ++ .platform_data = &ja76pf_i2c_gpio_data, ++ } ++}; ++ ++#define JA76PF_WAN_PHYMASK (1 << 4) ++#define JA76PF_LAN_PHYMASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 < 3)) ++#define JA76PF_MDIO_PHYMASK (JA76PF_LAN_PHYMASK | JA76PF_WAN_PHYMASK) ++ ++static void __init ja76pf_init(void) ++{ ++ ar71xx_add_device_m25p80(NULL); ++ ++ ar71xx_add_device_mdio(~JA76PF_MDIO_PHYMASK); ++ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; ++ ar71xx_eth0_data.phy_mask = JA76PF_LAN_PHYMASK; ++ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; ++ ar71xx_eth1_data.phy_mask = JA76PF_WAN_PHYMASK; ++ ar71xx_eth1_data.speed = SPEED_1000; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ++ ar71xx_add_device_eth(0); ++ ar71xx_add_device_eth(1); ++ ++ platform_device_register(&ja76pf_i2c_gpio_device); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ja76pf_leds_gpio), ++ ja76pf_leds_gpio); ++ ++ ar71xx_register_gpio_keys_polled(-1, JA76PF_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(ja76pf_gpio_keys), ++ ja76pf_gpio_keys); ++ ++ ar71xx_add_device_usb(); ++ pb42_pci_init(); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_JA76PF, "JA76PF", "jjPlus JA76PF", ja76pf_init); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-jwap003.c linux-2.6.39/arch/mips/ar71xx/mach-jwap003.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-jwap003.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-jwap003.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,83 @@ ++/* ++ * jjPlus JWAP003 board support ++ * ++ */ ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++#include <linux/i2c.h> ++#include <linux/i2c-gpio.h> ++#include <linux/platform_device.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-m25p80.h" ++#include "dev-gpio-buttons.h" ++#include "dev-pb42-pci.h" ++#include "dev-usb.h" ++ ++#define JWAP003_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define JWAP003_KEYS_DEBOUNCE_INTERVAL (3 * JWAP003_KEYS_POLL_INTERVAL) ++ ++#define JWAP003_GPIO_WPS 11 ++#define JWAP003_GPIO_I2C_SCL 0 ++#define JWAP003_GPIO_I2C_SDA 1 ++ ++static struct gpio_keys_button jwap003_gpio_keys[] __initdata = { ++ { ++ .desc = "wps", ++ .type = EV_KEY, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = JWAP003_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = JWAP003_GPIO_WPS, ++ .active_low = 1, ++ } ++}; ++ ++static struct i2c_gpio_platform_data jwap003_i2c_gpio_data = { ++ .sda_pin = JWAP003_GPIO_I2C_SDA, ++ .scl_pin = JWAP003_GPIO_I2C_SCL, ++}; ++ ++static struct platform_device jwap003_i2c_gpio_device = { ++ .name = "i2c-gpio", ++ .id = 0, ++ .dev = { ++ .platform_data = &jwap003_i2c_gpio_data, ++ } ++}; ++ ++#define JWAP003_WAN_PHYMASK BIT(0) ++#define JWAP003_LAN_PHYMASK BIT(4) ++ ++static void __init jwap003_init(void) ++{ ++ ar71xx_add_device_m25p80(NULL); ++ ++ ar71xx_add_device_mdio(0x0); ++ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth0_data.phy_mask = JWAP003_WAN_PHYMASK; ++ ar71xx_eth0_data.speed = SPEED_100; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.has_ar8216 = 1; ++ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.phy_mask = JWAP003_LAN_PHYMASK; ++ ar71xx_eth1_data.speed = SPEED_100; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ++ ar71xx_add_device_eth(0); ++ ar71xx_add_device_eth(1); ++ ++ platform_device_register(&jwap003_i2c_gpio_device); ++ ++ ar71xx_add_device_usb(); ++ ++ ar71xx_register_gpio_keys_polled(-1, JWAP003_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(jwap003_gpio_keys), ++ jwap003_gpio_keys); ++ ++ pb42_pci_init(); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_JWAP003, "JWAP003", "jjPlus JWAP003", jwap003_init); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.39/arch/mips/ar71xx/mach-mzk-w04nu.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-mzk-w04nu.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,165 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-mzk-w04nu.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,166 @@ +/* + * Planex MZK-W04NU board support + * @@ -3941,7 +5492,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.39/arch/ + +#include "machtype.h" +#include "devices.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-m25p80.h" @@ -3958,7 +5509,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.39/arch/ +#define MZK_W04NU_GPIO_BTN_WPS 12 +#define MZK_W04NU_GPIO_BTN_RESET 21 + -+#define MZK_W04NU_BUTTONS_POLL_INTERVAL 20 ++#define MZK_W04NU_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define MZK_W04NU_KEYS_DEBOUNCE_INTERVAL (3 * MZK_W04NU_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition mzk_w04nu_partitions[] = { @@ -3967,24 +5519,24 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.39/arch/ + .offset = 0, + .size = 0x040000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "u-boot-env", + .offset = 0x040000, + .size = 0x010000, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x050000, + .size = 0x160000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x1b0000, + .size = 0x630000, -+ } , { ++ }, { + .name = "art", + .offset = 0x7e0000, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x050000, + .size = 0x790000, @@ -3994,8 +5546,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.39/arch/ + +static struct flash_platform_data mzk_w04nu_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = mzk_w04nu_partitions, -+ .nr_parts = ARRAY_SIZE(mzk_w04nu_partitions), ++ .parts = mzk_w04nu_partitions, ++ .nr_parts = ARRAY_SIZE(mzk_w04nu_partitions), +#endif +}; + @@ -4027,26 +5579,26 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.39/arch/ + } +}; + -+static struct gpio_button mzk_w04nu_gpio_buttons[] __initdata = { ++static struct gpio_keys_button mzk_w04nu_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = MZK_W04NU_KEYS_DEBOUNCE_INTERVAL, + .gpio = MZK_W04NU_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = MZK_W04NU_KEYS_DEBOUNCE_INTERVAL, + .gpio = MZK_W04NU_GPIO_BTN_WPS, + .active_low = 1, + }, { + .desc = "aprouter", + .type = EV_KEY, + .code = BTN_2, -+ .threshold = 3, ++ .debounce_interval = MZK_W04NU_KEYS_DEBOUNCE_INTERVAL, + .gpio = MZK_W04NU_GPIO_BTN_APROUTER, + .active_low = 0, + } @@ -4059,15 +5611,15 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.39/arch/ +{ + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(eeprom); -+ + ar71xx_add_device_mdio(MZK_W04NU_MDIO_MASK); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, eeprom, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ar71xx_eth0_data.has_ar8216 = 1; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, eeprom, 1); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.phy_mask = MZK_W04NU_WAN_PHYMASK; + @@ -4079,20 +5631,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.39/arch/ + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(mzk_w04nu_leds_gpio), + mzk_w04nu_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, MZK_W04NU_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(mzk_w04nu_gpio_buttons), -+ mzk_w04nu_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, MZK_W04NU_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(mzk_w04nu_gpio_keys), ++ mzk_w04nu_gpio_keys); + ar71xx_add_device_usb(); + -+ ar913x_add_device_wmac(eeprom, NULL); ++ ar9xxx_add_device_wmac(eeprom, NULL); +} + +MIPS_MACHINE(AR71XX_MACH_MZK_W04NU, "MZK-W04NU", "Planex MZK-W04NU", + mzk_w04nu_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.39/arch/mips/ar71xx/mach-mzk-w300nh.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-mzk-w300nh.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,158 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-mzk-w300nh.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,159 @@ +/* + * Planex MZK-W300NH board support + * @@ -4112,7 +5664,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.39/arch +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" + @@ -4126,7 +5678,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.39/arch +#define MZK_W300NH_GPIO_BTN_WPS 12 +#define MZK_W300NH_GPIO_BTN_RESET 21 + -+#define MZK_W04NU_BUTTONS_POLL_INTERVAL 20 ++#define MZK_W300NH_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define MZK_W300NH_KEYS_DEBOUNCE_INTERVAL (3 * MZK_W300NH_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition mzk_w300nh_partitions[] = { @@ -4135,24 +5688,24 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.39/arch + .offset = 0, + .size = 0x040000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "u-boot-env", + .offset = 0x040000, + .size = 0x010000, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x050000, + .size = 0x160000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x1b0000, + .size = 0x630000, -+ } , { ++ }, { + .name = "art", + .offset = 0x7e0000, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x050000, + .size = 0x790000, @@ -4162,8 +5715,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.39/arch + +static struct flash_platform_data mzk_w300nh_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = mzk_w300nh_partitions, -+ .nr_parts = ARRAY_SIZE(mzk_w300nh_partitions), ++ .parts = mzk_w300nh_partitions, ++ .nr_parts = ARRAY_SIZE(mzk_w300nh_partitions), +#endif +}; + @@ -4191,26 +5744,26 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.39/arch + } +}; + -+static struct gpio_button mzk_w300nh_gpio_buttons[] __initdata = { ++static struct gpio_keys_button mzk_w300nh_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = MZK_W300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = MZK_W300NH_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = MZK_W300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = MZK_W300NH_GPIO_BTN_WPS, + .active_low = 1, + }, { + .desc = "aprouter", + .type = EV_KEY, + .code = BTN_2, -+ .threshold = 3, ++ .debounce_interval = MZK_W300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = MZK_W300NH_GPIO_BTN_APROUTER, + .active_low = 0, + } @@ -4223,15 +5776,15 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.39/arch +{ + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(eeprom); -+ + ar71xx_add_device_mdio(MZK_W300NH_MDIO_MASK); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, eeprom, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ar71xx_eth0_data.has_ar8216 = 1; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, eeprom, 1); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.phy_mask = MZK_W300NH_WAN_PHYMASK; + @@ -4241,20 +5794,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.39/arch + ar71xx_add_device_m25p80(&mzk_w300nh_flash_data); + + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(mzk_w300nh_leds_gpio), -+ mzk_w300nh_leds_gpio); ++ mzk_w300nh_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, MZK_W04NU_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(mzk_w300nh_gpio_buttons), -+ mzk_w300nh_gpio_buttons); -+ ar913x_add_device_wmac(eeprom, NULL); ++ ar71xx_register_gpio_keys_polled(-1, MZK_W300NH_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(mzk_w300nh_gpio_keys), ++ mzk_w300nh_gpio_keys); ++ ar9xxx_add_device_wmac(eeprom, NULL); +} + +MIPS_MACHINE(AR71XX_MACH_MZK_W300NH, "MZK-W300NH", "Planex MZK-W300NH", + mzk_w300nh_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mips/ar71xx/mach-nbg460n.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-nbg460n.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,222 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-nbg460n.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,225 @@ +/* + * Zyxel NBG 460N/550N/550NH board support + * @@ -4271,7 +5824,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/delay.h> -+#include <linux/rtl8366s.h> ++#include <linux/rtl8366.h> + +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> @@ -4282,7 +5835,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" + @@ -4295,7 +5848,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi +/* Buttons */ +#define NBG460N_GPIO_BTN_WPS 12 +#define NBG460N_GPIO_BTN_RESET 21 -+#define NBG460N_BUTTONS_POLL_INTERVAL 20 ++ ++#define NBG460N_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define NBG460N_KEYS_DEBOUNCE_INTERVAL (3 * NBG460N_KEYS_POLL_INTERVAL) + +/* RTC chip PCF8563 I2C interface */ +#define NBG460N_GPIO_PCF8563_SDA 8 @@ -4312,28 +5867,28 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi + .offset = 0, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "U-Boot Config", + .offset = 0x010000, + .size = 0x030000, -+ } , { ++ }, { + .name = "U-Boot", + .offset = 0x040000, + .size = 0x030000, -+ } , { ++ }, { + .name = "linux", + .offset = 0x070000, + .size = 0x0e0000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x150000, + .size = 0x2a0000, -+ } , { ++ }, { + .name = "CalibData", + .offset = 0x3f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x070000, + .size = 0x380000, @@ -4343,8 +5898,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi + +static struct flash_platform_data nbg460n_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = nbg460n_partitions, -+ .nr_parts = ARRAY_SIZE(nbg460n_partitions), ++ .parts = nbg460n_partitions, ++ .nr_parts = ARRAY_SIZE(nbg460n_partitions), +#endif +}; + @@ -4371,19 +5926,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi + } +}; + -+static struct gpio_button nbg460n_gpio_buttons[] __initdata = { ++static struct gpio_keys_button nbg460n_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = NBG460N_KEYS_DEBOUNCE_INTERVAL, + .gpio = NBG460N_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = NBG460N_KEYS_DEBOUNCE_INTERVAL, + .gpio = NBG460N_GPIO_BTN_WPS, + .active_low = 1, + } @@ -4421,9 +5976,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi +} + + -+static struct rtl8366s_platform_data nbg460n_rtl8366s_data = { -+ .gpio_sda = NBG460N_GPIO_RTL8366_SDA, -+ .gpio_sck = NBG460N_GPIO_RTL8366_SCK, ++static struct rtl8366_platform_data nbg460n_rtl8366s_data = { ++ .gpio_sda = NBG460N_GPIO_RTL8366_SDA, ++ .gpio_sck = NBG460N_GPIO_RTL8366_SCK, +}; + +static struct platform_device nbg460n_rtl8366s_device = { @@ -4436,20 +5991,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi + +static void __init nbg460n_setup(void) +{ -+ /* end of bootloader sector contains mac address*/ ++ /* end of bootloader sector contains mac address */ + u8 *mac = (u8 *) KSEG1ADDR(0x1fc0fff8); + /* last sector contains wlan calib data */ + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(mac); -+ + /* LAN Port */ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); + ar71xx_eth0_data.mii_bus_dev = &nbg460n_rtl8366s_device.dev; + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.speed = SPEED_1000; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + + /* WAN Port */ ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); + ar71xx_eth1_data.mii_bus_dev = &nbg460n_rtl8366s_device.dev; + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth1_data.phy_mask = 0x10; @@ -4463,7 +6018,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi + /* register flash */ + ar71xx_add_device_m25p80(&nbg460n_flash_data); + -+ ar913x_add_device_wmac(eeprom, mac); ++ ar9xxx_add_device_wmac(eeprom, mac); + + /* register RTC chip */ + nbg460n_i2c_init(); @@ -4471,16 +6026,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.39/arch/mi + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(nbg460n_leds_gpio), + nbg460n_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, NBG460N_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(nbg460n_gpio_buttons), -+ nbg460n_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, NBG460N_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(nbg460n_gpio_keys), ++ nbg460n_gpio_keys); +} + -+MIPS_MACHINE(AR71XX_MACH_NBG460N, "NBG460N", "Zyxel NBG460N/550N/550NH", nbg460n_setup); ++MIPS_MACHINE(AR71XX_MACH_NBG460N, "NBG460N", "Zyxel NBG460N/550N/550NH", ++ nbg460n_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb42.c linux-2.6.39/arch/mips/ar71xx/mach-pb42.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-pb42.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-pb42.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,71 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-pb42.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,74 @@ +/* + * Atheros PB42 board support + * @@ -4501,24 +6057,25 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb42.c linux-2.6.39/arch/mips/ +#include "dev-pb42-pci.h" +#include "dev-usb.h" + -+#define PB42_BUTTONS_POLL_INTERVAL 20 ++#define PB42_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define PB42_KEYS_DEBOUNCE_INTERVAL (3 * PB42_KEYS_POLL_INTERVAL) + +#define PB42_GPIO_BTN_SW4 8 +#define PB42_GPIO_BTN_SW5 3 + -+static struct gpio_button pb42_gpio_buttons[] __initdata = { ++static struct gpio_keys_button pb42_gpio_keys[] __initdata = { + { + .desc = "sw4", + .type = EV_KEY, + .code = BTN_0, -+ .threshold = 3, ++ .debounce_interval = PB42_KEYS_DEBOUNCE_INTERVAL, + .gpio = PB42_GPIO_BTN_SW4, + .active_low = 1, -+ } , { ++ }, { + .desc = "sw5", + .type = EV_KEY, + .code = BTN_1, -+ .threshold = 3, ++ .debounce_interval = PB42_KEYS_DEBOUNCE_INTERVAL, + .gpio = PB42_GPIO_BTN_SW5, + .active_low = 1, + } @@ -4534,9 +6091,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb42.c linux-2.6.39/arch/mips/ + + ar71xx_add_device_mdio(~PB42_MDIO_PHYMASK); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; + ar71xx_eth0_data.phy_mask = PB42_WAN_PHYMASK; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, ar71xx_mac_base, 1); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.speed = SPEED_100; + ar71xx_eth1_data.duplex = DUPLEX_FULL; @@ -4544,9 +6103,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb42.c linux-2.6.39/arch/mips/ + ar71xx_add_device_eth(0); + ar71xx_add_device_eth(1); + -+ ar71xx_add_device_gpio_buttons(-1, PB42_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(pb42_gpio_buttons), -+ pb42_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, PB42_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(pb42_gpio_keys), ++ pb42_gpio_keys); + + pb42_pci_init(); +} @@ -4554,8 +6113,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb42.c linux-2.6.39/arch/mips/ +MIPS_MACHINE(AR71XX_MACH_PB42, "PB42", "Atheros PB42", pb42_init); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb44.c linux-2.6.39/arch/mips/ar71xx/mach-pb44.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-pb44.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-pb44.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,207 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-pb44.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,213 @@ +/* + * Atheros PB44 board support + * @@ -4612,6 +6171,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb44.c linux-2.6.39/arch/mips/ +#define PB44_GPIO_LED_JUMP1 (PB44_GPIO_EXP_BASE + PB44_PCF8757_LED_JUMP1) +#define PB44_GPIO_LED_JUMP2 (PB44_GPIO_EXP_BASE + PB44_PCF8757_LED_JUMP2) + ++#define PB44_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define PB44_KEYS_DEBOUNCE_INTERVAL (3 * PB44_KEYS_POLL_INTERVAL) ++ +static struct i2c_gpio_platform_data pb44_i2c_gpio_data = { + .sda_pin = PB44_GPIO_I2C_SDA, + .scl_pin = PB44_GPIO_I2C_SCL, @@ -4648,19 +6210,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb44.c linux-2.6.39/arch/mips/ + }, +}; + -+static struct gpio_button pb44_gpio_buttons[] __initdata = { ++static struct gpio_keys_button pb44_gpio_keys[] __initdata = { + { + .desc = "soft_reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL, + .gpio = PB44_GPIO_SW_RESET, + .active_low = 1, -+ } , { ++ }, { + .desc = "jumpstart", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL, + .gpio = PB44_GPIO_SW_JUMP, + .active_low = 1, + } @@ -4731,11 +6293,13 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb44.c linux-2.6.39/arch/mips/ +{ + ar71xx_add_device_mdio(~PB44_MDIO_PHYMASK); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.phy_mask = PB44_WAN_PHYMASK; + + ar71xx_add_device_eth(0); + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, ar71xx_mac_base, 1); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth1_data.speed = SPEED_1000; + ar71xx_eth1_data.duplex = DUPLEX_FULL; @@ -4748,7 +6312,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb44.c linux-2.6.39/arch/mips/ + pb42_pci_init(); + + i2c_register_board_info(0, pb44_i2c_board_info, -+ ARRAY_SIZE(pb44_i2c_board_info)); ++ ARRAY_SIZE(pb44_i2c_board_info)); + + platform_device_register(&pb44_i2c_gpio_device); + @@ -4756,17 +6320,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb44.c linux-2.6.39/arch/mips/ + platform_device_register(&pb44_spi_device); + + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(pb44_leds_gpio), -+ pb44_leds_gpio); ++ pb44_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, 20, ARRAY_SIZE(pb44_gpio_buttons), -+ pb44_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, PB44_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(pb44_gpio_keys), ++ pb44_gpio_keys); +} + +MIPS_MACHINE(AR71XX_MACH_PB44, "PB44", "Atheros PB44", pb44_init); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb92.c linux-2.6.39/arch/mips/ar71xx/mach-pb92.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-pb92.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-pb92.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,109 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-pb92.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,105 @@ +/* + * Atheros PB92 board support + * @@ -4797,19 +6362,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb92.c linux-2.6.39/arch/mips/ + .offset = 0, + .size = 0x040000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "u-boot-env", + .offset = 0x040000, + .size = 0x010000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x050000, + .size = 0x2b0000, -+ } , { ++ }, { + .name = "uImage", + .offset = 0x300000, + .size = 0x0e0000, -+ } , { ++ }, { + .name = "ART", + .offset = 0x3e0000, + .size = 0x020000, @@ -4820,30 +6385,30 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb92.c linux-2.6.39/arch/mips/ + +static struct flash_platform_data pb92_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = pb92_partitions, -+ .nr_parts = ARRAY_SIZE(pb92_partitions), ++ .parts = pb92_partitions, ++ .nr_parts = ARRAY_SIZE(pb92_partitions), +#endif +}; + -+ -+#define PB92_BUTTONS_POLL_INTERVAL 20 ++#define PB92_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define PB92_KEYS_DEBOUNCE_INTERVAL (3 * PB92_KEYS_POLL_INTERVAL) + +#define PB92_GPIO_BTN_SW4 8 +#define PB92_GPIO_BTN_SW5 3 + -+static struct gpio_button pb92_gpio_buttons[] __initdata = { ++static struct gpio_keys_button pb92_gpio_keys[] __initdata = { + { + .desc = "sw4", + .type = EV_KEY, + .code = BTN_0, -+ .threshold = 3, ++ .debounce_interval = PB92_KEYS_DEBOUNCE_INTERVAL, + .gpio = PB92_GPIO_BTN_SW4, + .active_low = 1, -+ } , { ++ }, { + .desc = "sw5", + .type = EV_KEY, + .code = BTN_1, -+ .threshold = 3, ++ .debounce_interval = PB92_KEYS_DEBOUNCE_INTERVAL, + .gpio = PB92_GPIO_BTN_SW5, + .active_low = 1, + } @@ -4853,24 +6418,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb92.c linux-2.6.39/arch/mips/ +{ + u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000); + -+ ar71xx_set_mac_base(mac); + ar71xx_add_device_m25p80(&pb92_flash_data); + -+ ar71xx_add_device_mdio(~0); -+ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_add_device_mdio(~BIT(0)); ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.speed = SPEED_1000; + ar71xx_eth0_data.duplex = DUPLEX_FULL; -+ -+ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; -+ ar71xx_eth1_data.speed = SPEED_1000; -+ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = BIT(0); + + ar71xx_add_device_eth(0); -+ ar71xx_add_device_eth(1); + -+ ar71xx_add_device_gpio_buttons(-1, PB92_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(pb92_gpio_buttons), -+ pb92_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, PB92_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(pb92_gpio_keys), ++ pb92_gpio_keys); + + pb9x_pci_init(); +} @@ -4878,12 +6439,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-pb92.c linux-2.6.39/arch/mips/ +MIPS_MACHINE(AR71XX_MACH_PB92, "PB92", "Atheros PB92", pb92_init); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips/ar71xx/mach-rb4xx.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-rb4xx.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,290 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-rb4xx.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,344 @@ +/* + * MikroTik RouterBOARD 4xx series support + * -+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2008-2010 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 @@ -4897,9 +6458,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/spi/mmc_spi.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> + +#include <asm/mach-ar71xx/ar71xx.h> +#include <asm/mach-ar71xx/pci.h> ++#include <asm/mach-ar71xx/rb4xx_cpld.h> + +#include "machtype.h" +#include "devices.h" @@ -4910,22 +6474,50 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips +#define RB4XX_GPIO_USER_LED 4 +#define RB4XX_GPIO_RESET_SWITCH 7 + -+#define RB4XX_BUTTONS_POLL_INTERVAL 20 ++#define RB4XX_GPIO_CPLD_BASE 32 ++#define RB4XX_GPIO_CPLD_LED1 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED1) ++#define RB4XX_GPIO_CPLD_LED2 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED2) ++#define RB4XX_GPIO_CPLD_LED3 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED3) ++#define RB4XX_GPIO_CPLD_LED4 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED4) ++#define RB4XX_GPIO_CPLD_LED5 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED5) ++ ++#define RB4XX_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define RB4XX_KEYS_DEBOUNCE_INTERVAL (3 * RB4XX_KEYS_POLL_INTERVAL) + +static struct gpio_led rb4xx_leds_gpio[] __initdata = { + { + .name = "rb4xx:yellow:user", + .gpio = RB4XX_GPIO_USER_LED, + .active_low = 0, ++ }, { ++ .name = "rb4xx:green:led1", ++ .gpio = RB4XX_GPIO_CPLD_LED1, ++ .active_low = 1, ++ }, { ++ .name = "rb4xx:green:led2", ++ .gpio = RB4XX_GPIO_CPLD_LED2, ++ .active_low = 1, ++ }, { ++ .name = "rb4xx:green:led3", ++ .gpio = RB4XX_GPIO_CPLD_LED3, ++ .active_low = 1, ++ }, { ++ .name = "rb4xx:green:led4", ++ .gpio = RB4XX_GPIO_CPLD_LED4, ++ .active_low = 1, ++ }, { ++ .name = "rb4xx:green:led5", ++ .gpio = RB4XX_GPIO_CPLD_LED5, ++ .active_low = 0, + }, +}; + -+static struct gpio_button rb4xx_gpio_buttons[] __initdata = { ++static struct gpio_keys_button rb4xx_gpio_keys[] __initdata = { + { + .desc = "reset_switch", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = RB4XX_KEYS_DEBOUNCE_INTERVAL, + .gpio = RB4XX_GPIO_RESET_SWITCH, + .active_low = 1, + } @@ -4960,107 +6552,117 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips + } +}; + -+#if 0 -+/* -+ * SPI device support is experimental -+ */ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition rb4xx_partitions[] = { ++ { ++ .name = "routerboot", ++ .offset = 0, ++ .size = 0x0b000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "hard_config", ++ .offset = 0x0b000, ++ .size = 0x01000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "bios", ++ .offset = 0x0d000, ++ .size = 0x02000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "soft_config", ++ .offset = 0x0f000, ++ .size = 0x01000, ++ } ++}; ++#define rb4xx_num_partitions ARRAY_SIZE(rb4xx_partitions) ++#else /* CONFIG_MTD_PARTITIONS */ ++#define rb4xx_partitions NULL ++#define rb4xx_num_partitions 0 ++#endif /* CONFIG_MTD_PARTITIONS */ ++ +static struct flash_platform_data rb4xx_flash_data = { -+ .type = "pm25lv512", ++ .type = "pm25lv512", ++ .parts = rb4xx_partitions, ++ .nr_parts = rb4xx_num_partitions, +}; + -+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 rb4xx_cpld_platform_data rb4xx_cpld_data = { ++ .gpio_base = RB4XX_GPIO_CPLD_BASE, +}; + -+static struct mmc_spi_platform_data rb433_mmc_data = { ++static struct mmc_spi_platform_data rb4xx_mmc_data = { + .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, +}; + -+static struct spi_board_info rb433_spi_info[] = { ++static struct spi_board_info rb4xx_spi_info[] = { + { + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 25000000, + .modalias = "m25p80", -+ .platform_data = &rb433_flash_data, ++ .platform_data = &rb4xx_flash_data, + }, { + .bus_num = 0, -+ .chip_select = 2, ++ .chip_select = 1, + .max_speed_hz = 25000000, -+ .modalias = "mmc_spi", -+ .platform_data = &rb433_mmc_data, ++ .modalias = "spi-rb4xx-cpld", ++ .platform_data = &rb4xx_cpld_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); -+ } ++static struct spi_board_info rb4xx_microsd_info[] = { ++ { ++ .bus_num = 0, ++ .chip_select = 2, ++ .max_speed_hz = 25000000, ++ .modalias = "mmc_spi", ++ .platform_data = &rb4xx_mmc_data, + } ++}; + -+ 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 struct resource rb4xx_spi_resources[] = { ++ { ++ .start = AR71XX_SPI_BASE, ++ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, +}; + -+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 struct platform_device rb4xx_spi_device = { ++ .name = "rb4xx-spi", ++ .id = -1, ++ .resource = rb4xx_spi_resources, ++ .num_resources = ARRAY_SIZE(rb4xx_spi_resources), ++}; + +static void __init rb4xx_generic_setup(void) +{ + ar71xx_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN | -+ AR71XX_GPIO_FUNC_SPI_CS2_EN); ++ AR71XX_GPIO_FUNC_SPI_CS2_EN); + + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(rb4xx_leds_gpio), + rb4xx_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, RB4XX_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(rb4xx_gpio_buttons), -+ rb4xx_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, RB4XX_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(rb4xx_gpio_keys), ++ rb4xx_gpio_keys); + ++ spi_register_board_info(rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info)); ++ platform_device_register(&rb4xx_spi_device); + platform_device_register(&rb4xx_nand_device); +} + +static void __init rb411_setup(void) +{ + rb4xx_generic_setup(); -+ rb4xx_add_device_spi(); ++ spi_register_board_info(rb4xx_microsd_info, ++ ARRAY_SIZE(rb4xx_microsd_info)); + + ar71xx_add_device_mdio(0xfffffffc); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; + ar71xx_eth0_data.phy_mask = 0x00000003; + @@ -5081,19 +6683,25 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips +MIPS_MACHINE(AR71XX_MACH_RB_411U, "411U", "MikroTik RouterBOARD 411U", + rb411u_setup); + ++#define RB433_LAN_PHYMASK BIT(0) ++#define RB433_WAN_PHYMASK BIT(4) ++#define RB433_MDIO_PHYMASK (RB433_LAN_PHYMASK | RB433_WAN_PHYMASK) ++ +static void __init rb433_setup(void) +{ + rb4xx_generic_setup(); -+ rb433_add_device_spi(); ++ spi_register_board_info(rb4xx_microsd_info, ++ ARRAY_SIZE(rb4xx_microsd_info)); + -+ ar71xx_add_device_mdio(0xffffffe9); ++ ar71xx_add_device_mdio(~RB433_MDIO_PHYMASK); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 1); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; -+ ar71xx_eth0_data.speed = SPEED_100; -+ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = RB433_LAN_PHYMASK; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; -+ ar71xx_eth1_data.phy_mask = 0x00000010; ++ ar71xx_eth1_data.phy_mask = RB433_WAN_PHYMASK; + + ar71xx_add_device_eth(1); + ar71xx_add_device_eth(0); @@ -5113,20 +6721,24 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips +MIPS_MACHINE(AR71XX_MACH_RB_433U, "433U", "MikroTik RouterBOARD 433UAH", + rb433u_setup); + ++#define RB450_LAN_PHYMASK BIT(0) ++#define RB450_WAN_PHYMASK BIT(4) ++#define RB450_MDIO_PHYMASK (RB450_LAN_PHYMASK | RB450_WAN_PHYMASK) ++ +static void __init rb450_generic_setup(int gige) +{ + rb4xx_generic_setup(); -+ rb4xx_add_device_spi(); -+ -+ ar71xx_add_device_mdio(0xffffffe0); ++ ar71xx_add_device_mdio(~RB450_MDIO_PHYMASK); + -+ ar71xx_eth0_data.phy_if_mode = (gige) ? PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_MII; -+ ar71xx_eth0_data.phy_mask = (gige) ? (1 << 0) : 0; -+ ar71xx_eth0_data.speed = (gige) ? SPEED_1000 : SPEED_100; -+ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 1); ++ ar71xx_eth0_data.phy_if_mode = (gige) ? ++ PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_MII; ++ ar71xx_eth0_data.phy_mask = RB450_LAN_PHYMASK; + -+ ar71xx_eth1_data.phy_if_mode = (gige) ? PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_RMII; -+ ar71xx_eth1_data.phy_mask = 0x00000010; ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, ar71xx_mac_base, 0); ++ ar71xx_eth1_data.phy_if_mode = (gige) ? ++ PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.phy_mask = RB450_WAN_PHYMASK; + + ar71xx_add_device_eth(1); + ar71xx_add_device_eth(0); @@ -5143,6 +6755,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips +static void __init rb450g_setup(void) +{ + rb450_generic_setup(1); ++ spi_register_board_info(rb4xx_microsd_info, ++ ARRAY_SIZE(rb4xx_microsd_info)); +} + +MIPS_MACHINE(AR71XX_MACH_RB_450G, "450G", "MikroTik RouterBOARD 450G", @@ -5151,14 +6765,15 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips +static void __init rb493_setup(void) +{ + rb4xx_generic_setup(); -+ rb4xx_add_device_spi(); + + ar71xx_add_device_mdio(0x3fffff00); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, ar71xx_mac_base, 1); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.phy_mask = 0x00000001; + @@ -5172,8 +6787,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.39/arch/mips + rb493_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb750.c linux-2.6.39/arch/mips/ar71xx/mach-rb750.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-rb750.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-rb750.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,133 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-rb750.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,144 @@ +/* + * MikroTik RouterBOARD 750 support + * @@ -5189,7 +6804,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb750.c linux-2.6.39/arch/mips +#include <asm/mach-ar71xx/mach-rb750.h> + +#include "machtype.h" -+#include "dev-ap91-eth.h" ++#include "devices.h" + +static struct rb750_led_data rb750_leds[] = { + { @@ -5231,13 +6846,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb750.c linux-2.6.39/arch/mips + } +}; + -+static const char *rb750_port_names[AP91_ETH_NUM_PORT_NAMES] __initdata = { -+ "port5", -+ "port4", -+ "port3", -+ "port2", -+}; -+ +static struct platform_device rb750_nand_device = { + .name = "rb750-nand", + .id = -1, @@ -5286,7 +6894,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb750.c linux-2.6.39/arch/mips + + ret = 1; + -+ unlock: ++unlock: + spin_unlock_irqrestore(&lock, flags); + return ret; +} @@ -5300,7 +6908,25 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb750.c linux-2.6.39/arch/mips + AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN | + AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN); + -+ ap91_eth_init(NULL, rb750_port_names); ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, ar71xx_mac_base, 1); ++ ++ /* WAN port */ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth0_data.speed = SPEED_100; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = BIT(4); ++ ++ /* LAN ports */ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.speed = SPEED_1000; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ar71xx_eth1_data.has_ar7240_switch = 1; ++ ++ ar71xx_add_device_mdio(0x0); ++ ar71xx_add_device_eth(1); ++ ar71xx_add_device_eth(0); ++ + platform_device_register(&rb750_leds_device); + platform_device_register(&rb750_nand_device); +} @@ -5309,8 +6935,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-rb750.c linux-2.6.39/arch/mips + rb750_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.39/arch/mips/ar71xx/mach-tew-632brp.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-tew-632brp.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,149 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-tew-632brp.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,151 @@ +/* + * TrendNET TEW-632BRP board support + * @@ -5330,7 +6956,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.39/arch +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "nvram.h" @@ -5341,7 +6967,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.39/arch +#define TEW_632BRP_GPIO_BTN_WPS 12 +#define TEW_632BRP_GPIO_BTN_RESET 21 + -+#define TEW_632BRP_BUTTONS_POLL_INTERVAL 20 ++#define TEW_632BRP_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define TEW_632BRP_KEYS_DEBOUNCE_INTERVAL (3 * TEW_632BRP_KEYS_POLL_INTERVAL) + +#define TEW_632BRP_CONFIG_ADDR 0x1f020000 +#define TEW_632BRP_CONFIG_SIZE 0x10000 @@ -5353,24 +6980,24 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.39/arch + .offset = 0, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "config", + .offset = 0x020000, + .size = 0x010000, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x030000, -+ .size = 0x0d0000, -+ } , { ++ .size = 0x0e0000, ++ }, { + .name = "rootfs", -+ .offset = 0x100000, -+ .size = 0x2f0000, -+ } , { ++ .offset = 0x110000, ++ .size = 0x2e0000, ++ }, { + .name = "art", + .offset = 0x3f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x030000, + .size = 0x3c0000, @@ -5380,8 +7007,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.39/arch + +static struct flash_platform_data tew_632brp_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = tew_632brp_partitions, -+ .nr_parts = ARRAY_SIZE(tew_632brp_partitions), ++ .parts = tew_632brp_partitions, ++ .nr_parts = ARRAY_SIZE(tew_632brp_partitions), +#endif +}; + @@ -5401,18 +7028,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.39/arch + } +}; + -+static struct gpio_button tew_632brp_gpio_buttons[] __initdata = { ++static struct gpio_keys_button tew_632brp_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = TEW_632BRP_KEYS_DEBOUNCE_INTERVAL, + .gpio = TEW_632BRP_GPIO_BTN_RESET, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = TEW_632BRP_KEYS_DEBOUNCE_INTERVAL, + .gpio = TEW_632BRP_GPIO_BTN_WPS, + } +}; @@ -5430,8 +7057,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.39/arch + u8 *wlan_mac = NULL; + + if (nvram_parse_mac_addr(config, TEW_632BRP_CONFIG_SIZE, -+ "lan_mac=", mac) == 0) { -+ ar71xx_set_mac_base(mac); ++ "lan_mac=", mac) == 0) { ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); + wlan_mac = mac; + } + @@ -5451,18 +7079,458 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.39/arch + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tew_632brp_leds_gpio), + tew_632brp_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, TEW_632BRP_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(tew_632brp_gpio_buttons), -+ tew_632brp_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, TEW_632BRP_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(tew_632brp_gpio_keys), ++ tew_632brp_gpio_keys); + -+ ar913x_add_device_wmac(eeprom, wlan_mac); ++ ar9xxx_add_device_wmac(eeprom, wlan_mac); +} + +MIPS_MACHINE(AR71XX_MACH_TEW_632BRP, "TEW-632BRP", "TRENDnet TEW-632BRP", + tew_632brp_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-mr3x20.c linux-2.6.39/arch/mips/ar71xx/mach-tl-mr3x20.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-mr3x20.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-tl-mr3x20.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,166 @@ ++/* ++ * TP-LINK TL-MR3220/3420 board support ++ * ++ * Copyright (C) 2010 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 <linux/gpio.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-m25p80.h" ++#include "dev-ap91-pci.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++#include "dev-usb.h" ++ ++#define TL_MR3X20_GPIO_LED_QSS 0 ++#define TL_MR3X20_GPIO_LED_SYSTEM 1 ++#define TL_MR3X20_GPIO_LED_3G 8 ++ ++#define TL_MR3X20_GPIO_BTN_RESET 11 ++#define TL_MR3X20_GPIO_BTN_QSS 12 ++ ++#define TL_MR3X20_GPIO_USB_POWER 6 ++ ++#define TL_MR3X20_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define TL_MR3X20_KEYS_DEBOUNCE_INTERVAL (3 * TL_MR3X20_KEYS_POLL_INTERVAL) ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition tl_mr3x20_partitions[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = 0x020000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "kernel", ++ .offset = 0x020000, ++ .size = 0x140000, ++ }, { ++ .name = "rootfs", ++ .offset = 0x160000, ++ .size = 0x290000, ++ }, { ++ .name = "art", ++ .offset = 0x3f0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "firmware", ++ .offset = 0x020000, ++ .size = 0x3d0000, ++ } ++}; ++#define tl_mr3x20_num_partitions ARRAY_SIZE(tl_mr3x20_partitions) ++#else ++#define tl_mr3x20_partitions NULL ++#define tl_mr3x20_num_partitions 0 ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct flash_platform_data tl_mr3x20_flash_data = { ++ .parts = tl_mr3x20_partitions, ++ .nr_parts = tl_mr3x20_num_partitions, ++}; ++ ++static struct gpio_led tl_mr3x20_leds_gpio[] __initdata = { ++ { ++ .name = "tl-mr3x20:green:system", ++ .gpio = TL_MR3X20_GPIO_LED_SYSTEM, ++ .active_low = 1, ++ }, { ++ .name = "tl-mr3x20:green:qss", ++ .gpio = TL_MR3X20_GPIO_LED_QSS, ++ .active_low = 1, ++ }, { ++ .name = "tl-mr3x20:green:3g", ++ .gpio = TL_MR3X20_GPIO_LED_3G, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_keys_button tl_mr3x20_gpio_keys[] __initdata = { ++ { ++ .desc = "reset", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = TL_MR3X20_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = TL_MR3X20_GPIO_BTN_RESET, ++ .active_low = 1, ++ }, { ++ .desc = "qss", ++ .type = EV_KEY, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = TL_MR3X20_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = TL_MR3X20_GPIO_BTN_QSS, ++ .active_low = 1, ++ } ++}; ++ ++static void __init tl_mr3x20_setup(void) ++{ ++ u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00); ++ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000); ++ ++ /* enable power for the USB port */ ++ gpio_request(TL_MR3X20_GPIO_USB_POWER, "USB power"); ++ gpio_direction_output(TL_MR3X20_GPIO_USB_POWER, 1); ++ ++ ar71xx_add_device_m25p80(&tl_mr3x20_flash_data); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_mr3x20_leds_gpio), ++ tl_mr3x20_leds_gpio); ++ ++ ar71xx_register_gpio_keys_polled(-1, TL_MR3X20_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(tl_mr3x20_gpio_keys), ++ tl_mr3x20_gpio_keys); ++ ++ ar71xx_eth1_data.has_ar7240_switch = 1; ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); ++ ++ /* WAN port */ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth0_data.speed = SPEED_100; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = BIT(4); ++ ++ /* LAN ports */ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.speed = SPEED_1000; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ++ ar71xx_add_device_mdio(0x0); ++ ar71xx_add_device_eth(1); ++ ar71xx_add_device_eth(0); ++ ++ ar71xx_add_device_usb(); ++ ++ ap91_pci_init(ee, mac); ++} ++ ++static void __init tl_mr3220_setup(void) ++{ ++ tl_mr3x20_setup(); ++ ap91_pci_setup_wmac_led_pin(1); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_TL_MR3220, "TL-MR3220", "TP-LINK TL-MR3220", ++ tl_mr3220_setup); ++ ++static void __init tl_mr3420_setup(void) ++{ ++ tl_mr3x20_setup(); ++ ap91_pci_setup_wmac_led_pin(0); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_TL_MR3420, "TL-MR3420", "TP-LINK TL-MR3420", ++ tl_mr3420_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wa901nd-v2.c linux-2.6.39/arch/mips/ar71xx/mach-tl-wa901nd-v2.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wa901nd-v2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wa901nd-v2.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,132 @@ ++/* ++ * TP-LINK TL-WA901ND v2 board support ++ * ++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2010 Pieter Hollants <pieter@hollants.com> ++ * Copyright (C) 2011 Jonathan Bennett <jbscience87@gmail.com> ++ * ++ * 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/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-m25p80.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++#include "dev-ar9xxx-wmac.h" ++ ++#define TL_WA901ND_V2_GPIO_LED_QSS 4 ++#define TL_WA901ND_V2_GPIO_LED_SYSTEM 2 ++#define TL_WA901ND_V2_GPIO_LED_WLAN 9 ++ ++ ++#define TL_WA901ND_V2_GPIO_BTN_RESET 3 ++#define TL_WA901ND_V2_GPIO_BTN_QSS 7 ++ ++#define TL_WA901ND_V2_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define TL_WA901ND_V2_KEYS_DEBOUNCE_INTERVAL \ ++ (3 * TL_WA901ND_V2_KEYS_POLL_INTERVAL) ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition tl_wa901nd_v2_partitions[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = 0x020000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "kernel", ++ .offset = 0x020000, ++ .size = 0x140000, ++ }, { ++ .name = "rootfs", ++ .offset = 0x160000, ++ .size = 0x290000, ++ }, { ++ .name = "art", ++ .offset = 0x3f0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "firmware", ++ .offset = 0x020000, ++ .size = 0x3d0000, ++ } ++}; ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct flash_platform_data tl_wa901nd_v2_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .parts = tl_wa901nd_v2_partitions, ++ .nr_parts = ARRAY_SIZE(tl_wa901nd_v2_partitions), ++#endif ++}; ++ ++static struct gpio_led tl_wa901nd_v2_leds_gpio[] __initdata = { ++ { ++ .name = "tl-wa901nd-v2:green:system", ++ .gpio = TL_WA901ND_V2_GPIO_LED_SYSTEM, ++ .active_low = 1, ++ }, { ++ .name = "tl-wa901nd-v2:green:qss", ++ .gpio = TL_WA901ND_V2_GPIO_LED_QSS, ++ }, { ++ .name = "tl-wa901nd-v2:green:wlan", ++ .gpio = TL_WA901ND_V2_GPIO_LED_WLAN, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_keys_button tl_wa901nd_v2_gpio_keys[] __initdata = { ++ { ++ .desc = "reset", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = TL_WA901ND_V2_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = TL_WA901ND_V2_GPIO_BTN_RESET, ++ .active_low = 1, ++ }, { ++ .desc = "qss", ++ .type = EV_KEY, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = TL_WA901ND_V2_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = TL_WA901ND_V2_GPIO_BTN_QSS, ++ .active_low = 1, ++ } ++}; ++ ++static void __init tl_wa901nd_v2_setup(void) ++{ ++ u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00); ++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); ++ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; ++ ar71xx_eth0_data.phy_mask = 0x00001000; ++ ar71xx_add_device_mdio(0x0); ++ ++ ar71xx_eth0_data.reset_bit = RESET_MODULE_GE0_MAC | ++ RESET_MODULE_GE0_PHY; ++ ar71xx_add_device_eth(0); ++ ++ ar71xx_add_device_m25p80(&tl_wa901nd_v2_flash_data); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wa901nd_v2_leds_gpio), ++ tl_wa901nd_v2_leds_gpio); ++ ++ ar71xx_register_gpio_keys_polled(-1, TL_WA901ND_V2_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(tl_wa901nd_v2_gpio_keys), ++ tl_wa901nd_v2_gpio_keys); ++ ++ ar9xxx_add_device_wmac(eeprom, mac); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_TL_WA901ND_V2, "TL-WA901ND-v2", ++ "TP-LINK TL-WA901ND v2", tl_wa901nd_v2_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wa901nd.c linux-2.6.39/arch/mips/ar71xx/mach-tl-wa901nd.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wa901nd.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wa901nd.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,130 @@ ++/* ++ * TP-LINK TL-WA901ND board support ++ * ++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2010 Pieter Hollants <pieter@hollants.com> ++ * ++ * 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/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-m25p80.h" ++#include "dev-ap91-pci.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++ ++#define TL_WA901ND_GPIO_LED_QSS 0 ++#define TL_WA901ND_GPIO_LED_SYSTEM 1 ++ ++#define TL_WA901ND_GPIO_BTN_RESET 11 ++#define TL_WA901ND_GPIO_BTN_QSS 12 ++ ++#define TL_WA901ND_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define TL_WA901ND_KEYS_DEBOUNCE_INTERVAL (3 * TL_WA901ND_KEYS_POLL_INTERVAL) ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition tl_wa901nd_partitions[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = 0x020000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "kernel", ++ .offset = 0x020000, ++ .size = 0x140000, ++ }, { ++ .name = "rootfs", ++ .offset = 0x160000, ++ .size = 0x290000, ++ }, { ++ .name = "art", ++ .offset = 0x3f0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "firmware", ++ .offset = 0x020000, ++ .size = 0x3d0000, ++ } ++}; ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct flash_platform_data tl_wa901nd_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .parts = tl_wa901nd_partitions, ++ .nr_parts = ARRAY_SIZE(tl_wa901nd_partitions), ++#endif ++}; ++ ++static struct gpio_led tl_wa901nd_leds_gpio[] __initdata = { ++ { ++ .name = "tl-wa901nd:green:system", ++ .gpio = TL_WA901ND_GPIO_LED_SYSTEM, ++ .active_low = 1, ++ }, { ++ .name = "tl-wa901nd:green:qss", ++ .gpio = TL_WA901ND_GPIO_LED_QSS, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_keys_button tl_wa901nd_gpio_keys[] __initdata = { ++ { ++ .desc = "reset", ++ .type = EV_KEY, ++ .code = BTN_0, ++ .debounce_interval = TL_WA901ND_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = TL_WA901ND_GPIO_BTN_RESET, ++ .active_low = 1, ++ }, { ++ .desc = "qss", ++ .type = EV_KEY, ++ .code = BTN_1, ++ .debounce_interval = TL_WA901ND_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = TL_WA901ND_GPIO_BTN_QSS, ++ .active_low = 1, ++ } ++}; ++ ++static void __init tl_wa901nd_setup(void) ++{ ++ u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00); ++ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000); ++ ++ /* ++ * ar71xx_eth0 would be the WAN port, but is not connected on ++ * the TL-WA901ND. ar71xx_eth1 connects to the internal switch chip, ++ * however we have a single LAN port only. ++ */ ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 0); ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.speed = SPEED_1000; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ar71xx_eth1_data.has_ar7240_switch = 1; ++ ++ ar71xx_add_device_mdio(0x0); ++ ar71xx_add_device_eth(1); ++ ++ ar71xx_add_device_m25p80(&tl_wa901nd_flash_data); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wa901nd_leds_gpio), ++ tl_wa901nd_leds_gpio); ++ ++ ar71xx_register_gpio_keys_polled(-1, TL_WA901ND_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(tl_wa901nd_gpio_keys), ++ tl_wa901nd_gpio_keys); ++ ++ ap91_pci_init(ee, mac); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_TL_WA901ND, "TL-WA901ND", "TP-LINK TL-WA901ND", ++ tl_wa901nd_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.39/arch/mips/ar71xx/mach-tl-wr1043nd.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wr1043nd.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wr1043nd.c 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,156 @@ +/* + * TP-LINK TL-WR1043ND board support @@ -5477,13 +7545,13 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.39/arc +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> -+#include <linux/rtl8366rb.h> ++#include <linux/rtl8366.h> +#include <asm/mach-ar71xx/ar71xx.h> + +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-usb.h" @@ -5499,7 +7567,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.39/arc +#define TL_WR1043ND_GPIO_RTL8366_SDA 18 +#define TL_WR1043ND_GPIO_RTL8366_SCK 19 + -+#define TL_WR1043ND_BUTTONS_POLL_INTERVAL 20 ++#define TL_WR1043ND_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define TL_WR1043ND_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR1043ND_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition tl_wr1043nd_partitions[] = { @@ -5508,20 +7577,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.39/arc + .offset = 0, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x020000, + .size = 0x140000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x160000, + .size = 0x690000, -+ } , { ++ }, { + .name = "art", + .offset = 0x7f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x020000, + .size = 0x7d0000, @@ -5556,25 +7625,25 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.39/arc + } +}; + -+static struct gpio_button tl_wr1043nd_gpio_buttons[] __initdata = { ++static struct gpio_keys_button tl_wr1043nd_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = TL_WR1043ND_KEYS_DEBOUNCE_INTERVAL, + .gpio = TL_WR1043ND_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "qss", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = TL_WR1043ND_KEYS_DEBOUNCE_INTERVAL, + .gpio = TL_WR1043ND_GPIO_BTN_QSS, + .active_low = 1, + } +}; + -+static struct rtl8366rb_platform_data tl_wr1043nd_rtl8366rb_data = { ++static struct rtl8366_platform_data tl_wr1043nd_rtl8366rb_data = { + .gpio_sda = TL_WR1043ND_GPIO_RTL8366_SDA, + .gpio_sck = TL_WR1043ND_GPIO_RTL8366_SCK, +}; @@ -5592,8 +7661,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.39/arc + u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00); + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(mac); -+ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); + ar71xx_eth0_data.mii_bus_dev = &tl_wr1043nd_rtl8366rb_device.dev; + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.speed = SPEED_1000; @@ -5611,19 +7679,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.39/arc + + platform_device_register(&tl_wr1043nd_rtl8366rb_device); + -+ ar71xx_add_device_gpio_buttons(-1, TL_WR1043ND_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(tl_wr1043nd_gpio_buttons), -+ tl_wr1043nd_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, TL_WR1043ND_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(tl_wr1043nd_gpio_keys), ++ tl_wr1043nd_gpio_keys); + -+ ar913x_add_device_wmac(eeprom, mac); ++ ar9xxx_add_device_wmac(eeprom, mac); +} + +MIPS_MACHINE(AR71XX_MACH_TL_WR1043ND, "TL-WR1043ND", "TP-LINK TL-WR1043ND", + tl_wr1043nd_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.39/arch/mips/ar71xx/mach-tl-wr741nd.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr741nd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wr741nd.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,115 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wr741nd.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,135 @@ +/* + * TP-LINK TL-WR741ND board support + * @@ -5642,7 +7710,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.39/arch +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ap91-eth.h" +#include "dev-ap91-pci.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" @@ -5653,7 +7720,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.39/arch +#define TL_WR741ND_GPIO_BTN_RESET 11 +#define TL_WR741ND_GPIO_BTN_QSS 12 + -+#define TL_WR741ND_BUTTONS_POLL_INTERVAL 20 ++#define TL_WR741ND_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define TL_WR741ND_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR741ND_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition tl_wr741nd_partitions[] = { @@ -5662,20 +7730,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.39/arch + .offset = 0, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x020000, + .size = 0x140000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x160000, + .size = 0x290000, -+ } , { ++ }, { + .name = "art", + .offset = 0x3f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x020000, + .size = 0x3d0000, @@ -5685,8 +7753,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.39/arch + +static struct flash_platform_data tl_wr741nd_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = tl_wr741nd_partitions, -+ .nr_parts = ARRAY_SIZE(tl_wr741nd_partitions), ++ .parts = tl_wr741nd_partitions, ++ .nr_parts = ARRAY_SIZE(tl_wr741nd_partitions), +#endif +}; + @@ -5702,19 +7770,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.39/arch + } +}; + -+static struct gpio_button tl_wr741nd_gpio_buttons[] __initdata = { ++static struct gpio_keys_button tl_wr741nd_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = TL_WR741ND_KEYS_DEBOUNCE_INTERVAL, + .gpio = TL_WR741ND_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "qss", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = TL_WR741ND_KEYS_DEBOUNCE_INTERVAL, + .gpio = TL_WR741ND_GPIO_BTN_QSS, + .active_low = 1, + } @@ -5730,19 +7798,39 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.39/arch + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr741nd_leds_gpio), + tl_wr741nd_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, TL_WR741ND_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(tl_wr741nd_gpio_buttons), -+ tl_wr741nd_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, TL_WR741ND_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(tl_wr741nd_gpio_keys), ++ tl_wr741nd_gpio_keys); ++ ++ ar71xx_eth1_data.has_ar7240_switch = 1; ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); ++ ++ /* WAN port */ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth0_data.speed = SPEED_100; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = BIT(4); ++ ++ /* LAN ports */ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.speed = SPEED_1000; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ++ ar71xx_add_device_mdio(0x0); ++ ar71xx_add_device_eth(1); ++ ar71xx_add_device_eth(0); ++ ++ ap91_pci_setup_wmac_led_pin(1); + -+ ap91_eth_init(mac, NULL); + ap91_pci_init(ee, mac); +} +MIPS_MACHINE(AR71XX_MACH_TL_WR741ND, "TL-WR741ND", "TP-LINK TL-WR741ND", + tl_wr741nd_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.39/arch/mips/ar71xx/mach-tl-wr841n.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wr841n.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,143 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wr841n.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,144 @@ +/* + * TP-LINK TL-WR841N board support + * @@ -5773,7 +7861,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.39/arch/ +#define TL_WR841ND_V1_GPIO_BTN_RESET 3 +#define TL_WR841ND_V1_GPIO_BTN_QSS 7 + -+#define TL_WR841ND_V1_BUTTONS_POLL_INTERVAL 20 ++#define TL_WR841ND_V1_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define TL_WR841ND_V1_KEYS_DEBOUNCE_INTERVAL \ ++ (3 * TL_WR841ND_V1_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition tl_wr841n_v1_partitions[] = { @@ -5782,20 +7872,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.39/arch/ + .offset = 0, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x020000, + .size = 0x140000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x160000, + .size = 0x280000, -+ } , { ++ }, { + .name = "config", + .offset = 0x3e0000, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x020000, + .size = 0x3c0000, @@ -5805,8 +7895,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.39/arch/ + +static struct flash_platform_data tl_wr841n_v1_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = tl_wr841n_v1_partitions, -+ .nr_parts = ARRAY_SIZE(tl_wr841n_v1_partitions), ++ .parts = tl_wr841n_v1_partitions, ++ .nr_parts = ARRAY_SIZE(tl_wr841n_v1_partitions), +#endif +}; + @@ -5824,19 +7914,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.39/arch/ + } +}; + -+static struct gpio_button tl_wr841n_v1_gpio_buttons[] __initdata = { ++static struct gpio_keys_button tl_wr841n_v1_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = TL_WR841ND_V1_KEYS_DEBOUNCE_INTERVAL, + .gpio = TL_WR841ND_V1_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "qss", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = TL_WR841ND_V1_KEYS_DEBOUNCE_INTERVAL, + .gpio = TL_WR841ND_V1_GPIO_BTN_QSS, + .active_low = 1, + } @@ -5860,10 +7950,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.39/arch/ +{ + u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00); + -+ ar71xx_set_mac_base(mac); -+ + ar71xx_add_device_mdio(0x0); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; @@ -5877,9 +7966,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.39/arch/ + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v1_leds_gpio), + tl_wr841n_v1_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, TL_WR841ND_V1_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(tl_wr841n_v1_gpio_buttons), -+ tl_wr841n_v1_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, TL_WR841ND_V1_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(tl_wr841n_v1_gpio_keys), ++ tl_wr841n_v1_gpio_keys); + + pb42_pci_init(); +} @@ -5888,8 +7977,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.39/arch/ + tl_wr841n_v1_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.39/arch/mips/ar71xx/mach-tl-wr941nd.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr941nd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wr941nd.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,142 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-tl-wr941nd.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,147 @@ +/* + * TP-LINK TL-WR941ND board support + * @@ -5909,18 +7998,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.39/arch +#include "devices.h" +#include "dev-dsa.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" + +#define TL_WR941ND_GPIO_LED_SYSTEM 2 +#define TL_WR941ND_GPIO_LED_QSS_RED 4 +#define TL_WR941ND_GPIO_LED_QSS_GREEN 5 ++#define TL_WR941ND_GPIO_LED_WLAN 9 + +#define TL_WR941ND_GPIO_BTN_RESET 3 +#define TL_WR941ND_GPIO_BTN_QSS 7 + -+#define TL_WR941ND_BUTTONS_POLL_INTERVAL 20 ++#define TL_WR941ND_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define TL_WR941ND_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR941ND_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition tl_wr941nd_partitions[] = { @@ -5929,20 +8020,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.39/arch + .offset = 0, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x020000, + .size = 0x140000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x160000, + .size = 0x290000, -+ } , { ++ }, { + .name = "art", + .offset = 0x3f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x020000, + .size = 0x3d0000, @@ -5952,8 +8043,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.39/arch + +static struct flash_platform_data tl_wr941nd_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = tl_wr941nd_partitions, -+ .nr_parts = ARRAY_SIZE(tl_wr941nd_partitions), ++ .parts = tl_wr941nd_partitions, ++ .nr_parts = ARRAY_SIZE(tl_wr941nd_partitions), +#endif +}; + @@ -5968,22 +8059,26 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.39/arch + }, { + .name = "tl-wr941nd:green:qss", + .gpio = TL_WR941ND_GPIO_LED_QSS_GREEN, ++ }, { ++ .name = "tl-wr941nd:green:wlan", ++ .gpio = TL_WR941ND_GPIO_LED_WLAN, ++ .active_low = 1, + } +}; + -+static struct gpio_button tl_wr941nd_gpio_buttons[] __initdata = { ++static struct gpio_keys_button tl_wr941nd_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = TL_WR941ND_KEYS_DEBOUNCE_INTERVAL, + .gpio = TL_WR941ND_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "qss", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = TL_WR941ND_KEYS_DEBOUNCE_INTERVAL, + .gpio = TL_WR941ND_GPIO_BTN_QSS, + .active_low = 1, + } @@ -6008,10 +8103,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.39/arch + u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00); + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(mac); -+ + ar71xx_add_device_mdio(0x0); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; @@ -6024,18 +8118,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.39/arch + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr941nd_leds_gpio), + tl_wr941nd_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, TL_WR941ND_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(tl_wr941nd_gpio_buttons), -+ tl_wr941nd_gpio_buttons); -+ ar913x_add_device_wmac(eeprom, mac); ++ ar71xx_register_gpio_keys_polled(-1, TL_WR941ND_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(tl_wr941nd_gpio_keys), ++ tl_wr941nd_gpio_keys); ++ ar9xxx_add_device_wmac(eeprom, mac); +} + +MIPS_MACHINE(AR71XX_MACH_TL_WR941ND, "TL-WR941ND", "TP-LINK TL-WR941ND", + tl_wr941nd_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ar71xx/mach-ubnt.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-ubnt.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,281 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-ubnt.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,333 @@ +/* + * Ubiquiti RouterStation support + * @@ -6076,7 +8170,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ +#define UBNT_M_GPIO_LED_L4 7 +#define UBNT_M_GPIO_BTN_RESET 12 + -+#define UBNT_BUTTONS_POLL_INTERVAL 20 ++#define UBNT_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define UBNT_KEYS_DEBOUNCE_INTERVAL (3 * UBNT_KEYS_POLL_INTERVAL) + +static struct gpio_led ubnt_rs_leds_gpio[] __initdata = { + { @@ -6138,23 +8233,23 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ + } +}; + -+static struct gpio_button ubnt_gpio_buttons[] __initdata = { ++static struct gpio_keys_button ubnt_gpio_keys[] __initdata = { + { + .desc = "sw4", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = UBNT_KEYS_DEBOUNCE_INTERVAL, + .gpio = UBNT_RS_GPIO_SW4, + .active_low = 1, + } +}; + -+static struct gpio_button ubnt_m_gpio_buttons[] __initdata = { ++static struct gpio_keys_button ubnt_m_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = UBNT_KEYS_DEBOUNCE_INTERVAL, + .gpio = UBNT_M_GPIO_BTN_RESET, + .active_low = 1, + } @@ -6164,15 +8259,26 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ +{ + ar71xx_add_device_m25p80(NULL); + -+ ar71xx_add_device_gpio_buttons(-1, UBNT_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(ubnt_gpio_buttons), -+ ubnt_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, UBNT_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(ubnt_gpio_keys), ++ ubnt_gpio_keys); + + pb42_pci_init(); +} + -+#define UBNT_RS_WAN_PHYMASK (1 << 20) -+#define UBNT_RS_LAN_PHYMASK ((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19)) ++/* ++ * There is Secondary MAC address duplicate problem with some UBNT HW batches. ++ * Do not increase Secondary MAC address by 1 but do workaround ++ * with 'Locally Administrated' bit. ++ */ ++static void __init ubnt_init_secondary_mac(unsigned char *mac_base) ++{ ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac_base, 0); ++ ar71xx_eth1_data.mac_addr[0] |= 0x02; ++} ++ ++#define UBNT_RS_WAN_PHYMASK BIT(20) ++#define UBNT_RS_LAN_PHYMASK (BIT(16) | BIT(17) | BIT(18) | BIT(19)) + +static void __init ubnt_rs_setup(void) +{ @@ -6180,9 +8286,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ + + ar71xx_add_device_mdio(~(UBNT_RS_WAN_PHYMASK | UBNT_RS_LAN_PHYMASK)); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; + ar71xx_eth0_data.phy_mask = UBNT_RS_WAN_PHYMASK; + ++ ubnt_init_secondary_mac(ar71xx_mac_base); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.speed = SPEED_100; + ar71xx_eth1_data.duplex = DUPLEX_FULL; @@ -6199,21 +8307,21 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ +MIPS_MACHINE(AR71XX_MACH_UBNT_RS, "UBNT-RS", "Ubiquiti RouterStation", + ubnt_rs_setup); + -+MIPS_MACHINE(AR71XX_MACH_UBNT_AR71XX, "Ubiquiti AR71xx-based board", -+ "Ubiquiti RouterStation", ubnt_rs_setup); -+ -+#define UBNT_RSPRO_WAN_PHYMASK (1 << 4) -+#define UBNT_RSPRO_LAN_PHYMASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) ++#define UBNT_RSPRO_WAN_PHYMASK BIT(4) ++#define UBNT_RSPRO_LAN_PHYMASK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +static void __init ubnt_rspro_setup(void) +{ + ubnt_generic_setup(); + -+ ar71xx_add_device_mdio(~(UBNT_RSPRO_WAN_PHYMASK | UBNT_RSPRO_LAN_PHYMASK)); ++ ar71xx_add_device_mdio(~(UBNT_RSPRO_WAN_PHYMASK | ++ UBNT_RSPRO_LAN_PHYMASK)); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.phy_mask = UBNT_RSPRO_WAN_PHYMASK; + ++ ubnt_init_secondary_mac(ar71xx_mac_base); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth1_data.phy_mask = UBNT_RSPRO_LAN_PHYMASK; + ar71xx_eth1_data.speed = SPEED_1000; @@ -6238,7 +8346,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ + +MIPS_MACHINE(AR71XX_MACH_UBNT_LSX, "UBNT-LSX", "Ubiquiti LSX", ubnt_lsx_setup); + -+#define UBNT_LSSR71_PHY_MASK (1 << 1) ++#define UBNT_LSSR71_PHY_MASK BIT(1) + +static void __init ubnt_lssr71_setup(void) +{ @@ -6246,6 +8354,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ + + ar71xx_add_device_mdio(~UBNT_LSSR71_PHY_MASK); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; + ar71xx_eth0_data.phy_mask = UBNT_LSSR71_PHY_MASK; + @@ -6258,23 +8367,24 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ +MIPS_MACHINE(AR71XX_MACH_UBNT_LSSR71, "UBNT-LS-SR71", "Ubiquiti LS-SR71", + ubnt_lssr71_setup); + ++#define UBNT_M_WAN_PHYMASK BIT(4) ++ +static void __init ubnt_m_setup(void) +{ -+ u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000); ++ u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000); ++ u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN); + u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(mac); -+ + ar71xx_add_device_m25p80(NULL); + -+ ar71xx_add_device_mdio(~0); ++ ar71xx_add_device_mdio(~UBNT_M_WAN_PHYMASK); + -+ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac1, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac2, 0); ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; -+ ar71xx_eth0_data.fifo_cfg1 = 0x0010ffff; -+ ar71xx_eth0_data.fifo_cfg2 = 0x015500aa; -+ ar71xx_eth0_data.fifo_cfg3 = 0x01f00140; ++ ar71xx_eth0_data.phy_mask = UBNT_M_WAN_PHYMASK; + + ar71xx_add_device_eth(0); + @@ -6283,9 +8393,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_m_leds_gpio), + ubnt_m_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, UBNT_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(ubnt_m_gpio_buttons), -+ ubnt_m_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, UBNT_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(ubnt_m_gpio_keys), ++ ubnt_m_gpio_keys); +} + +static void __init ubnt_rocket_m_setup(void) @@ -6305,22 +8415,58 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.39/arch/mips/ +{ + ubnt_m_setup(); + ++ ar71xx_eth1_data.has_ar7240_switch = 1; + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.speed = SPEED_1000; + ar71xx_eth1_data.duplex = DUPLEX_FULL; -+ ar71xx_eth1_data.fifo_cfg1 = 0x0010ffff; -+ ar71xx_eth1_data.fifo_cfg2 = 0x015500aa; -+ ar71xx_eth1_data.fifo_cfg3 = 0x01f00140; + + ar71xx_add_device_eth(1); +} + +MIPS_MACHINE(AR71XX_MACH_UBNT_NANO_M, "UBNT-NM", "Ubiquiti Nanostation M", + ubnt_nano_m_setup); ++ ++static struct gpio_led ubnt_unifi_leds_gpio[] __initdata = { ++ { ++ .name = "ubnt:orange:dome", ++ .gpio = 1, ++ .active_low = 0, ++ }, { ++ .name = "ubnt:green:dome", ++ .gpio = 0, ++ .active_low = 0, ++ } ++}; ++ ++static void __init ubnt_unifi_setup(void) ++{ ++ u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000); ++ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000); ++ ++ ar71xx_add_device_m25p80(NULL); ++ ++ ar71xx_add_device_mdio(~UBNT_M_WAN_PHYMASK); ++ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth0_data.speed = SPEED_100; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = UBNT_M_WAN_PHYMASK; ++ ++ ar71xx_add_device_eth(0); ++ ++ ap91_pci_init(ee, NULL); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_leds_gpio), ++ ubnt_unifi_leds_gpio); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_UBNT_UNIFI, "UBNT-XM", "Ubiquiti UniFi", ++ ubnt_unifi_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.39/arch/mips/ar71xx/mach-wndr3700.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-wndr3700.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-wndr3700.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,209 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-wndr3700.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,290 @@ +/* + * Netgear WNDR3700 board support + * @@ -6336,7 +8482,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.39/arch/m +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/delay.h> -+#include <linux/rtl8366s.h> ++#include <linux/rtl8366.h> + +#include <asm/mach-ar71xx/ar71xx.h> + @@ -6361,7 +8507,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.39/arch/m +#define WNDR3700_GPIO_RTL8366_SDA 5 +#define WNDR3700_GPIO_RTL8366_SCK 7 + -+#define WNDR3700_BUTTONS_POLL_INTERVAL 20 ++#define WNDR3700_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define WNDR3700_KEYS_DEBOUNCE_INTERVAL (3 * WNDR3700_KEYS_POLL_INTERVAL) ++ ++#define WNDR3700_ETH0_MAC_OFFSET 0 ++#define WNDR3700_ETH1_MAC_OFFSET 0x6 + +#define WNDR3700_WMAC0_MAC_OFFSET 0 +#define WNDR3700_WMAC1_MAC_OFFSET 0xc @@ -6375,55 +8525,105 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.39/arch/m + .offset = 0, + .size = 0x050000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "env", + .offset = 0x050000, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x070000, + .size = 0x720000, -+ } , { ++ }, { + .name = "config", + .offset = 0x790000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "config_bak", + .offset = 0x7a0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "pot", + .offset = 0x7b0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "traffic_meter", + .offset = 0x7c0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "language", + .offset = 0x7d0000, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "caldata", + .offset = 0x7f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, + } +}; -+#endif /* CONFIG_MTD_PARTITIONS */ + -+static struct flash_platform_data wndr3700_flash_data = { -+#ifdef CONFIG_MTD_PARTITIONS -+ .parts = wndr3700_partitions, -+ .nr_parts = ARRAY_SIZE(wndr3700_partitions), -+#endif ++static struct mtd_partition wndr3700v2_partitions[] = { ++ { ++ .name = "uboot", ++ .offset = 0, ++ .size = 0x050000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "env", ++ .offset = 0x050000, ++ .size = 0x020000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "rootfs", ++ .offset = 0x070000, ++ .size = 0xe40000, ++ }, { ++ .name = "config", ++ .offset = 0xeb0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "config_bak", ++ .offset = 0xec0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "pot", ++ .offset = 0xed0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "traffic_meter", ++ .offset = 0xee0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "language", ++ .offset = 0xef0000, ++ .size = 0x100000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "caldata", ++ .offset = 0xff0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ } +}; ++#define wndr3700_num_partitions ARRAY_SIZE(wndr3700_partitions) ++#define wndr3700v2_num_partitions ARRAY_SIZE(wndr3700v2_partitions) ++#else ++#define wndr3700_partitions NULL ++#define wndr3700_num_partitions 0 ++#define wndr3700v2_partitions NULL ++#define wndr3700v2_num_partitions 0 ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct flash_platform_data wndr3700_flash_data; + +static struct gpio_led wndr3700_leds_gpio[] __initdata = { + { @@ -6449,34 +8649,34 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.39/arch/m + } +}; + -+static struct gpio_button wndr3700_gpio_buttons[] __initdata = { ++static struct gpio_keys_button wndr3700_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = WNDR3700_KEYS_DEBOUNCE_INTERVAL, + .gpio = WNDR3700_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = WNDR3700_KEYS_DEBOUNCE_INTERVAL, + .gpio = WNDR3700_GPIO_BTN_WPS, + .active_low = 1, -+ } , { ++ }, { + .desc = "wifi", + .type = EV_KEY, + .code = BTN_2, -+ .threshold = 3, ++ .debounce_interval = WNDR3700_KEYS_DEBOUNCE_INTERVAL, + .gpio = WNDR3700_GPIO_BTN_WIFI, + .active_low = 1, + } +}; + -+static struct rtl8366s_platform_data wndr3700_rtl8366s_data = { -+ .gpio_sda = WNDR3700_GPIO_RTL8366_SDA, -+ .gpio_sck = WNDR3700_GPIO_RTL8366_SCK, ++static struct rtl8366_platform_data wndr3700_rtl8366s_data = { ++ .gpio_sda = WNDR3700_GPIO_RTL8366_SDA, ++ .gpio_sck = WNDR3700_GPIO_RTL8366_SCK, +}; + +static struct platform_device wndr3700_rtl8366s_device = { @@ -6487,18 +8687,20 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.39/arch/m + } +}; + -+static void __init wndr3700_setup(void) ++static void __init wndr3700_common_setup(void) +{ + u8 *art = (u8 *) KSEG1ADDR(0x1fff0000); + -+ ar71xx_set_mac_base(art); -+ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ++ art + WNDR3700_ETH0_MAC_OFFSET, 0); + ar71xx_eth0_pll_data.pll_1000 = 0x11110000; + ar71xx_eth0_data.mii_bus_dev = &wndr3700_rtl8366s_device.dev; + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.speed = SPEED_1000; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, ++ art + WNDR3700_ETH1_MAC_OFFSET, 0); + ar71xx_eth1_pll_data.pll_1000 = 0x11110000; + ar71xx_eth1_data.mii_bus_dev = &wndr3700_rtl8366s_device.dev; + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; @@ -6511,29 +8713,54 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.39/arch/m + + ar71xx_add_device_m25p80(&wndr3700_flash_data); + -+ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wndr3700_leds_gpio), -+ wndr3700_leds_gpio); ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wndr3700_leds_gpio), ++ wndr3700_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, WNDR3700_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(wndr3700_gpio_buttons), -+ wndr3700_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, WNDR3700_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(wndr3700_gpio_keys), ++ wndr3700_gpio_keys); + + platform_device_register(&wndr3700_rtl8366s_device); + platform_device_register_simple("wndr3700-led-usb", -1, NULL, 0); + -+ ap94_pci_enable_quirk_wndr3700(); ++ ap94_pci_setup_wmac_led_pin(0, 5); ++ ap94_pci_setup_wmac_led_pin(1, 5); ++ ++ /* 2.4 GHz uses the first fixed antenna group (1, 0, 1, 0) */ ++ ap94_pci_setup_wmac_gpio(0, (0xf << 6), (0xa << 6)); ++ ++ /* 5 GHz uses the second fixed antenna group (0, 1, 1, 0) */ ++ ap94_pci_setup_wmac_gpio(1, (0xf << 6), (0x6 << 6)); ++ + ap94_pci_init(art + WNDR3700_CALDATA0_OFFSET, + art + WNDR3700_WMAC0_MAC_OFFSET, + art + WNDR3700_CALDATA1_OFFSET, + art + WNDR3700_WMAC1_MAC_OFFSET); +} + ++static void __init wndr3700_setup(void) ++{ ++ wndr3700_flash_data.parts = wndr3700_partitions, ++ wndr3700_flash_data.nr_parts = wndr3700_num_partitions, ++ wndr3700_common_setup(); ++} ++ +MIPS_MACHINE(AR71XX_MACH_WNDR3700, "WNDR3700", "NETGEAR WNDR3700", + wndr3700_setup); ++ ++static void __init wndr3700v2_setup(void) ++{ ++ wndr3700_flash_data.parts = wndr3700v2_partitions, ++ wndr3700_flash_data.nr_parts = wndr3700v2_num_partitions, ++ wndr3700_common_setup(); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_WNDR3700V2, "WNDR3700v2", "NETGEAR WNDR3700v2", ++ wndr3700v2_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.39/arch/mips/ar71xx/mach-wnr2000.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-wnr2000.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,148 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-wnr2000.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,150 @@ +/* + * NETGEAR WNR2000 board support + * @@ -6554,7 +8781,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.39/arch/mi +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" + @@ -6565,7 +8792,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.39/arch/mi +#define WNR2000_GPIO_BTN_RESET 21 +#define WNR2000_GPIO_BTN_WPS 8 + -+#define WNR2000_BUTTONS_POLL_INTERVAL 20 ++#define WNR2000_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define WNR2000_KEYS_DEBOUNCE_INTERVAL (3 * WNR2000_KEYS_POLL_INTERVAL) + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition wnr2000_partitions[] = { @@ -6574,31 +8802,31 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.39/arch/mi + .offset = 0, + .size = 0x040000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "u-boot-env", + .offset = 0x040000, + .size = 0x010000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x050000, + .size = 0x240000, -+ } , { ++ }, { + .name = "user-config", + .offset = 0x290000, + .size = 0x010000, -+ } , { ++ }, { + .name = "uImage", + .offset = 0x2a0000, + .size = 0x120000, -+ } , { ++ }, { + .name = "language_table", + .offset = 0x3c0000, + .size = 0x020000, -+ } , { ++ }, { + .name = "rootfs_checksum", + .offset = 0x3e0000, + .size = 0x010000, -+ } , { ++ }, { + .name = "art", + .offset = 0x3f0000, + .size = 0x010000, @@ -6609,8 +8837,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.39/arch/mi + +static struct flash_platform_data wnr2000_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = wnr2000_partitions, -+ .nr_parts = ARRAY_SIZE(wnr2000_partitions), ++ .parts = wnr2000_partitions, ++ .nr_parts = ARRAY_SIZE(wnr2000_partitions), +#endif +}; + @@ -6634,18 +8862,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.39/arch/mi + } +}; + -+static struct gpio_button wnr2000_gpio_buttons[] __initdata = { ++static struct gpio_keys_button wnr2000_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = WNR2000_KEYS_DEBOUNCE_INTERVAL, + .gpio = WNR2000_GPIO_BTN_RESET, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = WNR2000_KEYS_DEBOUNCE_INTERVAL, + .gpio = WNR2000_GPIO_BTN_WPS, + } +}; @@ -6654,14 +8882,15 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.39/arch/mi +{ + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); + -+ ar71xx_set_mac_base(eeprom); + ar71xx_add_device_mdio(0x0); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, eeprom, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ar71xx_eth0_data.has_ar8216 = 1; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, eeprom, 1); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.phy_mask = 0x10; + @@ -6673,19 +8902,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.39/arch/mi + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wnr2000_leds_gpio), + wnr2000_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, WNR2000_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(wnr2000_gpio_buttons), -+ wnr2000_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, WNR2000_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(wnr2000_gpio_keys), ++ wnr2000_gpio_keys); + + -+ ar913x_add_device_wmac(eeprom, NULL); ++ ar9xxx_add_device_wmac(eeprom, NULL); +} + +MIPS_MACHINE(AR71XX_MACH_WNR2000, "WNR2000", "NETGEAR WNR2000", wnr2000_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wp543.c linux-2.6.39/arch/mips/ar71xx/mach-wp543.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-wp543.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-wp543.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,99 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-wp543.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,101 @@ +/* + * Compex WP543/WPJ543 board support + * @@ -6718,7 +8947,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wp543.c linux-2.6.39/arch/mips +#define WP543_GPIO_LED_DIAG 7 +#define WP543_GPIO_SW4 8 + -+#define WP543_BUTTONS_POLL_INTERVAL 20 ++#define WP543_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define WP543_KEYS_DEBOUNCE_INTERVAL (3 * WP543_KEYS_POLL_INTERVAL) + +static struct gpio_led wp543_leds_gpio[] __initdata = { + { @@ -6744,18 +8974,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wp543.c linux-2.6.39/arch/mips + } +}; + -+static struct gpio_button wp543_gpio_buttons[] __initdata = { ++static struct gpio_keys_button wp543_gpio_keys[] __initdata = { + { + .desc = "sw6", + .type = EV_KEY, + .code = BTN_0, -+ .threshold = 3, ++ .debounce_interval = WP543_KEYS_DEBOUNCE_INTERVAL, + .gpio = WP543_GPIO_SW6, + }, { + .desc = "sw4", + .type = EV_KEY, + .code = BTN_1, -+ .threshold = 3, ++ .debounce_interval = WP543_KEYS_DEBOUNCE_INTERVAL, + .gpio = WP543_GPIO_SW4, + } +}; @@ -6766,6 +8996,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wp543.c linux-2.6.39/arch/mips + + ar71xx_add_device_mdio(0xfffffff7); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 0); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; + ar71xx_eth0_data.phy_mask = 0x08; + ar71xx_eth0_data.reset_bit = RESET_MODULE_GE0_MAC | @@ -6779,16 +9010,16 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wp543.c linux-2.6.39/arch/mips + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wp543_leds_gpio), + wp543_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, WP543_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(wp543_gpio_buttons), -+ wp543_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, WP543_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(wp543_gpio_keys), ++ wp543_gpio_keys); +} + +MIPS_MACHINE(AR71XX_MACH_WP543, "WP543", "Compex WP543", wp543_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/mips/ar71xx/mach-wrt160nl.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-wrt160nl.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,158 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-wrt160nl.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,161 @@ +/* + * Linksys WRT160NL board support + * @@ -6807,7 +9038,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/m +#include "machtype.h" +#include "devices.h" +#include "dev-m25p80.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-usb.h" @@ -6821,7 +9052,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/m +#define WRT160NL_GPIO_BTN_WPS 7 +#define WRT160NL_GPIO_BTN_RESET 21 + -+#define WRT160NL_BUTTONS_POLL_INTERVAL 20 ++#define WRT160NL_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define WRT160NL_KEYS_DEBOUNCE_INTERVAL (3 * WRT160NL_KEYS_POLL_INTERVAL) + +#define WRT160NL_NVRAM_ADDR 0x1f7e0000 +#define WRT160NL_NVRAM_SIZE 0x10000 @@ -6833,25 +9065,25 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/m + .offset = 0, + .size = 0x040000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "kernel", + .offset = 0x040000, + .size = 0x0e0000, -+ } , { ++ }, { + .name = "filesytem", + .offset = 0x120000, + .size = 0x6c0000, -+ } , { ++ }, { + .name = "nvram", + .offset = 0x7e0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "ART", + .offset = 0x7f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x040000, + .size = 0x7a0000, @@ -6861,8 +9093,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/m + +static struct flash_platform_data wrt160nl_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = wrt160nl_partitions, -+ .nr_parts = ARRAY_SIZE(wrt160nl_partitions), ++ .parts = wrt160nl_partitions, ++ .nr_parts = ARRAY_SIZE(wrt160nl_partitions), +#endif +}; + @@ -6887,19 +9119,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/m + } +}; + -+static struct gpio_button wrt160nl_gpio_buttons[] __initdata = { ++static struct gpio_keys_button wrt160nl_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = WRT160NL_KEYS_DEBOUNCE_INTERVAL, + .gpio = WRT160NL_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = WRT160NL_KEYS_DEBOUNCE_INTERVAL, + .gpio = WRT160NL_GPIO_BTN_WPS, + .active_low = 1, + } @@ -6912,8 +9144,10 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/m + u8 mac[6]; + + if (nvram_parse_mac_addr(nvram, WRT160NL_NVRAM_SIZE, -+ "lan_hwaddr=", mac) == 0) -+ ar71xx_set_mac_base(mac); ++ "lan_hwaddr=", mac) == 0) { ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); ++ } + + ar71xx_add_device_mdio(0x0); + @@ -6931,17 +9165,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/m + ar71xx_add_device_usb(); + + if (nvram_parse_mac_addr(nvram, WRT160NL_NVRAM_SIZE, -+ "wl0_hwaddr=", mac) == 0) -+ ar913x_add_device_wmac(eeprom, mac); ++ "wl0_hwaddr=", mac) == 0) ++ ar9xxx_add_device_wmac(eeprom, mac); + else -+ ar913x_add_device_wmac(eeprom, NULL); ++ ar9xxx_add_device_wmac(eeprom, NULL); + + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wrt160nl_leds_gpio), + wrt160nl_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, WRT160NL_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(wrt160nl_gpio_buttons), -+ wrt160nl_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, WRT160NL_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(wrt160nl_gpio_keys), ++ wrt160nl_gpio_keys); + +} + @@ -6949,8 +9183,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.39/arch/m + wrt160nl_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.39/arch/mips/ar71xx/mach-wrt400n.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt400n.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-wrt400n.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,168 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-wrt400n.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,164 @@ +/* + * Linksys WRT400N board support + * @@ -6982,7 +9216,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.39/arch/mi +#define WRT400N_GPIO_BTN_RESET 8 +#define WRT400N_GPIO_BTN_WLSEC 3 + -+#define WRT400N_BUTTONS_POLL_INTERVAL 20 ++#define WRT400N_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define WRT400N_KEYS_DEBOUNE_INTERVAL (3 * WRT400N_KEYS_POLL_INTERVAL) + +#define WRT400N_MAC_ADDR_OFFSET 0x120c +#define WRT400N_CALDATA0_OFFSET 0x1000 @@ -6995,40 +9230,40 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.39/arch/mi + .offset = 0, + .size = 0x030000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "env", + .offset = 0x030000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "linux", + .offset = 0x040000, + .size = 0x140000, -+ } , { ++ }, { + .name = "rootfs", + .offset = 0x180000, + .size = 0x630000, -+ } , { ++ }, { + .name = "nvram", + .offset = 0x7b0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "factory", + .offset = 0x7c0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "language", + .offset = 0x7d0000, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "caldata", + .offset = 0x7f0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, -+ } , { ++ }, { + .name = "firmware", + .offset = 0x040000, + .size = 0x770000, @@ -7038,8 +9273,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.39/arch/mi + +static struct flash_platform_data wrt400n_flash_data = { +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = wrt400n_partitions, -+ .nr_parts = ARRAY_SIZE(wrt400n_partitions), ++ .parts = wrt400n_partitions, ++ .nr_parts = ARRAY_SIZE(wrt400n_partitions), +#endif +}; + @@ -7063,19 +9298,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.39/arch/mi + } +}; + -+static struct gpio_button wrt400n_gpio_buttons[] __initdata = { ++static struct gpio_keys_button wrt400n_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = WRT400N_KEYS_DEBOUNE_INTERVAL, + .gpio = WRT400N_GPIO_BTN_RESET, + .active_low = 1, -+ } , { ++ }, { + .desc = "wlsec", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = WRT400N_KEYS_DEBOUNE_INTERVAL, + .gpio = WRT400N_GPIO_BTN_WLSEC, + .active_low = 1, + } @@ -7084,21 +9319,16 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.39/arch/mi +static void __init wrt400n_setup(void) +{ + u8 *art = (u8 *) KSEG1ADDR(0x1fff0000); -+ u8 mac[6]; -+ int i; -+ -+ memcpy(mac, art + WRT400N_MAC_ADDR_OFFSET, 6); -+ for (i = 5; i >= 3; i--) -+ if (++mac[i] != 0x00) break; -+ -+ ar71xx_set_mac_base(mac); ++ u8 *mac = art + WRT400N_MAC_ADDR_OFFSET; + + ar71xx_add_device_mdio(0x0); + ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 1); + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth0_data.speed = SPEED_100; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 2); + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; + ar71xx_eth1_data.phy_mask = 0x10; + @@ -7110,19 +9340,254 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.39/arch/mi + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wrt400n_leds_gpio), + wrt400n_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, WRT400N_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(wrt400n_gpio_buttons), -+ wrt400n_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, WRT400N_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(wrt400n_gpio_keys), ++ wrt400n_gpio_keys); + + ap94_pci_init(art + WRT400N_CALDATA0_OFFSET, NULL, + art + WRT400N_CALDATA1_OFFSET, NULL); +} + +MIPS_MACHINE(AR71XX_MACH_WRT400N, "WRT400N", "Linksys WRT400N", wrt400n_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-ag300h.c linux-2.6.39/arch/mips/ar71xx/mach-wzr-hp-ag300h.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-ag300h.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-wzr-hp-ag300h.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,231 @@ ++/* ++ * Buffalo WZR-HP-AG300H board support ++ * ++ * Copyright (C) 2011 Felix Fietkau <nbd@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/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/mtd/concat.h> ++ ++#include <asm/mips_machine.h> ++#include <asm/mach-ar71xx/ar71xx.h> ++#include <asm/mach-ar71xx/gpio.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-ap94-pci.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++#include "dev-m25p80.h" ++#include "dev-usb.h" ++ ++#define WZRHPAG300H_MAC_OFFSET 0x20c ++#define WZRHPAG300H_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL (3 * WZRHPAG300H_KEYS_POLL_INTERVAL) ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition wzrhpag300h_flash_partitions[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = 0x0040000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "u-boot-env", ++ .offset = 0x0040000, ++ .size = 0x0010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "art", ++ .offset = 0x0050000, ++ .size = 0x0010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "kernel", ++ .offset = 0x0060000, ++ .size = 0x0100000, ++ }, { ++ .name = "rootfs", ++ .offset = 0x0160000, ++ .size = 0x1e90000, ++ }, { ++ .name = "user_property", ++ .offset = 0x1ff0000, ++ .size = 0x0010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "firmware", ++ .offset = 0x0060000, ++ .size = 0x1f90000, ++ } ++}; ++ ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct mtd_info *concat_devs[2] = { NULL, NULL }; ++static struct work_struct mtd_concat_work; ++ ++static void mtd_concat_add_work(struct work_struct *work) ++{ ++ struct mtd_info *mtd; ++ ++ mtd = mtd_concat_create(concat_devs, ARRAY_SIZE(concat_devs), "flash"); ++ ++#ifdef CONFIG_MTD_PARTITIONS ++ add_mtd_partitions(mtd, wzrhpag300h_flash_partitions, ++ ARRAY_SIZE(wzrhpag300h_flash_partitions)); ++#else ++ add_mtd_device(mtd); ++#endif ++} ++ ++static void mtd_concat_add(struct mtd_info *mtd) ++{ ++ static bool registered = false; ++ ++ if (registered) ++ return; ++ ++ if (!strcmp(mtd->name, "spi0.0")) ++ concat_devs[0] = mtd; ++ else if (!strcmp(mtd->name, "spi0.1")) ++ concat_devs[1] = mtd; ++ else ++ return; ++ ++ if (!concat_devs[0] || !concat_devs[1]) ++ return; ++ ++ registered = true; ++ INIT_WORK(&mtd_concat_work, mtd_concat_add_work); ++ schedule_work(&mtd_concat_work); ++} ++ ++static void mtd_concat_remove(struct mtd_info *mtd) ++{ ++} ++ ++static void add_mtd_concat_notifier(void) ++{ ++ static struct mtd_notifier not = { ++ .add = mtd_concat_add, ++ .remove = mtd_concat_remove, ++ }; ++ ++ register_mtd_user(¬); ++} ++ ++static struct gpio_led wzrhpag300h_leds_gpio[] __initdata = { ++ { ++ .name = "wzr-hp-ag300h:red:diag", ++ .gpio = 1, ++ .active_low = 1, ++ }, ++}; ++ ++ ++static struct gpio_keys_button wzrhpag300h_gpio_keys[] __initdata = { ++ { ++ .desc = "reset", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = 11, ++ .active_low = 1, ++ }, { ++ .desc = "usb", ++ .type = EV_KEY, ++ .code = BTN_2, ++ .debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = 3, ++ .active_low = 1, ++ }, { ++ .desc = "aoss", ++ .type = EV_KEY, ++ .code = KEY_WPS_BUTTON, ++ .debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = 5, ++ .active_low = 1, ++ }, { ++ .desc = "router_auto", ++ .type = EV_KEY, ++ .code = BTN_6, ++ .debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = 6, ++ .active_low = 1, ++ }, { ++ .desc = "router_off", ++ .type = EV_KEY, ++ .code = BTN_5, ++ .debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = 7, ++ .active_low = 1, ++ } ++}; ++ ++static struct spi_board_info ar71xx_spi_info[] = { ++ { ++ .bus_num = 0, ++ .chip_select = 0, ++ .max_speed_hz = 25000000, ++ .modalias = "m25p80", ++ }, ++ { ++ .bus_num = 0, ++ .chip_select = 1, ++ .max_speed_hz = 25000000, ++ .modalias = "m25p80", ++ } ++}; ++ ++static void __init wzrhpag300h_setup(void) ++{ ++ u8 *eeprom1 = (u8 *) KSEG1ADDR(0x1f051000); ++ u8 *eeprom2 = (u8 *) KSEG1ADDR(0x1f055000); ++ u8 *mac1 = eeprom1 + WZRHPAG300H_MAC_OFFSET; ++ u8 *mac2 = eeprom2 + WZRHPAG300H_MAC_OFFSET; ++ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac1, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac2, 1); ++ ++ ar71xx_add_device_mdio(~(BIT(0) | BIT(4))); ++ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; ++ ar71xx_eth0_data.speed = SPEED_1000; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ar71xx_eth0_data.phy_mask = BIT(0); ++ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; ++ ar71xx_eth1_data.phy_mask = BIT(4); ++ ++ ar71xx_add_device_eth(0); ++ ar71xx_add_device_eth(1); ++ ++ ar71xx_add_device_usb(); ++ gpio_request(2, "usb"); ++ gpio_direction_output(2, 1); ++ ++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wzrhpag300h_leds_gpio), ++ wzrhpag300h_leds_gpio); ++ ++ ar71xx_register_gpio_keys_polled(-1, WZRHPAG300H_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(wzrhpag300h_gpio_keys), ++ wzrhpag300h_gpio_keys); ++ ++ ar71xx_add_device_spi(NULL, ar71xx_spi_info, ++ ARRAY_SIZE(ar71xx_spi_info)); ++ ++ add_mtd_concat_notifier(); ++ ++ ap94_pci_init(eeprom1, mac1, eeprom2, mac2); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_WZR_HP_AG300H, "WZR-HP-AG300H", ++ "Buffalo WZR-HP-AG300H", wzrhpag300h_setup); ++ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.39/arch/mips/ar71xx/mach-wzr-hp-g300nh.c --- linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/mach-wzr-hp-g300nh.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,265 @@ ++++ linux-2.6.39/arch/mips/ar71xx/mach-wzr-hp-g300nh.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,292 @@ +/* + * Buffalo WZR-HP-G300NH board support + * @@ -7137,7 +9602,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.39/a +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/nxp_74hc153.h> -+#include <linux/rtl8366s.h> ++#include <linux/rtl8366.h> + +#include <asm/mips_machine.h> +#include <asm/mach-ar71xx/ar71xx.h> @@ -7145,7 +9610,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.39/a + +#include "machtype.h" +#include "devices.h" -+#include "dev-ar913x-wmac.h" ++#include "dev-ar9xxx-wmac.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-usb.h" @@ -7173,7 +9638,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.39/a +#define WZRHPG300NH_GPIO_BTN_ROUTER_AUTO (WZRHPG300NH_GPIO_EXP_BASE + 6) +#define WZRHPG300NH_GPIO_BTN_QOS_OFF (WZRHPG300NH_GPIO_EXP_BASE + 7) + -+#define WZRHPG300NH_BUTTONS_POLL_INTERVAL 20 ++#define WZRHPG300NH_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL (3 * WZRHPG300NH_KEYS_POLL_INTERVAL) + +#define WZRHPG300NH_MAC_OFFSET 0x20c + @@ -7218,8 +9684,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.39/a +static struct ar91xx_flash_platform_data wzrhpg300nh_flash_data = { + .width = 2, +#ifdef CONFIG_MTD_PARTITIONS -+ .parts = wzrhpg300nh_flash_partitions, -+ .nr_parts = ARRAY_SIZE(wzrhpg300nh_flash_partitions), ++ .parts = wzrhpg300nh_flash_partitions, ++ .nr_parts = ARRAY_SIZE(wzrhpg300nh_flash_partitions), +#endif +}; + @@ -7268,54 +9734,54 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.39/a + } +}; + -+static struct gpio_button wzrhpg300nh_gpio_buttons[] __initdata = { ++static struct gpio_keys_button wzrhpg300nh_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, -+ .threshold = 3, ++ .debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = WZRHPG300NH_GPIO_BTN_RESET, + .active_low = 1, + }, { + .desc = "aoss", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, -+ .threshold = 3, ++ .debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = WZRHPG300NH_GPIO_BTN_AOSS, + .active_low = 1, + }, { + .desc = "usb", + .type = EV_KEY, + .code = BTN_2, -+ .threshold = 3, ++ .debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = WZRHPG300NH_GPIO_BTN_USB, + .active_low = 1, + }, { + .desc = "qos_on", + .type = EV_KEY, + .code = BTN_3, -+ .threshold = 3, ++ .debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = WZRHPG300NH_GPIO_BTN_QOS_ON, + .active_low = 0, + }, { + .desc = "qos_off", + .type = EV_KEY, + .code = BTN_4, -+ .threshold = 3, ++ .debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = WZRHPG300NH_GPIO_BTN_QOS_OFF, + .active_low = 0, + }, { + .desc = "router_on", + .type = EV_KEY, + .code = BTN_5, -+ .threshold = 3, ++ .debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = WZRHPG300NH_GPIO_BTN_ROUTER_ON, + .active_low = 0, + }, { + .desc = "router_auto", + .type = EV_KEY, + .code = BTN_6, -+ .threshold = 3, ++ .debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL, + .gpio = WZRHPG300NH_GPIO_BTN_ROUTER_AUTO, + .active_low = 0, + } @@ -7337,33 +9803,55 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.39/a + } +}; + -+static struct rtl8366s_platform_data wzrhpg300nh_rtl8366s_data = { -+ .gpio_sda = WZRHPG300NH_GPIO_RTL8366_SDA, -+ .gpio_sck = WZRHPG300NH_GPIO_RTL8366_SCK, ++static struct rtl8366_platform_data wzrhpg300nh_rtl8366_data = { ++ .gpio_sda = WZRHPG300NH_GPIO_RTL8366_SDA, ++ .gpio_sck = WZRHPG300NH_GPIO_RTL8366_SCK, +}; + +static struct platform_device wzrhpg300nh_rtl8366s_device = { + .name = RTL8366S_DRIVER_NAME, + .id = -1, + .dev = { -+ .platform_data = &wzrhpg300nh_rtl8366s_data, ++ .platform_data = &wzrhpg300nh_rtl8366_data, ++ } ++}; ++ ++static struct platform_device wzrhpg300nh_rtl8366rb_device = { ++ .name = RTL8366RB_DRIVER_NAME, ++ .id = -1, ++ .dev = { ++ .platform_data = &wzrhpg300nh_rtl8366_data, + } +}; + +static void __init wzrhpg300nh_setup(void) +{ + u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000); ++ u8 *mac = eeprom + WZRHPG300NH_MAC_OFFSET; ++ bool hasrtl8366rb = false; ++ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); + -+ ar71xx_set_mac_base(eeprom + WZRHPG300NH_MAC_OFFSET); ++ if (rtl8366_smi_detect(&wzrhpg300nh_rtl8366_data) == RTL8366_TYPE_RB) ++ hasrtl8366rb = true; ++ ++ if (hasrtl8366rb) { ++ ar71xx_eth0_pll_data.pll_1000 = 0x1f000000; ++ ar71xx_eth0_data.mii_bus_dev = &wzrhpg300nh_rtl8366rb_device.dev; ++ ar71xx_eth1_pll_data.pll_1000 = 0x100; ++ ar71xx_eth1_data.mii_bus_dev = &wzrhpg300nh_rtl8366rb_device.dev; ++ } else { ++ ar71xx_eth0_pll_data.pll_1000 = 0x1e000100; ++ ar71xx_eth0_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev; ++ ar71xx_eth1_pll_data.pll_1000 = 0x1e000100; ++ ar71xx_eth1_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev; ++ } + -+ ar71xx_eth0_pll_data.pll_1000 = 0x1e000100; -+ ar71xx_eth0_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev; + ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth0_data.speed = SPEED_1000; + ar71xx_eth0_data.duplex = DUPLEX_FULL; + -+ ar71xx_eth1_pll_data.pll_1000 = 0x1e000100; -+ ar71xx_eth1_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev; + ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; + ar71xx_eth1_data.phy_mask = 0x10; + @@ -7371,27 +9859,249 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.39/a + ar71xx_add_device_eth(1); + + ar71xx_add_device_usb(); -+ ar913x_add_device_wmac(eeprom, NULL); ++ ar9xxx_add_device_wmac(eeprom, NULL); + + platform_device_register(&wzrhpg300nh_74hc153_device); + platform_device_register(&wzrhpg300nh_flash_device); -+ platform_device_register(&wzrhpg300nh_rtl8366s_device); ++ ++ if (hasrtl8366rb) ++ platform_device_register(&wzrhpg300nh_rtl8366rb_device); ++ else ++ platform_device_register(&wzrhpg300nh_rtl8366s_device); + + ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wzrhpg300nh_leds_gpio), -+ wzrhpg300nh_leds_gpio); ++ wzrhpg300nh_leds_gpio); + -+ ar71xx_add_device_gpio_buttons(-1, WZRHPG300NH_BUTTONS_POLL_INTERVAL, -+ ARRAY_SIZE(wzrhpg300nh_gpio_buttons), -+ wzrhpg300nh_gpio_buttons); ++ ar71xx_register_gpio_keys_polled(-1, WZRHPG300NH_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(wzrhpg300nh_gpio_keys), ++ wzrhpg300nh_gpio_keys); + +} + +MIPS_MACHINE(AR71XX_MACH_WZR_HP_G300NH, "WZR-HP-G300NH", + "Buffalo WZR-HP-G300NH", wzrhpg300nh_setup); +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/mach-zcn-1523h.c linux-2.6.39/arch/mips/ar71xx/mach-zcn-1523h.c +--- linux-2.6.39.orig/arch/mips/ar71xx/mach-zcn-1523h.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/mach-zcn-1523h.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,214 @@ ++/* ++ * Zcomax ZCN-1523H-2-8/5-16 board support ++ * ++ * Copyright (C) 2010 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 <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++ ++#include "machtype.h" ++#include "devices.h" ++#include "dev-m25p80.h" ++#include "dev-ap91-pci.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++ ++#define ZCN_1523H_GPIO_BTN_RESET 0 ++#define ZCN_1523H_GPIO_LED_INIT 11 ++#define ZCN_1523H_GPIO_LED_LAN1 17 ++ ++#define ZCN_1523H_2_GPIO_LED_WEAK 13 ++#define ZCN_1523H_2_GPIO_LED_MEDIUM 14 ++#define ZCN_1523H_2_GPIO_LED_STRONG 15 ++ ++#define ZCN_1523H_5_GPIO_LED_UNKNOWN 1 ++#define ZCN_1523H_5_GPIO_LED_LAN2 13 ++#define ZCN_1523H_5_GPIO_LED_WEAK 14 ++#define ZCN_1523H_5_GPIO_LED_MEDIUM 15 ++#define ZCN_1523H_5_GPIO_LED_STRONG 16 ++ ++#define ZCN_1523H_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define ZCN_1523H_KEYS_DEBOUNCE_INTERVAL (3 * ZCN_1523H_KEYS_POLL_INTERVAL) ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition zcn_1523h_partitions[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = 0x040000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "u-boot-env", ++ .offset = 0x040000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "rootfs", ++ .offset = 0x050000, ++ .size = 0x610000, ++ }, { ++ .name = "kernel", ++ .offset = 0x660000, ++ .size = 0x170000, ++ }, { ++ .name = "configure", ++ .offset = 0x7d0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "mfg", ++ .offset = 0x7e0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "eeprom", ++ .offset = 0x7f0000, ++ .size = 0x010000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "firmware", ++ .offset = 0x050000, ++ .size = 0x780000, ++ } ++}; ++#endif /* CONFIG_MTD_PARTITIONS */ ++ ++static struct flash_platform_data zcn_1523h_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .parts = zcn_1523h_partitions, ++ .nr_parts = ARRAY_SIZE(zcn_1523h_partitions), ++#endif ++}; ++ ++static struct gpio_keys_button zcn_1523h_gpio_keys[] __initdata = { ++ { ++ .desc = "reset", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = ZCN_1523H_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = ZCN_1523H_GPIO_BTN_RESET, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_led zcn_1523h_leds_gpio[] __initdata = { ++ { ++ .name = "zcn-1523h:amber:init", ++ .gpio = ZCN_1523H_GPIO_LED_INIT, ++ .active_low = 1, ++ }, { ++ .name = "zcn-1523h:green:lan1", ++ .gpio = ZCN_1523H_GPIO_LED_LAN1, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_led zcn_1523h_2_leds_gpio[] __initdata = { ++ { ++ .name = "zcn-1523h:red:weak", ++ .gpio = ZCN_1523H_2_GPIO_LED_WEAK, ++ .active_low = 1, ++ }, { ++ .name = "zcn-1523h:amber:medium", ++ .gpio = ZCN_1523H_2_GPIO_LED_MEDIUM, ++ .active_low = 1, ++ }, { ++ .name = "zcn-1523h:green:strong", ++ .gpio = ZCN_1523H_2_GPIO_LED_STRONG, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_led zcn_1523h_5_leds_gpio[] __initdata = { ++ { ++ .name = "zcn-1523h:red:weak", ++ .gpio = ZCN_1523H_5_GPIO_LED_WEAK, ++ .active_low = 1, ++ }, { ++ .name = "zcn-1523h:amber:medium", ++ .gpio = ZCN_1523H_5_GPIO_LED_MEDIUM, ++ .active_low = 1, ++ }, { ++ .name = "zcn-1523h:green:strong", ++ .gpio = ZCN_1523H_5_GPIO_LED_STRONG, ++ .active_low = 1, ++ }, { ++ .name = "zcn-1523h:green:lan2", ++ .gpio = ZCN_1523H_5_GPIO_LED_LAN2, ++ .active_low = 1, ++ }, { ++ .name = "zcn-1523h:amber:unknown", ++ .gpio = ZCN_1523H_5_GPIO_LED_UNKNOWN, ++ } ++}; ++ ++static void __init zcn_1523h_generic_setup(void) ++{ ++ u8 *mac = (u8 *) KSEG1ADDR(0x1f7e0004); ++ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000); ++ ++ ar71xx_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN | ++ AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN | ++ AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN | ++ AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN | ++ AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN); ++ ++ ar71xx_add_device_m25p80(&zcn_1523h_flash_data); ++ ++ ar71xx_add_device_leds_gpio(0, ARRAY_SIZE(zcn_1523h_leds_gpio), ++ zcn_1523h_leds_gpio); ++ ++ ar71xx_register_gpio_keys_polled(-1, ZCN_1523H_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(zcn_1523h_gpio_keys), ++ zcn_1523h_gpio_keys); ++ ++ ap91_pci_init(ee, mac); ++ ++ ar71xx_init_mac(ar71xx_eth0_data.mac_addr, mac, 0); ++ ar71xx_init_mac(ar71xx_eth1_data.mac_addr, mac, 1); ++ ++ /* LAN1 port */ ++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth0_data.speed = SPEED_100; ++ ar71xx_eth0_data.duplex = DUPLEX_FULL; ++ ++ /* LAN2 port */ ++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII; ++ ar71xx_eth1_data.speed = SPEED_1000; ++ ar71xx_eth1_data.duplex = DUPLEX_FULL; ++ ++ ar71xx_add_device_mdio(0x0); ++ ar71xx_add_device_eth(0); ++} ++ ++static void __init zcn_1523h_2_setup(void) ++{ ++ zcn_1523h_generic_setup(); ++ ap91_pci_setup_wmac_gpio(BIT(9), 0); ++ ++ ar71xx_add_device_leds_gpio(1, ARRAY_SIZE(zcn_1523h_2_leds_gpio), ++ zcn_1523h_2_leds_gpio); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_ZCN_1523H_2, "ZCN-1523H-2", "Zcomax ZCN-1523H-2", ++ zcn_1523h_2_setup); ++ ++static void __init zcn_1523h_5_setup(void) ++{ ++ zcn_1523h_generic_setup(); ++ ap91_pci_setup_wmac_gpio(BIT(8), 0); ++ ++ ar71xx_add_device_leds_gpio(1, ARRAY_SIZE(zcn_1523h_5_leds_gpio), ++ zcn_1523h_5_leds_gpio); ++ ar71xx_add_device_eth(1); ++} ++ ++MIPS_MACHINE(AR71XX_MACH_ZCN_1523H_5, "ZCN-1523H-5", "Zcomax ZCN-1523H-5", ++ zcn_1523h_5_setup); diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/machtype.h linux-2.6.39/arch/mips/ar71xx/machtype.h --- linux-2.6.39.orig/arch/mips/ar71xx/machtype.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/machtype.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,60 @@ ++++ linux-2.6.39/arch/mips/ar71xx/machtype.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,75 @@ +/* + * Atheros AR71xx machine type definitions + * @@ -7410,12 +10120,16 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/machtype.h linux-2.6.39/arch/mips/a + +enum ar71xx_mach_type { + AR71XX_MACH_GENERIC = 0, ++ AR71XX_MACH_AP121, /* Atheros AP121 */ ++ AR71XX_MACH_AP121_MINI, /* Atheros AP121-MINI */ + AR71XX_MACH_AP81, /* Atheros AP81 */ + AR71XX_MACH_AP83, /* Atheros AP83 */ + AR71XX_MACH_AW_NR580, /* AzureWave AW-NR580 */ + AR71XX_MACH_DIR_600_A1, /* D-Link DIR-600 rev. A1 */ + AR71XX_MACH_DIR_615_C1, /* D-Link DIR-615 rev. C1 */ + AR71XX_MACH_DIR_825_B1, /* D-Link DIR-825 rev. B1 */ ++ AR71XX_MACH_JA76PF, /* jjPlus JA76PF */ ++ AR71XX_MACH_JWAP003, /* jjPlus JWAP003 */ + AR71XX_MACH_RB_411, /* MikroTik RouterBOARD 411/411A/411AH */ + AR71XX_MACH_RB_411U, /* MikroTik RouterBOARD 411U */ + AR71XX_MACH_RB_433, /* MikroTik RouterBOARD 433/433AH */ @@ -7431,6 +10145,10 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/machtype.h linux-2.6.39/arch/mips/a + AR71XX_MACH_MZK_W300NH, /* Planex MZK-W300NH */ + AR71XX_MACH_NBG460N, /* Zyxel NBG460N/550N/550NH */ + AR71XX_MACH_TEW_632BRP, /* TRENDnet TEW-632BRP */ ++ AR71XX_MACH_TL_MR3220, /* TP-LINK TL-MR3220 */ ++ AR71XX_MACH_TL_MR3420, /* TP-LINK TL-MR3420 */ ++ AR71XX_MACH_TL_WA901ND, /* TP-LINK TL-WA901ND */ ++ AR71XX_MACH_TL_WA901ND_V2, /* TP-LINK TL-WA901ND v2 */ + AR71XX_MACH_TL_WR741ND, /* TP-LINK TL-WR741ND */ + AR71XX_MACH_TL_WR841N_V1, /* TP-LINK TL-WR841N v1 */ + AR71XX_MACH_TL_WR941ND, /* TP-LINK TL-WR941ND */ @@ -7438,23 +10156,30 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/machtype.h linux-2.6.39/arch/mips/a + AR71XX_MACH_UBNT_LSSR71, /* Ubiquiti LS-SR71 */ + AR71XX_MACH_UBNT_LSX, /* Ubiquiti LSX */ + AR71XX_MACH_UBNT_RS, /* Ubiquiti RouterStation */ -+ AR71XX_MACH_UBNT_AR71XX, /* Ubiquiti AR71xx-based board */ + AR71XX_MACH_UBNT_RSPRO, /* Ubiquiti RouterStation Pro */ + AR71XX_MACH_UBNT_BULLET_M, /* Ubiquiti Bullet M */ + AR71XX_MACH_UBNT_ROCKET_M, /* Ubiquiti Rocket M */ + AR71XX_MACH_UBNT_NANO_M, /* Ubiquiti NanoStation M */ + AR71XX_MACH_WNDR3700, /* NETGEAR WNDR3700 */ ++ AR71XX_MACH_WNDR3700V2, /* NETGEAR WNDR3700v2 */ + AR71XX_MACH_WNR2000, /* NETGEAR WNR2000 */ + AR71XX_MACH_WP543, /* Compex WP543 */ + AR71XX_MACH_WRT160NL, /* Linksys WRT160NL */ + AR71XX_MACH_WRT400N, /* Linksys WRT400N */ ++ AR71XX_MACH_WZR_HP_AG300H, /* Buffalo WZR-HP-AG300H */ + AR71XX_MACH_WZR_HP_G300NH, /* Buffalo WZR-HP-G300NH */ ++ AR71XX_MACH_EAP7660D, /* Senao EAP7660D */ ++ AR71XX_MACH_ZCN_1523H_2, /* Zcomax ZCN-1523H-2-xx */ ++ AR71XX_MACH_ZCN_1523H_5, /* Zcomax ZCN-1523H-5-xx */ ++ AR71XX_MACH_AP96, /* Atheros AP96 */ ++ AR71XX_MACH_UBNT_UNIFI, /* Unifi */ ++ AR71XX_MACH_DB120, /* Atheros DB120 (AR934x based) */ +}; + +#endif /* _AR71XX_MACHTYPE_H */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/nvram.c linux-2.6.39/arch/mips/ar71xx/nvram.c --- linux-2.6.39.orig/arch/mips/ar71xx/nvram.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/nvram.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/nvram.c 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,75 @@ +/* + * Atheros AR71xx minimal nvram support @@ -7527,13 +10252,13 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/nvram.c linux-2.6.39/arch/mips/ar71 + + ret = 0; + -+ free: ++free: + vfree(buf); + return ret; +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/nvram.h linux-2.6.39/arch/mips/ar71xx/nvram.h --- linux-2.6.39.orig/arch/mips/ar71xx/nvram.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/nvram.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/ar71xx/nvram.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,19 @@ +/* + * Atheros AR71xx minimal nvram support @@ -7554,10 +10279,147 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/nvram.h linux-2.6.39/arch/mips/ar71 + const char *name, char *mac) __init; + +#endif /* _AR71XX_NVRAM_H */ +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/pci-ath9k-fixup.c linux-2.6.39/arch/mips/ar71xx/pci-ath9k-fixup.c +--- linux-2.6.39.orig/arch/mips/ar71xx/pci-ath9k-fixup.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/pci-ath9k-fixup.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,123 @@ ++/* ++ * Atheros AP94 reference board PCI initialization ++ * ++ * Copyright (C) 2009-2010 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 <linux/pci.h> ++#include <linux/delay.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++#include <asm/mach-ar71xx/pci.h> ++ ++struct ath9k_fixup { ++ u16 *cal_data; ++ unsigned slot; ++}; ++ ++static int ath9k_num_fixups; ++static struct ath9k_fixup ath9k_fixups[2]; ++ ++static void ath9k_pci_fixup(struct pci_dev *dev) ++{ ++ void __iomem *mem; ++ u16 *cal_data = NULL; ++ u16 cmd; ++ u32 bar0; ++ u32 val; ++ unsigned i; ++ ++ for (i = 0; i < ath9k_num_fixups; i++) { ++ if (ath9k_fixups[i].cal_data == NULL) ++ continue; ++ ++ if (ath9k_fixups[i].slot != PCI_SLOT(dev->devfn)) ++ continue; ++ ++ cal_data = ath9k_fixups[i].cal_data; ++ break; ++ } ++ ++ if (cal_data == NULL) ++ return; ++ ++ if (*cal_data != 0xa55a) { ++ pr_err("pci %s: invalid calibration data\n", pci_name(dev)); ++ return; ++ } ++ ++ pr_info("pci %s: fixup device configuration\n", pci_name(dev)); ++ ++ mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000); ++ if (!mem) { ++ pr_err("pci %s: ioremap error\n", pci_name(dev)); ++ return; ++ } ++ ++ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0); ++ ++ switch (ar71xx_soc) { ++ case AR71XX_SOC_AR7161: ++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, ++ AR71XX_PCI_MEM_BASE); ++ break; ++ case AR71XX_SOC_AR7240: ++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0xffff); ++ break; ++ ++ case AR71XX_SOC_AR7241: ++ case AR71XX_SOC_AR7242: ++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x1000ffff); ++ break; ++ ++ default: ++ BUG(); ++ } ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ ++ /* set pointer to first reg address */ ++ cal_data += 3; ++ while (*cal_data != 0xffff) { ++ u32 reg; ++ reg = *cal_data++; ++ val = *cal_data++; ++ val |= (*cal_data++) << 16; ++ ++ __raw_writel(val, mem + reg); ++ udelay(100); ++ } ++ ++ pci_read_config_dword(dev, PCI_VENDOR_ID, &val); ++ dev->vendor = val & 0xffff; ++ dev->device = (val >> 16) & 0xffff; ++ ++ pci_read_config_dword(dev, PCI_CLASS_REVISION, &val); ++ dev->revision = val & 0xff; ++ dev->class = val >> 8; /* upper 3 bytes */ ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ ++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0); ++ ++ iounmap(mem); ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ath9k_pci_fixup); ++ ++void __init pci_enable_ath9k_fixup(unsigned slot, u16 *cal_data) ++{ ++ if (ath9k_num_fixups >= ARRAY_SIZE(ath9k_fixups)) ++ return; ++ ++ ath9k_fixups[ath9k_num_fixups].slot = slot; ++ ath9k_fixups[ath9k_num_fixups].cal_data = cal_data; ++ ath9k_num_fixups++; ++} +diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/pci-ath9k-fixup.h linux-2.6.39/arch/mips/ar71xx/pci-ath9k-fixup.h +--- linux-2.6.39.orig/arch/mips/ar71xx/pci-ath9k-fixup.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/ar71xx/pci-ath9k-fixup.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,6 @@ ++#ifndef _PCI_ATH9K_FIXUP ++#define _PCI_ATH9K_FIXUP ++ ++void pci_enable_ath9k_fixup(unsigned slot, u16 *cal_data) __init; ++ ++#endif /* _PCI_ATH9K_FIXUP */ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/pci.c linux-2.6.39/arch/mips/ar71xx/pci.c --- linux-2.6.39.orig/arch/mips/ar71xx/pci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/pci.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,93 @@ ++++ linux-2.6.39/arch/mips/ar71xx/pci.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,97 @@ +/* + * Atheros AR71xx PCI setup code + * @@ -7614,6 +10476,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/pci.c linux-2.6.39/arch/mips/ar71xx + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: + ret = ar724x_pcibios_map_irq(dev, slot, pin); + break; + @@ -7639,6 +10503,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/pci.c linux-2.6.39/arch/mips/ar71xx + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: + ret = ar724x_pcibios_init(); + break; + @@ -7653,12 +10519,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/pci.c linux-2.6.39/arch/mips/ar71xx +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/prom.c linux-2.6.39/arch/mips/ar71xx/prom.c --- linux-2.6.39.orig/arch/mips/ar71xx/prom.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/prom.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,105 @@ ++++ linux-2.6.39/arch/mips/ar71xx/prom.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,189 @@ +/* + * Atheros AR71xx SoC specific prom routines + * -+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2008-2010 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 @@ -7673,6 +10539,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/prom.c linux-2.6.39/arch/mips/ar71x + +#include <asm/bootinfo.h> +#include <asm/addrspace.h> ++#include <asm/fw/myloader/myloader.h> + +#include <asm/mach-ar71xx/ar71xx.h> + @@ -7698,30 +10565,90 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/prom.c linux-2.6.39/arch/mips/ar71x + strlcat(arcs_cmdline, buf, sizeof(arcs_cmdline)); +} + -+static void __init ar71xx_prom_find_env(char **envp, const char *name) ++static const char * __init ar71xx_prom_find_env(char **envp, const char *name) +{ -+ int len = strlen(name); ++ const char *ret = NULL; ++ int len; + char **p; + + if (!is_valid_ram_addr(envp)) -+ return; ++ return NULL; + ++ len = strlen(name); + for (p = envp; is_valid_ram_addr(*p); p++) { + if (strncmp(name, *p, len) == 0 && (*p)[len] == '=') { -+ ar71xx_prom_append_cmdline(name, *p + len + 1); ++ ret = *p + len + 1; + break; + } + + /* RedBoot env comes in pointer pairs - key, value */ + if (strncmp(name, *p, len) == 0 && (*p)[len] == 0) + if (is_valid_ram_addr(*(++p))) { -+ ar71xx_prom_append_cmdline(name, *p); ++ ret = *p; + break; + } + } ++ ++ return ret; ++} ++ ++static int __init ar71xx_prom_init_myloader(void) ++{ ++ struct myloader_info *mylo; ++ char mac_buf[32]; ++ char *mac; ++ ++ mylo = myloader_get_info(); ++ if (!mylo) ++ return 0; ++ ++ switch (mylo->did) { ++ case DEVID_COMPEX_WP543: ++ ar71xx_prom_append_cmdline("board", "WP543"); ++ break; ++ default: ++ printk(KERN_WARNING "prom: unknown device id: %x\n", ++ mylo->did); ++ return 0; ++ } ++ ++ mac = mylo->macs[0]; ++ snprintf(mac_buf, sizeof(mac_buf), "%02x:%02x:%02x:%02x:%02x:%02x", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); ++ ++ ar71xx_prom_append_cmdline("ethaddr", mac_buf); ++ ++ return 1; +} + -+static int inline ar71xx_use__image_cmdline(void) { return 0; } ++#ifdef CONFIG_IMAGE_CMDLINE_HACK ++extern char __image_cmdline[]; ++ ++static int __init ar71xx_use__image_cmdline(void) ++{ ++ char *p = __image_cmdline; ++ int replace = 0; ++ ++ if (*p == '-') { ++ replace = 1; ++ p++; ++ } ++ ++ if (*p == '\0') ++ return 0; ++ ++ if (replace) { ++ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline)); ++ } else { ++ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); ++ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); ++ } ++ ++ return 1; ++} ++#else ++static inline int ar71xx_use__image_cmdline(void) { return 0; } ++#endif + +static __init void ar71xx_prom_init_cmdline(int argc, char **argv) +{ @@ -7742,6 +10669,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/prom.c linux-2.6.39/arch/mips/ar71x + +void __init prom_init(void) +{ ++ const char *env; + char **envp; + + printk(KERN_DEBUG "prom: fw_arg0=%08x, fw_arg1=%08x, " @@ -7750,10 +10678,32 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/prom.c linux-2.6.39/arch/mips/ar71x + (unsigned int)fw_arg2, (unsigned int)fw_arg3); + + ++ if (ar71xx_prom_init_myloader()) ++ return; ++ + ar71xx_prom_init_cmdline(fw_arg0, (char **)fw_arg1); + + envp = (char **)fw_arg2; -+ ar71xx_prom_find_env(envp, "board"); ++ if (!strstr(arcs_cmdline, "ethaddr=")) { ++ env = ar71xx_prom_find_env(envp, "ethaddr"); ++ if (env) ++ ar71xx_prom_append_cmdline("ethaddr", env); ++ } ++ ++ if (!strstr(arcs_cmdline, "board=")) { ++ env = ar71xx_prom_find_env(envp, "board"); ++ if (env) { ++ /* Workaround for buggy bootloaders */ ++ if (strcmp(env, "RouterStation") == 0 || ++ strcmp(env, "Ubiquiti AR71xx-based board") == 0) ++ env = "UBNT-RS"; ++ ++ if (strcmp(env, "RouterStation PRO") == 0) ++ env = "UBNT-RSPRO"; ++ ++ ar71xx_prom_append_cmdline("board", env); ++ } ++ } +} + +void __init prom_free_prom_memory(void) @@ -7762,15 +10712,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/prom.c linux-2.6.39/arch/mips/ar71x +} diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71xx/setup.c --- linux-2.6.39.orig/arch/mips/ar71xx/setup.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/ar71xx/setup.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,310 @@ ++++ linux-2.6.39/arch/mips/ar71xx/setup.c 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,446 @@ +/* + * Atheros AR71xx SoC specific setup + * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2009 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 ++ * Parts of this file are based on Atheros 2.6.15 BSP ++ * Parts of this file are based on Atheros 2.6.31 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 @@ -7792,9 +10744,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 +#include "devices.h" + +#define AR71XX_SYS_TYPE_LEN 64 -+#define AR71XX_BASE_FREQ 40000000 -+#define AR91XX_BASE_FREQ 5000000 -+#define AR724X_BASE_FREQ 5000000 + +u32 ar71xx_cpu_freq; +EXPORT_SYMBOL_GPL(ar71xx_cpu_freq); @@ -7805,9 +10754,15 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 +u32 ar71xx_ddr_freq; +EXPORT_SYMBOL_GPL(ar71xx_ddr_freq); + ++u32 ar71xx_ref_freq; ++EXPORT_SYMBOL_GPL(ar71xx_ref_freq); ++ +enum ar71xx_soc_type ar71xx_soc; +EXPORT_SYMBOL_GPL(ar71xx_soc); + ++u32 ar71xx_soc_rev; ++EXPORT_SYMBOL_GPL(ar71xx_soc_rev); ++ +static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN]; + +static void ar71xx_restart(char *command) @@ -7829,7 +10784,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + unsigned long size; + + for (size = AR71XX_MEM_SIZE_MIN; size < AR71XX_MEM_SIZE_MAX; -+ size <<= 1 ) { ++ size <<= 1) { + if (!memcmp(ar71xx_detect_mem_size, + ar71xx_detect_mem_size + size, 1024)) + break; @@ -7875,19 +10830,19 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + case REV_ID_MAJOR_AR7240: + ar71xx_soc = AR71XX_SOC_AR7240; + chip = "7240"; -+ rev = (id & AR724X_REV_ID_REVISION_MASK); ++ rev = id & AR724X_REV_ID_REVISION_MASK; + break; + + case REV_ID_MAJOR_AR7241: + ar71xx_soc = AR71XX_SOC_AR7241; + chip = "7241"; -+ rev = (id & AR724X_REV_ID_REVISION_MASK); ++ rev = id & AR724X_REV_ID_REVISION_MASK; + break; + + case REV_ID_MAJOR_AR7242: + ar71xx_soc = AR71XX_SOC_AR7242; + chip = "7242"; -+ rev = (id & AR724X_REV_ID_REVISION_MASK); ++ rev = id & AR724X_REV_ID_REVISION_MASK; + break; + + case REV_ID_MAJOR_AR913X: @@ -7907,11 +10862,76 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + } + break; + ++ case REV_ID_MAJOR_AR9330: ++ ar71xx_soc = AR71XX_SOC_AR9330; ++ chip = "9330"; ++ rev = id & AR933X_REV_ID_REVISION_MASK; ++ break; ++ ++ case REV_ID_MAJOR_AR9331: ++ ar71xx_soc = AR71XX_SOC_AR9331; ++ chip = "9331"; ++ rev = id & AR933X_REV_ID_REVISION_MASK; ++ break; ++ ++ case REV_ID_MAJOR_AR9342: ++ ar71xx_soc = AR71XX_SOC_AR9342; ++ chip = "9342"; ++ rev = id & AR934X_REV_ID_REVISION_MASK; ++ break; ++ ++ case REV_ID_MAJOR_AR9344: ++ ar71xx_soc = AR71XX_SOC_AR9344; ++ chip = "9344"; ++ rev = id & AR934X_REV_ID_REVISION_MASK; ++ break; ++ + default: + panic("ar71xx: unknown chip id:0x%08x\n", id); + } + ++ ar71xx_soc_rev = rev; ++ + sprintf(ar71xx_sys_type, "Atheros AR%s rev %u", chip, rev); ++ pr_info("SoC: %s\n", ar71xx_sys_type); ++} ++ ++static void __init ar934x_detect_sys_frequency(void) ++{ ++ u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv; ++ ++ if (ar71xx_reset_rr(AR934X_RESET_REG_BOOTSTRAP) & AR934X_REF_CLK_40) ++ ar71xx_ref_freq = 40 * 1000 * 1000; ++ else ++ ar71xx_ref_freq = 25 * 1000 * 1000; ++ ++ clk_ctrl = ar71xx_pll_rr(AR934X_PLL_REG_DDR_CTRL_CLOCK); ++ ++ pll = ar71xx_pll_rr(AR934X_PLL_REG_CPU_CONFIG); ++ out_div = AR934X_CPU_PLL_CFG_OUTDIV_GET(pll); ++ ref_div = AR934X_CPU_PLL_CFG_REFDIV_GET(pll); ++ nint = AR934X_CPU_PLL_CFG_NINT_GET(pll); ++ frac = AR934X_CPU_PLL_CFG_NFRAC_GET(pll); ++ postdiv = AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_GET(clk_ctrl); ++ ar71xx_cpu_freq = ((nint * ar71xx_ref_freq / ref_div) >> out_div) / ++ (postdiv + 1); ++ ++ out_div = AR934X_DDR_PLL_CFG_OUTDIV_GET(pll); ++ ref_div = AR934X_DDR_PLL_CFG_REFDIV_GET(pll); ++ nint = AR934X_DDR_PLL_CFG_NINT_GET(pll); ++ frac = AR934X_DDR_PLL_CFG_NFRAC_GET(pll); ++ postdiv = AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_GET(clk_ctrl); ++ ar71xx_ddr_freq = ((nint * ar71xx_ref_freq / ref_div) >> out_div) / ++ (postdiv + 1); ++ ++ postdiv = AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_GET(clk_ctrl); ++ ++ if (AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_GET(clk_ctrl)) { ++ ar71xx_ahb_freq = ar71xx_ddr_freq / (postdiv + 1); ++ } else { ++ ar71xx_ahb_freq = ar71xx_cpu_freq / (postdiv + 1); ++ } ++ +} + +static void __init ar91xx_detect_sys_frequency(void) @@ -7920,10 +10940,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + u32 freq; + u32 div; + ++ ar71xx_ref_freq = 5 * 1000 * 1000; ++ + pll = ar71xx_pll_rr(AR91XX_PLL_REG_CPU_CONFIG); + + div = ((pll >> AR91XX_PLL_DIV_SHIFT) & AR91XX_PLL_DIV_MASK); -+ freq = div * AR91XX_BASE_FREQ; ++ freq = div * ar71xx_ref_freq; + + ar71xx_cpu_freq = freq; + @@ -7940,10 +10962,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + u32 freq; + u32 div; + ++ ar71xx_ref_freq = 40 * 1000 * 1000; ++ + pll = ar71xx_pll_rr(AR71XX_PLL_REG_CPU_CONFIG); + + div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; -+ freq = div * AR71XX_BASE_FREQ; ++ freq = div * ar71xx_ref_freq; + + div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; + ar71xx_cpu_freq = freq / div; @@ -7961,10 +10985,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + u32 freq; + u32 div; + ++ ar71xx_ref_freq = 5 * 1000 * 1000; ++ + pll = ar71xx_pll_rr(AR724X_PLL_REG_CPU_CONFIG); + + div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); -+ freq = div * AR724X_BASE_FREQ; ++ freq = div * ar71xx_ref_freq; + + div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); + freq *= div; @@ -7978,6 +11004,56 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + ar71xx_ahb_freq = ar71xx_cpu_freq / div; +} + ++static void __init ar933x_detect_sys_frequency(void) ++{ ++ u32 clock_ctrl; ++ u32 cpu_config; ++ u32 freq; ++ u32 t; ++ ++ t = ar71xx_reset_rr(AR933X_RESET_REG_BOOTSTRAP); ++ if (t & AR933X_BOOTSTRAP_REF_CLK_40) ++ ar71xx_ref_freq = (40 * 1000 * 1000); ++ else ++ ar71xx_ref_freq = (25 * 1000 * 1000); ++ ++ clock_ctrl = ar71xx_pll_rr(AR933X_PLL_CLOCK_CTRL_REG); ++ if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { ++ ar71xx_cpu_freq = ar71xx_ref_freq; ++ ar71xx_ahb_freq = ar71xx_ref_freq; ++ ar71xx_ddr_freq = ar71xx_ref_freq; ++ } else { ++ cpu_config = ar71xx_pll_rr(AR933X_PLL_CPU_CONFIG_REG); ++ ++ t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & ++ AR933X_PLL_CPU_CONFIG_REFDIV_MASK; ++ freq = ar71xx_ref_freq / t; ++ ++ t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & ++ AR933X_PLL_CPU_CONFIG_NINT_MASK; ++ freq *= t; ++ ++ t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & ++ AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; ++ if (t == 0) ++ t = 1; ++ ++ freq >>= t; ++ ++ t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & ++ AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; ++ ar71xx_cpu_freq = freq / t; ++ ++ t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & ++ AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; ++ ar71xx_ddr_freq = freq / t; ++ ++ t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & ++ AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; ++ ar71xx_ahb_freq = freq / t; ++ } ++} ++ +static void __init detect_sys_frequency(void) +{ + switch (ar71xx_soc) { @@ -7998,6 +11074,16 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + ar91xx_detect_sys_frequency(); + break; + ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ ar933x_detect_sys_frequency(); ++ break; ++ ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ ar934x_detect_sys_frequency(); ++ break; + default: + BUG(); + } @@ -8035,12 +11121,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + ar71xx_detect_sys_type(); + detect_sys_frequency(); + -+ printk(KERN_INFO -+ "%s, CPU:%u.%03u MHz, AHB:%u.%03u MHz, DDR:%u.%03u MHz\n", -+ ar71xx_sys_type, ++ pr_info("Clocks: CPU:%u.%03uMHz, DDR:%u.%03uMHz, AHB:%u.%03uMHz, " ++ "Ref:%u.%03uMHz", + ar71xx_cpu_freq / 1000000, (ar71xx_cpu_freq / 1000) % 1000, ++ ar71xx_ddr_freq / 1000000, (ar71xx_ddr_freq / 1000) % 1000, + ar71xx_ahb_freq / 1000000, (ar71xx_ahb_freq / 1000) % 1000, -+ ar71xx_ddr_freq / 1000000, (ar71xx_ddr_freq / 1000) % 1000); ++ ar71xx_ref_freq / 1000000, (ar71xx_ref_freq / 1000) % 1000); + + _machine_restart = ar71xx_restart; + _machine_halt = ar71xx_halt; @@ -8074,17 +11160,110 @@ diff -Nur linux-2.6.39.orig/arch/mips/ar71xx/setup.c linux-2.6.39/arch/mips/ar71 + +MIPS_MACHINE(AR71XX_MACH_GENERIC, "Generic", "Generic AR71xx board", + ar71xx_generic_init); +diff -Nur linux-2.6.39.orig/arch/mips/include/asm/checksum.h linux-2.6.39/arch/mips/include/asm/checksum.h +--- linux-2.6.39.orig/arch/mips/include/asm/checksum.h 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/checksum.h 2011-08-24 18:17:23.000000000 +0200 +@@ -12,6 +12,7 @@ + #define _ASM_CHECKSUM_H + + #include <linux/in6.h> ++#include <linux/unaligned/packed_struct.h> + + #include <asm/uaccess.h> + +@@ -104,26 +105,30 @@ + const unsigned int *stop = word + ihl; + unsigned int csum; + int carry; ++ unsigned int w; + +- csum = word[0]; +- csum += word[1]; +- carry = (csum < word[1]); ++ csum = __get_unaligned_cpu32(word++); ++ ++ w = __get_unaligned_cpu32(word++); ++ csum += w; ++ carry = (csum < w); + csum += carry; + +- csum += word[2]; +- carry = (csum < word[2]); ++ w = __get_unaligned_cpu32(word++); ++ csum += w; ++ carry = (csum < w); + csum += carry; + +- csum += word[3]; +- carry = (csum < word[3]); ++ w = __get_unaligned_cpu32(word++); ++ csum += w; ++ carry = (csum < w); + csum += carry; + +- word += 4; + do { +- csum += *word; +- carry = (csum < *word); ++ w = __get_unaligned_cpu32(word++); ++ csum += w; ++ carry = (csum < w); + csum += carry; +- word++; + } while (word != stop); + + return csum_fold(csum); +diff -Nur linux-2.6.39.orig/arch/mips/include/asm/fw/myloader/myloader.h linux-2.6.39/arch/mips/include/asm/fw/myloader/myloader.h +--- linux-2.6.39.orig/arch/mips/include/asm/fw/myloader/myloader.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/include/asm/fw/myloader/myloader.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * Compex's MyLoader specific definitions ++ * ++ * Copyright (C) 2006-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_FW_MYLOADER_H ++#define _ASM_MIPS_FW_MYLOADER_H ++ ++#include <linux/myloader.h> ++ ++struct myloader_info { ++ uint32_t vid; ++ uint32_t did; ++ uint32_t svid; ++ uint32_t sdid; ++ uint8_t macs[MYLO_ETHADDR_COUNT][6]; ++}; ++ ++#ifdef CONFIG_MYLOADER ++extern struct myloader_info *myloader_get_info(void) __init; ++#else ++static inline struct myloader_info *myloader_get_info(void) ++{ ++ return NULL; ++} ++#endif /* CONFIG_MYLOADER */ ++ ++#endif /* _ASM_MIPS_FW_MYLOADER_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar71xx.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar71xx.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,514 @@ ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar71xx.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,769 @@ +/* + * Atheros AR71xx SoC specific definitions + * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2009 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 ++ * Parts of this file are based on Atheros 2.6.15 BSP ++ * Parts of this file are based on Atheros 2.6.31 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 @@ -8148,15 +11327,23 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#define AR91XX_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000) +#define AR91XX_WMAC_SIZE 0x30000 + ++#define AR933X_UART_BASE (AR71XX_APB_BASE + 0x00020000) ++#define AR933X_UART_SIZE 0x14 ++#define AR933X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) ++#define AR933X_WMAC_SIZE 0x20000 ++ ++#define AR934X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) ++#define AR934X_WMAC_SIZE 0x20000 ++ +#define AR71XX_MEM_SIZE_MIN 0x0200000 +#define AR71XX_MEM_SIZE_MAX 0x10000000 + +#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_MISC_IRQ_COUNT 32 ++#define AR71XX_GPIO_IRQ_BASE 40 +#define AR71XX_GPIO_IRQ_COUNT 32 -+#define AR71XX_PCI_IRQ_BASE 48 ++#define AR71XX_PCI_IRQ_BASE 72 +#define AR71XX_PCI_IRQ_COUNT 8 + +#define AR71XX_CPU_IRQ_IP2 (AR71XX_CPU_IRQ_BASE + 2) @@ -8174,6 +11361,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#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_MISC_IRQ_TIMER2 (AR71XX_MISC_IRQ_BASE + 8) ++#define AR71XX_MISC_IRQ_TIMER3 (AR71XX_MISC_IRQ_BASE + 9) ++#define AR71XX_MISC_IRQ_TIMER4 (AR71XX_MISC_IRQ_BASE + 10) ++#define AR71XX_MISC_IRQ_DDR_PERF (AR71XX_MISC_IRQ_BASE + 11) ++#define AR71XX_MISC_IRQ_ENET_LINK (AR71XX_MISC_IRQ_BASE + 12) + +#define AR71XX_GPIO_IRQ(_x) (AR71XX_GPIO_IRQ_BASE + (_x)) + @@ -8185,6 +11377,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +extern u32 ar71xx_ahb_freq; +extern u32 ar71xx_cpu_freq; +extern u32 ar71xx_ddr_freq; ++extern u32 ar71xx_ref_freq; + +enum ar71xx_soc_type { + AR71XX_SOC_UNKNOWN, @@ -8195,8 +11388,14 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 + AR71XX_SOC_AR7241, + AR71XX_SOC_AR7242, + AR71XX_SOC_AR9130, -+ AR71XX_SOC_AR9132 ++ AR71XX_SOC_AR9132, ++ AR71XX_SOC_AR9330, ++ AR71XX_SOC_AR9331, ++ AR71XX_SOC_AR9341, ++ AR71XX_SOC_AR9342, ++ AR71XX_SOC_AR9344, +}; ++extern u32 ar71xx_soc_rev; + +extern enum ar71xx_soc_type ar71xx_soc; + @@ -8232,6 +11431,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#define AR724X_DDR_DIV_SHIFT 22 +#define AR724X_DDR_DIV_MASK 0x3 + ++#define AR7242_PLL_REG_ETH0_INT_CLOCK 0x2c ++ +#define AR91XX_PLL_REG_CPU_CONFIG 0x00 +#define AR91XX_PLL_REG_ETH_CONFIG 0x04 +#define AR91XX_PLL_REG_ETH0_INT_CLOCK 0x14 @@ -8247,6 +11448,185 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#define AR91XX_ETH0_PLL_SHIFT 20 +#define AR91XX_ETH1_PLL_SHIFT 22 + ++#define AR933X_PLL_CPU_CONFIG_REG 0x00 ++#define AR933X_PLL_CLOCK_CTRL_REG 0x08 ++ ++#define AR933X_PLL_CPU_CONFIG_NINT_SHIFT 10 ++#define AR933X_PLL_CPU_CONFIG_NINT_MASK 0x3f ++#define AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT 16 ++#define AR933X_PLL_CPU_CONFIG_REFDIV_MASK 0x1f ++#define AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT 23 ++#define AR933X_PLL_CPU_CONFIG_OUTDIV_MASK 0x7 ++ ++#define AR933X_PLL_CLOCK_CTRL_BYPASS BIT(2) ++#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT 5 ++#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK 0x3 ++#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT 10 ++#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK 0x3 ++#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT 15 ++#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK 0x7 ++ ++#define AR934X_PLL_REG_CPU_CONFIG 0x00 ++#define AR934X_PLL_REG_DDR_CTRL_CLOCK 0x8 ++ ++#define AR934X_CPU_PLL_CFG_OUTDIV_MSB 21 ++#define AR934X_CPU_PLL_CFG_OUTDIV_LSB 19 ++#define AR934X_CPU_PLL_CFG_OUTDIV_MASK 0x00380000 ++ ++#define AR934X_CPU_PLL_CFG_OUTDIV_GET(x) \ ++ (((x) & AR934X_CPU_PLL_CFG_OUTDIV_MASK) >> \ ++ AR934X_CPU_PLL_CFG_OUTDIV_LSB) ++ ++#define AR934X_DDR_PLL_CFG_OUTDIV_MSB 25 ++#define AR934X_DDR_PLL_CFG_OUTDIV_LSB 23 ++#define AR934X_DDR_PLL_CFG_OUTDIV_MASK 0x03800000 ++ ++#define AR934X_DDR_PLL_CFG_OUTDIV_GET(x) \ ++ (((x) & AR934X_DDR_PLL_CFG_OUTDIV_MASK) >> \ ++ AR934X_DDR_PLL_CFG_OUTDIV_LSB) ++ ++#define AR934X_DDR_PLL_CFG_OUTDIV_SET(x) \ ++ (((x) << AR934X_DDR_PLL_CFG_OUTDIV_LSB) & \ ++ AR934X_DDR_PLL_CFG_OUTDIV_MASK) ++ ++#define AR934X_CPU_PLL_CFG_REFDIV_MSB 16 ++#define AR934X_CPU_PLL_CFG_REFDIV_LSB 12 ++#define AR934X_CPU_PLL_CFG_REFDIV_MASK 0x0001f000 ++ ++#define AR934X_CPU_PLL_CFG_REFDIV_GET(x) \ ++ (((x) & AR934X_CPU_PLL_CFG_REFDIV_MASK) >> \ ++ AR934X_CPU_PLL_CFG_REFDIV_LSB) ++ ++#define AR934X_CPU_PLL_CFG_REFDIV_SET(x) \ ++ (((x) << AR934X_CPU_PLL_CFG_REFDIV_LSB) & \ ++ AR934X_CPU_PLL_CFG_REFDIV_MASK) ++ ++#define AR934X_CPU_PLL_CFG_REFDIV_RESET 2 ++ ++#define AR934X_CPU_PLL_CFG_NINT_MSB 11 ++#define AR934X_CPU_PLL_CFG_NINT_LSB 6 ++#define AR934X_CPU_PLL_CFG_NINT_MASK 0x00000fc0 ++ ++#define AR934X_CPU_PLL_CFG_NINT_GET(x) \ ++ (((x) & AR934X_CPU_PLL_CFG_NINT_MASK) >> \ ++ AR934X_CPU_PLL_CFG_NINT_LSB) ++ ++#define AR934X_CPU_PLL_CFG_NINT_SET(x) \ ++ (((x) << AR934X_CPU_PLL_CFG_NINT_LSB) & \ ++ AR934X_CPU_PLL_CFG_NINT_MASK) ++ ++#define AR934X_CPU_PLL_CFG_NINT_RESET 20 ++ ++#define AR934X_CPU_PLL_CFG_NFRAC_MSB 5 ++#define AR934X_CPU_PLL_CFG_NFRAC_LSB 0 ++#define AR934X_CPU_PLL_CFG_NFRAC_MASK 0x0000003f ++ ++#define AR934X_CPU_PLL_CFG_NFRAC_GET(x) \ ++ (((x) & AR934X_CPU_PLL_CFG_NFRAC_MASK) >> \ ++ AR934X_CPU_PLL_CFG_NFRAC_LSB) ++ ++#define AR934X_CPU_PLL_CFG_NFRAC_SET(x) \ ++ (((x) << AR934X_CPU_PLL_CFG_NFRAC_LSB) & \ ++ AR934X_CPU_PLL_CFG_NFRAC_MASK) ++ ++#define AR934X_DDR_PLL_CFG_REFDIV_MSB 20 ++#define AR934X_DDR_PLL_CFG_REFDIV_LSB 16 ++#define AR934X_DDR_PLL_CFG_REFDIV_MASK 0x001f0000 ++ ++#define AR934X_DDR_PLL_CFG_REFDIV_GET(x) \ ++ (((x) & AR934X_DDR_PLL_CFG_REFDIV_MASK) >> \ ++ AR934X_DDR_PLL_CFG_REFDIV_LSB) ++ ++#define AR934X_DDR_PLL_CFG_REFDIV_SET(x) \ ++ (((x) << AR934X_DDR_PLL_CFG_REFDIV_LSB) & \ ++ AR934X_DDR_PLL_CFG_REFDIV_MASK) ++ ++#define AR934X_DDR_PLL_CFG_REFDIV_RESET 2 ++ ++#define AR934X_DDR_PLL_CFG_NINT_MSB 15 ++#define AR934X_DDR_PLL_CFG_NINT_LSB 10 ++#define AR934X_DDR_PLL_CFG_NINT_MASK 0x0000fc00 ++ ++#define AR934X_DDR_PLL_CFG_NINT_GET(x) \ ++ (((x) & AR934X_DDR_PLL_CFG_NINT_MASK) >> \ ++ AR934X_DDR_PLL_CFG_NINT_LSB) ++ ++#define AR934X_DDR_PLL_CFG_NINT_SET(x) \ ++ (((x) << AR934X_DDR_PLL_CFG_NINT_LSB) & \ ++ AR934X_DDR_PLL_CFG_NINT_MASK) ++ ++#define AR934X_DDR_PLL_CFG_NINT_RESET 20 ++ ++#define AR934X_DDR_PLL_CFG_NFRAC_MSB 9 ++#define AR934X_DDR_PLL_CFG_NFRAC_LSB 0 ++#define AR934X_DDR_PLL_CFG_NFRAC_MASK 0x000003ff ++ ++#define AR934X_DDR_PLL_CFG_NFRAC_GET(x) \ ++ (((x) & AR934X_DDR_PLL_CFG_NFRAC_MASK) >> \ ++ AR934X_DDR_PLL_CFG_NFRAC_LSB) ++ ++#define AR934X_DDR_PLL_CFG_NFRAC_SET(x) \ ++ (((x) << AR934X_DDR_PLL_CFG_NFRAC_LSB) & \ ++ AR934X_DDR_PLL_CFG_NFRAC_MASK) ++ ++#define AR934X_DDR_PLL_CFG_NFRAC_RESET 512 ++ ++#define AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MSB 19 ++#define AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_LSB 15 ++#define AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK 0x000f8000 ++ ++#define AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_GET(x) \ ++ (((x) & AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK) >> \ ++ AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_LSB) ++ ++#define AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SET(x) \ ++ (((x) << AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_LSB) & \ ++ AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK) ++ ++#define AR934X_CPU_DDR_CLK_CTRL_AHB_POST_DIV_RESET 0 ++ ++#define AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MSB 14 ++#define AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_LSB 10 ++#define AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK 0x00007c00 ++ ++#define AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_GET(x) \ ++ (((x) & AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK) >> \ ++ AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_LSB) ++ ++#define AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SET(x) \ ++ (((x) << AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_LSB) & \ ++ AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK) ++ ++#define AR934X_CPU_DDR_CLK_CTRL_DDR_POST_DIV_RESET 0 ++ ++#define AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MSB 9 ++#define AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_LSB 5 ++#define AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK 0x000003e0 ++ ++#define AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_GET(x) \ ++ (((x) & AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK) >> \ ++ AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_LSB) ++ ++#define AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SET(x) \ ++ (((x) << AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_LSB) & \ ++ AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK) ++ ++#define AR934X_CPU_DDR_CLK_CTRL_CPU_POST_DIV_RESET 0 ++ ++#define AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_MSB 24 ++#define AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_LSB 24 ++#define AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_MASK 0x01000000 ++ ++#define AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_GET(x) \ ++ (((x) & AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_MASK) >> \ ++ AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_LSB) ++ ++#define AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_SET(x) \ ++ (((x) << AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_LSB) & \ ++ AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_MASK) ++ ++#define AR934X_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL_RESET 1 ++ +extern void __iomem *ar71xx_pll_base; + +static inline void ar71xx_pll_wr(unsigned reg, u32 val) @@ -8335,6 +11715,14 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 + +#define AR91XX_GPIO_COUNT 22 + ++#define AR933X_GPIO_COUNT 30 ++ ++#define AR934X_GPIO_FUNC_SPI_CS_1_EN BIT(14) ++#define AR934X_GPIO_FUNC_SPI_CS_0_EN BIT(13) ++ ++#define AR934X_GPIO_COUNT 32 ++#define AR934X_GPIO_FUNC_DDR_DQOE_EN BIT(17) ++ +extern void __iomem *ar71xx_gpio_base; + +static inline void ar71xx_gpio_wr(unsigned reg, u32 value) @@ -8378,6 +11766,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#define AR91XX_DDR_REG_FLUSH_USB 0x84 +#define AR91XX_DDR_REG_FLUSH_WMAC 0x88 + ++#define AR933X_DDR_REG_FLUSH_GE0 0x7c ++#define AR933X_DDR_REG_FLUSH_GE1 0x80 ++#define AR933X_DDR_REG_FLUSH_USB 0x84 ++#define AR933X_DDR_REG_FLUSH_WMAC 0x88 ++ ++#define AR934X_DDR_REG_FLUSH_GE0 0x9c ++#define AR934X_DDR_REG_FLUSH_GE1 0xa0 ++#define AR934X_DDR_REG_FLUSH_USB 0xa4 ++#define AR934X_DDR_REG_FLUSH_PCIE 0xa8 ++ ++ +#define PCI_WIN0_OFFS 0x10000000 +#define PCI_WIN1_OFFS 0x11000000 +#define PCI_WIN2_OFFS 0x12000000 @@ -8465,6 +11864,16 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 + +#define AR724X_RESET_REG_RESET_MODULE 0x1c + ++#define AR933X_RESET_REG_RESET_MODULE 0x1c ++#define AR933X_RESET_REG_BOOTSTRAP 0xac ++#define AR933X_BOOTSTRAP_EEPBUSY BIT(4) ++#define AR933X_BOOTSTRAP_REF_CLK_40 BIT(0) ++ ++#define AR934X_RESET_REG_RESET_MODULE 0x1c ++#define AR934X_RESET_REG_BOOTSTRAP 0xb0 ++/* 0 - 25MHz 1 - 40 MHz */ ++#define AR934X_REF_CLK_40 (1 << 4) ++ +#define WDOG_CTRL_LAST_RESET BIT(31) +#define WDOG_CTRL_ACTION_MASK 3 +#define WDOG_CTRL_ACTION_NONE 0 /* no action */ @@ -8472,6 +11881,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#define WDOG_CTRL_ACTION_NMI 2 /* NMI */ +#define WDOG_CTRL_ACTION_FCR 3 /* full chip reset */ + ++#define MISC_INT_ENET_LINK BIT(12) ++#define MISC_INT_DDR_PERF BIT(11) ++#define MISC_INT_TIMER4 BIT(10) ++#define MISC_INT_TIMER3 BIT(9) ++#define MISC_INT_TIMER2 BIT(8) +#define MISC_INT_DMA BIT(7) +#define MISC_INT_OHCI BIT(6) +#define MISC_INT_PERFC BIT(5) @@ -8512,6 +11926,15 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#define AR724X_RESET_PCIE_PHY_SERIAL BIT(10) +#define AR724X_RESET_PCIE_PHY BIT(7) +#define AR724X_RESET_PCIE BIT(6) ++#define AR724X_RESET_USB_HOST BIT(5) ++#define AR724X_RESET_USB_PHY BIT(4) ++#define AR724X_RESET_USBSUS_OVERRIDE BIT(3) ++ ++#define AR933X_RESET_WMAC BIT(11) ++#define AR933X_RESET_GE1_MDIO BIT(23) ++#define AR933X_RESET_GE0_MDIO BIT(22) ++#define AR933X_RESET_GE1_MAC BIT(13) ++#define AR933X_RESET_GE0_MAC BIT(9) + +#define REV_ID_MAJOR_MASK 0xfff0 +#define REV_ID_MAJOR_AR71XX 0x00a0 @@ -8519,6 +11942,11 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#define REV_ID_MAJOR_AR7240 0x00c0 +#define REV_ID_MAJOR_AR7241 0x0100 +#define REV_ID_MAJOR_AR7242 0x1100 ++#define REV_ID_MAJOR_AR9330 0x0110 ++#define REV_ID_MAJOR_AR9331 0x1110 ++#define REV_ID_MAJOR_AR9341 0x0120 ++#define REV_ID_MAJOR_AR9342 0x1120 ++#define REV_ID_MAJOR_AR9344 0x2120 + +#define AR71XX_REV_ID_MINOR_MASK 0x3 +#define AR71XX_REV_ID_MINOR_AR7130 0x0 @@ -8535,6 +11963,10 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 + +#define AR724X_REV_ID_REVISION_MASK 0x3 + ++#define AR933X_REV_ID_REVISION_MASK 0xf ++ ++#define AR934X_REV_ID_REVISION_MASK 0xf ++ +extern void __iomem *ar71xx_reset_base; + +static inline void ar71xx_reset_wr(unsigned reg, u32 val) @@ -8594,7 +12026,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6 +#endif /* __ASM_MACH_AR71XX_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,26 @@ +/* + * AR91xx parallel flash driver platform data definitions @@ -8622,9 +12054,102 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h lin +}; + +#endif /* __AR91XX_FLASH_H */ +diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h +--- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,67 @@ ++/* ++ * Atheros AR933X UART defines ++ * ++ * Copyright (C) 2011 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 __AR933X_UART_H ++#define __AR933X_UART_H ++ ++#define AR933X_UART_REGS_SIZE 20 ++#define AR933X_UART_FIFO_SIZE 16 ++ ++#define AR933X_UART_DATA_REG 0x00 ++#define AR933X_UART_CS_REG 0x04 ++#define AR933X_UART_CLOCK_REG 0x08 ++#define AR933X_UART_INT_REG 0x0c ++#define AR933X_UART_INT_EN_REG 0x10 ++ ++#define AR933X_UART_DATA_TX_RX_MASK 0xff ++#define AR933X_UART_DATA_RX_CSR BIT(8) ++#define AR933X_UART_DATA_TX_CSR BIT(9) ++ ++#define AR933X_UART_CS_PARITY_S 0 ++#define AR933X_UART_CS_PARITY_M 0x3 ++#define AR933X_UART_CS_PARITY_NONE 0 ++#define AR933X_UART_CS_PARITY_ODD 1 ++#define AR933X_UART_CS_PARITY_EVEN 2 ++#define AR933X_UART_CS_IF_MODE_S 2 ++#define AR933X_UART_CS_IF_MODE_M 0x3 ++#define AR933X_UART_CS_IF_MODE_NONE 0 ++#define AR933X_UART_CS_IF_MODE_DTE 1 ++#define AR933X_UART_CS_IF_MODE_DCE 2 ++#define AR933X_UART_CS_FLOW_CTRL_S 4 ++#define AR933X_UART_CS_FLOW_CTRL_M 0x3 ++#define AR933X_UART_CS_DMA_EN BIT(6) ++#define AR933X_UART_CS_TX_READY_ORIDE BIT(7) ++#define AR933X_UART_CS_RX_READY_ORIDE BIT(8) ++#define AR933X_UART_CS_TX_READY BIT(9) ++#define AR933X_UART_CS_RX_BREAK BIT(10) ++#define AR933X_UART_CS_TX_BREAK BIT(11) ++#define AR933X_UART_CS_HOST_INT BIT(12) ++#define AR933X_UART_CS_HOST_INT_EN BIT(13) ++#define AR933X_UART_CS_TX_BUSY BIT(14) ++#define AR933X_UART_CS_RX_BUSY BIT(15) ++ ++#define AR933X_UART_CLOCK_STEP_M 0xffff ++#define AR933X_UART_CLOCK_SCALE_M 0xfff ++#define AR933X_UART_CLOCK_SCALE_S 16 ++#define AR933X_UART_CLOCK_STEP_M 0xffff ++ ++#define AR933X_UART_INT_RX_VALID BIT(0) ++#define AR933X_UART_INT_TX_READY BIT(1) ++#define AR933X_UART_INT_RX_FRAMING_ERR BIT(2) ++#define AR933X_UART_INT_RX_OFLOW_ERR BIT(3) ++#define AR933X_UART_INT_TX_OFLOW_ERR BIT(4) ++#define AR933X_UART_INT_RX_PARITY_ERR BIT(5) ++#define AR933X_UART_INT_RX_BREAK_ON BIT(6) ++#define AR933X_UART_INT_RX_BREAK_OFF BIT(7) ++#define AR933X_UART_INT_RX_FULL BIT(8) ++#define AR933X_UART_INT_TX_EMPTY BIT(9) ++#define AR933X_UART_INT_ALLINTS 0x3ff ++ ++#endif /* __AR933X_UART_H */ +diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar933x_uart_platform.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar933x_uart_platform.h +--- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/ar933x_uart_platform.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/ar933x_uart_platform.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Platform data definition for Atheros AR933X UART ++ * ++ * Copyright (C) 2011 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 _AR933X_UART_PLATFORM_H ++#define _AR933X_UART_PLATFORM_H ++ ++struct ar933x_uart_platform_data { ++ unsigned uartclk; ++}; ++ ++#endif /* _AR933X_UART_PLATFORM_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,56 @@ +/* + * Atheros AR71xx specific CPU feature overrides @@ -8684,7 +12209,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/cpu-feature-overri +#endif /* __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/gpio.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/gpio.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/gpio.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/gpio.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/gpio.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,53 @@ +/* + * Atheros AR71xx GPIO API definitions @@ -8741,7 +12266,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/gpio.h linux-2.6.3 +#endif /* __ASM_MACH_AR71XX_GPIO_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/irq.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/irq.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/irq.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/irq.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/irq.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> @@ -8755,14 +12280,14 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/irq.h linux-2.6.39 +#define __ASM_MACH_AR71XX_IRQ_H + +#define MIPS_CPU_IRQ_BASE 0 -+#define NR_IRQS 56 ++#define NR_IRQS 80 + +#include_next <irq.h> + +#endif /* __ASM_MACH_AR71XX_IRQ_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,32 @@ +/* + * Atheros AR71xx specific kernel entry setup @@ -8798,7 +12323,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/kernel-entry-init. +#endif /* __ASM_MACH_AR71XX_KERNEL_ENTRY_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/mach-rb750.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/mach-rb750.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/mach-rb750.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/mach-rb750.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/mach-rb750.h 2011-08-24 18:17:23.000000000 +0200 @@ -0,0 +1,66 @@ +/* + * MikroTik RouterBOARD 750 definitions @@ -8869,14 +12394,14 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/mach-rb750.h linux \ No newline at end of file diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/mangle-port.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/mangle-port.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/mangle-port.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/mangle-port.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/mangle-port.h 2011-08-24 18:17:23.000000000 +0200 @@ -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 ++ * 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 @@ -8918,8 +12443,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/mangle-port.h linu +#endif /* __ASM_MACH_AR71XX_MANGLE_PORT_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/pci.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/pci.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/pci.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/pci.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,39 @@ ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/pci.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,46 @@ +/* + * Atheros AR71xx SoC specific PCI definitions + * @@ -8942,6 +12467,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/pci.h linux-2.6.39 + u8 pin; +}; + ++#ifdef CONFIG_PCI +extern int (*ar71xx_pci_plat_dev_init)(struct pci_dev *dev); +extern unsigned ar71xx_pci_nr_irqs __initdata; +extern struct ar71xx_pci_irq *ar71xx_pci_irq_map __initdata; @@ -8957,12 +12483,18 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/pci.h linux-2.6.39 +int ar724x_pcibios_init(void) __init; + +int ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map) __init; ++#else ++static inline int ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map) ++{ ++ return 0; ++} ++#endif + +#endif /* __ASM_MACH_AR71XX_PCI_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/platform.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/platform.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/platform.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/platform.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,61 @@ ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/platform.h 2011-08-24 18:17:23.000000000 +0200 +@@ -0,0 +1,63 @@ +/* + * Atheros AR71xx SoC specific platform data definitions + * @@ -8994,11 +12526,13 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/platform.h linux-2 + + u8 has_gbit:1; + u8 is_ar91xx:1; ++ u8 is_ar7240:1; + u8 is_ar724x:1; + u8 has_ar8216:1; ++ u8 has_ar7240_switch:1; + -+ void (* ddr_flush)(void); -+ void (* set_pll)(int speed); ++ void (*ddr_flush)(void); ++ void (*set_pll)(int speed); + + u32 fifo_cfg1; + u32 fifo_cfg2; @@ -9024,9 +12558,61 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/platform.h linux-2 +#define AR71XX_SPI_CS_ACTIVE 1 + +#endif /* __ASM_MACH_AR71XX_PLATFORM_H */ +diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/rb4xx_cpld.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/rb4xx_cpld.h +--- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/rb4xx_cpld.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/rb4xx_cpld.h 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,48 @@ ++/* ++ * SPI driver definitions for the CPLD chip on the Mikrotik RB4xx boards ++ * ++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file was based on the patches for Linux 2.6.27.39 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. ++ */ ++ ++#define CPLD_GPIO_nLED1 0 ++#define CPLD_GPIO_nLED2 1 ++#define CPLD_GPIO_nLED3 2 ++#define CPLD_GPIO_nLED4 3 ++#define CPLD_GPIO_FAN 4 ++#define CPLD_GPIO_ALE 5 ++#define CPLD_GPIO_CLE 6 ++#define CPLD_GPIO_nCE 7 ++#define CPLD_GPIO_nLED5 8 ++ ++#define CPLD_NUM_GPIOS 9 ++ ++#define CPLD_CFG_nLED1 BIT(CPLD_GPIO_nLED1) ++#define CPLD_CFG_nLED2 BIT(CPLD_GPIO_nLED2) ++#define CPLD_CFG_nLED3 BIT(CPLD_GPIO_nLED3) ++#define CPLD_CFG_nLED4 BIT(CPLD_GPIO_nLED4) ++#define CPLD_CFG_FAN BIT(CPLD_GPIO_FAN) ++#define CPLD_CFG_ALE BIT(CPLD_GPIO_ALE) ++#define CPLD_CFG_CLE BIT(CPLD_GPIO_CLE) ++#define CPLD_CFG_nCE BIT(CPLD_GPIO_nCE) ++#define CPLD_CFG_nLED5 BIT(CPLD_GPIO_nLED5) ++ ++struct rb4xx_cpld_platform_data { ++ unsigned gpio_base; ++}; ++ ++extern int rb4xx_cpld_change_cfg(unsigned mask, unsigned value); ++extern int rb4xx_cpld_read(unsigned char *rx_buf, ++ const unsigned char *verify_buf, ++ unsigned cnt); ++extern int rb4xx_cpld_read_from(unsigned addr, ++ unsigned char *rx_buf, ++ const unsigned char *verify_buf, ++ unsigned cnt); ++extern int rb4xx_cpld_write(const unsigned char *buf, unsigned count); diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/war.h linux-2.6.39/arch/mips/include/asm/mach-ar71xx/war.h --- linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/war.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/war.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/mach-ar71xx/war.h 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public @@ -9055,7 +12641,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/mach-ar71xx/war.h linux-2.6.39 +#endif /* __ASM_MACH_AR71XX_WAR_H */ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/time.h linux-2.6.39/arch/mips/include/asm/time.h --- linux-2.6.39.orig/arch/mips/include/asm/time.h 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/mips/include/asm/time.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/include/asm/time.h 2011-08-24 18:17:24.000000000 +0200 @@ -52,6 +52,7 @@ */ #ifdef CONFIG_CEVT_R4K_LIB @@ -9064,28 +12650,17 @@ diff -Nur linux-2.6.39.orig/arch/mips/include/asm/time.h linux-2.6.39/arch/mips/ extern int r4k_clockevent_init(void); #endif -diff -Nur linux-2.6.39.orig/arch/mips/kernel/Makefile linux-2.6.39/arch/mips/kernel/Makefile ---- linux-2.6.39.orig/arch/mips/kernel/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/mips/kernel/Makefile 2011-05-27 14:36:51.000000000 +0200 -@@ -94,6 +94,7 @@ - - obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o - obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -+obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o - obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o - obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o - diff -Nur linux-2.6.39.orig/arch/mips/kernel/traps.c linux-2.6.39/arch/mips/kernel/traps.c --- linux-2.6.39.orig/arch/mips/kernel/traps.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/mips/kernel/traps.c 2011-05-27 14:36:51.000000000 +0200 -@@ -46,6 +46,7 @@ - #include <asm/ptrace.h> - #include <asm/sections.h> - #include <asm/system.h> ++++ linux-2.6.39/arch/mips/kernel/traps.c 2011-08-24 18:17:24.000000000 +0200 +@@ -54,6 +54,7 @@ + #include <asm/types.h> + #include <asm/stacktrace.h> + #include <asm/uasm.h> +#include <asm/time.h> - #include <asm/tlbdebug.h> - #include <asm/traps.h> - #include <asm/uaccess.h> + + extern void check_wait(void); + extern asmlinkage void r4k_wait(void); @@ -1576,6 +1577,8 @@ if (cpu_has_mips_r2) { cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; @@ -9097,7 +12672,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/kernel/traps.c linux-2.6.39/arch/mips/kern cp0_perfcount_irq = -1; diff -Nur linux-2.6.39.orig/arch/mips/pci/Makefile linux-2.6.39/arch/mips/pci/Makefile --- linux-2.6.39.orig/arch/mips/pci/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/mips/pci/Makefile 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/arch/mips/pci/Makefile 2011-08-24 18:17:24.000000000 +0200 @@ -18,6 +18,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ @@ -9108,8 +12683,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/Makefile linux-2.6.39/arch/mips/pci/Ma # These are still pretty much in the old state, watch, go blind. diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pci/pci-ar71xx.c --- linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/pci/pci-ar71xx.c 2011-06-01 14:02:22.000000000 +0200 -@@ -0,0 +1,408 @@ ++++ linux-2.6.39/arch/mips/pci/pci-ar71xx.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,415 @@ +/* + * Atheros AR71xx PCI host controller driver + * @@ -9219,7 +12794,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc + __raw_writel(ahb_err, base + PCI_REG_AHB_ERR); + } + -+ return ((ahb_err | pci_err) ? 1 : 0); ++ return (ahb_err | pci_err) ? 1 : 0; +} + +static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, @@ -9248,6 +12823,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc + static u32 mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0}; + unsigned long flags; + u32 data; ++ int retry = 0; + int ret; + + ret = PCIBIOS_SUCCESSFUL; @@ -9255,6 +12831,7 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc + DBG("PCI: read config: %02x:%02x.%01x/%02x:%01d\n", bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); + ++retry: + spin_lock_irqsave(&ar71xx_pci_lock, flags); + + if (bus->number == 0 && devfn == 0) { @@ -9288,6 +12865,14 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc + + *value = (data >> (8 * (where & 3))) & mask[size & 7]; + ++ /* ++ * PCI controller bug: sometimes reads to the PCI_COMMAND register ++ * return 0xffff, even though the PCI trace shows the correct value. ++ * Work around this by retrying reads to this register ++ */ ++ if (where == PCI_COMMAND && (*value & 0xffff) == 0xffff && retry++ < 2) ++ goto retry; ++ + return ret; +} + @@ -9433,13 +13018,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc + +static void ar71xx_pci_irq_unmask(struct irq_data *d) +{ ++ unsigned int irq = d->irq - AR71XX_PCI_IRQ_BASE; + void __iomem *base = ar71xx_reset_base; + u32 t; + -+ d->irq -= AR71XX_PCI_IRQ_BASE; -+ + t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+ __raw_writel(t | (1 << d->irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); ++ __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); @@ -9447,13 +13031,12 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc + +static void ar71xx_pci_irq_mask(struct irq_data *d) +{ ++ unsigned int irq = d->irq - AR71XX_PCI_IRQ_BASE; + void __iomem *base = ar71xx_reset_base; + u32 t; + -+ d->irq -= AR71XX_PCI_IRQ_BASE; -+ + t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+ __raw_writel(t & ~(1 << d->irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); ++ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); @@ -9461,8 +13044,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc + +static struct irq_chip ar71xx_pci_irq_chip = { + .name = "AR71XX PCI ", -+ .irq_mask = ar71xx_pci_irq_mask, -+ .irq_unmask = ar71xx_pci_irq_unmask, ++ .irq_mask = ar71xx_pci_irq_mask, ++ .irq_unmask = ar71xx_pci_irq_unmask, + .irq_mask_ack = ar71xx_pci_irq_mask, +}; + @@ -9475,10 +13058,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc + __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS); + + for (i = AR71XX_PCI_IRQ_BASE; -+ i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) { ++ i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, + handle_level_irq); -+ } + + irq_set_chained_handler(AR71XX_CPU_IRQ_IP2, ar71xx_pci_irq_handler); +} @@ -9520,8 +13102,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.39/arch/mips/pc +} diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c linux-2.6.39/arch/mips/pci/pci-ar724x.c --- linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/mips/pci/pci-ar724x.c 2011-06-01 14:02:22.000000000 +0200 -@@ -0,0 +1,394 @@ ++++ linux-2.6.39/arch/mips/pci/pci-ar724x.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,389 @@ +/* + * Atheros AR724x PCI host controller driver + * @@ -9635,10 +13217,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c linux-2.6.39/arch/mips/pc + * if we set the BAR with proper base address + */ + if ((where == 0x10) && (size == 4)) { -+ if (ar71xx_soc == AR71XX_SOC_AR7240) -+ ar724x_pci_write(ar724x_pci_devcfg_base, where, size, 0xffff); -+ else -+ ar724x_pci_write(ar724x_pci_devcfg_base, where, size, 0x1000ffff); ++ u32 val; ++ val = (ar71xx_soc == AR71XX_SOC_AR7240) ? 0xffff : 0x1000ffff; ++ ar724x_pci_write(ar724x_pci_devcfg_base, where, size, val); + } + + return PCIBIOS_SUCCESSFUL; @@ -9780,7 +13361,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c linux-2.6.39/arch/mips/pc + return -ENODEV; + } + -+ if (ar71xx_soc == AR71XX_SOC_AR7241 || ar71xx_soc == AR71XX_SOC_AR7242) { ++ if (ar71xx_soc == AR71XX_SOC_AR7241 || ++ ar71xx_soc == AR71XX_SOC_AR7242) { + t = __raw_readl(base + AR724X_PCI_REG_APP); + t |= BIT(16); + __raw_writel(t, base + AR724X_PCI_REG_APP); @@ -9811,8 +13393,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c linux-2.6.39/arch/mips/pc + + switch (d->irq) { + case AR71XX_PCI_IRQ_DEV0: -+ d->irq -= AR71XX_PCI_IRQ_BASE; -+ + t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); + __raw_writel(t | AR724X_PCI_INT_DEV0, + base + AR724X_PCI_REG_INT_MASK); @@ -9828,8 +13408,6 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c linux-2.6.39/arch/mips/pc + + switch (d->irq) { + case AR71XX_PCI_IRQ_DEV0: -+ d->irq -= AR71XX_PCI_IRQ_BASE; -+ + t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); + __raw_writel(t & ~AR724X_PCI_INT_DEV0, + base + AR724X_PCI_REG_INT_MASK); @@ -9848,8 +13426,8 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c linux-2.6.39/arch/mips/pc + +static struct irq_chip ar724x_pci_irq_chip = { + .name = "AR724X PCI ", -+ .irq_mask = ar724x_pci_irq_mask, -+ .irq_unmask = ar724x_pci_irq_unmask, ++ .irq_mask = ar724x_pci_irq_mask, ++ .irq_unmask = ar724x_pci_irq_unmask, + .irq_mask_ack = ar724x_pci_irq_mask, +}; + @@ -9869,10 +13447,9 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c linux-2.6.39/arch/mips/pc + __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); + + for (i = AR71XX_PCI_IRQ_BASE; -+ i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) { ++ i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, + handle_level_irq); -+ } + + irq_set_chained_handler(AR71XX_CPU_IRQ_IP2, ar724x_pci_irq_handler); +} @@ -9907,48 +13484,32 @@ diff -Nur linux-2.6.39.orig/arch/mips/pci/pci-ar724x.c linux-2.6.39/arch/mips/pc + + return 0; + -+ err_unmap_ctrl: ++err_unmap_ctrl: + iounmap(ar724x_pci_ctrl_base); -+ err_unmap_devcfg: ++err_unmap_devcfg: + iounmap(ar724x_pci_devcfg_base); -+ err_unmap_localcfg: ++err_unmap_localcfg: + iounmap(ar724x_pci_localcfg_base); -+ err: ++err: + return ret; +} -diff -Nur linux-2.6.39.orig/drivers/char/Kconfig linux-2.6.39/drivers/char/Kconfig ---- linux-2.6.39.orig/drivers/char/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/char/Kconfig 2011-05-27 14:36:51.000000000 +0200 -@@ -511,6 +511,14 @@ - pc8736x_gpio drivers. If those drivers are built as - modules, this one will be too, named nsc_gpio - -+config GPIO_DEVICE -+ tristate "GPIO device support" -+ depends on GENERIC_GPIO -+ help -+ Say Y to enable Linux GPIO device support. This allows control of -+ GPIO pins using a character device -+ -+ - config RAW_DRIVER - tristate "RAW driver (/dev/raw/rawN)" - depends on BLOCK -diff -Nur linux-2.6.39.orig/drivers/char/Makefile linux-2.6.39/drivers/char/Makefile ---- linux-2.6.39.orig/drivers/char/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/char/Makefile 2011-05-27 14:36:51.000000000 +0200 -@@ -47,6 +47,7 @@ - obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o - obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o - obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o -+obj-$(CONFIG_GPIO_DEVICE) += gpio_dev.o - obj-$(CONFIG_GPIO_TB0219) += tb0219.o - obj-$(CONFIG_TELCLOCK) += tlclk.o - +diff -Nur linux-2.6.39.orig/drivers/Makefile linux-2.6.39/drivers/Makefile +--- linux-2.6.39.orig/drivers/Makefile 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/drivers/Makefile 2011-08-24 18:17:24.000000000 +0200 +@@ -46,8 +46,8 @@ + obj-$(CONFIG_SCSI) += scsi/ + obj-$(CONFIG_ATA) += ata/ + obj-$(CONFIG_TARGET_CORE) += target/ +-obj-$(CONFIG_MTD) += mtd/ + obj-$(CONFIG_SPI) += spi/ ++obj-$(CONFIG_MTD) += mtd/ + obj-y += net/ + obj-$(CONFIG_ATM) += atm/ + obj-$(CONFIG_FUSION) += message/ diff -Nur linux-2.6.39.orig/drivers/gpio/nxp_74hc153.c linux-2.6.39/drivers/gpio/nxp_74hc153.c --- linux-2.6.39.orig/drivers/gpio/nxp_74hc153.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/gpio/nxp_74hc153.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,246 @@ ++++ linux-2.6.39/drivers/gpio/nxp_74hc153.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,247 @@ +/* + * NXP 74HC153 - Dual 4-input multiplexer GPIO driver + * @@ -9962,6 +13523,7 @@ diff -Nur linux-2.6.39.orig/drivers/gpio/nxp_74hc153.c linux-2.6.39/drivers/gpio +#include <linux/module.h> +#include <linux/init.h> +#include <linux/gpio.h> ++#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/nxp_74hc153.h> + @@ -10129,15 +13691,15 @@ diff -Nur linux-2.6.39.orig/drivers/gpio/nxp_74hc153.c linux-2.6.39/drivers/gpio + platform_set_drvdata(pdev, nxp); + return 0; + -+ err_free_2y: ++err_free_2y: + gpio_free(pdata->gpio_pin_2y); -+ err_free_1y: ++err_free_1y: + gpio_free(pdata->gpio_pin_1y); -+ err_free_s1: ++err_free_s1: + gpio_free(pdata->gpio_pin_s1); -+ err_free_s0: ++err_free_s0: + gpio_free(pdata->gpio_pin_s0); -+ err_free_nxp: ++err_free_nxp: + kfree(nxp); + return err; +} @@ -10195,263 +13757,10 @@ diff -Nur linux-2.6.39.orig/drivers/gpio/nxp_74hc153.c linux-2.6.39/drivers/gpio +MODULE_DESCRIPTION("GPIO expander driver for NXP 74HC153"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" NXP_74HC153_DRIVER_NAME); -diff -Nur linux-2.6.39.orig/drivers/input/misc/Kconfig linux-2.6.39/drivers/input/misc/Kconfig ---- linux-2.6.39.orig/drivers/input/misc/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/input/misc/Kconfig 2011-05-27 14:36:51.000000000 +0200 -@@ -467,4 +467,20 @@ - To compile this driver as a module, choose M here: the - module will be called xen-kbdfront. - -+config INPUT_GPIO_BUTTONS -+ tristate "Polled GPIO buttons interface" -+ depends on GENERIC_GPIO -+ select INPUT_POLLDEV -+ help -+ This driver implements support for buttons connected -+ to GPIO pins of various CPUs (and some other chips). -+ -+ Say Y here if your device has buttons connected -+ directly to such GPIO pins. Your board-specific -+ setup logic must also provide a platform device, -+ with configuration data saying which GPIOs are used. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called gpio-buttons. -+ - endif -diff -Nur linux-2.6.39.orig/drivers/input/misc/Makefile linux-2.6.39/drivers/input/misc/Makefile ---- linux-2.6.39.orig/drivers/input/misc/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/input/misc/Makefile 2011-05-27 14:36:51.000000000 +0200 -@@ -44,4 +44,5 @@ - obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o - obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o - obj-$(CONFIG_INPUT_YEALINK) += yealink.o -+obj-$(CONFIG_INPUT_GPIO_BUTTONS) += gpio_buttons.o - -diff -Nur linux-2.6.39.orig/drivers/input/misc/gpio_buttons.c linux-2.6.39/drivers/input/misc/gpio_buttons.c ---- linux-2.6.39.orig/drivers/input/misc/gpio_buttons.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/input/misc/gpio_buttons.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,216 @@ -+/* -+ * Driver for buttons on GPIO lines not capable of generating interrupts -+ * -+ * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com> -+ * -+ * This file was based on: /drivers/input/misc/cobalt_btns.c -+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> -+ * -+ * also was based on: /drivers/input/keyboard/gpio_keys.c -+ * Copyright 2005 Phil Blundell -+ * -+ * 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/slab.h> -+ -+#include <linux/input.h> -+#include <linux/input-polldev.h> -+#include <linux/ioport.h> -+#include <linux/platform_device.h> -+ -+#include <linux/gpio_buttons.h> -+ -+#include <asm/gpio.h> -+ -+#define DRV_NAME "gpio-buttons" -+#define DRV_VERSION "0.1.2" -+#define PFX DRV_NAME ": " -+ -+struct gpio_button_data { -+ int last_state; -+ int count; -+}; -+ -+struct gpio_buttons_dev { -+ struct input_polled_dev *poll_dev; -+ struct gpio_buttons_platform_data *pdata; -+ struct gpio_button_data *data; -+}; -+ -+static void gpio_buttons_poll(struct input_polled_dev *dev) -+{ -+ struct gpio_buttons_dev *bdev = dev->private; -+ struct gpio_buttons_platform_data *pdata = bdev->pdata; -+ struct input_dev *input = dev->input; -+ int i; -+ -+ for (i = 0; i < bdev->pdata->nbuttons; i++) { -+ struct gpio_button *button = &pdata->buttons[i]; -+ unsigned int type = button->type ?: EV_KEY; -+ int state; -+ -+ if (bdev->data[i].count < button->threshold) { -+ bdev->data[i].count++; -+ continue; -+ } -+ -+ state = gpio_get_value(button->gpio) ? 1 : 0; -+ if (state != bdev->data[i].last_state) { -+ input_event(input, type, button->code, -+ !!(state ^ button->active_low)); -+ input_sync(input); -+ bdev->data[i].count = 0; -+ bdev->data[i].last_state = state; -+ } -+ } -+} -+ -+static int __devinit gpio_buttons_probe(struct platform_device *pdev) -+{ -+ struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data; -+ struct gpio_buttons_dev *bdev; -+ struct input_polled_dev *poll_dev; -+ struct input_dev *input; -+ int error, i; -+ -+ if (!pdata) -+ return -ENXIO; -+ -+ bdev = kzalloc(sizeof(struct gpio_buttons_dev) + -+ sizeof(struct gpio_button_data) * pdata->nbuttons, -+ GFP_KERNEL); -+ if (!bdev) { -+ printk(KERN_ERR DRV_NAME "no memory for device\n"); -+ return -ENOMEM; -+ } -+ -+ bdev->data = (struct gpio_button_data *) &bdev[1]; -+ -+ poll_dev = input_allocate_polled_device(); -+ if (!poll_dev) { -+ printk(KERN_ERR DRV_NAME "no memory for polled device\n"); -+ error = -ENOMEM; -+ goto err_free_bdev; -+ } -+ -+ poll_dev->private = bdev; -+ poll_dev->poll = gpio_buttons_poll; -+ poll_dev->poll_interval = pdata->poll_interval; -+ -+ input = poll_dev->input; -+ -+ input->evbit[0] = BIT(EV_KEY); -+ input->name = pdev->name; -+ input->phys = "gpio-buttons/input0"; -+ input->dev.parent = &pdev->dev; -+ -+ input->id.bustype = BUS_HOST; -+ input->id.vendor = 0x0001; -+ input->id.product = 0x0001; -+ input->id.version = 0x0100; -+ -+ for (i = 0; i < pdata->nbuttons; i++) { -+ struct gpio_button *button = &pdata->buttons[i]; -+ unsigned int gpio = button->gpio; -+ unsigned int type = button->type ?: EV_KEY; -+ -+ error = gpio_request(gpio, button->desc ? -+ button->desc : DRV_NAME); -+ if (error) { -+ printk(KERN_ERR PFX "unable to claim gpio %u, " -+ "error %d\n", gpio, error); -+ goto err_free_gpio; -+ } -+ -+ error = gpio_direction_input(gpio); -+ if (error) { -+ printk(KERN_ERR PFX "unable to set direction on " -+ "gpio %u, error %d\n", gpio, error); -+ goto err_free_gpio; -+ } -+ -+ input_set_capability(input, type, button->code); -+ bdev->data[i].last_state = gpio_get_value(button->gpio) ? 1 : 0; -+ } -+ -+ bdev->poll_dev = poll_dev; -+ bdev->pdata = pdata; -+ platform_set_drvdata(pdev, bdev); -+ -+ error = input_register_polled_device(poll_dev); -+ if (error) { -+ printk(KERN_ERR PFX "unable to register polled device, " -+ "error %d\n", error); -+ goto err_free_gpio; -+ } -+ -+ return 0; -+ -+err_free_gpio: -+ for (i = i - 1; i >= 0; i--) -+ gpio_free(pdata->buttons[i].gpio); -+ -+ input_free_polled_device(poll_dev); -+ -+err_free_bdev: -+ kfree(bdev); -+ -+ platform_set_drvdata(pdev, NULL); -+ return error; -+} -+ -+static int __devexit gpio_buttons_remove(struct platform_device *pdev) -+{ -+ struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev); -+ struct gpio_buttons_platform_data *pdata = bdev->pdata; -+ int i; -+ -+ input_unregister_polled_device(bdev->poll_dev); -+ -+ for (i = 0; i < pdata->nbuttons; i++) -+ gpio_free(pdata->buttons[i].gpio); -+ -+ input_free_polled_device(bdev->poll_dev); -+ -+ kfree(bdev); -+ platform_set_drvdata(pdev, NULL); -+ -+ return 0; -+} -+ -+static struct platform_driver gpio_buttons_driver = { -+ .probe = gpio_buttons_probe, -+ .remove = __devexit_p(gpio_buttons_remove), -+ .driver = { -+ .name = DRV_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init gpio_buttons_init(void) -+{ -+ printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n"); -+ return platform_driver_register(&gpio_buttons_driver); -+} -+ -+static void __exit gpio_buttons_exit(void) -+{ -+ platform_driver_unregister(&gpio_buttons_driver); -+} -+ -+module_init(gpio_buttons_init); -+module_exit(gpio_buttons_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>"); -+MODULE_VERSION(DRV_VERSION); -+MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs"); -+ diff -Nur linux-2.6.39.orig/drivers/leds/leds-rb750.c linux-2.6.39/drivers/leds/leds-rb750.c --- linux-2.6.39.orig/drivers/leds/leds-rb750.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/leds/leds-rb750.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,140 @@ ++++ linux-2.6.39/drivers/leds/leds-rb750.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,141 @@ +/* + * LED driver for the RouterBOARD 750 + * @@ -10466,6 +13775,7 @@ diff -Nur linux-2.6.39.orig/drivers/leds/leds-rb750.c linux-2.6.39/drivers/leds/ +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> ++#include <linux/slab.h> + +#include <asm/mach-ar71xx/mach-rb750.h> + @@ -10543,7 +13853,7 @@ diff -Nur linux-2.6.39.orig/drivers/leds/leds-rb750.c linux-2.6.39/drivers/leds/ + platform_set_drvdata(pdev, drvdata); + return 0; + -+ err: ++err: + for (i = i - 1; i >= 0; i--) + led_classdev_unregister(&drvdata->led_devs[i].cdev); + @@ -10594,7 +13904,7 @@ diff -Nur linux-2.6.39.orig/drivers/leds/leds-rb750.c linux-2.6.39/drivers/leds/ +MODULE_LICENSE("GPL v2"); diff -Nur linux-2.6.39.orig/drivers/leds/leds-wndr3700-usb.c linux-2.6.39/drivers/leds/leds-wndr3700-usb.c --- linux-2.6.39.orig/drivers/leds/leds-wndr3700-usb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/leds/leds-wndr3700-usb.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/leds/leds-wndr3700-usb.c 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,75 @@ +/* + * USB LED driver for the NETGEAR WNDR3700 @@ -10671,9 +13981,71 @@ diff -Nur linux-2.6.39.orig/drivers/leds/leds-wndr3700-usb.c linux-2.6.39/driver +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); +diff -Nur linux-2.6.39.orig/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.6.39/drivers/mtd/chips/cfi_cmdset_0002.c +--- linux-2.6.39.orig/drivers/mtd/chips/cfi_cmdset_0002.c 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/drivers/mtd/chips/cfi_cmdset_0002.c 2011-08-24 18:17:24.000000000 +0200 +@@ -39,7 +39,7 @@ + #include <linux/mtd/xip.h> + + #define AMD_BOOTLOC_BUG +-#define FORCE_WORD_WRITE 0 ++#define FORCE_WORD_WRITE 1 + + #define MAX_WORD_RETRIES 3 + +@@ -50,7 +50,9 @@ + + static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); + static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); ++#if !FORCE_WORD_WRITE + static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); ++#endif + static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *); + static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); + static void cfi_amdstd_sync (struct mtd_info *); +@@ -186,6 +188,7 @@ + } + #endif + ++#if !FORCE_WORD_WRITE + static void fixup_use_write_buffers(struct mtd_info *mtd) + { + struct map_info *map = mtd->priv; +@@ -195,6 +198,7 @@ + mtd->write = cfi_amdstd_write_buffers; + } + } ++#endif /* !FORCE_WORD_WRITE */ + + /* Atmel chips don't use the same PRI format as AMD chips */ + static void fixup_convert_atmel_pri(struct mtd_info *mtd) +@@ -1377,6 +1381,7 @@ + /* + * FIXME: interleaved mode not tested, and probably not supported! + */ ++#if !FORCE_WORD_WRITE + static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, + unsigned long adr, const u_char *buf, + int len) +@@ -1487,7 +1492,6 @@ + return ret; + } + +- + static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) + { +@@ -1566,6 +1570,7 @@ + + return 0; + } ++#endif /* !FORCE_WORD_WRITE */ + + + /* diff -Nur linux-2.6.39.orig/drivers/mtd/maps/Kconfig linux-2.6.39/drivers/mtd/maps/Kconfig --- linux-2.6.39.orig/drivers/mtd/maps/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/mtd/maps/Kconfig 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/mtd/maps/Kconfig 2011-08-24 18:17:24.000000000 +0200 @@ -260,6 +260,13 @@ Support for parsing CFE image tag and creating MTD partitions on Broadcom BCM63xx boards. @@ -10690,18 +14062,18 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/maps/Kconfig linux-2.6.39/drivers/mtd/ma depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN diff -Nur linux-2.6.39.orig/drivers/mtd/maps/Makefile linux-2.6.39/drivers/mtd/maps/Makefile --- linux-2.6.39.orig/drivers/mtd/maps/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/mtd/maps/Makefile 2011-05-27 14:36:51.000000000 +0200 -@@ -7,6 +7,7 @@ - endif - - # Chip mappings ++++ linux-2.6.39/drivers/mtd/maps/Makefile 2011-08-24 18:17:24.000000000 +0200 +@@ -40,6 +40,7 @@ + obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o + obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o + obj-$(CONFIG_MTD_PCI) += pci.o +obj-$(CONFIG_MTD_AR91XX_FLASH) += ar91xx_flash.o - obj-$(CONFIG_MTD_CDB89712) += cdb89712.o - obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o - obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o + obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o + obj-$(CONFIG_MTD_EDB7312) += edb7312.o + obj-$(CONFIG_MTD_IMPA7) += impa7.o diff -Nur linux-2.6.39.orig/drivers/mtd/maps/ar91xx_flash.c linux-2.6.39/drivers/mtd/maps/ar91xx_flash.c --- linux-2.6.39.orig/drivers/mtd/maps/ar91xx_flash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/mtd/maps/ar91xx_flash.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/mtd/maps/ar91xx_flash.c 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,310 @@ +/* + * Parallel flash driver for the Atheros AR91xx SoC @@ -10932,7 +14304,7 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/maps/ar91xx_flash.c linux-2.6.39/drivers + add_mtd_device(info->mtd); + return 0; + -+ err_out: ++err_out: + ar91xx_flash_remove(pdev); + return err; +} @@ -10951,7 +14323,7 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/maps/ar91xx_flash.c linux-2.6.39/drivers + + return 0; + -+ fail: ++fail: + if (info->mtd->suspend) { + BUG_ON(!info->mtd->resume); + info->mtd->resume(info->mtd); @@ -11015,19 +14387,20 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/maps/ar91xx_flash.c linux-2.6.39/drivers +MODULE_ALIAS("platform:" DRV_NAME); diff -Nur linux-2.6.39.orig/drivers/mtd/nand/Kconfig linux-2.6.39/drivers/mtd/nand/Kconfig --- linux-2.6.39.orig/drivers/mtd/nand/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/mtd/nand/Kconfig 2011-05-27 14:36:51.000000000 +0200 -@@ -531,4 +531,8 @@ ++++ linux-2.6.39/drivers/mtd/nand/Kconfig 2011-08-24 18:17:24.000000000 +0200 +@@ -531,4 +531,9 @@ Enables support for NAND Flash chips on the ST Microelectronics Flexible Static Memory Controller (FSMC) +config MTD_NAND_RB4XX + tristate "NAND flash driver for RouterBoard 4xx series" + depends on MTD_NAND && AR71XX_MACH_RB4XX ++ select SPI_AR71XX + endif # MTD_NAND diff -Nur linux-2.6.39.orig/drivers/mtd/nand/Makefile linux-2.6.39/drivers/mtd/nand/Makefile --- linux-2.6.39.orig/drivers/mtd/nand/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/mtd/nand/Makefile 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/mtd/nand/Makefile 2011-08-24 18:17:24.000000000 +0200 @@ -34,6 +34,7 @@ obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o @@ -11038,12 +14411,12 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/Makefile linux-2.6.39/drivers/mtd/n obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.39/drivers/mtd/nand/rb4xx_nand.c --- linux-2.6.39.orig/drivers/mtd/nand/rb4xx_nand.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/mtd/nand/rb4xx_nand.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,513 @@ ++++ linux-2.6.39/drivers/mtd/nand/rb4xx_nand.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,311 @@ +/* + * NAND flash driver for the MikroTik RouterBoard 4xx series + * -+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2008-2011 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 @@ -11065,49 +14438,16 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.39/drivers/m +#include <linux/slab.h> + +#include <asm/mach-ar71xx/ar71xx.h> ++#include <asm/mach-ar71xx/rb4xx_cpld.h> + +#define DRV_NAME "rb4xx-nand" -+#define DRV_VERSION "0.1.10" ++#define DRV_VERSION "0.2.0" +#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) ++#define RB4XX_NAND_GPIO_READY 5 ++#define RB4XX_NAND_GPIO_ALE 37 ++#define RB4XX_NAND_GPIO_CLE 38 ++#define RB4XX_NAND_GPIO_NCE 39 + +struct rb4xx_nand_info { + struct nand_chip chip; @@ -11135,332 +14475,150 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.39/drivers/m + { + .name = "kernel", + .offset = (256 * 1024), -+ .size = (4 * 1024 * 1024) - (256 * 1024), ++ .size = (6 * 1024 * 1024) - (256 * 1024), + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_NXTBLK, -+ .size = (1024*1024*64) - (1024*256) - (4 * 1024 * 1024) -+ }, -+ { -+ .name = "cfgfs", -+ .offset = (1024*1024*64) - (1024*256), -+ .size = (1024*256), ++ .size = MTDPART_SIZ_FULL, + }, +}; + -+#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) ++static int rb4xx_nand_dev_ready(struct mtd_info *mtd) +{ -+ 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)); ++ return gpio_get_value_cansleep(RB4XX_NAND_GPIO_READY); +} + -+#if USE_FAST_WRITE -+static inline void do_spi_clk_fast(int bit1, int bit2) ++static void rb4xx_nand_write_cmd(unsigned char cmd) +{ -+ unsigned bval = (SBIT_IOC_BASE | -+ ((bit1 << SBIT_IOC_DO_SHIFT) & SBIT_IOC_DO) | -+ ((bit2 << SBIT_IOC_DO2_SHIFT) & SBIT_IOC_DO2)); ++ unsigned char data = cmd; ++ int err; + -+ rb4xx_spi_wreg(SPI_REG_IOC, bval); -+ rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK); ++ err = rb4xx_cpld_write(&data, 1); ++ if (err) ++ pr_err("rb4xx_nand: write cmd failed, err=%d\n", err); +} + -+static inline void do_spi_byte_fast(uint8_t byte) ++static void rb4xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, ++ unsigned int ctrl) +{ -+ 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); ++ if (ctrl & NAND_CTRL_CHANGE) { ++ gpio_set_value_cansleep(RB4XX_NAND_GPIO_CLE, ++ (ctrl & NAND_CLE) ? 1 : 0); ++ gpio_set_value_cansleep(RB4XX_NAND_GPIO_ALE, ++ (ctrl & NAND_ALE) ? 1 : 0); ++ gpio_set_value_cansleep(RB4XX_NAND_GPIO_NCE, ++ (ctrl & NAND_NCE) ? 0 : 1); ++ } + -+ 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); ++ if (cmd != NAND_CMD_NONE) ++ rb4xx_nand_write_cmd(cmd); +} -+#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) ++static unsigned char rb4xx_nand_read_byte(struct mtd_info *mtd) +{ -+ 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); ++ unsigned char data = 0; ++ int err; + -+ 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; -+ } ++ err = rb4xx_cpld_read(&data, NULL, 1); ++ if (err) { ++ pr_err("rb4xx_nand: read data failed, err=%d\n", err); ++ data = 0xff; + } + -+ 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; ++ return data; +} + -+static int got_write = 1; -+ -+static void rb4xx_nand_write_data(const uint8_t *byte, unsigned cnt) ++static void rb4xx_nand_write_buf(struct mtd_info *mtd, const unsigned char *buf, ++ int len) +{ -+ do_spi_cmd(CPLD_CMD_WRITE_MULT, cnt, byte, 1, NULL, NULL, 1); -+ got_write = 1; -+} ++ int err; + -+static void rb4xx_nand_write_byte(uint8_t byte) -+{ -+ rb4xx_nand_write_data(&byte, 1); ++ err = rb4xx_cpld_write(buf, len); ++ if (err) ++ pr_err("rb4xx_nand: write buf failed, err=%d\n", err); +} + -+#if USE_FAST_READ -+static uint8_t *rb4xx_nand_read_getaddr(unsigned cnt) ++static void rb4xx_nand_read_buf(struct mtd_info *mtd, unsigned char *buf, ++ int len) +{ -+ 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); ++ int err; + -+ nboffset += cnt; -+ return (uint8_t *)addr; ++ err = rb4xx_cpld_read(buf, NULL, len); ++ if (err) ++ pr_err("rb4xx_nand: read buf failed, err=%d\n", err); +} + -+static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt) ++static int __init rb4xx_nand_probe(struct platform_device *pdev) +{ -+ unsigned size32 = cnt & ~31; -+ unsigned remain = cnt & 31; ++ struct rb4xx_nand_info *info; ++ int ret; + -+ if (size32) { -+ uint8_t *addr = rb4xx_nand_read_getaddr(size32); -+ memcpy(buf, (void *)addr, size32); -+ } ++ printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n"); + -+ if (remain) { -+ do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain, -+ buf + size32, NULL, 0); ++ ret = gpio_request(RB4XX_NAND_GPIO_READY, "NAND RDY"); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to request gpio %d\n", ++ RB4XX_NAND_GPIO_READY); ++ goto err; + } -+} + -+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; ++ ret = gpio_direction_input(RB4XX_NAND_GPIO_READY); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to set input mode on gpio %d\n", ++ RB4XX_NAND_GPIO_READY); ++ goto err_free_gpio_ready; + } + -+ if (remain) { -+ return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain, -+ NULL, buf + size32, 0); ++ ret = gpio_request(RB4XX_NAND_GPIO_ALE, "NAND ALE"); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to request gpio %d\n", ++ RB4XX_NAND_GPIO_ALE); ++ goto err_free_gpio_ready; + } -+ 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); ++ ret = gpio_direction_output(RB4XX_NAND_GPIO_ALE, 0); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to set output mode on gpio %d\n", ++ RB4XX_NAND_GPIO_ALE); ++ goto err_free_gpio_ale; + } + -+ 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); ++ ret = gpio_request(RB4XX_NAND_GPIO_CLE, "NAND CLE"); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to request gpio %d\n", ++ RB4XX_NAND_GPIO_CLE); ++ goto err_free_gpio_ale; + } + -+ 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_direction_output(RB4XX_NAND_GPIO_CLE, 0); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to set output mode on gpio %d\n", ++ RB4XX_NAND_GPIO_CLE); ++ goto err_free_gpio_cle; ++ } + -+ ret = gpio_request(RB4XX_NAND_GPIO_RDY, "NAND RDY"); ++ ret = gpio_request(RB4XX_NAND_GPIO_NCE, "NAND NCE"); + if (ret) { -+ printk(KERN_ERR "rb4xx-nand: gpio request failed\n"); -+ return ret; ++ dev_err(&pdev->dev, "unable to request gpio %d\n", ++ RB4XX_NAND_GPIO_NCE); ++ goto err_free_gpio_cle; + } + -+ ret = gpio_direction_input(RB4XX_NAND_GPIO_RDY); ++ ret = gpio_direction_output(RB4XX_NAND_GPIO_NCE, 1); + if (ret) { -+ printk(KERN_ERR "rb4xx-nand: unable to set input mode " -+ "on gpio%d\n", RB4XX_NAND_GPIO_RDY); -+ goto err_free_gpio; ++ dev_err(&pdev->dev, "unable to set output mode on gpio %d\n", ++ RB4XX_NAND_GPIO_ALE); ++ goto err_free_gpio_nce; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { -+ printk(KERN_ERR "rb4xx-nand: no memory for private data\n"); ++ dev_err(&pdev->dev, "rb4xx-nand: no memory for private data\n"); + ret = -ENOMEM; -+ goto err_free_gpio; ++ goto err_free_gpio_nce; + } + -+#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; @@ -11470,7 +14628,9 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.39/drivers/m + info->chip.read_byte = rb4xx_nand_read_byte; + info->chip.write_buf = rb4xx_nand_write_buf; + info->chip.read_buf = rb4xx_nand_read_buf; ++#if 0 + info->chip.verify_buf = rb4xx_nand_verify_buf; ++#endif + + info->chip.chip_delay = 25; + info->chip.ecc.mode = NAND_ECC_SOFT; @@ -11510,8 +14670,15 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.39/drivers/m + platform_set_drvdata(pdev, NULL); +err_free_info: + kfree(info); -+err_free_gpio: -+ gpio_free(RB4XX_NAND_GPIO_RDY); ++err_free_gpio_nce: ++ gpio_free(RB4XX_NAND_GPIO_NCE); ++err_free_gpio_cle: ++ gpio_free(RB4XX_NAND_GPIO_CLE); ++err_free_gpio_ale: ++ gpio_free(RB4XX_NAND_GPIO_ALE); ++err_free_gpio_ready: ++ gpio_free(RB4XX_NAND_GPIO_READY); ++err: + return ret; +} + @@ -11522,6 +14689,10 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.39/drivers/m + nand_release(&info->mtd); + platform_set_drvdata(pdev, NULL); + kfree(info); ++ gpio_free(RB4XX_NAND_GPIO_NCE); ++ gpio_free(RB4XX_NAND_GPIO_CLE); ++ gpio_free(RB4XX_NAND_GPIO_ALE); ++ gpio_free(RB4XX_NAND_GPIO_READY); + + return 0; +} @@ -11555,8 +14726,8 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.39/drivers/m +MODULE_LICENSE("GPL v2"); diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb750_nand.c linux-2.6.39/drivers/mtd/nand/rb750_nand.c --- linux-2.6.39.orig/drivers/mtd/nand/rb750_nand.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/mtd/nand/rb750_nand.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,360 @@ ++++ linux-2.6.39/drivers/mtd/nand/rb750_nand.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,361 @@ +/* + * NAND flash driver for the MikroTik RouterBOARD 750 + * @@ -11573,6 +14744,7 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb750_nand.c linux-2.6.39/drivers/m +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> +#include <linux/io.h> ++#include <linux/slab.h> + +#include <asm/mach-ar71xx/ar71xx.h> +#include <asm/mach-ar71xx/mach-rb750.h> @@ -11871,11 +15043,11 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb750_nand.c linux-2.6.39/drivers/m + + return 0; + -+ err_release_nand: ++err_release_nand: + nand_release(&info->mtd); -+ err_set_drvdata: ++err_set_drvdata: + platform_set_drvdata(pdev, NULL); -+ err_free_info: ++err_free_info: + kfree(info); + return ret; +} @@ -11919,8 +15091,8 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/nand/rb750_nand.c linux-2.6.39/drivers/m +MODULE_LICENSE("GPL v2"); diff -Nur linux-2.6.39.orig/drivers/mtd/wrt160nl_part.c linux-2.6.39/drivers/mtd/wrt160nl_part.c --- linux-2.6.39.orig/drivers/mtd/wrt160nl_part.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/mtd/wrt160nl_part.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,181 @@ ++++ linux-2.6.39/drivers/mtd/wrt160nl_part.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,190 @@ +/* + * Copyright (C) 2009 Christian Daniel <cd@maintech.de> + * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> @@ -12001,6 +15173,10 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/wrt160nl_part.c linux-2.6.39/drivers/mtd + +static struct mtd_partition trx_parts[TRX_PARTS]; + ++#define WRT160NL_UBOOT_LEN 0x40000 ++#define WRT160NL_ART_LEN 0x10000 ++#define WRT160NL_NVRAM_LEN 0x10000 ++ +static int wrt160nl_parse_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + unsigned long origin) @@ -12010,6 +15186,9 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/wrt160nl_part.c linux-2.6.39/drivers/mtd + struct uimage_header *uheader; + size_t retlen; + unsigned int kernel_len; ++ unsigned int uboot_len = max(master->erasesize, WRT160NL_UBOOT_LEN); ++ unsigned int nvram_len = max(master->erasesize, WRT160NL_NVRAM_LEN); ++ unsigned int art_len = max(master->erasesize, WRT160NL_ART_LEN); + int ret; + + header = vmalloc(sizeof(*header)); @@ -12018,7 +15197,7 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/wrt160nl_part.c linux-2.6.39/drivers/mtd + goto out; + } + -+ ret = master->read(master, 4 * master->erasesize, sizeof(*header), ++ ret = master->read(master, uboot_len, sizeof(*header), + &retlen, (void *) header); + if (ret) + goto free_hdr; @@ -12046,11 +15225,12 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/wrt160nl_part.c linux-2.6.39/drivers/mtd + goto free_hdr; + } + -+ kernel_len = le32_to_cpu(theader->offsets[1]) + sizeof(struct cybertan_header); ++ kernel_len = le32_to_cpu(theader->offsets[1]) + ++ sizeof(struct cybertan_header); + + trx_parts[0].name = "u-boot"; + trx_parts[0].offset = 0; -+ trx_parts[0].size = 4 * master->erasesize; ++ trx_parts[0].size = uboot_len; + trx_parts[0].mask_flags = MTD_WRITEABLE; + + trx_parts[1].name = "kernel"; @@ -12060,30 +15240,31 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/wrt160nl_part.c linux-2.6.39/drivers/mtd + + trx_parts[2].name = "rootfs"; + trx_parts[2].offset = trx_parts[1].offset + trx_parts[1].size; -+ trx_parts[2].size = master->size - 6 * master->erasesize - trx_parts[1].size; ++ trx_parts[2].size = master->size - uboot_len - nvram_len - art_len - ++ trx_parts[1].size; + trx_parts[2].mask_flags = 0; + + trx_parts[3].name = "nvram"; -+ trx_parts[3].offset = master->size - 2 * master->erasesize; -+ trx_parts[3].size = master->erasesize; ++ trx_parts[3].offset = master->size - nvram_len - art_len; ++ trx_parts[3].size = nvram_len; + trx_parts[3].mask_flags = MTD_WRITEABLE; + + trx_parts[4].name = "art"; -+ trx_parts[4].offset = master->size - master->erasesize; -+ trx_parts[4].size = master->erasesize; ++ trx_parts[4].offset = master->size - art_len; ++ trx_parts[4].size = art_len; + trx_parts[4].mask_flags = MTD_WRITEABLE; + + trx_parts[5].name = "firmware"; -+ trx_parts[5].offset = 4 * master->erasesize; -+ trx_parts[5].size = master->size - 6 * master->erasesize; ++ trx_parts[5].offset = uboot_len; ++ trx_parts[5].size = master->size - uboot_len - nvram_len - art_len; + trx_parts[5].mask_flags = 0; + + *pparts = trx_parts; + ret = TRX_PARTS; + -+ free_hdr: ++free_hdr: + vfree(header); -+ out: ++out: + return ret; +} + @@ -12104,7 +15285,7 @@ diff -Nur linux-2.6.39.orig/drivers/mtd/wrt160nl_part.c linux-2.6.39/drivers/mtd +MODULE_AUTHOR("Christian Daniel <cd@maintech.de>"); diff -Nur linux-2.6.39.orig/drivers/net/Kconfig linux-2.6.39/drivers/net/Kconfig --- linux-2.6.39.orig/drivers/net/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/net/Kconfig 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/net/Kconfig 2011-08-24 18:17:24.000000000 +0200 @@ -2071,6 +2071,8 @@ The safe and default value for this is N. @@ -12116,7 +15297,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/Kconfig linux-2.6.39/drivers/net/Kconfig depends on PCI diff -Nur linux-2.6.39.orig/drivers/net/Makefile linux-2.6.39/drivers/net/Makefile --- linux-2.6.39.orig/drivers/net/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/net/Makefile 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/net/Makefile 2011-08-24 18:17:24.000000000 +0200 @@ -112,6 +112,7 @@ # end link order section # @@ -12127,7 +15308,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/Makefile linux-2.6.39/drivers/net/Makefi obj-$(CONFIG_NET) += Space.o loopback.o diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/Kconfig linux-2.6.39/drivers/net/ag71xx/Kconfig --- linux-2.6.39.orig/drivers/net/ag71xx/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/Kconfig 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/net/ag71xx/Kconfig 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,33 @@ +config AG71XX + tristate "Atheros AR71xx built-in ethernet mac support" @@ -12164,8 +15345,8 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/Kconfig linux-2.6.39/drivers/net/ +endif diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/Makefile linux-2.6.39/drivers/net/ag71xx/Makefile --- linux-2.6.39.orig/drivers/net/ag71xx/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/Makefile 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,14 @@ ++++ linux-2.6.39/drivers/net/ag71xx/Makefile 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,15 @@ +# +# Makefile for the Atheros AR71xx built-in ethernet macs +# @@ -12174,6 +15355,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/Makefile linux-2.6.39/drivers/net +ag71xx-y += ag71xx_ethtool.o +ag71xx-y += ag71xx_phy.o +ag71xx-y += ag71xx_mdio.o ++ag71xx-y += ag71xx_ar7240.o + +ag71xx-$(CONFIG_AG71XX_DEBUG_FS) += ag71xx_debugfs.o +ag71xx-$(CONFIG_AG71XX_AR8216_SUPPORT) += ag71xx_ar8216.o @@ -12182,8 +15364,8 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/Makefile linux-2.6.39/drivers/net + diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net/ag71xx/ag71xx.h --- linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/ag71xx.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,500 @@ ++++ linux-2.6.39/drivers/net/ag71xx/ag71xx.h 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,518 @@ +/* + * Atheros AR71xx built-in ethernet mac driver + * @@ -12211,6 +15393,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net +#include <linux/platform_device.h> +#include <linux/ethtool.h> +#include <linux/etherdevice.h> ++#include <linux/if_vlan.h> +#include <linux/phy.h> +#include <linux/skbuff.h> +#include <linux/dma-mapping.h> @@ -12221,8 +15404,6 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net +#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.5.35" + @@ -12236,18 +15417,16 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net +#define AG71XX_INT_POLL (AG71XX_INT_RX | AG71XX_INT_TX) +#define AG71XX_INT_INIT (AG71XX_INT_ERR | AG71XX_INT_POLL) + -+#define AG71XX_TX_FIFO_LEN 2048 -+#define AG71XX_TX_MTU_LEN 1536 ++#define AG71XX_TX_MTU_LEN 1540 +#define AG71XX_RX_PKT_RESERVE 64 +#define AG71XX_RX_PKT_SIZE \ -+ (AG71XX_RX_PKT_RESERVE + ETH_HLEN + ETH_FRAME_LEN + ETH_FCS_LEN) ++ (AG71XX_RX_PKT_RESERVE + ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) + -+#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_TX_RING_SIZE_DEFAULT 64 ++#define AG71XX_RX_RING_SIZE_DEFAULT 128 + -+#define AG71XX_RX_RING_SIZE 128 ++#define AG71XX_TX_RING_SIZE_MAX 256 ++#define AG71XX_RX_RING_SIZE_MAX 256 + +#ifdef CONFIG_AG71XX_DEBUG +#define DBG(fmt, args...) printk(KERN_DEBUG fmt, ## args) @@ -12275,9 +15454,9 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net + +struct ag71xx_buf { + struct sk_buff *skb; -+ struct ag71xx_desc *desc; ++ struct ag71xx_desc *desc; + dma_addr_t dma_addr; -+ u32 pad; ++ unsigned long timestamp; +}; + +struct ag71xx_ring { @@ -12322,8 +15501,6 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net + +struct ag71xx_debug { + struct dentry *debugfs_dir; -+ struct dentry *debugfs_int_stats; -+ struct dentry *debugfs_napi_stats; + + struct ag71xx_int_stats int_stats; + struct ag71xx_napi_stats napi_stats; @@ -12339,17 +15516,22 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net + struct napi_struct napi; + u32 msg_enable; + ++ struct ag71xx_desc *stop_desc; ++ dma_addr_t stop_desc_dma; ++ + struct ag71xx_ring rx_ring; + struct ag71xx_ring tx_ring; + + struct mii_bus *mii_bus; + struct phy_device *phy_dev; ++ void *phy_priv; + + unsigned int link; + unsigned int speed; -+ int duplex; ++ int duplex; + + struct work_struct restart_work; ++ struct delayed_work link_work; + struct timer_list oom_timer; + +#ifdef CONFIG_AG71XX_DEBUG_FS @@ -12375,12 +15557,12 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net + +static inline int ag71xx_desc_empty(struct ag71xx_desc *desc) +{ -+ return ((desc->ctrl & DESC_EMPTY) != 0); ++ return (desc->ctrl & DESC_EMPTY) != 0; +} + +static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc) +{ -+ return (desc->ctrl & DESC_PKTLEN_M); ++ return desc->ctrl & DESC_PKTLEN_M; +} + +/* Register offsets */ @@ -12422,6 +15604,10 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net +#define AG71XX_REG_INT_ENABLE 0x0198 +#define AG71XX_REG_INT_STATUS 0x019c + ++#define AG71XX_REG_FIFO_DEPTH 0x01a8 ++#define AG71XX_REG_RX_SM 0x01b0 ++#define AG71XX_REG_TX_SM 0x01b4 ++ +#define MAC_CFG1_TXE BIT(0) /* Tx Enable */ +#define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */ +#define MAC_CFG1_RXE BIT(2) /* Rx Enable */ @@ -12537,6 +15723,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net + switch (reg) { + case AG71XX_REG_MAC_CFG1 ... AG71XX_REG_MAC_MFL: + case AG71XX_REG_MAC_IFCTL ... AG71XX_REG_INT_STATUS: ++ case AG71XX_REG_MII_CFG: + break; + + default: @@ -12617,7 +15804,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net + return __raw_readl(ag->mii_ctrl); +} + -+static void inline ag71xx_mii_ctrl_set_if(struct ag71xx *ag, ++static inline void ag71xx_mii_ctrl_set_if(struct ag71xx *ag, + unsigned int mii_if) +{ + u32 t; @@ -12628,7 +15815,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net + ag71xx_mii_ctrl_wr(ag, t); +} + -+static void inline ag71xx_mii_ctrl_set_speed(struct ag71xx *ag, ++static inline void ag71xx_mii_ctrl_set_speed(struct ag71xx *ag, + unsigned int speed) +{ + u32 t; @@ -12683,10 +15870,940 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.39/drivers/net + int rx, int tx) {} +#endif /* CONFIG_AG71XX_DEBUG_FS */ + ++void ag71xx_ar7240_start(struct ag71xx *ag); ++void ag71xx_ar7240_stop(struct ag71xx *ag); ++int ag71xx_ar7240_init(struct ag71xx *ag); ++void ag71xx_ar7240_cleanup(struct ag71xx *ag); ++ ++int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg); ++void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val); ++ ++u16 ar7240sw_phy_read(struct mii_bus *mii, unsigned phy_addr, ++ unsigned reg_addr); ++int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr, ++ unsigned reg_addr, u16 reg_val); ++ +#endif /* _AG71XX_H */ +diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_ar7240.c linux-2.6.39/drivers/net/ag71xx/ag71xx_ar7240.c +--- linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_ar7240.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/drivers/net/ag71xx/ag71xx_ar7240.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,913 @@ ++/* ++ * Driver for the built-in ethernet switch of the Atheros AR7240 SoC ++ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (c) 2010 Felix Fietkau <nbd@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/etherdevice.h> ++#include <linux/list.h> ++#include <linux/netdevice.h> ++#include <linux/phy.h> ++#include <linux/mii.h> ++#include <linux/bitops.h> ++#include <linux/switch.h> ++#include "ag71xx.h" ++ ++#define BITM(_count) (BIT(_count) - 1) ++#define BITS(_shift, _count) (BITM(_count) << _shift) ++ ++#define AR7240_REG_MASK_CTRL 0x00 ++#define AR7240_MASK_CTRL_REVISION_M BITM(8) ++#define AR7240_MASK_CTRL_VERSION_M BITM(8) ++#define AR7240_MASK_CTRL_VERSION_S 8 ++#define AR7240_MASK_CTRL_SOFT_RESET BIT(31) ++ ++#define AR7240_REG_MAC_ADDR0 0x20 ++#define AR7240_REG_MAC_ADDR1 0x24 ++ ++#define AR7240_REG_FLOOD_MASK 0x2c ++#define AR7240_FLOOD_MASK_BROAD_TO_CPU BIT(26) ++ ++#define AR7240_REG_GLOBAL_CTRL 0x30 ++#define AR7240_GLOBAL_CTRL_MTU_M BITM(12) ++ ++#define AR7240_REG_VTU 0x0040 ++#define AR7240_VTU_OP BITM(3) ++#define AR7240_VTU_OP_NOOP 0x0 ++#define AR7240_VTU_OP_FLUSH 0x1 ++#define AR7240_VTU_OP_LOAD 0x2 ++#define AR7240_VTU_OP_PURGE 0x3 ++#define AR7240_VTU_OP_REMOVE_PORT 0x4 ++#define AR7240_VTU_ACTIVE BIT(3) ++#define AR7240_VTU_FULL BIT(4) ++#define AR7240_VTU_PORT BITS(8, 4) ++#define AR7240_VTU_PORT_S 8 ++#define AR7240_VTU_VID BITS(16, 12) ++#define AR7240_VTU_VID_S 16 ++#define AR7240_VTU_PRIO BITS(28, 3) ++#define AR7240_VTU_PRIO_S 28 ++#define AR7240_VTU_PRIO_EN BIT(31) ++ ++#define AR7240_REG_VTU_DATA 0x0044 ++#define AR7240_VTUDATA_MEMBER BITS(0, 10) ++#define AR7240_VTUDATA_VALID BIT(11) ++ ++#define AR7240_REG_ATU 0x50 ++#define AR7240_ATU_FLUSH_ALL 0x1 ++ ++#define AR7240_REG_AT_CTRL 0x5c ++#define AR7240_AT_CTRL_AGE_TIME BITS(0, 15) ++#define AR7240_AT_CTRL_AGE_EN BIT(17) ++#define AR7240_AT_CTRL_LEARN_CHANGE BIT(18) ++#define AR7240_AT_CTRL_ARP_EN BIT(20) ++ ++#define AR7240_REG_TAG_PRIORITY 0x70 ++ ++#define AR7240_REG_SERVICE_TAG 0x74 ++#define AR7240_SERVICE_TAG_M BITM(16) ++ ++#define AR7240_REG_CPU_PORT 0x78 ++#define AR7240_MIRROR_PORT_S 4 ++#define AR7240_CPU_PORT_EN BIT(8) ++ ++#define AR7240_REG_MIB_FUNCTION0 0x80 ++#define AR7240_MIB_TIMER_M BITM(16) ++#define AR7240_MIB_AT_HALF_EN BIT(16) ++#define AR7240_MIB_BUSY BIT(17) ++#define AR7240_MIB_FUNC_S 24 ++#define AR7240_MIB_FUNC_NO_OP 0x0 ++#define AR7240_MIB_FUNC_FLUSH 0x1 ++#define AR7240_MIB_FUNC_CAPTURE 0x3 ++ ++#define AR7240_REG_MDIO_CTRL 0x98 ++#define AR7240_MDIO_CTRL_DATA_M BITM(16) ++#define AR7240_MDIO_CTRL_REG_ADDR_S 16 ++#define AR7240_MDIO_CTRL_PHY_ADDR_S 21 ++#define AR7240_MDIO_CTRL_CMD_WRITE 0 ++#define AR7240_MDIO_CTRL_CMD_READ BIT(27) ++#define AR7240_MDIO_CTRL_MASTER_EN BIT(30) ++#define AR7240_MDIO_CTRL_BUSY BIT(31) ++ ++#define AR7240_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100) ++ ++#define AR7240_REG_PORT_STATUS(_port) (AR7240_REG_PORT_BASE((_port)) + 0x00) ++#define AR7240_PORT_STATUS_SPEED_M BITM(2) ++#define AR7240_PORT_STATUS_SPEED_10 0 ++#define AR7240_PORT_STATUS_SPEED_100 1 ++#define AR7240_PORT_STATUS_SPEED_1000 2 ++#define AR7240_PORT_STATUS_TXMAC BIT(2) ++#define AR7240_PORT_STATUS_RXMAC BIT(3) ++#define AR7240_PORT_STATUS_TXFLOW BIT(4) ++#define AR7240_PORT_STATUS_RXFLOW BIT(5) ++#define AR7240_PORT_STATUS_DUPLEX BIT(6) ++#define AR7240_PORT_STATUS_LINK_UP BIT(8) ++#define AR7240_PORT_STATUS_LINK_AUTO BIT(9) ++#define AR7240_PORT_STATUS_LINK_PAUSE BIT(10) ++ ++#define AR7240_REG_PORT_CTRL(_port) (AR7240_REG_PORT_BASE((_port)) + 0x04) ++#define AR7240_PORT_CTRL_STATE_M BITM(3) ++#define AR7240_PORT_CTRL_STATE_DISABLED 0 ++#define AR7240_PORT_CTRL_STATE_BLOCK 1 ++#define AR7240_PORT_CTRL_STATE_LISTEN 2 ++#define AR7240_PORT_CTRL_STATE_LEARN 3 ++#define AR7240_PORT_CTRL_STATE_FORWARD 4 ++#define AR7240_PORT_CTRL_LEARN_LOCK BIT(7) ++#define AR7240_PORT_CTRL_VLAN_MODE_S 8 ++#define AR7240_PORT_CTRL_VLAN_MODE_KEEP 0 ++#define AR7240_PORT_CTRL_VLAN_MODE_STRIP 1 ++#define AR7240_PORT_CTRL_VLAN_MODE_ADD 2 ++#define AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG 3 ++#define AR7240_PORT_CTRL_IGMP_SNOOP BIT(10) ++#define AR7240_PORT_CTRL_HEADER BIT(11) ++#define AR7240_PORT_CTRL_MAC_LOOP BIT(12) ++#define AR7240_PORT_CTRL_SINGLE_VLAN BIT(13) ++#define AR7240_PORT_CTRL_LEARN BIT(14) ++#define AR7240_PORT_CTRL_DOUBLE_TAG BIT(15) ++#define AR7240_PORT_CTRL_MIRROR_TX BIT(16) ++#define AR7240_PORT_CTRL_MIRROR_RX BIT(17) ++ ++#define AR7240_REG_PORT_VLAN(_port) (AR7240_REG_PORT_BASE((_port)) + 0x08) ++ ++#define AR7240_PORT_VLAN_DEFAULT_ID_S 0 ++#define AR7240_PORT_VLAN_DEST_PORTS_S 16 ++#define AR7240_PORT_VLAN_MODE_S 30 ++#define AR7240_PORT_VLAN_MODE_PORT_ONLY 0 ++#define AR7240_PORT_VLAN_MODE_PORT_FALLBACK 1 ++#define AR7240_PORT_VLAN_MODE_VLAN_ONLY 2 ++#define AR7240_PORT_VLAN_MODE_SECURE 3 ++ ++ ++#define AR7240_REG_STATS_BASE(_port) (0x20000 + (_port) * 0x100) ++ ++#define AR7240_STATS_RXBROAD 0x00 ++#define AR7240_STATS_RXPAUSE 0x04 ++#define AR7240_STATS_RXMULTI 0x08 ++#define AR7240_STATS_RXFCSERR 0x0c ++#define AR7240_STATS_RXALIGNERR 0x10 ++#define AR7240_STATS_RXRUNT 0x14 ++#define AR7240_STATS_RXFRAGMENT 0x18 ++#define AR7240_STATS_RX64BYTE 0x1c ++#define AR7240_STATS_RX128BYTE 0x20 ++#define AR7240_STATS_RX256BYTE 0x24 ++#define AR7240_STATS_RX512BYTE 0x28 ++#define AR7240_STATS_RX1024BYTE 0x2c ++#define AR7240_STATS_RX1518BYTE 0x30 ++#define AR7240_STATS_RXMAXBYTE 0x34 ++#define AR7240_STATS_RXTOOLONG 0x38 ++#define AR7240_STATS_RXGOODBYTE 0x3c ++#define AR7240_STATS_RXBADBYTE 0x44 ++#define AR7240_STATS_RXOVERFLOW 0x4c ++#define AR7240_STATS_FILTERED 0x50 ++#define AR7240_STATS_TXBROAD 0x54 ++#define AR7240_STATS_TXPAUSE 0x58 ++#define AR7240_STATS_TXMULTI 0x5c ++#define AR7240_STATS_TXUNDERRUN 0x60 ++#define AR7240_STATS_TX64BYTE 0x64 ++#define AR7240_STATS_TX128BYTE 0x68 ++#define AR7240_STATS_TX256BYTE 0x6c ++#define AR7240_STATS_TX512BYTE 0x70 ++#define AR7240_STATS_TX1024BYTE 0x74 ++#define AR7240_STATS_TX1518BYTE 0x78 ++#define AR7240_STATS_TXMAXBYTE 0x7c ++#define AR7240_STATS_TXOVERSIZE 0x80 ++#define AR7240_STATS_TXBYTE 0x84 ++#define AR7240_STATS_TXCOLLISION 0x8c ++#define AR7240_STATS_TXABORTCOL 0x90 ++#define AR7240_STATS_TXMULTICOL 0x94 ++#define AR7240_STATS_TXSINGLECOL 0x98 ++#define AR7240_STATS_TXEXCDEFER 0x9c ++#define AR7240_STATS_TXDEFER 0xa0 ++#define AR7240_STATS_TXLATECOL 0xa4 ++ ++#define AR7240_PORT_CPU 0 ++#define AR7240_NUM_PORTS 6 ++#define AR7240_NUM_PHYS 5 ++ ++#define AR7240_PHY_ID1 0x004d ++#define AR7240_PHY_ID2 0xd041 ++ ++#define AR7240_PORT_MASK(_port) BIT((_port)) ++#define AR7240_PORT_MASK_ALL BITM(AR7240_NUM_PORTS) ++#define AR7240_PORT_MASK_BUT(_port) (AR7240_PORT_MASK_ALL & ~BIT((_port))) ++ ++#define AR7240_MAX_VLANS 16 ++ ++#define sw_to_ar7240(_dev) container_of(_dev, struct ar7240sw, swdev) ++ ++struct ar7240sw { ++ struct mii_bus *mii_bus; ++ struct switch_dev swdev; ++ bool vlan; ++ u16 vlan_id[AR7240_MAX_VLANS]; ++ u8 vlan_table[AR7240_MAX_VLANS]; ++ u8 vlan_tagged; ++ u16 pvid[AR7240_NUM_PORTS]; ++}; ++ ++struct ar7240sw_hw_stat { ++ char string[ETH_GSTRING_LEN]; ++ int sizeof_stat; ++ int reg; ++}; ++ ++static DEFINE_MUTEX(reg_mutex); ++ ++static inline void ar7240sw_init(struct ar7240sw *as, struct mii_bus *mii) ++{ ++ as->mii_bus = mii; ++} ++ ++static inline u16 mk_phy_addr(u32 reg) ++{ ++ return 0x17 & ((reg >> 4) | 0x10); ++} ++ ++static inline u16 mk_phy_reg(u32 reg) ++{ ++ return (reg << 1) & 0x1e; ++} ++ ++static inline u16 mk_high_addr(u32 reg) ++{ ++ return (reg >> 7) & 0x1ff; ++} ++ ++static u32 __ar7240sw_reg_read(struct mii_bus *mii, u32 reg) ++{ ++ unsigned long flags; ++ u16 phy_addr; ++ u16 phy_reg; ++ u32 hi, lo; ++ ++ reg = (reg & 0xfffffffc) >> 2; ++ phy_addr = mk_phy_addr(reg); ++ phy_reg = mk_phy_reg(reg); ++ ++ local_irq_save(flags); ++ ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg)); ++ lo = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg); ++ hi = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg + 1); ++ local_irq_restore(flags); ++ ++ return (hi << 16) | lo; ++} ++ ++static void __ar7240sw_reg_write(struct mii_bus *mii, u32 reg, u32 val) ++{ ++ unsigned long flags; ++ u16 phy_addr; ++ u16 phy_reg; ++ ++ reg = (reg & 0xfffffffc) >> 2; ++ phy_addr = mk_phy_addr(reg); ++ phy_reg = mk_phy_reg(reg); ++ ++ local_irq_save(flags); ++ ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg)); ++ ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg + 1, (val >> 16)); ++ ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg, (val & 0xffff)); ++ local_irq_restore(flags); ++} ++ ++static u32 ar7240sw_reg_read(struct mii_bus *mii, u32 reg_addr) ++{ ++ u32 ret; ++ ++ mutex_lock(®_mutex); ++ ret = __ar7240sw_reg_read(mii, reg_addr); ++ mutex_unlock(®_mutex); ++ ++ return ret; ++} ++ ++static void ar7240sw_reg_write(struct mii_bus *mii, u32 reg_addr, u32 reg_val) ++{ ++ mutex_lock(®_mutex); ++ __ar7240sw_reg_write(mii, reg_addr, reg_val); ++ mutex_unlock(®_mutex); ++} ++ ++static u32 ar7240sw_reg_rmw(struct mii_bus *mii, u32 reg, u32 mask, u32 val) ++{ ++ u32 t; ++ ++ mutex_lock(®_mutex); ++ t = __ar7240sw_reg_read(mii, reg); ++ t &= ~mask; ++ t |= val; ++ __ar7240sw_reg_write(mii, reg, t); ++ mutex_unlock(®_mutex); ++ ++ return t; ++} ++ ++static void ar7240sw_reg_set(struct mii_bus *mii, u32 reg, u32 val) ++{ ++ u32 t; ++ ++ mutex_lock(®_mutex); ++ t = __ar7240sw_reg_read(mii, reg); ++ t |= val; ++ __ar7240sw_reg_write(mii, reg, t); ++ mutex_unlock(®_mutex); ++} ++ ++static int __ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val, ++ unsigned timeout) ++{ ++ int i; ++ ++ for (i = 0; i < timeout; i++) { ++ u32 t; ++ ++ t = __ar7240sw_reg_read(mii, reg); ++ if ((t & mask) == val) ++ return 0; ++ ++ msleep(1); ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++static int ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val, ++ unsigned timeout) ++{ ++ int ret; ++ ++ mutex_lock(®_mutex); ++ ret = __ar7240sw_reg_wait(mii, reg, mask, val, timeout); ++ mutex_unlock(®_mutex); ++ return ret; ++} ++ ++u16 ar7240sw_phy_read(struct mii_bus *mii, unsigned phy_addr, ++ unsigned reg_addr) ++{ ++ u32 t, val = 0xffff; ++ int err; ++ ++ if (phy_addr >= AR7240_NUM_PHYS) ++ return 0xffff; ++ ++ mutex_lock(®_mutex); ++ t = (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) | ++ (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) | ++ AR7240_MDIO_CTRL_MASTER_EN | ++ AR7240_MDIO_CTRL_BUSY | ++ AR7240_MDIO_CTRL_CMD_READ; ++ ++ __ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t); ++ err = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL, ++ AR7240_MDIO_CTRL_BUSY, 0, 5); ++ if (!err) ++ val = __ar7240sw_reg_read(mii, AR7240_REG_MDIO_CTRL); ++ mutex_unlock(®_mutex); ++ ++ return val & AR7240_MDIO_CTRL_DATA_M; ++} ++ ++int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr, ++ unsigned reg_addr, u16 reg_val) ++{ ++ u32 t; ++ int ret; ++ ++ if (phy_addr >= AR7240_NUM_PHYS) ++ return -EINVAL; ++ ++ mutex_lock(®_mutex); ++ t = (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) | ++ (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) | ++ AR7240_MDIO_CTRL_MASTER_EN | ++ AR7240_MDIO_CTRL_BUSY | ++ AR7240_MDIO_CTRL_CMD_WRITE | ++ reg_val; ++ ++ __ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t); ++ ret = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL, ++ AR7240_MDIO_CTRL_BUSY, 0, 5); ++ mutex_unlock(®_mutex); ++ ++ return ret; ++} ++ ++static int ar7240sw_capture_stats(struct ar7240sw *as) ++{ ++ struct mii_bus *mii = as->mii_bus; ++ int ret; ++ ++ /* Capture the hardware statistics for all ports */ ++ ar7240sw_reg_write(mii, AR7240_REG_MIB_FUNCTION0, ++ (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S)); ++ ++ /* Wait for the capturing to complete. */ ++ ret = ar7240sw_reg_wait(mii, AR7240_REG_MIB_FUNCTION0, ++ AR7240_MIB_BUSY, 0, 10); ++ return ret; ++} ++ ++static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port) ++{ ++ ar7240sw_reg_write(as->mii_bus, AR7240_REG_PORT_CTRL(port), ++ AR7240_PORT_CTRL_STATE_DISABLED); ++} ++ ++static void ar7240sw_setup(struct ar7240sw *as) ++{ ++ struct mii_bus *mii = as->mii_bus; ++ ++ /* Enable CPU port, and disable mirror port */ ++ ar7240sw_reg_write(mii, AR7240_REG_CPU_PORT, ++ AR7240_CPU_PORT_EN | ++ (15 << AR7240_MIRROR_PORT_S)); ++ ++ /* Setup TAG priority mapping */ ++ ar7240sw_reg_write(mii, AR7240_REG_TAG_PRIORITY, 0xfa50); ++ ++ /* Enable ARP frame acknowledge, aging, MAC replacing */ ++ ar7240sw_reg_write(mii, AR7240_REG_AT_CTRL, ++ 0x2b /* 5 min age time */ | ++ AR7240_AT_CTRL_AGE_EN | ++ AR7240_AT_CTRL_ARP_EN | ++ AR7240_AT_CTRL_LEARN_CHANGE); ++ ++ /* Enable Broadcast frames transmitted to the CPU */ ++ ar7240sw_reg_set(mii, AR7240_REG_FLOOD_MASK, ++ AR7240_FLOOD_MASK_BROAD_TO_CPU); ++ ++ /* setup MTU */ ++ ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL, AR7240_GLOBAL_CTRL_MTU_M, ++ 1536); ++ ++ /* setup Service TAG */ ++ ar7240sw_reg_rmw(mii, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, 0); ++} ++ ++static int ar7240sw_reset(struct ar7240sw *as) ++{ ++ struct mii_bus *mii = as->mii_bus; ++ int ret; ++ int i; ++ ++ /* Set all ports to disabled state. */ ++ for (i = 0; i < AR7240_NUM_PORTS; i++) ++ ar7240sw_disable_port(as, i); ++ ++ /* Wait for transmit queues to drain. */ ++ msleep(2); ++ ++ /* Reset the switch. */ ++ ar7240sw_reg_write(mii, AR7240_REG_MASK_CTRL, ++ AR7240_MASK_CTRL_SOFT_RESET); ++ ++ ret = ar7240sw_reg_wait(mii, AR7240_REG_MASK_CTRL, ++ AR7240_MASK_CTRL_SOFT_RESET, 0, 1000); ++ ++ ar7240sw_setup(as); ++ return ret; ++} ++ ++static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask) ++{ ++ struct mii_bus *mii = as->mii_bus; ++ u32 ctrl; ++ u32 dest_ports; ++ u32 vlan; ++ ++ ctrl = AR7240_PORT_CTRL_STATE_FORWARD | AR7240_PORT_CTRL_LEARN | ++ AR7240_PORT_CTRL_SINGLE_VLAN; ++ ++ if (port == AR7240_PORT_CPU) { ++ ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port), ++ AR7240_PORT_STATUS_SPEED_1000 | ++ AR7240_PORT_STATUS_TXFLOW | ++ AR7240_PORT_STATUS_RXFLOW | ++ AR7240_PORT_STATUS_TXMAC | ++ AR7240_PORT_STATUS_RXMAC | ++ AR7240_PORT_STATUS_DUPLEX); ++ } else { ++ ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port), ++ AR7240_PORT_STATUS_LINK_AUTO); ++ } ++ ++ /* Set the default VID for this port */ ++ if (as->vlan) { ++ vlan = as->vlan_id[as->pvid[port]]; ++ vlan |= AR7240_PORT_VLAN_MODE_SECURE << ++ AR7240_PORT_VLAN_MODE_S; ++ } else { ++ vlan = port; ++ vlan |= AR7240_PORT_VLAN_MODE_PORT_ONLY << ++ AR7240_PORT_VLAN_MODE_S; ++ } ++ ++ if (as->vlan && (as->vlan_tagged & BIT(port))) { ++ ctrl |= AR7240_PORT_CTRL_VLAN_MODE_ADD << ++ AR7240_PORT_CTRL_VLAN_MODE_S; ++ } else { ++ ctrl |= AR7240_PORT_CTRL_VLAN_MODE_STRIP << ++ AR7240_PORT_CTRL_VLAN_MODE_S; ++ } ++ ++ if (!portmask) { ++ if (port == AR7240_PORT_CPU) ++ portmask = AR7240_PORT_MASK_BUT(AR7240_PORT_CPU); ++ else ++ portmask = AR7240_PORT_MASK(AR7240_PORT_CPU); ++ } ++ ++ /* allow the port to talk to all other ports, but exclude its ++ * own ID to prevent frames from being reflected back to the ++ * port that they came from */ ++ dest_ports = AR7240_PORT_MASK_BUT(port); ++ ++ /* set default VID and and destination ports for this VLAN */ ++ vlan |= (portmask << AR7240_PORT_VLAN_DEST_PORTS_S); ++ ++ ar7240sw_reg_write(mii, AR7240_REG_PORT_CTRL(port), ctrl); ++ ar7240sw_reg_write(mii, AR7240_REG_PORT_VLAN(port), vlan); ++} ++ ++static int ar7240_set_addr(struct ar7240sw *as, u8 *addr) ++{ ++ struct mii_bus *mii = as->mii_bus; ++ u32 t; ++ ++ t = (addr[4] << 8) | addr[5]; ++ ar7240sw_reg_write(mii, AR7240_REG_MAC_ADDR0, t); ++ ++ t = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; ++ ar7240sw_reg_write(mii, AR7240_REG_MAC_ADDR1, t); ++ ++ return 0; ++} ++ ++static int ++ar7240_set_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ as->vlan_id[val->port_vlan] = val->value.i; ++ return 0; ++} ++ ++static int ++ar7240_get_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ val->value.i = as->vlan_id[val->port_vlan]; ++ return 0; ++} ++ ++static int ++ar7240_set_pvid(struct switch_dev *dev, int port, int vlan) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ ++ /* make sure no invalid PVIDs get set */ ++ ++ if (vlan >= dev->vlans) ++ return -EINVAL; ++ ++ as->pvid[port] = vlan; ++ return 0; ++} ++ ++static int ++ar7240_get_pvid(struct switch_dev *dev, int port, int *vlan) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ *vlan = as->pvid[port]; ++ return 0; ++} ++ ++static int ++ar7240_get_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ u8 ports = as->vlan_table[val->port_vlan]; ++ int i; ++ ++ val->len = 0; ++ for (i = 0; i < AR7240_NUM_PORTS; i++) { ++ struct switch_port *p; ++ ++ if (!(ports & (1 << i))) ++ continue; ++ ++ p = &val->value.ports[val->len++]; ++ p->id = i; ++ if (as->vlan_tagged & (1 << i)) ++ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); ++ else ++ p->flags = 0; ++ } ++ return 0; ++} ++ ++static int ++ar7240_set_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ u8 *vt = &as->vlan_table[val->port_vlan]; ++ int i, j; ++ ++ *vt = 0; ++ for (i = 0; i < val->len; i++) { ++ struct switch_port *p = &val->value.ports[i]; ++ ++ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ++ as->vlan_tagged |= (1 << p->id); ++ else { ++ as->vlan_tagged &= ~(1 << p->id); ++ as->pvid[p->id] = val->port_vlan; ++ ++ /* make sure that an untagged port does not ++ * appear in other vlans */ ++ for (j = 0; j < AR7240_MAX_VLANS; j++) { ++ if (j == val->port_vlan) ++ continue; ++ as->vlan_table[j] &= ~(1 << p->id); ++ } ++ } ++ ++ *vt |= 1 << p->id; ++ } ++ return 0; ++} ++ ++static int ++ar7240_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ as->vlan = !!val->value.i; ++ return 0; ++} ++ ++static int ++ar7240_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ val->value.i = as->vlan; ++ return 0; ++} ++ ++ ++static void ++ar7240_vtu_op(struct ar7240sw *as, u32 op, u32 val) ++{ ++ struct mii_bus *mii = as->mii_bus; ++ ++ if (ar7240sw_reg_wait(mii, AR7240_REG_VTU, AR7240_VTU_ACTIVE, 0, 5)) ++ return; ++ ++ if ((op & AR7240_VTU_OP) == AR7240_VTU_OP_LOAD) { ++ val &= AR7240_VTUDATA_MEMBER; ++ val |= AR7240_VTUDATA_VALID; ++ ar7240sw_reg_write(mii, AR7240_REG_VTU_DATA, val); ++ } ++ op |= AR7240_VTU_ACTIVE; ++ ar7240sw_reg_write(mii, AR7240_REG_VTU, op); ++} ++ ++static int ++ar7240_hw_apply(struct switch_dev *dev) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ u8 portmask[AR7240_NUM_PORTS]; ++ int i, j; ++ ++ /* flush all vlan translation unit entries */ ++ ar7240_vtu_op(as, AR7240_VTU_OP_FLUSH, 0); ++ ++ memset(portmask, 0, sizeof(portmask)); ++ if (as->vlan) { ++ /* calculate the port destination masks and load vlans ++ * into the vlan translation unit */ ++ for (j = 0; j < AR7240_MAX_VLANS; j++) { ++ u8 vp = as->vlan_table[j]; ++ ++ if (!vp) ++ continue; ++ ++ for (i = 0; i < AR7240_NUM_PORTS; i++) { ++ u8 mask = (1 << i); ++ if (vp & mask) ++ portmask[i] |= vp & ~mask; ++ } ++ ++ ar7240_vtu_op(as, ++ AR7240_VTU_OP_LOAD | ++ (as->vlan_id[j] << AR7240_VTU_VID_S), ++ as->vlan_table[j]); ++ } ++ } else { ++ /* vlan disabled: ++ * isolate all ports, but connect them to the cpu port */ ++ for (i = 0; i < AR7240_NUM_PORTS; i++) { ++ if (i == AR7240_PORT_CPU) ++ continue; ++ ++ portmask[i] = 1 << AR7240_PORT_CPU; ++ portmask[AR7240_PORT_CPU] |= (1 << i); ++ } ++ } ++ ++ /* update the port destination mask registers and tag settings */ ++ for (i = 0; i < AR7240_NUM_PORTS; i++) ++ ar7240sw_setup_port(as, i, portmask[i]); ++ ++ return 0; ++} ++ ++static int ++ar7240_reset_switch(struct switch_dev *dev) ++{ ++ struct ar7240sw *as = sw_to_ar7240(dev); ++ ar7240sw_reset(as); ++ return 0; ++} ++ ++static struct switch_attr ar7240_globals[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "Enable VLAN mode", ++ .set = ar7240_set_vlan, ++ .get = ar7240_get_vlan, ++ .max = 1 ++ }, ++}; ++ ++static struct switch_attr ar7240_port[] = { ++}; ++ ++static struct switch_attr ar7240_vlan[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "vid", ++ .description = "VLAN ID", ++ .set = ar7240_set_vid, ++ .get = ar7240_get_vid, ++ .max = 4094, ++ }, ++}; ++ ++static const struct switch_dev_ops ar7240_ops = { ++ .attr_global = { ++ .attr = ar7240_globals, ++ .n_attr = ARRAY_SIZE(ar7240_globals), ++ }, ++ .attr_port = { ++ .attr = ar7240_port, ++ .n_attr = ARRAY_SIZE(ar7240_port), ++ }, ++ .attr_vlan = { ++ .attr = ar7240_vlan, ++ .n_attr = ARRAY_SIZE(ar7240_vlan), ++ }, ++ .get_port_pvid = ar7240_get_pvid, ++ .set_port_pvid = ar7240_set_pvid, ++ .get_vlan_ports = ar7240_get_ports, ++ .set_vlan_ports = ar7240_set_ports, ++ .apply_config = ar7240_hw_apply, ++ .reset_switch = ar7240_reset_switch, ++}; ++ ++static struct ar7240sw *ar7240_probe(struct ag71xx *ag) ++{ ++ struct mii_bus *mii = ag->mii_bus; ++ struct ar7240sw *as; ++ struct switch_dev *swdev; ++ u32 ctrl; ++ u16 phy_id1; ++ u16 phy_id2; ++ u8 ver; ++ int i; ++ ++ as = kzalloc(sizeof(*as), GFP_KERNEL); ++ if (!as) ++ return NULL; ++ ++ ar7240sw_init(as, mii); ++ ++ ctrl = ar7240sw_reg_read(mii, AR7240_REG_MASK_CTRL); ++ ++ ver = (ctrl >> AR7240_MASK_CTRL_VERSION_S) & AR7240_MASK_CTRL_VERSION_M; ++ if (ver != 1) { ++ pr_err("%s: unsupported chip, ctrl=%08x\n", ++ ag->dev->name, ctrl); ++ return NULL; ++ } ++ ++ phy_id1 = ar7240sw_phy_read(mii, 0, MII_PHYSID1); ++ phy_id2 = ar7240sw_phy_read(mii, 0, MII_PHYSID2); ++ if (phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) { ++ pr_err("%s: unknown phy id '%04x:%04x'\n", ++ ag->dev->name, phy_id1, phy_id2); ++ return NULL; ++ } ++ ++ swdev = &as->swdev; ++ swdev->name = "AR7240 built-in switch"; ++ swdev->ports = AR7240_NUM_PORTS; ++ swdev->cpu_port = AR7240_PORT_CPU; ++ swdev->vlans = AR7240_MAX_VLANS; ++ swdev->ops = &ar7240_ops; ++ ++ if (register_switch(&as->swdev, ag->dev) < 0) { ++ kfree(as); ++ return NULL; ++ } ++ ++ pr_info("%s: Found an AR7240 built-in switch\n", ag->dev->name); ++ ++ /* initialize defaults */ ++ for (i = 0; i < AR7240_MAX_VLANS; i++) ++ as->vlan_id[i] = i; ++ ++ as->vlan_table[0] = AR7240_PORT_MASK_ALL; ++ ++ return as; ++} ++ ++static void link_function(struct work_struct *work) { ++ struct ag71xx *ag = container_of(work, struct ag71xx, link_work.work); ++ unsigned long flags; ++ int i; ++ int status = 0; ++ ++ for (i = 0; i < 4; i++) { ++ int link = ar7240sw_phy_read(ag->mii_bus, i, MII_BMSR); ++ if(link & BMSR_LSTATUS) { ++ status = 1; ++ break; ++ } ++ } ++ ++ spin_lock_irqsave(&ag->lock, flags); ++ if(status != ag->link) { ++ ag->link = status; ++ ag71xx_link_adjust(ag); ++ } ++ spin_unlock_irqrestore(&ag->lock, flags); ++ ++ schedule_delayed_work(&ag->link_work, HZ / 2); ++} ++ ++void ag71xx_ar7240_start(struct ag71xx *ag) ++{ ++ struct ar7240sw *as = ag->phy_priv; ++ ++ ar7240sw_reset(as); ++ ++ ag->speed = SPEED_1000; ++ ag->duplex = 1; ++ ++ ar7240_set_addr(as, ag->dev->dev_addr); ++ ar7240_hw_apply(&as->swdev); ++ ++ schedule_delayed_work(&ag->link_work, HZ / 10); ++} ++ ++void ag71xx_ar7240_stop(struct ag71xx *ag) ++{ ++ cancel_delayed_work_sync(&ag->link_work); ++} ++ ++int __devinit ag71xx_ar7240_init(struct ag71xx *ag) ++{ ++ struct ar7240sw *as; ++ ++ as = ar7240_probe(ag); ++ if (!as) ++ return -ENODEV; ++ ++ ag->phy_priv = as; ++ ar7240sw_reset(as); ++ ++ INIT_DELAYED_WORK(&ag->link_work, link_function); ++ ++ return 0; ++} ++ ++void ag71xx_ar7240_cleanup(struct ag71xx *ag) ++{ ++ struct ar7240sw *as = ag->phy_priv; ++ ++ if (!as) ++ return; ++ ++ unregister_switch(&as->swdev); ++ kfree(as); ++ ag->phy_priv = NULL; ++} diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_ar8216.c linux-2.6.39/drivers/net/ag71xx/ag71xx_ar8216.c --- linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_ar8216.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/ag71xx_ar8216.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/net/ag71xx/ag71xx_ar8216.c 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,44 @@ +/* + * Atheros AR71xx built-in ethernet mac driver @@ -12734,8 +16851,8 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_ar8216.c linux-2.6.39/driv +} diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_debugfs.c linux-2.6.39/drivers/net/ag71xx/ag71xx_debugfs.c --- linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_debugfs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/ag71xx_debugfs.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,197 @@ ++++ linux-2.6.39/drivers/net/ag71xx/ag71xx_debugfs.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,280 @@ +/* + * Atheros AR71xx built-in ethernet mac driver + * @@ -12782,8 +16899,8 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_debugfs.c linux-2.6.39/dri +static ssize_t read_file_int_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ -+#define PR_INT_STAT(_label, _field) \ -+ len += snprintf(buf + len, sizeof(buf) - len, \ ++#define PR_INT_STAT(_label, _field) \ ++ len += snprintf(buf + len, sizeof(buf) - len, \ + "%20s: %10lu\n", _label, ag->debug.int_stats._field); + + struct ag71xx *ag = file->private_data; @@ -12837,38 +16954,48 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_debugfs.c linux-2.6.39/dri +{ + struct ag71xx *ag = file->private_data; + struct ag71xx_napi_stats *stats = &ag->debug.napi_stats; -+ char buf[2048]; ++ char *buf; ++ unsigned int buflen; + unsigned int len = 0; + unsigned long rx_avg = 0; + unsigned long tx_avg = 0; ++ int ret; + int i; + ++ buflen = 2048; ++ buf = kmalloc(buflen, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ + if (stats->rx_count) + rx_avg = stats->rx_packets / stats->rx_count; + + if (stats->tx_count) + tx_avg = stats->tx_packets / stats->tx_count; + -+ len += snprintf(buf + len, sizeof(buf) - len, "%3s %10s %10s\n", ++ len += snprintf(buf + len, buflen - len, "%3s %10s %10s\n", + "len", "rx", "tx"); + + for (i = 1; i <= AG71XX_NAPI_WEIGHT; i++) -+ len += snprintf(buf + len, sizeof(buf) - len, ++ len += snprintf(buf + len, buflen - len, + "%3d: %10lu %10lu\n", + i, stats->rx[i], stats->tx[i]); + -+ len += snprintf(buf + len, sizeof(buf) - len, "\n"); ++ len += snprintf(buf + len, buflen - len, "\n"); + -+ len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n", ++ len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n", + "sum", stats->rx_count, stats->tx_count); -+ len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n", ++ len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n", + "avg", rx_avg, tx_avg); -+ len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n", ++ len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n", + "max", stats->rx_packets_max, stats->tx_packets_max); -+ len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n", ++ len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n", + "pkt", stats->rx_packets, stats->tx_packets); + -+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ ++ return ret; +} + +static const struct file_operations ag71xx_fops_napi_stats = { @@ -12877,11 +17004,97 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_debugfs.c linux-2.6.39/dri + .owner = THIS_MODULE +}; + ++#define DESC_PRINT_LEN 64 ++ ++static ssize_t read_file_ring(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos, ++ struct ag71xx *ag, ++ struct ag71xx_ring *ring, ++ unsigned desc_reg) ++{ ++ char *buf; ++ unsigned int buflen; ++ unsigned int len = 0; ++ unsigned long flags; ++ ssize_t ret; ++ int curr; ++ int dirty; ++ u32 desc_hw; ++ int i; ++ ++ buflen = (ring->size * DESC_PRINT_LEN); ++ buf = kmalloc(buflen, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ len += snprintf(buf + len, buflen - len, ++ "Idx ... %-8s %-8s %-8s %-8s . %-10s\n", ++ "desc", "next", "data", "ctrl", "timestamp"); ++ ++ spin_lock_irqsave(&ag->lock, flags); ++ ++ curr = (ring->curr % ring->size); ++ dirty = (ring->dirty % ring->size); ++ desc_hw = ag71xx_rr(ag, desc_reg); ++ for (i = 0; i < ring->size; i++) { ++ struct ag71xx_buf *ab = &ring->buf[i]; ++ u32 desc_dma = ((u32) ring->descs_dma) + i * ring->desc_size; ++ ++ len += snprintf(buf + len, buflen - len, ++ "%3d %c%c%c %08x %08x %08x %08x %c %10lu\n", ++ i, ++ (i == curr) ? 'C' : ' ', ++ (i == dirty) ? 'D' : ' ', ++ (desc_hw == desc_dma) ? 'H' : ' ', ++ desc_dma, ++ ab->desc->next, ++ ab->desc->data, ++ ab->desc->ctrl, ++ (ab->desc->ctrl & DESC_EMPTY) ? 'E' : '*', ++ ab->timestamp); ++ } ++ ++ spin_unlock_irqrestore(&ag->lock, flags); ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ ++ return ret; ++} ++ ++static ssize_t read_file_tx_ring(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ag71xx *ag = file->private_data; ++ ++ return read_file_ring(file, user_buf, count, ppos, ag, &ag->tx_ring, ++ AG71XX_REG_TX_DESC); ++} ++ ++static const struct file_operations ag71xx_fops_tx_ring = { ++ .open = ag71xx_debugfs_generic_open, ++ .read = read_file_tx_ring, ++ .owner = THIS_MODULE ++}; ++ ++static ssize_t read_file_rx_ring(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ag71xx *ag = file->private_data; ++ ++ return read_file_ring(file, user_buf, count, ppos, ag, &ag->rx_ring, ++ AG71XX_REG_RX_DESC); ++} ++ ++static const struct file_operations ag71xx_fops_rx_ring = { ++ .open = ag71xx_debugfs_generic_open, ++ .read = read_file_rx_ring, ++ .owner = THIS_MODULE ++}; ++ +void ag71xx_debugfs_exit(struct ag71xx *ag) +{ -+ debugfs_remove(ag->debug.debugfs_napi_stats); -+ debugfs_remove(ag->debug.debugfs_int_stats); -+ debugfs_remove(ag->debug.debugfs_dir); ++ debugfs_remove_recursive(ag->debug.debugfs_dir); +} + +int ag71xx_debugfs_init(struct ag71xx *ag) @@ -12889,31 +17102,18 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_debugfs.c linux-2.6.39/dri + ag->debug.debugfs_dir = debugfs_create_dir(ag->dev->name, + ag71xx_debugfs_root); + if (!ag->debug.debugfs_dir) -+ goto err; -+ -+ ag->debug.debugfs_int_stats = -+ debugfs_create_file("int_stats", -+ S_IRUGO, -+ ag->debug.debugfs_dir, -+ ag, -+ &ag71xx_fops_int_stats); -+ if (!ag->debug.debugfs_int_stats) -+ goto err; ++ return -ENOMEM; + -+ ag->debug.debugfs_napi_stats = -+ debugfs_create_file("napi_stats", -+ S_IRUGO, -+ ag->debug.debugfs_dir, -+ ag, -+ &ag71xx_fops_napi_stats); -+ if (!ag->debug.debugfs_napi_stats) -+ goto err; ++ debugfs_create_file("int_stats", S_IRUGO, ag->debug.debugfs_dir, ++ ag, &ag71xx_fops_int_stats); ++ debugfs_create_file("napi_stats", S_IRUGO, ag->debug.debugfs_dir, ++ ag, &ag71xx_fops_napi_stats); ++ debugfs_create_file("tx_ring", S_IRUGO, ag->debug.debugfs_dir, ++ ag, &ag71xx_fops_tx_ring); ++ debugfs_create_file("rx_ring", S_IRUGO, ag->debug.debugfs_dir, ++ ag, &ag71xx_fops_rx_ring); + + return 0; -+ -+ err: -+ ag71xx_debugfs_exit(ag); -+ return -ENOMEM; +} + +int ag71xx_debugfs_root_init(void) @@ -12935,8 +17135,8 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_debugfs.c linux-2.6.39/dri +} diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_ethtool.c linux-2.6.39/drivers/net/ag71xx/ag71xx_ethtool.c --- linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_ethtool.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/ag71xx_ethtool.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,71 @@ ++++ linux-2.6.39/drivers/net/ag71xx/ag71xx_ethtool.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,124 @@ +/* + * Atheros AR71xx built-in ethernet mac driver + * @@ -13000,18 +17200,71 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_ethtool.c linux-2.6.39/dri + ag->msg_enable = msg_level; +} + ++static void ag71xx_ethtool_get_ringparam(struct net_device *dev, ++ struct ethtool_ringparam *er) ++{ ++ struct ag71xx *ag = netdev_priv(dev); ++ ++ er->tx_max_pending = AG71XX_TX_RING_SIZE_MAX; ++ er->rx_max_pending = AG71XX_RX_RING_SIZE_MAX; ++ er->rx_mini_max_pending = 0; ++ er->rx_jumbo_max_pending = 0; ++ ++ er->tx_pending = ag->tx_ring.size; ++ er->rx_pending = ag->rx_ring.size; ++ er->rx_mini_pending = 0; ++ er->rx_jumbo_pending = 0; ++} ++ ++static int ag71xx_ethtool_set_ringparam(struct net_device *dev, ++ struct ethtool_ringparam *er) ++{ ++ struct ag71xx *ag = netdev_priv(dev); ++ unsigned tx_size; ++ unsigned rx_size; ++ int err; ++ ++ if (er->rx_mini_pending != 0|| ++ er->rx_jumbo_pending != 0 || ++ er->rx_pending == 0 || ++ er->tx_pending == 0) ++ return -EINVAL; ++ ++ tx_size = er->tx_pending < AG71XX_TX_RING_SIZE_MAX ? ++ er->tx_pending : AG71XX_TX_RING_SIZE_MAX; ++ ++ rx_size = er->rx_pending < AG71XX_RX_RING_SIZE_MAX ? ++ er->rx_pending : AG71XX_RX_RING_SIZE_MAX; ++ ++ if (netif_running(dev)) { ++ err = dev->netdev_ops->ndo_stop(dev); ++ if (err) ++ return err; ++ } ++ ++ ag->tx_ring.size = tx_size; ++ ag->rx_ring.size = rx_size; ++ ++ if (netif_running(dev)) ++ err = dev->netdev_ops->ndo_open(dev); ++ ++ return err; ++} ++ +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_msglevel = ag71xx_ethtool_get_msglevel, + .set_msglevel = ag71xx_ethtool_set_msglevel, ++ .get_ringparam = ag71xx_ethtool_get_ringparam, ++ .set_ringparam = ag71xx_ethtool_set_ringparam, + .get_link = ethtool_op_get_link, +}; diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/drivers/net/ag71xx/ag71xx_main.c --- linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/ag71xx_main.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,1184 @@ ++++ linux-2.6.39/drivers/net/ag71xx/ag71xx_main.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,1291 @@ +/* + * Atheros AR71xx built-in ethernet mac driver + * @@ -13028,14 +17281,14 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver +#include "ag71xx.h" + +#define AG71XX_DEFAULT_MSG_ENABLE \ -+ ( NETIF_MSG_DRV \ ++ (NETIF_MSG_DRV \ + | NETIF_MSG_PROBE \ + | NETIF_MSG_LINK \ + | NETIF_MSG_TIMER \ + | NETIF_MSG_IFDOWN \ + | NETIF_MSG_IFUP \ + | NETIF_MSG_RX_ERR \ -+ | NETIF_MSG_TX_ERR ) ++ | NETIF_MSG_TX_ERR) + +static int ag71xx_msg_level = -1; + @@ -13104,7 +17357,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + ring->descs_cpu, ring->descs_dma); +} + -+static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size) ++static int ag71xx_ring_alloc(struct ag71xx_ring *ring) +{ + int err; + int i; @@ -13117,30 +17370,30 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + ring->desc_size = roundup(ring->desc_size, cache_line_size()); + } + -+ ring->descs_cpu = dma_alloc_coherent(NULL, size * ring->desc_size, ++ ring->descs_cpu = dma_alloc_coherent(NULL, ring->size * ring->desc_size, + &ring->descs_dma, GFP_ATOMIC); + if (!ring->descs_cpu) { + err = -ENOMEM; + goto err; + } + -+ ring->size = size; + -+ ring->buf = kzalloc(size * sizeof(*ring->buf), GFP_KERNEL); ++ ring->buf = kzalloc(ring->size * sizeof(*ring->buf), GFP_KERNEL); + if (!ring->buf) { + err = -ENOMEM; + goto err; + } + -+ for (i = 0; i < size; i++) { -+ ring->buf[i].desc = (struct ag71xx_desc *)&ring->descs_cpu[i * ring->desc_size]; ++ for (i = 0; i < ring->size; i++) { ++ int idx = i * ring->desc_size; ++ ring->buf[i].desc = (struct ag71xx_desc *)&ring->descs_cpu[idx]; + DBG("ag71xx: ring %p, desc %d at %p\n", + ring, i, ring->buf[i].desc); + } + + return 0; + -+ err: ++err: + return err; +} + @@ -13150,7 +17403,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + struct net_device *dev = ag->dev; + + while (ring->curr != ring->dirty) { -+ u32 i = ring->dirty % AG71XX_TX_RING_SIZE; ++ u32 i = ring->dirty % ring->size; + + if (!ag71xx_desc_empty(ring->buf[i].desc)) { + ring->buf[i].desc->ctrl = 0; @@ -13175,9 +17428,9 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + struct ag71xx_ring *ring = &ag->tx_ring; + int i; + -+ for (i = 0; i < AG71XX_TX_RING_SIZE; i++) { ++ for (i = 0; i < ring->size; i++) { + ring->buf[i].desc->next = (u32) (ring->descs_dma + -+ ring->desc_size * ((i + 1) % AG71XX_TX_RING_SIZE)); ++ ring->desc_size * ((i + 1) % ring->size)); + + ring->buf[i].desc->ctrl = DESC_EMPTY; + ring->buf[i].skb = NULL; @@ -13198,7 +17451,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + if (!ring->buf) + return; + -+ for (i = 0; i < AG71XX_RX_RING_SIZE; i++) ++ for (i = 0; i < ring->size; i++) + if (ring->buf[i].skb) { + dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr, + AG71XX_RX_PKT_SIZE, DMA_FROM_DEVICE); @@ -13232,16 +17485,16 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + int ret; + + ret = 0; -+ for (i = 0; i < AG71XX_RX_RING_SIZE; i++) { ++ for (i = 0; i < ring->size; i++) { + ring->buf[i].desc->next = (u32) (ring->descs_dma + -+ ring->desc_size * ((i + 1) % AG71XX_RX_RING_SIZE)); ++ ring->desc_size * ((i + 1) % ring->size)); + + DBG("ag71xx: RX desc at %p, next is %08x\n", + ring->buf[i].desc, + ring->buf[i].desc->next); + } + -+ for (i = 0; i < AG71XX_RX_RING_SIZE; i++) { ++ for (i = 0; i < ring->size; i++) { + struct sk_buff *skb; + dma_addr_t dma_addr; + @@ -13282,7 +17535,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + for (; ring->curr - ring->dirty > 0; ring->dirty++) { + unsigned int i; + -+ i = ring->dirty % AG71XX_RX_RING_SIZE; ++ i = ring->dirty % ring->size; + + if (ring->buf[i].skb == NULL) { + dma_addr_t dma_addr; @@ -13320,13 +17573,13 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver +{ + int ret; + -+ ret = ag71xx_ring_alloc(&ag->tx_ring, AG71XX_TX_RING_SIZE); ++ ret = ag71xx_ring_alloc(&ag->tx_ring); + if (ret) + return ret; + + ag71xx_ring_tx_init(ag); + -+ ret = ag71xx_ring_alloc(&ag->rx_ring, AG71XX_RX_RING_SIZE); ++ ret = ag71xx_ring_alloc(&ag->rx_ring); + if (ret) + return ret; + @@ -13357,93 +17610,6 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + return "?"; +} + -+void ag71xx_link_adjust(struct ag71xx *ag) -+{ -+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); -+ u32 cfg2; -+ u32 ifctl; -+ u32 fifo5; -+ u32 mii_speed; -+ -+ if (!ag->link) { -+ netif_carrier_off(ag->dev); -+ if (netif_msg_link(ag)) -+ 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_BM; -+ -+ switch (ag->speed) { -+ case SPEED_1000: -+ mii_speed = MII_CTRL_SPEED_1000; -+ cfg2 |= MAC_CFG2_IF_1000; -+ fifo5 |= FIFO_CFG5_BM; -+ break; -+ case SPEED_100: -+ mii_speed = MII_CTRL_SPEED_100; -+ cfg2 |= MAC_CFG2_IF_10_100; -+ ifctl |= MAC_IFCTL_SPEED; -+ break; -+ case SPEED_10: -+ mii_speed = MII_CTRL_SPEED_10; -+ cfg2 |= MAC_CFG2_IF_10_100; -+ break; -+ default: -+ BUG(); -+ return; -+ } -+ -+ if (pdata->is_ar91xx) -+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff); -+ else if (pdata->is_ar724x) -+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, pdata->fifo_cfg3); -+ else -+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff); -+ -+ if (pdata->set_pll) -+ pdata->set_pll(ag->speed); -+ -+ 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); -+ if (netif_msg_link(ag)) -+ 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: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\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=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\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)); -+ -+ DBG("%s: mac_cfg2=%#x, mac_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_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac) +{ + u32 t; @@ -13468,9 +17634,15 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); + ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); + ++ /* ++ * give the hardware some time to really stop all rx/tx activity ++ * clearing the descriptors too early causes random memory corruption ++ */ ++ mdelay(1); ++ + /* clear descriptor addresses */ -+ ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0); -+ ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0); ++ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->stop_desc_dma); ++ ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->stop_desc_dma); + + /* clear pending RX/TX interrupts */ + for (i = 0; i < 256; i++) { @@ -13518,24 +17690,20 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \ + FIFO_CFG5_17 | FIFO_CFG5_SF) + -+static void ag71xx_hw_init(struct ag71xx *ag) ++static void ag71xx_hw_stop(struct ag71xx *ag) +{ -+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); -+ -+ ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR); -+ udelay(20); ++ /* disable all interrupts and stop the rx/tx engine */ ++ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0); ++ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); ++ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); ++} + -+ ar71xx_device_stop(pdata->reset_bit); -+ mdelay(100); -+ ar71xx_device_start(pdata->reset_bit); -+ mdelay(100); ++static void ag71xx_hw_setup(struct ag71xx *ag) ++{ ++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); + + /* setup MAC configuration registers */ -+ if (pdata->is_ar724x) -+ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, -+ MAC_CFG1_INIT | MAC_CFG1_TFC | MAC_CFG1_RFC); -+ else -+ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT); ++ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT); + + ag71xx_sb(ag, AG71XX_REG_MAC_CFG2, + MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK); @@ -13557,8 +17725,67 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + } + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT); + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT); ++} ++ ++static void ag71xx_hw_init(struct ag71xx *ag) ++{ ++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); ++ u32 reset_mask = pdata->reset_bit; ++ ++ ag71xx_hw_stop(ag); ++ ++ if (pdata->is_ar724x) { ++ u32 reset_phy = reset_mask; ++ ++ reset_phy &= RESET_MODULE_GE0_PHY | RESET_MODULE_GE1_PHY; ++ reset_mask &= ~(RESET_MODULE_GE0_PHY | RESET_MODULE_GE1_PHY); ++ ++ ar71xx_device_stop(reset_phy); ++ mdelay(50); ++ ar71xx_device_start(reset_phy); ++ mdelay(200); ++ } ++ ++ ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR); ++ udelay(20); ++ ++ ar71xx_device_stop(reset_mask); ++ mdelay(100); ++ ar71xx_device_start(reset_mask); ++ mdelay(200); ++ ++ ag71xx_hw_setup(ag); ++ ++ ag71xx_dma_reset(ag); ++} ++ ++static void ag71xx_fast_reset(struct ag71xx *ag) ++{ ++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); ++ struct net_device *dev = ag->dev; ++ u32 reset_mask = pdata->reset_bit; ++ u32 rx_ds, tx_ds; ++ u32 mii_reg; ++ ++ reset_mask &= RESET_MODULE_GE0_MAC | RESET_MODULE_GE1_MAC; ++ ++ mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG); ++ rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC); ++ tx_ds = ag71xx_rr(ag, AG71XX_REG_TX_DESC); ++ ++ ar71xx_device_stop(reset_mask); ++ udelay(10); ++ ar71xx_device_start(reset_mask); ++ udelay(10); + + ag71xx_dma_reset(ag); ++ ag71xx_hw_setup(ag); ++ ++ ag71xx_wr(ag, AG71XX_REG_RX_DESC, rx_ds); ++ ag71xx_wr(ag, AG71XX_REG_TX_DESC, tx_ds); ++ ag71xx_wr(ag, AG71XX_REG_MII_CFG, mii_reg); ++ ++ ag71xx_hw_set_macaddr(ag, dev->dev_addr); +} + +static void ag71xx_hw_start(struct ag71xx *ag) @@ -13570,12 +17797,96 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT); +} + -+static void ag71xx_hw_stop(struct ag71xx *ag) ++void ag71xx_link_adjust(struct ag71xx *ag) +{ -+ /* disable all interrupts */ -+ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0); ++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); ++ u32 cfg2; ++ u32 ifctl; ++ u32 fifo5; ++ u32 mii_speed; + -+ ag71xx_dma_reset(ag); ++ if (!ag->link) { ++ ag71xx_hw_stop(ag); ++ netif_carrier_off(ag->dev); ++ if (netif_msg_link(ag)) ++ printk(KERN_INFO "%s: link down\n", ag->dev->name); ++ return; ++ } ++ ++ if (pdata->is_ar724x) ++ ag71xx_fast_reset(ag); ++ ++ 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_BM; ++ ++ switch (ag->speed) { ++ case SPEED_1000: ++ mii_speed = MII_CTRL_SPEED_1000; ++ cfg2 |= MAC_CFG2_IF_1000; ++ fifo5 |= FIFO_CFG5_BM; ++ break; ++ case SPEED_100: ++ mii_speed = MII_CTRL_SPEED_100; ++ cfg2 |= MAC_CFG2_IF_10_100; ++ ifctl |= MAC_IFCTL_SPEED; ++ break; ++ case SPEED_10: ++ mii_speed = MII_CTRL_SPEED_10; ++ cfg2 |= MAC_CFG2_IF_10_100; ++ break; ++ default: ++ BUG(); ++ return; ++ } ++ ++ if (pdata->is_ar91xx) ++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff); ++ else if (pdata->is_ar724x) ++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, pdata->fifo_cfg3); ++ else ++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff); ++ ++ if (pdata->set_pll) ++ pdata->set_pll(ag->speed); ++ ++ 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); ++ ag71xx_hw_start(ag); ++ ++ netif_carrier_on(ag->dev); ++ if (netif_msg_link(ag)) ++ 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: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\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=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\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)); ++ ++ DBG("%s: mac_cfg2=%#x, mac_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 int ag71xx_open(struct net_device *dev) @@ -13597,13 +17908,11 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + + ag71xx_hw_set_macaddr(ag, dev->dev_addr); + -+ ag71xx_hw_start(ag); -+ + netif_start_queue(dev); + + return 0; + -+ err: ++err: + ag71xx_rings_cleanup(ag); + return ret; +} @@ -13621,6 +17930,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + netif_stop_queue(dev); + + ag71xx_hw_stop(ag); ++ ag71xx_dma_reset(ag); + + napi_disable(&ag->napi); + del_timer_sync(&ag->oom_timer); @@ -13641,7 +17951,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + dma_addr_t dma_addr; + int i; + -+ i = ring->curr % AG71XX_TX_RING_SIZE; ++ i = ring->curr % ring->size; + desc = ring->buf[i].desc; + + if (!ag71xx_desc_empty(desc)) @@ -13659,6 +17969,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + DMA_TO_DEVICE); + + ring->buf[i].skb = skb; ++ ring->buf[i].timestamp = jiffies; + + /* setup descriptor fields */ + desc->data = (u32) dma_addr; @@ -13668,7 +17979,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + wmb(); + + ring->curr++; -+ if (ring->curr == (ring->dirty + AG71XX_TX_THRES_STOP)) { ++ if (ring->curr == (ring->dirty + ring->size)) { + DBG("%s: tx queue full\n", ag->dev->name); + netif_stop_queue(dev); + } @@ -13680,7 +17991,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + + return NETDEV_TX_OK; + -+ err_drop: ++err_drop: + dev->stats.tx_dropped++; + + dev_kfree_skb(skb); @@ -13689,7 +18000,6 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + +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; + @@ -13721,7 +18031,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + if (ag->phy_dev == NULL) + break; + -+ return phy_mii_ioctl(ag->phy_dev, data, cmd); ++ return phy_mii_ioctl(ag->phy_dev, ifr, cmd); + + default: + break; @@ -13752,25 +18062,59 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver +{ + struct ag71xx *ag = container_of(work, struct ag71xx, restart_work); + ++ if (ag71xx_get_pdata(ag)->is_ar724x) { ++ ag->link = 0; ++ ag71xx_link_adjust(ag); ++ return; ++ } ++ + ag71xx_stop(ag->dev); + ag71xx_open(ag->dev); +} + ++static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp) ++{ ++ u32 rx_sm, tx_sm, rx_fd; ++ ++ if (likely(time_before(jiffies, timestamp + HZ/10))) ++ return false; ++ ++ if (!netif_carrier_ok(ag->dev)) ++ return false; ++ ++ rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM); ++ if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6) ++ return true; ++ ++ tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM); ++ rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH); ++ if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) && ++ ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0) ++ return true; ++ ++ return false; ++} ++ +static int ag71xx_tx_packets(struct ag71xx *ag) +{ + struct ag71xx_ring *ring = &ag->tx_ring; ++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); + int sent; + + DBG("%s: processing TX ring\n", ag->dev->name); + + sent = 0; + while (ring->dirty != ring->curr) { -+ unsigned int i = ring->dirty % AG71XX_TX_RING_SIZE; ++ unsigned int i = ring->dirty % ring->size; + struct ag71xx_desc *desc = ring->buf[i].desc; + struct sk_buff *skb = ring->buf[i].skb; + -+ if (!ag71xx_desc_empty(desc)) ++ if (!ag71xx_desc_empty(desc)) { ++ if (pdata->is_ar7240 && ++ ag71xx_check_dma_stuck(ag, ring->buf[i].timestamp)) ++ schedule_work(&ag->restart_work); + break; ++ } + + ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); + @@ -13786,7 +18130,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + + DBG("%s: %d packets sent out\n", ag->dev->name, sent); + -+ if ((ring->curr - ring->dirty) < AG71XX_TX_THRES_WAKEUP) ++ if ((ring->curr - ring->dirty) < (ring->size * 3) / 4) + netif_wake_queue(ag->dev); + + return sent; @@ -13802,7 +18146,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + dev->name, limit, ring->curr, ring->dirty); + + while (done < limit) { -+ unsigned int i = ring->curr % AG71XX_RX_RING_SIZE; ++ unsigned int i = ring->curr % ring->size; + struct ag71xx_desc *desc = ring->buf[i].desc; + struct sk_buff *skb; + int pktlen; @@ -13811,7 +18155,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + if (ag71xx_desc_empty(desc)) + break; + -+ if ((ring->dirty + AG71XX_RX_RING_SIZE) == ring->curr) { ++ if ((ring->dirty + ring->size) == ring->curr) { + ag71xx_assert(0); + break; + } @@ -13881,7 +18225,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + ag71xx_debugfs_update_napi_stats(ag, rx_done, tx_done); + + rx_ring = &ag->rx_ring; -+ if (rx_ring->buf[rx_ring->dirty % AG71XX_RX_RING_SIZE].skb == NULL) ++ if (rx_ring->buf[rx_ring->dirty % rx_ring->size].skb == NULL) + goto oom; + + status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS); @@ -13913,12 +18257,12 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + return rx_done; + } + -+ more: ++more: + DBG("%s: stay in polling mode, rx=%d, tx=%d, limit=%d\n", + dev->name, rx_done, tx_done, limit); + return rx_done; + -+ oom: ++oom: + if (netif_msg_rx_err(ag)) + printk(KERN_DEBUG "%s: out of memory\n", dev->name); + @@ -13995,7 +18339,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver +#endif +}; + -+static int __init ag71xx_probe(struct platform_device *pdev) ++static int __devinit ag71xx_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct resource *res; @@ -14062,7 +18406,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + + dev->irq = platform_get_irq(pdev, 0); + err = request_irq(dev->irq, ag71xx_interrupt, -+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM, ++ IRQF_DISABLED, + dev->name, dev); + if (err) { + dev_err(&pdev->dev, "unable to request IRQ %d\n", dev->irq); @@ -14079,6 +18423,19 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + ag->oom_timer.data = (unsigned long) dev; + ag->oom_timer.function = ag71xx_oom_timer_handler; + ++ ag->tx_ring.size = AG71XX_TX_RING_SIZE_DEFAULT; ++ ag->rx_ring.size = AG71XX_RX_RING_SIZE_DEFAULT; ++ ++ ag->stop_desc = dma_alloc_coherent(NULL, ++ sizeof(struct ag71xx_desc), &ag->stop_desc_dma, GFP_KERNEL); ++ ++ if (!ag->stop_desc) ++ goto err_free_irq; ++ ++ ag->stop_desc->data = 0; ++ ag->stop_desc->ctrl = 0; ++ ag->stop_desc->next = (u32) ag->stop_desc_dma; ++ + memcpy(dev->dev_addr, pdata->mac_addr, ETH_ALEN); + + netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT); @@ -14086,7 +18443,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + err = register_netdev(dev); + if (err) { + dev_err(&pdev->dev, "unable to register net device\n"); -+ goto err_free_irq; ++ goto err_free_desc; + } + + printk(KERN_INFO "%s: Atheros AG71xx at 0x%08lx, irq %d\n", @@ -14110,24 +18467,27 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + + return 0; + -+ err_phy_disconnect: ++err_phy_disconnect: + ag71xx_phy_disconnect(ag); -+ err_unregister_netdev: ++err_unregister_netdev: + unregister_netdev(dev); -+ err_free_irq: ++err_free_desc: ++ dma_free_coherent(NULL, sizeof(struct ag71xx_desc), ag->stop_desc, ++ ag->stop_desc_dma); ++err_free_irq: + free_irq(dev->irq, dev); -+ err_unmap_mii_ctrl: ++err_unmap_mii_ctrl: + iounmap(ag->mii_ctrl); -+ err_unmap_base: ++err_unmap_base: + iounmap(ag->mac_base); -+ err_free_dev: ++err_free_dev: + kfree(dev); -+ err_out: ++err_out: + platform_set_drvdata(pdev, NULL); + return err; +} + -+static int __exit ag71xx_remove(struct platform_device *pdev) ++static int __devexit ag71xx_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + @@ -14173,11 +18533,11 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver + + return 0; + -+ err_mdio_exit: ++err_mdio_exit: + ag71xx_mdio_driver_exit(); -+ err_debugfs_exit: ++err_debugfs_exit: + ag71xx_debugfs_root_exit(); -+ err_out: ++err_out: + return ret; +} + @@ -14198,8 +18558,8 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.39/driver +MODULE_ALIAS("platform:" AG71XX_DRV_NAME); diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.39/drivers/net/ag71xx/ag71xx_mdio.c --- linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_mdio.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/ag71xx_mdio.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,243 @@ ++++ linux-2.6.39/drivers/net/ag71xx/ag71xx_mdio.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,248 @@ +/* + * Atheros AR71xx built-in ethernet mac driver + * @@ -14249,7 +18609,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.39/driver + ag71xx_mdio_rr(am, AG71XX_REG_MII_IND)); +} + -+static int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg) ++int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg) +{ + int ret; + int i; @@ -14275,12 +18635,11 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.39/driver + + DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret); + -+ out: ++out: + return ret; +} + -+static void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, -+ int addr, int reg, u16 val) ++void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val) +{ + int i; + @@ -14324,18 +18683,24 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.39/driver +{ + struct ag71xx_mdio *am = bus->priv; + -+ return ag71xx_mdio_mii_read(am, addr, reg); ++ if (am->pdata->is_ar7240) ++ return ar7240sw_phy_read(bus, addr, reg); ++ else ++ return ag71xx_mdio_mii_read(am, addr, reg); +} + +static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct ag71xx_mdio *am = bus->priv; + -+ ag71xx_mdio_mii_write(am, addr, reg, val); ++ if (am->pdata->is_ar7240) ++ ar7240sw_phy_write(bus, addr, reg, val); ++ else ++ ag71xx_mdio_mii_write(am, addr, reg, val); + return 0; +} + -+static int __init ag71xx_mdio_probe(struct platform_device *pdev) ++static int __devinit ag71xx_mdio_probe(struct platform_device *pdev) +{ + struct ag71xx_mdio_platform_data *pdata; + struct ag71xx_mdio *am; @@ -14401,17 +18766,17 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.39/driver + platform_set_drvdata(pdev, am); + return 0; + -+ err_free_bus: ++err_free_bus: + mdiobus_free(am->mii_bus); -+ err_iounmap: ++err_iounmap: + iounmap(am->mdio_base); -+ err_free_mdio: ++err_free_mdio: + kfree(am); -+ err_out: ++err_out: + return err; +} + -+static int __exit ag71xx_mdio_remove(struct platform_device *pdev) ++static int __devexit ag71xx_mdio_remove(struct platform_device *pdev) +{ + struct ag71xx_mdio *am = platform_get_drvdata(pdev); + @@ -14434,7 +18799,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.39/driver + } +}; + -+int ag71xx_mdio_driver_init(void) ++int __init ag71xx_mdio_driver_init(void) +{ + return platform_driver_register(&ag71xx_mdio_driver); +} @@ -14445,8 +18810,8 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.39/driver +} diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_phy.c linux-2.6.39/drivers/net/ag71xx/ag71xx_phy.c --- linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_phy.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/ag71xx/ag71xx_phy.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,213 @@ ++++ linux-2.6.39/drivers/net/ag71xx/ag71xx_phy.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,228 @@ +/* + * Atheros AR71xx built-in ethernet mac driver + * @@ -14493,8 +18858,12 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_phy.c linux-2.6.39/drivers + +void ag71xx_phy_start(struct ag71xx *ag) +{ ++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); ++ + if (ag->phy_dev) { + phy_start(ag->phy_dev); ++ } else if (pdata->has_ar7240_switch) { ++ ag71xx_ar7240_start(ag); + } else { + ag->link = 1; + ag71xx_link_adjust(ag); @@ -14503,9 +18872,13 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_phy.c linux-2.6.39/drivers + +void ag71xx_phy_stop(struct ag71xx *ag) +{ ++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); ++ + if (ag->phy_dev) { + phy_stop(ag->phy_dev); + } else { ++ if (pdata->has_ar7240_switch) ++ ag71xx_ar7240_stop(ag); + ag->link = 0; + ag71xx_link_adjust(ag); + } @@ -14631,7 +19004,7 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_phy.c linux-2.6.39/drivers + return NULL; +} + -+int ag71xx_phy_connect(struct ag71xx *ag) ++int __devinit ag71xx_phy_connect(struct ag71xx *ag) +{ + struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); + @@ -14649,6 +19022,9 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_phy.c linux-2.6.39/drivers + mutex_unlock(&ag->mii_bus->mdio_lock); + } + ++ if (pdata->has_ar7240_switch) ++ return ag71xx_ar7240_init(ag); ++ + if (pdata->phy_mask) + return ag71xx_phy_connect_multi(ag); + @@ -14657,26 +19033,348 @@ diff -Nur linux-2.6.39.orig/drivers/net/ag71xx/ag71xx_phy.c linux-2.6.39/drivers + +void ag71xx_phy_disconnect(struct ag71xx *ag) +{ -+ if (ag->phy_dev) ++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); ++ ++ if (pdata->has_ar7240_switch) ++ ag71xx_ar7240_cleanup(ag); ++ else if (ag->phy_dev) + phy_disconnect(ag->phy_dev); +} diff -Nur linux-2.6.39.orig/drivers/net/phy/Kconfig linux-2.6.39/drivers/net/phy/Kconfig --- linux-2.6.39.orig/drivers/net/phy/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/net/phy/Kconfig 2011-05-27 14:36:51.000000000 +0200 -@@ -91,6 +91,10 @@ - ---help--- - Supports the KSZ9021, VSC8201, KS8001 PHYs. ++++ linux-2.6.39/drivers/net/phy/Kconfig 2011-08-24 18:17:24.000000000 +0200 +@@ -13,6 +13,12 @@ -+config IP175C_PHY -+ tristate "Driver for IC+ IP175C/IP178C switches" -+ select SWCONFIG + if PHYLIB + ++config SWCONFIG ++ tristate "Switch configuration API" ++ ---help--- ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. + - config FIXED_PHY - bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" - depends on PHYLIB=y + comment "MII PHY device drivers" + + config MARVELL_PHY +diff -Nur linux-2.6.39.orig/drivers/net/phy/Makefile linux-2.6.39/drivers/net/phy/Makefile +--- linux-2.6.39.orig/drivers/net/phy/Makefile 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/drivers/net/phy/Makefile 2011-08-24 18:17:24.000000000 +0200 +@@ -3,6 +3,7 @@ + libphy-objs := phy.o phy_device.o mdio_bus.o + + obj-$(CONFIG_PHYLIB) += libphy.o ++obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_DAVICOM_PHY) += davicom.o + obj-$(CONFIG_CICADA_PHY) += cicada.o +diff -Nur linux-2.6.39.orig/drivers/net/phy/micrel.c linux-2.6.39/drivers/net/phy/micrel.c +--- linux-2.6.39.orig/drivers/net/phy/micrel.c 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/drivers/net/phy/micrel.c 2011-08-24 18:17:24.000000000 +0200 +@@ -1,251 +1,82 @@ + /* +- * drivers/net/phy/micrel.c ++ * Driver for Micrel/Kendin PHYs + * +- * Driver for Micrel PHYs ++ * Copyright (c) 2008-2009 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * +- * Author: David J. Choi ++ * 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. + * +- * Copyright (c) 2010 Micrel, Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- * +- * Support : ksz9021 1000/100/10 phy from Micrel +- * ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy + */ + +-#include <linux/kernel.h> +-#include <linux/module.h> ++#include <linux/delay.h> ++#include <linux/skbuff.h> + #include <linux/phy.h> +-#include <linux/micrel_phy.h> + +-/* general Interrupt control/status reg in vendor specific block. */ +-#define MII_KSZPHY_INTCS 0x1B +-#define KSZPHY_INTCS_JABBER (1 << 15) +-#define KSZPHY_INTCS_RECEIVE_ERR (1 << 14) +-#define KSZPHY_INTCS_PAGE_RECEIVE (1 << 13) +-#define KSZPHY_INTCS_PARELLEL (1 << 12) +-#define KSZPHY_INTCS_LINK_PARTNER_ACK (1 << 11) +-#define KSZPHY_INTCS_LINK_DOWN (1 << 10) +-#define KSZPHY_INTCS_REMOTE_FAULT (1 << 9) +-#define KSZPHY_INTCS_LINK_UP (1 << 8) +-#define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\ +- KSZPHY_INTCS_LINK_DOWN) +- +-/* general PHY control reg in vendor specific block. */ +-#define MII_KSZPHY_CTRL 0x1F +-/* bitmap of PHY register to set interrupt mode */ +-#define KSZPHY_CTRL_INT_ACTIVE_HIGH (1 << 9) +-#define KSZ9021_CTRL_INT_ACTIVE_HIGH (1 << 14) +-#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14) +-#define KSZ8051_RMII_50MHZ_CLK (1 << 7) ++#define KSZ_REG_INT_CTRL 0x1b + +-static int kszphy_ack_interrupt(struct phy_device *phydev) +-{ +- /* bit[7..0] int status, which is a read and clear register. */ +- int rc; ++#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 */ + +- rc = phy_read(phydev, MII_KSZPHY_INTCS); +- +- return (rc < 0) ? rc : 0; +-} ++#define KSZ_INT_INIT (KSZ_INT_LU_EN | KSZ_INT_LD_EN) + +-static int kszphy_set_interrupt(struct phy_device *phydev) ++static int ksz8041_ack_interrupt(struct phy_device *phydev) + { +- int temp; +- temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ? +- KSZPHY_INTCS_ALL : 0; +- return phy_write(phydev, MII_KSZPHY_INTCS, temp); +-} ++ int err; + +-static int kszphy_config_intr(struct phy_device *phydev) +-{ +- int temp, rc; ++ err = phy_read(phydev, KSZ_REG_INT_CTRL); + +- /* set the interrupt pin active low */ +- temp = phy_read(phydev, MII_KSZPHY_CTRL); +- temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH; +- phy_write(phydev, MII_KSZPHY_CTRL, temp); +- rc = kszphy_set_interrupt(phydev); +- return rc < 0 ? rc : 0; ++ return (err < 0) ? err : 0; + } + +-static int ksz9021_config_intr(struct phy_device *phydev) ++static int ksz8041_config_intr(struct phy_device *phydev) + { +- int temp, rc; ++ int err; + +- /* set the interrupt pin active low */ +- temp = phy_read(phydev, MII_KSZPHY_CTRL); +- temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH; +- phy_write(phydev, MII_KSZPHY_CTRL, temp); +- rc = kszphy_set_interrupt(phydev); +- return rc < 0 ? rc : 0; +-} +- +-static int ks8737_config_intr(struct phy_device *phydev) +-{ +- int temp, rc; ++ 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); + +- /* set the interrupt pin active low */ +- temp = phy_read(phydev, MII_KSZPHY_CTRL); +- temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH; +- phy_write(phydev, MII_KSZPHY_CTRL, temp); +- rc = kszphy_set_interrupt(phydev); +- return rc < 0 ? rc : 0; ++ return err; + } + +-static int kszphy_config_init(struct phy_device *phydev) +-{ +- return 0; +-} +- +-static int ks8051_config_init(struct phy_device *phydev) +-{ +- int regval; +- +- if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) { +- regval = phy_read(phydev, MII_KSZPHY_CTRL); +- regval |= KSZ8051_RMII_50MHZ_CLK; +- phy_write(phydev, MII_KSZPHY_CTRL, regval); +- } +- +- return 0; +-} +- +-static struct phy_driver ks8737_driver = { +- .phy_id = PHY_ID_KS8737, +- .phy_id_mask = 0x00fffff0, +- .name = "Micrel KS8737", +- .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), +- .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, +- .config_init = kszphy_config_init, ++static struct phy_driver ksz8041_phy_driver = { ++ .phy_id = 0x00221512, ++ .name = "Micrel 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 = kszphy_ack_interrupt, +- .config_intr = ks8737_config_intr, +- .driver = { .owner = THIS_MODULE,}, ++ .ack_interrupt = ksz8041_ack_interrupt, ++ .config_intr = ksz8041_config_intr, ++ .driver = { ++ .owner = THIS_MODULE, ++ }, + }; + +-static struct phy_driver ks8041_driver = { +- .phy_id = PHY_ID_KS8041, +- .phy_id_mask = 0x00fffff0, +- .name = "Micrel KS8041", +- .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause +- | SUPPORTED_Asym_Pause), +- .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, +- .config_init = kszphy_config_init, +- .config_aneg = genphy_config_aneg, +- .read_status = genphy_read_status, +- .ack_interrupt = kszphy_ack_interrupt, +- .config_intr = kszphy_config_intr, +- .driver = { .owner = THIS_MODULE,}, +-}; +- +-static struct phy_driver ks8051_driver = { +- .phy_id = PHY_ID_KS8051, +- .phy_id_mask = 0x00fffff0, +- .name = "Micrel KS8051", +- .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause +- | SUPPORTED_Asym_Pause), +- .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, +- .config_init = ks8051_config_init, +- .config_aneg = genphy_config_aneg, +- .read_status = genphy_read_status, +- .ack_interrupt = kszphy_ack_interrupt, +- .config_intr = kszphy_config_intr, +- .driver = { .owner = THIS_MODULE,}, +-}; +- +-static struct phy_driver ks8001_driver = { +- .phy_id = PHY_ID_KS8001, +- .name = "Micrel KS8001 or KS8721", +- .phy_id_mask = 0x00fffff0, +- .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), +- .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, +- .config_init = kszphy_config_init, +- .config_aneg = genphy_config_aneg, +- .read_status = genphy_read_status, +- .ack_interrupt = kszphy_ack_interrupt, +- .config_intr = kszphy_config_intr, +- .driver = { .owner = THIS_MODULE,}, +-}; +- +-static struct phy_driver ksz9021_driver = { +- .phy_id = PHY_ID_KSZ9021, +- .phy_id_mask = 0x000fff10, +- .name = "Micrel KSZ9021 Gigabit PHY", +- .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause +- | SUPPORTED_Asym_Pause), +- .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, +- .config_init = kszphy_config_init, +- .config_aneg = genphy_config_aneg, +- .read_status = genphy_read_status, +- .ack_interrupt = kszphy_ack_interrupt, +- .config_intr = ksz9021_config_intr, +- .driver = { .owner = THIS_MODULE, }, +-}; +- +-static int __init ksphy_init(void) ++static int __init micrel_phy_init(void) + { +- int ret; +- +- ret = phy_driver_register(&ks8001_driver); +- if (ret) +- goto err1; +- +- ret = phy_driver_register(&ksz9021_driver); +- if (ret) +- goto err2; +- +- ret = phy_driver_register(&ks8737_driver); +- if (ret) +- goto err3; +- ret = phy_driver_register(&ks8041_driver); +- if (ret) +- goto err4; +- ret = phy_driver_register(&ks8051_driver); +- if (ret) +- goto err5; +- +- return 0; +- +-err5: +- phy_driver_unregister(&ks8041_driver); +-err4: +- phy_driver_unregister(&ks8737_driver); +-err3: +- phy_driver_unregister(&ksz9021_driver); +-err2: +- phy_driver_unregister(&ks8001_driver); +-err1: +- return ret; ++ return phy_driver_register(&ksz8041_phy_driver); + } + +-static void __exit ksphy_exit(void) ++static void __exit micrel_phy_exit(void) + { +- phy_driver_unregister(&ks8001_driver); +- phy_driver_unregister(&ks8737_driver); +- phy_driver_unregister(&ksz9021_driver); +- phy_driver_unregister(&ks8041_driver); +- phy_driver_unregister(&ks8051_driver); ++ phy_driver_unregister(&ksz8041_phy_driver); + } + +-module_init(ksphy_init); +-module_exit(ksphy_exit); +- +-MODULE_DESCRIPTION("Micrel PHY driver"); +-MODULE_AUTHOR("David J. Choi"); +-MODULE_LICENSE("GPL"); +- +-static struct mdio_device_id __maybe_unused micrel_tbl[] = { +- { PHY_ID_KSZ9021, 0x000fff10 }, +- { PHY_ID_KS8001, 0x00fffff0 }, +- { PHY_ID_KS8737, 0x00fffff0 }, +- { PHY_ID_KS8041, 0x00fffff0 }, +- { PHY_ID_KS8051, 0x00fffff0 }, +- { } +-}; ++#ifdef MODULE ++module_init(micrel_phy_init); ++module_exit(micrel_phy_exit); ++#else ++subsys_initcall(micrel_phy_init); ++#endif + +-MODULE_DEVICE_TABLE(mdio, micrel_tbl); ++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 -Nur linux-2.6.39.orig/drivers/net/phy/phy.c linux-2.6.39/drivers/net/phy/phy.c --- linux-2.6.39.orig/drivers/net/phy/phy.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/net/phy/phy.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/net/phy/phy.c 2011-08-24 18:17:24.000000000 +0200 @@ -297,6 +297,50 @@ } EXPORT_SYMBOL(phy_ethtool_gset); @@ -14739,8 +19437,8 @@ diff -Nur linux-2.6.39.orig/drivers/net/phy/phy.c linux-2.6.39/drivers/net/phy/p idx = phy_find_valid(idx, phydev->supported); diff -Nur linux-2.6.39.orig/drivers/net/phy/phy_device.c linux-2.6.39/drivers/net/phy/phy_device.c --- linux-2.6.39.orig/drivers/net/phy/phy_device.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/net/phy/phy_device.c 2011-05-27 14:36:51.000000000 +0200 -@@ -149,6 +149,19 @@ ++++ linux-2.6.39/drivers/net/phy/phy_device.c 2011-08-24 18:17:24.000000000 +0200 +@@ -149,6 +149,18 @@ } EXPORT_SYMBOL(phy_scan_fixups); @@ -14756,11 +19454,10 @@ diff -Nur linux-2.6.39.orig/drivers/net/phy/phy_device.c linux-2.6.39/drivers/ne + return netif_rx(skb); +} + -+ static struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) { -@@ -180,6 +193,8 @@ +@@ -180,6 +192,8 @@ dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr); dev->state = PHY_DOWN; @@ -14769,9 +19466,967 @@ diff -Nur linux-2.6.39.orig/drivers/net/phy/phy_device.c linux-2.6.39/drivers/ne mutex_init(&dev->lock); INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); +diff -Nur linux-2.6.39.orig/drivers/net/phy/swconfig.c linux-2.6.39/drivers/net/phy/swconfig.c +--- linux-2.6.39.orig/drivers/net/phy/swconfig.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/drivers/net/phy/swconfig.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,954 @@ ++/* ++ * swconfig.c: Switch configuration API ++ * ++ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/if.h> ++#include <linux/if_ether.h> ++#include <linux/capability.h> ++#include <linux/skbuff.h> ++#include <linux/switch.h> ++ ++//#define DEBUG 1 ++#ifdef DEBUG ++#define DPRINTF(format, ...) printk("%s: " format, __func__, ##__VA_ARGS__) ++#else ++#define DPRINTF(...) do {} while(0) ++#endif ++ ++#define SWCONFIG_DEVNAME "switch%d" ++ ++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>"); ++MODULE_LICENSE("GPL"); ++ ++static int swdev_id = 0; ++static struct list_head swdevs; ++static DEFINE_SPINLOCK(swdevs_lock); ++struct swconfig_callback; ++ ++struct swconfig_callback ++{ ++ struct sk_buff *msg; ++ struct genlmsghdr *hdr; ++ struct genl_info *info; ++ int cmd; ++ ++ /* callback for filling in the message data */ ++ int (*fill)(struct swconfig_callback *cb, void *arg); ++ ++ /* callback for closing the message before sending it */ ++ int (*close)(struct swconfig_callback *cb, void *arg); ++ ++ struct nlattr *nest[4]; ++ int args[4]; ++}; ++ ++/* defaults */ ++ ++static int ++swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ int ret; ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ if (!dev->ops->get_vlan_ports) ++ return -EOPNOTSUPP; ++ ++ ret = dev->ops->get_vlan_ports(dev, val); ++ return ret; ++} ++ ++static int ++swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ struct switch_port *ports = val->value.ports; ++ const struct switch_dev_ops *ops = dev->ops; ++ int i; ++ ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ /* validate ports */ ++ if (val->len > dev->ports) ++ return -EINVAL; ++ ++ if (!ops->set_vlan_ports) ++ return -EOPNOTSUPP; ++ ++ for (i = 0; i < val->len; i++) { ++ if (ports[i].id >= dev->ports) ++ return -EINVAL; ++ ++ if (ops->set_port_pvid && ++ !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED))) ++ ops->set_port_pvid(dev, ports[i].id, val->port_vlan); ++ } ++ ++ return ops->set_vlan_ports(dev, val); ++} ++ ++static int ++swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ if (val->port_vlan >= dev->ports) ++ return -EINVAL; ++ ++ if (!dev->ops->set_port_pvid) ++ return -EOPNOTSUPP; ++ ++ return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i); ++} ++ ++static int ++swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ if (val->port_vlan >= dev->ports) ++ return -EINVAL; ++ ++ if (!dev->ops->get_port_pvid) ++ return -EOPNOTSUPP; ++ ++ return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i); ++} ++ ++static int ++swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ /* don't complain if not supported by the switch driver */ ++ if (!dev->ops->apply_config) ++ return 0; ++ ++ return dev->ops->apply_config(dev); ++} ++ ++static int ++swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) ++{ ++ /* don't complain if not supported by the switch driver */ ++ if (!dev->ops->reset_switch) ++ return 0; ++ ++ return dev->ops->reset_switch(dev); ++} ++ ++enum global_defaults { ++ GLOBAL_APPLY, ++ GLOBAL_RESET, ++}; ++ ++enum vlan_defaults { ++ VLAN_PORTS, ++}; ++ ++enum port_defaults { ++ PORT_PVID, ++}; ++ ++static struct switch_attr default_global[] = { ++ [GLOBAL_APPLY] = { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "apply", ++ .description = "Activate changes in the hardware", ++ .set = swconfig_apply_config, ++ }, ++ [GLOBAL_RESET] = { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "reset", ++ .description = "Reset the switch", ++ .set = swconfig_reset_switch, ++ } ++}; ++ ++static struct switch_attr default_port[] = { ++ [PORT_PVID] = { ++ .type = SWITCH_TYPE_INT, ++ .name = "pvid", ++ .description = "Primary VLAN ID", ++ .set = swconfig_set_pvid, ++ .get = swconfig_get_pvid, ++ } ++}; ++ ++static struct switch_attr default_vlan[] = { ++ [VLAN_PORTS] = { ++ .type = SWITCH_TYPE_PORTS, ++ .name = "ports", ++ .description = "VLAN port mapping", ++ .set = swconfig_set_vlan_ports, ++ .get = swconfig_get_vlan_ports, ++ }, ++}; ++ ++ ++static void swconfig_defaults_init(struct switch_dev *dev) ++{ ++ const struct switch_dev_ops *ops = dev->ops; ++ ++ dev->def_global = 0; ++ dev->def_vlan = 0; ++ dev->def_port = 0; ++ ++ if (ops->get_vlan_ports || ops->set_vlan_ports) ++ set_bit(VLAN_PORTS, &dev->def_vlan); ++ ++ if (ops->get_port_pvid || ops->set_port_pvid) ++ set_bit(PORT_PVID, &dev->def_port); ++ ++ /* always present, can be no-op */ ++ set_bit(GLOBAL_APPLY, &dev->def_global); ++ set_bit(GLOBAL_RESET, &dev->def_global); ++} ++ ++ ++static struct genl_family switch_fam = { ++ .id = GENL_ID_GENERATE, ++ .name = "switch", ++ .hdrsize = 0, ++ .version = 1, ++ .maxattr = SWITCH_ATTR_MAX, ++}; ++ ++static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = { ++ [SWITCH_ATTR_ID] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING }, ++ [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED }, ++ [SWITCH_ATTR_TYPE] = { .type = NLA_U32 }, ++}; ++ ++static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = { ++ [SWITCH_PORT_ID] = { .type = NLA_U32 }, ++ [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, ++}; ++ ++static inline void ++swconfig_lock(void) ++{ ++ spin_lock(&swdevs_lock); ++} ++ ++static inline void ++swconfig_unlock(void) ++{ ++ spin_unlock(&swdevs_lock); ++} ++ ++static struct switch_dev * ++swconfig_get_dev(struct genl_info *info) ++{ ++ struct switch_dev *dev = NULL; ++ struct switch_dev *p; ++ int id; ++ ++ if (!info->attrs[SWITCH_ATTR_ID]) ++ goto done; ++ ++ id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]); ++ swconfig_lock(); ++ list_for_each_entry(p, &swdevs, dev_list) { ++ if (id != p->id) ++ continue; ++ ++ dev = p; ++ break; ++ } ++ if (dev) ++ spin_lock(&dev->lock); ++ else ++ DPRINTF("device %d not found\n", id); ++ swconfig_unlock(); ++done: ++ return dev; ++} ++ ++static inline void ++swconfig_put_dev(struct switch_dev *dev) ++{ ++ spin_unlock(&dev->lock); ++} ++ ++static int ++swconfig_dump_attr(struct swconfig_callback *cb, void *arg) ++{ ++ struct switch_attr *op = arg; ++ struct genl_info *info = cb->info; ++ struct sk_buff *msg = cb->msg; ++ int id = cb->args[0]; ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam, ++ NLM_F_MULTI, SWITCH_CMD_NEW_ATTR); ++ if (IS_ERR(hdr)) ++ return -1; ++ ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, id); ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_TYPE, op->type); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_NAME, op->name); ++ if (op->description) ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_DESCRIPTION, ++ op->description); ++ ++ return genlmsg_end(msg, hdr); ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++/* spread multipart messages across multiple message buffers */ ++static int ++swconfig_send_multipart(struct swconfig_callback *cb, void *arg) ++{ ++ struct genl_info *info = cb->info; ++ int restart = 0; ++ int err; ++ ++ do { ++ if (!cb->msg) { ++ cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (cb->msg == NULL) ++ goto error; ++ } ++ ++ if (!(cb->fill(cb, arg) < 0)) ++ break; ++ ++ /* fill failed, check if this was already the second attempt */ ++ if (restart) ++ goto error; ++ ++ /* try again in a new message, send the current one */ ++ restart = 1; ++ if (cb->close) { ++ if (cb->close(cb, arg) < 0) ++ goto error; ++ } ++ err = genlmsg_reply(cb->msg, info); ++ cb->msg = NULL; ++ if (err < 0) ++ goto error; ++ ++ } while (restart); ++ ++ return 0; ++ ++error: ++ if (cb->msg) ++ nlmsg_free(cb->msg); ++ return -1; ++} ++ ++static int ++swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attrlist *alist; ++ struct switch_dev *dev; ++ struct swconfig_callback cb; ++ int err = -EINVAL; ++ int i; ++ ++ /* defaults */ ++ struct switch_attr *def_list; ++ unsigned long *def_active; ++ int n_def; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ switch(hdr->cmd) { ++ case SWITCH_CMD_LIST_GLOBAL: ++ alist = &dev->ops->attr_global; ++ def_list = default_global; ++ def_active = &dev->def_global; ++ n_def = ARRAY_SIZE(default_global); ++ break; ++ case SWITCH_CMD_LIST_VLAN: ++ alist = &dev->ops->attr_vlan; ++ def_list = default_vlan; ++ def_active = &dev->def_vlan; ++ n_def = ARRAY_SIZE(default_vlan); ++ break; ++ case SWITCH_CMD_LIST_PORT: ++ alist = &dev->ops->attr_port; ++ def_list = default_port; ++ def_active = &dev->def_port; ++ n_def = ARRAY_SIZE(default_port); ++ break; ++ default: ++ WARN_ON(1); ++ goto out; ++ } ++ ++ memset(&cb, 0, sizeof(cb)); ++ cb.info = info; ++ cb.fill = swconfig_dump_attr; ++ for (i = 0; i < alist->n_attr; i++) { ++ if (alist->attr[i].disabled) ++ continue; ++ cb.args[0] = i; ++ err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]); ++ if (err < 0) ++ goto error; ++ } ++ ++ /* defaults */ ++ for (i = 0; i < n_def; i++) { ++ if (!test_bit(i, def_active)) ++ continue; ++ cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i; ++ err = swconfig_send_multipart(&cb, (void *) &def_list[i]); ++ if (err < 0) ++ goto error; ++ } ++ swconfig_put_dev(dev); ++ ++ if (!cb.msg) ++ return 0; ++ ++ return genlmsg_reply(cb.msg, info); ++ ++error: ++ if (cb.msg) ++ nlmsg_free(cb.msg); ++out: ++ swconfig_put_dev(dev); ++ return err; ++} ++ ++static const struct switch_attr * ++swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, ++ struct switch_val *val) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attrlist *alist; ++ const struct switch_attr *attr = NULL; ++ int attr_id; ++ ++ /* defaults */ ++ struct switch_attr *def_list; ++ unsigned long *def_active; ++ int n_def; ++ ++ if (!info->attrs[SWITCH_ATTR_OP_ID]) ++ goto done; ++ ++ switch(hdr->cmd) { ++ case SWITCH_CMD_SET_GLOBAL: ++ case SWITCH_CMD_GET_GLOBAL: ++ alist = &dev->ops->attr_global; ++ def_list = default_global; ++ def_active = &dev->def_global; ++ n_def = ARRAY_SIZE(default_global); ++ break; ++ case SWITCH_CMD_SET_VLAN: ++ case SWITCH_CMD_GET_VLAN: ++ alist = &dev->ops->attr_vlan; ++ def_list = default_vlan; ++ def_active = &dev->def_vlan; ++ n_def = ARRAY_SIZE(default_vlan); ++ if (!info->attrs[SWITCH_ATTR_OP_VLAN]) ++ goto done; ++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]); ++ if (val->port_vlan >= dev->vlans) ++ goto done; ++ break; ++ case SWITCH_CMD_SET_PORT: ++ case SWITCH_CMD_GET_PORT: ++ alist = &dev->ops->attr_port; ++ def_list = default_port; ++ def_active = &dev->def_port; ++ n_def = ARRAY_SIZE(default_port); ++ if (!info->attrs[SWITCH_ATTR_OP_PORT]) ++ goto done; ++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]); ++ if (val->port_vlan >= dev->ports) ++ goto done; ++ break; ++ default: ++ WARN_ON(1); ++ goto done; ++ } ++ ++ if (!alist) ++ goto done; ++ ++ attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]); ++ if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) { ++ attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET; ++ if (attr_id >= n_def) ++ goto done; ++ if (!test_bit(attr_id, def_active)) ++ goto done; ++ attr = &def_list[attr_id]; ++ } else { ++ if (attr_id >= alist->n_attr) ++ goto done; ++ attr = &alist->attr[attr_id]; ++ } ++ ++ if (attr->disabled) ++ attr = NULL; ++ ++done: ++ if (!attr) ++ DPRINTF("attribute lookup failed\n"); ++ val->attr = attr; ++ return attr; ++} ++ ++static int ++swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, ++ struct switch_val *val, int max) ++{ ++ struct nlattr *nla; ++ int rem; ++ ++ val->len = 0; ++ nla_for_each_nested(nla, head, rem) { ++ struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; ++ struct switch_port *port = &val->value.ports[val->len]; ++ ++ if (val->len >= max) ++ return -EINVAL; ++ ++ if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla, ++ port_policy)) ++ return -EINVAL; ++ ++ if (!tb[SWITCH_PORT_ID]) ++ return -EINVAL; ++ ++ port->id = nla_get_u32(tb[SWITCH_PORT_ID]); ++ if (tb[SWITCH_PORT_FLAG_TAGGED]) ++ port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED); ++ val->len++; ++ } ++ ++ return 0; ++} ++ ++static int ++swconfig_set_attr(struct sk_buff *skb, struct genl_info *info) ++{ ++ const struct switch_attr *attr; ++ struct switch_dev *dev; ++ struct switch_val val; ++ int err = -EINVAL; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ memset(&val, 0, sizeof(val)); ++ attr = swconfig_lookup_attr(dev, info, &val); ++ if (!attr || !attr->set) ++ goto error; ++ ++ val.attr = attr; ++ switch(attr->type) { ++ case SWITCH_TYPE_NOVAL: ++ break; ++ case SWITCH_TYPE_INT: ++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT]) ++ goto error; ++ val.value.i = ++ nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]); ++ break; ++ case SWITCH_TYPE_STRING: ++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR]) ++ goto error; ++ val.value.s = ++ nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]); ++ break; ++ case SWITCH_TYPE_PORTS: ++ val.value.ports = dev->portbuf; ++ memset(dev->portbuf, 0, ++ sizeof(struct switch_port) * dev->ports); ++ ++ /* TODO: implement multipart? */ ++ if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) { ++ err = swconfig_parse_ports(skb, ++ info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], &val, dev->ports); ++ if (err < 0) ++ goto error; ++ } else { ++ val.len = 0; ++ err = 0; ++ } ++ break; ++ default: ++ goto error; ++ } ++ ++ err = attr->set(dev, attr, &val); ++error: ++ swconfig_put_dev(dev); ++ return err; ++} ++ ++static int ++swconfig_close_portlist(struct swconfig_callback *cb, void *arg) ++{ ++ if (cb->nest[0]) ++ nla_nest_end(cb->msg, cb->nest[0]); ++ return 0; ++} ++ ++static int ++swconfig_send_port(struct swconfig_callback *cb, void *arg) ++{ ++ const struct switch_port *port = arg; ++ struct nlattr *p = NULL; ++ ++ if (!cb->nest[0]) { ++ cb->nest[0] = nla_nest_start(cb->msg, cb->cmd); ++ if (!cb->nest[0]) ++ return -1; ++ } ++ ++ p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT); ++ if (!p) ++ goto error; ++ ++ NLA_PUT_U32(cb->msg, SWITCH_PORT_ID, port->id); ++ if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ++ NLA_PUT_FLAG(cb->msg, SWITCH_PORT_FLAG_TAGGED); ++ ++ nla_nest_end(cb->msg, p); ++ return 0; ++ ++nla_put_failure: ++ nla_nest_cancel(cb->msg, p); ++error: ++ nla_nest_cancel(cb->msg, cb->nest[0]); ++ return -1; ++} ++ ++static int ++swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr, ++ const struct switch_val *val) ++{ ++ struct swconfig_callback cb; ++ int err = 0; ++ int i; ++ ++ if (!val->value.ports) ++ return -EINVAL; ++ ++ memset(&cb, 0, sizeof(cb)); ++ cb.cmd = attr; ++ cb.msg = *msg; ++ cb.info = info; ++ cb.fill = swconfig_send_port; ++ cb.close = swconfig_close_portlist; ++ ++ cb.nest[0] = nla_nest_start(cb.msg, cb.cmd); ++ for (i = 0; i < val->len; i++) { ++ err = swconfig_send_multipart(&cb, &val->value.ports[i]); ++ if (err) ++ goto done; ++ } ++ err = val->len; ++ swconfig_close_portlist(&cb, NULL); ++ *msg = cb.msg; ++ ++done: ++ return err; ++} ++ ++static int ++swconfig_get_attr(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attr *attr; ++ struct switch_dev *dev; ++ struct sk_buff *msg = NULL; ++ struct switch_val val; ++ int err = -EINVAL; ++ int cmd = hdr->cmd; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ memset(&val, 0, sizeof(val)); ++ attr = swconfig_lookup_attr(dev, info, &val); ++ if (!attr || !attr->get) ++ goto error; ++ ++ if (attr->type == SWITCH_TYPE_PORTS) { ++ val.value.ports = dev->portbuf; ++ memset(dev->portbuf, 0, ++ sizeof(struct switch_port) * dev->ports); ++ } ++ ++ err = attr->get(dev, attr, &val); ++ if (err) ++ goto error; ++ ++ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (!msg) ++ goto error; ++ ++ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam, ++ 0, cmd); ++ if (IS_ERR(hdr)) ++ goto nla_put_failure; ++ ++ switch(attr->type) { ++ case SWITCH_TYPE_INT: ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i); ++ break; ++ case SWITCH_TYPE_STRING: ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s); ++ break; ++ case SWITCH_TYPE_PORTS: ++ err = swconfig_send_ports(&msg, info, ++ SWITCH_ATTR_OP_VALUE_PORTS, &val); ++ if (err < 0) ++ goto nla_put_failure; ++ break; ++ default: ++ DPRINTF("invalid type in attribute\n"); ++ err = -EINVAL; ++ goto error; ++ } ++ err = genlmsg_end(msg, hdr); ++ if (err < 0) ++ goto nla_put_failure; ++ ++ swconfig_put_dev(dev); ++ return genlmsg_reply(msg, info); ++ ++nla_put_failure: ++ if (msg) ++ nlmsg_free(msg); ++error: ++ swconfig_put_dev(dev); ++ if (!err) ++ err = -ENOMEM; ++ return err; ++} ++ ++static int ++swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, ++ const struct switch_dev *dev) ++{ ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, ++ SWITCH_CMD_NEW_ATTR); ++ if (IS_ERR(hdr)) ++ return -1; ++ ++ NLA_PUT_U32(msg, SWITCH_ATTR_ID, dev->id); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_DEV_NAME, dev->devname); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_ALIAS, dev->alias); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_NAME, dev->name); ++ NLA_PUT_U32(msg, SWITCH_ATTR_VLANS, dev->vlans); ++ NLA_PUT_U32(msg, SWITCH_ATTR_PORTS, dev->ports); ++ NLA_PUT_U32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port); ++ ++ return genlmsg_end(msg, hdr); ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++static int swconfig_dump_switches(struct sk_buff *skb, ++ struct netlink_callback *cb) ++{ ++ struct switch_dev *dev; ++ int start = cb->args[0]; ++ int idx = 0; ++ ++ swconfig_lock(); ++ list_for_each_entry(dev, &swdevs, dev_list) { ++ if (++idx <= start) ++ continue; ++ if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).pid, ++ cb->nlh->nlmsg_seq, NLM_F_MULTI, ++ dev) < 0) ++ break; ++ } ++ swconfig_unlock(); ++ cb->args[0] = idx; ++ ++ return skb->len; ++} ++ ++static int ++swconfig_done(struct netlink_callback *cb) ++{ ++ return 0; ++} ++ ++static struct genl_ops swconfig_ops[] = { ++ { ++ .cmd = SWITCH_CMD_LIST_GLOBAL, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_LIST_VLAN, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_LIST_PORT, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_GLOBAL, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_VLAN, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_PORT, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_GLOBAL, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_VLAN, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_PORT, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_SWITCH, ++ .dumpit = swconfig_dump_switches, ++ .policy = switch_policy, ++ .done = swconfig_done, ++ } ++}; ++ ++int ++register_switch(struct switch_dev *dev, struct net_device *netdev) ++{ ++ struct switch_dev *sdev; ++ const int max_switches = 8 * sizeof(unsigned long); ++ unsigned long in_use = 0; ++ int i; ++ ++ INIT_LIST_HEAD(&dev->dev_list); ++ if (netdev) { ++ dev->netdev = netdev; ++ if (!dev->alias) ++ dev->alias = netdev->name; ++ } ++ BUG_ON(!dev->alias); ++ ++ if (dev->ports > 0) { ++ dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports, ++ GFP_KERNEL); ++ if (!dev->portbuf) ++ return -ENOMEM; ++ } ++ swconfig_defaults_init(dev); ++ spin_lock_init(&dev->lock); ++ swconfig_lock(); ++ dev->id = ++swdev_id; ++ ++ list_for_each_entry(sdev, &swdevs, dev_list) { ++ if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i)) ++ continue; ++ if (i < 0 || i > max_switches) ++ continue; ++ ++ set_bit(i, &in_use); ++ } ++ i = find_first_zero_bit(&in_use, max_switches); ++ ++ if (i == max_switches) ++ return -ENFILE; ++ ++ /* fill device name */ ++ snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i); ++ ++ list_add(&dev->dev_list, &swdevs); ++ swconfig_unlock(); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(register_switch); ++ ++void ++unregister_switch(struct switch_dev *dev) ++{ ++ kfree(dev->portbuf); ++ spin_lock(&dev->lock); ++ swconfig_lock(); ++ list_del(&dev->dev_list); ++ swconfig_unlock(); ++ spin_unlock(&dev->lock); ++} ++EXPORT_SYMBOL_GPL(unregister_switch); ++ ++ ++static int __init ++swconfig_init(void) ++{ ++ int i, err; ++ ++ INIT_LIST_HEAD(&swdevs); ++ err = genl_register_family(&switch_fam); ++ if (err) ++ return err; ++ ++ for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) { ++ err = genl_register_ops(&switch_fam, &swconfig_ops[i]); ++ if (err) ++ goto unregister; ++ } ++ ++ return 0; ++ ++unregister: ++ genl_unregister_family(&switch_fam); ++ return err; ++} ++ ++static void __exit ++swconfig_exit(void) ++{ ++ genl_unregister_family(&switch_fam); ++} ++ ++module_init(swconfig_init); ++module_exit(swconfig_exit); ++ diff -Nur linux-2.6.39.orig/drivers/spi/Kconfig linux-2.6.39/drivers/spi/Kconfig --- linux-2.6.39.orig/drivers/spi/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/spi/Kconfig 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/spi/Kconfig 2011-08-24 18:17:24.000000000 +0200 @@ -67,6 +67,13 @@ This enables support for the SPI controller present on the Atheros AR71XX/AR724X/AR913X SoCs. @@ -14786,21 +20441,64 @@ diff -Nur linux-2.6.39.orig/drivers/spi/Kconfig linux-2.6.39/drivers/spi/Kconfig config SPI_ATMEL tristate "Atmel SPI Controller" depends on (ARCH_AT91 || AVR32) +@@ -301,6 +308,12 @@ + config SPI_PXA2XX_PCI + def_bool SPI_PXA2XX && X86_32 && PCI + ++config SPI_RB4XX ++ tristate "Mikrotik RB4XX SPI master" ++ depends on SPI_MASTER && AR71XX_MACH_RB4XX ++ help ++ SPI controller driver for the Mikrotik RB4xx series boards. ++ + config SPI_S3C24XX + tristate "Samsung S3C24XX series SPI" + depends on ARCH_S3C2410 && EXPERIMENTAL +@@ -457,6 +470,13 @@ + sysfs interface, with each line presented as a kind of GPIO + exposing both switch control and diagnostic feedback. + ++config SPI_RB4XX_CPLD ++ tristate "MikroTik RB4XX CPLD driver" ++ depends on AR71XX_MACH_RB4XX ++ help ++ SPI driver for the Xilinx CPLD chip present on the ++ MikroTik RB4xx boards. ++ + # + # Add new SPI protocol masters in alphabetical order above this line + # diff -Nur linux-2.6.39.orig/drivers/spi/Makefile linux-2.6.39/drivers/spi/Makefile --- linux-2.6.39.orig/drivers/spi/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/spi/Makefile 2011-05-27 14:36:51.000000000 +0200 -@@ -11,6 +11,7 @@ ++++ linux-2.6.39/drivers/spi/Makefile 2011-08-24 18:17:24.000000000 +0200 +@@ -10,6 +10,7 @@ + # SPI master controller drivers (bus) obj-$(CONFIG_SPI_ALTERA) += spi_altera.o - obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o +obj-$(CONFIG_SPI_AR71XX) += ar71xx_spi.o + obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o obj-$(CONFIG_SPI_ATH79) += ath79_spi.o obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o - obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o +@@ -54,6 +55,7 @@ + obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o + obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o + obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o ++obj-$(CONFIG_SPI_RB4XX) += rb4xx_spi.o + + # special build for s3c24xx spi driver with fiq support + spi_s3c24xx_hw-y := spi_s3c24xx.o +@@ -62,6 +64,7 @@ + # ... add above this line ... + + # SPI protocol drivers (device/link on bus) ++obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o + obj-$(CONFIG_SPI_SPIDEV) += spidev.o + obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o + # ... add above this line ... diff -Nur linux-2.6.39.orig/drivers/spi/ap83_spi.c linux-2.6.39/drivers/spi/ap83_spi.c --- linux-2.6.39.orig/drivers/spi/ap83_spi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/spi/ap83_spi.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,282 @@ ++++ linux-2.6.39/drivers/spi/ap83_spi.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,283 @@ +/* + * Atheros AP83 board specific SPI Controller driver + * @@ -14840,8 +20538,8 @@ diff -Nur linux-2.6.39.orig/drivers/spi/ap83_spi.c linux-2.6.39/drivers/spi/ap83 +#define AP83_SPI_GPIO_MISO 3 + +struct ap83_spi { -+ struct spi_bitbang bitbang; -+ void __iomem *base; ++ struct spi_bitbang bitbang; ++ void __iomem *base; + u32 addr; + + struct platform_device *pdev; @@ -14930,33 +20628,34 @@ diff -Nur linux-2.6.39.orig/drivers/spi/ap83_spi.c linux-2.6.39/drivers/spi/ap83 + +#define EXPAND_BITBANG_TXRX +#include <linux/spi/spi_bitbang.h> ++#include "spi_bitbang_txrx.h" + +static u32 ap83_spi_txrx_mode0(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + dev_dbg(&spi->dev, "TXRX0 word=%08x, bits=%u\n", word, bits); -+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); ++ return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); +} + +static u32 ap83_spi_txrx_mode1(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + dev_dbg(&spi->dev, "TXRX1 word=%08x, bits=%u\n", word, bits); -+ return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits); ++ return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits); +} + +static u32 ap83_spi_txrx_mode2(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + dev_dbg(&spi->dev, "TXRX2 word=%08x, bits=%u\n", word, bits); -+ return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits); ++ return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits); +} + +static u32 ap83_spi_txrx_mode3(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + dev_dbg(&spi->dev, "TXRX3 word=%08x, bits=%u\n", word, bits); -+ return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits); ++ return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits); +} + +static int ap83_spi_probe(struct platform_device *pdev) @@ -15032,15 +20731,15 @@ diff -Nur linux-2.6.39.orig/drivers/spi/ap83_spi.c linux-2.6.39/drivers/spi/ap83 + + return 0; + -+ err_unmap: ++err_unmap: + iounmap(sp->base); -+ err_spi_put: ++err_spi_put: + platform_set_drvdata(pdev, NULL); + spi_master_put(sp->bitbang.master); + -+ err_free_cs: ++err_free_cs: + gpio_free(AP83_SPI_GPIO_CS); -+ err_free_miso: ++err_free_miso: + gpio_free(AP83_SPI_GPIO_MISO); + return ret; +} @@ -15085,7 +20784,7 @@ diff -Nur linux-2.6.39.orig/drivers/spi/ap83_spi.c linux-2.6.39/drivers/spi/ap83 +MODULE_LICENSE("GPL v2"); diff -Nur linux-2.6.39.orig/drivers/spi/ar71xx_spi.c linux-2.6.39/drivers/spi/ar71xx_spi.c --- linux-2.6.39.orig/drivers/spi/ar71xx_spi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/spi/ar71xx_spi.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/spi/ar71xx_spi.c 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,283 @@ +/* + * Atheros AR71xx SPI Controller driver @@ -15120,11 +20819,11 @@ diff -Nur linux-2.6.39.orig/drivers/spi/ar71xx_spi.c linux-2.6.39/drivers/spi/ar +#undef PER_BIT_READ + +struct ar71xx_spi { -+ struct spi_bitbang bitbang; ++ struct spi_bitbang bitbang; + u32 ioc_base; + u32 reg_ctrl; + -+ void __iomem *base; ++ void __iomem *base; + + struct platform_device *pdev; + u32 (*get_ioc_base)(u8 chip_select, int cs_high, @@ -15323,7 +21022,7 @@ diff -Nur linux-2.6.39.orig/drivers/spi/ar71xx_spi.c linux-2.6.39/drivers/spi/ar + return 0; + + iounmap(sp->base); -+ err1: ++err1: + platform_set_drvdata(pdev, NULL); + spi_master_put(sp->bitbang.master); + @@ -15372,7 +21071,7 @@ diff -Nur linux-2.6.39.orig/drivers/spi/ar71xx_spi.c linux-2.6.39/drivers/spi/ar +MODULE_LICENSE("GPL v2"); diff -Nur linux-2.6.39.orig/drivers/spi/pb44_spi.c linux-2.6.39/drivers/spi/pb44_spi.c --- linux-2.6.39.orig/drivers/spi/pb44_spi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/spi/pb44_spi.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/spi/pb44_spi.c 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,299 @@ +/* + * Atheros PB44 board SPI controller driver @@ -15407,11 +21106,11 @@ diff -Nur linux-2.6.39.orig/drivers/spi/pb44_spi.c linux-2.6.39/drivers/spi/pb44 +#undef PER_BIT_READ + +struct ar71xx_spi { -+ struct spi_bitbang bitbang; ++ struct spi_bitbang bitbang; + u32 ioc_base; + u32 reg_ctrl; + -+ void __iomem *base; ++ void __iomem *base; + + struct platform_device *pdev; +}; @@ -15628,7 +21327,7 @@ diff -Nur linux-2.6.39.orig/drivers/spi/pb44_spi.c linux-2.6.39/drivers/spi/pb44 + return 0; + + iounmap(sp->base); -+ err1: ++err1: + platform_set_drvdata(pdev, NULL); + spi_master_put(sp->bitbang.master); + @@ -15673,10 +21372,932 @@ diff -Nur linux-2.6.39.orig/drivers/spi/pb44_spi.c linux-2.6.39/drivers/spi/pb44 +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_LICENSE("GPL v2"); +diff -Nur linux-2.6.39.orig/drivers/spi/rb4xx_spi.c linux-2.6.39/drivers/spi/rb4xx_spi.c +--- linux-2.6.39.orig/drivers/spi/rb4xx_spi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/drivers/spi/rb4xx_spi.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,474 @@ ++/* ++ * SPI controller driver for the Mikrotik RB4xx boards ++ * ++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file was based on the patches for Linux 2.6.27.39 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/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/spi/spi.h> ++ ++#include <asm/mach-ar71xx/ar71xx.h> ++ ++#define DRV_NAME "rb4xx-spi" ++#define DRV_DESC "Mikrotik RB4xx SPI controller driver" ++#define DRV_VERSION "0.1.0" ++ ++#define SPI_CTRL_FASTEST 0x40 ++#define SPI_FLASH_HZ 33333334 ++#define SPI_CPLD_HZ 33333334 ++ ++#define CPLD_CMD_READ_FAST 0x0b ++ ++#undef RB4XX_SPI_DEBUG ++ ++struct rb4xx_spi { ++ void __iomem *base; ++ struct spi_master *master; ++ ++ unsigned spi_ctrl_flash; ++ unsigned spi_ctrl_fread; ++ ++ spinlock_t lock; ++ struct list_head queue; ++ int busy:1; ++ int cs_wait; ++}; ++ ++static unsigned spi_clk_low = SPI_IOC_CS1; ++ ++#ifdef RB4XX_SPI_DEBUG ++static inline void do_spi_delay(void) ++{ ++ ndelay(20000); ++} ++#else ++static inline void do_spi_delay(void) { } ++#endif ++ ++static inline void do_spi_init(struct spi_device *spi) ++{ ++ unsigned cs = SPI_IOC_CS0 | SPI_IOC_CS1; ++ ++ if (!(spi->mode & SPI_CS_HIGH)) ++ cs ^= (spi->chip_select == 2) ? SPI_IOC_CS1 : SPI_IOC_CS0; ++ ++ spi_clk_low = cs; ++} ++ ++static inline void do_spi_finish(void __iomem *base) ++{ ++ do_spi_delay(); ++ __raw_writel(SPI_IOC_CS0 | SPI_IOC_CS1, base + SPI_REG_IOC); ++} ++ ++static inline void do_spi_clk(void __iomem *base, int bit) ++{ ++ unsigned bval = spi_clk_low | ((bit & 1) ? SPI_IOC_DO : 0); ++ ++ do_spi_delay(); ++ __raw_writel(bval, base + SPI_REG_IOC); ++ do_spi_delay(); ++ __raw_writel(bval | SPI_IOC_CLK, base + SPI_REG_IOC); ++} ++ ++static void do_spi_byte(void __iomem *base, unsigned char byte) ++{ ++ do_spi_clk(base, byte >> 7); ++ do_spi_clk(base, byte >> 6); ++ do_spi_clk(base, byte >> 5); ++ do_spi_clk(base, byte >> 4); ++ do_spi_clk(base, byte >> 3); ++ do_spi_clk(base, byte >> 2); ++ do_spi_clk(base, byte >> 1); ++ do_spi_clk(base, byte); ++ ++ pr_debug("spi_byte sent 0x%02x got 0x%02x\n", ++ (unsigned)byte, ++ (unsigned char)__raw_readl(base + SPI_REG_RDS)); ++} ++ ++static inline void do_spi_clk_fast(void __iomem *base, unsigned bit1, ++ unsigned bit2) ++{ ++ unsigned bval = (spi_clk_low | ++ ((bit1 & 1) ? SPI_IOC_DO : 0) | ++ ((bit2 & 1) ? SPI_IOC_CS2 : 0)); ++ do_spi_delay(); ++ __raw_writel(bval, base + SPI_REG_IOC); ++ do_spi_delay(); ++ __raw_writel(bval | SPI_IOC_CLK, base + SPI_REG_IOC); ++} ++ ++static void do_spi_byte_fast(void __iomem *base, unsigned char byte) ++{ ++ do_spi_clk_fast(base, byte >> 7, byte >> 6); ++ do_spi_clk_fast(base, byte >> 5, byte >> 4); ++ do_spi_clk_fast(base, byte >> 3, byte >> 2); ++ do_spi_clk_fast(base, byte >> 1, byte >> 0); ++ ++ pr_debug("spi_byte_fast sent 0x%02x got 0x%02x\n", ++ (unsigned)byte, ++ (unsigned char) __raw_readl(base + SPI_REG_RDS)); ++} ++ ++static int rb4xx_spi_txrx(void __iomem *base, struct spi_transfer *t) ++{ ++ const unsigned char *rxv_ptr = NULL; ++ const unsigned char *tx_ptr = t->tx_buf; ++ unsigned char *rx_ptr = t->rx_buf; ++ unsigned i; ++ ++ pr_debug("spi_txrx len %u tx %u rx %u\n", ++ t->len, ++ (t->tx_buf ? 1 : 0), ++ (t->rx_buf ? 1 : 0)); ++ ++ if (t->verify) { ++ rxv_ptr = tx_ptr; ++ tx_ptr = NULL; ++ } ++ ++ for (i = 0; i < t->len; ++i) { ++ unsigned char sdata = tx_ptr ? tx_ptr[i] : 0; ++ ++ if (t->fast_write) ++ do_spi_byte_fast(base, sdata); ++ else ++ do_spi_byte(base, sdata); ++ ++ if (rx_ptr) { ++ rx_ptr[i] = __raw_readl(base + SPI_REG_RDS) & 0xff; ++ } else if (rxv_ptr) { ++ unsigned char c = __raw_readl(base + SPI_REG_RDS); ++ if (rxv_ptr[i] != c) ++ return i; ++ } ++ } ++ ++ return i; ++} ++ ++static int rb4xx_spi_read_fast(struct rb4xx_spi *rbspi, ++ struct spi_message *m) ++{ ++ struct spi_transfer *t; ++ const unsigned char *tx_ptr; ++ unsigned addr; ++ void __iomem *base = rbspi->base; ++ ++ /* check for exactly two transfers */ ++ if (list_empty(&m->transfers) || ++ list_is_last(m->transfers.next, &m->transfers) || ++ !list_is_last(m->transfers.next->next, &m->transfers)) { ++ return -1; ++ } ++ ++ /* first transfer contains command and address */ ++ t = list_entry(m->transfers.next, ++ struct spi_transfer, transfer_list); ++ ++ if (t->len != 5 || t->tx_buf == NULL) ++ return -1; ++ ++ tx_ptr = t->tx_buf; ++ if (tx_ptr[0] != CPLD_CMD_READ_FAST) ++ return -1; ++ ++ addr = tx_ptr[1]; ++ addr = tx_ptr[2] | (addr << 8); ++ addr = tx_ptr[3] | (addr << 8); ++ addr += (unsigned) base; ++ ++ m->actual_length += t->len; ++ ++ /* second transfer contains data itself */ ++ t = list_entry(m->transfers.next->next, ++ struct spi_transfer, transfer_list); ++ ++ if (t->tx_buf && !t->verify) ++ return -1; ++ ++ __raw_writel(SPI_FS_GPIO, base + SPI_REG_FS); ++ __raw_writel(rbspi->spi_ctrl_fread, base + SPI_REG_CTRL); ++ __raw_writel(0, base + SPI_REG_FS); ++ ++ if (t->rx_buf) { ++ memcpy(t->rx_buf, (const void *)addr, t->len); ++ } else if (t->tx_buf) { ++ unsigned char buf[t->len]; ++ memcpy(buf, (const void *)addr, t->len); ++ if (memcmp(t->tx_buf, buf, t->len) != 0) ++ m->status = -EMSGSIZE; ++ } ++ m->actual_length += t->len; ++ ++ if (rbspi->spi_ctrl_flash != rbspi->spi_ctrl_fread) { ++ __raw_writel(SPI_FS_GPIO, base + SPI_REG_FS); ++ __raw_writel(rbspi->spi_ctrl_flash, base + SPI_REG_CTRL); ++ __raw_writel(0, base + SPI_REG_FS); ++ } ++ ++ return 0; ++} ++ ++static int rb4xx_spi_msg(struct rb4xx_spi *rbspi, struct spi_message *m) ++{ ++ struct spi_transfer *t = NULL; ++ void __iomem *base = rbspi->base; ++ ++ m->status = 0; ++ if (list_empty(&m->transfers)) ++ return -1; ++ ++ if (m->fast_read) ++ if (rb4xx_spi_read_fast(rbspi, m) == 0) ++ return -1; ++ ++ __raw_writel(SPI_FS_GPIO, base + SPI_REG_FS); ++ __raw_writel(SPI_CTRL_FASTEST, base + SPI_REG_CTRL); ++ do_spi_init(m->spi); ++ ++ list_for_each_entry(t, &m->transfers, transfer_list) { ++ int len; ++ ++ len = rb4xx_spi_txrx(base, t); ++ if (len != t->len) { ++ m->status = -EMSGSIZE; ++ break; ++ } ++ m->actual_length += len; ++ ++ if (t->cs_change) { ++ if (list_is_last(&t->transfer_list, &m->transfers)) { ++ /* wait for continuation */ ++ return m->spi->chip_select; ++ } ++ do_spi_finish(base); ++ ndelay(100); ++ } ++ } ++ ++ do_spi_finish(base); ++ __raw_writel(rbspi->spi_ctrl_flash, base + SPI_REG_CTRL); ++ __raw_writel(0, base + SPI_REG_FS); ++ return -1; ++} ++ ++static void rb4xx_spi_process_queue_locked(struct rb4xx_spi *rbspi, ++ unsigned long *flags) ++{ ++ int cs = rbspi->cs_wait; ++ ++ rbspi->busy = 1; ++ while (!list_empty(&rbspi->queue)) { ++ struct spi_message *m; ++ ++ list_for_each_entry(m, &rbspi->queue, queue) ++ if (cs < 0 || cs == m->spi->chip_select) ++ break; ++ ++ if (&m->queue == &rbspi->queue) ++ break; ++ ++ list_del_init(&m->queue); ++ spin_unlock_irqrestore(&rbspi->lock, *flags); ++ ++ cs = rb4xx_spi_msg(rbspi, m); ++ m->complete(m->context); ++ ++ spin_lock_irqsave(&rbspi->lock, *flags); ++ } ++ ++ rbspi->cs_wait = cs; ++ rbspi->busy = 0; ++ ++ if (cs >= 0) { ++ /* TODO: add timer to unlock cs after 1s inactivity */ ++ } ++} ++ ++static int rb4xx_spi_transfer(struct spi_device *spi, ++ struct spi_message *m) ++{ ++ struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master); ++ unsigned long flags; ++ ++ m->actual_length = 0; ++ m->status = -EINPROGRESS; ++ ++ spin_lock_irqsave(&rbspi->lock, flags); ++ list_add_tail(&m->queue, &rbspi->queue); ++ if (rbspi->busy || ++ (rbspi->cs_wait >= 0 && rbspi->cs_wait != m->spi->chip_select)) { ++ /* job will be done later */ ++ spin_unlock_irqrestore(&rbspi->lock, flags); ++ return 0; ++ } ++ ++ /* process job in current context */ ++ rb4xx_spi_process_queue_locked(rbspi, &flags); ++ spin_unlock_irqrestore(&rbspi->lock, flags); ++ ++ return 0; ++} ++ ++static int rb4xx_spi_setup(struct spi_device *spi) ++{ ++ struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master); ++ unsigned long flags; ++ ++ if (spi->mode & ~(SPI_CS_HIGH)) { ++ dev_err(&spi->dev, "mode %x not supported\n", ++ (unsigned) spi->mode); ++ return -EINVAL; ++ } ++ ++ if (spi->bits_per_word != 8 && spi->bits_per_word != 0) { ++ dev_err(&spi->dev, "bits_per_word %u not supported\n", ++ (unsigned) spi->bits_per_word); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&rbspi->lock, flags); ++ if (rbspi->cs_wait == spi->chip_select && !rbspi->busy) { ++ rbspi->cs_wait = -1; ++ rb4xx_spi_process_queue_locked(rbspi, &flags); ++ } ++ spin_unlock_irqrestore(&rbspi->lock, flags); ++ ++ 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); ++ pr_debug("rb4xx: %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 rb4xx_spi_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct rb4xx_spi *rbspi; ++ struct resource *r; ++ int err = 0; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(*rbspi)); ++ if (master == NULL) { ++ dev_err(&pdev->dev, "no memory for spi_master\n"); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ master->bus_num = 0; ++ master->num_chipselect = 3; ++ master->setup = rb4xx_spi_setup; ++ master->transfer = rb4xx_spi_transfer; ++ ++ rbspi = spi_master_get_devdata(master); ++ platform_set_drvdata(pdev, rbspi); ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (r == NULL) { ++ err = -ENOENT; ++ goto err_put_master; ++ } ++ ++ rbspi->base = ioremap(r->start, r->end - r->start + 1); ++ if (!rbspi->base) { ++ err = -ENXIO; ++ goto err_put_master; ++ } ++ ++ rbspi->master = master; ++ rbspi->spi_ctrl_flash = get_spi_ctrl(SPI_FLASH_HZ, "FLASH"); ++ rbspi->spi_ctrl_fread = get_spi_ctrl(SPI_CPLD_HZ, "CPLD"); ++ rbspi->cs_wait = -1; ++ ++ spin_lock_init(&rbspi->lock); ++ INIT_LIST_HEAD(&rbspi->queue); ++ ++ err = spi_register_master(master); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register SPI master\n"); ++ goto err_iounmap; ++ } ++ ++ return 0; ++ ++err_iounmap: ++ iounmap(rbspi->base); ++err_put_master: ++ platform_set_drvdata(pdev, NULL); ++ spi_master_put(master); ++err_out: ++ return err; ++} ++ ++static int rb4xx_spi_remove(struct platform_device *pdev) ++{ ++ struct rb4xx_spi *rbspi = platform_get_drvdata(pdev); ++ ++ iounmap(rbspi->base); ++ platform_set_drvdata(pdev, NULL); ++ spi_master_put(rbspi->master); ++ ++ return 0; ++} ++ ++static struct platform_driver rb4xx_spi_drv = { ++ .probe = rb4xx_spi_probe, ++ .remove = rb4xx_spi_remove, ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init rb4xx_spi_init(void) ++{ ++ return platform_driver_register(&rb4xx_spi_drv); ++} ++subsys_initcall(rb4xx_spi_init); ++ ++static void __exit rb4xx_spi_exit(void) ++{ ++ platform_driver_unregister(&rb4xx_spi_drv); ++} ++ ++module_exit(rb4xx_spi_exit); ++ ++MODULE_DESCRIPTION(DRV_DESC); ++MODULE_VERSION(DRV_VERSION); ++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-2.6.39.orig/drivers/spi/spi_rb4xx_cpld.c linux-2.6.39/drivers/spi/spi_rb4xx_cpld.c +--- linux-2.6.39.orig/drivers/spi/spi_rb4xx_cpld.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/drivers/spi/spi_rb4xx_cpld.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,440 @@ ++/* ++ * SPI driver for the CPLD chip on the Mikrotik RB4xx boards ++ * ++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file was based on the patches for Linux 2.6.27.39 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/types.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/device.h> ++#include <linux/bitops.h> ++#include <linux/spi/spi.h> ++#include <linux/gpio.h> ++#include <linux/slab.h> ++ ++#include <asm/mach-ar71xx/rb4xx_cpld.h> ++ ++#define DRV_NAME "spi-rb4xx-cpld" ++#define DRV_DESC "RB4xx CPLD driver" ++#define DRV_VERSION "0.1.0" ++ ++#define CPLD_CMD_WRITE_NAND 0x08 /* send cmd, n x send data, send indle */ ++#define CPLD_CMD_WRITE_CFG 0x09 /* send cmd, n x send cfg */ ++#define CPLD_CMD_READ_NAND 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 CPLD_CMD_LED5_ON 0x0c /* send cmd */ ++#define CPLD_CMD_LED5_OFF 0x0d /* send cmd */ ++ ++struct rb4xx_cpld { ++ struct spi_device *spi; ++ struct mutex lock; ++ struct gpio_chip chip; ++ unsigned int config; ++}; ++ ++static struct rb4xx_cpld *rb4xx_cpld; ++ ++static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip) ++{ ++ return container_of(chip, struct rb4xx_cpld, chip); ++} ++ ++static int rb4xx_cpld_write_cmd(struct rb4xx_cpld *cpld, unsigned char cmd) ++{ ++ struct spi_transfer t[1]; ++ struct spi_message m; ++ unsigned char tx_buf[1]; ++ int err; ++ ++ spi_message_init(&m); ++ memset(&t, 0, sizeof(t)); ++ ++ t[0].tx_buf = tx_buf; ++ t[0].len = sizeof(tx_buf); ++ spi_message_add_tail(&t[0], &m); ++ ++ tx_buf[0] = cmd; ++ ++ err = spi_sync(cpld->spi, &m); ++ return err; ++} ++ ++static int rb4xx_cpld_write_cfg(struct rb4xx_cpld *cpld, unsigned char config) ++{ ++ struct spi_transfer t[1]; ++ struct spi_message m; ++ unsigned char cmd[2]; ++ int err; ++ ++ spi_message_init(&m); ++ memset(&t, 0, sizeof(t)); ++ ++ t[0].tx_buf = cmd; ++ t[0].len = sizeof(cmd); ++ spi_message_add_tail(&t[0], &m); ++ ++ cmd[0] = CPLD_CMD_WRITE_CFG; ++ cmd[1] = config; ++ ++ err = spi_sync(cpld->spi, &m); ++ return err; ++} ++ ++static int __rb4xx_cpld_change_cfg(struct rb4xx_cpld *cpld, unsigned mask, ++ unsigned value) ++{ ++ unsigned int config; ++ int err; ++ ++ config = cpld->config & ~mask; ++ config |= value; ++ ++ if ((cpld->config ^ config) & 0xff) { ++ err = rb4xx_cpld_write_cfg(cpld, config); ++ if (err) ++ return err; ++ } ++ ++ if ((cpld->config ^ config) & CPLD_CFG_nLED5) { ++ err = rb4xx_cpld_write_cmd(cpld, (value) ? CPLD_CMD_LED5_ON : ++ CPLD_CMD_LED5_OFF); ++ if (err) ++ return err; ++ } ++ ++ cpld->config = config; ++ return 0; ++} ++ ++int rb4xx_cpld_change_cfg(unsigned mask, unsigned value) ++{ ++ int ret; ++ ++ if (rb4xx_cpld == NULL) ++ return -ENODEV; ++ ++ mutex_lock(&rb4xx_cpld->lock); ++ ret = __rb4xx_cpld_change_cfg(rb4xx_cpld, mask, value); ++ mutex_unlock(&rb4xx_cpld->lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg); ++ ++int rb4xx_cpld_read_from(unsigned addr, unsigned char *rx_buf, ++ const unsigned char *verify_buf, unsigned count) ++{ ++ const unsigned char cmd[5] = { ++ CPLD_CMD_READ_FAST, ++ (addr >> 16) & 0xff, ++ (addr >> 8) & 0xff, ++ addr & 0xff, ++ 0 ++ }; ++ struct spi_transfer t[2] = { ++ { ++ .tx_buf = &cmd, ++ .len = 5, ++ }, ++ { ++ .tx_buf = verify_buf, ++ .rx_buf = rx_buf, ++ .len = count, ++ .verify = (verify_buf != NULL), ++ }, ++ }; ++ struct spi_message m; ++ ++ if (rb4xx_cpld == NULL) ++ return -ENODEV; ++ ++ spi_message_init(&m); ++ m.fast_read = 1; ++ spi_message_add_tail(&t[0], &m); ++ spi_message_add_tail(&t[1], &m); ++ return spi_sync(rb4xx_cpld->spi, &m); ++} ++EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from); ++ ++#if 0 ++int rb4xx_cpld_read(unsigned char *buf, unsigned char *verify_buf, ++ unsigned count) ++{ ++ struct spi_transfer t[2]; ++ struct spi_message m; ++ unsigned char cmd[2]; ++ ++ if (rb4xx_cpld == NULL) ++ return -ENODEV; ++ ++ spi_message_init(&m); ++ memset(&t, 0, sizeof(t)); ++ ++ /* send command */ ++ t[0].tx_buf = cmd; ++ t[0].len = sizeof(cmd); ++ spi_message_add_tail(&t[0], &m); ++ ++ cmd[0] = CPLD_CMD_READ_NAND; ++ cmd[1] = 0; ++ ++ /* read data */ ++ t[1].rx_buf = buf; ++ t[1].len = count; ++ spi_message_add_tail(&t[1], &m); ++ ++ return spi_sync(rb4xx_cpld->spi, &m); ++} ++#else ++int rb4xx_cpld_read(unsigned char *rx_buf, const unsigned char *verify_buf, ++ unsigned count) ++{ ++ static const unsigned char cmd[2] = { CPLD_CMD_READ_NAND, 0 }; ++ struct spi_transfer t[2] = { ++ { ++ .tx_buf = &cmd, ++ .len = 2, ++ }, { ++ .tx_buf = verify_buf, ++ .rx_buf = rx_buf, ++ .len = count, ++ .verify = (verify_buf != NULL), ++ }, ++ }; ++ struct spi_message m; ++ ++ if (rb4xx_cpld == NULL) ++ return -ENODEV; ++ ++ spi_message_init(&m); ++ spi_message_add_tail(&t[0], &m); ++ spi_message_add_tail(&t[1], &m); ++ return spi_sync(rb4xx_cpld->spi, &m); ++} ++#endif ++EXPORT_SYMBOL_GPL(rb4xx_cpld_read); ++ ++int rb4xx_cpld_write(const unsigned char *buf, unsigned count) ++{ ++#if 0 ++ struct spi_transfer t[3]; ++ struct spi_message m; ++ unsigned char cmd[1]; ++ ++ if (rb4xx_cpld == NULL) ++ return -ENODEV; ++ ++ memset(&t, 0, sizeof(t)); ++ spi_message_init(&m); ++ ++ /* send command */ ++ t[0].tx_buf = cmd; ++ t[0].len = sizeof(cmd); ++ spi_message_add_tail(&t[0], &m); ++ ++ cmd[0] = CPLD_CMD_WRITE_NAND; ++ ++ /* write data */ ++ t[1].tx_buf = buf; ++ t[1].len = count; ++ spi_message_add_tail(&t[1], &m); ++ ++ /* send idle */ ++ t[2].len = 1; ++ spi_message_add_tail(&t[2], &m); ++ ++ return spi_sync(rb4xx_cpld->spi, &m); ++#else ++ static const unsigned char cmd = CPLD_CMD_WRITE_NAND; ++ struct spi_transfer t[3] = { ++ { ++ .tx_buf = &cmd, ++ .len = 1, ++ }, { ++ .tx_buf = buf, ++ .len = count, ++ .fast_write = 1, ++ }, { ++ .len = 1, ++ .fast_write = 1, ++ }, ++ }; ++ struct spi_message m; ++ ++ if (rb4xx_cpld == NULL) ++ return -ENODEV; ++ ++ spi_message_init(&m); ++ spi_message_add_tail(&t[0], &m); ++ spi_message_add_tail(&t[1], &m); ++ spi_message_add_tail(&t[2], &m); ++ return spi_sync(rb4xx_cpld->spi, &m); ++#endif ++} ++EXPORT_SYMBOL_GPL(rb4xx_cpld_write); ++ ++static int rb4xx_cpld_gpio_get(struct gpio_chip *chip, unsigned offset) ++{ ++ struct rb4xx_cpld *cpld = gpio_to_cpld(chip); ++ int ret; ++ ++ mutex_lock(&cpld->lock); ++ ret = (cpld->config >> offset) & 1; ++ mutex_unlock(&cpld->lock); ++ ++ return ret; ++} ++ ++static void rb4xx_cpld_gpio_set(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ struct rb4xx_cpld *cpld = gpio_to_cpld(chip); ++ ++ mutex_lock(&cpld->lock); ++ __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset); ++ mutex_unlock(&cpld->lock); ++} ++ ++static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip, ++ unsigned offset) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static int rb4xx_cpld_gpio_direction_output(struct gpio_chip *chip, ++ unsigned offset, ++ int value) ++{ ++ struct rb4xx_cpld *cpld = gpio_to_cpld(chip); ++ int ret; ++ ++ mutex_lock(&cpld->lock); ++ ret = __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset); ++ mutex_unlock(&cpld->lock); ++ ++ return ret; ++} ++ ++static int rb4xx_cpld_gpio_init(struct rb4xx_cpld *cpld, unsigned int base) ++{ ++ int err; ++ ++ /* init config */ ++ cpld->config = CPLD_CFG_nLED1 | CPLD_CFG_nLED2 | CPLD_CFG_nLED3 | ++ CPLD_CFG_nLED4 | CPLD_CFG_nCE; ++ rb4xx_cpld_write_cfg(cpld, cpld->config); ++ ++ /* setup GPIO chip */ ++ cpld->chip.label = DRV_NAME; ++ ++ cpld->chip.get = rb4xx_cpld_gpio_get; ++ cpld->chip.set = rb4xx_cpld_gpio_set; ++ cpld->chip.direction_input = rb4xx_cpld_gpio_direction_input; ++ cpld->chip.direction_output = rb4xx_cpld_gpio_direction_output; ++ ++ cpld->chip.base = base; ++ cpld->chip.ngpio = CPLD_NUM_GPIOS; ++ cpld->chip.can_sleep = 1; ++ cpld->chip.dev = &cpld->spi->dev; ++ cpld->chip.owner = THIS_MODULE; ++ ++ err = gpiochip_add(&cpld->chip); ++ if (err) ++ dev_err(&cpld->spi->dev, "adding GPIO chip failed, err=%d\n", ++ err); ++ ++ return err; ++} ++ ++static int __devinit rb4xx_cpld_probe(struct spi_device *spi) ++{ ++ struct rb4xx_cpld *cpld; ++ struct rb4xx_cpld_platform_data *pdata; ++ int err; ++ ++ pdata = spi->dev.platform_data; ++ if (!pdata) { ++ dev_dbg(&spi->dev, "no platform data\n"); ++ return -EINVAL; ++ } ++ ++ cpld = kzalloc(sizeof(*cpld), GFP_KERNEL); ++ if (!cpld) { ++ dev_err(&spi->dev, "no memory for private data\n"); ++ return -ENOMEM; ++ } ++ ++ mutex_init(&cpld->lock); ++ cpld->spi = spi_dev_get(spi); ++ dev_set_drvdata(&spi->dev, cpld); ++ ++ spi->mode = SPI_MODE_0; ++ spi->bits_per_word = 8; ++ err = spi_setup(spi); ++ if (err) { ++ dev_err(&spi->dev, "spi_setup failed, err=%d\n", err); ++ goto err_drvdata; ++ } ++ ++ err = rb4xx_cpld_gpio_init(cpld, pdata->gpio_base); ++ if (err) ++ goto err_drvdata; ++ ++ rb4xx_cpld = cpld; ++ ++ return 0; ++ ++err_drvdata: ++ dev_set_drvdata(&spi->dev, NULL); ++ kfree(cpld); ++ ++ return err; ++} ++ ++static int __devexit rb4xx_cpld_remove(struct spi_device *spi) ++{ ++ struct rb4xx_cpld *cpld; ++ ++ rb4xx_cpld = NULL; ++ cpld = dev_get_drvdata(&spi->dev); ++ dev_set_drvdata(&spi->dev, NULL); ++ kfree(cpld); ++ ++ return 0; ++} ++ ++static struct spi_driver rb4xx_cpld_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ .bus = &spi_bus_type, ++ .owner = THIS_MODULE, ++ }, ++ .probe = rb4xx_cpld_probe, ++ .remove = __devexit_p(rb4xx_cpld_remove), ++}; ++ ++static int __init rb4xx_cpld_init(void) ++{ ++ return spi_register_driver(&rb4xx_cpld_driver); ++} ++module_init(rb4xx_cpld_init); ++ ++static void __exit rb4xx_cpld_exit(void) ++{ ++ spi_unregister_driver(&rb4xx_cpld_driver); ++} ++module_exit(rb4xx_cpld_exit); ++ ++MODULE_DESCRIPTION(DRV_DESC); ++MODULE_VERSION(DRV_VERSION); ++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); ++MODULE_LICENSE("GPL v2"); diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/spi_vsc7385.c --- linux-2.6.39.orig/drivers/spi/spi_vsc7385.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/spi/spi_vsc7385.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,620 @@ ++++ linux-2.6.39/drivers/spi/spi_vsc7385.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,621 @@ +/* + * SPI driver for the Vitesse VSC7385 ethernet switch + * @@ -15735,8 +22356,8 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s +#define VSC73XX_MAC_CFG_WEXC_DIS (1 << 31) +#define VSC73XX_MAC_CFG_PORT_RST (1 << 29) +#define VSC73XX_MAC_CFG_TX_EN (1 << 28) -+#define VSC73XX_MAC_CFG_SEED_LOAD (1 << 27) -+#define VSC73XX_MAC_CFG_FDX (1 << 18) ++#define VSC73XX_MAC_CFG_SEED_LOAD (1 << 27) ++#define VSC73XX_MAC_CFG_FDX (1 << 18) +#define VSC73XX_MAC_CFG_GIGE (1 << 17) +#define VSC73XX_MAC_CFG_RX_EN (1 << 16) +#define VSC73XX_MAC_CFG_VLAN_DBLAWR (1 << 15) @@ -16077,7 +22698,8 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s + rc = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0, + VSC73XX_ICPU_SRAM, &curVal); + if (rc) { -+ dev_err(&spi->dev, "could not read microcode %d\n",rc); ++ dev_err(&spi->dev, "could not read microcode %d\n", ++ rc); + goto out; + } + @@ -16109,7 +22731,7 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s + + rc = vsc7385_icpu_start(vsc); + -+ out: ++out: + release_firmware(firmware); + return rc; +} @@ -16154,7 +22776,7 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s + + return 0; + -+ err: ++err: + return err; +} + @@ -16199,7 +22821,7 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s + + rev = (t >> VSC73XX_ICPU_CHIPID_REV_SHIFT) & + VSC73XX_ICPU_CHIPID_REV_MASK; -+ dev_info(&spi->dev, "VSC%04X (rev. %d) switch found \n", id, rev); ++ dev_info(&spi->dev, "VSC%04X (rev. %d) switch found\n", id, rev); + + return 0; +} @@ -16215,13 +22837,13 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s + pdata = spi->dev.platform_data; + if (!pdata) { + dev_err(&spi->dev, "no platform data specified\n"); -+ return-ENODEV; ++ return -ENODEV; + } + + vsc = kzalloc(sizeof(*vsc), GFP_KERNEL); + if (!vsc) { + dev_err(&spi->dev, "no memory for private data\n"); -+ return-ENOMEM; ++ return -ENOMEM; + } + + mutex_init(&vsc->lock); @@ -16233,13 +22855,13 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s + spi->bits_per_word = 8; + err = spi_setup(spi); + if (err) { -+ dev_err(&spi->dev, "spi_setup failed, err=%d \n", err); ++ dev_err(&spi->dev, "spi_setup failed, err=%d\n", err); + goto err_drvdata; + } + + err = vsc7385_detect(vsc); + if (err) { -+ dev_err(&spi->dev, "no chip found, err=%d \n", err); ++ dev_err(&spi->dev, "no chip found, err=%d\n", err); + goto err_drvdata; + } + @@ -16253,7 +22875,7 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s + + return 0; + -+ err_drvdata: ++err_drvdata: + dev_set_drvdata(&spi->dev, NULL); + kfree(vsc); + return err; @@ -16297,9 +22919,701 @@ diff -Nur linux-2.6.39.orig/drivers/spi/spi_vsc7385.c linux-2.6.39/drivers/spi/s +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_LICENSE("GPL v2"); + +diff -Nur linux-2.6.39.orig/drivers/tty/serial/ar933x_uart.c linux-2.6.39/drivers/tty/serial/ar933x_uart.c +--- linux-2.6.39.orig/drivers/tty/serial/ar933x_uart.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/drivers/tty/serial/ar933x_uart.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,688 @@ ++/* ++ * Atheros AR933X SoC built-in UART driver ++ * ++ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. ++ * ++ * 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/module.h> ++#include <linux/ioport.h> ++#include <linux/init.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++#include <linux/delay.h> ++#include <linux/platform_device.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/serial_core.h> ++#include <linux/serial.h> ++#include <linux/slab.h> ++#include <linux/io.h> ++#include <linux/irq.h> ++ ++#include <asm/mach-ar71xx/ar933x_uart.h> ++#include <asm/mach-ar71xx/ar933x_uart_platform.h> ++ ++#define DRIVER_NAME "ar933x-uart" ++ ++#define AR933X_DUMMY_STATUS_RD 0x01 ++ ++static struct uart_driver ar933x_uart_driver; ++ ++struct ar933x_uart_port { ++ struct uart_port port; ++ unsigned int ier; /* shadow Interrupt Enable Register */ ++}; ++ ++static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, ++ int offset) ++{ ++ return readl(up->port.membase + offset); ++} ++ ++static inline void ar933x_uart_write(struct ar933x_uart_port *up, ++ int offset, unsigned int value) ++{ ++ writel(value, up->port.membase + offset); ++} ++ ++static inline void ar933x_uart_rmw(struct ar933x_uart_port *up, ++ unsigned int offset, ++ unsigned int mask, ++ unsigned int val) ++{ ++ unsigned int t; ++ ++ t = ar933x_uart_read(up, offset); ++ t &= ~mask; ++ t |= val; ++ ar933x_uart_write(up, offset, t); ++} ++ ++static inline void ar933x_uart_rmw_set(struct ar933x_uart_port *up, ++ unsigned int offset, ++ unsigned int val) ++{ ++ ar933x_uart_rmw(up, offset, 0, val); ++} ++ ++static inline void ar933x_uart_rmw_clear(struct ar933x_uart_port *up, ++ unsigned int offset, ++ unsigned int val) ++{ ++ ar933x_uart_rmw(up, offset, val, 0); ++} ++ ++static inline void ar933x_uart_start_tx_interrupt(struct ar933x_uart_port *up) ++{ ++ up->ier |= AR933X_UART_INT_TX_EMPTY; ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++} ++ ++static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up) ++{ ++ up->ier &= ~AR933X_UART_INT_TX_EMPTY; ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++} ++ ++static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) ++{ ++ unsigned int rdata; ++ ++ rdata = ch & AR933X_UART_DATA_TX_RX_MASK; ++ rdata |= AR933X_UART_DATA_TX_CSR; ++ ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata); ++} ++ ++static unsigned int ar933x_uart_tx_empty(struct uart_port *port) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ unsigned long flags; ++ unsigned int rdata; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT; ++} ++ ++static unsigned int ar933x_uart_get_mctrl(struct uart_port *port) ++{ ++ return TIOCM_CAR; ++} ++ ++static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) ++{ ++} ++ ++static void ar933x_uart_start_tx(struct uart_port *port) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ ++ ar933x_uart_start_tx_interrupt(up); ++} ++ ++static void ar933x_uart_stop_tx(struct uart_port *port) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ ++ ar933x_uart_stop_tx_interrupt(up); ++} ++ ++static void ar933x_uart_stop_rx(struct uart_port *port) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ ++ up->ier &= ~AR933X_UART_INT_RX_VALID; ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++} ++ ++static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ if (break_state == -1) ++ ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, ++ AR933X_UART_CS_TX_BREAK); ++ else ++ ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, ++ AR933X_UART_CS_TX_BREAK); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++} ++ ++static void ar933x_uart_enable_ms(struct uart_port *port) ++{ ++} ++ ++static void ar933x_uart_set_termios(struct uart_port *port, ++ struct ktermios *new, ++ struct ktermios *old) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ unsigned int cs; ++ unsigned long flags; ++ unsigned int baud, scale; ++ ++ /* Only CS8 is supported */ ++ new->c_cflag &= ~CSIZE; ++ new->c_cflag |= CS8; ++ ++ /* Only one stop bit is supported */ ++ new->c_cflag &= ~CSTOPB; ++ ++ cs = 0; ++ if (new->c_cflag & PARENB) { ++ if (!(new->c_cflag & PARODD)) ++ cs |= AR933X_UART_CS_PARITY_EVEN; ++ else ++ cs |= AR933X_UART_CS_PARITY_ODD; ++ } else { ++ cs |= AR933X_UART_CS_PARITY_NONE; ++ } ++ ++ /* Mark/space parity is not supported */ ++ new->c_cflag &= ~CMSPAR; ++ ++ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); ++ scale = (port->uartclk / (16 * baud)) - 1; ++ ++ /* ++ * Ok, we're now changing the port state. Do it with ++ * interrupts disabled. ++ */ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ++ /* Update the per-port timeout. */ ++ uart_update_timeout(port, new->c_cflag, baud); ++ ++ up->port.ignore_status_mask = 0; ++ ++ /* ignore all characters if CREAD is not set */ ++ if ((new->c_cflag & CREAD) == 0) ++ up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD; ++ ++ ar933x_uart_write(up, AR933X_UART_CLOCK_REG, ++ scale << AR933X_UART_CLOCK_SCALE_S | 8192); ++ ++ /* setup configuration register */ ++ ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs); ++ ++ /* enable host interrupt */ ++ ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, ++ AR933X_UART_CS_HOST_INT_EN); ++ ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ if (tty_termios_baud_rate(new)) ++ tty_termios_encode_baud_rate(new, baud, baud); ++} ++ ++static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) ++{ ++ struct tty_struct *tty; ++ int max_count = 256; ++ ++ tty = tty_port_tty_get(&up->port.state->port); ++ do { ++ unsigned int rdata; ++ unsigned char ch; ++ ++ rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); ++ if ((rdata & AR933X_UART_DATA_RX_CSR) == 0) ++ break; ++ ++ /* remove the character from the FIFO */ ++ ar933x_uart_write(up, AR933X_UART_DATA_REG, ++ AR933X_UART_DATA_RX_CSR); ++ ++ if (!tty) { ++ /* discard the data if no tty available */ ++ continue; ++ } ++ ++ up->port.icount.rx++; ++ ch = rdata & AR933X_UART_DATA_TX_RX_MASK; ++ ++ if (uart_handle_sysrq_char(&up->port, ch)) ++ continue; ++ ++ if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) ++ tty_insert_flip_char(tty, ch, TTY_NORMAL); ++ } while (max_count-- > 0); ++ ++ if (tty) { ++ tty_flip_buffer_push(tty); ++ tty_kref_put(tty); ++ } ++} ++ ++static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) ++{ ++ struct circ_buf *xmit = &up->port.state->xmit; ++ int count; ++ ++ if (uart_tx_stopped(&up->port)) ++ return; ++ ++ count = up->port.fifosize; ++ do { ++ unsigned int rdata; ++ ++ rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); ++ if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) ++ break; ++ ++ if (up->port.x_char) { ++ ar933x_uart_putc(up, up->port.x_char); ++ up->port.icount.tx++; ++ up->port.x_char = 0; ++ continue; ++ } ++ ++ if (uart_circ_empty(xmit)) ++ break; ++ ++ ar933x_uart_putc(up, xmit->buf[xmit->tail]); ++ ++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ++ up->port.icount.tx++; ++ } while (--count > 0); ++ ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) ++ uart_write_wakeup(&up->port); ++ ++ if (!uart_circ_empty(xmit)) ++ ar933x_uart_start_tx_interrupt(up); ++} ++ ++static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) ++{ ++ struct ar933x_uart_port *up = dev_id; ++ unsigned int status; ++ ++ status = ar933x_uart_read(up, AR933X_UART_CS_REG); ++ if ((status & AR933X_UART_CS_HOST_INT) == 0) ++ return IRQ_NONE; ++ ++ spin_lock(&up->port.lock); ++ ++ status = ar933x_uart_read(up, AR933X_UART_INT_REG); ++ status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG); ++ ++ if (status & AR933X_UART_INT_RX_VALID) { ++ ar933x_uart_write(up, AR933X_UART_INT_REG, ++ AR933X_UART_INT_RX_VALID); ++ ar933x_uart_rx_chars(up); ++ } ++ ++ if (status & AR933X_UART_INT_TX_EMPTY) { ++ ar933x_uart_write(up, AR933X_UART_INT_REG, ++ AR933X_UART_INT_TX_EMPTY); ++ ar933x_uart_stop_tx_interrupt(up); ++ ar933x_uart_tx_chars(up); ++ } ++ ++ spin_unlock(&up->port.lock); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ar933x_uart_startup(struct uart_port *port) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ unsigned long flags; ++ int ret; ++ ++ ret = request_irq(up->port.irq, ar933x_uart_interrupt, ++ up->port.irqflags, dev_name(up->port.dev), up); ++ if (ret) ++ return ret; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ++ /* Enable HOST interrupts */ ++ ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, ++ AR933X_UART_CS_HOST_INT_EN); ++ ++ /* Enable RX interrupts */ ++ up->ier = AR933X_UART_INT_RX_VALID; ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++ ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ return 0; ++} ++ ++static void ar933x_uart_shutdown(struct uart_port *port) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ ++ /* Disable all interrupts */ ++ up->ier = 0; ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++ ++ /* Disable break condition */ ++ ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, ++ AR933X_UART_CS_TX_BREAK); ++ ++ free_irq(up->port.irq, up); ++} ++ ++static const char *ar933x_uart_type(struct uart_port *port) ++{ ++ return (port->type == PORT_AR933X) ? "AR933X UART" : NULL; ++} ++ ++static void ar933x_uart_release_port(struct uart_port *port) ++{ ++ /* Nothing to release ... */ ++} ++ ++static int ar933x_uart_request_port(struct uart_port *port) ++{ ++ /* UARTs always present */ ++ return 0; ++} ++ ++static void ar933x_uart_config_port(struct uart_port *port, int flags) ++{ ++ if (flags & UART_CONFIG_TYPE) ++ port->type = PORT_AR933X; ++} ++ ++static int ar933x_uart_verify_port(struct uart_port *port, ++ struct serial_struct *ser) ++{ ++ if (ser->type != PORT_UNKNOWN && ++ ser->type != PORT_AR933X) ++ return -EINVAL; ++ ++ if (ser->irq < 0 || ser->irq >= NR_IRQS) ++ return -EINVAL; ++ ++ if (ser->baud_base < 28800) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static struct uart_ops ar933x_uart_ops = { ++ .tx_empty = ar933x_uart_tx_empty, ++ .set_mctrl = ar933x_uart_set_mctrl, ++ .get_mctrl = ar933x_uart_get_mctrl, ++ .stop_tx = ar933x_uart_stop_tx, ++ .start_tx = ar933x_uart_start_tx, ++ .stop_rx = ar933x_uart_stop_rx, ++ .enable_ms = ar933x_uart_enable_ms, ++ .break_ctl = ar933x_uart_break_ctl, ++ .startup = ar933x_uart_startup, ++ .shutdown = ar933x_uart_shutdown, ++ .set_termios = ar933x_uart_set_termios, ++ .type = ar933x_uart_type, ++ .release_port = ar933x_uart_release_port, ++ .request_port = ar933x_uart_request_port, ++ .config_port = ar933x_uart_config_port, ++ .verify_port = ar933x_uart_verify_port, ++}; ++ ++#ifdef CONFIG_SERIAL_AR933X_CONSOLE ++ ++static struct ar933x_uart_port * ++ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; ++ ++static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up) ++{ ++ unsigned int status; ++ unsigned int timeout = 60000; ++ ++ /* Wait up to 60ms for the character(s) to be sent. */ ++ do { ++ status = ar933x_uart_read(up, AR933X_UART_DATA_REG); ++ if (--timeout == 0) ++ break; ++ udelay(1); ++ } while ((status & AR933X_UART_DATA_TX_CSR) == 0); ++} ++ ++static void ar933x_uart_console_putchar(struct uart_port *port, int ch) ++{ ++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; ++ ++ ar933x_uart_wait_xmitr(up); ++ ar933x_uart_putc(up, ch); ++} ++ ++static void ar933x_uart_console_write(struct console *co, const char *s, ++ unsigned int count) ++{ ++ struct ar933x_uart_port *up = ar933x_console_ports[co->index]; ++ unsigned long flags; ++ unsigned int int_en; ++ int locked = 1; ++ ++ local_irq_save(flags); ++ ++ if (up->port.sysrq) ++ locked = 0; ++ else if (oops_in_progress) ++ locked = spin_trylock(&up->port.lock); ++ else ++ spin_lock(&up->port.lock); ++ ++ /* ++ * First save the IER then disable the interrupts ++ */ ++ int_en = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0); ++ ++ uart_console_write(&up->port, s, count, ar933x_uart_console_putchar); ++ ++ /* ++ * Finally, wait for transmitter to become empty ++ * and restore the IER ++ */ ++ ar933x_uart_wait_xmitr(up); ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, int_en); ++ ++ ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); ++ ++ if (locked) ++ spin_unlock(&up->port.lock); ++ ++ local_irq_restore(flags); ++} ++ ++static int ar933x_uart_console_setup(struct console *co, char *options) ++{ ++ struct ar933x_uart_port *up; ++ int baud = 115200; ++ int bits = 8; ++ int parity = 'n'; ++ int flow = 'n'; ++ ++ if (co->index < 0 || co->index >= CONFIG_SERIAL_AR933X_NR_UARTS) ++ return -EINVAL; ++ ++ up = ar933x_console_ports[co->index]; ++ if (!up) ++ return -ENODEV; ++ ++ if (options) ++ uart_parse_options(options, &baud, &parity, &bits, &flow); ++ ++ return uart_set_options(&up->port, co, baud, parity, bits, flow); ++} ++ ++static struct console ar933x_uart_console = { ++ .name = "ttyATH", ++ .write = ar933x_uart_console_write, ++ .device = uart_console_device, ++ .setup = ar933x_uart_console_setup, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++ .data = &ar933x_uart_driver, ++}; ++ ++static void ar933x_uart_add_console_port(struct ar933x_uart_port *up) ++{ ++ ar933x_console_ports[up->port.line] = up; ++} ++ ++#define AR933X_SERIAL_CONSOLE (&ar933x_uart_console) ++ ++#else ++ ++static inline void ar933x_uart_add_console_port(struct ar933x_uart_port *up) {} ++ ++#define AR933X_SERIAL_CONSOLE NULL ++ ++#endif /* CONFIG_SERIAL_AR933X_CONSOLE */ ++ ++static struct uart_driver ar933x_uart_driver = { ++ .owner = THIS_MODULE, ++ .driver_name = DRIVER_NAME, ++ .dev_name = "ttyATH", ++ .nr = CONFIG_SERIAL_AR933X_NR_UARTS, ++ .cons = AR933X_SERIAL_CONSOLE, ++}; ++ ++static int __devinit ar933x_uart_probe(struct platform_device *pdev) ++{ ++ struct ar933x_uart_platform_data *pdata; ++ struct ar933x_uart_port *up; ++ struct uart_port *port; ++ struct resource *mem_res; ++ struct resource *irq_res; ++ int id; ++ int ret; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) ++ return -EINVAL; ++ ++ id = pdev->id; ++ if (id == -1) ++ id = 0; ++ ++ if (id > CONFIG_SERIAL_AR933X_NR_UARTS) ++ return -EINVAL; ++ ++ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!mem_res) { ++ dev_err(&pdev->dev, "no MEM resource\n"); ++ return -EINVAL; ++ } ++ ++ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (!irq_res) { ++ dev_err(&pdev->dev, "no IRQ resource\n"); ++ return -EINVAL; ++ } ++ ++ up = kzalloc(sizeof(struct ar933x_uart_port), GFP_KERNEL); ++ if (!up) ++ return -ENOMEM; ++ ++ port = &up->port; ++ port->mapbase = mem_res->start; ++ ++ port->membase = ioremap(mem_res->start, AR933X_UART_REGS_SIZE); ++ if (!port->membase) { ++ ret = -ENOMEM; ++ goto err_free_up; ++ } ++ ++ port->line = id; ++ port->irq = irq_res->start; ++ port->dev = &pdev->dev; ++ port->type = PORT_AR933X; ++ port->iotype = UPIO_MEM32; ++ port->uartclk = pdata->uartclk; ++ ++ port->regshift = 2; ++ port->fifosize = AR933X_UART_FIFO_SIZE; ++ port->ops = &ar933x_uart_ops; ++ ++ ar933x_uart_add_console_port(up); ++ ++ ret = uart_add_one_port(&ar933x_uart_driver, &up->port); ++ if (ret) ++ goto err_unmap; ++ ++ platform_set_drvdata(pdev, up); ++ return 0; ++ ++err_unmap: ++ iounmap(up->port.membase); ++err_free_up: ++ kfree(up); ++ return ret; ++} ++ ++static int __devexit ar933x_uart_remove(struct platform_device *pdev) ++{ ++ struct ar933x_uart_port *up; ++ ++ up = platform_get_drvdata(pdev); ++ platform_set_drvdata(pdev, NULL); ++ ++ if (up) { ++ uart_remove_one_port(&ar933x_uart_driver, &up->port); ++ iounmap(up->port.membase); ++ kfree(up); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver ar933x_uart_platform_driver = { ++ .probe = ar933x_uart_probe, ++ .remove = __devexit_p(ar933x_uart_remove), ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init ar933x_uart_init(void) ++{ ++ int ret; ++ ++ ar933x_uart_driver.nr = CONFIG_SERIAL_AR933X_NR_UARTS; ++ ret = uart_register_driver(&ar933x_uart_driver); ++ if (ret) ++ goto err_out; ++ ++ ret = platform_driver_register(&ar933x_uart_platform_driver); ++ if (ret) ++ goto err_unregister_uart_driver; ++ ++ return 0; ++ ++err_unregister_uart_driver: ++ uart_unregister_driver(&ar933x_uart_driver); ++err_out: ++ return ret; ++} ++ ++static void __exit ar933x_uart_exit(void) ++{ ++ platform_driver_unregister(&ar933x_uart_platform_driver); ++ uart_unregister_driver(&ar933x_uart_driver); ++} ++ ++module_init(ar933x_uart_init); ++module_exit(ar933x_uart_exit); ++ ++MODULE_DESCRIPTION("Atheros AR933X UART driver"); ++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:" DRIVER_NAME); diff -Nur linux-2.6.39.orig/drivers/usb/host/Kconfig linux-2.6.39/drivers/usb/host/Kconfig --- linux-2.6.39.orig/drivers/usb/host/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/usb/host/Kconfig 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/usb/host/Kconfig 2011-08-24 18:17:24.000000000 +0200 @@ -129,6 +129,13 @@ config USB_FSL_MPH_DR_OF tristate @@ -16330,7 +23644,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/Kconfig linux-2.6.39/drivers/usb/ho depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) diff -Nur linux-2.6.39.orig/drivers/usb/host/ehci-ar71xx.c linux-2.6.39/drivers/usb/host/ehci-ar71xx.c --- linux-2.6.39.orig/drivers/usb/host/ehci-ar71xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/usb/host/ehci-ar71xx.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/usb/host/ehci-ar71xx.c 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,242 @@ +/* + * Bus Glue for Atheros AR71xx built-in EHCI controller. @@ -16451,12 +23765,12 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/ehci-ar71xx.c linux-2.6.39/drivers/ + + return 0; + -+ err_iounmap: ++err_iounmap: + iounmap(hcd->regs); + -+ err_release_region: ++err_release_region: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -+ err_put_hcd: ++err_put_hcd: + usb_put_hcd(hcd); + return ret; +} @@ -16576,7 +23890,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/ehci-ar71xx.c linux-2.6.39/drivers/ +}; diff -Nur linux-2.6.39.orig/drivers/usb/host/ehci-hcd.c linux-2.6.39/drivers/usb/host/ehci-hcd.c --- linux-2.6.39.orig/drivers/usb/host/ehci-hcd.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/usb/host/ehci-hcd.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/usb/host/ehci-hcd.c 2011-08-24 18:17:24.000000000 +0200 @@ -1265,6 +1265,11 @@ #define PLATFORM_DRIVER tegra_ehci_driver #endif @@ -16591,7 +23905,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/ehci-hcd.c linux-2.6.39/drivers/usb !defined(XILINX_OF_PLATFORM_DRIVER) diff -Nur linux-2.6.39.orig/drivers/usb/host/ohci-ar71xx.c linux-2.6.39/drivers/usb/host/ohci-ar71xx.c --- linux-2.6.39.orig/drivers/usb/host/ohci-ar71xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/usb/host/ohci-ar71xx.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/usb/host/ohci-ar71xx.c 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,165 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. @@ -16665,11 +23979,11 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/ohci-ar71xx.c linux-2.6.39/drivers/ + + return 0; + -+ err_stop_hcd: ++err_stop_hcd: + iounmap(hcd->regs); -+ err_release_region: ++err_release_region: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -+ err_put_hcd: ++err_put_hcd: + usb_put_hcd(hcd); + return ret; +} @@ -16697,7 +24011,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/ohci-ar71xx.c linux-2.6.39/drivers/ + + return 0; + -+ err: ++err: + ohci_stop(hcd); + return ret; +} @@ -16760,7 +24074,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/ohci-ar71xx.c linux-2.6.39/drivers/ +}; diff -Nur linux-2.6.39.orig/drivers/usb/host/ohci-hcd.c linux-2.6.39/drivers/usb/host/ohci-hcd.c --- linux-2.6.39.orig/drivers/usb/host/ohci-hcd.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/usb/host/ohci-hcd.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/usb/host/ohci-hcd.c 2011-08-24 18:17:24.000000000 +0200 @@ -1105,6 +1105,11 @@ #define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver #endif @@ -16775,7 +24089,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/ohci-hcd.c linux-2.6.39/drivers/usb !defined(OMAP1_PLATFORM_DRIVER) && \ diff -Nur linux-2.6.39.orig/drivers/watchdog/Kconfig linux-2.6.39/drivers/watchdog/Kconfig --- linux-2.6.39.orig/drivers/watchdog/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/watchdog/Kconfig 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/drivers/watchdog/Kconfig 2011-08-24 18:17:24.000000000 +0200 @@ -990,6 +990,13 @@ To compile this driver as a loadable module, choose M here. The module will be called bcm63xx_wdt. @@ -16792,25 +24106,28 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/Kconfig linux-2.6.39/drivers/watchd # POWERPC Architecture diff -Nur linux-2.6.39.orig/drivers/watchdog/Makefile linux-2.6.39/drivers/watchdog/Makefile --- linux-2.6.39.orig/drivers/watchdog/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/watchdog/Makefile 2011-05-27 14:36:51.000000000 +0200 -@@ -121,6 +121,7 @@ ++++ linux-2.6.39/drivers/watchdog/Makefile 2011-08-24 18:17:24.000000000 +0200 +@@ -119,6 +119,7 @@ + obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o + obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o ++obj-$(CONFIG_AR71XX_WDT) += ar71xx_wdt.o obj-$(CONFIG_AR7_WDT) += ar7_wdt.o obj-$(CONFIG_TXX9_WDT) += txx9wdt.o -+obj-$(CONFIG_AR71XX_WDT) += ar71xx_wdt.o obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o - octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o - diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/watchdog/ar71xx_wdt.c --- linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/watchdog/ar71xx_wdt.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,270 @@ ++++ linux-2.6.39/drivers/watchdog/ar71xx_wdt.c 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,299 @@ +/* + * Driver for the Atheros AR71xx SoC's built-in hardware watchdog timer. + * ++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * 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.31 BSP ++ * + * This driver was based on: drivers/watchdog/ixp4xx_wdt.c + * Author: Deepak Saxena <dsaxena@plexity.net> + * Copyright 2004 (c) MontaVista, Software, Inc. @@ -16835,6 +24152,7 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/watchdog.h> ++#include <linux/delay.h> + +#include <asm/mach-ar71xx/ar71xx.h> + @@ -16860,20 +24178,22 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w +static int wdt_timeout = WDT_TIMEOUT; +static int boot_status; +static int max_timeout; ++static u32 wdt_clk_freq; + -+static void inline ar71xx_wdt_keepalive(void) ++static inline void ar71xx_wdt_keepalive(void) +{ -+ ar71xx_reset_wr(AR71XX_RESET_REG_WDOG, ar71xx_ahb_freq * wdt_timeout); ++ ar71xx_reset_wr(AR71XX_RESET_REG_WDOG, wdt_clk_freq * wdt_timeout); +} + -+static void inline ar71xx_wdt_enable(void) ++static inline void ar71xx_wdt_enable(void) +{ + printk(KERN_DEBUG DRV_NAME ": enabling watchdog timer\n"); + ar71xx_wdt_keepalive(); ++ udelay(2); + ar71xx_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR); +} + -+static void inline ar71xx_wdt_disable(void) ++static inline void ar71xx_wdt_disable(void) +{ + printk(KERN_DEBUG DRV_NAME ": disabling watchdog timer\n"); + ar71xx_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE); @@ -16922,7 +24242,7 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w +static ssize_t ar71xx_wdt_write(struct file *file, const char *data, + size_t len, loff_t *ppos) +{ -+ if (len) { ++ if (len) { + if (!nowayout) { + size_t i; + @@ -16949,11 +24269,11 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w +static struct watchdog_info ar71xx_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE | WDIOF_CARDRESET, -+ .firmware_version = 0, ++ .firmware_version = 0, + .identity = "AR71XX watchdog", +}; + -+static int ar71xx_wdt_ioctl(struct inode *inode, struct file *file, ++static long ar71xx_wdt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int t; @@ -16963,7 +24283,7 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info *)arg, + &ar71xx_wdt_info, -+ sizeof(&ar71xx_wdt_info)) ? -EFAULT : 0; ++ sizeof(ar71xx_wdt_info)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: @@ -17004,7 +24324,7 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w +static const struct file_operations ar71xx_wdt_fops = { + .owner = THIS_MODULE, + .write = ar71xx_wdt_write, -+ .ioctl = ar71xx_wdt_ioctl, ++ .unlocked_ioctl = ar71xx_wdt_ioctl, + .open = ar71xx_wdt_open, + .release = ar71xx_wdt_release, +}; @@ -17019,12 +24339,35 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w +{ + int ret; + -+ max_timeout = (0xfffffffful / ar71xx_ahb_freq); ++ switch (ar71xx_soc) { ++ case AR71XX_SOC_AR7130: ++ case AR71XX_SOC_AR7141: ++ case AR71XX_SOC_AR7161: ++ case AR71XX_SOC_AR7240: ++ case AR71XX_SOC_AR7241: ++ case AR71XX_SOC_AR7242: ++ case AR71XX_SOC_AR9130: ++ case AR71XX_SOC_AR9132: ++ wdt_clk_freq = ar71xx_ahb_freq; ++ break; ++ ++ case AR71XX_SOC_AR9330: ++ case AR71XX_SOC_AR9331: ++ case AR71XX_SOC_AR9341: ++ case AR71XX_SOC_AR9342: ++ case AR71XX_SOC_AR9344: ++ wdt_clk_freq = ar71xx_ref_freq; ++ break; ++ ++ default: ++ BUG(); ++ } ++ ++ max_timeout = (0xfffffffful / wdt_clk_freq); + wdt_timeout = (max_timeout < WDT_TIMEOUT) ? max_timeout : WDT_TIMEOUT; + -+ boot_status = -+ (ar71xx_reset_rr(AR71XX_RESET_REG_WDOG_CTRL) & WDOG_CTRL_LAST_RESET) ? -+ WDIOF_CARDRESET : 0; ++ if (ar71xx_reset_rr(AR71XX_RESET_REG_WDOG_CTRL) & WDOG_CTRL_LAST_RESET) ++ boot_status = WDIOF_CARDRESET; + + ret = misc_register(&ar71xx_wdt_miscdev); + if (ret) @@ -17033,7 +24376,7 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w + printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n"); + + printk(KERN_DEBUG DRV_NAME ": timeout=%d secs (max=%d)\n", -+ wdt_timeout, max_timeout); ++ wdt_timeout, max_timeout); + + return 0; + @@ -17077,97 +24420,174 @@ diff -Nur linux-2.6.39.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.39/drivers/w +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff -Nur linux-2.6.39.orig/include/linux/ath9k_platform.h linux-2.6.39/include/linux/ath9k_platform.h --- linux-2.6.39.orig/include/linux/ath9k_platform.h 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/include/linux/ath9k_platform.h 2011-05-27 14:36:51.000000000 +0200 -@@ -1,19 +1,11 @@ - /* -- * Copyright (c) 2008 Atheros Communications Inc. -- * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org> -- * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org> -+ * ath9k platform data defines - * -- * Permission to use, copy, modify, and/or distribute this software for any -- * purpose with or without fee is hereby granted, provided that the above -- * copyright notice and this permission notice appear in all copies. -+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org> - * -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ * 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 _LINUX_ATH9K_PLATFORM_H -@@ -23,6 +15,9 @@ ++++ linux-2.6.39/include/linux/ath9k_platform.h 2011-08-24 18:17:24.000000000 +0200 +@@ -23,6 +23,15 @@ struct ath9k_platform_data { u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; + u8 *macaddr; + -+ unsigned long quirk_wndr3700:1; ++ int led_pin; ++ u32 gpio_mask; ++ u32 gpio_val; ++ ++ bool is_clk_25mhz; ++ int (*get_mac_revision)(void); ++ int (*external_reset)(void); }; #endif /* _LINUX_ATH9K_PLATFORM_H */ -diff -Nur linux-2.6.39.orig/include/linux/gpio_buttons.h linux-2.6.39/include/linux/gpio_buttons.h ---- linux-2.6.39.orig/include/linux/gpio_buttons.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/include/linux/gpio_buttons.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,33 @@ +diff -Nur linux-2.6.39.orig/include/linux/ip.h linux-2.6.39/include/linux/ip.h +--- linux-2.6.39.orig/include/linux/ip.h 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/include/linux/ip.h 2011-08-24 18:17:24.000000000 +0200 +@@ -102,7 +102,7 @@ + __be32 saddr; + __be32 daddr; + /*The options start here. */ +-}; ++} __packed; + + #ifdef __KERNEL__ + #include <linux/skbuff.h> +diff -Nur linux-2.6.39.orig/include/linux/ipv6.h linux-2.6.39/include/linux/ipv6.h +--- linux-2.6.39.orig/include/linux/ipv6.h 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/include/linux/ipv6.h 2011-08-24 18:17:24.000000000 +0200 +@@ -126,7 +126,7 @@ + + struct in6_addr saddr; + struct in6_addr daddr; +-}; ++} __packed; + + #ifdef __KERNEL__ + /* +diff -Nur linux-2.6.39.orig/include/linux/myloader.h linux-2.6.39/include/linux/myloader.h +--- linux-2.6.39.orig/include/linux/myloader.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/include/linux/myloader.h 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,120 @@ +/* -+ * Definitions for the GPIO buttons interface driver ++ * Compex's MyLoader specific definitions + * -+ * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org> + * -+ * This file was based on: /include/linux/gpio_keys.h -+ * The original gpio_keys.h seems not to have a license. -+ * -+ * 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. ++ * 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 _GPIO_BUTTONS_H_ -+#define _GPIO_BUTTONS_H_ -+ -+struct gpio_button { -+ int gpio; /* GPIO line number */ -+ int active_low; -+ char *desc; /* button description */ -+ int type; /* input event type (EV_KEY, EV_SW) */ -+ int code; /* input event code (KEY_*, SW_*) */ -+ int threshold; /* count threshold */ -+}; -+ -+struct gpio_buttons_platform_data { -+ struct gpio_button *buttons; -+ int nbuttons; /* number of buttons */ -+ int poll_interval; /* polling interval */ -+}; -+ -+#endif /* _GPIO_BUTTONS_H_ */ -diff -Nur linux-2.6.39.orig/include/linux/gpio_dev.h linux-2.6.39/include/linux/gpio_dev.h ---- linux-2.6.39.orig/include/linux/gpio_dev.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/include/linux/gpio_dev.h 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,11 @@ -+#ifndef _GPIODEV_H__ -+#define _GPIODEV_H__ -+ -+#define IOC_GPIODEV_MAGIC 'B' -+#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10) -+#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11) -+#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12) -+#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13) -+#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14) -+ -+#endif ++#ifndef _MYLOADER_H_ ++#define _MYLOADER_H_ ++ ++/* Myloader specific magic numbers */ ++#define MYLO_MAGIC_SYS_PARAMS 0x20021107 ++#define MYLO_MAGIC_PARTITIONS 0x20021103 ++#define MYLO_MAGIC_BOARD_PARAMS 0x20021103 ++ ++/* Vendor ID's (seems to be same as the PCI vendor ID's) */ ++#define VENID_COMPEX 0x11F6 ++ ++/* Devices based on the ADM5120 */ ++#define DEVID_COMPEX_NP27G 0x0078 ++#define DEVID_COMPEX_NP28G 0x044C ++#define DEVID_COMPEX_NP28GHS 0x044E ++#define DEVID_COMPEX_WP54Gv1C 0x0514 ++#define DEVID_COMPEX_WP54G 0x0515 ++#define DEVID_COMPEX_WP54AG 0x0546 ++#define DEVID_COMPEX_WPP54AG 0x0550 ++#define DEVID_COMPEX_WPP54G 0x0555 ++ ++/* Devices based on the Atheros AR2317 */ ++#define DEVID_COMPEX_NP25G 0x05E6 ++#define DEVID_COMPEX_WPE53G 0x05DC ++ ++/* Devices based on the Atheros AR71xx */ ++#define DEVID_COMPEX_WP543 0x0640 ++ ++/* Devices based on the IXP422 */ ++#define DEVID_COMPEX_WP18 0x047E ++#define DEVID_COMPEX_NP18A 0x0489 ++ ++/* Other devices */ ++#define DEVID_COMPEX_NP26G8M 0x03E8 ++#define DEVID_COMPEX_NP26G16M 0x03E9 ++ ++struct mylo_partition { ++ uint16_t flags; /* partition flags */ ++ uint16_t type; /* type of the partition */ ++ uint32_t addr; /* relative address of the partition from the ++ flash start */ ++ uint32_t size; /* size of the partition in bytes */ ++ uint32_t param; /* if this is the active partition, the ++ MyLoader load code to this address */ ++}; ++ ++#define PARTITION_FLAG_ACTIVE 0x8000 /* this is the active partition, ++ * MyLoader loads firmware from here */ ++#define PARTITION_FLAG_ISRAM 0x2000 /* FIXME: this is a RAM partition? */ ++#define PARTIIION_FLAG_RAMLOAD 0x1000 /* FIXME: load this partition into the RAM? */ ++#define PARTITION_FLAG_PRELOAD 0x0800 /* the partition data preloaded to RAM ++ * before decompression */ ++#define PARTITION_FLAG_LZMA 0x0100 /* partition data compressed by LZMA */ ++#define PARTITION_FLAG_HAVEHDR 0x0002 /* the partition data have a header */ ++ ++#define PARTITION_TYPE_FREE 0 ++#define PARTITION_TYPE_USED 1 ++ ++#define MYLO_MAX_PARTITIONS 8 /* maximum number of partitions in the ++ partition table */ ++ ++struct mylo_partition_table { ++ uint32_t magic; /* must be MYLO_MAGIC_PARTITIONS */ ++ uint32_t res0; /* unknown/unused */ ++ uint32_t res1; /* unknown/unused */ ++ uint32_t res2; /* unknown/unused */ ++ struct mylo_partition partitions[MYLO_MAX_PARTITIONS]; ++}; ++ ++struct mylo_partition_header { ++ uint32_t len; /* length of the partition data */ ++ uint32_t crc; /* CRC value of the partition data */ ++}; ++ ++struct mylo_system_params { ++ uint32_t magic; /* must be MYLO_MAGIC_SYS_PARAMS */ ++ uint32_t res0; ++ uint32_t res1; ++ uint32_t mylo_ver; ++ uint16_t vid; /* Vendor ID */ ++ uint16_t did; /* Device ID */ ++ uint16_t svid; /* Sub Vendor ID */ ++ uint16_t sdid; /* Sub Device ID */ ++ uint32_t rev; /* device revision */ ++ uint32_t fwhi; ++ uint32_t fwlo; ++ uint32_t tftp_addr; ++ uint32_t prog_start; ++ uint32_t flash_size; /* size of boot FLASH in bytes */ ++ uint32_t dram_size; /* size of onboard RAM in bytes */ ++}; ++ ++struct mylo_eth_addr { ++ uint8_t mac[6]; ++ uint8_t csum[2]; ++}; ++ ++#define MYLO_ETHADDR_COUNT 8 /* maximum number of ethernet address ++ in the board parameters */ ++ ++struct mylo_board_params { ++ uint32_t magic; /* must be MYLO_MAGIC_BOARD_PARAMS */ ++ uint32_t res0; ++ uint32_t res1; ++ uint32_t res2; ++ struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT]; ++}; ++ ++#endif /* _MYLOADER_H_*/ diff -Nur linux-2.6.39.orig/include/linux/netdevice.h linux-2.6.39/include/linux/netdevice.h --- linux-2.6.39.orig/include/linux/netdevice.h 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/include/linux/netdevice.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/include/linux/netdevice.h 2011-08-24 18:17:24.000000000 +0200 @@ -1182,6 +1182,7 @@ void *ax25_ptr; /* AX.25 specific data */ struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data, @@ -17178,7 +24598,7 @@ diff -Nur linux-2.6.39.orig/include/linux/netdevice.h linux-2.6.39/include/linux * Cache lines mostly used on receive path (including eth_type_trans()) diff -Nur linux-2.6.39.orig/include/linux/nxp_74hc153.h linux-2.6.39/include/linux/nxp_74hc153.h --- linux-2.6.39.orig/include/linux/nxp_74hc153.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/include/linux/nxp_74hc153.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/include/linux/nxp_74hc153.h 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,24 @@ +/* + * NXP 74HC153 - Dual 4-input multiplexer defines @@ -17206,7 +24626,7 @@ diff -Nur linux-2.6.39.orig/include/linux/nxp_74hc153.h linux-2.6.39/include/lin +#endif /* _NXP_74HC153_H */ diff -Nur linux-2.6.39.orig/include/linux/phy.h linux-2.6.39/include/linux/phy.h --- linux-2.6.39.orig/include/linux/phy.h 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/include/linux/phy.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/include/linux/phy.h 2011-08-24 18:17:24.000000000 +0200 @@ -332,6 +332,20 @@ void (*adjust_link)(struct net_device *dev); @@ -17236,9 +24656,29 @@ diff -Nur linux-2.6.39.orig/include/linux/phy.h linux-2.6.39/include/linux/phy.h int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); int phy_start_interrupts(struct phy_device *phydev); +diff -Nur linux-2.6.39.orig/include/linux/spi/spi.h linux-2.6.39/include/linux/spi/spi.h +--- linux-2.6.39.orig/include/linux/spi/spi.h 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/include/linux/spi/spi.h 2011-08-24 18:17:24.000000000 +0200 +@@ -441,6 +441,8 @@ + dma_addr_t rx_dma; + + unsigned cs_change:1; ++ unsigned verify:1; ++ unsigned fast_write:1; + u8 bits_per_word; + u16 delay_usecs; + u32 speed_hz; +@@ -482,6 +484,7 @@ + struct spi_device *spi; + + unsigned is_dma_mapped:1; ++ unsigned fast_read:1; + + /* REVISIT: we might want a flag affecting the behavior of the + * last transfer ... allowing things like "read 16 bit length L" diff -Nur linux-2.6.39.orig/include/linux/spi/vsc7385.h linux-2.6.39/include/linux/spi/vsc7385.h --- linux-2.6.39.orig/include/linux/spi/vsc7385.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/include/linux/spi/vsc7385.h 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/include/linux/spi/vsc7385.h 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,19 @@ +/* + * Platform data definition for the Vitesse VSC7385 ethernet switch driver @@ -17251,7 +24691,7 @@ diff -Nur linux-2.6.39.orig/include/linux/spi/vsc7385.h linux-2.6.39/include/lin + */ + +struct vsc7385_platform_data { -+ void (* reset)(void); ++ void (*reset)(void); + char *ucode_name; + struct { + u32 tx_ipg:5; @@ -17259,749 +24699,241 @@ diff -Nur linux-2.6.39.orig/include/linux/spi/vsc7385.h linux-2.6.39/include/lin + u32 clk_sel:3; + } mac_cfg; +}; -diff -Nur linux-2.6.39.orig/net/dsa/ar7240.c linux-2.6.39/net/dsa/ar7240.c ---- linux-2.6.39.orig/net/dsa/ar7240.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/net/dsa/ar7240.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,736 @@ +diff -Nur linux-2.6.39.orig/include/linux/switch.h linux-2.6.39/include/linux/switch.h +--- linux-2.6.39.orig/include/linux/switch.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39/include/linux/switch.h 2011-08-24 18:17:24.000000000 +0200 +@@ -0,0 +1,204 @@ +/* -+ * DSA driver for the built-in ethernet switch of the Atheros AR7240 SoC -+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org> ++ * switch.h: Switch configuration API + * -+ * This file was based on: -+ * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips -+ * Copyright (c) 2008 Marvell Semiconductor ++ * Copyright (C) 2008 Felix Fietkau <nbd@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. ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. + * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. + */ + -+#include <linux/etherdevice.h> -+#include <linux/list.h> -+#include <linux/netdevice.h> -+#include <linux/phy.h> -+#include <linux/mii.h> -+#include <linux/bitops.h> -+ -+#include "dsa_priv.h" -+ -+#define BITM(_count) (BIT(_count) - 1) -+ -+#define AR7240_REG_MASK_CTRL 0x00 -+#define AR7240_MASK_CTRL_REVISION_M BITM(8) -+#define AR7240_MASK_CTRL_VERSION_M BITM(8) -+#define AR7240_MASK_CTRL_VERSION_S 8 -+#define AR7240_MASK_CTRL_SOFT_RESET BIT(31) -+ -+#define AR7240_REG_MAC_ADDR0 0x20 -+#define AR7240_REG_MAC_ADDR1 0x24 -+ -+#define AR7240_REG_FLOOD_MASK 0x2c -+#define AR7240_FLOOD_MASK_BROAD_TO_CPU BIT(26) -+ -+#define AR7240_REG_GLOBAL_CTRL 0x30 -+#define AR7240_GLOBAL_CTRL_MTU_M BITM(12) -+ -+#define AR7240_REG_AT_CTRL 0x5c -+#define AR7240_AT_CTRL_ARP_EN BIT(20) -+ -+#define AR7240_REG_TAG_PRIORITY 0x70 -+ -+#define AR7240_REG_SERVICE_TAG 0x74 -+#define AR7240_SERVICE_TAG_M BITM(16) -+ -+#define AR7240_REG_CPU_PORT 0x78 -+#define AR7240_MIRROR_PORT_S 4 -+#define AR7240_CPU_PORT_EN BIT(8) -+ -+#define AR7240_REG_MIB_FUNCTION0 0x80 -+#define AR7240_MIB_TIMER_M BITM(16) -+#define AR7240_MIB_AT_HALF_EN BIT(16) -+#define AR7240_MIB_BUSY BIT(17) -+#define AR7240_MIB_FUNC_S 24 -+#define AR7240_MIB_FUNC_NO_OP 0x0 -+#define AR7240_MIB_FUNC_FLUSH 0x1 -+#define AR7240_MIB_FUNC_CAPTURE 0x3 -+ -+#define AR7240_REG_MDIO_CTRL 0x98 -+#define AR7240_MDIO_CTRL_DATA_M BITM(16) -+#define AR7240_MDIO_CTRL_REG_ADDR_S 16 -+#define AR7240_MDIO_CTRL_PHY_ADDR_S 21 -+#define AR7240_MDIO_CTRL_CMD_WRITE 0 -+#define AR7240_MDIO_CTRL_CMD_READ BIT(27) -+#define AR7240_MDIO_CTRL_MASTER_EN BIT(30) -+#define AR7240_MDIO_CTRL_BUSY BIT(31) ++#ifndef __LINUX_SWITCH_H ++#define __LINUX_SWITCH_H + -+#define AR7240_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100) ++#include <linux/types.h> ++#include <linux/netdevice.h> ++#include <linux/netlink.h> ++#include <linux/genetlink.h> ++#ifndef __KERNEL__ ++#include <netlink/netlink.h> ++#include <netlink/genl/genl.h> ++#include <netlink/genl/ctrl.h> ++#else ++#include <net/genetlink.h> ++#endif + -+#define AR7240_REG_PORT_STATUS(_port) (AR7240_REG_PORT_BASE((_port)) + 0x00) -+#define AR7240_PORT_STATUS_SPEED_M BITM(2) -+#define AR7240_PORT_STATUS_SPEED_10 0 -+#define AR7240_PORT_STATUS_SPEED_100 1 -+#define AR7240_PORT_STATUS_SPEED_1000 2 -+#define AR7240_PORT_STATUS_TXMAC BIT(2) -+#define AR7240_PORT_STATUS_RXMAC BIT(3) -+#define AR7240_PORT_STATUS_TXFLOW BIT(4) -+#define AR7240_PORT_STATUS_RXFLOW BIT(5) -+#define AR7240_PORT_STATUS_DUPLEX BIT(6) -+#define AR7240_PORT_STATUS_LINK_UP BIT(8) -+#define AR7240_PORT_STATUS_LINK_AUTO BIT(9) -+#define AR7240_PORT_STATUS_LINK_PAUSE BIT(10) ++/* main attributes */ ++enum { ++ SWITCH_ATTR_UNSPEC, ++ /* global */ ++ SWITCH_ATTR_TYPE, ++ /* device */ ++ SWITCH_ATTR_ID, ++ SWITCH_ATTR_DEV_NAME, ++ SWITCH_ATTR_ALIAS, ++ SWITCH_ATTR_NAME, ++ SWITCH_ATTR_VLANS, ++ SWITCH_ATTR_PORTS, ++ SWITCH_ATTR_CPU_PORT, ++ /* attributes */ ++ SWITCH_ATTR_OP_ID, ++ SWITCH_ATTR_OP_TYPE, ++ SWITCH_ATTR_OP_NAME, ++ SWITCH_ATTR_OP_PORT, ++ SWITCH_ATTR_OP_VLAN, ++ SWITCH_ATTR_OP_VALUE_INT, ++ SWITCH_ATTR_OP_VALUE_STR, ++ SWITCH_ATTR_OP_VALUE_PORTS, ++ SWITCH_ATTR_OP_DESCRIPTION, ++ /* port lists */ ++ SWITCH_ATTR_PORT, ++ SWITCH_ATTR_MAX ++}; ++ ++/* commands */ ++enum { ++ SWITCH_CMD_UNSPEC, ++ SWITCH_CMD_GET_SWITCH, ++ SWITCH_CMD_NEW_ATTR, ++ SWITCH_CMD_LIST_GLOBAL, ++ SWITCH_CMD_GET_GLOBAL, ++ SWITCH_CMD_SET_GLOBAL, ++ SWITCH_CMD_LIST_PORT, ++ SWITCH_CMD_GET_PORT, ++ SWITCH_CMD_SET_PORT, ++ SWITCH_CMD_LIST_VLAN, ++ SWITCH_CMD_GET_VLAN, ++ SWITCH_CMD_SET_VLAN ++}; ++ ++/* data types */ ++enum switch_val_type { ++ SWITCH_TYPE_UNSPEC, ++ SWITCH_TYPE_INT, ++ SWITCH_TYPE_STRING, ++ SWITCH_TYPE_PORTS, ++ SWITCH_TYPE_NOVAL, ++}; ++ ++/* port nested attributes */ ++enum { ++ SWITCH_PORT_UNSPEC, ++ SWITCH_PORT_ID, ++ SWITCH_PORT_FLAG_TAGGED, ++ SWITCH_PORT_ATTR_MAX ++}; ++ ++#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000 ++ ++#ifdef __KERNEL__ ++ ++struct switch_dev; ++struct switch_op; ++struct switch_val; ++struct switch_attr; ++struct switch_attrlist; ++ ++int register_switch(struct switch_dev *dev, struct net_device *netdev); ++void unregister_switch(struct switch_dev *dev); ++ ++/** ++ * struct switch_attrlist - attribute list ++ * ++ * @n_attr: number of attributes ++ * @attr: pointer to the attributes array ++ */ ++struct switch_attrlist { ++ int n_attr; ++ const struct switch_attr *attr; ++}; + -+#define AR7240_REG_PORT_CTRL(_port) (AR7240_REG_PORT_BASE((_port)) + 0x04) -+#define AR7240_PORT_CTRL_STATE_M BITM(3) -+#define AR7240_PORT_CTRL_STATE_DISABLED 0 -+#define AR7240_PORT_CTRL_STATE_BLOCK 1 -+#define AR7240_PORT_CTRL_STATE_LISTEN 2 -+#define AR7240_PORT_CTRL_STATE_LEARN 3 -+#define AR7240_PORT_CTRL_STATE_FORWARD 4 -+#define AR7240_PORT_CTRL_LEARN_LOCK BIT(7) -+#define AR7240_PORT_CTRL_VLAN_MODE_S 8 -+#define AR7240_PORT_CTRL_VLAN_MODE_KEEP 0 -+#define AR7240_PORT_CTRL_VLAN_MODE_STRIP 1 -+#define AR7240_PORT_CTRL_VLAN_MODE_ADD 2 -+#define AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG 3 -+#define AR7240_PORT_CTRL_IGMP_SNOOP BIT(10) -+#define AR7240_PORT_CTRL_HEADER BIT(11) -+#define AR7240_PORT_CTRL_MAC_LOOP BIT(12) -+#define AR7240_PORT_CTRL_SINGLE_VLAN BIT(13) -+#define AR7240_PORT_CTRL_LEARN BIT(14) -+#define AR7240_PORT_CTRL_DOUBLE_TAG BIT(15) -+#define AR7240_PORT_CTRL_MIRROR_TX BIT(16) -+#define AR7240_PORT_CTRL_MIRROR_RX BIT(17) ++/** ++ * struct switch_dev_ops - switch driver operations ++ * ++ * @attr_global: global switch attribute list ++ * @attr_port: port attribute list ++ * @attr_vlan: vlan attribute list ++ * ++ * Callbacks: ++ * ++ * @get_vlan_ports: read the port list of a VLAN ++ * @set_vlan_ports: set the port list of a VLAN ++ * ++ * @get_port_pvid: get the primary VLAN ID of a port ++ * @set_port_pvid: set the primary VLAN ID of a port ++ * ++ * @apply_config: apply all changed settings to the switch ++ * @reset_switch: resetting the switch ++ */ ++struct switch_dev_ops { ++ struct switch_attrlist attr_global, attr_port, attr_vlan; + -+#define AR7240_REG_PORT_VLAN(_port) (AR7240_REG_PORT_BASE((_port)) + 0x08) ++ int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val); ++ int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val); + -+#define AR7240_PORT_VLAN_DEFAULT_ID_S 0 -+#define AR7240_PORT_VLAN_DEST_PORTS_S 16 ++ int (*get_port_pvid)(struct switch_dev *dev, int port, int *val); ++ int (*set_port_pvid)(struct switch_dev *dev, int port, int val); + -+#define AR7240_REG_STATS_BASE(_port) (0x20000 + (_port) * 0x100) ++ int (*apply_config)(struct switch_dev *dev); ++ int (*reset_switch)(struct switch_dev *dev); ++}; + -+#define AR7240_STATS_RXBROAD 0x00 -+#define AR7240_STATS_RXPAUSE 0x04 -+#define AR7240_STATS_RXMULTI 0x08 -+#define AR7240_STATS_RXFCSERR 0x0c -+#define AR7240_STATS_RXALIGNERR 0x10 -+#define AR7240_STATS_RXRUNT 0x14 -+#define AR7240_STATS_RXFRAGMENT 0x18 -+#define AR7240_STATS_RX64BYTE 0x1c -+#define AR7240_STATS_RX128BYTE 0x20 -+#define AR7240_STATS_RX256BYTE 0x24 -+#define AR7240_STATS_RX512BYTE 0x28 -+#define AR7240_STATS_RX1024BYTE 0x2c -+#define AR7240_STATS_RX1518BYTE 0x30 -+#define AR7240_STATS_RXMAXBYTE 0x34 -+#define AR7240_STATS_RXTOOLONG 0x38 -+#define AR7240_STATS_RXGOODBYTE 0x3c -+#define AR7240_STATS_RXBADBYTE 0x44 -+#define AR7240_STATS_RXOVERFLOW 0x4c -+#define AR7240_STATS_FILTERED 0x50 -+#define AR7240_STATS_TXBROAD 0x54 -+#define AR7240_STATS_TXPAUSE 0x58 -+#define AR7240_STATS_TXMULTI 0x5c -+#define AR7240_STATS_TXUNDERRUN 0x60 -+#define AR7240_STATS_TX64BYTE 0x64 -+#define AR7240_STATS_TX128BYTE 0x68 -+#define AR7240_STATS_TX256BYTE 0x6c -+#define AR7240_STATS_TX512BYTE 0x70 -+#define AR7240_STATS_TX1024BYTE 0x74 -+#define AR7240_STATS_TX1518BYTE 0x78 -+#define AR7240_STATS_TXMAXBYTE 0x7c -+#define AR7240_STATS_TXOVERSIZE 0x80 -+#define AR7240_STATS_TXBYTE 0x84 -+#define AR7240_STATS_TXCOLLISION 0x8c -+#define AR7240_STATS_TXABORTCOL 0x90 -+#define AR7240_STATS_TXMULTICOL 0x94 -+#define AR7240_STATS_TXSINGLECOL 0x98 -+#define AR7240_STATS_TXEXCDEFER 0x9c -+#define AR7240_STATS_TXDEFER 0xa0 -+#define AR7240_STATS_TXLATECOL 0xa4 ++struct switch_dev { ++ const struct switch_dev_ops *ops; ++ /* will be automatically filled */ ++ char devname[IFNAMSIZ]; + -+#define AR7240_PORT_CPU 0 -+#define AR7240_NUM_PORTS 6 -+#define AR7240_NUM_PHYS 5 ++ const char *name; ++ /* NB: either alias or netdev must be set */ ++ const char *alias; ++ struct net_device *netdev; + -+#define AR7240_PHY_ID1 0x004d -+#define AR7240_PHY_ID2 0xd041 ++ int ports; ++ int vlans; ++ int cpu_port; + -+#define AR7240_PORT_MASK(_port) BIT((_port)) -+#define AR7240_PORT_MASK_ALL BITM(AR7240_NUM_PORTS) -+#define AR7240_PORT_MASK_BUT(_port) (AR7240_PORT_MASK_ALL & ~BIT((_port))) ++ /* the following fields are internal for swconfig */ ++ int id; ++ struct list_head dev_list; ++ unsigned long def_global, def_port, def_vlan; + -+struct ar7240sw { -+ struct mii_bus *mii_bus; -+ struct mutex reg_mutex; -+ struct mutex stats_mutex; ++ spinlock_t lock; ++ struct switch_port *portbuf; +}; + -+struct ar7240sw_hw_stat { -+ char string[ETH_GSTRING_LEN]; -+ int sizeof_stat; -+ int reg; ++struct switch_port { ++ u32 id; ++ u32 flags; +}; + -+static inline struct ar7240sw *dsa_to_ar7240sw(struct dsa_switch *ds) -+{ -+ return (struct ar7240sw *)(ds + 1); -+} -+ -+static inline void ar7240sw_init(struct ar7240sw *as, struct mii_bus *mii) -+{ -+ as->mii_bus = mii; -+ mutex_init(&as->reg_mutex); -+ mutex_init(&as->stats_mutex); -+} -+ -+static inline u16 mk_phy_addr(u32 reg) -+{ -+ return (0x17 & ((reg >> 4) | 0x10)); -+} -+ -+static inline u16 mk_phy_reg(u32 reg) -+{ -+ return ((reg << 1) & 0x1e); -+} -+ -+static inline u16 mk_high_addr(u32 reg) -+{ -+ return ((reg >> 7) & 0x1ff); -+} -+ -+static u32 __ar7240sw_reg_read(struct ar7240sw *as, u32 reg) -+{ -+ struct mii_bus *mii = as->mii_bus; -+ u16 phy_addr; -+ u16 phy_reg; -+ u32 hi, lo; -+ -+ reg = (reg & 0xfffffffc) >> 2; -+ -+ mdiobus_write(mii, 0x1f, 0x10, mk_high_addr(reg)); -+ -+ phy_addr = mk_phy_addr(reg); -+ phy_reg = mk_phy_reg(reg); -+ -+ lo = (u32) mdiobus_read(mii, phy_addr, phy_reg); -+ hi = (u32) mdiobus_read(mii, phy_addr, phy_reg + 1); -+ -+ return ((hi << 16) | lo); -+} -+ -+static void __ar7240sw_reg_write(struct ar7240sw *as, u32 reg, u32 val) -+{ -+ struct mii_bus *mii = as->mii_bus; -+ u16 phy_addr; -+ u16 phy_reg; -+ -+ reg = (reg & 0xfffffffc) >> 2; -+ -+ mdiobus_write(mii, 0x1f, 0x10, mk_high_addr(reg)); -+ -+ phy_addr = mk_phy_addr(reg); -+ phy_reg = mk_phy_reg(reg); -+ -+ mdiobus_write(mii, phy_addr, phy_reg + 1, (val >> 16)); -+ mdiobus_write(mii, phy_addr, phy_reg, (val & 0xffff)); -+} -+ -+static u32 ar7240sw_reg_read(struct ar7240sw *as, u32 reg_addr) -+{ -+ u32 ret; -+ -+ mutex_lock(&as->reg_mutex); -+ ret = __ar7240sw_reg_read(as, reg_addr); -+ mutex_unlock(&as->reg_mutex); -+ -+ return ret; -+} -+ -+static void ar7240sw_reg_write(struct ar7240sw *as, u32 reg_addr, u32 reg_val) -+{ -+ mutex_lock(&as->reg_mutex); -+ __ar7240sw_reg_write(as, reg_addr, reg_val); -+ mutex_unlock(&as->reg_mutex); -+} -+ -+static u32 ar7240sw_reg_rmw(struct ar7240sw *as, u32 reg, u32 mask, u32 val) -+{ -+ u32 t; -+ -+ mutex_lock(&as->reg_mutex); -+ t = __ar7240sw_reg_read(as, reg); -+ t &= ~mask; -+ t |= val; -+ __ar7240sw_reg_write(as, reg, t); -+ mutex_unlock(&as->reg_mutex); -+ -+ return t; -+} -+ -+static void ar7240sw_reg_set(struct ar7240sw *as, u32 reg, u32 val) -+{ -+ u32 t; -+ -+ mutex_lock(&as->reg_mutex); -+ t = __ar7240sw_reg_read(as, reg); -+ t |= val; -+ __ar7240sw_reg_write(as, reg, t); -+ mutex_unlock(&as->reg_mutex); -+} -+ -+static int ar7240sw_reg_wait(struct ar7240sw *as, u32 reg, u32 mask, u32 val, -+ unsigned timeout) -+{ -+ int i; -+ -+ for (i = 0; i < timeout; i++) { -+ u32 t; -+ -+ t = ar7240sw_reg_read(as, reg); -+ if ((t & mask) == val) -+ return 0; -+ -+ msleep(1); -+ } -+ -+ return -ETIMEDOUT; -+} -+ -+static u16 ar7240sw_phy_read(struct ar7240sw *as, unsigned phy_addr, -+ unsigned reg_addr) -+{ -+ u32 t; -+ int err; -+ -+ if (phy_addr >= AR7240_NUM_PHYS) -+ return 0xffff; -+ -+ t = (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) | -+ (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) | -+ AR7240_MDIO_CTRL_MASTER_EN | -+ AR7240_MDIO_CTRL_BUSY | -+ AR7240_MDIO_CTRL_CMD_READ; -+ -+ ar7240sw_reg_write(as, AR7240_REG_MDIO_CTRL, t); -+ err = ar7240sw_reg_wait(as, AR7240_REG_MDIO_CTRL, -+ AR7240_MDIO_CTRL_BUSY, 0, 5); -+ if (err) -+ return 0xffff; -+ -+ t = ar7240sw_reg_read(as, AR7240_REG_MDIO_CTRL); -+ return (t & AR7240_MDIO_CTRL_DATA_M); -+} -+ -+static int ar7240sw_phy_write(struct ar7240sw *as, unsigned phy_addr, -+ unsigned reg_addr, u16 reg_val) -+{ -+ u32 t; -+ int ret; -+ -+ if (phy_addr >= AR7240_NUM_PHYS) -+ return -EINVAL; -+ -+ t = (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) | -+ (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) | -+ AR7240_MDIO_CTRL_MASTER_EN | -+ AR7240_MDIO_CTRL_BUSY | -+ AR7240_MDIO_CTRL_CMD_WRITE | -+ reg_val; -+ -+ ar7240sw_reg_write(as, AR7240_REG_MDIO_CTRL, t); -+ ret = ar7240sw_reg_wait(as, AR7240_REG_MDIO_CTRL, -+ AR7240_MDIO_CTRL_BUSY, 0, 5); -+ return ret; -+} -+ -+static int ar7240sw_capture_stats(struct ar7240sw *as) -+{ -+ int ret; -+ -+ /* Capture the hardware statistics for all ports */ -+ ar7240sw_reg_write(as, AR7240_REG_MIB_FUNCTION0, -+ (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S)); -+ -+ /* Wait for the capturing to complete. */ -+ ret = ar7240sw_reg_wait(as, AR7240_REG_MIB_FUNCTION0, -+ AR7240_MIB_BUSY, 0, 10); -+ return ret; -+} -+ -+static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port) -+{ -+ ar7240sw_reg_write(as, AR7240_REG_PORT_CTRL(port), -+ AR7240_PORT_CTRL_STATE_DISABLED); -+} -+ -+static int ar7240sw_reset(struct ar7240sw *as) -+{ -+ int ret; -+ int i; -+ -+ /* Set all ports to disabled state. */ -+ for (i = 0; i < AR7240_NUM_PORTS; i++) -+ ar7240sw_disable_port(as, i); -+ -+ /* Wait for transmit queues to drain. */ -+ msleep(2); -+ -+ /* Reset the switch. */ -+ ar7240sw_reg_write(as, AR7240_REG_MASK_CTRL, -+ AR7240_MASK_CTRL_SOFT_RESET); -+ -+ ret = ar7240sw_reg_wait(as, AR7240_REG_MASK_CTRL, -+ AR7240_MASK_CTRL_SOFT_RESET, 0, 1000); -+ return ret; -+} -+ -+static void ar7240sw_setup(struct ar7240sw *as) -+{ -+ /* Enable CPU port, and disable mirror port */ -+ ar7240sw_reg_write(as, AR7240_REG_CPU_PORT, -+ AR7240_CPU_PORT_EN | -+ (15 << AR7240_MIRROR_PORT_S)); -+ -+ /* Setup TAG priority mapping */ -+ ar7240sw_reg_write(as, AR7240_REG_TAG_PRIORITY, 0xfa50); -+ -+ /* Enable ARP frame acknowledge */ -+ ar7240sw_reg_set(as, AR7240_REG_AT_CTRL, AR7240_AT_CTRL_ARP_EN); -+ -+ /* Enable Broadcast frames transmitted to the CPU */ -+ ar7240sw_reg_set(as, AR7240_REG_FLOOD_MASK, -+ AR7240_FLOOD_MASK_BROAD_TO_CPU); -+ -+ /* setup MTU */ -+ ar7240sw_reg_rmw(as, AR7240_REG_GLOBAL_CTRL, AR7240_GLOBAL_CTRL_MTU_M, -+ 1536); -+ -+ /* setup Service TAG */ -+ ar7240sw_reg_rmw(as, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, -+ ETH_P_QINQ); -+} -+ -+static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port) -+{ -+ u32 ctrl; -+ u32 dest_ports; -+ u32 vlan; -+ -+ ctrl = AR7240_PORT_CTRL_STATE_FORWARD; -+ -+ if (port == AR7240_PORT_CPU) { -+ ar7240sw_reg_write(as, AR7240_REG_PORT_STATUS(port), -+ AR7240_PORT_STATUS_SPEED_1000 | -+ AR7240_PORT_STATUS_TXFLOW | -+ AR7240_PORT_STATUS_RXFLOW | -+ AR7240_PORT_STATUS_TXMAC | -+ AR7240_PORT_STATUS_RXMAC | -+ AR7240_PORT_STATUS_DUPLEX); -+ -+ /* allow the CPU port to talk to each of the 'real' ports */ -+ dest_ports = AR7240_PORT_MASK_BUT(port); -+ -+ /* remove service tag from ingress frames */ -+ ctrl |= AR7240_PORT_CTRL_DOUBLE_TAG; -+ } else { -+ ar7240sw_reg_write(as, AR7240_REG_PORT_STATUS(port), -+ AR7240_PORT_STATUS_LINK_AUTO); -+ -+ /* -+ * allow each of the 'real' ports to only talk to the CPU -+ * port. -+ */ -+ dest_ports = AR7240_PORT_MASK(port) | -+ AR7240_PORT_MASK(AR7240_PORT_CPU); -+ -+ /* add service tag to egress frames */ -+ ctrl |= (AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG << -+ AR7240_PORT_CTRL_VLAN_MODE_S); -+ } -+ -+ /* set default VID and and destination ports for this VLAN */ -+ vlan = port; -+ vlan |= (dest_ports << AR7240_PORT_VLAN_DEST_PORTS_S); -+ -+ ar7240sw_reg_write(as, AR7240_REG_PORT_CTRL(port), ctrl); -+ ar7240sw_reg_write(as, AR7240_REG_PORT_VLAN(port), vlan); -+} -+ -+static char *ar7240_dsa_probe(struct mii_bus *mii, int sw_addr) -+{ -+ struct ar7240sw as; -+ u32 ctrl; -+ u16 phy_id1; -+ u16 phy_id2; -+ u8 ver; -+ -+ ar7240sw_init(&as, mii); -+ -+ ctrl = ar7240sw_reg_read(&as, AR7240_REG_MASK_CTRL); -+ -+ ver = (ctrl >> AR7240_MASK_CTRL_VERSION_S) & AR7240_MASK_CTRL_VERSION_M; -+ if (ver != 1) { -+ pr_err("ar7240_dsa: unsupported chip, ctrl=%08x\n", ctrl); -+ return NULL; -+ } -+ -+ phy_id1 = ar7240sw_phy_read(&as, 0, MII_PHYSID1); -+ phy_id2 = ar7240sw_phy_read(&as, 0, MII_PHYSID2); -+ if (phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) { -+ pr_err("ar7240_dsa: unknown phy id '%04x:%04x'\n", -+ phy_id1, phy_id2); -+ return NULL; -+ } -+ -+ return "Atheros AR7240 built-in"; -+} -+ -+static int ar7240_dsa_setup(struct dsa_switch *ds) -+{ -+ struct ar7240sw *as = dsa_to_ar7240sw(ds); -+ int i; -+ int ret; -+ -+ ar7240sw_init(as, ds->master_mii_bus); -+ -+ ret = ar7240sw_reset(as); -+ if (ret) -+ return ret; -+ -+ ar7240sw_setup(as); -+ -+ for (i = 0; i < AR7240_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i) || (ds->phys_port_mask & (1 << i))) -+ ar7240sw_setup_port(as, i); -+ else -+ ar7240sw_disable_port(as, i); -+ } -+ -+ return 0; -+} -+ -+static int ar7240_dsa_set_addr(struct dsa_switch *ds, u8 *addr) -+{ -+ struct ar7240sw *as = dsa_to_ar7240sw(ds); -+ u32 t; -+ -+ t = (addr[4] << 8) | addr[5]; -+ ar7240sw_reg_write(as, AR7240_REG_MAC_ADDR0, t); -+ -+ t = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; -+ ar7240sw_reg_write(as, AR7240_REG_MAC_ADDR1, t); -+ -+ return 0; -+} -+ -+static int ar7240_iort_to_phy_addr(int port) -+{ -+ if (port > 0 && port < AR7240_NUM_PORTS) -+ return port - 1; -+ -+ return -EINVAL; -+} -+ -+static int ar7240_dsa_phy_read(struct dsa_switch *ds, int port, int regnum) -+{ -+ struct ar7240sw *as = dsa_to_ar7240sw(ds); -+ int phy_addr; -+ -+ phy_addr = ar7240_iort_to_phy_addr(port); -+ if (phy_addr < 0) -+ return 0xffff; -+ -+ return ar7240sw_phy_read(as, phy_addr, regnum); -+} -+ -+static int ar7240_dsa_phy_write(struct dsa_switch *ds, int port, int regnum, -+ u16 val) -+{ -+ struct ar7240sw *as = dsa_to_ar7240sw(ds); -+ int phy_addr; -+ -+ phy_addr = ar7240_iort_to_phy_addr(port); -+ if (phy_addr < 0) -+ return 0xffff; -+ -+ return ar7240sw_phy_write(as, phy_addr, regnum, val); -+} -+ -+static const char *ar7240sw_speed_str(unsigned speed) -+{ -+ switch (speed) { -+ case AR7240_PORT_STATUS_SPEED_10: -+ return "10"; -+ case AR7240_PORT_STATUS_SPEED_100: -+ return "100"; -+ case AR7240_PORT_STATUS_SPEED_1000: -+ return "1000"; -+ } -+ -+ return "????"; -+} -+ -+static void ar7240_dsa_poll_link(struct dsa_switch *ds) -+{ -+ struct ar7240sw *as = dsa_to_ar7240sw(ds); -+ int i; -+ -+ for (i = 0; i < DSA_MAX_PORTS; i++) { -+ struct net_device *dev; -+ u32 status; -+ int link; -+ unsigned speed; -+ int duplex; -+ -+ dev = ds->ports[i]; -+ if (dev == NULL) -+ continue; -+ -+ link = 0; -+ if (dev->flags & IFF_UP) { -+ status = ar7240sw_reg_read(as, -+ AR7240_REG_PORT_STATUS(i)); -+ link = !!(status & AR7240_PORT_STATUS_LINK_UP); -+ } -+ -+ if (!link) { -+ if (netif_carrier_ok(dev)) { -+ pr_info("%s: link down\n", dev->name); -+ netif_carrier_off(dev); -+ } -+ continue; -+ } -+ -+ speed = (status & AR7240_PORT_STATUS_SPEED_M); -+ duplex = (status & AR7240_PORT_STATUS_DUPLEX) ? 1 : 0; -+ if (!netif_carrier_ok(dev)) { -+ pr_info("%s: link up, %sMb/s, %s duplex", -+ dev->name, -+ ar7240sw_speed_str(speed), -+ duplex ? "full" : "half"); -+ netif_carrier_on(dev); -+ } -+ } -+} -+ -+static const struct ar7240sw_hw_stat ar7240_hw_stats[] = { -+ { "rx_broadcast" , 4, AR7240_STATS_RXBROAD, }, -+ { "rx_pause" , 4, AR7240_STATS_RXPAUSE, }, -+ { "rx_multicast" , 4, AR7240_STATS_RXMULTI, }, -+ { "rx_fcs_error" , 4, AR7240_STATS_RXFCSERR, }, -+ { "rx_align_error" , 4, AR7240_STATS_RXALIGNERR, }, -+ { "rx_undersize" , 4, AR7240_STATS_RXRUNT, }, -+ { "rx_fragments" , 4, AR7240_STATS_RXFRAGMENT, }, -+ { "rx_64bytes" , 4, AR7240_STATS_RX64BYTE, }, -+ { "rx_65_127bytes" , 4, AR7240_STATS_RX128BYTE, }, -+ { "rx_128_255bytes" , 4, AR7240_STATS_RX256BYTE, }, -+ { "rx_256_511bytes" , 4, AR7240_STATS_RX512BYTE, }, -+ { "rx_512_1023bytes" , 4, AR7240_STATS_RX1024BYTE, }, -+ { "rx_1024_1518bytes" , 4, AR7240_STATS_RX1518BYTE, }, -+ { "rx_1519_max_bytes" , 4, AR7240_STATS_RXMAXBYTE, }, -+ { "rx_oversize" , 4, AR7240_STATS_RXTOOLONG, }, -+ { "rx_good_bytes" , 8, AR7240_STATS_RXGOODBYTE, }, -+ { "rx_bad_bytes" , 8, AR7240_STATS_RXBADBYTE, }, -+ { "rx_overflow" , 4, AR7240_STATS_RXOVERFLOW, }, -+ { "filtered" , 4, AR7240_STATS_FILTERED, }, -+ { "tx_broadcast" , 4, AR7240_STATS_TXBROAD, }, -+ { "tx_pause" , 4, AR7240_STATS_TXPAUSE, }, -+ { "tx_multicast" , 4, AR7240_STATS_TXMULTI, }, -+ { "tx_underrun" , 4, AR7240_STATS_TXUNDERRUN, }, -+ { "tx_64bytes" , 4, AR7240_STATS_TX64BYTE, }, -+ { "tx_65_127bytes" , 4, AR7240_STATS_TX128BYTE, }, -+ { "tx_128_255bytes" , 4, AR7240_STATS_TX256BYTE, }, -+ { "tx_256_511bytes" , 4, AR7240_STATS_TX512BYTE, }, -+ { "tx_512_1023bytes" , 4, AR7240_STATS_TX1024BYTE, }, -+ { "tx_1024_1518bytes" , 4, AR7240_STATS_TX1518BYTE, }, -+ { "tx_1519_max_bytes" , 4, AR7240_STATS_TXMAXBYTE, }, -+ { "tx_oversize" , 4, AR7240_STATS_TXOVERSIZE, }, -+ { "tx_bytes" , 8, AR7240_STATS_TXBYTE, }, -+ { "tx_collisions" , 4, AR7240_STATS_TXCOLLISION, }, -+ { "tx_abort_collisions" , 4, AR7240_STATS_TXABORTCOL, }, -+ { "tx_multi_collisions" , 4, AR7240_STATS_TXMULTICOL, }, -+ { "tx_single_collisions", 4, AR7240_STATS_TXSINGLECOL, }, -+ { "tx_excessive_deferred", 4, AR7240_STATS_TXEXCDEFER, }, -+ { "tx_deferred" , 4, AR7240_STATS_TXDEFER, }, -+ { "tx_late_collisions" , 4, AR7240_STATS_TXLATECOL, }, -+}; -+ -+static void ar7240_dsa_get_strings(struct dsa_switch *ds, int port, -+ uint8_t *data) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(ar7240_hw_stats); i++) { -+ memcpy(data + i * ETH_GSTRING_LEN, -+ ar7240_hw_stats[i].string, ETH_GSTRING_LEN); -+ } -+} -+ -+static void ar7240_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, -+ uint64_t *data) -+{ -+ struct ar7240sw *as = dsa_to_ar7240sw(ds); -+ int err; -+ int i; -+ -+ mutex_lock(&as->stats_mutex); -+ -+ err = ar7240sw_capture_stats(as); -+ if (err) -+ goto unlock; -+ -+ for (i = 0; i < ARRAY_SIZE(ar7240_hw_stats); i++) { -+ const struct ar7240sw_hw_stat *s = &ar7240_hw_stats[i]; -+ u32 reg = AR7240_REG_STATS_BASE(port); -+ u32 low; -+ u32 high; -+ -+ low = ar7240sw_reg_read(as, reg + s->reg); -+ if (s->sizeof_stat == 8) -+ high = ar7240sw_reg_read(as, reg + s->reg); -+ else -+ high = 0; -+ -+ data[i] = (((u64) high) << 32) | low; -+ } ++struct switch_val { ++ const struct switch_attr *attr; ++ int port_vlan; ++ int len; ++ union { ++ const char *s; ++ u32 i; ++ struct switch_port *ports; ++ } value; ++}; + -+ unlock: -+ mutex_unlock(&as->stats_mutex); -+} ++struct switch_attr { ++ int disabled; ++ int type; ++ const char *name; ++ const char *description; + -+static int ar7240_dsa_get_sset_count(struct dsa_switch *ds) -+{ -+ return ARRAY_SIZE(ar7240_hw_stats); -+} ++ int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); ++ int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); + -+static struct dsa_switch_driver ar7240_dsa_driver = { -+ .tag_protocol = htons(ETH_P_QINQ), -+ .priv_size = sizeof(struct ar7240sw), -+ .probe = ar7240_dsa_probe, -+ .setup = ar7240_dsa_setup, -+ .set_addr = ar7240_dsa_set_addr, -+ .phy_read = ar7240_dsa_phy_read, -+ .phy_write = ar7240_dsa_phy_write, -+ .poll_link = ar7240_dsa_poll_link, -+ .get_strings = ar7240_dsa_get_strings, -+ .get_ethtool_stats = ar7240_dsa_get_ethtool_stats, -+ .get_sset_count = ar7240_dsa_get_sset_count, ++ /* for driver internal use */ ++ int id; ++ int ofs; ++ int max; +}; + -+int __init dsa_ar7240_init(void) -+{ -+ register_switch_driver(&ar7240_dsa_driver); -+ return 0; -+} -+module_init(dsa_ar7240_init); ++#endif + -+void __exit dsa_ar7240_cleanup(void) -+{ -+ unregister_switch_driver(&ar7240_dsa_driver); -+} -+module_exit(dsa_ar7240_cleanup); ++#endif +diff -Nur linux-2.6.39.orig/include/linux/tcp.h linux-2.6.39/include/linux/tcp.h +--- linux-2.6.39.orig/include/linux/tcp.h 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/include/linux/tcp.h 2011-08-24 18:17:24.000000000 +0200 +@@ -54,7 +54,7 @@ + __be16 window; + __sum16 check; + __be16 urg_ptr; +-}; ++} __packed; + + /* + * The union cast uses a gcc extension to avoid aliasing problems +diff -Nur linux-2.6.39.orig/include/linux/udp.h linux-2.6.39/include/linux/udp.h +--- linux-2.6.39.orig/include/linux/udp.h 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/include/linux/udp.h 2011-08-24 18:17:24.000000000 +0200 +@@ -24,7 +24,7 @@ + __be16 dest; + __be16 len; + __sum16 check; +-}; ++} __packed; + + /* UDP socket options */ + #define UDP_CORK 1 /* Never send partially complete segments */ diff -Nur linux-2.6.39.orig/net/dsa/mv88e6063.c linux-2.6.39/net/dsa/mv88e6063.c --- linux-2.6.39.orig/net/dsa/mv88e6063.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/net/dsa/mv88e6063.c 2011-05-27 14:36:51.000000000 +0200 ++++ linux-2.6.39/net/dsa/mv88e6063.c 2011-08-24 18:17:24.000000000 +0200 @@ -0,0 +1,294 @@ +/* + * net/dsa/mv88e6063.c - Driver for Marvell 88e6063 switch chips @@ -18297,134 +25229,25 @@ diff -Nur linux-2.6.39.orig/net/dsa/mv88e6063.c linux-2.6.39/net/dsa/mv88e6063.c + unregister_switch_driver(&mv88e6063_switch_driver); +} +module_exit(mv88e6063_cleanup); -diff -Nur linux-2.6.39.orig/net/dsa/tag_qinq.c linux-2.6.39/net/dsa/tag_qinq.c ---- linux-2.6.39.orig/net/dsa/tag_qinq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/net/dsa/tag_qinq.c 2011-05-27 14:36:51.000000000 +0200 -@@ -0,0 +1,127 @@ -+/* -+ * net/dsa/tag_qinq.c - QinQ tag format handling -+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org> -+ * -+ * This file was based on: -+ * net/dsa/tag_edsa.c - Ethertype DSA tagging -+ * Copyright (c) 2008-2009 Marvell Semiconductor -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include <linux/etherdevice.h> -+#include <linux/list.h> -+#include <linux/netdevice.h> -+#include <linux/if_vlan.h> -+ -+#include "dsa_priv.h" -+ -+netdev_tx_t qinq_xmit(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct dsa_slave_priv *p = netdev_priv(dev); -+ struct vlan_ethhdr *veth; -+ unsigned int len; -+ int ret; -+ -+ if (skb_cow_head(skb, VLAN_HLEN) < 0) -+ goto out_free_skb; -+ -+ veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); -+ -+ /* Move the mac addresses to the beginning of the new header. */ -+ memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN); -+ skb->mac_header -= VLAN_HLEN; -+ -+ /* setup VLAN header fields */ -+ veth->h_vlan_proto = htons(ETH_P_QINQ); -+ veth->h_vlan_TCI = htons(p->port); -+ -+ len = skb->len; -+ skb->protocol = htons(ETH_P_QINQ); -+ skb->dev = p->parent->dst->master_netdev; -+ -+ ret = dev_queue_xmit(skb); -+ if (unlikely(ret != NET_XMIT_SUCCESS)) -+ goto out_dropped; -+ -+ dev->stats.tx_packets++; -+ dev->stats.tx_bytes += len; -+ -+ return NETDEV_TX_OK; -+ -+ out_free_skb: -+ kfree_skb(skb); -+ out_dropped: -+ dev->stats.tx_dropped++; -+ return NETDEV_TX_OK; -+} -+ -+static int qinq_rcv(struct sk_buff *skb, struct net_device *dev, -+ struct packet_type *pt, struct net_device *orig_dev) -+{ -+ struct dsa_switch_tree *dst; -+ struct dsa_switch *ds; -+ struct vlan_hdr *vhdr; -+ int source_port; -+ -+ dst = dev->dsa_ptr; -+ if (unlikely(dst == NULL)) -+ goto out_drop; -+ ds = dst->ds[0]; -+ -+ skb = skb_unshare(skb, GFP_ATOMIC); -+ if (skb == NULL) -+ goto out; -+ -+ if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) -+ goto out_drop; -+ -+ vhdr = (struct vlan_hdr *)skb->data; -+ source_port = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; -+ if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) -+ goto out_drop; -+ -+ /* Remove the outermost VLAN tag and update checksum. */ -+ skb_pull_rcsum(skb, VLAN_HLEN); -+ memmove(skb->data - ETH_HLEN, -+ skb->data - ETH_HLEN - VLAN_HLEN, -+ 2 * ETH_ALEN); -+ -+ skb->dev = ds->ports[source_port]; -+ skb_push(skb, ETH_HLEN); -+ skb->pkt_type = PACKET_HOST; -+ skb->protocol = eth_type_trans(skb, skb->dev); -+ -+ skb->dev->stats.rx_packets++; -+ skb->dev->stats.rx_bytes += skb->len; -+ -+ netif_receive_skb(skb); -+ -+ return 0; -+ -+ out_drop: -+ kfree_skb(skb); -+ out: -+ return 0; -+} -+ -+static struct packet_type qinq_packet_type __read_mostly = { -+ .type = cpu_to_be16(ETH_P_QINQ), -+ .func = qinq_rcv, -+}; -+ -+static int __init qinq_init_module(void) -+{ -+ dev_add_pack(&qinq_packet_type); -+ return 0; -+} -+module_init(qinq_init_module); -+ -+static void __exit qinq_cleanup_module(void) -+{ -+ dev_remove_pack(&qinq_packet_type); -+} -+module_exit(qinq_cleanup_module); +diff -Nur linux-2.6.39.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c linux-2.6.39/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +--- linux-2.6.39.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2011-05-19 06:06:34.000000000 +0200 ++++ linux-2.6.39/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2011-08-24 18:17:24.000000000 +0200 +@@ -14,6 +14,7 @@ + #include <linux/skbuff.h> + #include <linux/icmp.h> + #include <linux/sysctl.h> ++#include <linux/unaligned/packed_struct.h> + #include <net/route.h> + #include <net/ip.h> + +@@ -44,8 +45,8 @@ + if (ap == NULL) + return false; + +- tuple->src.u3.ip = ap[0]; +- tuple->dst.u3.ip = ap[1]; ++ tuple->src.u3.ip = __get_unaligned_cpu32(ap++); ++ tuple->dst.u3.ip = __get_unaligned_cpu32(ap); + + return true; + } |