diff options
author | John Crispin <blogic@openwrt.org> | 2012-03-25 08:50:09 +0000 |
---|---|---|
committer | John Crispin <blogic@openwrt.org> | 2012-03-25 08:50:09 +0000 |
commit | 62692a5350408bf5820e43b4d68150bf8ecac2d2 (patch) | |
tree | fcbc09d1188b157091e186d10871e28abf340864 /target/linux | |
parent | 617f57c20a853957f6aa15611fff52ef410fc055 (diff) | |
download | master-187ad058-62692a5350408bf5820e43b4d68150bf8ecac2d2.tar.gz master-187ad058-62692a5350408bf5820e43b4d68150bf8ecac2d2.tar.bz2 master-187ad058-62692a5350408bf5820e43b4d68150bf8ecac2d2.zip |
[lantiq] bump kernel to 3.2.12
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@31060 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux')
135 files changed, 30640 insertions, 2275 deletions
diff --git a/target/linux/lantiq/Makefile b/target/linux/lantiq/Makefile index b0bed09dfd..10d6665442 100644 --- a/target/linux/lantiq/Makefile +++ b/target/linux/lantiq/Makefile @@ -12,7 +12,7 @@ BOARDNAME:=Lantiq GPON/XWAY FEATURES:=squashfs jffs2 DEFAULT_SUBTARGET:=danube -LINUX_VERSION:=3.1.10 +LINUX_VERSION:=3.2.12 CFLAGS=-Os -pipe -mips32r2 -mtune=mips32r2 -fno-caller-saves diff --git a/target/linux/lantiq/ar9/config-default b/target/linux/lantiq/ar9/config-default index 34192d03fc..ce21adf42e 100644 --- a/target/linux/lantiq/ar9/config-default +++ b/target/linux/lantiq/ar9/config-default @@ -1,54 +1,38 @@ CONFIG_ADM6996_PHY=y CONFIG_AR8216_PHY=y -# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set -# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -# CONFIG_ATH79 is not set -CONFIG_GENERIC_ATOMIC64=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DMA_API_DEBUG=y -CONFIG_HAVE_DMA_ATTRS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y -CONFIG_HAVE_GENERIC_HARDIRQS=y -CONFIG_HAVE_IRQ_WORK=y -CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_ATMEL_PWM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_FSNOTIFY=y +CONFIG_HAVE_MACH_CLKDEV=y CONFIG_HW_HAS_PCI=y CONFIG_INPUT=y CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_GPIO_BUTTONS is not set CONFIG_INPUT_POLLDEV=y +CONFIG_IRQ_FORCED_THREADING=y # CONFIG_ISDN is not set CONFIG_LANTIQ_ETOP=y -# CONFIG_LANTIQ_MACH_ARV45XX is not set +# CONFIG_LANTIQ_MACH_ARV is not set # CONFIG_LANTIQ_MACH_EASY50712 is not set +CONFIG_LANTIQ_MACH_FRITZ_AR9=y +# CONFIG_LANTIQ_MACH_FRITZ_VR9 is not set +# CONFIG_LANTIQ_MACH_GIGASX76X is not set CONFIG_LANTIQ_MACH_NETGEAR=y CONFIG_LANTIQ_MACH_WBMR=y -# CONFIG_LANTIQ_MACH_GIGASX76X is not set -CONFIG_MACH_NO_WESTBRIDGE=y -# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_NEED_PER_CPU_KM=y +# CONFIG_LANTIQ_VRX200 is not set +CONFIG_MDIO_BOARDINFO=y +# CONFIG_MLX4_CORE is not set +CONFIG_MTD_BLOCK2MTD=y CONFIG_PCI=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_LANTIQ is not set CONFIG_PCI_DOMAINS=y -CONFIG_PERF_USE_VMALLOC=y -# CONFIG_PREEMPT_RCU is not set -# CONFIG_QUOTACTL is not set +CONFIG_PCI_LANTIQ=y +# CONFIG_PCI_LANTIQ_NONE is not set CONFIG_RTL8306_PHY=y # CONFIG_SOC_AMAZON_SE is not set -# CONFIG_SOC_VR9 is not set # CONFIG_SOC_FALCON is not set CONFIG_SOC_TYPE_XWAY=y CONFIG_SOC_XWAY=y -CONFIG_SPI=y -CONFIG_SPI_BITBANG=y -# CONFIG_SPI_GPIO is not set -CONFIG_SPI_LANTIQ=y -CONFIG_SPI_MASTER=y +CONFIG_USB_ARCH_HAS_XHCI=y CONFIG_USB_SUPPORT=y -CONFIG_XZ_DEC=y -CONFIG_SPI_XWAY=y diff --git a/target/linux/lantiq/ar9/profiles/001-lantiq.mk b/target/linux/lantiq/ar9/profiles/001-lantiq.mk index 2039738ea9..a1fc2d24b2 100644 --- a/target/linux/lantiq/ar9/profiles/001-lantiq.mk +++ b/target/linux/lantiq/ar9/profiles/001-lantiq.mk @@ -1,5 +1,5 @@ define Profile/EASY50812 - NAME:=EASY50812 + NAME:=EASY50812 - Eval Board PACKAGES:= kmod-usb-core kmod-usb-dwc-otg endef diff --git a/target/linux/lantiq/ar9/profiles/002-netgear.mk b/target/linux/lantiq/ar9/profiles/002-netgear.mk index 1a77786255..a3c83bbcd2 100644 --- a/target/linux/lantiq/ar9/profiles/002-netgear.mk +++ b/target/linux/lantiq/ar9/profiles/002-netgear.mk @@ -1,5 +1,5 @@ define Profile/DGN3500B - NAME:=DGN3500B + NAME:=DGN3500B Netgear PACKAGES:= kmod-usb-core kmod-usb-dwc-otg endef diff --git a/target/linux/lantiq/ar9/profiles/004-avm.mk b/target/linux/lantiq/ar9/profiles/004-avm.mk new file mode 100644 index 0000000000..e424d6aaa7 --- /dev/null +++ b/target/linux/lantiq/ar9/profiles/004-avm.mk @@ -0,0 +1,7 @@ +define Profile/FRITZ7320 + NAME:=FRITZ7320 Fritzbox + PACKAGES:= kmod-usb-core kmod-usb-ifxhcd kmod-ledtrig-usbdev \ + kmod-ltq-dsl-firmware-b-ar9 kmod-ath9k wpad-mini +endef + +$(eval $(call Profile,FRITZ7320)) diff --git a/target/linux/lantiq/ase/config-default b/target/linux/lantiq/ase/config-default index a6c8a3d00f..8d2597d430 100644 --- a/target/linux/lantiq/ase/config-default +++ b/target/linux/lantiq/ase/config-default @@ -1,39 +1,22 @@ -# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set -# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -# CONFIG_ATH79 is not set -CONFIG_GENERIC_ATOMIC64=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DMA_API_DEBUG=y -CONFIG_HAVE_DMA_ATTRS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y -CONFIG_HAVE_GENERIC_HARDIRQS=y -CONFIG_HAVE_IRQ_WORK=y -CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_ATMEL_PWM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_FSNOTIFY=y +CONFIG_HAVE_MACH_CLKDEV=y CONFIG_INPUT=y CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_GPIO_BUTTONS is not set CONFIG_INPUT_POLLDEV=y +CONFIG_IRQ_FORCED_THREADING=y # CONFIG_ISDN is not set CONFIG_LANTIQ_ETOP=y CONFIG_LANTIQ_MACH_EASY50601=y -CONFIG_MACH_NO_WESTBRIDGE=y -# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set -# CONFIG_MTD_LATCH_ADDR is not set -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_NEED_PER_CPU_KM=y -CONFIG_PERF_USE_VMALLOC=y -# CONFIG_PREEMPT_RCU is not set -# CONFIG_QUOTACTL is not set +# CONFIG_LANTIQ_VRX200 is not set +CONFIG_MDIO_BOARDINFO=y CONFIG_SOC_AMAZON_SE=y -# CONFIG_SOC_VR9 is not set # CONFIG_SOC_FALCON is not set CONFIG_SOC_TYPE_XWAY=y # CONFIG_SOC_XWAY is not set -CONFIG_XZ_DEC=y -CONFIG_SPI_XWAY=y +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y diff --git a/target/linux/lantiq/config-default b/target/linux/lantiq/config-3.2 index d4e90c9b9a..d4e90c9b9a 100644 --- a/target/linux/lantiq/config-default +++ b/target/linux/lantiq/config-3.2 diff --git a/target/linux/lantiq/danube/config-default b/target/linux/lantiq/danube/config-default index 508706d812..ff04f3c70f 100644 --- a/target/linux/lantiq/danube/config-default +++ b/target/linux/lantiq/danube/config-default @@ -1,54 +1,37 @@ CONFIG_ADM6996_PHY=y CONFIG_AR8216_PHY=y -# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set -# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -# CONFIG_ATH79 is not set -CONFIG_GENERIC_ATOMIC64=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DMA_API_DEBUG=y -CONFIG_HAVE_DMA_ATTRS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y -CONFIG_HAVE_GENERIC_HARDIRQS=y -CONFIG_HAVE_IRQ_WORK=y -CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_ATMEL_PWM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_FSNOTIFY=y +CONFIG_HAVE_MACH_CLKDEV=y CONFIG_HW_HAS_PCI=y CONFIG_INPUT=y CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_GPIO_BUTTONS is not set CONFIG_INPUT_POLLDEV=y +CONFIG_IRQ_FORCED_THREADING=y # CONFIG_ISDN is not set CONFIG_LANTIQ_ETOP=y -CONFIG_LANTIQ_MACH_ARV45XX=y +CONFIG_LANTIQ_MACH_ARV=y CONFIG_LANTIQ_MACH_EASY50712=y +# CONFIG_LANTIQ_MACH_FRITZ_AR9 is not set +# CONFIG_LANTIQ_MACH_FRITZ_VR9 is not set +CONFIG_LANTIQ_MACH_GIGASX76X=y # CONFIG_LANTIQ_MACH_NETGEAR is not set # CONFIG_LANTIQ_MACH_WBMR is not set -CONFIG_LANTIQ_MACH_GIGASX76X=y -CONFIG_MACH_NO_WESTBRIDGE=y -# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_NEED_PER_CPU_KM=y +# CONFIG_LANTIQ_VRX200 is not set +CONFIG_MDIO_BOARDINFO=y +# CONFIG_MLX4_CORE is not set CONFIG_PCI=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_LANTIQ is not set CONFIG_PCI_DOMAINS=y -CONFIG_PERF_USE_VMALLOC=y -# CONFIG_PREEMPT_RCU is not set -# CONFIG_QUOTACTL is not set +CONFIG_PCI_LANTIQ=y +# CONFIG_PCI_LANTIQ_NONE is not set CONFIG_RTL8306_PHY=y # CONFIG_SOC_AMAZON_SE is not set # CONFIG_SOC_FALCON is not set -# CONFIG_SOC_VR9 is not set CONFIG_SOC_TYPE_XWAY=y CONFIG_SOC_XWAY=y -CONFIG_SPI=y -CONFIG_SPI_BITBANG=y -# CONFIG_SPI_GPIO is not set -CONFIG_SPI_LANTIQ=y -CONFIG_SPI_MASTER=y +CONFIG_USB_ARCH_HAS_XHCI=y CONFIG_USB_SUPPORT=y -CONFIG_XZ_DEC=y -CONFIG_SPI_XWAY=y diff --git a/target/linux/lantiq/danube/profiles/004-bt.mk b/target/linux/lantiq/danube/profiles/004-bt.mk new file mode 100644 index 0000000000..26dd93c4b7 --- /dev/null +++ b/target/linux/lantiq/danube/profiles/004-bt.mk @@ -0,0 +1,23 @@ +define Profile/BTHOMEHUBV2B + NAME:=BTHOMEHUBV2B - BT Homehub V2.0 Type B + PACKAGES:= kmod-usb-core kmod-usb-dwc-otg kmod-ledtrig-usbdev \ + kmod-ath9k wpad-mini kmod-ltq-dsl-firmware-a-danube +endef + +define Profile/BTHOMEHUBV2B/Description + Package set optimized for the BT Homehub V2.0 Type B using whole nand for OpenWRT +endef + +$(eval $(call Profile,BTHOMEHUBV2B)) + +define Profile/BTHOMEHUBV2BOPENRG + NAME:=BTHOMEHUBV2B - BT Homehub V2.0 Type B (OpenRG) + PACKAGES:= kmod-usb-core kmod-usb-dwc-otg kmod-ledtrig-usbdev \ + kmod-ath9k wpad-mini kmod-ltq-dsl-firmware-a-danube +endef + +define Profile/BTHOMEHUBV2BOPENRG/Description + Package set optimized for the BT Homehub V2.0 Type B but retaining OpenRG image +endef + +$(eval $(call Profile,BTHOMEHUBV2BOPENRG)) diff --git a/target/linux/lantiq/falcon/config-default b/target/linux/lantiq/falcon/config-default index f1d6e482e2..e1210e14b8 100644 --- a/target/linux/lantiq/falcon/config-default +++ b/target/linux/lantiq/falcon/config-default @@ -1,28 +1,20 @@ -CONFIG_CPU_MIPSR2_IRQ_EI=y -CONFIG_CPU_MIPSR2_IRQ_VI=y -CONFIG_IFX_VPE_CACHE_SPLIT=y -CONFIG_IFX_VPE_EXT=y +# CONFIG_ATMEL_PWM is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_FSNOTIFY=y +CONFIG_HAVE_MACH_CLKDEV=y +CONFIG_IRQ_FORCED_THREADING=y CONFIG_M25PXX_USE_FAST_READ=y -CONFIG_MIPS_MT=y -# CONFIG_MIPS_VPE_APSP_API is not set -CONFIG_MIPS_VPE_LOADER=y -CONFIG_MIPS_VPE_LOADER_TOM=y CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND_PLATFORM=y # CONFIG_MTD_SM_COMMON is not set -CONFIG_MTSCHED=y -# CONFIG_PERFCTRS is not set # CONFIG_SOC_AMAZON_SE is not set CONFIG_SOC_FALCON=y # CONFIG_SOC_TYPE_XWAY is not set # CONFIG_SOC_XWAY is not set -# CONFIG_SOC_VR9 is not set CONFIG_SPI=y # CONFIG_SPI_BITBANG is not set CONFIG_SPI_FALCON=y # CONFIG_SPI_GPIO is not set CONFIG_SPI_MASTER=y -# CONFIG_I2C_DESIGNWARE is not set - diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-fritz.c b/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-fritz.c deleted file mode 100644 index 9b542425c8..0000000000 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-fritz.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 John Crispin <blogic@openwrt.org> - */ - -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/physmap.h> -#include <linux/input.h> -#include <linux/phy.h> - -#include <lantiq_soc.h> -#include <irq.h> - -#include "../machtypes.h" -#include "devices.h" - -/*static struct mtd_partition fritz3370_partitions[] = { - { - .name = "uboot", - .offset = 0x0, - .size = 0x10000, - }, - { - .name = "uboot_env", - .offset = 0x10000, - .size = 0x10000, - }, - { - .name = "linux", - .offset = 0x20000, - .size = 0xe0000, - }, - { - .name = "rootfs", - .offset = 0x100000, - .size = 0x300000, - }, -}; - -static struct physmap_flash_data fritz3370_flash_data = { - .nr_parts = ARRAY_SIZE(fritz3370_partitions), - .parts = fritz3370_partitions, -}; - -static struct ltq_pci_data ltq_pci_data = { - .clock = PCI_CLOCK_INT, - .gpio = PCI_GNT1 | PCI_REQ1, - .irq = { - [14] = INT_NUM_IM0_IRL0 + 22, - }, -}; -*/ -static struct ltq_eth_data ltq_eth_data = { - .mii_mode = PHY_INTERFACE_MODE_MII, -}; - -extern void xway_register_nand(void); - -static void __init fritz3370_init(void) -{ -// ltq_register_gpio_stp(); -// ltq_register_nor(&fritz3370_flash_data); -// ltq_register_pci(<q_pci_data); - ltq_register_etop(<q_eth_data); - xway_register_nand(); -} - -MIPS_MACHINE(LANTIQ_MACH_FRITZ3370, - "FRITZ3370", - "FRITZ!BOX 3370", - fritz3370_init); diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-gigasx76x.c b/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-gigasx76x.c deleted file mode 100644 index 3dbfcb94d4..0000000000 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-gigasx76x.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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) 2011 Andrej VlaÅ¡ić - * Copyright (C) 2011 Luka Perkov - * - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/gpio.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/physmap.h> -#include <linux/input.h> -#include <linux/ath5k_platform.h> -#include <linux/pci.h> -#include <linux/phy.h> -#include <linux/io.h> -#include <linux/string.h> - -#include <irq.h> -#include <lantiq_soc.h> -#include <lantiq_platform.h> -#include <dev-gpio-leds.h> -#include <dev-gpio-buttons.h> - -#include "../machtypes.h" -#include "dev-wifi-ath5k.h" -#include "devices.h" -#include "dev-dwc_otg.h" - -#include "mach-gigasx76x.h" - -#define UBOOT_ENV_OFFSET 0x010000 -#define UBOOT_ENV_SIZE 0x010000 - -static struct mtd_partition gigasx76x_partitions[] = -{ - { - .name = "uboot", - .offset = 0x000000, - .size = 0x010000, - }, - { - .name = "uboot_env", - .offset = UBOOT_ENV_OFFSET, - .size = UBOOT_ENV_SIZE, - }, - { - .name = "linux", - .offset = 0x020000, - .size = 0x7e0000, - }, -}; - -static struct gpio_led -gigasx76x_gpio_leds[] __initdata = { - { .name = "soc:green:voip", .gpio = 216, }, - { .name = "soc:green:adsl", .gpio = 217, }, - { .name = "soc:green:usb", .gpio = 218, }, - { .name = "soc:green:wifi", .gpio = 219, }, - { .name = "soc:green:phone2", .gpio = 220, }, - { .name = "soc:green:phone1", .gpio = 221, }, - { .name = "soc:green:line", .gpio = 222, }, - { .name = "soc:green:online", .gpio = 223, }, -}; - -static struct gpio_keys_button -gigasx76x_gpio_keys[] __initdata = { - { - .desc = "wps", - .type = EV_KEY, - .code = KEY_WPS_BUTTON, - .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, - .gpio = 22, - .active_low = 1, - }, - { - .desc = "reset", - .type = EV_KEY, - .code = BTN_0, - .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, - .gpio = 14, - .active_low = 0, - }, -}; - -static struct physmap_flash_data gigasx76x_flash_data = { - .nr_parts = ARRAY_SIZE(gigasx76x_partitions), - .parts = gigasx76x_partitions, -}; - -static struct ltq_pci_data ltq_pci_data = { - .clock = PCI_CLOCK_INT, - .gpio = PCI_GNT1 | PCI_REQ1, - .irq = { [14] = INT_NUM_IM0_IRL0 + 22, }, -}; - -static struct ltq_eth_data ltq_eth_data = { - .mii_mode = PHY_INTERFACE_MODE_MII, -}; - -static char __init *get_uboot_env_var(char *haystack, int haystack_len, char *needle, int needle_len) { - int i; - for (i = 0; i <= haystack_len - needle_len; i++) { - if (memcmp(haystack + i, needle, needle_len) == 0) { - return haystack + i + needle_len; - } - } - return NULL; -} - -/* - * gigasx76x_parse_hex_* are not uniq. in arm/orion there are also duplicates: - * dns323_parse_hex_* - * TODO: one day write a patch for this :) - */ -static int __init gigasx76x_parse_hex_nibble(char n) { - if (n >= '0' && n <= '9') - return n - '0'; - - if (n >= 'A' && n <= 'F') - return n - 'A' + 10; - - if (n >= 'a' && n <= 'f') - return n - 'a' + 10; - - return -1; -} - -static int __init gigasx76x_parse_hex_byte(const char *b) { - int hi; - int lo; - - hi = gigasx76x_parse_hex_nibble(b[0]); - lo = gigasx76x_parse_hex_nibble(b[1]); - - if (hi < 0 || lo < 0) - return -1; - - return (hi << 4) | lo; -} - -static u16 gigasx76x_ath5k_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]; -static u8 gigasx76x_ath5k_eeprom_mac[6]; - -static int __init gigasx76x_register_ethernet(void) { - u_int8_t addr[6]; - int i; - char *uboot_env_page; - char *mac; - char *boardid; - - uboot_env_page = ioremap(LTQ_FLASH_START + UBOOT_ENV_OFFSET, UBOOT_ENV_SIZE); - if (!uboot_env_page) - return -ENOMEM; - - mac = get_uboot_env_var(uboot_env_page, UBOOT_ENV_SIZE, "\0ethaddr=", 9); - boardid = get_uboot_env_var(uboot_env_page, UBOOT_ENV_SIZE, "\0boardid=", 9); - - if (!mac) { - goto error_fail; - } - - if (!boardid) { - goto error_fail; - } - - /* Sanity check the string we're looking at */ - for (i = 0; i < 5; i++) { - if (*(mac + (i * 3) + 2) != ':') { - goto error_fail; - } - } - - for (i = 0; i < 6; i++) { - int byte; - byte = gigasx76x_parse_hex_byte(mac + (i * 3)); - if (byte < 0) { - goto error_fail; - } - addr[i] = byte; - } - - iounmap(uboot_env_page); - printk("GIGASX76X: Found ethernet MAC address: "); - for (i = 0; i < 6; i++) - printk("%.2x%s", addr[i], (i < 5) ? ":" : ".\n"); - - memcpy(<q_eth_data.mac.sa_data, addr, 6); - ltq_register_etop(<q_eth_data); - - memcpy(&gigasx76x_ath5k_eeprom_mac, addr, 6); - gigasx76x_ath5k_eeprom_mac[5]++; - - if (strncmp(boardid, "sx763", 5) == 0) { - printk("GIGASX76X: Board id is sx763."); - memcpy(&gigasx76x_ath5k_eeprom_data, sx763_eeprom_data, ATH5K_PLAT_EEP_MAX_WORDS); - } else if (strncmp(boardid, "sx762", 5) == 0) { - printk("GIGASX76X: Board id is sx762."); - memcpy(&gigasx76x_ath5k_eeprom_data, sx762_eeprom_data, ATH5K_PLAT_EEP_MAX_WORDS); - } else { - printk("GIGASX76X: Board id is unknown, fix uboot_env data."); - } - - return 0; - - error_fail: - iounmap(uboot_env_page); - return -EINVAL; -} - -static void __init gigasx76x_init(void) { -#define GIGASX76X_USB 29 -#define GIGASX76X_MADWIFI_ADDR 0xb07f0000 - - ltq_register_gpio_stp(); - ltq_register_nor(&gigasx76x_flash_data); - ltq_register_pci(<q_pci_data); - ltq_register_tapi(); - ltq_add_device_gpio_leds(-1, ARRAY_SIZE(gigasx76x_gpio_leds), gigasx76x_gpio_leds); - ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, ARRAY_SIZE(gigasx76x_gpio_keys), gigasx76x_gpio_keys); - ltq_register_ath5k(gigasx76x_ath5k_eeprom_data, gigasx76x_ath5k_eeprom_mac); - xway_register_dwc(GIGASX76X_USB); - gigasx76x_register_ethernet(); -} - -MIPS_MACHINE(LANTIQ_MACH_GIGASX76X, "GIGASX76X", "GIGASX76X - Gigaset SX761,SX762,SX763", gigasx76x_init); diff --git a/target/linux/lantiq/files-3.1/arch/mips/include/asm/mach-lantiq/dev-gpio-buttons.h b/target/linux/lantiq/files-3.2/arch/mips/include/asm/mach-lantiq/dev-gpio-buttons.h index adb531c39b..adb531c39b 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/include/asm/mach-lantiq/dev-gpio-buttons.h +++ b/target/linux/lantiq/files-3.2/arch/mips/include/asm/mach-lantiq/dev-gpio-buttons.h diff --git a/target/linux/lantiq/files-3.1/arch/mips/include/asm/mach-lantiq/dev-gpio-leds.h b/target/linux/lantiq/files-3.2/arch/mips/include/asm/mach-lantiq/dev-gpio-leds.h index d51e496d14..d51e496d14 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/include/asm/mach-lantiq/dev-gpio-leds.h +++ b/target/linux/lantiq/files-3.2/arch/mips/include/asm/mach-lantiq/dev-gpio-leds.h diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/dev-gpio-buttons.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/dev-gpio-buttons.c index ad25cac797..ad25cac797 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/dev-gpio-buttons.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/dev-gpio-buttons.c diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/dev-gpio-leds.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/dev-gpio-leds.c index 89dc79de61..89dc79de61 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/dev-gpio-leds.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/dev-gpio-leds.c diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/addon-easy98000.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/addon-easy98000.c index 2085a1c77d..317ee4001b 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/addon-easy98000.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/addon-easy98000.c @@ -10,6 +10,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/version.h> #include <linux/types.h> #include <linux/init.h> diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.c index d02d2617e0..94622cfda8 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/module.h> #include <linux/errno.h> #include <linux/leds.h> #include <linux/slab.h> diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.h b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.h index 3160189fe9..3160189fe9 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.h +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.h diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/mach-95C3AM1.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/mach-95C3AM1.c index 42a3344ae9..42a3344ae9 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/mach-95C3AM1.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/mach-95C3AM1.c diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/mach-easy98020.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/mach-easy98020.c index 4cdfc199db..4cdfc199db 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/falcon/mach-easy98020.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/falcon/mach-easy98020.c diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-dwc_otg.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-dwc_otg.c index 90b63fc72d..90b63fc72d 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-dwc_otg.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-dwc_otg.c diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-dwc_otg.h b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-dwc_otg.h index 521fad05ef..521fad05ef 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-dwc_otg.h +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-dwc_otg.h diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-wifi-ath5k.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-wifi-ath5k.c index 14fd5113db..14fd5113db 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-wifi-ath5k.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-wifi-ath5k.c diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-wifi-ath5k.h b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-wifi-ath5k.h index 37f6e411f2..37f6e411f2 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-wifi-ath5k.h +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-wifi-ath5k.h diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-wifi-rt2x00.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-wifi-rt2x00.c index 94932df785..94932df785 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-wifi-rt2x00.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-wifi-rt2x00.c diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-wifi-rt2x00.h b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-wifi-rt2x00.h index 060ca50270..060ca50270 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/dev-wifi-rt2x00.h +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/dev-wifi-rt2x00.h diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-arv45xx.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-arv.c index 9be1a5fb93..9cc90fe312 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-arv45xx.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-arv.c @@ -17,6 +17,7 @@ #include <linux/input.h> #include <linux/etherdevice.h> #include <linux/ath5k_platform.h> +#include <linux/ath9k_platform.h> #include <linux/pci.h> #include <lantiq_soc.h> @@ -26,57 +27,10 @@ #include "../machtypes.h" #include "dev-wifi-rt2x00.h" -#include "dev-wifi-ath5k.h" +#include "dev-wifi-athxk.h" #include "devices.h" #include "dev-dwc_otg.h" - -static struct mtd_partition arv4510_partitions[] = -{ - { - .name = "uboot", - .offset = 0x0, - .size = 0x20000, - }, - { - .name = "uboot_env", - .offset = 0x20000, - .size = 0x120000, - }, - { - .name = "linux", - .offset = 0x40000, - .size = 0xfa0000, - }, - { - .name = "board_config", - .offset = 0xfe0000, - .size = 0x20000, - }, -}; - -static struct mtd_partition arv45xx_partitions[] = -{ - { - .name = "uboot", - .offset = 0x0, - .size = 0x20000, - }, - { - .name = "uboot_env", - .offset = 0x20000, - .size = 0x10000, - }, - { - .name = "linux", - .offset = 0x30000, - .size = 0x3c0000, - }, - { - .name = "board_config", - .offset = 0x3f0000, - .size = 0x10000, - }, -}; +#include "pci-ath-fixup.h" static struct mtd_partition arv45xx_brnboot_partitions[] = { @@ -107,79 +61,110 @@ static struct mtd_partition arv45xx_brnboot_partitions[] = }, }; -static struct mtd_partition arv7525_partitions[] = +static struct mtd_partition arv75xx_brnboot_partitions[] = { { - .name = "uboot", + .name = "brn-boot", .offset = 0x0, - .size = 0x10000, + .size = 0x20000, }, { - .name = "uboot_env", - .offset = 0x10000, - .size = 0x10000, + .name = "config", + .offset = 0x20000, + .size = 0x40000, }, { .name = "linux", - .offset = 0x20000, - .size = 0x3d0000, + .offset = 0x440000, + .size = 0x3a0000, + }, + { + .name = "reserved", /* 12-byte signature at 0x7efff4 :/ */ + .offset = 0x7e0000, + .size = 0x010000, }, { .name = "board_config", - .offset = 0x3f0000, + .offset = 0x7f0000, .size = 0x10000, }, }; -static struct mtd_partition arv75xx_partitions[] = +/* + * this is generic configuration for all arv based boards, note that it can be + * rewriten in arv_load_nor() + */ +static struct mtd_partition arv_partitions[] = { { .name = "uboot", .offset = 0x0, - .size = 0x10000, + .size = 0x20000, }, { .name = "uboot_env", - .offset = 0x10000, + .offset = 0x20000, .size = 0x10000, }, { .name = "linux", - .offset = 0x20000, - .size = 0x7d0000, + .offset = 0x30000, + .size = 0x3c0000, }, { .name = "board_config", - .offset = 0x7f0000, + .offset = 0x3f0000, .size = 0x10000, }, }; -static struct physmap_flash_data arv4510_flash_data = { - .nr_parts = ARRAY_SIZE(arv4510_partitions), - .parts = arv4510_partitions, -}; - -static struct physmap_flash_data arv45xx_flash_data = { - .nr_parts = ARRAY_SIZE(arv45xx_partitions), - .parts = arv45xx_partitions, -}; - static struct physmap_flash_data arv45xx_brnboot_flash_data = { .nr_parts = ARRAY_SIZE(arv45xx_brnboot_partitions), .parts = arv45xx_brnboot_partitions, }; -static struct physmap_flash_data arv7525_flash_data = { - .nr_parts = ARRAY_SIZE(arv7525_partitions), - .parts = arv7525_partitions, +static struct physmap_flash_data arv75xx_brnboot_flash_data = { + .nr_parts = ARRAY_SIZE(arv75xx_brnboot_partitions), + .parts = arv75xx_brnboot_partitions, }; -static struct physmap_flash_data arv75xx_flash_data = { - .nr_parts = ARRAY_SIZE(arv75xx_partitions), - .parts = arv75xx_partitions, +static struct physmap_flash_data arv_flash_data = { + .nr_parts = ARRAY_SIZE(arv_partitions), + .parts = arv_partitions, }; +static void arv_load_nor(unsigned int max) +{ +#define UBOOT_MAGIC 0x27051956 + + int i; + int sector = -1; + + if (ltq_brn_boot) { + if (max == 0x800000) + ltq_register_nor(&arv75xx_brnboot_flash_data); + else + ltq_register_nor(&arv45xx_brnboot_flash_data); + return; + } + + for (i = 1; i < 4 && sector < 0; i++) { + unsigned int uboot_magic; + memcpy_fromio(&uboot_magic, (void *)KSEG1ADDR(LTQ_FLASH_START) + (i * 0x10000), 4); + if (uboot_magic == UBOOT_MAGIC) + sector = i; + } + + if (sector < 0) + return; + + arv_partitions[0].size = arv_partitions[1].offset = (sector - 1) * 0x10000; + arv_partitions[2].offset = arv_partitions[0].size + 0x10000; + arv_partitions[2].size = max - arv_partitions[2].offset - 0x10000; + arv_partitions[3].offset = max - 0x10000; + ltq_register_nor(&arv_flash_data); +} + static struct ltq_pci_data ltq_pci_data = { .clock = PCI_CLOCK_EXT, .gpio = PCI_GNT1 | PCI_REQ1, @@ -241,6 +226,45 @@ arv4518pw_gpio_keys[] __initdata = { }; static struct gpio_led +arv4519pw_gpio_leds[] __initdata = { + { .name = "soc:red:power", .gpio = 7, .active_low = 1, }, + { .name = "soc:green:power", .gpio = 2, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:wifi", .gpio = 6, .active_low = 1, }, + { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, }, + { .name = "soc:green:internet", .gpio = 5, .active_low = 1, }, + { .name = "soc:red:internet", .gpio = 8, .active_low = 1, }, + { .name = "soc:green:voip", .gpio = 100, .active_low = 1, }, + { .name = "soc:green:phone1", .gpio = 101, .active_low = 1, }, + { .name = "soc:green:phone2", .gpio = 102, .active_low = 1, }, + { .name = "soc:green:fxo", .gpio = 103, .active_low = 1, }, + { .name = "soc:green:usb", .gpio = 19, .active_low = 1, }, + { .name = "soc:orange:wps", .gpio = 104, .active_low = 1, }, + { .name = "soc:green:wps", .gpio = 105, .active_low = 1, }, + { .name = "soc:red:wps", .gpio = 106, .active_low = 1, }, + +}; + +static struct gpio_keys_button +arv4519pw_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = BTN_1, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 30, + .active_low = 1, + }, + { + .desc = "wlan", + .type = EV_KEY, + .code = BTN_2, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 28, + .active_low = 1, + }, +}; + +static struct gpio_led arv4520pw_gpio_leds[] __initdata = { { .name = "soc:blue:power", .gpio = 3, .active_low = 1, }, { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, }, @@ -285,8 +309,8 @@ arv4525pw_gpio_leds[] __initdata = { { .name = "soc:green:fxs-festnetz", .gpio = 4, .active_low = 1, .default_trigger = "default-on" }, }; -#define ARV4525PW_PHYRESET 13 -#define ARV4525PW_RELAY 31 +#define ARV4525PW_PHYRESET 13 +#define ARV4525PW_RELAY 31 static struct gpio arv4525pw_gpios[] __initdata = { { ARV4525PW_PHYRESET, GPIOF_OUT_INIT_HIGH, "phyreset" }, @@ -332,39 +356,48 @@ arv752dpw22_gpio_keys[] __initdata = { .active_low = 1, }, { - .desc = "btn2", - .type = EV_KEY, - .code = BTN_2, + .desc = "btn2", + .type = EV_KEY, + .code = BTN_2, .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, - .gpio = 28, - .active_low = 1, + .gpio = 28, + .active_low = 1, }, }; static struct gpio_led arv7518pw_gpio_leds[] __initdata = { - { .name = "soc:green:power", .gpio = 2, .active_low = 1, }, + { .name = "soc:red:power", .gpio = 7, .active_low = 1, }, + { .name = "soc:green:power", .gpio = 2, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:wifi", .gpio = 6, .active_low = 1, }, { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, }, { .name = "soc:green:internet", .gpio = 5, .active_low = 1, }, - { .name = "soc:green:wifi", .gpio = 6, .active_low = 1, }, { .name = "soc:red:internet", .gpio = 8, .active_low = 1, }, + { .name = "soc:green:voip", .gpio = 100, .active_low = 1, }, + { .name = "soc:green:phone1", .gpio = 101, .active_low = 1, }, + { .name = "soc:green:phone2", .gpio = 102, .active_low = 1, }, + { .name = "soc:orange:fail", .gpio = 103, .active_low = 1, }, { .name = "soc:green:usb", .gpio = 19, .active_low = 1, }, + { .name = "soc:orange:wps", .gpio = 104, .active_low = 1, }, + { .name = "soc:green:wps", .gpio = 105, .active_low = 1, }, + { .name = "soc:red:wps", .gpio = 106, .active_low = 1, }, + }; static struct gpio_keys_button arv7518pw_gpio_keys[] __initdata = { - { + /*{ .desc = "reset", .type = EV_KEY, - .code = BTN_0, + .code = BTN_1, .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, .gpio = 23, .active_low = 1, - }, + },*/ { .desc = "wifi", .type = EV_KEY, - .code = BTN_1, + .code = BTN_2, .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, .gpio = 25, .active_low = 1, @@ -384,70 +417,75 @@ arv7525pw_gpio_keys[] __initdata = { }; static void -arv45xx_register_ethernet(void) +arv_register_ethernet(unsigned int mac_addr) { -#define ARV45XX_BRN_MAC 0x3f0016 memcpy_fromio(<q_eth_data.mac.sa_data, - (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6); + (void *)KSEG1ADDR(LTQ_FLASH_START + mac_addr), 6); ltq_register_etop(<q_eth_data); } -static void -arv75xx_register_ethernet(void) -{ -#define ARV75XX_BRN_MAC 0x7f0016 - memcpy_fromio(<q_eth_data.mac.sa_data, - (void *)KSEG1ADDR(LTQ_FLASH_START + ARV75XX_BRN_MAC), 6); - ltq_register_etop(<q_eth_data); -} - -static void -bewan_register_ethernet(void) -{ -#define BEWAN_BRN_MAC 0x3f0014 - memcpy_fromio(<q_eth_data.mac.sa_data, - (void *)KSEG1ADDR(LTQ_FLASH_START + BEWAN_BRN_MAC), 6); - ltq_register_etop(<q_eth_data); -} - -static u16 arv45xx_ath5k_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]; -static u8 arv45xx_ath5k_eeprom_mac[6]; +static u16 arv_ath5k_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]; +static u16 arv_ath9k_eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; +static u8 arv_athxk_eeprom_mac[6]; void __init -arv45xx_register_ath5k(void) +arv_register_ath5k(unsigned int ath_addr, unsigned int mac_addr) { -#define ARV45XX_BRN_ATH 0x3f0478 int i; - static u16 eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]; - u32 *p = (u32*)arv45xx_ath5k_eeprom_data; - - memcpy_fromio(arv45xx_ath5k_eeprom_mac, - (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6); - arv45xx_ath5k_eeprom_mac[5]++; - memcpy_fromio(arv45xx_ath5k_eeprom_data, - (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_ATH), ATH5K_PLAT_EEP_MAX_WORDS); + + memcpy_fromio(arv_athxk_eeprom_mac, + (void *)KSEG1ADDR(LTQ_FLASH_START + mac_addr), 6); + arv_athxk_eeprom_mac[5]++; + memcpy_fromio(arv_ath5k_eeprom_data, + (void *)KSEG1ADDR(LTQ_FLASH_START + ath_addr), ATH5K_PLAT_EEP_MAX_WORDS); // swap eeprom bytes - for (i = 0; i < ATH5K_PLAT_EEP_MAX_WORDS>>1; i++){ - //arv4518_ath5k_eeprom_data[i] = ((eeprom_data[i]&0xff)<<8)|((eeprom_data[i]&0xff00)>>8); - p[i] = ((eeprom_data[(i<<1)+1]&0xff)<<24)|((eeprom_data[(i<<1)+1]&0xff00)<<8)|((eeprom_data[i<<1]&0xff)<<8)|((eeprom_data[i<<1]&0xff00)>>8); - if (i == 0xbf>>1){ - // printk ("regdomain: 0x%x --> 0x%x\n", p[i], (p[i] & 0xffff0000)|0x67); - /* regdomain is invalid?? how did original fw convert - * value to 0x82d4 ?? - * for now, force to 0x67 */ - p[i] &= 0xffff0000; - p[i] |= 0x67; + for (i = 0; i < ATH5K_PLAT_EEP_MAX_WORDS>>1; i++) { + arv_ath5k_eeprom_data[i] = swab16(arv_ath5k_eeprom_data[i]); + if (i == 0x17e>>1) { + /* + * regdomain is invalid. it's unknown how did original + * fw convered value to 0x82d4 so for now force to 0x67 + */ + arv_ath5k_eeprom_data[i] &= 0x0000; + arv_ath5k_eeprom_data[i] |= 0x67; } } } +void __init +arv_register_ath9k(unsigned int ath_addr, unsigned int mac_addr) +{ + int i; + u16 *eepdata, sum, el; + + memcpy_fromio(arv_athxk_eeprom_mac, + (void *)KSEG1ADDR(LTQ_FLASH_START + mac_addr), 6); + arv_athxk_eeprom_mac[5]++; + memcpy_fromio(arv_ath9k_eeprom_data, + (void *)KSEG1ADDR(LTQ_FLASH_START + ath_addr), ATH9K_PLAT_EEP_MAX_WORDS); + + // force regdomain to 0x67 + arv_ath9k_eeprom_data[0x208>>1] = 0x67; + + // calculate new checksum + sum = arv_ath9k_eeprom_data[0x200>>1]; + el = sum / sizeof(u16) - 2; /* skip length and (old) checksum */ + eepdata = (u16 *) (&arv_ath9k_eeprom_data[0x204>>1]); /* after checksum */ + for (i = 0; i < el; i++) + sum ^= *eepdata++; + sum ^= 0xffff; + arv_ath9k_eeprom_data[0x202>>1] = sum; +} + static void __init arv3527p_init(void) { +#define ARV3527P_MAC_ADDR 0x3f0016 + ltq_register_gpio_stp(); //ltq_add_device_gpio_leds(arv3527p_gpio_leds, ARRAY_SIZE(arv3527p_gpio_leds)); - ltq_register_nor(&arv45xx_flash_data); - arv45xx_register_ethernet(); + arv_load_nor(0x400000); + arv_register_ethernet(ARV3527P_MAC_ADDR); } MIPS_MACHINE(LANTIQ_MACH_ARV3527P, @@ -458,14 +496,16 @@ MIPS_MACHINE(LANTIQ_MACH_ARV3527P, static void __init arv4510pw_init(void) { +#define ARV4510PW_MAC_ADDR 0x3f0014 + ltq_register_gpio_stp(); ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv4510pw_gpio_leds), arv4510pw_gpio_leds); - ltq_register_nor(&arv4510_flash_data); + arv_load_nor(0x400000); ltq_pci_data.irq[12] = (INT_NUM_IM2_IRL0 + 31); ltq_pci_data.irq[15] = (INT_NUM_IM0_IRL0 + 26); ltq_pci_data.gpio |= PCI_EXIN2 | PCI_REQ2; ltq_register_pci(<q_pci_data); - bewan_register_ethernet(); + arv_register_ethernet(ARV4510PW_MAC_ADDR); } MIPS_MACHINE(LANTIQ_MACH_ARV4510PW, @@ -479,19 +519,21 @@ arv4518pw_init(void) #define ARV4518PW_EBU 0 #define ARV4518PW_USB 14 #define ARV4518PW_SWITCH_RESET 13 -#define ARV4518PW_MADWIFI_ADDR 0xb07f0400 +#define ARV4518PW_ATH_ADDR 0x3f0400 +#define ARV4518PW_MADWIFI_ADDR 0xb03f0400 +#define ARV4518PW_MAC_ADDR 0x3f0016 ltq_register_gpio_ebu(ARV4518PW_EBU); ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv4518pw_gpio_leds), arv4518pw_gpio_leds); ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, ARRAY_SIZE(arv4518pw_gpio_keys), arv4518pw_gpio_keys); - ltq_register_nor(&arv45xx_flash_data); + arv_load_nor(0x400000); ltq_pci_data.gpio = PCI_GNT2 | PCI_REQ2; ltq_register_pci(<q_pci_data); - ltq_register_madwifi_eep(ARV4518PW_MADWIFI_ADDR); - ltq_register_ath5k(arv45xx_ath5k_eeprom_data, arv45xx_ath5k_eeprom_mac); xway_register_dwc(ARV4518PW_USB); - arv45xx_register_ethernet(); + arv_register_ethernet(ARV4518PW_MAC_ADDR); + arv_register_ath5k(ARV4518PW_ATH_ADDR, ARV4518PW_MAC_ADDR); + ltq_register_ath5k(arv_ath5k_eeprom_data, arv_athxk_eeprom_mac); gpio_request(ARV4518PW_SWITCH_RESET, "switch"); gpio_direction_output(ARV4518PW_SWITCH_RESET, 1); @@ -504,18 +546,55 @@ MIPS_MACHINE(LANTIQ_MACH_ARV4518PW, arv4518pw_init); static void __init +arv4519pw_init(void) +{ +#define ARV4519PW_EBU 0 +#define ARV4519PW_USB 14 +#define ARV4519PW_RELAY 31 +#define ARV4519PW_SWITCH_RESET 13 +#define ARV4519PW_ATH_ADDR 0x3f0400 +#define ARV4519PW_MAC_ADDR 0x3f0016 + + arv_load_nor(0x400000); + ltq_register_gpio_ebu(ARV4519PW_EBU); + ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv4519pw_gpio_leds), arv4519pw_gpio_leds); + ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, + ARRAY_SIZE(arv4519pw_gpio_keys), arv4519pw_gpio_keys); + ltq_pci_data.gpio = PCI_GNT2 | PCI_REQ1; + ltq_register_pci(<q_pci_data); + xway_register_dwc(ARV4519PW_USB); + arv_register_ethernet(ARV4519PW_MAC_ADDR); + arv_register_ath5k(ARV4519PW_ATH_ADDR, ARV4519PW_MAC_ADDR); + ltq_register_ath5k(arv_ath5k_eeprom_data, arv_athxk_eeprom_mac); + + gpio_request(ARV4519PW_RELAY, "relay"); + gpio_direction_output(ARV4519PW_RELAY, 1); + gpio_export(ARV4519PW_RELAY, 0); + + gpio_request(ARV4519PW_SWITCH_RESET, "switch"); + gpio_set_value(ARV4519PW_SWITCH_RESET, 1); + gpio_export(ARV4519PW_SWITCH_RESET, 0); +} + +MIPS_MACHINE(LANTIQ_MACH_ARV4519PW, + "ARV4519PW", + "ARV4519PW - Vodafone, Pirelli", + arv4519pw_init); + +static void __init arv4520pw_init(void) { #define ARV4520PW_EBU 0x400 #define ARV4520PW_USB 28 #define ARV4520PW_SWITCH_RESET 110 +#define ARV4520PW_MAC_ADDR 0x3f0016 ltq_register_gpio_ebu(ARV4520PW_EBU); ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv4520pw_gpio_leds), arv4520pw_gpio_leds); - ltq_register_nor(&arv45xx_flash_data); + arv_load_nor(0x400000); ltq_register_pci(<q_pci_data); ltq_register_tapi(); - arv45xx_register_ethernet(); + arv_register_ethernet(ARV4520PW_MAC_ADDR); xway_register_dwc(ARV4520PW_USB); gpio_request(ARV4520PW_SWITCH_RESET, "switch"); @@ -535,16 +614,18 @@ arv452Cpw_init(void) #define ARV452CPW_RELAY1 31 #define ARV452CPW_RELAY2 107 #define ARV452CPW_SWITCH_RESET 110 -#define ARV452CPW_MADWIFI_ADDR 0xb07f0400 +#define ARV452CPW_ATH_ADDR 0x3f0400 +#define ARV452CPW_MADWIFI_ADDR 0xb03f0400 +#define ARV452CPW_MAC_ADDR 0x3f0016 ltq_register_gpio_ebu(ARV452CPW_EBU); ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv452cpw_gpio_leds), arv452cpw_gpio_leds); - ltq_register_nor(&arv45xx_flash_data); + arv_load_nor(0x400000); ltq_register_pci(<q_pci_data); - ltq_register_madwifi_eep(ARV452CPW_MADWIFI_ADDR); xway_register_dwc(ARV452CPW_USB); - arv45xx_register_ethernet(); - arv45xx_register_ath5k(); + arv_register_ethernet(ARV452CPW_MAC_ADDR); + arv_register_ath5k(ARV452CPW_ATH_ADDR, ARV452CPW_MAC_ADDR); + ltq_register_ath5k(arv_ath5k_eeprom_data, arv_athxk_eeprom_mac); gpio_request(ARV452CPW_SWITCH_RESET, "switch"); gpio_set_value(ARV452CPW_SWITCH_RESET, 1); @@ -567,23 +648,21 @@ MIPS_MACHINE(LANTIQ_MACH_ARV452CPW, static void __init arv4525pw_init(void) { +#define ARV4525PW_ATH_ADDR 0x3f0400 #define ARV4525PW_MADWIFI_ADDR 0xb03f0400 - if (ltq_brn_boot) - ltq_register_nor(&arv45xx_brnboot_flash_data); - else - ltq_register_nor(&arv45xx_flash_data); +#define ARV4525PW_MAC_ADDR 0x3f0016 + arv_load_nor(0x400000); ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv4525pw_gpio_leds), arv4525pw_gpio_leds); gpio_request_array(arv4525pw_gpios, ARRAY_SIZE(arv4525pw_gpios)); gpio_export(ARV4525PW_RELAY, false); gpio_export(ARV4525PW_PHYRESET, false); ltq_pci_data.clock = PCI_CLOCK_INT; ltq_register_pci(<q_pci_data); - ltq_register_madwifi_eep(ARV4525PW_MADWIFI_ADDR); - arv45xx_register_ath5k(); - ltq_register_ath5k(arv45xx_ath5k_eeprom_data, arv45xx_ath5k_eeprom_mac); + arv_register_ath5k(ARV4525PW_ATH_ADDR, ARV4525PW_MADWIFI_ADDR); + ltq_register_ath5k(arv_ath5k_eeprom_data, arv_athxk_eeprom_mac); ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII; - arv45xx_register_ethernet(); + arv_register_ethernet(ARV4525PW_MAC_ADDR); } MIPS_MACHINE(LANTIQ_MACH_ARV4525PW, @@ -594,8 +673,10 @@ MIPS_MACHINE(LANTIQ_MACH_ARV4525PW, static void __init arv7525pw_init(void) { +#define ARV7525P_MAC_ADDR 0x3f0016 + + arv_load_nor(0x400000); ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv4525pw_gpio_leds), arv4525pw_gpio_leds); - ltq_register_nor(&arv7525_flash_data); ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, ARRAY_SIZE(arv7525pw_gpio_keys), arv7525pw_gpio_keys); ltq_pci_data.clock = PCI_CLOCK_INT; @@ -605,7 +686,7 @@ arv7525pw_init(void) ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII; ltq_register_rt2x00("RT2860.eeprom"); ltq_register_tapi(); - arv45xx_register_ethernet(); + arv_register_ethernet(ARV7525P_MAC_ADDR); } MIPS_MACHINE(LANTIQ_MACH_ARV7525PW, @@ -618,17 +699,26 @@ arv7518pw_init(void) { #define ARV7518PW_EBU 0x2 #define ARV7518PW_USB 14 +#define ARV7518PW_SWITCH_RESET 13 +#define ARV7518PW_ATH_ADDR 0x7f0400 +#define ARV7518PW_MAC_ADDR 0x7f0016 + arv_load_nor(0x800000); ltq_register_gpio_ebu(ARV7518PW_EBU); ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv7518pw_gpio_leds), arv7518pw_gpio_leds); ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, ARRAY_SIZE(arv7518pw_gpio_keys), arv7518pw_gpio_keys); - ltq_register_nor(&arv75xx_flash_data); ltq_register_pci(<q_pci_data); ltq_register_tapi(); xway_register_dwc(ARV7518PW_USB); - arv75xx_register_ethernet(); - //arv7518_register_ath9k(mac); + arv_register_ethernet(ARV7518PW_MAC_ADDR); + arv_register_ath9k(ARV7518PW_ATH_ADDR, ARV7518PW_MAC_ADDR); + ltq_register_ath9k(arv_ath9k_eeprom_data, arv_athxk_eeprom_mac); + ltq_pci_ath_fixup(14, arv_ath9k_eeprom_data); + + gpio_request(ARV7518PW_SWITCH_RESET, "switch"); + gpio_direction_output(ARV7518PW_SWITCH_RESET, 1); + gpio_export(ARV7518PW_SWITCH_RESET, 0); } MIPS_MACHINE(LANTIQ_MACH_ARV7518PW, @@ -642,17 +732,18 @@ arv752dpw22_init(void) #define ARV752DPW22_EBU 0x2 #define ARV752DPW22_USB 100 #define ARV752DPW22_RELAY 101 +#define ARV752DPW22_MAC_ADDR 0x7f0016 + arv_load_nor(0x800000); ltq_register_gpio_ebu(ARV752DPW22_EBU); ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv752dpw22_gpio_leds), arv752dpw22_gpio_leds); ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, ARRAY_SIZE(arv752dpw22_gpio_keys), arv752dpw22_gpio_keys); - ltq_register_nor(&arv75xx_flash_data); ltq_pci_data.irq[15] = (INT_NUM_IM3_IRL0 + 31); ltq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2; ltq_register_pci(<q_pci_data); xway_register_dwc(ARV752DPW22_USB); - arv75xx_register_ethernet(); + arv_register_ethernet(ARV752DPW22_MAC_ADDR); gpio_request(ARV752DPW22_RELAY, "relay"); gpio_set_value(ARV752DPW22_RELAY, 1); diff --git a/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-bthomehubv2b.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-bthomehubv2b.c new file mode 100644 index 0000000000..44fe2f4efe --- /dev/null +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-bthomehubv2b.c @@ -0,0 +1,542 @@ +/* + * 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) 2011 Andrej VlaÅ¡ić + * Copyright (C) 2011 Luka Perkov + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/input.h> +#include <linux/ath5k_platform.h> +#include <linux/ath9k_platform.h> +#include <linux/pci.h> +#include <linux/phy.h> +#include <linux/io.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/module.h> + +#include <irq.h> +#include <lantiq_soc.h> +#include <lantiq_platform.h> +#include <dev-gpio-leds.h> +#include <dev-gpio-buttons.h> + +#include "../machtypes.h" +//#include "dev-wifi-ath9k.h" +#include "devices.h" +#include "dev-dwc_otg.h" + +#undef USE_BTHH_GPIO_INIT + +// this reads certain data from u-boot if it's there +#define USE_UBOOT_ENV_DATA + +#define UBOOT_ENV_OFFSET 0x040000 +#define UBOOT_ENV_SIZE 0x010000 + +#ifdef NAND_ORGLAYOUT +// this is only here for reference +// definition of NAND flash area +static struct mtd_partition bthomehubv2b_nand_partitions[] = +{ + { + .name = "ART", + .offset = 0x0000000, + .size = 0x0004000, + }, + { + .name = "image1", + .offset = 0x0004000, + .size = 0x0E00000, + }, + { + .name = "unknown1", + .offset = 0x0E04000, + .size = 0x00FC000, + }, + { + .name = "image2", + .offset = 0x0F00000, + .size = 0x0E00000, + }, + { + .name = "unknown2", + .offset = 0x1D00000, + .size = 0x0300000, + }, + +}; +#endif + +#ifdef NAND_KEEPOPENRG +// this allows both firmwares to co-exist + +static struct mtd_partition bthomehubv2b_nand_partitions[] = +{ + { + .name = "art", + .offset = 0x0000000, + .size = 0x0004000, + }, + { + .name = "Image1", + .offset = 0x0004000, + .size = 0x0E00000, + }, + { + .name = "linux", + .offset = 0x0E04000, + .size = 0x11fC000, + }, + { + .name = "wholeflash", + .offset = 0x0000000, + .size = 0x2000000, + }, + +}; +#endif + +// this gives more jffs2 by overwriting openrg + +static struct mtd_partition bthomehubv2b_nand_partitions[] = +{ + { + .name = "art", + .offset = 0x0000000, + .size = 0x0004000, + }, + { + .name = "linux", + .offset = 0x0004000, + .size = 0x1ffC000, + }, + { + .name = "wholeflash", + .offset = 0x0000000, + .size = 0x2000000, + }, + +}; + +extern void __init xway_register_nand(struct mtd_partition *parts, int count); + +// end BTHH_USE_NAND + +static struct gpio_led +bthomehubv2b_gpio_leds[] __initdata = { + + { .name = "soc:orange:upgrading", .gpio = 213, }, + { .name = "soc:orange:phone", .gpio = 214, }, + { .name = "soc:blue:phone", .gpio = 215, }, + { .name = "soc:orange:wireless", .gpio = 216, }, + { .name = "soc:blue:wireless", .gpio = 217, }, + { .name = "soc:red:broadband", .gpio = 218, }, + { .name = "soc:orange:broadband", .gpio = 219, }, + { .name = "soc:blue:broadband", .gpio = 220, }, + { .name = "soc:red:power", .gpio = 221, }, + { .name = "soc:orange:power", .gpio = 222, }, + { .name = "soc:blue:power", .gpio = 223, }, +}; + +static struct gpio_keys_button +bthomehubv2b_gpio_keys[] __initdata = { + { + .desc = "restart", + .type = EV_KEY, + .code = BTN_0, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 2, + .active_low = 1, + }, + { + .desc = "findhandset", + .type = EV_KEY, + .code = BTN_1, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 15, + .active_low = 1, + }, + { + .desc = "wps", + .type = EV_KEY, + .code = BTN_2, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 22, + .active_low = 1, + }, +}; + +// definition of NOR flash area - as per original. +static struct mtd_partition bthomehubv2b_partitions[] = +{ + { + .name = "uboot", + .offset = 0x000000, + .size = 0x040000, + }, + { + .name = "uboot_env", + .offset = UBOOT_ENV_OFFSET, + .size = UBOOT_ENV_SIZE, + }, + { + .name = "rg_conf_1", + .offset = 0x050000, + .size = 0x010000, + }, + { + .name = "rg_conf_2", + .offset = 0x060000, + .size = 0x010000, + }, + { + .name = "rg_conf_factory", + .offset = 0x070000, + .size = 0x010000, + }, +}; + + +/* nor flash */ +/* bt homehubv2b has a very small nor flash */ +/* so make it look for a small one, else we get a lot of alias chips identified - */ +/* not a bug problem, but fills the logs. */ +static struct resource bthhv2b_nor_resource = + MEM_RES("nor", LTQ_FLASH_START, 0x80000); + +static struct platform_device ltq_nor = { + .name = "ltq_nor", + .resource = &bthhv2b_nor_resource, + .num_resources = 1, +}; + +static void __init bthhv2b_register_nor(struct physmap_flash_data *data) +{ + ltq_nor.dev.platform_data = data; + platform_device_register(<q_nor); +} + +static struct physmap_flash_data bthomehubv2b_flash_data = { + .nr_parts = ARRAY_SIZE(bthomehubv2b_partitions), + .parts = bthomehubv2b_partitions, +}; + + + + +static struct ltq_pci_data ltq_pci_data = { + .clock = PCI_CLOCK_INT, + .gpio = PCI_GNT1 | PCI_REQ1, + .irq = { [14] = INT_NUM_IM0_IRL0 + 22, }, +}; + + + + +static struct ltq_eth_data ltq_eth_data = { + .mii_mode = PHY_INTERFACE_MODE_MII, +}; + + + + +static char __init *get_uboot_env_var(char *haystack, int haystack_len, char *needle, int needle_len) { + int i; + for (i = 0; i <= haystack_len - needle_len; i++) { + if (memcmp(haystack + i, needle, needle_len) == 0) { + return haystack + i + needle_len; + } + } + return NULL; +} + +/* + * bthomehubv2b_parse_hex_* are not uniq. in arm/orion there are also duplicates: + * dns323_parse_hex_* + * TODO: one day write a patch for this :) + */ +static int __init bthomehubv2b_parse_hex_nibble(char n) { + if (n >= '0' && n <= '9') + return n - '0'; + + if (n >= 'A' && n <= 'F') + return n - 'A' + 10; + + if (n >= 'a' && n <= 'f') + return n - 'a' + 10; + + return -1; +} + +static int __init bthomehubv2b_parse_hex_byte(const char *b) { + int hi; + int lo; + + hi = bthomehubv2b_parse_hex_nibble(b[0]); + lo = bthomehubv2b_parse_hex_nibble(b[1]); + + if (hi < 0 || lo < 0) + return -1; + + return (hi << 4) | lo; +} + +static int __init bthomehubv2b_register_ethernet(void) { + u_int8_t addr[6]; + int i; + char *mac = "01:02:03:04:05:06"; + int gotmac = 0; + char *boardid = "BTHHV2B"; + int gotboardid = 0; + + char *uboot_env_page; + uboot_env_page = ioremap(LTQ_FLASH_START + UBOOT_ENV_OFFSET, UBOOT_ENV_SIZE); + if (uboot_env_page) + { + char *Data = NULL; + Data = get_uboot_env_var(uboot_env_page, UBOOT_ENV_SIZE, "\0ethaddr=", 9); + if (Data) + { + mac = Data; + } + + Data = get_uboot_env_var(uboot_env_page, UBOOT_ENV_SIZE, "\0boardid=", 9); + + if (Data) + boardid = Data; + } + else + { + printk("bthomehubv2b: Failed to get uboot_env_page"); + } + + if (!mac) { + goto error_fail; + } + + if (!boardid) { + goto error_fail; + } + + /* Sanity check the string we're looking at */ + for (i = 0; i < 5; i++) { + if (*(mac + (i * 3) + 2) != ':') { + goto error_fail; + } + } + + for (i = 0; i < 6; i++) { + int byte; + byte = bthomehubv2b_parse_hex_byte(mac + (i * 3)); + if (byte < 0) { + goto error_fail; + } + addr[i] = byte; + } + + if (gotmac) + printk("bthomehubv2b: Found ethernet MAC address: "); + else + printk("bthomehubv2b: using default MAC (pls set ethaddr in u-boot): "); + + for (i = 0; i < 6; i++) + printk("%.2x%s", addr[i], (i < 5) ? ":" : ".\n"); + + memcpy(<q_eth_data.mac.sa_data, addr, 6); + ltq_register_etop(<q_eth_data); + + //memcpy(&bthomehubv2b_ath5k_eeprom_mac, addr, 6); + //bthomehubv2b_ath5k_eeprom_mac[5]++; + + if (gotboardid) + printk("bthomehubv2b: Board id is %s.", boardid); + else + printk("bthomehubv2b: Default Board id is %s.", boardid); + + if (strncmp(boardid, "BTHHV2B", 7) == 0) { + // read in dev-wifi-ath9k + //memcpy(&bthomehubv2b_ath5k_eeprom_data, sx763_eeprom_data, ATH5K_PLAT_EEP_MAX_WORDS); + } + else { + printk("bthomehubv2b: Board id is unknown, fix uboot_env data."); + } + + + // should not unmap while we are using the ram? + if (uboot_env_page) + iounmap(uboot_env_page); + + return 0; + +error_fail: + if (uboot_env_page) + iounmap(uboot_env_page); + return -EINVAL; +} + + +#define PORTA2_HW_PASS1 0 +#define PORTA2_HW_PASS1_SC14480 1 +#define PORTA2_HW_PASS2 2 + +int porta2_hw_revision = -1; +EXPORT_SYMBOL(porta2_hw_revision); + +#define LTQ_GPIO_OUT 0x00 +#define LTQ_GPIO_IN 0x04 +#define LTQ_GPIO_DIR 0x08 +#define LTQ_GPIO_ALTSEL0 0x0C +#define LTQ_GPIO_ALTSEL1 0x10 +#define LTQ_GPIO_OD 0x14 +#define LTQ_GPIO_PUDSEL 0x1C +#define LTQ_GPIO_PUDEN 0x20 + +#ifdef USE_BTHH_GPIO_INIT +static void bthomehubv2b_board_prom_init(void) +{ + int revision = 0; + unsigned int gpio = 0; + void __iomem *mem = ioremap(LTQ_GPIO0_BASE_ADDR, LTQ_GPIO_SIZE*2); + +#define DANUBE_GPIO_P0_OUT (unsigned short *)(mem + LTQ_GPIO_OUT) +#define DANUBE_GPIO_P0_IN (unsigned short *)(mem + LTQ_GPIO_IN) +#define DANUBE_GPIO_P0_DIR (unsigned short *)(mem + LTQ_GPIO_DIR) +#define DANUBE_GPIO_P0_ALTSEL0 (unsigned short *)(mem + LTQ_GPIO_ALTSEL0) +#define DANUBE_GPIO_P0_ALTSEL1 (unsigned short *)(mem + LTQ_GPIO_ALTSEL1) + +#define DANUBE_GPIO_P1_OUT (unsigned short *)(mem + LTQ_GPIO_SIZE + LTQ_GPIO_OUT) +#define DANUBE_GPIO_P1_IN (unsigned short *)(mem + LTQ_GPIO_SIZE + LTQ_GPIO_IN) +#define DANUBE_GPIO_P1_DIR (unsigned short *)(mem + LTQ_GPIO_SIZE + LTQ_GPIO_DIR) +#define DANUBE_GPIO_P1_ALTSEL0 (unsigned short *)(mem + LTQ_GPIO_SIZE + LTQ_GPIO_ALTSEL0) +#define DANUBE_GPIO_P1_ALTSEL1 (unsigned short *)(mem + LTQ_GPIO_SIZE + LTQ_GPIO_ALTSEL1) +#define DANUBE_GPIO_P1_OD (unsigned short *)(mem + LTQ_GPIO_SIZE + LTQ_GPIO_OD) + + printk("About to sense board using GPIOs at %8.8X\n", (unsigned int)mem); + + + /* First detect HW revision of the board. For that we need to set the GPIO + * lines according to table 7.2.1/7.2.2 in HSI */ + *DANUBE_GPIO_P0_OUT = 0x0200; + *DANUBE_GPIO_P0_DIR = 0x2610; + *DANUBE_GPIO_P0_ALTSEL0 = 0x7812; + *DANUBE_GPIO_P0_ALTSEL1 = 0x0000; + + *DANUBE_GPIO_P1_OUT = 0x7008; + *DANUBE_GPIO_P1_DIR = 0xF3AE; + *DANUBE_GPIO_P1_ALTSEL0 = 0x83A7; + *DANUBE_GPIO_P1_ALTSEL1 = 0x0400; + + gpio = (*DANUBE_GPIO_P0_IN & 0xFFFF) | + ((*DANUBE_GPIO_P1_IN & 0xFFFF) << 16); + + revision |= (gpio & (1 << 27)) ? (1 << 0) : 0; + revision |= (gpio & (1 << 20)) ? (1 << 1) : 0; + revision |= (gpio & (1 << 8)) ? (1 << 2) : 0; + revision |= (gpio & (1 << 6)) ? (1 << 3) : 0; + revision |= (gpio & (1 << 5)) ? (1 << 4) : 0; + revision |= (gpio & (1 << 0)) ? (1 << 5) : 0; + + porta2_hw_revision = revision; + printk("PORTA2: detected HW revision %d\n", revision); + + /* Set GPIO lines according to HW revision. */ + /* !!! Note that we are setting SPI_CS5 (GPIO 9) to be GPIO out with value + * of HIGH since the FXO does not use the SPI CS mechanism, it does it + * manually by controlling the GPIO line. We need the CS line to be disabled + * (HIGH) until needed since it will intefere with other devices on the SPI + * bus. */ + *DANUBE_GPIO_P0_OUT = 0x0200; + /* + * During the manufacturing process a different machine takes over uart0 + * so set it as input (so it wouldn't drive the line) + */ +#define cCONFIG_SHC_BT_MFG_TEST 0 + *DANUBE_GPIO_P0_DIR = 0x2671 | (cCONFIG_SHC_BT_MFG_TEST ? 0 : (1 << 12)); + + if (revision == PORTA2_HW_PASS1_SC14480 || revision == PORTA2_HW_PASS2) + *DANUBE_GPIO_P0_ALTSEL0 = 0x7873; + else + *DANUBE_GPIO_P0_ALTSEL0 = 0x3873; + + *DANUBE_GPIO_P0_ALTSEL1 = 0x0001; + + + //################################################################################### + // Register values before patch + // P1_ALTSEL0 = 0x83A7 + // P1_ALTSEL1 = 0x0400 + // P1_OU T = 0x7008 + // P1_DIR = 0xF3AE + // P1_OD = 0xE3Fc + printk("\nApplying Patch for CPU1 IRQ Issue\n"); + *DANUBE_GPIO_P1_ALTSEL0 &= ~(1<<12); // switch P1.12 (GPIO28) to GPIO functionality + *DANUBE_GPIO_P1_ALTSEL1 &= ~(1<<12); // switch P1.12 (GPIO28) to GPIO functionality + *DANUBE_GPIO_P1_OUT &= ~(1<<12); // set P1.12 (GPIO28) to 0 + *DANUBE_GPIO_P1_DIR |= (1<<12); // configure P1.12 (GPIO28) as output + *DANUBE_GPIO_P1_OD |= (1<<12); // activate Push/Pull mode + udelay(100); // wait a little bit (100us) + *DANUBE_GPIO_P1_OD &= ~(1<<12); // switch back from Push/Pull to Open Drain + // important: before! setting output to 1 (3,3V) the mode must be switched + // back to Open Drain because the reset pin of the SC14488 is internally + // pulled to 1,8V + *DANUBE_GPIO_P1_OUT |= (1<<12); // set output P1.12 (GPIO28) to 1 + // Register values after patch, should be the same as before + // P1_ALTSEL0 = 0x83A7 + // P1_ALTSEL1 = 0x0400 + // P1_OUT = 0x7008 + // P1_DIR = 0xF3AE + // P1_OD = 0xE3Fc + //################################################################################### + + + *DANUBE_GPIO_P1_OUT = 0x7008; + *DANUBE_GPIO_P1_DIR = 0xEBAE | (revision == PORTA2_HW_PASS2 ? 0x1000 : 0); + *DANUBE_GPIO_P1_ALTSEL0 = 0x8BA7; + *DANUBE_GPIO_P1_ALTSEL1 = 0x0400; + + iounmap(mem); +} +#endif +static void __init bthomehubv2b_init(void) { +#define bthomehubv2b_USB 13 + + // read the board version +#ifdef USE_BTHH_GPIO_INIT + bthomehubv2b_board_prom_init(); +#endif + + // register extra GPPOs used by LEDs as GPO 0x200+ + ltq_register_gpio_stp(); + ltq_add_device_gpio_leds(-1, ARRAY_SIZE(bthomehubv2b_gpio_leds), bthomehubv2b_gpio_leds); + bthhv2b_register_nor(&bthomehubv2b_flash_data); + xway_register_nand(bthomehubv2b_nand_partitions, ARRAY_SIZE(bthomehubv2b_nand_partitions)); + ltq_register_pci(<q_pci_data); + ltq_register_tapi(); + ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, ARRAY_SIZE(bthomehubv2b_gpio_keys), bthomehubv2b_gpio_keys); +// ltq_register_ath9k(); + xway_register_dwc(bthomehubv2b_USB); + bthomehubv2b_register_ethernet(); + +} + +MIPS_MACHINE(LANTIQ_MACH_BTHOMEHUBV2BOPENRG, + "BTHOMEHUBV2BOPENRG", + "BTHOMEHUBV2B - BT Homehub V2.0 Type B with OpenRG image retained", + bthomehubv2b_init); + +MIPS_MACHINE(LANTIQ_MACH_BTHOMEHUBV2B, + "BTHOMEHUBV2B", + "BTHOMEHUBV2B - BT Homehub V2.0 Type B", + bthomehubv2b_init); diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-easy50601.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-easy50601.c index a5a01057a3..a5a01057a3 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-easy50601.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-easy50601.c diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-easy50712.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-easy50712.c index 2fddfca6db..2fddfca6db 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-easy50712.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-easy50712.c diff --git a/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-fritz_ar9.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-fritz_ar9.c new file mode 100644 index 0000000000..503e4bebe3 --- /dev/null +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-fritz_ar9.c @@ -0,0 +1,114 @@ +/* + * 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 John Crispin <blogic@openwrt.org> + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/input.h> +#include <linux/phy.h> +#include <linux/spi/spi_gpio.h> +#include <linux/spi/flash.h> + +#include <lantiq_soc.h> +#include <irq.h> + +#include "../machtypes.h" +#include "devices.h" +#include "dev-ifxhcd.h" +#include "dev-gpio-leds.h" +#include "dev-gpio-buttons.h" + +static struct mtd_partition fritz7320_partitions[] = { + { + .name = "urlader", + .offset = 0x0, + .size = 0x20000, + }, + { + .name = "linux", + .offset = 0x20000, + .size = 0xf60000, + }, + { + .name = "tffs (1)", + .offset = 0xf80000, + .size = 0x40000, + }, + { + .name = "tffs (2)", + .offset = 0xfc0000, + .size = 0x40000, + }, +}; + +static struct physmap_flash_data fritz7320_flash_data = { + .nr_parts = ARRAY_SIZE(fritz7320_partitions), + .parts = fritz7320_partitions, +}; + +static struct gpio_led +fritz7320_gpio_leds[] __initdata = { + { .name = "soc:green:power", .gpio = 44, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:internet", .gpio = 47, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:dect", .gpio = 38, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:wlan", .gpio = 37, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:dual1", .gpio = 35, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:red:dual2", .gpio = 45, .active_low = 1, .default_trigger = "default-on" }, +}; + +static struct gpio_keys_button +fritz7320_gpio_keys[] __initdata = { + { + .desc = "wifi", + .type = EV_KEY, + .code = BTN_0, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 1, + .active_low = 1, + }, + { + .desc = "dect", + .type = EV_KEY, + .code = BTN_1, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 2, + .active_low = 1, + }, +}; + +static struct ltq_pci_data ltq_pci_data = { + .clock = PCI_CLOCK_INT, + .gpio = PCI_GNT1 | PCI_REQ1, + .irq = { + [14] = INT_NUM_IM0_IRL0 + 22, + }, +}; + +static struct ltq_eth_data ltq_eth_data = { + .mii_mode = PHY_INTERFACE_MODE_RMII, +}; + +static int usb_pins[2] = { 50, 51 }; + +static void __init fritz7320_init(void) +{ + ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, + ARRAY_SIZE(fritz7320_gpio_keys), fritz7320_gpio_keys); + ltq_add_device_gpio_leds(-1, ARRAY_SIZE(fritz7320_gpio_leds), fritz7320_gpio_leds); + ltq_register_pci(<q_pci_data); + ltq_register_etop(<q_eth_data); + ltq_register_nor(&fritz7320_flash_data); + xway_register_hcd(usb_pins); +} + +MIPS_MACHINE(LANTIQ_MACH_FRITZ7320, + "FRITZ7320", + "FRITZ!BOX 7320", + fritz7320_init); diff --git a/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-fritz_vr9.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-fritz_vr9.c new file mode 100644 index 0000000000..4a38988380 --- /dev/null +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-fritz_vr9.c @@ -0,0 +1,163 @@ +/* + * 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 John Crispin <blogic@openwrt.org> + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/input.h> +#include <linux/phy.h> +#include <linux/spi/spi_gpio.h> +#include <linux/spi/flash.h> + +#include <lantiq_soc.h> +#include <irq.h> + +#include "../machtypes.h" +#include "devices.h" +#include "dev-ifxhcd.h" +#include "dev-gpio-leds.h" +#include "dev-gpio-buttons.h" + +static struct mtd_partition fritz3370_partitions[] = { + { + .name = "linux", + .offset = 0x0, + .size = 0x400000, + }, + { + .name = "filesystem", + .offset = 0x400000, + .size = 0x3000000, + }, + { + .name = "reserved-kernel", + .offset = 0x3400000, + .size = 0x400000, + }, + { + .name = "reserved", + .offset = 0x3800000, + .size = 0x3000000, + }, + { + .name = "config", + .offset = 0x6800000, + .size = 0x200000, + }, + { + .name = "nand-filesystem", + .offset = 0x6a00000, + .size = 0x1600000, + }, +}; + +static struct mtd_partition spi_flash_partitions[] = { + { + .name = "urlader", + .offset = 0x0, + .size = 0x20000, + }, + { + .name = "tffs", + .offset = 0x20000, + .size = 0x10000, + }, + { + .name = "tffs", + .offset = 0x30000, + .size = 0x10000, + }, +}; + +static struct gpio_led +fritz3370_gpio_leds[] __initdata = { + { .name = "soc:green:1", .gpio = 32, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:red:2", .gpio = 33, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:red:3", .gpio = 34, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:4", .gpio = 35, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:5", .gpio = 36, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:6", .gpio = 47, .active_low = 1, .default_trigger = "default-on" }, +}; + +static struct gpio_keys_button +fritz3370_gpio_keys[] __initdata = { + { + .desc = "wifi", + .type = EV_KEY, + .code = BTN_0, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 29, + .active_low = 1, + }, +}; + +static struct ltq_eth_data ltq_eth_data = { + .mii_mode = PHY_INTERFACE_MODE_RMII, +}; + +static int usb_pins[2] = { 5, 14 }; + +#define SPI_GPIO_MRST 16 +#define SPI_GPIO_MTSR 17 +#define SPI_GPIO_CLK 18 +#define SPI_GPIO_CS0 10 + +static struct spi_gpio_platform_data spi_gpio_data = { + .sck = SPI_GPIO_CLK, + .mosi = SPI_GPIO_MTSR, + .miso = SPI_GPIO_MRST, + .num_chipselect = 2, +}; + +static struct platform_device spi_gpio_device = { + .name = "spi_gpio", + .dev.platform_data = &spi_gpio_data, +}; + +static struct flash_platform_data spi_flash_data = { + .name = "SPL", + .parts = spi_flash_partitions, + .nr_parts = ARRAY_SIZE(spi_flash_partitions), +}; + +static struct spi_board_info spi_flash __initdata = { + .modalias = "m25p80", + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 10 * 1000 * 1000, + .mode = SPI_MODE_3, + .chip_select = 0, + .controller_data = (void *) SPI_GPIO_CS0, + .platform_data = &spi_flash_data +}; + +static void __init +spi_gpio_init(void) +{ + spi_register_board_info(&spi_flash, 1); + platform_device_register(&spi_gpio_device); +} + +static void __init fritz3370_init(void) +{ + spi_gpio_init(); + platform_device_register_simple("pcie-xway", 0, NULL, 0); + xway_register_nand(fritz3370_partitions, ARRAY_SIZE(fritz3370_partitions)); + xway_register_hcd(usb_pins); + ltq_add_device_gpio_leds(-1, ARRAY_SIZE(fritz3370_gpio_leds), fritz3370_gpio_leds); + ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, + ARRAY_SIZE(fritz3370_gpio_keys), fritz3370_gpio_keys); + ltq_register_vrx200(<q_eth_data); +} + +MIPS_MACHINE(LANTIQ_MACH_FRITZ3370, + "FRITZ3370", + "FRITZ!BOX 3370", + fritz3370_init); diff --git a/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-gigasx76x.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-gigasx76x.c new file mode 100644 index 0000000000..c7a2de5017 --- /dev/null +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-gigasx76x.c @@ -0,0 +1,166 @@ +/* + * 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) 2011 Andrej VlaÅ¡ić + * Copyright (C) 2011 Luka Perkov + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/input.h> +#include <linux/ath5k_platform.h> +#include <linux/pci.h> +#include <linux/phy.h> +#include <linux/io.h> +#include <linux/if_ether.h> +#include <linux/etherdevice.h> +#include <linux/string.h> + +#include <irq.h> +#include <lantiq_soc.h> +#include <lantiq_platform.h> +#include <dev-gpio-leds.h> +#include <dev-gpio-buttons.h> + +#include "../machtypes.h" +#include "dev-wifi-athxk.h" +#include "devices.h" +#include "dev-dwc_otg.h" + +#include "mach-gigasx76x.h" + +static u8 ltq_ethaddr[6] = { 0 }; + +static int __init setup_ethaddr(char *str) +{ + if (!mac_pton(str, ltq_ethaddr)) + memset(ltq_ethaddr, 0, 6); + return 0; +} +__setup("ethaddr=", setup_ethaddr); + + +enum { + UNKNOWN = 0, + SX761, + SX762, + SX763, +}; +static u8 board = SX763; + +static int __init setup_board(char *str) +{ + if (!strcmp(str, "sx761")) + board = SX761; + else if (!strcmp(str, "sx762")) + board = SX762; + else if (!strcmp(str, "sx763")) + board = SX763; + else + board = UNKNOWN; + return 0; +} +__setup("board=", setup_board); + +static struct mtd_partition gigasx76x_partitions[] = +{ + { + .name = "uboot", + .offset = 0x0, + .size = 0x10000, + }, + { + .name = "uboot_env", + .offset = 0x10000, + .size = 0x10000, + }, + { + .name = "linux", + .offset = 0x20000, + .size = 0x7e0000, + }, +}; + +static struct gpio_led +gigasx76x_gpio_leds[] __initdata = { + { .name = "soc:green:voip", .gpio = 216, }, + { .name = "soc:green:adsl", .gpio = 217, }, + { .name = "soc:green:usb", .gpio = 218, }, + { .name = "soc:green:wifi", .gpio = 219, }, + { .name = "soc:green:phone2", .gpio = 220, }, + { .name = "soc:green:phone1", .gpio = 221, }, + { .name = "soc:green:line", .gpio = 222, }, + { .name = "soc:green:online", .gpio = 223, }, +}; + +static struct gpio_keys_button +gigasx76x_gpio_keys[] __initdata = { + { + .desc = "wps", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 22, + .active_low = 1, + }, + { + .desc = "reset", + .type = EV_KEY, + .code = BTN_0, + .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL, + .gpio = 14, + .active_low = 0, + }, +}; + +static struct physmap_flash_data gigasx76x_flash_data = { + .nr_parts = ARRAY_SIZE(gigasx76x_partitions), + .parts = gigasx76x_partitions, +}; + +static struct ltq_pci_data ltq_pci_data = { + .clock = PCI_CLOCK_INT, + .gpio = PCI_GNT1 | PCI_REQ1, + .irq = { [14] = INT_NUM_IM0_IRL0 + 22, }, +}; + +static struct ltq_eth_data ltq_eth_data = { + .mii_mode = PHY_INTERFACE_MODE_MII, +}; + +static void __init gigasx76x_init(void) +{ +#define GIGASX76X_USB 29 + + ltq_register_gpio_stp(); + ltq_register_nor(&gigasx76x_flash_data); + ltq_register_pci(<q_pci_data); + ltq_register_tapi(); + ltq_add_device_gpio_leds(-1, ARRAY_SIZE(gigasx76x_gpio_leds), gigasx76x_gpio_leds); + ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, ARRAY_SIZE(gigasx76x_gpio_keys), gigasx76x_gpio_keys); + xway_register_dwc(GIGASX76X_USB); + + if (!is_valid_ether_addr(ltq_ethaddr)) + random_ether_addr(ltq_ethaddr); + + memcpy(<q_eth_data.mac.sa_data, ltq_ethaddr, 6); + ltq_register_etop(<q_eth_data); + if (board == SX762) + ltq_register_ath5k(sx762_eeprom_data, ltq_ethaddr); + else + ltq_register_ath5k(sx763_eeprom_data, ltq_ethaddr); +} + +MIPS_MACHINE(LANTIQ_MACH_GIGASX76X, + "GIGASX76X", + "GIGASX76X - Gigaset SX761,SX762,SX763", + gigasx76x_init); diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-gigasx76x.h b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-gigasx76x.h index 186a146d90..c25a679978 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-gigasx76x.h +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-gigasx76x.h @@ -8,9 +8,12 @@ * */ +#ifndef _MACH_GIGASX76X_H__ +#define _MACH_GIGASX76X_H__ + static u16 sx763_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]= { -0x5aa5,0x168c,0x0200,0x0001,0x0000,0x5001,0x0000,0x2051,0x2051,0x1c0a,0x0100, +0x0013,0x168c,0x0200,0x0001,0x0000,0x5001,0x0000,0x2051,0x2051,0x1c0a,0x0100, 0x0000,0x01c2,0x0002,0xc606,0x0001,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xf165,0x7fbe,0x0003,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -108,7 +111,7 @@ static u16 sx763_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]= static u16 sx762_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]= { -0x5aa5,0x168c,0x0200,0x0001,0x0000,0x5001,0x0000,0x2051,0x2051,0x1c0a,0x0100, +0x001a,0x168c,0x0200,0x0001,0x0000,0x5001,0x0000,0x2051,0x2051,0x1c0a,0x0100, 0x0000,0x01c2,0x0002,0xc606,0x0001,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xf165,0x7fbe,0x0003,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -201,3 +204,5 @@ static u16 sx762_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]= 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, 0xffff,0xffff}; + +#endif diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-netgear.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-netgear.c index 826bfe2bcd..ed9098e7fc 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-netgear.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-netgear.c @@ -14,6 +14,7 @@ #include <linux/input.h> #include <linux/phy.h> #include <linux/spi/spi.h> +#include <linux/spi/flash.h> #include <lantiq_soc.h> #include <irq.h> @@ -33,11 +34,38 @@ static struct ltq_eth_data ltq_eth_data = { .mii_mode = PHY_INTERFACE_MODE_MII, }; -struct spi_board_info spi_info = { - .bus_num = 0, - .chip_select = 3, - .max_speed_hz = 25000000, - .modalias = "mx25l12805d", +static struct mtd_partition easy98000_nor_partitions[] = +{ + { + .name = "uboot", + .offset = 0x0, + .size = 0x40000, + }, + { + .name = "uboot_env", + .offset = 0x40000, + .size = 0x40000, /* 2 sectors for redundant env. */ + }, + { + .name = "linux", + .offset = 0x80000, + .size = 0xF80000, /* map only 16 MiB */ + }, +}; + +static struct flash_platform_data easy98000_spi_flash_platform_data = { + .name = "sflash", + .parts = easy98000_nor_partitions, + .nr_parts = ARRAY_SIZE(easy98000_nor_partitions) +}; + +static struct spi_board_info spi_info __initdata = { + .modalias = "m25p80", + .bus_num = 0, + .chip_select = 3, + .max_speed_hz = 10 * 1000 * 1000, + .mode = SPI_MODE_3, + .platform_data = &easy98000_spi_flash_platform_data }; struct ltq_spi_platform_data ltq_spi_data = { diff --git a/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-p2601hnf1.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-p2601hnf1.c new file mode 100644 index 0000000000..98c118135e --- /dev/null +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-p2601hnf1.c @@ -0,0 +1,106 @@ +/* + * 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 John Crispin <blogic@openwrt.org> + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/gpio_buttons.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/input.h> +#include <linux/etherdevice.h> +#include <linux/mdio-gpio.h> +#include <linux/kernel.h> +#include <linux/delay.h> + +#include <lantiq_soc.h> +#include <lantiq_platform.h> + +#include "../machtypes.h" +#include "devices.h" +#include "../dev-gpio-leds.h" +#include "dev-dwc_otg.h" + + +static struct mtd_partition p2601hnf1_partitions[] __initdata = +{ + { + .name = "uboot", + .offset = 0x0, + .size = 0x20000, + }, +/* { + .name = "uboot_env", + .offset = 0x20000, + .size = 0x20000, + }, +*/ { + .name = "linux", + .offset = 0x020000, + .size = 0xfc0000, + }, + { + .name = "board_config", + .offset = 0xfe0000, + .size = 0x20000, + }, +}; + +static struct physmap_flash_data p2601hnf1_flash_data __initdata = { + .nr_parts = ARRAY_SIZE(p2601hnf1_partitions), + .parts = p2601hnf1_partitions, +}; + +static struct gpio_led p2601hnf1_leds_gpio[] __initdata = { + { .name = "soc:red:power", .gpio = 29, .active_low = 1, .default_trigger = "default-off" }, + { .name = "soc:yellow:phone", .gpio = 64, .active_low = 1, .default_trigger = "default-off" }, + { .name = "soc:green:phone", .gpio = 65, .active_low = 1, .default_trigger = "default-off" }, + { .name = "soc:yellow:wlan", .gpio = 66, .active_low = 1, .default_trigger = "default-off" }, + { .name = "soc:green:power", .gpio = 67, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:red:internet", .gpio = 68, .active_low = 1, .default_trigger = "default-off" }, + { .name = "soc:green:internet", .gpio = 69, .active_low = 1, .default_trigger = "default-off" }, + { .name = "soc:green:dsl", .gpio = 70, .active_low = 1, .default_trigger = "default-off" }, + { .name = "soc:green:wlan", .gpio = 71, .active_low = 1, .default_trigger = "default-off" }, +}; + +static struct gpio_button +p2601hnf1_gpio_buttons[] /*__initdata*/ = { + { .desc = "reset", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 53, .active_low = 1, }, + { .desc = "wlan", .type = EV_KEY, .code = BTN_1, .threshold = 1, .gpio = 54, .active_low = 1, }, +}; + +static struct ltq_eth_data ltq_eth_data = { + .mii_mode = PHY_INTERFACE_MODE_RMII, +}; + +static void __init +p2601hnf1_init(void) +{ + +#define P2601HNF1_USB 9 + + ltq_register_gpio_stp(); + ltq_add_device_gpio_leds(-1, ARRAY_SIZE(p2601hnf1_leds_gpio), p2601hnf1_leds_gpio); + ltq_register_gpio_buttons(p2601hnf1_gpio_buttons, ARRAY_SIZE(p2601hnf1_gpio_buttons)); + ltq_register_nor(&p2601hnf1_flash_data); + ltq_register_etop(<q_eth_data); + xway_register_dwc(P2601HNF1_USB); + + // enable the ethernet ports on the SoC +// ltq_w32((ltq_r32(LTQ_GPORT_P0_CTL) & ~(1 << 17)) | (1 << 18), LTQ_GPORT_P0_CTL); +// ltq_w32((ltq_r32(LTQ_GPORT_P1_CTL) & ~(1 << 17)) | (1 << 18), LTQ_GPORT_P1_CTL); +// ltq_w32((ltq_r32(LTQ_GPORT_P2_CTL) & ~(1 << 17)) | (1 << 18), LTQ_GPORT_P2_CTL); +} + +MIPS_MACHINE(LANTIQ_MACH_P2601HNF1, + "P2601HNF1", + "ZyXEL P-2601HN-F1", + p2601hnf1_init); + diff --git a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-wbmr.c b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-wbmr.c index b11c2631bb..b11c2631bb 100644 --- a/target/linux/lantiq/files-3.1/arch/mips/lantiq/xway/mach-wbmr.c +++ b/target/linux/lantiq/files-3.2/arch/mips/lantiq/xway/mach-wbmr.c diff --git a/target/linux/lantiq/image/Makefile b/target/linux/lantiq/image/Makefile index 9ccf45d188..5f19d2b386 100644 --- a/target/linux/lantiq/image/Makefile +++ b/target/linux/lantiq/image/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2010 OpenWrt.org +# Copyright (C) 2010-2012 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -12,6 +12,7 @@ JFFS2_BLOCKSIZE = 64k 128k 256k ase_cmdline=-console=ttyLTQ0,115200 rootfstype=squashfs,jffs2 xway_cmdline=-console=ttyLTQ1,115200 rootfstype=squashfs,jffs2 falcon_cmdline=-console=ttyLTQ0,115200 rootfstype=squashfs,jffs2 +sx76x_cmdline=console=ttyLTQ1,115200 rootfstype=squashfs,jffs2 define CompressLzma $(STAGING_DIR_HOST)/bin/lzma e $(1) $(2) @@ -35,12 +36,23 @@ define MkImageLzma -d $(KDIR)/vmlinux-$(1).lzma $(KDIR)/uImage-$(1) endef +define MkImageEVA + lzma2eva 0x80002000 0x80002000 $(KDIR)/vmlinux-$(1).lzma $(KDIR)/$(1).eva.prealign + dd if=$(KDIR)/$(1).eva.prealign of=$(KDIR)/$(1).eva bs=64k conv=sync + cat ./eva.dummy.squashfs >> $(KDIR)/$(1).eva +endef + define Image/Build/squashfs cat $(KDIR)/uImage-$(2) $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image $(call prepare_generic_squashfs,$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image) $(if $(3),$(call MkBrnImage,$(3),$(4),$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(3)-brnImage,$(2),$(1),$(5))) endef +define Image/BuildEVA/squashfs + cat $(KDIR)/$(2).eva $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image.eva + $(call prepare_generic_squashfs,$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image.eva) +endef + define Image/Build/jffs2-64k dd if=$(KDIR)/uImage-$(2) of=$(KDIR)/uImage-$(2)-$(1) bs=64k conv=sync cat $(KDIR)/uImage-$(2)-$(1) $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image @@ -62,6 +74,12 @@ define Image/BuildKernel/Template $(CP) $(KDIR)/uImage-$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1)-uImage endef +define Image/BuildKernelEVA/Template + $(call PatchKernelLzma,$(1),$(if $(2),$(2) machtype=$(1),)) + $(call MkImageEVA,$(1)) + $(CP) $(KDIR)/$(1).eva $(BIN_DIR)/$(IMG_PREFIX)-$(1).eva +endef + ifeq ($(CONFIG_TARGET_lantiq_danube),y) define Image/BuildKernel/Profile/EASY50712 $(call Image/BuildKernel/Template,EASY50712,$(xway_cmdline)) @@ -103,6 +121,14 @@ define Image/Build/Profile/ARV4518PW $(call Image/Build/$(1),$(1),ARV4518PW) endef +define Image/BuildKernel/Profile/ARV4519PW + $(call Image/BuildKernel/Template,ARV4519PW,$(xway_cmdline)) +endef + +define Image/Build/Profile/ARV4519PW + $(call Image/Build/$(1),$(1),ARV4519PW,BRNDA4519,0x12345678,memsize=32) +endef + define Image/BuildKernel/Profile/ARV4520PW $(call Image/BuildKernel/Template,ARV4520PW,$(xway_cmdline)) endef @@ -140,7 +166,7 @@ define Image/BuildKernel/Profile/ARV7518PW endef define Image/Build/Profile/ARV7518PW - $(call Image/Build/$(1),$(1),ARV7518PW) + $(call Image/Build/$(1),$(1),ARV7518PW,BRNDA7519,0x12345678,memsize=64) endef define Image/BuildKernel/Profile/ARV752DPW @@ -160,13 +186,29 @@ define Image/Build/Profile/ARV752DPW22 endef define Image/BuildKernel/Profile/GIGASX76X - $(call Image/BuildKernel/Template,GIGASX76X,$(xway_cmdline)) + $(call Image/BuildKernel/Template,GIGASX76X,$(sx76x_cmdline)) endef define Image/Build/Profile/GIGASX76X $(call Image/Build/$(1),$(1),GIGASX76X) endef +define Image/BuildKernel/Profile/BTHOMEHUBV2B + $(call Image/BuildKernel/Template,BTHOMEHUBV2B,$(xway_cmdline)) +endef + +define Image/Build/Profile/BTHOMEHUBV2B + $(call Image/Build/$(1),$(1),BTHOMEHUBV2B) +endef + +define Image/BuildKernel/Profile/BTHOMEHUBV2BOPENRG + $(call Image/BuildKernel/Template,BTHOMEHUBV2BOPENRG,$(xway_cmdline)) +endef + +define Image/Build/Profile/BTHOMEHUBV2BOPENRG + $(call Image/Build/$(1),$(1),BTHOMEHUBV2BOPENRG) +endef + define Image/BuildKernel/Profile/Generic $(call Image/BuildKernel/Template,EASY4010,$(xway_cmdline)) $(call Image/BuildKernel/Template,EASY50712,$(xway_cmdline)) @@ -174,6 +216,7 @@ define Image/BuildKernel/Profile/Generic $(call Image/BuildKernel/Template,ARV3527P,$(xway_cmdline)) $(call Image/BuildKernel/Template,ARV4510PW,$(xway_cmdline)) $(call Image/BuildKernel/Template,ARV4518PW,$(xway_cmdline)) + $(call Image/BuildKernel/Template,ARV4519PW,$(xway_cmdline)) $(call Image/BuildKernel/Template,ARV4520PW,$(xway_cmdline)) $(call Image/BuildKernel/Template,ARV452CPW,$(xway_cmdline)) $(call Image/BuildKernel/Template,ARV4525PW,$(xway_cmdline)) @@ -182,6 +225,8 @@ define Image/BuildKernel/Profile/Generic $(call Image/BuildKernel/Template,ARV752DPW,$(xway_cmdline)) $(call Image/BuildKernel/Template,ARV752DPW22,$(xway_cmdline)) $(call Image/BuildKernel/Template,GIGASX76X,$(xway_cmdline)) + $(call Image/BuildKernel/Template,BTHOMEHUBV2B,$(xway_cmdline)) + $(call Image/BuildKernel/Template,BTHOMEHUBV2BOPENRG,$(xway_cmdline)) $(call Image/BuildKernel/Template,NONE) endef @@ -192,14 +237,17 @@ define Image/Build/Profile/Generic $(call Image/Build/$(1),$(1),ARV3527P) $(call Image/Build/$(1),$(1),ARV4510PW) $(call Image/Build/$(1),$(1),ARV4518PW) + $(call Image/Build/$(1),$(1),ARV4519PW,BRNDA4519,0x12345678,memsize=32) $(call Image/Build/$(1),$(1),ARV4520PW) $(call Image/Build/$(1),$(1),ARV452CPW) - $(call Image/Build/$(1),$(1),ARV4525PW) + $(call Image/Build/$(1),$(1),ARV4525PW,BRNDTW502,0x12345678,memsize=32) $(call Image/Build/$(1),$(1),ARV7525PW) - $(call Image/Build/$(1),$(1),ARV7518PW) + $(call Image/Build/$(1),$(1),ARV7518PW,BRNDA7519,0x12345678,memsize=32) $(call Image/Build/$(1),$(1),ARV752DPW) $(call Image/Build/$(1),$(1),ARV752DPW22) $(call Image/Build/$(1),$(1),GIGASX76X) + $(call Image/Build/$(1),$(1),BTHOMEHUBV2B) + $(call Image/Build/$(1),$(1),BTHOMEHUBV2BOPENRG) $(call Image/Build/$(1),$(1),NONE) $(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).rootfs endef @@ -222,15 +270,25 @@ define Image/Build/Profile/DGN3500B $(call Image/Build/$(1),$(1),DGN3500B) endef +define Image/BuildKernel/Profile/FRITZ7320 + $(call Image/BuildKernelEVA/Template,FRITZ7320,$(xway_cmdline)) +endef + +define Image/Build/Profile/FRITZ7320 + $(call Image/BuildEVA/$(1),$(1),FRITZ7320) +endef + define Image/BuildKernel/Profile/Generic $(call Image/BuildKernel/Template,WBMR,$(xway_cmdline)) $(call Image/BuildKernel/Template,DGN3500B,$(xway_cmdline)) + $(call Image/BuildKernelEVA/Template,FRITZ7320,$(xway_cmdline)) $(call Image/BuildKernel/Template,NONE) endef define Image/Build/Profile/Generic $(call Image/Build/$(1),$(1),WBMR) $(call Image/Build/$(1),$(1),DGN3500B) + $(call Image/BuildEVA/$(1),$(1),FRITZ7320) $(call Image/Build/$(1),$(1),NONE) $(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).rootfs endef @@ -288,6 +346,28 @@ define Image/Build/Profile/Generic endef endif +ifeq ($(CONFIG_TARGET_lantiq_vr9),y) +define Image/BuildKernel/Profile/FRITZ3370 + $(call Image/BuildKernel/Template,FRITZ3370,$(xway_cmdline)) + $(call Image/BuildKernelEVA/Template,FRITZ3370,$(xway_cmdline)) +endef + +define Image/Build/Profile/FRITZ3370 + $(call Image/Build/$(1),$(1),FRITZ3370) +endef + +define Image/BuildKernel/Profile/Generic + $(call Image/BuildKernel/Template,FRITZ3370,$(xway_cmdline)) + $(call Image/BuildKernel/Template,NONE) +endef + +define Image/Build/Profile/Generic + $(call Image/Build/$(1),$(1),FRITZ3370) + $(call Image/Build/$(1),$(1),NONE) + $(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).rootfs +endef +endif + define Image/BuildKernel $(call Image/BuildKernel/Profile/$(PROFILE)) endef diff --git a/target/linux/lantiq/image/eva.dummy.squashfs b/target/linux/lantiq/image/eva.dummy.squashfs Binary files differnew file mode 100644 index 0000000000..71c688c93e --- /dev/null +++ b/target/linux/lantiq/image/eva.dummy.squashfs diff --git a/target/linux/lantiq/modules.mk b/target/linux/lantiq/modules.mk index 0eccec5876..0868e6a386 100644 --- a/target/linux/lantiq/modules.mk +++ b/target/linux/lantiq/modules.mk @@ -29,7 +29,7 @@ USB_MENU:=USB Support define KernelPackage/usb-dwc-otg TITLE:=Synopsis DWC_OTG support SUBMENU:=$(USB_MENU) - DEPENDS+=@(TARGET_lantiq_danube||TARGET_lantiq_ar9||TARGET_lantiq_vr9) +kmod-usb-core + DEPENDS+=@(TARGET_lantiq_danube||TARGET_lantiq_ar9) +kmod-usb-core KCONFIG:=CONFIG_DWC_OTG \ CONFIG_DWC_OTG_DEBUG=n \ CONFIG_DWC_OTG_LANTIQ=y \ @@ -45,6 +45,39 @@ endef $(eval $(call KernelPackage,usb-dwc-otg)) +define KernelPackage/usb-ifxhcd + TITLE:=IFXHCD usb driver + SUBMENU:=$(USB_MENU) + DEPENDS+=@(TARGET_lantiq_vr9||TARGET_lantiq_ar9) +kmod-usb-core +ifeq ($(CONFIG_TARGET_lantiq_ar9),) + KCONFIG:=CONFIG_USB_HOST_IFX \ + CONFIG_USB_HOST_IFX_B=y \ + CONFIG_IFX_VR9=y \ + CONFIG_IFX_AR9=n \ + CONFIG_USB_HOST_IFX_FORCE_USB11=n \ + CONFIG_USB_HOST_IFX_WITH_HS_ELECT_TST=n \ + CONFIG_USB_HOST_IFX_WITH_ISO=n \ + CONFIG_USB_HOST_IFX_UNALIGNED_ADJ=y +else + KCONFIG:=CONFIG_USB_HOST_IFX \ + CONFIG_USB_HOST_IFX_B=y \ + CONFIG_IFX_AR9=y \ + CONFIG_IFX_VR9=n \ + CONFIG_USB_HOST_IFX_FORCE_USB11=n \ + CONFIG_USB_HOST_IFX_WITH_HS_ELECT_TST=n \ + CONFIG_USB_HOST_IFX_WITH_ISO=n \ + CONFIG_USB_HOST_IFX_UNALIGNED_ADJ=y +endif + FILES:=$(LINUX_DIR)/drivers/usb/ifxhcd/ifxusb_host.ko + AUTOLOAD:=$(call AutoLoad,50,ifxusb_host) +endef + +define KernelPackage/usb-ifxhcd/description + Kernel support for Synopsis USB on XWAY +endef + +$(eval $(call KernelPackage,usb-ifxhcd)) + I2C_FALCON_MODULES:= \ CONFIG_I2C_FALCON:drivers/i2c/busses/i2c-falcon diff --git a/target/linux/lantiq/patches-3.2/0001-GPIO-add-bindings-for-managed-devices.patch b/target/linux/lantiq/patches-3.2/0001-GPIO-add-bindings-for-managed-devices.patch new file mode 100644 index 0000000000..316d040d49 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0001-GPIO-add-bindings-for-managed-devices.patch @@ -0,0 +1,144 @@ +From 282f1ca84b35f3be68abc4fd8b52e229f3cb6bb7 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 13:23:53 +0100 +Subject: [PATCH 01/70] GPIO: add bindings for managed devices + +This patch adds 2 functions that allow managed devices to request GPIOs. +These GPIOs will then be managed by drivers/base/devres.c. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Grant Likely <grant.likely@secretlab.ca> +--- + drivers/gpio/Makefile | 2 +- + drivers/gpio/devres.c | 90 ++++++++++++++++++++++++++++++++++++++++++++ + include/asm-generic/gpio.h | 4 ++ + 3 files changed, 95 insertions(+), 1 deletions(-) + create mode 100644 drivers/gpio/devres.c + +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index 4e018d6..76dbd3f 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -2,7 +2,7 @@ + + ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG + +-obj-$(CONFIG_GPIOLIB) += gpiolib.o ++obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o + + # Device drivers. Generally keep list sorted alphabetically + obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o +diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c +new file mode 100644 +index 0000000..3dd2939 +--- /dev/null ++++ b/drivers/gpio/devres.c +@@ -0,0 +1,90 @@ ++/* ++ * drivers/gpio/devres.c - managed gpio resources ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * This file is based on kernel/irq/devres.c ++ * ++ * Copyright (c) 2011 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/gpio.h> ++#include <linux/device.h> ++#include <linux/gfp.h> ++ ++static void devm_gpio_release(struct device *dev, void *res) ++{ ++ unsigned *gpio = res; ++ ++ gpio_free(*gpio); ++} ++ ++static int devm_gpio_match(struct device *dev, void *res, void *data) ++{ ++ unsigned *this = res, *gpio = data; ++ ++ return *this == *gpio; ++} ++ ++/** ++ * devm_gpio_request - request a gpio for a managed device ++ * @dev: device to request the gpio for ++ * @gpio: gpio to allocate ++ * @label: the name of the requested gpio ++ * ++ * Except for the extra @dev argument, this function takes the ++ * same arguments and performs the same function as ++ * gpio_request(). GPIOs requested with this function will be ++ * automatically freed on driver detach. ++ * ++ * If an GPIO allocated with this function needs to be freed ++ * separately, devm_gpio_free() must be used. ++ */ ++ ++int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) ++{ ++ unsigned *dr; ++ int rc; ++ ++ dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL); ++ if (!dr) ++ return -ENOMEM; ++ ++ rc = gpio_request(gpio, label); ++ if (rc) { ++ devres_free(dr); ++ return rc; ++ } ++ ++ *dr = gpio; ++ devres_add(dev, dr); ++ ++ return 0; ++} ++EXPORT_SYMBOL(devm_gpio_request); ++ ++/** ++ * devm_gpio_free - free an interrupt ++ * @dev: device to free gpio for ++ * @gpio: gpio to free ++ * ++ * Except for the extra @dev argument, this function takes the ++ * same arguments and performs the same function as gpio_free(). ++ * This function instead of gpio_free() should be used to manually ++ * free GPIOs allocated with devm_gpio_request(). ++ */ ++void devm_gpio_free(struct device *dev, unsigned int gpio) ++{ ++ ++ WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match, ++ &gpio)); ++ gpio_free(gpio); ++} ++EXPORT_SYMBOL(devm_gpio_free); +diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h +index 8c86210..8601a02 100644 +--- a/include/asm-generic/gpio.h ++++ b/include/asm-generic/gpio.h +@@ -175,6 +175,10 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe + extern int gpio_request_array(const struct gpio *array, size_t num); + extern void gpio_free_array(const struct gpio *array, size_t num); + ++/* bindings for managed devices that want to request gpios */ ++int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); ++void devm_gpio_free(struct device *dev, unsigned int gpio); ++ + #ifdef CONFIG_GPIO_SYSFS + + /* +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0002-MIPS-remove-unused-prototype-kgdb_config.patch b/target/linux/lantiq/patches-3.2/0002-MIPS-remove-unused-prototype-kgdb_config.patch new file mode 100644 index 0000000000..d3b3c0ddc0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0002-MIPS-remove-unused-prototype-kgdb_config.patch @@ -0,0 +1,25 @@ +From b859096bdc4b029357217af98874d6feec3ff4bd Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 16 Mar 2012 16:27:35 +0100 +Subject: [PATCH 02/70] MIPS: remove unused prototype kgdb_config + +--- + arch/mips/include/asm/mips-boards/generic.h | 4 ---- + 1 files changed, 0 insertions(+), 4 deletions(-) + +diff --git a/arch/mips/include/asm/mips-boards/generic.h b/arch/mips/include/asm/mips-boards/generic.h +index 46c0856..6e23ceb 100644 +--- a/arch/mips/include/asm/mips-boards/generic.h ++++ b/arch/mips/include/asm/mips-boards/generic.h +@@ -93,8 +93,4 @@ extern void mips_pcibios_init(void); + #define mips_pcibios_init() do { } while (0) + #endif + +-#ifdef CONFIG_KGDB +-extern void kgdb_config(void); +-#endif +- + #endif /* __ASM_MIPS_BOARDS_GENERIC_H */ +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0003-MTD-MIPS-lantiq-reintroduce-support-for-cmdline-part.patch b/target/linux/lantiq/patches-3.2/0003-MTD-MIPS-lantiq-reintroduce-support-for-cmdline-part.patch new file mode 100644 index 0000000000..64b21011c2 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0003-MTD-MIPS-lantiq-reintroduce-support-for-cmdline-part.patch @@ -0,0 +1,39 @@ +From 63e9d017ce90dc1cd0822bace72e4e391feafdab Mon Sep 17 00:00:00 2001 +From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Date: Fri, 17 Feb 2012 22:32:18 +0100 +Subject: [PATCH 03/70] MTD: MIPS: lantiq: reintroduce support for cmdline + partitions + +Since commit ca97dec2ab5c87e9fbdf7e882e1820004a3966fa the +command line parsing of MTD partitions does not work anymore. + +Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + drivers/mtd/maps/lantiq-flash.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c +index 4f10e27..764d468 100644 +--- a/drivers/mtd/maps/lantiq-flash.c ++++ b/drivers/mtd/maps/lantiq-flash.c +@@ -45,6 +45,7 @@ struct ltq_mtd { + }; + + static char ltq_map_name[] = "ltq_nor"; ++static const char *ltq_probe_types[] __devinitconst = { "cmdlinepart", NULL }; + + static map_word + ltq_read16(struct map_info *map, unsigned long adr) +@@ -168,7 +169,7 @@ ltq_mtd_probe(struct platform_device *pdev) + cfi->addr_unlock1 ^= 1; + cfi->addr_unlock2 ^= 1; + +- err = mtd_device_parse_register(ltq_mtd->mtd, NULL, 0, ++ err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, 0, + ltq_mtd_data->parts, ltq_mtd_data->nr_parts); + if (err) { + dev_err(&pdev->dev, "failed to add partitions\n"); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0004-MTD-add-m25p80-id-for-mx25l2005a.patch b/target/linux/lantiq/patches-3.2/0004-MTD-add-m25p80-id-for-mx25l2005a.patch new file mode 100644 index 0000000000..75adef3fd1 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0004-MTD-add-m25p80-id-for-mx25l2005a.patch @@ -0,0 +1,24 @@ +From e4e27fbcaf2caa2a3e3ef45c736b4bb14f91ecfe Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 13 Mar 2012 18:03:33 +0100 +Subject: [PATCH 04/70] MTD: add m25p80 id for mx25l2005a + +--- + drivers/mtd/devices/m25p80.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c +index 884904d..3f37f5f 100644 +--- a/drivers/mtd/devices/m25p80.c ++++ b/drivers/mtd/devices/m25p80.c +@@ -676,6 +676,7 @@ static const struct spi_device_id m25p_ids[] = { + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + + /* Macronix */ ++ { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 8, SECT_4K) }, + { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, + { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, + { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0004-MIPS-lantiq-reorganize-xway-code.patch b/target/linux/lantiq/patches-3.2/0005-MIPS-lantiq-reorganize-xway-code.patch index 982b69da0d..2ab9522573 100644 --- a/target/linux/lantiq/patches/0004-MIPS-lantiq-reorganize-xway-code.patch +++ b/target/linux/lantiq/patches-3.2/0005-MIPS-lantiq-reorganize-xway-code.patch @@ -1,7 +1,7 @@ -From d90739a8962b541969b4c5f7ef1df8fec9c7f153 Mon Sep 17 00:00:00 2001 +From cf7086d4c2f7caeccd019c0a57bf1566c72c13ee Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Wed, 10 Aug 2011 14:57:04 +0200 -Subject: [PATCH 04/24] MIPS: lantiq: reorganize xway code +Subject: [PATCH 05/70] MIPS: lantiq: reorganize xway code Inside the folder arch/mips/lantiq/xway, there were alot of small files with lots of duplicated code. This patch adds a wrapper function for inserting and @@ -11,35 +11,35 @@ This patch makes the xway code consistent with the falcon support added later in this series. Signed-off-by: John Crispin <blogic@openwrt.org> -Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> -Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/mach-lantiq/lantiq.h | 14 +--- .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 14 ++++ arch/mips/lantiq/clk.c | 25 +------ arch/mips/lantiq/devices.c | 30 ++------ arch/mips/lantiq/devices.h | 4 + - arch/mips/lantiq/prom.c | 50 +++++++++++-- + arch/mips/lantiq/prom.c | 51 +++++++++++-- arch/mips/lantiq/prom.h | 4 + arch/mips/lantiq/xway/Makefile | 6 +- arch/mips/lantiq/xway/devices.c | 42 ++--------- - arch/mips/lantiq/xway/dma.c | 21 ++---- - arch/mips/lantiq/xway/ebu.c | 53 -------------- - arch/mips/lantiq/xway/pmu.c | 70 ------------------ - arch/mips/lantiq/xway/prom-ase.c | 9 +++ + arch/mips/lantiq/xway/dma.c | 21 +---- + arch/mips/lantiq/xway/ebu.c | 52 ------------- + arch/mips/lantiq/xway/pmu.c | 69 ----------------- + arch/mips/lantiq/xway/prom-ase.c | 9 ++ arch/mips/lantiq/xway/prom-xway.c | 10 +++ - arch/mips/lantiq/xway/reset.c | 21 ++---- + arch/mips/lantiq/xway/reset.c | 21 +---- arch/mips/lantiq/xway/setup-ase.c | 19 ----- arch/mips/lantiq/xway/setup-xway.c | 20 ----- - arch/mips/lantiq/xway/sysctrl.c | 77 ++++++++++++++++++++ + arch/mips/lantiq/xway/sysctrl.c | 78 ++++++++++++++++++++ drivers/watchdog/lantiq_wdt.c | 2 +- - 19 files changed, 197 insertions(+), 294 deletions(-) + 19 files changed, 199 insertions(+), 292 deletions(-) delete mode 100644 arch/mips/lantiq/xway/ebu.c delete mode 100644 arch/mips/lantiq/xway/pmu.c delete mode 100644 arch/mips/lantiq/xway/setup-ase.c delete mode 100644 arch/mips/lantiq/xway/setup-xway.c create mode 100644 arch/mips/lantiq/xway/sysctrl.c +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h +index ce2f029..66d7300 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -9,6 +9,7 @@ @@ -66,7 +66,7 @@ Cc: linux-mips@linux-mips.org extern unsigned int ltq_get_cpu_ver(void); extern unsigned int ltq_get_soc_type(void); -@@ -51,7 +43,9 @@ extern void ltq_enable_irq(struct irq_da +@@ -51,7 +43,9 @@ extern void ltq_enable_irq(struct irq_data *data); /* find out what caused the last cpu reset */ extern int ltq_reset_cause(void); @@ -77,9 +77,11 @@ Cc: linux-mips@linux-mips.org #define IOPORT_RESOURCE_START 0x10000000 #define IOPORT_RESOURCE_END 0xffffffff +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 8a3c6be..9b7ee366 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -65,6 +65,8 @@ +@@ -61,6 +61,8 @@ #define LTQ_CGU_BASE_ADDR 0x1F103000 #define LTQ_CGU_SIZE 0x1000 @@ -88,7 +90,7 @@ Cc: linux-mips@linux-mips.org /* ICU - interrupt control unit */ #define LTQ_ICU_BASE_ADDR 0x1F880200 #define LTQ_ICU_SIZE 0x100 -@@ -101,6 +103,8 @@ +@@ -97,6 +99,8 @@ #define LTQ_WDT_BASE_ADDR 0x1F8803F0 #define LTQ_WDT_SIZE 0x10 @@ -97,7 +99,7 @@ Cc: linux-mips@linux-mips.org /* STP - serial to parallel conversion unit */ #define LTQ_STP_BASE_ADDR 0x1E100BB0 #define LTQ_STP_SIZE 0x40 -@@ -125,11 +129,21 @@ +@@ -121,11 +125,21 @@ #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) @@ -119,6 +121,8 @@ Cc: linux-mips@linux-mips.org static inline int ltq_is_ar9(void) { +diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c +index 77ed70f..39eef7f 100644 --- a/arch/mips/lantiq/clk.c +++ b/arch/mips/lantiq/clk.c @@ -22,6 +22,7 @@ @@ -152,12 +156,12 @@ Cc: linux-mips@linux-mips.org - if (insert_resource(&iomem_resource, <q_cgu_resource) < 0) - panic("Failed to insert cgu memory\n"); -+ ltq_soc_init(); - +- - if (request_mem_region(ltq_cgu_resource.start, - resource_size(<q_cgu_resource), "cgu") < 0) - panic("Failed to request cgu memory\n"); -- ++ ltq_soc_init(); + - ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, - resource_size(<q_cgu_resource)); - if (!ltq_cgu_membase) { @@ -170,6 +174,8 @@ Cc: linux-mips@linux-mips.org + pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); clk_put(clk); } +diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c +index de1cb2b..7193d78 100644 --- a/arch/mips/lantiq/devices.c +++ b/arch/mips/lantiq/devices.c @@ -27,12 +27,8 @@ @@ -187,7 +193,7 @@ Cc: linux-mips@linux-mips.org static struct platform_device ltq_nor = { .name = "ltq_nor", -@@ -47,12 +43,8 @@ void __init ltq_register_nor(struct phys +@@ -47,12 +43,8 @@ void __init ltq_register_nor(struct physmap_flash_data *data) } /* watchdog */ @@ -229,6 +235,8 @@ Cc: linux-mips@linux-mips.org IRQ_RES(tx, LTQ_ASC_TIR(1)), IRQ_RES(rx, LTQ_ASC_RIR(1)), IRQ_RES(err, LTQ_ASC_EIR(1)), +diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h +index 2947bb1..a03c23f 100644 --- a/arch/mips/lantiq/devices.h +++ b/arch/mips/lantiq/devices.h @@ -14,6 +14,10 @@ @@ -242,6 +250,8 @@ Cc: linux-mips@linux-mips.org extern void ltq_register_nor(struct physmap_flash_data *data); extern void ltq_register_wdt(void); +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index e34fcfd..e3b1e25 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c @@ -16,6 +16,10 @@ @@ -255,7 +265,7 @@ Cc: linux-mips@linux-mips.org static struct ltq_soc_info soc_info; unsigned int ltq_get_cpu_ver(void) -@@ -57,16 +61,50 @@ static void __init prom_init_cmdline(voi +@@ -55,16 +59,51 @@ static void __init prom_init_cmdline(void) } } @@ -265,23 +275,23 @@ Cc: linux-mips@linux-mips.org - struct clk *clk; + __iomem void *ret = NULL; + struct resource *lookup = lookup_resource(&iomem_resource, res->start); - ++ + if (lookup && strcmp(lookup->name, res->name)) { -+ panic("conflicting memory range %s\n", res->name); ++ pr_err("conflicting memory range %s\n", res->name); + return NULL; + } + if (!lookup) { + if (insert_resource(&iomem_resource, res) < 0) { -+ panic("Failed to insert %s memory\n", res->name); ++ pr_err("Failed to insert %s memory\n", res->name); + return NULL; + } + } + if (request_mem_region(res->start, + resource_size(res), res->name) < 0) { -+ panic("Failed to request %s memory\n", res->name); ++ pr_err("Failed to request %s memory\n", res->name); + goto err_res; + } -+ + + ret = ioremap_nocache(res->start, resource_size(res)); + if (!ret) + goto err_mem; @@ -298,6 +308,7 @@ Cc: linux-mips@linux-mips.org + release_resource(res); + return NULL; +} ++EXPORT_SYMBOL(ltq_remap_resource); + +void __init prom_init(void) +{ @@ -312,6 +323,8 @@ Cc: linux-mips@linux-mips.org soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; pr_info("SoC: %s\n", soc_info.sys_type); prom_init_cmdline(); +diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h +index b4229d9..51dba1b 100644 --- a/arch/mips/lantiq/prom.h +++ b/arch/mips/lantiq/prom.h @@ -9,17 +9,21 @@ @@ -336,6 +349,8 @@ Cc: linux-mips@linux-mips.org extern void ltq_soc_setup(void); #endif +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index c517f2e..6678402 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -1,7 +1,7 @@ @@ -349,6 +364,8 @@ Cc: linux-mips@linux-mips.org obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index d614aa7..f97e565 100644 --- a/arch/mips/lantiq/xway/devices.c +++ b/arch/mips/lantiq/xway/devices.c @@ -31,22 +31,9 @@ @@ -421,9 +438,11 @@ Cc: linux-mips@linux-mips.org static struct platform_device ltq_etop = { .name = "ltq_etop", +diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c +index cbb6ae5..60cd11f 100644 --- a/arch/mips/lantiq/xway/dma.c +++ b/arch/mips/lantiq/xway/dma.c -@@ -23,6 +23,8 @@ +@@ -24,6 +24,8 @@ #include <lantiq_soc.h> #include <xway_dma.h> @@ -432,7 +451,7 @@ Cc: linux-mips@linux-mips.org #define LTQ_DMA_CTRL 0x10 #define LTQ_DMA_CPOLL 0x14 #define LTQ_DMA_CS 0x18 -@@ -54,12 +56,8 @@ +@@ -55,12 +57,8 @@ #define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \ ltq_dma_membase + (z)) @@ -447,7 +466,7 @@ Cc: linux-mips@linux-mips.org static void __iomem *ltq_dma_membase; -@@ -219,17 +217,8 @@ ltq_dma_init(void) +@@ -220,17 +218,8 @@ ltq_dma_init(void) { int i; @@ -466,6 +485,9 @@ Cc: linux-mips@linux-mips.org if (!ltq_dma_membase) panic("Failed to remap dma memory\n"); +diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c +deleted file mode 100644 +index 033b318..0000000 --- a/arch/mips/lantiq/xway/ebu.c +++ /dev/null @@ -1,52 +0,0 @@ @@ -521,6 +543,9 @@ Cc: linux-mips@linux-mips.org -} - -postcore_initcall(lantiq_ebu_init); +diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c +deleted file mode 100644 +index 39f0d26..0000000 --- a/arch/mips/lantiq/xway/pmu.c +++ /dev/null @@ -1,69 +0,0 @@ @@ -593,6 +618,8 @@ Cc: linux-mips@linux-mips.org -} - -core_initcall(ltq_pmu_init); +diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c +index ae4959a..3f86a3b 100644 --- a/arch/mips/lantiq/xway/prom-ase.c +++ b/arch/mips/lantiq/xway/prom-ase.c @@ -13,6 +13,7 @@ @@ -603,7 +630,7 @@ Cc: linux-mips@linux-mips.org #include "../prom.h" #define SOC_AMAZON_SE "Amazon_SE" -@@ -26,6 +27,7 @@ void __init ltq_soc_detect(struct ltq_so +@@ -26,6 +27,7 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) { i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; @@ -611,7 +638,7 @@ Cc: linux-mips@linux-mips.org switch (i->partnum) { case SOC_ID_AMAZON_SE: i->name = SOC_AMAZON_SE; -@@ -37,3 +39,10 @@ void __init ltq_soc_detect(struct ltq_so +@@ -37,3 +39,10 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) break; } } @@ -622,6 +649,8 @@ Cc: linux-mips@linux-mips.org + ltq_register_gpio(); + ltq_register_wdt(); +} +diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c +index 2228133..d823a92 100644 --- a/arch/mips/lantiq/xway/prom-xway.c +++ b/arch/mips/lantiq/xway/prom-xway.c @@ -13,6 +13,7 @@ @@ -632,7 +661,7 @@ Cc: linux-mips@linux-mips.org #include "../prom.h" #define SOC_DANUBE "Danube" -@@ -28,6 +29,7 @@ void __init ltq_soc_detect(struct ltq_so +@@ -28,6 +29,7 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) { i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; @@ -640,7 +669,7 @@ Cc: linux-mips@linux-mips.org switch (i->partnum) { case SOC_ID_DANUBE1: case SOC_ID_DANUBE2: -@@ -52,3 +54,11 @@ void __init ltq_soc_detect(struct ltq_so +@@ -52,3 +54,11 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) break; } } @@ -652,6 +681,8 @@ Cc: linux-mips@linux-mips.org + ltq_register_gpio(); + ltq_register_wdt(); +} +diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c +index 3d41f0b..ca2212a 100644 --- a/arch/mips/lantiq/xway/reset.c +++ b/arch/mips/lantiq/xway/reset.c @@ -15,6 +15,8 @@ @@ -697,6 +728,9 @@ Cc: linux-mips@linux-mips.org if (!ltq_rcu_membase) panic("Failed to remap rcu memory\n"); +diff --git a/arch/mips/lantiq/xway/setup-ase.c b/arch/mips/lantiq/xway/setup-ase.c +deleted file mode 100644 +index f6f3267..0000000 --- a/arch/mips/lantiq/xway/setup-ase.c +++ /dev/null @@ -1,19 +0,0 @@ @@ -719,6 +753,9 @@ Cc: linux-mips@linux-mips.org - ltq_register_gpio(); - ltq_register_wdt(); -} +diff --git a/arch/mips/lantiq/xway/setup-xway.c b/arch/mips/lantiq/xway/setup-xway.c +deleted file mode 100644 +index c292f64..0000000 --- a/arch/mips/lantiq/xway/setup-xway.c +++ /dev/null @@ -1,20 +0,0 @@ @@ -742,9 +779,12 @@ Cc: linux-mips@linux-mips.org - ltq_register_gpio(); - ltq_register_wdt(); -} +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +new file mode 100644 +index 0000000..8fd13a1 --- /dev/null +++ b/arch/mips/lantiq/xway/sysctrl.c -@@ -0,0 +1,77 @@ +@@ -0,0 +1,78 @@ +/* + * 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 @@ -754,6 +794,7 @@ Cc: linux-mips@linux-mips.org + */ + +#include <linux/ioport.h> ++#include <linux/export.h> + +#include <lantiq_soc.h> + @@ -822,6 +863,8 @@ Cc: linux-mips@linux-mips.org + /* make sure to unprotect the memory region where flash is located */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); +} +diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c +index 102aed0..179bf98 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c @@ -16,7 +16,7 @@ @@ -833,3 +876,6 @@ Cc: linux-mips@linux-mips.org /* Section 3.4 of the datasheet * The password sequence protects the WDT control register from unintended +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0006-MIPS-lantiq-change-ltq_request_gpio-call-signature.patch b/target/linux/lantiq/patches-3.2/0006-MIPS-lantiq-change-ltq_request_gpio-call-signature.patch new file mode 100644 index 0000000000..4700bc91d9 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0006-MIPS-lantiq-change-ltq_request_gpio-call-signature.patch @@ -0,0 +1,149 @@ +From 35f0a707698fc8f20e4164a704d7ac6af3342fb8 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 11 Nov 2011 12:45:24 +0100 +Subject: [PATCH 06/70] MIPS: lantiq: change ltq_request_gpio() call signature + +ltq_request_gpio() was using alt0/1 to multiplex the function of GPIO pins. +This was XWAY specific. In order to also accomodate SoCs that require more bits +we use a 32bit mask instead. This way the call signature is consistent between +XWAY and FALC-ON. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 4 +- + arch/mips/lantiq/xway/gpio.c | 8 ++-- + arch/mips/lantiq/xway/gpio_stp.c | 6 ++-- + arch/mips/pci/pci-lantiq.c | 36 +++++++++---------- + 4 files changed, 26 insertions(+), 28 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 9b7ee366..87f6d24 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -135,8 +135,8 @@ extern __iomem void *ltq_ebu_membase; + extern __iomem void *ltq_cgu_membase; + + /* request a non-gpio and set the PIO config */ +-extern int ltq_gpio_request(unsigned int pin, unsigned int alt0, +- unsigned int alt1, unsigned int dir, const char *name); ++extern int ltq_gpio_request(unsigned int pin, unsigned int mux, ++ unsigned int dir, const char *name); + extern void ltq_pmu_enable(unsigned int module); + extern void ltq_pmu_disable(unsigned int module); + extern void ltq_cgu_enable(unsigned int clk); +diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c +index d2fa98f..f204f6c 100644 +--- a/arch/mips/lantiq/xway/gpio.c ++++ b/arch/mips/lantiq/xway/gpio.c +@@ -48,8 +48,8 @@ int irq_to_gpio(unsigned int gpio) + } + EXPORT_SYMBOL(irq_to_gpio); + +-int ltq_gpio_request(unsigned int pin, unsigned int alt0, +- unsigned int alt1, unsigned int dir, const char *name) ++int ltq_gpio_request(unsigned int pin, unsigned int mux, ++ unsigned int dir, const char *name) + { + int id = 0; + +@@ -67,13 +67,13 @@ int ltq_gpio_request(unsigned int pin, unsigned int alt0, + pin -= PINS_PER_PORT; + id++; + } +- if (alt0) ++ if (mux & 0x2) + ltq_gpio_setbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL0, pin); + else + ltq_gpio_clearbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL0, pin); +- if (alt1) ++ if (mux & 0x1) + ltq_gpio_setbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL1, pin); + else +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index ff9991c..2c78660 100644 +--- a/arch/mips/lantiq/xway/gpio_stp.c ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -79,9 +79,9 @@ static struct gpio_chip ltq_stp_chip = { + static int ltq_stp_hw_init(void) + { + /* the 3 pins used to control the external stp */ +- ltq_gpio_request(4, 1, 0, 1, "stp-st"); +- ltq_gpio_request(5, 1, 0, 1, "stp-d"); +- ltq_gpio_request(6, 1, 0, 1, "stp-sh"); ++ ltq_gpio_request(4, 2, 1, "stp-st"); ++ ltq_gpio_request(5, 2, 1, "stp-d"); ++ ltq_gpio_request(6, 2, 1, "stp-sh"); + + /* sane defaults */ + ltq_stp_w32(0, LTQ_STP_AR); +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +index be1e1af..c001c5a 100644 +--- a/arch/mips/pci/pci-lantiq.c ++++ b/arch/mips/pci/pci-lantiq.c +@@ -70,28 +70,27 @@ + + struct ltq_pci_gpio_map { + int pin; +- int alt0; +- int alt1; ++ int mux; + int dir; + char *name; + }; + + /* the pci core can make use of the following gpios */ + static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = { +- { 0, 1, 0, 0, "pci-exin0" }, +- { 1, 1, 0, 0, "pci-exin1" }, +- { 2, 1, 0, 0, "pci-exin2" }, +- { 39, 1, 0, 0, "pci-exin3" }, +- { 10, 1, 0, 0, "pci-exin4" }, +- { 9, 1, 0, 0, "pci-exin5" }, +- { 30, 1, 0, 1, "pci-gnt1" }, +- { 23, 1, 0, 1, "pci-gnt2" }, +- { 19, 1, 0, 1, "pci-gnt3" }, +- { 38, 1, 0, 1, "pci-gnt4" }, +- { 29, 1, 0, 0, "pci-req1" }, +- { 31, 1, 0, 0, "pci-req2" }, +- { 3, 1, 0, 0, "pci-req3" }, +- { 37, 1, 0, 0, "pci-req4" }, ++ { 0, 2, 0, "pci-exin0" }, ++ { 1, 2, 0, "pci-exin1" }, ++ { 2, 2, 0, "pci-exin2" }, ++ { 39, 2, 0, "pci-exin3" }, ++ { 10, 2, 0, "pci-exin4" }, ++ { 9, 2, 0, "pci-exin5" }, ++ { 30, 2, 1, "pci-gnt1" }, ++ { 23, 2, 1, "pci-gnt2" }, ++ { 19, 2, 1, "pci-gnt3" }, ++ { 38, 2, 1, "pci-gnt4" }, ++ { 29, 2, 0, "pci-req1" }, ++ { 31, 2, 0, "pci-req2" }, ++ { 3, 2, 0, "pci-req3" }, ++ { 37, 2, 0, "pci-req4" }, + }; + + __iomem void *ltq_pci_mapped_cfg; +@@ -157,13 +156,12 @@ static void ltq_pci_setup_gpio(int gpio) + for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) { + if (gpio & (1 << i)) { + ltq_gpio_request(ltq_pci_gpio_map[i].pin, +- ltq_pci_gpio_map[i].alt0, +- ltq_pci_gpio_map[i].alt1, ++ ltq_pci_gpio_map[i].mux, + ltq_pci_gpio_map[i].dir, + ltq_pci_gpio_map[i].name); + } + } +- ltq_gpio_request(21, 0, 0, 1, "pci-reset"); ++ ltq_gpio_request(21, 0, 1, "pci-reset"); + ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; + } + +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0005-MIPS-lantiq-make-irq.c-support-the-FALC-ON.patch b/target/linux/lantiq/patches-3.2/0007-MIPS-lantiq-make-irq.c-support-the-FALC-ON.patch index 97d9461a59..fd45e61e4c 100644 --- a/target/linux/lantiq/patches/0005-MIPS-lantiq-make-irq.c-support-the-FALC-ON.patch +++ b/target/linux/lantiq/patches-3.2/0007-MIPS-lantiq-make-irq.c-support-the-FALC-ON.patch @@ -1,7 +1,7 @@ -From d9355bb07878f9aa40856cc437c43cedc87662fc Mon Sep 17 00:00:00 2001 +From 03f55cae0f5d9a4c30f935abf8d621ced64ae425 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Aug 2011 12:25:55 +0200 -Subject: [PATCH 05/24] MIPS: lantiq: make irq.c support the FALC-ON +Subject: [PATCH 07/70] MIPS: lantiq: make irq.c support the FALC-ON There are minor differences in how irqs work on xway and falcon socs. Xway needs 2 quirks that we need to disable for falcon to also work with @@ -10,16 +10,17 @@ this code. * EBU irq does not need to send a special ack to the EBU * The EIU does not exist -Signed-off-by: John Crispin <blogic@openwrt.org> Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> -Cc: linux-mips@linux-mips.org +Signed-off-by: John Crispin <blogic@openwrt.org> --- arch/mips/lantiq/irq.c | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-) +diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c +index f9737bb..17c057f 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c -@@ -195,7 +195,7 @@ static void ltq_hw_irqdispatch(int modul +@@ -195,7 +195,7 @@ static void ltq_hw_irqdispatch(int module) do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); /* if this is a EBU irq, we need to ack it or get a deadlock */ @@ -37,15 +38,14 @@ Cc: linux-mips@linux-mips.org + if (LTQ_EIU_BASE_ADDR) { + if (insert_resource(&iomem_resource, <q_eiu_resource) < 0) + panic("Failed to insert eiu memory\n"); -+ -+ if (request_mem_region(ltq_eiu_resource.start, -+ resource_size(<q_eiu_resource), "eiu") < 0) -+ panic("Failed to request eiu memory\n"); - if (request_mem_region(ltq_eiu_resource.start, - resource_size(<q_eiu_resource), "eiu") < 0) - panic("Failed to request eiu memory\n"); -- ++ if (request_mem_region(ltq_eiu_resource.start, ++ resource_size(<q_eiu_resource), "eiu") < 0) ++ panic("Failed to request eiu memory\n"); + - ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, + ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, resource_size(<q_eiu_resource)); @@ -68,3 +68,6 @@ Cc: linux-mips@linux-mips.org irq_set_chip_and_handler(i, <q_eiu_type, handle_level_irq); /* EIU3-5 only exist on ar9 and vr9 */ +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0006-MIPS-lantiq-add-basic-support-for-FALC-ON.patch b/target/linux/lantiq/patches-3.2/0008-MIPS-lantiq-add-basic-support-for-FALC-ON.patch index 780afa0025..72b0fa7438 100644 --- a/target/linux/lantiq/patches/0006-MIPS-lantiq-add-basic-support-for-FALC-ON.patch +++ b/target/linux/lantiq/patches-3.2/0008-MIPS-lantiq-add-basic-support-for-FALC-ON.patch @@ -1,18 +1,16 @@ -From ff57bc17a9964d24708759c6d78a51e337563d5f Mon Sep 17 00:00:00 2001 +From d54a53bc8bc25bf2f9076013f89b30cb9103f99f Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Aug 2011 14:33:04 +0200 -Subject: [PATCH 06/24] MIPS: lantiq: add basic support for FALC-ON +Subject: [PATCH 08/70] MIPS: lantiq: add basic support for FALC-ON -Adds support for the FALC-ON SoC. This SoC is from the fiber to the home GPON -series. +Adds support for the FALC-ON SoC. This SoC is from the FTTH/GPON SoC family. -Signed-off-by: John Crispin <blogic@openwrt.org> Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> -Cc: linux-mips@linux-mips.org +Signed-off-by: John Crispin <blogic@openwrt.org> --- .../include/asm/mach-lantiq/falcon/falcon_irq.h | 268 ++++++++++++++++++++ arch/mips/include/asm/mach-lantiq/falcon/irq.h | 18 ++ - .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 140 ++++++++++ + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 143 +++++++++++ arch/mips/include/asm/mach-lantiq/lantiq.h | 1 + arch/mips/lantiq/Kconfig | 4 + arch/mips/lantiq/Makefile | 1 + @@ -21,10 +19,10 @@ Cc: linux-mips@linux-mips.org arch/mips/lantiq/falcon/clk.c | 44 ++++ arch/mips/lantiq/falcon/devices.c | 87 +++++++ arch/mips/lantiq/falcon/devices.h | 18 ++ - arch/mips/lantiq/falcon/prom.c | 72 ++++++ + arch/mips/lantiq/falcon/prom.c | 93 +++++++ arch/mips/lantiq/falcon/reset.c | 87 +++++++ - arch/mips/lantiq/falcon/sysctrl.c | 181 +++++++++++++ - 14 files changed, 923 insertions(+), 0 deletions(-) + arch/mips/lantiq/falcon/sysctrl.c | 183 +++++++++++++ + 14 files changed, 949 insertions(+), 0 deletions(-) create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/irq.h create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h @@ -36,6 +34,9 @@ Cc: linux-mips@linux-mips.org create mode 100644 arch/mips/lantiq/falcon/reset.c create mode 100644 arch/mips/lantiq/falcon/sysctrl.c +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h +new file mode 100644 +index 0000000..4dc6466 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h @@ -0,0 +1,268 @@ @@ -307,6 +308,9 @@ Cc: linux-mips@linux-mips.org +#define FALCON_IRQ_VPE0_PMCIR (INT_NUM_IM4_IRL0 + 31) + +#endif /* _FALCON_IRQ__ */ +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/irq.h b/arch/mips/include/asm/mach-lantiq/falcon/irq.h +new file mode 100644 +index 0000000..2caccd9 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/irq.h @@ -0,0 +1,18 @@ @@ -328,9 +332,12 @@ Cc: linux-mips@linux-mips.org +#include_next <irq.h> + +#endif +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +new file mode 100644 +index 0000000..b074748 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -@@ -0,0 +1,140 @@ +@@ -0,0 +1,143 @@ +/* + * 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 @@ -361,8 +368,10 @@ Cc: linux-mips@linux-mips.org +#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1) +#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2) + -+/* during early_printk no ioremap possible at this early stage -+ lets use KSEG1 instead */ ++/* ++ * during early_printk no ioremap possible at this early stage ++ * lets use KSEG1 instead ++ */ +#define LTQ_EARLY_ASC KSEG1ADDR(LTQ_ASC0_BASE_ADDR) + +/* ICU - interrupt control unit */ @@ -407,6 +416,7 @@ Cc: linux-mips@linux-mips.org +#define LTQ_STATUS_BASE_ADDR 0x1E802000 + +#define LTQ_FALCON_CHIPID ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x0c)) ++#define LTQ_FALCON_CHIPTYPE ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x38)) +#define LTQ_FALCON_CHIPCONF ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x40)) + +/* SYSCTL - start/stop/restart/configure/... different parts of the Soc */ @@ -457,7 +467,7 @@ Cc: linux-mips@linux-mips.org + ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg) + +/* gpio_request wrapper to help configure the pin */ -+extern int ltq_gpio_request(unsigned int pin, unsigned int val, ++extern int ltq_gpio_request(unsigned int pin, unsigned int mux, + unsigned int dir, const char *name); +extern int ltq_gpio_mux_set(unsigned int pin, unsigned int mux); + @@ -471,9 +481,11 @@ Cc: linux-mips@linux-mips.org + +#endif /* CONFIG_SOC_FALCON */ +#endif /* _LTQ_XWAY_H__ */ +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h +index 66d7300..188de0f 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h -@@ -25,6 +25,7 @@ extern unsigned int ltq_get_soc_type(voi +@@ -25,6 +25,7 @@ extern unsigned int ltq_get_soc_type(void); /* clock speeds */ #define CLOCK_60M 60000000 #define CLOCK_83M 83333333 @@ -481,6 +493,8 @@ Cc: linux-mips@linux-mips.org #define CLOCK_111M 111111111 #define CLOCK_133M 133333333 #define CLOCK_167M 166666667 +diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig +index 3fccf21..cb6b39f 100644 --- a/arch/mips/lantiq/Kconfig +++ b/arch/mips/lantiq/Kconfig @@ -16,8 +16,12 @@ config SOC_XWAY @@ -496,13 +510,17 @@ Cc: linux-mips@linux-mips.org +source "arch/mips/lantiq/falcon/Kconfig" endif +diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile +index e5dae0e..7e9c69e 100644 --- a/arch/mips/lantiq/Makefile +++ b/arch/mips/lantiq/Makefile -@@ -9,3 +9,4 @@ obj-y := irq.o setup.o clk.o prom.o devi +@@ -9,3 +9,4 @@ obj-y := irq.o setup.o clk.o prom.o devices.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ +obj-$(CONFIG_SOC_FALCON) += falcon/ +diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform +index f3dff05..b3ec498 100644 --- a/arch/mips/lantiq/Platform +++ b/arch/mips/lantiq/Platform @@ -6,3 +6,4 @@ platform-$(CONFIG_LANTIQ) += lantiq/ @@ -510,10 +528,16 @@ Cc: linux-mips@linux-mips.org load-$(CONFIG_LANTIQ) = 0xffffffff80002000 cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway +cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon +diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile +new file mode 100644 +index 0000000..e9c7455 --- /dev/null +++ b/arch/mips/lantiq/falcon/Makefile @@ -0,0 +1 @@ +obj-y := clk.o prom.o reset.o sysctrl.o devices.o +diff --git a/arch/mips/lantiq/falcon/clk.c b/arch/mips/lantiq/falcon/clk.c +new file mode 100644 +index 0000000..afe1b52 --- /dev/null +++ b/arch/mips/lantiq/falcon/clk.c @@ -0,0 +1,44 @@ @@ -527,7 +551,7 @@ Cc: linux-mips@linux-mips.org + */ + +#include <linux/ioport.h> -+#include <linux/module.h> ++#include <linux/export.h> + +#include <lantiq_soc.h> + @@ -561,6 +585,9 @@ Cc: linux-mips@linux-mips.org + return CLOCK_100M; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +new file mode 100644 +index 0000000..c4606f2 --- /dev/null +++ b/arch/mips/lantiq/falcon/devices.c @@ -0,0 +1,87 @@ @@ -651,6 +678,9 @@ Cc: linux-mips@linux-mips.org +{ + platform_device_register(<q_flash_nand); +} +diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h +new file mode 100644 +index 0000000..e802a7c --- /dev/null +++ b/arch/mips/lantiq/falcon/devices.h @@ -0,0 +1,18 @@ @@ -672,9 +702,12 @@ Cc: linux-mips@linux-mips.org +extern void falcon_register_nand(void); + +#endif +diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c +new file mode 100644 +index 0000000..b50d6f9 --- /dev/null +++ b/arch/mips/lantiq/falcon/prom.c -@@ -0,0 +1,72 @@ +@@ -0,0 +1,93 @@ +/* + * 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 @@ -691,6 +724,9 @@ Cc: linux-mips@linux-mips.org +#include "../prom.h" + +#define SOC_FALCON "Falcon" ++#define SOC_FALCON_D "Falcon-D" ++#define SOC_FALCON_V "Falcon-V" ++#define SOC_FALCON_M "Falcon-M" + +#define PART_SHIFT 12 +#define PART_MASK 0x0FFFF000 @@ -698,6 +734,8 @@ Cc: linux-mips@linux-mips.org +#define REV_MASK 0xF0000000 +#define SREV_SHIFT 22 +#define SREV_MASK 0x03C00000 ++#define TYPE_SHIFT 26 ++#define TYPE_MASK 0x3C000000 + +#define MUXC_SIF_RX_PIN 112 +#define MUXC_SIF_TX_PIN 113 @@ -731,14 +769,30 @@ Cc: linux-mips@linux-mips.org +void __init +ltq_soc_detect(struct ltq_soc_info *i) +{ ++ u32 type; + i->partnum = (ltq_r32(LTQ_FALCON_CHIPID) & PART_MASK) >> PART_SHIFT; + i->rev = (ltq_r32(LTQ_FALCON_CHIPID) & REV_MASK) >> REV_SHIFT; -+ i->srev = (ltq_r32(LTQ_FALCON_CHIPCONF) & SREV_MASK) >> SREV_SHIFT; ++ i->srev = ((ltq_r32(LTQ_FALCON_CHIPCONF) & SREV_MASK) >> SREV_SHIFT); + sprintf(i->rev_type, "%c%d%d", (i->srev & 0x4) ? ('B') : ('A'), -+ i->rev & 0x7, i->srev & 0x3); ++ i->rev & 0x7, (i->srev & 0x3) + 1); ++ + switch (i->partnum) { + case SOC_ID_FALCON: -+ i->name = SOC_FALCON; ++ type = (ltq_r32(LTQ_FALCON_CHIPTYPE) & TYPE_MASK) >> TYPE_SHIFT; ++ switch (type) { ++ case 0: ++ i->name = SOC_FALCON_D; ++ break; ++ case 1: ++ i->name = SOC_FALCON_V; ++ break; ++ case 2: ++ i->name = SOC_FALCON_M; ++ break; ++ default: ++ i->name = SOC_FALCON; ++ break; ++ } + i->type = SOC_TYPE_FALCON; + break; + @@ -747,6 +801,9 @@ Cc: linux-mips@linux-mips.org + break; + } +} +diff --git a/arch/mips/lantiq/falcon/reset.c b/arch/mips/lantiq/falcon/reset.c +new file mode 100644 +index 0000000..cbcadc5 --- /dev/null +++ b/arch/mips/lantiq/falcon/reset.c @@ -0,0 +1,87 @@ @@ -763,7 +820,7 @@ Cc: linux-mips@linux-mips.org +#include <linux/io.h> +#include <linux/pm.h> +#include <asm/reboot.h> -+#include <linux/module.h> ++#include <linux/export.h> + +#include <lantiq_soc.h> + @@ -837,9 +894,12 @@ Cc: linux-mips@linux-mips.org +} + +arch_initcall(mips_reboot_setup); +diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c +new file mode 100644 +index 0000000..905a142 --- /dev/null +++ b/arch/mips/lantiq/falcon/sysctrl.c -@@ -0,0 +1,181 @@ +@@ -0,0 +1,183 @@ +/* + * 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 @@ -850,6 +910,7 @@ Cc: linux-mips@linux-mips.org + */ + +#include <linux/ioport.h> ++#include <linux/export.h> +#include <asm/delay.h> + +#include <lantiq_soc.h> @@ -905,11 +966,12 @@ Cc: linux-mips@linux-mips.org +#define ltq_status_r32(x) ltq_r32(ltq_status_membase + (x)) + +static inline void -+ltq_sysctl_wait(int module, unsigned int mask, unsigned int test) ++ltq_sysctl_wait(int module, unsigned int mask, ++ unsigned int test, unsigned int reg) +{ + int err = 1000000; + -+ do {} while (--err && ((ltq_reg_r32(module, LTQ_SYSCTL_ACTS) ++ do {} while (--err && ((ltq_reg_r32(module, reg) + & mask) != test)); + if (!err) + pr_err("module de/activation failed %d %08X %08X\n", @@ -924,7 +986,7 @@ Cc: linux-mips@linux-mips.org + + ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); + ltq_reg_w32(module, mask, LTQ_SYSCTL_ACT); -+ ltq_sysctl_wait(module, mask, mask); ++ ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); +} +EXPORT_SYMBOL(ltq_sysctl_activate); + @@ -936,7 +998,7 @@ Cc: linux-mips@linux-mips.org + + ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); + ltq_reg_w32(module, mask, LTQ_SYSCTL_DEACT); -+ ltq_sysctl_wait(module, mask, 0); ++ ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_ACTS); +} +EXPORT_SYMBOL(ltq_sysctl_deactivate); + @@ -947,7 +1009,7 @@ Cc: linux-mips@linux-mips.org + return; + + ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); -+ ltq_sysctl_wait(module, mask, mask); ++ ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_CLKS); +} +EXPORT_SYMBOL(ltq_sysctl_clken); + @@ -958,7 +1020,7 @@ Cc: linux-mips@linux-mips.org + return; + + ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); -+ ltq_sysctl_wait(module, mask, 0); ++ ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_CLKS); +} +EXPORT_SYMBOL(ltq_sysctl_clkdis); + @@ -974,7 +1036,7 @@ Cc: linux-mips@linux-mips.org + if ((~act & mask) != 0) + ltq_sysctl_activate(module, ~act & mask); + ltq_reg_w32(module, act & mask, LTQ_SYSCTL_RBT); -+ ltq_sysctl_wait(module, mask, mask); ++ ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); +} +EXPORT_SYMBOL(ltq_sysctl_reboot); + @@ -1021,3 +1083,6 @@ Cc: linux-mips@linux-mips.org + + ltq_gpe_enable(); +} +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0007-MIPS-lantiq-add-support-for-FALC-ON-GPIOs.patch b/target/linux/lantiq/patches-3.2/0009-MIPS-lantiq-add-support-for-FALC-ON-GPIOs.patch index 2f747d93d2..2e50422bbd 100644 --- a/target/linux/lantiq/patches/0007-MIPS-lantiq-add-support-for-FALC-ON-GPIOs.patch +++ b/target/linux/lantiq/patches-3.2/0009-MIPS-lantiq-add-support-for-FALC-ON-GPIOs.patch @@ -1,27 +1,30 @@ -From 02d9df56be1ba23c7bec51c94e5d2ac0d13d2d78 Mon Sep 17 00:00:00 2001 +From 95e7c9e7b37b06462c8b3b8431dc64d60369eb38 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Aug 2011 14:35:02 +0200 -Subject: [PATCH 07/24] MIPS: lantiq: add support for FALC-ON GPIOs +Subject: [PATCH 09/70] MIPS: lantiq: add support for FALC-ON GPIOs FALC-ON uses a different GPIO core than the other Lantiq SoCs. This patch adds the new driver. Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-mips@linux-mips.org --- arch/mips/lantiq/falcon/Makefile | 2 +- arch/mips/lantiq/falcon/devices.c | 41 ++++ arch/mips/lantiq/falcon/devices.h | 2 + - arch/mips/lantiq/falcon/gpio.c | 398 +++++++++++++++++++++++++++++++++++++ - 4 files changed, 442 insertions(+), 1 deletions(-) + arch/mips/lantiq/falcon/gpio.c | 399 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 443 insertions(+), 1 deletions(-) create mode 100644 arch/mips/lantiq/falcon/gpio.c +diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile +index e9c7455..de72209 100644 --- a/arch/mips/lantiq/falcon/Makefile +++ b/arch/mips/lantiq/falcon/Makefile @@ -1 +1 @@ -obj-y := clk.o prom.o reset.o sysctrl.o devices.o +obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +index c4606f2..4f47b44 100644 --- a/arch/mips/lantiq/falcon/devices.c +++ b/arch/mips/lantiq/falcon/devices.c @@ -9,6 +9,7 @@ @@ -76,6 +79,8 @@ Cc: linux-mips@linux-mips.org + ltq_sysctl_activate(SYSCTL_SYS1, + ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4); +} +diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h +index e802a7c..18be8b6 100644 --- a/arch/mips/lantiq/falcon/devices.h +++ b/arch/mips/lantiq/falcon/devices.h @@ -14,5 +14,7 @@ @@ -86,9 +91,12 @@ Cc: linux-mips@linux-mips.org +extern void falcon_register_gpio_extra(void); #endif +diff --git a/arch/mips/lantiq/falcon/gpio.c b/arch/mips/lantiq/falcon/gpio.c +new file mode 100644 +index 0000000..28f8639 --- /dev/null +++ b/arch/mips/lantiq/falcon/gpio.c -@@ -0,0 +1,398 @@ +@@ -0,0 +1,399 @@ +/* + * 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 @@ -101,6 +109,7 @@ Cc: linux-mips@linux-mips.org +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/slab.h> ++#include <linux/export.h> +#include <linux/platform_device.h> + +#include <lantiq_soc.h> @@ -187,8 +196,8 @@ Cc: linux-mips@linux-mips.org +} +EXPORT_SYMBOL(ltq_gpio_mux_set); + -+int ltq_gpio_request(unsigned int pin, unsigned int val, -+ unsigned int dir, const char *name) ++int ltq_gpio_request(unsigned int pin, unsigned int mux, ++ unsigned int dir, const char *name) +{ + int port = pin / 100; + int offset = pin % 100; @@ -206,7 +215,7 @@ Cc: linux-mips@linux-mips.org + else + gpio_direction_input(pin); + -+ return ltq_gpio_mux_set(pin, val); ++ return ltq_gpio_mux_set(pin, mux); +} +EXPORT_SYMBOL(ltq_gpio_request); + @@ -487,3 +496,6 @@ Cc: linux-mips@linux-mips.org +} + +postcore_initcall(falcon_gpio_init); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0008-MIPS-lantiq-add-support-for-the-EASY98000-evaluation.patch b/target/linux/lantiq/patches-3.2/0010-MIPS-lantiq-add-support-for-the-EASY98000-evaluation.patch index 10c73f5498..93d608e889 100644 --- a/target/linux/lantiq/patches/0008-MIPS-lantiq-add-support-for-the-EASY98000-evaluation.patch +++ b/target/linux/lantiq/patches-3.2/0010-MIPS-lantiq-add-support-for-the-EASY98000-evaluation.patch @@ -1,14 +1,13 @@ -From ec6ba0f79c010a878d679c057fb6306b50a201b0 Mon Sep 17 00:00:00 2001 +From 9397aa9584bade07ae667ecd5135653f9c04e236 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Aug 2011 14:09:35 +0200 -Subject: [PATCH 08/24] MIPS: lantiq: add support for the EASY98000 evaluation +Subject: [PATCH 10/70] MIPS: lantiq: add support for the EASY98000 evaluation board This patch adds the machine code for the EASY9800 evaluation board. Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-mips@linux-mips.org --- arch/mips/lantiq/falcon/Kconfig | 11 +++ arch/mips/lantiq/falcon/Makefile | 1 + @@ -18,6 +17,9 @@ Cc: linux-mips@linux-mips.org create mode 100644 arch/mips/lantiq/falcon/Kconfig create mode 100644 arch/mips/lantiq/falcon/mach-easy98000.c +diff --git a/arch/mips/lantiq/falcon/Kconfig b/arch/mips/lantiq/falcon/Kconfig +new file mode 100644 +index 0000000..03e999d --- /dev/null +++ b/arch/mips/lantiq/falcon/Kconfig @@ -0,0 +1,11 @@ @@ -32,11 +34,16 @@ Cc: linux-mips@linux-mips.org +endmenu + +endif +diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile +index de72209..56b22eb 100644 --- a/arch/mips/lantiq/falcon/Makefile +++ b/arch/mips/lantiq/falcon/Makefile @@ -1 +1,2 @@ obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o +obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o +diff --git a/arch/mips/lantiq/falcon/mach-easy98000.c b/arch/mips/lantiq/falcon/mach-easy98000.c +new file mode 100644 +index 0000000..361b8f0 --- /dev/null +++ b/arch/mips/lantiq/falcon/mach-easy98000.c @@ -0,0 +1,110 @@ @@ -150,6 +157,8 @@ Cc: linux-mips@linux-mips.org + "EASY98000NAND", + "EASY98000 Eval Board (NAND Flash)", + easy98000nand_init); +diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h +index 7e01b8c..dfc6af7 100644 --- a/arch/mips/lantiq/machtypes.h +++ b/arch/mips/lantiq/machtypes.h @@ -15,6 +15,11 @@ enum lantiq_mach_type { @@ -164,3 +173,6 @@ Cc: linux-mips@linux-mips.org }; #endif +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0001-MIPS-lantiq-fix-early-printk.patch b/target/linux/lantiq/patches-3.2/0011-MIPS-lantiq-fix-early-printk.patch index 57b330d2a7..8cffe09b6f 100644 --- a/target/linux/lantiq/patches/0001-MIPS-lantiq-fix-early-printk.patch +++ b/target/linux/lantiq/patches-3.2/0011-MIPS-lantiq-fix-early-printk.patch @@ -1,33 +1,38 @@ -From 91f8d0c8fbb9ea70bf78a291e312157177be8ee3 Mon Sep 17 00:00:00 2001 +From 68e9e86dda22c491e5e3c44271a91aefcf636434 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 20 Aug 2011 18:55:13 +0200 -Subject: [PATCH 01/24] MIPS: lantiq: fix early printk +Subject: [PATCH 11/70] MIPS: lantiq: fix early printk -The code was using a 32bit write operation in the early_printk code. This -resulted in 3 zero bytes also being written to the serial port. Change the -memory access to 8bit. +The code was using a 32bit write operations in the early_printk code. This +resulted in 3 zero bytes also being written to the serial port. This patch +changes the memory access to 8bit. Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-mips@linux-mips.org --- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 4 ++++ + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 6 ++++++ arch/mips/lantiq/early_printk.c | 14 ++++++++------ - 2 files changed, 12 insertions(+), 6 deletions(-) + 2 files changed, 14 insertions(+), 6 deletions(-) +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 87f6d24..e31f52d 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -34,6 +34,10 @@ +@@ -34,6 +34,12 @@ #define LTQ_ASC1_BASE_ADDR 0x1E100C00 #define LTQ_ASC_SIZE 0x400 -+/* during early_printk no ioremap is possible -+ lets use KSEG1 instead */ ++/* ++ * during early_printk no ioremap is possible ++ * lets use KSEG1 instead ++ */ +#define LTQ_EARLY_ASC KSEG1ADDR(LTQ_ASC1_BASE_ADDR) + /* RCU - reset control unit */ #define LTQ_RCU_BASE_ADDR 0x1F203000 #define LTQ_RCU_SIZE 0x1000 +diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c +index 972e05f..5089075 100644 --- a/arch/mips/lantiq/early_printk.c +++ b/arch/mips/lantiq/early_printk.c @@ -12,11 +12,13 @@ @@ -58,3 +63,6 @@ Cc: linux-mips@linux-mips.org + ltq_w8(c, LTQ_ASC_TBUF); local_irq_restore(flags); } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0002-MIPS-lantiq-fix-cmdline-parsing.patch b/target/linux/lantiq/patches-3.2/0012-MIPS-lantiq-fix-cmdline-parsing.patch index 6966e1cbc0..ac8103d427 100644 --- a/target/linux/lantiq/patches/0002-MIPS-lantiq-fix-cmdline-parsing.patch +++ b/target/linux/lantiq/patches-3.2/0012-MIPS-lantiq-fix-cmdline-parsing.patch @@ -1,21 +1,22 @@ -From b85d5204f2fe8c3b5e6172f7cc1741ad6e849334 Mon Sep 17 00:00:00 2001 +From 3be934b64f874e6cd2af7945f4fc441c7fadb34f Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 12 Aug 2011 16:27:38 +0200 -Subject: [PATCH 02/24] MIPS: lantiq: fix cmdline parsing +Subject: [PATCH 12/70] MIPS: lantiq: fix cmdline parsing The code tested if the KSEG1 mapped address of argv was != 0. We need to use CPHYSADDR instead to make the conditional actually work. Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-mips@linux-mips.org --- arch/mips/lantiq/prom.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index e3b1e25..acb8921 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c -@@ -45,10 +45,12 @@ static void __init prom_init_cmdline(voi +@@ -49,10 +49,12 @@ static void __init prom_init_cmdline(void) char **argv = (char **) KSEG1ADDR(fw_arg1); int i; @@ -30,3 +31,6 @@ Cc: linux-mips@linux-mips.org strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0024-MIPS-lantiq-fixes-STP-based-gpios.patch b/target/linux/lantiq/patches-3.2/0013-MIPS-lantiq-fix-STP-gpio-groups.patch index 04f84e0b51..7ca3b7a118 100644 --- a/target/linux/lantiq/patches/0024-MIPS-lantiq-fixes-STP-based-gpios.patch +++ b/target/linux/lantiq/patches-3.2/0013-MIPS-lantiq-fix-STP-gpio-groups.patch @@ -1,9 +1,10 @@ -From 2dfa2b3e50c5ac49052233d15fa427a9b9136df8 Mon Sep 17 00:00:00 2001 +From 556ba7f7149a0350a47ecf26185aed99c8d87176 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 27 Oct 2011 20:06:05 +0200 -Subject: [PATCH 10/22] MIPS: lantiq: fixes STP based gpios +Subject: [PATCH 13/70] MIPS: lantiq: fix STP gpio groups The STP engine has 3 groups of 8 pins. Only the first was activated by default. +This patch activates the 2 missing groups. Signed-off-by: Matti Laakso <malaakso@elisanet.fi> Signed-off-by: John Crispin <blogic@openwrt.org> @@ -11,6 +12,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> arch/mips/lantiq/xway/gpio_stp.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index 2c78660..cb6f170 100644 --- a/arch/mips/lantiq/xway/gpio_stp.c +++ b/arch/mips/lantiq/xway/gpio_stp.c @@ -35,6 +35,8 @@ @@ -34,3 +37,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> /* stp are update periodically by the FPI bus */ ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0025-MIPS-lantiq-activate-pull-up-resistors-when-gpio-is-.patch b/target/linux/lantiq/patches-3.2/0014-MIPS-lantiq-fix-pull-gpio-up-resistors-usage.patch index f8146f78c7..40b8667ca3 100644 --- a/target/linux/lantiq/patches/0025-MIPS-lantiq-activate-pull-up-resistors-when-gpio-is-.patch +++ b/target/linux/lantiq/patches-3.2/0014-MIPS-lantiq-fix-pull-gpio-up-resistors-usage.patch @@ -1,10 +1,10 @@ -From 6efd9a5f303c4561eee14ae429b8c0fafa6c5a83 Mon Sep 17 00:00:00 2001 +From e97f45d255f4a223d38e2f39c1ddf7a3e0766527 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 27 Oct 2011 20:06:30 +0200 -Subject: [PATCH 11/22] MIPS: lantiq: activate pull up resistors when gpio is - a input +Subject: [PATCH 14/70] MIPS: lantiq: fix pull gpio up resistors usage -The register that enables a gpios internal pullups was not set. +The register that enables a gpios internal pullups was not used. This patch +makes sure the pullups are activated correctly. Signed-off-by: Matti Laakso <malaakso@elisanet.fi> Signed-off-by: John Crispin <blogic@openwrt.org> @@ -12,6 +12,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> arch/mips/lantiq/xway/gpio.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) +diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c +index f204f6c..14ff7c7 100644 --- a/arch/mips/lantiq/xway/gpio.c +++ b/arch/mips/lantiq/xway/gpio.c @@ -21,6 +21,8 @@ @@ -23,7 +25,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #define PINS_PER_PORT 16 #define MAX_PORTS 3 -@@ -106,6 +108,8 @@ static int ltq_gpio_direction_input(stru +@@ -106,6 +108,8 @@ static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); @@ -32,7 +34,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> return 0; } -@@ -117,6 +121,8 @@ static int ltq_gpio_direction_output(str +@@ -117,6 +121,8 @@ static int ltq_gpio_direction_output(struct gpio_chip *chip, ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); @@ -41,3 +43,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> ltq_gpio_set(chip, offset, value); return 0; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0015-MIPS-lantiq-add-default-configs.patch b/target/linux/lantiq/patches-3.2/0015-MIPS-lantiq-add-default-configs.patch new file mode 100644 index 0000000000..bc55e51ee0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0015-MIPS-lantiq-add-default-configs.patch @@ -0,0 +1,247 @@ +From 9946990028431fc732d1244c6ccdfface1ee5640 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 11 Nov 2011 22:02:27 +0100 +Subject: [PATCH 15/70] MIPS: lantiq: add default configs + +This patch adds the default config for 3 Lantiq SoCs + +* Danube/AR9 (xway) +* Amazon-SE +* Falc-ON + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/configs/ase_defconfig | 67 +++++++++++++++++++++++++++++++++ + arch/mips/configs/falcon_defconfig | 72 ++++++++++++++++++++++++++++++++++++ + arch/mips/configs/xway_defconfig | 66 +++++++++++++++++++++++++++++++++ + 3 files changed, 205 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/configs/ase_defconfig + create mode 100644 arch/mips/configs/falcon_defconfig + create mode 100644 arch/mips/configs/xway_defconfig + +diff --git a/arch/mips/configs/ase_defconfig b/arch/mips/configs/ase_defconfig +new file mode 100644 +index 0000000..5bb1d93 +--- /dev/null ++++ b/arch/mips/configs/ase_defconfig +@@ -0,0 +1,67 @@ ++CONFIG_LANTIQ=y ++CONFIG_SOC_AMAZON_SE=y ++CONFIG_CPU_MIPS32_R2=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_EXPERIMENTAL=y ++CONFIG_DEFAULT_HOSTNAME="amazon_se" ++CONFIG_SYSVIPC=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="../root-lantiq/ ../root-lantiq/initramfs-base-files.txt" ++CONFIG_INITRAMFS_ROOT_UID=1000 ++CONFIG_INITRAMFS_ROOT_GID=1000 +++# CONFIG_RD_GZIP is not set ++CONFIG_RD_LZMA=y ++CONFIG_EMBEDDED=y ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_DEFAULT_DEADLINE=y ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_IP_ROUTE_VERBOSE=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++CONFIG_NETFILTER=y ++CONFIG_BRIDGE=m ++CONFIG_VLAN_8021Q=y ++CONFIG_NET_SCHED=y ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_GEOMETRY=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++CONFIG_MTD_COMPLEX_MAPPINGS=y ++CONFIG_MTD_LANTIQ=y ++CONFIG_MISC_DEVICES=y ++CONFIG_NETDEVICES=y ++CONFIG_MII=y ++CONFIG_LANTIQ_ETOP=y ++CONFIG_PHYLIB=y ++CONFIG_SERIAL_LANTIQ=y ++CONFIG_PINCTRL=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_WATCHDOG=y ++CONFIG_LANTIQ_WDT=y ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_SUMMARY=y ++CONFIG_JFFS2_FS_XATTR=y ++CONFIG_JFFS2_COMPRESSION_OPTIONS=y ++CONFIG_SQUASHFS=y ++CONFIG_SQUASHFS_XZ=y ++CONFIG_STRIP_ASM_SYMS=y ++CONFIG_DEBUG_FS=y +diff --git a/arch/mips/configs/falcon_defconfig b/arch/mips/configs/falcon_defconfig +new file mode 100644 +index 0000000..ce242a8 +--- /dev/null ++++ b/arch/mips/configs/falcon_defconfig +@@ -0,0 +1,72 @@ ++CONFIG_LANTIQ=y ++CONFIG_SOC_FALCON=y ++CONFIG_CPU_MIPS32_R2=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_EXPERIMENTAL=y ++CONFIG_DEFAULT_HOSTNAME="falcon" ++CONFIG_SYSVIPC=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="../root-lantiq/ ../root-lantiq/initramfs-base-files.txt" ++CONFIG_INITRAMFS_ROOT_UID=1000 ++CONFIG_INITRAMFS_ROOT_GID=1000 +++# CONFIG_RD_GZIP is not set ++CONFIG_RD_LZMA=y ++CONFIG_EMBEDDED=y ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_DEFAULT_DEADLINE=y ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_IP_ROUTE_VERBOSE=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++CONFIG_NETFILTER=y ++CONFIG_BRIDGE=m ++CONFIG_VLAN_8021Q=y ++CONFIG_NET_SCHED=y ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_GEOMETRY=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++CONFIG_MTD_COMPLEX_MAPPINGS=y ++CONFIG_MTD_LANTIQ=y ++CONFIG_MTD_M25P80=y ++CONFIG_MISC_DEVICES=y ++CONFIG_EEPROM_AT24=y ++CONFIG_NETDEVICES=y ++CONFIG_MII=y ++CONFIG_PHYLIB=y ++CONFIG_SERIAL_LANTIQ=y ++CONFIG_I2C=y ++CONFIG_I2C_FALCON=y ++CONFIG_SPI=y ++CONFIG_SPI_FALCON=y ++CONFIG_PINCTRL=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_WATCHDOG=y ++CONFIG_LANTIQ_WDT=y ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_SUMMARY=y ++CONFIG_JFFS2_FS_XATTR=y ++CONFIG_JFFS2_COMPRESSION_OPTIONS=y ++CONFIG_SQUASHFS=y ++CONFIG_SQUASHFS_XZ=y ++CONFIG_STRIP_ASM_SYMS=y ++CONFIG_DEBUG_FS=y +diff --git a/arch/mips/configs/xway_defconfig b/arch/mips/configs/xway_defconfig +new file mode 100644 +index 0000000..510a964 +--- /dev/null ++++ b/arch/mips/configs/xway_defconfig +@@ -0,0 +1,66 @@ ++CONFIG_LANTIQ=y ++CONFIG_CPU_MIPS32_R2=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_EXPERIMENTAL=y ++CONFIG_DEFAULT_HOSTNAME="danube" ++CONFIG_SYSVIPC=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="../root-lantiq/ ../root-lantiq/initramfs-base-files.txt" ++CONFIG_INITRAMFS_ROOT_UID=1000 ++CONFIG_INITRAMFS_ROOT_GID=1000 ++# CONFIG_RD_GZIP is not set ++CONFIG_RD_LZMA=y ++CONFIG_EMBEDDED=y ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_DEFAULT_DEADLINE=y ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_IP_ROUTE_VERBOSE=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++CONFIG_NETFILTER=y ++CONFIG_BRIDGE=m ++CONFIG_VLAN_8021Q=y ++CONFIG_NET_SCHED=y ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_GEOMETRY=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++CONFIG_MTD_COMPLEX_MAPPINGS=y ++CONFIG_MTD_LANTIQ=y ++CONFIG_MISC_DEVICES=y ++CONFIG_NETDEVICES=y ++CONFIG_MII=y ++CONFIG_LANTIQ_ETOP=y ++CONFIG_PHYLIB=y ++CONFIG_SERIAL_LANTIQ=y ++CONFIG_PINCTRL=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_WATCHDOG=y ++CONFIG_LANTIQ_WDT=y ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_SUMMARY=y ++CONFIG_JFFS2_FS_XATTR=y ++CONFIG_JFFS2_COMPRESSION_OPTIONS=y ++CONFIG_SQUASHFS=y ++CONFIG_SQUASHFS_XZ=y ++CONFIG_STRIP_ASM_SYMS=y ++CONFIG_DEBUG_FS=y +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0016-MAINTAINERS-add-entry-for-Lantiq-related-files.patch b/target/linux/lantiq/patches-3.2/0016-MAINTAINERS-add-entry-for-Lantiq-related-files.patch new file mode 100644 index 0000000000..9b8e3240ab --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0016-MAINTAINERS-add-entry-for-Lantiq-related-files.patch @@ -0,0 +1,38 @@ +From c68f8bdcd4c58a0c1d92e20230a943e8089d865a Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 10 Nov 2011 19:32:37 +0100 +Subject: [PATCH 16/70] MAINTAINERS: add entry for Lantiq related files + +Adds new entry to MAINTAINERS file for Lantiq SoC related code. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + MAINTAINERS | 12 ++++++++++++ + 1 files changed, 12 insertions(+), 0 deletions(-) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 62f1cd3..c04defd 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4348,6 +4348,18 @@ S: Supported + F: Documentation/mips/ + F: arch/mips/ + ++MIPS/LANTIQ ++M: John Crispin <blogic@openwrt.org> ++M: Thomas Langer <thomas.langer@lantiq.com> ++S: Maintained ++F: arch/mips/lantiq/* ++F: drivers/i2c/busses/i2c-falcon.c ++F: drivers/mtd/maps/lantiq-flash.c ++F: drivers/net/ethernet/lantiq_etop.c ++F: drivers/spi/spi-falcon.c ++F: drivers/tty/serial/lantiq.c ++F: drivers/watchdog/lantiq_wdt.c ++ + MISCELLANEOUS MCA-SUPPORT + M: James Bottomley <James.Bottomley@HansenPartnership.com> + S: Maintained +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0017-MIPS-make-oprofile-use-cp0_perfcount_irq-if-it-is-se.patch b/target/linux/lantiq/patches-3.2/0017-MIPS-make-oprofile-use-cp0_perfcount_irq-if-it-is-se.patch new file mode 100644 index 0000000000..a879cd8ba1 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0017-MIPS-make-oprofile-use-cp0_perfcount_irq-if-it-is-se.patch @@ -0,0 +1,55 @@ +From bc3a07e6c5149a82a22239a43e9f98514c2010d9 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 24 Aug 2011 13:24:11 +0200 +Subject: [PATCH 17/70] MIPS: make oprofile use cp0_perfcount_irq if it is set + +The patch makes the oprofile code use the performance counters irq. + +This patch is written by Felix Fietkau. + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/oprofile/op_model_mipsxx.c | 12 ++++++++++++ + 1 files changed, 12 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c +index 54759f1..86cf234 100644 +--- a/arch/mips/oprofile/op_model_mipsxx.c ++++ b/arch/mips/oprofile/op_model_mipsxx.c +@@ -298,6 +298,11 @@ static void reset_counters(void *arg) + } + } + ++static irqreturn_t mipsxx_perfcount_int(int irq, void *dev_id) ++{ ++ return mipsxx_perfcount_handler(); ++} ++ + static int __init mipsxx_init(void) + { + int counters; +@@ -374,6 +379,10 @@ static int __init mipsxx_init(void) + save_perf_irq = perf_irq; + perf_irq = mipsxx_perfcount_handler; + ++ if (cp0_perfcount_irq >= 0) ++ return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int, ++ IRQF_SHARED, "Perfcounter", save_perf_irq); ++ + return 0; + } + +@@ -381,6 +390,9 @@ static void mipsxx_exit(void) + { + int counters = op_model_mipsxx_ops.num_counters; + ++ if (cp0_perfcount_irq >= 0) ++ free_irq(cp0_perfcount_irq, save_perf_irq); ++ + counters = counters_per_cpu_to_total(counters); + on_each_cpu(reset_counters, (void *)(long)counters, 1); + +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0010-MIPS-enable-oprofile-support-on-lantiq-targets.patch b/target/linux/lantiq/patches-3.2/0018-MIPS-lantiq-enable-oprofile-support-on-lantiq-target.patch index d05178861f..7ab5ff76bd 100644 --- a/target/linux/lantiq/patches/0010-MIPS-enable-oprofile-support-on-lantiq-targets.patch +++ b/target/linux/lantiq/patches-3.2/0018-MIPS-lantiq-enable-oprofile-support-on-lantiq-target.patch @@ -1,20 +1,23 @@ -From cc4b9cdff8665a414ae51101d3a0ca6ed7444a27 Mon Sep 17 00:00:00 2001 +From e0bd3f1b16fbce1f0f7900a0dd624f9dc8a47f78 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Wed, 24 Aug 2011 13:28:55 +0200 -Subject: [PATCH 10/24] MIPS: enable oprofile support on lantiq targets +Subject: [PATCH 18/70] MIPS: lantiq: enable oprofile support on lantiq + targets -This patch sets the performance counters irq and HAVE_OPROFILE flag. +This patch sets the performance counters irq and HAVE_OPROFILE flag for Lantiq +SoCs. Signed-off-by: John Crispin <blogic@openwrt.org> -Cc: linux-mips@linux-mips.org --- arch/mips/Kconfig | 1 + arch/mips/lantiq/irq.c | 5 +++++ 2 files changed, 6 insertions(+), 0 deletions(-) +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index d46f1da..c1ceadb 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -230,6 +230,7 @@ config LANTIQ +@@ -226,6 +226,7 @@ config LANTIQ select SWAP_IO_SPACE select BOOT_RAW select HAVE_CLK @@ -22,6 +25,8 @@ Cc: linux-mips@linux-mips.org select MIPS_MACHINE config LASAT +diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c +index 17c057f..0b2ed87 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -40,6 +40,9 @@ @@ -43,3 +48,6 @@ Cc: linux-mips@linux-mips.org } unsigned int __cpuinit get_c0_compare_int(void) +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0015-MIPS-lantiq-adds-etop-support-for-ase-ar9.patch b/target/linux/lantiq/patches-3.2/0019-NET-MIPS-lantiq-make-etop-ethernet-work-on-ase-ar9.patch index 503c6bf78e..d7e2ed94a5 100644 --- a/target/linux/lantiq/patches/0015-MIPS-lantiq-adds-etop-support-for-ase-ar9.patch +++ b/target/linux/lantiq/patches-3.2/0019-NET-MIPS-lantiq-make-etop-ethernet-work-on-ase-ar9.patch @@ -1,25 +1,26 @@ -From c7881d8d2b3aed9a90aa37dcf797328a9cfbe7b6 Mon Sep 17 00:00:00 2001 +From 4b24c79196e5777baff0f5d53b62cf2a964e26ff Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Wed, 10 Aug 2011 15:32:16 +0200 -Subject: [PATCH 15/24] MIPS: lantiq: adds etop support for ase/ar9 +Subject: [PATCH 19/70] NET: MIPS: lantiq: make etop ethernet work on ase/ar9 Extend the driver to handle the different DMA channel layout for AR9 and -SoCs. The patch also adds support for the integrated PHY found on Amazon-SE -and the gigabit switch found inside the AR9. +Amazon-SE SoCs. The patch also adds support for the integrated PHY found +on Amazon-SE and the gigabit switch found inside the AR9. Signed-off-by: John Crispin <blogic@openwrt.org> -Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> +Cc: netdev@vger.kernel.org --- .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 22 +--- .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 10 ++ arch/mips/lantiq/xway/devices.c | 11 +- - arch/mips/lantiq/xway/mach-easy50601.c | 5 + - drivers/net/lantiq_etop.c | 172 ++++++++++++++++++-- - 5 files changed, 180 insertions(+), 40 deletions(-) + drivers/net/ethernet/lantiq_etop.c | 171 ++++++++++++++++++-- + 4 files changed, 174 insertions(+), 40 deletions(-) +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +index b4465a8..2a8d5ad 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h -@@ -40,26 +40,8 @@ +@@ -38,26 +38,8 @@ #define MIPS_CPU_TIMER_IRQ 7 @@ -48,17 +49,19 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> #define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index e31f52d..6983d75 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -80,6 +80,7 @@ +@@ -82,6 +82,7 @@ #define LTQ_PMU_SIZE 0x1000 #define PMU_DMA 0x0020 +#define PMU_EPHY 0x0080 #define PMU_USB 0x8041 - #define PMU_SPI 0x0100 #define PMU_LED 0x0800 -@@ -92,6 +93,10 @@ + #define PMU_GPT 0x1000 +@@ -93,6 +94,10 @@ #define LTQ_ETOP_BASE_ADDR 0x1E180000 #define LTQ_ETOP_SIZE 0x40000 @@ -69,7 +72,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> /* DMA */ #define LTQ_DMA_BASE_ADDR 0x1E104100 #define LTQ_DMA_SIZE 0x800 -@@ -146,6 +151,11 @@ extern void ltq_pmu_enable(unsigned int +@@ -147,6 +152,11 @@ extern void ltq_pmu_enable(unsigned int module); extern void ltq_pmu_disable(unsigned int module); extern void ltq_cgu_enable(unsigned int clk); @@ -81,6 +84,8 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> static inline int ltq_is_ar9(void) { return (ltq_get_soc_type() == SOC_TYPE_AR9); +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index f97e565..eab4644d 100644 --- a/arch/mips/lantiq/xway/devices.c +++ b/arch/mips/lantiq/xway/devices.c @@ -74,18 +74,23 @@ void __init ltq_register_ase_asc(void) @@ -110,23 +115,18 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> if (eth) { ltq_etop.dev.platform_data = eth; platform_device_register(<q_etop); ---- a/drivers/net/lantiq_etop.c -+++ b/drivers/net/lantiq_etop.c -@@ -34,6 +34,7 @@ - #include <linux/init.h> - #include <linux/delay.h> - #include <linux/io.h> -+#include <linux/dma-mapping.h> - - #include <asm/checksum.h> - -@@ -69,10 +70,43 @@ +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index 0b3567a..d3d4931 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -71,10 +71,43 @@ #define ETOP_MII_REVERSE 0xe #define ETOP_PLEN_UNDER 0x40 #define ETOP_CGEN 0x800 -+#define ETOP_CFG_MII0 0x01 - +- -/* use 2 static channels for TX/RX */ ++#define ETOP_CFG_MII0 0x01 ++ +#define LTQ_GBIT_MDIO_CTL 0xCC +#define LTQ_GBIT_MDIO_DATA 0xd0 +#define LTQ_GBIT_GCTL0 0x68 @@ -166,7 +166,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> #define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) #define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) -@@ -81,9 +115,15 @@ +@@ -83,9 +116,15 @@ #define ltq_etop_w32_mask(x, y, z) \ ltq_w32_mask(x, y, ltq_etop_membase + (z)) @@ -182,7 +182,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> struct ltq_etop_chan { int idx; -@@ -108,6 +148,9 @@ struct ltq_etop_priv { +@@ -110,6 +149,9 @@ struct ltq_etop_priv { spinlock_t lock; }; @@ -192,7 +192,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> static int ltq_etop_alloc_skb(struct ltq_etop_chan *ch) { -@@ -209,7 +252,7 @@ static irqreturn_t +@@ -211,7 +253,7 @@ static irqreturn_t ltq_etop_dma_irq(int irq, void *_priv) { struct ltq_etop_priv *priv = _priv; @@ -201,7 +201,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> napi_schedule(&priv->ch[ch].napi); return IRQ_HANDLED; -@@ -242,26 +285,66 @@ ltq_etop_hw_exit(struct net_device *dev) +@@ -244,15 +286,43 @@ ltq_etop_hw_exit(struct net_device *dev) ltq_etop_free_channel(dev, &priv->ch[i]); } @@ -210,8 +210,8 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> +{ + ltq_pmu_enable(PMU_SWITCH); + -+ ltq_gpio_request(42, 1, 0, 1, "MDIO"); -+ ltq_gpio_request(43, 1, 0, 1, "MDC"); ++ ltq_gpio_request(42, 2, 1, "MDIO"); ++ ltq_gpio_request(43, 2, 1, "MDC"); + + ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); + /** Disable MDIO auto polling mode */ @@ -238,19 +238,15 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> - switch (priv->pldata->mii_mode) { + if (ltq_has_gbit()) { + ltq_etop_gbit_init(); ++ /* force the etops link to the gbit to MII */ ++ mii_mode = PHY_INTERFACE_MODE_MII; + } + + switch (mii_mode) { -+ case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RMII: ltq_etop_w32_mask(ETOP_MII_MASK, ETOP_MII_REVERSE, LTQ_ETOP_CFG); - break; - -+ case PHY_INTERFACE_MODE_GMII: - case PHY_INTERFACE_MODE_MII: - ltq_etop_w32_mask(ETOP_MII_MASK, - ETOP_MII_NORMAL, LTQ_ETOP_CFG); +@@ -264,6 +334,18 @@ ltq_etop_hw_init(struct net_device *dev) break; default: @@ -269,7 +265,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> netdev_err(dev, "unknown mii mode %d\n", priv->pldata->mii_mode); return -ENOTSUPP; -@@ -273,7 +356,7 @@ ltq_etop_hw_init(struct net_device *dev) +@@ -275,7 +357,7 @@ ltq_etop_hw_init(struct net_device *dev) ltq_dma_init_port(DMA_PORT_ETOP); for (i = 0; i < MAX_DMA_CHAN; i++) { @@ -278,7 +274,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> struct ltq_etop_chan *ch = &priv->ch[i]; ch->idx = ch->dma.nr = i; -@@ -337,6 +420,39 @@ static const struct ethtool_ops ltq_etop +@@ -339,6 +421,39 @@ static const struct ethtool_ops ltq_etop_ethtool_ops = { }; static int @@ -318,7 +314,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data) { u32 val = MDIO_REQUEST | -@@ -377,14 +493,11 @@ ltq_etop_mdio_probe(struct net_device *d +@@ -379,14 +494,11 @@ ltq_etop_mdio_probe(struct net_device *dev) { struct ltq_etop_priv *priv = netdev_priv(dev); struct phy_device *phydev = NULL; @@ -337,7 +333,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> if (!phydev) { netdev_err(dev, "no PHY found\n"); -@@ -406,6 +519,9 @@ ltq_etop_mdio_probe(struct net_device *d +@@ -408,6 +520,9 @@ ltq_etop_mdio_probe(struct net_device *dev) | SUPPORTED_Autoneg | SUPPORTED_MII | SUPPORTED_TP); @@ -347,7 +343,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> phydev->advertising = phydev->supported; priv->phydev = phydev; -@@ -431,8 +547,13 @@ ltq_etop_mdio_init(struct net_device *de +@@ -433,8 +548,13 @@ ltq_etop_mdio_init(struct net_device *dev) } priv->mii_bus->priv = dev; @@ -363,7 +359,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> priv->mii_bus->name = "ltq_mii"; snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); -@@ -522,9 +643,9 @@ ltq_etop_tx(struct sk_buff *skb, struct +@@ -524,9 +644,9 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) struct ltq_etop_priv *priv = netdev_priv(dev); struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1]; struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; @@ -374,7 +370,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; -@@ -698,7 +819,7 @@ ltq_etop_probe(struct platform_device *p +@@ -700,7 +820,7 @@ ltq_etop_probe(struct platform_device *pdev) { struct net_device *dev; struct ltq_etop_priv *priv; @@ -383,7 +379,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> int err; int i; -@@ -726,6 +847,23 @@ ltq_etop_probe(struct platform_device *p +@@ -728,6 +848,23 @@ ltq_etop_probe(struct platform_device *pdev) goto err_out; } @@ -407,3 +403,6 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); strcpy(dev->name, "eth%d"); dev->netdev_ops = <q_eth_netdev_ops; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch b/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch new file mode 100644 index 0000000000..c0cc3d6fc0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0020-NET-MIPS-lantiq-non-existing-phy-was-not-handled-gra.patch @@ -0,0 +1,67 @@ +From d9cddd0b4062e66f350297b4b855ef4db3a1c16b Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 15 Nov 2011 14:52:21 +0100 +Subject: [PATCH 20/70] NET: MIPS: lantiq: non existing phy was not handled + gracefully + +The code blindly assumed that that a PHY device was present causing a BadVA. +In addition the driver should not fail to load incase no PHY was found. +Instead we print the following line and continue with no attached PHY. + + etop: mdio probe failed + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: netdev@vger.kernel.org +--- + drivers/net/ethernet/lantiq_etop.c | 14 ++++++++------ + 1 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index d3d4931..9fd6779 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -612,7 +612,8 @@ ltq_etop_open(struct net_device *dev) + ltq_dma_open(&ch->dma); + napi_enable(&ch->napi); + } +- phy_start(priv->phydev); ++ if (priv->phydev) ++ phy_start(priv->phydev); + netif_tx_start_all_queues(dev); + return 0; + } +@@ -624,7 +625,8 @@ ltq_etop_stop(struct net_device *dev) + int i; + + netif_tx_stop_all_queues(dev); +- phy_stop(priv->phydev); ++ if (priv->phydev) ++ phy_stop(priv->phydev); + for (i = 0; i < MAX_DMA_CHAN; i++) { + struct ltq_etop_chan *ch = &priv->ch[i]; + +@@ -770,9 +772,10 @@ ltq_etop_init(struct net_device *dev) + if (err) + goto err_netdev; + ltq_etop_set_multicast_list(dev); +- err = ltq_etop_mdio_init(dev); +- if (err) +- goto err_netdev; ++ if (!ltq_etop_mdio_init(dev)) ++ dev->ethtool_ops = <q_etop_ethtool_ops; ++ else ++ pr_warn("etop: mdio probe failed\n");; + return 0; + + err_netdev: +@@ -868,7 +871,6 @@ ltq_etop_probe(struct platform_device *pdev) + dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); + strcpy(dev->name, "eth%d"); + dev->netdev_ops = <q_eth_netdev_ops; +- dev->ethtool_ops = <q_etop_ethtool_ops; + priv = netdev_priv(dev); + priv->res = res; + priv->pldata = dev_get_platdata(&pdev->dev); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0021-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch b/target/linux/lantiq/patches-3.2/0021-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch new file mode 100644 index 0000000000..f27ebfbfdf --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0021-NET-MIPS-lantiq-return-value-of-request_irq-was-not-.patch @@ -0,0 +1,71 @@ +From 6916ef9742e45213d524b69700d937976098d1e6 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 15 Nov 2011 15:56:06 +0100 +Subject: [PATCH 21/70] NET: MIPS: lantiq: return value of request_irq was not + handled gracefully + +The return values of request_irq() were not checked leading to the following +error message. + +drivers/net/ethernet/lantiq_etop.c: In function 'ltq_etop_hw_init': +drivers/net/ethernet/lantiq_etop.c:368:15: warning: ignoring return value of 'request_irq', declared with attribute warn_unused_result +drivers/net/ethernet/lantiq_etop.c:377:15: warning: ignoring return value of 'request_irq', declared with attribute warn_unused_result + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: netdev@vger.kernel.org +--- + drivers/net/ethernet/lantiq_etop.c | 14 ++++++++------ + 1 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index 9fd6779..dddb9fe 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -312,6 +312,7 @@ ltq_etop_hw_init(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned int mii_mode = priv->pldata->mii_mode; ++ int err = 0; + int i; + + ltq_pmu_enable(PMU_PPE); +@@ -356,7 +357,7 @@ ltq_etop_hw_init(struct net_device *dev) + + ltq_dma_init_port(DMA_PORT_ETOP); + +- for (i = 0; i < MAX_DMA_CHAN; i++) { ++ for (i = 0; i < MAX_DMA_CHAN && !err; i++) { + int irq = LTQ_DMA_ETOP + i; + struct ltq_etop_chan *ch = &priv->ch[i]; + +@@ -364,21 +365,22 @@ ltq_etop_hw_init(struct net_device *dev) + + if (IS_TX(i)) { + ltq_dma_alloc_tx(&ch->dma); +- request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, + "etop_tx", priv); + } else if (IS_RX(i)) { + ltq_dma_alloc_rx(&ch->dma); + for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; + ch->dma.desc++) + if (ltq_etop_alloc_skb(ch)) +- return -ENOMEM; ++ err = -ENOMEM; + ch->dma.desc = 0; +- request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, + "etop_rx", priv); + } +- ch->dma.irq = irq; ++ if (!err) ++ ch->dma.irq = irq; + } +- return 0; ++ return err; + } + + static void +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0022-MIPS-lantiq-use-devres-managed-gpios.patch b/target/linux/lantiq/patches-3.2/0022-MIPS-lantiq-use-devres-managed-gpios.patch new file mode 100644 index 0000000000..0d4a92769a --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0022-MIPS-lantiq-use-devres-managed-gpios.patch @@ -0,0 +1,282 @@ +From 9819317c005d57e1a5924af1faa43f73ed156a2d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 08:37:25 +0100 +Subject: [PATCH 22/70] MIPS: lantiq: use devres managed gpios + +3.2 introduced devm_request_gpio() to allow managed gpios. + +The devres api requires a struct device pointer to work. Add a parameter to ltq_gpio_request() +so that managed gpios can work. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 4 +--- + arch/mips/include/asm/mach-lantiq/lantiq.h | 4 ++++ + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 --- + arch/mips/lantiq/falcon/gpio.c | 4 ++-- + arch/mips/lantiq/falcon/prom.c | 7 ------- + arch/mips/lantiq/xway/gpio.c | 4 ++-- + arch/mips/lantiq/xway/gpio_stp.c | 13 ++++++++----- + arch/mips/pci/pci-lantiq.c | 18 ++++++++++-------- + drivers/net/ethernet/lantiq_etop.c | 9 ++++++--- + drivers/tty/serial/lantiq.c | 12 ++++++++++++ + 10 files changed, 45 insertions(+), 33 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +index b074748..a5dc06a 100644 +--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -126,9 +126,7 @@ extern __iomem void *ltq_sys1_membase; + #define ltq_sys1_w32_mask(clear, set, reg) \ + ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg) + +-/* gpio_request wrapper to help configure the pin */ +-extern int ltq_gpio_request(unsigned int pin, unsigned int mux, +- unsigned int dir, const char *name); ++/* gpio wrapper to help configure the pin muxing */ + extern int ltq_gpio_mux_set(unsigned int pin, unsigned int mux); + + /* to keep the irq code generic we need to define these to 0 as falcon +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h +index 188de0f..924b91a 100644 +--- a/arch/mips/include/asm/mach-lantiq/lantiq.h ++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h +@@ -37,6 +37,10 @@ extern unsigned int ltq_get_soc_type(void); + /* spinlock all ebu i/o */ + extern spinlock_t ebu_lock; + ++/* request a non-gpio and set the PIO config */ ++extern int ltq_gpio_request(struct device *dev, unsigned int pin, ++ unsigned int mux, unsigned int dir, const char *name); ++ + /* some irq helpers */ + extern void ltq_disable_irq(struct irq_data *data); + extern void ltq_mask_and_ack_irq(struct irq_data *data); +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 6983d75..6c5b705 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -145,9 +145,6 @@ + extern __iomem void *ltq_ebu_membase; + extern __iomem void *ltq_cgu_membase; + +-/* request a non-gpio and set the PIO config */ +-extern int ltq_gpio_request(unsigned int pin, unsigned int mux, +- unsigned int dir, const char *name); + extern void ltq_pmu_enable(unsigned int module); + extern void ltq_pmu_disable(unsigned int module); + extern void ltq_cgu_enable(unsigned int clk); +diff --git a/arch/mips/lantiq/falcon/gpio.c b/arch/mips/lantiq/falcon/gpio.c +index 28f8639..a44f71b 100644 +--- a/arch/mips/lantiq/falcon/gpio.c ++++ b/arch/mips/lantiq/falcon/gpio.c +@@ -97,7 +97,7 @@ int ltq_gpio_mux_set(unsigned int pin, unsigned int mux) + } + EXPORT_SYMBOL(ltq_gpio_mux_set); + +-int ltq_gpio_request(unsigned int pin, unsigned int mux, ++int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, + unsigned int dir, const char *name) + { + int port = pin / 100; +@@ -106,7 +106,7 @@ int ltq_gpio_request(unsigned int pin, unsigned int mux, + if (offset >= PINS_PER_PORT || port >= MAX_PORTS) + return -EINVAL; + +- if (gpio_request(pin, name)) { ++ if (devm_gpio_request(dev, pin, name)) { + pr_err("failed to setup lantiq gpio: %s\n", name); + return -EBUSY; + } +diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c +index b50d6f9..f98b389 100644 +--- a/arch/mips/lantiq/falcon/prom.c ++++ b/arch/mips/lantiq/falcon/prom.c +@@ -27,9 +27,6 @@ + #define TYPE_SHIFT 26 + #define TYPE_MASK 0x3C000000 + +-#define MUXC_SIF_RX_PIN 112 +-#define MUXC_SIF_TX_PIN 113 +- + /* this parameter allows us enable/disable asc1 via commandline */ + static int register_asc1; + static int __init +@@ -48,10 +45,6 @@ ltq_soc_setup(void) + falcon_register_gpio(); + if (register_asc1) { + ltq_register_asc(1); +- if (ltq_gpio_request(MUXC_SIF_RX_PIN, 3, 0, "asc1-rx")) +- pr_err("failed to request asc1-rx"); +- if (ltq_gpio_request(MUXC_SIF_TX_PIN, 3, 1, "asc1-tx")) +- pr_err("failed to request asc1-tx"); + ltq_sysctl_activate(SYSCTL_SYS1, ACTS_ASC1_ACT); + } + } +diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c +index 14ff7c7..54ec6c9 100644 +--- a/arch/mips/lantiq/xway/gpio.c ++++ b/arch/mips/lantiq/xway/gpio.c +@@ -50,14 +50,14 @@ int irq_to_gpio(unsigned int gpio) + } + EXPORT_SYMBOL(irq_to_gpio); + +-int ltq_gpio_request(unsigned int pin, unsigned int mux, ++int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, + unsigned int dir, const char *name) + { + int id = 0; + + if (pin >= (MAX_PORTS * PINS_PER_PORT)) + return -EINVAL; +- if (gpio_request(pin, name)) { ++ if (devm_gpio_request(dev, pin, name)) { + pr_err("failed to setup lantiq gpio: %s\n", name); + return -EBUSY; + } +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index cb6f170..e6b4809 100644 +--- a/arch/mips/lantiq/xway/gpio_stp.c ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -80,11 +80,6 @@ static struct gpio_chip ltq_stp_chip = { + + static int ltq_stp_hw_init(void) + { +- /* the 3 pins used to control the external stp */ +- ltq_gpio_request(4, 2, 1, "stp-st"); +- ltq_gpio_request(5, 2, 1, "stp-d"); +- ltq_gpio_request(6, 2, 1, "stp-sh"); +- + /* sane defaults */ + ltq_stp_w32(0, LTQ_STP_AR); + ltq_stp_w32(0, LTQ_STP_CPU0); +@@ -133,6 +128,14 @@ static int __devinit ltq_stp_probe(struct platform_device *pdev) + dev_err(&pdev->dev, "failed to remap STP memory\n"); + return -ENOMEM; + } ++ ++ /* the 3 pins used to control the external stp */ ++ if (ltq_gpio_request(&pdev->dev, 4, 2, 1, "stp-st") || ++ ltq_gpio_request(&pdev->dev, 5, 2, 1, "stp-d") || ++ ltq_gpio_request(&pdev->dev, 6, 2, 1, "stp-sh")) { ++ dev_err(&pdev->dev, "failed to request needed gpios\n"); ++ return -EBUSY; ++ } + ret = gpiochip_add(<q_stp_chip); + if (!ret) + ret = ltq_stp_hw_init(); +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +index c001c5a..47b551c 100644 +--- a/arch/mips/pci/pci-lantiq.c ++++ b/arch/mips/pci/pci-lantiq.c +@@ -150,24 +150,26 @@ static u32 ltq_calc_bar11mask(void) + return bar11mask; + } + +-static void ltq_pci_setup_gpio(int gpio) ++static void ltq_pci_setup_gpio(struct device *dev) + { ++ struct ltq_pci_data *conf = (struct ltq_pci_data *) dev->platform_data; + int i; + for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) { +- if (gpio & (1 << i)) { +- ltq_gpio_request(ltq_pci_gpio_map[i].pin, ++ if (conf->gpio & (1 << i)) { ++ ltq_gpio_request(dev, ltq_pci_gpio_map[i].pin, + ltq_pci_gpio_map[i].mux, + ltq_pci_gpio_map[i].dir, + ltq_pci_gpio_map[i].name); + } + } +- ltq_gpio_request(21, 0, 1, "pci-reset"); +- ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; ++ ltq_gpio_request(dev, 21, 0, 1, "pci-reset"); ++ ltq_pci_req_mask = (conf->gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; + } + +-static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) ++static int __devinit ltq_pci_startup(struct device *dev) + { + u32 temp_buffer; ++ struct ltq_pci_data *conf = (struct ltq_pci_data *) dev->platform_data; + + /* set clock to 33Mhz */ + if (ltq_is_ar9()) { +@@ -190,7 +192,7 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) + } + + /* setup pci clock and gpis used by pci */ +- ltq_pci_setup_gpio(conf->gpio); ++ ltq_pci_setup_gpio(dev); + + /* enable auto-switching between PCI and EBU */ + ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); +@@ -275,7 +277,7 @@ static int __devinit ltq_pci_probe(struct platform_device *pdev) + ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); + ltq_pci_controller.io_map_base = + (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); +- ltq_pci_startup(ltq_pci_data); ++ ltq_pci_startup(&pdev->dev); + register_pci_controller(<q_pci_controller); + + return 0; +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index dddb9fe..fcbb9c7 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -291,9 +291,6 @@ ltq_etop_gbit_init(void) + { + ltq_pmu_enable(PMU_SWITCH); + +- ltq_gpio_request(42, 2, 1, "MDIO"); +- ltq_gpio_request(43, 2, 1, "MDC"); +- + ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); + /** Disable MDIO auto polling mode */ + ltq_gbit_w32_mask(0, PX_CTL_DMDIO, LTQ_GBIT_P0_CTL); +@@ -868,6 +865,12 @@ ltq_etop_probe(struct platform_device *pdev) + err = -ENOMEM; + goto err_out; + } ++ if (ltq_gpio_request(&pdev->dev, 42, 2, 1, "MDIO") || ++ ltq_gpio_request(&pdev->dev, 43, 2, 1, "MDC")) { ++ dev_err(&pdev->dev, "failed to request MDIO gpios\n"); ++ err = -EBUSY; ++ goto err_out; ++ } + } + + dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); +diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c +index 96c1cac..5d25828 100644 +--- a/drivers/tty/serial/lantiq.c ++++ b/drivers/tty/serial/lantiq.c +@@ -107,6 +107,9 @@ + #define ASCFSTAT_TXFREEMASK 0x3F000000 + #define ASCFSTAT_TXFREEOFF 24 + ++#define MUXC_SIF_RX_PIN 112 ++#define MUXC_SIF_TX_PIN 113 ++ + static void lqasc_tx_chars(struct uart_port *port); + static struct ltq_uart_port *lqasc_port[MAXPORTS]; + static struct uart_driver lqasc_reg; +@@ -529,6 +532,15 @@ lqasc_request_port(struct uart_port *port) + if (port->membase == NULL) + return -ENOMEM; + } ++ if (ltq_is_falcon() && (port->line == 1)) { ++ struct ltq_uart_port *ltq_port = lqasc_port[pdev->id]; ++ if (ltq_gpio_request(&pdev->dev, MUXC_SIF_RX_PIN, ++ 3, 0, "asc1-rx")) ++ return -EBUSY; ++ if (ltq_gpio_request(&pdev->dev, MUXC_SIF_TX_PIN, ++ 3, 1, "asc1-tx")) ++ return -EBUSY; ++ } + return 0; + } + +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0023-MIPS-add-clkdev.h.patch b/target/linux/lantiq/patches-3.2/0023-MIPS-add-clkdev.h.patch new file mode 100644 index 0000000000..f6686381d8 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0023-MIPS-add-clkdev.h.patch @@ -0,0 +1,49 @@ +From aeb5a729386db036163fa21a8f5e5e1f9a735ebf Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 16 Feb 2012 20:23:36 +0100 +Subject: [PATCH 23/70] MIPS: add clkdev.h + +For clkdev to work on MIPS we need this file + +include/linux/clkdev.h:#include <asm/clkdev.h> + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/include/asm/clkdev.h | 25 +++++++++++++++++++++++++ + 1 files changed, 25 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/clkdev.h + +diff --git a/arch/mips/include/asm/clkdev.h b/arch/mips/include/asm/clkdev.h +new file mode 100644 +index 0000000..2624754 +--- /dev/null ++++ b/arch/mips/include/asm/clkdev.h +@@ -0,0 +1,25 @@ ++/* ++ * based on arch/arm/include/asm/clkdev.h ++ * ++ * Copyright (C) 2008 Russell King. ++ * ++ * 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. ++ * ++ * Helper for the clk API to assist looking up a struct clk. ++ */ ++#ifndef __ASM_CLKDEV_H ++#define __ASM_CLKDEV_H ++ ++#include <linux/slab.h> ++ ++#define __clk_get(clk) ({ 1; }) ++#define __clk_put(clk) do { } while (0) ++ ++static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) ++{ ++ return kzalloc(size, GFP_KERNEL); ++} ++ ++#endif +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-helper-functions-for-SoC-detection.patch b/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-helper-functions-for-SoC-detection.patch new file mode 100644 index 0000000000..8fbb2c2c8a --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0024-MIPS-lantiq-helper-functions-for-SoC-detection.patch @@ -0,0 +1,59 @@ +From 8b47a5997efb253459fa62acce9c52202cbec9da Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 Feb 2012 14:25:03 +0100 +Subject: [PATCH 24/70] MIPS: lantiq: helper functions for SoC detection + +Add additional functions for runtime soc detection. We need these for the +serial driver. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 16 ++++++++++++++-- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 5 +++++ + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +index a5dc06a..0aa1f16 100644 +--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -134,8 +134,20 @@ extern int ltq_gpio_mux_set(unsigned int pin, unsigned int mux); + #define LTQ_EIU_BASE_ADDR 0 + #define LTQ_EBU_PCC_ISTAT 0 + +-#define ltq_is_ar9() 0 +-#define ltq_is_vr9() 0 ++static inline int ltq_is_ar9(void) ++{ ++ return 0; ++} ++ ++static inline int ltq_is_vr9(void) ++{ ++ return 0; ++} ++ ++static inline int ltq_is_falcon(void) ++{ ++ return 1; ++} + + #endif /* CONFIG_SOC_FALCON */ + #endif /* _LTQ_XWAY_H__ */ +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 6c5b705..45e480c 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -164,5 +164,10 @@ static inline int ltq_is_vr9(void) + return (ltq_get_soc_type() == SOC_TYPE_VR9); + } + ++static inline int ltq_is_falcon(void) ++{ ++ return 0; ++} ++ + #endif /* CONFIG_SOC_TYPE_XWAY */ + #endif /* _LTQ_XWAY_H__ */ +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-to-clkdev-api.patch new file mode 100644 index 0000000000..cad0a99ea0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0025-MIPS-lantiq-convert-to-clkdev-api.patch @@ -0,0 +1,299 @@ +From 25db3804c7c9ed3ee5161b00b38de84b1d19f6a8 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 08:39:06 +0100 +Subject: [PATCH 25/70] MIPS: lantiq: convert to clkdev api + +* Change setup from HAVE_CLK -> HAVE_MACH_CLKDEV/CLKDEV_LOOKUP +* Add clk_activate/clk_deactivate +* Add better error paths to the clk_*() functions +* Change the way our static clocks are referenced + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/Kconfig | 3 +- + arch/mips/include/asm/mach-lantiq/lantiq.h | 20 ++---- + arch/mips/lantiq/clk.c | 96 +++++++++++++++------------ + arch/mips/lantiq/clk.h | 52 ++++++++++++++- + arch/mips/lantiq/prom.c | 1 - + 5 files changed, 111 insertions(+), 61 deletions(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index c1ceadb..1b78cd7 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -225,7 +225,8 @@ config LANTIQ + select ARCH_REQUIRE_GPIOLIB + select SWAP_IO_SPACE + select BOOT_RAW +- select HAVE_CLK ++ select HAVE_MACH_CLKDEV ++ select CLKDEV_LOOKUP + select HAVE_OPROFILE + select MIPS_MACHINE + +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h +index 924b91a..622847f 100644 +--- a/arch/mips/include/asm/mach-lantiq/lantiq.h ++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h +@@ -9,6 +9,7 @@ + #define _LANTIQ_H__ + + #include <linux/irq.h> ++#include <linux/clk.h> + #include <linux/ioport.h> + + /* generic reg access functions */ +@@ -22,18 +23,6 @@ + extern unsigned int ltq_get_cpu_ver(void); + extern unsigned int ltq_get_soc_type(void); + +-/* clock speeds */ +-#define CLOCK_60M 60000000 +-#define CLOCK_83M 83333333 +-#define CLOCK_100M 100000000 +-#define CLOCK_111M 111111111 +-#define CLOCK_133M 133333333 +-#define CLOCK_167M 166666667 +-#define CLOCK_200M 200000000 +-#define CLOCK_266M 266666666 +-#define CLOCK_333M 333333333 +-#define CLOCK_400M 400000000 +- + /* spinlock all ebu i/o */ + extern spinlock_t ebu_lock; + +@@ -46,6 +35,13 @@ extern void ltq_disable_irq(struct irq_data *data); + extern void ltq_mask_and_ack_irq(struct irq_data *data); + extern void ltq_enable_irq(struct irq_data *data); + ++/* clock handling */ ++extern int clk_activate(struct clk *clk); ++extern void clk_deactivate(struct clk *clk); ++extern struct clk *clk_get_cpu(void); ++extern struct clk *clk_get_fpi(void); ++extern struct clk *clk_get_io(void); ++ + /* find out what caused the last cpu reset */ + extern int ltq_reset_cause(void); + +diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c +index 39eef7f..84a201e 100644 +--- a/arch/mips/lantiq/clk.c ++++ b/arch/mips/lantiq/clk.c +@@ -12,6 +12,7 @@ + #include <linux/kernel.h> + #include <linux/types.h> + #include <linux/clk.h> ++#include <linux/clkdev.h> + #include <linux/err.h> + #include <linux/list.h> + +@@ -24,33 +25,29 @@ + #include "clk.h" + #include "prom.h" + +-struct clk { +- const char *name; +- unsigned long rate; +- unsigned long (*get_rate) (void); +-}; ++/* lantiq socs have 3 static clocks */ ++static struct clk cpu_clk_generic[3]; + +-static struct clk *cpu_clk; +-static int cpu_clk_cnt; ++void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io) ++{ ++ cpu_clk_generic[0].rate = cpu; ++ cpu_clk_generic[1].rate = fpi; ++ cpu_clk_generic[2].rate = io; ++} + +-/* lantiq socs have 3 static clocks */ +-static struct clk cpu_clk_generic[] = { +- { +- .name = "cpu", +- .get_rate = ltq_get_cpu_hz, +- }, { +- .name = "fpi", +- .get_rate = ltq_get_fpi_hz, +- }, { +- .name = "io", +- .get_rate = ltq_get_io_region_clock, +- }, +-}; +- +-void clk_init(void) ++struct clk *clk_get_cpu(void) ++{ ++ return &cpu_clk_generic[0]; ++} ++ ++struct clk *clk_get_fpi(void) + { +- cpu_clk = cpu_clk_generic; +- cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); ++ return &cpu_clk_generic[1]; ++} ++ ++struct clk *clk_get_io(void) ++{ ++ return &cpu_clk_generic[2]; + } + + static inline int clk_good(struct clk *clk) +@@ -73,36 +70,49 @@ unsigned long clk_get_rate(struct clk *clk) + } + EXPORT_SYMBOL(clk_get_rate); + +-struct clk *clk_get(struct device *dev, const char *id) ++int clk_enable(struct clk *clk) + { +- int i; ++ if (unlikely(!clk_good(clk))) ++ return -1; ++ ++ if (clk->enable) ++ return clk->enable(clk); + +- for (i = 0; i < cpu_clk_cnt; i++) +- if (!strcmp(id, cpu_clk[i].name)) +- return &cpu_clk[i]; +- BUG(); +- return ERR_PTR(-ENOENT); ++ return -1; + } +-EXPORT_SYMBOL(clk_get); ++EXPORT_SYMBOL(clk_enable); + +-void clk_put(struct clk *clk) ++void clk_disable(struct clk *clk) + { +- /* not used */ ++ if (unlikely(!clk_good(clk))) ++ return; ++ ++ if (clk->disable) ++ clk->disable(clk); + } +-EXPORT_SYMBOL(clk_put); ++EXPORT_SYMBOL(clk_disable); + +-int clk_enable(struct clk *clk) ++int clk_activate(struct clk *clk) + { +- /* not used */ +- return 0; ++ if (unlikely(!clk_good(clk))) ++ return -1; ++ ++ if (clk->activate) ++ return clk->activate(clk); ++ ++ return -1; + } +-EXPORT_SYMBOL(clk_enable); ++EXPORT_SYMBOL(clk_activate); + +-void clk_disable(struct clk *clk) ++void clk_deactivate(struct clk *clk) + { +- /* not used */ ++ if (unlikely(!clk_good(clk))) ++ return; ++ ++ if (clk->deactivate) ++ clk->deactivate(clk); + } +-EXPORT_SYMBOL(clk_disable); ++EXPORT_SYMBOL(clk_deactivate); + + static inline u32 ltq_get_counter_resolution(void) + { +@@ -126,7 +136,7 @@ void __init plat_time_init(void) + + ltq_soc_init(); + +- clk = clk_get(0, "cpu"); ++ clk = clk_get_cpu(); + mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); + write_c0_compare(read_c0_count()); + pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); +diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h +index 3328925..d047768 100644 +--- a/arch/mips/lantiq/clk.h ++++ b/arch/mips/lantiq/clk.h +@@ -9,10 +9,54 @@ + #ifndef _LTQ_CLK_H__ + #define _LTQ_CLK_H__ + +-extern void clk_init(void); ++#include <linux/clkdev.h> + +-extern unsigned long ltq_get_cpu_hz(void); +-extern unsigned long ltq_get_fpi_hz(void); +-extern unsigned long ltq_get_io_region_clock(void); ++/* clock speeds */ ++#define CLOCK_60M 60000000 ++#define CLOCK_62_5M 62500000 ++#define CLOCK_83M 83333333 ++#define CLOCK_83_5M 83500000 ++#define CLOCK_98_304M 98304000 ++#define CLOCK_100M 100000000 ++#define CLOCK_111M 111111111 ++#define CLOCK_125M 125000000 ++#define CLOCK_133M 133333333 ++#define CLOCK_150M 150000000 ++#define CLOCK_166M 166666666 ++#define CLOCK_167M 166666667 ++#define CLOCK_196_608M 196608000 ++#define CLOCK_200M 200000000 ++#define CLOCK_250M 250000000 ++#define CLOCK_266M 266666666 ++#define CLOCK_300M 300000000 ++#define CLOCK_333M 333333333 ++#define CLOCK_393M 393215332 ++#define CLOCK_400M 400000000 ++#define CLOCK_500M 500000000 ++#define CLOCK_600M 600000000 ++ ++struct clk { ++ struct clk_lookup cl; ++ unsigned long rate; ++ unsigned long (*get_rate) (void); ++ unsigned int module; ++ unsigned int bits; ++ int (*enable) (struct clk *clk); ++ void (*disable) (struct clk *clk); ++ int (*activate) (struct clk *clk); ++ void (*deactivate) (struct clk *clk); ++ void (*reboot) (struct clk *clk); ++}; ++ ++extern void clkdev_add_static(unsigned long cpu, unsigned long fpi, ++ unsigned long io); ++ ++extern unsigned long ltq_danube_cpu_hz(void); ++extern unsigned long ltq_danube_fpi_hz(void); ++extern unsigned long ltq_danube_io_region_clock(void); ++ ++extern unsigned long ltq_vr9_cpu_hz(void); ++extern unsigned long ltq_vr9_fpi_hz(void); ++extern unsigned long ltq_vr9_io_region_clock(void); + + #endif +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index acb8921..971554b 100644 +--- a/arch/mips/lantiq/prom.c ++++ b/arch/mips/lantiq/prom.c +@@ -103,7 +103,6 @@ EXPORT_SYMBOL(ltq_remap_resource); + void __init prom_init(void) + { + ltq_soc_detect(&soc_info); +- clk_init(); + snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev %s", + soc_info.name, soc_info.rev_type); + soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-xway-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-xway-to-clkdev-api.patch new file mode 100644 index 0000000000..c35f2302a0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0026-MIPS-lantiq-convert-xway-to-clkdev-api.patch @@ -0,0 +1,736 @@ +From 418e330dc60aaabdb5cf4509ec08cce07d63f32e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:18:22 +0100 +Subject: [PATCH 26/70] MIPS: lantiq: convert xway to clkdev api + +Unify xway/ase clock code and add clkdev hooks to sysctrl.c + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 13 -- + arch/mips/lantiq/xway/Makefile | 6 +- + arch/mips/lantiq/xway/clk-ase.c | 48 ---- + arch/mips/lantiq/xway/clk-xway.c | 223 ------------------- + arch/mips/lantiq/xway/clk.c | 227 ++++++++++++++++++++ + arch/mips/lantiq/xway/sysctrl.c | 104 ++++++++- + 6 files changed, 325 insertions(+), 296 deletions(-) + delete mode 100644 arch/mips/lantiq/xway/clk-ase.c + delete mode 100644 arch/mips/lantiq/xway/clk-xway.c + create mode 100644 arch/mips/lantiq/xway/clk.c + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 45e480c..e9d2dd4 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -81,15 +81,6 @@ + #define LTQ_PMU_BASE_ADDR 0x1F102000 + #define LTQ_PMU_SIZE 0x1000 + +-#define PMU_DMA 0x0020 +-#define PMU_EPHY 0x0080 +-#define PMU_USB 0x8041 +-#define PMU_LED 0x0800 +-#define PMU_GPT 0x1000 +-#define PMU_PPE 0x2000 +-#define PMU_FPI 0x4000 +-#define PMU_SWITCH 0x10000000 +- + /* ETOP - ethernet */ + #define LTQ_ETOP_BASE_ADDR 0x1E180000 + #define LTQ_ETOP_SIZE 0x40000 +@@ -145,10 +136,6 @@ + extern __iomem void *ltq_ebu_membase; + extern __iomem void *ltq_cgu_membase; + +-extern void ltq_pmu_enable(unsigned int module); +-extern void ltq_pmu_disable(unsigned int module); +-extern void ltq_cgu_enable(unsigned int clk); +- + static inline int ltq_is_ase(void) + { + return (ltq_get_soc_type() == SOC_TYPE_AMAZON_SE); +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 6678402..4dcb96f 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,7 +1,7 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o + +-obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o +-obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o ++obj-$(CONFIG_SOC_XWAY) += prom-xway.o ++obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c +deleted file mode 100644 +index 6522583..0000000 +--- a/arch/mips/lantiq/xway/clk-ase.c ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* +- * 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) 2011 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/io.h> +-#include <linux/export.h> +-#include <linux/init.h> +-#include <linux/clk.h> +- +-#include <asm/time.h> +-#include <asm/irq.h> +-#include <asm/div64.h> +- +-#include <lantiq_soc.h> +- +-/* cgu registers */ +-#define LTQ_CGU_SYS 0x0010 +- +-unsigned int ltq_get_io_region_clock(void) +-{ +- return CLOCK_133M; +-} +-EXPORT_SYMBOL(ltq_get_io_region_clock); +- +-unsigned int ltq_get_fpi_bus_clock(int fpi) +-{ +- return CLOCK_133M; +-} +-EXPORT_SYMBOL(ltq_get_fpi_bus_clock); +- +-unsigned int ltq_get_cpu_hz(void) +-{ +- if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) +- return CLOCK_266M; +- else +- return CLOCK_133M; +-} +-EXPORT_SYMBOL(ltq_get_cpu_hz); +- +-unsigned int ltq_get_fpi_hz(void) +-{ +- return CLOCK_133M; +-} +-EXPORT_SYMBOL(ltq_get_fpi_hz); +diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c +deleted file mode 100644 +index 696b1a3..0000000 +--- a/arch/mips/lantiq/xway/clk-xway.c ++++ /dev/null +@@ -1,223 +0,0 @@ +-/* +- * 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 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/io.h> +-#include <linux/export.h> +-#include <linux/init.h> +-#include <linux/clk.h> +- +-#include <asm/time.h> +-#include <asm/irq.h> +-#include <asm/div64.h> +- +-#include <lantiq_soc.h> +- +-static unsigned int ltq_ram_clocks[] = { +- CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; +-#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] +- +-#define BASIC_FREQUENCY_1 35328000 +-#define BASIC_FREQUENCY_2 36000000 +-#define BASIS_REQUENCY_USB 12000000 +- +-#define GET_BITS(x, msb, lsb) \ +- (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) +- +-#define LTQ_CGU_PLL0_CFG 0x0004 +-#define LTQ_CGU_PLL1_CFG 0x0008 +-#define LTQ_CGU_PLL2_CFG 0x000C +-#define LTQ_CGU_SYS 0x0010 +-#define LTQ_CGU_UPDATE 0x0014 +-#define LTQ_CGU_IF_CLK 0x0018 +-#define LTQ_CGU_OSC_CON 0x001C +-#define LTQ_CGU_SMD 0x0020 +-#define LTQ_CGU_CT1SR 0x0028 +-#define LTQ_CGU_CT2SR 0x002C +-#define LTQ_CGU_PCMCR 0x0030 +-#define LTQ_CGU_PCI_CR 0x0034 +-#define LTQ_CGU_PD_PC 0x0038 +-#define LTQ_CGU_FMR 0x003C +- +-#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ +- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) +-#define CGU_PLL0_BYPASS \ +- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) +-#define CGU_PLL0_CFG_DSMSEL \ +- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) +-#define CGU_PLL0_CFG_FRAC_EN \ +- (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) +-#define CGU_PLL1_SRC \ +- (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) +-#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ +- (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) +-#define CGU_SYS_FPI_SEL (1 << 6) +-#define CGU_SYS_DDR_SEL 0x3 +-#define CGU_PLL0_SRC (1 << 29) +- +-#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) +-#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) +-#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) +-#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) +-#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) +- +-static unsigned int ltq_get_pll0_fdiv(void); +- +-static inline unsigned int get_input_clock(int pll) +-{ +- switch (pll) { +- case 0: +- if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) +- return BASIS_REQUENCY_USB; +- else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) +- return BASIC_FREQUENCY_1; +- else +- return BASIC_FREQUENCY_2; +- case 1: +- if (CGU_PLL1_SRC) +- return BASIS_REQUENCY_USB; +- else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) +- return BASIC_FREQUENCY_1; +- else +- return BASIC_FREQUENCY_2; +- case 2: +- switch (CGU_PLL2_SRC) { +- case 0: +- return ltq_get_pll0_fdiv(); +- case 1: +- return CGU_PLL2_PHASE_DIVIDER_ENABLE ? +- BASIC_FREQUENCY_1 : +- BASIC_FREQUENCY_2; +- case 2: +- return BASIS_REQUENCY_USB; +- } +- default: +- return 0; +- } +-} +- +-static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) +-{ +- u64 res, clock = get_input_clock(pll); +- +- res = num * clock; +- do_div(res, den); +- return res; +-} +- +-static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, +- unsigned int K) +-{ +- unsigned int num = ((N + 1) << 10) + K; +- unsigned int den = (M + 1) << 10; +- +- return cal_dsm(pll, num, den); +-} +- +-static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, +- unsigned int K) +-{ +- unsigned int num = ((N + 1) << 11) + K + 512; +- unsigned int den = (M + 1) << 11; +- +- return cal_dsm(pll, num, den); +-} +- +-static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, +- unsigned int K) +-{ +- unsigned int num = K >= 512 ? +- ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; +- unsigned int den = (M + 1) << 12; +- +- return cal_dsm(pll, num, den); +-} +- +-static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, +- unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) +-{ +- if (!dsmsel) +- return mash_dsm(pll, M, N, K); +- else if (!phase_div_en) +- return mash_dsm(pll, M, N, K); +- else +- return ssff_dsm_2(pll, M, N, K); +-} +- +-static inline unsigned int ltq_get_pll0_fosc(void) +-{ +- if (CGU_PLL0_BYPASS) +- return get_input_clock(0); +- else +- return !CGU_PLL0_CFG_FRAC_EN +- ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, +- CGU_PLL0_CFG_DSMSEL, +- CGU_PLL0_PHASE_DIVIDER_ENABLE) +- : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, +- CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, +- CGU_PLL0_PHASE_DIVIDER_ENABLE); +-} +- +-static unsigned int ltq_get_pll0_fdiv(void) +-{ +- unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; +- +- return (ltq_get_pll0_fosc() + (div >> 1)) / div; +-} +- +-unsigned int ltq_get_io_region_clock(void) +-{ +- unsigned int ret = ltq_get_pll0_fosc(); +- +- switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { +- default: +- case 0: +- return (ret + 1) / 2; +- case 1: +- return (ret * 2 + 2) / 5; +- case 2: +- return (ret + 1) / 3; +- case 3: +- return (ret + 2) / 4; +- } +-} +-EXPORT_SYMBOL(ltq_get_io_region_clock); +- +-unsigned int ltq_get_fpi_bus_clock(int fpi) +-{ +- unsigned int ret = ltq_get_io_region_clock(); +- +- if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) +- ret >>= 1; +- return ret; +-} +-EXPORT_SYMBOL(ltq_get_fpi_bus_clock); +- +-unsigned int ltq_get_cpu_hz(void) +-{ +- switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { +- case 0: +- return CLOCK_333M; +- case 4: +- return DDR_HZ; +- case 8: +- return DDR_HZ << 1; +- default: +- return DDR_HZ >> 1; +- } +-} +-EXPORT_SYMBOL(ltq_get_cpu_hz); +- +-unsigned int ltq_get_fpi_hz(void) +-{ +- unsigned int ddr_clock = DDR_HZ; +- +- if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) +- return ddr_clock >> 1; +- return ddr_clock; +-} +-EXPORT_SYMBOL(ltq_get_fpi_hz); +diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c +new file mode 100644 +index 0000000..f3b50fc +--- /dev/null ++++ b/arch/mips/lantiq/xway/clk.c +@@ -0,0 +1,227 @@ ++/* ++ * 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 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/io.h> ++#include <linux/export.h> ++#include <linux/init.h> ++#include <linux/clk.h> ++ ++#include <asm/time.h> ++#include <asm/irq.h> ++#include <asm/div64.h> ++ ++#include <lantiq_soc.h> ++ ++#include "../clk.h" ++ ++static unsigned int ltq_ram_clocks[] = { ++ CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; ++#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] ++ ++#define BASIC_FREQUENCY_1 35328000 ++#define BASIC_FREQUENCY_2 36000000 ++#define BASIS_REQUENCY_USB 12000000 ++ ++#define GET_BITS(x, msb, lsb) \ ++ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) ++ ++/* legacy xway clock */ ++#define LTQ_CGU_PLL0_CFG 0x0004 ++#define LTQ_CGU_PLL1_CFG 0x0008 ++#define LTQ_CGU_PLL2_CFG 0x000C ++#define LTQ_CGU_SYS 0x0010 ++#define LTQ_CGU_UPDATE 0x0014 ++#define LTQ_CGU_IF_CLK 0x0018 ++#define LTQ_CGU_OSC_CON 0x001C ++#define LTQ_CGU_SMD 0x0020 ++#define LTQ_CGU_CT1SR 0x0028 ++#define LTQ_CGU_CT2SR 0x002C ++#define LTQ_CGU_PCMCR 0x0030 ++#define LTQ_CGU_PCI_CR 0x0034 ++#define LTQ_CGU_PD_PC 0x0038 ++#define LTQ_CGU_FMR 0x003C ++ ++#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ ++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) ++#define CGU_PLL0_BYPASS \ ++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) ++#define CGU_PLL0_CFG_DSMSEL \ ++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) ++#define CGU_PLL0_CFG_FRAC_EN \ ++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) ++#define CGU_PLL1_SRC \ ++ (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) ++#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ ++ (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) ++#define CGU_SYS_FPI_SEL (1 << 6) ++#define CGU_SYS_DDR_SEL 0x3 ++#define CGU_PLL0_SRC (1 << 29) ++ ++#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) ++#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) ++#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) ++#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) ++#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) ++ ++/* vr9 clock */ ++#define LTQ_CGU_SYS_VR9 0x0c ++#define LTQ_CGU_IF_CLK_VR9 0x24 ++ ++ ++static unsigned int ltq_get_pll0_fdiv(void); ++ ++static inline unsigned int get_input_clock(int pll) ++{ ++ switch (pll) { ++ case 0: ++ if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) ++ return BASIS_REQUENCY_USB; ++ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) ++ return BASIC_FREQUENCY_1; ++ else ++ return BASIC_FREQUENCY_2; ++ case 1: ++ if (CGU_PLL1_SRC) ++ return BASIS_REQUENCY_USB; ++ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) ++ return BASIC_FREQUENCY_1; ++ else ++ return BASIC_FREQUENCY_2; ++ case 2: ++ switch (CGU_PLL2_SRC) { ++ case 0: ++ return ltq_get_pll0_fdiv(); ++ case 1: ++ return CGU_PLL2_PHASE_DIVIDER_ENABLE ? ++ BASIC_FREQUENCY_1 : ++ BASIC_FREQUENCY_2; ++ case 2: ++ return BASIS_REQUENCY_USB; ++ } ++ default: ++ return 0; ++ } ++} ++ ++static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) ++{ ++ u64 res, clock = get_input_clock(pll); ++ ++ res = num * clock; ++ do_div(res, den); ++ return res; ++} ++ ++static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, ++ unsigned int K) ++{ ++ unsigned int num = ((N + 1) << 10) + K; ++ unsigned int den = (M + 1) << 10; ++ ++ return cal_dsm(pll, num, den); ++} ++ ++static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, ++ unsigned int K) ++{ ++ unsigned int num = ((N + 1) << 11) + K + 512; ++ unsigned int den = (M + 1) << 11; ++ ++ return cal_dsm(pll, num, den); ++} ++ ++static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, ++ unsigned int K) ++{ ++ unsigned int num = K >= 512 ? ++ ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; ++ unsigned int den = (M + 1) << 12; ++ ++ return cal_dsm(pll, num, den); ++} ++ ++static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, ++ unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) ++{ ++ if (!dsmsel) ++ return mash_dsm(pll, M, N, K); ++ else if (!phase_div_en) ++ return mash_dsm(pll, M, N, K); ++ else ++ return ssff_dsm_2(pll, M, N, K); ++} ++ ++static inline unsigned int ltq_get_pll0_fosc(void) ++{ ++ if (CGU_PLL0_BYPASS) ++ return get_input_clock(0); ++ else ++ return !CGU_PLL0_CFG_FRAC_EN ++ ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, ++ CGU_PLL0_CFG_DSMSEL, ++ CGU_PLL0_PHASE_DIVIDER_ENABLE) ++ : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, ++ CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, ++ CGU_PLL0_PHASE_DIVIDER_ENABLE); ++} ++ ++static unsigned int ltq_get_pll0_fdiv(void) ++{ ++ unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; ++ ++ return (ltq_get_pll0_fosc() + (div >> 1)) / div; ++} ++ ++unsigned long ltq_danube_io_region_clock(void) ++{ ++ unsigned int ret = ltq_get_pll0_fosc(); ++ ++ switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { ++ default: ++ case 0: ++ return (ret + 1) / 2; ++ case 1: ++ return (ret * 2 + 2) / 5; ++ case 2: ++ return (ret + 1) / 3; ++ case 3: ++ return (ret + 2) / 4; ++ } ++} ++ ++unsigned long ltq_danube_fpi_bus_clock(int fpi) ++{ ++ unsigned long ret = ltq_danube_io_region_clock(); ++ ++ if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) ++ ret >>= 1; ++ return ret; ++} ++ ++unsigned long ltq_danube_cpu_hz(void) ++{ ++ switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { ++ case 0: ++ return CLOCK_333M; ++ case 4: ++ return DDR_HZ; ++ case 8: ++ return DDR_HZ << 1; ++ default: ++ return DDR_HZ >> 1; ++ } ++} ++ ++unsigned long ltq_danube_fpi_hz(void) ++{ ++ unsigned long ddr_clock = DDR_HZ; ++ ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) ++ return ddr_clock >> 1; ++ return ddr_clock; ++} +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 8fd13a1..c5782b5 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -8,17 +8,48 @@ + + #include <linux/ioport.h> + #include <linux/export.h> ++#include <linux/clkdev.h> + + #include <lantiq_soc.h> + ++#include "../clk.h" + #include "../devices.h" + + /* clock control register */ + #define LTQ_CGU_IFCCR 0x0018 ++/* system clock register */ ++#define LTQ_CGU_SYS 0x0010 + + /* the enable / disable registers */ + #define LTQ_PMU_PWDCR 0x1C + #define LTQ_PMU_PWDSR 0x20 ++#define LTQ_PMU_PWDCR1 0x24 ++#define LTQ_PMU_PWDSR1 0x28 ++ ++#define PWDCR(x) ((x) ? (LTQ_PMU_PWDCR1) : (LTQ_PMU_PWDCR)) ++#define PWDSR(x) ((x) ? (LTQ_PMU_PWDSR1) : (LTQ_PMU_PWDSR)) ++ ++/* CGU - clock generation unit */ ++#define CGU_EPHY 0x10 ++ ++/* PMU - power management unit */ ++#define PMU_DMA 0x0020 ++#define PMU_SPI 0x0100 ++#define PMU_EPHY 0x0080 ++#define PMU_USB 0x8041 ++#define PMU_STP 0x0800 ++#define PMU_GPT 0x1000 ++#define PMU_PPE 0x2000 ++#define PMU_FPI 0x4000 ++#define PMU_SWITCH 0x10000000 ++#define PMU_AHBS 0x2000 ++#define PMU_AHBM 0x8000 ++#define PMU_PCIE_CLK 0x80000000 ++ ++#define PMU1_PCIE_PHY 0x0001 ++#define PMU1_PCIE_CTL 0x0002 ++#define PMU1_PCIE_MSI 0x0020 ++#define PMU1_PCIE_PDI 0x0010 + + #define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) + #define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) +@@ -36,28 +67,64 @@ void __iomem *ltq_cgu_membase; + void __iomem *ltq_ebu_membase; + static void __iomem *ltq_pmu_membase; + +-void ltq_cgu_enable(unsigned int clk) ++static int ltq_cgu_enable(struct clk *clk) + { +- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk, LTQ_CGU_IFCCR); ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk->bits, LTQ_CGU_IFCCR); ++ return 0; + } + +-void ltq_pmu_enable(unsigned int module) ++static void ltq_cgu_disable(struct clk *clk) ++{ ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~clk->bits, LTQ_CGU_IFCCR); ++} ++ ++static int ltq_pmu_enable(struct clk *clk) + { + int err = 1000000; + +- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR); +- do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module)); ++ ltq_pmu_w32(ltq_pmu_r32(PWDCR(clk->module)) & ~clk->bits, ++ PWDCR(clk->module)); ++ do {} while (--err && (ltq_pmu_r32(PWDSR(clk->module)) & clk->bits)); + + if (!err) + panic("activating PMU module failed!\n"); ++ ++ return 0; + } +-EXPORT_SYMBOL(ltq_pmu_enable); + +-void ltq_pmu_disable(unsigned int module) ++static void ltq_pmu_disable(struct clk *clk) + { +- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); ++ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | clk->bits, LTQ_PMU_PWDCR); ++} ++ ++static inline void clkdev_add_pmu(const char *dev, const char *con, ++ unsigned int module, unsigned int bits) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ clk->cl.dev_id = dev; ++ clk->cl.con_id = con; ++ clk->cl.clk = clk; ++ clk->enable = ltq_pmu_enable; ++ clk->disable = ltq_pmu_disable; ++ clk->module = module; ++ clk->bits = bits; ++ clkdev_add(&clk->cl); ++} ++ ++static inline void clkdev_add_cgu(const char *dev, const char *con, ++ unsigned int bits) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ clk->cl.dev_id = dev; ++ clk->cl.con_id = con; ++ clk->cl.clk = clk; ++ clk->enable = ltq_cgu_enable; ++ clk->disable = ltq_cgu_disable; ++ clk->bits = bits; ++ clkdev_add(&clk->cl); + } +-EXPORT_SYMBOL(ltq_pmu_disable); + + void __init ltq_soc_init(void) + { +@@ -75,4 +142,23 @@ void __init ltq_soc_init(void) + + /* make sure to unprotect the memory region where flash is located */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); ++ ++ /* add our clocks */ ++ clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); ++ clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); ++ clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); ++ clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); ++ if (ltq_is_ase()) { ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) ++ clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); ++ else ++ clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); ++ clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), ++ clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); ++ } else { ++ clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), ++ ltq_danube_io_region_clock()); ++ if (ltq_is_ar9()) ++ clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); ++ } + } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-falcon-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-falcon-to-clkdev-api.patch new file mode 100644 index 0000000000..83cd89e4e3 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0027-MIPS-lantiq-convert-falcon-to-clkdev-api.patch @@ -0,0 +1,244 @@ +From 07c4da1cf419022e5874c881511f051bb81e984e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:19:11 +0100 +Subject: [PATCH 27/70] MIPS: lantiq: convert falcon to clkdev api + +Unify sysctrl/clock code and add clkdev hooks to sysctrl.c + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 8 +- + arch/mips/lantiq/falcon/Makefile | 2 +- + arch/mips/lantiq/falcon/sysctrl.c | 129 ++++++++++++-------- + 3 files changed, 80 insertions(+), 59 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +index 0aa1f16..120c56c 100644 +--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -95,6 +95,7 @@ + + /* Activation Status Register */ + #define ACTS_ASC1_ACT 0x00000800 ++#define ACTS_I2C_ACT 0x00004000 + #define ACTS_P0 0x00010000 + #define ACTS_P1 0x00010000 + #define ACTS_P2 0x00020000 +@@ -106,13 +107,6 @@ + #define ACTS_PADCTRL3 0x00200000 + #define ACTS_PADCTRL4 0x00400000 + +-extern void ltq_sysctl_activate(int module, unsigned int mask); +-extern void ltq_sysctl_deactivate(int module, unsigned int mask); +-extern void ltq_sysctl_clken(int module, unsigned int mask); +-extern void ltq_sysctl_clkdis(int module, unsigned int mask); +-extern void ltq_sysctl_reboot(int module, unsigned int mask); +-extern int ltq_gpe_is_activated(unsigned int mask); +- + /* global register ranges */ + extern __iomem void *ltq_ebu_membase; + extern __iomem void *ltq_sys1_membase; +diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile +index 56b22eb..3634154 100644 +--- a/arch/mips/lantiq/falcon/Makefile ++++ b/arch/mips/lantiq/falcon/Makefile +@@ -1,2 +1,2 @@ +-obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o ++obj-y := prom.o reset.o sysctrl.o devices.o gpio.o + obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o +diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c +index 905a142..900f0e5 100644 +--- a/arch/mips/lantiq/falcon/sysctrl.c ++++ b/arch/mips/lantiq/falcon/sysctrl.c +@@ -9,11 +9,13 @@ + + #include <linux/ioport.h> + #include <linux/export.h> ++#include <linux/clkdev.h> + #include <asm/delay.h> + + #include <lantiq_soc.h> + + #include "devices.h" ++#include "../clk.h" + + /* infrastructure control register */ + #define SYS1_INFRAC 0x00bc +@@ -38,6 +40,10 @@ + #define LTQ_SYSCTL_DEACT 0x0028 + /* reboot Register */ + #define LTQ_SYSCTL_RBT 0x002c ++/* CPU0 Clock Control Register */ ++#define LTQ_SYS1_CPU0CC 0x0040 ++/* clock divider bit */ ++#define LTQ_CPU0CC_CPUDIV 0x0001 + + static struct resource ltq_sysctl_res[] = { + MEM_RES("sys1", LTQ_SYS1_BASE_ADDR, LTQ_SYS1_SIZE), +@@ -64,79 +70,67 @@ void __iomem *ltq_ebu_membase; + #define ltq_status_r32(x) ltq_r32(ltq_status_membase + (x)) + + static inline void +-ltq_sysctl_wait(int module, unsigned int mask, ++ltq_sysctl_wait(struct clk *clk, + unsigned int test, unsigned int reg) + { + int err = 1000000; + +- do {} while (--err && ((ltq_reg_r32(module, reg) +- & mask) != test)); ++ do {} while (--err && ((ltq_reg_r32(clk->module, reg) ++ & clk->bits) != test)); + if (!err) +- pr_err("module de/activation failed %d %08X %08X\n", +- module, mask, test); ++ pr_err("module de/activation failed %d %08X %08X %08X\n", ++ clk->module, clk->bits, test, ++ ltq_reg_r32(clk->module, reg) & clk->bits); + } + +-void +-ltq_sysctl_activate(int module, unsigned int mask) ++static int ++ltq_sysctl_activate(struct clk *clk) + { +- if (module > SYSCTL_SYSGPE) +- return; +- +- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); +- ltq_reg_w32(module, mask, LTQ_SYSCTL_ACT); +- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_ACT); ++ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS); ++ return 0; + } +-EXPORT_SYMBOL(ltq_sysctl_activate); + +-void +-ltq_sysctl_deactivate(int module, unsigned int mask) ++static void ++ltq_sysctl_deactivate(struct clk *clk) + { +- if (module > SYSCTL_SYSGPE) +- return; +- +- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); +- ltq_reg_w32(module, mask, LTQ_SYSCTL_DEACT); +- ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_ACTS); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_DEACT); ++ ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_ACTS); + } +-EXPORT_SYMBOL(ltq_sysctl_deactivate); + +-void +-ltq_sysctl_clken(int module, unsigned int mask) ++static int ++ltq_sysctl_clken(struct clk *clk) + { +- if (module > SYSCTL_SYSGPE) +- return; +- +- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); +- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_CLKS); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN); ++ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_CLKS); ++ return 0; + } +-EXPORT_SYMBOL(ltq_sysctl_clken); + +-void +-ltq_sysctl_clkdis(int module, unsigned int mask) ++static void ++ltq_sysctl_clkdis(struct clk *clk) + { +- if (module > SYSCTL_SYSGPE) +- return; +- +- ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); +- ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_CLKS); ++ ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR); ++ ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_CLKS); + } +-EXPORT_SYMBOL(ltq_sysctl_clkdis); + +-void +-ltq_sysctl_reboot(int module, unsigned int mask) ++static void ++ltq_sysctl_reboot(struct clk *clk) + { + unsigned int act; +- +- if (module > SYSCTL_SYSGPE) +- return; +- +- act = ltq_reg_r32(module, LTQ_SYSCTL_ACT); +- if ((~act & mask) != 0) +- ltq_sysctl_activate(module, ~act & mask); +- ltq_reg_w32(module, act & mask, LTQ_SYSCTL_RBT); +- ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); ++ unsigned int bits; ++ ++ act = ltq_reg_r32(clk->module, LTQ_SYSCTL_ACT); ++ bits = ~act & clk->bits; ++ if (bits != 0) { ++ ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_CLKEN); ++ ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_ACT); ++ ltq_sysctl_wait(clk, bits, LTQ_SYSCTL_ACTS); ++ } ++ ltq_reg_w32(clk->module, act & clk->bits, LTQ_SYSCTL_RBT); ++ ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS); + } +-EXPORT_SYMBOL(ltq_sysctl_reboot); + + /* enable the ONU core */ + static void +@@ -167,6 +161,24 @@ ltq_gpe_enable(void) + udelay(1); + } + ++static inline void ++clkdev_add_sys(const char *dev, unsigned int module, ++ unsigned int bits) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ clk->cl.dev_id = dev; ++ clk->cl.con_id = NULL; ++ clk->cl.clk = clk; ++ clk->module = module; ++ clk->activate = ltq_sysctl_activate; ++ clk->deactivate = ltq_sysctl_deactivate; ++ clk->enable = ltq_sysctl_clken; ++ clk->disable = ltq_sysctl_clkdis; ++ clk->reboot = ltq_sysctl_reboot; ++ clkdev_add(&clk->cl); ++} ++ + void __init + ltq_soc_init(void) + { +@@ -180,4 +192,19 @@ ltq_soc_init(void) + ltq_ebu_membase = ltq_remap_resource(<q_ebu_res); + + ltq_gpe_enable(); ++ ++ /* get our 3 static rates for cpu, fpi and io clocks */ ++ if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV) ++ clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M); ++ else ++ clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M); ++ ++ /* add our clock domains */ ++ clkdev_add_sys("falcon_gpio.0", SYSCTL_SYSETH, ACTS_PADCTRL0 | ACTS_P0); ++ clkdev_add_sys("falcon_gpio.1", SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1); ++ clkdev_add_sys("falcon_gpio.2", SYSCTL_SYSETH, ACTS_PADCTRL2 | ACTS_P2); ++ clkdev_add_sys("falcon_gpio.3", SYSCTL_SYS1, ACTS_PADCTRL3 | ACTS_P3); ++ clkdev_add_sys("falcon_gpio.4", SYSCTL_SYS1, ACTS_PADCTRL4 | ACTS_P4); ++ clkdev_add_sys("ltq_asc.1", SYSCTL_SYS1, ACTS_ASC1_ACT); ++ clkdev_add_sys("falcon_i2c", SYSCTL_SYS1, ACTS_I2C_ACT); + } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch new file mode 100644 index 0000000000..6458af5ccf --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0028-MIPS-lantiq-convert-dma-driver-to-clkdev-api.patch @@ -0,0 +1,65 @@ +From e6a19ba12790d04267a9f052a3dc64fa1a8cac16 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:21:08 +0100 +Subject: [PATCH 28/70] MIPS: lantiq: convert dma driver to clkdev api + +Update from old pmu_{dis,en}able() to ckldev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/xway/Makefile.rej | 11 +++++++++++ + arch/mips/lantiq/xway/dma.c | 6 +++++- + 2 files changed, 16 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/lantiq/xway/Makefile.rej + +diff --git a/arch/mips/lantiq/xway/Makefile.rej b/arch/mips/lantiq/xway/Makefile.rej +new file mode 100644 +index 0000000..c0d5b52 +--- /dev/null ++++ b/arch/mips/lantiq/xway/Makefile.rej +@@ -0,0 +1,11 @@ ++--- arch/mips/lantiq/xway/Makefile +++++ arch/mips/lantiq/xway/Makefile ++@@ -1,7 +1,4 @@ ++-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o ++- ++-obj-$(CONFIG_SOC_XWAY) += prom-xway.o ++-obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o +++obj-y := prom.o sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o ++ ++ obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o ++ obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c +index 60cd11f..388f1aa 100644 +--- a/arch/mips/lantiq/xway/dma.c ++++ b/arch/mips/lantiq/xway/dma.c +@@ -20,6 +20,7 @@ + #include <linux/io.h> + #include <linux/dma-mapping.h> + #include <linux/export.h> ++#include <linux/clk.h> + + #include <lantiq_soc.h> + #include <xway_dma.h> +@@ -216,6 +217,7 @@ EXPORT_SYMBOL_GPL(ltq_dma_init_port); + int __init + ltq_dma_init(void) + { ++ struct clk *clk; + int i; + + /* remap dma register range */ +@@ -224,7 +226,9 @@ ltq_dma_init(void) + panic("Failed to remap dma memory\n"); + + /* power up and reset the dma engine */ +- ltq_pmu_enable(PMU_DMA); ++ clk = clk_get_sys("ltq_dma", NULL); ++ WARN_ON(!clk); ++ clk_enable(clk); + ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); + + /* disable all interrupts */ +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch new file mode 100644 index 0000000000..7b56c4f470 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0029-MIPS-lantiq-convert-gpio_stp-driver-to-clkdev-api.patch @@ -0,0 +1,60 @@ +From 81cf50fd6cfff13e06cd587094f5094dec32d57d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:21:33 +0100 +Subject: [PATCH 29/70] MIPS: lantiq: convert gpio_stp driver to clkdev api + +Update from old pmu_{dis,en}able() to ckldev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/xway/gpio_stp.c | 12 +++++++++--- + 1 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index e6b4809..da91c5e 100644 +--- a/arch/mips/lantiq/xway/gpio_stp.c ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -15,6 +15,8 @@ + #include <linux/mutex.h> + #include <linux/io.h> + #include <linux/gpio.h> ++#include <linux/clk.h> ++#include <linux/err.h> + + #include <lantiq_soc.h> + +@@ -78,8 +80,10 @@ static struct gpio_chip ltq_stp_chip = { + .owner = THIS_MODULE, + }; + +-static int ltq_stp_hw_init(void) ++static int ltq_stp_hw_init(struct device *dev) + { ++ struct clk *clk; ++ + /* sane defaults */ + ltq_stp_w32(0, LTQ_STP_AR); + ltq_stp_w32(0, LTQ_STP_CPU0); +@@ -105,7 +109,9 @@ static int ltq_stp_hw_init(void) + */ + ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0); + +- ltq_pmu_enable(PMU_LED); ++ clk = clk_get(dev, NULL); ++ WARN_ON(IS_ERR(clk)); ++ clk_enable(clk); + return 0; + } + +@@ -138,7 +144,7 @@ static int __devinit ltq_stp_probe(struct platform_device *pdev) + } + ret = gpiochip_add(<q_stp_chip); + if (!ret) +- ret = ltq_stp_hw_init(); ++ ret = ltq_stp_hw_init(&pdev->dev); + + return ret; + } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0030-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0030-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch new file mode 100644 index 0000000000..733112edd3 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0030-MIPS-lantiq-convert-falcon-gpio-to-clkdev-api.patch @@ -0,0 +1,73 @@ +From 3cb13f9992ae1948b6ca05c88d2bd25cf9e7cd41 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:22:03 +0100 +Subject: [PATCH 30/70] MIPS: lantiq: convert falcon gpio to clkdev api + +The falcon gpio clocks used to be enabled when registering the platform device. +Move this code into the driver and use clkdev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/falcon/devices.c | 5 ----- + arch/mips/lantiq/falcon/gpio.c | 10 ++++++++++ + 2 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +index 4f47b44..6cd7a88 100644 +--- a/arch/mips/lantiq/falcon/devices.c ++++ b/arch/mips/lantiq/falcon/devices.c +@@ -111,9 +111,6 @@ falcon_register_gpio(void) + falcon_gpio1_res, ARRAY_SIZE(falcon_gpio1_res)); + platform_device_register_simple("falcon_gpio", 2, + falcon_gpio2_res, ARRAY_SIZE(falcon_gpio2_res)); +- ltq_sysctl_activate(SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1); +- ltq_sysctl_activate(SYSCTL_SYSETH, ACTS_PADCTRL0 | +- ACTS_PADCTRL2 | ACTS_P0 | ACTS_P2); + } + + void __init +@@ -123,6 +120,4 @@ falcon_register_gpio_extra(void) + falcon_gpio3_res, ARRAY_SIZE(falcon_gpio3_res)); + platform_device_register_simple("falcon_gpio", 4, + falcon_gpio4_res, ARRAY_SIZE(falcon_gpio4_res)); +- ltq_sysctl_activate(SYSCTL_SYS1, +- ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4); + } +diff --git a/arch/mips/lantiq/falcon/gpio.c b/arch/mips/lantiq/falcon/gpio.c +index a44f71b..4147d61 100644 +--- a/arch/mips/lantiq/falcon/gpio.c ++++ b/arch/mips/lantiq/falcon/gpio.c +@@ -11,6 +11,7 @@ + #include <linux/interrupt.h> + #include <linux/slab.h> + #include <linux/export.h> ++#include <linux/err.h> + #include <linux/platform_device.h> + + #include <lantiq_soc.h> +@@ -71,6 +72,7 @@ struct falcon_gpio_port { + void __iomem *port; + unsigned int irq_base; + unsigned int chained_irq; ++ struct clk *clk; + }; + + static struct falcon_gpio_port ltq_gpio_port[MAX_PORTS]; +@@ -332,6 +334,14 @@ falcon_gpio_probe(struct platform_device *pdev) + goto err; + } + ++ gpio_port->clk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(gpio_port->clk)) { ++ dev_err(&pdev->dev, "Could not get clock\n"); ++ ret = PTR_ERR(gpio_port->clk);; ++ goto err; ++ } ++ clk_enable(gpio_port->clk); ++ + if (irq > 0) { + /* irq_chip support */ + gpio_port->gpio_chip.to_irq = falcon_gpio_to_irq; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0031-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch b/target/linux/lantiq/patches-3.2/0031-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch new file mode 100644 index 0000000000..dc651aa9e0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0031-SERIAL-MIPS-lantiq-convert-serial-driver-to-clkdev-a.patch @@ -0,0 +1,41 @@ +From 1fdd8c04b65bd55730e6931a520cc1dabfc4d190 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 16 Feb 2012 20:17:16 +0100 +Subject: [PATCH 31/70] SERIAL: MIPS: lantiq: convert serial driver to clkdev + api + +Reference the FPI clock via its new access function. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-serial@vger.kernel.org +--- + drivers/tty/serial/lantiq.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c +index 5d25828..1542ad6 100644 +--- a/drivers/tty/serial/lantiq.c ++++ b/drivers/tty/serial/lantiq.c +@@ -540,6 +540,10 @@ lqasc_request_port(struct uart_port *port) + if (ltq_gpio_request(&pdev->dev, MUXC_SIF_TX_PIN, + 3, 1, "asc1-tx")) + return -EBUSY; ++ ltq_port->clk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(ltq_port->clk)) ++ return PTR_ERR(ltq_port->clk); ++ clk_enable(ltq_port->clk); + } + return 0; + } +@@ -698,7 +702,7 @@ lqasc_probe(struct platform_device *pdev) + if (lqasc_port[pdev->id] != NULL) + return -EBUSY; + +- clk = clk_get(&pdev->dev, "fpi"); ++ clk = clk_get_fpi(); + if (IS_ERR(clk)) { + pr_err("failed to get fpi clk\n"); + return -ENOENT; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0032-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0032-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch new file mode 100644 index 0000000000..e13f951cb8 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0032-MIPS-lantiq-convert-falcon-debug-uart-to-clkdev-api.patch @@ -0,0 +1,73 @@ +From 005044f41ed9884ee23d756a5950e38679d31cc7 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 Feb 2012 14:25:21 +0100 +Subject: [PATCH 32/70] MIPS: lantiq: convert falcon debug uart to clkdev api + +On Falcon SoCs we have a secondary serial port that can be used to help +debug the voice core. For the port to work several clocking bits need to +be activated. We convert the code to clkdev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/falcon/prom.c | 4 +--- + drivers/tty/serial/lantiq.c | 7 ++++--- + 2 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c +index f98b389..2a4eea1 100644 +--- a/arch/mips/lantiq/falcon/prom.c ++++ b/arch/mips/lantiq/falcon/prom.c +@@ -43,10 +43,8 @@ ltq_soc_setup(void) + ltq_register_asc(0); + ltq_register_wdt(); + falcon_register_gpio(); +- if (register_asc1) { ++ if (register_asc1) + ltq_register_asc(1); +- ltq_sysctl_activate(SYSCTL_SYS1, ACTS_ASC1_ACT); +- } + } + + void __init +diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c +index 1542ad6..82956de 100644 +--- a/drivers/tty/serial/lantiq.c ++++ b/drivers/tty/serial/lantiq.c +@@ -117,6 +117,7 @@ static DEFINE_SPINLOCK(ltq_asc_lock); + + struct ltq_uart_port { + struct uart_port port; ++ struct clk *fpiclk; + struct clk *clk; + unsigned int tx_irq; + unsigned int rx_irq; +@@ -319,7 +320,7 @@ lqasc_startup(struct uart_port *port) + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + int retval; + +- port->uartclk = clk_get_rate(ltq_port->clk); ++ port->uartclk = clk_get_rate(ltq_port->fpiclk); + + ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), + port->membase + LTQ_ASC_CLC); +@@ -646,7 +647,7 @@ lqasc_console_setup(struct console *co, char *options) + + port = <q_port->port; + +- port->uartclk = clk_get_rate(ltq_port->clk); ++ port->uartclk = clk_get_rate(ltq_port->fpiclk); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); +@@ -731,7 +732,7 @@ lqasc_probe(struct platform_device *pdev) + port->irq = tx_irq; /* unused, just to be backward-compatibe */ + port->mapbase = mmres->start; + +- ltq_port->clk = clk; ++ ltq_port->fpiclk = clk; + + ltq_port->tx_irq = tx_irq; + ltq_port->rx_irq = rx_irq; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0033-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch b/target/linux/lantiq/patches-3.2/0033-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch new file mode 100644 index 0000000000..a57b956048 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0033-NET-MIPS-lantiq-convert-etop-driver-to-clkdev-api.patch @@ -0,0 +1,123 @@ +From c96f5cae05788c326f63c8b769e53c6e15215e70 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:23:00 +0100 +Subject: [PATCH 33/70] NET: MIPS: lantiq: convert etop driver to clkdev api + +Update from old pmu_{dis,en}able() to ckldev api. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: netdev@vger.kernel.org +--- + drivers/net/ethernet/lantiq_etop.c | 49 ++++++++++++++++++++++++++++++----- + 1 files changed, 42 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index fcbb9c7..a084d74 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -36,6 +36,7 @@ + #include <linux/io.h> + #include <linux/dma-mapping.h> + #include <linux/module.h> ++#include <linux/clk.h> + + #include <asm/checksum.h> + +@@ -147,6 +148,11 @@ struct ltq_etop_priv { + int tx_free[MAX_DMA_CHAN >> 1]; + + spinlock_t lock; ++ ++ struct clk *clk_ppe; ++ struct clk *clk_switch; ++ struct clk *clk_ephy; ++ struct clk *clk_ephycgu; + }; + + static int ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, +@@ -280,16 +286,27 @@ ltq_etop_hw_exit(struct net_device *dev) + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + +- ltq_pmu_disable(PMU_PPE); ++ clk_disable(priv->clk_ppe); ++ ++ if (ltq_has_gbit()) ++ clk_disable(priv->clk_switch); ++ ++ if (ltq_is_ase()) { ++ clk_disable(priv->clk_ephy); ++ clk_disable(priv->clk_ephycgu); ++ } ++ + for (i = 0; i < MAX_DMA_CHAN; i++) + if (IS_TX(i) || IS_RX(i)) + ltq_etop_free_channel(dev, &priv->ch[i]); + } + + static void +-ltq_etop_gbit_init(void) ++ltq_etop_gbit_init(struct net_device *dev) + { +- ltq_pmu_enable(PMU_SWITCH); ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ ++ clk_enable(priv->clk_switch); + + ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0); + /** Disable MDIO auto polling mode */ +@@ -312,10 +329,10 @@ ltq_etop_hw_init(struct net_device *dev) + int err = 0; + int i; + +- ltq_pmu_enable(PMU_PPE); ++ clk_enable(priv->clk_ppe); + + if (ltq_has_gbit()) { +- ltq_etop_gbit_init(); ++ ltq_etop_gbit_init(dev); + /* force the etops link to the gbit to MII */ + mii_mode = PHY_INTERFACE_MODE_MII; + } +@@ -333,11 +350,11 @@ ltq_etop_hw_init(struct net_device *dev) + + default: + if (ltq_is_ase()) { +- ltq_pmu_enable(PMU_EPHY); ++ clk_enable(priv->clk_ephy); + /* disable external MII */ + ltq_etop_w32_mask(0, ETOP_CFG_MII0, LTQ_ETOP_CFG); + /* enable clock for internal PHY */ +- ltq_cgu_enable(CGU_EPHY); ++ clk_enable(priv->clk_ephycgu); + /* we need to write this magic to the internal phy to + make it work */ + ltq_etop_mdio_wr(NULL, 0x8, 0x12, 0xC020); +@@ -880,6 +897,24 @@ ltq_etop_probe(struct platform_device *pdev) + priv->res = res; + priv->pldata = dev_get_platdata(&pdev->dev); + priv->netdev = dev; ++ ++ priv->clk_ppe = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk_ppe)) ++ return PTR_ERR(priv->clk_ppe); ++ if (ltq_has_gbit()) { ++ priv->clk_switch = clk_get(&pdev->dev, "switch"); ++ if (IS_ERR(priv->clk_switch)) ++ return PTR_ERR(priv->clk_switch); ++ } ++ if (ltq_is_ase()) { ++ priv->clk_ephy = clk_get(&pdev->dev, "ephy"); ++ if (IS_ERR(priv->clk_ephy)) ++ return PTR_ERR(priv->clk_ephy); ++ priv->clk_ephycgu = clk_get(&pdev->dev, "ephycgu"); ++ if (IS_ERR(priv->clk_ephycgu)) ++ return PTR_ERR(priv->clk_ephycgu); ++ } ++ + spin_lock_init(&priv->lock); + + for (i = 0; i < MAX_DMA_CHAN; i++) { +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0034-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch b/target/linux/lantiq/patches-3.2/0034-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch new file mode 100644 index 0000000000..8eb401d296 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0034-WDT-MIPS-lantiq-convert-watchdog-driver-to-clkdev-ap.patch @@ -0,0 +1,30 @@ +From ac9ded7942720231ed139ac0660e60a3a2f82b86 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 16 Feb 2012 20:17:50 +0100 +Subject: [PATCH 34/70] WDT: MIPS: lantiq: convert watchdog driver to clkdev + api + +Refrence the IO region clock via its new access function. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-watchdog@vger.kernel.org +--- + drivers/watchdog/lantiq_wdt.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c +index 179bf98..da2b09f 100644 +--- a/drivers/watchdog/lantiq_wdt.c ++++ b/drivers/watchdog/lantiq_wdt.c +@@ -206,7 +206,7 @@ ltq_wdt_probe(struct platform_device *pdev) + } + + /* we do not need to enable the clock as it is always running */ +- clk = clk_get(&pdev->dev, "io"); ++ clk = clk_get_io(); + WARN_ON(!clk); + ltq_io_region_clk_rate = clk_get_rate(clk); + clk_put(clk); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-unify-xway-prom-code.patch b/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-unify-xway-prom-code.patch new file mode 100644 index 0000000000..69a0ffb417 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0035-MIPS-lantiq-unify-xway-prom-code.patch @@ -0,0 +1,262 @@ +From cab49331fac138102493dea8f1b1d8c28cae6db5 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 11:44:55 +0100 +Subject: [PATCH 35/70] MIPS: lantiq: unify xway prom code + +The xway prom-ase.c and prom-xway.c files are redundant. Unify the 2 files. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/xway/Makefile | 5 +-- + arch/mips/lantiq/xway/Makefile.rej | 11 ----- + arch/mips/lantiq/xway/prom-ase.c | 48 ---------------------- + arch/mips/lantiq/xway/prom-xway.c | 64 ----------------------------- + arch/mips/lantiq/xway/prom.c | 79 ++++++++++++++++++++++++++++++++++++ + 5 files changed, 80 insertions(+), 127 deletions(-) + delete mode 100644 arch/mips/lantiq/xway/Makefile.rej + delete mode 100644 arch/mips/lantiq/xway/prom-ase.c + delete mode 100644 arch/mips/lantiq/xway/prom-xway.c + create mode 100644 arch/mips/lantiq/xway/prom.c + +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 4dcb96f..9d1a0a2 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,7 +1,4 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o +- +-obj-$(CONFIG_SOC_XWAY) += prom-xway.o +-obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/Makefile.rej b/arch/mips/lantiq/xway/Makefile.rej +deleted file mode 100644 +index c0d5b52..0000000 +--- a/arch/mips/lantiq/xway/Makefile.rej ++++ /dev/null +@@ -1,11 +0,0 @@ +---- arch/mips/lantiq/xway/Makefile +-+++ arch/mips/lantiq/xway/Makefile +-@@ -1,7 +1,4 @@ +--obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o +-- +--obj-$(CONFIG_SOC_XWAY) += prom-xway.o +--obj-$(CONFIG_SOC_AMAZON_SE) += prom-ase.o +-+obj-y := prom.o sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o +- +- obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o +- obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c +deleted file mode 100644 +index 3f86a3b..0000000 +--- a/arch/mips/lantiq/xway/prom-ase.c ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* +- * 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 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/export.h> +-#include <linux/clk.h> +-#include <asm/bootinfo.h> +-#include <asm/time.h> +- +-#include <lantiq_soc.h> +- +-#include "devices.h" +-#include "../prom.h" +- +-#define SOC_AMAZON_SE "Amazon_SE" +- +-#define PART_SHIFT 12 +-#define PART_MASK 0x0FFFFFFF +-#define REV_SHIFT 28 +-#define REV_MASK 0xF0000000 +- +-void __init ltq_soc_detect(struct ltq_soc_info *i) +-{ +- i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; +- i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; +- sprintf(i->rev_type, "1.%d", i->rev); +- switch (i->partnum) { +- case SOC_ID_AMAZON_SE: +- i->name = SOC_AMAZON_SE; +- i->type = SOC_TYPE_AMAZON_SE; +- break; +- +- default: +- unreachable(); +- break; +- } +-} +- +-void __init ltq_soc_setup(void) +-{ +- ltq_register_ase_asc(); +- ltq_register_gpio(); +- ltq_register_wdt(); +-} +diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c +deleted file mode 100644 +index d823a92..0000000 +--- a/arch/mips/lantiq/xway/prom-xway.c ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* +- * 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 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/export.h> +-#include <linux/clk.h> +-#include <asm/bootinfo.h> +-#include <asm/time.h> +- +-#include <lantiq_soc.h> +- +-#include "devices.h" +-#include "../prom.h" +- +-#define SOC_DANUBE "Danube" +-#define SOC_TWINPASS "Twinpass" +-#define SOC_AR9 "AR9" +- +-#define PART_SHIFT 12 +-#define PART_MASK 0x0FFFFFFF +-#define REV_SHIFT 28 +-#define REV_MASK 0xF0000000 +- +-void __init ltq_soc_detect(struct ltq_soc_info *i) +-{ +- i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; +- i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; +- sprintf(i->rev_type, "1.%d", i->rev); +- switch (i->partnum) { +- case SOC_ID_DANUBE1: +- case SOC_ID_DANUBE2: +- i->name = SOC_DANUBE; +- i->type = SOC_TYPE_DANUBE; +- break; +- +- case SOC_ID_TWINPASS: +- i->name = SOC_TWINPASS; +- i->type = SOC_TYPE_DANUBE; +- break; +- +- case SOC_ID_ARX188: +- case SOC_ID_ARX168: +- case SOC_ID_ARX182: +- i->name = SOC_AR9; +- i->type = SOC_TYPE_AR9; +- break; +- +- default: +- unreachable(); +- break; +- } +-} +- +-void __init ltq_soc_setup(void) +-{ +- ltq_register_asc(0); +- ltq_register_asc(1); +- ltq_register_gpio(); +- ltq_register_wdt(); +-} +diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c +new file mode 100644 +index 0000000..0929acb +--- /dev/null ++++ b/arch/mips/lantiq/xway/prom.c +@@ -0,0 +1,79 @@ ++/* ++ * 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 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/export.h> ++#include <linux/clk.h> ++#include <asm/bootinfo.h> ++#include <asm/time.h> ++ ++#include <lantiq_soc.h> ++ ++#include "../prom.h" ++#include "devices.h" ++ ++#define SOC_DANUBE "Danube" ++#define SOC_TWINPASS "Twinpass" ++#define SOC_AR9 "AR9" ++#define SOC_VR9 "VR9" ++ ++#define PART_SHIFT 12 ++#define PART_MASK 0x0FFFFFFF ++#define REV_SHIFT 28 ++#define REV_MASK 0xF0000000 ++ ++#define SOC_AMAZON_SE "Amazon_SE" ++ ++void __init ltq_soc_detect(struct ltq_soc_info *i) ++{ ++ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; ++ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; ++ sprintf(i->rev_type, "1.%d", i->rev); ++ switch (i->partnum) { ++ case SOC_ID_DANUBE1: ++ case SOC_ID_DANUBE2: ++ i->name = SOC_DANUBE; ++ i->type = SOC_TYPE_DANUBE; ++ break; ++ ++ case SOC_ID_TWINPASS: ++ i->name = SOC_TWINPASS; ++ i->type = SOC_TYPE_DANUBE; ++ break; ++ ++ case SOC_ID_ARX188: ++ case SOC_ID_ARX168: ++ case SOC_ID_ARX182: ++ i->name = SOC_AR9; ++ i->type = SOC_TYPE_AR9; ++ break; ++ ++ case SOC_ID_AMAZON_SE: ++ i->name = SOC_AMAZON_SE; ++ i->type = SOC_TYPE_AMAZON_SE; ++#ifdef CONFIG_PCI ++ panic("ase is only supported for non pci kernels"); ++#endif ++ break; ++ ++ default: ++ unreachable(); ++ break; ++ } ++} ++ ++void __init ltq_soc_setup(void) ++{ ++ if (ltq_is_ase()) { ++ ltq_register_ase_asc(); ++ } else { ++ ltq_register_asc(0); ++ ltq_register_asc(1); ++ } ++ ltq_register_gpio(); ++ ltq_register_wdt(); ++} +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-vr9-support.patch b/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-vr9-support.patch new file mode 100644 index 0000000000..c63be05def --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0036-MIPS-lantiq-add-vr9-support.patch @@ -0,0 +1,172 @@ +From 27c4128ab1835a2aff1a0ce6413bb21cfa614d93 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 Feb 2012 09:48:11 +0100 +Subject: [PATCH 36/70] MIPS: lantiq: add vr9 support + +VR9 is a VDSL SoC made by Lantiq. It is very similar to the AR9. +This patch adds the clkdev init code and SoC detection for the VR9. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 + + arch/mips/lantiq/xway/clk.c | 83 ++++++++++++++++++++ + arch/mips/lantiq/xway/prom.c | 6 ++ + arch/mips/lantiq/xway/sysctrl.c | 12 +++- + 4 files changed, 103 insertions(+), 1 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index e9d2dd4..5d11eb7 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -21,6 +21,9 @@ + #define SOC_ID_ARX188 0x16C + #define SOC_ID_ARX168 0x16D + #define SOC_ID_ARX182 0x16F ++#define SOC_ID_VRX288 0x1C0 /* VRX288 v1.1 */ ++#define SOC_ID_VRX268 0x1C2 /* VRX268 v1.1 */ ++#define SOC_ID_GRX288 0x1C9 /* GRX288 v1.1 */ + + /* SoC Types */ + #define SOC_TYPE_DANUBE 0x01 +diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c +index f3b50fc..3635c9f 100644 +--- a/arch/mips/lantiq/xway/clk.c ++++ b/arch/mips/lantiq/xway/clk.c +@@ -225,3 +225,86 @@ unsigned long ltq_danube_fpi_hz(void) + return ddr_clock >> 1; + return ddr_clock; + } ++ ++unsigned long ltq_vr9_cpu_hz(void) ++{ ++ unsigned int cpu_sel; ++ unsigned long clk; ++ ++ cpu_sel = (ltq_cgu_r32(LTQ_CGU_SYS_VR9) >> 4) & 0xf; ++ ++ switch (cpu_sel) { ++ case 0: ++ clk = CLOCK_600M; ++ break; ++ case 1: ++ clk = CLOCK_500M; ++ break; ++ case 2: ++ clk = CLOCK_393M; ++ break; ++ case 3: ++ clk = CLOCK_333M; ++ break; ++ case 5: ++ case 6: ++ clk = CLOCK_196_608M; ++ break; ++ case 7: ++ clk = CLOCK_167M; ++ break; ++ case 4: ++ case 8: ++ case 9: ++ clk = CLOCK_125M; ++ break; ++ default: ++ clk = 0; ++ break; ++ } ++ ++ return clk; ++} ++ ++unsigned long ltq_vr9_fpi_hz(void) ++{ ++ unsigned int ocp_sel, cpu_clk; ++ unsigned long clk; ++ ++ cpu_clk = ltq_vr9_cpu_hz(); ++ ocp_sel = ltq_cgu_r32(LTQ_CGU_SYS_VR9) & 0x3; ++ ++ switch (ocp_sel) { ++ case 0: ++ /* OCP ratio 1 */ ++ clk = cpu_clk; ++ break; ++ case 2: ++ /* OCP ratio 2 */ ++ clk = cpu_clk / 2; ++ break; ++ case 3: ++ /* OCP ratio 2.5 */ ++ clk = (cpu_clk * 2) / 5; ++ break; ++ case 4: ++ /* OCP ratio 3 */ ++ clk = cpu_clk / 3; ++ break; ++ default: ++ clk = 0; ++ break; ++ } ++ ++ return clk; ++} ++ ++unsigned long ltq_vr9_io_region_clock(void) ++{ ++ return ltq_vr9_fpi_hz(); ++} ++ ++unsigned long ltq_vr9_fpi_bus_clock(int fpi) ++{ ++ return ltq_vr9_fpi_hz(); ++} +diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c +index 0929acb..b6f56b7 100644 +--- a/arch/mips/lantiq/xway/prom.c ++++ b/arch/mips/lantiq/xway/prom.c +@@ -60,6 +60,12 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) + #endif + break; + ++ case SOC_ID_VRX268: ++ case SOC_ID_VRX288: ++ i->name = SOC_VR9; ++ i->type = SOC_TYPE_VR9; ++ break; ++ + default: + unreachable(); + break; +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index c5782b5..38f02f9 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -147,7 +147,8 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); + clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); + clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); +- clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); ++ if (!ltq_is_vr9()) ++ clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); + if (ltq_is_ase()) { + if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) + clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); +@@ -155,6 +156,15 @@ void __init ltq_soc_init(void) + clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); + clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), + clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); ++ } else if (ltq_is_vr9()) { ++ clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), ++ ltq_vr9_io_region_clock()); ++ clkdev_add_pmu("ltq_pcie", "phy", 1, PMU1_PCIE_PHY); ++ clkdev_add_pmu("ltq_pcie", "bus", 0, PMU_PCIE_CLK); ++ clkdev_add_pmu("ltq_pcie", "msi", 1, PMU1_PCIE_MSI); ++ clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); ++ clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); ++ clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), + ltq_danube_io_region_clock()); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch b/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch new file mode 100644 index 0000000000..06e7dd3f31 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0037-MIPS-lantiq-add-ipi-handlers-to-make-vsmp-work.patch @@ -0,0 +1,124 @@ +From 58d1ae79d144e6725a68fab99ef6a9b20b25a765 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 Feb 2012 21:09:01 +0100 +Subject: [PATCH 37/70] MIPS: lantiq: add ipi handlers to make vsmp work + +Add IPI handlers to the interrupt code. This patch makes MIPS_MT_SMP work +on lantiq SoCs. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/lantiq/irq.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ + arch/mips/lantiq/prom.c | 5 ++++ + 2 files changed, 66 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c +index 0b2ed87..770a10c 100644 +--- a/arch/mips/lantiq/irq.c ++++ b/arch/mips/lantiq/irq.c +@@ -9,6 +9,7 @@ + + #include <linux/interrupt.h> + #include <linux/ioport.h> ++#include <linux/sched.h> + + #include <asm/bootinfo.h> + #include <asm/irq_cpu.h> +@@ -54,6 +55,14 @@ + #define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) + #define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) + ++/* our 2 ipi interrupts for VSMP */ ++#define MIPS_CPU_IPI_RESCHED_IRQ 0 ++#define MIPS_CPU_IPI_CALL_IRQ 1 ++ ++#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) ++int gic_present; ++#endif ++ + static unsigned short ltq_eiu_irq[MAX_EIU] = { + LTQ_EIU_IR0, + LTQ_EIU_IR1, +@@ -219,6 +228,47 @@ static void ltq_hw5_irqdispatch(void) + do_IRQ(MIPS_CPU_TIMER_IRQ); + } + ++#ifdef CONFIG_MIPS_MT_SMP ++void __init arch_init_ipiirq(int irq, struct irqaction *action) ++{ ++ setup_irq(irq, action); ++ irq_set_handler(irq, handle_percpu_irq); ++} ++ ++static void ltq_sw0_irqdispatch(void) ++{ ++ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); ++} ++ ++static void ltq_sw1_irqdispatch(void) ++{ ++ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); ++} ++static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) ++{ ++ scheduler_ipi(); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) ++{ ++ smp_call_function_interrupt(); ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction irq_resched = { ++ .handler = ipi_resched_interrupt, ++ .flags = IRQF_PERCPU, ++ .name = "IPI_resched" ++}; ++ ++static struct irqaction irq_call = { ++ .handler = ipi_call_interrupt, ++ .flags = IRQF_PERCPU, ++ .name = "IPI_call" ++}; ++#endif ++ + asmlinkage void plat_irq_dispatch(void) + { + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; +@@ -314,6 +364,17 @@ void __init arch_init_irq(void) + irq_set_chip_and_handler(i, <q_irq_type, + handle_level_irq); + ++#if defined(CONFIG_MIPS_MT_SMP) ++ if (cpu_has_vint) { ++ pr_info("Setting up IPI vectored interrupts\n"); ++ set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ltq_sw0_irqdispatch); ++ set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ltq_sw1_irqdispatch); ++ } ++ arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ, ++ &irq_resched); ++ arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call); ++#endif ++ + #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) + set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | + IE_IRQ3 | IE_IRQ4 | IE_IRQ5); +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index 971554b..00ad59c 100644 +--- a/arch/mips/lantiq/prom.c ++++ b/arch/mips/lantiq/prom.c +@@ -108,4 +108,9 @@ void __init prom_init(void) + soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; + pr_info("SoC: %s\n", soc_info.sys_type); + prom_init_cmdline(); ++ ++#if defined(CONFIG_MIPS_MT_SMP) ++ if (register_vsmp_smp_ops()) ++ panic("failed to register_vsmp_smp_ops()"); ++#endif + } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0038-MIPS-lantiq-add-additional-soc-ids.patch b/target/linux/lantiq/patches-3.2/0038-MIPS-lantiq-add-additional-soc-ids.patch new file mode 100644 index 0000000000..d5ab3843cd --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0038-MIPS-lantiq-add-additional-soc-ids.patch @@ -0,0 +1,156 @@ +From 655f264da58e9e49d61bf26374f877e2175125e4 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 12 Mar 2012 15:23:39 +0100 +Subject: [PATCH 38/70] MIPS: lantiq: add additional soc ids + +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 38 +++++++++++++++---- + arch/mips/lantiq/xway/prom.c | 35 ++++++++++++++++-- + 2 files changed, 61 insertions(+), 12 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 5d11eb7..3f22acb 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -17,20 +17,32 @@ + #define SOC_ID_DANUBE1 0x129 + #define SOC_ID_DANUBE2 0x12B + #define SOC_ID_TWINPASS 0x12D +-#define SOC_ID_AMAZON_SE 0x152 ++#define SOC_ID_AMAZON_SE_1 0x152 /* 50601 */ ++#define SOC_ID_AMAZON_SE_2 0x153 /* 50600 */ + #define SOC_ID_ARX188 0x16C +-#define SOC_ID_ARX168 0x16D ++#define SOC_ID_ARX168_1 0x16D ++#define SOC_ID_ARX168_2 0x16E + #define SOC_ID_ARX182 0x16F +-#define SOC_ID_VRX288 0x1C0 /* VRX288 v1.1 */ +-#define SOC_ID_VRX268 0x1C2 /* VRX268 v1.1 */ +-#define SOC_ID_GRX288 0x1C9 /* GRX288 v1.1 */ ++#define SOC_ID_GRX188 0x170 ++#define SOC_ID_GRX168 0x171 ++ ++#define SOC_ID_VRX288 0x1C0 /* v1.1 */ ++#define SOC_ID_VRX282 0x1C1 /* v1.1 */ ++#define SOC_ID_VRX268 0x1C2 /* v1.1 */ ++#define SOC_ID_GRX268 0x1C8 /* v1.1 */ ++#define SOC_ID_GRX288 0x1C9 /* v1.1 */ ++#define SOC_ID_VRX288_2 0x00B /* v1.2 */ ++#define SOC_ID_VRX268_2 0x00C /* v1.2 */ ++#define SOC_ID_GRX288_2 0x00D /* v1.2 */ ++#define SOC_ID_GRX282_2 0x00E /* v1.2 */ + + /* SoC Types */ + #define SOC_TYPE_DANUBE 0x01 + #define SOC_TYPE_TWINPASS 0x02 + #define SOC_TYPE_AR9 0x03 +-#define SOC_TYPE_VR9 0x04 +-#define SOC_TYPE_AMAZON_SE 0x05 ++#define SOC_TYPE_VR9_1 0x04 /* v1.1 */ ++#define SOC_TYPE_VR9_2 0x05 /* v1.2 */ ++#define SOC_TYPE_AMAZON_SE 0x06 + + /* ASC0/1 - serial port */ + #define LTQ_ASC0_BASE_ADDR 0x1E100400 +@@ -149,9 +161,19 @@ static inline int ltq_is_ar9(void) + return (ltq_get_soc_type() == SOC_TYPE_AR9); + } + ++static inline int ltq_is_vr9_1(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_VR9_1); ++} ++ ++static inline int ltq_is_vr9_2(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_VR9_2); ++} ++ + static inline int ltq_is_vr9(void) + { +- return (ltq_get_soc_type() == SOC_TYPE_VR9); ++ return (ltq_is_vr9_1() || ltq_is_vr9_2()); + } + + static inline int ltq_is_falcon(void) +diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c +index b6f56b7..e3dcbbd 100644 +--- a/arch/mips/lantiq/xway/prom.c ++++ b/arch/mips/lantiq/xway/prom.c +@@ -18,7 +18,9 @@ + + #define SOC_DANUBE "Danube" + #define SOC_TWINPASS "Twinpass" ++#define SOC_AMAZON_SE "Amazon_SE" + #define SOC_AR9 "AR9" ++#define SOC_GR9 "GR9" + #define SOC_VR9 "VR9" + + #define PART_SHIFT 12 +@@ -26,7 +28,6 @@ + #define REV_SHIFT 28 + #define REV_MASK 0xF0000000 + +-#define SOC_AMAZON_SE "Amazon_SE" + + void __init ltq_soc_detect(struct ltq_soc_info *i) + { +@@ -46,13 +47,21 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) + break; + + case SOC_ID_ARX188: +- case SOC_ID_ARX168: ++ case SOC_ID_ARX168_1: ++ case SOC_ID_ARX168_2: + case SOC_ID_ARX182: + i->name = SOC_AR9; + i->type = SOC_TYPE_AR9; + break; + +- case SOC_ID_AMAZON_SE: ++ case SOC_ID_GRX188: ++ case SOC_ID_GRX168: ++ i->name = SOC_GR9; ++ i->type = SOC_TYPE_AR9; ++ break; ++ ++ case SOC_ID_AMAZON_SE_1: ++ case SOC_ID_AMAZON_SE_2: + i->name = SOC_AMAZON_SE; + i->type = SOC_TYPE_AMAZON_SE; + #ifdef CONFIG_PCI +@@ -60,12 +69,30 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) + #endif + break; + ++ case SOC_ID_VRX282: + case SOC_ID_VRX268: + case SOC_ID_VRX288: + i->name = SOC_VR9; +- i->type = SOC_TYPE_VR9; ++ i->type = SOC_TYPE_VR9_1; + break; + ++ case SOC_ID_GRX268: ++ case SOC_ID_GRX288: ++ i->name = SOC_GR9; ++ i->type = SOC_TYPE_VR9_1; ++ break; ++ ++ case SOC_ID_VRX268_2: ++ case SOC_ID_VRX288_2: ++ i->name = SOC_VR9; ++ i->type = SOC_TYPE_VR9_2; ++ break; ++ ++ case SOC_ID_GRX282_2: ++ case SOC_ID_GRX288_2: ++ i->name = SOC_GR9; ++ i->type = SOC_TYPE_VR9_2; ++ + default: + unreachable(); + break; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0013-MIPS-lantiq-adds-FALC-ON-spi-driver.patch b/target/linux/lantiq/patches-3.2/0039-SPI-MIPS-lantiq-add-FALC-ON-spi-driver.patch index 079e401f7c..384ed2e003 100644 --- a/target/linux/lantiq/patches/0013-MIPS-lantiq-adds-FALC-ON-spi-driver.patch +++ b/target/linux/lantiq/patches-3.2/0039-SPI-MIPS-lantiq-add-FALC-ON-spi-driver.patch @@ -1,43 +1,34 @@ -From 2bd534c30688bcb3f70f1816fbcff813fc746103 Mon Sep 17 00:00:00 2001 +From 0ebdb2202a06d096114aa7676f02d5f426a20366 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 27 Aug 2011 18:12:26 +0200 -Subject: [PATCH 13/24] MIPS: lantiq: adds FALC-ON spi driver +Subject: [PATCH 39/70] SPI: MIPS: lantiq: add FALC-ON spi driver The external bus unit (EBU) found on the FALC-ON SoC has spi emulation that is -designed for serial flash access. +designed for serial flash access. This driver has only been tested with m25p80 +type chips. The hardware has no support for other types of spi peripherals. Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: spi-devel-general@lists.sourceforge.net --- - arch/mips/lantiq/falcon/devices.c | 12 +- + arch/mips/lantiq/falcon/devices.c | 13 + arch/mips/lantiq/falcon/devices.h | 4 + arch/mips/lantiq/falcon/mach-easy98000.c | 27 ++ drivers/spi/Kconfig | 4 + drivers/spi/Makefile | 1 + - drivers/spi/spi-falcon.c | 477 ++++++++++++++++++++++++++++++ - 6 files changed, 523 insertions(+), 2 deletions(-) + drivers/spi/spi-falcon.c | 483 ++++++++++++++++++++++++++++++ + 6 files changed, 532 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/spi-falcon.c +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +index 6cd7a88..92ec571 100644 --- a/arch/mips/lantiq/falcon/devices.c +++ b/arch/mips/lantiq/falcon/devices.c -@@ -129,7 +129,7 @@ falcon_register_gpio_extra(void) - - /* i2c */ - static struct resource falcon_i2c_resources[] = { -- MEM_RES("i2c", GPON_I2C_BASE,GPON_I2C_END), -+ MEM_RES("i2c", LTQ_I2C_BASE_ADDR, LTQ_I2C_SIZE), - IRQ_RES("i2c_lb", FALCON_IRQ_I2C_LBREQ), - IRQ_RES("i2c_b", FALCON_IRQ_I2C_BREQ), - IRQ_RES("i2c_err", FALCON_IRQ_I2C_I2C_ERR), -@@ -140,10 +140,18 @@ void __init falcon_register_i2c(void) - { - platform_device_register_simple("i2c-falcon", 0, - falcon_i2c_resources, ARRAY_SIZE(falcon_i2c_resources)); -- sys1_hw_activate(ACTS_I2C_ACT); -+ ltq_sysctl_activate(SYSCTL_SYS1, ACTS_I2C_ACT); +@@ -121,3 +121,16 @@ falcon_register_gpio_extra(void) + platform_device_register_simple("falcon_gpio", 4, + falcon_gpio4_res, ARRAY_SIZE(falcon_gpio4_res)); } - --void __init falcon_register_crypto(void) ++ +/* spi flash */ +static struct platform_device ltq_spi = { + .name = "falcon_spi", @@ -46,14 +37,15 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + +void __init +falcon_register_spi_flash(struct spi_board_info *data) - { -- platform_device_register_simple("ltq_falcon_deu", 0, NULL, 0); ++{ + spi_register_board_info(data, 1); + platform_device_register(<q_spi); - } ++} +diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h +index 18be8b6..5e6f720 100644 --- a/arch/mips/lantiq/falcon/devices.h +++ b/arch/mips/lantiq/falcon/devices.h -@@ -11,11 +11,15 @@ +@@ -11,10 +11,14 @@ #ifndef _FALCON_DEVICES_H__ #define _FALCON_DEVICES_H__ @@ -65,13 +57,14 @@ Signed-off-by: John Crispin <blogic@openwrt.org> extern void falcon_register_nand(void); extern void falcon_register_gpio(void); extern void falcon_register_gpio_extra(void); - extern void falcon_register_i2c(void); +extern void falcon_register_spi_flash(struct spi_board_info *data); #endif +diff --git a/arch/mips/lantiq/falcon/mach-easy98000.c b/arch/mips/lantiq/falcon/mach-easy98000.c +index 361b8f0..1a7caad 100644 --- a/arch/mips/lantiq/falcon/mach-easy98000.c +++ b/arch/mips/lantiq/falcon/mach-easy98000.c -@@ -40,6 +40,21 @@ struct physmap_flash_data easy98000_nor_ +@@ -40,6 +40,21 @@ struct physmap_flash_data easy98000_nor_flash_data = { .parts = easy98000_nor_partitions, }; @@ -119,9 +112,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> MIPS_MACHINE(LANTIQ_MACH_EASY98000NAND, "EASY98000NAND", "EASY98000 Eval Board (NAND Flash)", +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 8ba4510..b8424ba 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -189,6 +189,10 @@ config SPI_MPC52xx +@@ -180,6 +180,10 @@ config SPI_MPC52xx This drivers supports the MPC52xx SPI controller in master SPI mode. @@ -132,9 +127,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> config SPI_MPC52xx_PSC tristate "Freescale MPC52xx PSC SPI controller" depends on PPC_MPC52xx && EXPERIMENTAL +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 61c3261..570894c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -25,6 +25,7 @@ obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmi +@@ -25,6 +25,7 @@ obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o @@ -142,9 +139,12 @@ Signed-off-by: John Crispin <blogic@openwrt.org> obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o +diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c +new file mode 100644 +index 0000000..447bbaa --- /dev/null +++ b/drivers/spi/spi-falcon.c -@@ -0,0 +1,477 @@ +@@ -0,0 +1,483 @@ +/* + * 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 @@ -287,8 +287,10 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + txp++; + bytelen--; + if (bytelen) { -+ /* more data: -+ * maybe address and/or dummy */ ++ /* ++ * more data: ++ * maybe address and/or dummy ++ */ + state = state_command_prepare; + break; + } else { @@ -313,8 +315,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + state = state_end; + break; + } -+ case state_command_prepare: /* collect tx data for -+ address and dummy phase */ ++ /* collect tx data for address and dummy phase */ ++ case state_command_prepare: + { + /* txp is valid, already checked */ + val = 0; @@ -353,8 +355,10 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + /* end of sequence? */ + state = state_disable_cs; + } else { -+ /* go to end and expect another -+ * call (read or write) */ ++ /* ++ * go to end and expect another ++ * call (read or write) ++ */ + state = state_end; + } + break; @@ -452,7 +456,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +falcon_spi_setup(struct spi_device *spi) +{ + struct device *dev = &spi->dev; -+ const u32 ebuclk = CLOCK_100M; ++ const u32 ebuclk = 100000000; + unsigned int i; + unsigned long flags; + @@ -486,8 +490,10 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + | (i << (SFTIME_SCK_PER_OFFSET + 1)), + LTQ_SFTIME); + -+ /* set some bits of unused_wd, to not trigger HOLD/WP -+ * signals on non QUAD flashes */ ++ /* ++ * set some bits of unused_wd, to not trigger HOLD/WP ++ * signals on non QUAD flashes ++ */ + ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), LTQ_SFIO); + + ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX, @@ -622,24 +628,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver"); ---- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -@@ -48,6 +48,10 @@ - - #define LTQ_EBU_MODCON 0x000C - -+/* I2C */ -+#define LTQ_I2C_BASE_ADDR 0x1E200000 -+#define LTQ_I2C_SIZE 0x00010000 -+ - /* GPIO */ - #define LTQ_GPIO0_BASE_ADDR 0x1D810000 - #define LTQ_GPIO0_SIZE 0x0080 -@@ -92,6 +96,7 @@ - - /* Activation Status Register */ - #define ACTS_ASC1_ACT 0x00000800 -+#define ACTS_I2C_ACT 0x00004000 - #define ACTS_P0 0x00010000 - #define ACTS_P1 0x00010000 - #define ACTS_P2 0x00020000 +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0011-MIPS-lantiq-adds-falcon-I2C.patch b/target/linux/lantiq/patches-3.2/0040-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch index eceb1e4f2e..f8534bfaf0 100644 --- a/target/linux/lantiq/patches/0011-MIPS-lantiq-adds-falcon-I2C.patch +++ b/target/linux/lantiq/patches-3.2/0040-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch @@ -1,78 +1,185 @@ -From 6437f41dfdf9475178e22ab0dd886af033f90cc2 Mon Sep 17 00:00:00 2001 +From 97050437c6a3ce59ce2c5a8286b9bc1c9f1b3b60 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> -Date: Thu, 29 Sep 2011 21:10:16 +0200 -Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C +Date: Fri, 4 Nov 2011 16:00:34 +0100 +Subject: [PATCH 40/70] I2C: MIPS: lantiq: add FALC-ON i2c bus master +This patch adds the driver needed to make the I2C bus work on FALC-ON SoCs. + +Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-i2c@vger.kernel.org --- - arch/mips/lantiq/falcon/devices.c | 21 + - arch/mips/lantiq/falcon/devices.h | 1 + - drivers/i2c/busses/Kconfig | 4 + - drivers/i2c/busses/Makefile | 1 + - drivers/i2c/busses/i2c-falcon.c | 815 +++++++++++++++++++++++++++++++++++++ - 5 files changed, 842 insertions(+), 0 deletions(-) + .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 5 + + arch/mips/lantiq/falcon/clk.c | 44 - + arch/mips/lantiq/falcon/devices.c | 16 + + arch/mips/lantiq/falcon/devices.h | 1 + + arch/mips/lantiq/falcon/mach-easy98000.c | 1 + + drivers/i2c/busses/Kconfig | 10 + + drivers/i2c/busses/Makefile | 1 + + drivers/i2c/busses/i2c-falcon.c | 1040 ++++++++++++++++++++ + 8 files changed, 1074 insertions(+), 44 deletions(-) + delete mode 100644 arch/mips/lantiq/falcon/clk.c create mode 100644 drivers/i2c/busses/i2c-falcon.c +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +index 120c56c..fff5ecd 100644 +--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -72,6 +72,10 @@ + #define LTQ_PADCTRL4_BASE_ADDR 0x1E800600 + #define LTQ_PADCTRL4_SIZE 0x0100 + ++/* I2C */ ++#define GPON_I2C_BASE 0x1E200000 ++#define GPON_I2C_SIZE 0x00010000 ++ + /* CHIP ID */ + #define LTQ_STATUS_BASE_ADDR 0x1E802000 + +@@ -106,6 +110,7 @@ + #define ACTS_PADCTRL2 0x00200000 + #define ACTS_PADCTRL3 0x00200000 + #define ACTS_PADCTRL4 0x00400000 ++#define ACTS_I2C_ACT 0x00004000 + + /* global register ranges */ + extern __iomem void *ltq_ebu_membase; +diff --git a/arch/mips/lantiq/falcon/clk.c b/arch/mips/lantiq/falcon/clk.c +deleted file mode 100644 +index afe1b52..0000000 +--- a/arch/mips/lantiq/falcon/clk.c ++++ /dev/null +@@ -1,44 +0,0 @@ +-/* +- * 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) 2011 Thomas Langer <thomas.langer@lantiq.com> +- * Copyright (C) 2011 John Crispin <blogic@openwrt.org> +- */ +- +-#include <linux/ioport.h> +-#include <linux/export.h> +- +-#include <lantiq_soc.h> +- +-#include "devices.h" +- +-/* CPU0 Clock Control Register */ +-#define LTQ_SYS1_CPU0CC 0x0040 +-/* clock divider bit */ +-#define LTQ_CPU0CC_CPUDIV 0x0001 +- +-unsigned int +-ltq_get_io_region_clock(void) +-{ +- return CLOCK_200M; +-} +-EXPORT_SYMBOL(ltq_get_io_region_clock); +- +-unsigned int +-ltq_get_cpu_hz(void) +-{ +- if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV) +- return CLOCK_200M; +- else +- return CLOCK_400M; +-} +-EXPORT_SYMBOL(ltq_get_cpu_hz); +- +-unsigned int +-ltq_get_fpi_hz(void) +-{ +- return CLOCK_100M; +-} +-EXPORT_SYMBOL(ltq_get_fpi_hz); +diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c +index 92ec571..e684ed4 100644 --- a/arch/mips/lantiq/falcon/devices.c +++ b/arch/mips/lantiq/falcon/devices.c -@@ -126,3 +126,24 @@ falcon_register_gpio_extra(void) - ltq_sysctl_activate(SYSCTL_SYS1, - ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4); +@@ -134,3 +134,19 @@ falcon_register_spi_flash(struct spi_board_info *data) + spi_register_board_info(data, 1); + platform_device_register(<q_spi); } + +/* i2c */ +static struct resource falcon_i2c_resources[] = { -+ MEM_RES("i2c", GPON_I2C_BASE,GPON_I2C_END), -+ IRQ_RES("i2c_lb", FALCON_IRQ_I2C_LBREQ), -+ IRQ_RES("i2c_b", FALCON_IRQ_I2C_BREQ), -+ IRQ_RES("i2c_err", FALCON_IRQ_I2C_I2C_ERR), -+ IRQ_RES("i2c_p", FALCON_IRQ_I2C_I2C_P), ++ MEM_RES("i2c", GPON_I2C_BASE, GPON_I2C_SIZE), ++ IRQ_RES(i2c_lb, FALCON_IRQ_I2C_LBREQ), ++ IRQ_RES(i2c_b, FALCON_IRQ_I2C_BREQ), ++ IRQ_RES(i2c_err, FALCON_IRQ_I2C_I2C_ERR), ++ IRQ_RES(i2c_p, FALCON_IRQ_I2C_I2C_P), +}; + -+void __init falcon_register_i2c(void) ++void __init ++falcon_register_i2c(void) +{ + platform_device_register_simple("i2c-falcon", 0, -+ falcon_i2c_resources, ARRAY_SIZE(falcon_i2c_resources)); -+ sys1_hw_activate(ACTS_I2C_ACT); -+} -+ -+void __init falcon_register_crypto(void) -+{ -+ platform_device_register_simple("ltq_falcon_deu", 0, NULL, 0); ++ falcon_i2c_resources, ARRAY_SIZE(falcon_i2c_resources)); +} +diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h +index 5e6f720..d81edbe 100644 --- a/arch/mips/lantiq/falcon/devices.h +++ b/arch/mips/lantiq/falcon/devices.h -@@ -16,5 +16,6 @@ - extern void falcon_register_nand(void); +@@ -20,5 +20,6 @@ extern void falcon_register_nand(void); extern void falcon_register_gpio(void); extern void falcon_register_gpio_extra(void); + extern void falcon_register_spi_flash(struct spi_board_info *data); +extern void falcon_register_i2c(void); #endif +diff --git a/arch/mips/lantiq/falcon/mach-easy98000.c b/arch/mips/lantiq/falcon/mach-easy98000.c +index 1a7caad..fc5720d 100644 +--- a/arch/mips/lantiq/falcon/mach-easy98000.c ++++ b/arch/mips/lantiq/falcon/mach-easy98000.c +@@ -98,6 +98,7 @@ easy98000_init_common(void) + { + spi_register_board_info(&easy98000_spi_gpio_devices, 1); + platform_device_register(&easy98000_spi_gpio_device); ++ falcon_register_i2c(); + } + + static void __init +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index a3afac4..41be6cc 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig -@@ -284,6 +284,10 @@ config I2C_POWERMAC - - comment "I2C system bus drivers (mostly embedded / system-on-chip)" +@@ -369,6 +369,16 @@ config I2C_DESIGNWARE_PCI + This driver can also be built as a module. If so, the module + will be called i2c-designware-pci. +config I2C_FALCON + tristate "Falcon I2C interface" -+# depends on SOC_FALCON -+ - config I2C_AT91 - tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on ARCH_AT91 && EXPERIMENTAL && BROKEN ++ depends on SOC_FALCON ++ help ++ If you say yes to this option, support will be included for the ++ Lantiq FALC-ON I2C core. ++ ++ This driver can also be built as a module. If so, the module ++ will be called i2c-falcon. ++ + config I2C_GPIO + tristate "GPIO-based bitbanging I2C" + depends on GENERIC_GPIO +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index fba6da6..36239c8 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile -@@ -82,5 +82,6 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o - obj-$(CONFIG_I2C_STUB) += i2c-stub.o - obj-$(CONFIG_SCx200_ACB) += scx200_acb.o - obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o +@@ -37,6 +37,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o + i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o + obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o + i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o +obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o - - ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG + obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o + obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o + obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o +diff --git a/drivers/i2c/busses/i2c-falcon.c b/drivers/i2c/busses/i2c-falcon.c +new file mode 100644 +index 0000000..fc4f0eb --- /dev/null +++ b/drivers/i2c/busses/i2c-falcon.c -@@ -0,0 +1,815 @@ +@@ -0,0 +1,1040 @@ +/* + * Lantiq FALC(tm) ON - I2C bus adapter + * @@ -91,14 +198,21 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> + */ + -+/* #define DEBUG */ ++/* ++ * CURRENT ISSUES: ++ * - no high speed support ++ * - supports only master mode ++ * - ten bit mode is not tested (no slave devices) ++ */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> -+#include <linux/slab.h> /* for kzalloc, kfree */ ++#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/clk.h> +#include <linux/errno.h> @@ -107,25 +221,242 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> ++#include <linux/err.h> +#include <linux/gpio.h> + -+#include <falcon/lantiq_soc.h> -+ -+/* CURRENT ISSUES: -+ * - no high speed support -+ * - supports only master mode -+ * - ten bit mode is not tested (no slave devices) ++#include <lantiq_soc.h> ++ ++/* I2C Identification Register */ ++/* Module ID */ ++#define I2C_ID_ID_MASK 0x0000FF00 ++/* field offset */ ++#define I2C_ID_ID_OFFSET 8 ++/* Revision */ ++#define I2C_ID_REV_MASK 0x000000FF ++/* field offset */ ++#define I2C_ID_REV_OFFSET 0 ++ ++/* I2C Error Interrupt Request Source Status Register */ ++/* TXF_OFL */ ++#define I2C_ERR_IRQSS_TXF_OFL 0x00000008 ++/* TXF_UFL */ ++#define I2C_ERR_IRQSS_TXF_UFL 0x00000004 ++/* RXF_OFL */ ++#define I2C_ERR_IRQSS_RXF_OFL 0x00000002 ++/* RXF_UFL */ ++#define I2C_ERR_IRQSS_RXF_UFL 0x00000001 ++ ++/* I2C Bus Status Register */ ++/* Bus Status */ ++#define I2C_BUS_STAT_BS_MASK 0x00000003 ++/* I2C Bus is free. */ ++#define I2C_BUS_STAT_BS_FREE 0x00000000 ++/* ++ * The device is working as master and has claimed the control ++ * on the I2C-bus (busy master). ++ */ ++#define I2C_BUS_STAT_BS_BM 0x00000002 ++ ++/* I2C Interrupt Clear Register */ ++/* Clear */ ++#define I2C_ICR_BREQ_INT_CLR 0x00000008 ++/* Clear */ ++#define I2C_ICR_LBREQ_INT_CLR 0x00000004 ++ ++/* I2C RUN Control Register */ ++/* Enable */ ++#define I2C_RUN_CTRL_RUN_EN 0x00000001 ++ ++/* I2C Kernel Clock Control Register */ ++/* field offset */ ++#define I2C_CLC_RMC_OFFSET 8 ++/* Enable */ ++#define I2C_IMSC_I2C_P_INT_EN 0x00000020 ++/* Enable */ ++#define I2C_IMSC_I2C_ERR_INT_EN 0x00000010 ++/* Enable */ ++#define I2C_IMSC_BREQ_INT_EN 0x00000008 ++/* Enable */ ++#define I2C_IMSC_LBREQ_INT_EN 0x00000004 ++ ++/* I2C Fractional Divider Configuration Register */ ++/* field offset */ ++#define I2C_FDIV_CFG_INC_OFFSET 16 ++/* field offset */ ++#define I2C_FDIV_CFG_DEC_OFFSET 0 ++ ++/* I2C Fractional Divider (highspeed mode) Configuration Register */ ++/* field offset */ ++#define I2C_FDIV_HIGH_CFG_INC_OFFSET 16 ++/* field offset */ ++#define I2C_FDIV_HIGH_CFG_DEC_OFFSET 0 ++ ++/* I2C Address Register */ ++/* Enable */ ++#define I2C_ADDR_CFG_SOPE_EN 0x00200000 ++/* Enable */ ++#define I2C_ADDR_CFG_SONA_EN 0x00100000 ++/* Enable */ ++#define I2C_ADDR_CFG_MnS_EN 0x00080000 ++ ++/* I2C Protocol Interrupt Request Source Status Register */ ++/* RX */ ++#define I2C_P_IRQSS_RX 0x00000040 ++/* TX_END */ ++#define I2C_P_IRQSS_TX_END 0x00000020 ++/* NACK */ ++#define I2C_P_IRQSS_NACK 0x00000010 ++/* AL */ ++#define I2C_P_IRQSS_AL 0x00000008 ++ ++/* I2C Raw Interrupt Status Register */ ++/* Read: Interrupt occurred. */ ++#define I2C_RIS_I2C_P_INT_INTOCC 0x00000020 ++/* Read: Interrupt occurred. */ ++#define I2C_RIS_I2C_ERR_INT_INTOCC 0x00000010 ++ ++/* I2C End Data Control Register */ ++/* ++ * Set End of Transmission - Note: Do not write '1' to this bit when bus is ++ * free. This will cause an abort after the first byte when a new transfer ++ * is started. + */ ++#define I2C_ENDD_CTRL_SETEND 0x00000002 ++/* TX FIFO Flow Control */ ++#define I2C_FIFO_CFG_TXFC 0x00020000 ++/* RX FIFO Flow Control */ ++#define I2C_FIFO_CFG_RXFC 0x00010000 ++/* Word aligned (character alignment of four characters) */ ++#define I2C_FIFO_CFG_TXFA_TXFA2 0x00002000 ++/* Word aligned (character alignment of four characters) */ ++#define I2C_FIFO_CFG_RXFA_RXFA2 0x00000200 ++/* 1 word */ ++#define I2C_FIFO_CFG_TXBS_TXBS0 0x00000000 ++/* 1 word */ ++#define I2C_FIFO_CFG_RXBS_RXBS0 0x00000000 ++ ++ ++/* I2C register structure */ ++struct gpon_reg_i2c { ++ /* I2C Kernel Clock Control Register */ ++ unsigned int clc; /* 0x00000000 */ ++ /* Reserved */ ++ unsigned int res_0; /* 0x00000004 */ ++ /* I2C Identification Register */ ++ unsigned int id; /* 0x00000008 */ ++ /* Reserved */ ++ unsigned int res_1; /* 0x0000000C */ ++ /* ++ * I2C RUN Control Register - This register enables and disables the I2C ++ * peripheral. Before enabling, the I2C has to be configured properly. ++ * After enabling no configuration is possible ++ */ ++ unsigned int run_ctrl; /* 0x00000010 */ ++ /* ++ * I2C End Data Control Register - This register is used to either turn ++ * around the data transmission direction or to address another slave ++ * without sending a stop condition. Also the software can stop the ++ * slave-transmitter by sending a not-accolade when working as ++ * master-receiver or even stop data transmission immediately when ++ * operating as master-transmitter. The writing to the bits of this ++ * control register is only effective when in MASTER RECEIVES BYTES, ++ * MASTER TRANSMITS BYTES, MASTER RESTART or SLAVE RECEIVE BYTES state ++ */ ++ unsigned int endd_ctrl; /* 0x00000014 */ ++ /* ++ * I2C Fractional Divider Configuration Register - These register is ++ * used to program the fractional divider of the I2C bus. Before the ++ * peripheral is switched on by setting the RUN-bit the two (fixed) ++ * values for the two operating frequencies are programmed into these ++ * (configuration) registers. The Register FDIV_HIGH_CFG has the same ++ * layout as I2C_FDIV_CFG. ++ */ ++ unsigned int fdiv_cfg; /* 0x00000018 */ ++ /* ++ * I2C Fractional Divider (highspeed mode) Configuration Register ++ * These register is used to program the fractional divider of the I2C ++ * bus. Before the peripheral is switched on by setting the RUN-bit the ++ * two (fixed) values for the two operating frequencies are programmed ++ * into these (configuration) registers. The Register FDIV_CFG has the ++ * same layout as I2C_FDIV_CFG. ++ */ ++ unsigned int fdiv_high_cfg; /* 0x0000001C */ ++ /* I2C Address Configuration Register */ ++ unsigned int addr_cfg; /* 0x00000020 */ ++ /* ++ * I2C Bus Status Register - This register gives a status information ++ * of the I2C. This additional information can be used by the software ++ * to start proper actions. ++ */ ++ unsigned int bus_stat; /* 0x00000024 */ ++ /* I2C FIFO Configuration Register */ ++ unsigned int fifo_cfg; /* 0x00000028 */ ++ /* I2C Maximum Received Packet Size Register */ ++ unsigned int mrps_ctrl; /* 0x0000002C */ ++ /* I2C Received Packet Size Status Register */ ++ unsigned int rps_stat; /* 0x00000030 */ ++ /* I2C Transmit Packet Size Register */ ++ unsigned int tps_ctrl; /* 0x00000034 */ ++ /* I2C Filled FIFO Stages Status Register */ ++ unsigned int ffs_stat; /* 0x00000038 */ ++ /* Reserved */ ++ unsigned int res_2; /* 0x0000003C */ ++ /* I2C Timing Configuration Register */ ++ unsigned int tim_cfg; /* 0x00000040 */ ++ /* Reserved */ ++ unsigned int res_3[7]; /* 0x00000044 */ ++ /* I2C Error Interrupt Request Source Mask Register */ ++ unsigned int err_irqsm; /* 0x00000060 */ ++ /* I2C Error Interrupt Request Source Status Register */ ++ unsigned int err_irqss; /* 0x00000064 */ ++ /* I2C Error Interrupt Request Source Clear Register */ ++ unsigned int err_irqsc; /* 0x00000068 */ ++ /* Reserved */ ++ unsigned int res_4; /* 0x0000006C */ ++ /* I2C Protocol Interrupt Request Source Mask Register */ ++ unsigned int p_irqsm; /* 0x00000070 */ ++ /* I2C Protocol Interrupt Request Source Status Register */ ++ unsigned int p_irqss; /* 0x00000074 */ ++ /* I2C Protocol Interrupt Request Source Clear Register */ ++ unsigned int p_irqsc; /* 0x00000078 */ ++ /* Reserved */ ++ unsigned int res_5; /* 0x0000007C */ ++ /* I2C Raw Interrupt Status Register */ ++ unsigned int ris; /* 0x00000080 */ ++ /* I2C Interrupt Mask Control Register */ ++ unsigned int imsc; /* 0x00000084 */ ++ /* I2C Masked Interrupt Status Register */ ++ unsigned int mis; /* 0x00000088 */ ++ /* I2C Interrupt Clear Register */ ++ unsigned int icr; /* 0x0000008C */ ++ /* I2C Interrupt Set Register */ ++ unsigned int isr; /* 0x00000090 */ ++ /* I2C DMA Enable Register */ ++ unsigned int dmae; /* 0x00000094 */ ++ /* Reserved */ ++ unsigned int res_6[8154]; /* 0x00000098 */ ++ /* I2C Transmit Data Register */ ++ unsigned int txd; /* 0x00008000 */ ++ /* Reserved */ ++ unsigned int res_7[4095]; /* 0x00008004 */ ++ /* I2C Receive Data Register */ ++ unsigned int rxd; /* 0x0000C000 */ ++ /* Reserved */ ++ unsigned int res_8[4095]; /* 0x0000C004 */ ++}; + +/* mapping for access macros */ ++#define i2c ((struct gpon_reg_i2c *)priv->membase) +#define reg_r32(reg) __raw_readl(reg) +#define reg_w32(val, reg) __raw_writel(val, reg) +#define reg_w32_mask(clear, set, reg) \ + reg_w32((reg_r32(reg) & ~(clear)) | (set), reg) +#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx]) +#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx]) -+#define i2c (priv->membase) -+#include <falcon/i2c_reg.h> ++ ++#define i2c_r32(reg) reg_r32(&i2c->reg) ++#define i2c_w32(val, reg) reg_w32(val, &i2c->reg) ++#define i2c_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &i2c->reg) + +#define DRV_NAME "i2c-falcon" +#define DRV_VERSION "1.01" @@ -133,12 +464,12 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C +#define FALCON_I2C_BUSY_TIMEOUT 20 /* ms */ + +#ifdef DEBUG -+#define FALCON_I2C_XFER_TIMEOUT 25*HZ ++#define FALCON_I2C_XFER_TIMEOUT (25 * HZ) +#else +#define FALCON_I2C_XFER_TIMEOUT HZ +#endif +#if defined(DEBUG) && 0 -+#define PRINTK(arg...) printk(arg) ++#define PRINTK(arg...) pr_info(arg) +#else +#define PRINTK(arg...) do {} while (0) +#endif @@ -209,7 +540,7 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C +static void prepare_msg_send_addr(struct falcon_i2c *priv) +{ + struct i2c_msg *msg = priv->current_msg; -+ int rd = !!(msg->flags & I2C_M_RD); /* extends to 0 or 1 */ ++ int rd = !!(msg->flags & I2C_M_RD); + u16 addr = msg->addr; + + /* new i2c_msg */ @@ -233,7 +564,7 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + struct i2c_msg *msg = priv->current_msg; + int len = (msg->flags & I2C_M_TEN) ? 2 : 1; + -+ PRINTK("set_tx_len %cX\n", (msg->flags & I2C_M_RD)?'R':'T'); ++ PRINTK("set_tx_len %cX\n", (msg->flags & I2C_M_RD) ? ('R') : ('T')); + + priv->status = STATUS_ADDR; + @@ -297,8 +628,8 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + fifo_cfg); + + /* configure address */ -+ i2c_w32(I2C_ADDR_CFG_SOPE_EN | /* generate stop when no more data in the -+ fifo */ ++ i2c_w32(I2C_ADDR_CFG_SOPE_EN | /* generate stop when no more data ++ in the fifo */ + I2C_ADDR_CFG_SONA_EN | /* generate stop when NA received */ + I2C_ADDR_CFG_MnS_EN | /* we are master device */ + 0, /* our slave address (not used!) */ @@ -339,14 +670,13 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + } else + last = 1; + -+ if (last) { ++ if (last) + disable_burst_irq(priv); -+ } +} + +static void falcon_i2c_rx(struct falcon_i2c *priv, int last) +{ -+ u32 fifo_stat,timeout; ++ u32 fifo_stat, timeout; + if (priv->msg_buf_len && priv->msg_buf) { + timeout = 5000000; + do { @@ -406,10 +736,10 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C +{ +#if defined(DEBUG) + int i, j; -+ printk("Messages %d %s\n", num, rx ? "out" : "in"); ++ pr_info("Messages %d %s\n", num, rx ? "out" : "in"); + for (i = 0; i < num; i++) { -+ printk("%2d %cX Msg(%d) addr=0x%X: ", i, -+ (msgs[i].flags & I2C_M_RD)?'R':'T', ++ pr_info("%2d %cX Msg(%d) addr=0x%X: ", i, ++ (msgs[i].flags & I2C_M_RD) ? ('R') : ('T'), + msgs[i].len, msgs[i].addr); + if (!(msgs[i].flags & I2C_M_RD) || rx) { + for (j = 0; j < msgs[i].len; j++) @@ -470,9 +800,8 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + ret = -EREMOTEIO; + goto done; + } -+ if (--priv->msgs_num) { ++ if (--priv->msgs_num) + priv->current_msg++; -+ } + } + /* no error? */ + ret = num; @@ -482,7 +811,7 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + + mutex_unlock(&priv->mutex); + -+ if (ret>=0) ++ if (ret >= 0) + dump_msgs(msgs, num, 1); + + PRINTK("XFER ret %d\n", ret); @@ -514,7 +843,7 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + break; + default: + disable_burst_irq(priv); -+ printk("Status R %d\n", priv->status); ++ PRINTK("Status R %d\n", priv->status); + break; + } + } else { @@ -529,7 +858,7 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + break; + default: + disable_burst_irq(priv); -+ printk("Status W %d\n", priv->status); ++ PRINTK("Status W %d\n", priv->status); + break; + } + } @@ -585,7 +914,7 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + +static irqreturn_t falcon_i2c_isr(int irq, void *dev_id) +{ -+ u32 i_raw, i_err=0; ++ u32 i_raw, i_err = 0; + struct falcon_i2c *priv = dev_id; + + i_raw = i2c_r32(mis); @@ -662,7 +991,7 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + return -ENODEV; + } + -+ clk = clk_get(&pdev->dev, "fpi"); ++ clk = clk_get_fpi(); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "failed to get fpi clk\n"); + return -ENOENT; @@ -672,6 +1001,11 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + dev_err(&pdev->dev, "input clock is not 100MHz\n"); + return -ENOENT; + } ++ clk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "failed to get i2c clk\n"); ++ return -ENOENT; ++ } + + /* allocate private data */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -694,16 +1028,10 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + init_completion(&priv->cmd_complete); + mutex_init(&priv->mutex); + -+ ret = ltq_gpio_request(107, 0, 0, 0, DRV_NAME":sda"); -+ if (ret) { -+ dev_err(&pdev->dev, "I2C gpio 107 (sda) not available\n"); -+ ret = -ENXIO; -+ goto err_free_priv; -+ } -+ ret = ltq_gpio_request(108, 0, 0, 0, DRV_NAME":scl"); -+ if (ret) { -+ gpio_free(107); -+ dev_err(&pdev->dev, "I2C gpio 108 (scl) not available\n"); ++ if (ltq_gpio_request(&pdev->dev, 107, 0, 0, DRV_NAME":sda") || ++ ltq_gpio_request(&pdev->dev, 108, 0, 0, DRV_NAME":scl")) ++ { ++ dev_err(&pdev->dev, "I2C gpios not available\n"); + ret = -ENXIO; + goto err_free_priv; + } @@ -729,7 +1057,8 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + ret = request_irq(priv->irq_lb, falcon_i2c_isr_burst, IRQF_DISABLED, + irqres_lb->name, priv); + if (ret) { -+ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", irqres_lb->start); ++ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", ++ irqres_lb->start); + ret = -ENODEV; + goto err_unmap_mem; + } @@ -738,7 +1067,8 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + ret = request_irq(priv->irq_b, falcon_i2c_isr_burst, IRQF_DISABLED, + irqres_b->name, priv); + if (ret) { -+ dev_err(&pdev->dev, "can't get burst IRQ %d\n", irqres_b->start); ++ dev_err(&pdev->dev, "can't get burst IRQ %d\n", ++ irqres_b->start); + ret = -ENODEV; + goto err_free_lb_irq; + } @@ -747,7 +1077,8 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + ret = request_irq(priv->irq_err, falcon_i2c_isr, IRQF_DISABLED, + irqres_err->name, priv); + if (ret) { -+ dev_err(&pdev->dev, "can't get error IRQ %d\n", irqres_err->start); ++ dev_err(&pdev->dev, "can't get error IRQ %d\n", ++ irqres_err->start); + ret = -ENODEV; + goto err_free_b_irq; + } @@ -756,7 +1087,8 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C + ret = request_irq(priv->irq_p, falcon_i2c_isr, IRQF_DISABLED, + irqres_p->name, priv); + if (ret) { -+ dev_err(&pdev->dev, "can't get protocol IRQ %d\n", irqres_p->start); ++ dev_err(&pdev->dev, "can't get protocol IRQ %d\n", ++ irqres_p->start); + ret = -ENODEV; + goto err_free_err_irq; + } @@ -888,3 +1220,6 @@ Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0041-MIPS-lantiq-add-xway-nand-driver.patch b/target/linux/lantiq/patches-3.2/0041-MIPS-lantiq-add-xway-nand-driver.patch new file mode 100644 index 0000000000..c2e2e1bff4 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0041-MIPS-lantiq-add-xway-nand-driver.patch @@ -0,0 +1,310 @@ +From 9c7a6f8804aef7559ee8edcb7466676ee7d00c09 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sat, 27 Aug 2011 20:08:14 +0200 +Subject: [PATCH 41/70] MIPS: lantiq: add xway nand driver + +This patch adds a nand driver for XWAY SoCs. The patch makes use of the +plat_nand driver. As with the EBU NOR driver merged in 3.0, we have the +endianess swap problem on read. To workaround this problem we make the +read_byte() callback available via the plat_nand driver causing the nand +layer to do byte reads. + +Signed-off-by: John Crispin <blogic@openwrt.org> + +TODO : memory ranges + cs lines + plat dev + ebu2 and not ebu1 ? +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/devices.h | 1 + + arch/mips/lantiq/xway/nand.c | 216 ++++++++++++++++++++ + drivers/mtd/nand/plat_nand.c | 1 + + include/linux/mtd/nand.h | 1 + + 6 files changed, 222 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/lantiq/xway/nand.c + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index 3f22acb..ab2d236 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -145,6 +145,8 @@ + /* register access macros for EBU and CGU */ + #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) + #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) ++#define ltq_ebu_w32_mask(x, y, z) \ ++ ltq_w32_mask(x, y, ltq_ebu_membase + (z)) + #define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) + #define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) + +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 9d1a0a2..277aa34 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h +index e904934..d825cbd 100644 +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -16,5 +16,6 @@ extern void ltq_register_gpio(void); + extern void ltq_register_gpio_stp(void); + extern void ltq_register_ase_asc(void); + extern void ltq_register_etop(struct ltq_eth_data *eth); ++extern void xway_register_nand(struct mtd_partition *parts, int count); + + #endif +diff --git a/arch/mips/lantiq/xway/nand.c b/arch/mips/lantiq/xway/nand.c +new file mode 100644 +index 0000000..9ab91d8 +--- /dev/null ++++ b/arch/mips/lantiq/xway/nand.c +@@ -0,0 +1,216 @@ ++/* ++ * 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 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/mtd/physmap.h> ++#include <linux/mtd/nand.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_platform.h> ++ ++#include "devices.h" ++ ++/* nand registers */ ++#define LTQ_EBU_NAND_WAIT 0xB4 ++#define LTQ_EBU_NAND_ECC0 0xB8 ++#define LTQ_EBU_NAND_ECC_AC 0xBC ++#define LTQ_EBU_NAND_CON 0xB0 ++#define LTQ_EBU_ADDSEL1 0x24 ++ ++/* gpio definitions */ ++#define PIN_ALE 13 ++#define PIN_CLE 24 ++#define PIN_CS1 23 ++#define PIN_RDY 48 /* NFLASH_READY */ ++#define PIN_RD 49 /* NFLASH_READ_N */ ++ ++#define NAND_CMD_ALE (1 << 2) ++#define NAND_CMD_CLE (1 << 3) ++#define NAND_CMD_CS (1 << 4) ++#define NAND_WRITE_CMD_RESET 0xff ++#define NAND_WRITE_CMD (NAND_CMD_CS | NAND_CMD_CLE) ++#define NAND_WRITE_ADDR (NAND_CMD_CS | NAND_CMD_ALE) ++#define NAND_WRITE_DATA (NAND_CMD_CS) ++#define NAND_READ_DATA (NAND_CMD_CS) ++#define NAND_WAIT_WR_C (1 << 3) ++#define NAND_WAIT_RD (0x1) ++ ++#define ADDSEL1_MASK(x) (x << 4) ++#define ADDSEL1_REGEN 1 ++#define BUSCON1_SETUP (1 << 22) ++#define BUSCON1_BCGEN_RES (0x3 << 12) ++#define BUSCON1_WAITWRC2 (2 << 8) ++#define BUSCON1_WAITRDC2 (2 << 6) ++#define BUSCON1_HOLDC1 (1 << 4) ++#define BUSCON1_RECOVC1 (1 << 2) ++#define BUSCON1_CMULT4 1 ++#define NAND_CON_NANDM 1 ++#define NAND_CON_CSMUX (1 << 1) ++#define NAND_CON_CS_P (1 << 4) ++#define NAND_CON_SE_P (1 << 5) ++#define NAND_CON_WP_P (1 << 6) ++#define NAND_CON_PRE_P (1 << 7) ++#define NAND_CON_IN_CS0 0 ++#define NAND_CON_OUT_CS0 0 ++#define NAND_CON_IN_CS1 (1 << 8) ++#define NAND_CON_OUT_CS1 (1 << 10) ++#define NAND_CON_CE (1 << 20) ++ ++#define NAND_BASE_ADDRESS (KSEG1 | 0x14000000) ++ ++static const char *part_probes[] = { "cmdlinepart", NULL }; ++ ++static void xway_select_chip(struct mtd_info *mtd, int chip) ++{ ++ switch (chip) { ++ case -1: ++ ltq_ebu_w32_mask(NAND_CON_CE, 0, LTQ_EBU_NAND_CON); ++ ltq_ebu_w32_mask(NAND_CON_NANDM, 0, LTQ_EBU_NAND_CON); ++ break; ++ case 0: ++ ltq_ebu_w32_mask(0, NAND_CON_NANDM, LTQ_EBU_NAND_CON); ++ ltq_ebu_w32_mask(0, NAND_CON_CE, LTQ_EBU_NAND_CON); ++ /* reset the nand chip */ ++ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ++ ; ++ ltq_w32(NAND_WRITE_CMD_RESET, ++ ((u32 *) (NAND_BASE_ADDRESS | NAND_WRITE_CMD))); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void xway_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) ++{ ++ struct nand_chip *this = mtd->priv; ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if (ctrl & NAND_CLE) ++ this->IO_ADDR_W = (void __iomem *) ++ (NAND_BASE_ADDRESS | NAND_WRITE_CMD); ++ else if (ctrl & NAND_ALE) ++ this->IO_ADDR_W = (void __iomem *) ++ (NAND_BASE_ADDRESS | NAND_WRITE_ADDR); ++ } ++ ++ if (data != NAND_CMD_NONE) { ++ *(volatile u8*) ((u32) this->IO_ADDR_W) = data; ++ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ++ ; ++ } ++} ++ ++static int xway_dev_ready(struct mtd_info *mtd) ++{ ++ return ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_RD; ++} ++ ++void nand_write(unsigned int addr, unsigned int val) ++{ ++ ltq_w32(val, ((u32 *) (NAND_BASE_ADDRESS | addr))); ++ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ++ ; ++} ++ ++unsigned char xway_read_byte(struct mtd_info *mtd) ++{ ++ return ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA))); ++} ++ ++static void xway_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) ++ { ++ unsigned char res8 = ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA))); ++ buf[i] = res8; ++ } ++} ++ ++static void xway_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) ++ { ++ ltq_w8(buf[i], ((u32*)(NAND_BASE_ADDRESS | (NAND_WRITE_DATA)))); ++ while((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0); ++ } ++} ++ ++int xway_probe(struct platform_device *pdev) ++{ ++ /* might need this later ? ++ ltq_gpio_request(PIN_CS1, 2, 1, "NAND_CS1"); ++ */ ++ ltq_gpio_request(&pdev->dev, PIN_CLE, 2, 1, "NAND_CLE"); ++ ltq_gpio_request(&pdev->dev, PIN_ALE, 2, 1, "NAND_ALE"); ++ if (ltq_is_ar9() || ltq_is_vr9()) { ++ ltq_gpio_request(&pdev->dev, PIN_RDY, 2, 0, "NAND_BSY"); ++ ltq_gpio_request(&pdev->dev, PIN_RD, 2, 1, "NAND_RD"); ++ } ++ ++ ltq_ebu_w32((NAND_BASE_ADDRESS & 0x1fffff00) ++ | ADDSEL1_MASK(3) | ADDSEL1_REGEN, LTQ_EBU_ADDSEL1); ++ ++ ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2 ++ | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1 ++ | BUSCON1_CMULT4, LTQ_EBU_BUSCON1); ++ ++ ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P ++ | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P ++ | NAND_CON_IN_CS0 | NAND_CON_OUT_CS0, LTQ_EBU_NAND_CON); ++ ++ ltq_w32(NAND_WRITE_CMD_RESET, ++ ((u32 *) (NAND_BASE_ADDRESS | NAND_WRITE_CMD))); ++ while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ++ ; ++ ++ return 0; ++} ++ ++static struct platform_nand_data falcon_flash_nand_data = { ++ .chip = { ++ .nr_chips = 1, ++ .chip_delay = 30, ++ .part_probe_types = part_probes, ++ }, ++ .ctrl = { ++ .probe = xway_probe, ++ .cmd_ctrl = xway_cmd_ctrl, ++ .dev_ready = xway_dev_ready, ++ .select_chip = xway_select_chip, ++ .read_byte = xway_read_byte, ++ .read_buf = xway_read_buf, ++ .write_buf = xway_write_buf, ++ } ++}; ++ ++static struct resource ltq_nand_res = ++ MEM_RES("nand", 0x14000000, 0x7ffffff); ++ ++static struct platform_device ltq_flash_nand = { ++ .name = "gen_nand", ++ .id = -1, ++ .num_resources = 1, ++ .resource = <q_nand_res, ++ .dev = { ++ .platform_data = &falcon_flash_nand_data, ++ }, ++}; ++ ++void __init xway_register_nand(struct mtd_partition *parts, int count) ++{ ++ falcon_flash_nand_data.chip.partitions = parts; ++ falcon_flash_nand_data.chip.nr_partitions = count; ++ platform_device_register(<q_flash_nand); ++} +diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c +index ea8e123..9040ba1 100644 +--- a/drivers/mtd/nand/plat_nand.c ++++ b/drivers/mtd/nand/plat_nand.c +@@ -75,6 +75,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) + data->chip.select_chip = pdata->ctrl.select_chip; + data->chip.write_buf = pdata->ctrl.write_buf; + data->chip.read_buf = pdata->ctrl.read_buf; ++ data->chip.read_byte = pdata->ctrl.read_byte; + data->chip.chip_delay = pdata->chip.chip_delay; + data->chip.options |= pdata->chip.options; + data->chip.bbt_options |= pdata->chip.bbt_options; +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index 904131b..80e11b9 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -650,6 +650,7 @@ struct platform_nand_ctrl { + void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); + void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); + void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); ++ unsigned char (*read_byte)(struct mtd_info *mtd); + void *priv; + }; + +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0014-MIPS-lantiq-adds-xway-spi.patch b/target/linux/lantiq/patches-3.2/0042-SPI-MIPS-lantiq-adds-spi-xway.patch index 76ab292011..ca6e8921ab 100644 --- a/target/linux/lantiq/patches/0014-MIPS-lantiq-adds-xway-spi.patch +++ b/target/linux/lantiq/patches-3.2/0042-SPI-MIPS-lantiq-adds-spi-xway.patch @@ -1,18 +1,19 @@ -From e29263339db41d49d79482c93463c4c0cbe764d7 Mon Sep 17 00:00:00 2001 +From b257baf20b44e97770a2654a07f196fcbcd46e92 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> -Date: Fri, 30 Sep 2011 14:23:42 +0200 -Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi +Date: Mon, 10 Oct 2011 22:29:13 +0200 +Subject: [PATCH 42/70] SPI: MIPS: lantiq: adds spi xway --- .../mips/include/asm/mach-lantiq/lantiq_platform.h | 9 + .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 2 + - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 1 + drivers/spi/Kconfig | 8 + - drivers/spi/Makefile | 2 +- - drivers/spi/spi-xway.c | 1062 ++++++++++++++++++++ - 6 files changed, 1083 insertions(+), 1 deletions(-) + drivers/spi/Makefile | 1 + + drivers/spi/spi-xway.c | 1068 ++++++++++++++++++++ + 5 files changed, 1088 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/spi-xway.c +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +index a305f1d..38ed938 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h @@ -50,4 +50,13 @@ struct ltq_eth_data { @@ -29,6 +30,8 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi +}; + #endif +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +index 2a8d5ad..b7f10e6 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h @@ -27,6 +27,8 @@ @@ -40,19 +43,11 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi #define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) #define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -81,6 +81,7 @@ - - #define PMU_DMA 0x0020 - #define PMU_USB 0x8041 -+#define PMU_SPI 0x0100 - #define PMU_LED 0x0800 - #define PMU_GPT 0x1000 - #define PMU_PPE 0x2000 +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index b8424ba..ca4189c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -393,6 +393,14 @@ config SPI_NUC900 +@@ -384,6 +384,14 @@ config SPI_NUC900 help SPI driver for Nuvoton NUC900 series ARM SoCs @@ -67,17 +62,22 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi # # Add new SPI master controllers in alphabetical order above this line # +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 570894c..a465d9a 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -60,4 +60,5 @@ obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x +@@ -59,4 +59,5 @@ obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o obj-$(CONFIG_SPI_TXX9) += spi-txx9.o obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o +obj-$(CONFIG_SPI_XWAY) += spi-xway.o +diff --git a/drivers/spi/spi-xway.c b/drivers/spi/spi-xway.c +new file mode 100644 +index 0000000..016a6d0 --- /dev/null +++ b/drivers/spi/spi-xway.c -@@ -0,0 +1,1062 @@ +@@ -0,0 +1,1068 @@ +/* + * Lantiq SoC SPI controller + * @@ -234,7 +234,8 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + + struct device *dev; + void __iomem *base; -+ struct clk *clk; ++ struct clk *fpiclk; ++ struct clk *spiclk; + + int status; + int irq[3]; @@ -267,8 +268,7 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + +struct ltq_spi_cs_gpio_map { + unsigned gpio; -+ unsigned altsel0; -+ unsigned altsel1; ++ unsigned mux; +}; + +static inline struct ltq_spi *ltq_spi_to_hw(struct spi_device *spi) @@ -309,7 +309,7 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + u32 clc; + + /* Power-up mdule */ -+ ltq_pmu_enable(PMU_SPI); ++ clk_enable(hw->spiclk); + + /* + * Set clock divider for run mode to 1 to @@ -325,7 +325,7 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + ltq_spi_reg_write(hw, LTQ_SPI_CLC_DISS, LTQ_SPI_CLC); + + /* Power-down mdule */ -+ ltq_pmu_disable(PMU_SPI); ++ clk_disable(hw->spiclk); +} + +static void ltq_spi_reset_fifos(struct ltq_spi *hw) @@ -475,7 +475,7 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + * SPI module clock is derived from FPI bus clock dependent on + * divider value in CLC.RMS which is always set to 1. + */ -+ spi_clk = clk_get_rate(hw->clk); ++ spi_clk = clk_get_rate(hw->fpiclk); + + /* + * Maximum SPI clock frequency in master mode is half of @@ -628,12 +628,12 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi +} + +static const struct ltq_spi_cs_gpio_map ltq_spi_cs[] = { -+ { 15, 1, 0 }, -+ { 22, 1, 0 }, -+ { 13, 0, 1 }, -+ { 10, 0, 1 }, -+ { 9, 0, 1 }, -+ { 11, 1, 1 }, ++ { 15, 2 }, ++ { 22, 2 }, ++ { 13, 1 }, ++ { 10, 1 }, ++ { 9, 1 }, ++ { 11, 3 }, +}; + +static int ltq_spi_setup(struct spi_device *spi) @@ -680,9 +680,8 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + cstate->cs_activate = ltq_spi_gpio_cs_activate; + cstate->cs_deactivate = ltq_spi_gpio_cs_deactivate; + } else { -+ ret = ltq_gpio_request(ltq_spi_cs[spi->chip_select].gpio, -+ ltq_spi_cs[spi->chip_select].altsel0, -+ ltq_spi_cs[spi->chip_select].altsel1, ++ ret = ltq_gpio_request(&spi->dev, ltq_spi_cs[spi->chip_select].gpio, ++ ltq_spi_cs[spi->chip_select].mux, + 1, "spi-cs"); + if (ret) + return -EBUSY; @@ -989,10 +988,17 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + goto err_master; + } + -+ hw->clk = clk_get(&pdev->dev, "fpi"); -+ if (IS_ERR(hw->clk)) { ++ hw->fpiclk = clk_get_fpi(); ++ if (IS_ERR(hw->fpiclk)) { ++ dev_err(&pdev->dev, "clk_get\n"); ++ ret = PTR_ERR(hw->fpiclk); ++ goto err_master; ++ } ++ ++ hw->spiclk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(hw->spiclk)) { + dev_err(&pdev->dev, "clk_get\n"); -+ ret = PTR_ERR(hw->clk); ++ ret = PTR_ERR(hw->spiclk); + goto err_master; + } + @@ -1028,9 +1034,9 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + spin_lock_init(&hw->lock); + + /* Set GPIO alternate functions to SPI */ -+ ltq_gpio_request(LTQ_SPI_GPIO_DI, 1, 0, 0, "spi-di"); -+ ltq_gpio_request(LTQ_SPI_GPIO_DO, 1, 0, 1, "spi-do"); -+ ltq_gpio_request(LTQ_SPI_GPIO_CLK, 1, 0, 1, "spi-clk"); ++ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_DI, 2, 0, "spi-di"); ++ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_DO, 2, 1, "spi-do"); ++ ltq_gpio_request(&pdev->dev, LTQ_SPI_GPIO_CLK, 2, 1, "spi-clk"); + + ltq_spi_hw_enable(hw); + @@ -1076,7 +1082,7 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + ltq_spi_hw_disable(hw); + +err_irq: -+ clk_put(hw->clk); ++ clk_put(hw->fpiclk); + + for (; i > 0; i--) + free_irq(hw->irq[i], hw); @@ -1110,7 +1116,7 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + gpio_free(LTQ_SPI_GPIO_DO); + gpio_free(LTQ_SPI_GPIO_CLK); + -+ clk_put(hw->clk); ++ clk_put(hw->fpiclk); + spi_master_put(hw->bitbang.master); + + return 0; @@ -1118,7 +1124,7 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi + +static struct platform_driver ltq_spi_driver = { + .driver = { -+ .name = "ltq-spi", ++ .name = "ltq_spi", + .owner = THIS_MODULE, + }, + .remove = __exit_p(ltq_spi_remove), @@ -1140,3 +1146,6 @@ Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi +MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ltq-spi"); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0043-NET-adds-driver-for-lantiq-vr9-ethernet.patch b/target/linux/lantiq/patches-3.2/0043-NET-adds-driver-for-lantiq-vr9-ethernet.patch new file mode 100644 index 0000000000..312ac5630d --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0043-NET-adds-driver-for-lantiq-vr9-ethernet.patch @@ -0,0 +1,1470 @@ +From 7591c5702cfe842f415e42f387532fe71ea3640f Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 9 Mar 2012 19:03:40 +0100 +Subject: [PATCH 43/70] NET: adds driver for lantiq vr9 ethernet + +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 +- + arch/mips/lantiq/xway/devices.c | 20 + + arch/mips/lantiq/xway/devices.h | 1 + + drivers/net/ethernet/Kconfig | 6 + + drivers/net/ethernet/Makefile | 1 + + drivers/net/ethernet/lantiq_vrx200.c | 1358 ++++++++++++++++++++ + 6 files changed, 1387 insertions(+), 1 deletions(-) + create mode 100644 drivers/net/ethernet/lantiq_vrx200.c + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index ab2d236..d1b8cc8 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -102,7 +102,7 @@ + + /* GBIT - gigabit switch */ + #define LTQ_GBIT_BASE_ADDR 0x1E108000 +-#define LTQ_GBIT_SIZE 0x200 ++#define LTQ_GBIT_SIZE 0x4000 + + /* DMA */ + #define LTQ_DMA_BASE_ADDR 0x1E104100 +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index eab4644d..5efa4f3 100644 +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -83,6 +83,7 @@ static struct platform_device ltq_etop = { + .name = "ltq_etop", + .resource = ltq_etop_resources, + .num_resources = 1, ++ .id = -1, + }; + + void __init +@@ -96,3 +97,22 @@ ltq_register_etop(struct ltq_eth_data *eth) + platform_device_register(<q_etop); + } + } ++ ++/* ethernet */ ++static struct resource ltq_vrx200_resources[] = { ++ MEM_RES("gbit", LTQ_GBIT_BASE_ADDR, LTQ_GBIT_SIZE), ++}; ++ ++static struct platform_device ltq_vrx200 = { ++ .name = "ltq_vrx200", ++ .resource = ltq_vrx200_resources, ++ .num_resources = 1, ++ .id = -1, ++}; ++ ++void __init ++ltq_register_vrx200(struct ltq_eth_data *eth) ++{ ++ ltq_vrx200.dev.platform_data = eth; ++ platform_device_register(<q_vrx200); ++} +diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h +index d825cbd..08befd9 100644 +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -17,5 +17,6 @@ extern void ltq_register_gpio_stp(void); + extern void ltq_register_ase_asc(void); + extern void ltq_register_etop(struct ltq_eth_data *eth); + extern void xway_register_nand(struct mtd_partition *parts, int count); ++extern void ltq_register_vrx200(struct ltq_eth_data *eth); + + #endif +diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +index 597f4d4..2035cab 100644 +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -84,6 +84,12 @@ config LANTIQ_ETOP + ---help--- + Support for the MII0 inside the Lantiq SoC + ++config LANTIQ_VRX200 ++ tristate "Lantiq SoC vrx200 driver" ++ depends on SOC_TYPE_XWAY ++ ---help--- ++ Support for the MII0 inside the Lantiq SoC ++ + source "drivers/net/ethernet/marvell/Kconfig" + source "drivers/net/ethernet/mellanox/Kconfig" + source "drivers/net/ethernet/micrel/Kconfig" +diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +index be5dde0..4fde2be 100644 +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -35,6 +35,7 @@ obj-$(CONFIG_IP1000) += icplus/ + obj-$(CONFIG_JME) += jme.o + obj-$(CONFIG_KORINA) += korina.o + obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o ++obj-$(CONFIG_LANTIQ_VRX200) += lantiq_vrx200.o + obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/ + obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/ + obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/ +diff --git a/drivers/net/ethernet/lantiq_vrx200.c b/drivers/net/ethernet/lantiq_vrx200.c +new file mode 100644 +index 0000000..d79d380 +--- /dev/null ++++ b/drivers/net/ethernet/lantiq_vrx200.c +@@ -0,0 +1,1358 @@ ++/* ++ * 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 distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/interrupt.h> ++#include <linux/uaccess.h> ++#include <linux/in.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/phy.h> ++#include <linux/ip.h> ++#include <linux/tcp.h> ++#include <linux/skbuff.h> ++#include <linux/mm.h> ++#include <linux/platform_device.h> ++#include <linux/ethtool.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/io.h> ++#include <linux/dma-mapping.h> ++#include <linux/module.h> ++#include <linux/clk.h> ++ ++#include <asm/checksum.h> ++ ++#include <lantiq_soc.h> ++#include <xway_dma.h> ++#include <lantiq_platform.h> ++ ++#define LTQ_SWITCH_BASE 0x1E108000 ++#define LTQ_SWITCH_CORE_BASE LTQ_SWITCH_BASE ++#define LTQ_SWITCH_TOP_PDI_BASE LTQ_SWITCH_CORE_BASE ++#define LTQ_SWITCH_BM_PDI_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x40) ++#define LTQ_SWITCH_MAC_PDI_0_BASE (LTQ_SWITCH_CORE_BASE + 4 * 0x900) ++#define LTQ_SWITCH_MAC_PDI_X_BASE(x) (LTQ_SWITCH_MAC_PDI_0_BASE + x * 0x30) ++#define LTQ_SWITCH_TOPLEVEL_BASE (LTQ_SWITCH_BASE + 4 * 0xC40) ++#define LTQ_SWITCH_MDIO_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE) ++#define LTQ_SWITCH_MII_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x36) ++#define LTQ_SWITCH_PMAC_PDI_BASE (LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x82) ++ ++#define LTQ_ETHSW_MAC_CTRL0_PADEN (1 << 8) ++#define LTQ_ETHSW_MAC_CTRL0_FCS (1 << 7) ++#define LTQ_ETHSW_MAC_CTRL1_SHORTPRE (1 << 8) ++#define LTQ_ETHSW_MAC_CTRL2_MLEN (1 << 3) ++#define LTQ_ETHSW_MAC_CTRL2_LCHKL (1 << 2) ++#define LTQ_ETHSW_MAC_CTRL2_LCHKS_DIS 0 ++#define LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG 1 ++#define LTQ_ETHSW_MAC_CTRL2_LCHKS_TAG 2 ++#define LTQ_ETHSW_MAC_CTRL6_RBUF_DLY_WP_SHIFT 9 ++#define LTQ_ETHSW_MAC_CTRL6_RXBUF_BYPASS (1 << 6) ++#define LTQ_ETHSW_GLOB_CTRL_SE (1 << 15) ++#define LTQ_ETHSW_MDC_CFG1_MCEN (1 << 8) ++#define LTQ_ETHSW_PMAC_HD_CTL_FC (1 << 10) ++#define LTQ_ETHSW_PMAC_HD_CTL_RC (1 << 4) ++#define LTQ_ETHSW_PMAC_HD_CTL_AC (1 << 2) ++#define ADVERTIZE_MPD (1 << 10) ++ ++#define MDIO_DEVAD_NONE (-1) ++ ++#define LTQ_ETH_RX_BUFFER_CNT PKTBUFSRX ++ ++#define LTQ_MDIO_DRV_NAME "ltq-mdio" ++#define LTQ_ETH_DRV_NAME "ltq-eth" ++ ++#define LTQ_ETHSW_MAX_GMAC 1 ++#define LTQ_ETHSW_PMAC 1 ++ ++#define ltq_setbits(a, set) \ ++ ltq_w32(ltq_r32(a) | (set), a) ++ ++enum ltq_reset_modules { ++ LTQ_RESET_CORE, ++ LTQ_RESET_DMA, ++ LTQ_RESET_ETH, ++ LTQ_RESET_PHY, ++ LTQ_RESET_HARD, ++ LTQ_RESET_SOFT, ++}; ++ ++static inline void ++dbg_ltq_writel(void *a, unsigned int b) ++{ ++ ltq_w32(b, a); ++} ++ ++int ltq_reset_once(enum ltq_reset_modules module, ulong usec); ++ ++struct ltq_ethsw_mac_pdi_x_regs { ++ u32 pstat; /* Port status */ ++ u32 pisr; /* Interrupt status */ ++ u32 pier; /* Interrupt enable */ ++ u32 ctrl_0; /* Control 0 */ ++ u32 ctrl_1; /* Control 1 */ ++ u32 ctrl_2; /* Control 2 */ ++ u32 ctrl_3; /* Control 3 */ ++ u32 ctrl_4; /* Control 4 */ ++ u32 ctrl_5; /* Control 5 */ ++ u32 ctrl_6; /* Control 6 */ ++ u32 bufst; /* TX/RX buffer control */ ++ u32 testen; /* Test enable */ ++}; ++ ++struct ltq_ethsw_mac_pdi_regs { ++ struct ltq_ethsw_mac_pdi_x_regs mac[12]; ++}; ++ ++struct ltq_ethsw_mdio_pdi_regs { ++ u32 glob_ctrl; /* Global control 0 */ ++ u32 rsvd0[7]; ++ u32 mdio_ctrl; /* MDIO control */ ++ u32 mdio_read; /* MDIO read data */ ++ u32 mdio_write; /* MDIO write data */ ++ u32 mdc_cfg_0; /* MDC clock configuration 0 */ ++ u32 mdc_cfg_1; /* MDC clock configuration 1 */ ++ u32 rsvd[3]; ++ u32 phy_addr_5; /* PHY address port 5 */ ++ u32 phy_addr_4; /* PHY address port 4 */ ++ u32 phy_addr_3; /* PHY address port 3 */ ++ u32 phy_addr_2; /* PHY address port 2 */ ++ u32 phy_addr_1; /* PHY address port 1 */ ++ u32 phy_addr_0; /* PHY address port 0 */ ++ u32 mdio_stat_0; /* MDIO PHY polling status port 0 */ ++ u32 mdio_stat_1; /* MDIO PHY polling status port 1 */ ++ u32 mdio_stat_2; /* MDIO PHY polling status port 2 */ ++ u32 mdio_stat_3; /* MDIO PHY polling status port 3 */ ++ u32 mdio_stat_4; /* MDIO PHY polling status port 4 */ ++ u32 mdio_stat_5; /* MDIO PHY polling status port 5 */ ++}; ++ ++struct ltq_ethsw_mii_pdi_regs { ++ u32 mii_cfg0; /* xMII port 0 configuration */ ++ u32 pcdu0; /* Port 0 clock delay configuration */ ++ u32 mii_cfg1; /* xMII port 1 configuration */ ++ u32 pcdu1; /* Port 1 clock delay configuration */ ++ u32 mii_cfg2; /* xMII port 2 configuration */ ++ u32 rsvd0; ++ u32 mii_cfg3; /* xMII port 3 configuration */ ++ u32 rsvd1; ++ u32 mii_cfg4; /* xMII port 4 configuration */ ++ u32 rsvd2; ++ u32 mii_cfg5; /* xMII port 5 configuration */ ++ u32 pcdu5; /* Port 5 clock delay configuration */ ++}; ++ ++struct ltq_ethsw_pmac_pdi_regs { ++ u32 hd_ctl; /* PMAC header control */ ++ u32 tl; /* PMAC type/length */ ++ u32 sa1; /* PMAC source address 1 */ ++ u32 sa2; /* PMAC source address 2 */ ++ u32 sa3; /* PMAC source address 3 */ ++ u32 da1; /* PMAC destination address 1 */ ++ u32 da2; /* PMAC destination address 2 */ ++ u32 da3; /* PMAC destination address 3 */ ++ u32 vlan; /* PMAC VLAN */ ++ u32 rx_ipg; /* PMAC interpacket gap in RX direction */ ++ u32 st_etype; /* PMAC special tag ethertype */ ++ u32 ewan; /* PMAC ethernet WAN group */ ++}; ++ ++struct ltq_mdio_phy_addr_reg { ++ union { ++ struct { ++ unsigned rsvd:1; ++ unsigned lnkst:2; /* Link status control */ ++ unsigned speed:2; /* Speed control */ ++ unsigned fdup:2; /* Full duplex control */ ++ unsigned fcontx:2; /* Flow control mode TX */ ++ unsigned fconrx:2; /* Flow control mode RX */ ++ unsigned addr:5; /* PHY address */ ++ } bits; ++ u16 val; ++ }; ++}; ++ ++enum ltq_mdio_phy_addr_lnkst { ++ LTQ_MDIO_PHY_ADDR_LNKST_AUTO = 0, ++ LTQ_MDIO_PHY_ADDR_LNKST_UP = 1, ++ LTQ_MDIO_PHY_ADDR_LNKST_DOWN = 2, ++}; ++ ++enum ltq_mdio_phy_addr_speed { ++ LTQ_MDIO_PHY_ADDR_SPEED_M10 = 0, ++ LTQ_MDIO_PHY_ADDR_SPEED_M100 = 1, ++ LTQ_MDIO_PHY_ADDR_SPEED_G1 = 2, ++ LTQ_MDIO_PHY_ADDR_SPEED_AUTO = 3, ++}; ++ ++enum ltq_mdio_phy_addr_fdup { ++ LTQ_MDIO_PHY_ADDR_FDUP_AUTO = 0, ++ LTQ_MDIO_PHY_ADDR_FDUP_ENABLE = 1, ++ LTQ_MDIO_PHY_ADDR_FDUP_DISABLE = 3, ++}; ++ ++enum ltq_mdio_phy_addr_fcon { ++ LTQ_MDIO_PHY_ADDR_FCON_AUTO = 0, ++ LTQ_MDIO_PHY_ADDR_FCON_ENABLE = 1, ++ LTQ_MDIO_PHY_ADDR_FCON_DISABLE = 3, ++}; ++ ++struct ltq_mii_mii_cfg_reg { ++ union { ++ struct { ++ unsigned res:1; /* Hardware reset */ ++ unsigned en:1; /* xMII interface enable */ ++ unsigned isol:1; /* xMII interface isolate */ ++ unsigned ldclkdis:1; /* Link down clock disable */ ++ unsigned rsvd:1; ++ unsigned crs:2; /* CRS sensitivity config */ ++ unsigned rgmii_ibs:1; /* RGMII In Band status */ ++ unsigned rmii:1; /* RMII ref clock direction */ ++ unsigned miirate:3; /* xMII interface clock rate */ ++ unsigned miimode:4; /* xMII interface mode */ ++ } bits; ++ u16 val; ++ }; ++}; ++ ++enum ltq_mii_mii_cfg_miirate { ++ LTQ_MII_MII_CFG_MIIRATE_M2P5 = 0, ++ LTQ_MII_MII_CFG_MIIRATE_M25 = 1, ++ LTQ_MII_MII_CFG_MIIRATE_M125 = 2, ++ LTQ_MII_MII_CFG_MIIRATE_M50 = 3, ++ LTQ_MII_MII_CFG_MIIRATE_AUTO = 4, ++}; ++ ++enum ltq_mii_mii_cfg_miimode { ++ LTQ_MII_MII_CFG_MIIMODE_MIIP = 0, ++ LTQ_MII_MII_CFG_MIIMODE_MIIM = 1, ++ LTQ_MII_MII_CFG_MIIMODE_RMIIP = 2, ++ LTQ_MII_MII_CFG_MIIMODE_RMIIM = 3, ++ LTQ_MII_MII_CFG_MIIMODE_RGMII = 4, ++}; ++ ++struct ltq_eth_priv { ++ struct ltq_dma_device *dma_dev; ++ struct mii_dev *bus; ++ struct eth_device *dev; ++ struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC]; ++ int rx_num; ++}; ++ ++enum ltq_mdio_mbusy { ++ LTQ_MDIO_MBUSY_IDLE = 0, ++ LTQ_MDIO_MBUSY_BUSY = 1, ++}; ++ ++enum ltq_mdio_op { ++ LTQ_MDIO_OP_WRITE = 1, ++ LTQ_MDIO_OP_READ = 2, ++}; ++ ++struct ltq_mdio_access { ++ union { ++ struct { ++ unsigned rsvd:3; ++ unsigned mbusy:1; ++ unsigned op:2; ++ unsigned phyad:5; ++ unsigned regad:5; ++ } bits; ++ u16 val; ++ }; ++}; ++ ++enum LTQ_ETH_PORT_FLAGS { ++ LTQ_ETH_PORT_NONE = 0, ++ LTQ_ETH_PORT_PHY = 1, ++ LTQ_ETH_PORT_SWITCH = (1 << 1), ++ LTQ_ETH_PORT_MAC = (1 << 2), ++}; ++ ++struct ltq_eth_port_config { ++ u8 num; ++ u8 phy_addr; ++ u16 flags; ++ phy_interface_t phy_if; ++}; ++ ++struct ltq_eth_board_config { ++ const struct ltq_eth_port_config *ports; ++ int num_ports; ++}; ++ ++static const struct ltq_eth_port_config eth_port_config[] = { ++ /* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 0 */ ++ { 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII }, ++ /* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 1 */ ++ { 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII }, ++}; ++ ++static const struct ltq_eth_board_config board_config = { ++ .ports = eth_port_config, ++ .num_ports = ARRAY_SIZE(eth_port_config), ++}; ++ ++static struct ltq_ethsw_mac_pdi_regs *ltq_ethsw_mac_pdi_regs = ++ (struct ltq_ethsw_mac_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MAC_PDI_0_BASE); ++ ++static struct ltq_ethsw_mdio_pdi_regs *ltq_ethsw_mdio_pdi_regs = ++ (struct ltq_ethsw_mdio_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MDIO_PDI_BASE); ++ ++static struct ltq_ethsw_mii_pdi_regs *ltq_ethsw_mii_pdi_regs = ++ (struct ltq_ethsw_mii_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_MII_PDI_BASE); ++ ++static struct ltq_ethsw_pmac_pdi_regs *ltq_ethsw_pmac_pdi_regs = ++ (struct ltq_ethsw_pmac_pdi_regs *) CKSEG1ADDR(LTQ_SWITCH_PMAC_PDI_BASE); ++ ++ ++#define MAX_DMA_CHAN 0x8 ++#define MAX_DMA_CRC_LEN 0x4 ++#define MAX_DMA_DATA_LEN 0x600 ++ ++/* use 2 static channels for TX/RX ++ depending on the SoC we need to use different DMA channels for ethernet */ ++#define LTQ_ETOP_TX_CHANNEL 1 ++#define LTQ_ETOP_RX_CHANNEL 0 ++ ++#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) ++#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) ++ ++#define DRV_VERSION "1.0" ++ ++static void __iomem *ltq_vrx200_membase; ++ ++struct ltq_vrx200_chan { ++ int idx; ++ int tx_free; ++ struct net_device *netdev; ++ struct napi_struct napi; ++ struct ltq_dma_channel dma; ++ struct sk_buff *skb[LTQ_DESC_NUM]; ++}; ++ ++struct ltq_vrx200_priv { ++ struct net_device *netdev; ++ struct ltq_eth_data *pldata; ++ struct resource *res; ++ ++ struct mii_bus *mii_bus; ++ struct phy_device *phydev; ++ ++ struct ltq_vrx200_chan ch[MAX_DMA_CHAN]; ++ int tx_free[MAX_DMA_CHAN >> 1]; ++ ++ spinlock_t lock; ++ ++ struct clk *clk_ppe; ++}; ++ ++static int ltq_vrx200_mdio_wr(struct mii_bus *bus, int phy_addr, ++ int phy_reg, u16 phy_data); ++ ++static int ++ltq_vrx200_alloc_skb(struct ltq_vrx200_chan *ch) ++{ ++ ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN); ++ if (!ch->skb[ch->dma.desc]) ++ return -ENOMEM; ++ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL, ++ ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN, ++ DMA_FROM_DEVICE); ++ ch->dma.desc_base[ch->dma.desc].addr = ++ CPHYSADDR(ch->skb[ch->dma.desc]->data); ++ ch->dma.desc_base[ch->dma.desc].ctl = ++ LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | ++ MAX_DMA_DATA_LEN; ++ skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN); ++ return 0; ++} ++ ++static void ++ltq_vrx200_hw_receive(struct ltq_vrx200_chan *ch) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); ++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; ++ struct sk_buff *skb = ch->skb[ch->dma.desc]; ++ int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (ltq_vrx200_alloc_skb(ch)) { ++ netdev_err(ch->netdev, ++ "failed to allocate new rx buffer, stopping DMA\n"); ++ ltq_dma_close(&ch->dma); ++ } ++ ch->dma.desc++; ++ ch->dma.desc %= LTQ_DESC_NUM; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ skb_put(skb, len); ++ skb->dev = ch->netdev; ++ skb->protocol = eth_type_trans(skb, ch->netdev); ++ netif_receive_skb(skb); ++} ++ ++static int ++ltq_vrx200_poll_rx(struct napi_struct *napi, int budget) ++{ ++ struct ltq_vrx200_chan *ch = container_of(napi, ++ struct ltq_vrx200_chan, napi); ++ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); ++ int rx = 0; ++ int complete = 0; ++ unsigned long flags; ++ ++ while ((rx < budget) && !complete) { ++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; ++ ++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { ++ ltq_vrx200_hw_receive(ch); ++ rx++; ++ } else { ++ complete = 1; ++ } ++ } ++ if (complete || !rx) { ++ napi_complete(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_ack_irq(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ return rx; ++} ++ ++static int ++ltq_vrx200_poll_tx(struct napi_struct *napi, int budget) ++{ ++ struct ltq_vrx200_chan *ch = ++ container_of(napi, struct ltq_vrx200_chan, napi); ++ struct ltq_vrx200_priv *priv = netdev_priv(ch->netdev); ++ struct netdev_queue *txq = ++ netdev_get_tx_queue(ch->netdev, ch->idx >> 1); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ while ((ch->dma.desc_base[ch->tx_free].ctl & ++ (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { ++ dev_kfree_skb_any(ch->skb[ch->tx_free]); ++ ch->skb[ch->tx_free] = NULL; ++ memset(&ch->dma.desc_base[ch->tx_free], 0, ++ sizeof(struct ltq_dma_desc)); ++ ch->tx_free++; ++ ch->tx_free %= LTQ_DESC_NUM; ++ } ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (netif_tx_queue_stopped(txq)) ++ netif_tx_start_queue(txq); ++ napi_complete(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_ack_irq(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return 1; ++} ++ ++static irqreturn_t ++ltq_vrx200_dma_irq(int irq, void *_priv) ++{ ++ struct ltq_vrx200_priv *priv = _priv; ++ int ch = irq - LTQ_DMA_ETOP; ++ ++ napi_schedule(&priv->ch[ch].napi); ++ return IRQ_HANDLED; ++} ++ ++static void ++ltq_vrx200_free_channel(struct net_device *dev, struct ltq_vrx200_chan *ch) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ ltq_dma_free(&ch->dma); ++ if (ch->dma.irq) ++ free_irq(ch->dma.irq, priv); ++ if (IS_RX(ch->idx)) { ++ int desc; ++ for (desc = 0; desc < LTQ_DESC_NUM; desc++) ++ dev_kfree_skb_any(ch->skb[ch->dma.desc]); ++ } ++} ++ ++static void ++ltq_vrx200_hw_exit(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ ++ clk_disable(priv->clk_ppe); ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) ++ if (IS_TX(i) || IS_RX(i)) ++ ltq_vrx200_free_channel(dev, &priv->ch[i]); ++} ++ ++static void *ltq_eth_phy_addr_reg(int num) ++{ ++ switch (num) { ++ case 0: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_0; ++ case 1: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_1; ++ case 2: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_2; ++ case 3: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_3; ++ case 4: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_4; ++ case 5: ++ return <q_ethsw_mdio_pdi_regs->phy_addr_5; ++ } ++ ++ return NULL; ++} ++ ++static void *ltq_eth_mii_cfg_reg(int num) ++{ ++ switch (num) { ++ case 0: ++ return <q_ethsw_mii_pdi_regs->mii_cfg0; ++ case 1: ++ return <q_ethsw_mii_pdi_regs->mii_cfg1; ++ case 2: ++ return <q_ethsw_mii_pdi_regs->mii_cfg2; ++ case 3: ++ return <q_ethsw_mii_pdi_regs->mii_cfg3; ++ case 4: ++ return <q_ethsw_mii_pdi_regs->mii_cfg4; ++ case 5: ++ return <q_ethsw_mii_pdi_regs->mii_cfg5; ++ } ++ ++ return NULL; ++} ++ ++static void ltq_eth_gmac_update(struct phy_device *phydev, int num) ++{ ++ struct ltq_mdio_phy_addr_reg phy_addr_reg; ++ struct ltq_mii_mii_cfg_reg mii_cfg_reg; ++ void *phy_addr = ltq_eth_phy_addr_reg(num); ++ void *mii_cfg = ltq_eth_mii_cfg_reg(num); ++ ++ phy_addr_reg.val = ltq_r32(phy_addr); ++ mii_cfg_reg.val = ltq_r32(mii_cfg); ++ ++ phy_addr_reg.bits.addr = phydev->addr; ++ ++ if (phydev->link) ++ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_UP; ++ else ++ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN; ++ ++ switch (phydev->speed) { ++ case SPEED_1000: ++ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_G1; ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M125; ++ break; ++ case SPEED_100: ++ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M100; ++ switch (mii_cfg_reg.bits.miimode) { ++ case LTQ_MII_MII_CFG_MIIMODE_RMIIM: ++ case LTQ_MII_MII_CFG_MIIMODE_RMIIP: ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M50; ++ break; ++ default: ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M25; ++ break; ++ } ++ break; ++ default: ++ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10; ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5; ++ break; ++ } ++ ++ if (phydev->duplex == DUPLEX_FULL) ++ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_ENABLE; ++ else ++ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE; ++ ++ dbg_ltq_writel(phy_addr, phy_addr_reg.val); ++ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); ++ udelay(1); ++} ++ ++ ++static void ltq_eth_port_config(struct ltq_vrx200_priv *priv, ++ const struct ltq_eth_port_config *port) ++{ ++ struct ltq_mii_mii_cfg_reg mii_cfg_reg; ++ void *mii_cfg = ltq_eth_mii_cfg_reg(port->num); ++ int setup_gpio = 0; ++ ++ mii_cfg_reg.val = ltq_r32(mii_cfg); ++ ++ ++ switch (port->num) { ++ case 0: /* xMII0 */ ++ case 1: /* xMII1 */ ++ switch (port->phy_if) { ++ case PHY_INTERFACE_MODE_MII: ++ if (port->flags & LTQ_ETH_PORT_PHY) ++ /* MII MAC mode, connected to external PHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_MIIM; ++ else ++ /* MII PHY mode, connected to external MAC */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_MIIP; ++ setup_gpio = 1; ++ break; ++ case PHY_INTERFACE_MODE_RMII: ++ if (port->flags & LTQ_ETH_PORT_PHY) ++ /* RMII MAC mode, connected to external PHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_RMIIM; ++ else ++ /* RMII PHY mode, connected to external MAC */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_RMIIP; ++ setup_gpio = 1; ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ /* RGMII MAC mode, connected to external PHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_RGMII; ++ setup_gpio = 1; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 2: /* internal GPHY0 */ ++ case 3: /* internal GPHY0 */ ++ case 4: /* internal GPHY1 */ ++ switch (port->phy_if) { ++ case PHY_INTERFACE_MODE_MII: ++ case PHY_INTERFACE_MODE_GMII: ++ /* MII MAC mode, connected to internal GPHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_MIIM; ++ setup_gpio = 1; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 5: /* internal GPHY1 or xMII2 */ ++ switch (port->phy_if) { ++ case PHY_INTERFACE_MODE_MII: ++ /* MII MAC mode, connected to internal GPHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_MIIM; ++ setup_gpio = 1; ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ /* RGMII MAC mode, connected to external PHY */ ++ mii_cfg_reg.bits.miimode = ++ LTQ_MII_MII_CFG_MIIMODE_RGMII; ++ setup_gpio = 1; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ /* Enable MII interface */ ++ mii_cfg_reg.bits.en = port->flags ? 1 : 0; ++ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); ++ ++} ++ ++static void ltq_eth_gmac_init(int num) ++{ ++ struct ltq_mdio_phy_addr_reg phy_addr_reg; ++ struct ltq_mii_mii_cfg_reg mii_cfg_reg; ++ void *phy_addr = ltq_eth_phy_addr_reg(num); ++ void *mii_cfg = ltq_eth_mii_cfg_reg(num); ++ struct ltq_ethsw_mac_pdi_x_regs *mac_pdi_regs; ++ ++ mac_pdi_regs = <q_ethsw_mac_pdi_regs->mac[num]; ++ ++ /* Reset PHY status to link down */ ++ phy_addr_reg.val = ltq_r32(phy_addr); ++ phy_addr_reg.bits.addr = num; ++ phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN; ++ phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10; ++ phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE; ++ dbg_ltq_writel(phy_addr, phy_addr_reg.val); ++ ++ /* Reset and disable MII interface */ ++ mii_cfg_reg.val = ltq_r32(mii_cfg); ++ mii_cfg_reg.bits.en = 0; ++ mii_cfg_reg.bits.res = 1; ++ mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5; ++ dbg_ltq_writel(mii_cfg, mii_cfg_reg.val); ++ ++ /* ++ * Enable padding of short frames, enable frame checksum generation ++ * in transmit direction ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_0, LTQ_ETHSW_MAC_CTRL0_PADEN | ++ LTQ_ETHSW_MAC_CTRL0_FCS); ++ ++ /* Set inter packet gap size to 12 bytes */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_1, 12); ++ ++ /* ++ * Configure frame length checks: ++ * - allow jumbo frames ++ * - enable long length check ++ * - enable short length without VLAN tags ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_2, LTQ_ETHSW_MAC_CTRL2_MLEN | ++ LTQ_ETHSW_MAC_CTRL2_LCHKL | ++ LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG); ++} ++ ++ ++static void ltq_eth_pmac_init(void) ++{ ++ struct ltq_ethsw_mac_pdi_x_regs *mac_pdi_regs; ++ ++ mac_pdi_regs = <q_ethsw_mac_pdi_regs->mac[LTQ_ETHSW_PMAC]; ++ ++ /* ++ * Enable padding of short frames, enable frame checksum generation ++ * in transmit direction ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_0, LTQ_ETHSW_MAC_CTRL0_PADEN | ++ LTQ_ETHSW_MAC_CTRL0_FCS); ++ ++ /* ++ * Configure frame length checks: ++ * - allow jumbo frames ++ * - enable long length check ++ * - enable short length without VLAN tags ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_2, LTQ_ETHSW_MAC_CTRL2_MLEN | ++ LTQ_ETHSW_MAC_CTRL2_LCHKL | ++ LTQ_ETHSW_MAC_CTRL2_LCHKS_UNTAG); ++ ++ /* ++ * Apply workaround for buffer congestion: ++ * - shorten preambel to 1 byte ++ * - set minimum inter packet gap size to 7 bytes ++ * - enable receive buffer bypass mode ++ */ ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_1, LTQ_ETHSW_MAC_CTRL1_SHORTPRE | 7); ++ dbg_ltq_writel(&mac_pdi_regs->ctrl_6, ++ (6 << LTQ_ETHSW_MAC_CTRL6_RBUF_DLY_WP_SHIFT) | ++ LTQ_ETHSW_MAC_CTRL6_RXBUF_BYPASS); ++ ++ /* Set request assertion threshold to 8, IPG counter to 11 */ ++ dbg_ltq_writel(<q_ethsw_pmac_pdi_regs->rx_ipg, 0x8B); ++ ++ /* ++ * Configure frame header control: ++ * - enable reaction on pause frames (flow control) ++ * - remove CRC for packets from PMAC to DMA ++ * - add CRC for packets from DMA to PMAC ++ */ ++ dbg_ltq_writel(<q_ethsw_pmac_pdi_regs->hd_ctl, LTQ_ETHSW_PMAC_HD_CTL_FC | ++ /*LTQ_ETHSW_PMAC_HD_CTL_RC | */LTQ_ETHSW_PMAC_HD_CTL_AC); ++} ++ ++static int ++ltq_vrx200_hw_init(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int err = 0; ++ int i; ++ ++ netdev_info(dev, "setting up dma\n"); ++ ltq_dma_init_port(DMA_PORT_ETOP); ++ ++ netdev_info(dev, "setting up pmu\n"); ++ clk_enable(priv->clk_ppe); ++ ++ /* Reset ethernet and switch subsystems */ ++ netdev_info(dev, "reset core\n"); ++ ltq_reset_once(BIT(8), 10); ++ ++ /* Enable switch macro */ ++ ltq_setbits(<q_ethsw_mdio_pdi_regs->glob_ctrl, ++ LTQ_ETHSW_GLOB_CTRL_SE); ++ ++ /* Disable MDIO auto-polling for all ports */ ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdc_cfg_0, 0); ++ ++ /* ++ * Enable and set MDIO management clock to 2.5 MHz. This is the ++ * maximum clock for FE PHYs. ++ * Formula for clock is: ++ * ++ * 50 MHz ++ * x = ----------- - 1 ++ * 2 * f_MDC ++ */ ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdc_cfg_1, ++ LTQ_ETHSW_MDC_CFG1_MCEN | 9); ++ ++ /* Init MAC connected to CPU */ ++ ltq_eth_pmac_init(); ++ ++ /* Init MACs connected to external MII interfaces */ ++ for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) ++ ltq_eth_gmac_init(i); ++ ++ for (i = 0; i < MAX_DMA_CHAN && !err; i++) { ++ int irq = LTQ_DMA_ETOP + i; ++ struct ltq_vrx200_chan *ch = &priv->ch[i]; ++ ++ ch->idx = ch->dma.nr = i; ++ ++ if (IS_TX(i)) { ++ ltq_dma_alloc_tx(&ch->dma); ++ err = request_irq(irq, ltq_vrx200_dma_irq, IRQF_DISABLED, ++ "vrx200_tx", priv); ++ } else if (IS_RX(i)) { ++ ltq_dma_alloc_rx(&ch->dma); ++ for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; ++ ch->dma.desc++) ++ if (ltq_vrx200_alloc_skb(ch)) ++ err = -ENOMEM; ++ ch->dma.desc = 0; ++ err = request_irq(irq, ltq_vrx200_dma_irq, IRQF_DISABLED, ++ "vrx200_rx", priv); ++ } ++ if (!err) ++ ch->dma.irq = irq; ++ } ++ for (i = 0; i < board_config.num_ports; i++) ++ ltq_eth_port_config(priv, &board_config.ports[i]); ++ return err; ++} ++ ++static void ++ltq_vrx200_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) ++{ ++ strcpy(info->driver, "Lantiq ETOP"); ++ strcpy(info->bus_info, "internal"); ++ strcpy(info->version, DRV_VERSION); ++} ++ ++static int ++ltq_vrx200_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ return phy_ethtool_gset(priv->phydev, cmd); ++} ++ ++static int ++ltq_vrx200_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ return phy_ethtool_sset(priv->phydev, cmd); ++} ++ ++static int ++ltq_vrx200_nway_reset(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ return phy_start_aneg(priv->phydev); ++} ++ ++static const struct ethtool_ops ltq_vrx200_ethtool_ops = { ++ .get_drvinfo = ltq_vrx200_get_drvinfo, ++ .get_settings = ltq_vrx200_get_settings, ++ .set_settings = ltq_vrx200_set_settings, ++ .nway_reset = ltq_vrx200_nway_reset, ++}; ++ ++static inline int ltq_mdio_poll(struct mii_bus *bus) ++{ ++ struct ltq_mdio_access acc; ++ unsigned cnt = 10000; ++ ++ while (likely(cnt--)) { ++ acc.val = ltq_r32(<q_ethsw_mdio_pdi_regs->mdio_ctrl); ++ if (!acc.bits.mbusy) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int ++ltq_vrx200_mdio_wr(struct mii_bus *bus, int addr, int regnum, u16 val) ++{ ++ struct ltq_mdio_access acc; ++ int ret; ++ ++ acc.val = 0; ++ acc.bits.mbusy = LTQ_MDIO_MBUSY_BUSY; ++ acc.bits.op = LTQ_MDIO_OP_WRITE; ++ acc.bits.phyad = addr; ++ acc.bits.regad = regnum; ++ ++ ret = ltq_mdio_poll(bus); ++ if (ret) ++ return ret; ++ ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_write, val); ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_ctrl, acc.val); ++ ++ return 0; ++} ++ ++static int ++ltq_vrx200_mdio_rd(struct mii_bus *bus, int addr, int regnum) ++{ ++ struct ltq_mdio_access acc; ++ int ret; ++ ++ acc.val = 0; ++ acc.bits.mbusy = LTQ_MDIO_MBUSY_BUSY; ++ acc.bits.op = LTQ_MDIO_OP_READ; ++ acc.bits.phyad = addr; ++ acc.bits.regad = regnum; ++ ++ ret = ltq_mdio_poll(bus); ++ if (ret) ++ goto timeout; ++ ++ dbg_ltq_writel(<q_ethsw_mdio_pdi_regs->mdio_ctrl, acc.val); ++ ++ ret = ltq_mdio_poll(bus); ++ if (ret) ++ goto timeout; ++ ++ ret = ltq_r32(<q_ethsw_mdio_pdi_regs->mdio_read); ++ ++ return ret; ++timeout: ++ return -1; ++} ++ ++static void ++ltq_vrx200_mdio_link(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ltq_eth_gmac_update(priv->phydev, 0); ++} ++ ++static int ++ltq_vrx200_mdio_probe(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ struct phy_device *phydev = NULL; ++ int val; ++ ++ phydev = priv->mii_bus->phy_map[0]; ++ ++ if (!phydev) { ++ netdev_err(dev, "no PHY found\n"); ++ return -ENODEV; ++ } ++ ++ phydev = phy_connect(dev, dev_name(&phydev->dev), <q_vrx200_mdio_link, ++ 0, 0); ++ ++ if (IS_ERR(phydev)) { ++ netdev_err(dev, "Could not attach to PHY\n"); ++ return PTR_ERR(phydev); ++ } ++ ++ phydev->supported &= (SUPPORTED_10baseT_Half ++ | SUPPORTED_10baseT_Full ++ | SUPPORTED_100baseT_Half ++ | SUPPORTED_100baseT_Full ++ | SUPPORTED_1000baseT_Half ++ | SUPPORTED_1000baseT_Full ++ | SUPPORTED_Autoneg ++ | SUPPORTED_MII ++ | SUPPORTED_TP); ++ phydev->advertising = phydev->supported; ++ priv->phydev = phydev; ++ ++ pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n", ++ dev->name, phydev->drv->name, ++ dev_name(&phydev->dev), phydev->irq); ++ ++ val = ltq_vrx200_mdio_rd(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000); ++ val |= ADVERTIZE_MPD; ++ ltq_vrx200_mdio_wr(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000, val); ++ ltq_vrx200_mdio_wr(priv->mii_bus, 0, 0, 0x1040); ++ ++ phy_start_aneg(phydev); ++ ++ return 0; ++} ++ ++static int ++ltq_vrx200_mdio_init(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ int err; ++ ++ priv->mii_bus = mdiobus_alloc(); ++ if (!priv->mii_bus) { ++ netdev_err(dev, "failed to allocate mii bus\n"); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ priv->mii_bus->priv = dev; ++ priv->mii_bus->read = ltq_vrx200_mdio_rd; ++ priv->mii_bus->write = ltq_vrx200_mdio_wr; ++ priv->mii_bus->name = "ltq_mii"; ++ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); ++ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); ++ if (!priv->mii_bus->irq) { ++ err = -ENOMEM; ++ goto err_out_free_mdiobus; ++ } ++ ++ for (i = 0; i < PHY_MAX_ADDR; ++i) ++ priv->mii_bus->irq[i] = PHY_POLL; ++ ++ if (mdiobus_register(priv->mii_bus)) { ++ err = -ENXIO; ++ goto err_out_free_mdio_irq; ++ } ++ ++ if (ltq_vrx200_mdio_probe(dev)) { ++ err = -ENXIO; ++ goto err_out_unregister_bus; ++ } ++ return 0; ++ ++err_out_unregister_bus: ++ mdiobus_unregister(priv->mii_bus); ++err_out_free_mdio_irq: ++ kfree(priv->mii_bus->irq); ++err_out_free_mdiobus: ++ mdiobus_free(priv->mii_bus); ++err_out: ++ return err; ++} ++ ++static void ++ltq_vrx200_mdio_cleanup(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ phy_disconnect(priv->phydev); ++ mdiobus_unregister(priv->mii_bus); ++ kfree(priv->mii_bus->irq); ++ mdiobus_free(priv->mii_bus); ++} ++ ++void phy_dump(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ for (i = 0; i < 0x1F; i++) { ++ unsigned int val = ltq_vrx200_mdio_rd(priv->mii_bus, 0, i); ++ printk("%d %4X\n", i, val); ++ } ++} ++ ++static int ++ltq_vrx200_open(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ unsigned long flags; ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ struct ltq_vrx200_chan *ch = &priv->ch[i]; ++ ++ if (!IS_TX(i) && (!IS_RX(i))) ++ continue; ++ napi_enable(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_open(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ if (priv->phydev) { ++ phy_start(priv->phydev); ++ phy_dump(dev); ++ } ++ netif_tx_start_all_queues(dev); ++ return 0; ++} ++ ++static int ++ltq_vrx200_stop(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ int i; ++ unsigned long flags; ++ ++ netif_tx_stop_all_queues(dev); ++ if (priv->phydev) ++ phy_stop(priv->phydev); ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ struct ltq_vrx200_chan *ch = &priv->ch[i]; ++ ++ if (!IS_RX(i) && !IS_TX(i)) ++ continue; ++ napi_disable(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_close(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ return 0; ++} ++ ++static int ++ltq_vrx200_tx(struct sk_buff *skb, struct net_device *dev) ++{ ++ int queue = skb_get_queue_mapping(skb); ++ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ struct ltq_vrx200_chan *ch = &priv->ch[(queue << 1) | 1]; ++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; ++ unsigned long flags; ++ u32 byte_offset; ++ int len; ++ ++ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; ++ ++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { ++ netdev_err(dev, "tx ring full\n"); ++ netif_tx_stop_queue(txq); ++ return NETDEV_TX_BUSY; ++ } ++ ++ /* dma needs to start on a 16 byte aligned address */ ++ byte_offset = CPHYSADDR(skb->data) % 16; ++ ch->skb[ch->dma.desc] = skb; ++ ++ dev->trans_start = jiffies; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len, ++ DMA_TO_DEVICE)) - byte_offset; ++ wmb(); ++ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | ++ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); ++ ch->dma.desc++; ++ ch->dma.desc %= LTQ_DESC_NUM; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) ++ netif_tx_stop_queue(txq); ++ ++ return NETDEV_TX_OK; ++} ++ ++static int ++ltq_vrx200_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ ++ /* TODO: mii-toll reports "No MII transceiver present!." ?!*/ ++ return phy_mii_ioctl(priv->phydev, rq, cmd); ++} ++ ++static u16 ++ltq_vrx200_select_queue(struct net_device *dev, struct sk_buff *skb) ++{ ++ /* we are currently only using the first queue */ ++ return 0; ++} ++ ++static int ++ltq_vrx200_init(struct net_device *dev) ++{ ++ struct ltq_vrx200_priv *priv = netdev_priv(dev); ++ struct sockaddr mac; ++ int err; ++ ++ ether_setup(dev); ++ dev->watchdog_timeo = 10 * HZ; ++ ++ err = ltq_vrx200_hw_init(dev); ++ if (err) ++ goto err_hw; ++ ++ memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); ++ if (!is_valid_ether_addr(mac.sa_data)) { ++ pr_warn("vrx200: invalid MAC, using random\n"); ++ random_ether_addr(mac.sa_data); ++ } ++ eth_mac_addr(dev, &mac); ++ ++ if (!ltq_vrx200_mdio_init(dev)) ++ dev->ethtool_ops = <q_vrx200_ethtool_ops; ++ else ++ pr_warn("vrx200: mdio probe failed\n");; ++ return 0; ++ ++err_hw: ++ ltq_vrx200_hw_exit(dev); ++ return err; ++} ++ ++static void ++ltq_vrx200_tx_timeout(struct net_device *dev) ++{ ++ int err; ++ ++ ltq_vrx200_hw_exit(dev); ++ err = ltq_vrx200_hw_init(dev); ++ if (err) ++ goto err_hw; ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++ return; ++ ++err_hw: ++ ltq_vrx200_hw_exit(dev); ++ netdev_err(dev, "failed to restart vrx200 after TX timeout\n"); ++} ++ ++static const struct net_device_ops ltq_eth_netdev_ops = { ++ .ndo_open = ltq_vrx200_open, ++ .ndo_stop = ltq_vrx200_stop, ++ .ndo_start_xmit = ltq_vrx200_tx, ++ .ndo_change_mtu = eth_change_mtu, ++ .ndo_do_ioctl = ltq_vrx200_ioctl, ++ .ndo_set_mac_address = eth_mac_addr, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_select_queue = ltq_vrx200_select_queue, ++ .ndo_init = ltq_vrx200_init, ++ .ndo_tx_timeout = ltq_vrx200_tx_timeout, ++}; ++ ++static int __devinit ++ltq_vrx200_probe(struct platform_device *pdev) ++{ ++ struct net_device *dev; ++ struct ltq_vrx200_priv *priv; ++ struct resource *res; ++ int err; ++ int i; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get vrx200 resource\n"); ++ err = -ENOENT; ++ goto err_out; ++ } ++ ++ res = devm_request_mem_region(&pdev->dev, res->start, ++ resource_size(res), dev_name(&pdev->dev)); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to request vrx200 resource\n"); ++ err = -EBUSY; ++ goto err_out; ++ } ++ ++ ltq_vrx200_membase = devm_ioremap_nocache(&pdev->dev, ++ res->start, resource_size(res)); ++ if (!ltq_vrx200_membase) { ++ dev_err(&pdev->dev, "failed to remap vrx200 engine %d\n", ++ pdev->id); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ if (ltq_gpio_request(&pdev->dev, 42, 2, 1, "MDIO") || ++ ltq_gpio_request(&pdev->dev, 43, 2, 1, "MDC")) { ++ dev_err(&pdev->dev, "failed to request MDIO gpios\n"); ++ err = -EBUSY; ++ goto err_out; ++ } ++ ++ dev = alloc_etherdev_mq(sizeof(struct ltq_vrx200_priv), 4); ++ strcpy(dev->name, "eth%d"); ++ dev->netdev_ops = <q_eth_netdev_ops; ++ priv = netdev_priv(dev); ++ priv->res = res; ++ priv->pldata = dev_get_platdata(&pdev->dev); ++ priv->netdev = dev; ++ ++ priv->clk_ppe = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk_ppe)) ++ return PTR_ERR(priv->clk_ppe); ++ ++ spin_lock_init(&priv->lock); ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ if (IS_TX(i)) ++ netif_napi_add(dev, &priv->ch[i].napi, ++ ltq_vrx200_poll_tx, 8); ++ else if (IS_RX(i)) ++ netif_napi_add(dev, &priv->ch[i].napi, ++ ltq_vrx200_poll_rx, 32); ++ priv->ch[i].netdev = dev; ++ } ++ ++ err = register_netdev(dev); ++ if (err) ++ goto err_free; ++ ++ platform_set_drvdata(pdev, dev); ++ return 0; ++ ++err_free: ++ kfree(dev); ++err_out: ++ return err; ++} ++ ++static int __devexit ++ltq_vrx200_remove(struct platform_device *pdev) ++{ ++ struct net_device *dev = platform_get_drvdata(pdev); ++ ++ if (dev) { ++ netif_tx_stop_all_queues(dev); ++ ltq_vrx200_hw_exit(dev); ++ ltq_vrx200_mdio_cleanup(dev); ++ unregister_netdev(dev); ++ } ++ return 0; ++} ++ ++static struct platform_driver ltq_mii_driver = { ++ .probe = ltq_vrx200_probe, ++ .remove = __devexit_p(ltq_vrx200_remove), ++ .driver = { ++ .name = "ltq_vrx200", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(ltq_mii_driver); ++ ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Lantiq SoC ETOP"); ++MODULE_LICENSE("GPL"); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0044-MIPS-NET-several-fixes-to-etop-driver.patch b/target/linux/lantiq/patches-3.2/0044-MIPS-NET-several-fixes-to-etop-driver.patch new file mode 100644 index 0000000000..dbb205be63 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0044-MIPS-NET-several-fixes-to-etop-driver.patch @@ -0,0 +1,445 @@ +From 06663beb0230c02d1962eca8d9f6709c2e852328 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 21 Mar 2012 18:14:06 +0100 +Subject: [PATCH 44/70] MIPS: NET: several fixes to etop driver + +--- + drivers/net/ethernet/lantiq_etop.c | 208 +++++++++++++++++++----------------- + 1 files changed, 108 insertions(+), 100 deletions(-) + +diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c +index a084d74..1a807d8 100644 +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c +@@ -103,15 +103,6 @@ + /* the newer xway socks have a embedded 3/7 port gbit multiplexer */ + #define ltq_has_gbit() (ltq_is_ar9() || ltq_is_vr9()) + +-/* use 2 static channels for TX/RX +- depending on the SoC we need to use different DMA channels for ethernet */ +-#define LTQ_ETOP_TX_CHANNEL 1 +-#define LTQ_ETOP_RX_CHANNEL ((ltq_is_ase()) ? (5) : \ +- ((ltq_has_gbit()) ? (0) : (6))) +- +-#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) +-#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) +- + #define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x)) + #define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y)) + #define ltq_etop_w32_mask(x, y, z) \ +@@ -128,8 +119,8 @@ static void __iomem *ltq_etop_membase; + static void __iomem *ltq_gbit_membase; + + struct ltq_etop_chan { +- int idx; + int tx_free; ++ int irq; + struct net_device *netdev; + struct napi_struct napi; + struct ltq_dma_channel dma; +@@ -144,8 +135,8 @@ struct ltq_etop_priv { + struct mii_bus *mii_bus; + struct phy_device *phydev; + +- struct ltq_etop_chan ch[MAX_DMA_CHAN]; +- int tx_free[MAX_DMA_CHAN >> 1]; ++ struct ltq_etop_chan txch; ++ struct ltq_etop_chan rxch; + + spinlock_t lock; + +@@ -206,8 +197,10 @@ ltq_etop_poll_rx(struct napi_struct *napi, int budget) + { + struct ltq_etop_chan *ch = container_of(napi, + struct ltq_etop_chan, napi); ++ struct ltq_etop_priv *priv = netdev_priv(ch->netdev); + int rx = 0; + int complete = 0; ++ unsigned long flags; + + while ((rx < budget) && !complete) { + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; +@@ -221,7 +214,9 @@ ltq_etop_poll_rx(struct napi_struct *napi, int budget) + } + if (complete || !rx) { + napi_complete(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); + ltq_dma_ack_irq(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); + } + return rx; + } +@@ -233,7 +228,7 @@ ltq_etop_poll_tx(struct napi_struct *napi, int budget) + container_of(napi, struct ltq_etop_chan, napi); + struct ltq_etop_priv *priv = netdev_priv(ch->netdev); + struct netdev_queue *txq = +- netdev_get_tx_queue(ch->netdev, ch->idx >> 1); ++ netdev_get_tx_queue(ch->netdev, ch->dma.nr >> 1); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); +@@ -251,7 +246,9 @@ ltq_etop_poll_tx(struct napi_struct *napi, int budget) + if (netif_tx_queue_stopped(txq)) + netif_tx_start_queue(txq); + napi_complete(&ch->napi); ++ spin_lock_irqsave(&priv->lock, flags); + ltq_dma_ack_irq(&ch->dma); ++ spin_unlock_irqrestore(&priv->lock, flags); + return 1; + } + +@@ -259,9 +256,10 @@ static irqreturn_t + ltq_etop_dma_irq(int irq, void *_priv) + { + struct ltq_etop_priv *priv = _priv; +- int ch = irq - LTQ_DMA_ETOP; +- +- napi_schedule(&priv->ch[ch].napi); ++ if (irq == priv->txch.dma.irq) ++ napi_schedule(&priv->txch.napi); ++ else ++ napi_schedule(&priv->rxch.napi); + return IRQ_HANDLED; + } + +@@ -273,7 +271,7 @@ ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch) + ltq_dma_free(&ch->dma); + if (ch->dma.irq) + free_irq(ch->dma.irq, priv); +- if (IS_RX(ch->idx)) { ++ if (ch == &priv->txch) { + int desc; + for (desc = 0; desc < LTQ_DESC_NUM; desc++) + dev_kfree_skb_any(ch->skb[ch->dma.desc]); +@@ -284,7 +282,6 @@ static void + ltq_etop_hw_exit(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); +- int i; + + clk_disable(priv->clk_ppe); + +@@ -296,9 +293,8 @@ ltq_etop_hw_exit(struct net_device *dev) + clk_disable(priv->clk_ephycgu); + } + +- for (i = 0; i < MAX_DMA_CHAN; i++) +- if (IS_TX(i) || IS_RX(i)) +- ltq_etop_free_channel(dev, &priv->ch[i]); ++ ltq_etop_free_channel(dev, &priv->txch); ++ ltq_etop_free_channel(dev, &priv->rxch); + } + + static void +@@ -326,8 +322,6 @@ ltq_etop_hw_init(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned int mii_mode = priv->pldata->mii_mode; +- int err = 0; +- int i; + + clk_enable(priv->clk_ppe); + +@@ -369,31 +363,50 @@ ltq_etop_hw_init(struct net_device *dev) + /* enable crc generation */ + ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG); + ++ return 0; ++} ++ ++static int ++ltq_etop_dma_init(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int tx = 1; ++ int rx = ((ltq_is_ase()) ? (5) : \ ++ ((ltq_is_ar9()) ? (0) : (6))); ++ int tx_irq = LTQ_DMA_ETOP + tx; ++ int rx_irq = LTQ_DMA_ETOP + rx; ++ int err; ++ + ltq_dma_init_port(DMA_PORT_ETOP); + +- for (i = 0; i < MAX_DMA_CHAN && !err; i++) { +- int irq = LTQ_DMA_ETOP + i; +- struct ltq_etop_chan *ch = &priv->ch[i]; +- +- ch->idx = ch->dma.nr = i; +- +- if (IS_TX(i)) { +- ltq_dma_alloc_tx(&ch->dma); +- err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, +- "etop_tx", priv); +- } else if (IS_RX(i)) { +- ltq_dma_alloc_rx(&ch->dma); +- for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; +- ch->dma.desc++) +- if (ltq_etop_alloc_skb(ch)) +- err = -ENOMEM; +- ch->dma.desc = 0; +- err = request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, +- "etop_rx", priv); ++ priv->txch.dma.nr = tx; ++ ltq_dma_alloc_tx(&priv->txch.dma); ++ err = request_irq(tx_irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ "eth_tx", priv); ++ if (err) { ++ netdev_err(dev, "failed to allocate tx irq\n"); ++ goto err_out; ++ } ++ priv->txch.dma.irq = tx_irq; ++ ++ priv->rxch.dma.nr = rx; ++ ltq_dma_alloc_rx(&priv->rxch.dma); ++ for (priv->rxch.dma.desc = 0; priv->rxch.dma.desc < LTQ_DESC_NUM; ++ priv->rxch.dma.desc++) { ++ if (ltq_etop_alloc_skb(&priv->rxch)) { ++ netdev_err(dev, "failed to allocate skbs\n"); ++ err = -ENOMEM; ++ goto err_out; + } +- if (!err) +- ch->dma.irq = irq; + } ++ priv->rxch.dma.desc = 0; ++ err = request_irq(rx_irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ "eth_rx", priv); ++ if (err) ++ netdev_err(dev, "failed to allocate rx irq\n"); ++ else ++ priv->rxch.dma.irq = rx_irq; ++err_out: + return err; + } + +@@ -410,7 +423,10 @@ ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + +- return phy_ethtool_gset(priv->phydev, cmd); ++ if (priv->phydev) ++ return phy_ethtool_gset(priv->phydev, cmd); ++ else ++ return 0; + } + + static int +@@ -418,7 +434,10 @@ ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + +- return phy_ethtool_sset(priv->phydev, cmd); ++ if (priv->phydev) ++ return phy_ethtool_sset(priv->phydev, cmd); ++ else ++ return 0; + } + + static int +@@ -426,7 +445,10 @@ ltq_etop_nway_reset(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); + +- return phy_start_aneg(priv->phydev); ++ if (priv->phydev) ++ return phy_start_aneg(priv->phydev); ++ else ++ return 0; + } + + static const struct ethtool_ops ltq_etop_ethtool_ops = { +@@ -618,18 +640,19 @@ static int + ltq_etop_open(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); +- int i; ++ unsigned long flags; + +- for (i = 0; i < MAX_DMA_CHAN; i++) { +- struct ltq_etop_chan *ch = &priv->ch[i]; ++ napi_enable(&priv->txch.napi); ++ napi_enable(&priv->rxch.napi); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_open(&priv->txch.dma); ++ ltq_dma_open(&priv->rxch.dma); ++ spin_unlock_irqrestore(&priv->lock, flags); + +- if (!IS_TX(i) && (!IS_RX(i))) +- continue; +- ltq_dma_open(&ch->dma); +- napi_enable(&ch->napi); +- } + if (priv->phydev) + phy_start(priv->phydev); ++ + netif_tx_start_all_queues(dev); + return 0; + } +@@ -638,19 +661,19 @@ static int + ltq_etop_stop(struct net_device *dev) + { + struct ltq_etop_priv *priv = netdev_priv(dev); +- int i; ++ unsigned long flags; + + netif_tx_stop_all_queues(dev); + if (priv->phydev) + phy_stop(priv->phydev); +- for (i = 0; i < MAX_DMA_CHAN; i++) { +- struct ltq_etop_chan *ch = &priv->ch[i]; ++ napi_disable(&priv->txch.napi); ++ napi_disable(&priv->rxch.napi); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_dma_close(&priv->txch.dma); ++ ltq_dma_close(&priv->rxch.dma); ++ spin_unlock_irqrestore(&priv->lock, flags); + +- if (!IS_RX(i) && !IS_TX(i)) +- continue; +- napi_disable(&ch->napi); +- ltq_dma_close(&ch->dma); +- } + return 0; + } + +@@ -660,16 +683,16 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) + int queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); + struct ltq_etop_priv *priv = netdev_priv(dev); +- struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1]; +- struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; ++ struct ltq_dma_desc *desc = ++ &priv->txch.dma.desc_base[priv->txch.dma.desc]; + unsigned long flags; + u32 byte_offset; + int len; + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + +- if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { +- dev_kfree_skb_any(skb); ++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ++ priv->txch.skb[priv->txch.dma.desc]) { + netdev_err(dev, "tx ring full\n"); + netif_tx_stop_queue(txq); + return NETDEV_TX_BUSY; +@@ -677,7 +700,7 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) + + /* dma needs to start on a 16 byte aligned address */ + byte_offset = CPHYSADDR(skb->data) % 16; +- ch->skb[ch->dma.desc] = skb; ++ priv->txch.skb[priv->txch.dma.desc] = skb; + + dev->trans_start = jiffies; + +@@ -687,11 +710,11 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) + wmb(); + desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | + LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); +- ch->dma.desc++; +- ch->dma.desc %= LTQ_DESC_NUM; ++ priv->txch.dma.desc++; ++ priv->txch.dma.desc %= LTQ_DESC_NUM; + spin_unlock_irqrestore(&priv->lock, flags); + +- if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) ++ if (priv->txch.dma.desc_base[priv->txch.dma.desc].ctl & LTQ_DMA_OWN) + netif_tx_stop_queue(txq); + + return NETDEV_TX_OK; +@@ -776,6 +799,10 @@ ltq_etop_init(struct net_device *dev) + err = ltq_etop_hw_init(dev); + if (err) + goto err_hw; ++ err = ltq_etop_dma_init(dev); ++ if (err) ++ goto err_hw; ++ + ltq_etop_change_mtu(dev, 1500); + + memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); +@@ -811,6 +838,9 @@ ltq_etop_tx_timeout(struct net_device *dev) + err = ltq_etop_hw_init(dev); + if (err) + goto err_hw; ++ err = ltq_etop_dma_init(dev); ++ if (err) ++ goto err_hw; + dev->trans_start = jiffies; + netif_wake_queue(dev); + return; +@@ -834,14 +864,13 @@ static const struct net_device_ops ltq_eth_netdev_ops = { + .ndo_tx_timeout = ltq_etop_tx_timeout, + }; + +-static int __init ++static int __devinit + ltq_etop_probe(struct platform_device *pdev) + { + struct net_device *dev; + struct ltq_etop_priv *priv; + struct resource *res, *gbit_res; + int err; +- int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { +@@ -917,15 +946,10 @@ ltq_etop_probe(struct platform_device *pdev) + + spin_lock_init(&priv->lock); + +- for (i = 0; i < MAX_DMA_CHAN; i++) { +- if (IS_TX(i)) +- netif_napi_add(dev, &priv->ch[i].napi, +- ltq_etop_poll_tx, 8); +- else if (IS_RX(i)) +- netif_napi_add(dev, &priv->ch[i].napi, +- ltq_etop_poll_rx, 32); +- priv->ch[i].netdev = dev; +- } ++ netif_napi_add(dev, &priv->txch.napi, ltq_etop_poll_tx, 8); ++ netif_napi_add(dev, &priv->rxch.napi, ltq_etop_poll_rx, 32); ++ priv->txch.netdev = dev; ++ priv->rxch.netdev = dev; + + err = register_netdev(dev); + if (err) +@@ -955,6 +979,7 @@ ltq_etop_remove(struct platform_device *pdev) + } + + static struct platform_driver ltq_mii_driver = { ++ .probe = ltq_etop_probe, + .remove = __devexit_p(ltq_etop_remove), + .driver = { + .name = "ltq_etop", +@@ -962,24 +987,7 @@ static struct platform_driver ltq_mii_driver = { + }, + }; + +-int __init +-init_ltq_etop(void) +-{ +- int ret = platform_driver_probe(<q_mii_driver, ltq_etop_probe); +- +- if (ret) +- pr_err("ltq_etop: Error registering platfom driver!"); +- return ret; +-} +- +-static void __exit +-exit_ltq_etop(void) +-{ +- platform_driver_unregister(<q_mii_driver); +-} +- +-module_init(init_ltq_etop); +-module_exit(exit_ltq_etop); ++module_platform_driver(ltq_mii_driver); + + MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); + MODULE_DESCRIPTION("Lantiq SoC ETOP"); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0045-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch b/target/linux/lantiq/patches-3.2/0045-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch new file mode 100644 index 0000000000..afbdbc92f0 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0045-MTD-MIPS-lantiq-use-module_platform_driver-inside-la.patch @@ -0,0 +1,64 @@ +From f94454615da63008ac865e6a7b03bbe79041e8c2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 20 Feb 2012 12:15:25 +0100 +Subject: [PATCH 45/70] MTD: MIPS: lantiq: use module_platform_driver inside + lantiq map driver + +Reduce boilerplate code by converting driver to module_platform_driver. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-mtd@lists.infradead.org +--- + drivers/mtd/maps/lantiq-flash.c | 22 +++------------------- + 1 files changed, 3 insertions(+), 19 deletions(-) + +diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c +index 764d468..b55212c 100644 +--- a/drivers/mtd/maps/lantiq-flash.c ++++ b/drivers/mtd/maps/lantiq-flash.c +@@ -108,7 +108,7 @@ ltq_copy_to(struct map_info *map, unsigned long to, + spin_unlock_irqrestore(&ebu_lock, flags); + } + +-static int __init ++static int __devinit + ltq_mtd_probe(struct platform_device *pdev) + { + struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); +@@ -208,6 +208,7 @@ ltq_mtd_remove(struct platform_device *pdev) + } + + static struct platform_driver ltq_mtd_driver = { ++ .probe = ltq_mtd_probe, + .remove = __devexit_p(ltq_mtd_remove), + .driver = { + .name = "ltq_nor", +@@ -215,24 +216,7 @@ static struct platform_driver ltq_mtd_driver = { + }, + }; + +-static int __init +-init_ltq_mtd(void) +-{ +- int ret = platform_driver_probe(<q_mtd_driver, ltq_mtd_probe); +- +- if (ret) +- pr_err("ltq_nor: error registering platform driver"); +- return ret; +-} +- +-static void __exit +-exit_ltq_mtd(void) +-{ +- platform_driver_unregister(<q_mtd_driver); +-} +- +-module_init(init_ltq_mtd); +-module_exit(exit_ltq_mtd); ++module_platform_driver(ltq_mtd_driver); + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0046-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch b/target/linux/lantiq/patches-3.2/0046-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch new file mode 100644 index 0000000000..f8a247b907 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0046-WDT-MIPS-lantiq-use-module_platform_driver-inside-la.patch @@ -0,0 +1,61 @@ +From 7d332825d131e70daff66b934797c89f50c11ace Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 20 Feb 2012 12:16:31 +0100 +Subject: [PATCH 46/70] WDT: MIPS: lantiq: use module_platform_driver inside + lantiq watchdog driver + +Reduce boilerplate code by converting driver to module_platform_driver. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Cc: linux-watchdog@vger.kernel.org +--- + drivers/watchdog/lantiq_wdt.c | 19 +++---------------- + 1 files changed, 3 insertions(+), 16 deletions(-) + +diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c +index da2b09f..40c9eb7 100644 +--- a/drivers/watchdog/lantiq_wdt.c ++++ b/drivers/watchdog/lantiq_wdt.c +@@ -182,7 +182,7 @@ static struct miscdevice ltq_wdt_miscdev = { + .fops = <q_wdt_fops, + }; + +-static int __init ++static int __devinit + ltq_wdt_probe(struct platform_device *pdev) + { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -230,6 +230,7 @@ ltq_wdt_remove(struct platform_device *pdev) + + + static struct platform_driver ltq_wdt_driver = { ++ .probe = ltq_wdt_probe, + .remove = __devexit_p(ltq_wdt_remove), + .driver = { + .name = "ltq_wdt", +@@ -237,21 +238,7 @@ static struct platform_driver ltq_wdt_driver = { + }, + }; + +-static int __init +-init_ltq_wdt(void) +-{ +- return platform_driver_probe(<q_wdt_driver, ltq_wdt_probe); +-} +- +-static void __exit +-exit_ltq_wdt(void) +-{ +- return platform_driver_unregister(<q_wdt_driver); +-} +- +-module_init(init_ltq_wdt); +-module_exit(exit_ltq_wdt); +- ++module_platform_driver(ltq_wdt_driver); + module_param(nowayout, int, 0); + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); + +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0017-MIPS-lantiq-adds-GPTU-driver.patch b/target/linux/lantiq/patches-3.2/0047-MIPS-lantiq-adds-GPTU-driver.patch index 4b7c7b5488..8be0ad5061 100644 --- a/target/linux/lantiq/patches/0017-MIPS-lantiq-adds-GPTU-driver.patch +++ b/target/linux/lantiq/patches-3.2/0047-MIPS-lantiq-adds-GPTU-driver.patch @@ -1,16 +1,20 @@ -From 45dbb232686978816e8148753e12f27caa2b2eb3 Mon Sep 17 00:00:00 2001 +From b672c54f9ae4504687a80bb51cdfe102bdae96e1 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 29 Sep 2011 17:16:38 +0200 -Subject: [PATCH 17/24] MIPS: lantiq: adds GPTU driver +Subject: [PATCH 47/70] MIPS: lantiq: adds GPTU driver --- arch/mips/include/asm/mach-lantiq/lantiq_timer.h | 155 ++++ arch/mips/lantiq/xway/Makefile | 2 +- - arch/mips/lantiq/xway/timer.c | 830 ++++++++++++++++++++++ - 3 files changed, 986 insertions(+), 1 deletions(-) + arch/mips/lantiq/xway/sysctrl.c | 1 + + arch/mips/lantiq/xway/timer.c | 846 ++++++++++++++++++++++ + 4 files changed, 1003 insertions(+), 1 deletions(-) create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_timer.h create mode 100644 arch/mips/lantiq/xway/timer.c +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_timer.h b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h +new file mode 100644 +index 0000000..ef564ab --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h @@ -0,0 +1,155 @@ @@ -169,17 +173,34 @@ Subject: [PATCH 17/24] MIPS: lantiq: adds GPTU driver + u32 reload, unsigned long arg1, unsigned long arg2); + +#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */ +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 277aa34..4c3106f 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -1,4 +1,4 @@ --obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o nand.o -+obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o nand.o timer.o +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o - obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o - obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 38f02f9..1a2e2d4 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -147,6 +147,7 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); + clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); + clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); ++ clkdev_add_pmu("ltq_gptu", NULL, 0, PMU_GPT); + if (!ltq_is_vr9()) + clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); + if (ltq_is_ase()) { +diff --git a/arch/mips/lantiq/xway/timer.c b/arch/mips/lantiq/xway/timer.c +new file mode 100644 +index 0000000..9794c87 --- /dev/null +++ b/arch/mips/lantiq/xway/timer.c -@@ -0,0 +1,830 @@ +@@ -0,0 +1,846 @@ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> @@ -195,6 +216,7 @@ Subject: [PATCH 17/24] MIPS: lantiq: adds GPTU driver + +#include <asm/irq.h> +#include <asm/div64.h> ++#include "../clk.h" + +#include <lantiq_soc.h> +#include <lantiq_irq.h> @@ -332,7 +354,18 @@ Subject: [PATCH 17/24] MIPS: lantiq: adds GPTU driver + struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2]; +}; + -+unsigned int ltq_get_fpi_bus_clock(int fpi); ++unsigned long ltq_danube_fpi_bus_clock(int fpi); ++unsigned long ltq_vr9_fpi_bus_clock(int fpi); ++ ++unsigned int ltq_get_fpi_bus_clock(int fpi) { ++ if (ltq_is_ase()) ++ return CLOCK_133M; ++ else if (ltq_is_vr9()) ++ return ltq_vr9_fpi_bus_clock(fpi); ++ ++ return ltq_danube_fpi_bus_clock(fpi); ++} ++ + +static long gptu_ioctl(struct file *, unsigned int, unsigned long); +static int gptu_open(struct inode *, struct file *); @@ -387,7 +420,10 @@ Subject: [PATCH 17/24] MIPS: lantiq: adds GPTU driver + +static inline void lq_enable_gptu(void) +{ -+ ltq_pmu_enable(PMU_GPT); ++ struct clk *clk = clk_get_sys("ltq_gptu", NULL); ++ clk_enable(clk); ++ ++ //ltq_pmu_enable(PMU_GPT); + + /* Set divider as 1, disable write protection for SPEN, enable module. */ + *LQ_GPTU_CLC = @@ -402,6 +438,7 @@ Subject: [PATCH 17/24] MIPS: lantiq: adds GPTU driver + +static inline void lq_disable_gptu(void) +{ ++ struct clk *clk = clk_get_sys("ltq_gptu", NULL); + ltq_w32(0x00, LQ_GPTU_IRNEN); + ltq_w32(0xfff, LQ_GPTU_IRNCR); + @@ -415,7 +452,7 @@ Subject: [PATCH 17/24] MIPS: lantiq: adds GPTU driver + GPTU_CLC_SPEN_SET(0) | + GPTU_CLC_DISR_SET(1); + -+ ltq_pmu_disable(PMU_GPT); ++ clk_enable(clk); +} + +int lq_request_timer(unsigned int timer, unsigned int flag, @@ -1010,3 +1047,6 @@ Subject: [PATCH 17/24] MIPS: lantiq: adds GPTU driver + +module_init(lq_gptu_init); +module_exit(lq_gptu_exit); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0018-MIPS-lantiq-adds-dwc_otg.patch b/target/linux/lantiq/patches-3.2/0048-MIPS-lantiq-adds-dwc_otg.patch index dd0b103770..2f47a2dafa 100644 --- a/target/linux/lantiq/patches/0018-MIPS-lantiq-adds-dwc_otg.patch +++ b/target/linux/lantiq/patches-3.2/0048-MIPS-lantiq-adds-dwc_otg.patch @@ -1,7 +1,7 @@ -From ffd7924fcc69ff146d62f131d72ef18575bf0227 Mon Sep 17 00:00:00 2001 +From 668e5f88aa80ef8c4c8cb935c7c222146de79825 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 30 Sep 2011 14:37:36 +0200 -Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +Subject: [PATCH 48/70] MIPS: lantiq: adds dwc_otg --- drivers/usb/Kconfig | 2 + @@ -45,9 +45,11 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg create mode 100644 drivers/usb/dwc_otg/dwc_otg_plat.h create mode 100644 drivers/usb/dwc_otg/dwc_otg_regs.h +diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig +index 791f11b..1eafa7a 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig -@@ -116,6 +116,8 @@ source "drivers/usb/wusbcore/Kconfig" +@@ -129,6 +129,8 @@ source "drivers/usb/wusbcore/Kconfig" source "drivers/usb/host/Kconfig" @@ -56,9 +58,11 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg source "drivers/usb/musb/Kconfig" source "drivers/usb/renesas_usbhs/Kconfig" +diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile +index 75eca76..7fe8e83 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile -@@ -28,6 +28,8 @@ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ +@@ -30,6 +30,8 @@ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ obj-$(CONFIG_USB_WUSB) += wusbcore/ @@ -67,9 +71,11 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_PRINTER) += class/ obj-$(CONFIG_USB_WDM) += class/ +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 7978146..6a7df52 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -2891,11 +2891,11 @@ hub_port_init (struct usb_hub *hub, stru +@@ -2935,11 +2935,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->ttport = hdev->ttport; } else if (udev->speed != USB_SPEED_HIGH && hdev->speed == USB_SPEED_HIGH) { @@ -83,6 +89,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg udev->tt = &hub->tt; udev->ttport = port1; } +diff --git a/drivers/usb/dwc_otg/Kconfig b/drivers/usb/dwc_otg/Kconfig +new file mode 100644 +index 0000000..e018490 --- /dev/null +++ b/drivers/usb/dwc_otg/Kconfig @@ -0,0 +1,37 @@ @@ -123,6 +132,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +config DWC_OTG_DEBUG + bool "Enable debug mode" + depends on DWC_OTG +diff --git a/drivers/usb/dwc_otg/Makefile b/drivers/usb/dwc_otg/Makefile +new file mode 100644 +index 0000000..d4d2355 --- /dev/null +++ b/drivers/usb/dwc_otg/Makefile @@ -0,0 +1,39 @@ @@ -165,6 +177,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + +#obj-$(CONFIG_DWC_OTG_IFX) := dwc_otg_ifx.o +#dwc_otg_ifx-objs := dwc_otg_ifx.o +diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.c b/drivers/usb/dwc_otg/dwc_otg_attr.c +new file mode 100644 +index 0000000..4675a5c --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_attr.c @@ -0,0 +1,802 @@ @@ -970,6 +985,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + device_remove_file(_dev, &dev_attr_rd_reg_test); + device_remove_file(_dev, &dev_attr_wr_reg_test); +} +diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.h b/drivers/usb/dwc_otg/dwc_otg_attr.h +new file mode 100644 +index 0000000..4bbf7df --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_attr.h @@ -0,0 +1,67 @@ @@ -1040,6 +1058,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +void dwc_otg_attr_remove (struct device *_dev); + +#endif +diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c +new file mode 100644 +index 0000000..42c69eb --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_cil.c @@ -0,0 +1,3025 @@ @@ -4068,6 +4089,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + _cb->p = _p; +} + +diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.h b/drivers/usb/dwc_otg/dwc_otg_cil.h +new file mode 100644 +index 0000000..bbb9516 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_cil.h @@ -0,0 +1,911 @@ @@ -4982,6 +5006,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + + +#endif +diff --git a/drivers/usb/dwc_otg/dwc_otg_cil_ifx.h b/drivers/usb/dwc_otg/dwc_otg_cil_ifx.h +new file mode 100644 +index 0000000..b0298ec --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_cil_ifx.h @@ -0,0 +1,58 @@ @@ -5043,6 +5070,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + +#endif // __DWC_OTG_CIL_IFX_H__ + +diff --git a/drivers/usb/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c +new file mode 100644 +index 0000000..d469ab4 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c @@ -0,0 +1,708 @@ @@ -5754,6 +5784,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + } + return retval; +} +diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c +new file mode 100644 +index 0000000..1b0daab --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_driver.c @@ -0,0 +1,1274 @@ @@ -7031,6 +7064,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + </td></tr> + +*/ +diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.h b/drivers/usb/dwc_otg/dwc_otg_driver.h +new file mode 100644 +index 0000000..7e6940d --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_driver.h @@ -0,0 +1,84 @@ @@ -7118,6 +7154,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +//#define dev_dbg(fake, format, arg...) printk(KERN_CRIT __FILE__ ":%d: " format "\n" , __LINE__, ## arg) + +#endif +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c +new file mode 100644 +index 0000000..ad6bc72 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c @@ -0,0 +1,2870 @@ @@ -9991,6 +10030,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +#endif +} +#endif /* DWC_DEVICE_ONLY */ +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.h b/drivers/usb/dwc_otg/dwc_otg_hcd.h +new file mode 100644 +index 0000000..8a20dff --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.h @@ -0,0 +1,676 @@ @@ -10670,6 +10712,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +#endif // DEBUG +#endif // __DWC_HCD_H__ +#endif /* DWC_DEVICE_ONLY */ +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +new file mode 100644 +index 0000000..834b5e0 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c @@ -0,0 +1,1841 @@ @@ -12514,6 +12559,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +} + +#endif /* DWC_DEVICE_ONLY */ +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c +new file mode 100644 +index 0000000..fcb5ce6 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c @@ -0,0 +1,794 @@ @@ -13311,6 +13359,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +} + +#endif /* DWC_DEVICE_ONLY */ +diff --git a/drivers/usb/dwc_otg/dwc_otg_ifx.c b/drivers/usb/dwc_otg/dwc_otg_ifx.c +new file mode 100644 +index 0000000..0a4c209 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_ifx.c @@ -0,0 +1,100 @@ @@ -13414,6 +13465,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +void ifx_usb_hc_remove(void) +{ +} +diff --git a/drivers/usb/dwc_otg/dwc_otg_ifx.h b/drivers/usb/dwc_otg/dwc_otg_ifx.h +new file mode 100644 +index 0000000..402d7a6 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_ifx.h @@ -0,0 +1,85 @@ @@ -13502,6 +13556,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + ltq_mask_and_ack_irq(&d); +} +#endif //__DWC_OTG_IFX_H__ +diff --git a/drivers/usb/dwc_otg/dwc_otg_plat.h b/drivers/usb/dwc_otg/dwc_otg_plat.h +new file mode 100644 +index 0000000..727d0c4 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_plat.h @@ -0,0 +1,269 @@ @@ -13774,6 +13831,9 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg + +#endif + +diff --git a/drivers/usb/dwc_otg/dwc_otg_regs.h b/drivers/usb/dwc_otg/dwc_otg_regs.h +new file mode 100644 +index 0000000..397a954 --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_regs.h @@ -0,0 +1,1797 @@ @@ -15574,3 +15634,6 @@ Subject: [PATCH 18/24] MIPS: lantiq: adds dwc_otg +} dwc_otg_host_if_t; + +#endif +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0049-dwc_otg-remove-bogus-halt_channel.patch b/target/linux/lantiq/patches-3.2/0049-dwc_otg-remove-bogus-halt_channel.patch new file mode 100644 index 0000000000..0a4d817afd --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0049-dwc_otg-remove-bogus-halt_channel.patch @@ -0,0 +1,26 @@ +From 7f73b86b26fc58e0513a792533b7e11450aa0737 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 23 Mar 2012 16:14:33 +0100 +Subject: [PATCH 49/70] dwc_otg: remove bogus halt_channel + +https://lists.openwrt.org/pipermail/openwrt-devel/2012-March/014524.html +--- + drivers/usb/dwc_otg/dwc_otg_hcd_intr.c | 2 -- + 1 files changed, 0 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +index 834b5e0..f6f3f3d 100644 +--- a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +@@ -1278,8 +1278,6 @@ static int32_t handle_hc_ack_intr(dwc_otg_hcd_t *_hcd, + * automatically executes the PING, then the transfer. + */ + halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free); +- } else { +- halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); + } + } + +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0050-MIPS-adds-ifxhcd.patch b/target/linux/lantiq/patches-3.2/0050-MIPS-adds-ifxhcd.patch new file mode 100644 index 0000000000..51a2c98e79 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0050-MIPS-adds-ifxhcd.patch @@ -0,0 +1,16672 @@ +From 09071b501014528984b158bc5408d8a738ef6883 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sun, 11 Mar 2012 15:59:39 +0100 +Subject: [PATCH 50/70] MIPS: adds ifxhcd + +--- + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/dev-ifxhcd.c | 45 + + arch/mips/lantiq/xway/dev-ifxhcd.h | 17 + + arch/mips/lantiq/xway/sysctrl.c | 2 + + drivers/usb/Kconfig | 2 + + drivers/usb/Makefile | 2 + + drivers/usb/ifxhcd/Kconfig | 58 + + drivers/usb/ifxhcd/Makefile | 85 + + drivers/usb/ifxhcd/TagHistory | 171 ++ + drivers/usb/ifxhcd/ifxhcd.c | 2523 +++++++++++++++++++++++ + drivers/usb/ifxhcd/ifxhcd.h | 628 ++++++ + drivers/usb/ifxhcd/ifxhcd_es.c | 549 +++++ + drivers/usb/ifxhcd/ifxhcd_intr.c | 3742 +++++++++++++++++++++++++++++++++++ + drivers/usb/ifxhcd/ifxhcd_queue.c | 418 ++++ + drivers/usb/ifxhcd/ifxusb_cif.c | 1458 ++++++++++++++ + drivers/usb/ifxhcd/ifxusb_cif.h | 665 +++++++ + drivers/usb/ifxhcd/ifxusb_cif_d.c | 458 +++++ + drivers/usb/ifxhcd/ifxusb_cif_h.c | 846 ++++++++ + drivers/usb/ifxhcd/ifxusb_ctl.c | 1385 +++++++++++++ + drivers/usb/ifxhcd/ifxusb_driver.c | 970 +++++++++ + drivers/usb/ifxhcd/ifxusb_plat.h | 1018 ++++++++++ + drivers/usb/ifxhcd/ifxusb_regs.h | 1420 +++++++++++++ + drivers/usb/ifxhcd/ifxusb_version.h | 5 + + 23 files changed, 16468 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/lantiq/xway/dev-ifxhcd.c + create mode 100644 arch/mips/lantiq/xway/dev-ifxhcd.h + create mode 100644 drivers/usb/ifxhcd/Kconfig + create mode 100644 drivers/usb/ifxhcd/Makefile + create mode 100644 drivers/usb/ifxhcd/TagHistory + create mode 100644 drivers/usb/ifxhcd/ifxhcd.c + create mode 100644 drivers/usb/ifxhcd/ifxhcd.h + create mode 100644 drivers/usb/ifxhcd/ifxhcd_es.c + create mode 100644 drivers/usb/ifxhcd/ifxhcd_intr.c + create mode 100644 drivers/usb/ifxhcd/ifxhcd_queue.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_cif.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_cif.h + create mode 100644 drivers/usb/ifxhcd/ifxusb_cif_d.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_cif_h.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_ctl.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_driver.c + create mode 100644 drivers/usb/ifxhcd/ifxusb_plat.h + create mode 100644 drivers/usb/ifxhcd/ifxusb_regs.h + create mode 100644 drivers/usb/ifxhcd/ifxusb_version.h + +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 4c3106f..c9baf91 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o ++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o dev-ifxhcd.o + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +diff --git a/arch/mips/lantiq/xway/dev-ifxhcd.c b/arch/mips/lantiq/xway/dev-ifxhcd.c +new file mode 100644 +index 0000000..ea08a35 +--- /dev/null ++++ b/arch/mips/lantiq/xway/dev-ifxhcd.c +@@ -0,0 +1,45 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/string.h> ++#include <linux/mtd/physmap.h> ++#include <linux/kernel.h> ++#include <linux/reboot.h> ++#include <linux/platform_device.h> ++#include <linux/leds.h> ++#include <linux/etherdevice.h> ++#include <linux/reboot.h> ++#include <linux/time.h> ++#include <linux/io.h> ++#include <linux/gpio.h> ++#include <linux/leds.h> ++ ++#include <asm/bootinfo.h> ++#include <asm/irq.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_platform.h> ++ ++static u64 dmamask = (u32)0x1fffffff; ++ ++static struct platform_device platform_dev = { ++ .name = "ifxusb_hcd", ++ .dev.dma_mask = &dmamask, ++}; ++ ++int __init ++xway_register_hcd(int *pins) ++{ ++ platform_dev.dev.platform_data = pins; ++ return platform_device_register(&platform_dev); ++} +diff --git a/arch/mips/lantiq/xway/dev-ifxhcd.h b/arch/mips/lantiq/xway/dev-ifxhcd.h +new file mode 100644 +index 0000000..18b3d2d +--- /dev/null ++++ b/arch/mips/lantiq/xway/dev-ifxhcd.h +@@ -0,0 +1,17 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifndef _LTQ_DEV_HCD_H__ ++#define _LTQ_DEV_HCD_H__ ++ ++#include <lantiq_platform.h> ++ ++extern void __init xway_register_hcd(int *pin); ++ ++#endif +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 1a2e2d4..ac7383f 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -166,6 +166,8 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); + clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); + clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); ++ clkdev_add_pmu("usb0", NULL, 0, (1<<6) | 1); ++ clkdev_add_pmu("usb1", NULL, 0, (1<<26) | (1<<27)); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), + ltq_danube_io_region_clock()); +diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig +index 1eafa7a..0f7926e 100644 +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -183,4 +183,6 @@ source "drivers/usb/gadget/Kconfig" + + source "drivers/usb/otg/Kconfig" + ++source "drivers/usb/ifxhcd/Kconfig" ++ + endif # USB_SUPPORT +diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile +index 7fe8e83..61b4c88 100644 +--- a/drivers/usb/Makefile ++++ b/drivers/usb/Makefile +@@ -57,3 +57,5 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg/ + obj-$(CONFIG_USB_GADGET) += gadget/ + + obj-$(CONFIG_USB_COMMON) += usb-common.o ++ ++obj-$(CONFIG_USB_HOST_IFX) += ifxhcd/ +diff --git a/drivers/usb/ifxhcd/Kconfig b/drivers/usb/ifxhcd/Kconfig +new file mode 100644 +index 0000000..7eb8ceb +--- /dev/null ++++ b/drivers/usb/ifxhcd/Kconfig +@@ -0,0 +1,58 @@ ++ ++config USB_HOST_IFX ++ tristate "Infineon USB Host Controller Driver" ++ depends on USB ++ default n ++ help ++ Infineon USB Host Controller ++ ++config USB_HOST_IFX_B ++ bool "USB host mode on core 1 and 2" ++ depends on USB_HOST_IFX ++ help ++ Both cores run as host ++ ++#config USB_HOST_IFX_1 ++#config USB_HOST_IFX_2 ++ ++#config IFX_DANUBE ++#config IFX_AMAZON_SE ++config IFX_AR9 ++ depends on USB_HOST_IFX ++ bool "AR9" ++ ++config IFX_VR9 ++ depends on USB_HOST_IFX ++ bool "VR9" ++ ++#config USB_HOST_IFX_FORCE_USB11 ++# bool "Forced USB1.1" ++# depends on USB_HOST_IFX ++# default n ++# help ++# force to be USB 1.1 ++ ++#config USB_HOST_IFX_WITH_HS_ELECT_TST ++# bool "With HS_Electrical Test" ++# depends on USB_HOST_IFX ++# default n ++# help ++# With USBIF HSET routines ++ ++#config USB_HOST_IFX_WITH_ISO ++# bool "With ISO transfer" ++# depends on USB_HOST_IFX ++# default n ++# help ++# With USBIF ISO transfer ++ ++config USB_HOST_IFX_UNALIGNED_ADJ ++ bool "Adjust" ++ depends on USB_HOST_IFX ++ help ++ USB_HOST_IFX_UNALIGNED_ADJ ++ ++#config USB_HOST_IFX_UNALIGNED_CHK ++#config USB_HOST_IFX_UNALIGNED_NONE ++ ++ +diff --git a/drivers/usb/ifxhcd/Makefile b/drivers/usb/ifxhcd/Makefile +new file mode 100644 +index 0000000..0a2ac99 +--- /dev/null ++++ b/drivers/usb/ifxhcd/Makefile +@@ -0,0 +1,85 @@ ++ ++# ++# Makefile for USB Core files and filesystem ++# ++ ifxusb_host-objs := ifxusb_driver.o ++ ifxusb_host-objs += ifxusb_ctl.o ++ ifxusb_host-objs += ifxusb_cif.o ++ ifxusb_host-objs += ifxusb_cif_h.o ++ ifxusb_host-objs += ifxhcd.o ++ ifxusb_host-objs += ifxhcd_es.o ++ ifxusb_host-objs += ifxhcd_intr.o ++ ifxusb_host-objs += ifxhcd_queue.o ++ ++ifeq ($(CONFIG_IFX_TWINPASS),y) ++ EXTRA_CFLAGS += -D__IS_TWINPASS__ ++endif ++ifeq ($(CONFIG_IFX_DANUBE),y) ++ EXTRA_CFLAGS += -D__IS_DANUBE__ ++endif ++ifeq ($(CONFIG_IFX_AMAZON_SE),y) ++ EXTRA_CFLAGS += -D__IS_AMAZON_SE__ ++endif ++ifeq ($(CONFIG_IFX_AR9),y) ++ EXTRA_CFLAGS += -D__IS_AR9__ ++endif ++ifeq ($(CONFIG_IFX_AMAZON_S),y) ++ EXTRA_CFLAGS += -D__IS_AR9__ ++endif ++ifeq ($(CONFIG_IFX_VR9),y) ++ EXTRA_CFLAGS += -D__IS_VR9__ ++endif ++ ++ifeq ($(CONFIG_USB_HOST_IFX),y) ++ EXTRA_CFLAGS += -Dlinux -D__LINUX__ ++ EXTRA_CFLAGS += -D__IS_HOST__ ++ EXTRA_CFLAGS += -D__KERNEL__ ++endif ++ ++ifeq ($(CONFIG_USB_HOST_IFX),m) ++ EXTRA_CFLAGS += -Dlinux -D__LINUX__ ++ EXTRA_CFLAGS += -D__IS_HOST__ ++ EXTRA_CFLAGS += -D__KERNEL__ ++endif ++ ++ifeq ($(CONFIG_USB_DEBUG),y) ++ EXTRA_CFLAGS += -D__DEBUG__ ++ EXTRA_CFLAGS += -D__ENABLE_DUMP__ ++endif ++ ++ifeq ($(CONFIG_USB_HOST_IFX_B),y) ++ EXTRA_CFLAGS += -D__IS_DUAL__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_1),y) ++ EXTRA_CFLAGS += -D__IS_FIRST__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_2),y) ++ EXTRA_CFLAGS += -D__IS_SECOND__ ++endif ++ ++ifeq ($(CONFIG_USB_HOST_IFX_FORCE_USB11),y) ++ EXTRA_CFLAGS += -D__FORCE_USB11__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_WITH_HS_ELECT_TST),y) ++ EXTRA_CFLAGS += -D__WITH_HS_ELECT_TST__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_WITH_ISO),y) ++ EXTRA_CFLAGS += -D__EN_ISOC__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_ADJ),y) ++ EXTRA_CFLAGS += -D__UNALIGNED_BUFFER_ADJ__ ++endif ++ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_CHK),y) ++ EXTRA_CFLAGS += -D__UNALIGNED_BUFFER_CHK__ ++endif ++ ++# EXTRA_CFLAGS += -D__DYN_SOF_INTR__ ++ EXTRA_CFLAGS += -D__UEIP__ ++# EXTRA_CFLAGS += -D__EN_ISOC__ ++# EXTRA_CFLAGS += -D__EN_ISOC_SPLIT__ ++ ++## 20110628 AVM/WK New flag for less SOF IRQs ++ EXTRA_CFLAGS += -D__USE_TIMER_4_SOF__ ++ ++obj-$(CONFIG_USB_HOST_IFX) += ifxusb_host.o ++ +diff --git a/drivers/usb/ifxhcd/TagHistory b/drivers/usb/ifxhcd/TagHistory +new file mode 100644 +index 0000000..3820d70 +--- /dev/null ++++ b/drivers/usb/ifxhcd/TagHistory +@@ -0,0 +1,171 @@ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://embeddedvm/home/SVN/drivers/usb_host20/tags/5.18-r240-non_musb_ar9_vr9-SOF_Timer_Fixed ++| Erzeugt mit SVN-Tagger Version 3.74. +++----------------------------------------------------------------------+ ++FIX - Korrektur bei der SOF-Timer/IRQ Steuerung. (Bug in Tag 5.17) ++FIX - Fehlerbehandlung an mehreren Stellen korrigiert bzw. eingebaut. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://embeddedvm/home/SVN/drivers/usb_host20/tags/5.17-r237-non_musb_ar9_vr9-2_6_32_41_Kompatibel ++| Erzeugt mit SVN-Tagger Version 3.73. +++----------------------------------------------------------------------+ ++FIX - Kompatiblität zum Update auf Kernel 2.6.32-41. Weiterhin für 28er geeignet. ++ENH - Reduktion der Interrruptlast durch Nutzung eines hrtimers anstatt SOF-IRQ. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.16-r208-non_musb_ar9_vr9-20110421_Zero_Paket_Optimiert ++| Erzeugt mit SVN-Tagger Version 3.66. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 / AR9 - Zero Packet. Optimierung korrigiert. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.15-r205-non_musb_ar9_vr9-20110421_Zero_Paket_WA_funktioniert ++| Erzeugt mit SVN-Tagger Version 3.66. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 / AR9 - "Zero Packet" funktioniert nun wirklich. Letzter Tag hatte einen Bug. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.14-r202-non_musb_ar9_vr9-20110420_Zero_Paket_WA ++| Erzeugt mit SVN-Tagger Version 3.66. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 / AR9 - Zero Packet Workaround: ZLP wird nun geschickt wenn URB_ZERO_PACKET aktiv ist. ++ Wird von LTE Altair Firmware benoetig. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.13-r199-non_musb_ar9_vr9-20110310_Init_Fix ++| Erzeugt mit SVN-Tagger Version 3.64. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 / AR9 - Timing der Initialisierungsphase angepasst zum Kernel 2.6.28 mit UGW-4.3.1. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.12-r184-non_musb_ar9_vr9-20110118_Full_Speed_Fix ++| Erzeugt mit SVN-Tagger Version 3.58. +++----------------------------------------------------------------------+ ++AR9/VR9 (3370,6840,7320): ++Makefile - FIX - (Workaround) Debug Modus hilft gegen Enumerationsfehler bei Full Speed Drucker. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.11-r175-non_musb_ar9_vr9-20101220_VR9_2_Ports_DMA_Fix ++| Erzeugt mit SVN-Tagger Version 3.58. +++----------------------------------------------------------------------+ ++ ++FIX - VR9 - Workaround DMA Burst Size. Wenn beiden USB Ports benutzt werden, geht der USB Host nicht mehr. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.10-r169-non_musb_ar9_vr9-Fix_Spontan_Reboot ++| Erzeugt mit SVN-Tagger Version 3.58. +++----------------------------------------------------------------------+ ++ ++FIX - Endlosschleife führte zu einem spontanen Reboot. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.9-r166-non_musb_ar9_vr9-20101112_deferred_completion ++| Erzeugt mit SVN-Tagger Version 3.58. +++----------------------------------------------------------------------+ ++ ++ENH - Deferred URB Completion Mechanismus eingebaut. Nun ca. 10% schneller bei usb-storage. ++ ++FIX - PING Flow Control gefixt. ++FIX - Channel Halt wird nun immer angerufen. (Split Transaction wurde nicht erfolgreich gestoppt). ++FIX - Spinlock Benutzung verbessert. Mehr Stabilitaet. ++ ++CHG - Ubersetztungsoption __DEBUG__ ist nun abhaengig von CONFIG_USB_DEBUG ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.8-r149-non_musb_ar9_vr9-20100827_LTE_Interrupt_EP_Fix ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++AR9/VR9 - FIX - Interrupt Packets gingen verloren, wegen falschem Timing beim OddFrame Bit. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.7-r142-non_musb_ar9_vr9-20100728_Unaligned_Buf_Fix ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++FIX - "Unaligned Data" Flag wieder nach Transfer geloescht. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.6-r133-non_musb_ar9_vr9-20100714_Toggle_Datenverlust_Fix ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++TL5508 - Einige UMTS Modems funktionierten nicht korrekt an der 7320 (AR9). ++FIX - USB Data Toggle des usbcore benutzen. Datenverlust nach EP-Halt. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.5-r130-non_musb_ar9_vr9-20100712_USB_Ports_abschaltbar ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++Power - Fix - Beide USB Port abschaltbar bei rmmod. ++rmmod - FIX - URB_Dequeue funktionierte beim Entladen des Treibers nicht (mehrere Ursachen). ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.4-r126-non_musb_ar9_vr9-20100701_Lost_Interrupt_Workaround ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++FIX - Workaround wegen verpasstem Interrupt, bei Full-Speed Interrupt EP. ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.3-r123-non_musb_ar9_vr9-20100630_UMTS_Fixes ++| Erzeugt mit SVN-Tagger Version 3.57. +++----------------------------------------------------------------------+ ++FIX - Full-Speed Interrupt Endpoint hinter Hi-Speed Hub funktioniert nun (UMTS Modems) ++FIX - usb_hcd_link_urb_from_ep API von USBCore muss benutzt werden. ++FIX - Interrupt URBs nicht bei NAK completen. ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.2-r114-non_musb_ar9_vr9-20100520_StickAndSurf_funktioniert ++| Erzeugt mit SVN-Tagger Version 3.56. +++----------------------------------------------------------------------+ ++- Merge mit neuen LANTIQ Sourcen "3.0alpha B100312" ++- Fix - Spin_lock eingebaut, Stick&Surf funktioniert nun ++ ++- DEP - CONFIG_USB_HOST_IFX_WITH_ISO wird nicht unterstuetzt: In der Kernel Config deaktivieren. ++ ++ ++ +++----------------------------------------------------------------------+ ++| TAG: svn://EmbeddedVM/home/SVN/drivers/usb_host20/tags/5.1-r107-non_musb_ar9_vr9-20100505_IFXUSB_Host_mit_Energiemonitor ++| Erzeugt mit SVN-Tagger Version 3.56. +++----------------------------------------------------------------------+ ++USB Host Treiber für AR9 und VR9 ++-------------------------------- ++FIX - Toggle Error nach STALL - Einfacher Workaround - Nun werden Massenspeicherpartitionen erkannt! ++AVM_POWERMETER - USB Energiemonitor Support. ++ ++Bekanntes Problem: Stick and Surf funktioniert nur sporadisch, weil CONTROL_IRQ manchmal ausbleibt. ++ +diff --git a/drivers/usb/ifxhcd/ifxhcd.c b/drivers/usb/ifxhcd/ifxhcd.c +new file mode 100644 +index 0000000..d2ae125 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd.c +@@ -0,0 +1,2523 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the structures, constants, and interfaces for ++ ** the Host Contoller Driver (HCD). ++ ** ++ ** The Host Controller Driver (HCD) is responsible for translating requests ++ ** from the USB Driver into the appropriate actions on the IFXUSB controller. ++ ** It isolates the USBD from the specifics of the controller by providing an ++ ** API to the USBD. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxhcd.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the implementation of the HCD. In Linux, ++ the HCD implements the hc_driver API. ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++ ++#include <linux/device.h> ++ ++#include <linux/errno.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/string.h> ++ ++#include <linux/dma-mapping.h> ++ ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++#include "ifxhcd.h" ++ ++#include <asm/irq.h> ++ ++#ifdef CONFIG_AVM_POWERMETER ++#include <linux/avm_power.h> ++#endif /*--- #ifdef CONFIG_AVM_POWERMETER ---*/ ++ ++#ifdef __DEBUG__ ++ static void dump_urb_info(struct urb *_urb, char* _fn_name); ++ static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); ++#endif ++ ++ ++/*! ++ \brief Sets the final status of an URB and returns it to the device driver. Any ++ required cleanup of the URB is performed. ++ */ ++void ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status) ++{ ++ struct urb *urb=NULL; ++ unsigned long flags = 0; ++ ++ /*== AVM/BC 20101111 Function called with Lock ==*/ ++ //SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ if (!list_empty(&_urbd->urbd_list_entry)) ++ list_del_init (&_urbd->urbd_list_entry); ++ ++ if(!_urbd->urb) ++ { ++ IFX_ERROR("%s: invalid urb\n",__func__); ++ /*== AVM/BC 20101111 Function called with Lock ==*/ ++ //SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return; ++ } ++ ++ urb=_urbd->urb; ++ ++ #ifdef __DEBUG__ ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) ++ { ++ IFX_PRINT("%s: _urbd %p, urb %p, device %d, ep %d %s/%s, status=%d\n", ++ __func__, _urbd,_urbd->urb, usb_pipedevice(_urbd->urb->pipe), ++ usb_pipeendpoint(_urbd->urb->pipe), ++ usb_pipein(_urbd->urb->pipe) ? "IN" : "OUT", ++ (_urbd->is_in) ? "IN" : "OUT", ++ _status); ++ if (_urbd->epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ int i; ++ for (i = 0; i < _urbd->urb->number_of_packets; i++) ++ IFX_PRINT(" ISO Desc %d status: %d\n", i, _urbd->urb->iso_frame_desc[i].status); ++ } ++ } ++ #endif ++ ++ if (!_urbd->epqh) ++ IFX_ERROR("%s: invalid epqd\n",__func__); ++ ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ else if(_urbd->is_active) ++ { ++ if( _urbd->epqh->aligned_checked && ++ _urbd->epqh->using_aligned_buf && ++ _urbd->xfer_buff && ++ _urbd->is_in ) ++ memcpy(_urbd->xfer_buff,_urbd->epqh->aligned_buf,_urbd->xfer_len); ++ _urbd->epqh->using_aligned_buf=0; ++ _urbd->epqh->using_aligned_setup=0; ++ _urbd->epqh->aligned_checked=0; ++ } ++ #endif ++ ++ urb->status = _status; ++ urb->hcpriv=NULL; ++ kfree(_urbd); ++ ++ usb_hcd_unlink_urb_from_ep(ifxhcd_to_syshcd(_ifxhcd), urb); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ ++// usb_hcd_giveback_urb(ifxhcd_to_syshcd(_ifxhcd), urb); ++ usb_hcd_giveback_urb(ifxhcd_to_syshcd(_ifxhcd), urb, _status); ++ ++ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++} ++ ++/*== AVM/BC 20101111 URB Complete deferred ++ * Must be called with Spinlock ++ */ ++ ++/*! ++ \brief Inserts an urbd structur in the completion list. The urbd will be ++ later completed by select_eps_sub ++ */ ++void defer_ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status) ++{ ++ ++ _urbd->status = _status; ++ ++ //Unlink Urbd from epqh / Insert it into the complete list ++ list_move_tail(&_urbd->urbd_list_entry, &_ifxhcd->urbd_complete_list); ++ ++} ++ ++/*! ++ \brief Processes all the URBs in a single EPQHs. Completes them with ++ status and frees the URBD. ++ */ ++//static ++void kill_all_urbs_in_epqh(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh, int _status) ++{ ++ struct list_head *urbd_item; ++ ifxhcd_urbd_t *urbd; ++ ++ if(!_epqh) ++ return; ++ ++ for (urbd_item = _epqh->urbd_list.next; ++ urbd_item != &_epqh->urbd_list; ++ urbd_item = _epqh->urbd_list.next) ++ { ++ urbd = list_entry(urbd_item, ifxhcd_urbd_t, urbd_list_entry); ++ ifxhcd_complete_urb(_ifxhcd, urbd, _status); ++ } ++} ++ ++ ++/*! ++ \brief Free all EPS in one Processes all the URBs in a single list of EPQHs. Completes them with ++ -ETIMEDOUT and frees the URBD. ++ */ ++//static ++void epqh_list_free(ifxhcd_hcd_t *_ifxhcd, struct list_head *_epqh_list) ++{ ++ struct list_head *item; ++ ifxhcd_epqh_t *epqh; ++ ++ if (!_epqh_list) ++ return; ++ if (_epqh_list->next == NULL) /* The list hasn't been initialized yet. */ ++ return; ++ ++ /* Ensure there are no URBDs or URBs left. */ ++ for (item = _epqh_list->next; item != _epqh_list; item = _epqh_list->next) ++ { ++ epqh = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ kill_all_urbs_in_epqh(_ifxhcd, epqh, -ETIMEDOUT); ++ ifxhcd_epqh_free(epqh); ++ } ++} ++ ++ ++ ++//static ++void epqh_list_free_all(ifxhcd_hcd_t *_ifxhcd) ++{ ++ unsigned long flags; ++ ++ /*== AVM/BC 20101111 - 2.6.28 Needs Spinlock ==*/ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_np_active ); ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_np_ready ); ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_intr_active ); ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_intr_ready ); ++ #ifdef __EN_ISOC__ ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_isoc_active ); ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_isoc_ready ); ++ #endif ++ epqh_list_free(_ifxhcd, &_ifxhcd->epqh_stdby ); ++ ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ ++} ++ ++ ++/*! ++ \brief This function is called to handle the disconnection of host port. ++ */ ++int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd) ++{ ++ IFX_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _ifxhcd); ++ ++ /* Set status flags for the hub driver. */ ++ _ifxhcd->flags.b.port_connect_status_change = 1; ++ _ifxhcd->flags.b.port_connect_status = 0; ++ ++ /* ++ * Shutdown any transfers in process by clearing the Tx FIFO Empty ++ * interrupt mask and status bits and disabling subsequent host ++ * channel interrupts. ++ */ ++ { ++ gint_data_t intr = { .d32 = 0 }; ++ intr.b.nptxfempty = 1; ++ intr.b.ptxfempty = 1; ++ intr.b.hcintr = 1; ++ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintmsk, intr.d32, 0); ++ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintsts, intr.d32, 0); ++ } ++ ++ /* Respond with an error status to all URBs in the schedule. */ ++ epqh_list_free_all(_ifxhcd); ++ ++ /* Clean up any host channels that were in use. */ ++ { ++ int num_channels; ++ ifxhcd_hc_t *channel; ++ ifxusb_hc_regs_t *hc_regs; ++ hcchar_data_t hcchar; ++ int i; ++ ++ num_channels = _ifxhcd->core_if.params.host_channels; ++ ++ for (i = 0; i < num_channels; i++) ++ { ++ channel = &_ifxhcd->ifxhc[i]; ++ if (list_empty(&channel->hc_list_entry)) ++ { ++ hc_regs = _ifxhcd->core_if.hc_regs[i]; ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen) ++ { ++ /* Halt the channel. */ ++ hcchar.b.chdis = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ } ++ list_add_tail(&channel->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, channel); ++ } ++ } ++ } ++ return 1; ++} ++ ++ ++/*! ++ \brief Frees secondary storage associated with the ifxhcd_hcd structure contained ++ in the struct usb_hcd field. ++ */ ++static void ifxhcd_freeextra(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ ++ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD FREE\n"); ++ ++ /* Free memory for EPQH/URBD lists */ ++ epqh_list_free_all(ifxhcd); ++ ++ /* Free memory for the host channels. */ ++ ifxusb_free_buf(ifxhcd->status_buf); ++ return; ++} ++#ifdef __USE_TIMER_4_SOF__ ++static enum hrtimer_restart ifxhcd_timer_func(struct hrtimer *timer) { ++ ifxhcd_hcd_t *ifxhcd = container_of(timer, ifxhcd_hcd_t, hr_timer); ++ ++ ifxhcd_handle_intr(ifxhcd); ++ ++ return HRTIMER_NORESTART; ++} ++#endif ++ ++/*! ++ \brief Initializes the HCD. This function allocates memory for and initializes the ++ static parts of the usb_hcd and ifxhcd_hcd structures. It also registers the ++ USB bus with the core and calls the hc_driver->start() function. It returns ++ a negative error on failure. ++ */ ++int ifxhcd_init(ifxhcd_hcd_t *_ifxhcd) ++{ ++ int retval = 0; ++ struct usb_hcd *syshcd = NULL; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD INIT\n"); ++ ++ spin_lock_init(&_ifxhcd->lock); ++#ifdef __USE_TIMER_4_SOF__ ++ hrtimer_init(&_ifxhcd->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ _ifxhcd->hr_timer.function = ifxhcd_timer_func; ++#endif ++ _ifxhcd->hc_driver.description = _ifxhcd->core_if.core_name; ++ _ifxhcd->hc_driver.product_desc = "IFX USB Controller"; ++ //_ifxhcd->hc_driver.hcd_priv_size = sizeof(ifxhcd_hcd_t); ++ _ifxhcd->hc_driver.hcd_priv_size = sizeof(unsigned long); ++ _ifxhcd->hc_driver.irq = ifxhcd_irq; ++ _ifxhcd->hc_driver.flags = HCD_MEMORY | HCD_USB2; ++ _ifxhcd->hc_driver.start = ifxhcd_start; ++ _ifxhcd->hc_driver.stop = ifxhcd_stop; ++ //_ifxhcd->hc_driver.reset = ++ //_ifxhcd->hc_driver.suspend = ++ //_ifxhcd->hc_driver.resume = ++ _ifxhcd->hc_driver.urb_enqueue = ifxhcd_urb_enqueue; ++ _ifxhcd->hc_driver.urb_dequeue = ifxhcd_urb_dequeue; ++ _ifxhcd->hc_driver.endpoint_disable = ifxhcd_endpoint_disable; ++ _ifxhcd->hc_driver.get_frame_number = ifxhcd_get_frame_number; ++ _ifxhcd->hc_driver.hub_status_data = ifxhcd_hub_status_data; ++ _ifxhcd->hc_driver.hub_control = ifxhcd_hub_control; ++ //_ifxhcd->hc_driver.hub_suspend = ++ //_ifxhcd->hc_driver.hub_resume = ++ ++ /* Allocate memory for and initialize the base HCD and */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) ++ syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->core_if.core_name); ++#else ++ syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->dev->bus_id); ++#endif ++ ++ if (syshcd == NULL) ++ { ++ retval = -ENOMEM; ++ goto error1; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) ++ syshcd->has_tt = 1; ++#endif ++ ++ syshcd->rsrc_start = (unsigned long)_ifxhcd->core_if.core_global_regs; ++ syshcd->regs = (void *)_ifxhcd->core_if.core_global_regs; ++ syshcd->self.otg_port = 0; ++ ++ //*((unsigned long *)(&(syshcd->hcd_priv)))=(unsigned long)_ifxhcd; ++ //*((unsigned long *)(&(syshcd->hcd_priv[0])))=(unsigned long)_ifxhcd; ++ syshcd->hcd_priv[0]=(unsigned long)_ifxhcd; ++ _ifxhcd->syshcd=syshcd; ++ ++ INIT_LIST_HEAD(&_ifxhcd->epqh_np_active ); ++ INIT_LIST_HEAD(&_ifxhcd->epqh_np_ready ); ++ INIT_LIST_HEAD(&_ifxhcd->epqh_intr_active ); ++ INIT_LIST_HEAD(&_ifxhcd->epqh_intr_ready ); ++ #ifdef __EN_ISOC__ ++ INIT_LIST_HEAD(&_ifxhcd->epqh_isoc_active ); ++ INIT_LIST_HEAD(&_ifxhcd->epqh_isoc_ready ); ++ #endif ++ INIT_LIST_HEAD(&_ifxhcd->epqh_stdby ); ++ INIT_LIST_HEAD(&_ifxhcd->urbd_complete_list); ++ ++ /* ++ * Create a host channel descriptor for each host channel implemented ++ * in the controller. Initialize the channel descriptor array. ++ */ ++ INIT_LIST_HEAD(&_ifxhcd->free_hc_list); ++ { ++ int num_channels = _ifxhcd->core_if.params.host_channels; ++ int i; ++ for (i = 0; i < num_channels; i++) ++ { ++ _ifxhcd->ifxhc[i].hc_num = i; ++ IFX_DEBUGPL(DBG_HCDV, "HCD Added channel #%d\n", i); ++ } ++ } ++ ++ /* Set device flags indicating whether the HCD supports DMA. */ ++ if(_ifxhcd->dev->dma_mask) ++ *(_ifxhcd->dev->dma_mask) = ~0; ++ _ifxhcd->dev->coherent_dma_mask = ~0; ++ ++ /* ++ * Finish generic HCD initialization and start the HCD. This function ++ * allocates the DMA buffer pool, registers the USB bus, requests the ++ * IRQ line, and calls ifxusb_hcd_start method. ++ */ ++// retval = usb_add_hcd(syshcd, _ifxhcd->core_if.irq, SA_INTERRUPT|SA_SHIRQ); ++ retval = usb_add_hcd(syshcd, _ifxhcd->core_if.irq, IRQF_DISABLED | IRQF_SHARED ); ++ if (retval < 0) ++ goto error2; ++ ++ /* ++ * Allocate space for storing data on status transactions. Normally no ++ * data is sent, but this space acts as a bit bucket. This must be ++ * done after usb_add_hcd since that function allocates the DMA buffer ++ * pool. ++ */ ++ _ifxhcd->status_buf = ifxusb_alloc_buf(IFXHCD_STATUS_BUF_SIZE, 1); ++ ++ if (_ifxhcd->status_buf) ++ { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Initialized, bus=%s, usbbus=%d\n", _ifxhcd->core_if.core_name, syshcd->self.busnum); ++#else ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Initialized, bus=%s, usbbus=%d\n", _ifxhcd->dev->bus_id, syshcd->self.busnum); ++#endif ++ return 0; ++ } ++ IFX_ERROR("%s: status_buf allocation failed\n", __func__); ++ ++ /* Error conditions */ ++ usb_remove_hcd(syshcd); ++error2: ++ ifxhcd_freeextra(syshcd); ++ usb_put_hcd(syshcd); ++error1: ++ return retval; ++} ++ ++/*! ++ \brief Removes the HCD. ++ Frees memory and resources associated with the HCD and deregisters the bus. ++ */ ++void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd) ++{ ++ struct usb_hcd *syshcd = ifxhcd_to_syshcd(_ifxhcd); ++ ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD REMOVE\n"); ++ ++/* == AVM/WK 20100709 - Fix: Order changed, disable IRQs not before remove_hcd == */ ++ ++ usb_remove_hcd(syshcd); ++ ++ /* Turn off all interrupts */ ++ ifxusb_wreg (&_ifxhcd->core_if.core_global_regs->gintmsk, 0); ++ ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gahbcfg, 1, 0); ++ ++ ifxhcd_freeextra(syshcd); ++ ++ usb_put_hcd(syshcd); ++ ++ return; ++} ++ ++ ++/* ========================================================================= ++ * Linux HC Driver Functions ++ * ========================================================================= */ ++ ++/*! ++ \brief Initializes the IFXUSB controller and its root hub and prepares it for host ++ mode operation. Activates the root port. Returns 0 on success and a negative ++ error code on failure. ++ Called by USB stack. ++ */ ++int ifxhcd_start(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ ifxusb_core_if_t *core_if = &ifxhcd->core_if; ++ struct usb_bus *bus; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD START\n"); ++ ++ bus = hcd_to_bus(_syshcd); ++ ++ /* Initialize the bus state. */ ++ _syshcd->state = HC_STATE_RUNNING; ++ ++ /* Initialize and connect root hub if one is not already attached */ ++ if (bus->root_hub) ++ { ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Has Root Hub\n"); ++ /* Inform the HUB driver to resume. */ ++ usb_hcd_resume_root_hub(_syshcd); ++ } ++ ++ ifxhcd->flags.d32 = 0; ++ ++ /* Put all channels in the free channel list and clean up channel states.*/ ++ { ++ struct list_head *item; ++ item = ifxhcd->free_hc_list.next; ++ while (item != &ifxhcd->free_hc_list) ++ { ++ list_del(item); ++ item = ifxhcd->free_hc_list.next; ++ } ++ } ++ { ++ int num_channels = ifxhcd->core_if.params.host_channels; ++ int i; ++ for (i = 0; i < num_channels; i++) ++ { ++ ifxhcd_hc_t *channel; ++ channel = &ifxhcd->ifxhc[i]; ++ list_add_tail(&channel->hc_list_entry, &ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&ifxhcd->core_if, channel); ++ } ++ } ++ /* Initialize the USB core for host mode operation. */ ++ ++ ifxusb_host_enable_interrupts(core_if); ++ ifxusb_enable_global_interrupts(core_if); ++ ifxusb_phy_power_on (core_if); ++ ++ ifxusb_vbus_init(core_if); ++ ++ /* Turn on the vbus power. */ ++ { ++ hprt0_data_t hprt0; ++ hprt0.d32 = ifxusb_read_hprt0(core_if); ++ ++ IFX_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr); ++ if (hprt0.b.prtpwr == 0 ) ++ { ++ hprt0.b.prtpwr = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ ifxusb_vbus_on(core_if); ++ } ++ } ++ return 0; ++} ++ ++ ++/*! ++ \brief Halts the IFXUSB host mode operations in a clean manner. USB transfers are ++ stopped. ++ */ ++void ifxhcd_stop(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ hprt0_data_t hprt0 = { .d32=0 }; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFX USB HCD STOP\n"); ++ ++ /* Turn off all interrupts. */ ++ ifxusb_disable_global_interrupts(&ifxhcd->core_if ); ++ ifxusb_host_disable_interrupts(&ifxhcd->core_if ); ++#ifdef __USE_TIMER_4_SOF__ ++ hrtimer_cancel(&ifxhcd->hr_timer); ++#endif ++ /* ++ * The root hub should be disconnected before this function is called. ++ * The disconnect will clear the URBD lists (via ..._hcd_urb_dequeue) ++ * and the EPQH lists (via ..._hcd_endpoint_disable). ++ */ ++ ++ /* Turn off the vbus power */ ++ IFX_PRINT("PortPower off\n"); ++ ++ ifxusb_vbus_off(&ifxhcd->core_if ); ++ ++ ifxusb_vbus_free(&ifxhcd->core_if ); ++ ++ hprt0.b.prtpwr = 0; ++ ifxusb_wreg(ifxhcd->core_if.hprt0, hprt0.d32); ++ return; ++} ++ ++/*! ++ \brief Returns the current frame number ++ */ ++int ifxhcd_get_frame_number(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ hfnum_data_t hfnum; ++ ++ hfnum.d32 = ifxusb_rreg(&ifxhcd->core_if.host_global_regs->hfnum); ++ ++ return hfnum.b.frnum; ++} ++ ++/*! ++ \brief Starts processing a USB transfer request specified by a USB Request Block ++ (URB). mem_flags indicates the type of memory allocation to use while ++ processing this URB. ++ */ ++int ifxhcd_urb_enqueue( struct usb_hcd *_syshcd, ++ /*--- struct usb_host_endpoint *_sysep, Parameter im 2.6.28 entfallen ---*/ ++ struct urb *_urb, ++ gfp_t _mem_flags) ++{ ++ int retval = 0; ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ struct usb_host_endpoint *_sysep = ifxhcd_urb_to_endpoint(_urb); ++ ifxhcd_epqh_t *epqh; ++ ++ #ifdef __DEBUG__ ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) ++ dump_urb_info(_urb, "ifxusb_hcd_urb_enqueue"); ++ #endif //__DEBUG__ ++ ++ if (!ifxhcd->flags.b.port_connect_status) /* No longer connected. */ ++ return -ENODEV; ++ ++ #ifndef __EN_ISOC__ ++ if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) ++ { ++ IFX_ERROR("ISOC transfer not supported!!!\n"); ++ return -ENODEV; ++ } ++ #endif ++ ++ retval=ifxhcd_urbd_create (ifxhcd,_urb); ++ ++ if (retval) ++ { ++ IFX_ERROR("IFXUSB HCD URB Enqueue failed creating URBD\n"); ++ return retval; ++ } ++ epqh = (ifxhcd_epqh_t *) _sysep->hcpriv; ++ ifxhcd_epqh_ready(ifxhcd, epqh); ++ ++ select_eps(ifxhcd); ++ //enable_sof(ifxhcd); ++ { ++ gint_data_t gintsts; ++ gintsts.d32=0; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&ifxhcd->core_if.core_global_regs->gintmsk, 0,gintsts.d32); ++ } ++ ++ return retval; ++} ++ ++/*! ++ \brief Aborts/cancels a USB transfer request. Always returns 0 to indicate ++ success. ++ */ ++int ifxhcd_urb_dequeue( struct usb_hcd *_syshcd, ++ struct urb *_urb, int status /* Parameter neu in 2.6.28 */) ++{ ++ unsigned long flags; ++ ifxhcd_hcd_t *ifxhcd; ++ ifxhcd_urbd_t *urbd; ++ ifxhcd_epqh_t *epqh; ++ int is_active=0; ++ int rc; ++ ++ struct usb_host_endpoint *_sysep; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD URB Dequeue\n"); ++ ++ #ifndef __EN_ISOC__ ++ if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) ++ return 0; ++ #endif ++ ++ _sysep = ifxhcd_urb_to_endpoint(_urb); ++ ++ ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ ++ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); ++ ++ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ ++ rc = usb_hcd_check_unlink_urb(_syshcd, _urb, status); ++ if (rc) { ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ return rc; ++ } ++ ++ urbd = (ifxhcd_urbd_t *) _urb->hcpriv; ++ ++ if(_sysep) ++ epqh = (ifxhcd_epqh_t *) _sysep->hcpriv; ++ else ++ epqh = (ifxhcd_epqh_t *) urbd->epqh; ++ ++ if(epqh!=urbd->epqh) ++ IFX_ERROR("%s inconsistant epqh %p %p\n",__func__,epqh,urbd->epqh); ++ ++ #ifdef __DEBUG__ ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) ++ { ++ dump_urb_info(_urb, "ifxhcd_urb_dequeue"); ++ if (epqh->is_active) ++ dump_channel_info(ifxhcd, epqh); ++ } ++ #endif //__DEBUG__ ++ ++ if(!epqh->hc) ++ epqh->is_active=0; ++ else if (!ifxhcd->flags.b.port_connect_status) ++ epqh->is_active=0; ++ else if (epqh->is_active && urbd->is_active) ++ { ++ /*== AVM/WK 20100709 - halt channel only if really started ==*/ ++ //if (epqh->hc->xfer_started && !epqh->hc->wait_for_sof) { ++ /*== AVM/WK 20101112 - halt channel if started ==*/ ++ if (epqh->hc->xfer_started) { ++ /* ++ * If still connected (i.e. in host mode), halt the ++ * channel so it can be used for other transfers. If ++ * no longer connected, the host registers can't be ++ * written to halt the channel since the core is in ++ * device mode. ++ */ ++ /* == 20110803 AVM/WK FIX propagate status == */ ++ if (_urb->status == -EINPROGRESS) { ++ _urb->status = status; ++ } ++ ifxhcd_hc_halt(&ifxhcd->core_if, epqh->hc, HC_XFER_URB_DEQUEUE); ++ epqh->hc = NULL; ++ is_active=1; ++ } ++ } ++ ++ if(is_active) ++ { ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ } ++ else ++ { ++ list_del_init(&urbd->urbd_list_entry); ++ kfree (urbd); ++ ++ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ ++ usb_hcd_unlink_urb_from_ep(_syshcd, _urb); ++ ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ _urb->hcpriv = NULL; ++// usb_hcd_giveback_urb(_syshcd, _urb); ++ usb_hcd_giveback_urb(_syshcd, _urb, status /* neu in 2.6.28 */); ++ select_eps(ifxhcd); ++ } ++ ++ return 0; ++} ++ ++ ++ ++/*! ++ \brief Frees resources in the IFXUSB controller related to a given endpoint. Also ++ clears state in the HCD related to the endpoint. Any URBs for the endpoint ++ must already be dequeued. ++ */ ++void ifxhcd_endpoint_disable( struct usb_hcd *_syshcd, ++ struct usb_host_endpoint *_sysep) ++{ ++ ifxhcd_epqh_t *epqh; ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); ++ unsigned long flags; ++ ++ int retry = 0; ++ ++ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD EP DISABLE: _bEndpointAddress=0x%02x, " ++ "endpoint=%d\n", _sysep->desc.bEndpointAddress, ++ ifxhcd_ep_addr_to_endpoint(_sysep->desc.bEndpointAddress)); ++ ++ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); ++ if((uint32_t)_sysep>=0x80000000 && (uint32_t)_sysep->hcpriv>=(uint32_t)0x80000000) ++ { ++ epqh = (ifxhcd_epqh_t *)(_sysep->hcpriv); ++ if (epqh && epqh->sysep==_sysep) ++ { ++ ++#if 1 /*== AVM/BC 20101111 CHG Option active: Kill URBs when disabling EP ==*/ ++ while (!list_empty(&epqh->urbd_list)) ++ { ++ if (retry++ > 250) ++ { ++ IFX_WARN("IFXUSB HCD EP DISABLE:" ++ " URBD List for this endpoint is not empty\n"); ++ break; ++ } ++ kill_all_urbs_in_epqh(ifxhcd, epqh, -ETIMEDOUT); ++ } ++#else ++ while (!list_empty(&epqh->urbd_list)) ++ { ++ /** Check that the QTD list is really empty */ ++ if (retry++ > 250) ++ { ++ IFX_WARN("IFXUSB HCD EP DISABLE:" ++ " URBD List for this endpoint is not empty\n"); ++ break; ++ } ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ schedule_timeout_uninterruptible(1); ++ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); ++ } ++#endif ++ ++ ifxhcd_epqh_free(epqh); ++ _sysep->hcpriv = NULL; ++ } ++ } ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++} ++ ++ ++/*! ++ \brief Handles host mode interrupts for the IFXUSB controller. Returns IRQ_NONE if ++ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid ++ * interrupt. ++ * ++ * This function is called by the USB core when an interrupt occurs ++ */ ++irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ int32_t retval=0; ++ ++ //mask_and_ack_ifx_irq (ifxhcd->core_if.irq); ++ retval = ifxhcd_handle_intr(ifxhcd); ++ return IRQ_RETVAL(retval); ++} ++ ++ ++/*! ++ \brief Handles host mode Over Current Interrupt ++ */ ++irqreturn_t ifxhcd_oc_irq(int _irq , void *_dev) ++{ ++ ifxhcd_hcd_t *ifxhcd = _dev; ++ int32_t retval=1; ++ ++ ifxhcd->flags.b.port_over_current_change = 1; ++ ifxusb_vbus_off(&ifxhcd->core_if); ++ IFX_DEBUGP("OC INTERRUPT # %d\n",ifxhcd->core_if.core_no); ++ ++ //mask_and_ack_ifx_irq (_irq); ++ return IRQ_RETVAL(retval); ++} ++ ++/*! ++ \brief Creates Status Change bitmap for the root hub and root port. The bitmap is ++ returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 ++ is the status change indicator for the single root port. Returns 1 if either ++ change indicator is 1, otherwise returns 0. ++ */ ++int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf) ++{ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ ++ _buf[0] = 0; ++ _buf[0] |= (ifxhcd->flags.b.port_connect_status_change || ++ ifxhcd->flags.b.port_reset_change || ++ ifxhcd->flags.b.port_enable_change || ++ ifxhcd->flags.b.port_suspend_change || ++ ifxhcd->flags.b.port_over_current_change) << 1; ++ ++ #ifdef __DEBUG__ ++ if (_buf[0]) ++ { ++ IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD HUB STATUS DATA:" ++ " Root port status changed\n"); ++ IFX_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", ++ ifxhcd->flags.b.port_connect_status_change); ++ IFX_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", ++ ifxhcd->flags.b.port_reset_change); ++ IFX_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", ++ ifxhcd->flags.b.port_enable_change); ++ IFX_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", ++ ifxhcd->flags.b.port_suspend_change); ++ IFX_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", ++ ifxhcd->flags.b.port_over_current_change); ++ } ++ #endif //__DEBUG__ ++ return (_buf[0] != 0); ++} ++ ++#ifdef __WITH_HS_ELECT_TST__ ++ extern void do_setup(ifxusb_core_if_t *_core_if) ; ++ extern void do_in_ack(ifxusb_core_if_t *_core_if); ++#endif //__WITH_HS_ELECT_TST__ ++ ++/*! ++ \brief Handles hub class-specific requests. ++ */ ++int ifxhcd_hub_control( struct usb_hcd *_syshcd, ++ u16 _typeReq, ++ u16 _wValue, ++ u16 _wIndex, ++ char *_buf, ++ u16 _wLength) ++{ ++ int retval = 0; ++ ++ ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); ++ ifxusb_core_if_t *core_if = &ifxhcd->core_if; ++ struct usb_hub_descriptor *desc; ++ hprt0_data_t hprt0 = {.d32 = 0}; ++ ++ uint32_t port_status; ++ ++ switch (_typeReq) ++ { ++ case ClearHubFeature: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearHubFeature 0x%x\n", _wValue); ++ switch (_wValue) ++ { ++ case C_HUB_LOCAL_POWER: ++ case C_HUB_OVER_CURRENT: ++ /* Nothing required here */ ++ break; ++ default: ++ retval = -EINVAL; ++ IFX_ERROR ("IFXUSB HCD - " ++ "ClearHubFeature request %xh unknown\n", _wValue); ++ } ++ break; ++ case ClearPortFeature: ++ if (!_wIndex || _wIndex > 1) ++ goto error; ++ ++ switch (_wValue) ++ { ++ case USB_PORT_FEAT_ENABLE: ++ IFX_DEBUGPL (DBG_ANY, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtena = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_SUSPEND: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtres = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ /* Clear Resume bit */ ++ mdelay (100); ++ hprt0.b.prtres = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_POWER: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_POWER\n"); ++ #ifdef __IS_DUAL__ ++ ifxusb_vbus_off(core_if); ++ #else ++ ifxusb_vbus_off(core_if); ++ #endif ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtpwr = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_INDICATOR: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); ++ /* Port inidicator not supported */ ++ break; ++ case USB_PORT_FEAT_C_CONNECTION: ++ /* Clears drivers internal connect status change ++ * flag */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); ++ ifxhcd->flags.b.port_connect_status_change = 0; ++ break; ++ case USB_PORT_FEAT_C_RESET: ++ /* Clears the driver's internal Port Reset Change ++ * flag */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); ++ ifxhcd->flags.b.port_reset_change = 0; ++ break; ++ case USB_PORT_FEAT_C_ENABLE: ++ /* Clears the driver's internal Port ++ * Enable/Disable Change flag */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); ++ ifxhcd->flags.b.port_enable_change = 0; ++ break; ++ case USB_PORT_FEAT_C_SUSPEND: ++ /* Clears the driver's internal Port Suspend ++ * Change flag, which is set when resume signaling on ++ * the host port is complete */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); ++ ifxhcd->flags.b.port_suspend_change = 0; ++ break; ++ case USB_PORT_FEAT_C_OVER_CURRENT: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); ++ ifxhcd->flags.b.port_over_current_change = 0; ++ break; ++ default: ++ retval = -EINVAL; ++ IFX_ERROR ("IFXUSB HCD - " ++ "ClearPortFeature request %xh " ++ "unknown or unsupported\n", _wValue); ++ } ++ break; ++ case GetHubDescriptor: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "GetHubDescriptor\n"); ++ desc = (struct usb_hub_descriptor *)_buf; ++ desc->bDescLength = 9; ++ desc->bDescriptorType = 0x29; ++ desc->bNbrPorts = 1; ++ desc->wHubCharacteristics = 0x08; ++ desc->bPwrOn2PwrGood = 1; ++ desc->bHubContrCurrent = 0; ++// desc->bitmap[0] = 0; ++// desc->bitmap[1] = 0xff; ++ break; ++ case GetHubStatus: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "GetHubStatus\n"); ++ memset (_buf, 0, 4); ++ break; ++ case GetPortStatus: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "GetPortStatus\n"); ++ if (!_wIndex || _wIndex > 1) ++ goto error; ++ ++# ifdef CONFIG_AVM_POWERMETER ++ { ++ /* first port only, but 2 Hosts */ ++ static unsigned char ucOldPower1 = 255; ++ static unsigned char ucOldPower2 = 255; ++ ++ unsigned char ucNewPower = 0; ++ struct usb_device *childdev = _syshcd->self.root_hub->children[0]; ++ ++ if (childdev != NULL) { ++ ucNewPower = (childdev->actconfig != NULL) ++ ? childdev->actconfig->desc.bMaxPower ++ : 50;/* default: 50 means 100 mA*/ ++ } ++ if (_syshcd->self.busnum == 1) { ++ if (ucOldPower1 != ucNewPower) { ++ ucOldPower1 = ucNewPower; ++ printk (KERN_INFO "IFXHCD#1: AVM Powermeter changed to %u mA\n", ucNewPower*2); ++ PowerManagmentRessourceInfo(powerdevice_usb_host, ucNewPower*2); ++ } ++ } else { ++ if (ucOldPower2 != ucNewPower) { ++ ucOldPower2 = ucNewPower; ++ printk (KERN_INFO "IFXHCD#2: AVM Powermeter changed to %u mA\n", ucNewPower*2); ++ PowerManagmentRessourceInfo(powerdevice_usb_host2, ucNewPower*2); ++ } ++ } ++ } ++# endif /*--- #ifdef CONFIG_AVM_POWERMETER ---*/ ++ ++ port_status = 0; ++ if (ifxhcd->flags.b.port_connect_status_change) ++ port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); ++ if (ifxhcd->flags.b.port_enable_change) ++ port_status |= (1 << USB_PORT_FEAT_C_ENABLE); ++ if (ifxhcd->flags.b.port_suspend_change) ++ port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); ++ if (ifxhcd->flags.b.port_reset_change) ++ port_status |= (1 << USB_PORT_FEAT_C_RESET); ++ if (ifxhcd->flags.b.port_over_current_change) ++ { ++ IFX_ERROR("Device Not Supported\n"); ++ port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT); ++ } ++ if (!ifxhcd->flags.b.port_connect_status) ++ { ++ /* ++ * The port is disconnected, which means the core is ++ * either in device mode or it soon will be. Just ++ * return 0's for the remainder of the port status ++ * since the port register can't be read if the core ++ * is in device mode. ++ */ ++ *((u32 *) _buf) = cpu_to_le32(port_status); ++ break; ++ } ++ ++ hprt0.d32 = ifxusb_rreg(core_if->hprt0); ++ IFX_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32); ++ if (hprt0.b.prtconnsts) ++ port_status |= (1 << USB_PORT_FEAT_CONNECTION); ++ if (hprt0.b.prtena) ++ port_status |= (1 << USB_PORT_FEAT_ENABLE); ++ if (hprt0.b.prtsusp) ++ port_status |= (1 << USB_PORT_FEAT_SUSPEND); ++ if (hprt0.b.prtovrcurract) ++ port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT); ++ if (hprt0.b.prtrst) ++ port_status |= (1 << USB_PORT_FEAT_RESET); ++ if (hprt0.b.prtpwr) ++ port_status |= (1 << USB_PORT_FEAT_POWER); ++/* if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) ++ port_status |= (1 << USB_PORT_FEAT_HIGHSPEED); ++ else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) ++ port_status |= (1 << USB_PORT_FEAT_LOWSPEED);*/ ++ if (hprt0.b.prttstctl) ++ port_status |= (1 << USB_PORT_FEAT_TEST); ++ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */ ++ *((u32 *) _buf) = cpu_to_le32(port_status); ++ break; ++ case SetHubFeature: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetHubFeature\n"); ++ /* No HUB features supported */ ++ break; ++ case SetPortFeature: ++ if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1)) ++ goto error; ++ /* ++ * The port is disconnected, which means the core is ++ * either in device mode or it soon will be. Just ++ * return without doing anything since the port ++ * register can't be written if the core is in device ++ * mode. ++ */ ++ if (!ifxhcd->flags.b.port_connect_status) ++ break; ++ switch (_wValue) ++ { ++ case USB_PORT_FEAT_SUSPEND: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ //IFX_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32); ++ /* Suspend the Phy Clock */ ++ { ++ pcgcctl_data_t pcgcctl = {.d32=0}; ++ pcgcctl.b.stoppclk = 1; ++ ifxusb_wreg(core_if->pcgcctl, pcgcctl.d32); ++ } ++ break; ++ case USB_PORT_FEAT_POWER: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_POWER\n"); ++ ifxusb_vbus_on (core_if); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtpwr = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_RESET: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_RESET\n"); ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtrst = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ ++ MDELAY (60); ++ hprt0.b.prtrst = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ break; ++ #ifdef __WITH_HS_ELECT_TST__ ++ case USB_PORT_FEAT_TEST: ++ { ++ uint32_t t; ++ gint_data_t gintmsk; ++ t = (_wIndex >> 8); /* MSB wIndex USB */ ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t); ++ warn("USB_PORT_FEAT_TEST %d\n", t); ++ if (t < 6) ++ { ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prttstctl = t; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ } ++ else if (t == 6) /* HS_HOST_PORT_SUSPEND_RESUME */ ++ { ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Drive suspend on the root port */ ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 1; ++ hprt0.b.prtres = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Drive resume on the root port */ ++ hprt0.d32 = ifxusb_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 0; ++ hprt0.b.prtres = 1; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ mdelay(100); ++ ++ /* Clear the resume bit */ ++ hprt0.b.prtres = 0; ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ ++ /* Restore interrupts */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); ++ } ++ else if (t == 7) /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ ++ { ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Send the Setup packet */ ++ do_setup(core_if); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Restore interrupts */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); ++ } ++ ++ else if (t == 8) /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ ++ { ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); ++ ++ /* Send the Setup packet */ ++ do_setup(core_if); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Send the In and Ack packets */ ++ do_in_ack(core_if); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Restore interrupts */ ++ ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); ++ } ++ } ++ break; ++ #endif //__WITH_HS_ELECT_TST__ ++ case USB_PORT_FEAT_INDICATOR: ++ IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); ++ /* Not supported */ ++ break; ++ default: ++ retval = -EINVAL; ++ IFX_ERROR ("IFXUSB HCD - " ++ "SetPortFeature request %xh " ++ "unknown or unsupported\n", _wValue); ++ } ++ break; ++ default: ++ error: ++ retval = -EINVAL; ++ IFX_WARN ("IFXUSB HCD - " ++ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", ++ _typeReq, _wIndex, _wValue); ++ } ++ return retval; ++} ++ ++ ++/*! ++ \brief Assigns transactions from a URBD to a free host channel and initializes the ++ host channel to perform the transactions. The host channel is removed from ++ the free list. ++ \param _ifxhcd The HCD state structure. ++ \param _epqh Transactions from the first URBD for this EPQH are selected and assigned to a free host channel. ++ */ ++static int assign_and_init_hc(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++{ ++ ifxhcd_hc_t *ifxhc; ++ ifxhcd_urbd_t *urbd; ++ struct urb *urb; ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _ifxhcd, _epqh); ++ ++ if(list_empty(&_epqh->urbd_list)) ++ return 0; ++ ++ ifxhc = list_entry(_ifxhcd->free_hc_list.next, ifxhcd_hc_t, hc_list_entry); ++ /* Remove the host channel from the free list. */ ++ list_del_init(&ifxhc->hc_list_entry); ++ ++ urbd = list_entry(_epqh->urbd_list.next, ifxhcd_urbd_t, urbd_list_entry); ++ urb = urbd->urb; ++ ++ _epqh->hc = ifxhc; ++ _epqh->urbd = urbd; ++ ifxhc->epqh = _epqh; ++ ++ urbd->is_active=1; ++ ++ /* ++ * Use usb_pipedevice to determine device address. This address is ++ * 0 before the SET_ADDRESS command and the correct address afterward. ++ */ ++ ifxhc->dev_addr = usb_pipedevice(urb->pipe); ++ ifxhc->ep_num = usb_pipeendpoint(urb->pipe); ++ ++ ifxhc->xfer_started = 0; ++ ++ if (urb->dev->speed == USB_SPEED_LOW) ifxhc->speed = IFXUSB_EP_SPEED_LOW; ++ else if (urb->dev->speed == USB_SPEED_FULL) ifxhc->speed = IFXUSB_EP_SPEED_FULL; ++ else ifxhc->speed = IFXUSB_EP_SPEED_HIGH; ++ ++ ifxhc->mps = _epqh->mps; ++ ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ++ ifxhc->ep_type = _epqh->ep_type; ++ ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) ++ { ++ ifxhc->control_phase=IFXHCD_CONTROL_SETUP; ++ ifxhc->is_in = 0; ++ ifxhc->data_pid_start = IFXUSB_HC_PID_SETUP; ++ ifxhc->xfer_buff = urbd->setup_buff; ++ ifxhc->xfer_len = 8; ++ ifxhc->xfer_count = 0; ++ ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; ++ } ++ else ++ { ++ ifxhc->is_in = urbd->is_in; ++ ifxhc->xfer_buff = urbd->xfer_buff; ++ ifxhc->xfer_len = urbd->xfer_len; ++ ifxhc->xfer_count = 0; ++ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ ++ //ifxhc->data_pid_start = _epqh->data_toggle; ++ ifxhc->data_pid_start = usb_gettoggle (urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout (urb->pipe)) ++ ? IFXUSB_HC_PID_DATA1 ++ : IFXUSB_HC_PID_DATA0; ++ if(ifxhc->is_in) ++ ifxhc->short_rw =0; ++ else ++ ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; ++ ++ #ifdef __EN_ISOC__ ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) ++ { ++ struct usb_iso_packet_descriptor *frame_desc; ++ frame_desc = &urb->iso_frame_desc[urbd->isoc_frame_index]; ++ ifxhc->xfer_buff += frame_desc->offset + urbd->isoc_split_offset; ++ ifxhc->xfer_len = frame_desc->length - urbd->isoc_split_offset; ++ if (ifxhc->isoc_xact_pos == IFXUSB_HCSPLIT_XACTPOS_ALL) ++ { ++ if (ifxhc->xfer_len <= 188) ++ ifxhc->isoc_xact_pos = IFXUSB_HCSPLIT_XACTPOS_ALL; ++ else ++ ifxhc->isoc_xact_pos = IFXUSB_HCSPLIT_XACTPOS_BEGIN; ++ } ++ } ++ #endif ++ } ++ ++ ifxhc->do_ping=0; ++ if (_ifxhcd->core_if.snpsid < 0x4f54271a && ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ ifxhc->do_ping=1; ++ ++ ++ /* Set the split attributes */ ++ ifxhc->split = 0; ++ if (_epqh->need_split) { ++ ifxhc->split = 1; ++ ifxhc->hub_addr = urb->dev->tt->hub->devnum; ++ ifxhc->port_addr = urb->dev->ttport; ++ } ++ ++ //ifxhc->uint16_t pkt_count_limit ++ ++ { ++ hcint_data_t hc_intr_mask; ++ uint8_t hc_num = ifxhc->hc_num; ++ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[hc_num]; ++ ++ /* Clear old interrupt conditions for this host channel. */ ++ hc_intr_mask.d32 = 0xFFFFFFFF; ++ hc_intr_mask.b.reserved = 0; ++ ifxusb_wreg(&hc_regs->hcint, hc_intr_mask.d32); ++ ++ /* Enable channel interrupts required for this transfer. */ ++ hc_intr_mask.d32 = 0; ++ hc_intr_mask.b.chhltd = 1; ++ hc_intr_mask.b.ahberr = 1; ++ ++ ifxusb_wreg(&hc_regs->hcintmsk, hc_intr_mask.d32); ++ ++ /* Enable the top level host channel interrupt. */ ++ { ++ uint32_t intr_enable; ++ intr_enable = (1 << hc_num); ++ ifxusb_mreg(&_ifxhcd->core_if.host_global_regs->haintmsk, 0, intr_enable); ++ } ++ ++ /* Make sure host channel interrupts are enabled. */ ++ { ++ gint_data_t gintmsk ={.d32 = 0}; ++ gintmsk.b.hcintr = 1; ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, 0, gintmsk.d32); ++ } ++ ++ /* ++ * Program the HCCHARn register with the endpoint characteristics for ++ * the current transfer. ++ */ ++ { ++ hcchar_data_t hcchar; ++ ++ hcchar.d32 = 0; ++ hcchar.b.devaddr = ifxhc->dev_addr; ++ hcchar.b.epnum = ifxhc->ep_num; ++ hcchar.b.lspddev = (ifxhc->speed == IFXUSB_EP_SPEED_LOW); ++ hcchar.b.eptype = ifxhc->ep_type; ++ hcchar.b.mps = ifxhc->mps; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, ifxhc->hc_num); ++ IFX_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n" , hcchar.b.devaddr); ++ IFX_DEBUGPL(DBG_HCDV, " Ep Num: %d\n" , hcchar.b.epnum); ++ IFX_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev); ++ IFX_DEBUGPL(DBG_HCDV, " Ep Type: %d\n" , hcchar.b.eptype); ++ IFX_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n" , hcchar.b.mps); ++ IFX_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n" , hcchar.b.multicnt); ++ } ++ /* Program the HCSPLIT register for SPLITs */ ++ { ++ hcsplt_data_t hcsplt; ++ ++ hcsplt.d32 = 0; ++ if (ifxhc->split) ++ { ++ IFX_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", ifxhc->hc_num, ++ (ifxhc->split==2) ? "CSPLIT" : "SSPLIT"); ++ hcsplt.b.spltena = 1; ++ hcsplt.b.compsplt = (ifxhc->split==2); ++ #ifdef __EN_ISOC__ ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) ++ hcsplt.b.xactpos = ifxhc->isoc_xact_pos; ++ else ++ #endif ++ hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL; ++ hcsplt.b.hubaddr = ifxhc->hub_addr; ++ hcsplt.b.prtaddr = ifxhc->port_addr; ++ IFX_DEBUGPL(DBG_HCDV, " comp split %d\n" , hcsplt.b.compsplt); ++ IFX_DEBUGPL(DBG_HCDV, " xact pos %d\n" , hcsplt.b.xactpos); ++ IFX_DEBUGPL(DBG_HCDV, " hub addr %d\n" , hcsplt.b.hubaddr); ++ IFX_DEBUGPL(DBG_HCDV, " port addr %d\n" , hcsplt.b.prtaddr); ++ IFX_DEBUGPL(DBG_HCDV, " is_in %d\n" , ifxhc->is_in); ++ IFX_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n" , ifxhc->mps); ++ IFX_DEBUGPL(DBG_HCDV, " xferlen: %d\n" , ifxhc->xfer_len); ++ } ++ ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32); ++ } ++ } ++ ++ ifxhc->nak_retry_r=ifxhc->nak_retry=0; ++ ifxhc->nak_countdown_r=ifxhc->nak_countdown=0; ++ ++ if (ifxhc->split) ++ { ++ if(ifxhc->is_in) ++ { ++ } ++ else ++ { ++ } ++ } ++ else if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) ++ { ++ if(ifxhc->is_in) ++ { ++ } ++ else ++ { ++ } ++ } ++ else if(_epqh->ep_type==IFXUSB_EP_TYPE_BULK) ++ { ++ if(ifxhc->is_in) ++ { ++// ifxhc->nak_retry_r=ifxhc->nak_retry=nak_retry_max; ++// ifxhc->nak_countdown_r=ifxhc->nak_countdown=nak_countdown_max; ++ } ++ else ++ { ++ } ++ } ++ else if(_epqh->ep_type==IFXUSB_EP_TYPE_INTR) ++ { ++ if(ifxhc->is_in) ++ { ++ } ++ else ++ { ++ } ++ } ++ else if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) ++ { ++ if(ifxhc->is_in) ++ { ++ } ++ else ++ { ++ } ++ } ++ ++ return 1; ++} ++ ++/*! ++ \brief This function selects transactions from the HCD transfer schedule and ++ assigns them to available host channels. It is called from HCD interrupt ++ handler functions. ++ */ ++static void select_eps_sub(ifxhcd_hcd_t *_ifxhcd) ++{ ++ struct list_head *epqh_ptr; ++ struct list_head *urbd_ptr; ++ ifxhcd_epqh_t *epqh; ++ ifxhcd_urbd_t *urbd; ++ int ret_val=0; ++ ++ /*== AVM/BC 20101111 Function called with Lock ==*/ ++ ++// #ifdef __DEBUG__ ++// IFX_DEBUGPL(DBG_HCD, " ifxhcd_select_ep\n"); ++// #endif ++ ++ /* Process entries in the periodic ready list. */ ++ #ifdef __EN_ISOC__ ++ epqh_ptr = _ifxhcd->epqh_isoc_ready.next; ++ while (epqh_ptr != &_ifxhcd->epqh_isoc_ready && !list_empty(&_ifxhcd->free_hc_list)) ++ { ++ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_ptr = epqh_ptr->next; ++ if(epqh->period_do) ++ { ++ if(assign_and_init_hc(_ifxhcd, epqh)) ++ { ++ IFX_DEBUGPL(DBG_HCD, " select_eps ISOC\n"); ++ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_active); ++ epqh->is_active=1; ++ ret_val=1; ++ epqh->period_do=0; ++ } ++ } ++ } ++ #endif ++ ++ epqh_ptr = _ifxhcd->epqh_intr_ready.next; ++ while (epqh_ptr != &_ifxhcd->epqh_intr_ready && !list_empty(&_ifxhcd->free_hc_list)) ++ { ++ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_ptr = epqh_ptr->next; ++ if(epqh->period_do) ++ { ++ if(assign_and_init_hc(_ifxhcd, epqh)) ++ { ++ IFX_DEBUGPL(DBG_HCD, " select_eps INTR\n"); ++ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_intr_active); ++ epqh->is_active=1; ++ ret_val=1; ++ epqh->period_do=0; ++ } ++ } ++ } ++ ++ epqh_ptr = _ifxhcd->epqh_np_ready.next; ++ while (epqh_ptr != &_ifxhcd->epqh_np_ready && !list_empty(&_ifxhcd->free_hc_list)) // may need to preserve at lease one for period ++ { ++ epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_ptr = epqh_ptr->next; ++ if(assign_and_init_hc(_ifxhcd, epqh)) ++ { ++ IFX_DEBUGPL(DBG_HCD, " select_eps CTRL/BULK\n"); ++ list_move_tail(&epqh->epqh_list_entry, &_ifxhcd->epqh_np_active); ++ epqh->is_active=1; ++ ret_val=1; ++ } ++ } ++ if(ret_val) ++ /*== AVM/BC 20101111 Function called with Lock ==*/ ++ process_channels_sub(_ifxhcd); ++ ++ /* AVM/BC 20101111 Urbds completion loop */ ++ while (!list_empty(&_ifxhcd->urbd_complete_list)) ++ { ++ urbd_ptr = _ifxhcd->urbd_complete_list.next; ++ list_del_init(urbd_ptr); ++ ++ urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, urbd_list_entry); ++ ++ ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status); ++ ++ } ++ ++} ++ ++static void select_eps_func(unsigned long data) ++{ ++ unsigned long flags; ++ ++ ifxhcd_hcd_t *ifxhcd; ++ ifxhcd=((ifxhcd_hcd_t *)data); ++ ++ /* AVM/BC 20101111 select_eps_in_use flag removed */ ++ ++ SPIN_LOCK_IRQSAVE(&ifxhcd->lock, flags); ++ ++ /*if(ifxhcd->select_eps_in_use){ ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++ return; ++ } ++ ifxhcd->select_eps_in_use=1; ++ */ ++ ++ select_eps_sub(ifxhcd); ++ ++ //ifxhcd->select_eps_in_use=0; ++ ++ SPIN_UNLOCK_IRQRESTORE(&ifxhcd->lock, flags); ++} ++ ++void select_eps(ifxhcd_hcd_t *_ifxhcd) ++{ ++ if(in_irq()) ++ { ++ if(!_ifxhcd->select_eps.func) ++ { ++ _ifxhcd->select_eps.next = NULL; ++ _ifxhcd->select_eps.state = 0; ++ atomic_set( &_ifxhcd->select_eps.count, 0); ++ _ifxhcd->select_eps.func = select_eps_func; ++ _ifxhcd->select_eps.data = (unsigned long)_ifxhcd; ++ } ++ tasklet_schedule(&_ifxhcd->select_eps); ++ } ++ else ++ { ++ unsigned long flags; ++ ++ /* AVM/BC 20101111 select_eps_in_use flag removed */ ++ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ /*if(_ifxhcd->select_eps_in_use){ ++ printk ("select_eps non_irq: busy\n"); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return; ++ } ++ _ifxhcd->select_eps_in_use=1; ++ */ ++ ++ select_eps_sub(_ifxhcd); ++ ++ //_ifxhcd->select_eps_in_use=0; ++ ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ } ++} ++ ++/*! ++ \brief ++ */ ++static void process_unaligned( ifxhcd_epqh_t *_epqh) ++{ ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ if(!_epqh->aligned_checked) ++ { ++ uint32_t xfer_len; ++ xfer_len=_epqh->urbd->xfer_len; ++ if(_epqh->urbd->is_in && xfer_len<_epqh->mps) ++ xfer_len = _epqh->mps; ++ _epqh->using_aligned_buf=0; ++ ++ if(xfer_len > 0 && ((unsigned long)_epqh->urbd->xfer_buff) & 3) ++ { ++ if( _epqh->aligned_buf ++ && _epqh->aligned_buf_len > 0 ++ && _epqh->aligned_buf_len < xfer_len ++ ) ++ { ++ ifxusb_free_buf(_epqh->aligned_buf); ++ _epqh->aligned_buf=NULL; ++ _epqh->aligned_buf_len=0; ++ } ++ if(! _epqh->aligned_buf || ! _epqh->aligned_buf_len) ++ { ++ _epqh->aligned_buf = ifxusb_alloc_buf(xfer_len, _epqh->urbd->is_in); ++ if(_epqh->aligned_buf) ++ _epqh->aligned_buf_len = xfer_len; ++ } ++ if(_epqh->aligned_buf) ++ { ++ if(!_epqh->urbd->is_in) ++ memcpy(_epqh->aligned_buf, _epqh->urbd->xfer_buff, xfer_len); ++ _epqh->using_aligned_buf=1; ++ _epqh->hc->xfer_buff = _epqh->aligned_buf; ++ } ++ else ++ IFX_WARN("%s():%d\n",__func__,__LINE__); ++ } ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) ++ { ++ _epqh->using_aligned_setup=0; ++ if(((unsigned long)_epqh->urbd->setup_buff) & 3) ++ { ++ if(! _epqh->aligned_setup) ++ _epqh->aligned_setup = ifxusb_alloc_buf(8,0); ++ if(_epqh->aligned_setup) ++ { ++ memcpy(_epqh->aligned_setup, _epqh->urbd->setup_buff, 8); ++ _epqh->using_aligned_setup=1; ++ } ++ else ++ IFX_WARN("%s():%d\n",__func__,__LINE__); ++ _epqh->hc->xfer_buff = _epqh->aligned_setup; ++ } ++ } ++ } ++ #elif defined(__UNALIGNED_BUFFER_CHK__) ++ if(!_epqh->aligned_checked) ++ { ++ if(_epqh->urbd->is_in) ++ { ++ if(_epqh->urbd->xfer_len==0) ++ IFX_WARN("%s():%d IN xfer while length is zero \n",__func__,__LINE__); ++ else{ ++ if(_epqh->urbd->xfer_len < _epqh->mps) ++ IFX_WARN("%s():%d IN xfer while length < mps \n",__func__,__LINE__); ++ ++ if(((unsigned long)_epqh->urbd->xfer_buff) & 3) ++ IFX_WARN("%s():%d IN xfer Buffer UNALIGNED\n",__func__,__LINE__); ++ } ++ } ++ else ++ { ++ if(_epqh->urbd->xfer_len > 0 && (((unsigned long)_epqh->urbd->xfer_buff) & 3) ) ++ IFX_WARN("%s():%d OUT xfer Buffer UNALIGNED\n",__func__,__LINE__); ++ } ++ ++ if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) ++ { ++ if(((unsigned long)_epqh->urbd->setup_buff) & 3) ++ IFX_WARN("%s():%d SETUP xfer Buffer UNALIGNED\n",__func__,__LINE__); ++ } ++ } ++ #endif ++ _epqh->aligned_checked=1; ++} ++ ++ ++/*! ++ \brief ++ */ ++void process_channels_sub(ifxhcd_hcd_t *_ifxhcd) ++{ ++ ifxhcd_epqh_t *epqh; ++ struct list_head *epqh_item; ++ struct ifxhcd_hc *hc; ++ ++ #ifdef __EN_ISOC__ ++ if (!list_empty(&_ifxhcd->epqh_isoc_active)) ++ { ++ for (epqh_item = _ifxhcd->epqh_isoc_active.next; ++ epqh_item != &_ifxhcd->epqh_isoc_active; ++ ) ++ { ++ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_item = epqh_item->next; ++ hc=epqh->hc; ++ if(hc && !hc->xfer_started && epqh->period_do) ++ { ++ if(hc->split==0 ++ || hc->split==1 ++ ) ++ { ++ //epqh->ping_state = 0; ++ process_unaligned(epqh); ++ hc->wait_for_sof=epqh->wait_for_sof; ++ epqh->wait_for_sof=0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, hc); ++ epqh->period_do=0; ++ { ++ gint_data_t gintsts = {.d32 = 0}; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk,0, gintsts.d32); ++ } ++ } ++ } ++ } ++ } ++ #endif ++ ++ if (!list_empty(&_ifxhcd->epqh_intr_active)) ++ { ++ for (epqh_item = _ifxhcd->epqh_intr_active.next; ++ epqh_item != &_ifxhcd->epqh_intr_active; ++ ) ++ { ++ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_item = epqh_item->next; ++ hc=epqh->hc; ++ if(hc && !hc->xfer_started && epqh->period_do) ++ { ++ if(hc->split==0 ++ || hc->split==1 ++ ) ++ { ++ //epqh->ping_state = 0; ++ process_unaligned(epqh); ++ hc->wait_for_sof=epqh->wait_for_sof; ++ epqh->wait_for_sof=0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, hc); ++ epqh->period_do=0; ++#ifdef __USE_TIMER_4_SOF__ ++ /* AVM/WK change: let hc_start decide, if irq is needed */ ++#else ++ { ++ gint_data_t gintsts = {.d32 = 0}; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk,0, gintsts.d32); ++ } ++#endif ++ } ++ } ++ ++ } ++ } ++ ++ if (!list_empty(&_ifxhcd->epqh_np_active)) ++ { ++ for (epqh_item = _ifxhcd->epqh_np_active.next; ++ epqh_item != &_ifxhcd->epqh_np_active; ++ ) ++ { ++ epqh = list_entry(epqh_item, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_item = epqh_item->next; ++ hc=epqh->hc; ++ if(hc) ++ { ++ if(!hc->xfer_started) ++ { ++ if(hc->split==0 ++ || hc->split==1 ++ //|| hc->split_counter == 0 ++ ) ++ { ++ //epqh->ping_state = 0; ++ process_unaligned(epqh); ++ hc->wait_for_sof=epqh->wait_for_sof; ++ epqh->wait_for_sof=0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, hc); ++ } ++ } ++ } ++ } ++ } ++} ++ ++void process_channels(ifxhcd_hcd_t *_ifxhcd) ++{ ++ unsigned long flags; ++ ++ /* AVM/WK Fix: use spin_lock instead busy flag ++ **/ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ //if(_ifxhcd->process_channels_in_use) ++ // return; ++ //_ifxhcd->process_channels_in_use=1; ++ ++ process_channels_sub(_ifxhcd); ++ //_ifxhcd->process_channels_in_use=0; ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++} ++ ++ ++#ifdef __HC_XFER_TIMEOUT__ ++ static void hc_xfer_timeout(unsigned long _ptr) ++ { ++ hc_xfer_info_t *xfer_info = (hc_xfer_info_t *)_ptr; ++ int hc_num = xfer_info->hc->hc_num; ++ IFX_WARN("%s: timeout on channel %d\n", __func__, hc_num); ++ IFX_WARN(" start_hcchar_val 0x%08x\n", xfer_info->hc->start_hcchar_val); ++ } ++#endif ++ ++void ifxhcd_hc_dumb_rx(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc,uint8_t *dump_buf) ++{ ++ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; ++ hctsiz_data_t hctsiz= { .d32=0 }; ++ hcchar_data_t hcchar; ++ ++ ++ _ifxhc->xfer_len = _ifxhc->mps; ++ hctsiz.b.xfersize = _ifxhc->mps; ++ hctsiz.b.pktcnt = 0; ++ hctsiz.b.pid = _ifxhc->data_pid_start; ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ ifxusb_wreg(&hc_regs->hcdma, (uint32_t)(CPHYSADDR( ((uint32_t)(dump_buf))))); ++ ++ { ++ hcint_data_t hcint= { .d32=0 }; ++// hcint.b.nak =1; ++// hcint.b.nyet=1; ++// hcint.b.ack =1; ++ hcint.d32 =0xFFFFFFFF; ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ } ++ ++ /* Set host channel enable after all other setup is complete. */ ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ hcchar.b.epdir = 1; ++ IFX_DEBUGPL(DBG_HCDV, " HCCHART: 0x%08x\n", hcchar.d32); ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++} ++ ++/*! ++ \brief This function trigger a data transfer for a host channel and ++ starts the transfer. ++ ++ For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ ++ register along with a packet count of 1 and the channel is enabled. This ++ causes a single PING transaction to occur. Other fields in HCTSIZ are ++ simply set to 0 since no data transfer occurs in this case. ++ ++ For a PING transfer in DMA mode, the HCTSIZ register is initialized with ++ all the information required to perform the subsequent data transfer. In ++ addition, the Do Ping bit is set in the HCTSIZ register. In this case, the ++ controller performs the entire PING protocol, then starts the data ++ transfer. ++ \param _core_if Pointer of core_if structure ++ \param _ifxhc Information needed to initialize the host channel. The xfer_len ++ value may be reduced to accommodate the max widths of the XferSize and ++ PktCnt fields in the HCTSIZn register. The multi_count value may be changed ++ to reflect the final xfer_len value. ++ */ ++void ifxhcd_hc_start(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc) ++{ ++ hctsiz_data_t hctsiz= { .d32=0 }; ++ hcchar_data_t hcchar; ++ uint32_t max_hc_xfer_size = _core_if->params.max_transfer_size; ++ uint16_t max_hc_pkt_count = _core_if->params.max_packet_count; ++ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; ++ hfnum_data_t hfnum; ++ ++ hctsiz.b.dopng = 0; ++// if(_ifxhc->do_ping && !_ifxhc->is_in) hctsiz.b.dopng = 1; ++ ++ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; ++ ++ /* AVM/BC 20101111 Workaround: Always PING if HI-Speed Out and xfer_len > 0 */ ++ if(/*_ifxhc->do_ping &&*/ ++ (!_ifxhc->is_in) && ++ (_ifxhc->speed == IFXUSB_EP_SPEED_HIGH) && ++ ((_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) || ((_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL) && (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP))) && ++ _ifxhc->xfer_len ++ ) ++ hctsiz.b.dopng = 1; ++ ++ _ifxhc->xfer_started = 1; ++ ++ if(_ifxhc->epqh->pkt_count_limit > 0 && _ifxhc->epqh->pkt_count_limit < max_hc_pkt_count ) ++ { ++ max_hc_pkt_count=_ifxhc->epqh->pkt_count_limit; ++ if(max_hc_pkt_count * _ifxhc->mps < max_hc_xfer_size) ++ max_hc_xfer_size = max_hc_pkt_count * _ifxhc->mps; ++ } ++ if (_ifxhc->split > 0) ++ { ++ { ++ gint_data_t gintsts = {.d32 = 0}; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_core_if->core_global_regs->gintmsk,0, gintsts.d32); ++ } ++ ++ _ifxhc->start_pkt_count = 1; ++ if(!_ifxhc->is_in && _ifxhc->split>1) // OUT CSPLIT ++ _ifxhc->xfer_len = 0; ++ if (_ifxhc->xfer_len > _ifxhc->mps) ++ _ifxhc->xfer_len = _ifxhc->mps; ++ if (_ifxhc->xfer_len > 188) ++ _ifxhc->xfer_len = 188; ++ } ++ else if(_ifxhc->is_in) ++ { ++ _ifxhc->short_rw = 0; ++ if (_ifxhc->xfer_len > 0) ++ { ++ if (_ifxhc->xfer_len > max_hc_xfer_size) ++ _ifxhc->xfer_len = max_hc_xfer_size - _ifxhc->mps + 1; ++ _ifxhc->start_pkt_count = (_ifxhc->xfer_len + _ifxhc->mps - 1) / _ifxhc->mps; ++ if (_ifxhc->start_pkt_count > max_hc_pkt_count) ++ _ifxhc->start_pkt_count = max_hc_pkt_count; ++ } ++ else /* Need 1 packet for transfer length of 0. */ ++ _ifxhc->start_pkt_count = 1; ++ _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps; ++ } ++ else //non-split out ++ { ++ if (_ifxhc->xfer_len == 0) ++ { ++ /*== AVM/BC WK 20110421 ZERO PACKET Workaround: Is not an error ==*/ ++ //if(_ifxhc->short_rw==0) ++ // printk(KERN_INFO "%s() line %d: ZLP write without short_rw set!\n",__func__,__LINE__); ++ _ifxhc->start_pkt_count = 1; ++ } ++ else ++ { ++ if (_ifxhc->xfer_len > max_hc_xfer_size) ++ { ++ _ifxhc->start_pkt_count = (max_hc_xfer_size / _ifxhc->mps); ++ _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps; ++ } ++ else ++ { ++ _ifxhc->start_pkt_count = (_ifxhc->xfer_len+_ifxhc->mps-1) / _ifxhc->mps; ++// if(_ifxhc->start_pkt_count * _ifxhc->mps == _ifxhc->xfer_len ) ++// _ifxhc->start_pkt_count += _ifxhc->short_rw; ++ /*== AVM/BC WK 20110421 ZERO PACKET Workaround / check if short_rw is needed ==*/ ++ if(_ifxhc->start_pkt_count * _ifxhc->mps != _ifxhc->xfer_len ) ++ _ifxhc->short_rw = 0; ++ } ++ } ++ } ++ ++ #ifdef __EN_ISOC__ ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ /* Set up the initial PID for the transfer. */ ++ #if 1 ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ #else ++ if (_ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ { ++ if (_ifxhc->is_in) ++ { ++ if (_ifxhc->multi_count == 1) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ else if (_ifxhc->multi_count == 2) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA2; ++ } ++ else ++ { ++ if (_ifxhc->multi_count == 1) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_MDATA; ++ } ++ } ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ #endif ++ } ++ #endif ++ ++ hctsiz.b.xfersize = _ifxhc->xfer_len; ++ hctsiz.b.pktcnt = _ifxhc->start_pkt_count; ++ hctsiz.b.pid = _ifxhc->data_pid_start; ++ ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _ifxhc->hc_num); ++ IFX_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize); ++ IFX_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n" , hctsiz.b.pktcnt); ++ IFX_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); ++ IFX_DEBUGPL(DBG_HCDV, " DMA: 0x%08x\n", (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count ))); ++ ifxusb_wreg(&hc_regs->hcdma, (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count ))); ++ ++ /* Start the split */ ++ if (_ifxhc->split>0) ++ { ++ hcsplt_data_t hcsplt; ++ hcsplt.d32 = ifxusb_rreg (&hc_regs->hcsplt); ++ hcsplt.b.spltena = 1; ++ if (_ifxhc->split>1) ++ hcsplt.b.compsplt = 1; ++ else ++ hcsplt.b.compsplt = 0; ++ ++ #ifdef __EN_ISOC__ ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) ++ hcsplt.b.xactpos = _ifxhc->isoc_xact_pos; ++ else ++ #endif ++ hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL;// if not ISO ++ ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32); ++ IFX_DEBUGPL(DBG_HCDV, " SPLIT: XACT_POS:0x%08x\n", hcsplt.d32); ++ } ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++// hcchar.b.multicnt = _ifxhc->multi_count; ++ hcchar.b.multicnt = 1; ++ ++ #ifdef __DEBUG__ ++ _ifxhc->start_hcchar_val = hcchar.d32; ++ if (hcchar.b.chdis) ++ IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", ++ __func__, _ifxhc->hc_num, hcchar.d32); ++ #endif ++ ++ /* Set host channel enable after all other setup is complete. */ ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ hcchar.b.epdir = _ifxhc->is_in; ++ _ifxhc->hcchar=hcchar.d32; ++ ++ IFX_DEBUGPL(DBG_HCDV, " HCCHART: 0x%08x\n", _ifxhc->hcchar); ++ ++ /* == 20110901 AVM/WK Fix: Clear IRQ flags in any case ==*/ ++ { ++ hcint_data_t hcint= { .d32=0 }; ++ hcint.d32 =0xFFFFFFFF; ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ } ++ ++ if(_ifxhc->wait_for_sof==0) ++ { ++ hcint_data_t hcint; ++ ++ hcint.d32=ifxusb_rreg(&hc_regs->hcintmsk); ++ ++ hcint.b.nak =0; ++ hcint.b.ack =0; ++ /* == 20110901 AVM/WK Fix: We don't need NOT YET IRQ ==*/ ++ hcint.b.nyet=0; ++ if(_ifxhc->nak_countdown_r) ++ hcint.b.nak =1; ++ ifxusb_wreg(&hc_regs->hcintmsk, hcint.d32); ++ ++ /* AVM WK / BC 20100827 ++ * MOVED. Oddframe updated inmediatly before write HCChar Register. ++ */ ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ hfnum.d32 = ifxusb_rreg(&_core_if->host_global_regs->hfnum); ++ /* 1 if _next_ frame is odd, 0 if it's even */ ++ hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; ++ _ifxhc->hcchar=hcchar.d32; ++ } ++ ++ ifxusb_wreg(&hc_regs->hcchar, _ifxhc->hcchar); ++#ifdef __USE_TIMER_4_SOF__ ++ } else { ++ //activate SOF IRQ ++ gint_data_t gintsts = {.d32 = 0}; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_core_if->core_global_regs->gintmsk,0, gintsts.d32); ++#endif ++ } ++ ++ #ifdef __HC_XFER_TIMEOUT__ ++ /* Start a timer for this transfer. */ ++ init_timer(&_ifxhc->hc_xfer_timer); ++ _ifxhc->hc_xfer_timer.function = hc_xfer_timeout; ++ _ifxhc->hc_xfer_timer.core_if = _core_if; ++ _ifxhc->hc_xfer_timer.hc = _ifxhc; ++ _ifxhc->hc_xfer_timer.data = (unsigned long)(&_ifxhc->hc_xfer_info); ++ _ifxhc->hc_xfer_timer.expires = jiffies + (HZ*10); ++ add_timer(&_ifxhc->hc_xfer_timer); ++ #endif ++} ++ ++/*! ++ \brief Attempts to halt a host channel. This function should only be called ++ to abort a transfer in DMA mode. Under normal circumstances in DMA mode, the ++ controller halts the channel when the transfer is complete or a condition ++ occurs that requires application intervention. ++ ++ In DMA mode, always sets the Channel Enable and Channel Disable bits of the ++ HCCHARn register. The controller ensures there is space in the request ++ queue before submitting the halt request. ++ ++ Some time may elapse before the core flushes any posted requests for this ++ host channel and halts. The Channel Halted interrupt handler completes the ++ deactivation of the host channel. ++ */ ++void ifxhcd_hc_halt(ifxusb_core_if_t *_core_if, ++ ifxhcd_hc_t *_ifxhc, ++ ifxhcd_halt_status_e _halt_status) ++{ ++ hcchar_data_t hcchar; ++ ifxusb_hc_regs_t *hc_regs; ++ ++ hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; ++ ++ WARN_ON(_halt_status == HC_XFER_NO_HALT_STATUS); ++ ++ if (_halt_status == HC_XFER_URB_DEQUEUE || ++ _halt_status == HC_XFER_AHB_ERR) ++ { ++ /* ++ * Disable all channel interrupts except Ch Halted. The URBD ++ * and EPQH state associated with this transfer has been cleared ++ * (in the case of URB_DEQUEUE), so the channel needs to be ++ * shut down carefully to prevent crashes. ++ */ ++ hcint_data_t hcintmsk; ++ hcintmsk.d32 = 0; ++ hcintmsk.b.chhltd = 1; ++ ifxusb_wreg(&hc_regs->hcintmsk, hcintmsk.d32); ++ ++ /* ++ * Make sure no other interrupts besides halt are currently ++ * pending. Handling another interrupt could cause a crash due ++ * to the URBD and EPQH state. ++ */ ++ ifxusb_wreg(&hc_regs->hcint, ~hcintmsk.d32); ++ ++ /* ++ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR ++ * even if the channel was already halted for some other ++ * reason. ++ */ ++ _ifxhc->halt_status = _halt_status; ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen == 0) ++ { ++ /* ++ * The channel is either already halted or it hasn't ++ * started yet. In DMA mode, the transfer may halt if ++ * it finishes normally or a condition occurs that ++ * requires driver intervention. Don't want to halt ++ * the channel again. In either Slave or DMA mode, ++ * it's possible that the transfer has been assigned ++ * to a channel, but not started yet when an URB is ++ * dequeued. Don't want to halt a channel that hasn't ++ * started yet. ++ */ ++ return; ++ } ++ } ++ ++ if (_ifxhc->halting) ++ { ++ /* ++ * A halt has already been issued for this channel. This might ++ * happen when a transfer is aborted by a higher level in ++ * the stack. ++ */ ++ #ifdef __DEBUG__ ++ IFX_PRINT("*** %s: Channel %d, _hc->halting already set ***\n", ++ __func__, _ifxhc->hc_num); ++ #endif ++ //ifxusb_dump_global_registers(_core_if); */ ++ //ifxusb_dump_host_registers(_core_if); */ ++ return; ++ } ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ /* == AVM/WK 20100709 halt channel only if enabled ==*/ ++ if (hcchar.b.chen) { ++ _ifxhc->halting = 1; ++ hcchar.b.chdis = 1; ++ ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ _ifxhc->halt_status = _halt_status; ++ } ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n" , __func__, _ifxhc->hc_num); ++ IFX_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n" , hcchar.d32); ++ IFX_DEBUGPL(DBG_HCDV, " halting: %d\n" , _ifxhc->halting); ++ IFX_DEBUGPL(DBG_HCDV, " halt_status: %d\n" , _ifxhc->halt_status); ++ ++ return; ++} ++ ++/*! ++ \brief Clears a host channel. ++ */ ++void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc) ++{ ++ ifxusb_hc_regs_t *hc_regs; ++ ++ _ifxhc->xfer_started = 0; ++ /* ++ * Clear channel interrupt enables and any unhandled channel interrupt ++ * conditions. ++ */ ++ hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; ++ ifxusb_wreg(&hc_regs->hcintmsk, 0); ++ ifxusb_wreg(&hc_regs->hcint, 0xFFFFFFFF); ++ ++ #ifdef __HC_XFER_TIMEOUT__ ++ del_timer(&_ifxhc->hc_xfer_timer); ++ #endif ++ #ifdef __DEBUG__ ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chdis) ++ IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", __func__, _ifxhc->hc_num, hcchar.d32); ++ } ++ #endif ++} ++ ++ ++ ++ ++ ++ ++ ++ ++#ifdef __DEBUG__ ++ static void dump_urb_info(struct urb *_urb, char* _fn_name) ++ { ++ IFX_PRINT("%s, urb %p\n" , _fn_name, _urb); ++ IFX_PRINT(" Device address: %d\n", usb_pipedevice(_urb->pipe)); ++ IFX_PRINT(" Endpoint: %d, %s\n" , usb_pipeendpoint(_urb->pipe), ++ (usb_pipein(_urb->pipe) ? "IN" : "OUT")); ++ IFX_PRINT(" Endpoint type: %s\n", ++ ({ char *pipetype; ++ switch (usb_pipetype(_urb->pipe)) { ++ case PIPE_CONTROL: pipetype = "CONTROL"; break; ++ case PIPE_BULK: pipetype = "BULK"; break; ++ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break; ++ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break; ++ default: pipetype = "UNKNOWN"; break; ++ }; ++ pipetype; ++ })); ++ IFX_PRINT(" Speed: %s\n", ++ ({ char *speed; ++ switch (_urb->dev->speed) { ++ case USB_SPEED_HIGH: speed = "HIGH"; break; ++ case USB_SPEED_FULL: speed = "FULL"; break; ++ case USB_SPEED_LOW: speed = "LOW"; break; ++ default: speed = "UNKNOWN"; break; ++ }; ++ speed; ++ })); ++ IFX_PRINT(" Max packet size: %d\n", ++ usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe))); ++ IFX_PRINT(" Data buffer length: %d\n", _urb->transfer_buffer_length); ++ IFX_PRINT(" Transfer buffer: %p, Transfer DMA: %p\n", ++ _urb->transfer_buffer, (void *)_urb->transfer_dma); ++ IFX_PRINT(" Setup buffer: %p, Setup DMA: %p\n", ++ _urb->setup_packet, (void *)_urb->setup_dma); ++ IFX_PRINT(" Interval: %d\n", _urb->interval); ++ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) ++ { ++ int i; ++ for (i = 0; i < _urb->number_of_packets; i++) ++ { ++ IFX_PRINT(" ISO Desc %d:\n", i); ++ IFX_PRINT(" offset: %d, length %d\n", ++ _urb->iso_frame_desc[i].offset, ++ _urb->iso_frame_desc[i].length); ++ } ++ } ++ } ++ ++ static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++ { ++ if (_epqh->hc != NULL) ++ { ++ ifxhcd_hc_t *hc = _epqh->hc; ++ struct list_head *item; ++ ifxhcd_epqh_t *epqh_item; ++ ++ ifxusb_hc_regs_t *hc_regs; ++ ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ ++ hc_regs = _ifxhcd->core_if.hc_regs[hc->hc_num]; ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ hcsplt.d32 = ifxusb_rreg(&hc_regs->hcsplt); ++ hctsiz.d32 = ifxusb_rreg(&hc_regs->hctsiz); ++ hcdma = ifxusb_rreg(&hc_regs->hcdma); ++ ++ IFX_PRINT(" Assigned to channel %d:\n" , hc->hc_num); ++ IFX_PRINT(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ IFX_PRINT(" hctsiz 0x%08x, hcdma 0x%08x\n" , hctsiz.d32, hcdma); ++ IFX_PRINT(" dev_addr: %d, ep_num: %d, is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->is_in); ++ IFX_PRINT(" ep_type: %d\n" , hc->ep_type); ++ IFX_PRINT(" max_packet_size: %d\n", hc->mps); ++ IFX_PRINT(" data_pid_start: %d\n" , hc->data_pid_start); ++ IFX_PRINT(" xfer_started: %d\n" , hc->xfer_started); ++ IFX_PRINT(" halt_status: %d\n" , hc->halt_status); ++ IFX_PRINT(" xfer_buff: %p\n" , hc->xfer_buff); ++ IFX_PRINT(" xfer_len: %d\n" , hc->xfer_len); ++ IFX_PRINT(" epqh: %p\n" , hc->epqh); ++ IFX_PRINT(" NP Active:\n"); ++ list_for_each(item, &_ifxhcd->epqh_np_active) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ IFX_PRINT(" NP Ready:\n"); ++ list_for_each(item, &_ifxhcd->epqh_np_ready) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ IFX_PRINT(" INTR Active:\n"); ++ list_for_each(item, &_ifxhcd->epqh_intr_active) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ IFX_PRINT(" INTR Ready:\n"); ++ list_for_each(item, &_ifxhcd->epqh_intr_ready) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ #ifdef __EN_ISOC__ ++ IFX_PRINT(" ISOC Active:\n"); ++ list_for_each(item, &_ifxhcd->epqh_isoc_active) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ IFX_PRINT(" ISOC Ready:\n"); ++ list_for_each(item, &_ifxhcd->epqh_isoc_ready) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ #endif ++ IFX_PRINT(" Standby:\n"); ++ list_for_each(item, &_ifxhcd->epqh_stdby) ++ { ++ epqh_item = list_entry(item, ifxhcd_epqh_t, epqh_list_entry); ++ IFX_PRINT(" %p\n", epqh_item); ++ } ++ } ++ } ++#endif //__DEBUG__ ++ ++ ++/*! ++ \brief This function writes a packet into the Tx FIFO associated with the Host ++ Channel. For a channel associated with a non-periodic EP, the non-periodic ++ Tx FIFO is written. For a channel associated with a periodic EP, the ++ periodic Tx FIFO is written. This function should only be called in Slave ++ mode. ++ ++ Upon return the xfer_buff and xfer_count fields in _hc are incremented by ++ then number of bytes written to the Tx FIFO. ++ */ ++ ++#ifdef __ENABLE_DUMP__ ++ void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd) ++ { ++ int num_channels; ++ int i; ++ num_channels = _ifxhcd->core_if.params.host_channels; ++ IFX_PRINT("\n"); ++ IFX_PRINT("************************************************************\n"); ++ IFX_PRINT("HCD State:\n"); ++ IFX_PRINT(" Num channels: %d\n", num_channels); ++ for (i = 0; i < num_channels; i++) { ++ ifxhcd_hc_t *hc = &_ifxhcd->ifxhc[i]; ++ IFX_PRINT(" Channel %d:\n", hc->hc_num); ++ IFX_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->is_in); ++ IFX_PRINT(" speed: %d\n" , hc->speed); ++ IFX_PRINT(" ep_type: %d\n" , hc->ep_type); ++ IFX_PRINT(" mps: %d\n", hc->mps); ++ IFX_PRINT(" data_pid_start: %d\n" , hc->data_pid_start); ++ IFX_PRINT(" xfer_started: %d\n" , hc->xfer_started); ++ IFX_PRINT(" xfer_buff: %p\n" , hc->xfer_buff); ++ IFX_PRINT(" xfer_len: %d\n" , hc->xfer_len); ++ IFX_PRINT(" xfer_count: %d\n" , hc->xfer_count); ++ IFX_PRINT(" halting: %d\n" , hc->halting); ++ IFX_PRINT(" halt_status: %d\n" , hc->halt_status); ++ IFX_PRINT(" split: %d\n" , hc->split); ++ IFX_PRINT(" hub_addr: %d\n" , hc->hub_addr); ++ IFX_PRINT(" port_addr: %d\n" , hc->port_addr); ++ #ifdef __EN_ISOC__ ++ IFX_PRINT(" isoc_xact_pos: %d\n" , hc->isoc_xact_pos); ++ #endif ++ IFX_PRINT(" epqh: %p\n" , hc->epqh); ++ IFX_PRINT(" short_rw: %d\n" , hc->short_rw); ++ IFX_PRINT(" do_ping: %d\n" , hc->do_ping); ++ IFX_PRINT(" control_phase: %d\n" , hc->control_phase); ++ IFX_PRINT(" pkt_count_limit: %d\n", hc->epqh->pkt_count_limit); ++ IFX_PRINT(" start_pkt_count: %d\n" , hc->start_pkt_count); ++ } ++ IFX_PRINT("************************************************************\n"); ++ IFX_PRINT("\n"); ++ } ++#endif //__ENABLE_DUMP__ ++ +diff --git a/drivers/usb/ifxhcd/ifxhcd.h b/drivers/usb/ifxhcd/ifxhcd.h +new file mode 100644 +index 0000000..3a40851 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd.h +@@ -0,0 +1,628 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd.h ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the structures, constants, and interfaces for ++ ** the Host Contoller Driver (HCD). ++ ** ++ ** The Host Controller Driver (HCD) is responsible for translating requests ++ ** from the USB Driver into the appropriate actions on the IFXUSB controller. ++ ** It isolates the USBD from the specifics of the controller by providing an ++ ** API to the USBD. ++ ** FUNCTIONS : ++ ** COMPILER : gcc ++ ** REFERENCE : Synopsys DWC-OTG Driver 2.7 ++ ** COPYRIGHT : ++ ** Version Control Section ** ++ ** $Author$ ++ ** $Date$ ++ ** $Revisions$ ++ ** $Log$ Revision history ++*****************************************************************************/ ++ ++/*! ++ \defgroup IFXUSB_HCD HCD Interface ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief The Host Controller Driver (HCD) is responsible for translating requests ++ from the USB Driver into the appropriate actions on the IFXUSB controller. ++ It isolates the USBD from the specifics of the controller by providing an ++ API to the USBD. ++ */ ++ ++ ++/*! ++ \file ifxhcd.h ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the structures, constants, and interfaces for ++ the Host Contoller Driver (HCD). ++ */ ++ ++#if !defined(__IFXHCD_H__) ++#define __IFXHCD_H__ ++ ++#include <linux/list.h> ++#include <linux/usb.h> ++ ++#ifdef __USE_TIMER_4_SOF__ ++#include <linux/hrtimer.h> ++#endif ++#include <linux/usb/hcd.h> ++ ++#include "ifxusb_cif.h" ++#include "ifxusb_plat.h" ++ ++ ++ ++/*! ++ \addtogroup IFXUSB_HCD ++ */ ++/*@{*/ ++ ++/* Phases for control transfers.*/ ++typedef enum ifxhcd_control_phase { ++ IFXHCD_CONTROL_SETUP, ++ IFXHCD_CONTROL_DATA, ++ IFXHCD_CONTROL_STATUS ++} ifxhcd_control_phase_e; ++ ++/* Reasons for halting a host channel. */ ++typedef enum ifxhcd_halt_status ++{ ++ HC_XFER_NO_HALT_STATUS, // Initial ++ HC_XFER_COMPLETE, // Xact complete without error, upward ++ HC_XFER_URB_COMPLETE, // Xfer complete without error, short upward ++ HC_XFER_STALL, // HC stopped abnormally, upward/downward ++ HC_XFER_XACT_ERR, // HC stopped abnormally, upward ++ HC_XFER_FRAME_OVERRUN, // HC stopped abnormally, upward ++ HC_XFER_BABBLE_ERR, // HC stopped abnormally, upward ++ HC_XFER_AHB_ERR, // HC stopped abnormally, upward ++ HC_XFER_DATA_TOGGLE_ERR, ++ HC_XFER_URB_DEQUEUE, // HC stopper manually, downward ++ HC_XFER_NAK // HC stopped by nak monitor, downward ++} ifxhcd_halt_status_e; ++ ++struct ifxhcd_urbd; ++struct ifxhcd_hc ; ++struct ifxhcd_epqh ; ++struct ifxhcd_hcd; ++ ++/*! ++ \brief A URB Descriptor (URBD) holds the state of a bulk, control, ++ interrupt, or isochronous transfer. A single URBD is created for each URB ++ (of one of these types) submitted to the HCD. The transfer associated with ++ a URBD may require one or multiple transactions. ++ ++ A URBD is linked to a EP Queue Head, which is entered in either the ++ isoc, intr or non-periodic schedule for execution. When a URBD is chosen for ++ execution, some or all of its transactions may be executed. After ++ execution, the state of the URBD is updated. The URBD may be retired if all ++ its transactions are complete or if an error occurred. Otherwise, it ++ remains in the schedule so more transactions can be executed later. ++ */ ++typedef struct ifxhcd_urbd { ++ struct list_head urbd_list_entry; // Hook for EPQH->urbd_list and ifxhcd->urbd_complete_list ++ struct urb *urb; /*!< URB for this transfer */ ++ //struct urb { ++ // struct list_head urb_list; ++ // struct list_head anchor_list; ++ // struct usb_anchor * anchor; ++ // struct usb_device * dev; ++ // struct usb_host_endpoint * ep; ++ // unsigned int pipe; ++ // int status; ++ // unsigned int transfer_flags; ++ // void * transfer_buffer; ++ // dma_addr_t transfer_dma; ++ // u32 transfer_buffer_length; ++ // u32 actual_length; ++ // unsigned char * setup_packet; ++ // dma_addr_t setup_dma; ++ // int start_frame; ++ // int number_of_packets; ++ // int interval; ++ // int error_count; ++ // void * context; ++ // usb_complete_t complete; ++ // struct usb_iso_packet_descriptor iso_frame_desc[0]; ++ //}; ++ //urb_list For use by current owner of the URB. ++ //anchor_list membership in the list of an anchor ++ //anchor to anchor URBs to a common mooring ++ //dev Identifies the USB device to perform the request. ++ //ep Points to the endpoint's data structure. Will ++ // eventually replace pipe. ++ //pipe Holds endpoint number, direction, type, and more. ++ // Create these values with the eight macros available; u ++ // sb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is ++ // "ctrl", "bulk", "int" or "iso". For example ++ // usb_sndbulkpipe or usb_rcvintpipe. Endpoint numbers ++ // range from zero to fifteen. Note that "in" endpoint two ++ // is a different endpoint (and pipe) from "out" endpoint ++ // two. The current configuration controls the existence, ++ // type, and maximum packet size of any given endpoint. ++ //status This is read in non-iso completion functions to get ++ // the status of the particular request. ISO requests ++ // only use it to tell whether the URB was unlinked; ++ // detailed status for each frame is in the fields of ++ // the iso_frame-desc. ++ //transfer_flags A variety of flags may be used to affect how URB ++ // submission, unlinking, or operation are handled. ++ // Different kinds of URB can use different flags. ++ // URB_SHORT_NOT_OK ++ // URB_ISO_ASAP ++ // URB_NO_TRANSFER_DMA_MAP ++ // URB_NO_SETUP_DMA_MAP ++ // URB_NO_FSBR ++ // URB_ZERO_PACKET ++ // URB_NO_INTERRUPT ++ //transfer_buffer This identifies the buffer to (or from) which the I/O ++ // request will be performed (unless URB_NO_TRANSFER_DMA_MAP ++ // is set). This buffer must be suitable for DMA; allocate it ++ // with kmalloc or equivalent. For transfers to "in" ++ // endpoints, contents of this buffer will be modified. This ++ // buffer is used for the data stage of control transfers. ++ //transfer_dma When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, the ++ // device driver is saying that it provided this DMA address, ++ // which the host controller driver should use in preference ++ // to the transfer_buffer. ++ //transfer_buffer_length How big is transfer_buffer. The transfer may be broken ++ // up into chunks according to the current maximum packet size ++ // for the endpoint, which is a function of the configuration ++ // and is encoded in the pipe. When the length is zero, neither ++ // transfer_buffer nor transfer_dma is used. ++ //actual_length This is read in non-iso completion functions, and it tells ++ // how many bytes (out of transfer_buffer_length) were transferred. ++ // It will normally be the same as requested, unless either an error ++ // was reported or a short read was performed. The URB_SHORT_NOT_OK ++ // transfer flag may be used to make such short reads be reported ++ // as errors. ++ //setup_packet Only used for control transfers, this points to eight bytes of ++ // setup data. Control transfers always start by sending this data ++ // to the device. Then transfer_buffer is read or written, if needed. ++ //setup_dma For control transfers with URB_NO_SETUP_DMA_MAP set, the device ++ // driver has provided this DMA address for the setup packet. The ++ // host controller driver should use this in preference to setup_packet. ++ //start_frame Returns the initial frame for isochronous transfers. ++ //number_of_packets Lists the number of ISO transfer buffers. ++ //interval Specifies the polling interval for interrupt or isochronous transfers. ++ // The units are frames (milliseconds) for for full and low speed devices, ++ // and microframes (1/8 millisecond) for highspeed ones. ++ //error_count Returns the number of ISO transfers that reported errors. ++ //context For use in completion functions. This normally points to request-specific ++ // driver context. ++ //complete Completion handler. This URB is passed as the parameter to the completion ++ // function. The completion function may then do what it likes with the URB, ++ // including resubmitting or freeing it. ++ //iso_frame_desc[0] Used to provide arrays of ISO transfer buffers and to collect the transfer ++ // status for each buffer. ++ ++ struct ifxhcd_epqh *epqh; ++ // Actual data portion, not SETUP or STATUS in case of CTRL XFER ++ // DMA adjusted ++ uint8_t *setup_buff; /*!< Pointer to the entire transfer buffer. (CPU accessable)*/ ++ uint8_t *xfer_buff; /*!< Pointer to the entire transfer buffer. (CPU accessable)*/ ++ uint32_t xfer_len; /*!< Total number of bytes to transfer in this xfer. */ ++ unsigned is_in :1; ++ unsigned is_active:1; ++ ++ // For ALL XFER ++ uint8_t error_count; /*!< Holds the number of bus errors that have occurred for a transaction ++ within this transfer. ++ */ ++ /*== AVM/BC 20101111 Needed for URB Complete List ==*/ ++ int status; ++ // For ISOC XFER only ++ #ifdef __EN_ISOC__ ++ int isoc_frame_index; /*!< Index of the next frame descriptor for an isochronous transfer. A ++ frame descriptor describes the buffer position and length of the ++ data to be transferred in the next scheduled (micro)frame of an ++ isochronous transfer. It also holds status for that transaction. ++ The frame index starts at 0. ++ */ ++ // For SPLITed ISOC XFER only ++ uint8_t isoc_split_pos; /*!< Position of the ISOC split on full/low speed */ ++ uint16_t isoc_split_offset;/*!< Position of the ISOC split in the buffer for the current frame */ ++ #endif ++} ifxhcd_urbd_t; ++ ++/*! ++ \brief A EP Queue Head (EPQH) holds the static characteristics of an endpoint and ++ maintains a list of transfers (URBDs) for that endpoint. A EPQH structure may ++ be entered in either the isoc, intr or non-periodic schedule. ++ */ ++ ++typedef struct ifxhcd_epqh { ++ struct list_head epqh_list_entry; // Hook for EP Queues ++ struct list_head urbd_list; /*!< List of URBDs for this EPQH. */ ++ struct ifxhcd_hc *hc; /*!< Host channel currently processing transfers for this EPQH. */ ++ struct ifxhcd_urbd *urbd; /*!< URBD currently assigned to a host channel for this EPQH. */ ++ struct usb_host_endpoint *sysep; ++ uint8_t ep_type; /*!< Endpoint type. One of the following values: ++ - IFXUSB_EP_TYPE_CTRL ++ - IFXUSB_EP_TYPE_ISOC ++ - IFXUSB_EP_TYPE_BULK ++ - IFXUSB_EP_TYPE_INTR ++ */ ++ uint16_t mps; /*!< wMaxPacketSize Field of Endpoint Descriptor. */ ++ ++ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ ++ /*uint8_t data_toggle;*/ /*!< Determines the PID of the next data packet ++ One of the following values: ++ - IFXHCD_HC_PID_DATA0 ++ - IFXHCD_HC_PID_DATA1 ++ */ ++ uint8_t is_active; ++ ++ uint8_t pkt_count_limit; ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ struct timer_list destroy_timer; ++ #endif ++ ++ uint16_t wait_for_sof; ++ uint8_t need_split; /*!< Full/low speed endpoint on high-speed hub requires split. */ ++ uint16_t interval; /*!< Interval between transfers in (micro)frames. (for INTR)*/ ++ ++ uint16_t period_counter; /*!< Interval between transfers in (micro)frames. */ ++ uint8_t period_do; ++ ++ uint8_t aligned_checked; ++ ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ uint8_t using_aligned_setup; ++ uint8_t *aligned_setup; ++ uint8_t using_aligned_buf; ++ uint8_t *aligned_buf; ++ unsigned aligned_buf_len : 19; ++ #endif ++ ++ uint8_t *dump_buf; ++} ifxhcd_epqh_t; ++ ++ ++#if defined(__HC_XFER_TIMEOUT__) ++ struct ifxusb_core_if; ++ struct ifxhcd_hc; ++ typedef struct hc_xfer_info ++ { ++ struct ifxusb_core_if *core_if; ++ struct ifxhcd_hc *hc; ++ } hc_xfer_info_t; ++#endif //defined(__HC_XFER_TIMEOUT__) ++ ++ ++/*! ++ \brief Host channel descriptor. This structure represents the state of a single ++ host channel when acting in host mode. It contains the data items needed to ++ transfer packets to an endpoint via a host channel. ++ */ ++typedef struct ifxhcd_hc ++{ ++ struct list_head hc_list_entry ; // Hook to free hc ++ struct ifxhcd_epqh *epqh ; /*!< EP Queue Head for the transfer being processed by this channel. */ ++ ++ uint8_t hc_num ; /*!< Host channel number used for register address lookup */ ++ uint8_t *xfer_buff ; /*!< Pointer to the entire transfer buffer. */ ++ uint32_t xfer_count ; /*!< Number of bytes transferred so far. The offset of the begin of the buf */ ++ uint32_t xfer_len ; /*!< Total number of bytes to transfer in this xfer. */ ++ uint16_t start_pkt_count ; /*!< Packet count at start of transfer. Used to calculate the actual xfer size*/ ++ ifxhcd_halt_status_e halt_status; /*!< Reason for halting the host channel. */ ++ ++ unsigned dev_addr : 7; /*!< Device to access */ ++ unsigned ep_num : 4; /*!< EP to access */ ++ unsigned is_in : 1; /*!< EP direction. 0: OUT, 1: IN */ ++ unsigned speed : 2; /*!< EP speed. */ ++ unsigned ep_type : 2; /*!< Endpoint type. */ ++ unsigned mps :11; /*!< Max packet size in bytes */ ++ unsigned data_pid_start : 2; /*!< PID for initial transaction. */ ++ unsigned do_ping : 1; /*!< Set to 1 to indicate that a PING request should be issued on this ++ channel. If 0, process normally. ++ */ ++ ++ unsigned xfer_started : 1; /*!< Flag to indicate whether the transfer has been started. Set to 1 if ++ it has been started, 0 otherwise. ++ */ ++ unsigned halting : 1; /*!< Set to 1 if the host channel has been halted, but the core is not ++ finished flushing queued requests. Otherwise 0. ++ */ ++ unsigned short_rw : 1; /*!< When Tx, means termination needed. ++ When Rx, indicate Short Read */ ++ /* Split settings for the host channel */ ++ unsigned split : 2; /*!< Split: 0-Non Split, 1-SSPLIT, 2&3 CSPLIT */ ++ ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ unsigned nyet_count; ++ ++ /* nak monitor */ ++ unsigned nak_retry_r : 16; ++ unsigned nak_retry : 16; ++ #define nak_retry_max 40000 ++ unsigned nak_countdown : 8; ++ unsigned nak_countdown_r: 8; ++ #define nak_countdown_max 1 ++ ++ uint16_t wait_for_sof; ++ ifxhcd_control_phase_e control_phase; /*!< Current phase for control transfers (Setup, Data, or Status). */ ++ uint32_t ssplit_out_xfer_count; /*!< How many bytes transferred during SSPLIT OUT */ ++ #ifdef __DEBUG__ ++ uint32_t start_hcchar_val; ++ #endif ++ #ifdef __HC_XFER_TIMEOUT__ ++ hc_xfer_info_t hc_xfer_info; ++ struct timer_list hc_xfer_timer; ++ #endif ++ uint32_t hcchar; ++ ++ /* Split settings for the host channel */ ++ uint8_t hub_addr; /*!< Address of high speed hub */ ++ uint8_t port_addr; /*!< Port of the low/full speed device */ ++ #ifdef __EN_ISOC__ ++ uint8_t isoc_xact_pos; /*!< Split transaction position */ ++ #endif ++} ifxhcd_hc_t; ++ ++ ++/*! ++ \brief This structure holds the state of the HCD, including the non-periodic and ++ periodic schedules. ++ */ ++typedef struct ifxhcd_hcd ++{ ++ struct device *dev; ++ struct hc_driver hc_driver; ++ ifxusb_core_if_t core_if; /*!< Pointer to the core interface structure. */ ++ struct usb_hcd *syshcd; ++ ++ volatile union ifxhcd_internal_flags ++ { ++ uint32_t d32; ++ struct ++ { ++ unsigned port_connect_status_change : 1; ++ unsigned port_connect_status : 1; ++ unsigned port_reset_change : 1; ++ unsigned port_enable_change : 1; ++ unsigned port_suspend_change : 1; ++ unsigned port_over_current_change : 1; ++ unsigned reserved : 27; ++ } b; ++ } flags; /*!< Internal HCD Flags */ ++ ++ struct ifxhcd_hc ifxhc[MAX_EPS_CHANNELS]; /*!< Array of pointers to the host channel descriptors. Allows accessing ++ a host channel descriptor given the host channel number. This is ++ useful in interrupt handlers. ++ */ ++ struct list_head free_hc_list; /*!< Free host channels in the controller. This is a list of ifxhcd_hc_t items. */ ++ uint8_t *status_buf; /*!< Buffer to use for any data received during the status phase of a ++ control transfer. Normally no data is transferred during the status ++ phase. This buffer is used as a bit bucket. ++ */ ++ #define IFXHCD_STATUS_BUF_SIZE 64 ++ ++ struct list_head epqh_np_active; // with URBD, with HC ++ struct list_head epqh_np_ready; // with URBD, No HC ++ ++ struct list_head epqh_intr_active; // with URBD, with HC ++ struct list_head epqh_intr_ready; // with URBD, no pass, No HC ++ ++ #ifdef __EN_ISOC__ ++ struct list_head epqh_isoc_active; // with URBD, with HC ++ struct list_head epqh_isoc_ready; // with URBD, no pass, No HC ++ #endif ++ ++ /*== AVM/BC 20101111 URB Complete List ==*/ ++ struct list_head urbd_complete_list; ++ ++ struct list_head epqh_stdby; ++ ++ /* AVM/BC 20101111 flags removed */ ++ //unsigned process_channels_in_use : 1; ++ //unsigned select_eps_in_use : 1; ++ ++ struct tasklet_struct select_eps; /*!< Tasket to do a reset */ ++ uint32_t lastframe; ++ spinlock_t lock; ++#ifdef __USE_TIMER_4_SOF__ ++ struct hrtimer hr_timer; ++#endif ++} ifxhcd_hcd_t; ++ ++/* Gets the ifxhcd_hcd from a struct usb_hcd */ ++static inline ifxhcd_hcd_t *syshcd_to_ifxhcd(struct usb_hcd *syshcd) ++{ ++ return (ifxhcd_hcd_t *)(syshcd->hcd_priv[0]); ++} ++ ++/* Gets the struct usb_hcd that contains a ifxhcd_hcd_t. */ ++static inline struct usb_hcd *ifxhcd_to_syshcd(ifxhcd_hcd_t *ifxhcd) ++{ ++ return (struct usb_hcd *)(ifxhcd->syshcd); ++} ++ ++/*! \brief HCD Create/Destroy Functions */ ++/*@{*/ ++ extern int ifxhcd_init (ifxhcd_hcd_t *_ifxhcd); ++ extern void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd); ++/*@}*/ ++ ++/*! \brief Linux HC Driver API Functions */ ++/*@{*/ ++extern int ifxhcd_start(struct usb_hcd *hcd); ++extern void ifxhcd_stop (struct usb_hcd *hcd); ++extern int ifxhcd_get_frame_number(struct usb_hcd *hcd); ++ ++ ++/*! ++ \brief This function does the setup for a data transfer for a host channel and ++ starts the transfer. May be called in either Slave mode or DMA mode. In ++ Slave mode, the caller must ensure that there is sufficient space in the ++ request queue and Tx Data FIFO. ++ ++ For an OUT transfer in Slave mode, it loads a data packet into the ++ appropriate FIFO. If necessary, additional data packets will be loaded in ++ the Host ISR. ++ ++ For an IN transfer in Slave mode, a data packet is requested. The data ++ packets are unloaded from the Rx FIFO in the Host ISR. If necessary, ++ additional data packets are requested in the Host ISR. ++ ++ For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ ++ register along with a packet count of 1 and the channel is enabled. This ++ causes a single PING transaction to occur. Other fields in HCTSIZ are ++ simply set to 0 since no data transfer occurs in this case. ++ ++ For a PING transfer in DMA mode, the HCTSIZ register is initialized with ++ all the information required to perform the subsequent data transfer. In ++ addition, the Do Ping bit is set in the HCTSIZ register. In this case, the ++ controller performs the entire PING protocol, then starts the data ++ transfer. ++ ++ @param _ifxhc Information needed to initialize the host channel. The xfer_len ++ value may be reduced to accommodate the max widths of the XferSize and ++ PktCnt fields in the HCTSIZn register. The multi_count value may be changed ++ to reflect the final xfer_len value. ++ */ ++extern void ifxhcd_hc_start(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); ++ ++//extern int ifxhcd_urb_enqueue(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep, struct urb *_urb, gfp_t mem_flags); ++//extern int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb); ++extern irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd); ++int ifxhcd_urb_enqueue( struct usb_hcd *_syshcd, ++ /*--- struct usb_host_endpoint *_sysep, Parameter im 2.6.28 entfallen ---*/ ++ struct urb *_urb, ++ gfp_t _mem_flags); ++int ifxhcd_urb_dequeue( struct usb_hcd *_syshcd, ++ struct urb *_urb, int status /* Parameter neu in 2.6.28 */); ++ ++extern void ifxhcd_endpoint_disable(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep); ++ ++extern int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf); ++extern int ifxhcd_hub_control( struct usb_hcd *_syshcd, ++ u16 _typeReq, ++ u16 _wValue, ++ u16 _wIndex, ++ char *_buf, ++ u16 _wLength); ++ ++/*@}*/ ++ ++/*! \brief Transaction Execution Functions */ ++/*@{*/ ++extern void ifxhcd_complete_urb (ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status); ++ ++/*@}*/ ++ ++/*! \brief Deferred Transaction Execution Functions */ ++/*@{*/ ++ ++/*== AVM/BC 20101111 URB Complete List ==*/ ++extern void defer_ifxhcd_complete_urb (ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status); ++ ++/*! ++ \brief Clears the transfer state for a host channel. This function is normally ++ called after a transfer is done and the host channel is being released. ++ */ ++extern void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); ++ ++/*! ++ \brief Attempts to halt a host channel. This function should only be called in ++ Slave mode or to abort a transfer in either Slave mode or DMA mode. Under ++ normal circumstances in DMA mode, the controller halts the channel when the ++ transfer is complete or a condition occurs that requires application ++ intervention. ++ ++ In slave mode, checks for a free request queue entry, then sets the Channel ++ Enable and Channel Disable bits of the Host Channel Characteristics ++ register of the specified channel to intiate the halt. If there is no free ++ request queue entry, sets only the Channel Disable bit of the HCCHARn ++ register to flush requests for this channel. In the latter case, sets a ++ flag to indicate that the host channel needs to be halted when a request ++ queue slot is open. ++ ++ In DMA mode, always sets the Channel Enable and Channel Disable bits of the ++ HCCHARn register. The controller ensures there is space in the request ++ queue before submitting the halt request. ++ ++ Some time may elapse before the core flushes any posted requests for this ++ host channel and halts. The Channel Halted interrupt handler completes the ++ deactivation of the host channel. ++ */ ++extern void ifxhcd_hc_halt(ifxusb_core_if_t *_core_if, ++ ifxhcd_hc_t *_ifxhc, ++ ifxhcd_halt_status_e _halt_status); ++ ++/*! ++ \brief Prepares a host channel for transferring packets to/from a specific ++ endpoint. The HCCHARn register is set up with the characteristics specified ++ in _ifxhc. Host channel interrupts that may need to be serviced while this ++ transfer is in progress are enabled. ++ */ ++extern void ifxhcd_hc_init(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); ++ ++/*! ++ \brief This function is called to handle the disconnection of host port. ++ */ ++int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd); ++/*@}*/ ++ ++/*! \brief Interrupt Handler Functions */ ++/*@{*/ ++extern irqreturn_t ifxhcd_oc_irq(int _irq, void *_dev); ++ ++extern int32_t ifxhcd_handle_oc_intr(ifxhcd_hcd_t *_ifxhcd); ++extern int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd); ++/*@}*/ ++ ++ ++/*! \brief Schedule Queue Functions */ ++/*@{*/ ++extern ifxhcd_epqh_t *ifxhcd_epqh_create (ifxhcd_hcd_t *_ifxhcd, struct urb *_urb); ++extern void ifxhcd_epqh_free ( ifxhcd_epqh_t *_epqh); ++extern void select_eps (ifxhcd_hcd_t *_ifxhcd); ++extern void process_channels(ifxhcd_hcd_t *_ifxhcd); ++extern void process_channels_sub(ifxhcd_hcd_t *_ifxhcd); ++extern void complete_channel(ifxhcd_hcd_t *_ifxhcd, ifxhcd_hc_t *_ifxhc, ifxhcd_urbd_t *_urbd); ++extern void ifxhcd_epqh_ready(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); ++extern void ifxhcd_epqh_active(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); ++extern void ifxhcd_epqh_idle(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh); ++extern void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh); ++extern int ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb); ++/*@}*/ ++ ++/*! \brief Gets the usb_host_endpoint associated with an URB. */ ++static inline struct usb_host_endpoint *ifxhcd_urb_to_endpoint(struct urb *_urb) ++{ ++ struct usb_device *dev = _urb->dev; ++ int ep_num = usb_pipeendpoint(_urb->pipe); ++ ++ return (usb_pipein(_urb->pipe))?(dev->ep_in[ep_num]):(dev->ep_out[ep_num]); ++} ++ ++/*! ++ * \brief Gets the endpoint number from a _bEndpointAddress argument. The endpoint is ++ * qualified with its direction (possible 32 endpoints per device). ++ */ ++#define ifxhcd_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ ++ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) ++ ++ ++/* AVM/WK: not needed? ++ ++extern struct usb_device *usb_alloc_dev (struct usb_device *parent, struct usb_bus *, unsigned port); ++extern int usb_add_hcd (struct usb_hcd *syshcd, unsigned int irqnum, unsigned long irqflags); ++extern void usb_remove_hcd (struct usb_hcd *syshcd); ++extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name); ++extern void usb_hcd_giveback_urb (struct usb_hcd *syshcd, struct urb *urb); ++extern void usb_put_hcd (struct usb_hcd *syshcd); ++extern long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount); ++ ++*/ ++/** Internal Functions */ ++void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd); ++extern char *syserr(int errno); ++ ++/*@}*//*IFXUSB_HCD*/ ++ ++#endif // __IFXHCD_H__ +diff --git a/drivers/usb/ifxhcd/ifxhcd_es.c b/drivers/usb/ifxhcd/ifxhcd_es.c +new file mode 100644 +index 0000000..ef9e8c0 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd_es.c +@@ -0,0 +1,549 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd_es.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The file contain function to enable host mode USB-IF Electrical Test function. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxhcd_es.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief The file contain function to enable host mode USB-IF Electrical Test function. ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <linux/kernel.h> ++ ++#include <linux/errno.h> ++ ++#include <linux/dma-mapping.h> ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++#include "ifxhcd.h" ++ ++ ++#ifdef __WITH_HS_ELECT_TST__ ++ /* ++ * Quick and dirty hack to implement the HS Electrical Test ++ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature. ++ * ++ * This code was copied from our userspace app "hset". It sends a ++ * Get Device Descriptor control sequence in two parts, first the ++ * Setup packet by itself, followed some time later by the In and ++ * Ack packets. Rather than trying to figure out how to add this ++ * functionality to the normal driver code, we just hijack the ++ * hardware, using these two function to drive the hardware ++ * directly. ++ */ ++ ++ ++ void do_setup(ifxusb_core_if_t *_core_if) ++ { ++ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs; ++ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0]; ++ uint32_t *data_fifo = _core_if->data_fifo[0]; ++ ++ gint_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ ++ ++ /* Enable HAINTs */ ++ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* ++ * Send Setup packet (Get Device Descriptor) ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ // hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 8; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = IFXUSB_HC_PID_SETUP; ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ ++ /* Fill FIFO with Setup data for Get Device Descriptor */ ++ ifxusb_wreg(data_fifo++, 0x01000680); ++ ifxusb_wreg(data_fifo++, 0x00080000); ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Disable HCINTs */ ++ ifxusb_wreg(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ } ++ ++ void do_in_ack(ifxusb_core_if_t *_core_if) ++ { ++ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs; ++ ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0]; ++ uint32_t *data_fifo = _core_if->data_fifo[0]; ++ ++ gint_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ grxsts_data_t grxsts; ++ ++ /* Enable HAINTs */ ++ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* ++ * Receive Control In packet ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 8; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = IFXUSB_HC_PID_DATA1; ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; ++ hcchar.b.epdir = 1; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp); ++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.hb.pktsts) { ++ case IFXUSB_HSTS_DATA_UPDT: ++ /* Read the data into the host buffer */ ++ if (grxsts.hb.bcnt > 0) { ++ int i; ++ int word_count = (grxsts.hb.bcnt + 3) / 4; ++ ++ for (i = 0; i < word_count; i++) { ++ (void)ifxusb_rreg(data_fifo++); ++ } ++ } ++ ++ //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.hb.bcnt); ++ break; ++ ++ default: ++ //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n"); ++ break; ++ } ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp); ++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.hb.pktsts) { ++ case IFXUSB_HSTS_XFER_COMP: ++ break; ++ ++ default: ++ //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n"); ++ break; ++ } ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ // usleep(100000); ++ // mdelay(100); ++ mdelay(1); ++ ++ /* ++ * Send handshake packet ++ */ ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ //fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32); ++ hcchar.b.chdis = 1; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //if (hcchar.b.chen) { ++ // fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32); ++ //} ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 0; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = IFXUSB_HC_PID_DATA1; ++ ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Disable HCINTs */ ++ ifxusb_wreg(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = ifxusb_rreg(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = ifxusb_rreg(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ ifxusb_wreg(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ ifxusb_wreg(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ } ++#endif //__WITH_HS_ELECT_TST__ ++ +diff --git a/drivers/usb/ifxhcd/ifxhcd_intr.c b/drivers/usb/ifxhcd/ifxhcd_intr.c +new file mode 100644 +index 0000000..76fe602 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd_intr.c +@@ -0,0 +1,3742 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd_intr.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the implementation of the HCD Interrupt handlers. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxhcd_intr.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the implementation of the HCD Interrupt handlers. ++*/ ++ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++#include "ifxhcd.h" ++ ++/* AVM/WK 20100520*/ ++#ifdef __EN_ISOC__ ++#error AVM/WK: CONFIG_USB_HOST_IFX_WITH_ISO currently not supported! ++#endif ++ ++/* Macro used to clear one channel interrupt */ ++#define clear_hc_int(_hc_regs_,_intr_) \ ++ do { \ ++ hcint_data_t hcint_clear = {.d32 = 0}; \ ++ hcint_clear.b._intr_ = 1; \ ++ ifxusb_wreg(&((_hc_regs_)->hcint), hcint_clear.d32); \ ++ } while (0) ++ ++/* ++ * Macro used to disable one channel interrupt. Channel interrupts are ++ * disabled when the channel is halted or released by the interrupt handler. ++ * There is no need to handle further interrupts of that type until the ++ * channel is re-assigned. In fact, subsequent handling may cause crashes ++ * because the channel structures are cleaned up when the channel is released. ++ */ ++#define disable_hc_int(_hc_regs_,_intr_) \ ++ do { \ ++ hcint_data_t hcintmsk = {.d32 = 0}; \ ++ hcintmsk.b._intr_ = 1; \ ++ ifxusb_mreg(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \ ++ } while (0) ++ ++#define enable_hc_int(_hc_regs_,_intr_) \ ++ do { \ ++ hcint_data_t hcintmsk = {.d32 = 0}; \ ++ hcintmsk.b._intr_ = 1; \ ++ ifxusb_mreg(&((_hc_regs_)->hcintmsk),0, hcintmsk.d32); \ ++ } while (0) ++ ++/* ++ * Save the starting data toggle for the next transfer. The data toggle is ++ * saved in the QH for non-control transfers and it's saved in the QTD for ++ * control transfers. ++ */ ++uint8_t read_data_toggle(ifxusb_hc_regs_t *_hc_regs) ++{ ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ return(hctsiz.b.pid); ++} ++ ++ ++static void release_channel_dump(ifxhcd_hc_t *ifxhc, ++ struct urb *urb, ++ ifxhcd_epqh_t *epqh, ++ ifxhcd_urbd_t *urbd, ++ ifxhcd_halt_status_e halt_status) ++{ ++ #ifdef __DEBUG__ ++ printk(KERN_INFO); ++ switch (halt_status) ++ { ++ case HC_XFER_NO_HALT_STATUS: ++ printk("HC_XFER_NO_HALT_STATUS");break; ++ case HC_XFER_URB_COMPLETE: ++ printk("HC_XFER_URB_COMPLETE");break; ++ case HC_XFER_AHB_ERR: ++ printk("HC_XFER_AHB_ERR");break; ++ case HC_XFER_STALL: ++ printk("HC_XFER_STALL");break; ++ case HC_XFER_BABBLE_ERR: ++ printk("HC_XFER_BABBLE_ERR");break; ++ case HC_XFER_XACT_ERR: ++ printk("HC_XFER_XACT_ERR");break; ++ case HC_XFER_URB_DEQUEUE: ++ printk("HC_XFER_URB_DEQUEUE");break; ++ case HC_XFER_FRAME_OVERRUN: ++ printk("HC_XFER_FRAME_OVERRUN");break; ++ case HC_XFER_DATA_TOGGLE_ERR: ++ printk("HC_XFER_DATA_TOGGLE_ERR");break; ++ case HC_XFER_NAK: ++ printk("HC_XFER_NAK");break; ++ case HC_XFER_COMPLETE: ++ printk("HC_XFER_COMPLETE");break; ++ default: ++ printk("KNOWN");break; ++ } ++ if(ifxhc) ++ printk("Ch %d %s%s S%d " , ifxhc->hc_num ++ ,(ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL)?"CTRL-": ++ ((ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)?"BULK-": ++ ((ifxhc->ep_type == IFXUSB_EP_TYPE_INTR)?"INTR-": ++ ((ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)?"ISOC-":"????" ++ ) ++ ) ++ ) ++ ,(ifxhc->is_in)?"IN":"OUT" ++ ,(ifxhc->split) ++ ); ++ else ++ printk(" [NULL HC] "); ++ printk("urb=%p epqh=%p urbd=%p\n",urb,epqh,urbd); ++ ++ if(urb) ++ { ++ printk(KERN_INFO " Device address: %d\n", usb_pipedevice(urb->pipe)); ++ printk(KERN_INFO " Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), ++ (usb_pipein(urb->pipe) ? "IN" : "OUT")); ++ printk(KERN_INFO " Endpoint type: %s\n", ++ ({char *pipetype; ++ switch (usb_pipetype(urb->pipe)) { ++ case PIPE_CONTROL: pipetype = "CTRL"; break; ++ case PIPE_BULK: pipetype = "BULK"; break; ++ case PIPE_INTERRUPT: pipetype = "INTR"; break; ++ case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; ++ default: pipetype = "????"; break; ++ }; pipetype;})); ++ printk(KERN_INFO " Speed: %s\n", ++ ({char *speed; ++ switch (urb->dev->speed) { ++ case USB_SPEED_HIGH: speed = "HS"; break; ++ case USB_SPEED_FULL: speed = "FS"; break; ++ case USB_SPEED_LOW: speed = "LS"; break; ++ default: speed = "????"; break; ++ }; speed;})); ++ printk(KERN_INFO " Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ printk(KERN_INFO " Data buffer length: %d\n", urb->transfer_buffer_length); ++ printk(KERN_INFO " Transfer buffer: %p, Transfer DMA: %p\n", ++ urb->transfer_buffer, (void *)urb->transfer_dma); ++ printk(KERN_INFO " Setup buffer: %p, Setup DMA: %p\n", ++ urb->setup_packet, (void *)urb->setup_dma); ++ printk(KERN_INFO " Interval: %d\n", urb->interval); ++ switch (urb->status) ++ { ++ case HC_XFER_NO_HALT_STATUS: ++ printk(KERN_INFO " STATUS:HC_XFER_NO_HALT_STATUS\n");break; ++ case HC_XFER_URB_COMPLETE: ++ printk(KERN_INFO " STATUS:HC_XFER_URB_COMPLETE\n");break; ++ case HC_XFER_AHB_ERR: ++ printk(KERN_INFO " STATUS:HC_XFER_AHB_ERR\n");break; ++ case HC_XFER_STALL: ++ printk(KERN_INFO " STATUS:HC_XFER_STALL\n");break; ++ case HC_XFER_BABBLE_ERR: ++ printk(KERN_INFO " STATUS:HC_XFER_BABBLE_ERR\n");break; ++ case HC_XFER_XACT_ERR: ++ printk(KERN_INFO " STATUS:HC_XFER_XACT_ERR\n");break; ++ case HC_XFER_URB_DEQUEUE: ++ printk(KERN_INFO " STATUS:HC_XFER_URB_DEQUEUE\n");break; ++ case HC_XFER_FRAME_OVERRUN: ++ printk(KERN_INFO " STATUS:HC_XFER_FRAME_OVERRUN\n");break; ++ case HC_XFER_DATA_TOGGLE_ERR: ++ printk(KERN_INFO " STATUS:HC_XFER_DATA_TOGGLE_ERR\n");break; ++ case HC_XFER_COMPLETE: ++ printk(KERN_INFO " STATUS:HC_XFER_COMPLETE\n");break; ++ default: ++ printk(KERN_INFO " STATUS:KNOWN\n");break; ++ } ++ } ++ #endif ++} ++ ++ ++static void release_channel(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxhcd_halt_status_e _halt_status) ++{ ++ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; ++ struct urb *urb = NULL; ++ ifxhcd_epqh_t *epqh = NULL; ++ ifxhcd_urbd_t *urbd = NULL; ++ ++ IFX_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", ++ __func__, _ifxhc->hc_num, _halt_status); ++ ++ epqh=_ifxhc->epqh; ++ ++ if(!epqh) ++ IFX_ERROR("%s epqh=null\n",__func__); ++ else ++ { ++ urbd=epqh->urbd; ++ if(!urbd) ++ IFX_ERROR("%s urbd=null\n",__func__); ++ else ++ { ++ urb=urbd->urb; ++ if(!urb) ++ IFX_ERROR("%s urb =null\n",__func__); ++ else { ++ /* == AVM/WK 20100710 Fix - Use toggle of usbcore ==*/ ++ unsigned toggle = (read_data_toggle(hc_regs) == IFXUSB_HC_PID_DATA0)? 0: 1; ++ usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout(urb->pipe), toggle); ++ } ++ } ++ //epqh->data_toggle = read_data_toggle(hc_regs); ++ ++ } ++ ++ switch (_halt_status) ++ { ++ case HC_XFER_NO_HALT_STATUS: ++ IFX_ERROR("%s: No halt_status, channel %d\n", __func__, _ifxhc->hc_num); ++ break; ++ case HC_XFER_COMPLETE: ++ IFX_ERROR("%s: Inavalid halt_status HC_XFER_COMPLETE, channel %d\n", __func__, _ifxhc->hc_num); ++ break; ++ case HC_XFER_URB_COMPLETE: ++ case HC_XFER_URB_DEQUEUE: ++ case HC_XFER_AHB_ERR: ++ case HC_XFER_XACT_ERR: ++ case HC_XFER_FRAME_OVERRUN: ++ if(urbd && urb) { ++ /* == 20110803 AVM/WK FIX set status, if still in progress == */ ++ if (urb->status == -EINPROGRESS) { ++ switch (_halt_status) { ++ case HC_XFER_URB_COMPLETE: ++ urb->status = 0; ++ break; ++ case HC_XFER_URB_DEQUEUE: ++ urb->status = -ECONNRESET; ++ break; ++ case HC_XFER_AHB_ERR: ++ case HC_XFER_XACT_ERR: ++ case HC_XFER_FRAME_OVERRUN: ++ urb->status = -EPROTO; ++ break; ++ default: ++ break; ++ } ++ } ++ /*== AVM/BC 20101111 Deferred Complete ==*/ ++ defer_ifxhcd_complete_urb(_ifxhcd, urbd, urb->status); ++ } ++ else ++ { ++ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ } ++ if(epqh) ++ ifxhcd_epqh_idle(_ifxhcd, epqh); ++ else ++ { ++ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ } ++ ++ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); ++ break; ++ case HC_XFER_STALL: ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ if(urbd) ++ /*== AVM/BC 20101111 Deferred Complete ==*/ ++ defer_ifxhcd_complete_urb(_ifxhcd, urbd, -EPIPE); ++ else ++ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); ++ if(epqh) ++ { ++// epqh->data_toggle = 0; ++ ifxhcd_epqh_idle(_ifxhcd, epqh); ++ } ++ else ++ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); ++ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); ++ break; ++ case HC_XFER_NAK: ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ if(urbd) ++ { ++ //ifxhcd_complete_urb(_ifxhcd, urbd, -ETIMEDOUT); ++ urb->status = 0; ++ /*== AVM/BC 20101111 Deferred Complete ==*/ ++ defer_ifxhcd_complete_urb(_ifxhcd, urbd, urb->status); ++ } ++ else ++ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); ++ if(epqh) ++ ifxhcd_epqh_idle(_ifxhcd, epqh); ++ else ++ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); ++ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); ++ break; ++ case HC_XFER_BABBLE_ERR: ++ case HC_XFER_DATA_TOGGLE_ERR: ++ release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); ++ if(urbd) ++ /*== AVM/BC 20101111 Deferred Complete ==*/ ++ defer_ifxhcd_complete_urb(_ifxhcd, urbd, -EOVERFLOW); ++ else ++ IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); ++ if(epqh) ++ ifxhcd_epqh_idle(_ifxhcd, epqh); ++ else ++ IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); ++ list_add_tail(&_ifxhc->hc_list_entry, &_ifxhcd->free_hc_list); ++ ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); ++ break; ++ } ++ select_eps(_ifxhcd); ++} ++ ++/* ++ * Updates the state of the URB after a Transfer Complete interrupt on the ++ * host channel. Updates the actual_length field of the URB based on the ++ * number of bytes transferred via the host channel. Sets the URB status ++ * if the data transfer is finished. ++ * ++ * @return 1 if the data transfer specified by the URB is completely finished, ++ * 0 otherwise. ++ */ ++static int update_urb_state_xfer_comp(ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ struct urb *_urb, ++ ifxhcd_urbd_t *_urbd) ++{ ++ int xfer_done = 0; ++ ++ if (_ifxhc->is_in) ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ _urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ if ((hctsiz.b.xfersize != 0) || (_urb->actual_length >= _urb->transfer_buffer_length)) ++ { ++ xfer_done = 1; ++ _urb->status = 0; ++ /* 20110805 AVM/WK Workaround: catch overflow error here, hardware does not */ ++ if (_urb->actual_length > _urb->transfer_buffer_length) { ++ _urb->status = -EOVERFLOW; ++ } ++ #if 0 ++ if (_urb->actual_length < _urb->transfer_buffer_length && _urb->transfer_flags & URB_SHORT_NOT_OK) ++ _urb->status = -EREMOTEIO; ++ #endif ++ } ++ ++ } ++ else ++ { ++ if (_ifxhc->split) ++ _urb->actual_length += _ifxhc->ssplit_out_xfer_count; ++ else ++ _urb->actual_length += _ifxhc->xfer_len; ++ ++ if (_urb->actual_length >= _urb->transfer_buffer_length) ++ { ++ /*== AVM/BC WK 20110421 ZERO PACKET Workaround ==*/ ++ if ((_ifxhc->short_rw == 1) && ( _ifxhc->xfer_len > 0) && ( _ifxhc->xfer_len % _ifxhc->mps == 0 )) ++ { ++ _ifxhc->short_rw = 0; ++ //Transfer not finished. Another iteration for ZLP. ++ } ++ else ++ { ++ xfer_done = 1; ++ } ++ _urb->status = 0; ++ } ++ } ++ ++ #ifdef __DEBUG__ ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB: %s: %s, channel %d\n", ++ __func__, (_ifxhc->is_in ? "IN" : "OUT"), _ifxhc->hc_num); ++ IFX_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _ifxhc->xfer_len); ++ IFX_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize); ++ IFX_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", ++ _urb->transfer_buffer_length); ++ IFX_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length); ++ } ++ #endif ++ return xfer_done; ++} ++ ++/*== AVM/BC 20101111 Function called with Lock ==*/ ++ ++void complete_channel(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxhcd_urbd_t *_urbd) ++{ ++ ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; ++ struct urb *urb = NULL; ++ ifxhcd_epqh_t *epqh = NULL; ++ int urb_xfer_done; ++ ++ IFX_DEBUGPL(DBG_HCD, "--Complete Channel %d : \n", _ifxhc->hc_num); ++ ++ if(!_urbd) ++ { ++ IFX_ERROR("ERROR %s():%d urbd=%p\n",__func__,__LINE__,_urbd); ++ return; ++ } ++ ++ urb = _urbd->urb; ++ epqh = _urbd->epqh; ++ ++ if(!urb || !epqh) ++ { ++ IFX_ERROR("ERROR %s():%d urb=%p epqh=%p\n",__func__,__LINE__,urb,epqh); ++ return; ++ } ++ ++ _ifxhc->do_ping=0; ++ ++ if (_ifxhc->split) ++ _ifxhc->split = 1; ++ ++ switch (epqh->ep_type) ++ { ++ case IFXUSB_EP_TYPE_CTRL: ++ switch (_ifxhc->control_phase) ++ { ++ case IFXHCD_CONTROL_SETUP: ++ IFX_DEBUGPL(DBG_HCDV, " Control setup transaction done\n"); ++ if (_urbd->xfer_len > 0) ++ { ++ _ifxhc->control_phase = IFXHCD_CONTROL_DATA; ++ _ifxhc->is_in = _urbd->is_in; ++ _ifxhc->xfer_len = _urbd->xfer_len; ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ if(epqh->using_aligned_buf) ++ _ifxhc->xfer_buff = epqh->aligned_buf; ++ else ++ #endif ++ _ifxhc->xfer_buff = _urbd->xfer_buff; ++ } ++ else ++ { ++ _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; ++ _ifxhc->is_in = 1; ++ _ifxhc->xfer_len = 0; ++ _ifxhc->xfer_buff = _ifxhcd->status_buf; ++ } ++ if(_ifxhc->is_in) ++ _ifxhc->short_rw =0; ++ else ++ _ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ _ifxhc->xfer_count = 0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ /*== AVM/BC 20101111 Lock not needed ==*/ ++ process_channels_sub(_ifxhcd); ++ break; ++ case IFXHCD_CONTROL_DATA: ++ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); ++ if (urb_xfer_done) ++ { ++ _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; ++ _ifxhc->is_in = (_urbd->is_in)?0:1; ++ _ifxhc->xfer_len = 0; ++ _ifxhc->xfer_count = 0; ++ _ifxhc->xfer_buff = _ifxhcd->status_buf; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ if(_ifxhc->is_in) ++ _ifxhc->short_rw =0; ++ else ++ _ifxhc->short_rw =1; ++ } ++ else // continue ++ { ++ _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; ++ _ifxhc->xfer_count = urb->actual_length; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->data_pid_start = read_data_toggle(hc_regs); ++ } ++ /*== AVM/BC 20101111 Lock not needed ==*/ ++ process_channels_sub(_ifxhcd); ++ break; ++ case IFXHCD_CONTROL_STATUS: ++ if (urb->status == -EINPROGRESS) ++ urb->status = 0; ++ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); ++ break; ++ } ++ break; ++ case IFXUSB_EP_TYPE_BULK: ++ IFX_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); ++ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); ++ if (urb_xfer_done) ++ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); ++ else ++ { ++ _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; ++ _ifxhc->xfer_count = urb->actual_length; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->data_pid_start = read_data_toggle(hc_regs); ++ /*== AVM/BC 20101111 Lock not needed ==*/ ++ process_channels_sub(_ifxhcd); ++ } ++ break; ++ case IFXUSB_EP_TYPE_INTR: ++ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); ++ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); ++ break; ++ case IFXUSB_EP_TYPE_ISOC: ++// if (_urbd->isoc_split_pos == IFXUSB_HCSPLIT_XACTPOS_ALL) ++// halt_status = update_isoc_urb_state(_ifxhcd, _ifxhc, hc_regs, _urbd, HC_XFER_COMPLETE); ++// complete_periodic_xfer(_ifxhcd, _ifxhc, hc_regs, _urbd, halt_status); ++ urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); ++ release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); ++ break; ++ } ++} ++ ++ ++ ++void showint(uint32_t val_hcint ++ ,uint32_t val_hcintmsk ++ ,uint32_t val_hctsiz) ++{ ++#ifdef __DEBUG__ ++ hcint_data_t hcint = {.d32 = val_hcint}; ++ hcint_data_t hcintmsk = {.d32 = val_hcintmsk}; ++ ++ printk(KERN_INFO " WITH FLAG: Sz:%08x I:%08X/M:%08X %s%s%s%s%s%s%s%s%s%s\n" ++ ,val_hctsiz,hcint.d32 ,hcintmsk.d32 ++ ,(hcint.b.datatglerr || hcintmsk.b.datatglerr)? ++ ( ++ (hcint.b.datatglerr && hcintmsk.b.datatglerr)?"datatglerr[*/*] ": ++ ( ++ (hcint.b.datatglerr)?"datatglerr[*/] ":"datatglerr[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.frmovrun || hcintmsk.b.frmovrun)? ++ ( ++ (hcint.b.frmovrun && hcintmsk.b.frmovrun)?"frmovrun[*/*] ": ++ ( ++ (hcint.b.frmovrun)?"frmovrun[*/] ":"frmovrun[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.bblerr || hcintmsk.b.bblerr)? ++ ( ++ (hcint.b.bblerr && hcintmsk.b.bblerr)?"bblerr[*/*] ": ++ ( ++ (hcint.b.bblerr)?"bblerr[*/] ":"bblerr[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.xacterr || hcintmsk.b.xacterr)? ++ ( ++ (hcint.b.xacterr && hcintmsk.b.xacterr)?"xacterr[*/*] ": ++ ( ++ (hcint.b.xacterr)?"xacterr[*/] ":"xacterr[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.nyet || hcintmsk.b.nyet)? ++ ( ++ (hcint.b.nyet && hcintmsk.b.nyet)?"nyet[*/*] ": ++ ( ++ (hcint.b.nyet)?"nyet[*/] ":"nyet[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.nak || hcintmsk.b.nak)? ++ ( ++ (hcint.b.nak && hcintmsk.b.nak)?"nak[*/*] ": ++ ( ++ (hcint.b.nak)?"nak[*/] ":"nak[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.ack || hcintmsk.b.ack)? ++ ( ++ (hcint.b.ack && hcintmsk.b.ack)?"ack[*/*] ": ++ ( ++ (hcint.b.ack)?"ack[*/] ":"ack[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.stall || hcintmsk.b.stall)? ++ ( ++ (hcint.b.stall && hcintmsk.b.stall)?"stall[*/*] ": ++ ( ++ (hcint.b.stall)?"stall[*/] ":"stall[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.ahberr || hcintmsk.b.ahberr)? ++ ( ++ (hcint.b.ahberr && hcintmsk.b.ahberr)?"ahberr[*/*] ": ++ ( ++ (hcint.b.ahberr)?"ahberr[*/] ":"ahberr[/*] " ++ ) ++ ) ++ :"" ++ ,(hcint.b.xfercomp || hcintmsk.b.xfercomp)? ++ ( ++ (hcint.b.xfercomp && hcintmsk.b.xfercomp)?"xfercomp[*/*] ": ++ ( ++ (hcint.b.xfercomp)?"xfercomp[*/] ":"xfercomp[/*] " ++ ) ++ ) ++ :"" ++ ); ++#endif ++} ++ ++ ++extern void ifxhcd_hc_dumb_rx(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc,uint8_t *dump_buf); ++ ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->do_ping = 0; ++ ++ if(_ifxhc->halt_status == HC_XFER_NAK) ++ { ++ if(_ifxhc->nak_retry_r) ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->nak_retry--; ++ if(_ifxhc->nak_retry) ++ { ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ } ++ } ++ else ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ ++ if (hcint.b.xfercomp) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if (hcint.b.stall) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ // ZLP shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ // Stall FIFO compensation. ++ #if 0 ++ int sz1,sz2; ++ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; ++ sz2*=_ifxhc->mps; ++ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; ++ sz2-=sz1; ++ if(sz2) ++ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); ++ #endif ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ } ++ return 1; ++ } ++ else if (hcint.b.bblerr) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ ++ // ZLP shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if (hcint.b.xacterr) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ++ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ ++ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { ++ _urbd->error_count = 1; ++ } else { ++ _urbd->error_count++; ++ } ++ ++ if (_urbd->error_count >= 3) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ #if 1 ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ #else ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ #endif ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT0 FRMOVRUN [should be Period only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.nyet ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT0 NYET [should be Out only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++#ifdef __DEBUG__ ++static int first=0; ++#endif ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++#ifdef __DEBUG__ ++if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK ++ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) ++{ ++ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ first=1; ++ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" ++ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) ++ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) ++ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) ++ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); ++ ++ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" ++ ,_urbd->urb->actual_length ++ ,_ifxhc->start_pkt_count ++ ,hctsiz.b.pktcnt ++ ,_urbd->xfer_len); ++} ++#endif ++ ++ if(_ifxhc->halt_status == HC_XFER_NAK) ++ { ++ if(_ifxhc->nak_retry_r) ++ { ++ _ifxhc->nak_retry--; ++ if(_ifxhc->nak_retry) ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ } ++ } ++ else ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ ++ if (hcint.b.xfercomp) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak) ++ { ++ // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr ++ // Solution: NoSplit: Resend at next SOF ++ // Split : Resend at next SOF with SSPLIT ++ if(hcint.b.nyet && !out_nak_enh) ++ _ifxhc->do_ping = 1; ++ else ++ _ifxhc->do_ping = 0; ++ _ifxhc->xfer_len = 0; ++ _ifxhc->xfer_count = 0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if (hcint.b.stall) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ } ++ return 1; ++ } ++ else if (hcint.b.xacterr) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ++ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =1; ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ if(!out_nak_enh) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _urbd->error_count ++ ; ++ if (_urbd->error_count == 3) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof =1; ++ if(!out_nak_enh) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ } ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 BABBLE [should be IN only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _ifxhc->do_ping = 0; ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.nak || hcint.b.nyet) ++ { ++ if(!out_nak_enh) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ if(!out_nak_enh) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ if(_ifxhc->xfer_len!=0) ++ { ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ } ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 DATATGLERR [should be IN only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT0 FRMOVRUN [should be PERIODIC only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->do_ping =0; ++ ++ if(_ifxhc->halt_status == HC_XFER_NAK) ++ { ++ if(_ifxhc->nak_retry_r) ++ { ++ _ifxhc->nak_retry--; ++ if(_ifxhc->nak_retry) ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ } ++ } ++ else ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ ++ if(hcint.b.xfercomp ) ++ { ++ _urbd->error_count =0; ++ //restart INTR immediately ++ #if 1 ++ if(hctsiz.b.pktcnt>0) ++ { ++ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if (hcint.b.stall) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ ++ // Don't care shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ // Stall FIFO compensation. ++ #if 0 ++ int sz1,sz2; ++ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; ++ sz2*=_ifxhc->mps; ++ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; ++ sz2-=sz1; ++ if(sz2) ++ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); ++ #endif ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ } ++ return 1; ++ } ++ ++ ++ else if (hcint.b.bblerr) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ ++ // Don't care shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ } ++ return 1; ++ } ++ else if (hcint.b.nak || hcint.b.datatglerr || hcint.b.frmovrun) ++ { ++ _urbd->error_count =0; ++ //restart INTR immediately ++ #if 1 ++ if(hctsiz.b.pktcnt>0) ++ { ++ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if (hcint.b.xacterr) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ ++ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { ++ _urbd->error_count = 1; ++ } else { ++ _urbd->error_count++; ++ } ++ ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ return 1; ++ } ++ else if(hcint.b.nyet ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT0 NYET [should be OUT only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ if(_ifxhc->halt_status == HC_XFER_NAK) ++ { ++ if(_ifxhc->nak_retry_r) ++ { ++ _ifxhc->nak_retry--; ++ if(_ifxhc->nak_retry) ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ } ++ } ++ else ++ { ++ if(_ifxhc->xfer_len!=0) ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ ++ if(hcint.b.xfercomp ) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count =0; ++ //restart INTR immediately ++ #if 0 ++ if(hctsiz.b.pktcnt>0) ++ { ++ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ if(hcint.b.nyet && !out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if (hcint.b.stall) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nyet); ++ disable_hc_int(_hc_regs,nak); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ ++ // Don't care shortcut ++ #if 0 ++ if(hctsiz.b.pktcnt==0) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ #endif ++ { ++ if(_ifxhc->xfer_len!=0)// !_ifxhc->is_in ++ _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ } ++ return 1; ++ } ++ else if(hcint.b.nak || hcint.b.frmovrun ) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nyet); ++ disable_hc_int(_hc_regs,nak); ++ _urbd->error_count =0; ++ //restart INTR immediately ++ #if 0 ++ if(hctsiz.b.pktcnt>0) ++ { ++ // TODO Re-initialize Channel (in next b_interval - 1 uF/F) ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ // ZLP shortcut ++ #if 1 ++ if(hctsiz.b.pktcnt==0) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ #endif ++ { ++ /* 20110803 AVM/WK FIX: Reset error count on any handshake */ ++ if (hcint.b.nak || hcint.b.nyet || hcint.b.ack) { ++ _urbd->error_count = 1; ++ } else { ++ _urbd->error_count++; ++ } ++ ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ //_ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ //if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _ifxhc->wait_for_sof=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++IFX_WARN("%s() %d Warning INTR OUT SPLIT0 BABBLEERR [should be IN only]\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN("%s() %d Warning INTR OUT SPLIT0 DATATGLERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ if (hcint.b.xfercomp || hcint.b.frmovrun) ++ { ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof = 0; ++ if (hcint.b.xfercomp) ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ else ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ } ++ else if (hcint.b.xacterr || hcint.b.bblerr) ++ { ++ #ifndef VR9Skip ++ if(hctsiz.b.pktcnt==0) ++ { ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ { ++ int sz1,sz2; ++ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; ++ sz2*=_ifxhc->mps; ++ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; ++ sz2-=sz1; ++ if(sz2) ++ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 1; ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ #endif ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.stall ) ++ { ++ warning ++ } ++ #else ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ if (hcint.b.xfercomp) ++ { ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof = 0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if (hcint.b.frmovrun) ++ { ++ #ifndef VR9Skip ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ #endif ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.bblerr ) ++ { ++ #ifndef VR9Skip ++ if(hctsiz.b.pktcnt==0) ++ { ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ else ++ { ++ int sz1,sz2; ++ sz2=_ifxhc->start_pkt_count - hctsiz.b.pktcnt; ++ sz2*=_ifxhc->mps; ++ sz1=_ifxhc->xfer_len - hctsiz.b.xfersize; ++ sz2-=sz1; ++ if(sz2) ++ ifxhcd_hc_dumb_rx(&_ifxhcd->core_if, _ifxhc,_ifxhc->epqh->dump_buf); ++ _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 1; ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ } ++ #endif ++ } ++ else if(hcint.b.xacterr ) ++ { ++ if(hctsiz.b.pktcnt==0) ++ { ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ warning ++ } ++ #else ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ _ifxhc->do_ping =0; ++ ++ if (hcint.b.ack) ++ { ++ _urbd->error_count=0; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof = 8; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if (hcint.b.nak) ++ { ++ _ifxhc->wait_for_sof = 1; ++ _urbd->error_count = 0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if (hcint.b.xacterr) ++ { ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof =1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 HC_XFER_DATA_TOGGLE_ERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 HC_XFER_FRAME_OVERRUN\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.nyet ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 NYET\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ else if(hcint.b.xfercomp ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK IN SPLIT1 COMPLETE\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++#ifdef __DEBUG__ ++static int first=0; ++#endif ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++#ifdef __DEBUG__ ++ if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK ++ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) ++ { ++ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ first=1; ++ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" ++ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) ++ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) ++ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) ++ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); ++ ++ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" ++ ,_urbd->urb->actual_length ++ ,_ifxhc->start_pkt_count ++ ,hctsiz.b.pktcnt ++ ,_urbd->xfer_len); ++ } ++#endif ++ ++ if (hcint.b.ack ) ++ { ++ _urbd->error_count=0; ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK || _ifxhc->control_phase != IFXHCD_CONTROL_SETUP) ++ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof =8; ++ _ifxhc->data_pid_start =read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT1 NYET\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count=0; ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK || _ifxhc->control_phase != IFXHCD_CONTROL_SETUP) ++ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof =1; ++ _ifxhc->data_pid_start =read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _ifxhc->wait_for_sof =1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _urbd->error_count =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof =1; ++ _ifxhc->do_ping =1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++IFX_WARN("%s() %d Warning CTRLBULK OUT SPLIT1 HC_XFER_FRAME_OVERRUN\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ _ifxhc->do_ping =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.xfercomp ) ++ { ++ printk(KERN_INFO "%s() %d Warning CTRLBULK OUT SPLIT1 COMPLETE\n",__func__,__LINE__); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ _ifxhc->do_ping =0; ++ ++ if (hcint.b.ack ) ++ { ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ _ifxhc->nyet_count=0; ++ ++ _urbd->error_count=0; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _urbd->error_count=0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ _urbd->error_count=hcchar.b.multicnt; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN( "%s() %d Warning INTR IN SPLIT1 DATATGLERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.xfercomp ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 COMPLETE\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ if (hcint.b.ack ) ++ { ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ _ifxhc->nyet_count=0; ++ ++ _urbd->error_count=0; ++ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++IFX_WARN("%s() %d Warning INTR OUT SPLIT1 NYET\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count=0; ++ _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; ++ _ifxhc->split=2; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->data_pid_start = read_data_toggle(_hc_regs); ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _urbd->error_count =0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ _urbd->error_count=hcchar.b.multicnt; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ enable_hc_int(_hc_regs,ack); ++ enable_hc_int(_hc_regs,nak); ++ enable_hc_int(_hc_regs,nyet); ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 DATATGLERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 BABBLEERR\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 STALL\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof =0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.xfercomp ) ++ { ++IFX_WARN("%s() %d Warning INTR IN SPLIT1 COMPLETE\n",__func__,__LINE__); ++showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ if (hcint.b.ack ) ++ { ++ Do Complete Split ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ Rewind Buffer Pointers ++ Retry Start Split (in next b_interval ¡V 1 uF) ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.bblerr ) ++ { ++ warning ++ } ++ else if(hcint.b.xacterr ) ++ { ++ warning ++ } ++ else if(hcint.b.stall ) ++ { ++ warning ++ } ++ else if(hcint.b.nak ) ++ { ++ warning ++ } ++ else if(hcint.b.xfercomp ) ++ { ++ warning ++ } ++ else if(hcint.b.nyet) ++ { ++ warning ++ } ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ if (hcint.b.ack ) ++ { ++ Do Next Start Split (in next b_interval ¡V 1 uF) ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ Do Next Transaction in next frame. ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.bblerr ) ++ { ++ warning ++ } ++ else if(hcint.b.xacterr ) ++ { ++ warning ++ } ++ else if(hcint.b.stall ) ++ { ++ warning ++ } ++ else if(hcint.b.nak ) ++ { ++ warning ++ } ++ else if(hcint.b.xfercomp ) ++ { ++ warning ++ } ++ else if(hcint.b.nyet) ++ { ++ warning ++ } ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_rx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ _ifxhc->do_ping = 0; ++ ++ if (hcint.b.xfercomp) ++ { ++ _urbd->error_count =0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->split=1; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if (hcint.b.nak) ++ { ++ _urbd->error_count=0; ++ ++ _ifxhc->split = 1; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++ _urbd->error_count=0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.stall || hcint.b.bblerr ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ if (hcint.b.stall) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ else if(hcint.b.bblerr ) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_ctrlbulk_tx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++#if 1 ++static int first=0; ++#endif ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++#if 1 ++ if(!first&& _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK ++ &&(hcint.b.stall || hcint.b.datatglerr || hcint.b.frmovrun || hcint.b.bblerr || hcint.b.xacterr) && !hcint.b.ack) ++ { ++ showint( hcint.d32,hcintmsk.d32,hctsiz.d32); ++ first=1; ++ printk(KERN_INFO " [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X] \n" ++ ,*(_ifxhc->xfer_buff+ 0),*(_ifxhc->xfer_buff+ 1),*(_ifxhc->xfer_buff+ 2),*(_ifxhc->xfer_buff+ 3) ++ ,*(_ifxhc->xfer_buff+ 4),*(_ifxhc->xfer_buff+ 5),*(_ifxhc->xfer_buff+ 6),*(_ifxhc->xfer_buff+ 7) ++ ,*(_ifxhc->xfer_buff+ 8),*(_ifxhc->xfer_buff+ 9),*(_ifxhc->xfer_buff+10),*(_ifxhc->xfer_buff+11) ++ ,*(_ifxhc->xfer_buff+12),*(_ifxhc->xfer_buff+13),*(_ifxhc->xfer_buff+14),*(_ifxhc->xfer_buff+15)); ++ ++ printk(KERN_INFO " [_urbd->urb->actual_length:%08X _ifxhc->start_pkt_count:%08X hctsiz.b.pktcnt:%08X ,_urbd->xfer_len:%08x] \n" ++ ,_urbd->urb->actual_length ++ ,_ifxhc->start_pkt_count ++ ,hctsiz.b.pktcnt ++ ,_urbd->xfer_len); ++ } ++#endif ++ ++ if(hcint.b.xfercomp ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->split=1; ++ _ifxhc->do_ping= 0; ++ #if 0 ++ if(_ifxhc->xfer_len==0 && !hcint.b.ack && (hcint.b.nak || hcint.b.nyet)) ++ { ++ // Walkaround: When sending ZLP and receive NYEY or NAK but also issue CMPT intr ++ // Solution: NoSplit: Resend at next SOF ++ // Split : Resend at next SOF with SSPLIT ++ _ifxhc->xfer_len = 0; ++ _ifxhc->xfer_count = 0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ else ++ #endif ++ { ++ _ifxhc->wait_for_sof = 0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ } ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _urbd->error_count=0; ++ ++ _ifxhc->split = 1; ++ _ifxhc->wait_for_sof = 1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++ //Retry Complete Split ++ // Issue Retry instantly on next SOF, without gothrough process_channels ++ _urbd->error_count=0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ _ifxhc->do_ping = 0; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.stall ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ _urbd->error_count++; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = 1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = 1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_rx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _ifxhc->do_ping = 0; ++ ++ if (hcint.b.xfercomp ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->split=1; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->split = 1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++ _urbd->error_count=0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 0; ++ ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ _ifxhc->nyet_count++; ++ if(_ifxhc->nyet_count > 2) { ++ _ifxhc->split = 1; ++ _ifxhc->nyet_count = 0; ++ _ifxhc->wait_for_sof = 5; ++ } ++ ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun || hcint.b.bblerr || hcint.b.stall ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ if (hcint.b.stall) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ else if(hcint.b.bblerr ) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ else if(hcint.b.frmovrun ) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ _urbd->error_count=hcchar.b.multicnt; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_intr_tx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ ++ if(hcint.b.xfercomp ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->split=1; ++ _ifxhc->do_ping = 0; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->split = 1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.nyet) ++ { ++ _urbd->error_count=0; ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ ++ /*== AVM/BC 20100701 - Workaround FullSpeed Interrupts with HiSpeed Hub ==*/ ++ _ifxhc->nyet_count++; ++ if(_ifxhc->nyet_count > 2) { ++ _ifxhc->split = 1; ++ _ifxhc->nyet_count = 0; ++ _ifxhc->wait_for_sof = 5; ++ } ++ ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.stall || hcint.b.frmovrun) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ if (hcint.b.stall) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ else if(hcint.b.frmovrun ) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ _urbd->error_count=hcchar.b.multicnt; ++ if(_urbd->error_count>=3) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); ++ } ++ else ++ { ++ _ifxhc->split=1; ++ _ifxhc->wait_for_sof = _ifxhc->epqh->interval-1; ++ if(!_ifxhc->wait_for_sof) _ifxhc->wait_for_sof=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ } ++ return 1; ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; ++ else ++ _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; ++ _ifxhc->split=1; ++ if(!out_nak_enh ) ++ _ifxhc->do_ping =1; ++ else ++ _ifxhc->do_ping =0; ++ _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; ++ _ifxhc->xfer_count = _urbd->urb->actual_length; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.bblerr ) ++ { ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->do_ping = 0; ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); ++ return 1; ++ } ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_rx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ if(hcint.b.xfercomp ) ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,nyet); ++ _urbd->error_count=0; ++ _ifxhc->wait_for_sof = 0; ++ _ifxhc->split=1; ++ complete_channel(_ifxhcd, _ifxhc, _urbd); ++ return 1; ++ } ++ else if(hcint.b.nak ) ++ { ++ Retry Start Split (in next b_interval ¡V 1 uF) ++ } ++ else if(hcint.b.nyet) ++ { ++ //Do Next Complete Split ++ // Issue Retry instantly on next SOF, without gothrough process_channels ++ _urbd->error_count=0; ++ //disable_hc_int(_hc_regs,ack); ++ //disable_hc_int(_hc_regs,nak); ++ //disable_hc_int(_hc_regs,datatglerr); ++ _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; ++ _ifxhc->wait_for_sof = 1; ++ ifxhcd_hc_start(&_ifxhcd->core_if, _ifxhc); ++ return 1; ++ } ++ else if(hcint.b.frmovrun || hcint.b.stall || hcint.b.bblerr) ++ { ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nyet); ++ disable_hc_int(_hc_regs,nak); ++ _ifxhc->wait_for_sof = 0; ++ ++ //if(hctsiz.b.pktcnt==0) ++ //{ ++ // complete_channel(_ifxhcd, _ifxhc, _urbd); ++ // return 1; ++ //} ++ //else ++ // _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); ++ if (hcint.b.stall) ++ release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); ++ else if(hcint.b.frmovrun ) ++ else if(hcint.b.bblerr ) ++ return 1; ++ } ++ else if(hcint.b.xacterr ) ++ { ++ Rewind Buffer Pointers ++ if (HCCHARn.EC = = 3) // ERR response received ++ { ++ Record ERR error ++ Do Next Start Split (in next frame) ++ } ++ else ++ { ++ De-allocate Channel ++ } ++ } ++ else if(hcint.b.datatglerr ) ++ { ++ warning ++ } ++ else if(hcint.b.ack ) ++ { ++ warning ++ } ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++static int32_t chhltd_isoc_tx_csplit(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) ++ hcint_data_t hcint; ++ hcint_data_t hcintmsk; ++ hctsiz_data_t hctsiz; ++ int out_nak_enh = 0; ++ ++ if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) ++ out_nak_enh = 1; ++ ++ hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); ++ hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ warning ++ #endif ++ return 0; ++} ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++static int32_t handle_hc_chhltd_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: Channel Halted--\n", _ifxhc->hc_num); ++ ++ _ifxhc->halting = 0; ++ _ifxhc->xfer_started = 0; ++ ++ if (_ifxhc->halt_status == HC_XFER_URB_DEQUEUE || ++ _ifxhc->halt_status == HC_XFER_AHB_ERR) { ++ /* ++ * Just release the channel. A dequeue can happen on a ++ * transfer timeout. In the case of an AHB Error, the channel ++ * was forced to halt because there's no way to gracefully ++ * recover. ++ */ ++ release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); ++ return 1; ++ } ++ ++ if (_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL || _ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) ++ { ++ if (_ifxhc->split==0) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_ctrlbulk_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_ctrlbulk_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==1) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_ctrlbulk_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_ctrlbulk_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==2) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_ctrlbulk_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_ctrlbulk_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ } ++ else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR) ++ { ++ if (_ifxhc->split==0) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_intr_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_intr_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==1) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_intr_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_intr_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==2) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_intr_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_intr_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ } ++ else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ if (_ifxhc->split==0) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_isoc_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_isoc_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==1) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_isoc_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_isoc_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ else if(_ifxhc->split==2) ++ { ++ if(_ifxhc->is_in) ++ return (chhltd_isoc_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ else ++ return (chhltd_isoc_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Handles a host channel AHB error interrupt. This handler is only called in ++ * DMA mode. ++ */ ++static void hc_other_intr_dump(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ #ifdef __DEBUG__ ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ struct urb *urb = _urbd->urb; ++ hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); ++ hcsplt.d32 = ifxusb_rreg(&_hc_regs->hcsplt); ++ hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); ++ hcdma = ifxusb_rreg(&_hc_regs->hcdma); ++ ++ IFX_ERROR("Channel %d\n", _ifxhc->hc_num); ++ IFX_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ IFX_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); ++ IFX_ERROR(" Device address: %d\n", usb_pipedevice(urb->pipe)); ++ IFX_ERROR(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), ++ (usb_pipein(urb->pipe) ? "IN" : "OUT")); ++ IFX_ERROR(" Endpoint type: %s\n", ++ ({char *pipetype; ++ switch (usb_pipetype(urb->pipe)) { ++ case PIPE_CONTROL: pipetype = "CTRL"; break; ++ case PIPE_BULK: pipetype = "BULK"; break; ++ case PIPE_INTERRUPT: pipetype = "INTR"; break; ++ case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; ++ default: pipetype = "????"; break; ++ }; pipetype;})); ++ IFX_ERROR(" Speed: %s\n", ++ ({char *speed; ++ switch (urb->dev->speed) { ++ case USB_SPEED_HIGH: speed = "HS"; break; ++ case USB_SPEED_FULL: speed = "FS"; break; ++ case USB_SPEED_LOW: speed = "LS"; break; ++ default: speed = "????"; break; ++ }; speed;})); ++ IFX_ERROR(" Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ IFX_ERROR(" Data buffer length: %d\n", urb->transfer_buffer_length); ++ IFX_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", ++ urb->transfer_buffer, (void *)urb->transfer_dma); ++ IFX_ERROR(" Setup buffer: %p, Setup DMA: %p\n", ++ urb->setup_packet, (void *)urb->setup_dma); ++ IFX_ERROR(" Interval: %d\n", urb->interval); ++ #endif //__DEBUG__ ++} ++ ++/* ++ * Handles a host channel ACK interrupt. This interrupt is enabled when ++ * errors occur, and during Start Split transactions. ++ */ ++static int32_t handle_hc_ack_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ _urbd->error_count=0; ++ if(_ifxhc->nak_countdown_r) ++ { ++ _ifxhc->nak_retry=_ifxhc->nak_retry_r; ++ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; ++ } ++ else ++ disable_hc_int(_hc_regs,nak); ++ disable_hc_int(_hc_regs,ack); ++ return 1; ++} ++ ++/* ++ * Handles a host channel ACK interrupt. This interrupt is enabled when ++ * errors occur, and during Start Split transactions. ++ */ ++static int32_t handle_hc_nak_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ ++ _urbd->error_count=0; ++ ++ if(_ifxhc->nak_countdown_r) ++ { ++ _ifxhc->nak_countdown--; ++ if(!_ifxhc->nak_countdown) ++ { ++ _ifxhc->nak_countdown=_ifxhc->nak_countdown_r; ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ ifxhcd_hc_halt(&_ifxhcd->core_if, _ifxhc, HC_XFER_NAK); ++ } ++ else ++ enable_hc_int(_hc_regs,ack); ++ } ++ else ++ { ++ disable_hc_int(_hc_regs,ack); ++ disable_hc_int(_hc_regs,nak); ++ } ++ return 1; ++} ++ ++/* ++ * Handles a host channel AHB error interrupt. This handler is only called in ++ * DMA mode. ++ */ ++static int32_t handle_hc_ahberr_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "AHB Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ ++ ifxhcd_hc_halt(&_ifxhcd->core_if, _ifxhc, HC_XFER_AHB_ERR); ++ return 1; ++} ++ ++/* ++ * Datatoggle ++ */ ++static int32_t handle_hc_datatglerr_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "DATATOGGLE Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,datatglerr); ++ return 1; ++} ++ ++ ++ ++/* ++ * Interrupts which should not been triggered ++ */ ++static int32_t handle_hc_frmovrun_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "FrameOverRun Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,frmovrun); ++ return 1; ++} ++ ++static int32_t handle_hc_bblerr_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "BBL Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,bblerr); ++ return 1; ++} ++ ++static int32_t handle_hc_xacterr_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "XACT Error--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,xacterr); ++ return 1; ++} ++ ++static int32_t handle_hc_nyet_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "NYET--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ _urbd->error_count=0; ++ disable_hc_int(_hc_regs,nyet); ++ return 1; ++} ++ ++static int32_t handle_hc_stall_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "STALL--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,stall); ++ return 1; ++} ++ ++static int32_t handle_hc_xfercomp_intr(ifxhcd_hcd_t *_ifxhcd, ++ ifxhcd_hc_t *_ifxhc, ++ ifxusb_hc_regs_t *_hc_regs, ++ ifxhcd_urbd_t *_urbd) ++{ ++ IFX_ERROR( "--Host Channel %d Interrupt: " ++ "XFERCOMP--\n", _ifxhc->hc_num); ++ hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); ++ disable_hc_int(_hc_regs,xfercomp); ++ return 1; ++} ++ ++ ++ ++/* This interrupt indicates that the specified host channels has a pending ++ * interrupt. There are multiple conditions that can cause each host channel ++ * interrupt. This function determines which conditions have occurred for this ++ * host channel interrupt and handles them appropriately. */ ++static int32_t handle_hc_n_intr (ifxhcd_hcd_t *_ifxhcd, uint32_t _num) ++{ ++ uint32_t hcintval,hcintmsk; ++ hcint_data_t hcint; ++ ifxhcd_hc_t *ifxhc; ++ ifxusb_hc_regs_t *hc_regs; ++ ifxhcd_urbd_t *urbd; ++ unsigned long flags; ++ ++ int retval = 0; ++ ++ IFX_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num); ++ ++ /*== AVM/BC 20101111 Lock needed ==*/ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ ifxhc = &_ifxhcd->ifxhc[_num]; ++ hc_regs = _ifxhcd->core_if.hc_regs[_num]; ++ ++ hcintval = ifxusb_rreg(&hc_regs->hcint); ++ hcintmsk = ifxusb_rreg(&hc_regs->hcintmsk); ++ hcint.d32 = hcintval & hcintmsk; ++ IFX_DEBUGPL(DBG_HCDV, " 0x%08x & 0x%08x = 0x%08x\n", ++ hcintval, hcintmsk, hcint.d32); ++ ++ urbd = list_entry(ifxhc->epqh->urbd_list.next, ifxhcd_urbd_t, urbd_list_entry); ++ ++ if (hcint.b.datatglerr) ++ retval |= handle_hc_datatglerr_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.frmovrun) ++ retval |= handle_hc_frmovrun_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.bblerr) ++ retval |= handle_hc_bblerr_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.xacterr) ++ retval |= handle_hc_xacterr_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.nyet) ++ retval |= handle_hc_nyet_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.ack) ++ retval |= handle_hc_ack_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.nak) ++ retval |= handle_hc_nak_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.stall) ++ retval |= handle_hc_stall_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ if (hcint.b.ahberr) { ++ clear_hc_int(hc_regs, ahberr); ++ retval |= handle_hc_ahberr_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ } ++ if (hcint.b.chhltd) { ++ /* == 20110901 AVM/WK Fix: Flag must not be cleared after restart of channel ==*/ ++ clear_hc_int(hc_regs, chhltd); ++ retval |= handle_hc_chhltd_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ } ++ if (hcint.b.xfercomp) ++ retval |= handle_hc_xfercomp_intr(_ifxhcd, ifxhc, hc_regs, urbd); ++ ++ /* == 20110901 AVM/WK Fix: Never clear possibly new intvals ==*/ ++ //ifxusb_wreg(&hc_regs->hcint,hcintval); ++ ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ ++ return retval; ++} ++ ++ ++ ++ ++ ++ ++static uint8_t update_interval_counter(ifxhcd_epqh_t *_epqh,uint32_t _diff) ++{ ++ if(_diff>=_epqh->period_counter) ++ { ++ _epqh->period_do=1; ++ if(_diff>_epqh->interval) ++ _epqh->period_counter=1; ++ else ++ _epqh->period_counter=_epqh->period_counter+_epqh->interval-_diff; ++ return 1; ++ } ++ _epqh->period_counter=_epqh->period_counter-_diff; ++ return 0; ++} ++ ++ ++ ++ ++/* ++ * Handles the start-of-frame interrupt in host mode. Non-periodic ++ * transactions may be queued to the DWC_otg controller for the current ++ * (micro)frame. Periodic transactions may be queued to the controller for the ++ * next (micro)frame. ++ */ ++static int32_t handle_sof_intr (ifxhcd_hcd_t *_ifxhcd) ++{ ++ #ifdef __DYN_SOF_INTR__ ++ uint8_t with_count_down=0; ++ #endif ++ uint8_t active_on=0; ++ uint8_t ready_on=0; ++ struct list_head *epqh_entry; ++ ifxhcd_epqh_t *epqh; ++ hfnum_data_t hfnum; ++ uint32_t fndiff; ++ ++ unsigned long flags; ++#ifdef __USE_TIMER_4_SOF__ ++ uint32_t wait_for_sof = 0x10000; ++#endif ++ ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++ { ++ int num_channels; ++ ifxusb_hc_regs_t *hc_regs; ++ int i; ++ num_channels = _ifxhcd->core_if.params.host_channels; ++ ++// AVM/WK moved block here due to use of SOF timer ++ hfnum.d32 = ifxusb_rreg(&_ifxhcd->core_if.host_global_regs->hfnum); ++ fndiff = hfnum.b.frnum; ++ fndiff+= 0x00004000; ++ fndiff-= _ifxhcd->lastframe ; ++ fndiff&= 0x00003FFF; ++ if(!fndiff) fndiff =1; ++ ++ for (i = 0; i < num_channels; i++) ++ { ++ if(_ifxhcd->ifxhc[i].wait_for_sof && _ifxhcd->ifxhc[i].xfer_started) ++ { ++#ifdef __USE_TIMER_4_SOF__ ++ if (_ifxhcd->ifxhc[i].wait_for_sof > fndiff) { ++ _ifxhcd->ifxhc[i].wait_for_sof -= fndiff; ++ } else { ++ _ifxhcd->ifxhc[i].wait_for_sof = 0; ++ } ++#else ++ _ifxhcd->ifxhc[i].wait_for_sof--; ++#endif ++ if(_ifxhcd->ifxhc[i].wait_for_sof==0) ++ { ++ hcint_data_t hcint= { .d32=0 }; ++ hc_regs = _ifxhcd->core_if.hc_regs[i]; ++ ++ hcint.d32 =0xFFFFFFFF; ++ ifxusb_wreg(&hc_regs->hcint, hcint.d32); ++ ++ hcint.d32=ifxusb_rreg(&hc_regs->hcintmsk); ++ hcint.b.nak =0; ++ hcint.b.ack =0; ++ /* == 20110901 AVM/WK Fix: We don't need NOT YET IRQ ==*/ ++ hcint.b.nyet=0; ++ _ifxhcd->ifxhc[i].nak_countdown=_ifxhcd->ifxhc[i].nak_countdown_r; ++ if(_ifxhcd->ifxhc[i].nak_countdown_r) ++ hcint.b.nak =1; ++ ifxusb_wreg(&hc_regs->hcintmsk, hcint.d32); ++ ++ /* AVM WK / BC 20100827 ++ * FIX: Packet was ignored because of wrong Oddframe bit ++ */ ++ if (_ifxhcd->ifxhc[i].ep_type == IFXUSB_EP_TYPE_INTR || _ifxhcd->ifxhc[i].ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = _ifxhcd->ifxhc[i].hcchar; ++ hfnum.d32 = ifxusb_rreg(&_ifxhcd->core_if.host_global_regs->hfnum); ++ /* 1 if _next_ frame is odd, 0 if it's even */ ++ hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; ++ _ifxhcd->ifxhc[i].hcchar = hcchar.d32; ++ } ++ ++ ifxusb_wreg(&hc_regs->hcchar, _ifxhcd->ifxhc[i].hcchar); ++ ++ } ++ } ++ else ++ _ifxhcd->ifxhc[i].wait_for_sof=0; ++ ++#ifdef __USE_TIMER_4_SOF__ ++ if (_ifxhcd->ifxhc[i].wait_for_sof && (wait_for_sof > _ifxhcd->ifxhc[i].wait_for_sof)) { ++ wait_for_sof = _ifxhcd->ifxhc[i].wait_for_sof; ++ } ++#endif ++ } ++ } ++ ++ // ISOC Active ++ #ifdef __EN_ISOC__ ++ #error ISOC not supported: missing SOF code ++ epqh_entry = _ifxhcd->epqh_isoc_active.next; ++ while (epqh_entry != &_ifxhcd->epqh_isoc_active) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++ active_on+=update_interval_counter(epqh,fndiff); ++ } ++ ++ // ISOC Ready ++ epqh_entry = _ifxhcd->epqh_isoc_ready.next; ++ while (epqh_entry != &_ifxhcd->epqh_isoc_ready) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++ ready_on+=update_interval_counter(epqh,fndiff); ++ } ++ #endif ++ ++ // INTR Active ++ epqh_entry = _ifxhcd->epqh_intr_active.next; ++ while (epqh_entry != &_ifxhcd->epqh_intr_active) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++#ifdef __USE_TIMER_4_SOF__ ++ if (update_interval_counter(epqh,fndiff)) { ++ active_on ++; ++ wait_for_sof = 1; ++ } else { ++ if (epqh->period_counter && (wait_for_sof > epqh->period_counter)) { ++ wait_for_sof = epqh->period_counter; ++ } ++ } ++#else ++ active_on+=update_interval_counter(epqh,fndiff); ++#endif ++ } ++ ++ // INTR Ready ++ epqh_entry = _ifxhcd->epqh_intr_ready.next; ++ while (epqh_entry != &_ifxhcd->epqh_intr_ready) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++#ifdef __USE_TIMER_4_SOF__ ++ if (update_interval_counter(epqh,fndiff)) { ++ ready_on ++; ++ wait_for_sof = 1; ++ } else { ++ if (epqh->period_counter && (wait_for_sof > epqh->period_counter)) { ++ wait_for_sof = epqh->period_counter; ++ } ++ } ++#else ++ ready_on+=update_interval_counter(epqh,fndiff); ++#endif ++ } ++ ++ // Stdby ++ epqh_entry = _ifxhcd->epqh_stdby.next; ++ while (epqh_entry != &_ifxhcd->epqh_stdby) ++ { ++ epqh = list_entry(epqh_entry, ifxhcd_epqh_t, epqh_list_entry); ++ epqh_entry = epqh_entry->next; ++ if(epqh->period_counter > 0 ) { ++#ifdef __USE_TIMER_4_SOF__ ++ if (epqh->period_counter > fndiff) { ++ epqh->period_counter -= fndiff; ++ } else { ++ epqh->period_counter = 0; ++ } ++#else ++ epqh->period_counter --; ++#endif ++ #ifdef __DYN_SOF_INTR__ ++ with_count_down=1; ++ #endif ++ } ++ if(epqh->period_counter == 0) { ++ ifxhcd_epqh_idle_periodic(epqh); ++ } ++#ifdef __USE_TIMER_4_SOF__ ++ else { ++ if (wait_for_sof > epqh->period_counter) { ++ wait_for_sof = epqh->period_counter; ++ } ++ } ++#endif ++ } ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ ++ if(ready_on) ++ select_eps(_ifxhcd); ++ else if(active_on) ++ process_channels(_ifxhcd); ++ ++ /* Clear interrupt */ ++ { ++ gint_data_t gintsts; ++ gintsts.d32=0; ++ gintsts.b.sofintr = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ ++ #ifdef __DYN_SOF_INTR__ ++ if(!with_count_down) ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, gintsts.d32,0); ++ #endif ++#ifdef __USE_TIMER_4_SOF__ ++ wait_for_sof &= 0xFFFF; // reduce to 16 Bits. ++ ++ if(wait_for_sof == 1) { ++ // enable SOF ++ gint_data_t gintsts; ++ gintsts.d32=0; ++ gintsts.b.sofintr = 1; ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, 0,gintsts.d32); ++ } else { ++ // disable SOF ++ ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, gintsts.d32,0); ++ if (wait_for_sof > 1) { ++ // use timer, not SOF IRQ ++ hprt0_data_t hprt0; ++ ktime_t ktime; ++ hprt0.d32 = ifxusb_read_hprt0 (&_ifxhcd->core_if); ++ if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) { ++ ktime = ktime_set(0, wait_for_sof * 125 * 1000); /*--- wakeup in n*125usec ---*/ ++ } else { ++ ktime = ktime_set(0, wait_for_sof * (1000*1000)); /*--- wakeup in n*1000usec ---*/ ++ } ++ hrtimer_start(&_ifxhcd->hr_timer, ktime, HRTIMER_MODE_REL); ++ } ++ } ++#endif ++ } ++ _ifxhcd->lastframe=hfnum.b.frnum; ++ return 1; ++} ++ ++ ++ ++/* There are multiple conditions that can cause a port interrupt. This function ++ * determines which interrupt conditions have occurred and handles them ++ * appropriately. */ ++static int32_t handle_port_intr (ifxhcd_hcd_t *_ifxhcd) ++{ ++ int retval = 0; ++ hprt0_data_t hprt0; ++ hprt0_data_t hprt0_modify; ++ ++ hprt0.d32 = ++ hprt0_modify.d32 = ifxusb_rreg(_ifxhcd->core_if.hprt0); ++ ++ /* Clear appropriate bits in HPRT0 to clear the interrupt bit in ++ * GINTSTS */ ++ ++ hprt0_modify.b.prtena = 0; ++ hprt0_modify.b.prtconndet = 0; ++ hprt0_modify.b.prtenchng = 0; ++ hprt0_modify.b.prtovrcurrchng = 0; ++ ++ /* Port Connect Detected ++ * Set flag and clear if detected */ ++ if (hprt0.b.prtconndet) { ++ IFX_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " ++ "Port Connect Detected--\n", hprt0.d32); ++ _ifxhcd->flags.b.port_connect_status_change = 1; ++ _ifxhcd->flags.b.port_connect_status = 1; ++ hprt0_modify.b.prtconndet = 1; ++ ++ /* The Hub driver asserts a reset when it sees port connect ++ * status change flag */ ++ retval |= 1; ++ } ++ ++ /* Port Enable Changed ++ * Clear if detected - Set internal flag if disabled */ ++ if (hprt0.b.prtenchng) { ++ ++ IFX_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Enable Changed--\n", hprt0.d32); ++ hprt0_modify.b.prtenchng = 1; ++ if (hprt0.b.prtena == 1) ++ /* Port has been enabled set the reset change flag */ ++ _ifxhcd->flags.b.port_reset_change = 1; ++ else ++ _ifxhcd->flags.b.port_enable_change = 1; ++ retval |= 1; ++ } ++ ++ /* Overcurrent Change Interrupt */ ++ ++ if (hprt0.b.prtovrcurrchng) { ++ IFX_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Overcurrent Changed--\n", hprt0.d32); ++ _ifxhcd->flags.b.port_over_current_change = 1; ++ hprt0_modify.b.prtovrcurrchng = 1; ++ retval |= 1; ++ } ++ ++ /* Clear Port Interrupts */ ++ ifxusb_wreg(_ifxhcd->core_if.hprt0, hprt0_modify.d32); ++ return retval; ++} ++ ++/* ++ * This interrupt indicates that SUSPEND state has been detected on ++ * the USB. ++ * No Functioning in Host Mode ++ */ ++static int32_t handle_usb_suspend_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ IFX_DEBUGP("USB SUSPEND RECEIVED!\n"); ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.usbsuspend = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/* ++ * This interrupt indicates that the IFXUSB controller has detected a ++ * resume or remote wakeup sequence. If the IFXUSB controller is in ++ * low power mode, the handler must brings the controller out of low ++ * power mode. The controller automatically begins resume ++ * signaling. The handler schedules a time to stop resume signaling. ++ */ ++static int32_t handle_wakeup_detected_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ hprt0_data_t hprt0 = {.d32=0}; ++ pcgcctl_data_t pcgcctl = {.d32=0}; ++ ifxusb_core_if_t *core_if = &_ifxhcd->core_if; ++ ++ IFX_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n"); ++ ++ /* ++ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms ++ * so that OPT tests pass with all PHYs). ++ */ ++ /* Restart the Phy Clock */ ++ pcgcctl.b.stoppclk = 1; ++ ifxusb_mreg(core_if->pcgcctl, pcgcctl.d32, 0); ++ UDELAY(10); ++ ++ /* Now wait for 70 ms. */ ++ hprt0.d32 = ifxusb_read_hprt0( core_if ); ++ IFX_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32); ++ MDELAY(70); ++ hprt0.b.prtres = 0; /* Resume */ ++ ifxusb_wreg(core_if->hprt0, hprt0.d32); ++ IFX_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", ifxusb_rreg(core_if->hprt0)); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.wkupintr = 1; ++ ifxusb_wreg(&core_if->core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/* ++ * This interrupt indicates that a device is initiating the Session ++ * Request Protocol to request the host to turn on bus power so a new ++ * session can begin. The handler responds by turning on bus power. If ++ * the DWC_otg controller is in low power mode, the handler brings the ++ * controller out of low power mode before turning on bus power. ++ */ ++static int32_t handle_session_req_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ /* Clear interrupt */ ++ gint_data_t gintsts = { .d32 = 0 }; ++ gintsts.b.sessreqintr = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/* ++ * This interrupt indicates that a device has been disconnected from ++ * the root port. ++ */ ++static int32_t handle_disconnect_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ ++ ifxhcd_disconnect(_ifxhcd); ++ ++ gintsts.d32 = 0; ++ gintsts.b.disconnect = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/* ++ * This function handles the Connector ID Status Change Interrupt. It ++ * reads the OTG Interrupt Register (GOTCTL) to determine whether this ++ * is a Device to Host Mode transition or a Host Mode to Device ++ * Transition. ++ * This only occurs when the cable is connected/removed from the PHY ++ * connector. ++ */ ++static int32_t handle_conn_id_status_change_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ ++ IFX_WARN("ID Status Change Interrupt: currently in %s mode\n", ++ ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device"); ++ ++ gintsts.d32 = 0; ++ gintsts.b.conidstschng = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++static int32_t handle_otg_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ ifxusb_core_global_regs_t *global_regs = _ifxhcd->core_if.core_global_regs; ++ gotgint_data_t gotgint; ++ gotgint.d32 = ifxusb_rreg( &global_regs->gotgint); ++ /* Clear GOTGINT */ ++ ifxusb_wreg (&global_regs->gotgint, gotgint.d32); ++ return 1; ++} ++ ++/** This function will log a debug message */ ++static int32_t handle_mode_mismatch_intr(ifxhcd_hcd_t *_ifxhcd) ++{ ++ gint_data_t gintsts; ++ ++ IFX_WARN("Mode Mismatch Interrupt: currently in %s mode\n", ++ ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device"); ++ gintsts.d32 = 0; ++ gintsts.b.modemismatch = 1; ++ ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/** This function handles interrupts for the HCD. */ ++int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd) ++{ ++ int retval = 0; ++ ++ ifxusb_core_if_t *core_if = &_ifxhcd->core_if; ++ /* AVM/BC 20101111 Unnecesary variable removed*/ ++ //gint_data_t gintsts,gintsts2; ++ gint_data_t gintsts; ++ ++ /* Check if HOST Mode */ ++ if (ifxusb_is_device_mode(core_if)) ++ { ++ IFX_ERROR("%s() CRITICAL! IN DEVICE MODE\n", __func__); ++ return 0; ++ } ++ ++ gintsts.d32 = ifxusb_read_core_intr(core_if); ++ ++ if (!gintsts.d32) ++ return 0; ++ ++ //Common INT ++ if (gintsts.b.modemismatch) ++ { ++ retval |= handle_mode_mismatch_intr(_ifxhcd); ++ gintsts.b.modemismatch=0; ++ } ++ if (gintsts.b.otgintr) ++ { ++ retval |= handle_otg_intr(_ifxhcd); ++ gintsts.b.otgintr=0; ++ } ++ if (gintsts.b.conidstschng) ++ { ++ retval |= handle_conn_id_status_change_intr(_ifxhcd); ++ gintsts.b.conidstschng=0; ++ } ++ if (gintsts.b.disconnect) ++ { ++ retval |= handle_disconnect_intr(_ifxhcd); ++ gintsts.b.disconnect=0; ++ } ++ if (gintsts.b.sessreqintr) ++ { ++ retval |= handle_session_req_intr(_ifxhcd); ++ gintsts.b.sessreqintr=0; ++ } ++ if (gintsts.b.wkupintr) ++ { ++ retval |= handle_wakeup_detected_intr(_ifxhcd); ++ gintsts.b.wkupintr=0; ++ } ++ if (gintsts.b.usbsuspend) ++ { ++ retval |= handle_usb_suspend_intr(_ifxhcd); ++ gintsts.b.usbsuspend=0; ++ } ++ ++ //Host Int ++ if (gintsts.b.sofintr) ++ { ++ retval |= handle_sof_intr (_ifxhcd); ++ gintsts.b.sofintr=0; ++ } ++ if (gintsts.b.portintr) ++ { ++ retval |= handle_port_intr (_ifxhcd); ++ gintsts.b.portintr=0; ++ } ++ if (gintsts.b.hcintr) ++ { ++ int i; ++ haint_data_t haint; ++ haint.d32 = ifxusb_read_host_all_channels_intr(core_if); ++ for (i=0; i< core_if->params.host_channels; i++) ++ if (haint.b2.chint & (1 << i)) ++ retval |= handle_hc_n_intr (_ifxhcd, i); ++ gintsts.b.hcintr=0; ++ } ++ return retval; ++} +diff --git a/drivers/usb/ifxhcd/ifxhcd_queue.c b/drivers/usb/ifxhcd/ifxhcd_queue.c +new file mode 100644 +index 0000000..8f9dd25 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxhcd_queue.c +@@ -0,0 +1,418 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxhcd_queue.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the functions to manage Queue Heads and Queue ++ ** Transfer Descriptors. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxhcd_queue.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the functions to manage Queue Heads and Queue ++ Transfer Descriptors. ++*/ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/device.h> ++#include <linux/errno.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/string.h> ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++#include "ifxhcd.h" ++ ++#ifdef __EPQD_DESTROY_TIMEOUT__ ++ #define epqh_self_destroy_timeout 5 ++ static void eqph_destroy_func(unsigned long _ptr) ++ { ++ ifxhcd_epqh_t *epqh=(ifxhcd_epqh_t *)_ptr; ++ if(epqh) ++ { ++ ifxhcd_epqh_free (epqh); ++ } ++ } ++#endif ++ ++#define SCHEDULE_SLOP 10 ++ ++/*! ++ \brief This function allocates and initializes a EPQH. ++ ++ \param _ifxhcd The HCD state structure for the USB Host controller. ++ \param[in] _urb Holds the information about the device/endpoint that we need ++ to initialize the EPQH. ++ ++ \return Returns pointer to the newly allocated EPQH, or NULL on error. ++ */ ++ifxhcd_epqh_t *ifxhcd_epqh_create (ifxhcd_hcd_t *_ifxhcd, struct urb *_urb) ++{ ++ ifxhcd_epqh_t *epqh; ++ ++ hprt0_data_t hprt0; ++ struct usb_host_endpoint *sysep = ifxhcd_urb_to_endpoint(_urb); ++ ++ /* Allocate memory */ ++// epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_KERNEL); ++ epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_ATOMIC); ++ ++ if(epqh == NULL) ++ return NULL; ++ ++ memset (epqh, 0, sizeof (ifxhcd_epqh_t)); ++ ++ epqh->sysep=sysep; ++ ++ /* Initialize EPQH */ ++ switch (usb_pipetype(_urb->pipe)) ++ { ++ case PIPE_CONTROL : epqh->ep_type = IFXUSB_EP_TYPE_CTRL; break; ++ case PIPE_BULK : epqh->ep_type = IFXUSB_EP_TYPE_BULK; break; ++ case PIPE_ISOCHRONOUS: epqh->ep_type = IFXUSB_EP_TYPE_ISOC; break; ++ case PIPE_INTERRUPT : epqh->ep_type = IFXUSB_EP_TYPE_INTR; break; ++ } ++ ++ //epqh->data_toggle = IFXUSB_HC_PID_DATA0; ++ ++ epqh->mps = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe))); ++ ++ hprt0.d32 = ifxusb_read_hprt0 (&_ifxhcd->core_if); ++ ++ INIT_LIST_HEAD(&epqh->urbd_list); ++ INIT_LIST_HEAD(&epqh->epqh_list_entry); ++ epqh->hc = NULL; ++ ++ epqh->dump_buf = ifxusb_alloc_buf(epqh->mps, 0); ++ ++ /* FS/LS Enpoint on HS Hub ++ * NOT virtual root hub */ ++ epqh->need_split = 0; ++ epqh->pkt_count_limit=0; ++ if(epqh->ep_type == IFXUSB_EP_TYPE_BULK && !(usb_pipein(_urb->pipe)) ) ++ epqh->pkt_count_limit=4; ++ if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED && ++ ((_urb->dev->speed == USB_SPEED_LOW) || ++ (_urb->dev->speed == USB_SPEED_FULL)) && ++ (_urb->dev->tt) && (_urb->dev->tt->hub->devnum != 1)) ++ { ++ IFX_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n", ++ usb_pipeendpoint(_urb->pipe), _urb->dev->tt->hub->devnum, ++ _urb->dev->ttport); ++ epqh->need_split = 1; ++ epqh->pkt_count_limit=1; ++ } ++ ++ if (epqh->ep_type == IFXUSB_EP_TYPE_INTR || ++ epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ { ++ /* Compute scheduling parameters once and save them. */ ++ epqh->interval = _urb->interval; ++ if(epqh->need_split) ++ epqh->interval *= 8; ++ } ++ ++ epqh->period_counter=0; ++ epqh->is_active=0; ++ ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ /* Start a timer for this transfer. */ ++ init_timer(&epqh->destroy_timer); ++ epqh->destroy_timer.function = eqph_destroy_func; ++ epqh->destroy_timer.data = (unsigned long)(epqh); ++ #endif ++ ++ #ifdef __DEBUG__ ++ IFX_DEBUGPL(DBG_HCD , "IFXUSB HCD EPQH Initialized\n"); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - epqh = %p\n", epqh); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Device Address = %d EP %d, %s\n", ++ _urb->dev->devnum, ++ usb_pipeendpoint(_urb->pipe), ++ usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT"); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Speed = %s\n", ++ ({ char *speed; switch (_urb->dev->speed) { ++ case USB_SPEED_LOW: speed = "low" ; break; ++ case USB_SPEED_FULL: speed = "full"; break; ++ case USB_SPEED_HIGH: speed = "high"; break; ++ default: speed = "?"; break; ++ }; speed;})); ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Type = %s\n", ++ ({ ++ char *type; switch (epqh->ep_type) ++ { ++ case IFXUSB_EP_TYPE_ISOC: type = "isochronous"; break; ++ case IFXUSB_EP_TYPE_INTR: type = "interrupt" ; break; ++ case IFXUSB_EP_TYPE_CTRL: type = "control" ; break; ++ case IFXUSB_EP_TYPE_BULK: type = "bulk" ; break; ++ default: type = "?"; break; ++ }; ++ type; ++ })); ++ if (epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - interval = %d\n", epqh->interval); ++ #endif ++ ++ return epqh; ++} ++ ++ ++ ++ ++ ++ ++/*! ++ \brief Free the EPQH. EPQH should already be removed from a list. ++ URBD list should already be empty if called from URB Dequeue. ++ ++ \param[in] _epqh The EPQH to free. ++ */ ++void ifxhcd_epqh_free (ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ ++ if(_epqh->sysep) _epqh->sysep->hcpriv=NULL; ++ _epqh->sysep=NULL; ++ ++ if(!_epqh) ++ return; ++ ++ /* Free each QTD in the QTD list */ ++ local_irq_save (flags); ++ if (!list_empty(&_epqh->urbd_list)) ++ IFX_WARN("%s() invalid epqh state\n",__func__); ++ ++ #if defined(__UNALIGNED_BUFFER_ADJ__) ++ if(_epqh->aligned_buf) ++ ifxusb_free_buf(_epqh->aligned_buf); ++ if(_epqh->aligned_setup) ++ ifxusb_free_buf(_epqh->aligned_setup); ++ #endif ++ ++ if (!list_empty(&_epqh->epqh_list_entry)) ++ list_del_init(&_epqh->epqh_list_entry); ++ ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ #endif ++ if(_epqh->dump_buf) ++ ifxusb_free_buf(_epqh->dump_buf); ++ _epqh->dump_buf=0; ++ ++ ++ kfree (_epqh); ++ local_irq_restore (flags); ++} ++ ++/*! ++ \brief This function adds a EPQH to ++ ++ \return 0 if successful, negative error code otherwise. ++ */ ++void ifxhcd_epqh_ready(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ if (list_empty(&_epqh->epqh_list_entry)) ++ { ++ #ifdef __EN_ISOC__ ++ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); ++ else ++ #endif ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); ++ else ++ list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); ++ _epqh->is_active=0; ++ } ++ else if(!_epqh->is_active) ++ { ++ #ifdef __EN_ISOC__ ++ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); ++ else ++ #endif ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); ++ else ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); ++ } ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ #endif ++ local_irq_restore(flags); ++} ++ ++void ifxhcd_epqh_active(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ if (list_empty(&_epqh->epqh_list_entry)) ++ IFX_WARN("%s() invalid epqh state\n",__func__); ++ #ifdef __EN_ISOC__ ++ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_active); ++ else ++ #endif ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_active); ++ else ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_active); ++ _epqh->is_active=1; ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ #endif ++ local_irq_restore(flags); ++} ++ ++void ifxhcd_epqh_idle(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ ++ if (list_empty(&_epqh->urbd_list)) ++ { ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_ISOC || _epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ { ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_stdby); ++ } ++ else ++ { ++ list_del_init(&_epqh->epqh_list_entry); ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout); ++ add_timer(&_epqh->destroy_timer ); ++ #endif ++ } ++ } ++ else ++ { ++ #ifdef __EN_ISOC__ ++ if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready); ++ else ++ #endif ++ if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR) ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready); ++ else ++ list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready); ++ } ++ _epqh->is_active=0; ++ local_irq_restore(flags); ++} ++ ++ ++void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh) ++{ ++ unsigned long flags; ++ if(_epqh->ep_type != IFXUSB_EP_TYPE_ISOC && _epqh->ep_type != IFXUSB_EP_TYPE_INTR) ++ return; ++ ++ local_irq_save(flags); ++ ++ if (list_empty(&_epqh->epqh_list_entry)) ++ IFX_WARN("%s() invalid epqh state\n",__func__); ++ if (!list_empty(&_epqh->urbd_list)) ++ IFX_WARN("%s() invalid epqh state(not empty)\n",__func__); ++ ++ _epqh->is_active=0; ++ list_del_init(&_epqh->epqh_list_entry); ++ #ifdef __EPQD_DESTROY_TIMEOUT__ ++ del_timer(&_epqh->destroy_timer); ++ _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout); ++ add_timer(&_epqh->destroy_timer ); ++ #endif ++ ++ local_irq_restore(flags); ++} ++ ++ ++int ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb) ++{ ++ ifxhcd_urbd_t *urbd; ++ struct usb_host_endpoint *sysep; ++ ifxhcd_epqh_t *epqh; ++ unsigned long flags; ++ /* == AVM/WK 20100714 retval correctly initialized ==*/ ++ int retval = -ENOMEM; ++ ++ /*== AVM/BC 20100630 - Spinlock ==*/ ++ //local_irq_save(flags); ++ SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags); ++ ++// urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_KERNEL); ++ urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_ATOMIC); ++ if (urbd != NULL) /* Initializes a QTD structure.*/ ++ { ++ retval = 0; ++ memset (urbd, 0, sizeof (ifxhcd_urbd_t)); ++ ++ sysep = ifxhcd_urb_to_endpoint(_urb); ++ epqh = (ifxhcd_epqh_t *)sysep->hcpriv; ++ if (epqh == NULL) ++ { ++ epqh = ifxhcd_epqh_create (_ifxhcd, _urb); ++ if (epqh == NULL) ++ { ++ retval = -ENOSPC; ++ kfree(urbd); ++ //local_irq_restore (flags); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return retval; ++ } ++ sysep->hcpriv = epqh; ++ } ++ ++ INIT_LIST_HEAD(&urbd->urbd_list_entry); ++ ++ /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/ ++ retval = usb_hcd_link_urb_to_ep(ifxhcd_to_syshcd(_ifxhcd), _urb); ++ ++ if (unlikely(retval)){ ++ kfree(urbd); ++ kfree(epqh); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return retval; ++ } ++ ++ list_add_tail(&urbd->urbd_list_entry, &epqh->urbd_list); ++ urbd->urb = _urb; ++ _urb->hcpriv = urbd; ++ ++ urbd->epqh=epqh; ++ urbd->is_in=usb_pipein(_urb->pipe) ? 1 : 0;; ++ ++ urbd->xfer_len=_urb->transfer_buffer_length; ++#define URB_NO_SETUP_DMA_MAP 0 ++ ++ if(urbd->xfer_len>0) ++ { ++ if(_urb->transfer_flags && URB_NO_TRANSFER_DMA_MAP) ++ urbd->xfer_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->transfer_dma)); ++ else ++ urbd->xfer_buff = (uint8_t *) _urb->transfer_buffer; ++ } ++ if(epqh->ep_type == IFXUSB_EP_TYPE_CTRL) ++ { ++ if(_urb->transfer_flags && URB_NO_SETUP_DMA_MAP) ++ urbd->setup_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->setup_dma)); ++ else ++ urbd->setup_buff = (uint8_t *) _urb->setup_packet; ++ } ++ } ++ //local_irq_restore (flags); ++ SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags); ++ return retval; ++} ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_cif.c b/drivers/usb/ifxhcd/ifxusb_cif.c +new file mode 100644 +index 0000000..10b1292 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_cif.c +@@ -0,0 +1,1458 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_cif.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The Core Interface provides basic services for accessing and ++ ** managing the IFX USB hardware. These services are used by both the ++ ** Host Controller Driver and the Peripheral Controller Driver. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxusb_cif.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the interface to the IFX USB Core. ++*/ ++ ++#include <linux/clk.h> ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <asm/byteorder.h> ++#include <asm/unaligned.h> ++ ++ ++#include <linux/jiffies.h> ++#include <linux/platform_device.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++ ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_pmu.h> ++// #include <ifx_pmu.h> ++#endif ++ ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++ ++#ifdef __IS_DEVICE__ ++ #include "ifxpcd.h" ++#endif ++ ++#ifdef __IS_HOST__ ++ #include "ifxhcd.h" ++#endif ++ ++#include <linux/mm.h> ++ ++#include <linux/gfp.h> ++ ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_board.h> ++ //#include <ifx_board.h> ++#endif ++ ++//#include <asm/ifx/ifx_gpio.h> ++//#include <ifx_gpio.h> ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_led.h> ++ //#include <ifx_led.h> ++#endif ++ ++ ++ ++#if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #ifndef USB_CTRL_PMU_SETUP ++ #define USB_CTRL_PMU_SETUP(__x) USB0_CTRL_PMU_SETUP(__x) ++ #endif ++ #ifndef USB_PHY_PMU_SETUP ++ #define USB_PHY_PMU_SETUP(__x) USB0_PHY_PMU_SETUP(__x) ++ #endif ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++#endif // defined(__UEIP__) ++ ++/*! ++ \brief This function is called to allocate buffer of specified size. ++ The allocated buffer is mapped into DMA accessable address. ++ \param size Size in BYTE to be allocated ++ \param clear 0: don't do clear after buffer allocated, other: do clear to zero ++ \return 0/NULL: Fail; uncached pointer of allocated buffer ++ */ ++void *ifxusb_alloc_buf(size_t size, int clear) ++{ ++ uint32_t *cached,*uncached; ++ uint32_t totalsize,page; ++ ++ if(!size) ++ return 0; ++ ++ size=(size+3)&0xFFFFFFFC; ++ totalsize=size + 12; ++ page=get_order(totalsize); ++ ++ cached = (void *) __get_free_pages(( GFP_ATOMIC | GFP_DMA), page); ++ ++ if(!cached) ++ { ++ IFX_PRINT("%s Allocation Failed size:%d\n",__func__,size); ++ return NULL; ++ } ++ ++ uncached = (uint32_t *)(KSEG1ADDR(cached)); ++ if(clear) ++ memset(uncached, 0, totalsize); ++ ++ *(uncached+0)=totalsize; ++ *(uncached+1)=page; ++ *(uncached+2)=(uint32_t)cached; ++ return (void *)(uncached+3); ++} ++ ++ ++/*! ++ \brief This function is called to free allocated buffer. ++ \param vaddr the uncached pointer of the buffer ++ */ ++void ifxusb_free_buf(void *vaddr) ++{ ++ uint32_t totalsize,page; ++ uint32_t *cached,*uncached; ++ ++ if(vaddr != NULL) ++ { ++ uncached=vaddr; ++ uncached-=3; ++ totalsize=*(uncached+0); ++ page=*(uncached+1); ++ cached=(uint32_t *)(*(uncached+2)); ++ if(totalsize && page==get_order(totalsize) && cached==(uint32_t *)(KSEG0ADDR(uncached))) ++ { ++ free_pages((unsigned long)cached, page); ++ return; ++ } ++ // the memory is not allocated by ifxusb_alloc_buf. Allowed but must be careful. ++ return; ++ } ++} ++ ++ ++ ++/*! ++ \brief This function is called to initialize the IFXUSB CSR data ++ structures. The register addresses in the device and host ++ structures are initialized from the base address supplied by the ++ caller. The calling function must make the OS calls to get the ++ base address of the IFXUSB controller registers. ++ ++ \param _core_if Pointer of core_if structure ++ \param _irq irq number ++ \param _reg_base_addr Base address of IFXUSB core registers ++ \param _fifo_base_addr Fifo base address ++ \param _fifo_dbg_addr Fifo debug address ++ \return 0: success; ++ */ ++int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, ++ int _irq, ++ uint32_t _reg_base_addr, ++ uint32_t _fifo_base_addr, ++ uint32_t _fifo_dbg_addr) ++{ ++ int retval = 0; ++ uint32_t *reg_base =NULL; ++ uint32_t *fifo_base =NULL; ++ uint32_t *fifo_dbg =NULL; ++ ++ int i; ++ ++ IFX_DEBUGPL(DBG_CILV, "%s(%p,%d,0x%08X,0x%08X,0x%08X)\n", __func__, ++ _core_if, ++ _irq, ++ _reg_base_addr, ++ _fifo_base_addr, ++ _fifo_dbg_addr); ++ ++ if( _core_if == NULL) ++ { ++ IFX_ERROR("%s() invalid _core_if\n", __func__); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ //memset(_core_if, 0, sizeof(ifxusb_core_if_t)); ++ ++ _core_if->irq=_irq; ++ ++ reg_base =ioremap_nocache(_reg_base_addr , IFXUSB_IOMEM_SIZE ); ++ fifo_base =ioremap_nocache(_fifo_base_addr, IFXUSB_FIFOMEM_SIZE); ++ fifo_dbg =ioremap_nocache(_fifo_dbg_addr , IFXUSB_FIFODBG_SIZE); ++ if( reg_base == NULL || fifo_base == NULL || fifo_dbg == NULL) ++ { ++ IFX_ERROR("%s() usb ioremap() failed\n", __func__); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ _core_if->core_global_regs = (ifxusb_core_global_regs_t *)reg_base; ++ ++ /* ++ * Attempt to ensure this device is really a IFXUSB Controller. ++ * Read and verify the SNPSID register contents. The value should be ++ * 0x45F42XXX ++ */ ++ { ++ int32_t snpsid; ++ snpsid = ifxusb_rreg(&_core_if->core_global_regs->gsnpsid); ++ if ((snpsid & 0xFFFFF000) != 0x4F542000) ++ { ++ IFX_ERROR("%s() snpsid error(0x%08x) failed\n", __func__,snpsid); ++ retval = -EINVAL; ++ goto fail; ++ } ++ _core_if->snpsid=snpsid; ++ } ++ ++ #ifdef __IS_HOST__ ++ _core_if->host_global_regs = (ifxusb_host_global_regs_t *) ++ ((uint32_t)reg_base + IFXUSB_HOST_GLOBAL_REG_OFFSET); ++ _core_if->hprt0 = (uint32_t*)((uint32_t)reg_base + IFXUSB_HOST_PORT_REGS_OFFSET); ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) ++ { ++ _core_if->hc_regs[i] = (ifxusb_hc_regs_t *) ++ ((uint32_t)reg_base + IFXUSB_HOST_CHAN_REGS_OFFSET + ++ (i * IFXUSB_CHAN_REGS_OFFSET)); ++ IFX_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n", ++ i, &_core_if->hc_regs[i]->hcchar); ++ } ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ _core_if->dev_global_regs = ++ (ifxusb_device_global_regs_t *)((uint32_t)reg_base + IFXUSB_DEV_GLOBAL_REG_OFFSET); ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) ++ { ++ _core_if->in_ep_regs[i] = (ifxusb_dev_in_ep_regs_t *) ++ ((uint32_t)reg_base + IFXUSB_DEV_IN_EP_REG_OFFSET + ++ (i * IFXUSB_EP_REG_OFFSET)); ++ _core_if->out_ep_regs[i] = (ifxusb_dev_out_ep_regs_t *) ++ ((uint32_t)reg_base + IFXUSB_DEV_OUT_EP_REG_OFFSET + ++ (i * IFXUSB_EP_REG_OFFSET)); ++ IFX_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p/%p %p/0x%08X/0x%08X\n", ++ i, &_core_if->in_ep_regs[i]->diepctl, _core_if->in_ep_regs[i], ++ reg_base,IFXUSB_DEV_IN_EP_REG_OFFSET,(i * IFXUSB_EP_REG_OFFSET) ++ ); ++ IFX_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p/%p %p/0x%08X/0x%08X\n", ++ i, &_core_if->out_ep_regs[i]->doepctl, _core_if->out_ep_regs[i], ++ reg_base,IFXUSB_DEV_OUT_EP_REG_OFFSET,(i * IFXUSB_EP_REG_OFFSET) ++ ); ++ } ++ #endif //__IS_DEVICE__ ++ ++ /* Setting the FIFO and other Address. */ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) ++ { ++ _core_if->data_fifo[i] = fifo_base + (i * IFXUSB_DATA_FIFO_SIZE); ++ IFX_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n", ++ i, (unsigned)_core_if->data_fifo[i]); ++ } ++ ++ _core_if->data_fifo_dbg = fifo_dbg; ++ _core_if->pcgcctl = (uint32_t*)(((uint32_t)reg_base) + IFXUSB_PCGCCTL_OFFSET); ++ ++ /* ++ * Store the contents of the hardware configuration registers here for ++ * easy access later. ++ */ ++ _core_if->hwcfg1.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg1); ++ _core_if->hwcfg2.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg2); ++ _core_if->hwcfg3.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg3); ++ _core_if->hwcfg4.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg4); ++ ++ IFX_DEBUGPL(DBG_CILV,"hwcfg1=%08x\n",_core_if->hwcfg1.d32); ++ IFX_DEBUGPL(DBG_CILV,"hwcfg2=%08x\n",_core_if->hwcfg2.d32); ++ IFX_DEBUGPL(DBG_CILV,"hwcfg3=%08x\n",_core_if->hwcfg3.d32); ++ IFX_DEBUGPL(DBG_CILV,"hwcfg4=%08x\n",_core_if->hwcfg4.d32); ++ ++ ++ #ifdef __DED_FIFO__ ++ IFX_PRINT("Waiting for PHY Clock Lock!\n"); ++ while(!( ifxusb_rreg(&_core_if->core_global_regs->grxfsiz) & (1<<9))) ++ { ++ } ++ IFX_PRINT("PHY Clock Locked!\n"); ++ //ifxusb_clean_spram(_core_if,128*1024/4); ++ #endif ++ ++ /* Create new workqueue and init works */ ++#if 0 ++ _core_if->wq_usb = create_singlethread_workqueue(_core_if->core_name); ++ ++ if(_core_if->wq_usb == 0) ++ { ++ IFX_DEBUGPL(DBG_CIL, "Creation of wq_usb failed\n"); ++ retval = -EINVAL; ++ goto fail; ++ } ++ ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ INIT_WORK(&core_if->w_conn_id, w_conn_id_status_change, core_if); ++ INIT_WORK(&core_if->w_wkp, w_wakeup_detected, core_if); ++ #else ++ INIT_WORK(&core_if->w_conn_id, w_conn_id_status_change); ++ INIT_DELAYED_WORK(&core_if->w_wkp, w_wakeup_detected); ++ #endif ++#endif ++ return 0; ++ ++fail: ++ if( reg_base != NULL) iounmap(reg_base ); ++ if( fifo_base != NULL) iounmap(fifo_base); ++ if( fifo_dbg != NULL) iounmap(fifo_dbg ); ++ return retval; ++} ++ ++/*! ++ \brief This function free the mapped address in the IFXUSB CSR data structures. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if) ++{ ++ /* Disable all interrupts */ ++ if( _core_if->core_global_regs != NULL) ++ { ++ ifxusb_mreg( &_core_if->core_global_regs->gahbcfg, 1, 0); ++ ifxusb_wreg( &_core_if->core_global_regs->gintmsk, 0); ++ } ++ ++ if( _core_if->core_global_regs != NULL) iounmap(_core_if->core_global_regs ); ++ if( _core_if->data_fifo[0] != NULL) iounmap(_core_if->data_fifo[0] ); ++ if( _core_if->data_fifo_dbg != NULL) iounmap(_core_if->data_fifo_dbg ); ++ ++#if 0 ++ if (_core_if->wq_usb) ++ destroy_workqueue(_core_if->wq_usb); ++#endif ++ memset(_core_if, 0, sizeof(ifxusb_core_if_t)); ++} ++ ++ ++ ++ ++/*! ++ \brief This function enbles the controller's Global Interrupt in the AHB Config register. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ) ++{ ++ gahbcfg_data_t ahbcfg ={ .d32 = 0}; ++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ ++ ifxusb_mreg(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32); ++} ++ ++/*! ++ \brief This function disables the controller's Global Interrupt in the AHB Config register. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ) ++{ ++ gahbcfg_data_t ahbcfg ={ .d32 = 0}; ++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ ++ ifxusb_mreg(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0); ++} ++ ++ ++ ++ ++/*! ++ \brief Flush Tx and Rx FIFO. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset ={ .d32 = 0}; ++ int count = 0; ++ ++ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); ++ greset.b.rxfflsh = 1; ++ greset.b.txfflsh = 1; ++ greset.b.txfnum = 0x10; ++ greset.b.intknqflsh=1; ++ greset.b.hstfrm=1; ++ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); ++ ++ do ++ { ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 10000) ++ { ++ IFX_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, greset.d32); ++ break; ++ } ++ } while (greset.b.rxfflsh == 1 || greset.b.txfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++/*! ++ \brief Flush a Tx FIFO. ++ \param _core_if Pointer of core_if structure ++ \param _num Tx FIFO to flush. ( 0x10 for ALL TX FIFO ) ++ */ ++void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset ={ .d32 = 0}; ++ int count = 0; ++ ++ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "Flush Tx FIFO %d\n", _num); ++ ++ greset.b.intknqflsh=1; ++ greset.b.txfflsh = 1; ++ greset.b.txfnum = _num; ++ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); ++ ++ do ++ { ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 10000&&(_num==0 ||_num==0x10)) ++ { ++ IFX_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", ++ __func__, greset.d32, ++ ifxusb_rreg( &global_regs->gnptxsts)); ++ break; ++ } ++ } while (greset.b.txfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++ ++/*! ++ \brief Flush Rx FIFO. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset ={ .d32 = 0}; ++ int count = 0; ++ ++ IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); ++ greset.b.rxfflsh = 1; ++ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); ++ ++ do ++ { ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 10000) ++ { ++ IFX_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, greset.d32); ++ break; ++ } ++ } while (greset.b.rxfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++ ++#define SOFT_RESET_DELAY 100 ++ ++/*! ++ \brief Do a soft reset of the core. Be careful with this because it ++ resets all the internal state machines of the core. ++ \param _core_if Pointer of core_if structure ++ */ ++int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset ={ .d32 = 0}; ++ int count = 0; ++ ++ IFX_DEBUGPL(DBG_CILV, "%s\n", __func__); ++ /* Wait for AHB master IDLE state. */ ++ do ++ { ++ UDELAY(10); ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 100000) ++ { ++ IFX_WARN("%s() HANG! AHB Idle GRSTCTL=%0x %x\n", __func__, ++ greset.d32, greset.b.ahbidle); ++ break; ++ } ++ } while (greset.b.ahbidle == 0); ++ ++ UDELAY(1); ++ ++ /* Core Soft Reset */ ++ count = 0; ++ greset.b.csftrst = 1; ++ ifxusb_wreg( &global_regs->grstctl, greset.d32 ); ++ ++ #ifdef SOFT_RESET_DELAY ++ MDELAY(SOFT_RESET_DELAY); ++ #endif ++ ++ do ++ { ++ UDELAY(10); ++ greset.d32 = ifxusb_rreg( &global_regs->grstctl); ++ if (++count > 100000) ++ { ++ IFX_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", __func__, greset.d32); ++ return -1; ++ } ++ } while (greset.b.csftrst == 1); ++ ++ #ifdef SOFT_RESET_DELAY ++ MDELAY(SOFT_RESET_DELAY); ++ #endif ++ ++ ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (4, VR9_RCU_USBRESET2); ++ MDELAY(50); ++ clear_bit (4, VR9_RCU_USBRESET2); ++ } ++ else ++ { ++ set_bit (5, VR9_RCU_USBRESET2); ++ MDELAY(50); ++ clear_bit (5, VR9_RCU_USBRESET2); ++ } ++ MDELAY(50); ++ #endif //defined(__IS_VR9__) ++ ++ IFX_PRINT("USB core #%d soft-reset\n",_core_if->core_no); ++ ++ return 0; ++} ++ ++/*! ++ \brief Turn on the USB Core Power ++ \param _core_if Pointer of core_if structure ++*/ ++void ifxusb_power_on (ifxusb_core_if_t *_core_if) ++{ ++ struct clk *clk0 = clk_get_sys("usb0", NULL); ++ struct clk *clk1 = clk_get_sys("usb1", NULL); ++ // set clock gating ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ #if defined(__UEIP__) ++ ++ #if defined(__IS_TWINPASS) || defined(__IS_DANUBE__) ++ set_bit (4, (volatile unsigned long *)DANUBE_CGU_IFCCR); ++ set_bit (5, (volatile unsigned long *)DANUBE_CGU_IFCCR); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ // clear_bit (4, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); ++ clear_bit (5, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ set_bit (0, (volatile unsigned long *)AR9_CGU_IFCCR); ++ set_bit (1, (volatile unsigned long *)AR9_CGU_IFCCR); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++// set_bit (0, (volatile unsigned long *)VR9_CGU_IFCCR); ++// set_bit (1, (volatile unsigned long *)VR9_CGU_IFCCR); ++ #endif //defined(__IS_VR9__) ++ ++ MDELAY(50); ++ ++ // set power ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ USB_CTRL_PMU_SETUP(IFX_PMU_ENABLE); ++ //#if defined(__IS_TWINPASS__) ++ // ifxusb_enable_afe_oc(); ++ //#endif ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) || defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ clk_enable(clk0); ++// USB0_CTRL_PMU_SETUP(IFX_PMU_ENABLE); ++ else ++ clk_enable(clk1); ++// USB1_CTRL_PMU_SETUP(IFX_PMU_ENABLE); ++ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) ++ ++ if(_core_if->core_global_regs) ++ { ++ // PHY configurations. ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ //ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_VR9__) ++ } ++ #else //defined(__UEIP__) ++ #if defined(__IS_TWINPASS) || defined(__IS_DANUBE__) ++ set_bit (4, (volatile unsigned long *)DANUBE_CGU_IFCCR); ++ set_bit (5, (volatile unsigned long *)DANUBE_CGU_IFCCR); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ // clear_bit (4, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); ++ clear_bit (5, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ set_bit (0, (volatile unsigned long *)AMAZON_S_CGU_IFCCR); ++ set_bit (1, (volatile unsigned long *)AMAZON_S_CGU_IFCCR); ++ #endif //defined(__IS_AR9__) ++ ++ MDELAY(50); ++ ++ // set power ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ clear_bit (6, (volatile unsigned long *)DANUBE_PMU_PWDCR);//USB ++ clear_bit (9, (volatile unsigned long *)DANUBE_PMU_PWDCR);//DSL ++ clear_bit (15, (volatile unsigned long *)DANUBE_PMU_PWDCR);//AHB ++ #if defined(__IS_TWINPASS__) ++ ifxusb_enable_afe_oc(); ++ #endif ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ clear_bit (6, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); ++ clear_bit (9, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); ++ clear_bit (15, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ clear_bit (6, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB ++ else ++ clear_bit (27, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB ++ clear_bit (9, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//DSL ++ clear_bit (15, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//AHB ++ #endif //defined(__IS_AR9__) ++ ++ if(_core_if->core_global_regs) ++ { ++ // PHY configurations. ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ } ++ ++ #endif //defined(__UEIP__) ++} ++ ++/*! ++ \brief Turn off the USB Core Power ++ \param _core_if Pointer of core_if structure ++*/ ++void ifxusb_power_off (ifxusb_core_if_t *_core_if) ++{ ++ struct clk *clk0 = clk_get_sys("usb0", NULL); ++ struct clk *clk1 = clk_get_sys("usb1", NULL); ++ ifxusb_phy_power_off (_core_if); ++ ++ // set power ++ #if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ USB_CTRL_PMU_SETUP(IFX_PMU_DISABLE); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) || defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ clk_disable(clk0); ++ //USB0_CTRL_PMU_SETUP(IFX_PMU_DISABLE); ++ else ++ clk_disable(clk1); ++ //USB1_CTRL_PMU_SETUP(IFX_PMU_DISABLE); ++ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) ++ #else //defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (6, (volatile unsigned long *)DANUBE_PMU_PWDCR);//USB ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (6, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR);//USB ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ set_bit (6, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB ++ else ++ set_bit (27, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB ++ #endif //defined(__IS_AR9__) ++ #endif //defined(__UEIP__) ++} ++ ++/*! ++ \brief Turn on the USB PHY Power ++ \param _core_if Pointer of core_if structure ++*/ ++void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if) ++{ ++ struct clk *clk0 = clk_get_sys("usb0", NULL); ++ struct clk *clk1 = clk_get_sys("usb1", NULL); ++ #if defined(__UEIP__) ++ if(_core_if->core_global_regs) ++ { ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9_S__) ++ if(_core_if->core_no==0) ++ set_bit (0, VR9_RCU_USB_ANA_CFG1A); ++ else ++ set_bit (0, VR9_RCU_USB_ANA_CFG1B); ++ #endif //defined(__IS_VR9__) ++ } ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ USB_PHY_PMU_SETUP(IFX_PMU_ENABLE); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) || defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ clk_enable(clk0); ++ //USB0_PHY_PMU_SETUP(IFX_PMU_ENABLE); ++ else ++ clk_enable(clk1); ++ //USB1_PHY_PMU_SETUP(IFX_PMU_ENABLE); ++ #endif //defined(__IS_AR9__) || defined(__IS_VR9__) ++ ++ // PHY configurations. ++ if(_core_if->core_global_regs) ++ { ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9_S__) ++ if(_core_if->core_no==0) ++ set_bit (0, VR9_RCU_USB_ANA_CFG1A); ++ else ++ set_bit (0, VR9_RCU_USB_ANA_CFG1B); ++ #endif //defined(__IS_VR9__) ++ } ++ #else //defined(__UEIP__) ++ // PHY configurations. ++ if(_core_if->core_global_regs) ++ { ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ } ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ clear_bit (0, (volatile unsigned long *)DANUBE_PMU_PWDCR);//PHY ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ clear_bit (0, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ clear_bit (0, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY ++ else ++ clear_bit (26, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY ++ #endif //defined(__IS_AR9__) ++ ++ // PHY configurations. ++ if(_core_if->core_global_regs) ++ { ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ } ++ #endif //defined(__UEIP__) ++} ++ ++ ++/*! ++ \brief Turn off the USB PHY Power ++ \param _core_if Pointer of core_if structure ++*/ ++void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if) ++{ ++ struct clk *clk0 = clk_get_sys("usb0", NULL); ++ struct clk *clk1 = clk_get_sys("usb1", NULL); ++ #if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ USB_PHY_PMU_SETUP(IFX_PMU_DISABLE); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) || defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ clk_disable(clk0); ++ //USB0_PHY_PMU_SETUP(IFX_PMU_DISABLE); ++ else ++ clk_disable(clk1); ++ //USB1_PHY_PMU_SETUP(IFX_PMU_DISABLE); ++ #endif // defined(__IS_AR9__) || defined(__IS_VR9__) ++ #else //defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (0, (volatile unsigned long *)DANUBE_PMU_PWDCR);//PHY ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (0, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR);//PHY ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ set_bit (0, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY ++ else ++ set_bit (26, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY ++ #endif //defined(__IS_AR9__) ++ #endif //defined(__UEIP__) ++} ++ ++ ++/*! ++ \brief Reset on the USB Core RCU ++ \param _core_if Pointer of core_if structure ++ */ ++#if defined(__IS_VR9__) ++ int already_hard_reset=0; ++#endif ++void ifxusb_hard_reset(ifxusb_core_if_t *_core_if) ++{ ++ #if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined (__IS_HOST__) ++ clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #endif ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AMAZON_SE__) ++ #if defined (__IS_HOST__) ++ clear_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #endif ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); ++ #endif ++ } ++ else ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); ++ #endif ++ } ++ #endif //defined(__IS_AR9__) ++ ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); ++ #endif ++ } ++ else ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); ++ #endif ++ } ++ #endif //defined(__IS_VR9__) ++ ++ ++ // set the HC's byte-order to big-endian ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (AMAZON_SE_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ clear_bit (AMAZON_SE_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (AR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); ++ clear_bit (AR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); ++ } ++ else ++ { ++ set_bit (AR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); ++ clear_bit (AR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); ++ } ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (VR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); ++ clear_bit (VR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); ++ } ++ else ++ { ++ set_bit (VR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); ++ clear_bit (VR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); ++ } ++ #endif //defined(__IS_VR9__) ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (4, DANUBE_RCU_RESET); ++ MDELAY(500); ++ clear_bit (4, DANUBE_RCU_RESET); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (4, AMAZON_SE_RCU_RESET); ++ MDELAY(500); ++ clear_bit (4, AMAZON_SE_RCU_RESET); ++ MDELAY(500); ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (4, AR9_RCU_USBRESET); ++ MDELAY(500); ++ clear_bit (4, AR9_RCU_USBRESET); ++ } ++ else ++ { ++ set_bit (28, AR9_RCU_USBRESET); ++ MDELAY(500); ++ clear_bit (28, AR9_RCU_USBRESET); ++ } ++ MDELAY(500); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ if(!already_hard_reset) ++ { ++ set_bit (4, VR9_RCU_USBRESET); ++ MDELAY(500); ++ clear_bit (4, VR9_RCU_USBRESET); ++ MDELAY(500); ++ already_hard_reset=1; ++ } ++ #endif //defined(__IS_VR9__) ++ ++ #if defined(__IS_TWINPASS__) ++ ifxusb_enable_afe_oc(); ++ #endif ++ ++ if(_core_if->core_global_regs) ++ { ++ // PHY configurations. ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ // ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_VR9__) ++ } ++ #else //defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined (__IS_HOST__) ++ clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #endif ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AMAZON_SE__) ++ #if defined (__IS_HOST__) ++ clear_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #endif ++ #endif //defined(__IS_AMAZON_SE__) ++ ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); ++ #endif ++ } ++ else ++ { ++ #if defined (__IS_HOST__) ++ clear_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); ++ #elif defined (__IS_DEVICE__) ++ set_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); ++ #endif ++ } ++ #endif //defined(__IS_AR9__) ++ ++ // set the HC's byte-order to big-endian ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (AMAZON_SE_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ clear_bit (AMAZON_SE_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (AMAZON_S_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); ++ clear_bit (AMAZON_S_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); ++ } ++ else ++ { ++ set_bit (AMAZON_S_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); ++ clear_bit (AMAZON_S_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); ++ } ++ #endif //defined(__IS_AR9__) ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ set_bit (4, DANUBE_RCU_RESET); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (4, AMAZON_SE_RCU_RESET); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ set_bit (4, AMAZON_S_RCU_USBRESET); ++ } ++ else ++ { ++ set_bit (28, AMAZON_S_RCU_USBRESET); ++ } ++ #endif //defined(__IS_AR9__) ++ ++ MDELAY(500); ++ ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ clear_bit (4, DANUBE_RCU_RESET); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ clear_bit (4, AMAZON_SE_RCU_RESET); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ clear_bit (4, AMAZON_S_RCU_USBRESET); ++ } ++ else ++ { ++ clear_bit (28, AMAZON_S_RCU_USBRESET); ++ } ++ #endif //defined(__IS_AR9__) ++ ++ MDELAY(500); ++ ++ #if defined(__IS_TWINPASS__) ++ ifxusb_enable_afe_oc(); ++ #endif ++ ++ if(_core_if->core_global_regs) ++ { ++ // PHY configurations. ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); ++ #endif //defined(__IS_AR9__) ++ } ++ #endif //defined(__UEIP__) ++} ++ ++#if defined(__GADGET_LED__) || defined(__HOST_LED__) ++ #if defined(__UEIP__) ++ static void *g_usb_led_trigger = NULL; ++ #endif ++ ++ void ifxusb_led_init(ifxusb_core_if_t *_core_if) ++ { ++ #if defined(__UEIP__) ++ if ( !g_usb_led_trigger ) ++ { ++ ifx_led_trigger_register("usb_link", &g_usb_led_trigger); ++ if ( g_usb_led_trigger != NULL ) ++ { ++ struct ifx_led_trigger_attrib attrib = {0}; ++ attrib.delay_on = 250; ++ attrib.delay_off = 250; ++ attrib.timeout = 2000; ++ attrib.def_value = 1; ++ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; ++ IFX_DEBUGP("Reg USB LED!!\n"); ++ ifx_led_trigger_set_attrib(g_usb_led_trigger, &attrib); ++ } ++ } ++ #endif //defined(__UEIP__) ++ } ++ ++ void ifxusb_led_free(ifxusb_core_if_t *_core_if) ++ { ++ #if defined(__UEIP__) ++ if ( g_usb_led_trigger ) ++ { ++ ifx_led_trigger_deregister(g_usb_led_trigger); ++ g_usb_led_trigger = NULL; ++ } ++ #endif //defined(__UEIP__) ++ } ++ ++ /*! ++ \brief Turn off the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ */ ++ void ifxusb_led(ifxusb_core_if_t *_core_if) ++ { ++ #if defined(__UEIP__) ++ if(g_usb_led_trigger) ++ ifx_led_trigger_activate(g_usb_led_trigger); ++ #else ++ #endif //defined(__UEIP__) ++ } ++#endif // defined(__GADGET_LED__) || defined(__HOST_LED__) ++ ++ ++ ++#if defined(__IS_HOST__) && defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) ++/*! ++ \brief Turn on the OC Int ++ */ ++ void ifxusb_oc_int_on() ++ { ++ #if defined(__UEIP__) ++ #else ++ #if defined(__IS_TWINPASS__) ++ irq_enable(DANUBE_USB_OC_INT); ++ #endif ++ #endif //defined(__UEIP__) ++ } ++/*! ++ \brief Turn off the OC Int ++ */ ++ void ifxusb_oc_int_off() ++ { ++ #if defined(__UEIP__) ++ #else ++ #if defined(__IS_TWINPASS__) ++ irq_disable(DANUBE_USB_OC_INT); ++ #endif ++ #endif //defined(__UEIP__) ++ } ++#endif //defined(__IS_HOST__) && defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) ++ ++/* internal routines for debugging */ ++void ifxusb_dump_msg(const u8 *buf, unsigned int length) ++{ ++#ifdef __DEBUG__ ++ unsigned int start, num, i; ++ char line[52], *p; ++ ++ if (length >= 512) ++ return; ++ start = 0; ++ while (length > 0) ++ { ++ num = min(length, 16u); ++ p = line; ++ for (i = 0; i < num; ++i) ++ { ++ if (i == 8) ++ *p++ = ' '; ++ sprintf(p, " %02x", buf[i]); ++ p += 3; ++ } ++ *p = 0; ++ IFX_PRINT( "%6x: %s\n", start, line); ++ buf += num; ++ start += num; ++ length -= num; ++ } ++#endif ++} ++ ++/* This functions reads the SPRAM and prints its content */ ++void ifxusb_dump_spram(ifxusb_core_if_t *_core_if) ++{ ++#ifdef __ENABLE_DUMP__ ++ volatile uint8_t *addr, *start_addr, *end_addr; ++ uint32_t size; ++ IFX_PRINT("SPRAM Data:\n"); ++ start_addr = (void*)_core_if->core_global_regs; ++ IFX_PRINT("Base Address: 0x%8X\n", (uint32_t)start_addr); ++ ++ start_addr = (void*)_core_if->data_fifo_dbg; ++ IFX_PRINT("Starting Address: 0x%8X\n", (uint32_t)start_addr); ++ ++ size=_core_if->hwcfg3.b.dfifo_depth; ++ size<<=2; ++ size+=0x200; ++ size&=0x0003FFFC; ++ ++ end_addr = (void*)_core_if->data_fifo_dbg; ++ end_addr += size; ++ ++ for(addr = start_addr; addr < end_addr; addr+=16) ++ { ++ IFX_PRINT("0x%8X:\t%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", (uint32_t)addr, ++ addr[ 0], addr[ 1], addr[ 2], addr[ 3], ++ addr[ 4], addr[ 5], addr[ 6], addr[ 7], ++ addr[ 8], addr[ 9], addr[10], addr[11], ++ addr[12], addr[13], addr[14], addr[15] ++ ); ++ } ++ return; ++#endif //__ENABLE_DUMP__ ++} ++ ++ ++ ++ ++/* This function reads the core global registers and prints them */ ++void ifxusb_dump_registers(ifxusb_core_if_t *_core_if) ++{ ++#ifdef __ENABLE_DUMP__ ++ int i; ++ volatile uint32_t *addr; ++ #ifdef __IS_DEVICE__ ++ volatile uint32_t *addri,*addro; ++ #endif ++ ++ IFX_PRINT("Core Global Registers\n"); ++ addr=&_core_if->core_global_regs->gotgctl; ++ IFX_PRINT("GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gotgint; ++ IFX_PRINT("GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gahbcfg; ++ IFX_PRINT("GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gusbcfg; ++ IFX_PRINT("GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->grstctl; ++ IFX_PRINT("GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gintsts; ++ IFX_PRINT("GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gintmsk; ++ IFX_PRINT("GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gi2cctl; ++ IFX_PRINT("GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gpvndctl; ++ IFX_PRINT("GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ggpio; ++ IFX_PRINT("GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->guid; ++ IFX_PRINT("GUID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->gsnpsid; ++ IFX_PRINT("GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg1; ++ IFX_PRINT("GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg2; ++ IFX_PRINT("GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg3; ++ IFX_PRINT("GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg4; ++ IFX_PRINT("GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ ++ addr=_core_if->pcgcctl; ++ IFX_PRINT("PCGCCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ ++ addr=&_core_if->core_global_regs->grxfsiz; ++ IFX_PRINT("GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ ++ #ifdef __IS_HOST__ ++ addr=&_core_if->core_global_regs->gnptxfsiz; ++ IFX_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->core_global_regs->hptxfsiz; ++ IFX_PRINT("HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_FIFO__ ++ addr=&_core_if->core_global_regs->gnptxfsiz; ++ IFX_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ for (i=0; i<= _core_if->hwcfg4.b.num_in_eps; i++) ++ { ++ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; ++ IFX_PRINT("DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,ifxusb_rreg(addr)); ++ } ++ #else ++ addr=&_core_if->core_global_regs->gnptxfsiz; ++ IFX_PRINT("TXFSIZ[00] @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ for (i=0; i< _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ { ++ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; ++ IFX_PRINT("TXFSIZ[%02d] @0x%08X : 0x%08X\n",i+1,(uint32_t)addr,ifxusb_rreg(addr)); ++ } ++ #endif ++ #endif //__IS_DEVICE__ ++ ++ #ifdef __IS_HOST__ ++ IFX_PRINT("Host Global Registers\n"); ++ addr=&_core_if->host_global_regs->hcfg; ++ IFX_PRINT("HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->hfir; ++ IFX_PRINT("HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->hfnum; ++ IFX_PRINT("HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->hptxsts; ++ IFX_PRINT("HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->haint; ++ IFX_PRINT("HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->host_global_regs->haintmsk; ++ IFX_PRINT("HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr= _core_if->hprt0; ++ IFX_PRINT("HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) ++ { ++ IFX_PRINT("Host Channel %d Specific Registers\n", i); ++ addr=&_core_if->hc_regs[i]->hcchar; ++ IFX_PRINT("HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hcsplt; ++ IFX_PRINT("HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hcint; ++ IFX_PRINT("HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hcintmsk; ++ IFX_PRINT("HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hctsiz; ++ IFX_PRINT("HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->hc_regs[i]->hcdma; ++ IFX_PRINT("HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ } ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ IFX_PRINT("Device Global Registers\n"); ++ addr=&_core_if->dev_global_regs->dcfg; ++ IFX_PRINT("DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->dctl; ++ IFX_PRINT("DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->dsts; ++ IFX_PRINT("DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->diepmsk; ++ IFX_PRINT("DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->doepmsk; ++ IFX_PRINT("DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->daintmsk; ++ IFX_PRINT("DAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->daint; ++ IFX_PRINT("DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->dvbusdis; ++ IFX_PRINT("DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ addr=&_core_if->dev_global_regs->dvbuspulse; ++ IFX_PRINT("DVBUSPULSE @0x%08X : 0x%08X\n", (uint32_t)addr,ifxusb_rreg(addr)); ++ ++ addr=&_core_if->dev_global_regs->dtknqr1; ++ IFX_PRINT("DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 6) { ++ addr=&_core_if->dev_global_regs->dtknqr2; ++ IFX_PRINT("DTKNQR2 @0x%08X : 0x%08X\n", (uint32_t)addr,ifxusb_rreg(addr)); ++ } ++ ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 14) ++ { ++ addr=&_core_if->dev_global_regs->dtknqr3_dthrctl; ++ IFX_PRINT("DTKNQR3_DTHRCTL @0x%08X : 0x%08X\n", (uint32_t)addr, ifxusb_rreg(addr)); ++ } ++ ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 22) ++ { ++ addr=&_core_if->dev_global_regs->dtknqr4_fifoemptymsk; ++ IFX_PRINT("DTKNQR4 @0x%08X : 0x%08X\n", (uint32_t)addr, ifxusb_rreg(addr)); ++ } ++ ++ //for (i=0; i<= MAX_EPS_CHANNELS; i++) ++ //for (i=0; i<= 10; i++) ++ for (i=0; i<= 3; i++) ++ { ++ IFX_PRINT("Device EP %d Registers\n", i); ++ addri=&_core_if->in_ep_regs[i]->diepctl;addro=&_core_if->out_ep_regs[i]->doepctl; ++ IFX_PRINT("DEPCTL I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ addro=&_core_if->out_ep_regs[i]->doepfn; ++ IFX_PRINT("DEPFN I: O: 0x%08X\n",ifxusb_rreg(addro)); ++ addri=&_core_if->in_ep_regs[i]->diepint;addro=&_core_if->out_ep_regs[i]->doepint; ++ IFX_PRINT("DEPINT I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ addri=&_core_if->in_ep_regs[i]->dieptsiz;addro=&_core_if->out_ep_regs[i]->doeptsiz; ++ IFX_PRINT("DETSIZ I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ addri=&_core_if->in_ep_regs[i]->diepdma;addro=&_core_if->out_ep_regs[i]->doepdma; ++ IFX_PRINT("DEPDMA I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ addri=&_core_if->in_ep_regs[i]->dtxfsts; ++ IFX_PRINT("DTXFSTS I: 0x%08X\n",ifxusb_rreg(addri) ); ++ addri=&_core_if->in_ep_regs[i]->diepdmab;addro=&_core_if->out_ep_regs[i]->doepdmab; ++ IFX_PRINT("DEPDMAB I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); ++ } ++ #endif //__IS_DEVICE__ ++#endif //__ENABLE_DUMP__ ++} ++ ++void ifxusb_clean_spram(ifxusb_core_if_t *_core_if,uint32_t dwords) ++{ ++ volatile uint32_t *addr1,*addr2, *start_addr, *end_addr; ++ ++ if(!dwords) ++ return; ++ ++ start_addr = (uint32_t *)_core_if->data_fifo_dbg; ++ ++ end_addr = (uint32_t *)_core_if->data_fifo_dbg; ++ end_addr += dwords; ++ ++ IFX_PRINT("Clearning SPRAM: 0x%8X-0x%8X\n", (uint32_t)start_addr,(uint32_t)end_addr); ++ for(addr1 = start_addr; addr1 < end_addr; addr1+=4) ++ { ++ for(addr2 = addr1; addr2 < addr1+4; addr2++) ++ *addr2=0x00000000; ++ } ++ IFX_PRINT("Clearning SPRAM: 0x%8X-0x%8X Done\n", (uint32_t)start_addr,(uint32_t)end_addr); ++ return; ++} ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_cif.h b/drivers/usb/ifxhcd/ifxusb_cif.h +new file mode 100644 +index 0000000..191781f +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_cif.h +@@ -0,0 +1,665 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_cif.h ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The Core Interface provides basic services for accessing and ++ ** managing the IFX USB hardware. These services are used by both the ++ ** Host Controller Driver and the Peripheral Controller Driver. ++ ** FUNCTIONS : ++ ** COMPILER : gcc ++ ** REFERENCE : IFX hardware ref handbook for each plateforms ++ ** COPYRIGHT : ++ ** Version Control Section ** ++ ** $Author$ ++ ** $Date$ ++ ** $Revisions$ ++ ** $Log$ Revision history ++*****************************************************************************/ ++ ++/*! ++ \defgroup IFXUSB_DRIVER_V3 IFX USB SS Project ++ \brief IFX USB subsystem V3.x ++ */ ++ ++/*! ++ \defgroup IFXUSB_CIF Core Interface APIs ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief The Core Interface provides basic services for accessing and ++ managing the IFXUSB hardware. These services are used by both the ++ Host Controller Driver and the Peripheral Controller Driver. ++ */ ++ ++ ++/*! ++ \file ifxusb_cif.h ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the interface to the IFX USB Core. ++ */ ++ ++#if !defined(__IFXUSB_CIF_H__) ++#define __IFXUSB_CIF_H__ ++ ++#include <linux/workqueue.h> ++ ++#include <linux/version.h> ++#include <asm/param.h> ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++ ++#ifdef __DEBUG__ ++ #include "linux/timer.h" ++#endif ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#define IFXUSB_PARAM_SPEED_HIGH 0 ++#define IFXUSB_PARAM_SPEED_FULL 1 ++ ++#define IFXUSB_EP_SPEED_LOW 0 ++#define IFXUSB_EP_SPEED_FULL 1 ++#define IFXUSB_EP_SPEED_HIGH 2 ++ ++#define IFXUSB_EP_TYPE_CTRL 0 ++#define IFXUSB_EP_TYPE_ISOC 1 ++#define IFXUSB_EP_TYPE_BULK 2 ++#define IFXUSB_EP_TYPE_INTR 3 ++ ++#define IFXUSB_HC_PID_DATA0 0 ++#define IFXUSB_HC_PID_DATA2 1 ++#define IFXUSB_HC_PID_DATA1 2 ++#define IFXUSB_HC_PID_MDATA 3 ++#define IFXUSB_HC_PID_SETUP 3 ++ ++ ++/*! ++ \addtogroup IFXUSB_CIF ++ */ ++/*@{*/ ++ ++/*! ++ \struct ifxusb_params ++ \brief IFXUSB Parameters structure. ++ This structure is used for both importing from insmod stage and run-time storage. ++ These parameters define how the IFXUSB controller should be configured. ++ */ ++typedef struct ifxusb_params ++{ ++ int32_t dma_burst_size; /*!< The DMA Burst size (applicable only for Internal DMA ++ Mode). 0(for single), 1(incr), 4(incr4), 8(incr8) 16(incr16) ++ */ ++ /* Translate this to GAHBCFG values */ ++ int32_t speed; /*!< Specifies the maximum speed of operation in host and device mode. ++ The actual speed depends on the speed of the attached device and ++ the value of phy_type. The actual speed depends on the speed of the ++ attached device. ++ 0 - High Speed (default) ++ 1 - Full Speed ++ */ ++ ++ int32_t data_fifo_size; /*!< Total number of dwords in the data FIFO memory. This ++ memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic ++ Tx FIFOs. ++ 32 to 32768 ++ */ ++ #ifdef __IS_DEVICE__ ++ int32_t rx_fifo_size; /*!< Number of dwords in the Rx FIFO in device mode. ++ 16 to 32768 ++ */ ++ ++ ++ int32_t tx_fifo_size[MAX_EPS_CHANNELS]; /*!< Number of dwords in each of the Tx FIFOs in device mode. ++ 4 to 768 ++ */ ++ #ifdef __DED_FIFO__ ++ int32_t thr_ctl; /*!< Threshold control on/off */ ++ int32_t tx_thr_length; /*!< Threshold length for Tx */ ++ int32_t rx_thr_length; /*!< Threshold length for Rx*/ ++ #endif ++ #else //__IS_HOST__ ++ int32_t host_channels; /*!< The number of host channel registers to use. ++ 1 to 16 ++ */ ++ ++ int32_t rx_fifo_size; /*!< Number of dwords in the Rx FIFO in host mode. ++ 16 to 32768 ++ */ ++ ++ int32_t nperio_tx_fifo_size;/*!< Number of dwords in the non-periodic Tx FIFO in host mode. ++ 16 to 32768 ++ */ ++ ++ int32_t perio_tx_fifo_size; /*!< Number of dwords in the host periodic Tx FIFO. ++ 16 to 32768 ++ */ ++ #endif //__IS_HOST__ ++ ++ int32_t max_transfer_size; /*!< The maximum transfer size supported in bytes. ++ 2047 to 65,535 ++ */ ++ ++ int32_t max_packet_count; /*!< The maximum number of packets in a transfer. ++ 15 to 511 (default 511) ++ */ ++ int32_t phy_utmi_width; /*!< Specifies the UTMI+ Data Width. ++ 8 or 16 bits (default 16) ++ */ ++ ++ int32_t turn_around_time_hs; /*!< Specifies the Turn-Around time at HS*/ ++ int32_t turn_around_time_fs; /*!< Specifies the Turn-Around time at FS*/ ++ ++ int32_t timeout_cal_hs; /*!< Specifies the Timeout_Calibration at HS*/ ++ int32_t timeout_cal_fs; /*!< Specifies the Timeout_Calibration at FS*/ ++} ifxusb_params_t; ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++/*! ++ \struct ifxusb_core_if ++ \brief The ifx_core_if structure contains information needed to manage ++ the IFX USB controller acting in either host or device mode. It ++ represents the programming view of the controller as a whole. ++ */ ++typedef struct ifxusb_core_if ++{ ++ ifxusb_params_t params; /*!< Run-time Parameters */ ++ ++ uint8_t core_no; /*!< core number (used as id when multi-core case */ ++ char *core_name; /*!< core name used for registration and informative purpose*/ ++ int irq; /*!< irq number this core is hooked */ ++ ++ /***************************************************************** ++ * Structures and pointers to physical register interface. ++ *****************************************************************/ ++ /** Core Global registers starting at offset 000h. */ ++ ifxusb_core_global_regs_t *core_global_regs; /*!< pointer to Core Global Registers, offset at 000h */ ++ ++ /** Host-specific registers */ ++ #ifdef __IS_HOST__ ++ /** Host Global Registers starting at offset 400h.*/ ++ ifxusb_host_global_regs_t *host_global_regs; /*!< pointer to Host Global Registers, offset at 400h */ ++ #define IFXUSB_HOST_GLOBAL_REG_OFFSET 0x400 ++ /** Host Port 0 Control and Status Register */ ++ volatile uint32_t *hprt0; /*!< pointer to HPRT0 Registers, offset at 440h */ ++ #define IFXUSB_HOST_PORT_REGS_OFFSET 0x440 ++ /** Host Channel Specific Registers at offsets 500h-5FCh. */ ++ ifxusb_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; /*!< pointer to Host-Channel n Registers, offset at 500h */ ++ #define IFXUSB_HOST_CHAN_REGS_OFFSET 0x500 ++ #define IFXUSB_CHAN_REGS_OFFSET 0x20 ++ #endif ++ ++ /** Device-specific registers */ ++ #ifdef __IS_DEVICE__ ++ /** Device Global Registers starting at offset 800h */ ++ ifxusb_device_global_regs_t *dev_global_regs; /*!< pointer to Device Global Registers, offset at 800h */ ++ #define IFXUSB_DEV_GLOBAL_REG_OFFSET 0x800 ++ ++ /** Device Logical IN Endpoint-Specific Registers 900h-AFCh */ ++ ifxusb_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; /*!< pointer to Device IN-EP Registers, offset at 900h */ ++ #define IFXUSB_DEV_IN_EP_REG_OFFSET 0x900 ++ #define IFXUSB_EP_REG_OFFSET 0x20 ++ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ ++ ifxusb_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];/*!< pointer to Device OUT-EP Registers, offset at 900h */ ++ #define IFXUSB_DEV_OUT_EP_REG_OFFSET 0xB00 ++ #endif ++ ++ /** Power and Clock Gating Control Register */ ++ volatile uint32_t *pcgcctl; /*!< pointer to Power and Clock Gating Control Registers, offset at E00h */ ++ #define IFXUSB_PCGCCTL_OFFSET 0xE00 ++ ++ /** Push/pop addresses for endpoints or host channels.*/ ++ uint32_t *data_fifo[MAX_EPS_CHANNELS]; /*!< pointer to FIFO access windows, offset at 1000h */ ++ #define IFXUSB_DATA_FIFO_OFFSET 0x1000 ++ #define IFXUSB_DATA_FIFO_SIZE 0x1000 ++ ++ uint32_t *data_fifo_dbg; /*!< pointer to FIFO debug windows, offset at 1000h */ ++ ++ /** Hardware Configuration -- stored here for convenience.*/ ++ hwcfg1_data_t hwcfg1; /*!< preserved Hardware Configuration 1 */ ++ hwcfg2_data_t hwcfg2; /*!< preserved Hardware Configuration 2 */ ++ hwcfg3_data_t hwcfg3; /*!< preserved Hardware Configuration 3 */ ++ hwcfg4_data_t hwcfg4; /*!< preserved Hardware Configuration 3 */ ++ uint32_t snpsid; /*!< preserved SNPSID */ ++ ++ /***************************************************************** ++ * Run-time informations. ++ *****************************************************************/ ++ /* Set to 1 if the core PHY interface bits in USBCFG have been initialized. */ ++ uint8_t phy_init_done; /*!< indicated PHY is initialized. */ ++ ++ #ifdef __IS_HOST__ ++ uint8_t queuing_high_bandwidth; /*!< Host mode, Queueing High Bandwidth. */ ++ #endif ++} ifxusb_core_if_t; ++ ++/*@}*//*IFXUSB_CIF*/ ++ ++ ++/*! ++ \fn void *ifxusb_alloc_buf(size_t size, int clear) ++ \brief This function is called to allocate buffer of specified size. ++ The allocated buffer is mapped into DMA accessable address. ++ \param size Size in BYTE to be allocated ++ \param clear 0: don't do clear after buffer allocated, other: do clear to zero ++ \return 0/NULL: Fail; uncached pointer of allocated buffer ++ \ingroup IFXUSB_CIF ++ */ ++extern void *ifxusb_alloc_buf(size_t size, int clear); ++ ++/*! ++ \fn void ifxusb_free_buf(void *vaddr) ++ \brief This function is called to free allocated buffer. ++ \param vaddr the uncached pointer of the buffer ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_free_buf(void *vaddr); ++ ++/*! ++ \fn int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, ++ int _irq, ++ uint32_t _reg_base_addr, ++ uint32_t _fifo_base_addr, ++ uint32_t _fifo_dbg_addr) ++ \brief This function is called to initialize the IFXUSB CSR data ++ structures. The register addresses in the device and host ++ structures are initialized from the base address supplied by the ++ caller. The calling function must make the OS calls to get the ++ base address of the IFXUSB controller registers. ++ \param _core_if Pointer of core_if structure ++ \param _irq irq number ++ \param _reg_base_addr Base address of IFXUSB core registers ++ \param _fifo_base_addr Fifo base address ++ \param _fifo_dbg_addr Fifo debug address ++ \return 0: success; ++ \ingroup IFXUSB_CIF ++ */ ++extern int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, ++ int _irq, ++ uint32_t _reg_base_addr, ++ uint32_t _fifo_base_addr, ++ uint32_t _fifo_dbg_addr); ++ ++ ++/*! ++ \fn void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if) ++ \brief This function free the mapped address in the IFXUSB CSR data structures. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ) ++ \brief This function enbles the controller's Global Interrupt in the AHB Config register. ++ \param _core_if Pointer of core_if structure ++ */ ++extern void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ); ++ ++/*! ++ \fn void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ) ++ \brief This function disables the controller's Global Interrupt in the AHB Config register. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ); ++ ++/*! ++ \fn void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ) ++ \brief Flush a Tx FIFO. ++ \param _core_if Pointer of core_if structure ++ \param _num Tx FIFO to flush. ( 0x10 for ALL TX FIFO ) ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ); ++ ++/*! ++ \fn void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ) ++ \brief Flush Rx FIFO. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ); ++ ++/*! ++ \fn void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ) ++ \brief Flush ALL Rx and Tx FIFO. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ); ++ ++ ++/*! ++ \fn int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if) ++ \brief Do core a soft reset of the core. Be careful with this because it ++ resets all the internal state machines of the core. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if); ++ ++ ++/*! ++ \brief Turn on the USB Core Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++*/ ++extern void ifxusb_power_on (ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_power_off (ifxusb_core_if_t *_core_if) ++ \brief Turn off the USB Core Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++*/ ++extern void ifxusb_power_off (ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if) ++ \brief Turn on the USB PHY Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++*/ ++extern void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if) ++ \brief Turn off the USB PHY Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++*/ ++extern void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if); ++ ++/*! ++ \fn void ifxusb_hard_reset(ifxusb_core_if_t *_core_if) ++ \brief Reset on the USB Core RCU ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++extern void ifxusb_hard_reset(ifxusb_core_if_t *_core_if); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ ++#ifdef __IS_HOST__ ++ /*! ++ \fn void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) ++ \brief This function initializes the IFXUSB controller registers for Host mode. ++ This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ request queues. ++ \param _core_if Pointer of core_if structure ++ \param _params parameters to be set ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params); ++ ++ /*! ++ \fn void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if) ++ \brief This function enables the Host mode interrupts. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if) ++ \brief This function disables the Host mode interrupts. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if); ++ ++ #if defined(__IS_TWINPASS__) ++ extern void ifxusb_enable_afe_oc(void); ++ #endif ++ ++ /*! ++ \fn void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) ++ \brief This function init the VBUS control. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_vbus_init(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) ++ \brief This function free the VBUS control. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_vbus_free(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) ++ \brief Turn on the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_vbus_on(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) ++ \brief Turn off the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_vbus_off(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn int ifxusb_vbus(ifxusb_core_if_t *_core_if) ++ \brief Read Current VBus status ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern int ifxusb_vbus(ifxusb_core_if_t *_core_if); ++ ++ #if defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) ++ /*! ++ \fn void ifxusb_oc_int_on(void) ++ \brief Turn on the OC interrupt ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_oc_int_on(void); ++ ++ /*! ++ \fn void ifxusb_oc_int_off(void) ++ \brief Turn off the OC interrupt ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_oc_int_off(void); ++ #endif //defined(__DO_OC_INT__) && defined(__DO_OC_INT_ENABLE__) ++#endif ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ ++#ifdef __IS_DEVICE__ ++ /*! ++ \fn void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) ++ \brief This function enables the Device mode interrupts. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) ++ \brief Gets the current USB frame number. This is the frame number from the last SOF packet. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) ++ \brief Set the EP STALL. ++ \param _core_if Pointer of core_if structure ++ \param _epno EP number ++ \param _is_in 1: is IN transfer ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in); ++ ++ /*! ++ \fn void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) ++ \brief Set the EP STALL. ++ \param _core_if Pointer of core_if structure ++ \param _epno EP number ++ \param _ep_type EP Type ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in); ++ ++ /*! ++ \fn void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) ++ \brief This function initializes the IFXUSB controller registers for Device mode. ++ This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ request queues. ++ This function validate the imported parameters and store the result in the CIF structure. ++ After ++ \param _core_if Pointer of core_if structure ++ \param _params structure of inported parameters ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params); ++#endif ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#if defined(__GADGET_LED__) || defined(__HOST_LED__) ++ /*! ++ \fn void ifxusb_led_init(ifxusb_core_if_t *_core_if) ++ \brief This function init the LED control. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_led_init(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_led_free(ifxusb_core_if_t *_core_if) ++ \brief This function free the LED control. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_led_free(ifxusb_core_if_t *_core_if); ++ ++ /*! ++ \fn void ifxusb_led(ifxusb_core_if_t *_core_if) ++ \brief This function trigger the LED access. ++ \param _core_if Pointer of core_if structure ++ \ingroup IFXUSB_CIF ++ */ ++ extern void ifxusb_led(ifxusb_core_if_t *_core_if); ++#endif ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++/* internal routines for debugging */ ++extern void ifxusb_dump_msg(const u8 *buf, unsigned int length); ++extern void ifxusb_dump_spram(ifxusb_core_if_t *_core_if); ++extern void ifxusb_dump_registers(ifxusb_core_if_t *_core_if); ++extern void ifxusb_clean_spram(ifxusb_core_if_t *_core_if,uint32_t dwords); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++static inline uint32_t ifxusb_read_core_intr(ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_rreg(&_core_if->core_global_regs->gintsts) & ++ (ifxusb_rreg(&_core_if->core_global_regs->gintmsk) ++#ifdef __USE_TIMER_4_SOF__ ++ | IFXUSB_SOF_INTR_MASK ++#endif ++ )); ++} ++ ++static inline uint32_t ifxusb_read_otg_intr (ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_rreg (&_core_if->core_global_regs->gotgint)); ++} ++ ++static inline uint32_t ifxusb_mode(ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_rreg( &_core_if->core_global_regs->gintsts ) & 0x1); ++} ++static inline uint8_t ifxusb_is_device_mode(ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_mode(_core_if) != 1); ++} ++static inline uint8_t ifxusb_is_host_mode(ifxusb_core_if_t *_core_if) ++{ ++ return (ifxusb_mode(_core_if) == 1); ++} ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#ifdef __IS_HOST__ ++ static inline uint32_t ifxusb_read_hprt0(ifxusb_core_if_t *_core_if) ++ { ++ hprt0_data_t hprt0; ++ hprt0.d32 = ifxusb_rreg(_core_if->hprt0); ++ hprt0.b.prtena = 0; ++ hprt0.b.prtconndet = 0; ++ hprt0.b.prtenchng = 0; ++ hprt0.b.prtovrcurrchng = 0; ++ return hprt0.d32; ++ } ++ ++ static inline uint32_t ifxusb_read_host_all_channels_intr (ifxusb_core_if_t *_core_if) ++ { ++ return (ifxusb_rreg (&_core_if->host_global_regs->haint)); ++ } ++ ++ static inline uint32_t ifxusb_read_host_channel_intr (ifxusb_core_if_t *_core_if, int hc_num) ++ { ++ return (ifxusb_rreg (&_core_if->hc_regs[hc_num]->hcint)); ++ } ++#endif ++ ++#ifdef __IS_DEVICE__ ++ static inline uint32_t ifxusb_read_dev_all_in_ep_intr(ifxusb_core_if_t *_core_if) ++ { ++ uint32_t v; ++ v = ifxusb_rreg(&_core_if->dev_global_regs->daint) & ++ ifxusb_rreg(&_core_if->dev_global_regs->daintmsk); ++ return (v & 0xffff); ++ } ++ ++ static inline uint32_t ifxusb_read_dev_all_out_ep_intr(ifxusb_core_if_t *_core_if) ++ { ++ uint32_t v; ++ v = ifxusb_rreg(&_core_if->dev_global_regs->daint) & ++ ifxusb_rreg(&_core_if->dev_global_regs->daintmsk); ++ return ((v & 0xffff0000) >> 16); ++ } ++ ++ static inline uint32_t ifxusb_read_dev_in_ep_intr(ifxusb_core_if_t *_core_if, int _ep_num) ++ { ++ uint32_t v; ++ v = ifxusb_rreg(&_core_if->in_ep_regs[_ep_num]->diepint) & ++ ifxusb_rreg(&_core_if->dev_global_regs->diepmsk); ++ return v; ++ } ++ ++ static inline uint32_t ifxusb_read_dev_out_ep_intr(ifxusb_core_if_t *_core_if, int _ep_num) ++ { ++ uint32_t v; ++ v = ifxusb_rreg(&_core_if->out_ep_regs[_ep_num]->doepint) & ++ ifxusb_rreg(&_core_if->dev_global_regs->doepmsk); ++ return v; ++ } ++ ++#endif ++ ++extern void ifxusb_attr_create (void *_dev); ++ ++extern void ifxusb_attr_remove (void *_dev); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#endif // !defined(__IFXUSB_CIF_H__) ++ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_cif_d.c b/drivers/usb/ifxhcd/ifxusb_cif_d.c +new file mode 100644 +index 0000000..36ab0e7 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_cif_d.c +@@ -0,0 +1,458 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_cif_d.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The Core Interface provides basic services for accessing and ++ ** managing the IFX USB hardware. These services are used by the ++ ** Peripheral Controller Driver only. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxusb_cif_d.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the interface to the IFX USB Core. ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++ ++#include <asm/byteorder.h> ++#include <asm/unaligned.h> ++ ++#ifdef __DEBUG__ ++ #include <linux/jiffies.h> ++#endif ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++#include "ifxpcd.h" ++ ++ ++ ++/*! ++ \brief Initializes the DevSpd field of the DCFG register depending on the PHY type ++ and the enumeration speed of the device. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_dev_init_spd(ifxusb_core_if_t *_core_if) ++{ ++ uint32_t val; ++ dcfg_data_t dcfg; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ if (_core_if->params.speed == IFXUSB_PARAM_SPEED_FULL) ++ /* High speed PHY running at full speed */ ++ val = 0x1; ++ else ++ /* High speed PHY running at high speed and full speed*/ ++ val = 0x0; ++ ++ IFX_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); ++ dcfg.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dcfg); ++ dcfg.b.devspd = val; ++ ifxusb_wreg(&_core_if->dev_global_regs->dcfg, dcfg.d32); ++} ++ ++ ++/*! ++ \brief This function enables the Device mode interrupts. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) ++{ ++ gint_data_t intr_mask ={ .d32 = 0}; ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); ++ ++ /* Clear any pending OTG Interrupts */ ++ ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); ++ ++ /* Clear any pending interrupts */ ++ ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); ++ ++ /* Enable the interrupts in the GINTMSK.*/ ++ intr_mask.b.modemismatch = 1; ++ intr_mask.b.conidstschng = 1; ++ intr_mask.b.wkupintr = 1; ++ intr_mask.b.disconnect = 1; ++ intr_mask.b.usbsuspend = 1; ++ ++ intr_mask.b.usbreset = 1; ++ intr_mask.b.enumdone = 1; ++ intr_mask.b.inepintr = 1; ++ intr_mask.b.outepintr = 1; ++ intr_mask.b.erlysuspend = 1; ++ #ifndef __DED_FIFO__ ++// intr_mask.b.epmismatch = 1; ++ #endif ++ ++ ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++ IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); ++} ++ ++/*! ++ \brief Gets the current USB frame number. This is the frame number from the last SOF packet. ++ \param _core_if Pointer of core_if structure ++ */ ++uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) ++{ ++ dsts_data_t dsts; ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ dsts.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dsts); ++ /* read current frame/microfreme number from DSTS register */ ++ return dsts.b.soffn; ++} ++ ++ ++/*! ++ \brief Set the EP STALL. ++ */ ++void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) ++{ ++ depctl_data_t depctl; ++ volatile uint32_t *depctl_addr; ++ ++ IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); ++ ++ depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): ++ (&(_core_if->out_ep_regs[_epno]->doepctl)); ++ depctl.d32 = ifxusb_rreg(depctl_addr); ++ depctl.b.stall = 1; ++ ++ if (_is_in && depctl.b.epena) ++ depctl.b.epdis = 1; ++ ++ ifxusb_wreg(depctl_addr, depctl.d32); ++ IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); ++ return; ++} ++ ++/*! ++\brief Clear the EP STALL. ++ */ ++void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) ++{ ++ depctl_data_t depctl; ++ volatile uint32_t *depctl_addr; ++ ++ IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); ++ ++ depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): ++ (&(_core_if->out_ep_regs[_epno]->doepctl)); ++ ++ depctl.d32 = ifxusb_rreg(depctl_addr); ++ /* clear the stall bits */ ++ depctl.b.stall = 0; ++ ++ /* ++ * USB Spec 9.4.5: For endpoints using data toggle, regardless ++ * of whether an endpoint has the Halt feature set, a ++ * ClearFeature(ENDPOINT_HALT) request always results in the ++ * data toggle being reinitialized to DATA0. ++ */ ++ if (_ep_type == IFXUSB_EP_TYPE_INTR || _ep_type == IFXUSB_EP_TYPE_BULK) ++ depctl.b.setd0pid = 1; /* DATA0 */ ++ ++ ifxusb_wreg(depctl_addr, depctl.d32); ++ IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); ++ return; ++} ++ ++/*! ++ \brief This function initializes the IFXUSB controller registers for Device mode. ++ This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ request queues. ++ \param _core_if Pointer of core_if structure ++ \param _params parameters to be set ++ */ ++void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ gusbcfg_data_t usbcfg ={.d32 = 0}; ++ gahbcfg_data_t ahbcfg ={.d32 = 0}; ++ dcfg_data_t dcfg ={.d32 = 0}; ++ grstctl_t resetctl ={.d32 = 0}; ++ gotgctl_data_t gotgctl ={.d32 = 0}; ++ ++ uint32_t dir; ++ int i; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); ++ ++ /* Copy Params */ ++ _core_if->params.dma_burst_size = _params->dma_burst_size; ++ _core_if->params.speed = _params->speed; ++ if(_params->max_transfer_size < 2048 || _params->max_transfer_size > ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1) ) ++ _core_if->params.max_transfer_size = ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1); ++ else ++ _core_if->params.max_transfer_size = _params->max_transfer_size; ++ ++ if(_params->max_packet_count < 16 || _params->max_packet_count > ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1) ) ++ _core_if->params.max_packet_count= ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1); ++ else ++ _core_if->params.max_packet_count= _params->max_packet_count; ++ _core_if->params.phy_utmi_width = _params->phy_utmi_width; ++ _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; ++ _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; ++ _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; ++ _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; ++ ++ #ifdef __DED_FIFO__ ++ _core_if->params.thr_ctl = _params->thr_ctl; ++ _core_if->params.tx_thr_length = _params->tx_thr_length; ++ _core_if->params.rx_thr_length = _params->rx_thr_length; ++ #endif ++ ++ /* Reset the Controller */ ++ do ++ { ++ while(ifxusb_core_soft_reset( _core_if )) ++ ifxusb_hard_reset(_core_if); ++ } while (ifxusb_is_host_mode(_core_if)); ++ ++ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); ++ #if 0 ++ #if defined(__DED_FIFO__) ++ usbcfg.b.ForceDevMode = 1; ++ usbcfg.b.ForceHstMode = 0; ++ #endif ++ #endif ++ usbcfg.b.term_sel_dl_pulse = 0; ++ ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* This programming sequence needs to happen in FS mode before any other ++ * programming occurs */ ++ /* High speed PHY. */ ++ if (!_core_if->phy_init_done) ++ { ++ _core_if->phy_init_done = 1; ++ /* HS PHY parameters. These parameters are preserved ++ * during soft reset so only program the first time. Do ++ * a soft reset immediately after setting phyif. */ ++ usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ ++ usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; ++ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); ++ /* Reset after setting the PHY parameters */ ++ ifxusb_core_soft_reset( _core_if ); ++ } ++ ++ /* Program the GAHBCFG Register.*/ ++ switch (_core_if->params.dma_burst_size) ++ { ++ case 0 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; ++ break; ++ case 1 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; ++ break; ++ case 4 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; ++ break; ++ case 8 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; ++ break; ++ case 16: ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; ++ break; ++ } ++ ahbcfg.b.dmaenable = 1; ++ ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); ++ ++ /* Program the GUSBCFG register. */ ++ usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Restart the Phy Clock */ ++ ifxusb_wreg(_core_if->pcgcctl, 0); ++ ++ /* Device configuration register */ ++ ifxusb_dev_init_spd(_core_if); ++ dcfg.d32 = ifxusb_rreg( &_core_if->dev_global_regs->dcfg); ++ dcfg.b.perfrint = IFXUSB_DCFG_FRAME_INTERVAL_80; ++ #if defined(__DED_FIFO__) ++ #if defined(__DESC_DMA__) ++ dcfg.b.descdma = 1; ++ #else ++ dcfg.b.descdma = 0; ++ #endif ++ #endif ++ ++ ifxusb_wreg( &_core_if->dev_global_regs->dcfg, dcfg.d32 ); ++ ++ /* Configure data FIFO sizes */ ++ _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; ++ _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); ++ IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); ++ IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); ++ ++ _core_if->params.tx_fifo_size[0]= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; ++ ++ #ifdef __DED_FIFO__ ++ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) ++ _core_if->params.tx_fifo_size[i] = ++ ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]) >> 16; ++ #else ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ _core_if->params.tx_fifo_size[i+1] = ++ ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]) >> 16; ++ #endif ++ ++ #ifdef __DEBUG__ ++ #ifdef __DED_FIFO__ ++ for (i=0; i <= _core_if->hwcfg4.b.num_in_eps; i++) ++ IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i]); ++ #else ++ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.tx_fifo_size[0]); ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i+1]); ++ #endif ++ #endif ++ ++ { ++ fifosize_data_t txfifosize; ++ if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) ++ _core_if->params.data_fifo_size = _params->data_fifo_size; ++ ++ ++ if(_params->rx_fifo_size >=0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) ++ _core_if->params.rx_fifo_size = _params->rx_fifo_size; ++ if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) ++ _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; ++ ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); ++ ++ for (i=0; i < MAX_EPS_CHANNELS; i++) ++ if(_params->tx_fifo_size[i] >=0 && _params->tx_fifo_size[i] < _core_if->params.tx_fifo_size[i]) ++ _core_if->params.tx_fifo_size[i] = _params->tx_fifo_size[i]; ++ ++ txfifosize.b.startaddr = _core_if->params.rx_fifo_size; ++ #ifdef __DED_FIFO__ ++ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) ++ _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; ++ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; ++ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) ++ { ++ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i] > _core_if->params.data_fifo_size) ++ _core_if->params.tx_fifo_size[i]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.tx_fifo_size[i]; ++ ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i-1], txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i]; ++ } ++ #else ++ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) ++ _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; ++ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ { ++ if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i+1] > _core_if->params.data_fifo_size) ++ _core_if->params.tx_fifo_size[i+1]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ //txfifosize.b.depth=_core_if->params.tx_fifo_size[i+1]; ++ ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i], txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i+1]; ++ } ++ #endif ++ } ++ ++ #ifdef __DEBUG__ ++ { ++ fifosize_data_t fifosize; ++ IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); ++ ++ IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X Sz=0x%06X\n", 0,ifxusb_rreg(&global_regs->grxfsiz)); ++ #ifdef __DED_FIFO__ ++ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " Tx[00] FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) ++ { ++ fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]); ++ IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); ++ } ++ #else ++ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) ++ { ++ fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]); ++ IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); ++ } ++ #endif ++ } ++ #endif ++ ++ /* Clear Host Set HNP Enable in the OTG Control Register */ ++ gotgctl.b.hstsethnpen = 1; ++ ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); ++ ++ /* Flush the FIFOs */ ++ ifxusb_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ ++ ifxusb_flush_rx_fifo(_core_if); ++ ++ /* Flush the Learning Queue. */ ++ resetctl.b.intknqflsh = 1; ++ ifxusb_wreg( &global_regs->grstctl, resetctl.d32); ++ ++ /* Clear all pending Device Interrupts */ ++ ifxusb_wreg( &_core_if->dev_global_regs->diepmsk , 0 ); ++ ifxusb_wreg( &_core_if->dev_global_regs->doepmsk , 0 ); ++ ifxusb_wreg( &_core_if->dev_global_regs->daint , 0xFFFFFFFF ); ++ ifxusb_wreg( &_core_if->dev_global_regs->daintmsk, 0 ); ++ ++ dir=_core_if->hwcfg1.d32; ++ for (i=0; i <= _core_if->hwcfg2.b.num_dev_ep ; i++,dir>>=2) ++ { ++ depctl_data_t depctl; ++ if((dir&0x03)==0 || (dir&0x03) ==1) ++ { ++ depctl.d32 = ifxusb_rreg(&_core_if->in_ep_regs[i]->diepctl); ++ if (depctl.b.epena) ++ { ++ depctl.d32 = 0; ++ depctl.b.epdis = 1; ++ depctl.b.snak = 1; ++ } ++ else ++ depctl.d32 = 0; ++ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepctl, depctl.d32); ++ #ifndef __DESC_DMA__ ++ ifxusb_wreg( &_core_if->in_ep_regs[i]->dieptsiz, 0); ++ #endif ++ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepdma, 0); ++ ifxusb_wreg( &_core_if->in_ep_regs[i]->diepint, 0xFF); ++ } ++ ++ if((dir&0x03)==0 || (dir&0x03) ==2) ++ { ++ depctl.d32 = ifxusb_rreg(&_core_if->out_ep_regs[i]->doepctl); ++ if (depctl.b.epena) ++ { ++ depctl.d32 = 0; ++ depctl.b.epdis = 1; ++ depctl.b.snak = 1; ++ } ++ else ++ depctl.d32 = 0; ++ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepctl, depctl.d32); ++ #ifndef __DESC_DMA__ ++ ifxusb_wreg( &_core_if->out_ep_regs[i]->doeptsiz, 0); ++ #endif ++ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepdma, 0); ++ ifxusb_wreg( &_core_if->out_ep_regs[i]->doepint, 0xFF); ++ } ++ } ++} ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_cif_h.c b/drivers/usb/ifxhcd/ifxusb_cif_h.c +new file mode 100644 +index 0000000..0f47ecd +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_cif_h.c +@@ -0,0 +1,846 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_cif_h.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The Core Interface provides basic services for accessing and ++ ** managing the IFX USB hardware. These services are used by the ++ ** Host Controller Driver only. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxusb_cif_h.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the interface to the IFX USB Core. ++*/ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <asm/byteorder.h> ++#include <asm/unaligned.h> ++ ++#ifdef __DEBUG__ ++ #include <linux/jiffies.h> ++#endif ++#include <linux/platform_device.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_board.h> ++#endif ++ ++//#include <asm/ifx/ifx_gpio.h> ++#if defined(__UEIP__) ++// #include <asm/ifx/ifx_led.h> ++#endif ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++#include "ifxhcd.h" ++ ++#if !defined(__UEIP__) ++ #undef __USING_LED_AS_GPIO__ ++#endif ++ ++ ++/*! ++ \brief This function enables the Host mode interrupts. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if) ++{ ++ gint_data_t intr_mask ={ .d32 = 0}; ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); ++ ++ /* Clear any pending OTG Interrupts */ ++ ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); ++ ++ /* Clear any pending interrupts */ ++ ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); ++ ++ /* Enable the interrupts in the GINTMSK.*/ ++ ++ /* Common interrupts */ ++ intr_mask.b.modemismatch = 1; ++ intr_mask.b.conidstschng = 1; ++ intr_mask.b.wkupintr = 1; ++ intr_mask.b.disconnect = 1; ++ intr_mask.b.usbsuspend = 1; ++ ++ /* Host interrupts */ ++ intr_mask.b.sofintr = 1; ++ intr_mask.b.portintr = 1; ++ intr_mask.b.hcintr = 1; ++ ++ ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++ IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); ++} ++ ++/*! ++ \brief This function disables the Host mode interrupts. ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ IFX_DEBUGPL(DBG_CILV, "%s()\n", __func__); ++ ++ #if 1 ++ ifxusb_wreg( &global_regs->gintmsk, 0); ++ #else ++ /* Common interrupts */ ++ { ++ gint_data_t intr_mask ={.d32 = 0}; ++ intr_mask.b.modemismatch = 1; ++ intr_mask.b.rxstsqlvl = 1; ++ intr_mask.b.conidstschng = 1; ++ intr_mask.b.wkupintr = 1; ++ intr_mask.b.disconnect = 1; ++ intr_mask.b.usbsuspend = 1; ++ ++ /* Host interrupts */ ++ intr_mask.b.sofintr = 1; ++ intr_mask.b.portintr = 1; ++ intr_mask.b.hcintr = 1; ++ intr_mask.b.ptxfempty = 1; ++ intr_mask.b.nptxfempty = 1; ++ ifxusb_mreg(&global_regs->gintmsk, intr_mask.d32, 0); ++ } ++ #endif ++} ++ ++/*! ++ \brief This function initializes the IFXUSB controller registers for Host mode. ++ This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ request queues. ++ \param _core_if Pointer of core_if structure ++ \param _params parameters to be set ++ */ ++void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) ++{ ++ ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ ++ gusbcfg_data_t usbcfg ={.d32 = 0}; ++ gahbcfg_data_t ahbcfg ={.d32 = 0}; ++ gotgctl_data_t gotgctl ={.d32 = 0}; ++ ++ int i; ++ ++ IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); ++ ++ /* Copy Params */ ++ ++ _core_if->params.dma_burst_size = _params->dma_burst_size; ++ _core_if->params.speed = _params->speed; ++ _core_if->params.max_transfer_size = _params->max_transfer_size; ++ _core_if->params.max_packet_count = _params->max_packet_count; ++ _core_if->params.phy_utmi_width = _params->phy_utmi_width; ++ _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; ++ _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; ++ _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; ++ _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; ++ ++ /* Reset the Controller */ ++ do ++ { ++ while(ifxusb_core_soft_reset( _core_if )) ++ ifxusb_hard_reset(_core_if); ++ } while (ifxusb_is_device_mode(_core_if)); ++ ++ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); ++// usbcfg.b.ulpi_ext_vbus_drv = 1; ++ usbcfg.b.term_sel_dl_pulse = 0; ++ ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* This programming sequence needs to happen in FS mode before any other ++ * programming occurs */ ++ /* High speed PHY. */ ++ if (!_core_if->phy_init_done) ++ { ++ _core_if->phy_init_done = 1; ++ /* HS PHY parameters. These parameters are preserved ++ * during soft reset so only program the first time. Do ++ * a soft reset immediately after setting phyif. */ ++ usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ ++ usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; ++ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); ++ /* Reset after setting the PHY parameters */ ++ ifxusb_core_soft_reset( _core_if ); ++ } ++ ++ usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); ++// usbcfg.b.ulpi_fsls = 0; ++// usbcfg.b.ulpi_clk_sus_m = 0; ++ ifxusb_wreg(&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Program the GAHBCFG Register.*/ ++ switch (_core_if->params.dma_burst_size) ++ { ++ case 0 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; ++ break; ++ case 1 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; ++ break; ++ case 4 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; ++ break; ++ case 8 : ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; ++ break; ++ case 16: ++ ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; ++ break; ++ } ++ ahbcfg.b.dmaenable = 1; ++ ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); ++ ++ /* Program the GUSBCFG register. */ ++ usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Restart the Phy Clock */ ++ ifxusb_wreg(_core_if->pcgcctl, 0); ++ ++ /* Initialize Host Configuration Register */ ++ { ++ hcfg_data_t hcfg; ++ hcfg.d32 = ifxusb_rreg(&_core_if->host_global_regs->hcfg); ++ hcfg.b.fslspclksel = IFXUSB_HCFG_30_60_MHZ; ++ if (_params->speed == IFXUSB_PARAM_SPEED_FULL) ++ hcfg.b.fslssupp = 1; ++ ifxusb_wreg(&_core_if->host_global_regs->hcfg, hcfg.d32); ++ } ++ ++ _core_if->params.host_channels=(_core_if->hwcfg2.b.num_host_chan + 1); ++ ++ if(_params->host_channels>0 && _params->host_channels < _core_if->params.host_channels) ++ _core_if->params.host_channels = _params->host_channels; ++ ++ /* Configure data FIFO sizes */ ++ _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; ++ _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); ++ _core_if->params.nperio_tx_fifo_size= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; ++ _core_if->params.perio_tx_fifo_size = ifxusb_rreg(&global_regs->hptxfsiz) >> 16; ++ IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); ++ IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); ++ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.nperio_tx_fifo_size); ++ IFX_DEBUGPL(DBG_CIL, " PTx FIFO Size=0x%06X\n", _core_if->params.perio_tx_fifo_size); ++ ++ { ++ fifosize_data_t txfifosize; ++ if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) ++ _core_if->params.data_fifo_size = _params->data_fifo_size; ++ ++ if( _params->rx_fifo_size >= 0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) ++ _core_if->params.rx_fifo_size = _params->rx_fifo_size; ++ if( _params->nperio_tx_fifo_size >=0 && _params->nperio_tx_fifo_size < _core_if->params.nperio_tx_fifo_size) ++ _core_if->params.nperio_tx_fifo_size = _params->nperio_tx_fifo_size; ++ if( _params->perio_tx_fifo_size >=0 && _params->perio_tx_fifo_size < _core_if->params.perio_tx_fifo_size) ++ _core_if->params.perio_tx_fifo_size = _params->perio_tx_fifo_size; ++ ++ if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) ++ _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; ++ ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); ++ txfifosize.b.startaddr = _core_if->params.rx_fifo_size; ++ ++ if(txfifosize.b.startaddr + _core_if->params.nperio_tx_fifo_size > _core_if->params.data_fifo_size) ++ _core_if->params.nperio_tx_fifo_size = _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.nperio_tx_fifo_size; ++ ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.nperio_tx_fifo_size; ++ ++ if(txfifosize.b.startaddr + _core_if->params.perio_tx_fifo_size > _core_if->params.data_fifo_size) ++ _core_if->params.perio_tx_fifo_size = _core_if->params.data_fifo_size - txfifosize.b.startaddr; ++ txfifosize.b.depth=_core_if->params.perio_tx_fifo_size; ++ ifxusb_wreg( &global_regs->hptxfsiz, txfifosize.d32); ++ txfifosize.b.startaddr += _core_if->params.perio_tx_fifo_size; ++ } ++ ++ #ifdef __DEBUG__ ++ { ++ fifosize_data_t fifosize; ++ IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); ++ ++ fifosize.d32=ifxusb_rreg(&global_regs->grxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ fifosize.d32=ifxusb_rreg(&global_regs->hptxfsiz); ++ IFX_DEBUGPL(DBG_CIL, " PTx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); ++ } ++ #endif ++ ++ /* Clear Host Set HNP Enable in the OTG Control Register */ ++ gotgctl.b.hstsethnpen = 1; ++ ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); ++ ++ /* Flush the FIFOs */ ++ ifxusb_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ ++ ifxusb_flush_rx_fifo(_core_if); ++ ++ for (i = 0; i < _core_if->hwcfg2.b.num_host_chan + 1; i++) ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); ++ hcchar.b.chen = 0; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ ifxusb_wreg(&_core_if->hc_regs[i]->hcchar, hcchar.d32); ++ } ++ /* Halt all channels to put them into a known state. */ ++ for (i = 0; i < _core_if->hwcfg2.b.num_host_chan + 1; i++) ++ { ++ hcchar_data_t hcchar; ++ int count = 0; ++ ++ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ ifxusb_wreg(&_core_if->hc_regs[i]->hcchar, hcchar.d32); ++ ++ IFX_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i); ++ do{ ++ hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); ++ if (++count > 1000) ++ { ++ IFX_ERROR("%s: Unable to clear halt on channel %d\n", __func__, i); ++ break; ++ } ++ } while (hcchar.b.chen); ++ } ++} ++ ++////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#if defined(__UEIP__) ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ int ifxusb_vbus_status =-1; ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS1) || defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ int ifxusb_vbus1_status =-1; ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS2) || defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ int ifxusb_vbus2_status =-1; ++ #endif ++ ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ static void *g_usb_vbus_trigger = NULL; ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ static void *g_usb_vbus1_trigger = NULL; ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ static void *g_usb_vbus2_trigger = NULL; ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ int ifxusb_vbus_gpio_inited=0; ++ #endif ++ ++#else //defined(__UEIP__) ++ int ifxusb_vbus_gpio_inited=0; ++#endif ++ ++////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) ++{ ++ #if defined(__UEIP__) ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ if ( !g_usb_vbus_trigger ) ++ { ++ ifx_led_trigger_register("USB_VBUS", &g_usb_vbus_trigger); ++ if ( g_usb_vbus_trigger != NULL ) ++ { ++ struct ifx_led_trigger_attrib attrib = {0}; ++ attrib.delay_on = 0; ++ attrib.delay_off = 0; ++ attrib.timeout = 0; ++ attrib.def_value = 0; ++ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; ++ IFX_DEBUGP("Reg USB power!!\n"); ++ ifx_led_trigger_set_attrib(g_usb_vbus_trigger, &attrib); ++ ifxusb_vbus_status =0; ++ } ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0 && !g_usb_vbus1_trigger ) ++ { ++ ifx_led_trigger_register("USB_VBUS1", &g_usb_vbus1_trigger); ++ if ( g_usb_vbus1_trigger != NULL ) ++ { ++ struct ifx_led_trigger_attrib attrib = {0}; ++ attrib.delay_on = 0; ++ attrib.delay_off = 0; ++ attrib.timeout = 0; ++ attrib.def_value = 0; ++ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; ++ IFX_DEBUGP("Reg USB1 power!!\n"); ++ ifx_led_trigger_set_attrib(g_usb_vbus1_trigger, &attrib); ++ ifxusb_vbus1_status =0; ++ } ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1 && !g_usb_vbus2_trigger ) ++ { ++ ifx_led_trigger_register("USB_VBUS2", &g_usb_vbus2_trigger); ++ if ( g_usb_vbus2_trigger != NULL ) ++ { ++ struct ifx_led_trigger_attrib attrib = {0}; ++ attrib.delay_on = 0; ++ attrib.delay_off = 0; ++ attrib.timeout = 0; ++ attrib.def_value = 0; ++ attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; ++ IFX_DEBUGP("Reg USB2 power!!\n"); ++ ifx_led_trigger_set_attrib(g_usb_vbus2_trigger, &attrib); ++ ifxusb_vbus2_status =0; ++ } ++ } ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ /* == 20100712 AVM/WK use gpio_inited as bitmask == */ ++ if(ifxusb_vbus_gpio_inited == 0) ++ { ++ if(!ifx_gpio_register(IFX_GPIO_MODULE_USB)) ++ { ++ IFX_DEBUGP("Register USB VBus through GPIO OK!!\n"); ++ #ifdef IFX_GPIO_USB_VBUS ++ ifxusb_vbus_status =0; ++ #endif //IFX_GPIO_USB_VBUS ++ #ifdef IFX_GPIO_USB_VBUS1 ++ ifxusb_vbus1_status=0; ++ #endif //IFX_GPIO_USB_VBUS1 ++ #ifdef IFX_GPIO_USB_VBUS2 ++ ifxusb_vbus2_status=0; ++ #endif //IFX_GPIO_USB_VBUS2 ++ ifxusb_vbus_gpio_inited|= (1<<_core_if->core_no); ++ } ++ else ++ IFX_PRINT("Register USB VBus Failed!!\n"); ++ } else { ++ ifxusb_vbus_gpio_inited|= (1<<_core_if->core_no); ++ } ++ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ #endif //defined(__UEIP__) ++} ++ ++void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) ++{ ++ #if defined(__UEIP__) ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ if ( g_usb_vbus_trigger ) ++ { ++ ifx_led_trigger_deregister(g_usb_vbus_trigger); ++ g_usb_vbus_trigger = NULL; ++ ifxusb_vbus_status =-1; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0 && g_usb_vbus1_trigger ) ++ { ++ ifx_led_trigger_deregister(g_usb_vbus1_trigger); ++ g_usb_vbus1_trigger = NULL; ++ ifxusb_vbus1_status =-1; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1 && g_usb_vbus2_trigger ) ++ { ++ ifx_led_trigger_deregister(g_usb_vbus2_trigger); ++ g_usb_vbus2_trigger = NULL; ++ ifxusb_vbus2_status =-1; ++ } ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ /* == 20100712 AVM/WK use gpio_inited as bitmask == */ ++ if((ifxusb_vbus_gpio_inited & (1<<_core_if->core_no)) == ifxusb_vbus_gpio_inited) ++ { ++ ifx_gpio_deregister(IFX_GPIO_MODULE_USB); ++ #ifdef IFX_GPIO_USB_VBUS ++ ifxusb_vbus_status =-1; ++ #endif //IFX_GPIO_USB_VBUS ++ #ifdef IFX_GPIO_USB_VBUS1 ++ ifxusb_vbus1_status=-1; ++ #endif //IFX_GPIO_USB_VBUS1 ++ #ifdef IFX_GPIO_USB_VBUS2 ++ ifxusb_vbus2_status=-1; ++ #endif //IFX_GPIO_USB_VBUS2 ++ } ++ ifxusb_vbus_gpio_inited &= ~(1<<_core_if->core_no); ++ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ #endif //defined(__UEIP__) ++} ++ ++ ++/*! ++ \brief Turn on the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) ++{ ++ IFX_DEBUGP("SENDING VBus POWER UP\n"); ++ #if defined(__UEIP__) ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ if ( g_usb_vbus_trigger && ifxusb_vbus_status==0) ++ { ++ ifx_led_trigger_activate(g_usb_vbus_trigger); ++ IFX_DEBUGP("Enable USB power!!\n"); ++ ifxusb_vbus_status=1; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0 && g_usb_vbus1_trigger && ifxusb_vbus1_status==0) ++ { ++ ifx_led_trigger_activate(g_usb_vbus1_trigger); ++ IFX_DEBUGP("Enable USB1 power!!\n"); ++ ifxusb_vbus1_status=1; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1 && g_usb_vbus2_trigger && ifxusb_vbus2_status==0) ++ { ++ ifx_led_trigger_activate(g_usb_vbus2_trigger); ++ IFX_DEBUGP("Enable USB2 power!!\n"); ++ ifxusb_vbus2_status=1; ++ } ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ if(ifxusb_vbus_gpio_inited) ++ { ++ #if defined(IFX_GPIO_USB_VBUS) ++ if(ifxusb_vbus_status==0) ++ { ++ ifx_gpio_output_set(IFX_GPIO_USB_VBUS,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus_status=1; ++ } ++ #endif ++ #if defined(IFX_GPIO_USB_VBUS1) ++ if(_core_if->core_no==0 && ifxusb_vbus1_status==0) ++ { ++ ifx_gpio_output_set(IFX_GPIO_USB_VBUS1,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus1_status=1; ++ } ++ #endif ++ #if defined(IFX_GPIO_USB_VBUS2) ++ if(_core_if->core_no==1 && ifxusb_vbus2_status==0) ++ { ++ ifx_gpio_output_set(IFX_GPIO_USB_VBUS2,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus2_status=1; ++ } ++ #endif ++ } ++ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ #else ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_vbus_status=1; ++ //usb_set_vbus_on(); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ set_bit (4, (volatile unsigned long *)AMAZON_SE_GPIO_P0_OUT); ++ ifxusb_vbus_status=1; ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ if (bsp_port_reserve_pin(1, 13, PORT_MODULE_USB) != 0) ++ { ++ IFX_PRINT("Can't enable USB1 5.5V power!!\n"); ++ return; ++ } ++ bsp_port_clear_altsel0(1, 13, PORT_MODULE_USB); ++ bsp_port_clear_altsel1(1, 13, PORT_MODULE_USB); ++ bsp_port_set_dir_out(1, 13, PORT_MODULE_USB); ++ bsp_port_set_pudsel(1, 13, PORT_MODULE_USB); ++ bsp_port_set_puden(1, 13, PORT_MODULE_USB); ++ bsp_port_set_output(1, 13, PORT_MODULE_USB); ++ IFX_DEBUGP("Enable USB1 power!!\n"); ++ ifxusb_vbus1_status=1; ++ } ++ else ++ { ++ if (bsp_port_reserve_pin(3, 4, PORT_MODULE_USB) != 0) ++ { ++ IFX_PRINT("Can't enable USB2 5.5V power!!\n"); ++ return; ++ } ++ bsp_port_clear_altsel0(3, 4, PORT_MODULE_USB); ++ bsp_port_clear_altsel1(3, 4, PORT_MODULE_USB); ++ bsp_port_set_dir_out(3, 4, PORT_MODULE_USB); ++ bsp_port_set_pudsel(3, 4, PORT_MODULE_USB); ++ bsp_port_set_puden(3, 4, PORT_MODULE_USB); ++ bsp_port_set_output(3, 4, PORT_MODULE_USB); ++ IFX_DEBUGP("Enable USB2 power!!\n"); ++ ifxusb_vbus2_status=1; ++ } ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ ifxusb_vbus1_status=1; ++ } ++ else ++ { ++ ifxusb_vbus2_status=1; ++ } ++ #endif //defined(__IS_VR9__) ++ #endif //defined(__UEIP__) ++} ++ ++ ++/*! ++ \brief Turn off the USB 5V VBus Power ++ \param _core_if Pointer of core_if structure ++ */ ++void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) ++{ ++ IFX_DEBUGP("SENDING VBus POWER OFF\n"); ++ ++ #if defined(__UEIP__) ++ #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ if ( g_usb_vbus_trigger && ifxusb_vbus_status==1) ++ { ++ ifx_led_trigger_deactivate(g_usb_vbus_trigger); ++ IFX_DEBUGP("Disable USB power!!\n"); ++ ifxusb_vbus_status=0; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0 && g_usb_vbus1_trigger && ifxusb_vbus1_status==1) ++ { ++ ifx_led_trigger_deactivate(g_usb_vbus1_trigger); ++ IFX_DEBUGP("Disable USB1 power!!\n"); ++ ifxusb_vbus1_status=0; ++ } ++ #endif ++ #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1 && g_usb_vbus2_trigger && ifxusb_vbus2_status==1) ++ { ++ ifx_led_trigger_deactivate(g_usb_vbus2_trigger); ++ IFX_DEBUGP("Disable USB2 power!!\n"); ++ ifxusb_vbus2_status=0; ++ } ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ if(ifxusb_vbus_gpio_inited) ++ { ++ #if defined(IFX_GPIO_USB_VBUS) ++ if(ifxusb_vbus_status==1) ++ { ++ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus_status=0; ++ } ++ #endif ++ #if defined(IFX_GPIO_USB_VBUS1) ++ if(_core_if->core_no==0 && ifxusb_vbus1_status==1) ++ { ++ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS1,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus1_status=0; ++ } ++ #endif ++ #if defined(IFX_GPIO_USB_VBUS2) ++ if(_core_if->core_no==1 && ifxusb_vbus2_status==1) ++ { ++ ifx_gpio_output_clear(IFX_GPIO_USB_VBUS2,IFX_GPIO_MODULE_USB); ++ ifxusb_vbus2_status=0; ++ } ++ #endif ++ } ++ #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) ++ #else ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ ifxusb_vbus_status=0; ++ //usb_set_vbus_on(); ++ #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++ #if defined(__IS_AMAZON_SE__) ++ clear_bit (4, (volatile unsigned long *)AMAZON_SE_GPIO_P0_OUT); ++ ifxusb_vbus_status=0; ++ #endif //defined(__IS_AMAZON_SE__) ++ #if defined(__IS_AR9__) ++ if(_core_if->core_no==0) ++ { ++ if (bsp_port_reserve_pin(1, 13, PORT_MODULE_USB) != 0) { ++ IFX_PRINT("Can't Disable USB1 5.5V power!!\n"); ++ return; ++ } ++ bsp_port_clear_altsel0(1, 13, PORT_MODULE_USB); ++ bsp_port_clear_altsel1(1, 13, PORT_MODULE_USB); ++ bsp_port_set_dir_out(1, 13, PORT_MODULE_USB); ++ bsp_port_set_pudsel(1, 13, PORT_MODULE_USB); ++ bsp_port_set_puden(1, 13, PORT_MODULE_USB); ++ bsp_port_clear_output(1, 13, PORT_MODULE_USB); ++ IFX_DEBUGP("Disable USB1 power!!\n"); ++ ifxusb_vbus1_status=0; ++ } ++ else ++ { ++ if (bsp_port_reserve_pin(3, 4, PORT_MODULE_USB) != 0) { ++ IFX_PRINT("Can't Disable USB2 5.5V power!!\n"); ++ return; ++ } ++ bsp_port_clear_altsel0(3, 4, PORT_MODULE_USB); ++ bsp_port_clear_altsel1(3, 4, PORT_MODULE_USB); ++ bsp_port_set_dir_out(3, 4, PORT_MODULE_USB); ++ bsp_port_set_pudsel(3, 4, PORT_MODULE_USB); ++ bsp_port_set_puden(3, 4, PORT_MODULE_USB); ++ bsp_port_clear_output(3, 4, PORT_MODULE_USB); ++ IFX_DEBUGP("Disable USB2 power!!\n"); ++ ++ ifxusb_vbus2_status=0; ++ } ++ #endif //defined(__IS_AR9__) ++ #if defined(__IS_VR9__) ++ if(_core_if->core_no==0) ++ { ++ ifxusb_vbus1_status=0; ++ } ++ else ++ { ++ ifxusb_vbus2_status=0; ++ } ++ #endif //defined(__IS_VR9__) ++ #endif //defined(__UEIP__) ++} ++ ++ ++ ++/*! ++ \brief Read Current VBus status ++ \param _core_if Pointer of core_if structure ++ */ ++int ifxusb_vbus(ifxusb_core_if_t *_core_if) ++{ ++#if defined(__UEIP__) ++ #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) ++ return (ifxusb_vbus_status); ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS1) || defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) ++ if(_core_if->core_no==0) ++ return (ifxusb_vbus1_status); ++ #endif ++ ++ #if defined(IFX_GPIO_USB_VBUS2) || defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) ++ if(_core_if->core_no==1) ++ return (ifxusb_vbus2_status); ++ #endif ++#else //defined(__UEIP__) ++#endif ++ return -1; ++} ++ ++#if defined(__UEIP__) ++#else ++ #if defined(__IS_TWINPASS__) ++ #define ADSL_BASE 0x20000 ++ #define CRI_BASE 0x31F00 ++ #define CRI_CCR0 CRI_BASE + 0x00 ++ #define CRI_CCR1 CRI_BASE + 0x01*4 ++ #define CRI_CDC0 CRI_BASE + 0x02*4 ++ #define CRI_CDC1 CRI_BASE + 0x03*4 ++ #define CRI_RST CRI_BASE + 0x04*4 ++ #define CRI_MASK0 CRI_BASE + 0x05*4 ++ #define CRI_MASK1 CRI_BASE + 0x06*4 ++ #define CRI_MASK2 CRI_BASE + 0x07*4 ++ #define CRI_STATUS0 CRI_BASE + 0x08*4 ++ #define CRI_STATUS1 CRI_BASE + 0x09*4 ++ #define CRI_STATUS2 CRI_BASE + 0x0A*4 ++ #define CRI_AMASK0 CRI_BASE + 0x0B*4 ++ #define CRI_AMASK1 CRI_BASE + 0x0C*4 ++ #define CRI_UPDCTL CRI_BASE + 0x0D*4 ++ #define CRI_MADST CRI_BASE + 0x0E*4 ++ // 0x0f is missing ++ #define CRI_EVENT0 CRI_BASE + 0x10*4 ++ #define CRI_EVENT1 CRI_BASE + 0x11*4 ++ #define CRI_EVENT2 CRI_BASE + 0x12*4 ++ ++ #define IRI_I_ENABLE 0x32000 ++ #define STY_SMODE 0x3c004 ++ #define AFE_TCR_0 0x3c0dc ++ #define AFE_ADDR_ADDR 0x3c0e8 ++ #define AFE_RDATA_ADDR 0x3c0ec ++ #define AFE_WDATA_ADDR 0x3c0f0 ++ #define AFE_CONFIG 0x3c0f4 ++ #define AFE_SERIAL_CFG 0x3c0fc ++ ++ #define DFE_BASE_ADDR 0xBE116000 ++ //#define DFE_BASE_ADDR 0x9E116000 ++ ++ #define MEI_FR_ARCINT_C (DFE_BASE_ADDR + 0x0000001C) ++ #define MEI_DBG_WADDR_C (DFE_BASE_ADDR + 0x00000024) ++ #define MEI_DBG_RADDR_C (DFE_BASE_ADDR + 0x00000028) ++ #define MEI_DBG_DATA_C (DFE_BASE_ADDR + 0x0000002C) ++ #define MEI_DBG_DECO_C (DFE_BASE_ADDR + 0x00000030) ++ #define MEI_DBG_MASTER_C (DFE_BASE_ADDR + 0x0000003C) ++ ++ static void WriteARCmem(uint32_t addr, uint32_t data) ++ { ++ writel(1 ,(volatile uint32_t *)MEI_DBG_MASTER_C); ++ writel(1 ,(volatile uint32_t *)MEI_DBG_DECO_C ); ++ writel(addr ,(volatile uint32_t *)MEI_DBG_WADDR_C ); ++ writel(data ,(volatile uint32_t *)MEI_DBG_DATA_C ); ++ while( (ifxusb_rreg((volatile uint32_t *)MEI_FR_ARCINT_C) & 0x20) != 0x20 ){}; ++ writel(0 ,(volatile uint32_t *)MEI_DBG_MASTER_C); ++ IFX_DEBUGP("WriteARCmem %08x %08x\n",addr,data); ++ }; ++ ++ static uint32_t ReadARCmem(uint32_t addr) ++ { ++ u32 data; ++ writel(1 ,(volatile uint32_t *)MEI_DBG_MASTER_C); ++ writel(1 ,(volatile uint32_t *)MEI_DBG_DECO_C ); ++ writel(addr ,(volatile uint32_t *)MEI_DBG_RADDR_C ); ++ while( (ifxusb_rreg((volatile uint32_t *)MEI_FR_ARCINT_C) & 0x20) != 0x20 ){}; ++ data = ifxusb_rreg((volatile uint32_t *)MEI_DBG_DATA_C ); ++ writel(0 ,(volatile uint32_t *)MEI_DBG_MASTER_C); ++ IFX_DEBUGP("ReadARCmem %08x %08x\n",addr,data); ++ return data; ++ }; ++ ++ void ifxusb_enable_afe_oc(void) ++ { ++ /* Start the clock */ ++ WriteARCmem(CRI_UPDCTL ,0x00000008); ++ WriteARCmem(CRI_CCR0 ,0x00000014); ++ WriteARCmem(CRI_CCR1 ,0x00000500); ++ WriteARCmem(AFE_CONFIG ,0x000001c8); ++ WriteARCmem(AFE_SERIAL_CFG,0x00000016); // (DANUBE_PCI_CFG_BASE+(1<<addrline))AFE serial interface clock & data latch edge ++ WriteARCmem(AFE_TCR_0 ,0x00000002); ++ //Take afe out of reset ++ WriteARCmem(AFE_CONFIG ,0x000000c0); ++ WriteARCmem(IRI_I_ENABLE ,0x00000101); ++ WriteARCmem(STY_SMODE ,0x00001980); ++ ++ ReadARCmem(CRI_UPDCTL ); ++ ReadARCmem(CRI_CCR0 ); ++ ReadARCmem(CRI_CCR1 ); ++ ReadARCmem(AFE_CONFIG ); ++ ReadARCmem(AFE_SERIAL_CFG); // (DANUBE_PCI_CFG_BASE+(1<<addrline))AFE serial interface clock & data latch edge ++ ReadARCmem(AFE_TCR_0 ); ++ ReadARCmem(AFE_CONFIG ); ++ ReadARCmem(IRI_I_ENABLE ); ++ ReadARCmem(STY_SMODE ); ++ } ++ #endif //defined(__IS_TWINPASS__) ++#endif //defined(__UEIP__) ++ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_ctl.c b/drivers/usb/ifxhcd/ifxusb_ctl.c +new file mode 100644 +index 0000000..ade8e13 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_ctl.c +@@ -0,0 +1,1385 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_ctl.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : Implementing the procfs and sysfs for IFX USB driver ++ *****************************************************************************/ ++ ++/*! \file ifxusb_ctl.c ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief Implementing the procfs and sysfs for IFX USB driver ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++ ++#include <linux/proc_fs.h> ++#include <asm/byteorder.h> ++#include <asm/unaligned.h> ++#include <asm/uaccess.h> ++ ++#include "ifxusb_plat.h" ++#include "ifxusb_regs.h" ++#include "ifxusb_cif.h" ++ ++#ifdef __IS_DEVICE__ ++ #include "ifxpcd.h" ++#endif ++ ++#ifdef __IS_HOST__ ++ #include "ifxhcd.h" ++#endif ++ ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/gfp.h> ++ ++ ++#ifdef __IS_HOST__ ++ extern char ifxusb_driver_name[]; ++ ++ #ifdef __IS_DUAL__ ++ extern ifxhcd_hcd_t ifxusb_hcd_1; ++ extern ifxhcd_hcd_t ifxusb_hcd_2; ++ extern char ifxusb_hcd_name_1[]; ++ extern char ifxusb_hcd_name_2[]; ++ #else ++ extern ifxhcd_hcd_t ifxusb_hcd; ++ extern char ifxusb_hcd_name[]; ++ #endif ++ ++#endif ++ ++#ifdef __IS_DEVICE__ ++ extern char ifxusb_driver_name[]; ++ ++ extern ifxpcd_pcd_t ifxusb_pcd; ++ extern char ifxusb_pcd_name[]; ++#endif ++ ++ ++//Attributes for sysfs (for 2.6 only) ++ ++extern struct device_attribute dev_attr_dbglevel; ++ ++#ifdef __IS_DUAL__ ++ extern struct device_attribute dev_attr_dump_params_1; ++ extern struct device_attribute dev_attr_dump_params_2; ++#else ++ extern struct device_attribute dev_attr_dump_params; ++#endif ++ ++#ifdef __IS_DUAL__ ++ extern struct device_attribute dev_attr_mode_1; ++ extern struct device_attribute dev_attr_mode_2; ++#else ++ extern struct device_attribute dev_attr_mode; ++#endif ++ ++#ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ extern struct device_attribute dev_attr_buspower_1; ++ extern struct device_attribute dev_attr_buspower_2; ++ extern struct device_attribute dev_attr_bussuspend_1; ++ extern struct device_attribute dev_attr_bussuspend_2; ++ extern struct device_attribute dev_attr_busconnected_1; ++ extern struct device_attribute dev_attr_busconnected_2; ++ extern struct device_attribute dev_attr_connectspeed_1; ++ extern struct device_attribute dev_attr_connectspeed_1; ++ #else ++ extern struct device_attribute dev_attr_buspower; ++ extern struct device_attribute dev_attr_bussuspend; ++ extern struct device_attribute dev_attr_busconnected; ++ extern struct device_attribute dev_attr_connectspeed; ++ #endif ++#endif //__IS_HOST__ ++ ++#ifdef __IS_DEVICE__ ++ extern struct device_attribute dev_attr_devspeed; ++ extern struct device_attribute dev_attr_enumspeed; ++#endif //__IS_DEVICE__ ++ ++#ifdef __ENABLE_DUMP__ ++ #ifdef __IS_DUAL__ ++ extern struct device_attribute dev_attr_dump_reg_1; ++ extern struct device_attribute dev_attr_dump_reg_2; ++ extern struct device_attribute dev_attr_dump_spram_1; ++ extern struct device_attribute dev_attr_dump_spram_2; ++ #ifdef __IS_HOST__ ++ extern struct device_attribute dev_attr_dump_host_state_1; ++ extern struct device_attribute dev_attr_dump_host_state_2; ++ #else ++ #endif ++ #else ++ extern struct device_attribute dev_attr_dump_reg; ++ extern struct device_attribute dev_attr_dump_spram; ++ #ifdef __IS_HOST__ ++ extern struct device_attribute dev_attr_dump_host_state; ++ #else ++ #endif ++ #endif ++#endif //__ENABLE_DUMP__ ++ ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++static ssize_t procfs_dbglevel_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++{ ++ #ifdef __IS_HOST__ ++ return sprintf( buf, "%08X\n",h_dbg_lvl ); ++ #else ++ return sprintf( buf, "%08X\n",d_dbg_lvl ); ++ #endif ++} ++ ++static ssize_t procfs_dbglevel_store(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ #ifdef __IS_HOST__ ++ h_dbg_lvl =value; ++ #else ++ d_dbg_lvl =value; ++ #endif ++ //turn on and off power ++ return count; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dbglevel_show( struct device *_dev, struct device_attribute *attr,char *buf) ++#else ++ static ssize_t sysfs_dbglevel_show( struct device *_dev, char *buf) ++#endif ++{ ++ #ifdef __IS_HOST__ ++ return sprintf( buf, "%08X\n",h_dbg_lvl ); ++ #else ++ return sprintf( buf, "%08X\n",d_dbg_lvl ); ++ #endif ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dbglevel_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) ++#else ++ static ssize_t sysfs_dbglevel_store( struct device *_dev, const char *buffer, size_t count ) ++#endif ++{ ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ #ifdef __IS_HOST__ ++ h_dbg_lvl =value; ++ #else ++ d_dbg_lvl =value; ++ #endif ++ //turn on and off power ++ return count; ++} ++ ++DEVICE_ATTR(dbglevel, S_IRUGO|S_IWUSR, sysfs_dbglevel_show, sysfs_dbglevel_store); ++ ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++static void ifxusb_dump_params(ifxusb_core_if_t *_core_if); ++ ++#ifdef __IS_DUAL__ ++ static void dump_params_1(void) ++ { ++ ifxusb_dump_params(&ifxusb_hcd_1.core_if); ++ } ++ static void dump_params_2(void) ++ { ++ ifxusb_dump_params(&ifxusb_hcd_2.core_if); ++ } ++ ++ static ssize_t procfs_dump_params_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_params_1(); ++ return 0; ++ } ++ static ssize_t procfs_dump_params_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_params_2(); ++ return 0; ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_params_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_params_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_params_1(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_params_1, S_IRUGO|S_IWUSR, sysfs_dump_params_show_1, NULL); ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_params_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_params_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_params_2(); ++ return 0; ++ } ++ ++ DEVICE_ATTR(dump_params_2, S_IRUGO|S_IWUSR, sysfs_dump_params_show_2, NULL); ++#else ++ static void dump_params(void) ++ { ++ #ifdef __IS_HOST__ ++ ifxusb_dump_params(&ifxusb_hcd.core_if); ++ #else ++ ifxusb_dump_params(&ifxusb_pcd.core_if); ++ #endif ++ } ++ ++ static ssize_t procfs_dump_params_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_params(); ++ return 0; ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_params_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_params_show( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_params(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_params, S_IRUGO|S_IWUSR, sysfs_dump_params_show, NULL); ++#endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#ifdef __IS_DUAL__ ++ static ssize_t mode_show_1(char *buf) ++ { ++ if((ifxusb_rreg(&ifxusb_hcd_1.core_if.core_global_regs->gintsts ) & 0x1) == 1) ++ return sprintf( buf, "HOST\n" ); ++ else ++ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); ++ } ++ ++ static ssize_t mode_show_2(char *buf) ++ { ++ if((ifxusb_rreg(&ifxusb_hcd_2.core_if.core_global_regs->gintsts ) & 0x1) == 1) ++ return sprintf( buf, "HOST\n" ); ++ else ++ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); ++ } ++ ++ static ssize_t procfs_mode_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return mode_show_1(buf); ++ } ++ static ssize_t procfs_mode_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return mode_show_2(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_mode_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_mode_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return mode_show_1(buf); ++ } ++ ++ DEVICE_ATTR(mode_1, S_IRUGO|S_IWUSR, sysfs_mode_show_1, 0); ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_mode_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_mode_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return mode_show_2(buf); ++ } ++ DEVICE_ATTR(mode_2, S_IRUGO|S_IWUSR, sysfs_mode_show_2, NULL); ++#else ++ static ssize_t mode_show(char *buf) ++ { ++ #ifdef __IS_HOST__ ++ if((ifxusb_rreg(&ifxusb_hcd.core_if.core_global_regs->gintsts ) & 0x1) == 1) ++ return sprintf( buf, "HOST\n" ); ++ else ++ return sprintf( buf, "DEVICE(INCORRECT!)\n" ); ++ #else ++ if((ifxusb_rreg(&ifxusb_pcd.core_if.core_global_regs->gintsts ) & 0x1) != 1) ++ return sprintf( buf, "DEVICE\n" ); ++ else ++ return sprintf( buf, "HOST(INCORRECT!)\n" ); ++ #endif ++ } ++ static ssize_t procfs_mode_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return mode_show(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_mode_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_mode_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return mode_show(buf); ++ } ++ DEVICE_ATTR(mode, S_IRUGO|S_IWUSR, sysfs_mode_show, NULL); ++#endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++#ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ static ssize_t buspower_show_1(char *buf) ++ { ++ if(ifxusb_vbus (&ifxusb_hcd_1.core_if)==1) return sprintf( buf, "1\n" ); ++ if(ifxusb_vbus (&ifxusb_hcd_1.core_if)==0) return sprintf( buf, "0\n" ); ++ return sprintf( buf, "UNKNOWN\n" ); ++ } ++ static void buspower_store_1(uint32_t value) ++ { ++ if (value==1) ifxusb_vbus_on (&ifxusb_hcd_1.core_if); ++ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd_1.core_if); ++ } ++ static ssize_t buspower_show_2(char *buf) ++ { ++ if(ifxusb_vbus (&ifxusb_hcd_2.core_if)==1) return sprintf( buf, "1\n" ); ++ if(ifxusb_vbus (&ifxusb_hcd_2.core_if)==0) return sprintf( buf, "0\n" ); ++ return sprintf( buf, "UNKNOWN\n" ); ++ } ++ static void buspower_store_2(uint32_t value) ++ { ++ if (value==1) ifxusb_vbus_on (&ifxusb_hcd_2.core_if); ++ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd_2.core_if); ++ } ++ static ssize_t procfs_buspower_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return buspower_show_1(buf); ++ } ++ static ssize_t procfs_buspower_store_1(struct file *file, const char *buffer, unsigned long count, void *data) ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store_1(value); ++ return count; ++ } ++ static ssize_t procfs_buspower_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return buspower_show_2(buf); ++ } ++ static ssize_t procfs_buspower_store_2(struct file *file, const char *buffer, unsigned long count, void *data) ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store_2(value); ++ return count; ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_buspower_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return buspower_show_1(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) ++ #else ++ static ssize_t sysfs_buspower_store_1( struct device *_dev, const char *buffer, size_t count ) ++ #endif ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store_1(value); ++ return count; ++ } ++ DEVICE_ATTR(buspower_1, S_IRUGO|S_IWUSR, sysfs_buspower_show_1, sysfs_buspower_store_1); ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_buspower_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return buspower_show_2(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) ++ #else ++ static ssize_t sysfs_buspower_store_2( struct device *_dev, const char *buffer, size_t count ) ++ #endif ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store_2(value); ++ return count; ++ } ++ DEVICE_ATTR(buspower_2, S_IRUGO|S_IWUSR, sysfs_buspower_show_2, sysfs_buspower_store_2); ++ #else ++ static ssize_t buspower_show(char *buf) ++ { ++ if(ifxusb_vbus (&ifxusb_hcd.core_if)==1) return sprintf( buf, "1\n" ); ++ if(ifxusb_vbus (&ifxusb_hcd.core_if)==0) return sprintf( buf, "0\n" ); ++ return sprintf( buf, "UNKNOWN\n" ); ++ } ++ static void buspower_store(uint32_t value) ++ { ++ if (value==1) ifxusb_vbus_on (&ifxusb_hcd.core_if); ++ else if(value==0) ifxusb_vbus_off(&ifxusb_hcd.core_if); ++ } ++ static ssize_t procfs_buspower_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return buspower_show(buf); ++ } ++ static ssize_t procfs_buspower_store(struct file *file, const char *buffer, unsigned long count, void *data) ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store(value); ++ return count; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_buspower_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return buspower_show(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_buspower_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) ++ #else ++ static ssize_t sysfs_buspower_store( struct device *_dev, const char *buffer, size_t count ) ++ #endif ++ { ++ char buf[10]; ++ int i = 0; ++ uint32_t value; ++ if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) ++ return -EFAULT; ++ value = simple_strtoul(buf, NULL, 16); ++ buspower_store(value); ++ return count; ++ } ++ DEVICE_ATTR(buspower, S_IRUGO|S_IWUSR, sysfs_buspower_show, sysfs_buspower_store); ++ #endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ ++ #ifdef __IS_DUAL__ ++ static ssize_t bussuspend_show_1(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); ++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); ++ } ++ static ssize_t bussuspend_show_2(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); ++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); ++ } ++ ++ static ssize_t procfs_bussuspend_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return bussuspend_show_1(buf); ++ } ++ static ssize_t procfs_bussuspend_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return bussuspend_show_2(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_bussuspend_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_bussuspend_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return bussuspend_show_1(buf); ++ } ++ DEVICE_ATTR(bussuspend_1, S_IRUGO|S_IWUSR, sysfs_bussuspend_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_bussuspend_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_bussuspend_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return bussuspend_show_2(buf); ++ } ++ DEVICE_ATTR(bussuspend_2, S_IRUGO|S_IWUSR, sysfs_bussuspend_show_2, 0); ++ #else ++ static ssize_t bussuspend_show(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); ++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); ++ } ++ static ssize_t procfs_bussuspend_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return bussuspend_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_bussuspend_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_bussuspend_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return bussuspend_show(buf); ++ } ++ DEVICE_ATTR(bussuspend, S_IRUGO|S_IWUSR, sysfs_bussuspend_show, 0); ++ #endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #ifdef __IS_DUAL__ ++ static ssize_t busconnected_show_1(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); ++ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); ++ } ++ static ssize_t busconnected_show_2(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); ++ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); ++ } ++ ++ static ssize_t procfs_busconnected_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return busconnected_show_1(buf); ++ } ++ static ssize_t procfs_busconnected_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return busconnected_show_2(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_busconnected_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_busconnected_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return busconnected_show_1(buf); ++ } ++ DEVICE_ATTR(busconnected_1, S_IRUGO|S_IWUSR, sysfs_busconnected_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_busconnected_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_busconnected_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return busconnected_show_2(buf); ++ } ++ DEVICE_ATTR(busconnected_2, S_IRUGO|S_IWUSR, sysfs_busconnected_show_2, 0); ++ #else ++ static ssize_t busconnected_show(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); ++ return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); ++ } ++ static ssize_t procfs_busconnected_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return busconnected_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_busconnected_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_busconnected_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return busconnected_show(buf); ++ } ++ DEVICE_ATTR(busconnected, S_IRUGO|S_IWUSR, sysfs_busconnected_show, 0); ++ #endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #ifdef __IS_DUAL__ ++ static ssize_t connectspeed_show_1(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); ++ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); ++ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); ++ } ++ static ssize_t connectspeed_show_2(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); ++ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); ++ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); ++ } ++ ++ static ssize_t procfs_connectspeed_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return connectspeed_show_1(buf); ++ } ++ static ssize_t procfs_connectspeed_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return connectspeed_show_2(buf); ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_connectspeed_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_connectspeed_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ return connectspeed_show_1(buf); ++ } ++ DEVICE_ATTR(connectspeed_1, S_IRUGO|S_IWUSR, sysfs_connectspeed_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_connectspeed_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_connectspeed_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ return connectspeed_show_2(buf); ++ } ++ DEVICE_ATTR(connectspeed_2, S_IRUGO|S_IWUSR, sysfs_connectspeed_show_2, 0); ++ #else ++ static ssize_t connectspeed_show(char *buf) ++ { ++ hprt0_data_t val; ++ val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); ++ if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); ++ if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); ++ return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); ++ } ++ ++ static ssize_t procfs_connectspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return connectspeed_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_connectspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_connectspeed_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return connectspeed_show(buf); ++ } ++ DEVICE_ATTR(connectspeed, S_IRUGO|S_IWUSR, sysfs_connectspeed_show, 0); ++ #endif ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++#endif ++ ++ ++#ifdef __IS_DEVICE__ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ static ssize_t devspeed_show(char *buf) ++ { ++ dcfg_data_t val; ++ val.d32 = ifxusb_rreg(&ifxusb_pcd.core_if.dev_global_regs->dcfg); ++ if( val.b.devspd ==0) return sprintf (buf, "Dev Speed = High (%d)\n", val.b.devspd); ++ if( val.b.devspd ==1) return sprintf (buf, "Dev Speed = Full (%d)\n", val.b.devspd); ++ if( val.b.devspd ==3) return sprintf (buf, "Dev Speed = Full (%d)\n", val.b.devspd); ++ return sprintf (buf, "Dev Speed = Unknown (%d)\n", val.b.devspd); ++ } ++ ++ static ssize_t procfs_devspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return devspeed_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_devspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_devspeed_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return devspeed_show(buf); ++ } ++ DEVICE_ATTR(devspeed, S_IRUGO|S_IWUSR, sysfs_devspeed_show, 0); ++ ++ static ssize_t enumspeed_show(char *buf) ++ { ++ dsts_data_t val; ++ val.d32 = ifxusb_rreg(&ifxusb_pcd.core_if.dev_global_regs->dsts); ++ if( val.b.enumspd ==0) return sprintf (buf, "Enum Speed = High (%d)\n", val.b.enumspd); ++ if( val.b.enumspd ==1) return sprintf (buf, "Enum Speed = Full (%d)\n", val.b.enumspd); ++ if( val.b.enumspd ==2) return sprintf (buf, "Enum Speed = Low (%d)\n", val.b.enumspd); ++ return sprintf (buf, "Enum Speed = invalid(%d)\n", val.b.enumspd); ++ } ++ ++ static ssize_t procfs_enumspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ return enumspeed_show(buf); ++ } ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_enumspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_enumspeed_show( struct device *_dev, char *buf) ++ #endif ++ { ++ return enumspeed_show(buf); ++ } ++ DEVICE_ATTR(enumspeed, S_IRUGO|S_IWUSR, sysfs_enumspeed_show, 0); ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++#endif ++ ++ ++////////////////////////////////////////////////////////////////////////////////// ++#ifdef __ENABLE_DUMP__ ++ ++ #ifdef __IS_DUAL__ ++ static void dump_reg_1(void) ++ { ++ ifxusb_dump_registers(&ifxusb_hcd_1.core_if); ++ } ++ static void dump_reg_2(void) ++ { ++ ifxusb_dump_registers(&ifxusb_hcd_2.core_if); ++ } ++ ++ static ssize_t procfs_dump_reg_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_reg_1(); ++ return 0; ++ } ++ static ssize_t procfs_dump_reg_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_reg_2(); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_reg_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_reg_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_reg_1(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_reg_1, S_IRUGO|S_IWUSR, sysfs_dump_reg_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_reg_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_reg_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_reg_2(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_reg_2, S_IRUGO|S_IWUSR, sysfs_dump_reg_show_2, 0); ++ #else ++ static void dump_reg(void) ++ { ++ #ifdef __IS_HOST__ ++ ifxusb_dump_registers(&ifxusb_hcd.core_if); ++ #endif ++ #ifdef __IS_DEVICE__ ++ ifxusb_dump_registers(&ifxusb_pcd.core_if); ++ #endif ++ } ++ static ssize_t procfs_dump_reg_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_reg(); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_reg_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_reg_show( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_reg(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_reg, S_IRUGO|S_IWUSR, sysfs_dump_reg_show, 0); ++ #endif ++ ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #ifdef __IS_DUAL__ ++ static void dump_spram_1(void) ++ { ++ ifxusb_dump_spram(&ifxusb_hcd_1.core_if); ++ } ++ static void dump_spram_2(void) ++ { ++ ifxusb_dump_spram(&ifxusb_hcd_2.core_if); ++ } ++ ++ static ssize_t procfs_dump_spram_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_spram_1(); ++ return 0; ++ } ++ static ssize_t procfs_dump_spram_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_spram_2(); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_spram_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_spram_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_spram_1(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_spram_1, S_IRUGO|S_IWUSR, sysfs_dump_spram_show_1, 0); ++ ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_spram_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_spram_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_spram_2(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_spram_2, S_IRUGO|S_IWUSR, sysfs_dump_spram_show_2, 0); ++ #else ++ static void dump_spram(void) ++ { ++ #ifdef __IS_HOST__ ++ ifxusb_dump_spram(&ifxusb_hcd.core_if); ++ #endif ++ #ifdef __IS_DEVICE__ ++ ifxusb_dump_spram(&ifxusb_pcd.core_if); ++ #endif ++ } ++ static ssize_t procfs_dump_spram_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ dump_spram(); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_spram_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_spram_show( struct device *_dev,char *buf) ++ #endif ++ { ++ dump_spram(); ++ return 0; ++ } ++ DEVICE_ATTR(dump_spram, S_IRUGO|S_IWUSR, sysfs_dump_spram_show, 0); ++ #endif ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ static ssize_t procfs_dump_host_state_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ ifxhcd_dump_state(&ifxusb_hcd_1); ++ return 0; ++ } ++ static ssize_t procfs_dump_host_state_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ ifxhcd_dump_state(&ifxusb_hcd_2); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_host_state_show_1( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_host_state_show_1( struct device *_dev,char *buf) ++ #endif ++ { ++ ifxhcd_dump_state(&ifxusb_hcd_1); ++ return 0; ++ } ++ DEVICE_ATTR(dump_host_state_1, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show_1, 0); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_host_state_show_2( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_host_state_show_2( struct device *_dev,char *buf) ++ #endif ++ { ++ ifxhcd_dump_state(&ifxusb_hcd_2); ++ return 0; ++ } ++ DEVICE_ATTR(dump_host_state_2, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show_2, 0); ++ #else ++ static ssize_t procfs_dump_host_state_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) ++ { ++ ifxhcd_dump_state(&ifxusb_hcd); ++ return 0; ++ } ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ static ssize_t sysfs_dump_host_state_show( struct device *_dev, struct device_attribute *attr,char *buf) ++ #else ++ static ssize_t sysfs_dump_host_state_show( struct device *_dev,char *buf) ++ #endif ++ { ++ ifxhcd_dump_state(&ifxusb_hcd); ++ return 0; ++ } ++ DEVICE_ATTR(dump_host_state, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show, 0); ++ #endif ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ #endif //IS_HOST_ ++ ++#endif //__ENABLE_DUMP__ ++ ++////////////////////////////////////////////////////////////////////////////////// ++ ++static int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw); ++static void ifx_proc_delproc(char *funcname); ++ ++////////////////////////////////////////////////////////////////////////////////// ++ ++/*! ++ \brief This function create the sysfs and procfs entries ++ \param[in] _dev Pointer of device structure, if applied ++ */ ++void ifxusb_attr_create (void *_dev) ++{ ++ int error; ++ ++ struct device *dev = (struct device *) _dev; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ error = ifx_proc_addproc("dbglevel", procfs_dbglevel_show, procfs_dbglevel_store); ++ error = device_create_file(dev, &dev_attr_dbglevel); ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("dump_params_1", procfs_dump_params_show_1, NULL); ++ error = ifx_proc_addproc("dump_params_2", procfs_dump_params_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_dump_params_1); ++ error = device_create_file(dev, &dev_attr_dump_params_2); ++ #else ++ error = ifx_proc_addproc("dump_params", procfs_dump_params_show, NULL); ++ error = device_create_file(dev, &dev_attr_dump_params); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("mode_1", procfs_mode_show_1, NULL); ++ error = ifx_proc_addproc("mode_2", procfs_mode_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_mode_1); ++ error = device_create_file(dev, &dev_attr_mode_2); ++ #else ++ error = ifx_proc_addproc("mode", procfs_mode_show, NULL); ++ error = device_create_file(dev, &dev_attr_mode); ++ #endif ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("buspower_1", procfs_buspower_show_1, procfs_buspower_store_1); ++ error = ifx_proc_addproc("buspower_2", procfs_buspower_show_2, procfs_buspower_store_2); ++ error = device_create_file(dev, &dev_attr_buspower_1); ++ error = device_create_file(dev, &dev_attr_buspower_2); ++ #else ++ error = ifx_proc_addproc("buspower", procfs_buspower_show, procfs_buspower_store); ++ error = device_create_file(dev, &dev_attr_buspower); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("bussuspend_1", procfs_bussuspend_show_1, NULL); ++ error = ifx_proc_addproc("bussuspend_2", procfs_bussuspend_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_bussuspend_1); ++ error = device_create_file(dev, &dev_attr_bussuspend_2); ++ #else ++ error = ifx_proc_addproc("bussuspend", procfs_bussuspend_show, NULL); ++ error = device_create_file(dev, &dev_attr_bussuspend); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("busconnected_1", procfs_busconnected_show_1, NULL); ++ error = ifx_proc_addproc("busconnected_2", procfs_busconnected_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_busconnected_1); ++ error = device_create_file(dev, &dev_attr_busconnected_2); ++ #else ++ error = ifx_proc_addproc("busconnected", procfs_busconnected_show, NULL); ++ error = device_create_file(dev, &dev_attr_busconnected); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("connectspeed_1", procfs_connectspeed_show_1, NULL); ++ error = ifx_proc_addproc("connectspeed_2", procfs_connectspeed_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_connectspeed_1); ++ error = device_create_file(dev, &dev_attr_connectspeed_2); ++ #else ++ error = ifx_proc_addproc("connectspeed", procfs_connectspeed_show, NULL); ++ error = device_create_file(dev, &dev_attr_connectspeed); ++ #endif ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ error = ifx_proc_addproc("devspeed", procfs_devspeed_show, NULL); ++ error = device_create_file(dev, &dev_attr_devspeed); ++ error = ifx_proc_addproc("enumspeed", procfs_enumspeed_show, NULL); ++ error = device_create_file(dev, &dev_attr_enumspeed); ++ #endif ++ ++ ////////////////////////////////////////////////////// ++ #ifdef __ENABLE_DUMP__ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("dump_reg_1", procfs_dump_reg_show_1, NULL); ++ error = ifx_proc_addproc("dump_reg_2", procfs_dump_reg_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_dump_reg_1); ++ error = device_create_file(dev, &dev_attr_dump_reg_2); ++ #else ++ error = ifx_proc_addproc("dump_reg", procfs_dump_reg_show, NULL); ++ error = device_create_file(dev, &dev_attr_dump_reg); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("dump_spram_1", procfs_dump_spram_show_1, NULL); ++ error = ifx_proc_addproc("dump_spram_2", procfs_dump_spram_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_dump_spram_1); ++ error = device_create_file(dev, &dev_attr_dump_spram_2); ++ #else ++ error = ifx_proc_addproc("dump_spram", procfs_dump_spram_show, NULL); ++ error = device_create_file(dev, &dev_attr_dump_spram); ++ #endif ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ error = ifx_proc_addproc("dump_host_state_1", procfs_dump_host_state_show_1, NULL); ++ error = ifx_proc_addproc("dump_host_state_2", procfs_dump_host_state_show_2, NULL); ++ error = device_create_file(dev, &dev_attr_dump_host_state_1); ++ error = device_create_file(dev, &dev_attr_dump_host_state_2); ++ #else ++ error = ifx_proc_addproc("dump_host_state", procfs_dump_host_state_show, NULL); ++ error = device_create_file(dev, &dev_attr_dump_host_state); ++ #endif ++ #endif ++ #endif //__ENABLE_DUMP__ ++ ////////////////////////////////////////////////////// ++} ++ ++ ++/*! ++ \brief This function remove the sysfs and procfs entries ++ \param[in] _dev Pointer of device structure, if applied ++ */ ++void ifxusb_attr_remove (void *_dev) ++{ ++ struct device *dev = (struct device *) _dev; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ifx_proc_delproc("dbglevel"); ++ device_remove_file(dev, &dev_attr_dbglevel); ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("dump_params_1"); ++ ifx_proc_delproc("dump_params_2"); ++ device_remove_file(dev, &dev_attr_dump_params_1); ++ device_remove_file(dev, &dev_attr_dump_params_2); ++ #else ++ ifx_proc_delproc("dump_params"); ++ device_remove_file(dev, &dev_attr_dump_params); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("mode_1"); ++ ifx_proc_delproc("mode_2"); ++ device_remove_file(dev, &dev_attr_mode_1); ++ device_remove_file(dev, &dev_attr_mode_2); ++ #else ++ ifx_proc_delproc("mode"); ++ device_remove_file(dev, &dev_attr_mode); ++ #endif ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("buspower_1"); ++ ifx_proc_delproc("buspower_2"); ++ device_remove_file(dev, &dev_attr_buspower_1); ++ device_remove_file(dev, &dev_attr_buspower_2); ++ #else ++ ifx_proc_delproc("buspower"); ++ device_remove_file(dev, &dev_attr_buspower); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("bussuspend_1"); ++ ifx_proc_delproc("bussuspend_2"); ++ device_remove_file(dev, &dev_attr_bussuspend_1); ++ device_remove_file(dev, &dev_attr_bussuspend_2); ++ #else ++ ifx_proc_delproc("bussuspend"); ++ device_remove_file(dev, &dev_attr_bussuspend); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("busconnected_1"); ++ ifx_proc_delproc("busconnected_2"); ++ device_remove_file(dev, &dev_attr_busconnected_1); ++ device_remove_file(dev, &dev_attr_busconnected_2); ++ #else ++ ifx_proc_delproc("busconnected"); ++ device_remove_file(dev, &dev_attr_busconnected); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("connectspeed_1"); ++ ifx_proc_delproc("connectspeed_2"); ++ device_remove_file(dev, &dev_attr_connectspeed_1); ++ device_remove_file(dev, &dev_attr_connectspeed_2); ++ #else ++ ifx_proc_delproc("connectspeed"); ++ device_remove_file(dev, &dev_attr_connectspeed); ++ #endif ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ ifx_proc_delproc("devspeed"); ++ device_remove_file(dev, &dev_attr_devspeed); ++ ifx_proc_delproc("enumspeed"); ++ device_remove_file(dev, &dev_attr_enumspeed); ++ #endif ++ ++ #ifdef __ENABLE_DUMP__ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("dump_reg_1"); ++ ifx_proc_delproc("dump_reg_2"); ++ device_remove_file(dev, &dev_attr_dump_reg_1); ++ device_remove_file(dev, &dev_attr_dump_reg_2); ++ #else ++ ifx_proc_delproc("dump_reg"); ++ device_remove_file(dev, &dev_attr_dump_reg); ++ #endif ++ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("dump_spram_1"); ++ ifx_proc_delproc("dump_spram_2"); ++ device_remove_file(dev, &dev_attr_dump_spram_1); ++ device_remove_file(dev, &dev_attr_dump_spram_2); ++ #else ++ ifx_proc_delproc("dump_spram"); ++ device_remove_file(dev, &dev_attr_dump_spram); ++ #endif ++ ++ #ifdef __IS_HOST__ ++ #ifdef __IS_DUAL__ ++ ifx_proc_delproc("dump_host_state_1"); ++ ifx_proc_delproc("dump_host_state_2"); ++ device_remove_file(dev, &dev_attr_dump_host_state_1); ++ device_remove_file(dev, &dev_attr_dump_host_state_2); ++ #else ++ ifx_proc_delproc("dump_host_state"); ++ device_remove_file(dev, &dev_attr_dump_host_state); ++ #endif ++ #endif ++ #endif //__ENABLE_DUMP__ ++ /* AVM/WK fix: del IFXUSB root dir*/ ++ ifx_proc_delproc(NULL); ++} ++ ++static struct proc_dir_entry * proc_ifx_root = NULL; ++ ++/* initialize the proc file system and make a dir named /proc/[name] */ ++static void ifx_proc_init(void) ++{ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ proc_ifx_root = proc_mkdir(ifxusb_driver_name, (void *)0); ++ if (!proc_ifx_root){ ++ IFX_PRINT("%s proc initialization failed! \n", ifxusb_driver_name); ++ return; ++ } ++} ++ ++/* proc file system add function for debugging. */ ++static int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw) ++{ ++ struct proc_dir_entry *pe; ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ if (!proc_ifx_root) ++ ifx_proc_init(); ++ ++ if (hookfuncw == NULL) ++ { ++ pe = create_proc_read_entry(funcname, S_IRUGO, proc_ifx_root, hookfuncr, NULL); ++ if (!pe) ++ { ++ IFX_PRINT("ERROR in creating read proc entry (%s)! \n", funcname); ++ return -1; ++ } ++ } ++ else ++ { ++ pe = create_proc_entry(funcname, S_IRUGO | S_IWUGO, proc_ifx_root); ++ if (pe) ++ { ++ pe->read_proc = hookfuncr; ++ pe->write_proc = hookfuncw; ++ } ++ else ++ { ++ IFX_PRINT("ERROR in creating proc entry (%s)! \n", funcname); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++ ++/* proc file system del function for removing module. */ ++static void ifx_proc_delproc(char *funcname) ++{ ++/* AVM/WK Fix*/ ++ if (funcname != NULL) { ++ remove_proc_entry(funcname, proc_ifx_root); ++ } else { ++ remove_proc_entry(ifxusb_driver_name, NULL); ++ proc_ifx_root = NULL; ++ } ++} ++ ++static void ifxusb_dump_params(ifxusb_core_if_t *_core_if) ++{ ++ ifxusb_params_t *params=&_core_if->params; ++ ++ #ifdef __IS_HOST__ ++ IFX_PRINT("IFXUSB Dump Parameters ( Host Mode) \n"); ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ IFX_PRINT("IFXUSB Dump Parameters ( Device Mode) \n"); ++ #endif //__IS_DEVICE__ ++ ++ #ifdef __DESC_DMA__ ++ IFX_PRINT("DMA: Hermes DMA\n"); ++ #else ++ IFX_PRINT("DMA: Non-Desc DMA\n"); ++ #endif ++ IFX_PRINT(" Burst size: %d\n",params->dma_burst_size); ++ ++ if (params->speed==1) ++ IFX_PRINT("Full Speed only\n"); ++ else if(params->speed==0) ++ IFX_PRINT("Full/Hign Speed\n"); ++ else ++ IFX_PRINT("Unkonwn setting (%d) for Speed\n",params->speed); ++ ++ IFX_PRINT("Total Data FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->data_fifo_size,params->data_fifo_size, ++ params->data_fifo_size*4, params->data_fifo_size*4 ++ ); ++ ++ #ifdef __IS_DEVICE__ ++ IFX_PRINT("Rx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->rx_fifo_size,params->rx_fifo_size, ++ params->rx_fifo_size*4, params->rx_fifo_size*4 ++ ); ++ { ++ int i; ++ for(i=0;i<MAX_EPS_CHANNELS;i++) ++ { ++ IFX_PRINT("Tx FIFO #%d size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n",i, ++ params->tx_fifo_size[i],params->tx_fifo_size[i], ++ params->tx_fifo_size[i]*4, params->tx_fifo_size[i]*4 ++ ); ++ } ++ } ++ #ifdef __DED_FIFO__ ++ IFX_PRINT("Treshold : %s Rx:%d Tx:%d \n", ++ (params->thr_ctl)?"On":"Off",params->tx_thr_length,params->rx_thr_length); ++ #endif ++ #else //__IS_HOST__ ++ IFX_PRINT("Host Channels: %d\n",params->host_channels); ++ ++ IFX_PRINT("Rx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->data_fifo_size,params->data_fifo_size, ++ params->data_fifo_size*4, params->data_fifo_size*4 ++ ); ++ ++ IFX_PRINT("NP Tx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->nperio_tx_fifo_size,params->nperio_tx_fifo_size, ++ params->nperio_tx_fifo_size*4, params->nperio_tx_fifo_size*4 ++ ); ++ ++ IFX_PRINT(" P Tx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", ++ params->perio_tx_fifo_size,params->perio_tx_fifo_size, ++ params->perio_tx_fifo_size*4, params->perio_tx_fifo_size*4 ++ ); ++ #endif //__IS_HOST__ ++ ++ IFX_PRINT("Max Transfer size: %d(0x%06X) Bytes\n", ++ params->max_transfer_size,params->max_transfer_size ++ ); ++ IFX_PRINT("Max Packet Count: %d(0x%06X)\n", ++ params->max_packet_count,params->max_packet_count ++ ); ++ ++ IFX_PRINT("PHY UTMI Width: %d\n",params->phy_utmi_width); ++ ++ IFX_PRINT("Turn Around Time: HS:%d FS:%d\n",params->turn_around_time_hs,params->turn_around_time_fs); ++ IFX_PRINT("Timeout Calibration: HS:%d FS:%d\n",params->timeout_cal_hs,params->timeout_cal_fs); ++ ++ ++ IFX_PRINT("==================================================\n"); ++ IFX_PRINT("End of Parameters Dump\n"); ++ IFX_PRINT("==================================================\n"); ++} ++ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_driver.c b/drivers/usb/ifxhcd/ifxusb_driver.c +new file mode 100644 +index 0000000..2334905 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_driver.c +@@ -0,0 +1,970 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_driver.c ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : The provides the initialization and cleanup entry ++ ** points for the IFX USB driver. This module can be ++ ** dynamically loaded with insmod command or built-in ++ ** with kernel. When loaded or executed the ifxusb_driver_init ++ ** function is called. When the module is removed (using rmmod), ++ ** the ifxusb_driver_cleanup function is called. ++ *****************************************************************************/ ++ ++/*! ++ \file ifxusb_driver.c ++ \brief This file contains the loading/unloading interface to the Linux driver. ++*/ ++ ++#include <linux/version.h> ++#include "ifxusb_version.h" ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++ ++#include <linux/device.h> ++#include <linux/platform_device.h> ++ ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/stat.h> /* permission constants */ ++#include <linux/gpio.h> ++#include <lantiq_soc.h> ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ #include <linux/irq.h> ++#endif ++ ++#include <asm/io.h> ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include <asm/irq.h> ++#endif ++ ++#include "ifxusb_plat.h" ++ ++#include "ifxusb_cif.h" ++ ++#ifdef __IS_HOST__ ++ #include "ifxhcd.h" ++ ++ #define USB_DRIVER_DESC "IFX USB HCD driver" ++ const char ifxusb_driver_name[] = "ifxusb_hcd"; ++ ++ #ifdef __IS_DUAL__ ++ ifxhcd_hcd_t ifxusb_hcd_1; ++ ifxhcd_hcd_t ifxusb_hcd_2; ++ const char ifxusb_hcd_name_1[] = "ifxusb_hcd_1"; ++ const char ifxusb_hcd_name_2[] = "ifxusb_hcd_2"; ++ #else ++ ifxhcd_hcd_t ifxusb_hcd; ++ const char ifxusb_hcd_name[] = "ifxusb_hcd"; ++ #endif ++ ++ #if defined(__DO_OC_INT__) ++ static unsigned int oc_int_installed=0; ++ static ifxhcd_hcd_t *oc_int_id=NULL; ++ #endif ++#endif ++ ++#ifdef __IS_DEVICE__ ++ #include "ifxpcd.h" ++ ++ #define USB_DRIVER_DESC "IFX USB PCD driver" ++ const char ifxusb_driver_name[] = "ifxusb_pcd"; ++ ++ ifxpcd_pcd_t ifxusb_pcd; ++ const char ifxusb_pcd_name[] = "ifxusb_pcd"; ++#endif ++ ++/* Global Debug Level Mask. */ ++#ifdef __IS_HOST__ ++ uint32_t h_dbg_lvl = 0x00; ++#endif ++ ++#ifdef __IS_DEVICE__ ++ uint32_t d_dbg_lvl = 0x00; ++#endif ++ ++ifxusb_params_t ifxusb_module_params; ++ ++static void parse_parms(void); ++ ++ ++#include <lantiq_irq.h> ++#define IFX_USB0_IR (INT_NUM_IM1_IRL0 + 22) ++#define IFX_USB1_IR (INT_NUM_IM2_IRL0 + 19) ++ ++/*! ++ \brief This function is called when a driver is unregistered. This happens when ++ the rmmod command is executed. The device may or may not be electrically ++ present. If it is present, the driver stops device processing. Any resources ++ used on behalf of this device are freed. ++*/ ++static int ifxusb_driver_remove(struct platform_device *_dev) ++{ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ #ifdef __IS_HOST__ ++ #if defined(__DO_OC_INT__) ++ #if defined(__DO_OC_INT_ENABLE__) ++ ifxusb_oc_int_off(); ++ #endif ++ ++ if(oc_int_installed && oc_int_id) ++ free_irq((unsigned int)IFXUSB_OC_IRQ, oc_int_id ); ++ oc_int_installed=0; ++ oc_int_id=NULL; ++ #endif ++ ++ #if defined(__IS_DUAL__) ++ ifxhcd_remove(&ifxusb_hcd_1); ++ ifxusb_core_if_remove(&ifxusb_hcd_1.core_if ); ++ ifxhcd_remove(&ifxusb_hcd_2); ++ ifxusb_core_if_remove(&ifxusb_hcd_2.core_if ); ++ #else ++ ifxhcd_remove(&ifxusb_hcd); ++ ifxusb_core_if_remove(&ifxusb_hcd.core_if ); ++ #endif ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ ifxpcd_remove(); ++ ifxusb_core_if_remove(&ifxusb_pcd.core_if ); ++ #endif ++ ++ /* Remove the device attributes */ ++ ++ ifxusb_attr_remove(&_dev->dev); ++ ++ return 0; ++} ++ ++ ++/* Function to setup the structures to control one usb core running as host*/ ++#ifdef __IS_HOST__ ++/*! ++ \brief inlined by ifxusb_driver_probe(), handling host mode probing. Run at each host core. ++*/ ++ static inline int ifxusb_driver_probe_h(ifxhcd_hcd_t *_hcd, ++ int _irq, ++ uint32_t _iobase, ++ uint32_t _fifomem, ++ uint32_t _fifodbg ++ ) ++ { ++ int retval = 0; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ++#ifdef __DEV_NEW__ ++ ifxusb_power_off (&_hcd->core_if); ++ ifxusb_phy_power_off (&_hcd->core_if); // Test ++ mdelay(500); ++#endif //__DEV_NEW__ ++ ifxusb_power_on (&_hcd->core_if); ++ mdelay(50); ++ ifxusb_phy_power_on (&_hcd->core_if); // Test ++ mdelay(50); ++ ifxusb_hard_reset(&_hcd->core_if); ++ retval =ifxusb_core_if_init(&_hcd->core_if, ++ _irq, ++ _iobase, ++ _fifomem, ++ _fifodbg); ++ if(retval) ++ return retval; ++ ++ ifxusb_host_core_init(&_hcd->core_if,&ifxusb_module_params); ++ ++ ifxusb_disable_global_interrupts( &_hcd->core_if); ++ ++ /* The driver is now initialized and need to be registered into Linux USB sub-system */ ++ ++ retval = ifxhcd_init(_hcd); // hook the hcd into usb ss ++ ++ if (retval != 0) ++ { ++ IFX_ERROR("_hcd_init failed\n"); ++ return retval; ++ } ++ ++ //ifxusb_enable_global_interrupts( _hcd->core_if ); // this should be done at hcd_start , including hcd_interrupt ++ return 0; ++ } ++#endif //__IS_HOST__ ++ ++#ifdef __IS_DEVICE__ ++/*! ++ \brief inlined by ifxusb_driver_probe(), handling device mode probing. ++*/ ++ static inline int ifxusb_driver_probe_d(ifxpcd_pcd_t *_pcd, ++ int _irq, ++ uint32_t _iobase, ++ uint32_t _fifomem, ++ uint32_t _fifodbg ++ ) ++ { ++ int retval = 0; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++#ifdef __DEV_NEW__ ++ ifxusb_power_off (&_pcd->core_if); ++ ifxusb_phy_power_off (&_pcd->core_if); // Test ++ mdelay(500); ++#endif // __DEV_NEW__ ++ ifxusb_power_on (&_pcd->core_if); ++ mdelay(50); ++ ifxusb_phy_power_on (&_pcd->core_if); // Test ++ mdelay(50); ++ ifxusb_hard_reset(&_pcd->core_if); ++ retval =ifxusb_core_if_init(&_pcd->core_if, ++ _irq, ++ _iobase, ++ _fifomem, ++ _fifodbg); ++ if(retval) ++ return retval; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ifxusb_dev_core_init(&_pcd->core_if,&ifxusb_module_params); ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ifxusb_disable_global_interrupts( &_pcd->core_if); ++ ++ /* The driver is now initialized and need to be registered into ++ Linux USB Gadget sub-system ++ */ ++ retval = ifxpcd_init(); ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ++ if (retval != 0) ++ { ++ IFX_ERROR("_pcd_init failed\n"); ++ return retval; ++ } ++ //ifxusb_enable_global_interrupts( _pcd->core_if ); // this should be done at gadget bind or start ++ return 0; ++ } ++#endif //__IS_DEVICE__ ++ ++ ++ ++/*! ++ \brief This function is called by module management in 2.6 kernel or by ifxusb_driver_init with 2.4 kernel ++ It is to probe and setup IFXUSB core(s). ++*/ ++static int ifxusb_driver_probe(struct platform_device *_dev) ++{ ++ int retval = 0; ++ int *pins = _dev->dev.platform_data; ++ if (ltq_is_vr9()) { ++ gpio_request(6, "id1"); ++ gpio_request(9, "id2"); ++ gpio_direction_input(6); ++ gpio_direction_input(9); ++ } ++ if (pins) { ++ if (pins[0]) { ++ gpio_request(pins[0], "vbus1"); ++ gpio_direction_output(pins[0], 1); ++ } ++ if (pins[1] && ltq_is_vr9()) { ++ gpio_request(pins[1], "vbus2"); ++ gpio_direction_output(pins[1], 1); ++ } ++ } ++ // Parsing and store the parameters ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ parse_parms(); ++ ++ #ifdef __IS_HOST__ ++ #if defined(__IS_DUAL__) ++ memset(&ifxusb_hcd_1, 0, sizeof(ifxhcd_hcd_t)); ++ memset(&ifxusb_hcd_2, 0, sizeof(ifxhcd_hcd_t)); ++ ++ ifxusb_hcd_1.core_if.core_no=0; ++ ifxusb_hcd_2.core_if.core_no=1; ++ ifxusb_hcd_1.core_if.core_name=(char *)ifxusb_hcd_name_1; ++ ifxusb_hcd_2.core_if.core_name=(char *)ifxusb_hcd_name_2; ++ ++ ifxusb_hcd_1.dev=&_dev->dev; ++ ifxusb_hcd_2.dev=&_dev->dev; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd_1, ++ IFX_USB0_IR, ++ IFXUSB1_IOMEM_BASE, ++ IFXUSB1_FIFOMEM_BASE, ++ IFXUSB1_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd_2, ++ IFX_USB1_IR, ++ IFXUSB2_IOMEM_BASE, ++ IFXUSB2_FIFOMEM_BASE, ++ IFXUSB2_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ ++ #elif defined(__IS_FIRST__) ++ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); ++ ++ ifxusb_hcd.core_if.core_no=0; ++ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; ++ ++ ifxusb_hcd.dev=&_dev->dev; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd, ++ IFX_USB0_IR, ++ IFXUSB1_IOMEM_BASE, ++ IFXUSB1_FIFOMEM_BASE, ++ IFXUSB1_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ ++ #elif defined(__IS_SECOND__) ++ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); ++ ++ ifxusb_hcd.core_if.core_no=1; ++ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; ++ ++ ifxusb_hcd.dev=&_dev->dev; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd, ++ IFX_USB1_IR, ++ IFXUSB2_IOMEM_BASE, ++ IFXUSB2_FIFOMEM_BASE, ++ IFXUSB2_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ ++ #else ++ memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); ++ ++ ifxusb_hcd.core_if.core_no=0; ++ ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; ++ ++ ifxusb_hcd.dev=&_dev->dev; ++ ++ retval = ifxusb_driver_probe_h(&ifxusb_hcd, ++ IFXUSB_IRQ, ++ IFXUSB_IOMEM_BASE, ++ IFXUSB_FIFOMEM_BASE, ++ IFXUSB_FIFODBG_BASE ++ ); ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ #endif ++ ++ #if defined(__DO_OC_INT__) ++ IFXUSB_DEBUGPL( DBG_CIL, "registering (overcurrent) handler for irq%d\n", IFXUSB_OC_IRQ); ++ #if defined(__IS_DUAL__) ++ request_irq((unsigned int)IFXUSB_OC_IRQ, &ifx_hcd_oc_irq, ++// SA_INTERRUPT|SA_SHIRQ, "ifxusb_oc", (void *)&ifxusb_hcd_1); ++ IRQF_DISABLED | IRQF_SHARED, "ifxusb_oc", (void *)&ifxusb_hcd_1); ++ oc_int_id=&ifxusb_hcd_1; ++ #else ++ request_irq((unsigned int)IFXUSB_OC_IRQ, &ifx_hcd_oc_irq, ++// SA_INTERRUPT|SA_SHIRQ, "ifxusb_oc", (void *)&ifxusb_hcd); ++ IRQF_DISABLED | IRQF_SHARED, "ifxusb_oc", (void *)&ifxusb_hcd); ++ oc_int_id=&ifxusb_hcd; ++ #endif ++ oc_int_installed=1; ++ ++ #if defined(__DO_OC_INT_ENABLE__) ++ ifxusb_oc_int_on(); ++ #endif ++ #endif ++ ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ memset(&ifxusb_pcd, 0, sizeof(ifxpcd_pcd_t)); ++ ifxusb_pcd.core_if.core_name=(char *)&ifxusb_pcd_name[0]; ++ ++ ifxusb_pcd.dev=&_dev->dev; ++ ++ #if defined(__IS_FIRST__) ++ ifxusb_pcd.core_if.core_no=0; ++ retval = ifxusb_driver_probe_d(&ifxusb_pcd, ++ IFXUSB1_IRQ, ++ IFXUSB1_IOMEM_BASE, ++ IFXUSB1_FIFOMEM_BASE, ++ IFXUSB1_FIFODBG_BASE ++ ); ++ #elif defined(__IS_SECOND__) ++ ifxusb_pcd.core_if.core_no=1; ++ retval = ifxusb_driver_probe_d(&ifxusb_pcd, ++ IFXUSB2_IRQ, ++ IFXUSB2_IOMEM_BASE, ++ IFXUSB2_FIFOMEM_BASE, ++ IFXUSB2_FIFODBG_BASE ++ ); ++ #else ++ ifxusb_pcd.core_if.core_no=0; ++ retval = ifxusb_driver_probe_d(&ifxusb_pcd, ++ IFXUSB_IRQ, ++ IFXUSB_IOMEM_BASE, ++ IFXUSB_FIFOMEM_BASE, ++ IFXUSB_FIFODBG_BASE ++ ); ++ #endif ++ if(retval) ++ goto ifxusb_driver_probe_fail; ++ #endif ++ ++ ifxusb_attr_create(&_dev->dev); ++ ++ return 0; ++ ++ifxusb_driver_probe_fail: ++ ifxusb_driver_remove(_dev); ++ return retval; ++} ++ ++ ++ ++/*! ++ \brief This function is called when the ifxusb_driver is installed with the insmod command. ++*/ ++ ++ ++static struct platform_driver ifxusb_driver = { ++ .driver = { ++ .name = ifxusb_driver_name, ++ .owner = THIS_MODULE, ++ }, ++ .probe = ifxusb_driver_probe, ++ .remove = ifxusb_driver_remove, ++}; ++ ++int __init ifxusb_driver_init(void) ++{ ++ int retval = 0; ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ IFX_PRINT("%s: version %s\n", ifxusb_driver_name, IFXUSB_VERSION); ++ ++ retval = platform_driver_register(&ifxusb_driver); ++ ++ if (retval < 0) { ++ IFX_ERROR("%s retval=%d\n", __func__, retval); ++ return retval; ++ } ++ return retval; ++} ++ ++#if 0 // 2.4 ++ int __init ifxusb_driver_init(void) ++ { ++ int retval = 0; ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ IFX_PRINT("%s: version %s\n", ifxusb_driver_name, IFXUSB_VERSION); ++ retval = ifxusb_driver_probe(); ++ ++ if (retval < 0) { ++ IFX_ERROR("%s retval=%d\n", __func__, retval); ++ return retval; ++ } ++ ++ return retval; ++ } ++#endif ++ ++module_init(ifxusb_driver_init); ++ ++ ++/*! ++ \brief This function is called when the driver is removed from the kernel ++ with the rmmod command. The driver unregisters itself with its bus ++ driver. ++*/ ++ ++void __exit ifxusb_driver_cleanup(void) ++{ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ++ platform_driver_unregister(&ifxusb_driver); ++ ++ IFX_PRINT("%s module removed\n", ifxusb_driver_name); ++} ++#if 0 ++ void __exit ifxusb_driver_cleanup(void) ++ { ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ ifxusb_driver_remove(); ++ IFX_PRINT("%s module removed\n", ifxusb_driver_name); ++ } ++#endif ++module_exit(ifxusb_driver_cleanup); ++ ++ ++ ++MODULE_DESCRIPTION(USB_DRIVER_DESC); ++MODULE_AUTHOR("Infineon"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++// Parameters set when loaded ++//static long dbg_lvl =0xFFFFFFFF; ++static long dbg_lvl =0; ++static short dma_burst_size =-1; ++static short speed =-1; ++static long data_fifo_size =-1; ++#ifdef __IS_DEVICE__ ++ static long rx_fifo_size =-1; ++ #ifdef __DED_FIFO__ ++ static long tx_fifo_size_00 =-1; ++ static long tx_fifo_size_01 =-1; ++ static long tx_fifo_size_02 =-1; ++ static long tx_fifo_size_03 =-1; ++ static long tx_fifo_size_04 =-1; ++ static long tx_fifo_size_05 =-1; ++ static long tx_fifo_size_06 =-1; ++ static long tx_fifo_size_07 =-1; ++ static long tx_fifo_size_08 =-1; ++ static long tx_fifo_size_09 =-1; ++ static long tx_fifo_size_10 =-1; ++ static long tx_fifo_size_11 =-1; ++ static long tx_fifo_size_12 =-1; ++ static long tx_fifo_size_13 =-1; ++ static long tx_fifo_size_14 =-1; ++ static long tx_fifo_size_15 =-1; ++ static short thr_ctl=-1; ++ static long tx_thr_length =-1; ++ static long rx_thr_length =-1; ++ #else ++ static long nperio_tx_fifo_size =-1; ++ static long perio_tx_fifo_size_01 =-1; ++ static long perio_tx_fifo_size_02 =-1; ++ static long perio_tx_fifo_size_03 =-1; ++ static long perio_tx_fifo_size_04 =-1; ++ static long perio_tx_fifo_size_05 =-1; ++ static long perio_tx_fifo_size_06 =-1; ++ static long perio_tx_fifo_size_07 =-1; ++ static long perio_tx_fifo_size_08 =-1; ++ static long perio_tx_fifo_size_09 =-1; ++ static long perio_tx_fifo_size_10 =-1; ++ static long perio_tx_fifo_size_11 =-1; ++ static long perio_tx_fifo_size_12 =-1; ++ static long perio_tx_fifo_size_13 =-1; ++ static long perio_tx_fifo_size_14 =-1; ++ static long perio_tx_fifo_size_15 =-1; ++ #endif ++ static short dev_endpoints =-1; ++#endif ++ ++#ifdef __IS_HOST__ ++ static long rx_fifo_size =-1; ++ static long nperio_tx_fifo_size =-1; ++ static long perio_tx_fifo_size =-1; ++ static short host_channels =-1; ++#endif ++ ++static long max_transfer_size =-1; ++static long max_packet_count =-1; ++static long phy_utmi_width =-1; ++static long turn_around_time_hs =-1; ++static long turn_around_time_fs =-1; ++static long timeout_cal_hs =-1; ++static long timeout_cal_fs =-1; ++ ++/*! ++ \brief Parsing the parameters taken when module load ++*/ ++static void parse_parms(void) ++{ ++ ++ IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); ++ #ifdef __IS_HOST__ ++ h_dbg_lvl=dbg_lvl; ++ #endif ++ #ifdef __IS_DEVICE__ ++ d_dbg_lvl=dbg_lvl; ++ #endif ++ ++ switch(dma_burst_size) ++ { ++ case 0: ++ case 1: ++ case 4: ++ case 8: ++ case 16: ++ ifxusb_module_params.dma_burst_size=dma_burst_size; ++ break; ++ default: ++ ifxusb_module_params.dma_burst_size=default_param_dma_burst_size; ++ } ++ ++ if(speed==0 || speed==1) ++ ifxusb_module_params.speed=speed; ++ else ++ ifxusb_module_params.speed=default_param_speed; ++ ++ if(max_transfer_size>=2048 && max_transfer_size<=65535) ++ ifxusb_module_params.max_transfer_size=max_transfer_size; ++ else ++ ifxusb_module_params.max_transfer_size=default_param_max_transfer_size; ++ ++ if(max_packet_count>=15 && max_packet_count<=511) ++ ifxusb_module_params.max_packet_count=max_packet_count; ++ else ++ ifxusb_module_params.max_packet_count=default_param_max_packet_count; ++ ++ switch(phy_utmi_width) ++ { ++ case 8: ++ case 16: ++ ifxusb_module_params.phy_utmi_width=phy_utmi_width; ++ break; ++ default: ++ ifxusb_module_params.phy_utmi_width=default_param_phy_utmi_width; ++ } ++ ++ if(turn_around_time_hs>=0 && turn_around_time_hs<=7) ++ ifxusb_module_params.turn_around_time_hs=turn_around_time_hs; ++ else ++ ifxusb_module_params.turn_around_time_hs=default_param_turn_around_time_hs; ++ ++ if(turn_around_time_fs>=0 && turn_around_time_fs<=7) ++ ifxusb_module_params.turn_around_time_fs=turn_around_time_fs; ++ else ++ ifxusb_module_params.turn_around_time_fs=default_param_turn_around_time_fs; ++ ++ if(timeout_cal_hs>=0 && timeout_cal_hs<=7) ++ ifxusb_module_params.timeout_cal_hs=timeout_cal_hs; ++ else ++ ifxusb_module_params.timeout_cal_hs=default_param_timeout_cal_hs; ++ ++ if(timeout_cal_fs>=0 && timeout_cal_fs<=7) ++ ifxusb_module_params.timeout_cal_fs=timeout_cal_fs; ++ else ++ ifxusb_module_params.timeout_cal_fs=default_param_timeout_cal_fs; ++ ++ if(data_fifo_size>=32 && data_fifo_size<=32768) ++ ifxusb_module_params.data_fifo_size=data_fifo_size; ++ else ++ ifxusb_module_params.data_fifo_size=default_param_data_fifo_size; ++ ++ #ifdef __IS_HOST__ ++ if(host_channels>=1 && host_channels<=16) ++ ifxusb_module_params.host_channels=host_channels; ++ else ++ ifxusb_module_params.host_channels=default_param_host_channels; ++ ++ if(rx_fifo_size>=16 && rx_fifo_size<=32768) ++ ifxusb_module_params.rx_fifo_size=rx_fifo_size; ++ else ++ ifxusb_module_params.rx_fifo_size=default_param_rx_fifo_size; ++ ++ if(nperio_tx_fifo_size>=16 && nperio_tx_fifo_size<=32768) ++ ifxusb_module_params.nperio_tx_fifo_size=nperio_tx_fifo_size; ++ else ++ ifxusb_module_params.nperio_tx_fifo_size=default_param_nperio_tx_fifo_size; ++ ++ if(perio_tx_fifo_size>=16 && perio_tx_fifo_size<=32768) ++ ifxusb_module_params.perio_tx_fifo_size=perio_tx_fifo_size; ++ else ++ ifxusb_module_params.perio_tx_fifo_size=default_param_perio_tx_fifo_size; ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ if(rx_fifo_size>=16 && rx_fifo_size<=32768) ++ ifxusb_module_params.rx_fifo_size=rx_fifo_size; ++ else ++ ifxusb_module_params.rx_fifo_size=default_param_rx_fifo_size; ++ #ifdef __DED_FIFO__ ++ if(tx_fifo_size_00>=16 && tx_fifo_size_00<=32768) ++ ifxusb_module_params.tx_fifo_size[ 0]=tx_fifo_size_00; ++ else ++ ifxusb_module_params.tx_fifo_size[ 0]=default_param_tx_fifo_size_00; ++ if(tx_fifo_size_01>=0 && tx_fifo_size_01<=32768) ++ ifxusb_module_params.tx_fifo_size[ 1]=tx_fifo_size_01; ++ else ++ ifxusb_module_params.tx_fifo_size[ 1]=default_param_tx_fifo_size_01; ++ if(tx_fifo_size_02>=0 && tx_fifo_size_02<=32768) ++ ifxusb_module_params.tx_fifo_size[ 2]=tx_fifo_size_02; ++ else ++ ifxusb_module_params.tx_fifo_size[ 2]=default_param_tx_fifo_size_02; ++ if(tx_fifo_size_03>=0 && tx_fifo_size_03<=32768) ++ ifxusb_module_params.tx_fifo_size[ 3]=tx_fifo_size_03; ++ else ++ ifxusb_module_params.tx_fifo_size[ 3]=default_param_tx_fifo_size_03; ++ if(tx_fifo_size_04>=0 && tx_fifo_size_04<=32768) ++ ifxusb_module_params.tx_fifo_size[ 4]=tx_fifo_size_04; ++ else ++ ifxusb_module_params.tx_fifo_size[ 4]=default_param_tx_fifo_size_04; ++ if(tx_fifo_size_05>=0 && tx_fifo_size_05<=32768) ++ ifxusb_module_params.tx_fifo_size[ 5]=tx_fifo_size_05; ++ else ++ ifxusb_module_params.tx_fifo_size[ 5]=default_param_tx_fifo_size_05; ++ if(tx_fifo_size_06>=0 && tx_fifo_size_06<=32768) ++ ifxusb_module_params.tx_fifo_size[ 6]=tx_fifo_size_06; ++ else ++ ifxusb_module_params.tx_fifo_size[ 6]=default_param_tx_fifo_size_06; ++ if(tx_fifo_size_07>=0 && tx_fifo_size_07<=32768) ++ ifxusb_module_params.tx_fifo_size[ 7]=tx_fifo_size_07; ++ else ++ ifxusb_module_params.tx_fifo_size[ 7]=default_param_tx_fifo_size_07; ++ if(tx_fifo_size_08>=0 && tx_fifo_size_08<=32768) ++ ifxusb_module_params.tx_fifo_size[ 8]=tx_fifo_size_08; ++ else ++ ifxusb_module_params.tx_fifo_size[ 8]=default_param_tx_fifo_size_08; ++ if(tx_fifo_size_09>=0 && tx_fifo_size_09<=32768) ++ ifxusb_module_params.tx_fifo_size[ 9]=tx_fifo_size_09; ++ else ++ ifxusb_module_params.tx_fifo_size[ 9]=default_param_tx_fifo_size_09; ++ if(tx_fifo_size_10>=0 && tx_fifo_size_10<=32768) ++ ifxusb_module_params.tx_fifo_size[10]=tx_fifo_size_10; ++ else ++ ifxusb_module_params.tx_fifo_size[10]=default_param_tx_fifo_size_10; ++ if(tx_fifo_size_11>=0 && tx_fifo_size_11<=32768) ++ ifxusb_module_params.tx_fifo_size[11]=tx_fifo_size_11; ++ else ++ ifxusb_module_params.tx_fifo_size[11]=default_param_tx_fifo_size_11; ++ if(tx_fifo_size_12>=0 && tx_fifo_size_12<=32768) ++ ifxusb_module_params.tx_fifo_size[12]=tx_fifo_size_12; ++ else ++ ifxusb_module_params.tx_fifo_size[12]=default_param_tx_fifo_size_12; ++ if(tx_fifo_size_13>=0 && tx_fifo_size_13<=32768) ++ ifxusb_module_params.tx_fifo_size[13]=tx_fifo_size_13; ++ else ++ ifxusb_module_params.tx_fifo_size[13]=default_param_tx_fifo_size_13; ++ if(tx_fifo_size_14>=0 && tx_fifo_size_14<=32768) ++ ifxusb_module_params.tx_fifo_size[14]=tx_fifo_size_14; ++ else ++ ifxusb_module_params.tx_fifo_size[14]=default_param_tx_fifo_size_14; ++ if(tx_fifo_size_15>=0 && tx_fifo_size_15<=32768) ++ ifxusb_module_params.tx_fifo_size[15]=tx_fifo_size_15; ++ else ++ ifxusb_module_params.tx_fifo_size[15]=default_param_tx_fifo_size_15; ++ if(thr_ctl==0 || thr_ctl==1) ++ ifxusb_module_params.thr_ctl=thr_ctl; ++ else ++ ifxusb_module_params.thr_ctl=default_param_thr_ctl; ++ if(tx_thr_length>=16 && tx_thr_length<=511) ++ ifxusb_module_params.tx_thr_length=tx_thr_length; ++ else ++ ifxusb_module_params.tx_thr_length=default_param_tx_thr_length; ++ if(rx_thr_length>=16 && rx_thr_length<=511) ++ ifxusb_module_params.rx_thr_length=rx_thr_length; ++ else ++ ifxusb_module_params.rx_thr_length=default_param_rx_thr_length; ++ #else //__DED_FIFO__ ++ if(nperio_tx_fifo_size>=16 && nperio_tx_fifo_size<=32768) ++ ifxusb_module_params.tx_fifo_size[ 0]=nperio_tx_fifo_size; ++ else ++ ifxusb_module_params.tx_fifo_size[ 0]=default_param_nperio_tx_fifo_size; ++ if(perio_tx_fifo_size_01>=0 && perio_tx_fifo_size_01<=32768) ++ ifxusb_module_params.tx_fifo_size[ 1]=perio_tx_fifo_size_01; ++ else ++ ifxusb_module_params.tx_fifo_size[ 1]=default_param_perio_tx_fifo_size_01; ++ if(perio_tx_fifo_size_02>=0 && perio_tx_fifo_size_02<=32768) ++ ifxusb_module_params.tx_fifo_size[ 2]=perio_tx_fifo_size_02; ++ else ++ ifxusb_module_params.tx_fifo_size[ 2]=default_param_perio_tx_fifo_size_02; ++ if(perio_tx_fifo_size_03>=0 && perio_tx_fifo_size_03<=32768) ++ ifxusb_module_params.tx_fifo_size[ 3]=perio_tx_fifo_size_03; ++ else ++ ifxusb_module_params.tx_fifo_size[ 3]=default_param_perio_tx_fifo_size_03; ++ if(perio_tx_fifo_size_04>=0 && perio_tx_fifo_size_04<=32768) ++ ifxusb_module_params.tx_fifo_size[ 4]=perio_tx_fifo_size_04; ++ else ++ ifxusb_module_params.tx_fifo_size[ 4]=default_param_perio_tx_fifo_size_04; ++ if(perio_tx_fifo_size_05>=0 && perio_tx_fifo_size_05<=32768) ++ ifxusb_module_params.tx_fifo_size[ 5]=perio_tx_fifo_size_05; ++ else ++ ifxusb_module_params.tx_fifo_size[ 5]=default_param_perio_tx_fifo_size_05; ++ if(perio_tx_fifo_size_06>=0 && perio_tx_fifo_size_06<=32768) ++ ifxusb_module_params.tx_fifo_size[ 6]=perio_tx_fifo_size_06; ++ else ++ ifxusb_module_params.tx_fifo_size[ 6]=default_param_perio_tx_fifo_size_06; ++ if(perio_tx_fifo_size_07>=0 && perio_tx_fifo_size_07<=32768) ++ ifxusb_module_params.tx_fifo_size[ 7]=perio_tx_fifo_size_07; ++ else ++ ifxusb_module_params.tx_fifo_size[ 7]=default_param_perio_tx_fifo_size_07; ++ if(perio_tx_fifo_size_08>=0 && perio_tx_fifo_size_08<=32768) ++ ifxusb_module_params.tx_fifo_size[ 8]=perio_tx_fifo_size_08; ++ else ++ ifxusb_module_params.tx_fifo_size[ 8]=default_param_perio_tx_fifo_size_08; ++ if(perio_tx_fifo_size_09>=0 && perio_tx_fifo_size_09<=32768) ++ ifxusb_module_params.tx_fifo_size[ 9]=perio_tx_fifo_size_09; ++ else ++ ifxusb_module_params.tx_fifo_size[ 9]=default_param_perio_tx_fifo_size_09; ++ if(perio_tx_fifo_size_10>=0 && perio_tx_fifo_size_10<=32768) ++ ifxusb_module_params.tx_fifo_size[10]=perio_tx_fifo_size_10; ++ else ++ ifxusb_module_params.tx_fifo_size[10]=default_param_perio_tx_fifo_size_10; ++ if(perio_tx_fifo_size_11>=0 && perio_tx_fifo_size_11<=32768) ++ ifxusb_module_params.tx_fifo_size[11]=perio_tx_fifo_size_11; ++ else ++ ifxusb_module_params.tx_fifo_size[11]=default_param_perio_tx_fifo_size_11; ++ if(perio_tx_fifo_size_12>=0 && perio_tx_fifo_size_12<=32768) ++ ifxusb_module_params.tx_fifo_size[12]=perio_tx_fifo_size_12; ++ else ++ ifxusb_module_params.tx_fifo_size[12]=default_param_perio_tx_fifo_size_12; ++ if(perio_tx_fifo_size_13>=0 && perio_tx_fifo_size_13<=32768) ++ ifxusb_module_params.tx_fifo_size[13]=perio_tx_fifo_size_13; ++ else ++ ifxusb_module_params.tx_fifo_size[13]=default_param_perio_tx_fifo_size_13; ++ if(perio_tx_fifo_size_14>=0 && perio_tx_fifo_size_14<=32768) ++ ifxusb_module_params.tx_fifo_size[14]=perio_tx_fifo_size_14; ++ else ++ ifxusb_module_params.tx_fifo_size[14]=default_param_perio_tx_fifo_size_14; ++ if(perio_tx_fifo_size_15>=0 && perio_tx_fifo_size_15<=32768) ++ ifxusb_module_params.tx_fifo_size[15]=perio_tx_fifo_size_15; ++ else ++ ifxusb_module_params.tx_fifo_size[15]=default_param_perio_tx_fifo_size_15; ++ #endif //__DED_FIFO__ ++ #endif //__IS_DEVICE__ ++} ++ ++ ++ ++ ++ ++ ++ ++module_param(dbg_lvl, long, 0444); ++MODULE_PARM_DESC(dbg_lvl, "Debug level."); ++ ++module_param(dma_burst_size, short, 0444); ++MODULE_PARM_DESC(dma_burst_size, "DMA Burst Size 0, 1, 4, 8, 16"); ++ ++module_param(speed, short, 0444); ++MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); ++ ++module_param(data_fifo_size, long, 0444); ++MODULE_PARM_DESC(data_fifo_size, "Total number of words in the data FIFO memory 32-32768"); ++ ++#ifdef __IS_DEVICE__ ++ module_param(rx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++ ++ #ifdef __DED_FIFO__ ++ module_param(tx_fifo_size_00, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_00, "Number of words in the Tx FIFO #00 16-32768"); ++ module_param(tx_fifo_size_01, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_01, "Number of words in the Tx FIFO #01 0-32768"); ++ module_param(tx_fifo_size_02, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_02, "Number of words in the Tx FIFO #02 0-32768"); ++ module_param(tx_fifo_size_03, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_03, "Number of words in the Tx FIFO #03 0-32768"); ++ module_param(tx_fifo_size_04, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_04, "Number of words in the Tx FIFO #04 0-32768"); ++ module_param(tx_fifo_size_05, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_05, "Number of words in the Tx FIFO #05 0-32768"); ++ module_param(tx_fifo_size_06, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_06, "Number of words in the Tx FIFO #06 0-32768"); ++ module_param(tx_fifo_size_07, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_07, "Number of words in the Tx FIFO #07 0-32768"); ++ module_param(tx_fifo_size_08, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_08, "Number of words in the Tx FIFO #08 0-32768"); ++ module_param(tx_fifo_size_09, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_09, "Number of words in the Tx FIFO #09 0-32768"); ++ module_param(tx_fifo_size_10, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_10, "Number of words in the Tx FIFO #10 0-32768"); ++ module_param(tx_fifo_size_11, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_11, "Number of words in the Tx FIFO #11 0-32768"); ++ module_param(tx_fifo_size_12, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_12, "Number of words in the Tx FIFO #12 0-32768"); ++ module_param(tx_fifo_size_13, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_13, "Number of words in the Tx FIFO #13 0-32768"); ++ module_param(tx_fifo_size_14, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_14, "Number of words in the Tx FIFO #14 0-32768"); ++ module_param(tx_fifo_size_15, long, 0444); ++ MODULE_PARM_DESC(tx_fifo_size_15, "Number of words in the Tx FIFO #15 0-32768"); ++ ++ module_param(thr_ctl, short, 0444); ++ MODULE_PARM_DESC(thr_ctl, "0=Without 1=With Theshold Ctrl"); ++ ++ module_param(tx_thr_length, long, 0444); ++ MODULE_PARM_DESC(tx_thr_length, "TX Threshold length"); ++ ++ module_param(rx_thr_length, long, 0444); ++ MODULE_PARM_DESC(rx_thr_length, "RX Threshold length"); ++ ++ #else ++ module_param(nperio_tx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); ++ ++ module_param(perio_tx_fifo_size_01, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_01, "Number of words in the periodic Tx FIFO #01 0-32768"); ++ module_param(perio_tx_fifo_size_02, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_02, "Number of words in the periodic Tx FIFO #02 0-32768"); ++ module_param(perio_tx_fifo_size_03, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_03, "Number of words in the periodic Tx FIFO #03 0-32768"); ++ module_param(perio_tx_fifo_size_04, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_04, "Number of words in the periodic Tx FIFO #04 0-32768"); ++ module_param(perio_tx_fifo_size_05, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_05, "Number of words in the periodic Tx FIFO #05 0-32768"); ++ module_param(perio_tx_fifo_size_06, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_06, "Number of words in the periodic Tx FIFO #06 0-32768"); ++ module_param(perio_tx_fifo_size_07, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_07, "Number of words in the periodic Tx FIFO #07 0-32768"); ++ module_param(perio_tx_fifo_size_08, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_08, "Number of words in the periodic Tx FIFO #08 0-32768"); ++ module_param(perio_tx_fifo_size_09, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_09, "Number of words in the periodic Tx FIFO #09 0-32768"); ++ module_param(perio_tx_fifo_size_10, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_10, "Number of words in the periodic Tx FIFO #10 0-32768"); ++ module_param(perio_tx_fifo_size_11, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_11, "Number of words in the periodic Tx FIFO #11 0-32768"); ++ module_param(perio_tx_fifo_size_12, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_12, "Number of words in the periodic Tx FIFO #12 0-32768"); ++ module_param(perio_tx_fifo_size_13, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_13, "Number of words in the periodic Tx FIFO #13 0-32768"); ++ module_param(perio_tx_fifo_size_14, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_14, "Number of words in the periodic Tx FIFO #14 0-32768"); ++ module_param(perio_tx_fifo_size_15, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size_15, "Number of words in the periodic Tx FIFO #15 0-32768"); ++ #endif//__DED_FIFO__ ++ module_param(dev_endpoints, short, 0444); ++ MODULE_PARM_DESC(dev_endpoints, "The number of endpoints in addition to EP0 available for device mode 1-15"); ++#endif ++ ++#ifdef __IS_HOST__ ++ module_param(rx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++ ++ module_param(nperio_tx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); ++ ++ module_param(perio_tx_fifo_size, long, 0444); ++ MODULE_PARM_DESC(perio_tx_fifo_size, "Number of words in the host periodic Tx FIFO 16-32768"); ++ ++ module_param(host_channels, short, 0444); ++ MODULE_PARM_DESC(host_channels, "The number of host channel registers to use 1-16"); ++#endif ++ ++module_param(max_transfer_size, long, 0444); ++MODULE_PARM_DESC(max_transfer_size, "The maximum transfer size supported in bytes 2047-65535"); ++ ++module_param(max_packet_count, long, 0444); ++MODULE_PARM_DESC(max_packet_count, "The maximum number of packets in a transfer 15-511"); ++ ++module_param(phy_utmi_width, long, 0444); ++MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); ++ ++module_param(turn_around_time_hs, long, 0444); ++MODULE_PARM_DESC(turn_around_time_hs, "Turn-Around time for HS"); ++ ++module_param(turn_around_time_fs, long, 0444); ++MODULE_PARM_DESC(turn_around_time_fs, "Turn-Around time for FS"); ++ ++module_param(timeout_cal_hs, long, 0444); ++MODULE_PARM_DESC(timeout_cal_hs, "Timeout Cal for HS"); ++ ++module_param(timeout_cal_fs, long, 0444); ++MODULE_PARM_DESC(timeout_cal_fs, "Timeout Cal for FS"); ++ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_plat.h b/drivers/usb/ifxhcd/ifxusb_plat.h +new file mode 100644 +index 0000000..a50294f +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_plat.h +@@ -0,0 +1,1018 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_plat.h ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the Platform Specific constants, interfaces ++ ** (functions and macros). ++ ** FUNCTIONS : ++ ** COMPILER : gcc ++ ** REFERENCE : IFX hardware ref handbook for each plateforms ++ ** COPYRIGHT : ++ ** Version Control Section ** ++ ** $Author$ ++ ** $Date$ ++ ** $Revisions$ ++ ** $Log$ Revision history ++ *****************************************************************************/ ++ ++ ++/*! ++ \defgroup IFXUSB_PLATEFORM_DEFINITION Platform Specific constants, interfaces (functions and macros). ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief Maintain plateform specific definitions and macros in this file. ++ Each plateform has its own definition zone. ++ */ ++ ++/*! ++ \defgroup IFXUSB_PLATEFORM_MEM_ADDR Definition of memory address and size and default parameters ++ \ingroup IFXUSB_PLATEFORM_DEFINITION ++ */ ++ ++/*! ++ \defgroup IFXUSB_DBG_ROUTINE Routines for debug message ++ \ingroup IFXUSB_PLATEFORM_DEFINITION ++ */ ++ ++ ++/*! \file ifxusb_plat.h ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the Platform Specific constants, interfaces (functions and macros). ++*/ ++ ++#if !defined(__IFXUSB_PLAT_H__) ++#define __IFXUSB_PLAT_H__ ++ ++ ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/list.h> ++#include <linux/delay.h> ++#include <asm/io.h> ++ ++ ++#define IFXUSB_IOMEM_SIZE 0x00001000 ++#define IFXUSB_FIFOMEM_SIZE 0x00010000 ++#define IFXUSB_FIFODBG_SIZE 0x00020000 ++ ++ ++ ++/*! ++ \addtogroup IFXUSB_PLATEFORM_MEM_ADDR ++ */ ++/*@{*/ ++#if defined(__UEIP__) ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++// #define IFXUSB_IRQ 54 ++ #define IFXUSB_IOMEM_BASE 0x1e101000 ++ #define IFXUSB_FIFOMEM_BASE 0x1e120000 ++ #define IFXUSB_FIFODBG_BASE 0x1e140000 ++// #define IFXUSB_OC_IRQ 151 ++ ++ #ifndef DANUBE_RCU_BASE_ADDR ++ #define DANUBE_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef DANUBE_CGU ++ #define DANUBE_CGU (0xBF103000) ++ #endif ++ #ifndef DANUBE_CGU_IFCCR ++ #define DANUBE_CGU_IFCCR ((volatile unsigned long *)(DANUBE_CGU+ 0x0018)) ++ #endif ++ #ifndef DANUBE_PMU ++ #define DANUBE_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef DANUBE_PMU_PWDCR ++ #define DANUBE_PMU_PWDCR ((volatile unsigned long *)(DANUBE_PMU+0x001C)) ++ #endif ++ ++ #ifndef DANUBE_GPIO_P0_OUT ++ #define DANUBE_GPIO_P0_OUT (0xBF103000+0x10) ++ #define DANUBE_GPIO_P0_DIR (0xBF103000+0x18) ++ #define DANUBE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define DANUBE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define DANUBE_GPIO_P0_OD (0xBF103000+0x24) ++ #define DANUBE_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define DANUBE_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define DANUBE_GPIO_P1_OUT (0xBF103000+0x40) ++ #define DANUBE_GPIO_P1_DIR (0xBF103000+0x48) ++ #define DANUBE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define DANUBE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define DANUBE_GPIO_P1_OD (0xBF103000+0x54) ++ #define DANUBE_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define DANUBE_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define DANUBE_RCU_USBCFG ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x18)) ++ #define DANUBE_RCU_RESET ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x10)) ++ #define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 ++ #define default_param_turn_around_time_fs 4 ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 640 ++ #define default_param_nperio_tx_fifo_size 640 ++ #define default_param_perio_tx_fifo_size 768 ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 1024 ++ #define default_param_nperio_tx_fifo_size 1016 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 1024 ++ #define default_param_nperio_tx_fifo_size 1024 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_AMAZON_SE__) ++ //#include <asm/amazon_se/amazon_se.h> ++ //#include <asm/amazon_se/irq.h> ++ ++// #define IFXUSB_IRQ 31 ++ #define IFXUSB_IOMEM_BASE 0x1e101000 ++ #define IFXUSB_FIFOMEM_BASE 0x1e120000 ++ #define IFXUSB_FIFODBG_BASE 0x1e140000 ++// #define IFXUSB_OC_IRQ 20 ++ ++ #ifndef AMAZON_SE_RCU_BASE_ADDR ++ #define AMAZON_SE_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ #define AMAZON_SE_RCU_USBCFG ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x18)) ++ #define AMAZON_SE_RCU_RESET ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x10)) ++ #define AMAZON_SE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AMAZON_SE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AMAZON_SE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ #ifndef AMAZON_SE_GPIO_P0_OUT ++ #define AMAZON_SE_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AMAZON_SE_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AMAZON_SE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AMAZON_SE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AMAZON_SE_GPIO_P0_OD (0xBF103000+0x24) ++ #define AMAZON_SE_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AMAZON_SE_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AMAZON_SE_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AMAZON_SE_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AMAZON_SE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AMAZON_SE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AMAZON_SE_GPIO_P1_OD (0xBF103000+0x54) ++ #define AMAZON_SE_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AMAZON_SE_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #ifndef AMAZON_SE_CGU ++ #define AMAZON_SE_CGU (0xBF103000) ++ #endif ++ #ifndef AMAZON_SE_CGU_IFCCR ++ #define AMAZON_SE_CGU_IFCCR ((volatile unsigned long *)(AMAZON_SE_CGU+ 0x0018)) ++ #endif ++ #ifndef AMAZON_SE_PMU ++ #define AMAZON_SE_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AMAZON_SE_PMU_PWDCR ++ #define AMAZON_SE_PMU_PWDCR ((volatile unsigned long *)(AMAZON_SE_PMU+0x001C)) ++ #endif ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 248 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 256 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_AR9__) ++// #define IFXUSB1_IRQ 54 ++ #define IFXUSB1_IOMEM_BASE 0x1E101000 ++ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 ++ #define IFXUSB1_FIFODBG_BASE 0x1E140000 ++ ++// #define IFXUSB2_IRQ 83 ++ #define IFXUSB2_IOMEM_BASE 0x1E106000 ++ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 ++ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 ++ ++// #define IFXUSB_OC_IRQ 60 ++ ++ #ifndef AR9_RCU_BASE_ADDR ++ #define AR9_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef AR9_CGU ++ #define AR9_CGU (0xBF103000) ++ #endif ++ #ifndef AR9_CGU_IFCCR ++ #define AR9_CGU_IFCCR ((volatile unsigned long *)(AR9_CGU+ 0x0018)) ++ #endif ++ ++ #ifndef AR9_PMU ++ #define AR9_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AR9_PMU_PWDCR ++ #define AR9_PMU_PWDCR ((volatile unsigned long *)(AR9_PMU+0x001C)) ++ #endif ++ ++ #ifndef AR9_GPIO_P0_OUT ++ #define AR9_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AR9_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AR9_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AR9_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AR9_GPIO_P0_OD (0xBF103000+0x24) ++ #define AR9_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AR9_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AR9_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AR9_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AR9_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AR9_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AR9_GPIO_P1_OD (0xBF103000+0x54) ++ #define AR9_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AR9_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define AR9_RCU_USB1CFG ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x18)) ++ #define AR9_RCU_USB2CFG ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x34)) ++ #define AR9_RCU_USBRESET ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x10)) ++ #define AR9_USBCFG_ARB 7 // ++ #define AR9_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AR9_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AR9_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 256 ++// #define default_param_nperio_tx_fifo_size 248 ++// #define default_param_perio_tx_fifo_size_01 8 ++ #define default_param_nperio_tx_fifo_size 252 ++ #define default_param_perio_tx_fifo_size_01 4 ++ #else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 256 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_VR9__) ++// #define IFXUSB1_IRQ 54 ++ #define IFXUSB1_IOMEM_BASE 0x1E101000 ++ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 ++ #define IFXUSB1_FIFODBG_BASE 0x1E140000 ++ ++// #define IFXUSB2_IRQ 83 ++ #define IFXUSB2_IOMEM_BASE 0x1E106000 ++ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 ++ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 ++// #define IFXUSB_OC_IRQ 60 ++ ++ #ifndef VR9_RCU_BASE_ADDR ++ #define VR9_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef VR9_CGU ++ #define VR9_CGU (0xBF103000) ++ #endif ++ #ifndef VR9_CGU_IFCCR ++ #define VR9_CGU_IFCCR ((volatile unsigned long *)(VR9_CGU+ 0x0018)) ++ #endif ++ ++ #ifndef VR9_PMU ++ #define VR9_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef VR9_PMU_PWDCR ++ #define VR9_PMU_PWDCR ((volatile unsigned long *)(VR9_PMU+0x001C)) ++ #endif ++ ++ #ifndef VR9_GPIO_P0_OUT ++ #define VR9_GPIO_P0_OUT (0xBF103000+0x10) ++ #define VR9_GPIO_P0_DIR (0xBF103000+0x18) ++ #define VR9_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define VR9_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define VR9_GPIO_P0_OD (0xBF103000+0x24) ++ #define VR9_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define VR9_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define VR9_GPIO_P1_OUT (0xBF103000+0x40) ++ #define VR9_GPIO_P1_DIR (0xBF103000+0x48) ++ #define VR9_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define VR9_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define VR9_GPIO_P1_OD (0xBF103000+0x54) ++ #define VR9_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define VR9_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define VR9_RCU_USB1CFG ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x18)) ++ #define VR9_RCU_USB2CFG ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x34)) ++ #define VR9_RCU_USB_ANA_CFG1A ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x38)) ++ #define VR9_RCU_USB_ANA_CFG1B ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x3C)) ++ #define VR9_RCU_USBRESET ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x10)) ++ #define VR9_RCU_USBRESET2 ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x48)) ++ #define VR9_USBCFG_ARB 7 // ++ #define VR9_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define VR9_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define VR9_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ /*== AVM/BC 20101220 Workaround VR9 DMA burst size == ++ * Using 2 Devices in diferent ports cause a general USB Host Error. ++ * Workaround found in UGW4.3 ++ */ ++// #define default_param_dma_burst_size 4 //(ALL) ++ //WA for AHB ++ #define default_param_dma_burst_size 0 //(ALL) ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a ++ #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++#if 0 ++ #define default_param_rx_fifo_size 256 ++ #define default_param_tx_fifo_size_00 -1 ++ #define default_param_tx_fifo_size_01 -1 ++ #define default_param_tx_fifo_size_02 -1 ++#else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_tx_fifo_size_00 32 ++ #define default_param_tx_fifo_size_01 200 ++ #define default_param_tx_fifo_size_02 8 ++#endif ++ #define default_param_tx_fifo_size_03 -1 ++ #define default_param_tx_fifo_size_04 -1 ++ #define default_param_tx_fifo_size_05 -1 ++ #define default_param_tx_fifo_size_06 -1 ++ #define default_param_tx_fifo_size_07 -1 ++ #define default_param_tx_fifo_size_08 -1 ++ #define default_param_tx_fifo_size_09 -1 ++ #define default_param_tx_fifo_size_10 -1 ++ #define default_param_tx_fifo_size_11 -1 ++ #define default_param_tx_fifo_size_12 -1 ++ #define default_param_tx_fifo_size_13 -1 ++ #define default_param_tx_fifo_size_14 -1 ++ #define default_param_tx_fifo_size_15 -1 ++ #define default_param_dma_unalgned_tx -1 ++ #define default_param_dma_unalgned_rx -1 ++ #define default_param_thr_ctl -1 ++ #define default_param_tx_thr_length -1 ++ #define default_param_rx_thr_length -1 ++ #endif //__IS_DEVICE__ ++ #else // __IS_VR9__ ++ #error "Please choose one platform!!" ++ #endif // __IS_VR9__ ++ ++#else //UEIP ++ #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) ++// #define IFXUSB_IRQ 54 ++ #define IFXUSB_IOMEM_BASE 0x1e101000 ++ #define IFXUSB_FIFOMEM_BASE 0x1e120000 ++ #define IFXUSB_FIFODBG_BASE 0x1e140000 ++// #define IFXUSB_OC_IRQ 151 ++ ++ ++ #ifndef DANUBE_RCU_BASE_ADDR ++ #define DANUBE_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef DANUBE_CGU ++ #define DANUBE_CGU (0xBF103000) ++ #endif ++ #ifndef DANUBE_CGU_IFCCR ++ #define DANUBE_CGU_IFCCR ((volatile unsigned long *)(DANUBE_CGU+ 0x0018)) ++ #endif ++ #ifndef DANUBE_PMU ++ #define DANUBE_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef DANUBE_PMU_PWDCR ++ #define DANUBE_PMU_PWDCR ((volatile unsigned long *)(DANUBE_PMU+0x001C)) ++ #endif ++ ++ #ifndef DANUBE_GPIO_P0_OUT ++ #define DANUBE_GPIO_P0_OUT (0xBF103000+0x10) ++ #define DANUBE_GPIO_P0_DIR (0xBF103000+0x18) ++ #define DANUBE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define DANUBE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define DANUBE_GPIO_P0_OD (0xBF103000+0x24) ++ #define DANUBE_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define DANUBE_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define DANUBE_GPIO_P1_OUT (0xBF103000+0x40) ++ #define DANUBE_GPIO_P1_DIR (0xBF103000+0x48) ++ #define DANUBE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define DANUBE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define DANUBE_GPIO_P1_OD (0xBF103000+0x54) ++ #define DANUBE_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define DANUBE_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ ++ #define DANUBE_RCU_USBCFG ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x18)) ++ #define DANUBE_RCU_RESET ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x10)) ++ #define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 640 ++ #define default_param_nperio_tx_fifo_size 640 ++ #define default_param_perio_tx_fifo_size 768 ++ #endif //__IS_HOST__ ++ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 1024 ++ #define default_param_nperio_tx_fifo_size 1016 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 1024 ++ #define default_param_nperio_tx_fifo_size 1024 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_AMAZON_SE__) ++ #include <asm/amazon_se/amazon_se.h> ++ //#include <asm/amazon_se/irq.h> ++ ++// #define IFXUSB_IRQ 31 ++ #define IFXUSB_IOMEM_BASE 0x1e101000 ++ #define IFXUSB_FIFOMEM_BASE 0x1e120000 ++ #define IFXUSB_FIFODBG_BASE 0x1e140000 ++// #define IFXUSB_OC_IRQ 20 ++ ++ #define AMAZON_SE_RCU_USBCFG ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x18)) ++ #define AMAZON_SE_RCU_RESET ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x10)) ++ #define AMAZON_SE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AMAZON_SE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AMAZON_SE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end ++ ++ #ifndef AMAZON_SE_GPIO_P0_OUT ++ #define AMAZON_SE_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AMAZON_SE_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AMAZON_SE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AMAZON_SE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AMAZON_SE_GPIO_P0_OD (0xBF103000+0x24) ++ #define AMAZON_SE_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AMAZON_SE_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AMAZON_SE_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AMAZON_SE_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AMAZON_SE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AMAZON_SE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AMAZON_SE_GPIO_P1_OD (0xBF103000+0x54) ++ #define AMAZON_SE_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AMAZON_SE_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ ++ #ifndef AMAZON_SE_CGU ++ #define AMAZON_SE_CGU (0xBF103000) ++ #endif ++ #ifndef AMAZON_SE_CGU_IFCCR ++ #define AMAZON_SE_CGU_IFCCR ((volatile unsigned long *)(AMAZON_SE_CGU+ 0x0018)) ++ #endif ++ #ifndef AMAZON_SE_PMU ++ #define AMAZON_SE_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AMAZON_SE_PMU_PWDCR ++ #define AMAZON_SE_PMU_PWDCR ((volatile unsigned long *)(AMAZON_SE_PMU+0x001C)) ++ #endif ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 248 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 256 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_AR9__) ++// #define IFXUSB1_IRQ 54 ++ #define IFXUSB1_IOMEM_BASE 0x1E101000 ++ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 ++ #define IFXUSB1_FIFODBG_BASE 0x1E140000 ++ ++// #define IFXUSB2_IRQ 83 ++ #define IFXUSB2_IOMEM_BASE 0x1E106000 ++ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 ++ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 ++ ++// #define IFXUSB_OC_IRQ 60 ++ ++ #ifndef AMAZON_S_RCU_BASE_ADDR ++ #define AMAZON_S_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef AMAZON_S_CGU ++ #define AMAZON_S_CGU (0xBF103000) ++ #endif ++ #ifndef AMAZON_S_CGU_IFCCR ++ #define AMAZON_S_CGU_IFCCR ((volatile unsigned long *)(AMAZON_S_CGU+ 0x0018)) ++ #endif ++ ++ #ifndef AMAZON_S_PMU ++ #define AMAZON_S_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AMAZON_S_PMU_PWDCR ++ #define AMAZON_S_PMU_PWDCR ((volatile unsigned long *)(AMAZON_S_PMU+0x001C)) ++ #endif ++ ++ #ifndef AMAZON_S_GPIO_P0_OUT ++ #define AMAZON_S_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AMAZON_S_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AMAZON_S_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AMAZON_S_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AMAZON_S_GPIO_P0_OD (0xBF103000+0x24) ++ #define AMAZON_S_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AMAZON_S_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AMAZON_S_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AMAZON_S_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AMAZON_S_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AMAZON_S_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AMAZON_S_GPIO_P1_OD (0xBF103000+0x54) ++ #define AMAZON_S_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AMAZON_S_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define AMAZON_S_RCU_USB1CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x18)) ++ #define AMAZON_S_RCU_USB2CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x34)) ++ #define AMAZON_S_RCU_USBRESET ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x10)) ++ #define AMAZON_S_USBCFG_ARB 7 // ++ #define AMAZON_S_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AMAZON_S_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AMAZON_S_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 4 //(NoChange) ++ #define default_param_turn_around_time_fs 4 //(NoChange) ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #ifdef __DED_INTR__ ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 248 ++ #define default_param_perio_tx_fifo_size_01 8 ++ #else ++ #define default_param_rx_fifo_size 256 ++ #define default_param_nperio_tx_fifo_size 256 ++ #define default_param_perio_tx_fifo_size_01 0 ++ #endif ++ #define default_param_perio_tx_fifo_size_02 0 ++ #define default_param_perio_tx_fifo_size_03 0 ++ #define default_param_perio_tx_fifo_size_04 0 ++ #define default_param_perio_tx_fifo_size_05 0 ++ #define default_param_perio_tx_fifo_size_06 0 ++ #define default_param_perio_tx_fifo_size_07 0 ++ #define default_param_perio_tx_fifo_size_08 0 ++ #define default_param_perio_tx_fifo_size_09 0 ++ #define default_param_perio_tx_fifo_size_10 0 ++ #define default_param_perio_tx_fifo_size_11 0 ++ #define default_param_perio_tx_fifo_size_12 0 ++ #define default_param_perio_tx_fifo_size_13 0 ++ #define default_param_perio_tx_fifo_size_14 0 ++ #define default_param_perio_tx_fifo_size_15 0 ++ #endif //__IS_DEVICE__ ++ ++ #elif defined(__IS_VR9__) ++// #define IFXUSB1_IRQ 54 ++ #define IFXUSB1_IOMEM_BASE 0x1E101000 ++ #define IFXUSB1_FIFOMEM_BASE 0x1E120000 ++ #define IFXUSB1_FIFODBG_BASE 0x1E140000 ++ ++// #define IFXUSB2_IRQ 83 ++ #define IFXUSB2_IOMEM_BASE 0x1E106000 ++ #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 ++ #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 ++// #define IFXUSB_OC_IRQ 60 ++ ++ #ifndef AMAZON_S_RCU_BASE_ADDR ++ #define AMAZON_S_RCU_BASE_ADDR (0xBF203000) ++ #endif ++ ++ #ifndef AMAZON_S_CGU ++ #define AMAZON_S_CGU (0xBF103000) ++ #endif ++ #ifndef AMAZON_S_CGU_IFCCR ++ #define AMAZON_S_CGU_IFCCR ((volatile unsigned long *)(AMAZON_S_CGU+ 0x0018)) ++ #endif ++ ++ #ifndef AMAZON_S_PMU ++ #define AMAZON_S_PMU (KSEG1+0x1F102000) ++ #endif ++ #ifndef AMAZON_S_PMU_PWDCR ++ #define AMAZON_S_PMU_PWDCR ((volatile unsigned long *)(AMAZON_S_PMU+0x001C)) ++ #endif ++ ++ #ifndef AMAZON_S_GPIO_P0_OUT ++ #define AMAZON_S_GPIO_P0_OUT (0xBF103000+0x10) ++ #define AMAZON_S_GPIO_P0_DIR (0xBF103000+0x18) ++ #define AMAZON_S_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) ++ #define AMAZON_S_GPIO_P0_ALTSEL1 (0xBF103000+0x20) ++ #define AMAZON_S_GPIO_P0_OD (0xBF103000+0x24) ++ #define AMAZON_S_GPIO_P0_PUDSEL (0xBF103000+0x2C) ++ #define AMAZON_S_GPIO_P0_PUDEN (0xBF103000+0x30) ++ #define AMAZON_S_GPIO_P1_OUT (0xBF103000+0x40) ++ #define AMAZON_S_GPIO_P1_DIR (0xBF103000+0x48) ++ #define AMAZON_S_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) ++ #define AMAZON_S_GPIO_P1_ALTSEL1 (0xBF103000+0x50) ++ #define AMAZON_S_GPIO_P1_OD (0xBF103000+0x54) ++ #define AMAZON_S_GPIO_P1_PUDSEL (0xBF103000+0x5C) ++ #define AMAZON_S_GPIO_P1_PUDEN (0xBF103000+0x60) ++ #endif ++ ++ #define AMAZON_S_RCU_USB1CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x18)) ++ #define AMAZON_S_RCU_USB2CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x34)) ++ #define AMAZON_S_RCU_USBRESET ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x10)) ++ #define AMAZON_S_USBCFG_ARB 7 // ++ #define AMAZON_S_USBCFG_HDSEL_BIT 11 // 0:host, 1:device ++ #define AMAZON_S_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end ++ #define AMAZON_S_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end ++ ++ #define default_param_dma_burst_size 4 //(ALL) ++ ++ #define default_param_speed IFXUSB_PARAM_SPEED_HIGH ++ ++ #define default_param_max_transfer_size -1 //(Max, hwcfg) ++ #define default_param_max_packet_count -1 //(Max, hwcfg) ++ #define default_param_phy_utmi_width 16 ++ ++ #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a ++ #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a ++ #define default_param_timeout_cal_hs -1 //(NoChange) ++ #define default_param_timeout_cal_fs -1 //(NoChange) ++ ++ #define default_param_data_fifo_size -1 //(Max, hwcfg) ++ ++ #ifdef __IS_HOST__ ++ #define default_param_host_channels -1 //(Max, hwcfg) ++ #define default_param_rx_fifo_size 240 ++ #define default_param_nperio_tx_fifo_size 240 ++ #define default_param_perio_tx_fifo_size 32 ++ #endif //__IS_HOST__ ++ #ifdef __IS_DEVICE__ ++ #define default_param_rx_fifo_size 256 ++ #define default_param_tx_fifo_size_00 -1 ++ #define default_param_tx_fifo_size_01 -1 ++ #define default_param_tx_fifo_size_02 -1 ++ #define default_param_tx_fifo_size_03 -1 ++ #define default_param_tx_fifo_size_04 -1 ++ #define default_param_tx_fifo_size_05 -1 ++ #define default_param_tx_fifo_size_06 -1 ++ #define default_param_tx_fifo_size_07 -1 ++ #define default_param_tx_fifo_size_08 -1 ++ #define default_param_tx_fifo_size_09 -1 ++ #define default_param_tx_fifo_size_10 -1 ++ #define default_param_tx_fifo_size_11 -1 ++ #define default_param_tx_fifo_size_12 -1 ++ #define default_param_tx_fifo_size_13 -1 ++ #define default_param_tx_fifo_size_14 -1 ++ #define default_param_tx_fifo_size_15 -1 ++ #define default_param_dma_unalgned_tx -1 ++ #define default_param_dma_unalgned_rx -1 ++ #define default_param_thr_ctl -1 ++ #define default_param_tx_thr_length -1 ++ #define default_param_rx_thr_length -1 ++ #endif //__IS_DEVICE__ ++ #else // __IS_VR9__ ++ #error "Please choose one platform!!" ++ #endif // __IS_VR9__ ++#endif //UEIP ++ ++/*@}*//*IFXUSB_PLATEFORM_MEM_ADDR*/ ++ ++///////////////////////////////////////////////////////////////////////// ++ ++#ifdef __IS_HOST__ ++ #ifdef CONFIG_USB_HOST_IFX_FORCE_USB11 ++ #undef default_param_speed ++ #define default_param_speed IFXUSB_PARAM_SPEED_FULL ++ #endif ++#endif ++#ifdef __IS_DEVICE__ ++ #ifndef CONFIG_USB_GADGET_DUALSPEED ++ #undef default_param_speed ++ #define default_param_speed IFXUSB_PARAM_SPEED_FULL ++ #endif ++#endif ++ ++///////////////////////////////////////////////////////////////////////// ++ ++static __inline__ void UDELAY( const uint32_t _usecs ) ++{ ++ udelay( _usecs ); ++} ++ ++static __inline__ void MDELAY( const uint32_t _msecs ) ++{ ++ mdelay( _msecs ); ++} ++ ++static __inline__ void SPIN_LOCK( spinlock_t *_lock ) ++{ ++ spin_lock(_lock); ++} ++ ++static __inline__ void SPIN_UNLOCK( spinlock_t *_lock ) ++{ ++ spin_unlock(_lock); ++} ++ ++#define SPIN_LOCK_IRQSAVE( _l, _f ) \ ++ { \ ++ spin_lock_irqsave(_l,_f); \ ++ } ++ ++#define SPIN_UNLOCK_IRQRESTORE( _l,_f ) \ ++ { \ ++ spin_unlock_irqrestore(_l,_f); \ ++ } ++ ++///////////////////////////////////////////////////////////////////////// ++/*! ++ \addtogroup IFXUSB_DBG_ROUTINE ++ */ ++/*@{*/ ++#ifdef __IS_HOST__ ++ extern uint32_t h_dbg_lvl; ++#endif ++ ++#ifdef __IS_DEVICE__ ++ extern uint32_t d_dbg_lvl; ++#endif ++ ++/*! \brief When debug level has the DBG_CIL bit set, display CIL Debug messages. */ ++#define DBG_CIL (0x2) ++/*! \brief When debug level has the DBG_CILV bit set, display CIL Verbose debug messages */ ++#define DBG_CILV (0x20) ++/*! \brief When debug level has the DBG_PCD bit set, display PCD (Device) debug messages */ ++#define DBG_PCD (0x4) ++/*! \brief When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug messages */ ++#define DBG_PCDV (0x40) ++/*! \brief When debug level has the DBG_HCD bit set, display Host debug messages */ ++#define DBG_HCD (0x8) ++/*! \brief When debug level has the DBG_HCDV bit set, display Verbose Host debug messages */ ++#define DBG_HCDV (0x80) ++/*! \brief When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host mode. */ ++#define DBG_HCD_URB (0x800) ++/*! \brief When debug level has any bit set, display debug messages */ ++#define DBG_ANY (0xFF) ++/*! \brief All debug messages off */ ++#define DBG_OFF 0 ++ ++#define DBG_ENTRY (0x8000) ++ ++#define IFXUSB "IFXUSB: " ++ ++/*! ++ \fn inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) ++ \brief Set the Debug Level variable. ++ \param _new 32-bit mask of debug level. ++ \return previous debug level ++ */ ++static inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) ++{ ++ #ifdef __IS_HOST__ ++ uint32_t old = h_dbg_lvl; ++ h_dbg_lvl = _new; ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ uint32_t old = d_dbg_lvl; ++ d_dbg_lvl = _new; ++ #endif ++ return old; ++} ++ ++#ifdef __DEBUG__ ++ #ifdef __IS_HOST__ ++ # define IFX_DEBUGPL(lvl, x...) do{ if ((lvl)&h_dbg_lvl)printk( KERN_DEBUG IFXUSB x ); }while(0) ++ # define CHK_DEBUG_LEVEL(level) ((level) & h_dbg_lvl) ++ #endif ++ ++ #ifdef __IS_DEVICE__ ++ # define IFX_DEBUGPL(lvl, x...) do{ if ((lvl)&d_dbg_lvl)printk( KERN_DEBUG IFXUSB x ); }while(0) ++ # define CHK_DEBUG_LEVEL(level) ((level) & d_dbg_lvl) ++ #endif ++ ++ # define IFX_DEBUGP(x...) IFX_DEBUGPL(DBG_ANY, x ) ++#else ++ # define IFX_DEBUGPL(lvl, x...) do{}while(0) ++ # define IFX_DEBUGP(x...) ++ # define CHK_DEBUG_LEVEL(level) (0) ++#endif //__DEBUG__ ++ ++/* Print an Error message. */ ++#define IFX_ERROR(x...) printk( KERN_ERR IFXUSB x ) ++/* Print a Warning message. */ ++#define IFX_WARN(x...) printk( KERN_WARNING IFXUSB x ) ++/* Print a notice (normal but significant message). */ ++#define IFX_NOTICE(x...) printk( KERN_NOTICE IFXUSB x ) ++/* Basic message printing. */ ++#define IFX_PRINT(x...) printk( KERN_INFO IFXUSB x ) ++ ++/*@}*//*IFXUSB_DBG_ROUTINE*/ ++ ++ ++#endif //__IFXUSB_PLAT_H__ ++ +diff --git a/drivers/usb/ifxhcd/ifxusb_regs.h b/drivers/usb/ifxhcd/ifxusb_regs.h +new file mode 100644 +index 0000000..014c6db +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_regs.h +@@ -0,0 +1,1420 @@ ++/***************************************************************************** ++ ** FILE NAME : ifxusb_regs.h ++ ** PROJECT : IFX USB sub-system V3 ++ ** MODULES : IFX USB sub-system Host and Device driver ++ ** SRC VERSION : 1.0 ++ ** DATE : 1/Jan/2009 ++ ** AUTHOR : Chen, Howard ++ ** DESCRIPTION : This file contains the data structures for accessing the IFXUSB core ++ ** registers. ++ ** The application interfaces with the USB core by reading from and ++ ** writing to the Control and Status Register (CSR) space through the ++ ** AHB Slave interface. These registers are 32 bits wide, and the ++ ** addresses are 32-bit-block aligned. ++ ** CSRs are classified as follows: ++ ** - Core Global Registers ++ ** - Device Mode Registers ++ ** - Device Global Registers ++ ** - Device Endpoint Specific Registers ++ ** - Host Mode Registers ++ ** - Host Global Registers ++ ** - Host Port CSRs ++ ** - Host Channel Specific Registers ++ ** ++ ** Only the Core Global registers can be accessed in both Device and ++ ** Host modes. When the USB core is operating in one mode, either ++ ** Device or Host, the application must not access registers from the ++ ** other mode. When the core switches from one mode to another, the ++ ** registers in the new mode of operation must be reprogrammed as they ++ ** would be after a power-on reset. ++ ** FUNCTIONS : ++ ** COMPILER : gcc ++ ** REFERENCE : Synopsys DWC-OTG Driver 2.7 ++ ** COPYRIGHT : ++ ** Version Control Section ** ++ ** $Author$ ++ ** $Date$ ++ ** $Revisions$ ++ ** $Log$ Revision history ++*****************************************************************************/ ++ ++ ++ ++/*! ++ \defgroup IFXUSB_CSR_DEFINITION Control and Status Register bit-map definition ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief Data structures for accessing the IFXUSB core registers. ++ The application interfaces with the USB core by reading from and ++ writing to the Control and Status Register (CSR) space through the ++ AHB Slave interface. These registers are 32 bits wide, and the ++ addresses are 32-bit-block aligned. ++ CSRs are classified as follows: ++ - Core Global Registers ++ - Device Mode Registers ++ - Device Global Registers ++ - Device Endpoint Specific Registers ++ - Host Mode Registers ++ - Host Global Registers ++ - Host Port CSRs ++ - Host Channel Specific Registers ++ ++ Only the Core Global registers can be accessed in both Device andHost modes. ++ When the USB core is operating in one mode, either Device or Host, the ++ application must not access registers from the other mode. When the core ++ switches from one mode to another, the registers in the new mode of operation ++ must be reprogrammed as they would be after a power-on reset. ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_DEVICE_GLOBAL_REG Device Mode Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Device Mode Global Registers ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_DEVICE_EP_REG Device Mode EP Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Device Mode EP Registers ++ There will be one set of endpoint registers per logical endpoint ++ implemented. ++ These registers are visible only in Device mode and must not be ++ accessed in Host mode, as the results are unknown. ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_DEVICE_DMA_DESC Device mode scatter dma descriptor strusture ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to DMA descriptor ++ */ ++ ++ ++/*! ++ \defgroup IFXUSB_CSR_HOST_GLOBAL_REG Host Mode Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Host Mode Global Registers ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_HOST_HC_REG Host Mode HC Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Host Mode Host Channel Registers ++ There will be one set of endpoint registers per host channel ++ implemented. ++ These registers are visible only in Host mode and must not be ++ accessed in Device mode, as the results are unknown. ++ */ ++ ++/*! ++ \defgroup IFXUSB_CSR_PWR_CLK_GATING_REG Power and Clock Gating Control Register ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to Power and Clock Gating Control Register ++ */ ++ ++ ++ ++ ++ ++ ++ ++ ++/*! ++ \defgroup IFXUSB_CSR_CORE_GLOBAL_REG Core Global Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Core Global Registers ++ */ ++/*! ++ \defgroup IFXUSB_CSR_CORE_GLOBAL_REG Core Global Registers ++ \ingroup IFXUSB_CSR_DEFINITION ++ \brief Bit-mapped structure to access Core Global Registers ++ */ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++/*! ++ \file ifxusb_regs.h ++ \ingroup IFXUSB_DRIVER_V3 ++ \brief This file contains the data structures for accessing the IFXUSB core registers. ++ */ ++ ++ ++#ifndef __IFXUSB_REGS_H__ ++#define __IFXUSB_REGS_H__ ++ ++/****************************************************************************/ ++ ++#define MAX_PERIO_FIFOS 15 /** Maximum number of Periodic FIFOs */ ++#define MAX_TX_FIFOS 15 /** Maximum number of Periodic FIFOs */ ++#define MAX_EPS_CHANNELS 16 /** Maximum number of Endpoints/HostChannels */ ++ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_ACCESS_MACROS ++ */ ++/*@{*/ ++ ++//#define RecordRegRW ++ ++/*! ++ \fn static __inline__ uint32_t ifxusb_rreg( volatile uint32_t *_reg) ++ \brief Reads the content of a register. ++ \param _reg address of register to read. ++ \return contents of the register. ++ */ ++static __inline__ uint32_t ifxusb_rreg( volatile uint32_t *_reg) ++{ ++ #ifdef RecordRegRW ++ uint32_t r; ++ r=*(_reg); ++ return (r); ++ #else ++ return (*(_reg)); ++ #endif ++}; ++ ++ ++/*! ++ \fn static __inline__ void ifxusb_wreg( volatile uint32_t *_reg, const uint32_t _value) ++ \brief Writes a register with a 32 bit value. ++ \param _reg address of register to write. ++ \param _value value to write to _reg. ++ */ ++static __inline__ void ifxusb_wreg( volatile uint32_t *_reg, const uint32_t _value) ++{ ++ #ifdef RecordRegRW ++ printk(KERN_INFO "[W %p<-%08X]\n",_reg,_value); ++ #else ++ *(_reg)=_value; ++ #endif ++}; ++ ++/*! ++ \fn static __inline__ void ifxusb_mreg( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) ++ \brief Modifies bit values in a register. Using the ++ algorithm: (reg_contents & ~clear_mask) | set_mask. ++ \param _reg address of register to modify. ++ \param _clear_mask bit mask to be cleared. ++ \param _set_mask bit mask to be set. ++ */ ++static __inline__ void ifxusb_mreg( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) ++{ ++ uint32_t v; ++ #ifdef RecordRegRW ++ uint32_t r; ++ v= *(_reg); ++ r=v; ++ r&=(~_clear_mask); ++ r|= _set_mask; ++ *(_reg)=r ; ++ printk(KERN_INFO "[M %p->%08X+%08X/%08X<-%08X]\n",_reg,r,_clear_mask,_set_mask,r); ++ #else ++ v= *(_reg); ++ v&=(~_clear_mask); ++ v|= _set_mask; ++ *(_reg)=v ; ++ #endif ++}; ++ ++/*@}*//*IFXUSB_CSR_ACCESS_MACROS*/ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_CORE_GLOBAL_REG ++ */ ++/*@{*/ ++ ++/*! ++ \struct ifxusb_core_global_regs ++ \brief IFXUSB Core registers . ++ The ifxusb_core_global_regs structure defines the size ++ and relative field offsets for the Core Global registers. ++ */ ++typedef struct ifxusb_core_global_regs ++{ ++ volatile uint32_t gotgctl; /*!< 000h OTG Control and Status Register. */ ++ volatile uint32_t gotgint; /*!< 004h OTG Interrupt Register. */ ++ volatile uint32_t gahbcfg; /*!< 008h Core AHB Configuration Register. */ ++ volatile uint32_t gusbcfg; /*!< 00Ch Core USB Configuration Register. */ ++ volatile uint32_t grstctl; /*!< 010h Core Reset Register. */ ++ volatile uint32_t gintsts; /*!< 014h Core Interrupt Register. */ ++ volatile uint32_t gintmsk; /*!< 018h Core Interrupt Mask Register. */ ++ volatile uint32_t grxstsr; /*!< 01Ch Receive Status Queue Read Register (Read Only). */ ++ volatile uint32_t grxstsp; /*!< 020h Receive Status Queue Read & POP Register (Read Only). */ ++ volatile uint32_t grxfsiz; /*!< 024h Receive FIFO Size Register. */ ++ volatile uint32_t gnptxfsiz; /*!< 028h Non Periodic Transmit FIFO Size Register. */ ++ volatile uint32_t gnptxsts; /*!< 02Ch Non Periodic Transmit FIFO/Queue Status Register (Read Only). */ ++ volatile uint32_t gi2cctl; /*!< 030h I2C Access Register. */ ++ volatile uint32_t gpvndctl; /*!< 034h PHY Vendor Control Register. */ ++ volatile uint32_t ggpio; /*!< 038h General Purpose Input/Output Register. */ ++ volatile uint32_t guid; /*!< 03Ch User ID Register. */ ++ volatile uint32_t gsnpsid; /*!< 040h Synopsys ID Register (Read Only). */ ++ volatile uint32_t ghwcfg1; /*!< 044h User HW Config1 Register (Read Only). */ ++ volatile uint32_t ghwcfg2; /*!< 048h User HW Config2 Register (Read Only). */ ++ volatile uint32_t ghwcfg3; /*!< 04Ch User HW Config3 Register (Read Only). */ ++ volatile uint32_t ghwcfg4; /*!< 050h User HW Config4 Register (Read Only). */ ++ volatile uint32_t reserved[43]; /*!< 054h Reserved 054h-0FFh */ ++ volatile uint32_t hptxfsiz; /*!< 100h Host Periodic Transmit FIFO Size Register. */ ++ volatile uint32_t dptxfsiz_dieptxf[15];/*!< 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15. ++ Device Periodic Transmit FIFO#n Register if dedicated ++ fifos are disabled, otherwise Device Transmit FIFO#n ++ Register. ++ */ ++} ifxusb_core_global_regs_t; ++ ++/*! ++ \brief Bits of the Core OTG Control and Status Register (GOTGCTL). ++ */ ++typedef union gotgctl_data ++{ ++ uint32_t d32; ++ struct{ ++ unsigned reserved21_31 : 11; ++ unsigned currmod : 1 ; /*!< 20 */ ++ unsigned bsesvld : 1 ; /*!< 19 */ ++ unsigned asesvld : 1 ; /*!< 18 */ ++ unsigned reserved17 : 1 ; ++ unsigned conidsts : 1 ; /*!< 16 */ ++ unsigned reserved12_15 : 4 ; ++ unsigned devhnpen : 1 ; /*!< 11 */ ++ unsigned hstsethnpen : 1 ; /*!< 10 */ ++ unsigned hnpreq : 1 ; /*!< 09 */ ++ unsigned hstnegscs : 1 ; /*!< 08 */ ++ unsigned reserved2_7 : 6 ; ++ unsigned sesreq : 1 ; /*!< 01 */ ++ unsigned sesreqscs : 1 ; /*!< 00 */ ++ } b; ++} gotgctl_data_t; ++ ++/*! ++ \brief Bit fields of the Core OTG Interrupt Register (GOTGINT). ++ */ ++typedef union gotgint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31_20 : 12; ++ unsigned debdone : 1 ; /*!< 19 Debounce Done */ ++ unsigned adevtoutchng : 1 ; /*!< 18 A-Device Timeout Change */ ++ unsigned hstnegdet : 1 ; /*!< 17 Host Negotiation Detected */ ++ unsigned reserver10_16 : 7 ; ++ unsigned hstnegsucstschng : 1 ; /*!< 09 Host Negotiation Success Status Change */ ++ unsigned sesreqsucstschng : 1 ; /*!< 08 Session Request Success Status Change */ ++ unsigned reserved3_7 : 5 ; ++ unsigned sesenddet : 1 ; /*!< 02 Session End Detected */ ++ unsigned reserved0_1 : 2 ; ++ } b; ++} gotgint_data_t; ++ ++/*! ++ \brief Bit fields of the Core AHB Configuration Register (GAHBCFG). ++ */ ++typedef union gahbcfg_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved9_31 : 23; ++ unsigned ptxfemplvl : 1 ; /*!< 08 Periodic FIFO empty level trigger condition*/ ++ unsigned nptxfemplvl : 1 ; /*!< 07 Non-Periodic FIFO empty level trigger condition*/ ++ #define IFXUSB_GAHBCFG_TXFEMPTYLVL_EMPTY 1 ++ #define IFXUSB_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 ++ unsigned reserved : 1 ; ++ unsigned dmaenable : 1 ; /*!< 05 DMA enable*/ ++ #define IFXUSB_GAHBCFG_DMAENABLE 1 ++ unsigned hburstlen : 4 ; /*!< 01-04 DMA Burst-length*/ ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE 0 ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR 1 ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4 3 ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8 5 ++ #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16 7 ++ unsigned glblintrmsk : 1 ; /*!< 00 USB Global Interrupt Enable */ ++ #define IFXUSB_GAHBCFG_GLBINT_ENABLE 1 ++ } b; ++} gahbcfg_data_t; ++ ++/*! ++ \brief Bit fields of the Core USB Configuration Register (GUSBCFG). ++*/ ++typedef union gusbcfg_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31 : 1; ++ unsigned ForceDevMode : 1; /*!< 30 Force Device Mode */ ++ unsigned ForceHstMode : 1; /*!< 29 Force Host Mode */ ++ unsigned TxEndDelay : 1; /*!< 28 Tx End Delay */ ++ unsigned reserved2723 : 5; ++ unsigned term_sel_dl_pulse : 1; /*!< 22 TermSel DLine Pulsing Selection */ ++ unsigned reserved2117 : 5; ++ unsigned otgutmifssel : 1; /*!< 16 UTMIFS Select */ ++ unsigned phylpwrclksel : 1; /*!< 15 PHY Low-Power Clock Select */ ++ unsigned reserved14 : 1; ++ unsigned usbtrdtim : 4; /*!< 13-10 USB Turnaround Time */ ++ unsigned hnpcap : 1; /*!< 09 HNP-Capable */ ++ unsigned srpcap : 1; /*!< 08 SRP-Capable */ ++ unsigned reserved07 : 1; ++ unsigned physel : 1; /*!< 06 USB 2.0 High-Speed PHY or ++ USB 1.1 Full-Speed Serial ++ Transceiver Select */ ++ unsigned fsintf : 1; /*!< 05 Full-Speed Serial Interface Select */ ++ unsigned ulpi_utmi_sel : 1; /*!< 04 ULPI or UTMI+ Select */ ++ unsigned phyif : 1; /*!< 03 PHY Interface */ ++ unsigned toutcal : 3; /*!< 00-02 HS/FS Timeout Calibration */ ++ }b; ++} gusbcfg_data_t; ++ ++/*! ++ \brief Bit fields of the Core Reset Register (GRSTCTL). ++ */ ++typedef union grstctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned ahbidle : 1; /*!< 31 AHB Master Idle. Indicates the AHB Master State ++ Machine is in IDLE condition. */ ++ unsigned dmareq : 1; /*!< 30 DMA Request Signal. Indicated DMA request is in ++ probress. Used for debug purpose. */ ++ unsigned reserved11_29 :19; ++ unsigned txfnum : 5; /*!< 10-06 TxFIFO Number (TxFNum) to be flushed. ++ 0x00: Non Periodic TxFIFO Flush or TxFIFO 0 ++ 0x01-0x0F: Periodic TxFIFO Flush or TxFIFO n ++ 0x10: Flush all TxFIFO ++ */ ++ unsigned txfflsh : 1; /*!< 05 TxFIFO Flush */ ++ unsigned rxfflsh : 1; /*!< 04 RxFIFO Flush */ ++ unsigned intknqflsh : 1; /*!< 03 In Token Sequence Learning Queue Flush (Device Only) */ ++ unsigned hstfrm : 1; /*!< 02 Host Frame Counter Reset (Host Only) */ ++ unsigned hsftrst : 1; /*!< 01 Hclk Soft Reset */ ++ ++ unsigned csftrst : 1; /*!< 00 Core Soft Reset ++ The application can flush the control logic in the ++ entire core using this bit. This bit resets the ++ pipelines in the AHB Clock domain as well as the ++ PHY Clock domain. ++ The state machines are reset to an IDLE state, the ++ control bits in the CSRs are cleared, all the ++ transmit FIFOs and the receive FIFO are flushed. ++ The status mask bits that control the generation of ++ the interrupt, are cleared, to clear the ++ interrupt. The interrupt status bits are not ++ cleared, so the application can get the status of ++ any events that occurred in the core after it has ++ set this bit. ++ Any transactions on the AHB are terminated as soon ++ as possible following the protocol. Any ++ transactions on the USB are terminated immediately. ++ The configuration settings in the CSRs are ++ unchanged, so the software doesn't have to ++ reprogram these registers (Device ++ Configuration/Host Configuration/Core System ++ Configuration/Core PHY Configuration). ++ The application can write to this bit, any time it ++ wants to reset the core. This is a self clearing ++ bit and the core clears this bit after all the ++ necessary logic is reset in the core, which may ++ take several clocks, depending on the current state ++ of the core. ++ */ ++ }b; ++} grstctl_t; ++ ++/*! ++ \brief Bit fields of the Core Interrupt Mask Register (GINTMSK) and ++ Core Interrupt Register (GINTSTS). ++ */ ++typedef union gint_data ++{ ++ uint32_t d32; ++ #define IFXUSB_SOF_INTR_MASK 0x0008 ++ struct ++ { ++ unsigned wkupintr : 1; /*!< 31 Resume/Remote Wakeup Detected Interrupt */ ++ unsigned sessreqintr : 1; /*!< 30 Session Request/New Session Detected Interrupt */ ++ unsigned disconnect : 1; /*!< 29 Disconnect Detected Interrupt */ ++ unsigned conidstschng : 1; /*!< 28 Connector ID Status Change */ ++ unsigned reserved27 : 1; ++ unsigned ptxfempty : 1; /*!< 26 Periodic TxFIFO Empty */ ++ unsigned hcintr : 1; /*!< 25 Host Channels Interrupt */ ++ unsigned portintr : 1; /*!< 24 Host Port Interrupt */ ++ unsigned reserved23 : 1; ++ unsigned fetsuspmsk : 1; /*!< 22 Data Fetch Suspended */ ++ unsigned incomplisoout : 1; /*!< 21 Incomplete IsochronousOUT/Period Transfer */ ++ unsigned incomplisoin : 1; /*!< 20 Incomplete Isochronous IN Transfer */ ++ unsigned outepintr : 1; /*!< 19 OUT Endpoints Interrupt */ ++ unsigned inepintr : 1; /*!< 18 IN Endpoints Interrupt */ ++ unsigned epmismatch : 1; /*!< 17 Endpoint Mismatch Interrupt */ ++ unsigned reserved16 : 1; ++ unsigned eopframe : 1; /*!< 15 End of Periodic Frame Interrupt */ ++ unsigned isooutdrop : 1; /*!< 14 Isochronous OUT Packet Dropped Interrupt */ ++ unsigned enumdone : 1; /*!< 13 Enumeration Done */ ++ unsigned usbreset : 1; /*!< 12 USB Reset */ ++ unsigned usbsuspend : 1; /*!< 11 USB Suspend */ ++ unsigned erlysuspend : 1; /*!< 10 Early Suspend */ ++ unsigned i2cintr : 1; /*!< 09 I2C Interrupt */ ++ unsigned reserved8 : 1; ++ unsigned goutnakeff : 1; /*!< 07 Global OUT NAK Effective */ ++ unsigned ginnakeff : 1; /*!< 06 Global Non-periodic IN NAK Effective */ ++ unsigned nptxfempty : 1; /*!< 05 Non-periodic TxFIFO Empty */ ++ unsigned rxstsqlvl : 1; /*!< 04 Receive FIFO Non-Empty */ ++ unsigned sofintr : 1; /*!< 03 Start of (u)Frame */ ++ unsigned otgintr : 1; /*!< 02 OTG Interrupt */ ++ unsigned modemismatch : 1; /*!< 01 Mode Mismatch Interrupt */ ++ unsigned reserved0 : 1; ++ } b; ++} gint_data_t; ++ ++/*! ++ \brief Bit fields in the Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) ++ */ ++typedef union grxsts_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 7; ++ unsigned fn : 4; /*!< 24-21 Frame Number */ ++ unsigned pktsts : 4; /*!< 20-17 Packet Status */ ++ #define IFXUSB_DSTS_DATA_UPDT 0x2 // OUT Data Packet ++ #define IFXUSB_DSTS_XFER_COMP 0x3 // OUT Data Transfer Complete ++ #define IFXUSB_DSTS_GOUT_NAK 0x1 // Global OUT NAK ++ #define IFXUSB_DSTS_SETUP_COMP 0x4 // Setup Phase Complete ++ #define IFXUSB_DSTS_SETUP_UPDT 0x6 // SETUP Packet ++ unsigned dpid : 2; /*!< 16-15 Data PID */ ++ unsigned bcnt :11; /*!< 14-04 Byte Count */ ++ unsigned epnum : 4; /*!< 03-00 Endpoint Number */ ++ } db; ++ struct ++ { ++ unsigned reserved :11; ++ unsigned pktsts : 4; /*!< 20-17 Packet Status */ ++ #define IFXUSB_HSTS_DATA_UPDT 0x2 // OUT Data Packet ++ #define IFXUSB_HSTS_XFER_COMP 0x3 // OUT Data Transfer Complete ++ #define IFXUSB_HSTS_DATA_TOGGLE_ERR 0x5 // DATA TOGGLE Error ++ #define IFXUSB_HSTS_CH_HALTED 0x7 // Channel Halted ++ unsigned dpid : 2; /*!< 16-15 Data PID */ ++ unsigned bcnt :11; /*!< 14-04 Byte Count */ ++ unsigned chnum : 4; /*!< 03-00 Channel Number */ ++ } hb; ++} grxsts_data_t; ++ ++/*! ++ \brief Bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn). ++ */ ++typedef union fifosize_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned depth : 16; /*!< 31-16 TxFIFO Depth (in DWord)*/ ++ unsigned startaddr : 16; /*!< 15-00 RAM Starting address */ ++ } b; ++} fifosize_data_t; ++ ++/*! ++ \brief Bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS). ++ */ ++ ++typedef union gnptxsts_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 1; ++ unsigned nptxqtop_chnep : 4; /*!< 30-27 Channel/EP Number of top of the Non-Periodic ++ Transmit Request Queue ++ */ ++ unsigned nptxqtop_token : 2; /*!< 26-25 Token Type top of the Non-Periodic ++ Transmit Request Queue ++ 0 - IN/OUT ++ 1 - Zero Length OUT ++ 2 - PING/Complete Split ++ 3 - Channel Halt ++ */ ++ unsigned nptxqtop_terminate : 1; /*!< 24 Terminate (Last entry for the selected ++ channel/EP)*/ ++ unsigned nptxqspcavail : 8; /*!< 23-16 Transmit Request Queue Space Available */ ++ unsigned nptxfspcavail :16; /*!< 15-00 TxFIFO Space Avail (in DWord)*/ ++ }b; ++} gnptxsts_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Transmit FIFO Status Register (DTXFSTS). ++ */ ++typedef union dtxfsts_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 16; ++ unsigned txfspcavail : 16; /*!< 15-00 TxFIFO Space Avail (in DWord)*/ ++ }b; ++} dtxfsts_data_t; ++ ++ ++/*! ++ \brief Bit fields in the I2C Control Register (I2CCTL). ++ */ ++typedef union gi2cctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned bsydne : 1; /*!< 31 I2C Busy/Done*/ ++ unsigned rw : 1; /*!< 30 Read/Write Indicator */ ++ unsigned reserved : 2; ++ unsigned i2cdevaddr : 2; /*!< 27-26 I2C Device Address */ ++ unsigned i2csuspctl : 1; /*!< 25 I2C Suspend Control */ ++ unsigned ack : 1; /*!< 24 I2C ACK */ ++ unsigned i2cen : 1; /*!< 23 I2C Enable */ ++ unsigned addr : 7; /*!< 22-16 I2C Address */ ++ unsigned regaddr : 8; /*!< 15-08 I2C Register Addr */ ++ unsigned rwdata : 8; /*!< I2C Read/Write Data */ ++ } b; ++} gi2cctl_data_t; ++ ++ ++/*! ++ \brief Bit fields in the User HW Config1 Register. ++ */ ++typedef union hwcfg1_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned ep_dir15 : 2; /*!< Direction of each EP ++ 0: BIDIR (IN and OUT) endpoint ++ 1: IN endpoint ++ 2: OUT endpoint ++ 3: Reserved ++ */ ++ unsigned ep_dir14 : 2; ++ unsigned ep_dir13 : 2; ++ unsigned ep_dir12 : 2; ++ unsigned ep_dir11 : 2; ++ unsigned ep_dir10 : 2; ++ unsigned ep_dir09 : 2; ++ unsigned ep_dir08 : 2; ++ unsigned ep_dir07 : 2; ++ unsigned ep_dir06 : 2; ++ unsigned ep_dir05 : 2; ++ unsigned ep_dir04 : 2; ++ unsigned ep_dir03 : 2; ++ unsigned ep_dir02 : 2; ++ unsigned ep_dir01 : 2; ++ unsigned ep_dir00 : 2; ++ }b; ++} hwcfg1_data_t; ++ ++/*! ++ \brief Bit fields in the User HW Config2 Register. ++ */ ++typedef union hwcfg2_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31 : 1; ++ unsigned dev_token_q_depth : 5; /*!< 30-26 Device Mode IN Token Sequence Learning Queue Depth */ ++ unsigned host_perio_tx_q_depth : 2; /*!< 25-24 Host Mode Periodic Request Queue Depth */ ++ unsigned nonperio_tx_q_depth : 2; /*!< 23-22 Non-periodic Request Queue Depth */ ++ unsigned rx_status_q_depth : 2; /*!< 21-20 Multi Processor Interrupt Enabled */ ++ unsigned dynamic_fifo : 1; /*!< 19 Dynamic FIFO Sizing Enabled */ ++ unsigned perio_ep_supported : 1; /*!< 18 Periodic OUT Channels Supported in Host Mode */ ++ unsigned num_host_chan : 4; /*!< 17-14 Number of Host Channels */ ++ unsigned num_dev_ep : 4; /*!< 13-10 Number of Device Endpoints */ ++ unsigned fs_phy_type : 2; /*!< 09-08 Full-Speed PHY Interface Type */ ++ #define IFXUSB_HWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0 ++ #define IFXUSB_HWCFG2_FS_PHY_TYPE_DEDICATE 1 ++ #define IFXUSB_HWCFG2_FS_PHY_TYPE_UTMI 2 ++ #define IFXUSB_HWCFG2_FS_PHY_TYPE_ULPI 3 ++ unsigned hs_phy_type : 2; /*!< 07-06 High-Speed PHY Interface Type */ ++ #define IFXUSB_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 ++ #define IFXUSB_HWCFG2_HS_PHY_TYPE_UTMI 1 ++ #define IFXUSB_HWCFG2_HS_PHY_TYPE_ULPI 2 ++ #define IFXUSB_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 ++ unsigned point2point : 1; /*!< 05 Point-to-Point */ ++ unsigned architecture : 2; /*!< 04-03 Architecture */ ++ #define IFXUSB_HWCFG2_ARCH_SLAVE_ONLY 0 ++ #define IFXUSB_HWCFG2_ARCH_EXT_DMA 1 ++ #define IFXUSB_HWCFG2_ARCH_INT_DMA 2 ++ unsigned op_mode : 3; /*!< 02-00 Mode of Operation */ ++ #define IFXUSB_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 ++ #define IFXUSB_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 ++ #define IFXUSB_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 ++ #define IFXUSB_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 ++ #define IFXUSB_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 ++ #define IFXUSB_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 ++ #define IFXUSB_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 ++ } b; ++} hwcfg2_data_t; ++ ++/*! ++ \brief Bit fields in the User HW Config3 Register. ++ */ ++typedef union hwcfg3_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned dfifo_depth :16; /*!< 31-16 DFIFO Depth */ ++ unsigned reserved15_12 : 4; ++ unsigned synch_reset_type : 1; /*!< 11 Reset Style for Clocked always Blocks in RTL */ ++ unsigned optional_features : 1; /*!< 10 Optional Features Removed */ ++ unsigned vendor_ctrl_if : 1; /*!< 09 Vendor Control Interface Support */ ++ unsigned i2c : 1; /*!< 08 I2C Selection */ ++ unsigned otg_func : 1; /*!< 07 OTG Function Enabled */ ++ unsigned packet_size_cntr_width : 3; /*!< 06-04 Width of Packet Size Counters */ ++ unsigned xfer_size_cntr_width : 4; /*!< 03-00 Width of Transfer Size Counters */ ++ } b; ++} hwcfg3_data_t; ++ ++/*! ++ \brief Bit fields in the User HW Config4 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg4_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned desc_dma_dyn : 1; /*!< 31 Scatter/Gather DMA */ ++ unsigned desc_dma : 1; /*!< 30 Scatter/Gather DMA configuration */ ++ unsigned num_in_eps : 4; /*!< 29-26 Number of Device Mode IN Endpoints Including Control Endpoints */ ++ unsigned ded_fifo_en : 1; /*!< 25 Enable Dedicated Transmit FIFO for device IN Endpoints */ ++ unsigned session_end_filt_en : 1; /*!< 24 session_end Filter Enabled */ ++ unsigned b_valid_filt_en : 1; /*!< 23 b_valid Filter Enabled */ ++ unsigned a_valid_filt_en : 1; /*!< 22 a_valid Filter Enabled */ ++ unsigned vbus_valid_filt_en : 1; /*!< 21 vbus_valid Filter Enabled */ ++ unsigned iddig_filt_en : 1; /*!< 20 iddig Filter Enable */ ++ unsigned num_dev_mode_ctrl_ep : 4; /*!< 19-16 Number of Device Mode Control Endpoints in Addition to Endpoint 0 */ ++ unsigned utmi_phy_data_width : 2; /*!< 15-14 UTMI+ PHY/ULPI-to-Internal UTMI+ Wrapper Data Width */ ++ unsigned reserved13_06 : 8; ++ unsigned min_ahb_freq : 1; /*!< 05 Minimum AHB Frequency Less Than 60 MHz */ ++ unsigned power_optimiz : 1; /*!< 04 Enable Power Optimization? */ ++ unsigned num_dev_perio_in_ep : 4; /*!< 03-00 Number of Device Mode Periodic IN Endpoints */ ++ } b; ++} hwcfg4_data_t; ++ ++/*@}*//*IFXUSB_CSR_CORE_GLOBAL_REG*/ ++ ++/****************************************************************************/ ++/*! ++ \addtogroup IFXUSB_CSR_DEVICE_GLOBAL_REG ++ */ ++/*@{*/ ++ ++/*! ++ \struct ifxusb_dev_global_regs ++ \brief IFXUSB Device Mode Global registers. Offsets 800h-BFFh ++ The ifxusb_dev_global_regs structure defines the size ++ and relative field offsets for the Device Global registers. ++ These registers are visible only in Device mode and must not be ++ accessed in Host mode, as the results are unknown. ++ */ ++typedef struct ifxusb_dev_global_regs ++{ ++ volatile uint32_t dcfg; /*!< 800h Device Configuration Register. */ ++ volatile uint32_t dctl; /*!< 804h Device Control Register. */ ++ volatile uint32_t dsts; /*!< 808h Device Status Register (Read Only). */ ++ uint32_t unused; ++ volatile uint32_t diepmsk; /*!< 810h Device IN Endpoint Common Interrupt Mask Register. */ ++ volatile uint32_t doepmsk; /*!< 814h Device OUT Endpoint Common Interrupt Mask Register. */ ++ volatile uint32_t daint; /*!< 818h Device All Endpoints Interrupt Register. */ ++ volatile uint32_t daintmsk; /*!< 81Ch Device All Endpoints Interrupt Mask Register. */ ++ volatile uint32_t dtknqr1; /*!< 820h Device IN Token Queue Read Register-1 (Read Only). */ ++ volatile uint32_t dtknqr2; /*!< 824h Device IN Token Queue Read Register-2 (Read Only). */ ++ volatile uint32_t dvbusdis; /*!< 828h Device VBUS discharge Register.*/ ++ volatile uint32_t dvbuspulse; /*!< 82Ch Device VBUS Pulse Register. */ ++ volatile uint32_t dtknqr3_dthrctl; /*!< 830h Device IN Token Queue Read Register-3 (Read Only). ++ Device Thresholding control register (Read/Write) ++ */ ++ volatile uint32_t dtknqr4_fifoemptymsk; /*!< 834h Device IN Token Queue Read Register-4 (Read Only). ++ Device IN EPs empty Inr. Mask Register (Read/Write) ++ */ ++} ifxusb_device_global_regs_t; ++ ++/*! ++ \brief Bit fields in the Device Configuration Register. ++ */ ++ ++typedef union dcfg_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31_26 : 6; ++ unsigned perschintvl : 2; /*!< 25-24 Periodic Scheduling Interval */ ++ unsigned descdma : 1; /*!< 23 Enable Descriptor DMA in Device mode */ ++ unsigned epmscnt : 5; /*!< 22-18 In Endpoint Mis-match count */ ++ unsigned reserved13_17 : 5; ++ unsigned perfrint : 2; /*!< 12-11 Periodic Frame Interval */ ++ #define IFXUSB_DCFG_FRAME_INTERVAL_80 0 ++ #define IFXUSB_DCFG_FRAME_INTERVAL_85 1 ++ #define IFXUSB_DCFG_FRAME_INTERVAL_90 2 ++ #define IFXUSB_DCFG_FRAME_INTERVAL_95 3 ++ unsigned devaddr : 7; /*!< 10-04 Device Addresses */ ++ unsigned reserved3 : 1; ++ unsigned nzstsouthshk : 1; /*!< 02 Non Zero Length Status OUT Handshake */ ++ #define IFXUSB_DCFG_SEND_STALL 1 ++ unsigned devspd : 2; /*!< 01-00 Device Speed */ ++ } b; ++} dcfg_data_t; ++ ++/*! ++ \brief Bit fields in the Device Control Register. ++ */ ++typedef union dctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved16_31 :16; ++ unsigned ifrmnum : 1; /*!< 15 Ignore Frame Number for ISOC EPs */ ++ unsigned gmc : 2; /*!< 14-13 Global Multi Count */ ++ unsigned gcontbna : 1; /*!< 12 Global Continue on BNA */ ++ unsigned pwronprgdone : 1; /*!< 11 Power-On Programming Done */ ++ unsigned cgoutnak : 1; /*!< 10 Clear Global OUT NAK */ ++ unsigned sgoutnak : 1; /*!< 09 Set Global OUT NAK */ ++ unsigned cgnpinnak : 1; /*!< 08 Clear Global Non-Periodic IN NAK */ ++ unsigned sgnpinnak : 1; /*!< 07 Set Global Non-Periodic IN NAK */ ++ unsigned tstctl : 3; /*!< 06-04 Test Control */ ++ unsigned goutnaksts : 1; /*!< 03 Global OUT NAK Status */ ++ unsigned gnpinnaksts : 1; /*!< 02 Global Non-Periodic IN NAK Status */ ++ unsigned sftdiscon : 1; /*!< 01 Soft Disconnect */ ++ unsigned rmtwkupsig : 1; /*!< 00 Remote Wakeup */ ++ } b; ++} dctl_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device Status Register. ++ */ ++typedef union dsts_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved22_31 :10; ++ unsigned soffn :14; /*!< 21-08 Frame or Microframe Number of the received SOF */ ++ unsigned reserved4_7 : 4; ++ unsigned errticerr : 1; /*!< 03 Erratic Error */ ++ unsigned enumspd : 2; /*!< 02-01 Enumerated Speed */ ++ #define IFXUSB_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 ++ #define IFXUSB_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 ++ #define IFXUSB_DSTS_ENUMSPD_LS_PHY_6MHZ 2 ++ #define IFXUSB_DSTS_ENUMSPD_FS_PHY_48MHZ 3 ++ unsigned suspsts : 1; /*!< 00 Suspend Status */ ++ } b; ++} dsts_data_t; ++ ++/*! ++ \brief Bit fields in the Device IN EP Interrupt Register ++ and the Device IN EP Common Mask Register. ++ */ ++typedef union diepint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved14_31 :18; ++ unsigned nakmsk : 1; /*!< 13 NAK interrupt Mask */ ++ unsigned reserved10_12 : 3; ++ unsigned bna : 1; /*!< 09 BNA Interrupt mask */ ++ unsigned txfifoundrn : 1; /*!< 08 Fifo Underrun Mask */ ++ unsigned emptyintr : 1; /*!< 07 IN Endpoint HAK Effective mask */ ++ unsigned inepnakeff : 1; /*!< 06 IN Endpoint HAK Effective mask */ ++ unsigned intknepmis : 1; /*!< 05 IN Token Received with EP mismatch mask */ ++ unsigned intktxfemp : 1; /*!< 04 IN Token received with TxF Empty mask */ ++ unsigned timeout : 1; /*!< 03 TimeOUT Handshake mask (non-ISOC EPs) */ ++ unsigned ahberr : 1; /*!< 02 AHB Error mask */ ++ unsigned epdisabled : 1; /*!< 01 Endpoint disable mask */ ++ unsigned xfercompl : 1; /*!< 00 Transfer complete mask */ ++ } b; ++} diepint_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device OUT EP Interrupt Register and ++ Device OUT EP Common Interrupt Mask Register. ++ */ ++typedef union doepint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved15_31 :17; ++ unsigned nyetmsk : 1; /*!< 14 NYET Interrupt */ ++ unsigned nakmsk : 1; /*!< 13 NAK Interrupt */ ++ unsigned bbleerrmsk : 1; /*!< 12 Babble Interrupt */ ++ unsigned reserved10_11 : 2; ++ unsigned bna : 1; /*!< 09 BNA Interrupt */ ++ unsigned outpkterr : 1; /*!< 08 OUT packet Error */ ++ unsigned reserved07 : 1; ++ unsigned back2backsetup : 1; /*!< 06 Back-to-Back SETUP Packets Received */ ++ unsigned stsphsercvd : 1; /*!< 05 */ ++ unsigned outtknepdis : 1; /*!< 04 OUT Token Received when Endpoint Disabled */ ++ unsigned setup : 1; /*!< 03 Setup Phase Done (contorl EPs) */ ++ unsigned ahberr : 1; /*!< 02 AHB Error */ ++ unsigned epdisabled : 1; /*!< 01 Endpoint disable */ ++ unsigned xfercompl : 1; /*!< 00 Transfer complete */ ++ } b; ++} doepint_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device All EP Interrupt Registers. ++ */ ++typedef union daint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned out : 16; /*!< 31-16 OUT Endpoint bits */ ++ unsigned in : 16; /*!< 15-00 IN Endpoint bits */ ++ } eps; ++ struct ++ { ++ /** OUT Endpoint bits */ ++ unsigned outep15 : 1; ++ unsigned outep14 : 1; ++ unsigned outep13 : 1; ++ unsigned outep12 : 1; ++ unsigned outep11 : 1; ++ unsigned outep10 : 1; ++ unsigned outep09 : 1; ++ unsigned outep08 : 1; ++ unsigned outep07 : 1; ++ unsigned outep06 : 1; ++ unsigned outep05 : 1; ++ unsigned outep04 : 1; ++ unsigned outep03 : 1; ++ unsigned outep02 : 1; ++ unsigned outep01 : 1; ++ unsigned outep00 : 1; ++ /** IN Endpoint bits */ ++ unsigned inep15 : 1; ++ unsigned inep14 : 1; ++ unsigned inep13 : 1; ++ unsigned inep12 : 1; ++ unsigned inep11 : 1; ++ unsigned inep10 : 1; ++ unsigned inep09 : 1; ++ unsigned inep08 : 1; ++ unsigned inep07 : 1; ++ unsigned inep06 : 1; ++ unsigned inep05 : 1; ++ unsigned inep04 : 1; ++ unsigned inep03 : 1; ++ unsigned inep02 : 1; ++ unsigned inep01 : 1; ++ unsigned inep00 : 1; ++ } ep; ++} daint_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device IN Token Queue Read Registers. ++ */ ++typedef union dtknq1_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned epnums0_5 :24; /*!< 31-08 EP Numbers of IN Tokens 0 ... 4 */ ++ unsigned wrap_bit : 1; /*!< 07 write pointer has wrapped */ ++ unsigned reserved05_06 : 2; ++ unsigned intknwptr : 5; /*!< 04-00 In Token Queue Write Pointer */ ++ }b; ++} dtknq1_data_t; ++ ++ ++/*! ++ \brief Bit fields in Threshold control Register ++ */ ++typedef union dthrctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved26_31 : 6; ++ unsigned rx_thr_len : 9; /*!< 25-17 Rx Thr. Length */ ++ unsigned rx_thr_en : 1; /*!< 16 Rx Thr. Enable */ ++ unsigned reserved11_15 : 5; ++ unsigned tx_thr_len : 9; /*!< 10-02 Tx Thr. Length */ ++ unsigned iso_thr_en : 1; /*!< 01 ISO Tx Thr. Enable */ ++ unsigned non_iso_thr_en : 1; /*!< 00 non ISO Tx Thr. Enable */ ++ } b; ++} dthrctl_data_t; ++ ++/*@}*//*IFXUSB_CSR_DEVICE_GLOBAL_REG*/ ++ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_DEVICE_EP_REG ++ */ ++/*@{*/ ++ ++/*! ++ \struct ifxusb_dev_in_ep_regs ++ \brief Device Logical IN Endpoint-Specific Registers. ++ There will be one set of endpoint registers per logical endpoint ++ implemented. ++ each EP's IN EP Register are offset at : ++ 900h + * (ep_num * 20h) ++ */ ++ ++typedef struct ifxusb_dev_in_ep_regs ++{ ++ volatile uint32_t diepctl; /*!< 00h: Endpoint Control Register */ ++ uint32_t reserved04; /*!< 04h: */ ++ volatile uint32_t diepint; /*!< 08h: Endpoint Interrupt Register */ ++ uint32_t reserved0C; /*!< 0Ch: */ ++ volatile uint32_t dieptsiz; /*!< 10h: Endpoint Transfer Size Register.*/ ++ volatile uint32_t diepdma; /*!< 14h: Endpoint DMA Address Register. */ ++ volatile uint32_t dtxfsts; /*!< 18h: Endpoint Transmit FIFO Status Register. */ ++ volatile uint32_t diepdmab; /*!< 1Ch: Endpoint DMA Buffer Register. */ ++} ifxusb_dev_in_ep_regs_t; ++ ++/*! ++ \brief Device Logical OUT Endpoint-Specific Registers. ++ There will be one set of endpoint registers per logical endpoint ++ implemented. ++ each EP's OUT EP Register are offset at : ++ B00h + * (ep_num * 20h) + 00h ++ */ ++typedef struct ifxusb_dev_out_ep_regs ++{ ++ volatile uint32_t doepctl; /*!< 00h: Endpoint Control Register */ ++ volatile uint32_t doepfn; /*!< 04h: Endpoint Frame number Register */ ++ volatile uint32_t doepint; /*!< 08h: Endpoint Interrupt Register */ ++ uint32_t reserved0C; /*!< 0Ch: */ ++ volatile uint32_t doeptsiz; /*!< 10h: Endpoint Transfer Size Register.*/ ++ volatile uint32_t doepdma; /*!< 14h: Endpoint DMA Address Register. */ ++ uint32_t reserved18; /*!< 18h: */ ++ volatile uint32_t doepdmab; /*!< 1Ch: Endpoint DMA Buffer Register. */ ++} ifxusb_dev_out_ep_regs_t; ++ ++ ++/*! ++ \brief Bit fields in the Device EP Control ++ Register. ++ */ ++typedef union depctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned epena : 1; /*!< 31 Endpoint Enable */ ++ unsigned epdis : 1; /*!< 30 Endpoint Disable */ ++ unsigned setd1pid : 1; /*!< 29 Set DATA1 PID (INTR/Bulk IN and OUT endpoints) */ ++ unsigned setd0pid : 1; /*!< 28 Set DATA0 PID (INTR/Bulk IN and OUT endpoints) */ ++ unsigned snak : 1; /*!< 27 Set NAK */ ++ unsigned cnak : 1; /*!< 26 Clear NAK */ ++ unsigned txfnum : 4; /*!< 25-22 Tx Fifo Number */ ++ unsigned stall : 1; /*!< 21 Stall Handshake */ ++ unsigned snp : 1; /*!< 20 Snoop Mode */ ++ unsigned eptype : 2; /*!< 19-18 Endpoint Type ++ 0: Control ++ 1: Isochronous ++ 2: Bulk ++ 3: Interrupt ++ */ ++ unsigned naksts : 1; /*!< 17 NAK Status */ ++ unsigned dpid : 1; /*!< 16 Endpoint DPID (INTR/Bulk IN and OUT endpoints) */ ++ unsigned usbactep : 1; /*!< 15 USB Active Endpoint */ ++ unsigned nextep : 4; /*!< 14-11 Next Endpoint */ ++ unsigned mps :11; /*!< 10-00 Maximum Packet Size */ ++ #define IFXUSB_DEP0CTL_MPS_64 0 ++ #define IFXUSB_DEP0CTL_MPS_32 1 ++ #define IFXUSB_DEP0CTL_MPS_16 2 ++ #define IFXUSB_DEP0CTL_MPS_8 3 ++ } b; ++} depctl_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Device EP Transfer Size Register. (EP0 and EPn) ++ */ ++typedef union deptsiz_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31 : 1; ++ unsigned supcnt : 2; /*!< 30-29 Setup Packet Count */ ++ unsigned reserved20_28 : 9; ++ unsigned pktcnt : 1; /*!< 19 Packet Count */ ++ unsigned reserved7_18 :12; ++ unsigned xfersize : 7; /*!< 06-00 Transfer size */ ++ }b0; ++ struct ++ { ++ unsigned reserved : 1; ++ unsigned mc : 2; /*!< 30-29 Multi Count */ ++ unsigned pktcnt :10; /*!< 28-19 Packet Count */ ++ unsigned xfersize :19; /*!< 18-00 Transfer size */ ++ } b; ++} deptsiz_data_t; ++ ++/*@}*//*IFXUSB_CSR_DEVICE_EP_REG*/ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_DEVICE_DMA_DESC ++ */ ++/*@{*/ ++/*! ++ \struct desc_sts_data ++ \brief Bit fields in the DMA Descriptor status quadlet. ++ */ ++typedef union desc_sts_data ++{ ++ struct ++ { ++ unsigned bs : 2; /*!< 31-30 Buffer Status */ ++ #define BS_HOST_READY 0x0 ++ #define BS_DMA_BUSY 0x1 ++ #define BS_DMA_DONE 0x2 ++ #define BS_HOST_BUSY 0x3 ++ unsigned sts : 2; /*!< 29-28 Receive/Trasmit Status */ ++ #define RTS_SUCCESS 0x0 ++ #define RTS_BUFFLUSH 0x1 ++ #define RTS_RESERVED 0x2 ++ #define RTS_BUFERR 0x3 ++ unsigned l : 1; /*!< 27 Last */ ++ unsigned sp : 1; /*!< 26 Short Packet */ ++ unsigned ioc : 1; /*!< 25 Interrupt On Complete */ ++ unsigned sr : 1; /*!< 24 Setup Packet received */ ++ unsigned mtrf : 1; /*!< 23 Multiple Transfer */ ++ unsigned reserved16_22 : 7; ++ unsigned bytes :16; /*!< 15-00 Transfer size in bytes */ ++ } b; ++ uint32_t d32; /*!< DMA Descriptor data buffer pointer */ ++} desc_sts_data_t; ++ ++/*@}*//*IFXUSB_CSR_DEVICE_DMA_DESC*/ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_HOST_GLOBAL_REG ++ */ ++/*@{*/ ++/*! ++ \struct ifxusb_host_global_regs ++ \brief IFXUSB Host Mode Global registers. Offsets 400h-7FFh ++ The ifxusb_host_global_regs structure defines the size ++ and relative field offsets for the Host Global registers. ++ These registers are visible only in Host mode and must not be ++ accessed in Device mode, as the results are unknown. ++ */ ++typedef struct ifxusb_host_global_regs ++{ ++ volatile uint32_t hcfg; /*!< 400h Host Configuration Register. */ ++ volatile uint32_t hfir; /*!< 404h Host Frame Interval Register. */ ++ volatile uint32_t hfnum; /*!< 408h Host Frame Number / Frame Remaining Register. */ ++ uint32_t reserved40C; ++ volatile uint32_t hptxsts; /*!< 410h Host Periodic Transmit FIFO/ Queue Status Register. */ ++ volatile uint32_t haint; /*!< 414h Host All Channels Interrupt Register. */ ++ volatile uint32_t haintmsk; /*!< 418h Host All Channels Interrupt Mask Register. */ ++} ifxusb_host_global_regs_t; ++ ++/*! ++ \brief Bit fields in the Host Configuration Register. ++ */ ++typedef union hcfg_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved31_03 :29; ++ unsigned fslssupp : 1; /*!< 02 FS/LS Only Support */ ++ unsigned fslspclksel : 2; /*!< 01-00 FS/LS Phy Clock Select */ ++ #define IFXUSB_HCFG_30_60_MHZ 0 ++ #define IFXUSB_HCFG_48_MHZ 1 ++ #define IFXUSB_HCFG_6_MHZ 2 ++ } b; ++} hcfg_data_t; ++ ++/*! ++ \brief Bit fields in the Host Frame Interval Register. ++ */ ++typedef union hfir_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 16; ++ unsigned frint : 16; /*!< 15-00 Frame Interval */ ++ } b; ++} hfir_data_t; ++ ++/*! ++ \brief Bit fields in the Host Frame Time Remaing/Number Register. ++ */ ++typedef union hfnum_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned frrem : 16; /*!< 31-16 Frame Time Remaining */ ++ unsigned frnum : 16; /*!< 15-00 Frame Number*/ ++ #define IFXUSB_HFNUM_MAX_FRNUM 0x3FFF ++ } b; ++} hfnum_data_t; ++ ++/*! ++ \brief Bit fields in the Host Periodic Transmit FIFO/Queue Status Register ++ */ ++typedef union hptxsts_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ struct ++ { ++ /** Top of the Periodic Transmit Request Queue ++ * - bit 24 - Terminate (last entry for the selected channel) ++ */ ++ unsigned ptxqtop_odd : 1; /*!< 31 Top of the Periodic Transmit Request ++ Queue Odd/even microframe*/ ++ unsigned ptxqtop_chnum : 4; /*!< 30-27 Top of the Periodic Transmit Request ++ Channel Number */ ++ unsigned ptxqtop_token : 2; /*!< 26-25 Top of the Periodic Transmit Request ++ Token Type ++ 0 - Zero length ++ 1 - Ping ++ 2 - Disable ++ */ ++ unsigned ptxqtop_terminate : 1; /*!< 24 Top of the Periodic Transmit Request ++ Terminate (last entry for the selected channel)*/ ++ unsigned ptxqspcavail : 8; /*!< 23-16 Periodic Transmit Request Queue Space Available */ ++ unsigned ptxfspcavail :16; /*!< 15-00 Periodic Transmit Data FIFO Space Available */ ++ } b; ++} hptxsts_data_t; ++ ++/*! ++ \brief Bit fields in the Host Port Control and Status Register. ++ */ ++typedef union hprt0_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved19_31 :13; ++ unsigned prtspd : 2; /*!< 18-17 Port Speed */ ++ #define IFXUSB_HPRT0_PRTSPD_HIGH_SPEED 0 ++ #define IFXUSB_HPRT0_PRTSPD_FULL_SPEED 1 ++ #define IFXUSB_HPRT0_PRTSPD_LOW_SPEED 2 ++ unsigned prttstctl : 4; /*!< 16-13 Port Test Control */ ++ unsigned prtpwr : 1; /*!< 12 Port Power */ ++ unsigned prtlnsts : 2; /*!< 11-10 Port Line Status */ ++ unsigned reserved9 : 1; ++ unsigned prtrst : 1; /*!< 08 Port Reset */ ++ unsigned prtsusp : 1; /*!< 07 Port Suspend */ ++ unsigned prtres : 1; /*!< 06 Port Resume */ ++ unsigned prtovrcurrchng : 1; /*!< 05 Port Overcurrent Change */ ++ unsigned prtovrcurract : 1; /*!< 04 Port Overcurrent Active */ ++ unsigned prtenchng : 1; /*!< 03 Port Enable/Disable Change */ ++ unsigned prtena : 1; /*!< 02 Port Enable */ ++ unsigned prtconndet : 1; /*!< 01 Port Connect Detected */ ++ unsigned prtconnsts : 1; /*!< 00 Port Connect Status */ ++ }b; ++} hprt0_data_t; ++ ++/*! ++ \brief Bit fields in the Host All Interrupt Register. ++ */ ++typedef union haint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 16; ++ unsigned ch15 : 1; ++ unsigned ch14 : 1; ++ unsigned ch13 : 1; ++ unsigned ch12 : 1; ++ unsigned ch11 : 1; ++ unsigned ch10 : 1; ++ unsigned ch09 : 1; ++ unsigned ch08 : 1; ++ unsigned ch07 : 1; ++ unsigned ch06 : 1; ++ unsigned ch05 : 1; ++ unsigned ch04 : 1; ++ unsigned ch03 : 1; ++ unsigned ch02 : 1; ++ unsigned ch01 : 1; ++ unsigned ch00 : 1; ++ } b; ++ struct ++ { ++ unsigned reserved : 16; ++ unsigned chint : 16; ++ } b2; ++} haint_data_t; ++/*@}*//*IFXUSB_CSR_HOST_GLOBAL_REG*/ ++/****************************************************************************/ ++/*! ++ \addtogroup IFXUSB_CSR_HOST_HC_REG ++ */ ++/*@{*/ ++/*! ++ \brief Host Channel Specific Registers ++ There will be one set of hc registers per host channelimplemented. ++ each HC's Register are offset at : ++ 500h + * (hc_num * 20h) ++ */ ++typedef struct ifxusb_hc_regs ++{ ++ volatile uint32_t hcchar; /*!< 00h Host Channel Characteristic Register.*/ ++ volatile uint32_t hcsplt; /*!< 04h Host Channel Split Control Register.*/ ++ volatile uint32_t hcint; /*!< 08h Host Channel Interrupt Register. */ ++ volatile uint32_t hcintmsk; /*!< 0Ch Host Channel Interrupt Mask Register. */ ++ volatile uint32_t hctsiz; /*!< 10h Host Channel Transfer Size Register. */ ++ volatile uint32_t hcdma; /*!< 14h Host Channel DMA Address Register. */ ++ uint32_t reserved[2]; /*!< 18h Reserved. */ ++} ifxusb_hc_regs_t; ++ ++ ++/*! ++ \brief Bit fields in the Host Channel Characteristics Register. ++ */ ++typedef union hcchar_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned chen : 1; /*!< 31 Channel enable */ ++ unsigned chdis : 1; /*!< 30 Channel disable */ ++ unsigned oddfrm : 1; /*!< 29 Frame to transmit periodic transaction */ ++ unsigned devaddr : 7; /*!< 28-22 Device address */ ++ unsigned multicnt : 2; /*!< 21-20 Packets per frame for periodic transfers */ ++ unsigned eptype : 2; /*!< 19-18 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ ++ unsigned lspddev : 1; /*!< 17 0: Full/high speed device, 1: Low speed device */ ++ unsigned reserved : 1; ++ unsigned epdir : 1; /*!< 15 0: OUT, 1: IN */ ++ unsigned epnum : 4; /*!< 14-11 Endpoint number */ ++ unsigned mps :11; /*!< 10-00 Maximum packet size in bytes */ ++ } b; ++} hcchar_data_t; ++ ++/*! ++ \brief Bit fields in the Host Channel Split Control Register ++ */ ++typedef union hcsplt_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned spltena : 1; /*!< 31 Split Enble */ ++ unsigned reserved :14; ++ unsigned compsplt : 1; /*!< 16 Do Complete Split */ ++ unsigned xactpos : 2; /*!< 15-14 Transaction Position */ ++ #define IFXUSB_HCSPLIT_XACTPOS_MID 0 ++ #define IFXUSB_HCSPLIT_XACTPOS_END 1 ++ #define IFXUSB_HCSPLIT_XACTPOS_BEGIN 2 ++ #define IFXUSB_HCSPLIT_XACTPOS_ALL 3 ++ unsigned hubaddr : 7; /*!< 13-07 Hub Address */ ++ unsigned prtaddr : 7; /*!< 06-00 Port Address */ ++ } b; ++} hcsplt_data_t; ++ ++/*! ++ \brief Bit fields in the Host Interrupt Register. ++ */ ++typedef union hcint_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved :21; ++ unsigned datatglerr : 1; /*!< 10 Data Toggle Error */ ++ unsigned frmovrun : 1; /*!< 09 Frame Overrun */ ++ unsigned bblerr : 1; /*!< 08 Babble Error */ ++ unsigned xacterr : 1; /*!< 07 Transaction Err */ ++ unsigned nyet : 1; /*!< 06 NYET Response Received */ ++ unsigned ack : 1; /*!< 05 ACK Response Received */ ++ unsigned nak : 1; /*!< 04 NAK Response Received */ ++ unsigned stall : 1; /*!< 03 STALL Response Received */ ++ unsigned ahberr : 1; /*!< 02 AHB Error */ ++ unsigned chhltd : 1; /*!< 01 Channel Halted */ ++ unsigned xfercomp : 1; /*!< 00 Channel Halted */ ++ }b; ++} hcint_data_t; ++ ++ ++/*! ++ \brief Bit fields in the Host Channel Transfer Size ++ Register. ++ */ ++typedef union hctsiz_data ++{ ++ uint32_t d32; ++ struct ++ { ++ /** */ ++ unsigned dopng : 1; /*!< 31 Do PING protocol when 1 */ ++ /** ++ * Packet ID for next data packet ++ * 0: DATA0 ++ * 1: DATA2 ++ * 2: DATA1 ++ * 3: MDATA (non-Control), SETUP (Control) ++ */ ++ unsigned pid : 2; /*!< 30-29 Packet ID for next data packet ++ 0: DATA0 ++ 1: DATA2 ++ 2: DATA1 ++ 3: MDATA (non-Control), SETUP (Control) ++ */ ++ #define IFXUSB_HCTSIZ_DATA0 0 ++ #define IFXUSB_HCTSIZ_DATA1 2 ++ #define IFXUSB_HCTSIZ_DATA2 1 ++ #define IFXUSB_HCTSIZ_MDATA 3 ++ #define IFXUSB_HCTSIZ_SETUP 3 ++ unsigned pktcnt :10; /*!< 28-19 Data packets to transfer */ ++ unsigned xfersize :19; /*!< 18-00 Total transfer size in bytes */ ++ }b; ++} hctsiz_data_t; ++ ++/*@}*//*IFXUSB_CSR_HOST_HC_REG*/ ++ ++/****************************************************************************/ ++ ++/*! ++ \addtogroup IFXUSB_CSR_PWR_CLK_GATING_REG ++ */ ++/*@{*/ ++/*! ++ \brief Bit fields in the Power and Clock Gating Control Register ++ */ ++typedef union pcgcctl_data ++{ ++ uint32_t d32; ++ struct ++ { ++ unsigned reserved : 27; ++ unsigned physuspended : 1; /*!< 04 PHY Suspended */ ++ unsigned rstpdwnmodule : 1; /*!< 03 Reset Power Down Modules */ ++ unsigned pwrclmp : 1; /*!< 02 Power Clamp */ ++ unsigned gatehclk : 1; /*!< 01 Gate Hclk */ ++ unsigned stoppclk : 1; /*!< 00 Stop Pclk */ ++ } b; ++} pcgcctl_data_t; ++/*@}*//*IFXUSB_CSR_PWR_CLK_GATING_REG*/ ++ ++/****************************************************************************/ ++ ++#endif //__IFXUSB_REGS_H__ +diff --git a/drivers/usb/ifxhcd/ifxusb_version.h b/drivers/usb/ifxhcd/ifxusb_version.h +new file mode 100644 +index 0000000..2dff735 +--- /dev/null ++++ b/drivers/usb/ifxhcd/ifxusb_version.h +@@ -0,0 +1,5 @@ ++ ++#ifndef IFXUSB_VERSION ++#define IFXUSB_VERSION "3.0alpha B100312" ++#endif ++ +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0051-MIPS-adds-gptu-driver.patch b/target/linux/lantiq/patches-3.2/0051-MIPS-adds-gptu-driver.patch new file mode 100644 index 0000000000..e8b9318afa --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0051-MIPS-adds-gptu-driver.patch @@ -0,0 +1,195 @@ +From a7c55f5e927b69bb30912fe1c3e5bcd8751e8381 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 14 Mar 2012 15:37:19 +0100 +Subject: [PATCH 51/70] MIPS: adds gptu driver + +--- + arch/mips/lantiq/xway/gptu.c | 176 ++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 176 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/lantiq/xway/gptu.c + +diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c +new file mode 100644 +index 0000000..ac82c37 +--- /dev/null ++++ b/arch/mips/lantiq/xway/gptu.c +@@ -0,0 +1,176 @@ ++/* ++ * 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) 2012 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/ioport.h> ++#include <linux/pm.h> ++#include <linux/export.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <asm/reboot.h> ++ ++#include <lantiq_soc.h> ++#include "../clk.h" ++ ++#include "../devices.h" ++ ++#define ltq_gptu_w32(x, y) ltq_w32((x), ltq_gptu_membase + (y)) ++#define ltq_gptu_r32(x) ltq_r32(ltq_gptu_membase + (x)) ++ ++ ++/* the magic ID byte of the core */ ++#define GPTU_MAGIC 0x59 ++/* clock control register */ ++#define GPTU_CLC 0x00 ++/* id register */ ++#define GPTU_ID 0x08 ++/* interrupt node enable */ ++#define GPTU_IRNEN 0xf4 ++/* interrupt control register */ ++#define GPTU_IRCR 0xf8 ++/* interrupt capture register */ ++#define GPTU_IRNCR 0xfc ++/* there are 3 identical blocks of 2 timers. calculate register offsets */ ++#define GPTU_SHIFT(x) (x % 2 ? 4 : 0) ++#define GPTU_BASE(x) (((x >> 1) * 0x20) + 0x10) ++/* timer control register */ ++#define GPTU_CON(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00) ++/* timer auto reload register */ ++#define GPTU_RUN(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08) ++/* timer manual reload register */ ++#define GPTU_RLD(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10) ++/* timer count register */ ++#define GPTU_CNT(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18) ++ ++/* GPTU_CON(x) */ ++#define CON_CNT BIT(2) ++#define CON_EDGE_FALL BIT(7) ++#define CON_SYNC BIT(8) ++#define CON_CLK_INT BIT(10) ++ ++/* GPTU_RUN(x) */ ++#define RUN_SEN BIT(0) ++#define RUN_RL BIT(2) ++ ++/* set clock to runmode */ ++#define CLC_RMC BIT(8) ++/* bring core out of suspend */ ++#define CLC_SUSPEND BIT(4) ++/* the disable bit */ ++#define CLC_DISABLE BIT(0) ++ ++#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22) ++ ++enum gptu_timer { ++ TIMER1A = 0, ++ TIMER1B, ++ TIMER2A, ++ TIMER2B, ++ TIMER3A, ++ TIMER3B ++}; ++ ++static struct resource ltq_gptu_resource = ++ MEM_RES("GPTU", LTQ_GPTU_BASE_ADDR, LTQ_GPTU_SIZE); ++ ++static void __iomem *ltq_gptu_membase; ++ ++static irqreturn_t timer_irq_handler(int irq, void *priv) ++{ ++ int timer = irq - TIMER_INTERRUPT; ++ ltq_gptu_w32(1 << timer, GPTU_IRNCR); ++ return IRQ_HANDLED; ++} ++ ++static void gptu_hwinit(void) ++{ ++ struct clk *clk = clk_get_sys("ltq_gptu", NULL); ++ clk_enable(clk); ++ ltq_gptu_w32(0x00, GPTU_IRNEN); ++ ltq_gptu_w32(0xff, GPTU_IRNCR); ++ ltq_gptu_w32(CLC_RMC | CLC_SUSPEND, GPTU_CLC); ++} ++ ++static void gptu_hwexit(void) ++{ ++ ltq_gptu_w32(0x00, GPTU_IRNEN); ++ ltq_gptu_w32(0xff, GPTU_IRNCR); ++ ltq_gptu_w32(CLC_DISABLE, GPTU_CLC); ++} ++ ++static int ltq_gptu_enable(struct clk *clk) ++{ ++ int ret = request_irq(TIMER_INTERRUPT + clk->bits, timer_irq_handler, ++ IRQF_TIMER, "timer", NULL); ++ if (ret) { ++ pr_err("gptu: failed to request irq\n"); ++ return ret; ++ } ++ ++ ltq_gptu_w32(CON_CNT | CON_EDGE_FALL | CON_SYNC | CON_CLK_INT, ++ GPTU_CON(clk->bits)); ++ ltq_gptu_w32(1, GPTU_RLD(clk->bits)); ++ ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) | clk->bits, GPTU_IRNEN); ++ ltq_gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits)); ++ return 0; ++} ++ ++static void ltq_gptu_disable(struct clk *clk) ++{ ++ ltq_gptu_w32(0, GPTU_RUN(clk->bits)); ++ ltq_gptu_w32(0, GPTU_CON(clk->bits)); ++ ltq_gptu_w32(0, GPTU_RLD(clk->bits)); ++ ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) & ~clk->bits, GPTU_IRNEN); ++ free_irq(TIMER_INTERRUPT + clk->bits, NULL); ++} ++ ++static inline void clkdev_add_gptu(const char *con, unsigned int timer) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ clk->cl.dev_id = "ltq_gptu"; ++ clk->cl.con_id = con; ++ clk->cl.clk = clk; ++ clk->enable = ltq_gptu_enable; ++ clk->disable = ltq_gptu_disable; ++ clk->bits = timer; ++ clkdev_add(&clk->cl); ++} ++ ++static int __init gptu_setup(void) ++{ ++ /* remap gptu register range */ ++ ltq_gptu_membase = ltq_remap_resource(<q_gptu_resource); ++ if (!ltq_gptu_membase) ++ panic("Failed to remap gptu memory"); ++ ++ /* power up the core */ ++ gptu_hwinit(); ++ ++ /* the gptu has a ID register */ ++ if (((ltq_gptu_r32(GPTU_ID) >> 8) & 0xff) != GPTU_MAGIC) { ++ pr_err("gptu: failed to find magic\n"); ++ gptu_hwexit(); ++ return -ENAVAIL; ++ } ++ ++ /* register the clocks */ ++ clkdev_add_gptu("timer1a", TIMER1A); ++ clkdev_add_gptu("timer1b", TIMER1B); ++ clkdev_add_gptu("timer2a", TIMER2A); ++ clkdev_add_gptu("timer2b", TIMER2B); ++ clkdev_add_gptu("timer3a", TIMER3A); ++ clkdev_add_gptu("timer3b", TIMER3B); ++ ++ pr_info("gptu: 6 timers loaded\n"); ++ ++ return 0; ++} ++ ++arch_initcall(gptu_setup); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-rename-variable-inside.patch b/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-rename-variable-inside.patch new file mode 100644 index 0000000000..5c1cb5579b --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0052-MIPS-lantiq-pci-rename-variable-inside.patch @@ -0,0 +1,79 @@ +From 3571f6a294783e617c2f8f52021f9c33bc9e5a36 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 12:00:17 +0100 +Subject: [PATCH 52/70] MIPS: lantiq: pci: rename variable inside + +* rename a global var inside the pci code +--- + arch/mips/pci/ops-lantiq.c | 6 +++--- + arch/mips/pci/pci-lantiq.c | 6 +++--- + arch/mips/pci/pci-lantiq.h | 2 +- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c +index 1f2afb5..5cbb0cf 100644 +--- a/arch/mips/pci/ops-lantiq.c ++++ b/arch/mips/pci/ops-lantiq.c +@@ -41,7 +41,7 @@ static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, + + spin_lock_irqsave(&ebu_lock, flags); + +- cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ cfg_base = (unsigned long) ltq_pci_cfgbase; + cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << + LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); + +@@ -55,11 +55,11 @@ static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, + wmb(); + + /* clean possible Master abort */ +- cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ cfg_base = (unsigned long) ltq_pci_cfgbase; + cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; + temp = ltq_r32(((u32 *)(cfg_base))); + temp = swab32(temp); +- cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ cfg_base = (unsigned long) ltq_pci_cfgbase; + cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; + ltq_w32(temp, ((u32 *)cfg_base)); + +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +index 47b551c..efcdd45 100644 +--- a/arch/mips/pci/pci-lantiq.c ++++ b/arch/mips/pci/pci-lantiq.c +@@ -65,8 +65,8 @@ + #define ltq_pci_w32(x, y) ltq_w32((x), ltq_pci_membase + (y)) + #define ltq_pci_r32(x) ltq_r32(ltq_pci_membase + (x)) + +-#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y)) +-#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x)) ++#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_cfgbase + (y)) ++#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_cfgbase + (x)) + + struct ltq_pci_gpio_map { + int pin; +@@ -273,7 +273,7 @@ static int __devinit ltq_pci_probe(struct platform_device *pdev) + pci_probe_only = 0; + ltq_pci_irq_map = ltq_pci_data->irq; + ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE); +- ltq_pci_mapped_cfg = ++ ltq_pci_cfgbase = + ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); + ltq_pci_controller.io_map_base = + (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); +diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h +index 66bf6cd..c4721b4 100644 +--- a/arch/mips/pci/pci-lantiq.h ++++ b/arch/mips/pci/pci-lantiq.h +@@ -9,7 +9,7 @@ + #ifndef _LTQ_PCI_H__ + #define _LTQ_PCI_H__ + +-extern __iomem void *ltq_pci_mapped_cfg; ++extern __iomem void *ltq_pci_cfgbase; + extern int ltq_pci_read_config_dword(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 *val); + extern int ltq_pci_write_config_dword(struct pci_bus *bus, +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch b/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch new file mode 100644 index 0000000000..fd5ba070c7 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0053-MIPS-lantiq-pci-give-xway-pci-support-its-own-kbuild.patch @@ -0,0 +1,45 @@ +From 00dda451e12b6fc519cd4f575a696c4216f45992 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 13:13:31 +0100 +Subject: [PATCH 53/70] MIPS: lantiq: pci: give xway pci support its own + kbuild symbol + +--- + arch/mips/lantiq/Kconfig | 5 +++++ + arch/mips/pci/Makefile | 2 +- + 2 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig +index cb6b39f..dde9fc6 100644 +--- a/arch/mips/lantiq/Kconfig ++++ b/arch/mips/lantiq/Kconfig +@@ -19,8 +19,13 @@ config SOC_XWAY + + config SOC_FALCON + bool "FALCON" ++ + endchoice + ++config PCI_LANTIQ ++ bool "PCI Support" ++ depends on SOC_XWAY && PCI ++ + source "arch/mips/lantiq/xway/Kconfig" + source "arch/mips/lantiq/falcon/Kconfig" + +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index bb82cbd..afad91d 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -40,7 +40,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o + obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o + obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o + obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o +-obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o ++obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o + obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o + obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o + obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch b/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch new file mode 100644 index 0000000000..500b224d5f --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0054-MIPS-lantiq-pci-move-pcibios-code-into-fixup-lantiq..patch @@ -0,0 +1,131 @@ +From 49b5d2242091e216736216d98d7f940870d4f1ec Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 15:53:10 +0100 +Subject: [PATCH 54/70] MIPS: lantiq: pci: move pcibios code into + fixup-lantiq.c + +--- + arch/mips/pci/Makefile | 1 + + arch/mips/pci/fixup-lantiq.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + arch/mips/pci/pci-lantiq.c | 24 ++---------------------- + 3 files changed, 45 insertions(+), 22 deletions(-) + create mode 100644 arch/mips/pci/fixup-lantiq.c + +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index afad91d..3ca5f75 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -40,6 +40,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o + obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o + obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o + obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o ++obj-$(CONFIG_LANTIQ) += fixup-lantiq.o + obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o + obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o + obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o +diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c +new file mode 100644 +index 0000000..daf5ae9 +--- /dev/null ++++ b/arch/mips/pci/fixup-lantiq.c +@@ -0,0 +1,42 @@ ++/* ++ * 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) 2012 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/of_irq.h> ++#include <linux/of_pci.h> ++ ++int (*ltqpci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin) = NULL; ++int (*ltqpci_plat_arch_init)(struct pci_dev *dev) = NULL; ++int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; ++int *ltq_pci_irq_map; ++ ++int pcibios_plat_dev_init(struct pci_dev *dev) ++{ ++ if (ltqpci_plat_arch_init) ++ return ltqpci_plat_arch_init(dev); ++ ++ if (ltqpci_plat_dev_init) ++ return ltqpci_plat_dev_init(dev); ++ ++ return 0; ++} ++ ++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ if (ltqpci_map_irq) ++ return ltqpci_map_irq(dev, slot, pin); ++ if (ltq_pci_irq_map[slot]) { ++ dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, ltq_pci_irq_map[slot]); ++ return ltq_pci_irq_map[slot]; ++ } ++ printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", ++ slot); ++ ++ return 0; ++} ++ ++ +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +index efcdd45..7a29738 100644 +--- a/arch/mips/pci/pci-lantiq.c ++++ b/arch/mips/pci/pci-lantiq.c +@@ -93,16 +93,14 @@ static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = { + { 37, 2, 0, "pci-req4" }, + }; + +-__iomem void *ltq_pci_mapped_cfg; ++__iomem void *ltq_pci_cfgbase; + static __iomem void *ltq_pci_membase; + +-int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; +- + /* Since the PCI REQ pins can be reused for other functionality, make it + possible to exclude those from interpretation by the PCI controller */ + static int ltq_pci_req_mask = 0xf; + +-static int *ltq_pci_irq_map; ++extern int *ltq_pci_irq_map; + + struct pci_ops ltq_pci_ops = { + .read = ltq_pci_read_config_dword, +@@ -131,14 +129,6 @@ static struct pci_controller ltq_pci_controller = { + .io_offset = 0x00000000UL, + }; + +-int pcibios_plat_dev_init(struct pci_dev *dev) +-{ +- if (ltqpci_plat_dev_init) +- return ltqpci_plat_dev_init(dev); +- +- return 0; +-} +- + static u32 ltq_calc_bar11mask(void) + { + u32 mem, bar11mask; +@@ -256,16 +246,6 @@ static int __devinit ltq_pci_startup(struct device *dev) + return 0; + } + +-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +-{ +- if (ltq_pci_irq_map[slot]) +- return ltq_pci_irq_map[slot]; +- printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", +- slot); +- +- return 0; +-} +- + static int __devinit ltq_pci_probe(struct platform_device *pdev) + { + struct ltq_pci_data *ltq_pci_data = +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-pcie-add-pcie-driver.patch b/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-pcie-add-pcie-driver.patch new file mode 100644 index 0000000000..85766a7767 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0055-MIPS-lantiq-pcie-add-pcie-driver.patch @@ -0,0 +1,3503 @@ +From a53d622001ae396d89c9abacb62f3c3c7fbd3c13 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 8 Mar 2012 15:57:33 +0100 +Subject: [PATCH 55/70] MIPS: lantiq: pcie: add pcie driver + +--- + arch/mips/Kconfig | 1 + + arch/mips/lantiq/Kconfig | 4 - + arch/mips/lantiq/xway/Kconfig | 21 + + arch/mips/pci/Makefile | 2 + + arch/mips/pci/fixup-lantiq-pcie.c | 81 +++ + arch/mips/pci/pci.c | 25 + + arch/mips/pci/pcie-lantiq-msi.c | 399 +++++++++++ + arch/mips/pci/pcie-lantiq-phy.c | 408 ++++++++++++ + arch/mips/pci/pcie-lantiq.c | 1146 ++++++++++++++++++++++++++++++++ + arch/mips/pci/pcie-lantiq.h | 1305 +++++++++++++++++++++++++++++++++++++ + 10 files changed, 3388 insertions(+), 4 deletions(-) + create mode 100644 arch/mips/pci/fixup-lantiq-pcie.c + create mode 100644 arch/mips/pci/pcie-lantiq-msi.c + create mode 100644 arch/mips/pci/pcie-lantiq-phy.c + create mode 100644 arch/mips/pci/pcie-lantiq.c + create mode 100644 arch/mips/pci/pcie-lantiq.h + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 1b78cd7..bbaff9b 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -2329,6 +2329,7 @@ config PCI_DOMAINS + bool + + source "drivers/pci/Kconfig" ++source "drivers/pci/pcie/Kconfig" + + # + # ISA support is now enabled via select. Too many systems still have the one +diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig +index dde9fc6..d21d9d4 100644 +--- a/arch/mips/lantiq/Kconfig ++++ b/arch/mips/lantiq/Kconfig +@@ -22,10 +22,6 @@ config SOC_FALCON + + endchoice + +-config PCI_LANTIQ +- bool "PCI Support" +- depends on SOC_XWAY && PCI +- + source "arch/mips/lantiq/xway/Kconfig" + source "arch/mips/lantiq/falcon/Kconfig" + +diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig +index 2b857de..54a51ff 100644 +--- a/arch/mips/lantiq/xway/Kconfig ++++ b/arch/mips/lantiq/xway/Kconfig +@@ -8,6 +8,27 @@ config LANTIQ_MACH_EASY50712 + + endmenu + ++choice ++ prompt "PCI" ++ default PCI_LANTIQ_NONE ++ ++config PCI_LANTIQ_NONE ++ bool "None" ++ ++config PCI_LANTIQ ++ bool "PCI Support" ++ depends on PCI ++ ++config PCIE_LANTIQ ++ bool "PCIE Support" ++ select ARCH_SUPPORTS_MSI ++ ++endchoice ++ ++config PCIE_LANTIQ_MSI ++ bool ++ depends on PCIE_LANTIQ && PCI_MSI ++ default y + endif + + if SOC_AMAZON_SE +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index 3ca5f75..3386888 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -42,6 +42,8 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o + obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o + obj-$(CONFIG_LANTIQ) += fixup-lantiq.o + obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o ++obj-$(CONFIG_PCIE_LANTIQ) += pcie-lantiq-phy.o pcie-lantiq.o fixup-lantiq-pcie.o ++obj-$(CONFIG_PCIE_LANTIQ_MSI) += pcie-lantiq-msi.o + obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o + obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o + obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o +diff --git a/arch/mips/pci/fixup-lantiq-pcie.c b/arch/mips/pci/fixup-lantiq-pcie.c +new file mode 100644 +index 0000000..84517df +--- /dev/null ++++ b/arch/mips/pci/fixup-lantiq-pcie.c +@@ -0,0 +1,81 @@ ++/****************************************************************************** ++** ++** FILE NAME : ifxmips_fixup_pcie.c ++** PROJECT : IFX UEIP for VRX200 ++** MODULES : PCIe ++** ++** DATE : 02 Mar 2009 ++** AUTHOR : Lei Chuanhua ++** DESCRIPTION : PCIe Root Complex Driver ++** COPYRIGHT : Copyright (c) 2009 ++** Infineon Technologies AG ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** ++** 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. ++** HISTORY ++** $Version $Date $Author $Comment ++** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version ++*******************************************************************************/ ++/*! ++ \file ifxmips_fixup_pcie.c ++ \ingroup IFX_PCIE ++ \brief PCIe Fixup functions source file ++*/ ++#include <linux/pci.h> ++#include <linux/pci_regs.h> ++#include <linux/pci_ids.h> ++ ++#include <lantiq_soc.h> ++ ++#include "pcie-lantiq.h" ++ ++#define PCI_VENDOR_ID_INFINEON 0x15D1 ++#define PCI_DEVICE_ID_INFINEON_DANUBE 0x000F ++#define PCI_DEVICE_ID_INFINEON_PCIE 0x0011 ++#define PCI_VENDOR_ID_LANTIQ 0x1BEF ++#define PCI_DEVICE_ID_LANTIQ_PCIE 0x0011 ++ ++ ++ ++static void __devinit ++ifx_pcie_fixup_resource(struct pci_dev *dev) ++{ ++ u32 reg; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev)); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s: fixup host controller %s (%04x:%04x)\n", ++ __func__, pci_name(dev), dev->vendor, dev->device); ++ ++ /* Setup COMMAND register */ ++ reg = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER /* | ++ PCI_COMMAND_INTX_DISABLE */| PCI_COMMAND_SERR; ++ pci_write_config_word(dev, PCI_COMMAND, reg); ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev)); ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE, ifx_pcie_fixup_resource); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_VENDOR_ID_LANTIQ, ifx_pcie_fixup_resource); ++ ++static void __devinit ++ifx_pcie_rc_class_early_fixup(struct pci_dev *dev) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev)); ++ ++ if (dev->devfn == PCI_DEVFN(0, 0) && ++ (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) { ++ ++ dev->class = (PCI_CLASS_BRIDGE_PCI << 8) | (dev->class & 0xff); ++ ++ printk(KERN_INFO "%s: fixed pcie host bridge to pci-pci bridge\n", __func__); ++ } ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev)); ++} ++ ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE, ++ ifx_pcie_rc_class_early_fixup); ++ ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_DEVICE_ID_LANTIQ_PCIE, ++ ifx_pcie_rc_class_early_fixup); +diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c +index 41af7fa..2239cda 100644 +--- a/arch/mips/pci/pci.c ++++ b/arch/mips/pci/pci.c +@@ -167,6 +167,31 @@ static int __init pcibios_init(void) + + subsys_initcall(pcibios_init); + ++int pcibios_host_nr(void) ++{ ++ int count; ++ struct pci_controller *hose; ++ for (count = 0, hose = hose_head; hose; hose = hose->next, count++) { ++ ; ++ } ++ return count; ++} ++EXPORT_SYMBOL(pcibios_host_nr); ++ ++int pcibios_1st_host_bus_nr(void) ++{ ++ int bus_nr = 0; ++ struct pci_controller *hose = hose_head; ++ ++ if (hose != NULL) { ++ if (hose->bus != NULL) { ++ bus_nr = hose->bus->subordinate + 1; ++ } ++ } ++ return bus_nr; ++} ++EXPORT_SYMBOL(pcibios_1st_host_bus_nr); ++ + static int pcibios_enable_resources(struct pci_dev *dev, int mask) + { + u16 cmd, old_cmd; +diff --git a/arch/mips/pci/pcie-lantiq-msi.c b/arch/mips/pci/pcie-lantiq-msi.c +new file mode 100644 +index 0000000..9cbf639 +--- /dev/null ++++ b/arch/mips/pci/pcie-lantiq-msi.c +@@ -0,0 +1,399 @@ ++/****************************************************************************** ++** ++** FILE NAME : ifxmips_pcie_msi.c ++** PROJECT : IFX UEIP for VRX200 ++** MODULES : PCI MSI sub module ++** ++** DATE : 02 Mar 2009 ++** AUTHOR : Lei Chuanhua ++** DESCRIPTION : PCIe MSI Driver ++** COPYRIGHT : Copyright (c) 2009 ++** Infineon Technologies AG ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** ++** 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. ++** HISTORY ++** $Date $Author $Comment ++** 02 Mar,2009 Lei Chuanhua Initial version ++*******************************************************************************/ ++/*! ++ \defgroup IFX_PCIE_MSI MSI OS APIs ++ \ingroup IFX_PCIE ++ \brief PCIe bus driver OS interface functions ++*/ ++ ++/*! ++ \file ifxmips_pcie_msi.c ++ \ingroup IFX_PCIE ++ \brief PCIe MSI OS interface file ++*/ ++ ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/interrupt.h> ++#include <linux/kernel_stat.h> ++#include <linux/pci.h> ++#include <linux/msi.h> ++#include <linux/module.h> ++#include <asm/bootinfo.h> ++#include <asm/irq.h> ++#include <asm/traps.h> ++ ++#include "pcie-lantiq.h" ++ ++#define IFX_MSI_IRQ_NUM 16 ++#define SM(_v, _f) (((_v) << _f##_S) & (_f)) ++ ++#define IFX_MSI_PIC_REG_BASE (KSEG1 | 0x1F700000) ++#define IFX_PCIE_MSI_IR0 (INT_NUM_IM4_IRL0 + 27) ++#define IFX_PCIE_MSI_IR1 (INT_NUM_IM4_IRL0 + 28) ++#define IFX_PCIE_MSI_IR2 (INT_NUM_IM4_IRL0 + 29) ++#define IFX_PCIE_MSI_IR3 (INT_NUM_IM0_IRL0 + 30) ++ ++#define IFX_MSI_PCI_INT_DISABLE 0x80000000 ++#define IFX_MSI_PIC_INT_LINE 0x30000000 ++#define IFX_MSI_PIC_MSG_ADDR 0x0FFF0000 ++#define IFX_MSI_PIC_MSG_DATA 0x0000FFFF ++#define IFX_MSI_PIC_BIG_ENDIAN 1 ++#define IFX_MSI_PIC_INT_LINE_S 28 ++#define IFX_MSI_PIC_MSG_ADDR_S 16 ++#define IFX_MSI_PIC_MSG_DATA_S 0x0 ++ ++enum { ++ IFX_PCIE_MSI_IDX0 = 0, ++ IFX_PCIE_MSI_IDX1, ++ IFX_PCIE_MSI_IDX2, ++ IFX_PCIE_MSI_IDX3, ++}; ++ ++typedef struct ifx_msi_irq_idx { ++ const int irq; ++ const int idx; ++}ifx_msi_irq_idx_t; ++ ++struct ifx_msi_pic { ++ volatile u32 pic_table[IFX_MSI_IRQ_NUM]; ++ volatile u32 pic_endian; /* 0x40 */ ++}; ++typedef struct ifx_msi_pic *ifx_msi_pic_t; ++ ++typedef struct ifx_msi_irq { ++ const volatile ifx_msi_pic_t msi_pic_p; ++ const u32 msi_phy_base; ++ const ifx_msi_irq_idx_t msi_irq_idx[IFX_MSI_IRQ_NUM]; ++ /* ++ * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is ++ * in use. ++ */ ++ u16 msi_free_irq_bitmask; ++ ++ /* ++ * Each bit in msi_multiple_irq_bitmask tells that the device using ++ * this bit in msi_free_irq_bitmask is also using the next bit. This ++ * is used so we can disable all of the MSI interrupts when a device ++ * uses multiple. ++ */ ++ u16 msi_multiple_irq_bitmask; ++}ifx_msi_irq_t; ++ ++static ifx_msi_irq_t msi_irqs[IFX_PCIE_CORE_NR] = { ++ { ++ .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI_PIC_REG_BASE, ++ .msi_phy_base = PCIE_MSI_PHY_BASE, ++ .msi_irq_idx = { ++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ }, ++ .msi_free_irq_bitmask = 0, ++ .msi_multiple_irq_bitmask= 0, ++ }, ++#ifdef CONFIG_IFX_PCIE_2ND_CORE ++ { ++ .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI1_PIC_REG_BASE, ++ .msi_phy_base = PCIE1_MSI_PHY_BASE, ++ .msi_irq_idx = { ++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1}, ++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3}, ++ }, ++ .msi_free_irq_bitmask = 0, ++ .msi_multiple_irq_bitmask= 0, ++ ++ }, ++#endif /* CONFIG_IFX_PCIE_2ND_CORE */ ++}; ++ ++/* ++ * This lock controls updates to msi_free_irq_bitmask, ++ * msi_multiple_irq_bitmask and pic register settting ++ */ ++static DEFINE_SPINLOCK(ifx_pcie_msi_lock); ++ ++void pcie_msi_pic_init(int pcie_port) ++{ ++ spin_lock(&ifx_pcie_msi_lock); ++ msi_irqs[pcie_port].msi_pic_p->pic_endian = IFX_MSI_PIC_BIG_ENDIAN; ++ spin_unlock(&ifx_pcie_msi_lock); ++} ++ ++/** ++ * \fn int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) ++ * \brief Called when a driver request MSI interrupts instead of the ++ * legacy INT A-D. This routine will allocate multiple interrupts ++ * for MSI devices that support them. A device can override this by ++ * programming the MSI control bits [6:4] before calling ++ * pci_enable_msi(). ++ * ++ * \param[in] pdev Device requesting MSI interrupts ++ * \param[in] desc MSI descriptor ++ * ++ * \return -EINVAL Invalid pcie root port or invalid msi bit ++ * \return 0 OK ++ * \ingroup IFX_PCIE_MSI ++ */ ++int ++arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) ++{ ++ int irq, pos; ++ u16 control; ++ int irq_idx; ++ int irq_step; ++ int configured_private_bits; ++ int request_private_bits; ++ struct msi_msg msg; ++ u16 search_mask; ++ struct ifx_pci_controller *ctrl = pdev->bus->sysdata; ++ int pcie_port = ctrl->port; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s %s enter\n", __func__, pci_name(pdev)); ++ ++ /* XXX, skip RC MSI itself */ ++ if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s RC itself doesn't use MSI interrupt\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* ++ * Read the MSI config to figure out how many IRQs this device ++ * wants. Most devices only want 1, which will give ++ * configured_private_bits and request_private_bits equal 0. ++ */ ++ pci_read_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &control); ++ ++ /* ++ * If the number of private bits has been configured then use ++ * that value instead of the requested number. This gives the ++ * driver the chance to override the number of interrupts ++ * before calling pci_enable_msi(). ++ */ ++ configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4; ++ if (configured_private_bits == 0) { ++ /* Nothing is configured, so use the hardware requested size */ ++ request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1; ++ } ++ else { ++ /* ++ * Use the number of configured bits, assuming the ++ * driver wanted to override the hardware request ++ * value. ++ */ ++ request_private_bits = configured_private_bits; ++ } ++ ++ /* ++ * The PCI 2.3 spec mandates that there are at most 32 ++ * interrupts. If this device asks for more, only give it one. ++ */ ++ if (request_private_bits > 5) { ++ request_private_bits = 0; ++ } ++again: ++ /* ++ * The IRQs have to be aligned on a power of two based on the ++ * number being requested. ++ */ ++ irq_step = (1 << request_private_bits); ++ ++ /* Mask with one bit for each IRQ */ ++ search_mask = (1 << irq_step) - 1; ++ ++ /* ++ * We're going to search msi_free_irq_bitmask_lock for zero ++ * bits. This represents an MSI interrupt number that isn't in ++ * use. ++ */ ++ spin_lock(&ifx_pcie_msi_lock); ++ for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos += irq_step) { ++ if ((msi_irqs[pcie_port].msi_free_irq_bitmask & (search_mask << pos)) == 0) { ++ msi_irqs[pcie_port].msi_free_irq_bitmask |= search_mask << pos; ++ msi_irqs[pcie_port].msi_multiple_irq_bitmask |= (search_mask >> 1) << pos; ++ break; ++ } ++ } ++ spin_unlock(&ifx_pcie_msi_lock); ++ ++ /* Make sure the search for available interrupts didn't fail */ ++ if (pos >= IFX_MSI_IRQ_NUM) { ++ if (request_private_bits) { ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s: Unable to find %d free " ++ "interrupts, trying just one", __func__, 1 << request_private_bits); ++ request_private_bits = 0; ++ goto again; ++ } ++ else { ++ printk(KERN_ERR "%s: Unable to find a free MSI interrupt\n", __func__); ++ return -EINVAL; ++ } ++ } ++ irq = msi_irqs[pcie_port].msi_irq_idx[pos].irq; ++ irq_idx = msi_irqs[pcie_port].msi_irq_idx[pos].idx; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "pos %d, irq %d irq_idx %d\n", pos, irq, irq_idx); ++ ++ /* ++ * Initialize MSI. This has to match the memory-write endianess from the device ++ * Address bits [23:12] ++ */ ++ spin_lock(&ifx_pcie_msi_lock); ++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] = SM(irq_idx, IFX_MSI_PIC_INT_LINE) | ++ SM((msi_irqs[pcie_port].msi_phy_base >> 12), IFX_MSI_PIC_MSG_ADDR) | ++ SM((1 << pos), IFX_MSI_PIC_MSG_DATA); ++ ++ /* Enable this entry */ ++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~IFX_MSI_PCI_INT_DISABLE; ++ spin_unlock(&ifx_pcie_msi_lock); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "pic_table[%d]: 0x%08x\n", ++ pos, msi_irqs[pcie_port].msi_pic_p->pic_table[pos]); ++ ++ /* Update the number of IRQs the device has available to it */ ++ control &= ~PCI_MSI_FLAGS_QSIZE; ++ control |= (request_private_bits << 4); ++ pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, control); ++ ++ irq_set_msi_desc(irq, desc); ++ msg.address_hi = 0x0; ++ msg.address_lo = msi_irqs[pcie_port].msi_phy_base; ++ msg.data = SM((1 << pos), IFX_MSI_PIC_MSG_DATA); ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "msi_data: pos %d 0x%08x\n", pos, msg.data); ++ ++ write_msi_msg(irq, &msg); ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__); ++ return 0; ++} ++ ++static int ++pcie_msi_irq_to_port(unsigned int irq, int *port) ++{ ++ int ret = 0; ++ ++ if (irq == IFX_PCIE_MSI_IR0 || irq == IFX_PCIE_MSI_IR1 || ++ irq == IFX_PCIE_MSI_IR2 || irq == IFX_PCIE_MSI_IR3) { ++ *port = IFX_PCIE_PORT0; ++ } ++#ifdef CONFIG_IFX_PCIE_2ND_CORE ++ else if (irq == IFX_PCIE1_MSI_IR0 || irq == IFX_PCIE1_MSI_IR1 || ++ irq == IFX_PCIE1_MSI_IR2 || irq == IFX_PCIE1_MSI_IR3) { ++ *port = IFX_PCIE_PORT1; ++ } ++#endif /* CONFIG_IFX_PCIE_2ND_CORE */ ++ else { ++ printk(KERN_ERR "%s: Attempted to teardown illegal " ++ "MSI interrupt (%d)\n", __func__, irq); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++/** ++ * \fn void arch_teardown_msi_irq(unsigned int irq) ++ * \brief Called when a device no longer needs its MSI interrupts. All ++ * MSI interrupts for the device are freed. ++ * ++ * \param irq The devices first irq number. There may be multple in sequence. ++ * \return none ++ * \ingroup IFX_PCIE_MSI ++ */ ++void ++arch_teardown_msi_irq(unsigned int irq) ++{ ++ int pos; ++ int number_irqs; ++ u16 bitmask; ++ int pcie_port; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s enter\n", __func__); ++ ++ BUG_ON(irq > (INT_NUM_IM4_IRL0 + 31)); ++ ++ if (pcie_msi_irq_to_port(irq, &pcie_port) != 0) { ++ return; ++ } ++ ++ /* Shift the mask to the correct bit location, not always correct ++ * Probally, the first match will be chosen. ++ */ ++ for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos++) { ++ if ((msi_irqs[pcie_port].msi_irq_idx[pos].irq == irq) ++ && (msi_irqs[pcie_port].msi_free_irq_bitmask & ( 1 << pos))) { ++ break; ++ } ++ } ++ if (pos >= IFX_MSI_IRQ_NUM) { ++ printk(KERN_ERR "%s: Unable to find a matched MSI interrupt\n", __func__); ++ return; ++ } ++ spin_lock(&ifx_pcie_msi_lock); ++ /* Disable this entry */ ++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] |= IFX_MSI_PCI_INT_DISABLE; ++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~(IFX_MSI_PIC_INT_LINE | IFX_MSI_PIC_MSG_ADDR | IFX_MSI_PIC_MSG_DATA); ++ spin_unlock(&ifx_pcie_msi_lock); ++ /* ++ * Count the number of IRQs we need to free by looking at the ++ * msi_multiple_irq_bitmask. Each bit set means that the next ++ * IRQ is also owned by this device. ++ */ ++ number_irqs = 0; ++ while (((pos + number_irqs) < IFX_MSI_IRQ_NUM) && ++ (msi_irqs[pcie_port].msi_multiple_irq_bitmask & (1 << (pos + number_irqs)))) { ++ number_irqs++; ++ } ++ number_irqs++; ++ ++ /* Mask with one bit for each IRQ */ ++ bitmask = (1 << number_irqs) - 1; ++ ++ bitmask <<= pos; ++ if ((msi_irqs[pcie_port].msi_free_irq_bitmask & bitmask) != bitmask) { ++ printk(KERN_ERR "%s: Attempted to teardown MSI " ++ "interrupt (%d) not in use\n", __func__, irq); ++ return; ++ } ++ /* Checks are done, update the in use bitmask */ ++ spin_lock(&ifx_pcie_msi_lock); ++ msi_irqs[pcie_port].msi_free_irq_bitmask &= ~bitmask; ++ msi_irqs[pcie_port].msi_multiple_irq_bitmask &= ~(bitmask >> 1); ++ spin_unlock(&ifx_pcie_msi_lock); ++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__); ++} ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Chuanhua.Lei@infineon.com"); ++MODULE_SUPPORTED_DEVICE("Infineon PCIe IP builtin MSI PIC module"); ++MODULE_DESCRIPTION("Infineon PCIe IP builtin MSI PIC driver"); ++ +diff --git a/arch/mips/pci/pcie-lantiq-phy.c b/arch/mips/pci/pcie-lantiq-phy.c +new file mode 100644 +index 0000000..9f5027d +--- /dev/null ++++ b/arch/mips/pci/pcie-lantiq-phy.c +@@ -0,0 +1,408 @@ ++/****************************************************************************** ++** ++** FILE NAME : ifxmips_pcie_phy.c ++** PROJECT : IFX UEIP for VRX200 ++** MODULES : PCIe PHY sub module ++** ++** DATE : 14 May 2009 ++** AUTHOR : Lei Chuanhua ++** DESCRIPTION : PCIe Root Complex Driver ++** COPYRIGHT : Copyright (c) 2009 ++** Infineon Technologies AG ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** ++** 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. ++** HISTORY ++** $Version $Date $Author $Comment ++** 0.0.1 14 May,2009 Lei Chuanhua Initial version ++*******************************************************************************/ ++/*! ++ \file ifxmips_pcie_phy.c ++ \ingroup IFX_PCIE ++ \brief PCIe PHY PLL register programming source file ++*/ ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/paccess.h> ++#include <linux/delay.h> ++ ++#include "pcie-lantiq.h" ++ ++/* PCIe PDI only supports 16 bit operation */ ++ ++#define IFX_PCIE_PHY_REG_WRITE16(__addr, __data) \ ++ ((*(volatile u16 *) (__addr)) = (__data)) ++ ++#define IFX_PCIE_PHY_REG_READ16(__addr) \ ++ (*(volatile u16 *) (__addr)) ++ ++#define IFX_PCIE_PHY_REG16(__addr) \ ++ (*(volatile u16 *) (__addr)) ++ ++#define IFX_PCIE_PHY_REG(__reg, __value, __mask) do { \ ++ u16 read_data; \ ++ u16 write_data; \ ++ read_data = IFX_PCIE_PHY_REG_READ16((__reg)); \ ++ write_data = (read_data & ((u16)~(__mask))) | (((u16)(__value)) & ((u16)(__mask)));\ ++ IFX_PCIE_PHY_REG_WRITE16((__reg), write_data); \ ++} while (0) ++ ++#define IFX_PCIE_PLL_TIMEOUT 1000 /* Tunnable */ ++ ++static void ++pcie_phy_comm_setup(int pcie_port) ++{ ++ /* PLL Setting */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF); ++ ++ /* increase the bias reference voltage */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF); ++ ++ /* Endcnt */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF); ++ ++ /* force */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008); ++ ++ /* predrv_ser_en */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF); ++ ++ /* ctrl_lim */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF); ++ ++ /* ctrl */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00); ++ ++ /* predrv_ser_en */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00); ++ ++ /* RTERM*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF); ++ ++ /* Improved 100MHz clock output */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF); ++ ++ /* Reduced CDR BW to avoid glitches */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF); ++} ++ ++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE ++static void ++pcie_phy_36mhz_mode_setup(int pcie_port) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); ++ ++ /* en_ext_mmd_div_ratio */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); ++ ++ /* ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); ++ ++ /* pll_ensdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); ++ ++ /* en_const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); ++ ++ /* mmd */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); ++ ++ /* lf_mode */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); ++ ++ /* const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); ++ ++ /* const sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); ++ ++ /* pllmod */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); ++} ++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */ ++ ++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE ++static void ++pcie_phy_36mhz_ssc_mode_setup(int pcie_port) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); ++ ++ /* PLL Setting */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF); ++ ++ /* Increase the bias reference voltage */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF); ++ ++ /* Endcnt */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF); ++ ++ /* Force */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008); ++ ++ /* Predrv_ser_en */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF); ++ ++ /* ctrl_lim */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF); ++ ++ /* ctrl */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00); ++ ++ /* predrv_ser_en */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00); ++ ++ /* RTERM*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF); ++ ++ /* en_ext_mmd_div_ratio */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); ++ ++ /* ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); ++ ++ /* pll_ensdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0400, 0x0400); ++ ++ /* en_const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); ++ ++ /* mmd */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); ++ ++ /* lf_mode */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); ++ ++ /* const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); ++ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0100); ++ /* const sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); ++ ++ /* pllmod */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1c72, 0xFFFF); ++ ++ /* improved 100MHz clock output */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF); ++ ++ /* reduced CDR BW to avoid glitches */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); ++} ++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE */ ++ ++#ifdef CONFIG_IFX_PCIE_PHY_25MHZ_MODE ++static void ++pcie_phy_25mhz_mode_setup(int pcie_port) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); ++ /* en_const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); ++ ++ /* pll_ensdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0200); ++ ++ /* en_ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0002, 0x0002); ++ ++ /* ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0040, 0x0070); ++ ++ /* mmd */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x6000, 0xe000); ++ ++ /* lf_mode */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x4000, 0x4000); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); ++} ++#endif /* CONFIG_IFX_PCIE_PHY_25MHZ_MODE */ ++ ++#ifdef CONFIG_IFX_PCIE_PHY_100MHZ_MODE ++static void ++pcie_phy_100mhz_mode_setup(int pcie_port) ++{ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port); ++ /* en_ext_mmd_div_ratio */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002); ++ ++ /* ext_mmd_div_ratio*/ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070); ++ ++ /* pll_ensdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200); ++ ++ /* en_const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100); ++ ++ /* mmd */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000); ++ ++ /* lf_mode */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000); ++ ++ /* const_sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF); ++ ++ /* const sdm */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF); ++ ++ /* pllmod */ ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port); ++} ++#endif /* CONFIG_IFX_PCIE_PHY_100MHZ_MODE */ ++ ++static int ++pcie_phy_wait_startup_ready(int pcie_port) ++{ ++ int i; ++ ++ for (i = 0; i < IFX_PCIE_PLL_TIMEOUT; i++) { ++ if ((IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_STATUS(pcie_port)) & 0x0040) != 0) { ++ break; ++ } ++ udelay(10); ++ } ++ if (i >= IFX_PCIE_PLL_TIMEOUT) { ++ printk(KERN_ERR "%s PLL Link timeout\n", __func__); ++ return -1; ++ } ++ return 0; ++} ++ ++static void ++pcie_phy_load_enable(int pcie_port, int slice) ++{ ++ /* Set the load_en of tx/rx slice to '1' */ ++ switch (slice) { ++ case 1: ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0010, 0x0010); ++ break; ++ case 2: ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0010, 0x0010); ++ break; ++ case 3: ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0002, 0x0002); ++ break; ++ } ++} ++ ++static void ++pcie_phy_load_disable(int pcie_port, int slice) ++{ ++ /* set the load_en of tx/rx slice to '0' */ ++ switch (slice) { ++ case 1: ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0000, 0x0010); ++ break; ++ case 2: ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0000, 0x0010); ++ break; ++ case 3: ++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0000, 0x0002); ++ break; ++ } ++} ++ ++static void pcie_phy_load_war(int pcie_port) ++{ ++ int slice; ++ ++ for (slice = 1; slice < 4; slice++) { ++ pcie_phy_load_enable(pcie_port, slice); ++ udelay(1); ++ pcie_phy_load_disable(pcie_port, slice); ++ } ++} ++ ++static void pcie_phy_tx2_modulation(int pcie_port) ++{ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD1(pcie_port), 0x1FFE, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD2(pcie_port), 0xFFFE, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0601, 0xFFFF); ++ mdelay(1); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0001, 0xFFFF); ++} ++ ++static void pcie_phy_tx1_modulation(int pcie_port) ++{ ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD1(pcie_port), 0x1FFE, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD2(pcie_port), 0xFFFE, 0xFFFF); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0601, 0xFFFF); ++ mdelay(1); ++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0001, 0xFFFF); ++} ++ ++static void pcie_phy_tx_modulation_war(int pcie_port) ++{ ++ int i; ++#define PCIE_PHY_MODULATION_NUM 5 ++ for (i = 0; i < PCIE_PHY_MODULATION_NUM; i++) { ++ pcie_phy_tx2_modulation(pcie_port); ++ pcie_phy_tx1_modulation(pcie_port); ++ } ++#undef PCIE_PHY_MODULATION_NUM ++} ++ ++void pcie_phy_clock_mode_setup(int pcie_port) ++{ ++ pcie_pdi_big_endian(pcie_port); ++ ++ /* Enable PDI to access PCIe PHY register */ ++ pcie_pdi_pmu_enable(pcie_port); ++ ++ /* Configure PLL and PHY clock */ ++ pcie_phy_comm_setup(pcie_port); ++ ++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE ++ pcie_phy_36mhz_mode_setup(pcie_port); ++#elif defined(CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE) ++ pcie_phy_36mhz_ssc_mode_setup(pcie_port); ++#elif defined(CONFIG_IFX_PCIE_PHY_25MHZ_MODE) ++ pcie_phy_25mhz_mode_setup(pcie_port); ++#elif defined (CONFIG_IFX_PCIE_PHY_100MHZ_MODE) ++ pcie_phy_100mhz_mode_setup(pcie_port); ++#else ++ #error "PCIE PHY Clock Mode must be chosen first!!!!" ++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */ ++ ++ /* Enable PCIe PHY and make PLL setting take effect */ ++ pcie_phy_pmu_enable(pcie_port); ++ ++ /* Check if we are in startup_ready status */ ++ pcie_phy_wait_startup_ready(pcie_port); ++ ++ pcie_phy_load_war(pcie_port); ++ ++ /* Apply TX modulation workarounds */ ++ pcie_phy_tx_modulation_war(pcie_port); ++ ++#ifdef IFX_PCI_PHY_REG_DUMP ++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "Modified PHY register dump\n"); ++ pcie_phy_reg_dump(pcie_port); ++#endif ++} ++ +diff --git a/arch/mips/pci/pcie-lantiq.c b/arch/mips/pci/pcie-lantiq.c +new file mode 100644 +index 0000000..1df55b5 +--- /dev/null ++++ b/arch/mips/pci/pcie-lantiq.c +@@ -0,0 +1,1146 @@ ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/mm.h> ++#include <asm/paccess.h> ++#include <linux/pci.h> ++#include <linux/pci_regs.h> ++#include <linux/platform_device.h> ++ ++#define CONFIG_IFX_PCIE_1ST_CORE ++ ++#include "pcie-lantiq.h" ++ ++#define IFX_PCIE_IR (INT_NUM_IM4_IRL0 + 25) ++#define IFX_PCIE_INTA (INT_NUM_IM4_IRL0 + 8) ++#define IFX_PCIE_INTB (INT_NUM_IM4_IRL0 + 9) ++#define IFX_PCIE_INTC (INT_NUM_IM4_IRL0 + 10) ++#define IFX_PCIE_INTD (INT_NUM_IM4_IRL0 + 11) ++#define MS(_v, _f) (((_v) & (_f)) >> _f##_S) ++#define SM(_v, _f) (((_v) << _f##_S) & (_f)) ++#define IFX_REG_SET_BIT(_f, _r) \ ++ IFX_REG_W32((IFX_REG_R32((_r)) &~ (_f)) | (_f), (_r)) ++#define IFX_PCIE_LTSSM_ENABLE_TIMEOUT 10 ++#define IFX_PCIE_PHY_LINK_UP_TIMEOUT 1000 ++#define IFX_PCIE_PHY_LOOP_CNT 5 ++ ++static DEFINE_SPINLOCK(ifx_pcie_lock); ++ ++int pcibios_1st_host_bus_nr(void); ++ ++unsigned int g_pcie_debug_flag = PCIE_MSG_ANY & (~PCIE_MSG_CFG); ++ ++static ifx_pcie_irq_t pcie_irqs[IFX_PCIE_CORE_NR] = { ++ { ++ .ir_irq = { ++ .irq = IFX_PCIE_IR, ++ .name = "ifx_pcie_rc0", ++ }, ++ ++ .legacy_irq = { ++ { ++ .irq_bit = PCIE_IRN_INTA, ++ .irq = IFX_PCIE_INTA, ++ }, ++ { ++ .irq_bit = PCIE_IRN_INTB, ++ .irq = IFX_PCIE_INTB, ++ }, ++ { ++ .irq_bit = PCIE_IRN_INTC, ++ .irq = IFX_PCIE_INTC, ++ }, ++ { ++ .irq_bit = PCIE_IRN_INTD, ++ .irq = IFX_PCIE_INTD, ++ }, ++ }, ++ }, ++}; ++ ++static inline int pcie_ltssm_enable(int pcie_port) ++{ ++ int i; ++ ++ IFX_REG_W32(PCIE_RC_CCR_LTSSM_ENABLE, PCIE_RC_CCR(pcie_port)); /* Enable LTSSM */ ++ ++ /* Wait for the link to come up */ ++ for (i = 0; i < IFX_PCIE_LTSSM_ENABLE_TIMEOUT; i++) { ++ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_RETRAIN_PENDING)) { ++ break; ++ } ++ udelay(10); ++ } ++ if (i >= IFX_PCIE_LTSSM_ENABLE_TIMEOUT) { ++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s link timeout!!!!!\n", __func__); ++ return -1; ++ } ++ return 0; ++} ++ ++static inline void pcie_status_register_clear(int pcie_port) ++{ ++ IFX_REG_W32(0, PCIE_RC_DR(pcie_port)); ++ IFX_REG_W32(0, PCIE_PCICMDSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_DCTLSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_LCTLSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_SLCTLSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_RSTS(pcie_port)); ++ IFX_REG_W32(0, PCIE_UES_R(pcie_port)); ++ IFX_REG_W32(0, PCIE_UEMR(pcie_port)); ++ IFX_REG_W32(0, PCIE_UESR(pcie_port)); ++ IFX_REG_W32(0, PCIE_CESR(pcie_port)); ++ IFX_REG_W32(0, PCIE_CEMR(pcie_port)); ++ IFX_REG_W32(0, PCIE_RESR(pcie_port)); ++ IFX_REG_W32(0, PCIE_PVCCRSR(pcie_port)); ++ IFX_REG_W32(0, PCIE_VC0_RSR0(pcie_port)); ++ IFX_REG_W32(0, PCIE_TPFCS(pcie_port)); ++ IFX_REG_W32(0, PCIE_TNPFCS(pcie_port)); ++ IFX_REG_W32(0, PCIE_TCFCS(pcie_port)); ++ IFX_REG_W32(0, PCIE_QSR(pcie_port)); ++ IFX_REG_W32(0, PCIE_IOBLSECS(pcie_port)); ++} ++ ++static inline int ifx_pcie_link_up(int pcie_port) ++{ ++ return (IFX_REG_R32(PCIE_PHY_SR(pcie_port)) & PCIE_PHY_SR_PHY_LINK_UP) ? 1 : 0; ++} ++ ++static inline void pcie_mem_io_setup(int pcie_port) ++{ ++ unsigned int reg; ++ /* ++ * BAR[0:1] readonly register ++ * RC contains only minimal BARs for packets mapped to this device ++ * Mem/IO filters defines a range of memory occupied by memory mapped IO devices that ++ * reside on the downstream side fo the bridge. ++ */ ++ reg = SM((PCIE_MEM_PHY_PORT_TO_END(pcie_port) >> 20), PCIE_MBML_MEM_LIMIT_ADDR) ++ | SM((PCIE_MEM_PHY_PORT_TO_BASE(pcie_port) >> 20), PCIE_MBML_MEM_BASE_ADDR); ++ IFX_REG_W32(reg, PCIE_MBML(pcie_port)); ++ ++ /* PCIe_PBML, same as MBML */ ++ IFX_REG_W32(IFX_REG_R32(PCIE_MBML(pcie_port)), PCIE_PMBL(pcie_port)); ++ ++ /* IO Address Range */ ++ reg = SM((PCIE_IO_PHY_PORT_TO_END(pcie_port) >> 12), PCIE_IOBLSECS_IO_LIMIT_ADDR) ++ | SM((PCIE_IO_PHY_PORT_TO_BASE(pcie_port) >> 12), PCIE_IOBLSECS_IO_BASE_ADDR); ++ reg |= PCIE_IOBLSECS_32BIT_IO_ADDR; ++ IFX_REG_W32(reg, PCIE_IOBLSECS(pcie_port)); ++ ++ reg = SM((PCIE_IO_PHY_PORT_TO_END(pcie_port) >> 16), PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT) ++ | SM((PCIE_IO_PHY_PORT_TO_BASE(pcie_port) >> 16), PCIE_IO_BANDL_UPPER_16BIT_IO_BASE); ++ IFX_REG_W32(reg, PCIE_IO_BANDL(pcie_port)); ++} ++ ++static inline void pcie_msi_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* XXX, MSI stuff should only apply to EP */ ++ /* MSI Capability: Only enable 32-bit addresses */ ++ reg = IFX_REG_R32(PCIE_MCAPR(pcie_port)); ++ reg &= ~PCIE_MCAPR_ADDR64_CAP; ++ reg |= PCIE_MCAPR_MSI_ENABLE; ++ ++ /* Disable multiple message */ ++ reg &= ~(PCIE_MCAPR_MULTI_MSG_CAP | PCIE_MCAPR_MULTI_MSG_ENABLE); ++ IFX_REG_W32(reg, PCIE_MCAPR(pcie_port)); ++} ++ ++static inline void pcie_pm_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* Enable PME, Soft reset enabled */ ++ reg = IFX_REG_R32(PCIE_PM_CSR(pcie_port)); ++ reg |= PCIE_PM_CSR_PME_ENABLE | PCIE_PM_CSR_SW_RST; ++ IFX_REG_W32(reg, PCIE_PM_CSR(pcie_port)); ++} ++ ++static inline void pcie_bus_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ reg = SM(0, PCIE_BNR_PRIMARY_BUS_NUM) | SM(1, PCIE_PNR_SECONDARY_BUS_NUM) | SM(0xFF, PCIE_PNR_SUB_BUS_NUM); ++ IFX_REG_W32(reg, PCIE_BNR(pcie_port)); ++} ++ ++static inline void pcie_device_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* Device capability register, set up Maximum payload size */ ++ reg = IFX_REG_R32(PCIE_DCAP(pcie_port)); ++ reg |= PCIE_DCAP_ROLE_BASE_ERR_REPORT; ++ reg |= SM(PCIE_MAX_PAYLOAD_128, PCIE_DCAP_MAX_PAYLOAD_SIZE); ++ ++ /* Only available for EP */ ++ reg &= ~(PCIE_DCAP_EP_L0S_LATENCY | PCIE_DCAP_EP_L1_LATENCY); ++ IFX_REG_W32(reg, PCIE_DCAP(pcie_port)); ++ ++ /* Device control and status register */ ++ /* Set Maximum Read Request size for the device as a Requestor */ ++ reg = IFX_REG_R32(PCIE_DCTLSTS(pcie_port)); ++ ++ /* ++ * Request size can be larger than the MPS used, but the completions returned ++ * for the read will be bounded by the MPS size. ++ * In our system, Max request size depends on AHB burst size. It is 64 bytes. ++ * but we set it as 128 as minimum one. ++ */ ++ reg |= SM(PCIE_MAX_PAYLOAD_128, PCIE_DCTLSTS_MAX_READ_SIZE) ++ | SM(PCIE_MAX_PAYLOAD_128, PCIE_DCTLSTS_MAX_PAYLOAD_SIZE); ++ ++ /* Enable relaxed ordering, no snoop, and all kinds of errors */ ++ reg |= PCIE_DCTLSTS_RELAXED_ORDERING_EN | PCIE_DCTLSTS_ERR_EN | PCIE_DCTLSTS_NO_SNOOP_EN; ++ ++ IFX_REG_W32(reg, PCIE_DCTLSTS(pcie_port)); ++} ++ ++static inline void pcie_link_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* ++ * XXX, Link capability register, bit 18 for EP CLKREQ# dynamic clock management for L1, L2/3 CPM ++ * L0s is reported during link training via TS1 order set by N_FTS ++ */ ++ reg = IFX_REG_R32(PCIE_LCAP(pcie_port)); ++ reg &= ~PCIE_LCAP_L0S_EIXT_LATENCY; ++ reg |= SM(3, PCIE_LCAP_L0S_EIXT_LATENCY); ++ IFX_REG_W32(reg, PCIE_LCAP(pcie_port)); ++ ++ /* Link control and status register */ ++ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port)); ++ ++ /* Link Enable, ASPM enabled */ ++ reg &= ~PCIE_LCTLSTS_LINK_DISABLE; ++ ++#ifdef CONFIG_PCIEASPM ++ /* ++ * We use the same physical reference clock that the platform provides on the connector ++ * It paved the way for ASPM to calculate the new exit Latency ++ */ ++ reg |= PCIE_LCTLSTS_SLOT_CLK_CFG; ++ reg |= PCIE_LCTLSTS_COM_CLK_CFG; ++ /* ++ * We should disable ASPM by default except that we have dedicated power management support ++ * Enable ASPM will cause the system hangup/instability, performance degration ++ */ ++ reg |= PCIE_LCTLSTS_ASPM_ENABLE; ++#else ++ reg &= ~PCIE_LCTLSTS_ASPM_ENABLE; ++#endif /* CONFIG_PCIEASPM */ ++ ++ /* ++ * The maximum size of any completion with data packet is bounded by the MPS setting ++ * in device control register ++ */ ++ /* RCB may cause multiple split transactions, two options available, we use 64 byte RCB */ ++ reg &= ~ PCIE_LCTLSTS_RCB128; ++ IFX_REG_W32(reg, PCIE_LCTLSTS(pcie_port)); ++} ++ ++static inline void pcie_error_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* ++ * Forward ERR_COR, ERR_NONFATAL, ERR_FATAL to the backbone ++ * Poisoned write TLPs and completions indicating poisoned TLPs will set the PCIe_PCICMDSTS.MDPE ++ */ ++ reg = IFX_REG_R32(PCIE_INTRBCTRL(pcie_port)); ++ reg |= PCIE_INTRBCTRL_SERR_ENABLE | PCIE_INTRBCTRL_PARITY_ERR_RESP_ENABLE; ++ ++ IFX_REG_W32(reg, PCIE_INTRBCTRL(pcie_port)); ++ ++ /* Uncorrectable Error Mask Register, Unmask <enable> all bits in PCIE_UESR */ ++ reg = IFX_REG_R32(PCIE_UEMR(pcie_port)); ++ reg &= ~PCIE_ALL_UNCORRECTABLE_ERR; ++ IFX_REG_W32(reg, PCIE_UEMR(pcie_port)); ++ ++ /* Uncorrectable Error Severity Register, ALL errors are FATAL */ ++ IFX_REG_W32(PCIE_ALL_UNCORRECTABLE_ERR, PCIE_UESR(pcie_port)); ++ ++ /* Correctable Error Mask Register, unmask <enable> all bits */ ++ reg = IFX_REG_R32(PCIE_CEMR(pcie_port)); ++ reg &= ~PCIE_CORRECTABLE_ERR; ++ IFX_REG_W32(reg, PCIE_CEMR(pcie_port)); ++ ++ /* Advanced Error Capabilities and Control Registr */ ++ reg = IFX_REG_R32(PCIE_AECCR(pcie_port)); ++ reg |= PCIE_AECCR_ECRC_CHECK_EN | PCIE_AECCR_ECRC_GEN_EN; ++ IFX_REG_W32(reg, PCIE_AECCR(pcie_port)); ++ ++ /* Root Error Command Register, Report all types of errors */ ++ reg = IFX_REG_R32(PCIE_RECR(pcie_port)); ++ reg |= PCIE_RECR_ERR_REPORT_EN; ++ IFX_REG_W32(reg, PCIE_RECR(pcie_port)); ++ ++ /* Clear the Root status register */ ++ reg = IFX_REG_R32(PCIE_RESR(pcie_port)); ++ IFX_REG_W32(reg, PCIE_RESR(pcie_port)); ++} ++ ++static inline void pcie_root_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* Root control and capabilities register */ ++ reg = IFX_REG_R32(PCIE_RCTLCAP(pcie_port)); ++ reg |= PCIE_RCTLCAP_SERR_ENABLE | PCIE_RCTLCAP_PME_INT_EN; ++ IFX_REG_W32(reg, PCIE_RCTLCAP(pcie_port)); ++} ++ ++static inline void pcie_vc_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* Port VC Capability Register 2 */ ++ reg = IFX_REG_R32(PCIE_PVC2(pcie_port)); ++ reg &= ~PCIE_PVC2_VC_ARB_WRR; ++ reg |= PCIE_PVC2_VC_ARB_16P_FIXED_WRR; ++ IFX_REG_W32(reg, PCIE_PVC2(pcie_port)); ++ ++ /* VC0 Resource Capability Register */ ++ reg = IFX_REG_R32(PCIE_VC0_RC(pcie_port)); ++ reg &= ~PCIE_VC0_RC_REJECT_SNOOP; ++ IFX_REG_W32(reg, PCIE_VC0_RC(pcie_port)); ++} ++ ++static inline void pcie_port_logic_setup(int pcie_port) ++{ ++ unsigned int reg; ++ ++ /* FTS number, default 12, increase to 63, may increase time from/to L0s to L0 */ ++ reg = IFX_REG_R32(PCIE_AFR(pcie_port)); ++ reg &= ~(PCIE_AFR_FTS_NUM | PCIE_AFR_COM_FTS_NUM); ++ reg |= SM(PCIE_AFR_FTS_NUM_DEFAULT, PCIE_AFR_FTS_NUM) ++ | SM(PCIE_AFR_FTS_NUM_DEFAULT, PCIE_AFR_COM_FTS_NUM); ++ /* L0s and L1 entry latency */ ++ reg &= ~(PCIE_AFR_L0S_ENTRY_LATENCY | PCIE_AFR_L1_ENTRY_LATENCY); ++ reg |= SM(PCIE_AFR_L0S_ENTRY_LATENCY_DEFAULT, PCIE_AFR_L0S_ENTRY_LATENCY) ++ | SM(PCIE_AFR_L1_ENTRY_LATENCY_DEFAULT, PCIE_AFR_L1_ENTRY_LATENCY); ++ IFX_REG_W32(reg, PCIE_AFR(pcie_port)); ++ ++ /* Port Link Control Register */ ++ reg = IFX_REG_R32(PCIE_PLCR(pcie_port)); ++ reg |= PCIE_PLCR_DLL_LINK_EN; /* Enable the DLL link */ ++ IFX_REG_W32(reg, PCIE_PLCR(pcie_port)); ++ ++ /* Lane Skew Register */ ++ reg = IFX_REG_R32(PCIE_LSR(pcie_port)); ++ /* Enable ACK/NACK and FC */ ++ reg &= ~(PCIE_LSR_ACKNAK_DISABLE | PCIE_LSR_FC_DISABLE); ++ IFX_REG_W32(reg, PCIE_LSR(pcie_port)); ++ ++ /* Symbol Timer Register and Filter Mask Register 1 */ ++ reg = IFX_REG_R32(PCIE_STRFMR(pcie_port)); ++ ++ /* Default SKP interval is very accurate already, 5us */ ++ /* Enable IO/CFG transaction */ ++ reg |= PCIE_STRFMR_RX_CFG_TRANS_ENABLE | PCIE_STRFMR_RX_IO_TRANS_ENABLE; ++ /* Disable FC WDT */ ++ reg &= ~PCIE_STRFMR_FC_WDT_DISABLE; ++ IFX_REG_W32(reg, PCIE_STRFMR(pcie_port)); ++ ++ /* Filter Masker Register 2 */ ++ reg = IFX_REG_R32(PCIE_FMR2(pcie_port)); ++ reg |= PCIE_FMR2_VENDOR_MSG1_PASSED_TO_TRGT1 | PCIE_FMR2_VENDOR_MSG0_PASSED_TO_TRGT1; ++ IFX_REG_W32(reg, PCIE_FMR2(pcie_port)); ++ ++ /* VC0 Completion Receive Queue Control Register */ ++ reg = IFX_REG_R32(PCIE_VC0_CRQCR(pcie_port)); ++ reg &= ~PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE; ++ reg |= SM(PCIE_VC0_TLP_QUEUE_MODE_BYPASS, PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE); ++ IFX_REG_W32(reg, PCIE_VC0_CRQCR(pcie_port)); ++} ++ ++static inline void pcie_rc_cfg_reg_setup(int pcie_port) ++{ ++ /* diable ltssm */ ++ IFX_REG_W32(0, PCIE_RC_CCR(pcie_port)); ++ ++ pcie_mem_io_setup(pcie_port); ++ pcie_msi_setup(pcie_port); ++ pcie_pm_setup(pcie_port); ++ pcie_bus_setup(pcie_port); ++ pcie_device_setup(pcie_port); ++ pcie_link_setup(pcie_port); ++ pcie_error_setup(pcie_port); ++ pcie_root_setup(pcie_port); ++ pcie_vc_setup(pcie_port); ++ pcie_port_logic_setup(pcie_port); ++} ++ ++static int ifx_pcie_wait_phy_link_up(int pcie_port) ++{ ++ int i; ++ ++ /* Wait for PHY link is up */ ++ for (i = 0; i < IFX_PCIE_PHY_LINK_UP_TIMEOUT; i++) { ++ if (ifx_pcie_link_up(pcie_port)) { ++ break; ++ } ++ udelay(100); ++ } ++ if (i >= IFX_PCIE_PHY_LINK_UP_TIMEOUT) { ++ printk(KERN_ERR "%s timeout\n", __func__); ++ return -1; ++ } ++ ++ /* Check data link up or not */ ++ if (!(IFX_REG_R32(PCIE_RC_DR(pcie_port)) & PCIE_RC_DR_DLL_UP)) { ++ printk(KERN_ERR "%s DLL link is still down\n", __func__); ++ return -1; ++ } ++ ++ /* Check Data link active or not */ ++ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_DLL_ACTIVE)) { ++ printk(KERN_ERR "%s DLL is not active\n", __func__); ++ return -1; ++ } ++ return 0; ++} ++ ++static inline int pcie_app_loigc_setup(int pcie_port) ++{ ++ IFX_REG_W32(PCIE_AHB_CTRL_BUS_ERROR_SUPPRESS, PCIE_AHB_CTRL(pcie_port)); ++ ++ /* Pull PCIe EP out of reset */ ++ pcie_device_rst_deassert(pcie_port); ++ ++ /* Start LTSSM training between RC and EP */ ++ pcie_ltssm_enable(pcie_port); ++ ++ /* Check PHY status after enabling LTSSM */ ++ if (ifx_pcie_wait_phy_link_up(pcie_port) != 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * Must be done after ltssm due to based on negotiated link ++ * width and payload size ++ * Update the Replay Time Limit. Empirically, some PCIe ++ * devices take a little longer to respond than expected under ++ * load. As a workaround for this we configure the Replay Time ++ * Limit to the value expected for a 512 byte MPS instead of ++ * our actual 128 byte MPS. The numbers below are directly ++ * from the PCIe spec table 3-4/5. ++ */ ++static inline void pcie_replay_time_update(int pcie_port) ++{ ++ unsigned int reg; ++ int nlw; ++ int rtl; ++ ++ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port)); ++ ++ nlw = MS(reg, PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH); ++ switch (nlw) { ++ case PCIE_MAX_LENGTH_WIDTH_X1: ++ rtl = 1677; ++ break; ++ case PCIE_MAX_LENGTH_WIDTH_X2: ++ rtl = 867; ++ break; ++ case PCIE_MAX_LENGTH_WIDTH_X4: ++ rtl = 462; ++ break; ++ case PCIE_MAX_LENGTH_WIDTH_X8: ++ rtl = 258; ++ break; ++ default: ++ rtl = 1677; ++ break; ++ } ++ reg = IFX_REG_R32(PCIE_ALTRT(pcie_port)); ++ reg &= ~PCIE_ALTRT_REPLAY_TIME_LIMIT; ++ reg |= SM(rtl, PCIE_ALTRT_REPLAY_TIME_LIMIT); ++ IFX_REG_W32(reg, PCIE_ALTRT(pcie_port)); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_ALTRT 0x%08x\n", ++ __func__, IFX_REG_R32(PCIE_ALTRT(pcie_port))); ++} ++ ++/* ++ * Table 359 Enhanced Configuration Address Mapping1) ++ * 1) This table is defined in Table 7-1, page 341, PCI Express Base Specification v1.1 ++ * Memory Address PCI Express Configuration Space ++ * A[(20+n-1):20] Bus Number 1 < n < 8 ++ * A[19:15] Device Number ++ * A[14:12] Function Number ++ * A[11:8] Extended Register Number ++ * A[7:2] Register Number ++ * A[1:0] Along with size of the access, used to generate Byte Enables ++ * For VR9, only the address bits [22:0] are mapped to the configuration space: ++ * . Address bits [22:20] select the target bus (1-of-8)1) ++ * . Address bits [19:15] select the target device (1-of-32) on the bus ++ * . Address bits [14:12] select the target function (1-of-8) within the device. ++ * . Address bits [11:2] selects the target dword (1-of-1024) within the selected function.s configuration space ++ * . Address bits [1:0] define the start byte location within the selected dword. ++ */ ++static inline unsigned int pcie_bus_addr(u8 bus_num, u16 devfn, int where) ++{ ++ unsigned int addr; ++ u8 bus; ++ ++ if (!bus_num) { ++ /* type 0 */ ++ addr = ((PCI_SLOT(devfn) & 0x1F) << 15) | ((PCI_FUNC(devfn) & 0x7) << 12) | ((where & 0xFFF)& ~3); ++ } else { ++ bus = bus_num; ++ /* type 1, only support 8 buses */ ++ addr = ((bus & 0x7) << 20) | ((PCI_SLOT(devfn) & 0x1F) << 15) | ++ ((PCI_FUNC(devfn) & 0x7) << 12) | ((where & 0xFFF) & ~3); ++ } ++ IFX_PCIE_PRINT(PCIE_MSG_CFG, "%s: bus addr : %02x:%02x.%01x/%02x, addr=%08x\n", ++ __func__, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), where, addr); ++ return addr; ++} ++ ++static int pcie_valid_config(int pcie_port, int bus, int dev) ++{ ++ /* RC itself */ ++ if ((bus == 0) && (dev == 0)) ++ return 1; ++ ++ /* No physical link */ ++ if (!ifx_pcie_link_up(pcie_port)) ++ return 0; ++ ++ /* Bus zero only has RC itself ++ * XXX, check if EP will be integrated ++ */ ++ if ((bus == 0) && (dev != 0)) ++ return 0; ++ ++ /* Maximum 8 buses supported for VRX */ ++ if (bus > 9) ++ return 0; ++ ++ /* ++ * PCIe is PtP link, one bus only supports only one device ++ * except bus zero and PCIe switch which is virtual bus device ++ * The following two conditions really depends on the system design ++ * and attached the device. ++ * XXX, how about more new switch ++ */ ++ if ((bus == 1) && (dev != 0)) ++ return 0; ++ ++ if ((bus >= 3) && (dev != 0)) ++ return 0; ++ return 1; ++} ++ ++static inline unsigned int ifx_pcie_cfg_rd(int pcie_port, unsigned int reg) ++{ ++ return IFX_REG_R32((volatile unsigned int *)(PCIE_CFG_PORT_TO_BASE(pcie_port) + reg)); ++} ++ ++static inline void ifx_pcie_cfg_wr(int pcie_port, unsigned int reg, unsigned int val) ++{ ++ IFX_REG_W32( val, (volatile unsigned int *)(PCIE_CFG_PORT_TO_BASE(pcie_port) + reg)); ++} ++ ++static inline unsigned int ifx_pcie_rc_cfg_rd(int pcie_port, unsigned int reg) ++{ ++ return IFX_REG_R32((volatile unsigned int *)(PCIE_RC_PORT_TO_BASE(pcie_port) + reg)); ++} ++ ++static inline void ifx_pcie_rc_cfg_wr(int pcie_port, unsigned int reg, unsigned int val) ++{ ++ IFX_REG_W32(val, (volatile unsigned int *)(PCIE_RC_PORT_TO_BASE(pcie_port) + reg)); ++} ++ ++unsigned int ifx_pcie_bus_enum_read_hack(int where, unsigned int value) ++{ ++ unsigned int tvalue = value; ++ ++ if (where == PCI_PRIMARY_BUS) { ++ u8 primary, secondary, subordinate; ++ ++ primary = tvalue & 0xFF; ++ secondary = (tvalue >> 8) & 0xFF; ++ subordinate = (tvalue >> 16) & 0xFF; ++ primary += pcibios_1st_host_bus_nr(); ++ secondary += pcibios_1st_host_bus_nr(); ++ subordinate += pcibios_1st_host_bus_nr(); ++ tvalue = (tvalue & 0xFF000000) | (unsigned int)primary | (unsigned int)(secondary << 8) | (unsigned int)(subordinate << 16); ++ } ++ return tvalue; ++} ++ ++unsigned int ifx_pcie_bus_enum_write_hack(int where, unsigned int value) ++{ ++ unsigned int tvalue = value; ++ ++ if (where == PCI_PRIMARY_BUS) { ++ u8 primary, secondary, subordinate; ++ ++ primary = tvalue & 0xFF; ++ secondary = (tvalue >> 8) & 0xFF; ++ subordinate = (tvalue >> 16) & 0xFF; ++ if (primary > 0 && primary != 0xFF) ++ primary -= pcibios_1st_host_bus_nr(); ++ if (secondary > 0 && secondary != 0xFF) ++ secondary -= pcibios_1st_host_bus_nr(); ++ if (subordinate > 0 && subordinate != 0xFF) ++ subordinate -= pcibios_1st_host_bus_nr(); ++ tvalue = (tvalue & 0xFF000000) | (unsigned int)primary | (unsigned int)(secondary << 8) | (unsigned int)(subordinate << 16); ++ } else if (where == PCI_SUBORDINATE_BUS) { ++ u8 subordinate = tvalue & 0xFF; ++ subordinate = subordinate > 0 ? subordinate - pcibios_1st_host_bus_nr() : 0; ++ tvalue = subordinate; ++ } ++ return tvalue; ++} ++ ++/** ++ * \fn static int ifx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, ++ * int where, int size, unsigned int *value) ++ * \brief Read a value from configuration space ++ * ++ * \param[in] bus Pointer to pci bus ++ * \param[in] devfn PCI device function number ++ * \param[in] where PCI register number ++ * \param[in] size Register read size ++ * \param[out] value Pointer to return value ++ * \return PCIBIOS_BAD_REGISTER_NUMBER Invalid register number ++ * \return PCIBIOS_FUNC_NOT_SUPPORTED PCI function not supported ++ * \return PCIBIOS_DEVICE_NOT_FOUND PCI device not found ++ * \return PCIBIOS_SUCCESSFUL OK ++ * \ingroup IFX_PCIE_OS ++ */ ++static int ifx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int *value) ++{ ++ unsigned int data = 0; ++ int bus_number = bus->number; ++ static const unsigned int mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0}; ++ int ret = PCIBIOS_SUCCESSFUL; ++ struct ifx_pci_controller *ctrl = bus->sysdata; ++ int pcie_port = ctrl->port; ++ ++ if (unlikely(size != 1 && size != 2 && size != 4)){ ++ ret = PCIBIOS_BAD_REGISTER_NUMBER; ++ goto out; ++ } ++ ++ /* Make sure the address is aligned to natural boundary */ ++ if (unlikely(((size - 1) & where))) { ++ ret = PCIBIOS_BAD_REGISTER_NUMBER; ++ goto out; ++ } ++ ++ /* ++ * If we are second controller, we have to cheat OS so that it assume ++ * its bus number starts from 0 in host controller ++ */ ++ bus_number = ifx_pcie_bus_nr_deduct(bus_number, pcie_port); ++ ++ /* ++ * We need to force the bus number to be zero on the root ++ * bus. Linux numbers the 2nd root bus to start after all ++ * busses on root 0. ++ */ ++ if (bus->parent == NULL) ++ bus_number = 0; ++ ++ /* ++ * PCIe only has a single device connected to it. It is ++ * always device ID 0. Don't bother doing reads for other ++ * device IDs on the first segment. ++ */ ++ if ((bus_number == 0) && (PCI_SLOT(devfn) != 0)) { ++ ret = PCIBIOS_FUNC_NOT_SUPPORTED; ++ goto out; ++ } ++ ++ if (pcie_valid_config(pcie_port, bus_number, PCI_SLOT(devfn)) == 0) { ++ *value = 0xffffffff; ++ ret = PCIBIOS_DEVICE_NOT_FOUND; ++ goto out; ++ } ++ ++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: %02x:%02x.%01x/%02x:%01d\n", __func__, bus_number, ++ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); ++ ++ PCIE_IRQ_LOCK(ifx_pcie_lock); ++ if (bus_number == 0) { /* RC itself */ ++ unsigned int t; ++ ++ t = (where & ~3); ++ data = ifx_pcie_rc_cfg_rd(pcie_port, t); ++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: rd local cfg, offset:%08x, data:%08x\n", ++ __func__, t, data); ++ } else { ++ unsigned int addr = pcie_bus_addr(bus_number, devfn, where); ++ ++ data = ifx_pcie_cfg_rd(pcie_port, addr); ++ if (pcie_port == IFX_PCIE_PORT0) { ++#ifdef CONFIG_IFX_PCIE_HW_SWAP ++ data = le32_to_cpu(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } else { ++#ifdef CONFIG_IFX_PCIE1_HW_SWAP ++ data = le32_to_cpu(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } ++ } ++ /* To get a correct PCI topology, we have to restore the bus number to OS */ ++ data = ifx_pcie_bus_enum_hack(bus, devfn, where, data, pcie_port, 1); ++ ++ PCIE_IRQ_UNLOCK(ifx_pcie_lock); ++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: read config: data=%08x raw=%08x\n", ++ __func__, (data >> (8 * (where & 3))) & mask[size & 7], data); ++ ++ *value = (data >> (8 * (where & 3))) & mask[size & 7]; ++out: ++ return ret; ++} ++ ++static unsigned int ifx_pcie_size_to_value(int where, int size, unsigned int data, unsigned int value) ++{ ++ unsigned int shift; ++ unsigned int tdata = data; ++ ++ switch (size) { ++ case 1: ++ shift = (where & 0x3) << 3; ++ tdata &= ~(0xffU << shift); ++ tdata |= ((value & 0xffU) << shift); ++ break; ++ case 2: ++ shift = (where & 3) << 3; ++ tdata &= ~(0xffffU << shift); ++ tdata |= ((value & 0xffffU) << shift); ++ break; ++ case 4: ++ tdata = value; ++ break; ++ } ++ return tdata; ++} ++ ++/** ++ * \fn static static int ifx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, ++ * int where, int size, unsigned int value) ++ * \brief Write a value to PCI configuration space ++ * ++ * \param[in] bus Pointer to pci bus ++ * \param[in] devfn PCI device function number ++ * \param[in] where PCI register number ++ * \param[in] size The register size to be written ++ * \param[in] value The valule to be written ++ * \return PCIBIOS_BAD_REGISTER_NUMBER Invalid register number ++ * \return PCIBIOS_DEVICE_NOT_FOUND PCI device not found ++ * \return PCIBIOS_SUCCESSFUL OK ++ * \ingroup IFX_PCIE_OS ++ */ ++static int ifx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int value) ++{ ++ int bus_number = bus->number; ++ int ret = PCIBIOS_SUCCESSFUL; ++ struct ifx_pci_controller *ctrl = bus->sysdata; ++ int pcie_port = ctrl->port; ++ unsigned int tvalue = value; ++ unsigned int data; ++ ++ /* Make sure the address is aligned to natural boundary */ ++ if (unlikely(((size - 1) & where))) { ++ ret = PCIBIOS_BAD_REGISTER_NUMBER; ++ goto out; ++ } ++ /* ++ * If we are second controller, we have to cheat OS so that it assume ++ * its bus number starts from 0 in host controller ++ */ ++ bus_number = ifx_pcie_bus_nr_deduct(bus_number, pcie_port); ++ ++ /* ++ * We need to force the bus number to be zero on the root ++ * bus. Linux numbers the 2nd root bus to start after all ++ * busses on root 0. ++ */ ++ if (bus->parent == NULL) ++ bus_number = 0; ++ ++ if (pcie_valid_config(pcie_port, bus_number, PCI_SLOT(devfn)) == 0) { ++ ret = PCIBIOS_DEVICE_NOT_FOUND; ++ goto out; ++ } ++ ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: %02x:%02x.%01x/%02x:%01d value=%08x\n", __func__, ++ bus_number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value); ++ ++ /* XXX, some PCIe device may need some delay */ ++ PCIE_IRQ_LOCK(ifx_pcie_lock); ++ ++ /* ++ * To configure the correct bus topology using native way, we have to cheat Os so that ++ * it can configure the PCIe hardware correctly. ++ */ ++ tvalue = ifx_pcie_bus_enum_hack(bus, devfn, where, value, pcie_port, 0); ++ ++ if (bus_number == 0) { /* RC itself */ ++ unsigned int t; ++ ++ t = (where & ~3); ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr local cfg, offset:%08x, fill:%08x\n", __func__, t, value); ++ data = ifx_pcie_rc_cfg_rd(pcie_port, t); ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd local cfg, offset:%08x, data:%08x\n", __func__, t, data); ++ ++ data = ifx_pcie_size_to_value(where, size, data, tvalue); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr local cfg, offset:%08x, value:%08x\n", __func__, t, data); ++ ifx_pcie_rc_cfg_wr(pcie_port, t, data); ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd local cfg, offset:%08x, value:%08x\n", ++ __func__, t, ifx_pcie_rc_cfg_rd(pcie_port, t)); ++ } else { ++ unsigned int addr = pcie_bus_addr(bus_number, devfn, where); ++ ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr cfg, offset:%08x, fill:%08x\n", __func__, addr, value); ++ data = ifx_pcie_cfg_rd(pcie_port, addr); ++ if (pcie_port == IFX_PCIE_PORT0) { ++#ifdef CONFIG_IFX_PCIE_HW_SWAP ++ data = le32_to_cpu(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } else { ++#ifdef CONFIG_IFX_PCIE1_HW_SWAP ++ data = le32_to_cpu(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd cfg, offset:%08x, data:%08x\n", __func__, addr, data); ++ ++ data = ifx_pcie_size_to_value(where, size, data, tvalue); ++ if (pcie_port == IFX_PCIE_PORT0) { ++#ifdef CONFIG_IFX_PCIE_HW_SWAP ++ data = cpu_to_le32(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } else { ++#ifdef CONFIG_IFX_PCIE1_HW_SWAP ++ data = cpu_to_le32(data); ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ } ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: wr cfg, offset:%08x, value:%08x\n", __func__, addr, data); ++ ifx_pcie_cfg_wr(pcie_port, addr, data); ++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: rd cfg, offset:%08x, value:%08x\n", ++ __func__, addr, ifx_pcie_cfg_rd(pcie_port, addr)); ++ } ++ PCIE_IRQ_UNLOCK(ifx_pcie_lock); ++out: ++ return ret; ++} ++ ++static struct resource ifx_pcie_io_resource = { ++ .name = "PCIe0 I/O space", ++ .start = PCIE_IO_PHY_BASE, ++ .end = PCIE_IO_PHY_END, ++ .flags = IORESOURCE_IO, ++}; ++ ++static struct resource ifx_pcie_mem_resource = { ++ .name = "PCIe0 Memory space", ++ .start = PCIE_MEM_PHY_BASE, ++ .end = PCIE_MEM_PHY_END, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct pci_ops ifx_pcie_ops = { ++ .read = ifx_pcie_read_config, ++ .write = ifx_pcie_write_config, ++}; ++ ++static struct ifx_pci_controller ifx_pcie_controller[IFX_PCIE_CORE_NR] = { ++ { ++ .pcic = { ++ .pci_ops = &ifx_pcie_ops, ++ .mem_resource = &ifx_pcie_mem_resource, ++ .io_resource = &ifx_pcie_io_resource, ++ }, ++ .port = IFX_PCIE_PORT0, ++ }, ++}; ++ ++static inline void pcie_core_int_clear_all(int pcie_port) ++{ ++ unsigned int reg; ++ reg = IFX_REG_R32(PCIE_IRNCR(pcie_port)); ++ reg &= PCIE_RC_CORE_COMBINED_INT; ++ IFX_REG_W32(reg, PCIE_IRNCR(pcie_port)); ++} ++ ++static irqreturn_t pcie_rc_core_isr(int irq, void *dev_id) ++{ ++ struct ifx_pci_controller *ctrl = (struct ifx_pci_controller *)dev_id; ++ int pcie_port = ctrl->port; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_ISR, "PCIe RC error intr %d\n", irq); ++ pcie_core_int_clear_all(pcie_port); ++ return IRQ_HANDLED; ++} ++ ++static int pcie_rc_core_int_init(int pcie_port) ++{ ++ int ret; ++ ++ /* Enable core interrupt */ ++ IFX_REG_SET_BIT(PCIE_RC_CORE_COMBINED_INT, PCIE_IRNEN(pcie_port)); ++ ++ /* Clear it first */ ++ IFX_REG_SET_BIT(PCIE_RC_CORE_COMBINED_INT, PCIE_IRNCR(pcie_port)); ++ ret = request_irq(pcie_irqs[pcie_port].ir_irq.irq, pcie_rc_core_isr, IRQF_DISABLED, ++ pcie_irqs[pcie_port].ir_irq.name, &ifx_pcie_controller[pcie_port]); ++ if (ret) ++ printk(KERN_ERR "%s request irq %d failed\n", __func__, IFX_PCIE_IR); ++ ++ return ret; ++} ++ ++int ifx_pcie_bios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ unsigned int irq_bit = 0; ++ int irq = 0; ++ struct ifx_pci_controller *ctrl = dev->bus->sysdata; ++ int pcie_port = ctrl->port; ++ ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s port %d dev %s slot %d pin %d \n", __func__, pcie_port, pci_name(dev), slot, pin); ++ ++ if ((pin == PCIE_LEGACY_DISABLE) || (pin > PCIE_LEGACY_INT_MAX)) { ++ printk(KERN_WARNING "WARNING: dev %s: invalid interrupt pin %d\n", pci_name(dev), pin); ++ return -1; ++ } ++ /* Pin index so minus one */ ++ irq_bit = pcie_irqs[pcie_port].legacy_irq[pin - 1].irq_bit; ++ irq = pcie_irqs[pcie_port].legacy_irq[pin - 1].irq; ++ IFX_REG_SET_BIT(irq_bit, PCIE_IRNEN(pcie_port)); ++ IFX_REG_SET_BIT(irq_bit, PCIE_IRNCR(pcie_port)); ++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s irq %d assigned\n", __func__, pci_name(dev), irq); ++ return irq; ++} ++ ++/** ++ * \fn int ifx_pcie_bios_plat_dev_init(struct pci_dev *dev) ++ * \brief Called to perform platform specific PCI setup ++ * ++ * \param[in] dev The Linux PCI device structure for the device to map ++ * \return OK ++ * \ingroup IFX_PCIE_OS ++ */ ++int ifx_pcie_bios_plat_dev_init(struct pci_dev *dev) ++{ ++ u16 config; ++ unsigned int dconfig; ++ int pos; ++ /* Enable reporting System errors and parity errors on all devices */ ++ /* Enable parity checking and error reporting */ ++ pci_read_config_word(dev, PCI_COMMAND, &config); ++ config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR /*| PCI_COMMAND_INVALIDATE | ++ PCI_COMMAND_FAST_BACK*/; ++ pci_write_config_word(dev, PCI_COMMAND, config); ++ ++ if (dev->subordinate) { ++ /* Set latency timers on sub bridges */ ++ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); /* XXX, */ ++ /* More bridge error detection */ ++ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config); ++ config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR; ++ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config); ++ } ++ /* Enable the PCIe normal error reporting */ ++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP); ++ if (pos) { ++ /* Disable system error generation in response to error messages */ ++ pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &config); ++ config &= ~(PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | PCI_EXP_RTCTL_SEFEE); ++ pci_write_config_word(dev, pos + PCI_EXP_RTCTL, config); ++ ++ /* Clear PCIE Capability's Device Status */ ++ pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &config); ++ pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, config); ++ ++ /* Update Device Control */ ++ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config); ++ /* Correctable Error Reporting */ ++ config |= PCI_EXP_DEVCTL_CERE; ++ /* Non-Fatal Error Reporting */ ++ config |= PCI_EXP_DEVCTL_NFERE; ++ /* Fatal Error Reporting */ ++ config |= PCI_EXP_DEVCTL_FERE; ++ /* Unsupported Request */ ++ config |= PCI_EXP_DEVCTL_URRE; ++ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config); ++ } ++ ++ /* Find the Advanced Error Reporting capability */ ++ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); ++ if (pos) { ++ /* Clear Uncorrectable Error Status */ ++ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &dconfig); ++ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, dconfig); ++ /* Enable reporting of all uncorrectable errors */ ++ /* Uncorrectable Error Mask - turned on bits disable errors */ ++ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0); ++ /* ++ * Leave severity at HW default. This only controls if ++ * errors are reported as uncorrectable or ++ * correctable, not if the error is reported. ++ */ ++ /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */ ++ /* Clear Correctable Error Status */ ++ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig); ++ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig); ++ /* Enable reporting of all correctable errors */ ++ /* Correctable Error Mask - turned on bits disable errors */ ++ pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0); ++ /* Advanced Error Capabilities */ ++ pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig); ++ /* ECRC Generation Enable */ ++ if (dconfig & PCI_ERR_CAP_ECRC_GENC) ++ dconfig |= PCI_ERR_CAP_ECRC_GENE; ++ /* ECRC Check Enable */ ++ if (dconfig & PCI_ERR_CAP_ECRC_CHKC) ++ dconfig |= PCI_ERR_CAP_ECRC_CHKE; ++ pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig); ++ ++ /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */ ++ /* Enable Root Port's interrupt in response to error messages */ ++ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ++ PCI_ERR_ROOT_CMD_COR_EN | ++ PCI_ERR_ROOT_CMD_NONFATAL_EN | ++ PCI_ERR_ROOT_CMD_FATAL_EN); ++ /* Clear the Root status register */ ++ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig); ++ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig); ++ } ++ /* WAR, only 128 MRRS is supported, force all EPs to support this value */ ++ pcie_set_readrq(dev, 128); ++ return 0; ++} ++ ++static void pcie_phy_rst(int pcie_port) ++{ ++ pcie_phy_rst_assert(pcie_port); ++ pcie_phy_rst_deassert(pcie_port); ++ /* Make sure PHY PLL is stable */ ++ udelay(20); ++} ++ ++static int pcie_rc_initialize(int pcie_port) ++{ ++ int i; ++ ++ pcie_rcu_endian_setup(pcie_port); ++ ++ pcie_ep_gpio_rst_init(pcie_port); ++ ++ /* ++ * XXX, PCIe elastic buffer bug will cause not to be detected. One more ++ * reset PCIe PHY will solve this issue ++ */ ++ for (i = 0; i < IFX_PCIE_PHY_LOOP_CNT; i++) { ++ /* Disable PCIe PHY Analog part for sanity check */ ++ pcie_phy_pmu_disable(pcie_port); ++ pcie_phy_rst(pcie_port); ++ /* PCIe Core reset enabled, low active, sw programmed */ ++ pcie_core_rst_assert(pcie_port); ++ /* Put PCIe EP in reset status */ ++ pcie_device_rst_assert(pcie_port); ++ /* PCI PHY & Core reset disabled, high active, sw programmed */ ++ pcie_core_rst_deassert(pcie_port); ++ /* Already in a quiet state, program PLL, enable PHY, check ready bit */ ++ pcie_phy_clock_mode_setup(pcie_port); ++ /* Enable PCIe PHY and Clock */ ++ pcie_core_pmu_setup(pcie_port); ++ /* Clear status registers */ ++ pcie_status_register_clear(pcie_port); ++#ifdef CONFIG_PCI_MSI ++ pcie_msi_init(pcie_port); ++#endif /* CONFIG_PCI_MSI */ ++ pcie_rc_cfg_reg_setup(pcie_port); ++ ++ /* Once link is up, break out */ ++ if (pcie_app_loigc_setup(pcie_port) == 0) ++ break; ++ } ++ if (i >= IFX_PCIE_PHY_LOOP_CNT) { ++ printk(KERN_ERR "%s link up failed!!!!!\n", __func__); ++ return -EIO; ++ } ++ /* NB, don't increase ACK/NACK timer timeout value, which will cause a lot of COR errors */ ++ pcie_replay_time_update(pcie_port); ++ return 0; ++} ++ ++static int inline ifx_pcie_startup_port_nr(void) ++{ ++ int pcie_port = IFX_PCIE_PORT0; ++ ++ pcie_port = IFX_PCIE_PORT0; ++ return pcie_port; ++} ++ ++/** ++ * \fn static int __init ifx_pcie_bios_init(void) ++ * \brief Initialize the IFX PCIe controllers ++ * ++ * \return -EIO PCIe PHY link is not up ++ * \return -ENOMEM Configuration/IO space failed to map ++ * \return 0 OK ++ * \ingroup IFX_PCIE_OS ++ */ ++extern int (*ltqpci_plat_arch_init)(struct pci_dev *dev); ++extern int (*ltqpci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); ++static int __devinit ltq_pcie_probe(struct platform_device *pdev) ++{ ++ char ver_str[128] = {0}; ++ void __iomem *io_map_base; ++ int pcie_port; ++ int startup_port; ++ ltqpci_map_irq = ifx_pcie_bios_map_irq; ++ ltqpci_plat_arch_init = ifx_pcie_bios_plat_dev_init; ++ /* Enable AHB Master/ Slave */ ++ pcie_ahb_pmu_setup(); ++ ++ startup_port = ifx_pcie_startup_port_nr(); ++ ++ ltq_gpio_request(&pdev->dev, IFX_PCIE_GPIO_RESET, 0, 1, "pcie-reset"); ++ ++ for (pcie_port = startup_port; pcie_port < IFX_PCIE_CORE_NR; pcie_port++){ ++ if (pcie_rc_initialize(pcie_port) == 0) { ++ /* Otherwise, warning will pop up */ ++ io_map_base = ioremap(PCIE_IO_PHY_PORT_TO_BASE(pcie_port), PCIE_IO_SIZE); ++ if (io_map_base == NULL) ++ return -ENOMEM; ++ ifx_pcie_controller[pcie_port].pcic.io_map_base = (unsigned long)io_map_base; ++ register_pci_controller(&ifx_pcie_controller[pcie_port].pcic); ++ /* XXX, clear error status */ ++ pcie_rc_core_int_init(pcie_port); ++ } ++ } ++ ++ printk(KERN_INFO "%s", ver_str); ++return 0; ++} ++ ++static struct platform_driver ltq_pcie_driver = { ++ .probe = ltq_pcie_probe, ++ .driver = { ++ .name = "pcie-xway", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init pciebios_init(void) ++{ ++ return platform_driver_register(<q_pcie_driver); ++} ++ ++arch_initcall(pciebios_init); +diff --git a/arch/mips/pci/pcie-lantiq.h b/arch/mips/pci/pcie-lantiq.h +new file mode 100644 +index 0000000..d877c23 +--- /dev/null ++++ b/arch/mips/pci/pcie-lantiq.h +@@ -0,0 +1,1305 @@ ++/****************************************************************************** ++** ++** FILE NAME : ifxmips_pcie_reg.h ++** PROJECT : IFX UEIP for VRX200 ++** MODULES : PCIe module ++** ++** DATE : 02 Mar 2009 ++** AUTHOR : Lei Chuanhua ++** DESCRIPTION : PCIe Root Complex Driver ++** COPYRIGHT : Copyright (c) 2009 ++** Infineon Technologies AG ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** ++** 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. ++** HISTORY ++** $Version $Date $Author $Comment ++** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version ++*******************************************************************************/ ++#ifndef IFXMIPS_PCIE_REG_H ++#define IFXMIPS_PCIE_REG_H ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/pci.h> ++#include <linux/interrupt.h> ++/*! ++ \file ifxmips_pcie_reg.h ++ \ingroup IFX_PCIE ++ \brief header file for PCIe module register definition ++*/ ++/* PCIe Address Mapping Base */ ++#define PCIE_CFG_PHY_BASE 0x1D000000UL ++#define PCIE_CFG_BASE (KSEG1 + PCIE_CFG_PHY_BASE) ++#define PCIE_CFG_SIZE (8 * 1024 * 1024) ++ ++#define PCIE_MEM_PHY_BASE 0x1C000000UL ++#define PCIE_MEM_BASE (KSEG1 + PCIE_MEM_PHY_BASE) ++#define PCIE_MEM_SIZE (16 * 1024 * 1024) ++#define PCIE_MEM_PHY_END (PCIE_MEM_PHY_BASE + PCIE_MEM_SIZE - 1) ++ ++#define PCIE_IO_PHY_BASE 0x1D800000UL ++#define PCIE_IO_BASE (KSEG1 + PCIE_IO_PHY_BASE) ++#define PCIE_IO_SIZE (1 * 1024 * 1024) ++#define PCIE_IO_PHY_END (PCIE_IO_PHY_BASE + PCIE_IO_SIZE - 1) ++ ++#define PCIE_RC_CFG_BASE (KSEG1 + 0x1D900000) ++#define PCIE_APP_LOGIC_REG (KSEG1 + 0x1E100900) ++#define PCIE_MSI_PHY_BASE 0x1F600000UL ++ ++#define PCIE_PDI_PHY_BASE 0x1F106800UL ++#define PCIE_PDI_BASE (KSEG1 + PCIE_PDI_PHY_BASE) ++#define PCIE_PDI_SIZE 0x400 ++ ++#define PCIE1_CFG_PHY_BASE 0x19000000UL ++#define PCIE1_CFG_BASE (KSEG1 + PCIE1_CFG_PHY_BASE) ++#define PCIE1_CFG_SIZE (8 * 1024 * 1024) ++ ++#define PCIE1_MEM_PHY_BASE 0x18000000UL ++#define PCIE1_MEM_BASE (KSEG1 + PCIE1_MEM_PHY_BASE) ++#define PCIE1_MEM_SIZE (16 * 1024 * 1024) ++#define PCIE1_MEM_PHY_END (PCIE1_MEM_PHY_BASE + PCIE1_MEM_SIZE - 1) ++ ++#define PCIE1_IO_PHY_BASE 0x19800000UL ++#define PCIE1_IO_BASE (KSEG1 + PCIE1_IO_PHY_BASE) ++#define PCIE1_IO_SIZE (1 * 1024 * 1024) ++#define PCIE1_IO_PHY_END (PCIE1_IO_PHY_BASE + PCIE1_IO_SIZE - 1) ++ ++#define PCIE1_RC_CFG_BASE (KSEG1 + 0x19900000) ++#define PCIE1_APP_LOGIC_REG (KSEG1 + 0x1E100700) ++#define PCIE1_MSI_PHY_BASE 0x1F400000UL ++ ++#define PCIE1_PDI_PHY_BASE 0x1F700400UL ++#define PCIE1_PDI_BASE (KSEG1 + PCIE1_PDI_PHY_BASE) ++#define PCIE1_PDI_SIZE 0x400 ++ ++#define PCIE_CFG_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_CFG_BASE) : (PCIE_CFG_BASE)) ++#define PCIE_MEM_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_MEM_BASE) : (PCIE_MEM_BASE)) ++#define PCIE_IO_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_IO_BASE) : (PCIE_IO_BASE)) ++#define PCIE_MEM_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_MEM_PHY_BASE) : (PCIE_MEM_PHY_BASE)) ++#define PCIE_MEM_PHY_PORT_TO_END(X) ((X) > 0 ? (PCIE1_MEM_PHY_END) : (PCIE_MEM_PHY_END)) ++#define PCIE_IO_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_IO_PHY_BASE) : (PCIE_IO_PHY_BASE)) ++#define PCIE_IO_PHY_PORT_TO_END(X) ((X) > 0 ? (PCIE1_IO_PHY_END) : (PCIE_IO_PHY_END)) ++#define PCIE_APP_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_APP_LOGIC_REG) : (PCIE_APP_LOGIC_REG)) ++#define PCIE_RC_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_RC_CFG_BASE) : (PCIE_RC_CFG_BASE)) ++#define PCIE_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_PDI_BASE) : (PCIE_PDI_BASE)) ++ ++/* PCIe Application Logic Register */ ++/* RC Core Control Register */ ++#define PCIE_RC_CCR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x10) ++/* This should be enabled after initializing configuratin registers ++ * Also should check link status retraining bit ++ */ ++#define PCIE_RC_CCR_LTSSM_ENABLE 0x00000001 /* Enable LTSSM to continue link establishment */ ++ ++/* RC Core Debug Register */ ++#define PCIE_RC_DR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x14) ++#define PCIE_RC_DR_DLL_UP 0x00000001 /* Data Link Layer Up */ ++#define PCIE_RC_DR_CURRENT_POWER_STATE 0x0000000E /* Current Power State */ ++#define PCIE_RC_DR_CURRENT_POWER_STATE_S 1 ++#define PCIE_RC_DR_CURRENT_LTSSM_STATE 0x000001F0 /* Current LTSSM State */ ++#define PCIE_RC_DR_CURRENT_LTSSM_STATE_S 4 ++ ++#define PCIE_RC_DR_PM_DEV_STATE 0x00000E00 /* Power Management D-State */ ++#define PCIE_RC_DR_PM_DEV_STATE_S 9 ++ ++#define PCIE_RC_DR_PM_ENABLED 0x00001000 /* Power Management State from PMU */ ++#define PCIE_RC_DR_PME_EVENT_ENABLED 0x00002000 /* Power Management Event Enable State */ ++#define PCIE_RC_DR_AUX_POWER_ENABLED 0x00004000 /* Auxiliary Power Enable */ ++ ++/* Current Power State Definition */ ++enum { ++ PCIE_RC_DR_D0 = 0, ++ PCIE_RC_DR_D1, /* Not supported */ ++ PCIE_RC_DR_D2, /* Not supported */ ++ PCIE_RC_DR_D3, ++ PCIE_RC_DR_UN, ++}; ++ ++/* PHY Link Status Register */ ++#define PCIE_PHY_SR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x18) ++#define PCIE_PHY_SR_PHY_LINK_UP 0x00000001 /* PHY Link Up/Down Indicator */ ++ ++/* Electromechanical Control Register */ ++#define PCIE_EM_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x1C) ++#define PCIE_EM_CR_CARD_IS_PRESENT 0x00000001 /* Card Presence Detect State */ ++#define PCIE_EM_CR_MRL_OPEN 0x00000002 /* MRL Sensor State */ ++#define PCIE_EM_CR_POWER_FAULT_SET 0x00000004 /* Power Fault Detected */ ++#define PCIE_EM_CR_MRL_SENSOR_SET 0x00000008 /* MRL Sensor Changed */ ++#define PCIE_EM_CR_PRESENT_DETECT_SET 0x00000010 /* Card Presense Detect Changed */ ++#define PCIE_EM_CR_CMD_CPL_INT_SET 0x00000020 /* Command Complete Interrupt */ ++#define PCIE_EM_CR_SYS_INTERLOCK_SET 0x00000040 /* System Electromechanical IterLock Engaged */ ++#define PCIE_EM_CR_ATTENTION_BUTTON_SET 0x00000080 /* Attention Button Pressed */ ++ ++/* Interrupt Status Register */ ++#define PCIE_IR_SR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x20) ++#define PCIE_IR_SR_PME_CAUSE_MSI 0x00000002 /* MSI caused by PME */ ++#define PCIE_IR_SR_HP_PME_WAKE_GEN 0x00000004 /* Hotplug PME Wake Generation */ ++#define PCIE_IR_SR_HP_MSI 0x00000008 /* Hotplug MSI */ ++#define PCIE_IR_SR_AHB_LU_ERR 0x00000030 /* AHB Bridge Lookup Error Signals */ ++#define PCIE_IR_SR_AHB_LU_ERR_S 4 ++#define PCIE_IR_SR_INT_MSG_NUM 0x00003E00 /* Interrupt Message Number */ ++#define PCIE_IR_SR_INT_MSG_NUM_S 9 ++#define PCIE_IR_SR_AER_INT_MSG_NUM 0xF8000000 /* Advanced Error Interrupt Message Number */ ++#define PCIE_IR_SR_AER_INT_MSG_NUM_S 27 ++ ++/* Message Control Register */ ++#define PCIE_MSG_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x30) ++#define PCIE_MSG_CR_GEN_PME_TURN_OFF_MSG 0x00000001 /* Generate PME Turn Off Message */ ++#define PCIE_MSG_CR_GEN_UNLOCK_MSG 0x00000002 /* Generate Unlock Message */ ++ ++#define PCIE_VDM_DR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x34) ++ ++/* Vendor-Defined Message Requester ID Register */ ++#define PCIE_VDM_RID(X) (PCIE_APP_PORT_TO_BASE (X) + 0x38) ++#define PCIE_VDM_RID_VENROR_MSG_REQ_ID 0x0000FFFF ++#define PCIE_VDM_RID_VDMRID_S 0 ++ ++/* ASPM Control Register */ ++#define PCIE_ASPM_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x40) ++#define PCIE_ASPM_CR_HOT_RST 0x00000001 /* Hot Reset Request to the downstream device */ ++#define PCIE_ASPM_CR_REQ_EXIT_L1 0x00000002 /* Request to Exit L1 */ ++#define PCIE_ASPM_CR_REQ_ENTER_L1 0x00000004 /* Request to Enter L1 */ ++ ++/* Vendor Message DW0 Register */ ++#define PCIE_VM_MSG_DW0(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x50) ++#define PCIE_VM_MSG_DW0_TYPE 0x0000001F /* Message type */ ++#define PCIE_VM_MSG_DW0_TYPE_S 0 ++#define PCIE_VM_MSG_DW0_FORMAT 0x00000060 /* Format */ ++#define PCIE_VM_MSG_DW0_FORMAT_S 5 ++#define PCIE_VM_MSG_DW0_TC 0x00007000 /* Traffic Class */ ++#define PCIE_VM_MSG_DW0_TC_S 12 ++#define PCIE_VM_MSG_DW0_ATTR 0x000C0000 /* Atrributes */ ++#define PCIE_VM_MSG_DW0_ATTR_S 18 ++#define PCIE_VM_MSG_DW0_EP_TLP 0x00100000 /* Poisoned TLP */ ++#define PCIE_VM_MSG_DW0_TD 0x00200000 /* TLP Digest */ ++#define PCIE_VM_MSG_DW0_LEN 0xFFC00000 /* Length */ ++#define PCIE_VM_MSG_DW0_LEN_S 22 ++ ++/* Format Definition */ ++enum { ++ PCIE_VM_MSG_FORMAT_00 = 0, /* 3DW Hdr, no data*/ ++ PCIE_VM_MSG_FORMAT_01, /* 4DW Hdr, no data */ ++ PCIE_VM_MSG_FORMAT_10, /* 3DW Hdr, with data */ ++ PCIE_VM_MSG_FORMAT_11, /* 4DW Hdr, with data */ ++}; ++ ++/* Traffic Class Definition */ ++enum { ++ PCIE_VM_MSG_TC0 = 0, ++ PCIE_VM_MSG_TC1, ++ PCIE_VM_MSG_TC2, ++ PCIE_VM_MSG_TC3, ++ PCIE_VM_MSG_TC4, ++ PCIE_VM_MSG_TC5, ++ PCIE_VM_MSG_TC6, ++ PCIE_VM_MSG_TC7, ++}; ++ ++/* Attributes Definition */ ++enum { ++ PCIE_VM_MSG_ATTR_00 = 0, /* RO and No Snoop cleared */ ++ PCIE_VM_MSG_ATTR_01, /* RO cleared , No Snoop set */ ++ PCIE_VM_MSG_ATTR_10, /* RO set, No Snoop cleared*/ ++ PCIE_VM_MSG_ATTR_11, /* RO and No Snoop set */ ++}; ++ ++/* Payload Size Definition */ ++#define PCIE_VM_MSG_LEN_MIN 0 ++#define PCIE_VM_MSG_LEN_MAX 1024 ++ ++/* Vendor Message DW1 Register */ ++#define PCIE_VM_MSG_DW1(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x54) ++#define PCIE_VM_MSG_DW1_FUNC_NUM 0x00000070 /* Function Number */ ++#define PCIE_VM_MSG_DW1_FUNC_NUM_S 8 ++#define PCIE_VM_MSG_DW1_CODE 0x00FF0000 /* Message Code */ ++#define PCIE_VM_MSG_DW1_CODE_S 16 ++#define PCIE_VM_MSG_DW1_TAG 0xFF000000 /* Tag */ ++#define PCIE_VM_MSG_DW1_TAG_S 24 ++ ++#define PCIE_VM_MSG_DW2(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x58) ++#define PCIE_VM_MSG_DW3(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x5C) ++ ++/* Vendor Message Request Register */ ++#define PCIE_VM_MSG_REQR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x60) ++#define PCIE_VM_MSG_REQR_REQ 0x00000001 /* Vendor Message Request */ ++ ++ ++/* AHB Slave Side Band Control Register */ ++#define PCIE_AHB_SSB(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x70) ++#define PCIE_AHB_SSB_REQ_BCM 0x00000001 /* Slave Reques BCM filed */ ++#define PCIE_AHB_SSB_REQ_EP 0x00000002 /* Slave Reques EP filed */ ++#define PCIE_AHB_SSB_REQ_TD 0x00000004 /* Slave Reques TD filed */ ++#define PCIE_AHB_SSB_REQ_ATTR 0x00000018 /* Slave Reques Attribute number */ ++#define PCIE_AHB_SSB_REQ_ATTR_S 3 ++#define PCIE_AHB_SSB_REQ_TC 0x000000E0 /* Slave Request TC Field */ ++#define PCIE_AHB_SSB_REQ_TC_S 5 ++ ++/* AHB Master SideBand Ctrl Register */ ++#define PCIE_AHB_MSB(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x74) ++#define PCIE_AHB_MSB_RESP_ATTR 0x00000003 /* Master Response Attribute number */ ++#define PCIE_AHB_MSB_RESP_ATTR_S 0 ++#define PCIE_AHB_MSB_RESP_BAD_EOT 0x00000004 /* Master Response Badeot filed */ ++#define PCIE_AHB_MSB_RESP_BCM 0x00000008 /* Master Response BCM filed */ ++#define PCIE_AHB_MSB_RESP_EP 0x00000010 /* Master Response EP filed */ ++#define PCIE_AHB_MSB_RESP_TD 0x00000020 /* Master Response TD filed */ ++#define PCIE_AHB_MSB_RESP_FUN_NUM 0x000003C0 /* Master Response Function number */ ++#define PCIE_AHB_MSB_RESP_FUN_NUM_S 6 ++ ++/* AHB Control Register, fixed bus enumeration exception */ ++#define PCIE_AHB_CTRL(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x78) ++#define PCIE_AHB_CTRL_BUS_ERROR_SUPPRESS 0x00000001 ++ ++/* Interrupt Enalbe Register */ ++#define PCIE_IRNEN(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xF4) ++#define PCIE_IRNCR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xF8) ++#define PCIE_IRNICR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xFC) ++ ++/* PCIe interrupt enable/control/capture register definition */ ++#define PCIE_IRN_AER_REPORT 0x00000001 /* AER Interrupt */ ++#define PCIE_IRN_AER_MSIX 0x00000002 /* Advanced Error MSI-X Interrupt */ ++#define PCIE_IRN_PME 0x00000004 /* PME Interrupt */ ++#define PCIE_IRN_HOTPLUG 0x00000008 /* Hotplug Interrupt */ ++#define PCIE_IRN_RX_VDM_MSG 0x00000010 /* Vendor-Defined Message Interrupt */ ++#define PCIE_IRN_RX_CORRECTABLE_ERR_MSG 0x00000020 /* Correctable Error Message Interrupt */ ++#define PCIE_IRN_RX_NON_FATAL_ERR_MSG 0x00000040 /* Non-fatal Error Message */ ++#define PCIE_IRN_RX_FATAL_ERR_MSG 0x00000080 /* Fatal Error Message */ ++#define PCIE_IRN_RX_PME_MSG 0x00000100 /* PME Message Interrupt */ ++#define PCIE_IRN_RX_PME_TURNOFF_ACK 0x00000200 /* PME Turnoff Ack Message Interrupt */ ++#define PCIE_IRN_AHB_BR_FATAL_ERR 0x00000400 /* AHB Fatal Error Interrupt */ ++#define PCIE_IRN_LINK_AUTO_BW_STATUS 0x00000800 /* Link Auto Bandwidth Status Interrupt */ ++#define PCIE_IRN_BW_MGT 0x00001000 /* Bandwidth Managment Interrupt */ ++#define PCIE_IRN_INTA 0x00002000 /* INTA */ ++#define PCIE_IRN_INTB 0x00004000 /* INTB */ ++#define PCIE_IRN_INTC 0x00008000 /* INTC */ ++#define PCIE_IRN_INTD 0x00010000 /* INTD */ ++#define PCIE_IRN_WAKEUP 0x00020000 /* Wake up Interrupt */ ++ ++#define PCIE_RC_CORE_COMBINED_INT (PCIE_IRN_AER_REPORT | PCIE_IRN_AER_MSIX | PCIE_IRN_PME | \ ++ PCIE_IRN_HOTPLUG | PCIE_IRN_RX_VDM_MSG | PCIE_IRN_RX_CORRECTABLE_ERR_MSG |\ ++ PCIE_IRN_RX_NON_FATAL_ERR_MSG | PCIE_IRN_RX_FATAL_ERR_MSG | \ ++ PCIE_IRN_RX_PME_MSG | PCIE_IRN_RX_PME_TURNOFF_ACK | PCIE_IRN_AHB_BR_FATAL_ERR | \ ++ PCIE_IRN_LINK_AUTO_BW_STATUS | PCIE_IRN_BW_MGT) ++/* PCIe RC Configuration Register */ ++#define PCIE_VDID(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x00) ++ ++/* Bit definition from pci_reg.h */ ++#define PCIE_PCICMDSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x04) ++#define PCIE_CCRID(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x08) ++#define PCIE_CLSLTHTBR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x0C) /* EP only */ ++/* BAR0, BAR1,Only necessary if the bridges implements a device-specific register set or memory buffer */ ++#define PCIE_BAR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x10) /* Not used*/ ++#define PCIE_BAR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x14) /* Not used */ ++ ++#define PCIE_BNR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x18) /* Mandatory */ ++/* Bus Number Register bits */ ++#define PCIE_BNR_PRIMARY_BUS_NUM 0x000000FF ++#define PCIE_BNR_PRIMARY_BUS_NUM_S 0 ++#define PCIE_PNR_SECONDARY_BUS_NUM 0x0000FF00 ++#define PCIE_PNR_SECONDARY_BUS_NUM_S 8 ++#define PCIE_PNR_SUB_BUS_NUM 0x00FF0000 ++#define PCIE_PNR_SUB_BUS_NUM_S 16 ++ ++/* IO Base/Limit Register bits */ ++#define PCIE_IOBLSECS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x1C) /* RC only */ ++#define PCIE_IOBLSECS_32BIT_IO_ADDR 0x00000001 ++#define PCIE_IOBLSECS_IO_BASE_ADDR 0x000000F0 ++#define PCIE_IOBLSECS_IO_BASE_ADDR_S 4 ++#define PCIE_IOBLSECS_32BIT_IOLIMT 0x00000100 ++#define PCIE_IOBLSECS_IO_LIMIT_ADDR 0x0000F000 ++#define PCIE_IOBLSECS_IO_LIMIT_ADDR_S 12 ++ ++/* Non-prefetchable Memory Base/Limit Register bit */ ++#define PCIE_MBML(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x20) /* RC only */ ++#define PCIE_MBML_MEM_BASE_ADDR 0x0000FFF0 ++#define PCIE_MBML_MEM_BASE_ADDR_S 4 ++#define PCIE_MBML_MEM_LIMIT_ADDR 0xFFF00000 ++#define PCIE_MBML_MEM_LIMIT_ADDR_S 20 ++ ++/* Prefetchable Memory Base/Limit Register bit */ ++#define PCIE_PMBL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x24) /* RC only */ ++#define PCIE_PMBL_64BIT_ADDR 0x00000001 ++#define PCIE_PMBL_UPPER_12BIT 0x0000FFF0 ++#define PCIE_PMBL_UPPER_12BIT_S 4 ++#define PCIE_PMBL_E64MA 0x00010000 ++#define PCIE_PMBL_END_ADDR 0xFFF00000 ++#define PCIE_PMBL_END_ADDR_S 20 ++#define PCIE_PMBU32(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x28) /* RC only */ ++#define PCIE_PMLU32(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x2C) /* RC only */ ++ ++/* I/O Base/Limit Upper 16 bits register */ ++#define PCIE_IO_BANDL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x30) /* RC only */ ++#define PCIE_IO_BANDL_UPPER_16BIT_IO_BASE 0x0000FFFF ++#define PCIE_IO_BANDL_UPPER_16BIT_IO_BASE_S 0 ++#define PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT 0xFFFF0000 ++#define PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT_S 16 ++ ++#define PCIE_CPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x34) ++#define PCIE_EBBAR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x38) ++ ++/* Interrupt and Secondary Bridge Control Register */ ++#define PCIE_INTRBCTRL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x3C) ++ ++#define PCIE_INTRBCTRL_INT_LINE 0x000000FF ++#define PCIE_INTRBCTRL_INT_LINE_S 0 ++#define PCIE_INTRBCTRL_INT_PIN 0x0000FF00 ++#define PCIE_INTRBCTRL_INT_PIN_S 8 ++#define PCIE_INTRBCTRL_PARITY_ERR_RESP_ENABLE 0x00010000 /* #PERR */ ++#define PCIE_INTRBCTRL_SERR_ENABLE 0x00020000 /* #SERR */ ++#define PCIE_INTRBCTRL_ISA_ENABLE 0x00040000 /* ISA enable, IO 64KB only */ ++#define PCIE_INTRBCTRL_VGA_ENABLE 0x00080000 /* VGA enable */ ++#define PCIE_INTRBCTRL_VGA_16BIT_DECODE 0x00100000 /* VGA 16bit decode */ ++#define PCIE_INTRBCTRL_RST_SECONDARY_BUS 0x00400000 /* Secondary bus rest, hot rest, 1ms */ ++/* Others are read only */ ++enum { ++ PCIE_INTRBCTRL_INT_NON = 0, ++ PCIE_INTRBCTRL_INTA, ++ PCIE_INTRBCTRL_INTB, ++ PCIE_INTRBCTRL_INTC, ++ PCIE_INTRBCTRL_INTD, ++}; ++ ++#define PCIE_PM_CAPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x40) ++ ++/* Power Management Control and Status Register */ ++#define PCIE_PM_CSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x44) ++ ++#define PCIE_PM_CSR_POWER_STATE 0x00000003 /* Power State */ ++#define PCIE_PM_CSR_POWER_STATE_S 0 ++#define PCIE_PM_CSR_SW_RST 0x00000008 /* Soft Reset Enabled */ ++#define PCIE_PM_CSR_PME_ENABLE 0x00000100 /* PME Enable */ ++#define PCIE_PM_CSR_PME_STATUS 0x00008000 /* PME status */ ++ ++/* MSI Capability Register for EP */ ++#define PCIE_MCAPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x50) ++ ++#define PCIE_MCAPR_MSI_CAP_ID 0x000000FF /* MSI Capability ID */ ++#define PCIE_MCAPR_MSI_CAP_ID_S 0 ++#define PCIE_MCAPR_MSI_NEXT_CAP_PTR 0x0000FF00 /* Next Capability Pointer */ ++#define PCIE_MCAPR_MSI_NEXT_CAP_PTR_S 8 ++#define PCIE_MCAPR_MSI_ENABLE 0x00010000 /* MSI Enable */ ++#define PCIE_MCAPR_MULTI_MSG_CAP 0x000E0000 /* Multiple Message Capable */ ++#define PCIE_MCAPR_MULTI_MSG_CAP_S 17 ++#define PCIE_MCAPR_MULTI_MSG_ENABLE 0x00700000 /* Multiple Message Enable */ ++#define PCIE_MCAPR_MULTI_MSG_ENABLE_S 20 ++#define PCIE_MCAPR_ADDR64_CAP 0X00800000 /* 64-bit Address Capable */ ++ ++/* MSI Message Address Register */ ++#define PCIE_MA(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x54) ++ ++#define PCIE_MA_ADDR_MASK 0xFFFFFFFC /* Message Address */ ++ ++/* MSI Message Upper Address Register */ ++#define PCIE_MUA(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x58) ++ ++/* MSI Message Data Register */ ++#define PCIE_MD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x5C) ++ ++#define PCIE_MD_DATA 0x0000FFFF /* Message Data */ ++#define PCIE_MD_DATA_S 0 ++ ++/* PCI Express Capability Register */ ++#define PCIE_XCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x70) ++ ++#define PCIE_XCAP_ID 0x000000FF /* PCI Express Capability ID */ ++#define PCIE_XCAP_ID_S 0 ++#define PCIE_XCAP_NEXT_CAP 0x0000FF00 /* Next Capability Pointer */ ++#define PCIE_XCAP_NEXT_CAP_S 8 ++#define PCIE_XCAP_VER 0x000F0000 /* PCI Express Capability Version */ ++#define PCIE_XCAP_VER_S 16 ++#define PCIE_XCAP_DEV_PORT_TYPE 0x00F00000 /* Device Port Type */ ++#define PCIE_XCAP_DEV_PORT_TYPE_S 20 ++#define PCIE_XCAP_SLOT_IMPLEMENTED 0x01000000 /* Slot Implemented */ ++#define PCIE_XCAP_MSG_INT_NUM 0x3E000000 /* Interrupt Message Number */ ++#define PCIE_XCAP_MSG_INT_NUM_S 25 ++ ++/* Device Capability Register */ ++#define PCIE_DCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x74) ++ ++#define PCIE_DCAP_MAX_PAYLOAD_SIZE 0x00000007 /* Max Payload size */ ++#define PCIE_DCAP_MAX_PAYLOAD_SIZE_S 0 ++#define PCIE_DCAP_PHANTOM_FUNC 0x00000018 /* Phanton Function, not supported */ ++#define PCIE_DCAP_PHANTOM_FUNC_S 3 ++#define PCIE_DCAP_EXT_TAG 0x00000020 /* Extended Tag Field */ ++#define PCIE_DCAP_EP_L0S_LATENCY 0x000001C0 /* EP L0s latency only */ ++#define PCIE_DCAP_EP_L0S_LATENCY_S 6 ++#define PCIE_DCAP_EP_L1_LATENCY 0x00000E00 /* EP L1 latency only */ ++#define PCIE_DCAP_EP_L1_LATENCY_S 9 ++#define PCIE_DCAP_ROLE_BASE_ERR_REPORT 0x00008000 /* Role Based ERR */ ++ ++/* Maximum payload size supported */ ++enum { ++ PCIE_MAX_PAYLOAD_128 = 0, ++ PCIE_MAX_PAYLOAD_256, ++ PCIE_MAX_PAYLOAD_512, ++ PCIE_MAX_PAYLOAD_1024, ++ PCIE_MAX_PAYLOAD_2048, ++ PCIE_MAX_PAYLOAD_4096, ++}; ++ ++/* Device Control and Status Register */ ++#define PCIE_DCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x78) ++ ++#define PCIE_DCTLSTS_CORRECTABLE_ERR_EN 0x00000001 /* COR-ERR */ ++#define PCIE_DCTLSTS_NONFATAL_ERR_EN 0x00000002 /* Non-fatal ERR */ ++#define PCIE_DCTLSTS_FATAL_ERR_EN 0x00000004 /* Fatal ERR */ ++#define PCIE_DCTLSYS_UR_REQ_EN 0x00000008 /* UR ERR */ ++#define PCIE_DCTLSTS_RELAXED_ORDERING_EN 0x00000010 /* Enable relaxing ordering */ ++#define PCIE_DCTLSTS_MAX_PAYLOAD_SIZE 0x000000E0 /* Max payload mask */ ++#define PCIE_DCTLSTS_MAX_PAYLOAD_SIZE_S 5 ++#define PCIE_DCTLSTS_EXT_TAG_EN 0x00000100 /* Extended tag field */ ++#define PCIE_DCTLSTS_PHANTOM_FUNC_EN 0x00000200 /* Phantom Function Enable */ ++#define PCIE_DCTLSTS_AUX_PM_EN 0x00000400 /* AUX Power PM Enable */ ++#define PCIE_DCTLSTS_NO_SNOOP_EN 0x00000800 /* Enable no snoop, except root port*/ ++#define PCIE_DCTLSTS_MAX_READ_SIZE 0x00007000 /* Max Read Request size*/ ++#define PCIE_DCTLSTS_MAX_READ_SIZE_S 12 ++#define PCIE_DCTLSTS_CORRECTABLE_ERR 0x00010000 /* COR-ERR Detected */ ++#define PCIE_DCTLSTS_NONFATAL_ERR 0x00020000 /* Non-Fatal ERR Detected */ ++#define PCIE_DCTLSTS_FATAL_ER 0x00040000 /* Fatal ERR Detected */ ++#define PCIE_DCTLSTS_UNSUPPORTED_REQ 0x00080000 /* UR Detected */ ++#define PCIE_DCTLSTS_AUX_POWER 0x00100000 /* Aux Power Detected */ ++#define PCIE_DCTLSTS_TRANSACT_PENDING 0x00200000 /* Transaction pending */ ++ ++#define PCIE_DCTLSTS_ERR_EN (PCIE_DCTLSTS_CORRECTABLE_ERR_EN | \ ++ PCIE_DCTLSTS_NONFATAL_ERR_EN | PCIE_DCTLSTS_FATAL_ERR_EN | \ ++ PCIE_DCTLSYS_UR_REQ_EN) ++ ++/* Link Capability Register */ ++#define PCIE_LCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7C) ++#define PCIE_LCAP_MAX_LINK_SPEED 0x0000000F /* Max link speed, 0x1 by default */ ++#define PCIE_LCAP_MAX_LINK_SPEED_S 0 ++#define PCIE_LCAP_MAX_LENGTH_WIDTH 0x000003F0 /* Maxium Length Width */ ++#define PCIE_LCAP_MAX_LENGTH_WIDTH_S 4 ++#define PCIE_LCAP_ASPM_LEVEL 0x00000C00 /* Active State Link PM Support */ ++#define PCIE_LCAP_ASPM_LEVEL_S 10 ++#define PCIE_LCAP_L0S_EIXT_LATENCY 0x00007000 /* L0s Exit Latency */ ++#define PCIE_LCAP_L0S_EIXT_LATENCY_S 12 ++#define PCIE_LCAP_L1_EXIT_LATENCY 0x00038000 /* L1 Exit Latency */ ++#define PCIE_LCAP_L1_EXIT_LATENCY_S 15 ++#define PCIE_LCAP_CLK_PM 0x00040000 /* Clock Power Management */ ++#define PCIE_LCAP_SDER 0x00080000 /* Surprise Down Error Reporting */ ++#define PCIE_LCAP_DLL_ACTIVE_REPROT 0x00100000 /* Data Link Layer Active Reporting Capable */ ++#define PCIE_LCAP_PORT_NUM 0xFF0000000 /* Port number */ ++#define PCIE_LCAP_PORT_NUM_S 24 ++ ++/* Maximum Length width definition */ ++#define PCIE_MAX_LENGTH_WIDTH_RES 0x00 ++#define PCIE_MAX_LENGTH_WIDTH_X1 0x01 /* Default */ ++#define PCIE_MAX_LENGTH_WIDTH_X2 0x02 ++#define PCIE_MAX_LENGTH_WIDTH_X4 0x04 ++#define PCIE_MAX_LENGTH_WIDTH_X8 0x08 ++#define PCIE_MAX_LENGTH_WIDTH_X12 0x0C ++#define PCIE_MAX_LENGTH_WIDTH_X16 0x10 ++#define PCIE_MAX_LENGTH_WIDTH_X32 0x20 ++ ++/* Active State Link PM definition */ ++enum { ++ PCIE_ASPM_RES0 = 0, ++ PCIE_ASPM_L0S_ENTRY_SUPPORT, /* L0s */ ++ PCIE_ASPM_RES1, ++ PCIE_ASPM_L0S_L1_ENTRY_SUPPORT, /* L0s and L1, default */ ++}; ++ ++/* L0s Exit Latency definition */ ++enum { ++ PCIE_L0S_EIXT_LATENCY_L64NS = 0, /* < 64 ns */ ++ PCIE_L0S_EIXT_LATENCY_B64A128, /* > 64 ns < 128 ns */ ++ PCIE_L0S_EIXT_LATENCY_B128A256, /* > 128 ns < 256 ns */ ++ PCIE_L0S_EIXT_LATENCY_B256A512, /* > 256 ns < 512 ns */ ++ PCIE_L0S_EIXT_LATENCY_B512TO1U, /* > 512 ns < 1 us */ ++ PCIE_L0S_EIXT_LATENCY_B1A2U, /* > 1 us < 2 us */ ++ PCIE_L0S_EIXT_LATENCY_B2A4U, /* > 2 us < 4 us */ ++ PCIE_L0S_EIXT_LATENCY_M4US, /* > 4 us */ ++}; ++ ++/* L1 Exit Latency definition */ ++enum { ++ PCIE_L1_EXIT_LATENCY_L1US = 0, /* < 1 us */ ++ PCIE_L1_EXIT_LATENCY_B1A2, /* > 1 us < 2 us */ ++ PCIE_L1_EXIT_LATENCY_B2A4, /* > 2 us < 4 us */ ++ PCIE_L1_EXIT_LATENCY_B4A8, /* > 4 us < 8 us */ ++ PCIE_L1_EXIT_LATENCY_B8A16, /* > 8 us < 16 us */ ++ PCIE_L1_EXIT_LATENCY_B16A32, /* > 16 us < 32 us */ ++ PCIE_L1_EXIT_LATENCY_B32A64, /* > 32 us < 64 us */ ++ PCIE_L1_EXIT_LATENCY_M64US, /* > 64 us */ ++}; ++ ++/* Link Control and Status Register */ ++#define PCIE_LCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x80) ++#define PCIE_LCTLSTS_ASPM_ENABLE 0x00000003 /* Active State Link PM Control */ ++#define PCIE_LCTLSTS_ASPM_ENABLE_S 0 ++#define PCIE_LCTLSTS_RCB128 0x00000008 /* Read Completion Boundary 128*/ ++#define PCIE_LCTLSTS_LINK_DISABLE 0x00000010 /* Link Disable */ ++#define PCIE_LCTLSTS_RETRIAN_LINK 0x00000020 /* Retrain Link */ ++#define PCIE_LCTLSTS_COM_CLK_CFG 0x00000040 /* Common Clock Configuration */ ++#define PCIE_LCTLSTS_EXT_SYNC 0x00000080 /* Extended Synch */ ++#define PCIE_LCTLSTS_CLK_PM_EN 0x00000100 /* Enable Clock Powerm Management */ ++#define PCIE_LCTLSTS_LINK_SPEED 0x000F0000 /* Link Speed */ ++#define PCIE_LCTLSTS_LINK_SPEED_S 16 ++#define PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH 0x03F00000 /* Negotiated Link Width */ ++#define PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH_S 20 ++#define PCIE_LCTLSTS_RETRAIN_PENDING 0x08000000 /* Link training is ongoing */ ++#define PCIE_LCTLSTS_SLOT_CLK_CFG 0x10000000 /* Slot Clock Configuration */ ++#define PCIE_LCTLSTS_DLL_ACTIVE 0x20000000 /* Data Link Layer Active */ ++ ++/* Slot Capabilities Register */ ++#define PCIE_SLCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x84) ++ ++/* Slot Capabilities */ ++#define PCIE_SLCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x88) ++ ++/* Root Control and Capability Register */ ++#define PCIE_RCTLCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x8C) ++#define PCIE_RCTLCAP_SERR_ON_CORRECTABLE_ERR 0x00000001 /* #SERR on COR-ERR */ ++#define PCIE_RCTLCAP_SERR_ON_NONFATAL_ERR 0x00000002 /* #SERR on Non-Fatal ERR */ ++#define PCIE_RCTLCAP_SERR_ON_FATAL_ERR 0x00000004 /* #SERR on Fatal ERR */ ++#define PCIE_RCTLCAP_PME_INT_EN 0x00000008 /* PME Interrupt Enable */ ++#define PCIE_RCTLCAP_SERR_ENABLE (PCIE_RCTLCAP_SERR_ON_CORRECTABLE_ERR | \ ++ PCIE_RCTLCAP_SERR_ON_NONFATAL_ERR | PCIE_RCTLCAP_SERR_ON_FATAL_ERR) ++/* Root Status Register */ ++#define PCIE_RSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x90) ++#define PCIE_RSTS_PME_REQ_ID 0x0000FFFF /* PME Request ID */ ++#define PCIE_RSTS_PME_REQ_ID_S 0 ++#define PCIE_RSTS_PME_STATUS 0x00010000 /* PME Status */ ++#define PCIE_RSTS_PME_PENDING 0x00020000 /* PME Pending */ ++ ++/* PCI Express Enhanced Capability Header */ ++#define PCIE_ENHANCED_CAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x100) ++#define PCIE_ENHANCED_CAP_ID 0x0000FFFF /* PCI Express Extended Capability ID */ ++#define PCIE_ENHANCED_CAP_ID_S 0 ++#define PCIE_ENHANCED_CAP_VER 0x000F0000 /* Capability Version */ ++#define PCIE_ENHANCED_CAP_VER_S 16 ++#define PCIE_ENHANCED_CAP_NEXT_OFFSET 0xFFF00000 /* Next Capability Offset */ ++#define PCIE_ENHANCED_CAP_NEXT_OFFSET_S 20 ++ ++/* Uncorrectable Error Status Register */ ++#define PCIE_UES_R(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x104) ++#define PCIE_DATA_LINK_PROTOCOL_ERR 0x00000010 /* Data Link Protocol Error Status */ ++#define PCIE_SURPRISE_DOWN_ERROR 0x00000020 /* Surprise Down Error Status */ ++#define PCIE_POISONED_TLP 0x00001000 /* Poisoned TLP Status */ ++#define PCIE_FC_PROTOCOL_ERR 0x00002000 /* Flow Control Protocol Error Status */ ++#define PCIE_COMPLETION_TIMEOUT 0x00004000 /* Completion Timeout Status */ ++#define PCIE_COMPLETOR_ABORT 0x00008000 /* Completer Abort Error */ ++#define PCIE_UNEXPECTED_COMPLETION 0x00010000 /* Unexpected Completion Status */ ++#define PCIE_RECEIVER_OVERFLOW 0x00020000 /* Receive Overflow Status */ ++#define PCIE_MALFORNED_TLP 0x00040000 /* Malformed TLP Stauts */ ++#define PCIE_ECRC_ERR 0x00080000 /* ECRC Error Stauts */ ++#define PCIE_UR_REQ 0x00100000 /* Unsupported Request Error Status */ ++#define PCIE_ALL_UNCORRECTABLE_ERR (PCIE_DATA_LINK_PROTOCOL_ERR | PCIE_SURPRISE_DOWN_ERROR | \ ++ PCIE_POISONED_TLP | PCIE_FC_PROTOCOL_ERR | PCIE_COMPLETION_TIMEOUT | \ ++ PCIE_COMPLETOR_ABORT | PCIE_UNEXPECTED_COMPLETION | PCIE_RECEIVER_OVERFLOW |\ ++ PCIE_MALFORNED_TLP | PCIE_ECRC_ERR | PCIE_UR_REQ) ++ ++/* Uncorrectable Error Mask Register, Mask means no report */ ++#define PCIE_UEMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x108) ++ ++/* Uncorrectable Error Severity Register */ ++#define PCIE_UESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x10C) ++ ++/* Correctable Error Status Register */ ++#define PCIE_CESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x110) ++#define PCIE_RX_ERR 0x00000001 /* Receive Error Status */ ++#define PCIE_BAD_TLP 0x00000040 /* Bad TLP Status */ ++#define PCIE_BAD_DLLP 0x00000080 /* Bad DLLP Status */ ++#define PCIE_REPLAY_NUM_ROLLOVER 0x00000100 /* Replay Number Rollover Status */ ++#define PCIE_REPLAY_TIMER_TIMEOUT_ERR 0x00001000 /* Reply Timer Timeout Status */ ++#define PCIE_ADVISORY_NONFTAL_ERR 0x00002000 /* Advisory Non-Fatal Error Status */ ++#define PCIE_CORRECTABLE_ERR (PCIE_RX_ERR | PCIE_BAD_TLP | PCIE_BAD_DLLP | PCIE_REPLAY_NUM_ROLLOVER |\ ++ PCIE_REPLAY_TIMER_TIMEOUT_ERR | PCIE_ADVISORY_NONFTAL_ERR) ++ ++/* Correctable Error Mask Register */ ++#define PCIE_CEMR(X) (volatile u32*)(PCIE_RC_CFG_BASE + 0x114) ++ ++/* Advanced Error Capabilities and Control Register */ ++#define PCIE_AECCR(X) (volatile u32*)(PCIE_RC_CFG_BASE + 0x118) ++#define PCIE_AECCR_FIRST_ERR_PTR 0x0000001F /* First Error Pointer */ ++#define PCIE_AECCR_FIRST_ERR_PTR_S 0 ++#define PCIE_AECCR_ECRC_GEN_CAP 0x00000020 /* ECRC Generation Capable */ ++#define PCIE_AECCR_ECRC_GEN_EN 0x00000040 /* ECRC Generation Enable */ ++#define PCIE_AECCR_ECRC_CHECK_CAP 0x00000080 /* ECRC Check Capable */ ++#define PCIE_AECCR_ECRC_CHECK_EN 0x00000100 /* ECRC Check Enable */ ++ ++/* Header Log Register 1 */ ++#define PCIE_HLR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x11C) ++ ++/* Header Log Register 2 */ ++#define PCIE_HLR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x120) ++ ++/* Header Log Register 3 */ ++#define PCIE_HLR3(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x124) ++ ++/* Header Log Register 4 */ ++#define PCIE_HLR4(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x128) ++ ++/* Root Error Command Register */ ++#define PCIE_RECR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x12C) ++#define PCIE_RECR_CORRECTABLE_ERR_REPORT_EN 0x00000001 /* COR-ERR */ ++#define PCIE_RECR_NONFATAL_ERR_REPORT_EN 0x00000002 /* Non-Fatal ERR */ ++#define PCIE_RECR_FATAL_ERR_REPORT_EN 0x00000004 /* Fatal ERR */ ++#define PCIE_RECR_ERR_REPORT_EN (PCIE_RECR_CORRECTABLE_ERR_REPORT_EN | \ ++ PCIE_RECR_NONFATAL_ERR_REPORT_EN | PCIE_RECR_FATAL_ERR_REPORT_EN) ++ ++/* Root Error Status Register */ ++#define PCIE_RESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x130) ++#define PCIE_RESR_CORRECTABLE_ERR 0x00000001 /* COR-ERR Receveid */ ++#define PCIE_RESR_MULTI_CORRECTABLE_ERR 0x00000002 /* Multiple COR-ERR Received */ ++#define PCIE_RESR_FATAL_NOFATAL_ERR 0x00000004 /* ERR Fatal/Non-Fatal Received */ ++#define PCIE_RESR_MULTI_FATAL_NOFATAL_ERR 0x00000008 /* Multiple ERR Fatal/Non-Fatal Received */ ++#define PCIE_RESR_FIRST_UNCORRECTABLE_FATAL_ERR 0x00000010 /* First UN-COR Fatal */ ++#define PCIR_RESR_NON_FATAL_ERR 0x00000020 /* Non-Fatal Error Message Received */ ++#define PCIE_RESR_FATAL_ERR 0x00000040 /* Fatal Message Received */ ++#define PCIE_RESR_AER_INT_MSG_NUM 0xF8000000 /* Advanced Error Interrupt Message Number */ ++#define PCIE_RESR_AER_INT_MSG_NUM_S 27 ++ ++/* Error Source Indentification Register */ ++#define PCIE_ESIR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x134) ++#define PCIE_ESIR_CORRECTABLE_ERR_SRC_ID 0x0000FFFF ++#define PCIE_ESIR_CORRECTABLE_ERR_SRC_ID_S 0 ++#define PCIE_ESIR_FATAL_NON_FATAL_SRC_ID 0xFFFF0000 ++#define PCIE_ESIR_FATAL_NON_FATAL_SRC_ID_S 16 ++ ++/* VC Enhanced Capability Header */ ++#define PCIE_VC_ECH(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x140) ++ ++/* Port VC Capability Register */ ++#define PCIE_PVC1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x144) ++#define PCIE_PVC1_EXT_VC_CNT 0x00000007 /* Extended VC Count */ ++#define PCIE_PVC1_EXT_VC_CNT_S 0 ++#define PCIE_PVC1_LOW_PRI_EXT_VC_CNT 0x00000070 /* Low Priority Extended VC Count */ ++#define PCIE_PVC1_LOW_PRI_EXT_VC_CNT_S 4 ++#define PCIE_PVC1_REF_CLK 0x00000300 /* Reference Clock */ ++#define PCIE_PVC1_REF_CLK_S 8 ++#define PCIE_PVC1_PORT_ARB_TAB_ENTRY_SIZE 0x00000C00 /* Port Arbitration Table Entry Size */ ++#define PCIE_PVC1_PORT_ARB_TAB_ENTRY_SIZE_S 10 ++ ++/* Extended Virtual Channel Count Defintion */ ++#define PCIE_EXT_VC_CNT_MIN 0 ++#define PCIE_EXT_VC_CNT_MAX 7 ++ ++/* Port Arbitration Table Entry Size Definition */ ++enum { ++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S1BIT = 0, ++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S2BIT, ++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S4BIT, ++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S8BIT, ++}; ++ ++/* Port VC Capability Register 2 */ ++#define PCIE_PVC2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x148) ++#define PCIE_PVC2_VC_ARB_16P_FIXED_WRR 0x00000001 /* HW Fixed arbitration, 16 phase WRR */ ++#define PCIE_PVC2_VC_ARB_32P_WRR 0x00000002 /* 32 phase WRR */ ++#define PCIE_PVC2_VC_ARB_64P_WRR 0x00000004 /* 64 phase WRR */ ++#define PCIE_PVC2_VC_ARB_128P_WRR 0x00000008 /* 128 phase WRR */ ++#define PCIE_PVC2_VC_ARB_WRR 0x0000000F ++#define PCIE_PVC2_VC_ARB_TAB_OFFSET 0xFF000000 /* VC arbitration table offset, not support */ ++#define PCIE_PVC2_VC_ARB_TAB_OFFSET_S 24 ++ ++/* Port VC Control and Status Register */ ++#define PCIE_PVCCRSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x14C) ++#define PCIE_PVCCRSR_LOAD_VC_ARB_TAB 0x00000001 /* Load VC Arbitration Table */ ++#define PCIE_PVCCRSR_VC_ARB_SEL 0x0000000E /* VC Arbitration Select */ ++#define PCIE_PVCCRSR_VC_ARB_SEL_S 1 ++#define PCIE_PVCCRSR_VC_ARB_TAB_STATUS 0x00010000 /* Arbitration Status */ ++ ++/* VC0 Resource Capability Register */ ++#define PCIE_VC0_RC(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x150) ++#define PCIE_VC0_RC_PORT_ARB_HW_FIXED 0x00000001 /* HW Fixed arbitration */ ++#define PCIE_VC0_RC_PORT_ARB_32P_WRR 0x00000002 /* 32 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB_64P_WRR 0x00000004 /* 64 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB_128P_WRR 0x00000008 /* 128 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB_TM_128P_WRR 0x00000010 /* Time-based 128 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB_TM_256P_WRR 0x00000020 /* Time-based 256 phase WRR */ ++#define PCIE_VC0_RC_PORT_ARB (PCIE_VC0_RC_PORT_ARB_HW_FIXED | PCIE_VC0_RC_PORT_ARB_32P_WRR |\ ++ PCIE_VC0_RC_PORT_ARB_64P_WRR | PCIE_VC0_RC_PORT_ARB_128P_WRR | \ ++ PCIE_VC0_RC_PORT_ARB_TM_128P_WRR | PCIE_VC0_RC_PORT_ARB_TM_256P_WRR) ++ ++#define PCIE_VC0_RC_REJECT_SNOOP 0x00008000 /* Reject Snoop Transactioin */ ++#define PCIE_VC0_RC_MAX_TIMESLOTS 0x007F0000 /* Maximum time Slots */ ++#define PCIE_VC0_RC_MAX_TIMESLOTS_S 16 ++#define PCIE_VC0_RC_PORT_ARB_TAB_OFFSET 0xFF000000 /* Port Arbitration Table Offset */ ++#define PCIE_VC0_RC_PORT_ARB_TAB_OFFSET_S 24 ++ ++/* VC0 Resource Control Register */ ++#define PCIE_VC0_RC0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x154) ++#define PCIE_VC0_RC0_TVM0 0x00000001 /* TC0 and VC0 */ ++#define PCIE_VC0_RC0_TVM1 0x00000002 /* TC1 and VC1 */ ++#define PCIE_VC0_RC0_TVM2 0x00000004 /* TC2 and VC2 */ ++#define PCIE_VC0_RC0_TVM3 0x00000008 /* TC3 and VC3 */ ++#define PCIE_VC0_RC0_TVM4 0x00000010 /* TC4 and VC4 */ ++#define PCIE_VC0_RC0_TVM5 0x00000020 /* TC5 and VC5 */ ++#define PCIE_VC0_RC0_TVM6 0x00000040 /* TC6 and VC6 */ ++#define PCIE_VC0_RC0_TVM7 0x00000080 /* TC7 and VC7 */ ++#define PCIE_VC0_RC0_TC_VC 0x000000FF /* TC/VC mask */ ++ ++#define PCIE_VC0_RC0_LOAD_PORT_ARB_TAB 0x00010000 /* Load Port Arbitration Table */ ++#define PCIE_VC0_RC0_PORT_ARB_SEL 0x000E0000 /* Port Arbitration Select */ ++#define PCIE_VC0_RC0_PORT_ARB_SEL_S 17 ++#define PCIE_VC0_RC0_VC_ID 0x07000000 /* VC ID */ ++#define PCIE_VC0_RC0_VC_ID_S 24 ++#define PCIE_VC0_RC0_VC_EN 0x80000000 /* VC Enable */ ++ ++/* VC0 Resource Status Register */ ++#define PCIE_VC0_RSR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x158) ++#define PCIE_VC0_RSR0_PORT_ARB_TAB_STATUS 0x00010000 /* Port Arbitration Table Status,not used */ ++#define PCIE_VC0_RSR0_VC_NEG_PENDING 0x00020000 /* VC Negotiation Pending */ ++ ++/* Ack Latency Timer and Replay Timer Register */ ++#define PCIE_ALTRT(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x700) ++#define PCIE_ALTRT_ROUND_TRIP_LATENCY_LIMIT 0x0000FFFF /* Round Trip Latency Time Limit */ ++#define PCIE_ALTRT_ROUND_TRIP_LATENCY_LIMIT_S 0 ++#define PCIE_ALTRT_REPLAY_TIME_LIMIT 0xFFFF0000 /* Replay Time Limit */ ++#define PCIE_ALTRT_REPLAY_TIME_LIMIT_S 16 ++ ++/* Other Message Register */ ++#define PCIE_OMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x704) ++ ++/* Port Force Link Register */ ++#define PCIE_PFLR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x708) ++#define PCIE_PFLR_LINK_NUM 0x000000FF /* Link Number */ ++#define PCIE_PFLR_LINK_NUM_S 0 ++#define PCIE_PFLR_FORCE_LINK 0x00008000 /* Force link */ ++#define PCIE_PFLR_LINK_STATE 0x003F0000 /* Link State */ ++#define PCIE_PFLR_LINK_STATE_S 16 ++#define PCIE_PFLR_LOW_POWER_ENTRY_CNT 0xFF000000 /* Low Power Entrance Count, only for EP */ ++#define PCIE_PFLR_LOW_POWER_ENTRY_CNT_S 24 ++ ++/* Ack Frequency Register */ ++#define PCIE_AFR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x70C) ++#define PCIE_AFR_AF 0x000000FF /* Ack Frequency */ ++#define PCIE_AFR_AF_S 0 ++#define PCIE_AFR_FTS_NUM 0x0000FF00 /* The number of Fast Training Sequence from L0S to L0 */ ++#define PCIE_AFR_FTS_NUM_S 8 ++#define PCIE_AFR_COM_FTS_NUM 0x00FF0000 /* N_FTS; when common clock is used*/ ++#define PCIE_AFR_COM_FTS_NUM_S 16 ++#define PCIE_AFR_L0S_ENTRY_LATENCY 0x07000000 /* L0s Entrance Latency */ ++#define PCIE_AFR_L0S_ENTRY_LATENCY_S 24 ++#define PCIE_AFR_L1_ENTRY_LATENCY 0x38000000 /* L1 Entrance Latency */ ++#define PCIE_AFR_L1_ENTRY_LATENCY_S 27 ++#define PCIE_AFR_FTS_NUM_DEFAULT 32 ++#define PCIE_AFR_L0S_ENTRY_LATENCY_DEFAULT 7 ++#define PCIE_AFR_L1_ENTRY_LATENCY_DEFAULT 5 ++ ++/* Port Link Control Register */ ++#define PCIE_PLCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x710) ++#define PCIE_PLCR_OTHER_MSG_REQ 0x00000001 /* Other Message Request */ ++#define PCIE_PLCR_SCRAMBLE_DISABLE 0x00000002 /* Scramble Disable */ ++#define PCIE_PLCR_LOOPBACK_EN 0x00000004 /* Loopback Enable */ ++#define PCIE_PLCR_LTSSM_HOT_RST 0x00000008 /* Force LTSSM to the hot reset */ ++#define PCIE_PLCR_DLL_LINK_EN 0x00000020 /* Enable Link initialization */ ++#define PCIE_PLCR_FAST_LINK_SIM_EN 0x00000080 /* Sets all internal timers to fast mode for simulation purposes */ ++#define PCIE_PLCR_LINK_MODE 0x003F0000 /* Link Mode Enable Mask */ ++#define PCIE_PLCR_LINK_MODE_S 16 ++#define PCIE_PLCR_CORRUPTED_CRC_EN 0x02000000 /* Enabled Corrupt CRC */ ++ ++/* Lane Skew Register */ ++#define PCIE_LSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x714) ++#define PCIE_LSR_LANE_SKEW_NUM 0x00FFFFFF /* Insert Lane Skew for Transmit, not applicable */ ++#define PCIE_LSR_LANE_SKEW_NUM_S 0 ++#define PCIE_LSR_FC_DISABLE 0x01000000 /* Disable of Flow Control */ ++#define PCIE_LSR_ACKNAK_DISABLE 0x02000000 /* Disable of Ack/Nak */ ++#define PCIE_LSR_LANE_DESKEW_DISABLE 0x80000000 /* Disable of Lane-to-Lane Skew */ ++ ++/* Symbol Number Register */ ++#define PCIE_SNR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x718) ++#define PCIE_SNR_TS 0x0000000F /* Number of TS Symbol */ ++#define PCIE_SNR_TS_S 0 ++#define PCIE_SNR_SKP 0x00000700 /* Number of SKP Symbol */ ++#define PCIE_SNR_SKP_S 8 ++#define PCIE_SNR_REPLAY_TIMER 0x0007C000 /* Timer Modifier for Replay Timer */ ++#define PCIE_SNR_REPLAY_TIMER_S 14 ++#define PCIE_SNR_ACKNAK_LATENCY_TIMER 0x00F80000 /* Timer Modifier for Ack/Nak Latency Timer */ ++#define PCIE_SNR_ACKNAK_LATENCY_TIMER_S 19 ++#define PCIE_SNR_FC_TIMER 0x1F000000 /* Timer Modifier for Flow Control Watchdog Timer */ ++#define PCIE_SNR_FC_TIMER_S 28 ++ ++/* Symbol Timer Register and Filter Mask Register 1 */ ++#define PCIE_STRFMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x71C) ++#define PCIE_STRFMR_SKP_INTERVAL 0x000007FF /* SKP lnterval Value */ ++#define PCIE_STRFMR_SKP_INTERVAL_S 0 ++#define PCIE_STRFMR_FC_WDT_DISABLE 0x00008000 /* Disable of FC Watchdog Timer */ ++#define PCIE_STRFMR_TLP_FUNC_MISMATCH_OK 0x00010000 /* Mask Function Mismatch Filtering for Incoming Requests */ ++#define PCIE_STRFMR_POISONED_TLP_OK 0x00020000 /* Mask Poisoned TLP Filtering */ ++#define PCIE_STRFMR_BAR_MATCH_OK 0x00040000 /* Mask BAR Match Filtering */ ++#define PCIE_STRFMR_TYPE1_CFG_REQ_OK 0x00080000 /* Mask Type 1 Configuration Request Filtering */ ++#define PCIE_STRFMR_LOCKED_REQ_OK 0x00100000 /* Mask Locked Request Filtering */ ++#define PCIE_STRFMR_CPL_TAG_ERR_RULES_OK 0x00200000 /* Mask Tag Error Rules for Received Completions */ ++#define PCIE_STRFMR_CPL_REQUESTOR_ID_MISMATCH_OK 0x00400000 /* Mask Requester ID Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_CPL_FUNC_MISMATCH_OK 0x00800000 /* Mask Function Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_CPL_TC_MISMATCH_OK 0x01000000 /* Mask Traffic Class Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_CPL_ATTR_MISMATCH_OK 0x02000000 /* Mask Attribute Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_CPL_LENGTH_MISMATCH_OK 0x04000000 /* Mask Length Mismatch Error for Received Completions */ ++#define PCIE_STRFMR_TLP_ECRC_ERR_OK 0x08000000 /* Mask ECRC Error Filtering */ ++#define PCIE_STRFMR_CPL_TLP_ECRC_OK 0x10000000 /* Mask ECRC Error Filtering for Completions */ ++#define PCIE_STRFMR_RX_TLP_MSG_NO_DROP 0x20000000 /* Send Message TLPs */ ++#define PCIE_STRFMR_RX_IO_TRANS_ENABLE 0x40000000 /* Mask Filtering of received I/O Requests */ ++#define PCIE_STRFMR_RX_CFG_TRANS_ENABLE 0x80000000 /* Mask Filtering of Received Configuration Requests */ ++ ++#define PCIE_DEF_SKP_INTERVAL 700 /* 1180 ~1538 , 125MHz * 2, 250MHz * 1 */ ++ ++/* Filter Masker Register 2 */ ++#define PCIE_FMR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x720) ++#define PCIE_FMR2_VENDOR_MSG0_PASSED_TO_TRGT1 0x00000001 /* Mask RADM Filtering and Error Handling Rules */ ++#define PCIE_FMR2_VENDOR_MSG1_PASSED_TO_TRGT1 0x00000002 /* Mask RADM Filtering and Error Handling Rules */ ++ ++/* Debug Register 0 */ ++#define PCIE_DBR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x728) ++ ++/* Debug Register 1 */ ++#define PCIE_DBR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x72C) ++ ++/* Transmit Posted FC Credit Status Register */ ++#define PCIE_TPFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x730) ++#define PCIE_TPFCS_TX_P_DATA_FC_CREDITS 0x00000FFF /* Transmit Posted Data FC Credits */ ++#define PCIE_TPFCS_TX_P_DATA_FC_CREDITS_S 0 ++#define PCIE_TPFCS_TX_P_HDR_FC_CREDITS 0x000FF000 /* Transmit Posted Header FC Credits */ ++#define PCIE_TPFCS_TX_P_HDR_FC_CREDITS_S 12 ++ ++/* Transmit Non-Posted FC Credit Status */ ++#define PCIE_TNPFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x734) ++#define PCIE_TNPFCS_TX_NP_DATA_FC_CREDITS 0x00000FFF /* Transmit Non-Posted Data FC Credits */ ++#define PCIE_TNPFCS_TX_NP_DATA_FC_CREDITS_S 0 ++#define PCIE_TNPFCS_TX_NP_HDR_FC_CREDITS 0x000FF000 /* Transmit Non-Posted Header FC Credits */ ++#define PCIE_TNPFCS_TX_NP_HDR_FC_CREDITS_S 12 ++ ++/* Transmit Complete FC Credit Status Register */ ++#define PCIE_TCFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x738) ++#define PCIE_TCFCS_TX_CPL_DATA_FC_CREDITS 0x00000FFF /* Transmit Completion Data FC Credits */ ++#define PCIE_TCFCS_TX_CPL_DATA_FC_CREDITS_S 0 ++#define PCIE_TCFCS_TX_CPL_HDR_FC_CREDITS 0x000FF000 /* Transmit Completion Header FC Credits */ ++#define PCIE_TCFCS_TX_CPL_HDR_FC_CREDITS_S 12 ++ ++/* Queue Status Register */ ++#define PCIE_QSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x73C) ++#define PCIE_QSR_WAIT_UPDATE_FC_DLL 0x00000001 /* Received TLP FC Credits Not Returned */ ++#define PCIE_QSR_TX_RETRY_BUF_NOT_EMPTY 0x00000002 /* Transmit Retry Buffer Not Empty */ ++#define PCIE_QSR_RX_QUEUE_NOT_EMPTY 0x00000004 /* Received Queue Not Empty */ ++ ++/* VC Transmit Arbitration Register 1 */ ++#define PCIE_VCTAR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x740) ++#define PCIE_VCTAR1_WRR_WEIGHT_VC0 0x000000FF /* WRR Weight for VC0 */ ++#define PCIE_VCTAR1_WRR_WEIGHT_VC1 0x0000FF00 /* WRR Weight for VC1 */ ++#define PCIE_VCTAR1_WRR_WEIGHT_VC2 0x00FF0000 /* WRR Weight for VC2 */ ++#define PCIE_VCTAR1_WRR_WEIGHT_VC3 0xFF000000 /* WRR Weight for VC3 */ ++ ++/* VC Transmit Arbitration Register 2 */ ++#define PCIE_VCTAR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x744) ++#define PCIE_VCTAR2_WRR_WEIGHT_VC4 0x000000FF /* WRR Weight for VC4 */ ++#define PCIE_VCTAR2_WRR_WEIGHT_VC5 0x0000FF00 /* WRR Weight for VC5 */ ++#define PCIE_VCTAR2_WRR_WEIGHT_VC6 0x00FF0000 /* WRR Weight for VC6 */ ++#define PCIE_VCTAR2_WRR_WEIGHT_VC7 0xFF000000 /* WRR Weight for VC7 */ ++ ++/* VC0 Posted Receive Queue Control Register */ ++#define PCIE_VC0_PRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x748) ++#define PCIE_VC0_PRQCR_P_DATA_CREDITS 0x00000FFF /* VC0 Posted Data Credits */ ++#define PCIE_VC0_PRQCR_P_DATA_CREDITS_S 0 ++#define PCIE_VC0_PRQCR_P_HDR_CREDITS 0x000FF000 /* VC0 Posted Header Credits */ ++#define PCIE_VC0_PRQCR_P_HDR_CREDITS_S 12 ++#define PCIE_VC0_PRQCR_P_TLP_QUEUE_MODE 0x00E00000 /* VC0 Posted TLP Queue Mode */ ++#define PCIE_VC0_PRQCR_P_TLP_QUEUE_MODE_S 20 ++#define PCIE_VC0_PRQCR_TLP_RELAX_ORDER 0x40000000 /* TLP Type Ordering for VC0 */ ++#define PCIE_VC0_PRQCR_VC_STRICT_ORDER 0x80000000 /* VC0 Ordering for Receive Queues */ ++ ++/* VC0 Non-Posted Receive Queue Control */ ++#define PCIE_VC0_NPRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x74C) ++#define PCIE_VC0_NPRQCR_NP_DATA_CREDITS 0x00000FFF /* VC0 Non-Posted Data Credits */ ++#define PCIE_VC0_NPRQCR_NP_DATA_CREDITS_S 0 ++#define PCIE_VC0_NPRQCR_NP_HDR_CREDITS 0x000FF000 /* VC0 Non-Posted Header Credits */ ++#define PCIE_VC0_NPRQCR_NP_HDR_CREDITS_S 12 ++#define PCIE_VC0_NPRQCR_NP_TLP_QUEUE_MODE 0x00E00000 /* VC0 Non-Posted TLP Queue Mode */ ++#define PCIE_VC0_NPRQCR_NP_TLP_QUEUE_MODE_S 20 ++ ++/* VC0 Completion Receive Queue Control */ ++#define PCIE_VC0_CRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x750) ++#define PCIE_VC0_CRQCR_CPL_DATA_CREDITS 0x00000FFF /* VC0 Completion TLP Queue Mode */ ++#define PCIE_VC0_CRQCR_CPL_DATA_CREDITS_S 0 ++#define PCIE_VC0_CRQCR_CPL_HDR_CREDITS 0x000FF000 /* VC0 Completion Header Credits */ ++#define PCIE_VC0_CRQCR_CPL_HDR_CREDITS_S 12 ++#define PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE 0x00E00000 /* VC0 Completion Data Credits */ ++#define PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE_S 21 ++ ++/* Applicable to the above three registers */ ++enum { ++ PCIE_VC0_TLP_QUEUE_MODE_STORE_FORWARD = 1, ++ PCIE_VC0_TLP_QUEUE_MODE_CUT_THROUGH = 2, ++ PCIE_VC0_TLP_QUEUE_MODE_BYPASS = 4, ++}; ++ ++/* VC0 Posted Buffer Depth Register */ ++#define PCIE_VC0_PBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7A8) ++#define PCIE_VC0_PBD_P_DATA_QUEUE_ENTRIES 0x00003FFF /* VC0 Posted Data Queue Depth */ ++#define PCIE_VC0_PBD_P_DATA_QUEUE_ENTRIES_S 0 ++#define PCIE_VC0_PBD_P_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Posted Header Queue Depth */ ++#define PCIE_VC0_PBD_P_HDR_QUEUE_ENTRIES_S 16 ++ ++/* VC0 Non-Posted Buffer Depth Register */ ++#define PCIE_VC0_NPBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7AC) ++#define PCIE_VC0_NPBD_NP_DATA_QUEUE_ENTRIES 0x00003FFF /* VC0 Non-Posted Data Queue Depth */ ++#define PCIE_VC0_NPBD_NP_DATA_QUEUE_ENTRIES_S 0 ++#define PCIE_VC0_NPBD_NP_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Non-Posted Header Queue Depth */ ++#define PCIE_VC0_NPBD_NP_HDR_QUEUE_ENTRIES_S 16 ++ ++/* VC0 Completion Buffer Depth Register */ ++#define PCIE_VC0_CBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7B0) ++#define PCIE_VC0_CBD_CPL_DATA_QUEUE_ENTRIES 0x00003FFF /* C0 Completion Data Queue Depth */ ++#define PCIE_VC0_CBD_CPL_DATA_QUEUE_ENTRIES_S 0 ++#define PCIE_VC0_CBD_CPL_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Completion Header Queue Depth */ ++#define PCIE_VC0_CBD_CPL_HDR_QUEUE_ENTRIES_S 16 ++ ++/* PHY Status Register, all zeros in VR9 */ ++#define PCIE_PHYSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x810) ++ ++/* PHY Control Register, all zeros in VR9 */ ++#define PCIE_PHYCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x814) ++ ++/* ++ * PCIe PDI PHY register definition, suppose all the following ++ * stuff is confidential. ++ * XXX, detailed bit definition ++ */ ++#define PCIE_PHY_PLL_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x22 << 1)) ++#define PCIE_PHY_PLL_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x23 << 1)) ++#define PCIE_PHY_PLL_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x24 << 1)) ++#define PCIE_PHY_PLL_CTRL4(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x25 << 1)) ++#define PCIE_PHY_PLL_CTRL5(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x26 << 1)) ++#define PCIE_PHY_PLL_CTRL6(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x27 << 1)) ++#define PCIE_PHY_PLL_CTRL7(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x28 << 1)) ++#define PCIE_PHY_PLL_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x29 << 1)) ++#define PCIE_PHY_PLL_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2A << 1)) ++#define PCIE_PHY_PLL_A_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2B << 1)) ++#define PCIE_PHY_PLL_STATUS(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2C << 1)) ++ ++#define PCIE_PHY_TX1_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x30 << 1)) ++#define PCIE_PHY_TX1_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x31 << 1)) ++#define PCIE_PHY_TX1_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x32 << 1)) ++#define PCIE_PHY_TX1_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x33 << 1)) ++#define PCIE_PHY_TX1_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x34 << 1)) ++#define PCIE_PHY_TX1_MOD1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x35 << 1)) ++#define PCIE_PHY_TX1_MOD2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x36 << 1)) ++#define PCIE_PHY_TX1_MOD3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x37 << 1)) ++ ++#define PCIE_PHY_TX2_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x38 << 1)) ++#define PCIE_PHY_TX2_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x39 << 1)) ++#define PCIE_PHY_TX2_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3B << 1)) ++#define PCIE_PHY_TX2_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3C << 1)) ++#define PCIE_PHY_TX2_MOD1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3D << 1)) ++#define PCIE_PHY_TX2_MOD2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3E << 1)) ++#define PCIE_PHY_TX2_MOD3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3F << 1)) ++ ++#define PCIE_PHY_RX1_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x50 << 1)) ++#define PCIE_PHY_RX1_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x51 << 1)) ++#define PCIE_PHY_RX1_CDR(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x52 << 1)) ++#define PCIE_PHY_RX1_EI(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x53 << 1)) ++#define PCIE_PHY_RX1_A_CTRL(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x55 << 1)) ++ ++/* Interrupt related stuff */ ++#define PCIE_LEGACY_DISABLE 0 ++#define PCIE_LEGACY_INTA 1 ++#define PCIE_LEGACY_INTB 2 ++#define PCIE_LEGACY_INTC 3 ++#define PCIE_LEGACY_INTD 4 ++#define PCIE_LEGACY_INT_MAX PCIE_LEGACY_INTD ++ ++#define PCIE_IRQ_LOCK(lock) do { \ ++ unsigned long flags; \ ++ spin_lock_irqsave(&(lock), flags); ++#define PCIE_IRQ_UNLOCK(lock) \ ++ spin_unlock_irqrestore(&(lock), flags); \ ++} while (0) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#define IRQF_SHARED SA_SHIRQ ++#endif ++ ++#define PCIE_MSG_MSI 0x00000001 ++#define PCIE_MSG_ISR 0x00000002 ++#define PCIE_MSG_FIXUP 0x00000004 ++#define PCIE_MSG_READ_CFG 0x00000008 ++#define PCIE_MSG_WRITE_CFG 0x00000010 ++#define PCIE_MSG_CFG (PCIE_MSG_READ_CFG | PCIE_MSG_WRITE_CFG) ++#define PCIE_MSG_REG 0x00000020 ++#define PCIE_MSG_INIT 0x00000040 ++#define PCIE_MSG_ERR 0x00000080 ++#define PCIE_MSG_PHY 0x00000100 ++#define PCIE_MSG_ANY 0x000001ff ++ ++#define IFX_PCIE_PORT0 0 ++#define IFX_PCIE_PORT1 1 ++ ++#ifdef CONFIG_IFX_PCIE_2ND_CORE ++#define IFX_PCIE_CORE_NR 2 ++#else ++#define IFX_PCIE_CORE_NR 1 ++#endif ++ ++//#define IFX_PCIE_ERROR_INT ++ ++//#define IFX_PCIE_DBG ++ ++#if defined(IFX_PCIE_DBG) ++#define IFX_PCIE_PRINT(_m, _fmt, args...) do { \ ++ if (g_pcie_debug_flag & (_m)) { \ ++ ifx_pcie_debug((_fmt), ##args); \ ++ } \ ++} while (0) ++ ++#define INLINE ++#else ++#define IFX_PCIE_PRINT(_m, _fmt, args...) \ ++ do {} while(0) ++#define INLINE inline ++#endif ++ ++struct ifx_pci_controller { ++ struct pci_controller pcic; ++ ++ /* RC specific, per host bus information */ ++ u32 port; /* Port index, 0 -- 1st core, 1 -- 2nd core */ ++}; ++ ++typedef struct ifx_pcie_ir_irq { ++ const unsigned int irq; ++ const char name[16]; ++}ifx_pcie_ir_irq_t; ++ ++typedef struct ifx_pcie_legacy_irq{ ++ const u32 irq_bit; ++ const int irq; ++}ifx_pcie_legacy_irq_t; ++ ++typedef struct ifx_pcie_irq { ++ ifx_pcie_ir_irq_t ir_irq; ++ ifx_pcie_legacy_irq_t legacy_irq[PCIE_LEGACY_INT_MAX]; ++}ifx_pcie_irq_t; ++ ++extern u32 g_pcie_debug_flag; ++extern void ifx_pcie_debug(const char *fmt, ...); ++extern void pcie_phy_clock_mode_setup(int pcie_port); ++extern void pcie_msi_pic_init(int pcie_port); ++extern u32 ifx_pcie_bus_enum_read_hack(int where, u32 value); ++extern u32 ifx_pcie_bus_enum_write_hack(int where, u32 value); ++ ++ ++#include <linux/types.h> ++#include <linux/delay.h> ++#include <linux/gpio.h> ++#include <linux/clk.h> ++ ++#include <lantiq_soc.h> ++ ++#define IFX_PCIE_GPIO_RESET 38 ++#define IFX_REG_R32 ltq_r32 ++#define IFX_REG_W32 ltq_w32 ++#define CONFIG_IFX_PCIE_HW_SWAP ++#define IFX_RCU_AHB_ENDIAN ((volatile u32*)(IFX_RCU + 0x004C)) ++#define IFX_RCU_RST_REQ ((volatile u32*)(IFX_RCU + 0x0010)) ++#define IFX_RCU_AHB_BE_PCIE_PDI 0x00000080 /* Configure PCIE PDI module in big endian*/ ++ ++#define IFX_RCU (KSEG1 | 0x1F203000) ++#define IFX_RCU_AHB_BE_PCIE_M 0x00000001 /* Configure AHB master port that connects to PCIe RC in big endian */ ++#define IFX_RCU_AHB_BE_PCIE_S 0x00000010 /* Configure AHB slave port that connects to PCIe RC in little endian */ ++#define IFX_RCU_AHB_BE_XBAR_M 0x00000002 /* Configure AHB master port that connects to XBAR in big endian */ ++#define CONFIG_IFX_PCIE_PHY_36MHZ_MODE ++ ++#define IFX_PMU1_MODULE_PCIE_PHY (0) ++#define IFX_PMU1_MODULE_PCIE_CTRL (1) ++#define IFX_PMU1_MODULE_PDI (4) ++#define IFX_PMU1_MODULE_MSI (5) ++ ++#define IFX_PMU_MODULE_PCIE_L0_CLK (31) ++ ++ ++static inline void pcie_ep_gpio_rst_init(int pcie_port) ++{ ++} ++ ++static inline void pcie_ahb_pmu_setup(void) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "ahb"); ++ clk_enable(clk); ++ //ltq_pmu_enable(PMU_AHBM | PMU_AHBS); ++} ++ ++static inline void pcie_rcu_endian_setup(int pcie_port) ++{ ++ u32 reg; ++ ++ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN); ++#ifdef CONFIG_IFX_PCIE_HW_SWAP ++ reg |= IFX_RCU_AHB_BE_PCIE_M; ++ reg |= IFX_RCU_AHB_BE_PCIE_S; ++ reg &= ~IFX_RCU_AHB_BE_XBAR_M; ++#else ++ reg |= IFX_RCU_AHB_BE_PCIE_M; ++ reg &= ~IFX_RCU_AHB_BE_PCIE_S; ++ reg &= ~IFX_RCU_AHB_BE_XBAR_M; ++#endif /* CONFIG_IFX_PCIE_HW_SWAP */ ++ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN); ++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s IFX_RCU_AHB_ENDIAN: 0x%08x\n", __func__, IFX_REG_R32(IFX_RCU_AHB_ENDIAN)); ++} ++ ++static inline void pcie_phy_pmu_enable(int pcie_port) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "phy"); ++ clk_enable(clk); ++ //ltq_pmu1_enable(1<<IFX_PMU1_MODULE_PCIE_PHY); ++} ++ ++static inline void pcie_phy_pmu_disable(int pcie_port) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "phy"); ++ clk_disable(clk); ++ //ltq_pmu1_disable(1<<IFX_PMU1_MODULE_PCIE_PHY); ++} ++ ++static inline void pcie_pdi_big_endian(int pcie_port) ++{ ++ u32 reg; ++ ++ /* SRAM2PDI endianness control. */ ++ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN); ++ /* Config AHB->PCIe and PDI endianness */ ++ reg |= IFX_RCU_AHB_BE_PCIE_PDI; ++ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN); ++} ++ ++static inline void pcie_pdi_pmu_enable(int pcie_port) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "pdi"); ++ clk_enable(clk); ++ //ltq_pmu1_enable(1<<IFX_PMU1_MODULE_PDI); ++} ++ ++static inline void pcie_core_rst_assert(int pcie_port) ++{ ++ u32 reg; ++ ++ reg = IFX_REG_R32(IFX_RCU_RST_REQ); ++ ++ /* Reset PCIe PHY & Core, bit 22, bit 26 may be affected if write it directly */ ++ reg |= 0x00400000; ++ IFX_REG_W32(reg, IFX_RCU_RST_REQ); ++} ++ ++static inline void pcie_core_rst_deassert(int pcie_port) ++{ ++ u32 reg; ++ ++ /* Make sure one micro-second delay */ ++ udelay(1); ++ ++ /* Reset PCIe PHY & Core, bit 22 */ ++ reg = IFX_REG_R32(IFX_RCU_RST_REQ); ++ reg &= ~0x00400000; ++ IFX_REG_W32(reg, IFX_RCU_RST_REQ); ++} ++ ++static inline void pcie_phy_rst_assert(int pcie_port) ++{ ++ u32 reg; ++ ++ reg = IFX_REG_R32(IFX_RCU_RST_REQ); ++ reg |= 0x00001000; /* Bit 12 */ ++ IFX_REG_W32(reg, IFX_RCU_RST_REQ); ++} ++ ++static inline void pcie_phy_rst_deassert(int pcie_port) ++{ ++ u32 reg; ++ ++ /* Make sure one micro-second delay */ ++ udelay(1); ++ ++ reg = IFX_REG_R32(IFX_RCU_RST_REQ); ++ reg &= ~0x00001000; /* Bit 12 */ ++ IFX_REG_W32(reg, IFX_RCU_RST_REQ); ++} ++ ++static inline void pcie_device_rst_assert(int pcie_port) ++{ ++ gpio_set_value(IFX_PCIE_GPIO_RESET, 0); ++ // ifx_gpio_output_clear(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id); ++} ++ ++static inline void pcie_device_rst_deassert(int pcie_port) ++{ ++ mdelay(100); ++ gpio_set_value(IFX_PCIE_GPIO_RESET, 1); ++// ifx_gpio_output_set(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id); ++} ++ ++static inline void pcie_core_pmu_setup(int pcie_port) ++{ ++ struct clk *clk; ++ clk = clk_get_sys("ltq_pcie", "ctl"); ++ clk_enable(clk); ++ clk = clk_get_sys("ltq_pcie", "bus"); ++ clk_enable(clk); ++ ++ //ltq_pmu1_enable(1 << IFX_PMU1_MODULE_PCIE_CTRL); ++ //ltq_pmu_enable(1 << IFX_PMU_MODULE_PCIE_L0_CLK); ++} ++ ++static inline void pcie_msi_init(int pcie_port) ++{ ++ struct clk *clk; ++ pcie_msi_pic_init(pcie_port); ++ clk = clk_get_sys("ltq_pcie", "msi"); ++ clk_enable(clk); ++ //ltq_pmu1_enable(1 << IFX_PMU1_MODULE_MSI); ++} ++ ++static inline u32 ++ifx_pcie_bus_nr_deduct(u32 bus_number, int pcie_port) ++{ ++ u32 tbus_number = bus_number; ++ ++#ifdef CONFIG_IFX_PCI ++ if (pcibios_host_nr() > 1) { ++ tbus_number -= pcibios_1st_host_bus_nr(); ++ } ++#endif /* CONFIG_IFX_PCI */ ++ return tbus_number; ++} ++ ++static inline u32 ++ifx_pcie_bus_enum_hack(struct pci_bus *bus, u32 devfn, int where, u32 value, int pcie_port, int read) ++{ ++ struct pci_dev *pdev; ++ u32 tvalue = value; ++ ++ /* Sanity check */ ++ pdev = pci_get_slot(bus, devfn); ++ if (pdev == NULL) { ++ return tvalue; ++ } ++ ++ /* Only care about PCI bridge */ ++ if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { ++ return tvalue; ++ } ++ ++ if (read) { /* Read hack */ ++ #ifdef CONFIG_IFX_PCI ++ if (pcibios_host_nr() > 1) { ++ tvalue = ifx_pcie_bus_enum_read_hack(where, tvalue); ++ } ++ #endif /* CONFIG_IFX_PCI */ ++ } ++ else { /* Write hack */ ++ #ifdef CONFIG_IFX_PCI ++ if (pcibios_host_nr() > 1) { ++ tvalue = ifx_pcie_bus_enum_write_hack(where, tvalue); ++ } ++ #endif ++ } ++ return tvalue; ++} ++ ++#endif /* IFXMIPS_PCIE_VR9_H */ ++ +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0026-MIPS-lantiq-adds-GPIO3-support-on-AR9.patch b/target/linux/lantiq/patches-3.2/0056-MIPS-lantiq-make-GPIO3-work-on-AR9.patch index ee41b3ab44..295e7acb96 100644 --- a/target/linux/lantiq/patches/0026-MIPS-lantiq-adds-GPIO3-support-on-AR9.patch +++ b/target/linux/lantiq/patches-3.2/0056-MIPS-lantiq-make-GPIO3-work-on-AR9.patch @@ -1,7 +1,7 @@ -From 92b24777385cd8388e0fa8b9f1d24e5bc4466641 Mon Sep 17 00:00:00 2001 +From b11a96f2bdf1730fe3fd3be1d0667e20a4eb5bff Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 13 Aug 2011 13:59:50 +0200 -Subject: [PATCH 12/22] MIPS: lantiq: make GPIO3 work on AR9 +Subject: [PATCH 56/70] MIPS: lantiq: make GPIO3 work on AR9 There are 3 16bit and 1 8bit gpio ports on AR9. The gpio driver needs a hack at 2 places to make the different register layout of the GPIO3 work properly @@ -13,14 +13,16 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> --- .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + arch/mips/lantiq/xway/devices.c | 3 + - arch/mips/lantiq/xway/gpio.c | 62 ++++++++++++++++---- + arch/mips/lantiq/xway/gpio.c | 84 ++++++++++++++++---- arch/mips/lantiq/xway/gpio_ebu.c | 3 +- arch/mips/lantiq/xway/gpio_stp.c | 3 +- - 5 files changed, 57 insertions(+), 16 deletions(-) + 5 files changed, 75 insertions(+), 20 deletions(-) +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index d1b8cc8..bfdeb16 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -121,7 +121,9 @@ +@@ -126,7 +126,9 @@ #define LTQ_GPIO0_BASE_ADDR 0x1E100B10 #define LTQ_GPIO1_BASE_ADDR 0x1E100B40 #define LTQ_GPIO2_BASE_ADDR 0x1E100B70 @@ -30,9 +32,11 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> /* SSC */ #define LTQ_SSC_BASE_ADDR 0x1e100800 +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index 5efa4f3..e6d45bc 100644 --- a/arch/mips/lantiq/xway/devices.c +++ b/arch/mips/lantiq/xway/devices.c -@@ -34,6 +34,7 @@ static struct resource ltq_gpio_resource +@@ -34,6 +34,7 @@ static struct resource ltq_gpio_resource[] = { MEM_RES("gpio0", LTQ_GPIO0_BASE_ADDR, LTQ_GPIO_SIZE), MEM_RES("gpio1", LTQ_GPIO1_BASE_ADDR, LTQ_GPIO_SIZE), MEM_RES("gpio2", LTQ_GPIO2_BASE_ADDR, LTQ_GPIO_SIZE), @@ -49,14 +53,18 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> } } +diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c +index 54ec6c9..375329b 100644 --- a/arch/mips/lantiq/xway/gpio.c +++ b/arch/mips/lantiq/xway/gpio.c -@@ -23,9 +23,15 @@ +@@ -23,9 +23,17 @@ #define LTQ_GPIO_OD 0x14 #define LTQ_GPIO_PUDSEL 0x1C #define LTQ_GPIO_PUDEN 0x20 +#define LTQ_GPIO3_OD 0x24 +#define LTQ_GPIO3_ALTSEL1 0x24 ++#define LTQ_GPIO3_PUDSEL 0x28 ++#define LTQ_GPIO3_PUDEN 0x2C +/* PORT3 only has 8 pins and its register layout + is slightly different */ @@ -68,34 +76,34 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> #define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p))) #define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r) -@@ -55,7 +61,7 @@ int ltq_gpio_request(unsigned int pin, u +@@ -55,7 +63,7 @@ int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, { int id = 0; - if (pin >= (MAX_PORTS * PINS_PER_PORT)) + if (pin >= MAX_PIN) return -EINVAL; - if (gpio_request(pin, name)) { + if (devm_gpio_request(dev, pin, name)) { pr_err("failed to setup lantiq gpio: %s\n", name); -@@ -75,12 +81,21 @@ int ltq_gpio_request(unsigned int pin, u +@@ -75,12 +83,21 @@ int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, else ltq_gpio_clearbit(ltq_gpio_port[id].membase, LTQ_GPIO_ALTSEL0, pin); -- if (alt1) +- if (mux & 0x1) - ltq_gpio_setbit(ltq_gpio_port[id].membase, - LTQ_GPIO_ALTSEL1, pin); - else - ltq_gpio_clearbit(ltq_gpio_port[id].membase, - LTQ_GPIO_ALTSEL1, pin); + if (id == 3) { -+ if (alt1) ++ if (mux & 0x1) + ltq_gpio_setbit(ltq_gpio_port[1].membase, + LTQ_GPIO3_ALTSEL1, pin); + else + ltq_gpio_clearbit(ltq_gpio_port[1].membase, + LTQ_GPIO3_ALTSEL1, pin); + } else { -+ if (alt1) ++ if (mux & 0x1) + ltq_gpio_setbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL1, pin); + else @@ -105,32 +113,53 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> return 0; } EXPORT_SYMBOL(ltq_gpio_request); -@@ -106,7 +121,11 @@ static int ltq_gpio_direction_input(stru +@@ -106,10 +123,19 @@ static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); -+ if (chip->ngpio == PINS_PORT3) ++ if (chip->ngpio == PINS_PORT3) { + ltq_gpio_clearbit(ltq_gpio_port[0].membase, + LTQ_GPIO3_OD, offset); -+ else ++ ltq_gpio_setbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_PUDSEL, offset); ++ ltq_gpio_setbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_PUDEN, offset); ++ } else { + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); ++ } ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); - ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); - ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); -@@ -119,7 +138,10 @@ static int ltq_gpio_direction_output(str +- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); +- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); + + return 0; + } +@@ -119,10 +145,19 @@ static int ltq_gpio_direction_output(struct gpio_chip *chip, { struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); - ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); -+ if (chip->ngpio == PINS_PORT3) -+ ltq_gpio_setbit(ltq_gpio_port[0].membase, LTQ_GPIO3_OD, offset); -+ else ++ if (chip->ngpio == PINS_PORT3) { ++ ltq_gpio_setbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_OD, offset); ++ ltq_gpio_clearbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_PUDSEL, offset); ++ ltq_gpio_clearbit(ltq_gpio_port[0].membase, ++ LTQ_GPIO3_PUDEN, offset); ++ } else { + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); ++ } ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); -@@ -133,7 +155,11 @@ static int ltq_gpio_req(struct gpio_chip +- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); +- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); + ltq_gpio_set(chip, offset, value); + + return 0; +@@ -133,7 +168,11 @@ static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset) struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset); @@ -143,14 +172,15 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> return 0; } -@@ -146,6 +172,15 @@ static int ltq_gpio_probe(struct platfor +@@ -146,6 +185,16 @@ static int ltq_gpio_probe(struct platform_device *pdev) pdev->id); return -EINVAL; } + + /* dirty hack - The registers of port3 are not mapped linearly. + Port 3 may only load if Port 1/2 are mapped */ -+ if ((pdev->id == 3) && (!ltq_gpio_port[1].membase || !ltq_gpio_port[2].membase)) { ++ if ((pdev->id == 3) && (!ltq_gpio_port[1].membase ++ || !ltq_gpio_port[2].membase)) { + dev_err(&pdev->dev, + "ports 1/2 need to be loaded before port 3 works\n"); + return -ENOMEM; @@ -159,7 +189,7 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", -@@ -175,7 +210,10 @@ static int ltq_gpio_probe(struct platfor +@@ -175,7 +224,10 @@ static int ltq_gpio_probe(struct platform_device *pdev) ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set; ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req; ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id; @@ -171,6 +201,8 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); return gpiochip_add(<q_gpio_port[pdev->id].chip); } +diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c +index b91c7f1..bc5696b 100644 --- a/arch/mips/lantiq/xway/gpio_ebu.c +++ b/arch/mips/lantiq/xway/gpio_ebu.c @@ -61,9 +61,8 @@ static struct gpio_chip ltq_ebu_chip = { @@ -184,9 +216,11 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> .owner = THIS_MODULE, }; +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +index da91c5e..9610c10 100644 --- a/arch/mips/lantiq/xway/gpio_stp.c +++ b/arch/mips/lantiq/xway/gpio_stp.c -@@ -72,9 +72,8 @@ static struct gpio_chip ltq_stp_chip = { +@@ -74,9 +74,8 @@ static struct gpio_chip ltq_stp_chip = { .label = "ltq_stp", .direction_output = ltq_stp_direction_output, .set = ltq_stp_set, @@ -197,3 +231,6 @@ Signed-off-by: Thomas Langer <thomas.langer@lantiq.com> .owner = THIS_MODULE, }; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0019-MIPS-lantiq-adds-VPE-extensions.patch b/target/linux/lantiq/patches-3.2/0057-MIPS-lantiq-VPE-extensions.patch index 1bd4c5b4e8..a1320d6073 100644 --- a/target/linux/lantiq/patches/0019-MIPS-lantiq-adds-VPE-extensions.patch +++ b/target/linux/lantiq/patches-3.2/0057-MIPS-lantiq-VPE-extensions.patch @@ -1,7 +1,7 @@ -From c6c810d83f0d95f54c3a6b338d219cec7ccef4c9 Mon Sep 17 00:00:00 2001 +From 587ca6b21ab64ab014625b1cacb36ef711c74962 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 29 Sep 2011 20:30:40 +0200 -Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions +Subject: [PATCH 57/70] MIPS: lantiq: VPE extensions --- arch/mips/Kconfig | 22 +++ @@ -17,9 +17,11 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions create mode 100644 arch/mips/kernel/mtsched_proc.c create mode 100644 arch/mips/kernel/perf_proc.c +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index bbaff9b..902aedb 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -1915,6 +1915,28 @@ config MIPS_VPE_LOADER +@@ -1897,6 +1897,28 @@ config MIPS_VPE_LOADER Includes a loader for loading an elf relocatable object onto another VPE and running it. @@ -48,6 +50,8 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions config MIPS_MT_SMTC_IM_BACKSTOP bool "Use per-TC register bits as backstop for inhibited IM bits" depends on MIPS_MT_SMTC +diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h +index c9420aa..04bfb4b 100644 --- a/arch/mips/include/asm/mipsmtregs.h +++ b/arch/mips/include/asm/mipsmtregs.h @@ -28,14 +28,34 @@ @@ -157,9 +161,11 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions /* GPR */ #define read_tc_gpr_sp() mftgpr(29) +diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile +index 1a96618..bc5989e 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile -@@ -86,7 +86,8 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo3 +@@ -88,7 +88,8 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_PROC_FS) += proc.o @@ -169,6 +175,8 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions obj-$(CONFIG_64BIT) += cpu-bugs64.o obj-$(CONFIG_I8253) += i8253.o +diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c +index c23d11f..11d6489 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -21,26 +21,96 @@ @@ -273,7 +281,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions /* * Dump new MIPS MT state for the core. Does not leave TCs halted. -@@ -78,18 +148,18 @@ void mips_mt_regdump(unsigned long mvpct +@@ -78,18 +148,18 @@ void mips_mt_regdump(unsigned long mvpctl) if ((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) { printk(" VPE %d\n", i); printk(" VPEControl : %08lx\n", @@ -309,6 +317,9 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions } /* +diff --git a/arch/mips/kernel/mtsched_proc.c b/arch/mips/kernel/mtsched_proc.c +new file mode 100644 +index 0000000..4dafded --- /dev/null +++ b/arch/mips/kernel/mtsched_proc.c @@ -0,0 +1,279 @@ @@ -591,6 +602,9 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions + +/* Automagically create the entry */ +module_init(init_mtsched_proc); +diff --git a/arch/mips/kernel/perf_proc.c b/arch/mips/kernel/perf_proc.c +new file mode 100644 +index 0000000..7eec015 --- /dev/null +++ b/arch/mips/kernel/perf_proc.c @@ -0,0 +1,191 @@ @@ -785,6 +799,8 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions + +/* Automagically create the entry */ +module_init(init_perf_proc); +diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c +index e309665..2de204f 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -7,6 +7,7 @@ @@ -795,7 +811,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions #include <asm/bootinfo.h> #include <asm/cpu.h> #include <asm/cpu-features.h> -@@ -110,3 +111,19 @@ const struct seq_operations cpuinfo_op = +@@ -110,3 +111,19 @@ const struct seq_operations cpuinfo_op = { .stop = c_stop, .show = show_cpuinfo, }; @@ -815,9 +831,11 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions + mips_proc = proc_mkdir("mips", NULL); + return(mips_proc); +} +diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c +index f0895e7..199e853 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c -@@ -1334,6 +1334,13 @@ void smtc_get_new_mmu_context(struct mm_ +@@ -1334,6 +1334,13 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) asid = asid_cache(cpu); do { @@ -831,9 +849,11 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions if (!((asid += ASID_INC) & ASID_MASK) ) { if (cpu_has_vtag_icache) flush_icache_all(); +diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c +index bfa12a4..e338ba5 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c -@@ -76,6 +76,58 @@ static struct kspd_notifications kspd_ev +@@ -75,6 +75,58 @@ static struct kspd_notifications kspd_events; static int kspd_events_reqd; #endif @@ -892,7 +912,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions /* grab the likely amount of memory we will need. */ #ifdef CONFIG_MIPS_VPE_LOADER_TOM #define P_SIZE (2 * 1024 * 1024) -@@ -268,6 +320,13 @@ static void *alloc_progmem(unsigned long +@@ -267,6 +319,13 @@ static void *alloc_progmem(unsigned long len) void *addr; #ifdef CONFIG_MIPS_VPE_LOADER_TOM @@ -906,7 +926,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions /* * This means you must tell Linux to use less memory than you * physically have, for example by passing a mem= boot argument. -@@ -746,6 +805,12 @@ static int vpe_run(struct vpe * v) +@@ -745,6 +804,12 @@ static int vpe_run(struct vpe * v) } /* Write the address we want it to start running from in the TCPC register. */ @@ -919,7 +939,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions write_tc_c0_tcrestart((unsigned long)v->__start); write_tc_c0_tccontext((unsigned long)0); -@@ -759,6 +824,20 @@ static int vpe_run(struct vpe * v) +@@ -758,6 +823,20 @@ static int vpe_run(struct vpe * v) write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); @@ -940,7 +960,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions /* * The sde-kit passes 'memsize' to __start in $a3, so set something * here... Or set $a3 to zero and define DFLT_STACK_SIZE and -@@ -833,6 +912,9 @@ static int find_vpe_symbols(struct vpe * +@@ -832,6 +911,9 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, if ( (v->__start == 0) || (v->shared_ptr == NULL)) return -1; @@ -950,7 +970,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions return 0; } -@@ -994,6 +1076,15 @@ static int vpe_elfload(struct vpe * v) +@@ -993,6 +1075,15 @@ static int vpe_elfload(struct vpe * v) (unsigned long)v->load_addr + v->len); if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { @@ -966,7 +986,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions if (v->__start == 0) { printk(KERN_WARNING "VPE loader: program does not contain " "a __start symbol\n"); -@@ -1064,6 +1155,9 @@ static int vpe_open(struct inode *inode, +@@ -1063,6 +1154,9 @@ static int vpe_open(struct inode *inode, struct file *filp) struct vpe_notifications *not; struct vpe *v; int ret; @@ -976,7 +996,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions if (minor != iminor(inode)) { /* assume only 1 device at the moment. */ -@@ -1089,7 +1183,12 @@ static int vpe_open(struct inode *inode, +@@ -1088,7 +1182,12 @@ static int vpe_open(struct inode *inode, struct file *filp) release_progmem(v->load_addr); cleanup_tc(get_tc(tclimit)); } @@ -990,7 +1010,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions /* this of-course trashes what was there before... */ v->pbuffer = vmalloc(P_SIZE); if (!v->pbuffer) { -@@ -1097,11 +1196,14 @@ static int vpe_open(struct inode *inode, +@@ -1096,11 +1195,14 @@ static int vpe_open(struct inode *inode, struct file *filp) return -ENOMEM; } v->plen = P_SIZE; @@ -1005,7 +1025,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions #ifdef CONFIG_MIPS_APSP_KSPD /* get kspd to tell us when a syscall_exit happens */ -@@ -1349,6 +1451,133 @@ static void kspd_sp_exit( int sp_id) +@@ -1348,6 +1450,133 @@ static void kspd_sp_exit( int sp_id) cleanup_tc(get_tc(sp_id)); } #endif @@ -1139,7 +1159,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions static ssize_t store_kill(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) -@@ -1430,6 +1659,18 @@ static int __init vpe_module_init(void) +@@ -1429,6 +1658,18 @@ static int __init vpe_module_init(void) printk("VPE loader: not a MIPS MT capable processor\n"); return -ENODEV; } @@ -1158,7 +1178,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions if (vpelimit == 0) { printk(KERN_WARNING "No VPEs reserved for AP/SP, not " -@@ -1474,10 +1715,12 @@ static int __init vpe_module_init(void) +@@ -1473,10 +1714,12 @@ static int __init vpe_module_init(void) mtflags = dmt(); vpflags = dvpe(); @@ -1172,7 +1192,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions val = read_c0_mvpconf0(); hw_tcs = (val & MVPCONF0_PTC) + 1; -@@ -1489,6 +1732,7 @@ static int __init vpe_module_init(void) +@@ -1488,6 +1731,7 @@ static int __init vpe_module_init(void) * reschedule send IPIs or similar we might hang. */ clear_c0_mvpcontrol(MVPCONTROL_VPC); @@ -1180,7 +1200,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions evpe(vpflags); emt(mtflags); local_irq_restore(flags); -@@ -1514,6 +1758,7 @@ static int __init vpe_module_init(void) +@@ -1513,6 +1757,7 @@ static int __init vpe_module_init(void) } v->ntcs = hw_tcs - tclimit; @@ -1188,7 +1208,7 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions /* add the tc to the list of this vpe's tc's. */ list_add(&t->tc, &v->tc); -@@ -1582,6 +1827,7 @@ static int __init vpe_module_init(void) +@@ -1581,6 +1826,7 @@ static int __init vpe_module_init(void) out_reenable: /* release config state */ clear_c0_mvpcontrol(MVPCONTROL_VPC); @@ -1196,3 +1216,6 @@ Subject: [PATCH 19/24] MIPS: lantiq: adds VPE extensions evpe(vpflags); emt(mtflags); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0020-MIPS-lantiq-adds-falcon-VPE-softdog.patch b/target/linux/lantiq/patches-3.2/0058-MIPS-lantiq-falcon-VPE-softdog.patch index 9173a5de09..d2865eb7a4 100644 --- a/target/linux/lantiq/patches/0020-MIPS-lantiq-adds-falcon-VPE-softdog.patch +++ b/target/linux/lantiq/patches-3.2/0058-MIPS-lantiq-falcon-VPE-softdog.patch @@ -1,7 +1,7 @@ -From e3c377986855f820513edf2924a022a39c363908 Mon Sep 17 00:00:00 2001 +From 6a76c0c9a33c32464319c24ff5647f7676642c51 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 29 Sep 2011 21:29:14 +0200 -Subject: [PATCH 20/24] MIPS: lantiq: adds falcon VPE softdog +Subject: [PATCH 58/70] MIPS: lantiq: falcon VPE softdog --- arch/mips/include/asm/mach-lantiq/falcon/vpe.h | 44 ++++++++++ @@ -10,6 +10,9 @@ Subject: [PATCH 20/24] MIPS: lantiq: adds falcon VPE softdog create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/vpe.h create mode 100644 arch/mips/lantiq/falcon/softdog_vpe.c +diff --git a/arch/mips/include/asm/mach-lantiq/falcon/vpe.h b/arch/mips/include/asm/mach-lantiq/falcon/vpe.h +new file mode 100644 +index 0000000..22a701b --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/vpe.h @@ -0,0 +1,44 @@ @@ -57,6 +60,9 @@ Subject: [PATCH 20/24] MIPS: lantiq: adds falcon VPE softdog +int32_t vpe1_sw_wdog_register_reset_handler(VPE_SW_WDOG_RESET reset_fn); + +#endif +diff --git a/arch/mips/lantiq/falcon/softdog_vpe.c b/arch/mips/lantiq/falcon/softdog_vpe.c +new file mode 100644 +index 0000000..85d22a2 --- /dev/null +++ b/arch/mips/lantiq/falcon/softdog_vpe.c @@ -0,0 +1,109 @@ @@ -169,9 +175,6 @@ Subject: [PATCH 20/24] MIPS: lantiq: adds falcon VPE softdog +MODULE_AUTHOR("LXDB"); +MODULE_DESCRIPTION("Software Watchdog For VPE1"); +MODULE_LICENSE("GPL"); ---- a/arch/mips/lantiq/falcon/Makefile -+++ b/arch/mips/lantiq/falcon/Makefile -@@ -1,2 +1,2 @@ --obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o -+obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o softdog_vpe.o - obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0022-MIPS-lantiq-adds-udp-in-kernel-redirect.patch b/target/linux/lantiq/patches-3.2/0059-MIPS-lantiq-udp-in-kernel-redirect.patch index c80731e83b..74025e8757 100644 --- a/target/linux/lantiq/patches/0022-MIPS-lantiq-adds-udp-in-kernel-redirect.patch +++ b/target/linux/lantiq/patches-3.2/0059-MIPS-lantiq-udp-in-kernel-redirect.patch @@ -1,7 +1,7 @@ -From 14ff975c660696fa636e8d6b58d0abed0ddc72ce Mon Sep 17 00:00:00 2001 +From 268b631d81d5428cdf1a82b9655e9f44f64a8238 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 29 Sep 2011 20:29:54 +0200 -Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect +Subject: [PATCH 59/70] MIPS: lantiq: udp in-kernel redirect --- include/linux/udp_redirect.h | 57 +++++++++++++ @@ -13,6 +13,9 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect create mode 100644 include/linux/udp_redirect.h create mode 100644 net/ipv4/udp_redirect_symb.c +diff --git a/include/linux/udp_redirect.h b/include/linux/udp_redirect.h +new file mode 100644 +index 0000000..de1e64f --- /dev/null +++ b/include/linux/udp_redirect.h @@ -0,0 +1,57 @@ @@ -73,6 +76,8 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect +extern int udpredirect_getfrag(void *p, char * to, int offset, + int fraglen, int odd, struct sk_buff *skb); +#endif +diff --git a/net/Kconfig b/net/Kconfig +index a073148..d13e3fa 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -72,6 +72,12 @@ config INET @@ -88,9 +93,11 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect if INET source "net/ipv4/Kconfig" source "net/ipv6/Kconfig" +diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile +index f2dc69c..6badd72 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile -@@ -14,6 +14,9 @@ obj-y := route.o inetpeer.o protocol +@@ -14,6 +14,9 @@ obj-y := route.o inetpeer.o protocol.o \ inet_fragment.o ping.o obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o @@ -100,6 +107,8 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o obj-$(CONFIG_IP_MROUTE) += ipmr.o +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index 5a65eea..cdfa0d4 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -108,6 +108,10 @@ @@ -113,7 +122,7 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect struct udp_table udp_table __read_mostly; EXPORT_SYMBOL(udp_table); -@@ -803,7 +807,7 @@ int udp_sendmsg(struct kiocb *iocb, stru +@@ -803,7 +807,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, u8 tos; int err, is_udplite = IS_UDPLITE(sk); int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; @@ -122,7 +131,7 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect struct sk_buff *skb; struct ip_options_data opt_copy; -@@ -820,7 +824,13 @@ int udp_sendmsg(struct kiocb *iocb, stru +@@ -820,7 +824,13 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.opt = NULL; ipc.tx_flags = 0; @@ -137,7 +146,7 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect fl4 = &inet->cork.fl.u.ip4; if (up->pending) { -@@ -1621,6 +1631,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, +@@ -1623,6 +1633,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, struct rtable *rt = skb_rtable(skb); __be32 saddr, daddr; struct net *net = dev_net(skb->dev); @@ -145,7 +154,7 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect /* * Validate the packet. -@@ -1653,7 +1664,16 @@ int __udp4_lib_rcv(struct sk_buff *skb, +@@ -1655,7 +1666,16 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); if (sk != NULL) { @@ -163,7 +172,7 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect sock_put(sk); /* a return value > 0 means to resubmit the input, but -@@ -1950,7 +1970,7 @@ struct proto udp_prot = { +@@ -1952,7 +1972,7 @@ struct proto udp_prot = { .clear_sk = sk_prot_clear_portaddr_nulls, }; EXPORT_SYMBOL(udp_prot); @@ -172,6 +181,9 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS +diff --git a/net/ipv4/udp_redirect_symb.c b/net/ipv4/udp_redirect_symb.c +new file mode 100644 +index 0000000..5617e86 --- /dev/null +++ b/net/ipv4/udp_redirect_symb.c @@ -0,0 +1,186 @@ @@ -361,3 +373,6 @@ Subject: [PATCH 22/24] MIPS: lantiq: adds udp in-kernel redirect +EXPORT_SYMBOL(udp_do_redirect_fn); +EXPORT_SYMBOL(udpredirect_getfrag_fn); +#endif /* CONFIG_IFX_UDP_REDIRECT* */ +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/0021-MIPS-lantiq-adds-cache-split.patch b/target/linux/lantiq/patches-3.2/0060-MIPS-lantiq-cache-split.patch index 640d1e2acf..cb0ad4a294 100644 --- a/target/linux/lantiq/patches/0021-MIPS-lantiq-adds-cache-split.patch +++ b/target/linux/lantiq/patches-3.2/0060-MIPS-lantiq-cache-split.patch @@ -1,7 +1,7 @@ -From 0f85e79f6f01f50cb703866a555085a9c65bad2f Mon Sep 17 00:00:00 2001 +From 307ba9e4d8fb0608566aacf88ab8cded5e20e005 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 29 Sep 2011 20:31:54 +0200 -Subject: [PATCH 21/24] MIPS: lantiq: adds cache split +Subject: [PATCH 60/70] MIPS: lantiq: cache split --- arch/mips/Kconfig | 22 ++++++ @@ -9,9 +9,11 @@ Subject: [PATCH 21/24] MIPS: lantiq: adds cache split arch/mips/mm/c-r4k.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 0 deletions(-) +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 902aedb..12ee3df 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -1922,6 +1922,28 @@ config IFX_VPE_EXT +@@ -1904,6 +1904,28 @@ config IFX_VPE_EXT help IFX included extensions in APRP @@ -40,9 +42,11 @@ Subject: [PATCH 21/24] MIPS: lantiq: adds cache split config PERFCTRS bool "34K Performance counters" depends on MIPS_MT && PROC_FS +diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c +index e338ba5..0511d11 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c -@@ -128,6 +128,13 @@ __setup("vpe1_wdog_timeout=", wdog_timeo +@@ -127,6 +127,13 @@ __setup("vpe1_wdog_timeout=", wdog_timeout); EXPORT_SYMBOL(vpe1_wdog_timeout); #endif @@ -56,7 +60,7 @@ Subject: [PATCH 21/24] MIPS: lantiq: adds cache split /* grab the likely amount of memory we will need. */ #ifdef CONFIG_MIPS_VPE_LOADER_TOM #define P_SIZE (2 * 1024 * 1024) -@@ -866,6 +873,65 @@ static int vpe_run(struct vpe * v) +@@ -865,6 +872,65 @@ static int vpe_run(struct vpe * v) /* enable this VPE */ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); @@ -122,9 +126,11 @@ Subject: [PATCH 21/24] MIPS: lantiq: adds cache split /* clear out any left overs from a previous program */ write_vpe_c0_status(0); write_vpe_c0_cause(0); +diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c +index a79fe9a..94cb24f 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c -@@ -1350,6 +1350,106 @@ static int __init setcoherentio(char *st +@@ -1383,6 +1383,106 @@ static int __init setcoherentio(char *str) __setup("coherentio", setcoherentio); #endif @@ -231,7 +237,7 @@ Subject: [PATCH 21/24] MIPS: lantiq: adds cache split void __cpuinit r4k_cache_init(void) { extern void build_clear_page(void); -@@ -1369,6 +1469,78 @@ void __cpuinit r4k_cache_init(void) +@@ -1402,6 +1502,78 @@ void __cpuinit r4k_cache_init(void) break; } @@ -310,36 +316,6 @@ Subject: [PATCH 21/24] MIPS: lantiq: adds cache split probe_pcache(); setup_scache(); ---- a/arch/mips/lantiq/setup.c -+++ b/arch/mips/lantiq/setup.c -@@ -18,10 +18,11 @@ - #include "devices.h" - #include "prom.h" - -+/* assume 16M as default incase uboot fails to pass proper ramsize */ -+unsigned long physical_memsize = 16L; -+ - void __init plat_mem_setup(void) - { -- /* assume 16M as default incase uboot fails to pass proper ramsize */ -- unsigned long memsize = 16; - char **envp = (char **) KSEG1ADDR(fw_arg2); - - ioport_resource.start = IOPORT_RESOURCE_START; -@@ -35,13 +36,13 @@ void __init plat_mem_setup(void) - char *e = (char *)KSEG1ADDR(*envp); - if (!strncmp(e, "memsize=", 8)) { - e += 8; -- if (strict_strtoul(e, 0, &memsize)) -+ if (strict_strtoul(e, 0, &physical_memsize)) - pr_warn("bad memsize specified\n"); - } - envp++; - } -- memsize *= 1024 * 1024; -- add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); -+ physical_memsize *= 1024 * 1024; -+ add_memory_region(0x00000000, physical_memsize, BOOT_MEM_RAM); - } - - static int __init +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0061-MIPS-clean-up-clock-code.patch b/target/linux/lantiq/patches-3.2/0061-MIPS-clean-up-clock-code.patch new file mode 100644 index 0000000000..9ec89ed8ea --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0061-MIPS-clean-up-clock-code.patch @@ -0,0 +1,319 @@ +From d23a3c21962bcc3dc18e7916c2499cd3b26feaf0 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 20 Mar 2012 08:26:04 +0100 +Subject: [PATCH 61/70] MIPS: clean up clock code + +--- + arch/mips/lantiq/clk.c | 11 +++ + arch/mips/lantiq/clk.h | 3 +- + arch/mips/lantiq/xway/devices.c | 2 +- + arch/mips/lantiq/xway/sysctrl.c | 166 ++++++++++++++++++++++++++++++--------- + 4 files changed, 143 insertions(+), 39 deletions(-) + +diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c +index 84a201e..5494b6e 100644 +--- a/arch/mips/lantiq/clk.c ++++ b/arch/mips/lantiq/clk.c +@@ -44,6 +44,7 @@ struct clk *clk_get_fpi(void) + { + return &cpu_clk_generic[1]; + } ++EXPORT_SYMBOL_GPL(clk_get_fpi); + + struct clk *clk_get_io(void) + { +@@ -70,6 +71,16 @@ unsigned long clk_get_rate(struct clk *clk) + } + EXPORT_SYMBOL(clk_get_rate); + ++int clk_set_rate(struct clk *clk, unsigned long rate) ++{ ++ if (unlikely(!clk_good(clk))) ++ return 0; ++ ++ clk->rate = rate; ++ return 0; ++} ++EXPORT_SYMBOL(clk_set_rate); ++ + int clk_enable(struct clk *clk) + { + if (unlikely(!clk_good(clk))) +diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h +index d047768..b34e675 100644 +--- a/arch/mips/lantiq/clk.h ++++ b/arch/mips/lantiq/clk.h +@@ -12,6 +12,7 @@ + #include <linux/clkdev.h> + + /* clock speeds */ ++#define CLOCK_33M 33333333 + #define CLOCK_60M 60000000 + #define CLOCK_62_5M 62500000 + #define CLOCK_83M 83333333 +@@ -38,9 +39,9 @@ + struct clk { + struct clk_lookup cl; + unsigned long rate; +- unsigned long (*get_rate) (void); + unsigned int module; + unsigned int bits; ++ unsigned long (*get_rate) (void); + int (*enable) (struct clk *clk); + void (*disable) (struct clk *clk); + int (*activate) (struct clk *clk); +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +index e6d45bc..5d4650d 100644 +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -59,7 +59,7 @@ static struct resource ltq_stp_resource = + + void __init ltq_register_gpio_stp(void) + { +- platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1); ++ platform_device_register_simple("ltq_stp", -1, <q_stp_resource, 1); + } + + /* asc ports - amazon se has its own serial mapping */ +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index ac7383f..9df048c 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -16,40 +16,57 @@ + #include "../devices.h" + + /* clock control register */ +-#define LTQ_CGU_IFCCR 0x0018 ++#define CGU_IFCCR 0x0018 + /* system clock register */ +-#define LTQ_CGU_SYS 0x0010 +- +-/* the enable / disable registers */ +-#define LTQ_PMU_PWDCR 0x1C +-#define LTQ_PMU_PWDSR 0x20 +-#define LTQ_PMU_PWDCR1 0x24 +-#define LTQ_PMU_PWDSR1 0x28 +- +-#define PWDCR(x) ((x) ? (LTQ_PMU_PWDCR1) : (LTQ_PMU_PWDCR)) +-#define PWDSR(x) ((x) ? (LTQ_PMU_PWDSR1) : (LTQ_PMU_PWDSR)) +- +-/* CGU - clock generation unit */ +-#define CGU_EPHY 0x10 ++#define CGU_SYS 0x0010 ++/* pci control register */ ++#define CGU_PCICR 0x0034 ++/* ephy configuration register */ ++#define CGU_EPHY 0x10 ++/* power control register */ ++#define PMU_PWDCR 0x1C ++/* power status register */ ++#define PMU_PWDSR 0x20 ++/* power control register */ ++#define PMU_PWDCR1 0x24 ++/* power status register */ ++#define PMU_PWDSR1 0x28 ++/* power control register */ ++#define PWDCR(x) ((x) ? (PMU_PWDCR1) : (PMU_PWDCR)) ++/* power status register */ ++#define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR)) + + /* PMU - power management unit */ +-#define PMU_DMA 0x0020 +-#define PMU_SPI 0x0100 +-#define PMU_EPHY 0x0080 +-#define PMU_USB 0x8041 +-#define PMU_STP 0x0800 +-#define PMU_GPT 0x1000 +-#define PMU_PPE 0x2000 +-#define PMU_FPI 0x4000 +-#define PMU_SWITCH 0x10000000 +-#define PMU_AHBS 0x2000 +-#define PMU_AHBM 0x8000 +-#define PMU_PCIE_CLK 0x80000000 +- +-#define PMU1_PCIE_PHY 0x0001 +-#define PMU1_PCIE_CTL 0x0002 +-#define PMU1_PCIE_MSI 0x0020 +-#define PMU1_PCIE_PDI 0x0010 ++#define PMU_USB0_P BIT(0) ++#define PMU_PCI BIT(4) ++#define PMU_DMA BIT(5) ++#define PMU_USB0 BIT(5) ++#define PMU_SPI BIT(8) ++#define PMU_EPHY BIT(7) ++#define PMU_EBU BIT(10) ++#define PMU_STP BIT(11) ++#define PMU_GPT BIT(12) ++#define PMU_PPE BIT(13) ++#define PMU_AHBS BIT(13) /* vr9 */ ++#define PMU_FPI BIT(14) ++#define PMU_AHBM BIT(15) ++#define PMU_PPE_QSB BIT(18) ++#define PMU_PPE_SLL01 BIT(19) ++#define PMU_PPE_TC BIT(21) ++#define PMU_PPE_EMA BIT(22) ++#define PMU_PPE_DPLUM BIT(23) ++#define PMU_PPE_DPLUS BIT(24) ++#define PMU_USB1_P BIT(26) ++#define PMU_USB1 BIT(27) ++#define PMU_SWITCH BIT(28) ++#define PMU_PPE_TOP BIT(29) ++#define PMU_GPHY BIT(30) ++#define PMU_PCIE_CLK BIT(31) ++ ++#define PMU1_PCIE_PHY BIT(0) ++#define PMU1_PCIE_CTL BIT(1) ++#define PMU1_PCIE_PDI BIT(4) ++#define PMU1_PCIE_MSI BIT(5) + + #define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) + #define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) +@@ -69,13 +86,13 @@ static void __iomem *ltq_pmu_membase; + + static int ltq_cgu_enable(struct clk *clk) + { +- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk->bits, LTQ_CGU_IFCCR); ++ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | clk->bits, CGU_IFCCR); + return 0; + } + + static void ltq_cgu_disable(struct clk *clk) + { +- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~clk->bits, LTQ_CGU_IFCCR); ++ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~clk->bits, CGU_IFCCR); + } + + static int ltq_pmu_enable(struct clk *clk) +@@ -94,9 +111,49 @@ static int ltq_pmu_enable(struct clk *clk) + + static void ltq_pmu_disable(struct clk *clk) + { +- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | clk->bits, LTQ_PMU_PWDCR); ++ ltq_pmu_w32(ltq_pmu_r32(PWDCR(clk->module)) | clk->bits, ++ PWDCR(clk->module)); ++} ++ ++static int ltq_pci_enable(struct clk *clk) ++{ ++ unsigned int ifccr = ltq_cgu_r32(CGU_IFCCR); ++ /* set clock bus speed */ ++ if (ltq_is_ar9()) { ++ ifccr &= ~0x1f00000; ++ if (clk->rate == CLOCK_33M) ++ ifccr |= 0xe00000; ++ else ++ ifccr |= 0x700000; /* 62.5M */ ++ } else { ++ ifccr &= ~0xf00000; ++ if (clk->rate == CLOCK_33M) ++ ifccr |= 0x800000; ++ else ++ ifccr |= 0x400000; /* 62.5M */ ++ } ++ ltq_cgu_w32(ifccr, CGU_IFCCR); ++ return 0; ++} ++ ++static int ltq_pci_ext_enable(struct clk *clk) ++{ ++ /* enable external pci clock */ ++ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~(1 << 16), ++ CGU_IFCCR); ++ ltq_cgu_w32((1 << 30), CGU_PCICR); ++ return 0; ++} ++ ++static void ltq_pci_ext_disable(struct clk *clk) ++{ ++ /* enable external pci clock */ ++ ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16), ++ CGU_IFCCR); ++ ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR); + } + ++/* manage the clock gates via PMU */ + static inline void clkdev_add_pmu(const char *dev, const char *con, + unsigned int module, unsigned int bits) + { +@@ -112,6 +169,7 @@ static inline void clkdev_add_pmu(const char *dev, const char *con, + clkdev_add(&clk->cl); + } + ++/* manage the clock generator */ + static inline void clkdev_add_cgu(const char *dev, const char *con, + unsigned int bits) + { +@@ -126,6 +184,33 @@ static inline void clkdev_add_cgu(const char *dev, const char *con, + clkdev_add(&clk->cl); + } + ++/* pci needs its own enable function */ ++static inline void clkdev_add_pci(void) ++{ ++ struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL); ++ ++ /* main pci clock */ ++ clk->cl.dev_id = "ltq_pci"; ++ clk->cl.con_id = NULL; ++ clk->cl.clk = clk; ++ clk->rate = CLOCK_33M; ++ clk->enable = ltq_pci_enable; ++ clk->disable = ltq_pmu_disable; ++ clk->module = 0; ++ clk->bits = PMU_PCI; ++ clkdev_add(&clk->cl); ++ ++ /* use internal/external bus clock */ ++ clk_ext->cl.dev_id = "ltq_pci"; ++ clk_ext->cl.con_id = "external"; ++ clk_ext->cl.clk = clk_ext; ++ clk_ext->enable = ltq_pci_ext_enable; ++ clk_ext->disable = ltq_pci_ext_disable; ++ clkdev_add(&clk_ext->cl); ++ ++} ++ + void __init ltq_soc_init(void) + { + ltq_pmu_membase = ltq_remap_resource(<q_pmu_resource); +@@ -144,14 +229,16 @@ void __init ltq_soc_init(void) + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); + + /* add our clocks */ ++ clkdev_add_pmu("ltq_fpi", NULL, 0, PMU_FPI); + clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA); + clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP); + clkdev_add_pmu("ltq_spi", NULL, 0, PMU_SPI); + clkdev_add_pmu("ltq_gptu", NULL, 0, PMU_GPT); ++ clkdev_add_pmu("ltq_ebu", NULL, 0, PMU_EBU); + if (!ltq_is_vr9()) + clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); + if (ltq_is_ase()) { +- if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) ++ if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) + clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); + else + clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); +@@ -166,11 +253,16 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI); + clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL); + clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); +- clkdev_add_pmu("usb0", NULL, 0, (1<<6) | 1); +- clkdev_add_pmu("usb1", NULL, 0, (1<<26) | (1<<27)); ++ clkdev_add_pmu("usb0", NULL, 0, PMU_USB0 | PMU_USB0_P); ++ clkdev_add_pmu("usb1", NULL, 0, PMU_USB1 | PMU_USB1_P); ++ clkdev_add_pmu("ltq_vrx200", NULL, 0, ++ PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | ++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | ++ PMU_PPE_QSB); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), + ltq_danube_io_region_clock()); ++ clkdev_add_pci(); + if (ltq_is_ar9()) + clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); + } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0062-MIPS-cleanup-reset-code.patch b/target/linux/lantiq/patches-3.2/0062-MIPS-cleanup-reset-code.patch new file mode 100644 index 0000000000..e6fae3fe4f --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0062-MIPS-cleanup-reset-code.patch @@ -0,0 +1,103 @@ +From 1748dc7b4974109040d0249ac1fc322c120eb528 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 16 Mar 2012 15:49:32 +0100 +Subject: [PATCH 62/70] MIPS: cleanup reset code + +--- + arch/mips/lantiq/xway/reset.c | 59 ++++++++++++++++++++++++++++++++++------ + 1 files changed, 50 insertions(+), 9 deletions(-) + +diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c +index ca2212a..8a5dff1 100644 +--- a/arch/mips/lantiq/xway/reset.c ++++ b/arch/mips/lantiq/xway/reset.c +@@ -11,6 +11,7 @@ + #include <linux/ioport.h> + #include <linux/pm.h> + #include <linux/export.h> ++#include <linux/delay.h> + #include <asm/reboot.h> + + #include <lantiq_soc.h> +@@ -20,12 +21,45 @@ + #define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y)) + #define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x)) + +-/* register definitions */ +-#define LTQ_RCU_RST 0x0010 +-#define LTQ_RCU_RST_ALL 0x40000000 +- +-#define LTQ_RCU_RST_STAT 0x0014 +-#define LTQ_RCU_STAT_SHIFT 26 ++/* reset request register */ ++#define RCU_RST_REQ 0x0010 ++/* reset status register */ ++#define RCU_RST_STAT 0x0014 ++ ++/* reset cause */ ++#define RCU_STAT_SHIFT 26 ++/* Global SW Reset */ ++#define RCU_RD_SRST BIT(30) ++/* Memory Controller */ ++#define RCU_RD_MC BIT(14) ++/* PCI core */ ++#define RCU_RD_PCI BIT(13) ++/* Voice DFE/AFE */ ++#define RCU_RD_DFE_AFE BIT(12) ++/* DSL AFE */ ++#define RCU_RD_DSL_AFE BIT(11) ++/* SDIO core */ ++#define RCU_RD_SDIO BIT(10) ++/* DMA core */ ++#define RCU_RD_DMA BIT(9) ++/* PPE core */ ++#define RCU_RD_PPE BIT(8) ++/* ARC/DFE core */ ++#define RCU_RD_ARC_DFE BIT(7) ++/* AHB bus */ ++#define RCU_RD_AHB BIT(6) ++/* Ethernet MAC1 */ ++#define RCU_RD_ENET_MAC1 BIT(5) ++/* USB and Phy core */ ++#define RCU_RD_USB BIT(4) ++/* CPU1 subsystem */ ++#define RCU_RD_CPU1 BIT(3) ++/* FPI bus */ ++#define RCU_RD_FPI BIT(2) ++/* CPU0 subsystem */ ++#define RCU_RD_CPU0 BIT(1) ++/* HW reset via HRST pin */ ++#define RCU_RD_HRST BIT(0) + + static struct resource ltq_rcu_resource = + MEM_RES("rcu", LTQ_RCU_BASE_ADDR, LTQ_RCU_SIZE); +@@ -36,16 +70,23 @@ static void __iomem *ltq_rcu_membase; + /* This function is used by the watchdog driver */ + int ltq_reset_cause(void) + { +- u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT); +- return val >> LTQ_RCU_STAT_SHIFT; ++ u32 val = ltq_rcu_r32(RCU_RST_STAT); ++ return val >> RCU_STAT_SHIFT; + } + EXPORT_SYMBOL_GPL(ltq_reset_cause); + ++void ltq_reset_once(unsigned int module, ulong usec) ++{ ++ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | module, RCU_RST_REQ); ++ udelay(usec); ++ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~module, RCU_RST_REQ); ++} ++ + static void ltq_machine_restart(char *command) + { + pr_notice("System restart\n"); + local_irq_disable(); +- ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST); ++ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | RCU_RD_SRST, RCU_RST_REQ); + unreachable(); + } + +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-ar9-vr9-clock.patch b/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-ar9-vr9-clock.patch new file mode 100644 index 0000000000..4a741608ac --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0063-MIPS-lantiq-fixes-ar9-vr9-clock.patch @@ -0,0 +1,116 @@ +From 449adc45e29be18da14b23e9ccd97ba5251ffcc9 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sat, 17 Mar 2012 09:58:07 +0100 +Subject: [PATCH 63/70] MIPS: lantiq: fixes ar9/vr9 clock + +--- + arch/mips/lantiq/clk.h | 4 +++- + arch/mips/lantiq/xway/clk.c | 29 ++++++++++++++++++++++++----- + arch/mips/lantiq/xway/sysctrl.c | 13 ++++++++----- + 3 files changed, 35 insertions(+), 11 deletions(-) + +diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h +index b34e675..010dfa7 100644 +--- a/arch/mips/lantiq/clk.h ++++ b/arch/mips/lantiq/clk.h +@@ -56,8 +56,10 @@ extern unsigned long ltq_danube_cpu_hz(void); + extern unsigned long ltq_danube_fpi_hz(void); + extern unsigned long ltq_danube_io_region_clock(void); + ++extern unsigned long ltq_ar9_cpu_hz(void); ++extern unsigned long ltq_ar9_fpi_hz(void); ++ + extern unsigned long ltq_vr9_cpu_hz(void); + extern unsigned long ltq_vr9_fpi_hz(void); +-extern unsigned long ltq_vr9_io_region_clock(void); + + #endif +diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c +index 3635c9f..2bafc04 100644 +--- a/arch/mips/lantiq/xway/clk.c ++++ b/arch/mips/lantiq/xway/clk.c +@@ -217,6 +217,30 @@ unsigned long ltq_danube_cpu_hz(void) + } + } + ++unsigned long ltq_ar9_sys_hz(void) ++{ ++ if (((ltq_cgu_r32(LTQ_CGU_SYS) >> 3) & 0x3) == 0x2) ++ return CLOCK_393M; ++ return CLOCK_333M; ++} ++ ++unsigned long ltq_ar9_fpi_hz(void) ++{ ++ unsigned long sys = ltq_ar9_sys_hz(); ++ ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & BIT(0)) ++ return sys; ++ return sys >> 1; ++} ++ ++unsigned long ltq_ar9_cpu_hz(void) ++{ ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & BIT(2)) ++ return ltq_ar9_fpi_hz(); ++ else ++ return ltq_ar9_sys_hz(); ++} ++ + unsigned long ltq_danube_fpi_hz(void) + { + unsigned long ddr_clock = DDR_HZ; +@@ -299,11 +323,6 @@ unsigned long ltq_vr9_fpi_hz(void) + return clk; + } + +-unsigned long ltq_vr9_io_region_clock(void) +-{ +- return ltq_vr9_fpi_hz(); +-} +- + unsigned long ltq_vr9_fpi_bus_clock(int fpi) + { + return ltq_vr9_fpi_hz(); +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 9df048c..6771a7e 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -237,6 +237,8 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_ebu", NULL, 0, PMU_EBU); + if (!ltq_is_vr9()) + clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE); ++ if (!ltq_is_ase()) ++ clkdev_add_pci(); + if (ltq_is_ase()) { + if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) + clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); +@@ -246,7 +248,7 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); + } else if (ltq_is_vr9()) { + clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), +- ltq_vr9_io_region_clock()); ++ ltq_vr9_fpi_hz()); + clkdev_add_pmu("ltq_pcie", "phy", 1, PMU1_PCIE_PHY); + clkdev_add_pmu("ltq_pcie", "bus", 0, PMU_PCIE_CLK); + clkdev_add_pmu("ltq_pcie", "msi", 1, PMU1_PCIE_MSI); +@@ -259,11 +261,12 @@ void __init ltq_soc_init(void) + PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | + PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | + PMU_PPE_QSB); ++ } else if (ltq_is_ar9()) { ++ clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), ++ ltq_ar9_fpi_hz()); ++ clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), +- ltq_danube_io_region_clock()); +- clkdev_add_pci(); +- if (ltq_is_ar9()) +- clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); ++ ltq_danube_io_region_clock()); + } + } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0064-MIPS-lantiq-fixes-danube-clock.patch b/target/linux/lantiq/patches-3.2/0064-MIPS-lantiq-fixes-danube-clock.patch new file mode 100644 index 0000000000..6d3cbf2c05 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0064-MIPS-lantiq-fixes-danube-clock.patch @@ -0,0 +1,57 @@ +From 1303ac4fbe98c7132717102223089dc10d0ab4a2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 19 Mar 2012 15:53:37 +0100 +Subject: [PATCH 64/70] MIPS: lantiq: fixes danube clock + +--- + arch/mips/lantiq/xway/clk.c | 20 ++++++++++---------- + 1 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c +index 2bafc04..5d850dc 100644 +--- a/arch/mips/lantiq/xway/clk.c ++++ b/arch/mips/lantiq/xway/clk.c +@@ -181,7 +181,7 @@ unsigned long ltq_danube_io_region_clock(void) + { + unsigned int ret = ltq_get_pll0_fosc(); + +- switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { ++ switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0x3) { + default: + case 0: + return (ret + 1) / 2; +@@ -203,6 +203,15 @@ unsigned long ltq_danube_fpi_bus_clock(int fpi) + return ret; + } + ++unsigned long ltq_danube_fpi_hz(void) ++{ ++ unsigned long ddr_clock = DDR_HZ; ++ ++ if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) ++ return ddr_clock >> 1; ++ return ddr_clock; ++} ++ + unsigned long ltq_danube_cpu_hz(void) + { + switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { +@@ -241,15 +250,6 @@ unsigned long ltq_ar9_cpu_hz(void) + return ltq_ar9_sys_hz(); + } + +-unsigned long ltq_danube_fpi_hz(void) +-{ +- unsigned long ddr_clock = DDR_HZ; +- +- if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) +- return ddr_clock >> 1; +- return ddr_clock; +-} +- + unsigned long ltq_vr9_cpu_hz(void) + { + unsigned int cpu_sel; +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0065-MIPS-adds-dsl-clocks.patch b/target/linux/lantiq/patches-3.2/0065-MIPS-adds-dsl-clocks.patch new file mode 100644 index 0000000000..2d7de34567 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0065-MIPS-adds-dsl-clocks.patch @@ -0,0 +1,66 @@ +From a840d623b6a70428e8b698f0116fecc38e16e668 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 20 Mar 2012 13:05:11 +0100 +Subject: [PATCH 65/70] MIPS: adds dsl clocks + +--- + arch/mips/lantiq/xway/sysctrl.c | 15 +++++++++++++-- + 1 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 6771a7e..3672fc6 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -41,8 +41,9 @@ + #define PMU_PCI BIT(4) + #define PMU_DMA BIT(5) + #define PMU_USB0 BIT(5) ++#define PMU_EPHY BIT(7) /* ase */ + #define PMU_SPI BIT(8) +-#define PMU_EPHY BIT(7) ++#define PMU_DFE BIT(9) + #define PMU_EBU BIT(10) + #define PMU_STP BIT(11) + #define PMU_GPT BIT(12) +@@ -147,7 +148,7 @@ static int ltq_pci_ext_enable(struct clk *clk) + + static void ltq_pci_ext_disable(struct clk *clk) + { +- /* enable external pci clock */ ++ /* disable external pci clock (internal) */ + ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16), + CGU_IFCCR); + ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR); +@@ -246,6 +247,9 @@ void __init ltq_soc_init(void) + clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); + clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY), + clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY); ++ clkdev_add_pmu("ltq_dsl", NULL, 0, ++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | ++ PMU_AHBS | PMU_DFE); + } else if (ltq_is_vr9()) { + clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), + ltq_vr9_fpi_hz()); +@@ -261,12 +265,19 @@ void __init ltq_soc_init(void) + PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | + PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | + PMU_PPE_QSB); ++ clkdev_add_pmu("ltq_dsl", NULL, 0, PMU_DFE | PMU_AHBS); + } else if (ltq_is_ar9()) { + clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), + ltq_ar9_fpi_hz()); + clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH); ++ clkdev_add_pmu("ltq_dsl", NULL, 0, ++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | ++ PMU_PPE_QSB | PMU_AHBS | PMU_DFE); + } else { + clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), + ltq_danube_io_region_clock()); ++ clkdev_add_pmu("ltq_dsl", NULL, 0, ++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | ++ PMU_PPE_QSB | PMU_AHBS | PMU_DFE); + } + } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-dont-always-register-asc0.patch b/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-dont-always-register-asc0.patch new file mode 100644 index 0000000000..460dd2ba18 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0066-MIPS-lantiq-dont-always-register-asc0.patch @@ -0,0 +1,31 @@ +From ff4470f274b61cebaeb1586f2f462ff66b8041cb Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 20 Mar 2012 08:22:11 +0100 +Subject: [PATCH 66/70] MIPS: lantiq: dont always register asc0 + +--- + arch/mips/lantiq/xway/prom.c | 6 ++---- + 1 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c +index e3dcbbd..f776d5a 100644 +--- a/arch/mips/lantiq/xway/prom.c ++++ b/arch/mips/lantiq/xway/prom.c +@@ -101,12 +101,10 @@ void __init ltq_soc_detect(struct ltq_soc_info *i) + + void __init ltq_soc_setup(void) + { +- if (ltq_is_ase()) { ++ if (ltq_is_ase()) + ltq_register_ase_asc(); +- } else { +- ltq_register_asc(0); ++ else + ltq_register_asc(1); +- } + ltq_register_gpio(); + ltq_register_wdt(); + } +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch b/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch new file mode 100644 index 0000000000..a97259c260 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0067-MIPS-lantiq-irqs-were-not-cleared-properly-on-boot.patch @@ -0,0 +1,34 @@ +From 845d2430d74cf6e2326da95b9205258170b30c86 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 20 Mar 2012 09:44:27 +0100 +Subject: [PATCH 67/70] MIPS: lantiq: irqs were not cleared properly on boot + +--- + arch/mips/lantiq/irq.c | 10 +++++----- + 1 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c +index 770a10c..d4e70b4 100644 +--- a/arch/mips/lantiq/irq.c ++++ b/arch/mips/lantiq/irq.c +@@ -327,12 +327,12 @@ void __init arch_init_irq(void) + panic("Failed to remap eiu memory\n"); + } + +- /* make sure all irqs are turned off by default */ +- for (i = 0; i < 5; i++) ++ for (i = 0; i < 5; i++) { ++ /* make sure all irqs are turned off by default */ + ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET)); +- +- /* clear all possibly pending interrupts */ +- ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); ++ /* clear all possibly pending interrupts */ ++ ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); ++ } + + mips_cpu_irq_init(); + +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-bootsel-helper.patch b/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-bootsel-helper.patch new file mode 100644 index 0000000000..81a0cdbfbe --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0068-MIPS-lantiq-adds-bootsel-helper.patch @@ -0,0 +1,66 @@ +From 091358d0004ae2d2a28c9132e6976d46cf96fd3e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 21 Mar 2012 14:17:37 +0100 +Subject: [PATCH 68/70] MIPS: lantiq: adds bootsel helper + +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 12 ++++++++++++ + arch/mips/lantiq/xway/reset.c | 12 +++++++++++- + 2 files changed, 23 insertions(+), 1 deletions(-) + +diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +index bfdeb16..1ec8f2a 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -144,6 +144,18 @@ + #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) + #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) + ++/* BOOT_SEL - find what boot media we have */ ++#define BS_EXT_ROM 0x0 ++#define BS_FLASH 0x1 ++#define BS_MII0 0x2 ++#define BS_PCI 0x3 ++#define BS_UART1 0x4 ++#define BS_SPI 0x5 ++#define BS_NAND 0x6 ++#define BS_RMII0 0x7 ++ ++extern unsigned char ltq_boot_select(void); ++ + /* register access macros for EBU and CGU */ + #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) + #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) +diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c +index 8a5dff1..b8f7ffb 100644 +--- a/arch/mips/lantiq/xway/reset.c ++++ b/arch/mips/lantiq/xway/reset.c +@@ -27,7 +27,11 @@ + #define RCU_RST_STAT 0x0014 + + /* reset cause */ +-#define RCU_STAT_SHIFT 26 ++#define RCU_STAT_SHIFT 26 ++/* boot selection */ ++#define RCU_BOOT_SEL_SHIFT 26 ++#define RCU_BOOT_SEL_MASK 0x7 ++ + /* Global SW Reset */ + #define RCU_RD_SRST BIT(30) + /* Memory Controller */ +@@ -75,6 +79,12 @@ int ltq_reset_cause(void) + } + EXPORT_SYMBOL_GPL(ltq_reset_cause); + ++unsigned char ltq_boot_select(void) ++{ ++ u32 val = ltq_rcu_r32(RCU_RST_STAT); ++ return (val >> RCU_BOOT_SEL_SHIFT) & RCU_BOOT_SEL_MASK; ++} ++ + void ltq_reset_once(unsigned int module, ulong usec) + { + ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | module, RCU_RST_REQ); +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch b/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch new file mode 100644 index 0000000000..a7ea1ad7d5 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/0069-MIPS-lantiq-adds-USB_ARCH_HAS_HCD-to-CONFIG_LANTIQ.patch @@ -0,0 +1,24 @@ +From 749d1baf548fda72bb1a74b7653415a63b00e8a0 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 23 Mar 2012 11:28:22 +0100 +Subject: [PATCH 69/70] MIPS: lantiq: adds USB_ARCH_HAS_HCD to CONFIG_LANTIQ + +--- + arch/mips/Kconfig | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 12ee3df..81b22c1 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -229,6 +229,7 @@ config LANTIQ + select CLKDEV_LOOKUP + select HAVE_OPROFILE + select MIPS_MACHINE ++ select USB_ARCH_HAS_HCD + + config LASAT + bool "LASAT Networks platforms" +-- +1.7.7.1 + diff --git a/target/linux/lantiq/patches/100-falcon_bsp_header.patch b/target/linux/lantiq/patches-3.2/100-falcon_bsp_header.patch index 61105504c0..61105504c0 100644 --- a/target/linux/lantiq/patches/100-falcon_bsp_header.patch +++ b/target/linux/lantiq/patches-3.2/100-falcon_bsp_header.patch diff --git a/target/linux/lantiq/patches/110-sdk-compat.patch b/target/linux/lantiq/patches-3.2/101-sdk-compat.patch index ca8d92eda3..ca8d92eda3 100644 --- a/target/linux/lantiq/patches/110-sdk-compat.patch +++ b/target/linux/lantiq/patches-3.2/101-sdk-compat.patch diff --git a/target/linux/lantiq/patches/200-owrt-netif_receive_skb.patch b/target/linux/lantiq/patches-3.2/200-owrt-netif_receive_skb.patch index d1cb2ab545..8bf776c629 100644 --- a/target/linux/lantiq/patches/200-owrt-netif_receive_skb.patch +++ b/target/linux/lantiq/patches-3.2/200-owrt-netif_receive_skb.patch @@ -1,5 +1,5 @@ ---- a/drivers/net/lantiq_etop.c -+++ b/drivers/net/lantiq_etop.c +--- a/drivers/net/ethernet/lantiq_etop.c ++++ b/drivers/net/ethernet/lantiq_etop.c @@ -190,8 +190,12 @@ ltq_etop_hw_receive(struct ltq_etop_chan skb_put(skb, len); diff --git a/target/linux/lantiq/patches-3.2/201-owrt-mtd_split.patch b/target/linux/lantiq/patches-3.2/201-owrt-mtd_split.patch new file mode 100644 index 0000000000..aaf2395fb2 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/201-owrt-mtd_split.patch @@ -0,0 +1,244 @@ +Index: linux-3.2.9/drivers/mtd/Kconfig +=================================================================== +--- linux-3.2.9.orig/drivers/mtd/Kconfig 2012-03-17 17:43:47.395607926 +0100 ++++ linux-3.2.9/drivers/mtd/Kconfig 2012-03-17 20:49:30.279873461 +0100 +@@ -31,6 +31,10 @@ + bool "Automatically split 'rootfs' partition for squashfs" + default y + ++config MTD_UIMAGE_SPLIT ++ bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'" ++ default y ++ + config MTD_REDBOOT_PARTS + tristate "RedBoot partition table parsing" + ---help--- +Index: linux-3.2.9/drivers/mtd/mtdpart.c +=================================================================== +--- linux-3.2.9.orig/drivers/mtd/mtdpart.c 2012-03-17 17:43:47.407607922 +0100 ++++ linux-3.2.9/drivers/mtd/mtdpart.c 2012-03-17 20:49:42.987873819 +0100 +@@ -874,6 +874,169 @@ + } + #endif /* CONFIG_MTD_ROOTFS_SPLIT */ + ++ ++#ifdef CONFIG_MTD_UIMAGE_SPLIT ++static unsigned long find_uimage_size(struct mtd_info *mtd, ++ unsigned long offset) ++{ ++#define UBOOT_MAGIC 0x56190527 ++ unsigned long magic = 0; ++ unsigned long temp; ++ size_t len; ++ int ret; ++ ++ ret = mtd->read(mtd, offset, 4, &len, (void *)&magic); ++ if (ret || len != sizeof(magic)) ++ return 0; ++ ++ if (le32_to_cpu(magic) != UBOOT_MAGIC) ++ return 0; ++ ++ ret = mtd->read(mtd, offset + 12, 4, &len, (void *)&temp); ++ if (ret || len != sizeof(temp)) ++ return 0; ++ ++ return temp + 0x40; ++} ++ ++static unsigned long find_eva_size(struct mtd_info *mtd, ++ unsigned long offset) ++{ ++#define EVA_MAGIC 0xfeed1281 ++ unsigned long magic = 0; ++ unsigned long temp; ++ size_t len; ++ int ret; ++ ++ ret = mtd->read(mtd, offset, 4, &len, (void *)&magic); ++ if (ret || len != sizeof(magic)) ++ return 0; ++ ++ if (le32_to_cpu(magic) != EVA_MAGIC) ++ return 0; ++ ++ ret = mtd->read(mtd, offset + 4, 4, &len, (void *)&temp); ++ if (ret || len != sizeof(temp)) ++ return 0; ++ ++ /* add eva header size */ ++ temp = le32_to_cpu(temp) + 0x18; ++ ++ temp &= ~0xffff; ++ temp += 0x10000; ++ return temp; ++} ++ ++static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset) ++{ ++ unsigned long temp; ++ size_t len; ++ int ret; ++ ++ ret = mtd->read(mtd, offset, 4, &len, (void *)&temp); ++ if (ret || len != sizeof(temp)) ++ return 0; ++ ++ ++ return le32_to_cpu(temp) == SQUASHFS_MAGIC; ++} ++ ++static int detect_eva_squashfs_partition(struct mtd_info *mtd, unsigned long offset) ++{ ++ unsigned long temp; ++ size_t len; ++ int ret; ++ ++ ret = mtd->read(mtd, offset, 4, &len, (void *)&temp); ++ if (ret || len != sizeof(temp)) ++ return 0; ++ ++ return be32_to_cpu(temp) == SQUASHFS_MAGIC; ++} ++ ++static unsigned long find_brnimage_size(struct mtd_info *mtd, ++ unsigned long offset) ++{ ++ unsigned long buf[4]; ++ // Assume at most 2MB of kernel image ++ unsigned long end = offset + (2 << 20); ++ unsigned long ptr = offset + 0x400 - 12; ++ size_t len; ++ int ret; ++ ++ while (ptr < end) { ++ long size_min = ptr - 0x400 - 12 - offset; ++ long size_max = ptr + 12 - offset; ++ ret = mtd->read(mtd, ptr, 16, &len, (void *)buf); ++ if (ret || len != 16) ++ return 0; ++ ++ if (le32_to_cpu(buf[0]) < size_min || ++ le32_to_cpu(buf[0]) > size_max) { ++ ptr += 0x400; ++ continue; ++ } ++ ++ if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC) ++ return ptr + 12 - offset; ++ ++ ptr += 0x400; ++ } ++ ++ return 0; ++} ++ ++static int split_uimage(struct mtd_info *mtd, ++ const struct mtd_partition *part) ++{ ++ static struct mtd_partition split_partitions[] = { ++ { ++ .name = "kernel", ++ .offset = 0x0, ++ .size = 0x0, ++ }, { ++ .name = "rootfs", ++ .offset = 0x0, ++ .size = 0x0, ++ }, ++ }; ++ ++ split_partitions[0].size = find_uimage_size(mtd, part->offset); ++ if (!split_partitions[0].size) { ++ split_partitions[0].size = find_eva_size(mtd, part->offset); ++ if (!split_partitions[0].size) { ++ split_partitions[0].size = find_brnimage_size(mtd, part->offset); ++ if (!split_partitions[0].size) { ++ printk(KERN_NOTICE "no uImage or brnImage or eva found in linux partition\n"); ++ return -1; ++ } ++ } ++ } ++ ++ if (detect_eva_squashfs_partition(mtd, ++ part->offset ++ + split_partitions[0].size)) { ++ split_partitions[0].size += 0x100; ++ pr_info("found eva dummy squashfs behind kernel\n"); ++ } else if (!detect_squashfs_partition(mtd, ++ part->offset ++ + split_partitions[0].size)) { ++ split_partitions[0].size &= ~(mtd->erasesize - 1); ++ split_partitions[0].size += mtd->erasesize; ++ } else { ++ pr_info("found squashfs behind kernel\n"); ++ } ++ ++ split_partitions[0].offset = part->offset; ++ split_partitions[1].offset = part->offset + split_partitions[0].size; ++ split_partitions[1].size = part->size - split_partitions[0].size; ++ ++ add_mtd_partitions(mtd, split_partitions, 2); ++ ++ return 0; ++} ++#endif ++ + /* + * This function, given a master MTD object and a partition table, creates + * and registers slave MTD objects which are bound to the master according to +@@ -907,6 +1070,17 @@ + + add_mtd_device(&slave->mtd); + ++#ifdef CONFIG_MTD_UIMAGE_SPLIT ++ if (!strcmp(parts[i].name, "linux")) { ++ ret = split_uimage(master, &parts[i]); ++ ++ if (ret) { ++ printk(KERN_WARNING ++ "Can't split linux partition\n"); ++ } ++ } ++#endif ++ + if (!strcmp(parts[i].name, "rootfs")) { + #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV + if (ROOT_DEV == 0) { +Index: linux-3.2.9/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +=================================================================== +--- linux-3.2.9.orig/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-03-17 20:49:32.000000000 +0100 ++++ linux-3.2.9/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-03-17 20:50:07.815874369 +0100 +@@ -156,6 +156,7 @@ + + extern __iomem void *ltq_ebu_membase; + extern __iomem void *ltq_cgu_membase; ++extern unsigned long ltq_brn_boot; + + static inline int ltq_is_ase(void) + { +Index: linux-3.2.9/arch/mips/lantiq/setup.c +=================================================================== +--- linux-3.2.9.orig/arch/mips/lantiq/setup.c 2012-03-17 20:49:32.000000000 +0100 ++++ linux-3.2.9/arch/mips/lantiq/setup.c 2012-03-17 20:50:07.815874369 +0100 +@@ -18,6 +18,9 @@ + #include "devices.h" + #include "prom.h" + ++/* set to 1 if the bootloader is BRN-BOOT instead of u-boot */ ++unsigned long ltq_brn_boot = 0; ++ + void __init plat_mem_setup(void) + { + /* assume 16M as default incase uboot fails to pass proper ramsize */ +@@ -38,6 +41,10 @@ + if (strict_strtoul(e, 0, &memsize)) + pr_warn("bad memsize specified\n"); + } ++ if (!strncmp(e, "BRN-BOOT", 8)){ ++ pr_info("Found BRN-BOOT instead of u-boot\n"); ++ ltq_brn_boot = 1; ++ } + envp++; + } + memsize *= 1024 * 1024; diff --git a/target/linux/lantiq/patches/202-owrt-atm.patch b/target/linux/lantiq/patches-3.2/202-owrt-atm.patch index 00af6e98f1..5f7be88aab 100644 --- a/target/linux/lantiq/patches/202-owrt-atm.patch +++ b/target/linux/lantiq/patches-3.2/202-owrt-atm.patch @@ -1,14 +1,16 @@ ---- a/arch/mips/lantiq/irq.c -+++ b/arch/mips/lantiq/irq.c -@@ -9,6 +9,7 @@ - +Index: linux-3.2.9/arch/mips/lantiq/irq.c +=================================================================== +--- linux-3.2.9.orig/arch/mips/lantiq/irq.c 2012-03-08 17:17:13.937473031 +0100 ++++ linux-3.2.9/arch/mips/lantiq/irq.c 2012-03-08 17:32:57.389513360 +0100 +@@ -10,6 +10,7 @@ #include <linux/interrupt.h> #include <linux/ioport.h> + #include <linux/sched.h> +#include <linux/module.h> #include <asm/bootinfo.h> #include <asm/irq_cpu.h> -@@ -102,6 +103,7 @@ void ltq_mask_and_ack_irq(struct irq_dat +@@ -111,6 +112,7 @@ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); ltq_icu_w32((1 << irq_nr), isr); } @@ -16,9 +18,11 @@ static void ltq_ack_irq(struct irq_data *d) { ---- a/arch/mips/mm/cache.c -+++ b/arch/mips/mm/cache.c -@@ -52,6 +52,8 @@ void (*_dma_cache_wback)(unsigned long s +Index: linux-3.2.9/arch/mips/mm/cache.c +=================================================================== +--- linux-3.2.9.orig/arch/mips/mm/cache.c 2012-03-01 01:32:49.000000000 +0100 ++++ linux-3.2.9/arch/mips/mm/cache.c 2012-03-08 17:17:14.193473042 +0100 +@@ -57,6 +57,8 @@ void (*_dma_cache_inv)(unsigned long start, unsigned long size); EXPORT_SYMBOL(_dma_cache_wback_inv); @@ -27,9 +31,11 @@ #endif /* CONFIG_DMA_NONCOHERENT */ ---- a/net/atm/proc.c -+++ b/net/atm/proc.c -@@ -154,7 +154,7 @@ static void *vcc_seq_next(struct seq_fil +Index: linux-3.2.9/net/atm/proc.c +=================================================================== +--- linux-3.2.9.orig/net/atm/proc.c 2012-03-01 01:32:49.000000000 +0100 ++++ linux-3.2.9/net/atm/proc.c 2012-03-08 17:17:14.193473042 +0100 +@@ -154,7 +154,7 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) { static const char *const class_name[] = { @@ -38,9 +44,11 @@ static const char *const aal_name[] = { "---", "1", "2", "3/4", /* 0- 3 */ "???", "5", "???", "???", /* 4- 7 */ ---- a/net/atm/common.c -+++ b/net/atm/common.c -@@ -62,11 +62,17 @@ static void vcc_remove_socket(struct soc +Index: linux-3.2.9/net/atm/common.c +=================================================================== +--- linux-3.2.9.orig/net/atm/common.c 2012-03-01 01:32:49.000000000 +0100 ++++ linux-3.2.9/net/atm/common.c 2012-03-08 17:17:14.193473042 +0100 +@@ -62,11 +62,17 @@ write_unlock_irq(&vcc_sklist_lock); } diff --git a/target/linux/lantiq/patches/203-owrt-cmdline.patch b/target/linux/lantiq/patches-3.2/203-owrt-cmdline.patch index cd7c95a9c7..cd7c95a9c7 100644 --- a/target/linux/lantiq/patches/203-owrt-cmdline.patch +++ b/target/linux/lantiq/patches-3.2/203-owrt-cmdline.patch diff --git a/target/linux/lantiq/patches/204-owrt-dm9000-polling.patch b/target/linux/lantiq/patches-3.2/204-owrt-dm9000-polling.patch index 11fa5396a5..4f5ce9e413 100644 --- a/target/linux/lantiq/patches/204-owrt-dm9000-polling.patch +++ b/target/linux/lantiq/patches-3.2/204-owrt-dm9000-polling.patch @@ -1,5 +1,5 @@ ---- a/drivers/net/dm9000.c -+++ b/drivers/net/dm9000.c +--- a/drivers/net/ethernet/davicom/dm9000.c ++++ b/drivers/net/ethernet/davicom/dm9000.c @@ -19,6 +19,7 @@ * Sascha Hauer <s.hauer@pengutronix.de> */ diff --git a/target/linux/lantiq/patches/205-owrt-gpio-export.patch b/target/linux/lantiq/patches-3.2/205-owrt-gpio-export.patch index 7839327e32..7839327e32 100644 --- a/target/linux/lantiq/patches/205-owrt-gpio-export.patch +++ b/target/linux/lantiq/patches-3.2/205-owrt-gpio-export.patch diff --git a/target/linux/lantiq/patches/210-machtypes.patch b/target/linux/lantiq/patches-3.2/206-machtypes.patch index 55b67428dc..c964488322 100644 --- a/target/linux/lantiq/patches/210-machtypes.patch +++ b/target/linux/lantiq/patches-3.2/206-machtypes.patch @@ -1,6 +1,6 @@ --- a/arch/mips/lantiq/machtypes.h +++ b/arch/mips/lantiq/machtypes.h -@@ -20,9 +20,34 @@ enum lantiq_mach_type { +@@ -20,6 +20,36 @@ enum lantiq_mach_type { LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ LANTIQ_MACH_EASY98000NAND, /* Falcon Eval Board, NAND Flash */ @@ -8,14 +8,12 @@ + LANTIQ_MACH_EASY98020_1LAN, /* EASY98020 Eval Board (1 LAN port) */ + LANTIQ_MACH_EASY98020_2LAN, /* EASY98020 Eval Board (2 LAN port) */ + LANTIQ_MACH_95C3AM1, /* 95C3AM1 Eval Board */ - - /* FRITZ!BOX */ - LANTIQ_MACH_FRITZ3370, /* FRITZ!BOX 3370 vdsl cpe */ + + /* Arcadyan */ + LANTIQ_MACH_ARV3527P, /* Arcor easybox a401 */ + LANTIQ_MACH_ARV4510PW, /* Wippies Homebox */ + LANTIQ_MACH_ARV4518PW, /* Airties WAV-221, SMC-7908A-ISP */ ++ LANTIQ_MACH_ARV4519PW, /* Vodafone, Pirelli */ + LANTIQ_MACH_ARV4520PW, /* Airties WAV-281, Arcor EasyboxA800 */ + LANTIQ_MACH_ARV452CPW, /* Arcor EasyboxA801 */ + LANTIQ_MACH_ARV4525PW, /* Speedport W502V */ @@ -27,6 +25,10 @@ + /* Netgear */ + LANTIQ_MACH_DGN3500B, /* Netgear DGN3500 */ + ++ /* FRITZ!BOX */ ++ LANTIQ_MACH_FRITZ3370, /* FRITZ!BOX 3370 vdsl cpe */ ++ LANTIQ_MACH_FRITZ7320, /* FRITZ!BOX 7320 1&1 homeserver */ ++ + /* Gigaset */ + LANTIQ_MACH_GIGASX76X, /* Gigaset SX76x */ + @@ -37,12 +39,12 @@ #endif --- a/arch/mips/lantiq/xway/Kconfig +++ b/arch/mips/lantiq/xway/Kconfig -@@ -6,6 +6,22 @@ config LANTIQ_MACH_EASY50712 +@@ -6,6 +6,30 @@ config LANTIQ_MACH_EASY50712 bool "Easy50712 - Danube" default y -+config LANTIQ_MACH_ARV45XX -+ bool "ARV45XX" ++config LANTIQ_MACH_ARV ++ bool "ARV" + default y + +config LANTIQ_MACH_NETGEAR @@ -57,18 +59,28 @@ + bool "WBMR-HP-G300H" + default y + ++config LANTIQ_MACH_FRITZ_VR9 ++ bool "FRITZ3370" ++ default y ++ ++config LANTIQ_MACH_FRITZ_AR9 ++ bool "FRITZ7320" ++ default y ++ endmenu - endif + choice --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile -@@ -7,3 +7,7 @@ obj-$(CONFIG_SOC_VR9) += clk-vr9.o prom- +@@ -2,3 +2,9 @@ obj-y := sysctrl.o reset.o gpio.o gpio_s + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o - obj-$(CONFIG_LANTIQ_MACH_FRITZ3370) += mach-fritz.o -+obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o -+obj-$(CONFIG_LANTIQ_MACH_NETGEAR) += mach-netgear.o ++obj-$(CONFIG_LANTIQ_MACH_ARV) += mach-arv.o ++obj-$(CONFIG_LANTIQ_MACH_FRITZ_AR9) += mach-fritz_ar9.o ++obj-$(CONFIG_LANTIQ_MACH_FRITZ_VR9) += mach-fritz_vr9.o +obj-$(CONFIG_LANTIQ_MACH_GIGASX76X) += mach-gigasx76x.o ++obj-$(CONFIG_LANTIQ_MACH_NETGEAR) += mach-netgear.o +obj-$(CONFIG_LANTIQ_MACH_WBMR) += mach-wbmr.o --- a/arch/mips/lantiq/falcon/Kconfig +++ b/arch/mips/lantiq/falcon/Kconfig @@ -90,7 +102,7 @@ --- a/arch/mips/lantiq/falcon/Makefile +++ b/arch/mips/lantiq/falcon/Makefile @@ -1,2 +1,6 @@ - obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o softdog_vpe.o + obj-y := prom.o reset.o sysctrl.o devices.o gpio.o +obj-$(CONFIG_LANTIQ_MACH_EASY98000) += addon-easy98000.o +obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o @@ -138,10 +150,10 @@ +#define EASY98000_GPIO_LED_3 12 +#define EASY98000_GPIO_LED_4 13 +#define EASY98000_GPIO_LED_5 14 -+ -+extern unsigned char ltq_ethaddr[6]; -static struct mtd_partition easy98000_nor_partitions[] = { ++extern unsigned char ltq_ethaddr[6]; ++ +static struct mtd_partition easy98000_nor_partitions[] = +{ { @@ -267,48 +279,27 @@ #define SPI_GPIO_BUS_NUM 1 static struct spi_gpio_platform_data easy98000_spi_gpio_data = { -@@ -93,29 +201,36 @@ static struct spi_board_info easy98000_s - .platform_data = &at25160n, +@@ -94,11 +202,22 @@ static struct spi_board_info easy98000_s }; --static void __init + static void __init -easy98000_init_common(void) -+static void __init easy98000_spi_gpio_init(void) ++easy98000_spi_gpio_init(void) { spi_register_board_info(&easy98000_spi_gpio_devices, 1); platform_device_register(&easy98000_spi_gpio_device); - } - --static void __init --easy98000_init(void) -+static void __init easy98000_init_common(void) ++} ++ ++static void __init ++easy98000_init_common(void) +{ -+ falcon_register_i2c(); + falcon_register_i2c(); + platform_device_register(&easy98000_i2c_gpio_device); + register_davicom(); + ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98000_leds_gpio), -+ easy98000_leds_gpio); ++ easy98000_leds_gpio); + register_easy98000_cpld(); + easy98000_spi_gpio_init(); -+} -+ -+static void __init easy98000_init(void) - { - easy98000_init_common(); - ltq_register_nor(&easy98000_nor_flash_data); - } - --static void __init --easy98000sf_init(void) -+static void __init easy98000sf_init(void) - { - easy98000_init_common(); - falcon_register_spi_flash(&easy98000_spi_flash_data); } --static void __init --easy98000nand_init(void) -+static void __init easy98000nand_init(void) - { - easy98000_init_common(); - falcon_register_nand(); + static void __init diff --git a/target/linux/lantiq/patches/211-devices.patch b/target/linux/lantiq/patches-3.2/207-devices.patch index 408d680f16..2bc498d1b2 100644 --- a/target/linux/lantiq/patches/211-devices.patch +++ b/target/linux/lantiq/patches-3.2/207-devices.patch @@ -40,14 +40,15 @@ #endif --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile -@@ -1,5 +1,7 @@ - obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o nand.o timer.o +@@ -1,5 +1,8 @@ + obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o clk.o prom.o nand.o timer.o dev-ifxhcd.o -+obj-y += dev-dwc_otg.o dev-wifi-rt2x00.o dev-wifi-ath5k.o ++obj-y += dev-dwc_otg.o ++obj-$(CONFIG_PCI) += dev-wifi-rt2x00.o dev-wifi-athxk.o pci-ath-fixup.o + - obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o - obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o - obj-$(CONFIG_SOC_VR9) += clk-vr9.o prom-vr9.o + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o + obj-$(CONFIG_LANTIQ_MACH_ARV) += mach-arv.o --- a/arch/mips/lantiq/xway/devices.c +++ b/arch/mips/lantiq/xway/devices.c @@ -19,6 +19,7 @@ @@ -58,25 +59,11 @@ #include <asm/bootinfo.h> #include <asm/irq.h> -@@ -99,3 +100,98 @@ ltq_register_etop(struct ltq_eth_data *e - platform_device_register(<q_etop); - } +@@ -119,3 +120,84 @@ ltq_register_vrx200(struct ltq_eth_data + ltq_vrx200.dev.platform_data = eth; + platform_device_register(<q_vrx200); } + -+/* madwifi */ -+int lantiq_emulate_madwifi_eep = 0; -+EXPORT_SYMBOL(lantiq_emulate_madwifi_eep); -+ -+int lantiq_madwifi_eep_addr = 0; -+EXPORT_SYMBOL(lantiq_madwifi_eep_addr); -+ -+void __init -+ltq_register_madwifi_eep(unsigned long long addr) -+{ -+ lantiq_madwifi_eep_addr = addr; -+ lantiq_emulate_madwifi_eep = 1; -+} -+ +/* ebu */ +static struct resource ltq_ebu_resource = +{ @@ -159,7 +146,7 @@ +} --- a/arch/mips/lantiq/xway/devices.h +++ b/arch/mips/lantiq/xway/devices.h -@@ -11,10 +11,17 @@ +@@ -11,6 +11,8 @@ #include "../devices.h" #include <linux/phy.h> @@ -168,12 +155,13 @@ extern void ltq_register_gpio(void); extern void ltq_register_gpio_stp(void); - extern void ltq_register_ase_asc(void); +@@ -18,5 +20,9 @@ extern void ltq_register_ase_asc(void); extern void ltq_register_etop(struct ltq_eth_data *eth); + extern void xway_register_nand(struct mtd_partition *parts, int count); + extern void ltq_register_vrx200(struct ltq_eth_data *eth); +extern void ltq_register_gpio_ebu(unsigned int value); +extern void ltq_register_spi(struct ltq_spi_platform_data *pdata, + struct spi_board_info const *info, unsigned n); -+extern void ltq_register_madwifi_eep(unsigned long long addr); +extern void ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt); #endif diff --git a/target/linux/lantiq/patches/810-fix-mach-easy98000.patch b/target/linux/lantiq/patches-3.2/208-fix-mach-easy98000.patch index 94b7b92be2..021bb88e4c 100644 --- a/target/linux/lantiq/patches/810-fix-mach-easy98000.patch +++ b/target/linux/lantiq/patches-3.2/208-fix-mach-easy98000.patch @@ -1,5 +1,7 @@ ---- a/arch/mips/lantiq/falcon/mach-easy98000.c -+++ b/arch/mips/lantiq/falcon/mach-easy98000.c +Index: linux-3.2.9/arch/mips/lantiq/falcon/mach-easy98000.c +=================================================================== +--- linux-3.2.9.orig/arch/mips/lantiq/falcon/mach-easy98000.c 2012-03-07 19:30:22.000000000 +0100 ++++ linux-3.2.9/arch/mips/lantiq/falcon/mach-easy98000.c 2012-03-07 19:35:47.804810934 +0100 @@ -17,10 +17,11 @@ #include <linux/spi/eeprom.h> #include <falcon/lantiq_soc.h> @@ -31,7 +33,7 @@ static struct mtd_partition easy98000_nor_partitions[] = { -@@ -70,7 +80,7 @@ static struct spi_board_info easy98000_s +@@ -70,7 +80,7 @@ .platform_data = &easy98000_spi_flash_platform_data }; @@ -40,7 +42,7 @@ { .name = "easy98000:green:0", .gpio = EASY98000_GPIO_LED_0, -@@ -104,12 +114,11 @@ static struct gpio_led easy98000_leds_gp +@@ -104,12 +114,11 @@ static struct dm9000_plat_data dm9000_plat_data = { .flags = DM9000_PLATF_8BITONLY, @@ -55,14 +57,14 @@ [2] = { /* with irq (210 -> gpio 110) the driver is very unreliable */ .start = -1, /* use polling */ -@@ -212,8 +221,8 @@ static void __init easy98000_init_common +@@ -214,8 +223,8 @@ falcon_register_i2c(); platform_device_register(&easy98000_i2c_gpio_device); register_davicom(); - ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98000_leds_gpio), -- easy98000_leds_gpio); +- easy98000_leds_gpio); + ltq_add_device_gpio_leds(-1, ARRAY_SIZE(easy98000_gpio_leds), -+ easy98000_gpio_leds); ++ easy98000_gpio_leds); register_easy98000_cpld(); easy98000_spi_gpio_init(); } diff --git a/target/linux/lantiq/patches-3.2/209-fritz_ram.patch b/target/linux/lantiq/patches-3.2/209-fritz_ram.patch new file mode 100644 index 0000000000..cb77a866e3 --- /dev/null +++ b/target/linux/lantiq/patches-3.2/209-fritz_ram.patch @@ -0,0 +1,17 @@ +Index: linux-3.2.9/arch/mips/lantiq/setup.c +=================================================================== +--- linux-3.2.9.orig/arch/mips/lantiq/setup.c 2012-03-20 11:23:49.000000000 +0100 ++++ linux-3.2.9/arch/mips/lantiq/setup.c 2012-03-20 11:25:54.119568502 +0100 +@@ -40,6 +40,12 @@ + e += 8; + if (strict_strtoul(e, 0, &memsize)) + pr_warn("bad memsize specified\n"); ++ } else if (!strcmp(e, "memsize")) { ++ envp++; ++ e = (char *)KSEG1ADDR(*envp); ++ if (strict_strtoul(e, 0, &memsize)) ++ pr_warn("bad memsize specified\n"); ++ memsize /= 1024 * 1024; + } + if (!strncmp(e, "BRN-BOOT", 8)){ + pr_info("Found BRN-BOOT instead of u-boot\n"); diff --git a/target/linux/lantiq/patches/0016-MIPS-lantiq-adds-xway-nand-driver.patch b/target/linux/lantiq/patches/0016-MIPS-lantiq-adds-xway-nand-driver.patch deleted file mode 100644 index b7ad789055..0000000000 --- a/target/linux/lantiq/patches/0016-MIPS-lantiq-adds-xway-nand-driver.patch +++ /dev/null @@ -1,253 +0,0 @@ -From e2d5b4ba92289cb0fcc9db741d159ef5eb852d9f Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sat, 27 Aug 2011 20:08:14 +0200 -Subject: [PATCH 16/24] MIPS: lantiq: adds xway nand driver - -This patch adds a nand driver for XWAY SoCs. The patch makes use of the -plat_nand driver. As with the EBU NOR driver merged in 3.0, we have the -endianess swap problem on read. To workaround this problem we make the -read_byte() callback available via the plat_nand driver causing the nand -layer to do byte reads. - -Signed-off-by: John Crispin <blogic@openwrt.org> - -TODO : memory ranges - cs lines - plat dev - ebu2 and not ebu1 ? ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + - arch/mips/lantiq/xway/Makefile | 2 +- - arch/mips/lantiq/xway/nand.c | 185 ++++++++++++++++++++ - drivers/mtd/nand/plat_nand.c | 1 + - include/linux/mtd/nand.h | 1 + - 5 files changed, 190 insertions(+), 1 deletions(-) - create mode 100644 arch/mips/lantiq/xway/nand.c - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -138,6 +138,8 @@ - /* register access macros for EBU and CGU */ - #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) - #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) -+#define ltq_ebu_w32_mask(x, y, z) \ -+ ltq_w32_mask(x, y, ltq_ebu_membase + (z)) - #define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) - #define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) - ---- a/arch/mips/lantiq/xway/Makefile -+++ b/arch/mips/lantiq/xway/Makefile -@@ -1,4 +1,4 @@ --obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o -+obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o nand.o - - obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o - obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o ---- /dev/null -+++ b/arch/mips/lantiq/xway/nand.c -@@ -0,0 +1,185 @@ -+/* -+ * 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 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/mtd/physmap.h> -+#include <linux/mtd/nand.h> -+#include <linux/platform_device.h> -+ -+#include <lantiq_soc.h> -+#include <lantiq_irq.h> -+#include <lantiq_platform.h> -+ -+#include "devices.h" -+ -+/* nand registers */ -+#define LTQ_EBU_NAND_WAIT 0xB4 -+#define LTQ_EBU_NAND_ECC0 0xB8 -+#define LTQ_EBU_NAND_ECC_AC 0xBC -+#define LTQ_EBU_NAND_CON 0xB0 -+#define LTQ_EBU_ADDSEL1 0x24 -+ -+/* gpio definitions */ -+#define PIN_ALE 13 -+#define PIN_CLE 24 -+#define PIN_CS1 23 -+#define PIN_RDY 48 /* NFLASH_READY */ -+#define PIN_RD 49 /* NFLASH_READ_N */ -+ -+#define NAND_CMD_ALE (1 << 2) -+#define NAND_CMD_CLE (1 << 3) -+#define NAND_CMD_CS (1 << 4) -+#define NAND_WRITE_CMD_RESET 0xff -+#define NAND_WRITE_CMD (NAND_CMD_CS | NAND_CMD_CLE) -+#define NAND_WRITE_ADDR (NAND_CMD_CS | NAND_CMD_ALE) -+#define NAND_WRITE_DATA (NAND_CMD_CS) -+#define NAND_READ_DATA (NAND_CMD_CS) -+#define NAND_WAIT_WR_C (1 << 3) -+#define NAND_WAIT_RD (0x1) -+ -+#define ADDSEL1_MASK(x) (x << 4) -+#define ADDSEL1_REGEN 1 -+#define BUSCON1_SETUP (1 << 22) -+#define BUSCON1_BCGEN_RES (0x3 << 12) -+#define BUSCON1_WAITWRC2 (2 << 8) -+#define BUSCON1_WAITRDC2 (2 << 6) -+#define BUSCON1_HOLDC1 (1 << 4) -+#define BUSCON1_RECOVC1 (1 << 2) -+#define BUSCON1_CMULT4 1 -+#define NAND_CON_NANDM 1 -+#define NAND_CON_CSMUX (1 << 1) -+#define NAND_CON_CS_P (1 << 4) -+#define NAND_CON_SE_P (1 << 5) -+#define NAND_CON_WP_P (1 << 6) -+#define NAND_CON_PRE_P (1 << 7) -+#define NAND_CON_IN_CS0 0 -+#define NAND_CON_OUT_CS0 0 -+#define NAND_CON_IN_CS1 (1 << 8) -+#define NAND_CON_OUT_CS1 (1 << 10) -+#define NAND_CON_CE (1 << 20) -+ -+#define NAND_BASE_ADDRESS (KSEG1 | 0x14000000) -+ -+static const char *part_probes[] = { "cmdlinepart", NULL }; -+ -+static void -+xway_select_chip(struct mtd_info *mtd, int chip) -+{ -+ switch (chip) { -+ case -1: -+ ltq_ebu_w32_mask(NAND_CON_CE, 0, LTQ_EBU_NAND_CON); -+ ltq_ebu_w32_mask(NAND_CON_NANDM, 0, LTQ_EBU_NAND_CON); -+ break; -+ case 0: -+ ltq_ebu_w32_mask(0, NAND_CON_NANDM, LTQ_EBU_NAND_CON); -+ ltq_ebu_w32_mask(0, NAND_CON_CE, LTQ_EBU_NAND_CON); -+ /* reset the nand chip */ -+ while((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0); -+ ltq_w32(NAND_WRITE_CMD_RESET, ((u32*)(NAND_BASE_ADDRESS | NAND_WRITE_CMD))); -+ break; -+ default: -+ BUG(); -+ } -+} -+ -+static void -+xway_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) -+{ -+ struct nand_chip *this = mtd->priv; -+ -+ if (ctrl & NAND_CTRL_CHANGE) { -+ if(ctrl & NAND_CLE) -+ this->IO_ADDR_W = (void __iomem *)(NAND_BASE_ADDRESS | NAND_WRITE_CMD); -+ else if(ctrl & NAND_ALE) -+ this->IO_ADDR_W = (void __iomem *)(NAND_BASE_ADDRESS | NAND_WRITE_ADDR); -+ } -+ -+ if(data != NAND_CMD_NONE) { -+ *(volatile u8*)((u32)this->IO_ADDR_W) = data; -+ while((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0); -+ } -+} -+ -+static int -+xway_dev_ready(struct mtd_info *mtd) -+{ -+ return ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_RD; -+} -+ -+void -+nand_write(unsigned int addr, unsigned int val) -+{ -+ ltq_w32(val, ((u32*)(NAND_BASE_ADDRESS | addr))); -+ while((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0); -+} -+ -+unsigned char -+ltq_nand_read_byte(struct mtd_info *mtd) -+{ -+ return ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA))); -+} -+ -+int xway_nand_probe(struct platform_device *pdev) -+{ -+// ltq_gpio_request(PIN_CS1, 1, 0, 1, "NAND_CS1"); -+ ltq_gpio_request(PIN_CLE, 1, 0, 1, "NAND_CLE"); -+ ltq_gpio_request(PIN_ALE, 1, 0, 1, "NAND_ALE"); -+ if (ltq_is_ar9() || ltq_is_vr9()) { -+ ltq_gpio_request(PIN_RDY, 1, 0, 0, "NAND_BSY"); -+ ltq_gpio_request(PIN_RD, 1, 0, 1, "NAND_RD"); -+ } -+ -+ ltq_ebu_w32((NAND_BASE_ADDRESS & 0x1fffff00) -+ | ADDSEL1_MASK(3) | ADDSEL1_REGEN, LTQ_EBU_ADDSEL1); -+ -+ ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2 -+ | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1 -+ | BUSCON1_CMULT4, LTQ_EBU_BUSCON1); -+ -+ ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P -+ | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P -+ | NAND_CON_IN_CS0 | NAND_CON_OUT_CS0, LTQ_EBU_NAND_CON); -+ -+ ltq_w32(NAND_WRITE_CMD_RESET, ((u32*)(NAND_BASE_ADDRESS | NAND_WRITE_CMD))); -+ while((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0); -+ -+ return 0; -+} -+ -+static struct platform_nand_data falcon_flash_nand_data = { -+ .chip = { -+ .nr_chips = 1, -+ .chip_delay = 30, -+ .part_probe_types = part_probes, -+ }, -+ .ctrl = { -+ .probe = xway_nand_probe, -+ .cmd_ctrl = xway_cmd_ctrl, -+ .dev_ready = xway_dev_ready, -+ .select_chip = xway_select_chip, -+ .read_byte = ltq_nand_read_byte, -+ } -+}; -+ -+static struct resource ltq_nand_res = -+ MEM_RES("nand", 0x14000000, 0x3ffffff); -+ -+static struct platform_device ltq_flash_nand = { -+ .name = "gen_nand", -+ .id = -1, -+ .num_resources = 1, -+ .resource = <q_nand_res, -+ .dev = { -+ .platform_data = &falcon_flash_nand_data, -+ }, -+}; -+ -+void __init -+xway_register_nand(void) -+{ -+ platform_device_register(<q_flash_nand); -+} ---- a/drivers/mtd/nand/plat_nand.c -+++ b/drivers/mtd/nand/plat_nand.c -@@ -77,6 +77,7 @@ static int __devinit plat_nand_probe(str - data->chip.select_chip = pdata->ctrl.select_chip; - data->chip.write_buf = pdata->ctrl.write_buf; - data->chip.read_buf = pdata->ctrl.read_buf; -+ data->chip.read_byte = pdata->ctrl.read_byte; - data->chip.chip_delay = pdata->chip.chip_delay; - data->chip.options |= pdata->chip.options; - ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -657,6 +657,7 @@ struct platform_nand_ctrl { - void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); - void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); - void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); -+ unsigned char (*read_byte)(struct mtd_info *mtd); - void *priv; - }; - diff --git a/target/linux/lantiq/patches/0023-MIPS-lantiq-adds-basic-vr9-support.patch b/target/linux/lantiq/patches/0023-MIPS-lantiq-adds-basic-vr9-support.patch deleted file mode 100644 index bb7422cf90..0000000000 --- a/target/linux/lantiq/patches/0023-MIPS-lantiq-adds-basic-vr9-support.patch +++ /dev/null @@ -1,262 +0,0 @@ -From 780a64cd52209fad15c7133f950b2b2d6b9b59e2 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sat, 27 Aug 2011 21:44:32 +0200 -Subject: [PATCH 23/24] MIPS: lantiq: adds basic vr9 support - ---- - .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + - arch/mips/lantiq/Kconfig | 9 ++ - arch/mips/lantiq/Platform | 1 + - arch/mips/lantiq/machtypes.h | 3 + - arch/mips/lantiq/xway/Kconfig | 12 +++ - arch/mips/lantiq/xway/Makefile | 2 + - arch/mips/lantiq/xway/clk-vr9.c | 78 ++++++++++++++++++++ - arch/mips/lantiq/xway/mach-fritz.c | 74 +++++++++++++++++++ - arch/mips/lantiq/xway/prom-vr9.c | 55 ++++++++++++++ - arch/mips/pci/Makefile | 2 +- - 10 files changed, 237 insertions(+), 1 deletions(-) - create mode 100644 arch/mips/lantiq/xway/clk-vr9.c - create mode 100644 arch/mips/lantiq/xway/mach-fritz.c - create mode 100644 arch/mips/lantiq/xway/prom-vr9.c - ---- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -@@ -21,6 +21,7 @@ - #define SOC_ID_ARX188 0x16C - #define SOC_ID_ARX168 0x16D - #define SOC_ID_ARX182 0x16F -+#define SOC_ID_VRX288 0x1C0 - - /* SoC Types */ - #define SOC_TYPE_DANUBE 0x01 -@@ -91,6 +92,7 @@ - - /* ETOP - ethernet */ - #define LTQ_ETOP_BASE_ADDR 0x1E180000 -+#define LTQ_ETOP_BASE_ADDR_VR9 0x1E200000 - #define LTQ_ETOP_SIZE 0x40000 - - /* GBIT - gigabit switch */ ---- a/arch/mips/lantiq/Kconfig -+++ b/arch/mips/lantiq/Kconfig -@@ -1,5 +1,8 @@ - if LANTIQ - -+config LANTIQ_PCIE -+ bool -+ - config SOC_TYPE_XWAY - bool - default n -@@ -17,6 +20,12 @@ config SOC_XWAY - select SOC_TYPE_XWAY - select HW_HAS_PCI - -+config SOC_VR9 -+ bool "VR9" -+ select SOC_TYPE_XWAY -+ select HW_HAS_PCI -+ select LANTIQ_PCIE -+ - config SOC_FALCON - bool "FALCON" - endchoice ---- a/arch/mips/lantiq/Platform -+++ b/arch/mips/lantiq/Platform -@@ -6,4 +6,5 @@ platform-$(CONFIG_LANTIQ) += lantiq/ - cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq - load-$(CONFIG_LANTIQ) = 0xffffffff80002000 - cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway -+cflags-$(CONFIG_SOC_TYPE_VR9) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway - cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon ---- a/arch/mips/lantiq/machtypes.h -+++ b/arch/mips/lantiq/machtypes.h -@@ -20,6 +20,9 @@ enum lantiq_mach_type { - LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ - LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ - LANTIQ_MACH_EASY98000NAND, /* Falcon Eval Board, NAND Flash */ -+ -+ /* FRITZ!BOX */ -+ LANTIQ_MACH_FRITZ3370, /* FRITZ!BOX 3370 vdsl cpe */ - }; - - #endif ---- a/arch/mips/lantiq/xway/Kconfig -+++ b/arch/mips/lantiq/xway/Kconfig -@@ -21,3 +21,15 @@ config LANTIQ_MACH_EASY50601 - endmenu - - endif -+ -+if SOC_VR9 -+ -+menu "MIPS Machine" -+ -+config LANTIQ_MACH_FRITZ3370 -+ bool "Fritz!Box 3370" -+ default y -+ -+endmenu -+ -+endif ---- a/arch/mips/lantiq/xway/Makefile -+++ b/arch/mips/lantiq/xway/Makefile -@@ -2,6 +2,8 @@ obj-y := sysctrl.o reset.o gpio.o gpio_s - - obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o - obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o -+obj-$(CONFIG_SOC_VR9) += clk-vr9.o prom-vr9.o - - obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o - obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o -+obj-$(CONFIG_LANTIQ_MACH_FRITZ3370) += mach-fritz.o ---- /dev/null -+++ b/arch/mips/lantiq/xway/clk-vr9.c -@@ -0,0 +1,78 @@ -+/* -+ * 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 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/clk.h> -+ -+#include <asm/time.h> -+#include <asm/irq.h> -+#include <asm/div64.h> -+ -+#include <lantiq_soc.h> -+ -+#define CLOCK_62_5M 62500000 -+#define CLOCK_83_5M 83500000 -+#define CLOCK_125M 125000000 -+#define CLOCK_200M 200000000 -+#define CLOCK_250M 250000000 -+#define CLOCK_300M 300000000 -+#define CLOCK_98_304M 98304000 -+#define CLOCK_150M 150000000 -+#define CLOCK_196_608M 196608000 -+#define CLOCK_600M 600000000 -+#define CLOCK_500M 500000000 -+#define CLOCK_393M 393215332 -+#define CLOCK_166M 166666666 -+ -+#define LTQ_CGU_SYS 0x0c -+#define LTQ_CGU_IF_CLK 0x24 -+ -+unsigned int ltq_get_cpu_hz(void) -+{ -+ int clks[] = { -+ CLOCK_600M, CLOCK_500M, CLOCK_393M, CLOCK_333M, CLOCK_125M, -+ CLOCK_125M, CLOCK_196_608M, CLOCK_166M, CLOCK_125M, CLOCK_125M }; -+ int val = (ltq_cgu_r32(LTQ_CGU_SYS) >> 4) & 0xf; -+ -+ if (val > 9) -+ panic("bad cpu speed\n"); -+ if (val == 2) -+ panic("missing workaround\n"); -+ //cgu_get_pll1_fosc(); //CLOCK_393M; -+ return clks[val]; -+} -+EXPORT_SYMBOL(ltq_get_cpu_hz); -+ -+unsigned int ltq_get_fpi_hz(void) -+{ -+ int clks[] = { -+ CLOCK_62_5M, CLOCK_62_5M, CLOCK_83_5M, CLOCK_125M, CLOCK_125M, -+ CLOCK_125M, CLOCK_167M, CLOCK_200M, CLOCK_250M, CLOCK_300M, -+ CLOCK_62_5M, CLOCK_98_304M, CLOCK_150M, CLOCK_196_608M }; -+ int val = ((ltq_cgu_r32(LTQ_CGU_IF_CLK) >> 25) & 0xf); -+ -+ if (val > 13) -+ panic("bad fpi speed\n"); -+ -+ return clks[val]; -+} -+EXPORT_SYMBOL(ltq_get_fpi_hz); -+ -+unsigned int ltq_get_io_region_clock(void) -+{ -+ return ltq_get_fpi_hz() / 2; -+} -+EXPORT_SYMBOL(ltq_get_io_region_clock); -+ -+unsigned int ltq_get_fpi_bus_clock(int fpi) -+{ -+ return ltq_get_fpi_hz(); -+} -+EXPORT_SYMBOL(ltq_get_fpi_bus_clock); ---- /dev/null -+++ b/arch/mips/lantiq/xway/prom-vr9.c -@@ -0,0 +1,55 @@ -+/* -+ * 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 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/module.h> -+#include <linux/clk.h> -+#include <asm/bootinfo.h> -+#include <asm/time.h> -+ -+#include <lantiq_soc.h> -+ -+#include "devices.h" -+#include "../prom.h" -+ -+#define SOC_VRX288 "VRX288" -+ -+#define PART_SHIFT 12 -+#define PART_MASK 0x0FFFFFFF -+#define REV_SHIFT 28 -+#define REV_MASK 0xF0000000 -+ -+void __init ltq_soc_detect(struct ltq_soc_info *i) -+{ -+ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; -+ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; -+ sprintf(i->rev_type, "1.%d", i->rev); -+ switch (i->partnum) { -+ case SOC_ID_VRX288: -+ i->name = SOC_VRX288; -+ i->type = SOC_TYPE_VR9; -+ break; -+ -+ default: -+ unreachable(); -+ break; -+ } -+ printk("%08X\n", i->partnum); -+} -+ -+void __init ltq_soc_setup(void) -+{ -+ /* -+ reg = IFX_REG_R32(IFX_XBAR_ALWAYS_LAST); -+ reg &= ~ IFX_XBAR_FPI_BURST_EN; -+ IFX_REG_W32(reg, IFX_XBAR_ALWAYS_LAST); -+ */ -+ -+ ltq_register_asc(1); -+ ltq_register_gpio(); -+ ltq_register_wdt(); -+} ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -41,7 +41,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1 - obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o - obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o - obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o --obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o -+obj-$(CONFIG_LANTIQ) += pci-lantiq.o ops-lantiq.o - obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o - obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o - obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o diff --git a/target/linux/lantiq/patches/201-owrt-mtd_uimage_split.patch b/target/linux/lantiq/patches/201-owrt-mtd_uimage_split.patch deleted file mode 100644 index 6c6a45ac04..0000000000 --- a/target/linux/lantiq/patches/201-owrt-mtd_uimage_split.patch +++ /dev/null @@ -1,116 +0,0 @@ ---- a/drivers/mtd/Kconfig -+++ b/drivers/mtd/Kconfig -@@ -41,6 +41,10 @@ config MTD_ROOTFS_SPLIT - bool "Automatically split 'rootfs' partition for squashfs" - default y - -+config MTD_UIMAGE_SPLIT -+ bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'" -+ default y -+ - config MTD_REDBOOT_PARTS - tristate "RedBoot partition table parsing" - ---help--- ---- a/drivers/mtd/mtdpart.c -+++ b/drivers/mtd/mtdpart.c -@@ -861,6 +861,82 @@ static int refresh_rootfs_split(struct m - } - #endif /* CONFIG_MTD_ROOTFS_SPLIT */ - -+ -+#ifdef CONFIG_MTD_UIMAGE_SPLIT -+static unsigned long find_uimage_size(struct mtd_info *mtd, -+ unsigned long offset) -+{ -+#define UBOOT_MAGIC 0x56190527 -+ unsigned long magic = 0; -+ unsigned long temp; -+ size_t len; -+ int ret; -+ -+ ret = mtd->read(mtd, offset, 4, &len, (void *)&magic); -+ if (ret || len != sizeof(magic)) -+ return 0; -+ -+ if (le32_to_cpu(magic) != UBOOT_MAGIC) -+ return 0; -+ -+ ret = mtd->read(mtd, offset + 12, 4, &len, (void *)&temp); -+ if (ret || len != sizeof(temp)) -+ return 0; -+ -+ return temp + 0x40; -+} -+ -+static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset) -+{ -+ unsigned long temp; -+ size_t len; -+ int ret; -+ -+ ret = mtd->read(mtd, offset, 4, &len, (void *)&temp); -+ if (ret || len != sizeof(temp)) -+ return 0; -+ -+ return le32_to_cpu(temp) == SQUASHFS_MAGIC; -+} -+ -+static int split_uimage(struct mtd_info *mtd, -+ const struct mtd_partition *part) -+{ -+ static struct mtd_partition split_partitions[] = { -+ { -+ .name = "kernel", -+ .offset = 0x0, -+ .size = 0x0, -+ }, { -+ .name = "rootfs", -+ .offset = 0x0, -+ .size = 0x0, -+ }, -+ }; -+ -+ split_partitions[0].size = find_uimage_size(mtd, part->offset); -+ if (!split_partitions[0].size) { -+ printk(KERN_NOTICE "no uImage found in linux partition\n"); -+ return -1; -+ } -+ -+ if (!detect_squashfs_partition(mtd, -+ part->offset -+ + split_partitions[0].size)) { -+ split_partitions[0].size &= ~(mtd->erasesize - 1); -+ split_partitions[0].size += mtd->erasesize; -+ } -+ -+ split_partitions[0].offset = part->offset; -+ split_partitions[1].offset = part->offset + split_partitions[0].size; -+ split_partitions[1].size = part->size - split_partitions[0].size; -+ -+ add_mtd_partitions(mtd, split_partitions, 2); -+ -+ return 0; -+} -+#endif -+ - /* - * This function, given a master MTD object and a partition table, creates - * and registers slave MTD objects which are bound to the master according to -@@ -894,6 +970,17 @@ int add_mtd_partitions(struct mtd_info * - - add_mtd_device(&slave->mtd); - -+#ifdef CONFIG_MTD_UIMAGE_SPLIT -+ if (!strcmp(parts[i].name, "linux")) { -+ ret = split_uimage(master, &parts[i]); -+ -+ if (ret) { -+ printk(KERN_WARNING -+ "Can't split linux partition\n"); -+ } -+ } -+#endif -+ - if (!strcmp(parts[i].name, "rootfs")) { - #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV - if (ROOT_DEV == 0) { diff --git a/target/linux/lantiq/patches/206-owrt-brnboot.patch b/target/linux/lantiq/patches/206-owrt-brnboot.patch deleted file mode 100644 index d10d66b1e2..0000000000 --- a/target/linux/lantiq/patches/206-owrt-brnboot.patch +++ /dev/null @@ -1,93 +0,0 @@ -Index: linux-3.1.10/drivers/mtd/mtdpart.c -=================================================================== ---- linux-3.1.10.orig/drivers/mtd/mtdpart.c 2012-02-14 19:38:40.102266817 +0100 -+++ linux-3.1.10/drivers/mtd/mtdpart.c 2012-02-14 19:38:40.146266819 +0100 -@@ -899,6 +899,38 @@ - return le32_to_cpu(temp) == SQUASHFS_MAGIC; - } - -+static unsigned long find_brnimage_size(struct mtd_info *mtd, -+ unsigned long offset) -+{ -+ unsigned long buf[4]; -+ // Assume at most 2MB of kernel image -+ unsigned long end = offset + (2 << 20); -+ unsigned long ptr = offset + 0x400 - 12; -+ size_t len; -+ int ret; -+ -+ while (ptr < end) { -+ long size_min = ptr - 0x400 - 12 - offset; -+ long size_max = ptr + 12 - offset; -+ ret = mtd->read(mtd, ptr, 16, &len, (void *)buf); -+ if (ret || len != 16) -+ return 0; -+ -+ if (le32_to_cpu(buf[0]) < size_min || -+ le32_to_cpu(buf[0]) > size_max) { -+ ptr += 0x400; -+ continue; -+ } -+ -+ if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC) -+ return ptr + 12 - offset; -+ -+ ptr += 0x400; -+ } -+ -+ return 0; -+} -+ - static int split_uimage(struct mtd_info *mtd, - const struct mtd_partition *part) - { -@@ -916,8 +948,11 @@ - - split_partitions[0].size = find_uimage_size(mtd, part->offset); - if (!split_partitions[0].size) { -- printk(KERN_NOTICE "no uImage found in linux partition\n"); -- return -1; -+ split_partitions[0].size = find_brnimage_size(mtd, part->offset); -+ if (!split_partitions[0].size) { -+ printk(KERN_NOTICE "no uImage or brnImage found in linux partition\n"); -+ return -1; -+ } - } - - if (!detect_squashfs_partition(mtd, -Index: linux-3.1.10/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h -=================================================================== ---- linux-3.1.10.orig/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-02-14 19:38:40.058266816 +0100 -+++ linux-3.1.10/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-02-14 19:57:07.790314179 +0100 -@@ -149,6 +149,7 @@ - - extern __iomem void *ltq_ebu_membase; - extern __iomem void *ltq_cgu_membase; -+extern unsigned long ltq_brn_boot; - - /* request a non-gpio and set the PIO config */ - extern int ltq_gpio_request(unsigned int pin, unsigned int alt0, -Index: linux-3.1.10/arch/mips/lantiq/setup.c -=================================================================== ---- linux-3.1.10.orig/arch/mips/lantiq/setup.c 2012-02-14 19:38:40.010266814 +0100 -+++ linux-3.1.10/arch/mips/lantiq/setup.c 2012-02-14 19:38:40.150266820 +0100 -@@ -20,6 +20,8 @@ - - /* assume 16M as default incase uboot fails to pass proper ramsize */ - unsigned long physical_memsize = 16L; -+/* set to 1 if the bootloader is BRN-BOOT instead of u-boot */ -+unsigned long ltq_brn_boot = 0; - - void __init plat_mem_setup(void) - { -@@ -39,6 +41,10 @@ - if (strict_strtoul(e, 0, &physical_memsize)) - pr_warn("bad memsize specified\n"); - } -+ if (!strncmp(e, "BRN-BOOT", 8)){ -+ pr_info("Found BRN-BOOT instead of u-boot\n"); -+ ltq_brn_boot = 1; -+ } - envp++; - } - physical_memsize *= 1024 * 1024; diff --git a/target/linux/lantiq/patches/800-fix-etop.patch b/target/linux/lantiq/patches/800-fix-etop.patch deleted file mode 100644 index 462a2c313d..0000000000 --- a/target/linux/lantiq/patches/800-fix-etop.patch +++ /dev/null @@ -1,67 +0,0 @@ ---- a/drivers/net/lantiq_etop.c -+++ b/drivers/net/lantiq_etop.c -@@ -397,7 +397,10 @@ ltq_etop_get_settings(struct net_device - { - struct ltq_etop_priv *priv = netdev_priv(dev); - -- return phy_ethtool_gset(priv->phydev, cmd); -+ if (priv->phydev) -+ return phy_ethtool_gset(priv->phydev, cmd); -+ else -+ return 0; - } - - static int -@@ -405,7 +408,10 @@ ltq_etop_set_settings(struct net_device - { - struct ltq_etop_priv *priv = netdev_priv(dev); - -- return phy_ethtool_sset(priv->phydev, cmd); -+ if (priv->phydev) -+ return phy_ethtool_sset(priv->phydev, cmd); -+ else -+ return 0; - } - - static int -@@ -413,7 +419,10 @@ ltq_etop_nway_reset(struct net_device *d - { - struct ltq_etop_priv *priv = netdev_priv(dev); - -- return phy_start_aneg(priv->phydev); -+ if (priv->phydev) -+ return phy_start_aneg(priv->phydev); -+ else -+ return 0; - } - - static const struct ethtool_ops ltq_etop_ethtool_ops = { -@@ -615,7 +624,8 @@ ltq_etop_open(struct net_device *dev) - ltq_dma_open(&ch->dma); - napi_enable(&ch->napi); - } -- phy_start(priv->phydev); -+ if (priv->phydev) -+ phy_start(priv->phydev); - netif_tx_start_all_queues(dev); - return 0; - } -@@ -627,7 +637,8 @@ ltq_etop_stop(struct net_device *dev) - int i; - - netif_tx_stop_all_queues(dev); -- phy_stop(priv->phydev); -+ if (priv->phydev) -+ phy_stop(priv->phydev); - for (i = 0; i < MAX_DMA_CHAN; i++) { - struct ltq_etop_chan *ch = &priv->ch[i]; - -@@ -775,7 +786,7 @@ ltq_etop_init(struct net_device *dev) - ltq_etop_set_multicast_list(dev); - err = ltq_etop_mdio_init(dev); - if (err) -- goto err_netdev; -+ pr_warn("etop: mdio probe failed\n");; - return 0; - - err_netdev: diff --git a/target/linux/lantiq/patches/820-fix-falcon-ltq_gpio_request.patch b/target/linux/lantiq/patches/820-fix-falcon-ltq_gpio_request.patch deleted file mode 100644 index b3fdf33f0b..0000000000 --- a/target/linux/lantiq/patches/820-fix-falcon-ltq_gpio_request.patch +++ /dev/null @@ -1,53 +0,0 @@ ---- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -@@ -129,8 +129,8 @@ extern __iomem void *ltq_sys1_membase; - ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg) - - /* gpio_request wrapper to help configure the pin */ --extern int ltq_gpio_request(unsigned int pin, unsigned int val, -- unsigned int dir, const char *name); -+extern int ltq_gpio_request(unsigned int pin, unsigned int alt0, -+ unsigned int alt1, unsigned int dir, const char *name); - extern int ltq_gpio_mux_set(unsigned int pin, unsigned int mux); - - /* to keep the irq code generic we need to define these to 0 as falcon ---- a/arch/mips/lantiq/falcon/gpio.c -+++ b/arch/mips/lantiq/falcon/gpio.c -@@ -96,11 +96,12 @@ int ltq_gpio_mux_set(unsigned int pin, u - } - EXPORT_SYMBOL(ltq_gpio_mux_set); - --int ltq_gpio_request(unsigned int pin, unsigned int val, -- unsigned int dir, const char *name) -+int ltq_gpio_request(unsigned int pin, unsigned int alt0, -+ unsigned int alt1, unsigned int dir, const char *name) - { - int port = pin / 100; - int offset = pin % 100; -+ unsigned int mux = (!!alt0) & ((!!alt1) << 1); - - if (offset >= PINS_PER_PORT || port >= MAX_PORTS) - return -EINVAL; -@@ -115,7 +116,7 @@ int ltq_gpio_request(unsigned int pin, u - else - gpio_direction_input(pin); - -- return ltq_gpio_mux_set(pin, val); -+ return ltq_gpio_mux_set(pin, mux); - } - EXPORT_SYMBOL(ltq_gpio_request); - ---- a/arch/mips/lantiq/falcon/prom.c -+++ b/arch/mips/lantiq/falcon/prom.c -@@ -43,9 +43,9 @@ ltq_soc_setup(void) - falcon_register_gpio(); - if (register_asc1) { - ltq_register_asc(1); -- if (ltq_gpio_request(MUXC_SIF_RX_PIN, 3, 0, "asc1-rx")) -+ if (ltq_gpio_request(MUXC_SIF_RX_PIN, 1, 1, 0, "asc1-rx")) - pr_err("failed to request asc1-rx"); -- if (ltq_gpio_request(MUXC_SIF_TX_PIN, 3, 1, "asc1-tx")) -+ if (ltq_gpio_request(MUXC_SIF_TX_PIN, 1, 1, 1, "asc1-tx")) - pr_err("failed to request asc1-tx"); - ltq_sysctl_activate(SYSCTL_SYS1, ACTS_ASC1_ACT); - } diff --git a/target/linux/lantiq/patches/830-fix-falcon-i2c-resources.patch b/target/linux/lantiq/patches/830-fix-falcon-i2c-resources.patch deleted file mode 100644 index ad0a11a666..0000000000 --- a/target/linux/lantiq/patches/830-fix-falcon-i2c-resources.patch +++ /dev/null @@ -1,17 +0,0 @@ ---- a/arch/mips/lantiq/falcon/devices.c -+++ b/arch/mips/lantiq/falcon/devices.c -@@ -130,10 +130,10 @@ falcon_register_gpio_extra(void) - /* i2c */ - static struct resource falcon_i2c_resources[] = { - MEM_RES("i2c", LTQ_I2C_BASE_ADDR, LTQ_I2C_SIZE), -- IRQ_RES("i2c_lb", FALCON_IRQ_I2C_LBREQ), -- IRQ_RES("i2c_b", FALCON_IRQ_I2C_BREQ), -- IRQ_RES("i2c_err", FALCON_IRQ_I2C_I2C_ERR), -- IRQ_RES("i2c_p", FALCON_IRQ_I2C_I2C_P), -+ IRQ_RES(i2c_lb, FALCON_IRQ_I2C_LBREQ), -+ IRQ_RES(i2c_b, FALCON_IRQ_I2C_BREQ), -+ IRQ_RES(i2c_err, FALCON_IRQ_I2C_I2C_ERR), -+ IRQ_RES(i2c_p, FALCON_IRQ_I2C_I2C_P), - }; - - void __init falcon_register_i2c(void) diff --git a/target/linux/lantiq/patches/840-fix-falcon-sysctrl.patch b/target/linux/lantiq/patches/840-fix-falcon-sysctrl.patch deleted file mode 100644 index 1a9b6fcee7..0000000000 --- a/target/linux/lantiq/patches/840-fix-falcon-sysctrl.patch +++ /dev/null @@ -1,61 +0,0 @@ ---- a/arch/mips/lantiq/falcon/sysctrl.c -+++ b/arch/mips/lantiq/falcon/sysctrl.c -@@ -63,11 +63,11 @@ void __iomem *ltq_ebu_membase; - #define ltq_status_r32(x) ltq_r32(ltq_status_membase + (x)) - - static inline void --ltq_sysctl_wait(int module, unsigned int mask, unsigned int test) -+ltq_sysctl_wait(int module, unsigned int mask, unsigned int test, unsigned int reg) - { - int err = 1000000; - -- do {} while (--err && ((ltq_reg_r32(module, LTQ_SYSCTL_ACTS) -+ do {} while (--err && ((ltq_reg_r32(module, reg) - & mask) != test)); - if (!err) - pr_err("module de/activation failed %d %08X %08X\n", -@@ -82,7 +82,7 @@ ltq_sysctl_activate(int module, unsigned - - ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); - ltq_reg_w32(module, mask, LTQ_SYSCTL_ACT); -- ltq_sysctl_wait(module, mask, mask); -+ ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); - } - EXPORT_SYMBOL(ltq_sysctl_activate); - -@@ -94,7 +94,7 @@ ltq_sysctl_deactivate(int module, unsign - - ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); - ltq_reg_w32(module, mask, LTQ_SYSCTL_DEACT); -- ltq_sysctl_wait(module, mask, 0); -+ ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_ACTS); - } - EXPORT_SYMBOL(ltq_sysctl_deactivate); - -@@ -105,7 +105,7 @@ ltq_sysctl_clken(int module, unsigned in - return; - - ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN); -- ltq_sysctl_wait(module, mask, mask); -+ ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_CLKS); - } - EXPORT_SYMBOL(ltq_sysctl_clken); - -@@ -116,7 +116,7 @@ ltq_sysctl_clkdis(int module, unsigned i - return; - - ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR); -- ltq_sysctl_wait(module, mask, 0); -+ ltq_sysctl_wait(module, mask, 0, LTQ_SYSCTL_CLKS); - } - EXPORT_SYMBOL(ltq_sysctl_clkdis); - -@@ -132,7 +132,7 @@ ltq_sysctl_reboot(int module, unsigned i - if ((~act & mask) != 0) - ltq_sysctl_activate(module, ~act & mask); - ltq_reg_w32(module, act & mask, LTQ_SYSCTL_RBT); -- ltq_sysctl_wait(module, mask, mask); -+ ltq_sysctl_wait(module, mask, mask, LTQ_SYSCTL_ACTS); - } - EXPORT_SYMBOL(ltq_sysctl_reboot); - diff --git a/target/linux/lantiq/patches/850-etop_irq.patch b/target/linux/lantiq/patches/850-etop_irq.patch deleted file mode 100644 index bc868f8187..0000000000 --- a/target/linux/lantiq/patches/850-etop_irq.patch +++ /dev/null @@ -1,70 +0,0 @@ -Index: linux-3.1.10/drivers/net/lantiq_etop.c -=================================================================== ---- linux-3.1.10.orig/drivers/net/lantiq_etop.c 2012-02-23 09:06:47.274557678 +0100 -+++ linux-3.1.10/drivers/net/lantiq_etop.c 2012-02-23 09:07:03.006558044 +0100 -@@ -203,8 +203,10 @@ - { - struct ltq_etop_chan *ch = container_of(napi, - struct ltq_etop_chan, napi); -+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev); - int rx = 0; - int complete = 0; -+ unsigned long flags; - - while ((rx < budget) && !complete) { - struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; -@@ -218,7 +220,9 @@ - } - if (complete || !rx) { - napi_complete(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); - ltq_dma_ack_irq(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); - } - return rx; - } -@@ -248,7 +252,9 @@ - if (netif_tx_queue_stopped(txq)) - netif_tx_start_queue(txq); - napi_complete(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); - ltq_dma_ack_irq(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); - return 1; - } - -@@ -615,13 +621,16 @@ - { - struct ltq_etop_priv *priv = netdev_priv(dev); - int i; -+ unsigned long flags; - - for (i = 0; i < MAX_DMA_CHAN; i++) { - struct ltq_etop_chan *ch = &priv->ch[i]; - - if (!IS_TX(i) && (!IS_RX(i))) - continue; -+ spin_lock_irqsave(&priv->lock, flags); - ltq_dma_open(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); - napi_enable(&ch->napi); - } - if (priv->phydev) -@@ -635,6 +644,7 @@ - { - struct ltq_etop_priv *priv = netdev_priv(dev); - int i; -+ unsigned long flags; - - netif_tx_stop_all_queues(dev); - if (priv->phydev) -@@ -645,7 +655,9 @@ - if (!IS_RX(i) && !IS_TX(i)) - continue; - napi_disable(&ch->napi); -+ spin_lock_irqsave(&priv->lock, flags); - ltq_dma_close(&ch->dma); -+ spin_unlock_irqrestore(&priv->lock, flags); - } - return 0; - } diff --git a/target/linux/lantiq/patches/860-falcon-fix-version.patch b/target/linux/lantiq/patches/860-falcon-fix-version.patch deleted file mode 100644 index e934d2efe3..0000000000 --- a/target/linux/lantiq/patches/860-falcon-fix-version.patch +++ /dev/null @@ -1,65 +0,0 @@ ---- a/arch/mips/lantiq/falcon/prom.c -+++ b/arch/mips/lantiq/falcon/prom.c -@@ -14,6 +14,9 @@ - #include "../prom.h" - - #define SOC_FALCON "Falcon" -+#define SOC_FALCON_D "Falcon-D" -+#define SOC_FALCON_V "Falcon-V" -+#define SOC_FALCON_M "Falcon-M" - - #define PART_SHIFT 12 - #define PART_MASK 0x0FFFF000 -@@ -21,6 +24,8 @@ - #define REV_MASK 0xF0000000 - #define SREV_SHIFT 22 - #define SREV_MASK 0x03C00000 -+#define TYPE_SHIFT 26 -+#define TYPE_MASK 0x3C000000 - - #define MUXC_SIF_RX_PIN 112 - #define MUXC_SIF_TX_PIN 113 -@@ -54,14 +59,30 @@ ltq_soc_setup(void) - void __init - ltq_soc_detect(struct ltq_soc_info *i) - { -+ u32 type; - i->partnum = (ltq_r32(LTQ_FALCON_CHIPID) & PART_MASK) >> PART_SHIFT; - i->rev = (ltq_r32(LTQ_FALCON_CHIPID) & REV_MASK) >> REV_SHIFT; -- i->srev = (ltq_r32(LTQ_FALCON_CHIPCONF) & SREV_MASK) >> SREV_SHIFT; -+ i->srev = ((ltq_r32(LTQ_FALCON_CHIPCONF) & SREV_MASK) >> SREV_SHIFT); - sprintf(i->rev_type, "%c%d%d", (i->srev & 0x4) ? ('B') : ('A'), -- i->rev & 0x7, i->srev & 0x3); -+ i->rev & 0x7, (i->srev & 0x3) + 1); -+ - switch (i->partnum) { - case SOC_ID_FALCON: -- i->name = SOC_FALCON; -+ type = (ltq_r32(LTQ_FALCON_CHIPTYPE) & TYPE_MASK) >> TYPE_SHIFT; -+ switch (type) { -+ case 0: -+ i->name = SOC_FALCON_D; -+ break; -+ case 1: -+ i->name = SOC_FALCON_V; -+ break; -+ case 2: -+ i->name = SOC_FALCON_M; -+ break; -+ default: -+ i->name = SOC_FALCON; -+ break; -+ } - i->type = SOC_TYPE_FALCON; - break; - ---- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h -@@ -78,6 +78,7 @@ - #define LTQ_STATUS_BASE_ADDR 0x1E802000 - - #define LTQ_FALCON_CHIPID ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x0c)) -+#define LTQ_FALCON_CHIPTYPE ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x38)) - #define LTQ_FALCON_CHIPCONF ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x40)) - - /* SYSCTL - start/stop/restart/configure/... different parts of the Soc */ diff --git a/target/linux/lantiq/patches/999-mtd.patch b/target/linux/lantiq/patches/999-mtd.patch deleted file mode 100644 index 713dd1f376..0000000000 --- a/target/linux/lantiq/patches/999-mtd.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/drivers/mtd/maps/lantiq-flash.c -+++ b/drivers/mtd/maps/lantiq-flash.c -@@ -20,6 +20,8 @@ - #include <linux/platform_device.h> - #include <linux/mtd/physmap.h> - -+#include "../mtdcore.h" -+ - #include <lantiq_soc.h> - #include <lantiq_platform.h> - diff --git a/target/linux/lantiq/vr9/config-default b/target/linux/lantiq/vr9/config-default index c2fc00146b..5fe73dbd0f 100644 --- a/target/linux/lantiq/vr9/config-default +++ b/target/linux/lantiq/vr9/config-default @@ -1,50 +1,54 @@ CONFIG_ADM6996_PHY=y CONFIG_AR8216_PHY=y -# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set -# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -# CONFIG_ATH79 is not set -CONFIG_GENERIC_ATOMIC64=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DMA_API_DEBUG=y -CONFIG_HAVE_DMA_ATTRS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y -CONFIG_HAVE_GENERIC_HARDIRQS=y -CONFIG_HAVE_IRQ_WORK=y -CONFIG_HAVE_PERF_EVENTS=y +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_ATMEL_PWM is not set +CONFIG_BLK_DEV_SD=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_FSNOTIFY=y +CONFIG_HAVE_MACH_CLKDEV=y CONFIG_HW_HAS_PCI=y CONFIG_INPUT=y CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_GPIO_BUTTONS is not set CONFIG_INPUT_POLLDEV=y +CONFIG_IRQ_FORCED_THREADING=y # CONFIG_ISDN is not set -CONFIG_LANTIQ_ETOP=y -CONFIG_LANTIQ_MACH_FRITZ3370=y -CONFIG_MACH_NO_WESTBRIDGE=y -# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_NEED_PER_CPU_KM=y +# CONFIG_LANTIQ_ETOP is not set +# CONFIG_LANTIQ_MACH_ARV is not set +# CONFIG_LANTIQ_MACH_EASY50712 is not set +# CONFIG_LANTIQ_MACH_FRITZ_AR9 is not set +CONFIG_LANTIQ_MACH_FRITZ_VR9=y +# CONFIG_LANTIQ_MACH_GIGASX76X is not set +# CONFIG_LANTIQ_MACH_NETGEAR is not set +# CONFIG_LANTIQ_MACH_WBMR is not set +CONFIG_LANTIQ_VRX200=y +CONFIG_M25PXX_USE_FAST_READ=y +CONFIG_MDIO_BOARDINFO=y +# CONFIG_MLX4_CORE is not set +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_PLATFORM=y +# CONFIG_MTD_SM_COMMON is not set +CONFIG_NLS=y CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_LANTIQ=y CONFIG_PCI_DOMAINS=y -CONFIG_PERF_USE_VMALLOC=y -# CONFIG_PREEMPT_RCU is not set -# CONFIG_QUOTACTL is not set +# CONFIG_PCI_LANTIQ is not set +# CONFIG_PCI_LANTIQ_NONE is not set CONFIG_RTL8306_PHY=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y # CONFIG_SOC_AMAZON_SE is not set -CONFIG_SOC_VR9=y # CONFIG_SOC_FALCON is not set CONFIG_SOC_TYPE_XWAY=y -# CONFIG_SOC_XWAY is not set +CONFIG_SOC_XWAY=y CONFIG_SPI=y CONFIG_SPI_BITBANG=y -# CONFIG_SPI_GPIO is not set -CONFIG_SPI_LANTIQ=y +CONFIG_SPI_GPIO=y CONFIG_SPI_MASTER=y +# CONFIG_SPI_XWAY is not set +CONFIG_USB_ARCH_HAS_XHCI=y CONFIG_USB_SUPPORT=y -CONFIG_XZ_DEC=y -CONFIG_SPI_XWAY=y diff --git a/target/linux/lantiq/vr9/profiles/001-avm.mk b/target/linux/lantiq/vr9/profiles/001-avm.mk new file mode 100644 index 0000000000..30de76abda --- /dev/null +++ b/target/linux/lantiq/vr9/profiles/001-avm.mk @@ -0,0 +1,6 @@ +define Profile/FRITZ3370 + NAME:=FRITZ3370 - Ftizbox + PACKAGES:=kmod-leds-gpio button-hotplug kmod-usb-ifxhcd +endef + +$(eval $(call Profile,FRITZ3370)) |